diff --git a/kstyle/CMakeLists.txt b/kstyle/CMakeLists.txt --- a/kstyle/CMakeLists.txt +++ b/kstyle/CMakeLists.txt @@ -120,6 +120,27 @@ animations/breezewidgetstateengine.cpp animations/breezewidgetstatedata.cpp debug/breezewidgetexplorer.cpp + widgets/checkbox.cpp + widgets/combobox.cpp + widgets/dial.cpp + widgets/dockwidget.cpp + widgets/groupbox.cpp + widgets/header.cpp + widgets/itemview.cpp + widgets/linedit.cpp + widgets/mdi.cpp + widgets/menu.cpp + widgets/menubar.cpp + widgets/progressbar.cpp + widgets/pushbutton.cpp + widgets/radiobutton.cpp + widgets/scrollbar.cpp + widgets/slider.cpp + widgets/spinbox.cpp + widgets/tabbar.cpp + widgets/toolbar.cpp + widgets/toolbox.cpp + widgets/toolbutton.cpp breezeaddeventfilter.cpp breezeframeshadow.cpp breezehelper.cpp diff --git a/kstyle/breezehelper.h b/kstyle/breezehelper.h --- a/kstyle/breezehelper.h +++ b/kstyle/breezehelper.h @@ -27,6 +27,7 @@ #include #include +#include #if BREEZE_USE_KDE4 #include @@ -356,3 +357,5 @@ } #endif + + diff --git a/kstyle/breezehelper.cpp b/kstyle/breezehelper.cpp --- a/kstyle/breezehelper.cpp +++ b/kstyle/breezehelper.cpp @@ -22,7 +22,6 @@ #include "breeze.h" #include "breezestyleconfigdata.h" -#include #include #include @@ -115,14 +114,6 @@ QColor Helper::hoverOutlineColor( const QPalette& palette ) const { return KColorUtils::mix( hoverColor( palette ), palette.color( QPalette::WindowText ), 0.15 ); } - //____________________________________________________________________ - QColor Helper::buttonFocusOutlineColor( const QPalette& palette ) const - { return KColorUtils::mix( focusColor( palette ), palette.color( QPalette::ButtonText ), 0.15 ); } - - //____________________________________________________________________ - QColor Helper::buttonHoverOutlineColor( const QPalette& palette ) const - { return KColorUtils::mix( hoverColor( palette ), palette.color( QPalette::ButtonText ), 0.15 ); } - //____________________________________________________________________ QColor Helper::sidePanelOutlineColor( const QPalette& palette, bool hasFocus, qreal opacity, AnimationMode mode ) const { @@ -194,216 +185,6 @@ } - //____________________________________________________________________ - QColor Helper::buttonOutlineColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const - { - - QColor outline( KColorUtils::mix( palette.color( QPalette::Button ), palette.color( QPalette::ButtonText ), 0.3 ) ); - if( mode == AnimationHover ) - { - - if( hasFocus ) - { - const QColor focus( buttonFocusOutlineColor( palette ) ); - const QColor hover( buttonHoverOutlineColor( palette ) ); - outline = KColorUtils::mix( focus, hover, opacity ); - - } else { - - const QColor hover( hoverColor( palette ) ); - outline = KColorUtils::mix( outline, hover, opacity ); - - } - - } else if( mouseOver ) { - - if( hasFocus ) outline = buttonHoverOutlineColor( palette ); - else outline = hoverColor( palette ); - - } else if( mode == AnimationFocus ) { - - const QColor focus( buttonFocusOutlineColor( palette ) ); - outline = KColorUtils::mix( outline, focus, opacity ); - - } else if( hasFocus ) { - - outline = buttonFocusOutlineColor( palette ); - - } - - return outline; - - } - - //____________________________________________________________________ - QColor Helper::buttonBackgroundColor( const QPalette& palette, bool mouseOver, bool hasFocus, bool sunken, qreal opacity, AnimationMode mode ) const - { - - QColor background( sunken ? - KColorUtils::mix( palette.color( QPalette::Button ), palette.color( QPalette::ButtonText ), 0.2 ): - palette.color( QPalette::Button ) ); - - if( mode == AnimationHover ) - { - - const QColor focus( focusColor( palette ) ); - const QColor hover( hoverColor( palette ) ); - if( hasFocus ) background = KColorUtils::mix( focus, hover, opacity ); - - } else if( mouseOver && hasFocus ) { - - background = hoverColor( palette ); - - } else if( mode == AnimationFocus ) { - - const QColor focus( focusColor( palette ) ); - background = KColorUtils::mix( background, focus, opacity ); - - } else if( hasFocus ) { - - background = focusColor( palette ); - - } - - return background; - - } - - //____________________________________________________________________ - QColor Helper::toolButtonColor( const QPalette& palette, bool mouseOver, bool hasFocus, bool sunken, qreal opacity, AnimationMode mode ) const - { - - QColor outline; - const QColor hoverColor( this->hoverColor( palette ) ); - const QColor focusColor( this->focusColor( palette ) ); - const QColor sunkenColor = alphaColor( palette.color( QPalette::WindowText ), 0.2 ); - - // hover takes precedence over focus - if( mode == AnimationHover ) - { - - if( hasFocus ) outline = KColorUtils::mix( focusColor, hoverColor, opacity ); - else if( sunken ) outline = sunkenColor; - else outline = alphaColor( hoverColor, opacity ); - - } else if( mouseOver ) { - - outline = hoverColor; - - } else if( mode == AnimationFocus ) { - - if( sunken ) outline = KColorUtils::mix( sunkenColor, focusColor, opacity ); - else outline = alphaColor( focusColor, opacity ); - - } else if( hasFocus ) { - - outline = focusColor; - - } else if( sunken ) { - - outline = sunkenColor; - - } - - return outline; - - } - - //____________________________________________________________________ - QColor Helper::sliderOutlineColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const - { - - QColor outline( KColorUtils::mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.4 ) ); - - // hover takes precedence over focus - if( mode == AnimationHover ) - { - - const QColor hover( hoverColor( palette ) ); - const QColor focus( focusColor( palette ) ); - if( hasFocus ) outline = KColorUtils::mix( focus, hover, opacity ); - else outline = KColorUtils::mix( outline, hover, opacity ); - - } else if( mouseOver ) { - - outline = hoverColor( palette ); - - } else if( mode == AnimationFocus ) { - - const QColor focus( focusColor( palette ) ); - outline = KColorUtils::mix( outline, focus, opacity ); - - } else if( hasFocus ) { - - outline = focusColor( palette ); - - } - - return outline; - - } - - //____________________________________________________________________ - QColor Helper::scrollBarHandleColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const - { - - QColor color( alphaColor( palette.color( QPalette::WindowText ), 0.5 ) ); - - // hover takes precedence over focus - if( mode == AnimationHover ) - { - - const QColor hover( hoverColor( palette ) ); - const QColor focus( focusColor( palette ) ); - if( hasFocus ) color = KColorUtils::mix( focus, hover, opacity ); - else color = KColorUtils::mix( color, hover, opacity ); - - } else if( mouseOver ) { - - color = hoverColor( palette ); - - } else if( mode == AnimationFocus ) { - - const QColor focus( focusColor( palette ) ); - color = KColorUtils::mix( color, focus, opacity ); - - } else if( hasFocus ) { - - color = focusColor( palette ); - - } - - return color; - - } - - //______________________________________________________________________________ - QColor Helper::checkBoxIndicatorColor( const QPalette& palette, bool mouseOver, bool active, qreal opacity, AnimationMode mode ) const - { - - QColor color( KColorUtils::mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.6 ) ); - if( mode == AnimationHover ) - { - - const QColor focus( focusColor( palette ) ); - const QColor hover( hoverColor( palette ) ); - if( active ) color = KColorUtils::mix( focus, hover, opacity ); - else color = KColorUtils::mix( color, hover, opacity ); - - } else if( mouseOver ) { - - color = hoverColor( palette ); - - } else if( active ) { - - color = focusColor( palette ); - - } - - return color; - - } - //______________________________________________________________________________ QColor Helper::separatorColor( const QPalette& palette ) const { return KColorUtils::mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.25 ); } @@ -527,792 +308,44 @@ } //______________________________________________________________________________ - void Helper::renderSidePanelFrame( QPainter* painter, const QRect& rect, const QColor& outline, Side side ) const - { - - // check color - if( !outline.isValid() ) return; - - // adjust rect - QRectF frameRect( rect ); - frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); - - // setup painter - painter->setRenderHint( QPainter::Antialiasing ); - painter->setPen( outline ); - - // render - switch( side ) - { - default: - case SideLeft: - painter->drawLine( frameRect.topRight(), frameRect.bottomRight() ); - break; - - case SideTop: - painter->drawLine( frameRect.topLeft(), frameRect.topRight() ); - break; - - case SideRight: - painter->drawLine( frameRect.topLeft(), frameRect.bottomLeft() ); - break; - - case SideBottom: - painter->drawLine( frameRect.bottomLeft(), frameRect.bottomRight() ); - break; - - case AllSides: - { - const qreal radius( frameRadius( -1.0 ) ); - painter->drawRoundedRect( frameRect, radius, radius ); - break; - } - - } - - } - - //______________________________________________________________________________ - void Helper::renderMenuFrame( + void Helper::renderSeparator( QPainter* painter, const QRect& rect, - const QColor& color, const QColor& outline, bool roundCorners ) const + const QColor& color, bool vertical ) const { + painter->setRenderHint( QPainter::Antialiasing, false ); + painter->setBrush( Qt::NoBrush ); + painter->setPen( color ); - // set brush - if( color.isValid() ) painter->setBrush( color ); - else painter->setBrush( Qt::NoBrush ); - - if( roundCorners ) + if( vertical ) { - painter->setRenderHint( QPainter::Antialiasing ); - QRectF frameRect( rect ); - qreal radius( frameRadius() ); - - // set pen - if( outline.isValid() ) - { - - painter->setPen( outline ); - frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); - radius = qMax( radius - 1, qreal( 0.0 ) ); - - } else painter->setPen( Qt::NoPen ); - - // render - painter->drawRoundedRect( frameRect, radius, radius ); + painter->translate( rect.width()/2, 0 ); + painter->drawLine( rect.topLeft(), rect.bottomLeft() ); } else { - painter->setRenderHint( QPainter::Antialiasing, false ); - QRect frameRect( rect ); - if( outline.isValid() ) - { - - painter->setPen( outline ); - frameRect.adjust( 0, 0, -1, -1 ); - - } else painter->setPen( Qt::NoPen ); - - painter->drawRect( frameRect ); - - } - - } - - //______________________________________________________________________________ - void Helper::renderButtonFrame( - QPainter* painter, const QRect& rect, - const QColor& color, const QColor& outline, const QColor& shadow, - bool hasFocus, bool sunken ) const - { - - // setup painter - painter->setRenderHint( QPainter::Antialiasing, true ); - - // copy rect - QRectF frameRect( rect ); - frameRect.adjust( 1, 1, -1, -1 ); - qreal radius( frameRadius() ); - - // shadow - if( sunken ) { - - frameRect.translate( 1, 1 ); - - } else if( shadow.isValid() ) { + painter->translate( 0, rect.height()/2 ); + painter->drawLine( rect.topLeft(), rect.topRight() ); - const qreal shadowRadius = qMax( radius - 1, qreal( 0.0 ) ); - painter->setPen( QPen( shadow, 2 ) ); - painter->setBrush( Qt::NoBrush ); - painter->drawRoundedRect( shadowRect( frameRect ), shadowRadius, shadowRadius ); } - if( outline.isValid() ) - { - - QLinearGradient gradient( frameRect.topLeft(), frameRect.bottomLeft() ); - gradient.setColorAt( 0, outline.lighter( hasFocus ? 103:101 ) ); - gradient.setColorAt( 1, outline.darker( hasFocus ? 110:103 ) ); - painter->setPen( QPen( QBrush( gradient ), 1.0 ) ); - - frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); - radius = qMax( radius - 1, qreal( 0.0 ) ); - - } else painter->setPen( Qt::NoPen ); - - // content - if( color.isValid() ) - { - - QLinearGradient gradient( frameRect.topLeft(), frameRect.bottomLeft() ); - gradient.setColorAt( 0, color.lighter( hasFocus ? 103:101 ) ); - gradient.setColorAt( 1, color.darker( hasFocus ? 110:103 ) ); - painter->setBrush( gradient ); - - } else painter->setBrush( Qt::NoBrush ); - - // render - painter->drawRoundedRect( frameRect, radius, radius ); - + } //______________________________________________________________________________ - void Helper::renderToolButtonFrame( - QPainter* painter, const QRect& rect, - const QColor& color, bool sunken ) const + void Helper::renderArrow( QPainter* painter, const QRect& rect, const QColor& color, ArrowOrientation orientation ) const { - - // do nothing for invalid color - if( !color.isValid() ) return; - - // setup painter - painter->setRenderHints( QPainter::Antialiasing ); - - const QRectF baseRect( rect ); - - if( sunken ) + // define polygon + QPolygonF arrow; + switch( orientation ) { - - const qreal radius( frameRadius() ); - - painter->setPen( Qt::NoPen ); - painter->setBrush( color ); - - const QRectF contentRect( baseRect.adjusted( 1, 1, -1, -1 ) ); - painter->drawRoundedRect( contentRect, radius, radius ); - - } else { - - const qreal radius( frameRadius(-0.5) ); - - painter->setPen( color ); - painter->setBrush( Qt::NoBrush ); - const QRectF outlineRect( baseRect.adjusted( 1.5, 1.5, -1.5, -1.5 ) ); - painter->drawRoundedRect( outlineRect, radius, radius ); - - } - - } - - //______________________________________________________________________________ - void Helper::renderToolBoxFrame( - QPainter* painter, const QRect& rect, int tabWidth, - const QColor& outline ) const - { - - if( !outline.isValid() ) return; - - // round radius - const qreal radius( frameRadius() ); - const QSizeF cornerSize( 2*radius, 2*radius ); - - // if rect - tabwidth is even, need to increase tabWidth by 1 unit - // for anti aliasing - if( !((rect.width() - tabWidth)%2) ) ++tabWidth; - - // adjust rect for antialiasing - QRectF baseRect( rect ); - baseRect.adjust( 0.5, 0.5, -0.5, -0.5 ); - - // create path - QPainterPath path; - path.moveTo( 0, baseRect.height()-1 ); - path.lineTo( ( baseRect.width() - tabWidth )/2 - radius, baseRect.height()-1 ); - path.arcTo( QRectF( QPointF( ( baseRect.width() - tabWidth )/2 - 2*radius, baseRect.height()-1 - 2*radius ), cornerSize ), 270, 90 ); - path.lineTo( ( baseRect.width() - tabWidth )/2, radius ); - path.arcTo( QRectF( QPointF( ( baseRect.width() - tabWidth )/2, 0 ), cornerSize ), 180, -90 ); - path.lineTo( ( baseRect.width() + tabWidth )/2 -1 - radius, 0 ); - path.arcTo( QRectF( QPointF( ( baseRect.width() + tabWidth )/2 - 1 - 2*radius, 0 ), cornerSize ), 90, -90 ); - path.lineTo( ( baseRect.width() + tabWidth )/2 -1, baseRect.height()-1 - radius ); - path.arcTo( QRectF( QPointF( ( baseRect.width() + tabWidth )/2 -1, baseRect.height()-1 - 2*radius ), cornerSize ), 180, 90 ); - path.lineTo( baseRect.width()-1, baseRect.height()-1 ); - - // render - painter->setRenderHints( QPainter::Antialiasing ); - painter->setBrush( Qt::NoBrush ); - painter->setPen( outline ); - painter->translate( baseRect.topLeft() ); - painter->drawPath( path ); - - } - - //______________________________________________________________________________ - void Helper::renderTabWidgetFrame( - QPainter* painter, const QRect& rect, - const QColor& color, const QColor& outline, Corners corners ) const - { - - painter->setRenderHint( QPainter::Antialiasing ); - - QRectF frameRect( rect.adjusted( 1, 1, -1, -1 ) ); - qreal radius( frameRadius() ); - - // set pen - if( outline.isValid() ) - { - - painter->setPen( outline ); - frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); - radius = qMax( radius-1, qreal( 0.0 ) ); - - } else painter->setPen( Qt::NoPen ); - - // set brush - if( color.isValid() ) painter->setBrush( color ); - else painter->setBrush( Qt::NoBrush ); - - // render - QPainterPath path( roundedPath( frameRect, corners, radius ) ); - painter->drawPath( path ); - - } - - - //______________________________________________________________________________ - void Helper::renderSelection( - QPainter* painter, const QRect& rect, - const QColor& color ) const - { - - painter->setRenderHint( QPainter::Antialiasing ); - painter->setPen( Qt::NoPen ); - painter->setBrush( color ); - painter->drawRect( rect ); - - } - - //______________________________________________________________________________ - void Helper::renderSeparator( - QPainter* painter, const QRect& rect, - const QColor& color, bool vertical ) const - { - - painter->setRenderHint( QPainter::Antialiasing, false ); - painter->setBrush( Qt::NoBrush ); - painter->setPen( color ); - - if( vertical ) - { - - painter->translate( rect.width()/2, 0 ); - painter->drawLine( rect.topLeft(), rect.bottomLeft() ); - - } else { - - painter->translate( 0, rect.height()/2 ); - painter->drawLine( rect.topLeft(), rect.topRight() ); - - - } - - - } - - //______________________________________________________________________________ - void Helper::renderCheckBoxBackground( - QPainter* painter, const QRect& rect, - const QColor& color, bool sunken ) const - { - - // setup painter - painter->setRenderHint( QPainter::Antialiasing, true ); - - // copy rect and radius - QRectF frameRect( rect ); - frameRect.adjust( 3, 3, -3, -3 ); - - if( sunken ) frameRect.translate(1, 1); - - painter->setPen( Qt::NoPen ); - painter->setBrush( color ); - painter->drawRect( frameRect ); - - } - - //______________________________________________________________________________ - void Helper::renderCheckBox( - QPainter* painter, const QRect& rect, - const QColor& color, const QColor& shadow, - bool sunken, CheckBoxState state, qreal animation ) const - { - - // setup painter - painter->setRenderHint( QPainter::Antialiasing, true ); - - // copy rect and radius - QRectF frameRect( rect ); - frameRect.adjust( 2, 2, -2, -2 ); - qreal radius( frameRadius() ); - - // shadow - if( sunken ) - { - - frameRect.translate(1, 1); - - } else { - - painter->setPen( QPen( shadow, 1 ) ); - painter->setBrush( Qt::NoBrush ); - - const qreal shadowRadius( radius + 0.5 ); - painter->drawRoundedRect( shadowRect( frameRect ).adjusted( -0.5, -0.5, 0.5, 0.5 ), shadowRadius, shadowRadius ); - - } - - // content - { - - painter->setPen( QPen( color, 1 ) ); - painter->setBrush( Qt::NoBrush ); - - radius = qMax( radius-1, qreal( 0.0 ) ); - const QRectF contentRect( frameRect.adjusted( 0.5, 0.5, -0.5, -0.5 ) ); - painter->drawRoundedRect( contentRect, radius, radius ); - - } - - // mark - if( state == CheckOn ) - { - - painter->setBrush( color ); - painter->setPen( Qt::NoPen ); - - const QRectF markerRect( frameRect.adjusted( 3, 3, -3, -3 ) ); - painter->drawRect( markerRect ); - - } else if( state == CheckPartial ) { - - QPen pen( color, 2 ); - pen.setJoinStyle( Qt::MiterJoin ); - painter->setPen( pen ); - - const QRectF markerRect( frameRect.adjusted( 4, 4, -4, -4 ) ); - painter->drawRect( markerRect ); - - painter->setPen( Qt::NoPen ); - painter->setBrush( color ); - painter->setRenderHint( QPainter::Antialiasing, false ); - - QPainterPath path; - path.moveTo( markerRect.topLeft() ); - path.lineTo( markerRect.right() - 1, markerRect.top() ); - path.lineTo( markerRect.left(), markerRect.bottom()-1 ); - painter->drawPath( path ); - - } else if( state == CheckAnimated ) { - - const QRectF markerRect( frameRect.adjusted( 3, 3, -3, -3 ) ); - QPainterPath path; - path.moveTo( markerRect.topRight() ); - path.lineTo( markerRect.center() + animation*( markerRect.topLeft() - markerRect.center() ) ); - path.lineTo( markerRect.bottomLeft() ); - path.lineTo( markerRect.center() + animation*( markerRect.bottomRight() - markerRect.center() ) ); - path.closeSubpath(); - - painter->setBrush( color ); - painter->setPen( Qt::NoPen ); - painter->drawPath( path ); - - } - - } - - //______________________________________________________________________________ - void Helper::renderRadioButtonBackground( QPainter* painter, const QRect& rect, const QColor& color, bool sunken ) const - { - - // setup painter - painter->setRenderHint( QPainter::Antialiasing, true ); - - // copy rect - QRectF frameRect( rect ); - frameRect.adjust( 3, 3, -3, -3 ); - if( sunken ) frameRect.translate(1, 1); - - painter->setPen( Qt::NoPen ); - painter->setBrush( color ); - painter->drawEllipse( frameRect ); - - } - - //______________________________________________________________________________ - void Helper::renderRadioButton( - QPainter* painter, const QRect& rect, - const QColor& color, const QColor& shadow, - bool sunken, RadioButtonState state, qreal animation ) const - { - - // setup painter - painter->setRenderHint( QPainter::Antialiasing, true ); - - // copy rect - QRectF frameRect( rect ); - frameRect.adjust( 2, 2, -2, -2 ); - - // shadow - if( sunken ) - { - - frameRect.translate( 1, 1 ); - - } else { - - painter->setPen( QPen( shadow, 1 ) ); - painter->setBrush( Qt::NoBrush ); - painter->drawEllipse( shadowRect( frameRect ).adjusted( -0.5, -0.5, 0.5, 0.5 ) ); - - } - - // content - { - - painter->setPen( QPen( color, 1 ) ); - painter->setBrush( Qt::NoBrush ); - - const QRectF contentRect( frameRect.adjusted( 0.5, 0.5, -0.5, -0.5 ) ); - painter->drawEllipse( contentRect ); - - } - - // mark - if( state == RadioOn ) - { - - painter->setBrush( color ); - painter->setPen( Qt::NoPen ); - - const QRectF markerRect( frameRect.adjusted( 3, 3, -3, -3 ) ); - painter->drawEllipse( markerRect ); - - } else if( state == RadioAnimated ) { - - painter->setBrush( color ); - painter->setPen( Qt::NoPen ); - QRectF markerRect( frameRect.adjusted( 3, 3, -3, -3 ) ); - - painter->translate( markerRect.center() ); - painter->rotate( 45 ); - - markerRect.setWidth( markerRect.width()*animation ); - markerRect.translate( -markerRect.center() ); - painter->drawEllipse( markerRect ); - - } - - } - - //______________________________________________________________________________ - void Helper::renderSliderGroove( - QPainter* painter, const QRect& rect, - const QColor& color ) const - { - - // setup painter - painter->setRenderHint( QPainter::Antialiasing, true ); - - const QRectF baseRect( rect ); - const qreal radius( 0.5*Metrics::Slider_GrooveThickness ); - - // content - if( color.isValid() ) - { - painter->setPen( Qt::NoPen ); - painter->setBrush( color ); - painter->drawRoundedRect( baseRect, radius, radius ); - } - - - } - - //______________________________________________________________________________ - void Helper::renderDialGroove( - QPainter* painter, const QRect& rect, - const QColor& color, - qreal first, qreal last ) const - { - - // setup painter - painter->setRenderHint( QPainter::Antialiasing, true ); - - const QRectF baseRect( rect ); - - // content - if( color.isValid() ) - { - const qreal penWidth( Metrics::Slider_GrooveThickness ); - const QRectF grooveRect( rect.adjusted( penWidth/2, penWidth/2, -penWidth/2, -penWidth/2 ) ); - - // setup angles - const int angleStart( first * 180 * 16 / M_PI ); - const int angleSpan( (last - first ) * 180 * 16 / M_PI ); - - // setup pen - if( angleSpan != 0 ) - { - QPen pen( color, penWidth ); - pen.setCapStyle( Qt::RoundCap ); - painter->setPen( pen ); - painter->setBrush( Qt::NoBrush ); - painter->drawArc( grooveRect, angleStart, angleSpan ); - } - } - - - } - - //______________________________________________________________________________ - void Helper::renderDialContents( - QPainter* painter, const QRect& rect, - const QColor& color, - qreal first, qreal second ) const - { - - // setup painter - painter->setRenderHint( QPainter::Antialiasing, true ); - - const QRectF baseRect( rect ); - - // content - if( color.isValid() ) - { - - // setup groove rect - const qreal penWidth( Metrics::Slider_GrooveThickness ); - const QRectF grooveRect( rect.adjusted( penWidth/2, penWidth/2, -penWidth/2, -penWidth/2 ) ); - - // setup angles - const int angleStart( first * 180 * 16 / M_PI ); - const int angleSpan( (second - first ) * 180 * 16 / M_PI ); - - // setup pen - if( angleSpan != 0 ) - { - QPen pen( color, penWidth ); - pen.setCapStyle( Qt::RoundCap ); - painter->setPen( pen ); - painter->setBrush( Qt::NoBrush ); - painter->drawArc( grooveRect, angleStart, angleSpan ); - } - - } - - - } - - //______________________________________________________________________________ - void Helper::renderSliderHandle( - QPainter* painter, const QRect& rect, - const QColor& color, - const QColor& outline, - const QColor& shadow, - bool sunken ) const - { - - // setup painter - painter->setRenderHint( QPainter::Antialiasing, true ); - - // copy rect - QRectF frameRect( rect ); - frameRect.adjust( 1, 1, -1, -1 ); - - // shadow - if( shadow.isValid() && !sunken ) - { - - painter->setPen( QPen( shadow, 2 ) ); - painter->setBrush( Qt::NoBrush ); - painter->drawEllipse( shadowRect( frameRect ) ); - - } - - // set pen - if( outline.isValid() ) - { - - painter->setPen( outline ); - frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); - - } else painter->setPen( Qt::NoPen ); - - // set brush - if( color.isValid() ) painter->setBrush( color ); - else painter->setBrush( Qt::NoBrush ); - - // render - painter->drawEllipse( frameRect ); - - } - - //______________________________________________________________________________ - void Helper::renderProgressBarGroove( - QPainter* painter, const QRect& rect, - const QColor& color ) const - { - - // setup painter - painter->setRenderHint( QPainter::Antialiasing, true ); - - const QRectF baseRect( rect ); - const qreal radius( 0.5*Metrics::ProgressBar_Thickness ); - - // content - if( color.isValid() ) - { - painter->setPen( Qt::NoPen ); - painter->setBrush( color ); - painter->drawRoundedRect( baseRect, radius, radius ); - } - - - } - - - //______________________________________________________________________________ - void Helper::renderProgressBarBusyContents( - QPainter* painter, const QRect& rect, - const QColor& first, - const QColor& second, - bool horizontal, - bool reverse, - int progress - ) const - { - - // setup painter - painter->setRenderHint( QPainter::Antialiasing, true ); - - const QRectF baseRect( rect ); - const qreal radius( 0.5*Metrics::ProgressBar_Thickness ); - - // setup brush - QPixmap pixmap( horizontal ? 2*Metrics::ProgressBar_BusyIndicatorSize : 1, horizontal ? 1:2*Metrics::ProgressBar_BusyIndicatorSize ); - pixmap.fill( second ); - if( horizontal ) - { - - QPainter painter( &pixmap ); - painter.setBrush( first ); - painter.setPen( Qt::NoPen ); - - progress %= 2*Metrics::ProgressBar_BusyIndicatorSize; - if( reverse ) progress = 2*Metrics::ProgressBar_BusyIndicatorSize - progress - 1; - painter.drawRect( QRect( 0, 0, Metrics::ProgressBar_BusyIndicatorSize, 1 ).translated( progress, 0 ) ); - - if( progress > Metrics::ProgressBar_BusyIndicatorSize ) - { painter.drawRect( QRect( 0, 0, Metrics::ProgressBar_BusyIndicatorSize, 1 ).translated( progress - 2*Metrics::ProgressBar_BusyIndicatorSize, 0 ) ); } - - } else { - - QPainter painter( &pixmap ); - painter.setBrush( first ); - painter.setPen( Qt::NoPen ); - - progress %= 2*Metrics::ProgressBar_BusyIndicatorSize; - progress = 2*Metrics::ProgressBar_BusyIndicatorSize - progress - 1; - painter.drawRect( QRect( 0, 0, 1, Metrics::ProgressBar_BusyIndicatorSize ).translated( 0, progress ) ); - - if( progress > Metrics::ProgressBar_BusyIndicatorSize ) - { painter.drawRect( QRect( 0, 0, 1, Metrics::ProgressBar_BusyIndicatorSize ).translated( 0, progress - 2*Metrics::ProgressBar_BusyIndicatorSize ) ); } - - } - - painter->setPen( Qt::NoPen ); - painter->setBrush( pixmap ); - painter->drawRoundedRect( baseRect, radius, radius ); - - } - - //______________________________________________________________________________ - void Helper::renderScrollBarHandle( - QPainter* painter, const QRect& rect, - const QColor& color ) const - { - - // setup painter - painter->setRenderHint( QPainter::Antialiasing, true ); - - const QRectF baseRect( rect ); - const qreal radius( 0.5 * std::min({baseRect.width(), baseRect.height(), (qreal)Metrics::ScrollBar_SliderWidth}) ); - - // content - if( color.isValid() ) - { - painter->setPen( Qt::NoPen ); - painter->setBrush( color ); - painter->drawRoundedRect( baseRect, radius, radius ); - } - - - } - - //______________________________________________________________________________ - void Helper::renderTabBarTab( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline, Corners corners ) const - { - - // setup painter - painter->setRenderHint( QPainter::Antialiasing, true ); - - QRectF frameRect( rect ); - qreal radius( frameRadius() ); - - // pen - if( outline.isValid() ) - { - - painter->setPen( outline ); - frameRect.adjust( 0.5, 0.5, -0.5, -0.5 ); - radius = qMax( radius-1, qreal( 0.0 ) ); - - } else painter->setPen( Qt::NoPen ); - - - // brush - if( color.isValid() ) painter->setBrush( color ); - else painter->setBrush( Qt::NoBrush ); - - // render - QPainterPath path( roundedPath( frameRect, corners, radius ) ); - painter->drawPath( path ); - - } - - //______________________________________________________________________________ - void Helper::renderArrow( QPainter* painter, const QRect& rect, const QColor& color, ArrowOrientation orientation ) const - { - // define polygon - QPolygonF arrow; - switch( orientation ) - { - case ArrowUp: arrow = QVector{QPointF( -4, 2 ), QPointF( 0, -2 ), QPointF( 4, 2 )}; break; - case ArrowDown: arrow = QVector{QPointF( -4, -2 ), QPointF( 0, 2 ), QPointF( 4, -2 )}; break; - case ArrowLeft: arrow = QVector{QPointF( 2, -4 ), QPointF( -2, 0 ), QPointF( 2, 4 )}; break; - case ArrowRight: arrow = QVector{QPointF( -2, -4 ), QPointF( 2, 0 ), QPointF( -2, 4 )}; break; - default: break; + case ArrowUp: arrow = QVector{QPointF( -4, 2 ), QPointF( 0, -2 ), QPointF( 4, 2 )}; break; + case ArrowDown: arrow = QVector{QPointF( -4, -2 ), QPointF( 0, 2 ), QPointF( 4, -2 )}; break; + case ArrowLeft: arrow = QVector{QPointF( 2, -4 ), QPointF( -2, 0 ), QPointF( 2, 4 )}; break; + case ArrowRight: arrow = QVector{QPointF( -2, -4 ), QPointF( 2, 0 ), QPointF( -2, 4 )}; break; + default: break; } painter->save(); @@ -1324,91 +357,6 @@ painter->restore(); } - //______________________________________________________________________________ - void Helper::renderDecorationButton( QPainter* painter, const QRect& rect, const QColor& color, ButtonType buttonType, bool inverted ) const - { - - painter->save(); - painter->setViewport( rect ); - painter->setWindow( 0, 0, 18, 18 ); - painter->setRenderHints( QPainter::Antialiasing ); - - // initialize pen - QPen pen; - pen.setCapStyle( Qt::RoundCap ); - pen.setJoinStyle( Qt::MiterJoin ); - - if( inverted ) - { - // render circle - painter->setPen( Qt::NoPen ); - painter->setBrush( color ); - painter->drawEllipse( QRectF( 0, 0, 18, 18 ) ); - - // take out the inner part - painter->setCompositionMode( QPainter::CompositionMode_DestinationOut ); - painter->setBrush( Qt::NoBrush ); - pen.setColor( Qt::black ); - - } else { - - painter->setBrush( Qt::NoBrush ); - pen.setColor( color ); - - } - - pen.setCapStyle( Qt::RoundCap ); - pen.setJoinStyle( Qt::MiterJoin ); - pen.setWidthF( 1.1*qMax(1.0, 18.0/rect.width() ) ); - painter->setPen( pen ); - - switch( buttonType ) - { - case ButtonClose: - { - painter->drawLine( QPointF( 5, 5 ), QPointF( 13, 13 ) ); - painter->drawLine( 13, 5, 5, 13 ); - break; - } - - case ButtonMaximize: - { - painter->drawPolyline( QVector{ - QPointF( 4, 11 ), - QPointF( 9, 6 ), - QPointF( 14, 11 )}); - break; - } - - case ButtonMinimize: - { - - painter->drawPolyline(QVector{ - QPointF( 4, 7 ), - QPointF( 9, 12 ), - QPointF( 14, 7 )} ); - break; - } - - case ButtonRestore: - { - pen.setJoinStyle( Qt::RoundJoin ); - painter->setPen( pen ); - painter->drawPolygon( QVector{ - QPointF( 4.5, 9 ), - QPointF( 9, 4.5 ), - QPointF( 13.5, 9 ), - QPointF( 9, 13.5 )}); - break; - } - - default: break; - } - - painter->restore(); - - } - //______________________________________________________________________________ bool Helper::isX11() { diff --git a/kstyle/breezestyle.h b/kstyle/breezestyle.h --- a/kstyle/breezestyle.h +++ b/kstyle/breezestyle.h @@ -24,6 +24,18 @@ #include "config-breeze.h" #include "breezehelper.h" +#include "breezeanimations.h" +#include "breezeframeshadow.h" +#include "breezemdiwindowshadow.h" +#include "breezemnemonics.h" +#include "breezepropertynames.h" +#include "breezeshadowhelper.h" +#include "breezesplitterproxy.h" +#include "breezestyleconfigdata.h" +#include "breezewidgetexplorer.h" +#include "breezewindowmanager.h" +#include "breezeblurhelper.h" + #if BREEZE_HAVE_KSTYLE #include #endif @@ -607,3 +619,5 @@ } #endif + + diff --git a/kstyle/breezestyle.cpp b/kstyle/breezestyle.cpp --- a/kstyle/breezestyle.cpp +++ b/kstyle/breezestyle.cpp @@ -18,21 +18,8 @@ *************************************************************************/ #include "breezestyle.h" - -#include "breeze.h" -#include "breezeanimations.h" -#include "breezeframeshadow.h" -#include "breezemdiwindowshadow.h" -#include "breezemnemonics.h" -#include "breezepropertynames.h" -#include "breezeshadowhelper.h" -#include "breezesplitterproxy.h" -#include "breezestyleconfigdata.h" -#include "breezewidgetexplorer.h" -#include "breezewindowmanager.h" -#include "breezeblurhelper.h" - -#include +#include "widgets/tabbar_p.h" +#include "widgets/combobox_p.h" #include #include @@ -43,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -60,97 +48,6 @@ #include #include -#if BREEZE_HAVE_QTQUICK -#include -#endif - -namespace BreezePrivate -{ - - // needed to keep track of tabbars when being dragged - class TabBarData: public QObject - { - - public: - - //* constructor - explicit TabBarData( QObject* parent ): - QObject( parent ) - {} - - //* assign target tabBar - void lock( const QWidget* widget ) - { _tabBar = widget; } - - //* true if tabbar is locked - bool isLocked( const QWidget* widget ) const - { return _tabBar && _tabBar.data() == widget; } - - //* release - void release() - { _tabBar.clear(); } - - private: - - //* pointer to target tabBar - Breeze::WeakPointer _tabBar; - - }; - - //* needed to have spacing added to items in combobox - class ComboBoxItemDelegate: public QItemDelegate - { - - public: - - //* constructor - explicit ComboBoxItemDelegate( QAbstractItemView* parent ): - QItemDelegate( parent ), - _proxy( parent->itemDelegate() ), - _itemMargin( Breeze::Metrics::ItemView_ItemMarginWidth ) - {} - - //* paint - void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override - { - // call either proxy or parent class - if( _proxy ) _proxy.data()->paint( painter, option, index ); - else QItemDelegate::paint( painter, option, index ); - } - - //* size hint for index - QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const override - { - - // get size from either proxy or parent class - auto size( _proxy ? - _proxy.data()->sizeHint( option, index ): - QItemDelegate::sizeHint( option, index ) ); - - // adjust and return - if( size.isValid() ) { size.rheight() += _itemMargin*2; } - return size; - - } - - private: - - //* proxy - Breeze::WeakPointer _proxy; - - //* margin - int _itemMargin; - - }; - - //_______________________________________________________________ - #if !BREEZE_USE_KDE4 - bool isProgressBarHorizontal( const QStyleOptionProgressBar* option ) - { return option && ( (option->state & QStyle::State_Horizontal ) || option->orientation == Qt::Horizontal ); } - #endif - -} - namespace Breeze { @@ -977,7 +874,6 @@ } - //___________________________________________________________________________________ void Style::drawItemText( QPainter* painter, const QRect& rect, int flags, const QPalette& palette, bool enabled, @@ -1153,203 +1049,6 @@ } - //_________________________________________________________ - bool Style::eventFilterComboBoxContainer( QWidget* widget, QEvent* event ) - { - if( event->type() == QEvent::Paint ) - { - - QPainter painter( widget ); - auto paintEvent = static_cast( event ); - painter.setClipRegion( paintEvent->region() ); - - const auto rect( widget->rect() ); - const auto& palette( widget->palette() ); - const auto background( _helper->frameBackgroundColor( palette ) ); - const auto outline( _helper->frameOutlineColor( palette ) ); - - const bool hasAlpha( _helper->hasAlphaChannel( widget ) ); - if( hasAlpha ) - { - - painter.setCompositionMode( QPainter::CompositionMode_Source ); - _helper->renderMenuFrame( &painter, rect, background, outline, true ); - - } else { - - _helper->renderMenuFrame( &painter, rect, background, outline, false ); - - } - - } - - return false; - - } - - //____________________________________________________________________________ - bool Style::eventFilterDockWidget( QDockWidget* dockWidget, QEvent* event ) - { - if( event->type() == QEvent::Paint ) - { - // create painter and clip - QPainter painter( dockWidget ); - QPaintEvent *paintEvent = static_cast( event ); - painter.setClipRegion( paintEvent->region() ); - - // store palette and set colors - const auto& palette( dockWidget->palette() ); - const auto background( _helper->frameBackgroundColor( palette ) ); - const auto outline( _helper->frameOutlineColor( palette ) ); - - // store rect - const auto rect( dockWidget->rect() ); - - // render - if( dockWidget->isFloating() ) - { - _helper->renderMenuFrame( &painter, rect, background, outline, false ); - - } else if( StyleConfigData::dockWidgetDrawFrame() || (dockWidget->features()&QDockWidget::AllDockWidgetFeatures) ) { - - _helper->renderFrame( &painter, rect, background, outline ); - - } - - } - - return false; - - } - - //____________________________________________________________________________ - bool Style::eventFilterMdiSubWindow( QMdiSubWindow* subWindow, QEvent* event ) - { - - if( event->type() == QEvent::Paint ) - { - QPainter painter( subWindow ); - QPaintEvent* paintEvent( static_cast( event ) ); - painter.setClipRegion( paintEvent->region() ); - - const auto rect( subWindow->rect() ); - const auto background( subWindow->palette().color( QPalette::Window ) ); - - if( subWindow->isMaximized() ) - { - - // full painting - painter.setPen( Qt::NoPen ); - painter.setBrush( background ); - painter.drawRect( rect ); - - } else { - - // framed painting - _helper->renderMenuFrame( &painter, rect, background, QColor() ); - - } - - } - - // continue with normal painting - return false; - - } - - //____________________________________________________________________________ - #if QT_VERSION >= 0x050000 - bool Style::eventFilterCommandLinkButton( QCommandLinkButton* button, QEvent* event ) - { - - if( event->type() == QEvent::Paint ) - { - - // painter - QPainter painter( button ); - painter.setClipRegion( static_cast( event )->region() ); - - const bool isFlat = false; - - // option - QStyleOptionButton option; - option.initFrom( button ); - option.features |= QStyleOptionButton::CommandLinkButton; - if( isFlat ) option.features |= QStyleOptionButton::Flat; - option.text = QString(); - option.icon = QIcon(); - - if( button->isChecked() ) option.state|=State_On; - if( button->isDown() ) option.state|=State_Sunken; - - // frame - drawControl(QStyle::CE_PushButton, &option, &painter, button ); - - // offset - const int margin( Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth ); - QPoint offset( margin, margin ); - - if( button->isDown() && !isFlat ) painter.translate( 1, 1 ); - { offset += QPoint( 1, 1 ); } - - // state - const State& state( option.state ); - const bool enabled( state & State_Enabled ); - bool mouseOver( enabled && ( state & State_MouseOver ) ); - bool hasFocus( enabled && ( state & State_HasFocus ) ); - - // icon - if( !button->icon().isNull() ) - { - - const auto pixmapSize( button->icon().actualSize( button->iconSize() ) ); - const QRect pixmapRect( QPoint( offset.x(), button->description().isEmpty() ? (button->height() - pixmapSize.height())/2:offset.y() ), pixmapSize ); - const QPixmap pixmap( button->icon().pixmap(pixmapSize, - enabled ? QIcon::Normal : QIcon::Disabled, - button->isChecked() ? QIcon::On : QIcon::Off) ); - drawItemPixmap( &painter, pixmapRect, Qt::AlignCenter, pixmap ); - - offset.rx() += pixmapSize.width() + Metrics::Button_ItemSpacing; - - } - - // text rect - QRect textRect( offset, QSize( button->size().width() - offset.x() - margin, button->size().height() - 2*margin ) ); - const QPalette::ColorRole textRole = (enabled && hasFocus && !mouseOver && !isFlat ) ? QPalette::HighlightedText : QPalette::ButtonText; - if( !button->text().isEmpty() ) - { - - QFont font( button->font() ); - font.setBold( true ); - painter.setFont( font ); - if( button->description().isEmpty() ) - { - - drawItemText( &painter, textRect, Qt::AlignLeft|Qt::AlignVCenter|Qt::TextHideMnemonic, button->palette(), enabled, button->text(), textRole ); - - } else { - - drawItemText( &painter, textRect, Qt::AlignLeft|Qt::AlignTop|Qt::TextHideMnemonic, button->palette(), enabled, button->text(), textRole ); - textRect.setTop( textRect.top() + QFontMetrics( font ).height() ); - - } - - painter.setFont( button->font() ); - - } - - if( !button->description().isEmpty() ) - { drawItemText( &painter, textRect, Qt::AlignLeft|Qt::AlignVCenter|Qt::TextWordWrap, button->palette(), enabled, button->description(), textRole ); } - - return true; - } - - // continue with normal painting - return false; - - } - #endif - //_____________________________________________________________________ void Style::configurationChanged() { @@ -1467,5732 +1166,273 @@ } //___________________________________________________________________________________________________________________ - QRect Style::pushButtonContentsRect( const QStyleOption* option, const QWidget* ) const - { return insideMargin( option->rect, Metrics::Frame_FrameWidth ); } - - //___________________________________________________________________________________________________________________ - QRect Style::checkBoxContentsRect( const QStyleOption* option, const QWidget* ) const - { return visualRect( option, option->rect.adjusted( Metrics::CheckBox_Size + Metrics::CheckBox_ItemSpacing, 0, 0, 0 ) ); } - - //___________________________________________________________________________________________________________________ - QRect Style::lineEditContentsRect( const QStyleOption* option, const QWidget* widget ) const + QRect Style::frameContentsRect( const QStyleOption* option, const QWidget* widget ) const { - // cast option and check - const auto frameOption( qstyleoption_cast( option ) ); - if( !frameOption ) return option->rect; + if( !StyleConfigData::sidePanelDrawFrame() && + qobject_cast( widget ) && + widget->property( PropertyNames::sidePanelView ).toBool() ) + { - // check flatness - const bool flat( frameOption->lineWidth == 0 ); - if( flat ) return option->rect; + // adjust margins for sidepanel widgets + return option->rect.adjusted( 0, 0, -1, 0 ); + + } else { - // copy rect and take out margins - auto rect( option->rect ); + // base class implementation + return ParentStyleClass::subElementRect( SE_FrameContents, option, widget ); - // take out margins if there is enough room - const int frameWidth( pixelMetric( PM_DefaultFrameWidth, option, widget ) ); - if( rect.height() >= option->fontMetrics.height() + 2*frameWidth ) return insideMargin( rect, frameWidth ); - else return rect; + } } - //___________________________________________________________________________________________________________________ - QRect Style::progressBarGrooveRect( const QStyleOption* option, const QWidget* widget ) const + //____________________________________________________________________ + QRect Style::genericLayoutItemRect( const QStyleOption* option, const QWidget* ) const + { return insideMargin( option->rect, -Metrics::Frame_FrameWidth ); } + + //______________________________________________________________ + bool Style::drawFramePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { - // cast option and check - const auto progressBarOption( qstyleoption_cast( option ) ); - if( !progressBarOption ) return option->rect; + // copy palette and rect + const auto& palette( option->palette ); + const auto& rect( option->rect ); + + // detect title widgets + const bool isTitleWidget( + StyleConfigData::titleWidgetDrawFrame() && + widget && + widget->parent() && + widget->parent()->inherits( "KTitleWidget" ) ); - // get flags and orientation - const bool textVisible( progressBarOption->textVisible ); - const bool busy( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ); + // copy state + const State& state( option->state ); + if( !isTitleWidget && !( state & (State_Sunken | State_Raised ) ) ) return true; - #if BREEZE_USE_KDE4 - const auto progressBarOption2( qstyleoption_cast( option ) ); - const bool horizontal( !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal ); + #if QT_VERSION >= 0x050000 + const bool isInputWidget( ( widget && widget->testAttribute( Qt::WA_Hover ) ) || + ( isQtQuickControl( option, widget ) && option->styleObject->property( "elementType" ).toString() == QStringLiteral( "edit") ) ); #else - const bool horizontal( BreezePrivate::isProgressBarHorizontal( progressBarOption ) ); + const bool isInputWidget( ( widget && widget->testAttribute( Qt::WA_Hover ) ) ); #endif - // copy rectangle and adjust - auto rect( option->rect ); - const int frameWidth( pixelMetric( PM_DefaultFrameWidth, option, widget ) ); - if( horizontal ) rect = insideMargin( rect, frameWidth, 0 ); - else rect = insideMargin( rect, 0, frameWidth ); + const bool enabled( state & State_Enabled ); + const bool mouseOver( enabled && isInputWidget && ( state & State_MouseOver ) ); + const bool hasFocus( enabled && isInputWidget && ( state & State_HasFocus ) ); - if( textVisible && !busy && horizontal ) - { + // focus takes precedence over mouse over + _animations->inputWidgetEngine().updateState( widget, AnimationFocus, hasFocus ); + _animations->inputWidgetEngine().updateState( widget, AnimationHover, mouseOver && !hasFocus ); - auto textRect( subElementRect( SE_ProgressBarLabel, option, widget ) ); - textRect = visualRect( option, textRect ); - rect.setRight( textRect.left() - Metrics::ProgressBar_ItemSpacing - 1 ); - rect = visualRect( option, rect ); - rect = centerRect( rect, rect.width(), Metrics::ProgressBar_Thickness ); + // retrieve animation mode and opacity + const AnimationMode mode( _animations->inputWidgetEngine().frameAnimationMode( widget ) ); + const qreal opacity( _animations->inputWidgetEngine().frameOpacity( widget ) ); - } else if( horizontal ) { + // render + if( !StyleConfigData::sidePanelDrawFrame() && widget && widget->property( PropertyNames::sidePanelView ).toBool() ) + { - rect = centerRect( rect, rect.width(), Metrics::ProgressBar_Thickness ); + const auto outline( _helper->sidePanelOutlineColor( palette, hasFocus, opacity, mode ) ); + const bool reverseLayout( option->direction == Qt::RightToLeft ); + const Side side( reverseLayout ? SideRight : SideLeft ); + _helper->renderSidePanelFrame( painter, rect, outline, side ); } else { - rect = centerRect( rect, Metrics::ProgressBar_Thickness, rect.height() ); + if( _frameShadowFactory->isRegistered( widget ) ) + { + + // update frame shadow factory + _frameShadowFactory->updateShadowsGeometry( widget, rect ); + _frameShadowFactory->updateState( widget, hasFocus, mouseOver, opacity, mode ); + + } + + const auto background( isTitleWidget ? palette.color( widget->backgroundRole() ):QColor() ); + const auto outline( _helper->frameOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); + _helper->renderFrame( painter, rect, background, outline ); } - return rect; + return true; } - //___________________________________________________________________________________________________________________ - QRect Style::progressBarContentsRect( const QStyleOption* option, const QWidget* widget ) const + //___________________________________________________________________________________ + bool Style::drawFrameFocusRectPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { + // no focus indicator on buttons / scrollbars, since it is rendered elsewhere + if ( qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) ) + { return true; } - // cast option and check - const auto progressBarOption( qstyleoption_cast( option ) ); - if( !progressBarOption ) return QRect(); + // no focus indicator on ComboBox list items + if (widget && widget->inherits("QComboBoxListView")) + { return true; } - // get groove rect - const auto rect( progressBarGrooveRect( option, widget ) ); + #if QT_VERSION >= 0x050000 + if ( option->styleObject && option->styleObject->property("elementType") == QLatin1String("button") ) + { return true; } + #endif - // in busy mode, grooveRect is used - const bool busy( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ); - if( busy ) return rect; + const State& state( option->state ); - // get orientation - #if BREEZE_USE_KDE4 - const auto progressBarOption2( qstyleoption_cast( option ) ); - const bool horizontal( !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal ); - #else - const bool horizontal( BreezePrivate::isProgressBarHorizontal( progressBarOption ) ); - #endif + // no focus indicator on selected list items + if ((state & State_Selected) && qobject_cast(widget)) + { return true; } - // check inverted appearance - #if BREEZE_USE_KDE4 - const bool inverted( progressBarOption2 ? progressBarOption2->invertedAppearance : false ); - #else - const bool inverted( progressBarOption->invertedAppearance ); - #endif + const auto rect( option->rect.adjusted( 0, 0, 0, 1 ) ); + const auto& palette( option->palette ); - // get progress and steps - const qreal progress( progressBarOption->progress - progressBarOption->minimum ); - const int steps( qMax( progressBarOption->maximum - progressBarOption->minimum, 1 ) ); + if( rect.width() < 10 ) return true; - //Calculate width fraction - const qreal widthFrac = qMin( qreal(1), progress/steps ); + const auto outlineColor( state & State_Selected ? palette.color( QPalette::HighlightedText ):palette.color( QPalette::Highlight ) ); + painter->setRenderHint( QPainter::Antialiasing, false ); + painter->setPen( outlineColor ); + painter->drawLine( QPoint( rect.bottomLeft() - QPoint( 0,1 ) ), QPoint( rect.bottomRight() - QPoint( 0,1 ) ) ); - // convert the pixel width - const int indicatorSize( widthFrac*( horizontal ? rect.width():rect.height() ) ); + return true; - QRect indicatorRect; - if( horizontal ) - { + } + + //___________________________________________________________________________________ + bool Style::drawFrameWindowPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const + { - indicatorRect = QRect( inverted ? ( rect.right() - indicatorSize + 1):rect.left(), rect.y(), indicatorSize, rect.height() ); - indicatorRect = visualRect( option->direction, rect, indicatorRect ); + // copy rect and palette + const auto& rect( option->rect ); + const auto& palette( option->palette ); + const State state( option->state ); + const bool selected( state & State_Selected ); - } else indicatorRect = QRect( rect.x(), inverted ? rect.top() : (rect.bottom() - indicatorSize + 1), rect.width(), indicatorSize ); + // render frame outline + const auto outline( _helper->frameOutlineColor( palette, false, selected ) ); + _helper->renderMenuFrame( painter, rect, QColor(), outline ); - return indicatorRect; + return true; } - //___________________________________________________________________________________________________________________ - QRect Style::frameContentsRect( const QStyleOption* option, const QWidget* widget ) const - { - if( !StyleConfigData::sidePanelDrawFrame() && - qobject_cast( widget ) && - widget->property( PropertyNames::sidePanelView ).toBool() ) - { - - // adjust margins for sidepanel widgets - return option->rect.adjusted( 0, 0, -1, 0 ); - - } else { - - // base class implementation - return ParentStyleClass::subElementRect( SE_FrameContents, option, widget ); - - } - } - - //___________________________________________________________________________________________________________________ - QRect Style::progressBarLabelRect( const QStyleOption* option, const QWidget* ) const - { - - // cast option and check - const auto progressBarOption( qstyleoption_cast( option ) ); - if( !progressBarOption ) return QRect(); - - // get flags and check - const bool textVisible( progressBarOption->textVisible ); - const bool busy( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ); - if( !textVisible || busy ) return QRect(); - - // get direction and check - #if BREEZE_USE_KDE4 - const auto progressBarOption2( qstyleoption_cast( option ) ); - const bool horizontal( !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal ); - #else - const bool horizontal( BreezePrivate::isProgressBarHorizontal( progressBarOption ) ); - #endif - if( !horizontal ) return QRect(); - - int textWidth = qMax( - option->fontMetrics.size( _mnemonics->textFlags(), progressBarOption->text ).width(), - option->fontMetrics.size( _mnemonics->textFlags(), QStringLiteral( "100%" ) ).width() ); - - auto rect( insideMargin( option->rect, Metrics::Frame_FrameWidth, 0 ) ); - rect.setLeft( rect.right() - textWidth + 1 ); - rect = visualRect( option, rect ); - - return rect; - - } - - //___________________________________________________________________________________________________________________ - QRect Style::headerArrowRect( const QStyleOption* option, const QWidget* ) const - { - - // cast option and check - const auto headerOption( qstyleoption_cast( option ) ); - if( !headerOption ) return option->rect; - - // check if arrow is necessary - if( headerOption->sortIndicator == QStyleOptionHeader::None ) return QRect(); - - auto arrowRect( insideMargin( option->rect, Metrics::Header_MarginWidth ) ); - arrowRect.setLeft( arrowRect.right() - Metrics::Header_ArrowSize + 1 ); - - return visualRect( option, arrowRect ); - - } - - //___________________________________________________________________________________________________________________ - QRect Style::headerLabelRect( const QStyleOption* option, const QWidget* ) const - { - - // cast option and check - const auto headerOption( qstyleoption_cast( option ) ); - if( !headerOption ) return option->rect; - - // check if arrow is necessary - auto labelRect( insideMargin( option->rect, Metrics::Header_MarginWidth, 0 ) ); - if( headerOption->sortIndicator == QStyleOptionHeader::None ) return labelRect; - - labelRect.adjust( 0, 0, -Metrics::Header_ArrowSize-Metrics::Header_ItemSpacing, 0 ); - return visualRect( option, labelRect ); - - } - - //____________________________________________________________________ - QRect Style::tabBarTabLeftButtonRect( const QStyleOption* option, const QWidget* ) const - { - - // cast option and check - #if BREEZE_USE_KDE4 - const auto tabOption( qstyleoption_cast( option ) ); - #else - const auto tabOption( qstyleoption_cast( option ) ); - #endif - if( !tabOption || tabOption->leftButtonSize.isEmpty() ) return QRect(); - - const auto rect( option->rect ); - const QSize size( tabOption->leftButtonSize ); - QRect buttonRect( QPoint(0,0), size ); - - // vertical positioning - switch( tabOption->shape ) - { - case QTabBar::RoundedNorth: - case QTabBar::TriangularNorth: - - case QTabBar::RoundedSouth: - case QTabBar::TriangularSouth: - buttonRect.moveLeft( rect.left() + Metrics::TabBar_TabMarginWidth ); - buttonRect.moveTop( ( rect.height() - buttonRect.height() )/2 ); - buttonRect = visualRect( option, buttonRect ); - break; - - case QTabBar::RoundedWest: - case QTabBar::TriangularWest: - buttonRect.moveBottom( rect.bottom() - Metrics::TabBar_TabMarginWidth ); - buttonRect.moveLeft( ( rect.width() - buttonRect.width() )/2 ); - break; - - case QTabBar::RoundedEast: - case QTabBar::TriangularEast: - buttonRect.moveTop( rect.top() + Metrics::TabBar_TabMarginWidth ); - buttonRect.moveLeft( ( rect.width() - buttonRect.width() )/2 ); - break; - - default: break; - } - - return buttonRect; - - } - - //____________________________________________________________________ - QRect Style::tabBarTabRightButtonRect( const QStyleOption* option, const QWidget* ) const - { - - // cast option and check - #if BREEZE_USE_KDE4 - const auto tabOption( qstyleoption_cast( option ) ); - #else - const auto tabOption( qstyleoption_cast( option ) ); - #endif - if( !tabOption || tabOption->rightButtonSize.isEmpty() ) return QRect(); - - const auto rect( option->rect ); - const auto size( tabOption->rightButtonSize ); - QRect buttonRect( QPoint(0,0), size ); - - // vertical positioning - switch( tabOption->shape ) - { - case QTabBar::RoundedNorth: - case QTabBar::TriangularNorth: - - case QTabBar::RoundedSouth: - case QTabBar::TriangularSouth: - buttonRect.moveRight( rect.right() - Metrics::TabBar_TabMarginWidth ); - buttonRect.moveTop( ( rect.height() - buttonRect.height() )/2 ); - buttonRect = visualRect( option, buttonRect ); - break; - - case QTabBar::RoundedWest: - case QTabBar::TriangularWest: - buttonRect.moveTop( rect.top() + Metrics::TabBar_TabMarginWidth ); - buttonRect.moveLeft( ( rect.width() - buttonRect.width() )/2 ); - break; - - case QTabBar::RoundedEast: - case QTabBar::TriangularEast: - buttonRect.moveBottom( rect.bottom() - Metrics::TabBar_TabMarginWidth ); - buttonRect.moveLeft( ( rect.width() - buttonRect.width() )/2 ); - break; - - default: break; - } - - return buttonRect; - - } - - //____________________________________________________________________ - QRect Style::tabWidgetTabBarRect( const QStyleOption* option, const QWidget* widget ) const - { - - // cast option and check - const auto tabOption = qstyleoption_cast( option ); - if( !tabOption ) return ParentStyleClass::subElementRect( SE_TabWidgetTabBar, option, widget ); - - // do nothing if tabbar is hidden - const QSize tabBarSize( tabOption->tabBarSize ); - - auto rect( option->rect ); - QRect tabBarRect( QPoint(0, 0), tabBarSize ); - - Qt::Alignment tabBarAlignment( styleHint( SH_TabBar_Alignment, option, widget ) ); - - // horizontal positioning - const bool verticalTabs( isVerticalTab( tabOption->shape ) ); - if( verticalTabs ) - { - - tabBarRect.setHeight( qMin( tabBarRect.height(), rect.height() - 2 ) ); - if( tabBarAlignment == Qt::AlignCenter ) tabBarRect.moveTop( rect.top() + ( rect.height() - tabBarRect.height() )/2 ); - else tabBarRect.moveTop( rect.top()+1 ); - - } else { - - // account for corner rects - // need to re-run visualRect to remove right-to-left handling, since it is re-added on tabBarRect at the end - const auto leftButtonRect( visualRect( option, subElementRect( SE_TabWidgetLeftCorner, option, widget ) ) ); - const auto rightButtonRect( visualRect( option, subElementRect( SE_TabWidgetRightCorner, option, widget ) ) ); - - rect.setLeft( leftButtonRect.width() ); - rect.setRight( rightButtonRect.left() - 1 ); - - tabBarRect.setWidth( qMin( tabBarRect.width(), rect.width() - 2 ) ); - if( tabBarAlignment == Qt::AlignCenter ) tabBarRect.moveLeft( rect.left() + (rect.width() - tabBarRect.width())/2 ); - else tabBarRect.moveLeft( rect.left() + 1 ); - - tabBarRect = visualRect( option, tabBarRect ); - - } - - // vertical positioning - switch( tabOption->shape ) - { - case QTabBar::RoundedNorth: - case QTabBar::TriangularNorth: - tabBarRect.moveTop( rect.top()+1 ); - break; - - case QTabBar::RoundedSouth: - case QTabBar::TriangularSouth: - tabBarRect.moveBottom( rect.bottom()-1 ); - break; - - case QTabBar::RoundedWest: - case QTabBar::TriangularWest: - tabBarRect.moveLeft( rect.left()+1 ); - break; - - case QTabBar::RoundedEast: - case QTabBar::TriangularEast: - tabBarRect.moveRight( rect.right()-1 ); - break; - - default: break; - - } - - return tabBarRect; - - } - - //____________________________________________________________________ - QRect Style::tabWidgetTabContentsRect( const QStyleOption* option, const QWidget* widget ) const - { - - // cast option and check - const auto tabOption = qstyleoption_cast( option ); - if( !tabOption ) return option->rect; - - // do nothing if tabbar is hidden - if( tabOption->tabBarSize.isEmpty() ) return option->rect; - const auto rect = tabWidgetTabPaneRect( option, widget ); - - const bool documentMode( tabOption->lineWidth == 0 ); - if( documentMode ) - { - - // add margin only to the relevant side - switch( tabOption->shape ) - { - case QTabBar::RoundedNorth: - case QTabBar::TriangularNorth: - return rect.adjusted( 0, Metrics::TabWidget_MarginWidth, 0, 0 ); - - case QTabBar::RoundedSouth: - case QTabBar::TriangularSouth: - return rect.adjusted( 0, 0, 0, -Metrics::TabWidget_MarginWidth ); - - case QTabBar::RoundedWest: - case QTabBar::TriangularWest: - return rect.adjusted( Metrics::TabWidget_MarginWidth, 0, 0, 0 ); - - case QTabBar::RoundedEast: - case QTabBar::TriangularEast: - return rect.adjusted( 0, 0, -Metrics::TabWidget_MarginWidth, 0 ); - - default: return rect; - } - - } else return insideMargin( rect, Metrics::TabWidget_MarginWidth ); - - } - - //____________________________________________________________________ - QRect Style::tabWidgetTabPaneRect( const QStyleOption* option, const QWidget* ) const - { - - const auto tabOption = qstyleoption_cast( option ); - if( !tabOption || tabOption->tabBarSize.isEmpty() ) return option->rect; - - const int overlap = Metrics::TabBar_BaseOverlap - 1; - const QSize tabBarSize( tabOption->tabBarSize - QSize( overlap, overlap ) ); - - auto rect( option->rect ); - switch( tabOption->shape ) - { - case QTabBar::RoundedNorth: - case QTabBar::TriangularNorth: - rect.adjust( 0, tabBarSize.height(), 0, 0 ); - break; - - case QTabBar::RoundedSouth: - case QTabBar::TriangularSouth: - rect.adjust( 0, 0, 0, -tabBarSize.height() ); - break; - - case QTabBar::RoundedWest: - case QTabBar::TriangularWest: - rect.adjust( tabBarSize.width(), 0, 0, 0 ); - break; - - case QTabBar::RoundedEast: - case QTabBar::TriangularEast: - rect.adjust( 0, 0, -tabBarSize.width(), 0 ); - break; - - default: return QRect(); - } - - return rect; - - } - - //____________________________________________________________________ - QRect Style::tabWidgetCornerRect( SubElement element, const QStyleOption* option, const QWidget* ) const - { - - // cast option and check - const auto tabOption = qstyleoption_cast( option ); - if( !tabOption ) return option->rect; - - // do nothing if tabbar is hidden - const QSize tabBarSize( tabOption->tabBarSize ); - if( tabBarSize.isEmpty() ) return QRect(); - - // do nothing for vertical tabs - const bool verticalTabs( isVerticalTab( tabOption->shape ) ); - if( verticalTabs ) return QRect(); - - const auto rect( option->rect ); - QRect cornerRect; - switch( element ) - { - case SE_TabWidgetLeftCorner: - cornerRect = QRect( QPoint(0,0), tabOption->leftCornerWidgetSize ); - cornerRect.moveLeft( rect.left() ); - break; - - case SE_TabWidgetRightCorner: - cornerRect = QRect( QPoint(0,0), tabOption->rightCornerWidgetSize ); - cornerRect.moveRight( rect.right() ); - break; - - default: break; - - } - - // expend height to tabBarSize, if needed, to make sure base is properly rendered - cornerRect.setHeight( qMax( cornerRect.height(), tabBarSize.height() + 1 ) ); - - switch( tabOption->shape ) - { - case QTabBar::RoundedNorth: - case QTabBar::TriangularNorth: - cornerRect.moveTop( rect.top() ); - break; - - case QTabBar::RoundedSouth: - case QTabBar::TriangularSouth: - cornerRect.moveBottom( rect.bottom() ); - break; - - default: break; - } - - // return cornerRect; - cornerRect = visualRect( option, cornerRect ); - return cornerRect; - - } - - //____________________________________________________________________ - QRect Style::toolBoxTabContentsRect( const QStyleOption* option, const QWidget* widget ) const - { - - // cast option and check - const auto toolBoxOption( qstyleoption_cast( option ) ); - if( !toolBoxOption ) return option->rect; - - // copy rect - const auto& rect( option->rect ); - - int contentsWidth(0); - if( !toolBoxOption->icon.isNull() ) - { - const int iconSize( pixelMetric( QStyle::PM_SmallIconSize, option, widget ) ); - contentsWidth += iconSize; - - if( !toolBoxOption->text.isEmpty() ) contentsWidth += Metrics::ToolBox_TabItemSpacing; - } - - if( !toolBoxOption->text.isEmpty() ) - { - - const int textWidth = toolBoxOption->fontMetrics.size( _mnemonics->textFlags(), toolBoxOption->text ).width(); - contentsWidth += textWidth; - - } - - contentsWidth += 2*Metrics::ToolBox_TabMarginWidth; - contentsWidth = qMin( contentsWidth, rect.width() ); - contentsWidth = qMax( contentsWidth, int(Metrics::ToolBox_TabMinWidth) ); - return centerRect( rect, contentsWidth, rect.height() ); - - } - - //____________________________________________________________________ - QRect Style::genericLayoutItemRect( const QStyleOption* option, const QWidget* ) const - { return insideMargin( option->rect, -Metrics::Frame_FrameWidth ); } - - //______________________________________________________________ - QRect Style::groupBoxSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const - { - - QRect rect = option->rect; - switch( subControl ) - { - - case SC_GroupBoxFrame: return rect; - - case SC_GroupBoxContents: - { - - // cast option and check - const auto groupBoxOption = qstyleoption_cast( option ); - if( !groupBoxOption ) break; - - // take out frame width - rect = insideMargin( rect, Metrics::Frame_FrameWidth ); - - // get state - const bool checkable( groupBoxOption->subControls & QStyle::SC_GroupBoxCheckBox ); - const bool emptyText( groupBoxOption->text.isEmpty() ); - - // calculate title height - int titleHeight( 0 ); - if( !emptyText ) titleHeight = groupBoxOption->fontMetrics.height(); - if( checkable ) titleHeight = qMax( titleHeight, int(Metrics::CheckBox_Size) ); - - // add margin - if( titleHeight > 0 ) titleHeight += 2*Metrics::GroupBox_TitleMarginWidth; - - rect.adjust( 0, titleHeight, 0, 0 ); - return rect; - - } - - case SC_GroupBoxCheckBox: - case SC_GroupBoxLabel: - { - - // cast option and check - const auto groupBoxOption = qstyleoption_cast( option ); - if( !groupBoxOption ) break; - - // take out frame width - rect = insideMargin( rect, Metrics::Frame_FrameWidth ); - - const bool emptyText( groupBoxOption->text.isEmpty() ); - const bool checkable( groupBoxOption->subControls & QStyle::SC_GroupBoxCheckBox ); - - // calculate title height - int titleHeight( 0 ); - int titleWidth( 0 ); - if( !emptyText ) - { - const QFontMetrics fontMetrics = option->fontMetrics; - titleHeight = qMax( titleHeight, fontMetrics.height() ); - titleWidth += fontMetrics.size( _mnemonics->textFlags(), groupBoxOption->text ).width(); - } - - if( checkable ) - { - titleHeight = qMax( titleHeight, int(Metrics::CheckBox_Size) ); - titleWidth += Metrics::CheckBox_Size; - if( !emptyText ) titleWidth += Metrics::CheckBox_ItemSpacing; - } - - // adjust height - auto titleRect( rect ); - titleRect.setHeight( titleHeight ); - titleRect.translate( 0, Metrics::GroupBox_TitleMarginWidth ); - - // center - titleRect = centerRect( titleRect, titleWidth, titleHeight ); - - if( subControl == SC_GroupBoxCheckBox ) - { - - // vertical centering - titleRect = centerRect( titleRect, titleWidth, Metrics::CheckBox_Size ); - - // horizontal positioning - const QRect subRect( titleRect.topLeft(), QSize( Metrics::CheckBox_Size, titleRect.height() ) ); - return visualRect( option->direction, titleRect, subRect ); - - } else { - - // vertical centering - QFontMetrics fontMetrics = option->fontMetrics; - titleRect = centerRect( titleRect, titleWidth, fontMetrics.height() ); - - // horizontal positioning - auto subRect( titleRect ); - if( checkable ) subRect.adjust( Metrics::CheckBox_Size + Metrics::CheckBox_ItemSpacing, 0, 0, 0 ); - return visualRect( option->direction, titleRect, subRect ); - - } - - } - - default: break; - - } - - return ParentStyleClass::subControlRect( CC_GroupBox, option, subControl, widget ); - - } - - //___________________________________________________________________________________________________________________ - QRect Style::toolButtonSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const - { - - // cast option and check - const auto toolButtonOption = qstyleoption_cast( option ); - if( !toolButtonOption ) return ParentStyleClass::subControlRect( CC_ToolButton, option, subControl, widget ); - - const bool hasPopupMenu( toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup ); - const bool hasInlineIndicator( - toolButtonOption->features&QStyleOptionToolButton::HasMenu - && toolButtonOption->features&QStyleOptionToolButton::PopupDelay - && !hasPopupMenu ); - - // store rect - const auto& rect( option->rect ); - const int menuButtonWidth( Metrics::MenuButton_IndicatorWidth ); - switch( subControl ) - { - case SC_ToolButtonMenu: - { - - // check features - if( !(hasPopupMenu || hasInlineIndicator ) ) return QRect(); - - // check features - auto menuRect( rect ); - menuRect.setLeft( rect.right() - menuButtonWidth + 1 ); - if( hasInlineIndicator ) - { menuRect.setTop( menuRect.bottom() - menuButtonWidth + 1 ); } - - return visualRect( option, menuRect ); - } - - case SC_ToolButton: - { - - if( hasPopupMenu ) - { - - auto contentsRect( rect ); - contentsRect.setRight( rect.right() - menuButtonWidth ); - return visualRect( option, contentsRect ); - - } else return rect; - - } - - default: return QRect(); - - } - - } - - //___________________________________________________________________________________________________________________ - QRect Style::comboBoxSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const - { - // cast option and check - const auto comboBoxOption( qstyleoption_cast( option ) ); - if( !comboBoxOption ) return ParentStyleClass::subControlRect( CC_ComboBox, option, subControl, widget ); - - const bool editable( comboBoxOption->editable ); - const bool flat( editable && !comboBoxOption->frame ); - - // copy rect - auto rect( option->rect ); - - switch( subControl ) - { - case SC_ComboBoxFrame: return flat ? rect : QRect(); - case SC_ComboBoxListBoxPopup: return rect; - - case SC_ComboBoxArrow: - { - - // take out frame width - if( !flat ) rect = insideMargin( rect, Metrics::Frame_FrameWidth ); - - QRect arrowRect( - rect.right() - Metrics::MenuButton_IndicatorWidth + 1, - rect.top(), - Metrics::MenuButton_IndicatorWidth, - rect.height() ); - - arrowRect = centerRect( arrowRect, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth ); - return visualRect( option, arrowRect ); - - } - - case SC_ComboBoxEditField: - { - - QRect labelRect; - const int frameWidth( pixelMetric( PM_ComboBoxFrameWidth, option, widget ) ); - labelRect = QRect( - rect.left(), rect.top(), - rect.width() - Metrics::MenuButton_IndicatorWidth, - rect.height() ); - - // remove margins - if( !flat && rect.height() >= option->fontMetrics.height() + 2*frameWidth ) - { labelRect.adjust( frameWidth, frameWidth, 0, -frameWidth ); } - - return visualRect( option, labelRect ); - - } - - default: break; - - } - - return ParentStyleClass::subControlRect( CC_ComboBox, option, subControl, widget ); - - } - - //___________________________________________________________________________________________________________________ - QRect Style::spinBoxSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const - { - - // cast option and check - const auto spinBoxOption( qstyleoption_cast( option ) ); - if( !spinBoxOption ) return ParentStyleClass::subControlRect( CC_SpinBox, option, subControl, widget ); - const bool flat( !spinBoxOption->frame ); - - // copy rect - auto rect( option->rect ); - - switch( subControl ) - { - case SC_SpinBoxFrame: return flat ? QRect():rect; - - case SC_SpinBoxUp: - case SC_SpinBoxDown: - { - - // take out frame width - if( !flat && rect.height() >= 2*Metrics::Frame_FrameWidth + Metrics::SpinBox_ArrowButtonWidth ) rect = insideMargin( rect, Metrics::Frame_FrameWidth ); - - QRect arrowRect; - arrowRect = QRect( - rect.right() - Metrics::SpinBox_ArrowButtonWidth + 1, - rect.top(), - Metrics::SpinBox_ArrowButtonWidth, - rect.height() ); - - const int arrowHeight( qMin( rect.height(), int(Metrics::SpinBox_ArrowButtonWidth) ) ); - arrowRect = centerRect( arrowRect, Metrics::SpinBox_ArrowButtonWidth, arrowHeight ); - arrowRect.setHeight( arrowHeight/2 ); - if( subControl == SC_SpinBoxDown ) arrowRect.translate( 0, arrowHeight/2 ); - - return visualRect( option, arrowRect ); - - } - - case SC_SpinBoxEditField: - { - - QRect labelRect; - labelRect = QRect( - rect.left(), rect.top(), - rect.width() - Metrics::SpinBox_ArrowButtonWidth, - rect.height() ); - - // remove right side line editor margins - const int frameWidth( pixelMetric( PM_SpinBoxFrameWidth, option, widget ) ); - if( !flat && labelRect.height() >= option->fontMetrics.height() + 2*frameWidth ) - { labelRect.adjust( frameWidth, frameWidth, 0, -frameWidth ); } - - return visualRect( option, labelRect ); - - } - - default: break; - - } - - return ParentStyleClass::subControlRect( CC_SpinBox, option, subControl, widget ); - - } - - //___________________________________________________________________________________________________________________ - QRect Style::scrollBarInternalSubControlRect( const QStyleOptionComplex* option, SubControl subControl ) const - { - - const auto& rect = option->rect; - const State& state( option->state ); - const bool horizontal( state & State_Horizontal ); - - switch( subControl ) - { - - case SC_ScrollBarSubLine: - { - int majorSize( scrollBarButtonHeight( _subLineButtons ) ); - if( horizontal ) return visualRect( option, QRect( rect.left(), rect.top(), majorSize, rect.height() ) ); - else return visualRect( option, QRect( rect.left(), rect.top(), rect.width(), majorSize ) ); - - } - - case SC_ScrollBarAddLine: - { - int majorSize( scrollBarButtonHeight( _addLineButtons ) ); - if( horizontal ) return visualRect( option, QRect( rect.right() - majorSize + 1, rect.top(), majorSize, rect.height() ) ); - else return visualRect( option, QRect( rect.left(), rect.bottom() - majorSize + 1, rect.width(), majorSize ) ); - } - - default: return QRect(); - - } - } - - //___________________________________________________________________________________________________________________ - QRect Style::scrollBarSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const - { - - // cast option and check - const auto sliderOption( qstyleoption_cast( option ) ); - if( !sliderOption ) return ParentStyleClass::subControlRect( CC_ScrollBar, option, subControl, widget ); - - // get relevant state - const State& state( option->state ); - const bool horizontal( state & State_Horizontal ); - - switch( subControl ) - { - - case SC_ScrollBarSubLine: - case SC_ScrollBarAddLine: - return scrollBarInternalSubControlRect( option, subControl ); - - case SC_ScrollBarGroove: - { - auto topRect = visualRect( option, scrollBarInternalSubControlRect( option, SC_ScrollBarSubLine ) ); - auto bottomRect = visualRect( option, scrollBarInternalSubControlRect( option, SC_ScrollBarAddLine ) ); - - QPoint topLeftCorner; - QPoint botRightCorner; - - if( horizontal ) - { - - topLeftCorner = QPoint( topRect.right() + 1, topRect.top() ); - botRightCorner = QPoint( bottomRect.left() - 1, topRect.bottom() ); - - } else { - - topLeftCorner = QPoint( topRect.left(), topRect.bottom() + 1 ); - botRightCorner = QPoint( topRect.right(), bottomRect.top() - 1 ); - - } - - // define rect - return visualRect( option, QRect( topLeftCorner, botRightCorner ) ); - - } - - case SC_ScrollBarSlider: - { - - // handle RTL here to unreflect things if need be - auto groove = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ) ); - - if( sliderOption->minimum == sliderOption->maximum ) return groove; - - // Figure out how much room there is - int space( horizontal ? groove.width() : groove.height() ); - - // Calculate the portion of this space that the slider should occupy - int sliderSize = space * qreal( sliderOption->pageStep ) / ( sliderOption->maximum - sliderOption->minimum + sliderOption->pageStep ); - sliderSize = qMax( sliderSize, static_cast(Metrics::ScrollBar_MinSliderHeight ) ); - sliderSize = qMin( sliderSize, space ); - - space -= sliderSize; - if( space <= 0 ) return groove; - - int pos = qRound( qreal( sliderOption->sliderPosition - sliderOption->minimum )/ ( sliderOption->maximum - sliderOption->minimum )*space ); - if( sliderOption->upsideDown ) pos = space - pos; - if( horizontal ) return visualRect( option, QRect( groove.left() + pos, groove.top(), sliderSize, groove.height() ) ); - else return visualRect( option, QRect( groove.left(), groove.top() + pos, groove.width(), sliderSize ) ); - } - - case SC_ScrollBarSubPage: - { - - // handle RTL here to unreflect things if need be - auto slider = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarSlider, widget ) ); - auto groove = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ) ); - - if( horizontal ) return visualRect( option, QRect( groove.left(), groove.top(), slider.left() - groove.left(), groove.height() ) ); - else return visualRect( option, QRect( groove.left(), groove.top(), groove.width(), slider.top() - groove.top() ) ); - } - - case SC_ScrollBarAddPage: - { - - // handle RTL here to unreflect things if need be - auto slider = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarSlider, widget ) ); - auto groove = visualRect( option, subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ) ); - - if( horizontal ) return visualRect( option, QRect( slider.right() + 1, groove.top(), groove.right() - slider.right(), groove.height() ) ); - else return visualRect( option, QRect( groove.left(), slider.bottom() + 1, groove.width(), groove.bottom() - slider.bottom() ) ); - - } - - default: return ParentStyleClass::subControlRect( CC_ScrollBar, option, subControl, widget );; - } - } - - //___________________________________________________________________________________________________________________ - QRect Style::dialSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const - { - - // cast option and check - const auto sliderOption( qstyleoption_cast( option ) ); - if( !sliderOption ) return ParentStyleClass::subControlRect( CC_Dial, option, subControl, widget ); - - // adjust rect to be square, and centered - auto rect( option->rect ); - const int dimension( qMin( rect.width(), rect.height() ) ); - rect = centerRect( rect, dimension, dimension ); - - switch( subControl ) - { - case QStyle::SC_DialGroove: return insideMargin( rect, (Metrics::Slider_ControlThickness - Metrics::Slider_GrooveThickness)/2 ); - case QStyle::SC_DialHandle: - { - - // calculate angle at which handle needs to be drawn - const qreal angle( dialAngle( sliderOption, sliderOption->sliderPosition ) ); - - // groove rect - const QRectF grooveRect( insideMargin( rect, Metrics::Slider_ControlThickness/2 ) ); - qreal radius( grooveRect.width()/2 ); - - // slider center - QPointF center( grooveRect.center() + QPointF( radius*std::cos( angle ), -radius*std::sin( angle ) ) ); - - // slider rect - QRect handleRect( 0, 0, Metrics::Slider_ControlThickness, Metrics::Slider_ControlThickness ); - handleRect.moveCenter( center.toPoint() ); - return handleRect; - - } - - default: return ParentStyleClass::subControlRect( CC_Dial, option, subControl, widget );; - - } - - } - - //___________________________________________________________________________________________________________________ - QRect Style::sliderSubControlRect( const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const - { - - // cast option and check - const auto sliderOption( qstyleoption_cast( option ) ); - if( !sliderOption ) return ParentStyleClass::subControlRect( CC_Slider, option, subControl, widget ); - - switch( subControl ) - { - case SC_SliderGroove: - { - - // direction - const bool horizontal( sliderOption->orientation == Qt::Horizontal ); - - // get base class rect - auto grooveRect( ParentStyleClass::subControlRect( CC_Slider, option, subControl, widget ) ); - grooveRect = insideMargin( grooveRect, pixelMetric( PM_DefaultFrameWidth, option, widget ) ); - - // centering - if( horizontal ) grooveRect = centerRect( grooveRect, grooveRect.width(), Metrics::Slider_GrooveThickness ); - else grooveRect = centerRect( grooveRect, Metrics::Slider_GrooveThickness, grooveRect.height() ); - return grooveRect; - - } - - default: return ParentStyleClass::subControlRect( CC_Slider, option, subControl, widget ); - } - - } - - //______________________________________________________________ - QSize Style::checkBoxSizeFromContents( const QStyleOption*, const QSize& contentsSize, const QWidget* ) const - { - // get contents size - QSize size( contentsSize ); - - // add focus height - size = expandSize( size, 0, Metrics::CheckBox_FocusMarginWidth ); - - // make sure there is enough height for indicator - size.setHeight( qMax( size.height(), int(Metrics::CheckBox_Size) ) ); - - // Add space for the indicator and the icon - size.rwidth() += Metrics::CheckBox_Size + Metrics::CheckBox_ItemSpacing; - - // also add extra space, to leave room to the right of the label - size.rwidth() += Metrics::CheckBox_ItemSpacing; - - return size; - - } - - //______________________________________________________________ - QSize Style::lineEditSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const - { - // cast option and check - const auto frameOption( qstyleoption_cast( option ) ); - if( !frameOption ) return contentsSize; - - const bool flat( frameOption->lineWidth == 0 ); - const int frameWidth( pixelMetric( PM_DefaultFrameWidth, option, widget ) ); - return flat ? contentsSize : expandSize( contentsSize, frameWidth ); - } - - //______________________________________________________________ - QSize Style::comboBoxSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const - { - - // cast option and check - const auto comboBoxOption( qstyleoption_cast( option ) ); - if( !comboBoxOption ) return contentsSize; - - // copy size - QSize size( contentsSize ); - - // add relevant margin - const bool flat( !comboBoxOption->frame ); - const int frameWidth( pixelMetric( PM_ComboBoxFrameWidth, option, widget ) ); - if( !flat ) size = expandSize( size, frameWidth ); - - // make sure there is enough height for the button - size.setHeight( qMax( size.height(), int(Metrics::MenuButton_IndicatorWidth) ) ); - - // add button width and spacing - size.rwidth() += Metrics::MenuButton_IndicatorWidth+2; - - return size; - - } - - //______________________________________________________________ - QSize Style::spinBoxSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const - { - - // cast option and check - const auto spinBoxOption( qstyleoption_cast( option ) ); - if( !spinBoxOption ) return contentsSize; - - const bool flat( !spinBoxOption->frame ); - - // copy size - QSize size( contentsSize ); - - // add editor margins - const int frameWidth( pixelMetric( PM_SpinBoxFrameWidth, option, widget ) ); - if( !flat ) size = expandSize( size, frameWidth ); - - // make sure there is enough height for the button - size.setHeight( qMax( size.height(), int(Metrics::SpinBox_ArrowButtonWidth) ) ); - - // add button width and spacing - size.rwidth() += Metrics::SpinBox_ArrowButtonWidth; - - return size; - - } - - //______________________________________________________________ - QSize Style::sliderSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const - { - - // cast option and check - const auto sliderOption( qstyleoption_cast( option ) ); - if( !sliderOption ) return contentsSize; - - // store tick position and orientation - const QSlider::TickPosition& tickPosition( sliderOption->tickPosition ); - const bool horizontal( sliderOption->orientation == Qt::Horizontal ); - const bool disableTicks( !StyleConfigData::sliderDrawTickMarks() ); - - // do nothing if no ticks are requested - if( tickPosition == QSlider::NoTicks ) return contentsSize; - - /* - * Qt adds its own tick length directly inside QSlider. - * Take it out and replace by ours, if needed - */ - const int tickLength( disableTicks ? 0 : ( - Metrics::Slider_TickLength + Metrics::Slider_TickMarginWidth + - (Metrics::Slider_GrooveThickness - Metrics::Slider_ControlThickness)/2 ) ); - - const int builtInTickLength( 5 ); - - QSize size( contentsSize ); - if( horizontal ) - { - - if(tickPosition & QSlider::TicksAbove) size.rheight() += tickLength - builtInTickLength; - if(tickPosition & QSlider::TicksBelow) size.rheight() += tickLength - builtInTickLength; - - } else { - - if(tickPosition & QSlider::TicksAbove) size.rwidth() += tickLength - builtInTickLength; - if(tickPosition & QSlider::TicksBelow) size.rwidth() += tickLength - builtInTickLength; - - } - - return size; - - } - - //______________________________________________________________ - QSize Style::pushButtonSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const - { - - // cast option and check - const auto buttonOption( qstyleoption_cast( option ) ); - if( !buttonOption ) return contentsSize; - - // output - QSize size; - - // check text and icon - const bool hasText( !buttonOption->text.isEmpty() ); - const bool flat( buttonOption->features & QStyleOptionButton::Flat ); - bool hasIcon( !buttonOption->icon.isNull() ); - - if( !( hasText||hasIcon ) ) - { - - /* - no text nor icon is passed. - assume custom button and use contentsSize as a starting point - */ - size = contentsSize; - - } else { - - /* - rather than trying to guess what Qt puts into its contents size calculation, - we recompute the button size entirely, based on button option - this ensures consistency with the rendering stage - */ - - // update has icon to honour showIconsOnPushButtons, when possible - hasIcon &= (showIconsOnPushButtons() || flat || !hasText ); - - // text - if( hasText ) size = buttonOption->fontMetrics.size( Qt::TextShowMnemonic, buttonOption->text ); - - // icon - if( hasIcon ) - { - QSize iconSize = buttonOption->iconSize; - if( !iconSize.isValid() ) iconSize = QSize( pixelMetric( PM_SmallIconSize, option, widget ), pixelMetric( PM_SmallIconSize, option, widget ) ); - - size.setHeight( qMax( size.height(), iconSize.height() ) ); - size.rwidth() += iconSize.width(); - - if( hasText ) size.rwidth() += Metrics::Button_ItemSpacing; - } - - } - - // menu - const bool hasMenu( buttonOption->features & QStyleOptionButton::HasMenu ); - if( hasMenu ) - { - size.rwidth() += Metrics::MenuButton_IndicatorWidth; - if( hasText||hasIcon ) size.rwidth() += Metrics::Button_ItemSpacing; - } - - // expand with buttons margin - size = expandSize( size, Metrics::Button_MarginWidth ); - - // make sure buttons have a minimum width - if( hasText ) - { size.setWidth( qMax( size.width(), int( Metrics::Button_MinWidth ) ) ); } - - // finally add frame margins - return expandSize( size, Metrics::Frame_FrameWidth ); - - } - - //______________________________________________________________ - QSize Style::toolButtonSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const - { - - // cast option and check - const auto toolButtonOption = qstyleoption_cast( option ); - if( !toolButtonOption ) return contentsSize; - - // copy size - QSize size = contentsSize; - - // get relevant state flags - const State& state( option->state ); - const bool autoRaise( state & State_AutoRaise ); - const bool hasPopupMenu( toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup ); - const bool hasInlineIndicator( - toolButtonOption->features&QStyleOptionToolButton::HasMenu - && toolButtonOption->features&QStyleOptionToolButton::PopupDelay - && !hasPopupMenu ); - - const int marginWidth( autoRaise ? Metrics::ToolButton_MarginWidth : Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth ); - - if( hasInlineIndicator ) size.rwidth() += Metrics::ToolButton_InlineIndicatorWidth; - size = expandSize( size, marginWidth ); - - return size; - - } - - //______________________________________________________________ - QSize Style::menuBarItemSizeFromContents( const QStyleOption*, const QSize& contentsSize, const QWidget* ) const - { - - return expandSize( contentsSize, Metrics::MenuBarItem_MarginWidth, Metrics::MenuBarItem_MarginHeight ); - - } - - //______________________________________________________________ - QSize Style::menuItemSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const - { - - // cast option and check - const auto menuItemOption = qstyleoption_cast( option ); - if( !menuItemOption ) return contentsSize; - - /* - * First calculate the intrinsic size of the item. - * this must be kept consistent with what's in drawMenuItemControl - */ - QSize size( contentsSize ); - switch( menuItemOption->menuItemType ) - { - - case QStyleOptionMenuItem::Normal: - case QStyleOptionMenuItem::DefaultItem: - case QStyleOptionMenuItem::SubMenu: - { - - int iconWidth = 0; - if( showIconsInMenuItems() ) iconWidth = isQtQuickControl( option, widget ) ? qMax( pixelMetric(PM_SmallIconSize, option, widget ), menuItemOption->maxIconWidth ) : menuItemOption->maxIconWidth; - - int leftColumnWidth = 0; - - // add icon width - if( iconWidth > 0 ) - { leftColumnWidth += iconWidth + Metrics::MenuItem_ItemSpacing; } - - // add checkbox indicator width - if( menuItemOption->menuHasCheckableItems ) - { leftColumnWidth += Metrics::CheckBox_Size + Metrics::MenuItem_ItemSpacing; } - - // add spacing for accelerator - /* - * Note: - * The width of the accelerator itself is not included here since - * Qt will add that on separately after obtaining the - * sizeFromContents() for each menu item in the menu to be shown - * ( see QMenuPrivate::calcActionRects() ) - */ - const bool hasAccelerator( menuItemOption->text.indexOf( QLatin1Char( '\t' ) ) >= 0 ); - if( hasAccelerator ) size.rwidth() += Metrics::MenuItem_AcceleratorSpace; - - // right column - const int rightColumnWidth = Metrics::MenuButton_IndicatorWidth + Metrics::MenuItem_ItemSpacing; - size.rwidth() += leftColumnWidth + rightColumnWidth; - - // make sure height is large enough for icon and arrow - size.setHeight( qMax( size.height(), int(Metrics::MenuButton_IndicatorWidth) ) ); - size.setHeight( qMax( size.height(), int(Metrics::CheckBox_Size) ) ); - size.setHeight( qMax( size.height(), iconWidth ) ); - return expandSize( size, Metrics::MenuItem_MarginWidth, Metrics::MenuItem_MarginHeight ); - - } - - case QStyleOptionMenuItem::Separator: - { - - if( menuItemOption->text.isEmpty() && menuItemOption->icon.isNull() ) - { - - return expandSize( QSize(0,1), Metrics::MenuItem_MarginWidth, Metrics::MenuItem_MarginHeight ); - - } else { - - // build toolbutton option - const QStyleOptionToolButton toolButtonOption( separatorMenuItemOption( menuItemOption, widget ) ); - - // make sure height is large enough for icon and text - const int iconWidth( menuItemOption->maxIconWidth ); - const int textHeight( menuItemOption->fontMetrics.height() ); - if( !menuItemOption->icon.isNull() ) size.setHeight( qMax( size.height(), iconWidth ) ); - if( !menuItemOption->text.isEmpty() ) - { - size.setHeight( qMax( size.height(), textHeight ) ); - size.setWidth( qMax( size.width(), menuItemOption->fontMetrics.width( menuItemOption->text ) ) ); - } - - return sizeFromContents( CT_ToolButton, &toolButtonOption, size, widget ); - - } - - } - - // for all other cases, return input - default: return contentsSize; - } - - } - - //______________________________________________________________ - QSize Style::progressBarSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const - { - - // cast option - const auto progressBarOption( qstyleoption_cast( option ) ); - if( !progressBarOption ) return contentsSize; - - #if BREEZE_USE_KDE4 - const auto progressBarOption2( qstyleoption_cast( option ) ); - const bool horizontal( !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal ); - #else - const bool horizontal( BreezePrivate::isProgressBarHorizontal( progressBarOption ) ); - #endif - - // make local copy - QSize size( contentsSize ); - - if( horizontal ) - { - - // check text visibility - const bool textVisible( progressBarOption->textVisible ); - - size.setWidth( qMax( size.width(), int(Metrics::ProgressBar_Thickness) ) ); - size.setHeight( qMax( size.height(), int(Metrics::ProgressBar_Thickness) ) ); - if( textVisible ) size.setHeight( qMax( size.height(), option->fontMetrics.height() ) ); - - } else { - - size.setHeight( qMax( size.height(), int(Metrics::ProgressBar_Thickness) ) ); - size.setWidth( qMax( size.width(), int(Metrics::ProgressBar_Thickness) ) ); - - } - - return size; - - } - - //______________________________________________________________ - QSize Style::tabWidgetSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const - { - // cast option and check - const auto tabOption = qstyleoption_cast( option ); - if( !tabOption ) return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); - - // try find direct children of type QTabBar and QStackedWidget - // this is needed in order to add TabWidget margins only if they are necessary around tabWidget content, not the tabbar - if( !widget ) return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); - QTabBar* tabBar = nullptr; - QStackedWidget* stack = nullptr; - auto children( widget->children() ); - foreach( auto child, children ) - { - if( !tabBar ) tabBar = qobject_cast( child ); - if( !stack ) stack = qobject_cast( child ); - if( tabBar && stack ) break; - } - - if( !( tabBar && stack ) ) return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); - - // tab orientation - const bool verticalTabs( tabOption && isVerticalTab( tabOption->shape ) ); - if( verticalTabs ) - { - const int tabBarHeight = tabBar->minimumSizeHint().height(); - const int stackHeight = stack->minimumSizeHint().height(); - if( contentsSize.height() == tabBarHeight && tabBarHeight + 2*(Metrics::Frame_FrameWidth - 1) >= stackHeight + 2*Metrics::TabWidget_MarginWidth ) return QSize( contentsSize.width() + 2*Metrics::TabWidget_MarginWidth, contentsSize.height() + 2*(Metrics::Frame_FrameWidth - 1) ); - else return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); - - } else { - - const int tabBarWidth = tabBar->minimumSizeHint().width(); - const int stackWidth = stack->minimumSizeHint().width(); - if( contentsSize.width() == tabBarWidth && tabBarWidth + 2*(Metrics::Frame_FrameWidth - 1) >= stackWidth + 2*Metrics::TabWidget_MarginWidth) return QSize( contentsSize.width() + 2*(Metrics::Frame_FrameWidth - 1), contentsSize.height() + 2*Metrics::TabWidget_MarginWidth ); - else return expandSize( contentsSize, Metrics::TabWidget_MarginWidth ); - - } - - } - - //______________________________________________________________ - QSize Style::tabBarTabSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const - { - const auto tabOption( qstyleoption_cast( option ) ); - const bool hasText( tabOption && !tabOption->text.isEmpty() ); - const bool hasIcon( tabOption && !tabOption->icon.isNull() ); - #if BREEZE_USE_KDE4 - const auto tabOptionV3( qstyleoption_cast( option ) ); - const bool hasLeftButton( tabOptionV3 && !tabOptionV3->leftButtonSize.isEmpty() ); - const bool hasRightButton( tabOptionV3 && !tabOptionV3->leftButtonSize.isEmpty() ); - #else - const bool hasLeftButton( tabOption && !tabOption->leftButtonSize.isEmpty() ); - const bool hasRightButton( tabOption && !tabOption->leftButtonSize.isEmpty() ); - #endif - - // calculate width increment for horizontal tabs - int widthIncrement = 0; - if( hasIcon && !( hasText || hasLeftButton || hasRightButton ) ) widthIncrement -= 4; - if( hasText && hasIcon ) widthIncrement += Metrics::TabBar_TabItemSpacing; - if( hasLeftButton && ( hasText || hasIcon ) ) widthIncrement += Metrics::TabBar_TabItemSpacing; - if( hasRightButton && ( hasText || hasIcon || hasLeftButton ) ) widthIncrement += Metrics::TabBar_TabItemSpacing; - - // add margins - QSize size( contentsSize ); - - // compare to minimum size - const bool verticalTabs( tabOption && isVerticalTab( tabOption ) ); - if( verticalTabs ) - { - - size.rheight() += widthIncrement; - if( hasIcon && !hasText ) size = size.expandedTo( QSize( Metrics::TabBar_TabMinHeight, 0 ) ); - else size = size.expandedTo( QSize( Metrics::TabBar_TabMinHeight, Metrics::TabBar_TabMinWidth ) ); - - } else { - - size.rwidth() += widthIncrement; - if( hasIcon && !hasText ) size = size.expandedTo( QSize( 0, Metrics::TabBar_TabMinHeight ) ); - else size = size.expandedTo( QSize( Metrics::TabBar_TabMinWidth, Metrics::TabBar_TabMinHeight ) ); - - } - - return size; - - } - - //______________________________________________________________ - QSize Style::headerSectionSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* ) const - { - - // cast option and check - const auto headerOption( qstyleoption_cast( option ) ); - if( !headerOption ) return contentsSize; - - // get text size - const bool horizontal( headerOption->orientation == Qt::Horizontal ); - const bool hasText( !headerOption->text.isEmpty() ); - const bool hasIcon( !headerOption->icon.isNull() ); - - const QSize textSize( hasText ? headerOption->fontMetrics.size( 0, headerOption->text ) : QSize() ); - const QSize iconSize( hasIcon ? QSize( 22,22 ) : QSize() ); - - // contents width - int contentsWidth( 0 ); - if( hasText ) contentsWidth += textSize.width(); - if( hasIcon ) - { - contentsWidth += iconSize.width(); - if( hasText ) contentsWidth += Metrics::Header_ItemSpacing; - } - - // contents height - int contentsHeight( headerOption->fontMetrics.height() ); - if( hasIcon ) contentsHeight = qMax( contentsHeight, iconSize.height() ); - - if( horizontal && headerOption->sortIndicator != QStyleOptionHeader::None ) - { - // also add space for sort indicator - contentsWidth += Metrics::Header_ArrowSize + Metrics::Header_ItemSpacing; - contentsHeight = qMax( contentsHeight, int(Metrics::Header_ArrowSize) ); - } - - // update contents size, add margins and return - const QSize size( contentsSize.expandedTo( QSize( contentsWidth, contentsHeight ) ) ); - return expandSize( size, Metrics::Header_MarginWidth ); - - } - - //______________________________________________________________ - QSize Style::itemViewItemSizeFromContents( const QStyleOption* option, const QSize& contentsSize, const QWidget* widget ) const - { - // call base class - const QSize size( ParentStyleClass::sizeFromContents( CT_ItemViewItem, option, contentsSize, widget ) ); - return expandSize( size, Metrics::ItemView_ItemMarginWidth ); - } - - //______________________________________________________________ - bool Style::drawFramePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // copy palette and rect - const auto& palette( option->palette ); - const auto& rect( option->rect ); - - // detect title widgets - const bool isTitleWidget( - StyleConfigData::titleWidgetDrawFrame() && - widget && - widget->parent() && - widget->parent()->inherits( "KTitleWidget" ) ); - - // copy state - const State& state( option->state ); - if( !isTitleWidget && !( state & (State_Sunken | State_Raised ) ) ) return true; - - #if QT_VERSION >= 0x050000 - const bool isInputWidget( ( widget && widget->testAttribute( Qt::WA_Hover ) ) || - ( isQtQuickControl( option, widget ) && option->styleObject->property( "elementType" ).toString() == QStringLiteral( "edit") ) ); - #else - const bool isInputWidget( ( widget && widget->testAttribute( Qt::WA_Hover ) ) ); - #endif - - const bool enabled( state & State_Enabled ); - const bool mouseOver( enabled && isInputWidget && ( state & State_MouseOver ) ); - const bool hasFocus( enabled && isInputWidget && ( state & State_HasFocus ) ); - - // focus takes precedence over mouse over - _animations->inputWidgetEngine().updateState( widget, AnimationFocus, hasFocus ); - _animations->inputWidgetEngine().updateState( widget, AnimationHover, mouseOver && !hasFocus ); - - // retrieve animation mode and opacity - const AnimationMode mode( _animations->inputWidgetEngine().frameAnimationMode( widget ) ); - const qreal opacity( _animations->inputWidgetEngine().frameOpacity( widget ) ); - - // render - if( !StyleConfigData::sidePanelDrawFrame() && widget && widget->property( PropertyNames::sidePanelView ).toBool() ) - { - - const auto outline( _helper->sidePanelOutlineColor( palette, hasFocus, opacity, mode ) ); - const bool reverseLayout( option->direction == Qt::RightToLeft ); - const Side side( reverseLayout ? SideRight : SideLeft ); - _helper->renderSidePanelFrame( painter, rect, outline, side ); - - } else { - - if( _frameShadowFactory->isRegistered( widget ) ) - { - - // update frame shadow factory - _frameShadowFactory->updateShadowsGeometry( widget, rect ); - _frameShadowFactory->updateState( widget, hasFocus, mouseOver, opacity, mode ); - - } - - const auto background( isTitleWidget ? palette.color( widget->backgroundRole() ):QColor() ); - const auto outline( _helper->frameOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); - _helper->renderFrame( painter, rect, background, outline ); - - } - - return true; - - } - - //______________________________________________________________ - bool Style::drawFrameLineEditPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - // copy palette and rect - const auto& palette( option->palette ); - const auto& rect( option->rect ); - - // make sure there is enough room to render frame - if( rect.height() < 2*Metrics::LineEdit_FrameWidth + option->fontMetrics.height()) - { - - const auto &background = palette.color( QPalette::Base ); - - painter->setPen( Qt::NoPen ); - painter->setBrush( background ); - painter->drawRect( rect ); - return true; - - } else { - - // copy state - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool mouseOver( enabled && ( state & State_MouseOver ) ); - const bool hasFocus( enabled && ( state & State_HasFocus ) ); - - // focus takes precedence over mouse over - _animations->inputWidgetEngine().updateState( widget, AnimationFocus, hasFocus ); - _animations->inputWidgetEngine().updateState( widget, AnimationHover, mouseOver && !hasFocus ); - - // retrieve animation mode and opacity - const AnimationMode mode( _animations->inputWidgetEngine().frameAnimationMode( widget ) ); - const qreal opacity( _animations->inputWidgetEngine().frameOpacity( widget ) ); - - // render - const auto &background = palette.color( QPalette::Base ); - const auto outline( _helper->frameOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); - _helper->renderFrame( painter, rect, background, outline ); - - } - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawFrameFocusRectPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - // no focus indicator on buttons / scrollbars, since it is rendered elsewhere - if ( qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) ) - { return true; } - - // no focus indicator on ComboBox list items - if (widget && widget->inherits("QComboBoxListView")) - { return true; } - - #if QT_VERSION >= 0x050000 - if ( option->styleObject && option->styleObject->property("elementType") == QLatin1String("button") ) - { return true; } - #endif - - const State& state( option->state ); - - // no focus indicator on selected list items - if ((state & State_Selected) && qobject_cast(widget)) - { return true; } - - const auto rect( option->rect.adjusted( 0, 0, 0, 1 ) ); - const auto& palette( option->palette ); - - if( rect.width() < 10 ) return true; - - const auto outlineColor( state & State_Selected ? palette.color( QPalette::HighlightedText ):palette.color( QPalette::Highlight ) ); - painter->setRenderHint( QPainter::Antialiasing, false ); - painter->setPen( outlineColor ); - painter->drawLine( QPoint( rect.bottomLeft() - QPoint( 0,1 ) ), QPoint( rect.bottomRight() - QPoint( 0,1 ) ) ); - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawFrameMenuPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - // only draw frame for (expanded) toolbars and QtQuick controls - // do nothing for other cases, for which frame is rendered via drawPanelMenuPrimitive - if( qobject_cast( widget ) ) - { - - const auto& palette( option->palette ); - const auto background( _helper->frameBackgroundColor( palette ) ); - const auto outline( _helper->frameOutlineColor( palette ) ); - - const bool hasAlpha( _helper->hasAlphaChannel( widget ) ); - _helper->renderMenuFrame( painter, option->rect, background, outline, hasAlpha ); - - } else if( isQtQuickControl( option, widget ) ) { - - const auto& palette( option->palette ); - const auto background( _helper->frameBackgroundColor( palette ) ); - const auto outline( _helper->frameOutlineColor( palette ) ); - - const bool hasAlpha( _helper->hasAlphaChannel( widget ) ); - _helper->renderMenuFrame( painter, option->rect, background, outline, hasAlpha ); - - } - - return true; - - } - - //______________________________________________________________ - bool Style::drawFrameGroupBoxPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const - { - - // cast option and check - const auto frameOption( qstyleoption_cast( option ) ); - if( !frameOption ) return true; - - // no frame for flat groupboxes - #if BREEZE_USE_KDE4 - QStyleOptionFrameV2 frameOption2( *frameOption ); - if( frameOption2.features & QStyleOptionFrameV2::Flat ) return true; - #else - if( frameOption->features & QStyleOptionFrame::Flat ) return true; - #endif - - // normal frame - const auto& palette( option->palette ); - const auto background( _helper->frameBackgroundColor( palette ) ); - const auto outline( _helper->frameOutlineColor( palette ) ); - - /* - * need to reset painter's clip region in order to paint behind textbox label - * (was taken out in QCommonStyle) - */ - - painter->setClipRegion( option->rect ); - _helper->renderFrame( painter, option->rect, background, outline ); - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawFrameTabWidgetPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - #if BREEZE_USE_KDE4 - const auto tabOption( qstyleoption_cast( option ) ); - #else - const auto tabOption( qstyleoption_cast( option ) ); - #endif - if( !tabOption ) return true; - - // do nothing if tabbar is hidden - const bool isQtQuickControl( this->isQtQuickControl( option, widget ) ); - if( tabOption->tabBarSize.isEmpty() && !isQtQuickControl ) return true; - - // adjust rect to handle overlaps - auto rect( option->rect ); - - const auto tabBarRect( tabOption->tabBarRect ); - const QSize tabBarSize( tabOption->tabBarSize ); - Corners corners = AllCorners; - - // adjust corners to deal with oversized tabbars - switch( tabOption->shape ) - { - case QTabBar::RoundedNorth: - case QTabBar::TriangularNorth: - if( isQtQuickControl ) rect.adjust( -1, -1, 1, 0 ); - if( tabBarSize.width() >= rect.width() - 2*Metrics::Frame_FrameRadius ) corners &= ~CornersTop; - if( tabBarRect.left() < rect.left() + Metrics::Frame_FrameRadius ) corners &= ~CornerTopLeft; - if( tabBarRect.right() > rect.right() - Metrics::Frame_FrameRadius ) corners &= ~CornerTopRight; - break; - - case QTabBar::RoundedSouth: - case QTabBar::TriangularSouth: - if( isQtQuickControl ) rect.adjust( -1, 0, 1, 1 ); - if( tabBarSize.width() >= rect.width()-2*Metrics::Frame_FrameRadius ) corners &= ~CornersBottom; - if( tabBarRect.left() < rect.left() + Metrics::Frame_FrameRadius ) corners &= ~CornerBottomLeft; - if( tabBarRect.right() > rect.right() - Metrics::Frame_FrameRadius ) corners &= ~CornerBottomRight; - break; - - case QTabBar::RoundedWest: - case QTabBar::TriangularWest: - if( isQtQuickControl ) rect.adjust( -1, 0, 0, 0 ); - if( tabBarSize.height() >= rect.height()-2*Metrics::Frame_FrameRadius ) corners &= ~CornersLeft; - if( tabBarRect.top() < rect.top() + Metrics::Frame_FrameRadius ) corners &= ~CornerTopLeft; - if( tabBarRect.bottom() > rect.bottom() - Metrics::Frame_FrameRadius ) corners &= ~CornerBottomLeft; - break; - - case QTabBar::RoundedEast: - case QTabBar::TriangularEast: - if( isQtQuickControl ) rect.adjust( 0, 0, 1, 0 ); - if( tabBarSize.height() >= rect.height()-2*Metrics::Frame_FrameRadius ) corners &= ~CornersRight; - if( tabBarRect.top() < rect.top() + Metrics::Frame_FrameRadius ) corners &= ~CornerTopRight; - if( tabBarRect.bottom() > rect.bottom() - Metrics::Frame_FrameRadius ) corners &= ~CornerBottomRight; - break; - - default: break; - } - - // define colors - const auto& palette( option->palette ); - const auto background( _helper->frameBackgroundColor( palette ) ); - const auto outline( _helper->frameOutlineColor( palette ) ); - _helper->renderTabWidgetFrame( painter, rect, background, outline, corners ); - - return true; - } - - //___________________________________________________________________________________ - bool Style::drawFrameTabBarBasePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const - { - - // tabbar frame used either for 'separate' tabbar, or in 'document mode' - - // cast option and check - const auto tabOption( qstyleoption_cast( option ) ); - if( !tabOption ) return true; - - // get rect, orientation, palette - const auto rect( option->rect ); - const auto outline( _helper->frameOutlineColor( option->palette ) ); - - // setup painter - painter->setBrush( Qt::NoBrush ); - painter->setRenderHint( QPainter::Antialiasing, false ); - painter->setPen( QPen( outline, 1 ) ); - - // render - switch( tabOption->shape ) - { - case QTabBar::RoundedNorth: - case QTabBar::TriangularNorth: - painter->drawLine( rect.bottomLeft() - QPoint( 1, 0 ), rect.bottomRight() + QPoint( 1, 0 ) ); - break; - - case QTabBar::RoundedSouth: - case QTabBar::TriangularSouth: - painter->drawLine( rect.topLeft() - QPoint( 1, 0 ), rect.topRight() + QPoint( 1, 0 ) ); - break; - - case QTabBar::RoundedWest: - case QTabBar::TriangularWest: - painter->drawLine( rect.topRight() - QPoint( 0, 1 ), rect.bottomRight() + QPoint( 1, 0 ) ); - break; - - case QTabBar::RoundedEast: - case QTabBar::TriangularEast: - painter->drawLine( rect.topLeft() - QPoint( 0, 1 ), rect.bottomLeft() + QPoint( 1, 0 ) ); - break; - - default: - break; - - } - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawFrameWindowPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const - { - - // copy rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - const State state( option->state ); - const bool selected( state & State_Selected ); - - // render frame outline - const auto outline( _helper->frameOutlineColor( palette, false, selected ) ); - _helper->renderMenuFrame( painter, rect, QColor(), outline ); - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawIndicatorArrowPrimitive( ArrowOrientation orientation, const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // store rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - - // store state - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - bool mouseOver( enabled && ( state & State_MouseOver ) ); - bool hasFocus( enabled && ( state & State_HasFocus ) ); - - // detect special buttons - const bool inTabBar( widget && qobject_cast( widget->parentWidget() ) ); - const bool inToolButton( qstyleoption_cast( option ) ); - - // color - QColor color; - if( inTabBar ) { - - // for tabbar arrows one uses animations to get the arrow color - /* - * get animation state - * there is no need to update the engine since this was already done when rendering the frame - */ - const AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); - const qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); - color = _helper->arrowColor( palette, mouseOver, hasFocus, opacity, mode ); - - } else if( mouseOver && !inToolButton ) { - - color = _helper->hoverColor( palette ); - - } else if( inToolButton ) { - - const bool flat( state & State_AutoRaise ); - - // cast option - const QStyleOptionToolButton* toolButtonOption( static_cast( option ) ); - const bool hasMenu( - ( toolButtonOption->subControls & SC_ToolButtonMenu ) || - ( toolButtonOption->features&QStyleOptionToolButton::HasMenu - && toolButtonOption->features&QStyleOptionToolButton::PopupDelay ) ); - const bool sunken( state & (State_On | State_Sunken) ); - if( flat && hasMenu ) - { - - if( sunken && !mouseOver ) color = palette.color( QPalette::HighlightedText ); - else { - - // for menu arrows in flat toolbutton one uses animations to get the arrow color - // handle arrow over animation - const bool arrowHover( mouseOver && ( toolButtonOption->activeSubControls & SC_ToolButtonMenu ) ); - _animations->toolButtonEngine().updateState( widget, AnimationHover, arrowHover ); - - const bool animated( _animations->toolButtonEngine().isAnimated( widget, AnimationHover ) ); - const qreal opacity( _animations->toolButtonEngine().opacity( widget, AnimationHover ) ); - - color = _helper->arrowColor( palette, arrowHover, false, opacity, animated ? AnimationHover:AnimationNone ); - - } - - } else if( flat ) { - - if( sunken && hasFocus && !mouseOver ) color = palette.color( QPalette::HighlightedText ); - else color = _helper->arrowColor( palette, QPalette::WindowText ); - - } else if( hasFocus && !mouseOver ) { - - color = palette.color( QPalette::HighlightedText ); - - } else { - - color = _helper->arrowColor( palette, QPalette::ButtonText ); - - } - - } else color = _helper->arrowColor( palette, QPalette::WindowText ); - - // render - _helper->renderArrow( painter, rect, color, orientation ); - - return true; - } - - //___________________________________________________________________________________ - bool Style::drawIndicatorHeaderArrowPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const - { - const auto headerOption( qstyleoption_cast( option ) ); - const State& state( option->state ); - - // arrow orientation - ArrowOrientation orientation( ArrowNone ); - if( state & State_UpArrow || ( headerOption && headerOption->sortIndicator==QStyleOptionHeader::SortUp ) ) orientation = ArrowUp; - else if( state & State_DownArrow || ( headerOption && headerOption->sortIndicator==QStyleOptionHeader::SortDown ) ) orientation = ArrowDown; - if( orientation == ArrowNone ) return true; - - // invert arrows if requested by (hidden) options - if( StyleConfigData::viewInvertSortIndicator() ) orientation = (orientation == ArrowUp) ? ArrowDown:ArrowUp; - - // state, rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - - // define color and polygon for drawing arrow - const auto color = _helper->arrowColor( palette, QPalette::ButtonText ); - - // render - _helper->renderArrow( painter, rect, color, orientation ); - - return true; - } - - //______________________________________________________________ - bool Style::drawPanelButtonCommandPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - const auto buttonOption( qstyleoption_cast< const QStyleOptionButton* >( option ) ); - if( !buttonOption ) return true; - - // rect and palette - const auto& rect( option->rect ); - - // button state - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool mouseOver( enabled && ( state & State_MouseOver ) ); - const bool hasFocus( ( enabled && ( state & State_HasFocus ) ) && !( widget && widget->focusProxy())); - const bool sunken( state & ( State_On|State_Sunken ) ); - const bool flat( buttonOption->features & QStyleOptionButton::Flat ); - - // update animation state - // mouse over takes precedence over focus - _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); - _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus && !mouseOver ); - - const AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); - const qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); - - if( flat ) - { - - // define colors and render - const auto& palette( option->palette ); - const auto color( _helper->toolButtonColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); - _helper->renderToolButtonFrame( painter, rect, color, sunken ); - - } else { - - // update button color from palette in case button is default - QPalette palette( option->palette ); - if( enabled && buttonOption->features & QStyleOptionButton::DefaultButton ) - { - const auto button( palette.color( QPalette::Button ) ); - const auto base( palette.color( QPalette::Base ) ); - palette.setColor( QPalette::Button, KColorUtils::mix( button, base, 0.7 ) ); - } - - const auto shadow( _helper->shadowColor( palette ) ); - const auto outline( _helper->buttonOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); - const auto background( _helper->buttonBackgroundColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); - - // render - _helper->renderButtonFrame( painter, rect, background, outline, shadow, hasFocus, sunken ); - - } - - return true; - - } - - //______________________________________________________________ - bool Style::drawPanelButtonToolPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // copy palette and rect - const auto& palette( option->palette ); - auto rect( option->rect ); - - // store relevant flags - const State& state( option->state ); - const bool autoRaise( state & State_AutoRaise ); - const bool enabled( state & State_Enabled ); - const bool sunken( state & (State_On | State_Sunken) ); - const bool mouseOver( enabled && (option->state & State_MouseOver) ); - const bool hasFocus( enabled && (option->state & (State_HasFocus | State_Sunken)) ); - - /* - * get animation state - * no need to update, this was already done in drawToolButtonComplexControl - */ - const AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); - const qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); - - if( !autoRaise ) - { - - // need to check widget for popup mode, because option is not set properly - const auto toolButton( qobject_cast( widget ) ); - const bool hasPopupMenu( toolButton && toolButton->popupMode() == QToolButton::MenuButtonPopup ); - - // render as push button - const auto shadow( _helper->shadowColor( palette ) ); - const auto outline( _helper->buttonOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); - const auto background( _helper->buttonBackgroundColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); - - // adjust frame in case of menu - if( hasPopupMenu ) - { - painter->setClipRect( rect ); - rect.adjust( 0, 0, Metrics::Frame_FrameRadius + 2, 0 ); - rect = visualRect( option, rect ); - } - - // render - _helper->renderButtonFrame( painter, rect, background, outline, shadow, hasFocus, sunken ); - - } else { - - const auto color( _helper->toolButtonColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); - _helper->renderToolButtonFrame( painter, rect, color, sunken ); - - } - - return true; - } - - //______________________________________________________________ - bool Style::drawTabBarPanelButtonToolPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // copy palette and rect - auto rect( option->rect ); - - // static_cast is safe here since check was already performed in calling function - const QTabBar* tabBar( static_cast( widget->parentWidget() ) ); - - // overlap. - // subtract 1, because of the empty pixel left the tabwidget frame - const int overlap( Metrics::TabBar_BaseOverlap - 1 ); - - // adjust rect based on tabbar shape - switch( tabBar->shape() ) - { - case QTabBar::RoundedNorth: - case QTabBar::TriangularNorth: - rect.adjust( 0, 0, 0, -overlap ); - break; - - case QTabBar::RoundedSouth: - case QTabBar::TriangularSouth: - rect.adjust( 0, overlap, 0, 0 ); - break; - - case QTabBar::RoundedWest: - case QTabBar::TriangularWest: - rect.adjust( 0, 0, -overlap, 0 ); - break; - - case QTabBar::RoundedEast: - case QTabBar::TriangularEast: - rect.adjust( overlap, 0, 0, 0 ); - break; - - default: break; - - } - - // get the relevant palette - const QWidget* parent( tabBar->parentWidget() ); - if( qobject_cast( parent ) ) parent = parent->parentWidget(); - const auto& palette( parent ? parent->palette() : QApplication::palette() ); - const auto color = hasAlteredBackground(parent) ? _helper->frameBackgroundColor( palette ):palette.color( QPalette::Window ); - - // render flat background - painter->setPen( Qt::NoPen ); - painter->setBrush( color ); - painter->drawRect( rect ); - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawPanelScrollAreaCornerPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // make sure background role matches viewport - const QAbstractScrollArea* scrollArea; - if( ( scrollArea = qobject_cast( widget ) ) && scrollArea->viewport() ) - { - - // need to adjust clipRect in order not to render outside of frame - const int frameWidth( pixelMetric( PM_DefaultFrameWidth, nullptr, scrollArea ) ); - painter->setClipRect( insideMargin( scrollArea->rect(), frameWidth ) ); - painter->setBrush( scrollArea->viewport()->palette().color( scrollArea->viewport()->backgroundRole() ) ); - painter->setPen( Qt::NoPen ); - painter->drawRect( option->rect ); - return true; - - } else { - - return false; - - } - - } - //___________________________________________________________________________________ - bool Style::drawPanelMenuPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - /* - * do nothing if menu is embedded in another widget - * this corresponds to having a transparent background - */ - if( widget && !widget->isWindow() ) return true; - - const auto& palette( option->palette ); - const auto outline( _helper->frameOutlineColor( palette ) ); - const bool hasAlpha( _helper->hasAlphaChannel( widget ) ); - auto background( _helper->frameBackgroundColor( palette ) ); - - #if !BREEZE_USE_KDE4 - if ( hasAlpha ) { - background.setAlphaF(StyleConfigData::menuOpacity() / 100.0); - } - #endif - - _helper->renderMenuFrame( painter, option->rect, background, outline, hasAlpha ); - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawPanelTipLabelPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // force registration of widget - if( widget && widget->window() ) - { _shadowHelper->registerWidget( widget->window(), true ); } - - const auto& palette( option->palette ); - const auto &background = palette.color( QPalette::ToolTipBase ); - const auto outline( KColorUtils::mix( palette.color( QPalette::ToolTipBase ), palette.color( QPalette::ToolTipText ), 0.25 ) ); - const bool hasAlpha( _helper->hasAlphaChannel( widget ) ); - - _helper->renderMenuFrame( painter, option->rect, background, outline, hasAlpha ); - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawPanelItemViewItemPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - #if BREEZE_USE_KDE4 - const auto viewItemOption = qstyleoption_cast( option ); - #else - const auto viewItemOption = qstyleoption_cast( option ); - #endif - if( !viewItemOption ) return false; - - // try cast widget - const auto abstractItemView = qobject_cast( widget ); - - // store palette and rect - const auto& palette( option->palette ); - auto rect( option->rect ); - - // store flags - const State& state( option->state ); - const bool mouseOver( ( state & State_MouseOver ) && ( !abstractItemView || abstractItemView->selectionMode() != QAbstractItemView::NoSelection ) ); - const bool selected( state & State_Selected ); - const bool enabled( state & State_Enabled ); - const bool active( state & State_Active ); - - const bool hasCustomBackground = viewItemOption->backgroundBrush.style() != Qt::NoBrush && !( state & State_Selected ); - const bool hasSolidBackground = !hasCustomBackground || viewItemOption->backgroundBrush.style() == Qt::SolidPattern; - #if BREEZE_USE_KDE4 - const bool hasAlternateBackground( viewItemOption->features & QStyleOptionViewItemV2::Alternate ); - #else - const bool hasAlternateBackground( viewItemOption->features & QStyleOptionViewItem::Alternate ); - #endif - - // do nothing if no background is to be rendered - if( !( mouseOver || selected || hasCustomBackground || hasAlternateBackground ) ) - { return true; } - - // define color group - QPalette::ColorGroup colorGroup; - if( enabled ) colorGroup = active ? QPalette::Active : QPalette::Inactive; - else colorGroup = QPalette::Disabled; - - // render alternate background - if( hasAlternateBackground ) - { - painter->setPen( Qt::NoPen ); - painter->setBrush( palette.brush( colorGroup, QPalette::AlternateBase ) ); - painter->drawRect( rect ); - } - - // stop here if no highlight is needed - if( !( mouseOver || selected ||hasCustomBackground ) ) - { return true; } - - // render custom background - if( hasCustomBackground && !hasSolidBackground ) - { - - painter->setBrushOrigin( viewItemOption->rect.topLeft() ); - painter->setBrush( viewItemOption->backgroundBrush ); - painter->setPen( Qt::NoPen ); - painter->drawRect( viewItemOption->rect ); - return true; - - } - - // render selection - // define color - QColor color; - if( hasCustomBackground && hasSolidBackground ) color = viewItemOption->backgroundBrush.color(); - else color = palette.color( colorGroup, QPalette::Highlight ); - - // change color to implement mouse over - if( mouseOver && !hasCustomBackground ) - { - if( !selected ) color.setAlphaF( 0.2 ); - else color = color.lighter( 110 ); - } - - // render - _helper->renderSelection( painter, rect, color ); - - return true; - } - - //___________________________________________________________________________________ - bool Style::drawIndicatorCheckBoxPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // copy rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - - // store flags - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool mouseOver( enabled && ( state & State_MouseOver ) ); - const bool sunken( enabled && ( state & State_Sunken ) ); - const bool active( ( state & (State_On|State_NoChange) ) ); - - // checkbox state - CheckBoxState checkBoxState( CheckOff ); - if( state & State_NoChange ) checkBoxState = CheckPartial; - else if( state & State_On ) checkBoxState = CheckOn; - - // detect checkboxes in lists - const bool isSelectedItem( this->isSelectedItem( widget, rect.center() ) ); - - // animation state - _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); - _animations->widgetStateEngine().updateState( widget, AnimationPressed, checkBoxState != CheckOff ); - if( _animations->widgetStateEngine().isAnimated( widget, AnimationPressed ) ) checkBoxState = CheckAnimated; - const qreal animation( _animations->widgetStateEngine().opacity( widget, AnimationPressed ) ); - - QColor color; - if( isSelectedItem ) { - - color = _helper->checkBoxIndicatorColor( palette, false, enabled && active ); - _helper->renderCheckBoxBackground( painter, rect, palette.color( QPalette::Base ), sunken ); - - } else { - - const AnimationMode mode( _animations->widgetStateEngine().isAnimated( widget, AnimationHover ) ? AnimationHover:AnimationNone ); - const qreal opacity( _animations->widgetStateEngine().opacity( widget, AnimationHover ) ); - color = _helper->checkBoxIndicatorColor( palette, mouseOver, enabled && active, opacity, mode ); - - } - - // render - const auto shadow( _helper->shadowColor( palette ) ); - _helper->renderCheckBox( painter, rect, color, shadow, sunken, checkBoxState, animation ); - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawIndicatorRadioButtonPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // copy rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - - // store flags - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool mouseOver( enabled && ( state & State_MouseOver ) ); - const bool sunken( state & State_Sunken ); - const bool checked( state & State_On ); - - // radio button state - RadioButtonState radioButtonState( state & State_On ? RadioOn:RadioOff ); - - // detect radiobuttons in lists - const bool isSelectedItem( this->isSelectedItem( widget, rect.center() ) ); - - // animation state - _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); - _animations->widgetStateEngine().updateState( widget, AnimationPressed, radioButtonState != RadioOff ); - if( _animations->widgetStateEngine().isAnimated( widget, AnimationPressed ) ) radioButtonState = RadioAnimated; - const qreal animation( _animations->widgetStateEngine().opacity( widget, AnimationPressed ) ); - - // colors - const auto shadow( _helper->shadowColor( palette ) ); - QColor color; - if( isSelectedItem ) - { - - color = _helper->checkBoxIndicatorColor( palette, false, enabled && checked ); - _helper->renderRadioButtonBackground( painter, rect, palette.color( QPalette::Base ), sunken ); - - } else { - - const AnimationMode mode( _animations->widgetStateEngine().isAnimated( widget, AnimationHover ) ? AnimationHover:AnimationNone ); - const qreal opacity( _animations->widgetStateEngine().opacity( widget, AnimationHover ) ); - color = _helper->checkBoxIndicatorColor( palette, mouseOver, enabled && checked, opacity, mode ); - - } - - // render - _helper->renderRadioButton( painter, rect, color, shadow, sunken, radioButtonState, animation ); - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawIndicatorButtonDropDownPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - const auto toolButtonOption( qstyleoption_cast( option ) ); - if( !toolButtonOption ) return true; - - // store state - const State& state( option->state ); - const bool autoRaise( state & State_AutoRaise ); - - // do nothing for autoraise buttons - if( autoRaise || !(toolButtonOption->subControls & SC_ToolButtonMenu) ) return true; - - // store palette and rect - const auto& palette( option->palette ); - const auto& rect( option->rect ); - - // store state - const bool enabled( state & State_Enabled ); - const bool hasFocus( enabled && ( state & ( State_HasFocus | State_Sunken ) ) ); - const bool mouseOver( enabled && ( state & State_MouseOver ) ); - const bool sunken( enabled && ( state & State_Sunken ) ); - - // update animation state - // mouse over takes precedence over focus - _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); - _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus && !mouseOver ); - - const AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); - const qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); - - // render as push button - const auto shadow( _helper->shadowColor( palette ) ); - const auto outline( _helper->buttonOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); - const auto background( _helper->buttonBackgroundColor( palette, mouseOver, hasFocus, false, opacity, mode ) ); - - auto frameRect( rect ); - painter->setClipRect( rect ); - frameRect.adjust( -Metrics::Frame_FrameRadius - 1, 0, 0, 0 ); - frameRect = visualRect( option, frameRect ); - - // render - _helper->renderButtonFrame( painter, frameRect, background, outline, shadow, hasFocus, sunken ); - - // also render separator - auto separatorRect( rect.adjusted( 0, 2, -2, -2 ) ); - separatorRect.setWidth( 1 ); - separatorRect = visualRect( option, separatorRect ); - if( sunken ) separatorRect.translate( 1, 1 ); - _helper->renderSeparator( painter, separatorRect, outline, true ); - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawIndicatorTabClosePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // get icon and check - QIcon icon( standardIcon( SP_TitleBarCloseButton, option, widget ) ); - if( icon.isNull() ) return false; - - // store state - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool active( state & State_Raised ); - const bool sunken( state & State_Sunken ); - - // decide icon mode and state - QIcon::Mode iconMode; - QIcon::State iconState; - if( !enabled ) - { - iconMode = QIcon::Disabled; - iconState = QIcon::Off; - - } else { - - if( active ) iconMode = QIcon::Active; - else iconMode = QIcon::Normal; - - iconState = sunken ? QIcon::On : QIcon::Off; - } - - // icon size - const int iconWidth( pixelMetric(QStyle::PM_SmallIconSize, option, widget ) ); - const QSize iconSize( iconWidth, iconWidth ); - - // get pixmap - const QPixmap pixmap( icon.pixmap( iconSize, iconMode, iconState ) ); - - // render - drawItemPixmap( painter, option->rect, Qt::AlignCenter, pixmap ); - return true; - } - - //___________________________________________________________________________________ - bool Style::drawIndicatorTabTearPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const - { - - // cast option and check - const auto tabOption( qstyleoption_cast( option ) ); - if( !tabOption ) return true; - - // store palette and rect - const auto& palette( option->palette ); - auto rect( option->rect ); - - const bool reverseLayout( option->direction == Qt::RightToLeft ); - - const auto color( _helper->alphaColor( palette.color( QPalette::WindowText ), 0.2 ) ); - painter->setRenderHint( QPainter::Antialiasing, false ); - painter->setPen( color ); - painter->setBrush( Qt::NoBrush ); - switch( tabOption->shape ) - { - - case QTabBar::TriangularNorth: - case QTabBar::RoundedNorth: - rect.adjust( 0, 1, 0, 0 ); - if( reverseLayout ) painter->drawLine( rect.topRight(), rect.bottomRight() ); - else painter->drawLine( rect.topLeft(), rect.bottomLeft() ); - break; - - case QTabBar::TriangularSouth: - case QTabBar::RoundedSouth: - rect.adjust( 0, 0, 0, -1 ); - if( reverseLayout ) painter->drawLine( rect.topRight(), rect.bottomRight() ); - else painter->drawLine( rect.topLeft(), rect.bottomLeft() ); - break; - - case QTabBar::TriangularWest: - case QTabBar::RoundedWest: - rect.adjust( 1, 0, 0, 0 ); - painter->drawLine( rect.topLeft(), rect.topRight() ); - break; - - case QTabBar::TriangularEast: - case QTabBar::RoundedEast: - rect.adjust( 0, 0, -1, 0 ); - painter->drawLine( rect.topLeft(), rect.topRight() ); - break; - - default: break; - } - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawIndicatorToolBarHandlePrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const - { - - // do nothing if disabled from options - if( !StyleConfigData::toolBarDrawItemSeparator() ) return true; - - // store rect and palette - auto rect( option->rect ); - const auto& palette( option->palette ); - - // store state - const State& state( option->state ); - const bool separatorIsVertical( state & State_Horizontal ); - - // define color and render - const auto color( _helper->separatorColor( palette ) ); - if( separatorIsVertical ) - { - rect.setWidth( Metrics::ToolBar_HandleWidth ); - rect = centerRect( option->rect, rect.size() ); - rect.setWidth( 3 ); - _helper->renderSeparator( painter, rect, color, separatorIsVertical ); - - rect.translate( 2, 0 ); - _helper->renderSeparator( painter, rect, color, separatorIsVertical ); - - } else { - - rect.setHeight( Metrics::ToolBar_HandleWidth ); - rect = centerRect( option->rect, rect.size() ); - rect.setHeight( 3 ); - _helper->renderSeparator( painter, rect, color, separatorIsVertical ); - - rect.translate( 0, 2 ); - _helper->renderSeparator( painter, rect, color, separatorIsVertical ); - - } - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawIndicatorToolBarSeparatorPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - /* - * do nothing if disabled from options - * also need to check if widget is a combobox, because of Qt hack using 'toolbar' separator primitive - * for rendering separators in comboboxes - */ - if( !( StyleConfigData::toolBarDrawItemSeparator() || qobject_cast( widget ) ) ) - { return true; } - - // store rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - - // store state - const State& state( option->state ); - const bool separatorIsVertical( state & State_Horizontal ); - - // define color and render - const auto color( _helper->separatorColor( palette ) ); - _helper->renderSeparator( painter, rect, color, separatorIsVertical ); - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawIndicatorBranchPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* ) const - { - - // copy rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - - // state - const State& state( option->state ); - const bool reverseLayout( option->direction == Qt::RightToLeft ); - - //draw expander - int expanderAdjust = 0; - if( state & State_Children ) - { - - // state - const bool expanderOpen( state & State_Open ); - const bool enabled( state & State_Enabled ); - const bool mouseOver( enabled && ( state & State_MouseOver ) ); - - // expander rect - int expanderSize = qMin( rect.width(), rect.height() ); - expanderSize = qMin( expanderSize, int(Metrics::ItemView_ArrowSize) ); - expanderAdjust = expanderSize/2 + 1; - const auto arrowRect = centerRect( rect, expanderSize, expanderSize ); - - // get orientation from option - ArrowOrientation orientation; - if( expanderOpen ) orientation = ArrowDown; - else if( reverseLayout ) orientation = ArrowLeft; - else orientation = ArrowRight; - - // color - const auto arrowColor( mouseOver ? _helper->hoverColor( palette ) : _helper->arrowColor( palette, QPalette::Text ) ); - - // render - _helper->renderArrow( painter, arrowRect, arrowColor, orientation ); - - } - - // tree branches - if( !StyleConfigData::viewDrawTreeBranchLines() ) return true; - - const auto center( rect.center() ); - const auto lineColor( KColorUtils::mix( palette.color( QPalette::Base ), palette.color( QPalette::Text ), 0.25 ) ); - painter->setRenderHint( QPainter::Antialiasing, true ); - painter->translate( 0.5, 0.5 ); - painter->setPen( QPen( lineColor, 1 ) ); - if( state & ( State_Item | State_Children | State_Sibling ) ) - { - const QLineF line( QPointF( center.x(), rect.top() ), QPointF( center.x(), center.y() - expanderAdjust - 1 ) ); - painter->drawLine( line ); - } - - // The right/left (depending on direction) line gets drawn if we have an item - if( state & State_Item ) - { - const QLineF line = reverseLayout ? - QLineF( QPointF( rect.left(), center.y() ), QPointF( center.x() - expanderAdjust, center.y() ) ): - QLineF( QPointF( center.x() + expanderAdjust, center.y() ), QPointF( rect.right(), center.y() ) ); - painter->drawLine( line ); - - } - - // The bottom if we have a sibling - if( state & State_Sibling ) - { - const QLineF line( QPointF( center.x(), center.y() + expanderAdjust ), QPointF( center.x(), rect.bottom() ) ); - painter->drawLine( line ); - } - - return true; - } - - //___________________________________________________________________________________ - bool Style::drawPushButtonLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - const auto buttonOption( qstyleoption_cast( option ) ); - if( !buttonOption ) return true; - - // copy rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - - // state - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool sunken( state & (State_On | State_Sunken) ); - const bool mouseOver( enabled && (option->state & State_MouseOver) ); - const bool hasFocus( enabled && !mouseOver && (option->state & State_HasFocus) ); - const bool flat( buttonOption->features & QStyleOptionButton::Flat ); - - // content - const bool hasText( !buttonOption->text.isEmpty() ); - const bool hasIcon( (showIconsOnPushButtons() || flat || !hasText ) && !buttonOption->icon.isNull() ); - - // contents - auto contentsRect( rect ); - if( sunken && !flat ) contentsRect.translate( 1, 1 ); - - // color role - QPalette::ColorRole textRole; - if( flat ) - { - - if( hasFocus && sunken ) textRole = QPalette::HighlightedText; - else textRole = QPalette::WindowText; - - } else if( hasFocus ) textRole = QPalette::HighlightedText; - else textRole = QPalette::ButtonText; - - // menu arrow - if( buttonOption->features & QStyleOptionButton::HasMenu ) - { - - // define rect - auto arrowRect( contentsRect ); - arrowRect.setLeft( contentsRect.right() - Metrics::MenuButton_IndicatorWidth + 1 ); - arrowRect = centerRect( arrowRect, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth ); - - contentsRect.setRight( arrowRect.left() - Metrics::Button_ItemSpacing - 1 ); - contentsRect.adjust( Metrics::Button_MarginWidth, 0, 0, 0 ); - - arrowRect = visualRect( option, arrowRect ); - - // define color - const auto arrowColor( _helper->arrowColor( palette, textRole ) ); - _helper->renderArrow( painter, arrowRect, arrowColor, ArrowDown ); - - } - - // icon size - QSize iconSize; - if( hasIcon ) - { - iconSize = buttonOption->iconSize; - if( !iconSize.isValid() ) - { - const int metric( pixelMetric( PM_SmallIconSize, option, widget ) ); - iconSize = QSize( metric, metric ); - } - } - - // text size - const int textFlags( _mnemonics->textFlags() | Qt::AlignCenter ); - const QSize textSize( option->fontMetrics.size( textFlags, buttonOption->text ) ); - - // adjust text and icon rect based on options - QRect iconRect; - QRect textRect; - - if( hasText && !hasIcon ) textRect = contentsRect; - else if( hasIcon && !hasText ) iconRect = contentsRect; - else { - - const int contentsWidth( iconSize.width() + textSize.width() + Metrics::Button_ItemSpacing ); - iconRect = QRect( QPoint( contentsRect.left() + (contentsRect.width() - contentsWidth )/2, contentsRect.top() + (contentsRect.height() - iconSize.height())/2 ), iconSize ); - textRect = QRect( QPoint( iconRect.right() + Metrics::ToolButton_ItemSpacing + 1, contentsRect.top() + (contentsRect.height() - textSize.height())/2 ), textSize ); - - } - - // handle right to left - if( iconRect.isValid() ) iconRect = visualRect( option, iconRect ); - if( textRect.isValid() ) textRect = visualRect( option, textRect ); - - // make sure there is enough room for icon - if( iconRect.isValid() ) iconRect = centerRect( iconRect, iconSize ); - - // render icon - if( hasIcon && iconRect.isValid() ) { - - // icon state and mode - const QIcon::State iconState( sunken ? QIcon::On : QIcon::Off ); - QIcon::Mode iconMode; - if( !enabled ) iconMode = QIcon::Disabled; - else if( !flat && hasFocus ) iconMode = QIcon::Selected; - else if( mouseOver && flat ) iconMode = QIcon::Active; - else iconMode = QIcon::Normal; - - const auto pixmap = buttonOption->icon.pixmap( iconSize, iconMode, iconState ); - drawItemPixmap( painter, iconRect, Qt::AlignCenter, pixmap ); - - } - - // render text - if( hasText && textRect.isValid() ) - { drawItemText( painter, textRect, textFlags, palette, enabled, buttonOption->text, textRole ); } - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawToolButtonLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - const auto toolButtonOption( qstyleoption_cast(option) ); - - // copy rect and palette - const auto& rect = option->rect; - const auto& palette = option->palette; - - // state - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool sunken( state & (State_On | State_Sunken) ); - const bool mouseOver( enabled && (option->state & State_MouseOver) ); - const bool flat( state & State_AutoRaise ); - - // focus flag is set to match the background color in either renderButtonFrame or renderToolButtonFrame - bool hasFocus( false ); - if( flat ) hasFocus = enabled && !mouseOver && (option->state & State_HasFocus); - else hasFocus = enabled && !mouseOver && (option->state & (State_HasFocus|State_Sunken) ); - - const bool hasArrow( toolButtonOption->features & QStyleOptionToolButton::Arrow ); - const bool hasIcon( !( hasArrow || toolButtonOption->icon.isNull() ) ); - const bool hasText( !toolButtonOption->text.isEmpty() ); - - // contents - auto contentsRect( rect ); - if( sunken && !flat ) contentsRect.translate( 1, 1 ); - - // icon size - const QSize iconSize( toolButtonOption->iconSize ); - - // text size - int textFlags( _mnemonics->textFlags() ); - const QSize textSize( option->fontMetrics.size( textFlags, toolButtonOption->text ) ); - - // adjust text and icon rect based on options - QRect iconRect; - QRect textRect; - - if( hasText && ( !(hasArrow||hasIcon) || toolButtonOption->toolButtonStyle == Qt::ToolButtonTextOnly ) ) - { - - // text only - textRect = contentsRect; - textFlags |= Qt::AlignCenter; - - } else if( (hasArrow||hasIcon) && (!hasText || toolButtonOption->toolButtonStyle == Qt::ToolButtonIconOnly ) ) { - - // icon only - iconRect = contentsRect; - - } else if( toolButtonOption->toolButtonStyle == Qt::ToolButtonTextUnderIcon ) { - - const int contentsHeight( iconSize.height() + textSize.height() + Metrics::ToolButton_ItemSpacing ); - iconRect = QRect( QPoint( contentsRect.left() + (contentsRect.width() - iconSize.width())/2, contentsRect.top() + (contentsRect.height() - contentsHeight)/2 ), iconSize ); - textRect = QRect( QPoint( contentsRect.left() + (contentsRect.width() - textSize.width())/2, iconRect.bottom() + Metrics::ToolButton_ItemSpacing + 1 ), textSize ); - textFlags |= Qt::AlignCenter; - - } else { - - const bool leftAlign( widget && widget->property( PropertyNames::toolButtonAlignment ).toInt() == Qt::AlignLeft ); - if( leftAlign ) { - const int marginWidth( Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth + 1 ); - iconRect = QRect( QPoint( contentsRect.left() + marginWidth, contentsRect.top() + (contentsRect.height() - iconSize.height())/2 ), iconSize ); - } - else { - - const int contentsWidth( iconSize.width() + textSize.width() + Metrics::ToolButton_ItemSpacing ); - iconRect = QRect( QPoint( contentsRect.left() + (contentsRect.width() - contentsWidth )/2, contentsRect.top() + (contentsRect.height() - iconSize.height())/2 ), iconSize ); - - } - - textRect = QRect( QPoint( iconRect.right() + Metrics::ToolButton_ItemSpacing + 1, contentsRect.top() + (contentsRect.height() - textSize.height())/2 ), textSize ); - - // handle right to left layouts - iconRect = visualRect( option, iconRect ); - textRect = visualRect( option, textRect ); - - textFlags |= Qt::AlignLeft | Qt::AlignVCenter; - - } - - // make sure there is enough room for icon - if( iconRect.isValid() ) iconRect = centerRect( iconRect, iconSize ); - - // render arrow or icon - if( hasArrow && iconRect.isValid() ) - { - - QStyleOptionToolButton copy( *toolButtonOption ); - copy.rect = iconRect; - switch( toolButtonOption->arrowType ) - { - case Qt::LeftArrow: drawPrimitive( PE_IndicatorArrowLeft, ©, painter, widget ); break; - case Qt::RightArrow: drawPrimitive( PE_IndicatorArrowRight, ©, painter, widget ); break; - case Qt::UpArrow: drawPrimitive( PE_IndicatorArrowUp, ©, painter, widget ); break; - case Qt::DownArrow: drawPrimitive( PE_IndicatorArrowDown, ©, painter, widget ); break; - default: break; - } - - } else if( hasIcon && iconRect.isValid() ) { - - // icon state and mode - const QIcon::State iconState( sunken ? QIcon::On : QIcon::Off ); - QIcon::Mode iconMode; - if( !enabled ) iconMode = QIcon::Disabled; - else if( (!flat && hasFocus) || (flat && (state & State_Sunken) && !mouseOver) ) iconMode = QIcon::Selected; - else if( mouseOver && flat ) iconMode = QIcon::Active; - else iconMode = QIcon::Normal; - - const QPixmap pixmap = toolButtonOption->icon.pixmap( iconSize, iconMode, iconState ); - drawItemPixmap( painter, iconRect, Qt::AlignCenter, pixmap ); - - } - - // render text - if( hasText && textRect.isValid() ) - { - - QPalette::ColorRole textRole( QPalette::ButtonText ); - if( flat ) textRole = ( ((hasFocus&&sunken) || (state & State_Sunken))&&!mouseOver) ? QPalette::HighlightedText: QPalette::WindowText; - else if( hasFocus&&!mouseOver ) textRole = QPalette::HighlightedText; - - painter->setFont(toolButtonOption->font); - drawItemText( painter, textRect, textFlags, palette, enabled, toolButtonOption->text, textRole ); - - } - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawCheckBoxLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - const auto buttonOption( qstyleoption_cast(option) ); - if( !buttonOption ) return true; - - // copy palette and rect - const auto& palette( option->palette ); - const auto& rect( option->rect ); - - // store state - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - - // text alignment - const bool reverseLayout( option->direction == Qt::RightToLeft ); - const int textFlags( _mnemonics->textFlags() | Qt::AlignVCenter | (reverseLayout ? Qt::AlignRight:Qt::AlignLeft ) ); - - // text rect - auto textRect( rect ); - - // render icon - if( !buttonOption->icon.isNull() ) - { - const QIcon::Mode mode( enabled ? QIcon::Normal : QIcon::Disabled ); - const QPixmap pixmap( buttonOption->icon.pixmap( buttonOption->iconSize, mode ) ); - drawItemPixmap( painter, rect, textFlags, pixmap ); - - // adjust rect (copied from QCommonStyle) - textRect.setLeft( textRect.left() + buttonOption->iconSize.width() + 4 ); - textRect = visualRect( option, textRect ); - - } - - // render text - if( !buttonOption->text.isEmpty() ) - { - textRect = option->fontMetrics.boundingRect( textRect, textFlags, buttonOption->text ); - drawItemText( painter, textRect, textFlags, palette, enabled, buttonOption->text, QPalette::WindowText ); - - // check focus state - const bool hasFocus( enabled && ( state & State_HasFocus ) ); - - // update animation state - _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus ); - const bool isFocusAnimated( _animations->widgetStateEngine().isAnimated( widget, AnimationFocus ) ); - const qreal opacity( _animations->widgetStateEngine().opacity( widget, AnimationFocus ) ); - - // focus color - QColor focusColor; - if( isFocusAnimated ) focusColor = _helper->alphaColor( _helper->focusColor( palette ), opacity ); - else if( hasFocus ) focusColor = _helper->focusColor( palette ); - - // render focus - _helper->renderFocusLine( painter, textRect, focusColor ); - - } - - return true; - - } - - - //___________________________________________________________________________________ - bool Style::drawComboBoxLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - const auto comboBoxOption( qstyleoption_cast( option ) ); - if( !comboBoxOption ) return false; - if( comboBoxOption->editable ) return false; - - // need to alter palette for focused buttons - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool sunken( state & (State_On | State_Sunken) ); - const bool mouseOver( enabled && (option->state & State_MouseOver) ); - const bool hasFocus( enabled && !mouseOver && (option->state & State_HasFocus) ); - const bool flat( !comboBoxOption->frame ); - - QPalette::ColorRole textRole; - if( flat ) { - - if( hasFocus && sunken ) textRole = QPalette::HighlightedText; - else textRole = QPalette::WindowText; - - } else if( hasFocus ) textRole = QPalette::HighlightedText; - else textRole = QPalette::ButtonText; - - // change pen color directly - painter->setPen( QPen( option->palette.color( textRole ), 1 ) ); - - // translate painter for pressed down comboboxes - if( sunken && !flat ) - { painter->translate( 1, 1 ); } - - #if QT_VERSION >= 0x050000 - if (const auto cb = qstyleoption_cast(option)) - { - auto editRect = proxy()->subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget); - painter->save(); - painter->setClipRect(editRect); - if (!cb->currentIcon.isNull()) { - QIcon::Mode mode; - - if ((cb->state & QStyle::State_Selected) && (cb->state & QStyle::State_Active)) { - mode = QIcon::Selected; - } else if (cb->state & QStyle::State_Enabled) { - mode = QIcon::Normal; - } else { - mode = QIcon::Disabled; - } - - QWindow *window = nullptr; - if (widget && widget->window()) { - window = widget->window()->windowHandle(); -#if BREEZE_HAVE_QTQUICK - } else if (QQuickItem *quickItem = qobject_cast(option->styleObject)) { - window = quickItem->window(); -#endif - } - - const auto pixmap = cb->currentIcon.pixmap(window, cb->iconSize, mode); - auto iconRect(editRect); - iconRect.setWidth(cb->iconSize.width() + 4); - iconRect = alignedRect(cb->direction, - Qt::AlignLeft | Qt::AlignVCenter, - iconRect.size(), editRect); - if (cb->editable) - painter->fillRect(iconRect, option->palette.brush(QPalette::Base)); - proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); - - if (cb->direction == Qt::RightToLeft) - editRect.translate(-4 - cb->iconSize.width(), 0); - else - editRect.translate(cb->iconSize.width() + 4, 0); - } - if (!cb->currentText.isEmpty() && !cb->editable) { - proxy()->drawItemText(painter, editRect.adjusted(1, 0, -1, 0), - visualAlignment(cb->direction, Qt::AlignLeft | Qt::AlignVCenter), - cb->palette, cb->state & State_Enabled, cb->currentText); - } - painter->restore(); - } - #else - // call base class method - ParentStyleClass::drawControl( CE_ComboBoxLabel, option, painter, widget ); - #endif - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawMenuBarItemControl( const QStyleOption* option, QPainter* painter, const QWidget* widget) const - { - - // cast option and check - const auto menuItemOption = qstyleoption_cast( option ); - if( !menuItemOption ) return true; - - // copy rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - - // store state - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool selected( enabled && (state & State_Selected) ); - const bool sunken( enabled && (state & State_Sunken) ); - const bool useStrongFocus( StyleConfigData::menuItemDrawStrongFocus() ); - - // render hover and focus - if( useStrongFocus && ( selected || sunken ) ) - { - - QColor outlineColor; - if( sunken ) outlineColor = _helper->focusColor( palette ); - else if( selected ) outlineColor = _helper->hoverColor( palette ); - _helper->renderFocusRect( painter, rect, outlineColor ); - - } - - /* - check if item as an icon, in which case only the icon should be rendered - consistently with comment in QMenuBarPrivate::calcActionRects - */ - if( !menuItemOption->icon.isNull() ) - { - // icon size is forced to SmallIconSize - const auto iconSize = pixelMetric(QStyle::PM_SmallIconSize, nullptr, widget); - const auto iconRect = centerRect( rect, iconSize, iconSize ); - - // decide icon mode and state - QIcon::Mode iconMode; - QIcon::State iconState; - if( !enabled ) - { - iconMode = QIcon::Disabled; - iconState = QIcon::Off; - - } else { - - if( useStrongFocus && sunken ) iconMode = QIcon::Selected; - else if( useStrongFocus && selected ) iconMode = QIcon::Active; - else iconMode = QIcon::Normal; - - iconState = sunken ? QIcon::On : QIcon::Off; - - } - - const auto pixmap = menuItemOption->icon.pixmap( iconSize, iconMode, iconState ); - drawItemPixmap( painter, iconRect, Qt::AlignCenter, pixmap ); - - // render outline - if( !useStrongFocus && ( selected || sunken ) ) - { - - QColor outlineColor; - if( sunken ) outlineColor = _helper->focusColor( palette ); - else if( selected ) outlineColor = _helper->hoverColor( palette ); - - _helper->renderFocusLine( painter, iconRect, outlineColor ); - - } - - } else { - - // get text rect - const int textFlags( Qt::AlignCenter|_mnemonics->textFlags() ); - const auto textRect = option->fontMetrics.boundingRect( rect, textFlags, menuItemOption->text ); - - // render text - const QPalette::ColorRole role = (useStrongFocus && sunken ) ? QPalette::HighlightedText : QPalette::WindowText; - drawItemText( painter, textRect, textFlags, palette, enabled, menuItemOption->text, role ); - - // render outline - if( !useStrongFocus && ( selected || sunken ) ) - { - - QColor outlineColor; - if( sunken ) outlineColor = _helper->focusColor( palette ); - else if( selected ) outlineColor = _helper->hoverColor( palette ); - - _helper->renderFocusLine( painter, textRect, outlineColor ); - - } - - } - - return true; - - } - - - //___________________________________________________________________________________ - bool Style::drawMenuItemControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - const auto menuItemOption = qstyleoption_cast( option ); - if( !menuItemOption ) return true; - if( menuItemOption->menuItemType == QStyleOptionMenuItem::EmptyArea ) return true; - - // copy rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - - // deal with separators - if( menuItemOption->menuItemType == QStyleOptionMenuItem::Separator ) - { - - // normal separator - if( menuItemOption->text.isEmpty() && menuItemOption->icon.isNull() ) - { - - const auto color( _helper->separatorColor( palette ) ); - _helper->renderSeparator( painter, rect, color ); - return true; - - } else { - - /* - * separator can have a title and an icon - * in that case they are rendered as menu title buttons - */ - QStyleOptionToolButton copy( separatorMenuItemOption( menuItemOption, widget ) ); - renderMenuTitle( ©, painter, widget ); - - return true; - - } - - } - - // store state - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool selected( enabled && (state & State_Selected) ); - const bool sunken( enabled && (state & (State_On|State_Sunken) ) ); - const bool reverseLayout( option->direction == Qt::RightToLeft ); - const bool useStrongFocus( StyleConfigData::menuItemDrawStrongFocus() ); - - // render hover and focus - if( useStrongFocus && ( selected || sunken ) ) - { - - const auto color = _helper->focusColor( palette ); - const auto outlineColor = _helper->focusOutlineColor( palette ); - - Sides sides = nullptr; - if( !menuItemOption->menuRect.isNull() ) - { - if( rect.top() <= menuItemOption->menuRect.top() ) sides |= SideTop; - if( rect.bottom() >= menuItemOption->menuRect.bottom() ) sides |= SideBottom; - if( rect.left() <= menuItemOption->menuRect.left() ) sides |= SideLeft; - if( rect.right() >= menuItemOption->menuRect.right() ) sides |= SideRight; - } - - _helper->renderFocusRect( painter, rect, color, outlineColor, sides ); - - } - - // get rect available for contents - auto contentsRect( insideMargin( rect, Metrics::MenuItem_MarginWidth, Metrics::MenuItem_MarginHeight ) ); - - // define relevant rectangles - // checkbox - QRect checkBoxRect; - if( menuItemOption->menuHasCheckableItems ) - { - checkBoxRect = QRect( contentsRect.left(), contentsRect.top() + (contentsRect.height()-Metrics::CheckBox_Size)/2, Metrics::CheckBox_Size, Metrics::CheckBox_Size ); - contentsRect.setLeft( checkBoxRect.right() + Metrics::MenuItem_ItemSpacing + 1 ); - } - - // render checkbox indicator - if( menuItemOption->checkType == QStyleOptionMenuItem::NonExclusive ) - { - - checkBoxRect = visualRect( option, checkBoxRect ); - - // checkbox state - - if( useStrongFocus && ( selected || sunken ) ) - { _helper->renderCheckBoxBackground( painter, checkBoxRect, palette.color( QPalette::Window ), sunken ); } - - CheckBoxState state( menuItemOption->checked ? CheckOn : CheckOff ); - const bool active( menuItemOption->checked ); - const auto shadow( _helper->shadowColor( palette ) ); - const auto color( _helper->checkBoxIndicatorColor( palette, false, enabled && active ) ); - _helper->renderCheckBox( painter, checkBoxRect, color, shadow, sunken, state ); - - } else if( menuItemOption->checkType == QStyleOptionMenuItem::Exclusive ) { - - checkBoxRect = visualRect( option, checkBoxRect ); - - if( useStrongFocus && ( selected || sunken ) ) - { _helper->renderRadioButtonBackground( painter, checkBoxRect, palette.color( QPalette::Window ), sunken ); } - - const bool active( menuItemOption->checked ); - const auto shadow( _helper->shadowColor( palette ) ); - const auto color( _helper->checkBoxIndicatorColor( palette, false, enabled && active ) ); - _helper->renderRadioButton( painter, checkBoxRect, color, shadow, sunken, active ? RadioOn:RadioOff ); - - } - - // icon - int iconWidth = 0; - const bool showIcon( showIconsInMenuItems() ); - if( showIcon ) iconWidth = isQtQuickControl( option, widget ) ? qMax( pixelMetric(PM_SmallIconSize, option, widget ), menuItemOption->maxIconWidth ) : menuItemOption->maxIconWidth; - - QRect iconRect; - if( showIcon && iconWidth > 0 ) - { - iconRect = QRect( contentsRect.left(), contentsRect.top() + (contentsRect.height()-iconWidth)/2, iconWidth, iconWidth ); - contentsRect.setLeft( iconRect.right() + Metrics::MenuItem_ItemSpacing + 1 ); - const QSize iconSize( pixelMetric( PM_SmallIconSize, option, widget ), pixelMetric( PM_SmallIconSize, option, widget ) ); - iconRect = centerRect( iconRect, iconSize ); - } - - if( showIcon && !menuItemOption->icon.isNull() ) - { - - iconRect = visualRect( option, iconRect ); - - // icon mode - QIcon::Mode mode; - if( selected && !useStrongFocus) mode = QIcon::Active; - else if( selected ) mode = QIcon::Selected; - else if( enabled ) mode = QIcon::Normal; - else mode = QIcon::Disabled; - - // icon state - const QIcon::State iconState( sunken ? QIcon::On:QIcon::Off ); - const QPixmap icon = menuItemOption->icon.pixmap( iconRect.size(), mode, iconState ); - painter->drawPixmap( iconRect, icon ); - - } - - // arrow - QRect arrowRect( contentsRect.right() - Metrics::MenuButton_IndicatorWidth + 1, contentsRect.top() + (contentsRect.height()-Metrics::MenuButton_IndicatorWidth)/2, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth ); - contentsRect.setRight( arrowRect.left() - Metrics::MenuItem_ItemSpacing - 1 ); - - if( menuItemOption->menuItemType == QStyleOptionMenuItem::SubMenu ) - { - - // apply right-to-left layout - arrowRect = visualRect( option, arrowRect ); - - // arrow orientation - const ArrowOrientation orientation( reverseLayout ? ArrowLeft:ArrowRight ); - - // color - QColor arrowColor; - if( useStrongFocus && ( selected || sunken ) ) arrowColor = palette.color( QPalette::HighlightedText ); - else if( sunken ) arrowColor = _helper->focusColor( palette ); - else if( selected ) arrowColor = _helper->hoverColor( palette ); - else arrowColor = _helper->arrowColor( palette, QPalette::WindowText ); - - // render - _helper->renderArrow( painter, arrowRect, arrowColor, orientation ); - - } - - - // text - auto textRect = contentsRect; - if( !menuItemOption->text.isEmpty() ) - { - - // adjust textRect - QString text = menuItemOption->text; - textRect = centerRect( textRect, textRect.width(), option->fontMetrics.size( _mnemonics->textFlags(), text ).height() ); - textRect = visualRect( option, textRect ); - - // set font - painter->setFont( menuItemOption->font ); - - // color role - const QPalette::ColorRole role = (useStrongFocus && ( selected || sunken )) ? QPalette::HighlightedText : QPalette::WindowText; - - // locate accelerator and render - const int tabPosition( text.indexOf( QLatin1Char( '\t' ) ) ); - if( tabPosition >= 0 ) - { - - const int textFlags( Qt::AlignVCenter | Qt::AlignRight ); - QString accelerator( text.mid( tabPosition + 1 ) ); - text = text.left( tabPosition ); - drawItemText( painter, textRect, textFlags, palette, enabled, accelerator, role ); - - } - - // render text - const int textFlags( Qt::AlignVCenter | (reverseLayout ? Qt::AlignRight : Qt::AlignLeft ) | _mnemonics->textFlags() ); - textRect = option->fontMetrics.boundingRect( textRect, textFlags, text ); - drawItemText( painter, textRect, textFlags, palette, enabled, text, role ); - - // render hover and focus - if( !useStrongFocus && ( selected || sunken ) ) - { - - QColor outlineColor; - if( sunken ) outlineColor = _helper->focusColor( palette ); - else if( selected ) outlineColor = _helper->hoverColor( palette ); - - _helper->renderFocusLine( painter, textRect, outlineColor ); - - } - - } - - return true; - } - - //___________________________________________________________________________________ - bool Style::drawProgressBarControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - const auto progressBarOption( qstyleoption_cast( option ) ); - if( !progressBarOption ) return true; - - // render groove - #if BREEZE_USE_KDE4 - QStyleOptionProgressBarV2 progressBarOption2 = *progressBarOption; - #else - QStyleOptionProgressBar progressBarOption2 = *progressBarOption; - #endif - progressBarOption2.rect = subElementRect( SE_ProgressBarGroove, progressBarOption, widget ); - drawControl( CE_ProgressBarGroove, &progressBarOption2, painter, widget ); - - #if QT_VERSION >= 0x050000 - const QObject* styleObject( widget ? widget:progressBarOption->styleObject ); - #else - const QObject* styleObject( widget ); - #endif - - // enable busy animations - // need to check both widget and passed styleObject, used for QML - if( styleObject && _animations->busyIndicatorEngine().enabled() ) - { - - #if QT_VERSION >= 0x050000 - // register QML object if defined - if( !widget && progressBarOption->styleObject ) - { _animations->busyIndicatorEngine().registerWidget( progressBarOption->styleObject ); } - #endif - - _animations->busyIndicatorEngine().setAnimated( styleObject, progressBarOption->maximum == 0 && progressBarOption->minimum == 0 ); - - } - - // check if animated and pass to option - if( _animations->busyIndicatorEngine().isAnimated( styleObject ) ) - { progressBarOption2.progress = _animations->busyIndicatorEngine().value(); } - - // render contents - progressBarOption2.rect = subElementRect( SE_ProgressBarContents, progressBarOption, widget ); - drawControl( CE_ProgressBarContents, &progressBarOption2, painter, widget ); - - // render text - const bool textVisible( progressBarOption->textVisible ); - const bool busy( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ); - if( textVisible && !busy ) - { - progressBarOption2.rect = subElementRect( SE_ProgressBarLabel, progressBarOption, widget ); - drawControl( CE_ProgressBarLabel, &progressBarOption2, painter, widget ); - } - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawProgressBarContentsControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const - { - - const auto progressBarOption( qstyleoption_cast( option ) ); - if( !progressBarOption ) return true; - - // copy rect and palette - auto rect( option->rect ); - const auto& palette( option->palette ); - - // get direction - #if BREEZE_USE_KDE4 - const auto progressBarOption2( qstyleoption_cast( option ) ); - const bool horizontal = !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal; - const bool inverted( progressBarOption2 ? progressBarOption2->invertedAppearance : false ); - #else - const bool horizontal( BreezePrivate::isProgressBarHorizontal( progressBarOption ) ); - const bool inverted( progressBarOption->invertedAppearance ); - #endif - bool reverse = horizontal && option->direction == Qt::RightToLeft; - if( inverted ) reverse = !reverse; - - // check if anything is to be drawn - const bool busy( ( progressBarOption->minimum == 0 && progressBarOption->maximum == 0 ) ); - if( busy ) - { - - const qreal progress( _animations->busyIndicatorEngine().value() ); - - const auto &first = palette.color( QPalette::Highlight ); - const auto second( KColorUtils::mix( palette.color( QPalette::Highlight ), palette.color( QPalette::Window ), 0.7 ) ); - _helper->renderProgressBarBusyContents( painter, rect, first, second, horizontal, reverse, progress ); - - } else { - - const QRegion oldClipRegion( painter->clipRegion() ); - if( horizontal ) - { - if( rect.width() < Metrics::ProgressBar_Thickness ) - { - painter->setClipRect( rect, Qt::IntersectClip ); - if( reverse ) rect.setLeft( rect.left() - Metrics::ProgressBar_Thickness + rect.width() ); - else rect.setWidth( Metrics::ProgressBar_Thickness ); - } - - } else { - - if( rect.height() < Metrics::ProgressBar_Thickness ) - { - painter->setClipRect( rect, Qt::IntersectClip ); - if( reverse ) rect.setHeight( Metrics::ProgressBar_Thickness ); - else rect.setTop( rect.top() - Metrics::ProgressBar_Thickness + rect.height() ); - } - - } - - auto contentsColor( - option->state.testFlag( QStyle::State_Selected ) ? - palette.color( QPalette::HighlightedText ) : - palette.color( QPalette::Highlight ) ); - - _helper->renderProgressBarContents( painter, rect, contentsColor ); - painter->setClipRegion( oldClipRegion ); - } - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawProgressBarGrooveControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const - { - const auto& palette( option->palette ); - const auto color( _helper->alphaColor( palette.color( QPalette::WindowText ), 0.3 ) ); - _helper->renderProgressBarGroove( painter, option->rect, color ); - return true; - } - - //___________________________________________________________________________________ - bool Style::drawProgressBarLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const - { - - // cast option and check - const auto progressBarOption( qstyleoption_cast( option ) ); - if( !progressBarOption ) return true; - - // get direction and check - #if BREEZE_USE_KDE4 - const auto progressBarOption2( qstyleoption_cast( option ) ); - const bool horizontal = !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal; - #else - const bool horizontal( BreezePrivate::isProgressBarHorizontal( progressBarOption ) ); - #endif - if( !horizontal ) return true; - - // store rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - - // store state and direction - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - - // define text rect - Qt::Alignment hAlign( ( progressBarOption->textAlignment == Qt::AlignLeft ) ? Qt::AlignHCenter : progressBarOption->textAlignment ); - drawItemText( painter, rect, Qt::AlignVCenter | hAlign, palette, enabled, progressBarOption->text, QPalette::WindowText ); - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawScrollBarSliderControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - const auto sliderOption( qstyleoption_cast( option ) ); - if( !sliderOption ) return true; - - // copy rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - - //try to understand if anywhere the widget is under mouse, not just the handle, use _animations in case of QWidget, option->styleObject in case of QML - #if QT_VERSION >= 0x050000 - bool widgetMouseOver( ( option->state & State_MouseOver ) ); - if( widget ) widgetMouseOver = _animations->scrollBarEngine().isHovered( widget, QStyle::SC_ScrollBarGroove ); - else if( option->styleObject ) widgetMouseOver = option->styleObject->property("hover").toBool(); - #else - const bool widgetMouseOver( _animations->scrollBarEngine().isHovered( widget, QStyle::SC_ScrollBarGroove ) ); - #endif - - qreal grooveAnimationOpacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); - if( grooveAnimationOpacity == AnimationData::OpacityInvalid ) grooveAnimationOpacity = (widgetMouseOver ? 1 : 0); - const qreal handleSize = StyleConfigData::animationsEnabled() ? ((Metrics::ScrollBar_SliderWidth / 2.0) * (1 - grooveAnimationOpacity) + Metrics::ScrollBar_SliderWidth * grooveAnimationOpacity) : (int)Metrics::ScrollBar_SliderWidth; - - // define handle rect - QRect handleRect; - const State& state( option->state ); - const bool horizontal( state & State_Horizontal ); - if( horizontal ) handleRect = centerRect( rect, rect.width(), handleSize ); - else handleRect = centerRect( rect, handleSize, rect.height() ); - - const bool enabled( state & State_Enabled ); - const bool mouseOver( enabled && ( state & State_MouseOver ) ); - - // check focus from relevant parent - const QWidget* parent( scrollBarParent( widget ) ); - const bool hasFocus( enabled && ( (widget && widget->hasFocus()) || (parent && parent->hasFocus()) ) ); - - // enable animation state - const bool handleActive( sliderOption->activeSubControls & SC_ScrollBarSlider ); - _animations->scrollBarEngine().updateState( widget, AnimationFocus, hasFocus ); - - _animations->scrollBarEngine().updateState( widget, AnimationHover, mouseOver && handleActive ); - - const auto mode( _animations->scrollBarEngine().animationMode( widget, SC_ScrollBarSlider ) ); - const qreal opacity( _animations->scrollBarEngine().opacity( widget, SC_ScrollBarSlider ) ); - auto color = _helper->scrollBarHandleColor( palette, mouseOver, hasFocus, opacity, mode ); - if (StyleConfigData::animationsEnabled()) { - color.setAlphaF(color.alphaF() * (0.7 + 0.3 * grooveAnimationOpacity)); - } - - _helper->renderScrollBarHandle( painter, handleRect, color ); - return true; - } - - //___________________________________________________________________________________ - bool Style::drawScrollBarAddLineControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // do nothing if no buttons are defined - if( _addLineButtons == NoButton ) return true; - - // cast option and check - const auto sliderOption( qstyleoption_cast( option ) ); - if( !sliderOption ) return true; - - const State& state( option->state ); - const bool horizontal( state & State_Horizontal ); - const bool reverseLayout( option->direction == Qt::RightToLeft ); - - // adjust rect, based on number of buttons to be drawn - const auto rect( scrollBarInternalSubControlRect( sliderOption, SC_ScrollBarAddLine ) ); - - QColor color; - QStyleOptionSlider copy( *sliderOption ); - if( _addLineButtons == DoubleButton ) - { - - if( horizontal ) - { - - //Draw the arrows - const QSize halfSize( rect.width()/2, rect.height() ); - const QRect leftSubButton( rect.topLeft(), halfSize ); - const QRect rightSubButton( leftSubButton.topRight() + QPoint( 1, 0 ), halfSize ); - - copy.rect = leftSubButton; - color = scrollBarArrowColor( ©, reverseLayout ? SC_ScrollBarAddLine:SC_ScrollBarSubLine, widget ); - _helper->renderArrow( painter, leftSubButton, color, ArrowLeft ); - - copy.rect = rightSubButton; - color = scrollBarArrowColor( ©, reverseLayout ? SC_ScrollBarSubLine:SC_ScrollBarAddLine, widget ); - _helper->renderArrow( painter, rightSubButton, color, ArrowRight ); - - } else { - - const QSize halfSize( rect.width(), rect.height()/2 ); - const QRect topSubButton( rect.topLeft(), halfSize ); - const QRect botSubButton( topSubButton.bottomLeft() + QPoint( 0, 1 ), halfSize ); - - copy.rect = topSubButton; - color = scrollBarArrowColor( ©, SC_ScrollBarSubLine, widget ); - _helper->renderArrow( painter, topSubButton, color, ArrowUp ); - - copy.rect = botSubButton; - color = scrollBarArrowColor( ©, SC_ScrollBarAddLine, widget ); - _helper->renderArrow( painter, botSubButton, color, ArrowDown ); - - } - - } else if( _addLineButtons == SingleButton ) { - - copy.rect = rect; - color = scrollBarArrowColor( ©, SC_ScrollBarAddLine, widget ); - if( horizontal ) - { - - if( reverseLayout ) _helper->renderArrow( painter, rect, color, ArrowLeft ); - else _helper->renderArrow( painter, rect.translated( 1, 0 ), color, ArrowRight ); - - } else _helper->renderArrow( painter, rect.translated( 0, 1 ), color, ArrowDown ); - - } - - return true; - } - - - //___________________________________________________________________________________ - bool Style::drawScrollBarSubLineControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // do nothing if no buttons are set - if( _subLineButtons == NoButton ) return true; - - // cast option and check - const auto sliderOption( qstyleoption_cast( option ) ); - if( !sliderOption ) return true; - - const State& state( option->state ); - const bool horizontal( state & State_Horizontal ); - const bool reverseLayout( option->direction == Qt::RightToLeft ); - - // colors - const auto& palette( option->palette ); - const auto &background = palette.color( QPalette::Window ); - - // adjust rect, based on number of buttons to be drawn - const auto rect( scrollBarInternalSubControlRect( sliderOption, SC_ScrollBarSubLine ) ); - - QColor color; - QStyleOptionSlider copy( *sliderOption ); - if( _subLineButtons == DoubleButton ) - { - - if( horizontal ) - { - - //Draw the arrows - const QSize halfSize( rect.width()/2, rect.height() ); - const QRect leftSubButton( rect.topLeft(), halfSize ); - const QRect rightSubButton( leftSubButton.topRight() + QPoint( 1, 0 ), halfSize ); - - copy.rect = leftSubButton; - color = scrollBarArrowColor( ©, reverseLayout ? SC_ScrollBarAddLine:SC_ScrollBarSubLine, widget ); - _helper->renderArrow( painter, leftSubButton, color, ArrowLeft ); - - copy.rect = rightSubButton; - color = scrollBarArrowColor( ©, reverseLayout ? SC_ScrollBarSubLine:SC_ScrollBarAddLine, widget ); - _helper->renderArrow( painter, rightSubButton, color, ArrowRight ); - - } else { - - const QSize halfSize( rect.width(), rect.height()/2 ); - const QRect topSubButton( rect.topLeft(), halfSize ); - const QRect botSubButton( topSubButton.bottomLeft() + QPoint( 0, 1 ), halfSize ); - - copy.rect = topSubButton; - color = scrollBarArrowColor( ©, SC_ScrollBarSubLine, widget ); - _helper->renderArrow( painter, topSubButton, color, ArrowUp ); - - copy.rect = botSubButton; - color = scrollBarArrowColor( ©, SC_ScrollBarAddLine, widget ); - _helper->renderArrow( painter, botSubButton, color, ArrowDown ); - - } - - } else if( _subLineButtons == SingleButton ) { - - copy.rect = rect; - color = scrollBarArrowColor( ©, SC_ScrollBarSubLine, widget ); - if( horizontal ) - { - - if( reverseLayout ) _helper->renderArrow( painter, rect.translated( 1, 0 ), color, ArrowRight ); - else _helper->renderArrow( painter, rect, color, ArrowLeft ); - - } else _helper->renderArrow( painter, rect, color, ArrowUp ); - - } - - return true; - } - - //___________________________________________________________________________________ - bool Style::drawShapedFrameControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - #if BREEZE_USE_KDE4 - const auto frameOpt = qstyleoption_cast( option ); - #else - const auto frameOpt = qstyleoption_cast( option ); - #endif - if( !frameOpt ) return false; - - switch( frameOpt->frameShape ) - { - - case QFrame::Box: - { - if( option->state & State_Sunken ) return true; - else break; - } - - case QFrame::HLine: - case QFrame::VLine: - { - - const auto& rect( option->rect ); - const auto color( _helper->separatorColor( option->palette ) ); - const bool isVertical( frameOpt->frameShape == QFrame::VLine ); - _helper->renderSeparator( painter, rect, color, isVertical ); - return true; - } - - case QFrame::StyledPanel: - { - - if( isQtQuickControl( option, widget ) ) - { - - // ComboBox popup frame - drawFrameMenuPrimitive( option, painter, widget ); - return true; - - } else break; - } - - default: break; - - } - - return false; - - } - - //___________________________________________________________________________________ - bool Style::drawRubberBandControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const - { - - const auto& palette( option->palette ); - const auto rect( option->rect ); - - auto color = palette.color( QPalette::Highlight ); - painter->setPen( KColorUtils::mix( color, palette.color( QPalette::Active, QPalette::WindowText ) ) ); - color.setAlpha( 50 ); - painter->setBrush( color ); - painter->setClipRegion( rect ); - painter->drawRect( rect.adjusted( 0, 0, -1, -1 ) ); - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawHeaderSectionControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - const auto& rect( option->rect ); - const auto& palette( option->palette ); - const auto& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool mouseOver( enabled && ( state & State_MouseOver ) ); - const bool sunken( enabled && ( state & (State_On|State_Sunken) ) ); - - const auto headerOption( qstyleoption_cast( option ) ); - if( !headerOption ) return true; - - const bool horizontal( headerOption->orientation == Qt::Horizontal ); - const bool isFirst( horizontal && ( headerOption->position == QStyleOptionHeader::Beginning ) ); - const bool isCorner( widget && widget->inherits( "QTableCornerButton" ) ); - const bool reverseLayout( option->direction == Qt::RightToLeft ); - - // update animation state - _animations->headerViewEngine().updateState( widget, rect.topLeft(), mouseOver ); - const bool animated( enabled && _animations->headerViewEngine().isAnimated( widget, rect.topLeft() ) ); - const qreal opacity( _animations->headerViewEngine().opacity( widget, rect.topLeft() ) ); - - // fill - const auto &normal = palette.color( QPalette::Button ); - const auto focus( KColorUtils::mix( normal, _helper->focusColor( palette ), 0.2 ) ); - const auto hover( KColorUtils::mix( normal, _helper->hoverColor( palette ), 0.2 ) ); - - QColor color; - if( sunken ) color = focus; - else if( animated ) color = KColorUtils::mix( normal, hover, opacity ); - else if( mouseOver ) color = hover; - else color = normal; - - painter->setRenderHint( QPainter::Antialiasing, false ); - painter->setBrush( color ); - painter->setPen( Qt::NoPen ); - painter->drawRect( rect ); - - // outline - painter->setBrush( Qt::NoBrush ); - painter->setPen( _helper->alphaColor( palette.color( QPalette::WindowText ), 0.1 ) ); - - if( isCorner ) - { - - if( reverseLayout ) painter->drawPoint( rect.bottomLeft() ); - else painter->drawPoint( rect.bottomRight() ); - - - } else if( horizontal ) { - - painter->drawLine( rect.bottomLeft(), rect.bottomRight() ); - - } else { - - if( reverseLayout ) painter->drawLine( rect.topLeft(), rect.bottomLeft() ); - else painter->drawLine( rect.topRight(), rect.bottomRight() ); - - } - - // separators - painter->setPen( _helper->alphaColor( palette.color( QPalette::WindowText ), 0.2 ) ); - - if( horizontal ) - { - if( headerOption->section != 0 || isFirst ) - { - - if( reverseLayout ) painter->drawLine( rect.topLeft(), rect.bottomLeft() - QPoint( 0, 1 ) ); - else painter->drawLine( rect.topRight(), rect.bottomRight() - QPoint( 0, 1 ) ); - - } - - } else { - - if( reverseLayout ) painter->drawLine( rect.bottomLeft()+QPoint( 1, 0 ), rect.bottomRight() ); - else painter->drawLine( rect.bottomLeft(), rect.bottomRight() - QPoint( 1, 0 ) ); - - } - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawHeaderEmptyAreaControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const - { - - // use the same background as in drawHeaderPrimitive - const auto& rect( option->rect ); - auto palette( option->palette ); - - const bool horizontal( option->state & QStyle::State_Horizontal ); - const bool reverseLayout( option->direction == Qt::RightToLeft ); - - // fill - painter->setRenderHint( QPainter::Antialiasing, false ); - painter->setBrush( palette.color( QPalette::Button ) ); - painter->setPen( Qt::NoPen ); - painter->drawRect( rect ); - - // outline - painter->setBrush( Qt::NoBrush ); - painter->setPen( _helper->alphaColor( palette.color( QPalette::ButtonText ), 0.1 ) ); - - if( horizontal ) { - - painter->drawLine( rect.bottomLeft(), rect.bottomRight() ); - - } else { - - if( reverseLayout ) painter->drawLine( rect.topLeft(), rect.bottomLeft() ); - else painter->drawLine( rect.topRight(), rect.bottomRight() ); - - } - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawTabBarTabLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // call parent style method - ParentStyleClass::drawControl( CE_TabBarTabLabel, option, painter, widget ); - - // store rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - - // check focus - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool selected( state & State_Selected ); - const bool hasFocus( enabled && selected && (state & State_HasFocus) ); - - // update mouse over animation state - _animations->tabBarEngine().updateState( widget, rect.topLeft(), AnimationFocus, hasFocus ); - const bool animated( enabled && selected && _animations->tabBarEngine().isAnimated( widget, rect.topLeft(), AnimationFocus ) ); - const qreal opacity( _animations->tabBarEngine().opacity( widget, rect.topLeft(), AnimationFocus ) ); - - if( !( hasFocus || animated ) ) return true; - - // code is copied from QCommonStyle, but adds focus - // cast option and check - const auto tabOption( qstyleoption_cast(option) ); - if( !tabOption || tabOption->text.isEmpty() ) return true; - - // tab option rect - const bool verticalTabs( isVerticalTab( tabOption ) ); - const int textFlags( Qt::AlignCenter | _mnemonics->textFlags() ); - - // text rect - auto textRect( subElementRect(SE_TabBarTabText, option, widget) ); - - if( verticalTabs ) - { - - // properly rotate painter - painter->save(); - int newX, newY, newRot; - if( tabOption->shape == QTabBar::RoundedEast || tabOption->shape == QTabBar::TriangularEast) - { - - newX = rect.width() + rect.x(); - newY = rect.y(); - newRot = 90; - - } else { - - newX = rect.x(); - newY = rect.y() + rect.height(); - newRot = -90; - - } - - QTransform transform; - transform.translate( newX, newY ); - transform.rotate(newRot); - painter->setTransform( transform, true ); - - } - - // adjust text rect based on font metrics - textRect = option->fontMetrics.boundingRect( textRect, textFlags, tabOption->text ); - - // focus color - QColor focusColor; - if( animated ) focusColor = _helper->alphaColor( _helper->focusColor( palette ), opacity ); - else if( hasFocus ) focusColor = _helper->focusColor( palette ); - - // render focus line - _helper->renderFocusLine( painter, textRect, focusColor ); - - if( verticalTabs ) painter->restore(); - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawTabBarTabShapeControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - const auto tabOption( qstyleoption_cast( option ) ); - if( !tabOption ) return true; - - // palette and state - const auto& palette( option->palette ); - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool selected( state & State_Selected ); - const bool mouseOver( enabled && !selected && ( state & State_MouseOver ) ); - - // check if tab is being dragged - const bool isDragged( widget && selected && painter->device() != widget ); - const bool isLocked( widget && _tabBarData->isLocked( widget ) ); - - // store rect - auto rect( option->rect ); - - // update mouse over animation state - _animations->tabBarEngine().updateState( widget, rect.topLeft(), AnimationHover, mouseOver ); - const bool animated( enabled && !selected && _animations->tabBarEngine().isAnimated( widget, rect.topLeft(), AnimationHover ) ); - const qreal opacity( _animations->tabBarEngine().opacity( widget, rect.topLeft(), AnimationHover ) ); - - // lock state - if( selected && widget && isDragged ) _tabBarData->lock( widget ); - else if( widget && selected && _tabBarData->isLocked( widget ) ) _tabBarData->release(); - - // tab position - const QStyleOptionTab::TabPosition& position = tabOption->position; - const bool isSingle( position == QStyleOptionTab::OnlyOneTab ); - const bool isQtQuickControl( this->isQtQuickControl( option, widget ) ); - bool isFirst( isSingle || position == QStyleOptionTab::Beginning ); - bool isLast( isSingle || position == QStyleOptionTab::End ); - bool isLeftOfSelected( !isLocked && tabOption->selectedPosition == QStyleOptionTab::NextIsSelected ); - bool isRightOfSelected( !isLocked && tabOption->selectedPosition == QStyleOptionTab::PreviousIsSelected ); - - // true if widget is aligned to the frame - // need to check for 'isRightOfSelected' because for some reason the isFirst flag is set when active tab is being moved - isFirst &= !isRightOfSelected; - isLast &= !isLeftOfSelected; - - // swap state based on reverse layout, so that they become layout independent - const bool reverseLayout( option->direction == Qt::RightToLeft ); - const bool verticalTabs( isVerticalTab( tabOption ) ); - if( reverseLayout && !verticalTabs ) - { - qSwap( isFirst, isLast ); - qSwap( isLeftOfSelected, isRightOfSelected ); - } - - // overlap - // for QtQuickControls, ovelap is already accounted of in the option. Unlike in the qwidget case - const int overlap( isQtQuickControl ? 0:Metrics::TabBar_TabOverlap ); - - // adjust rect and define corners based on tabbar orientation - Corners corners; - switch( tabOption->shape ) - { - case QTabBar::RoundedNorth: - case QTabBar::TriangularNorth: - if( selected ) - { - - corners = CornerTopLeft|CornerTopRight; - rect.adjust( 0, 0, 0, 1 ); - - } else { - - rect.adjust( 0, 0, 0, -1 ); - if( isFirst ) corners |= CornerTopLeft; - if( isLast ) corners |= CornerTopRight; - if( isRightOfSelected ) rect.adjust( -Metrics::Frame_FrameRadius, 0, 0, 0 ); - if( isLeftOfSelected ) rect.adjust( 0, 0, Metrics::Frame_FrameRadius, 0 ); - else if( !isLast ) rect.adjust( 0, 0, overlap, 0 ); - - } - break; - - case QTabBar::RoundedSouth: - case QTabBar::TriangularSouth: - if( selected ) - { - - corners = CornerBottomLeft|CornerBottomRight; - rect.adjust( 0, - 1, 0, 0 ); - - } else { - - rect.adjust( 0, 1, 0, 0 ); - if( isFirst ) corners |= CornerBottomLeft; - if( isLast ) corners |= CornerBottomRight; - if( isRightOfSelected ) rect.adjust( -Metrics::Frame_FrameRadius, 0, 0, 0 ); - if( isLeftOfSelected ) rect.adjust( 0, 0, Metrics::Frame_FrameRadius, 0 ); - else if( !isLast ) rect.adjust( 0, 0, overlap, 0 ); - - } - break; - - case QTabBar::RoundedWest: - case QTabBar::TriangularWest: - if( selected ) - { - corners = CornerTopLeft|CornerBottomLeft; - rect.adjust( 0, 0, 1, 0 ); - - } else { - - rect.adjust( 0, 0, -1, 0 ); - if( isFirst ) corners |= CornerTopLeft; - if( isLast ) corners |= CornerBottomLeft; - if( isRightOfSelected ) rect.adjust( 0, -Metrics::Frame_FrameRadius, 0, 0 ); - if( isLeftOfSelected ) rect.adjust( 0, 0, 0, Metrics::Frame_FrameRadius ); - else if( !isLast ) rect.adjust( 0, 0, 0, overlap ); - - } - break; - - case QTabBar::RoundedEast: - case QTabBar::TriangularEast: - if( selected ) - { - - corners = CornerTopRight|CornerBottomRight; - rect.adjust( -1, 0, 0, 0 ); - - } else { - - rect.adjust( 1, 0, 0, 0 ); - if( isFirst ) corners |= CornerTopRight; - if( isLast ) corners |= CornerBottomRight; - if( isRightOfSelected ) rect.adjust( 0, -Metrics::Frame_FrameRadius, 0, 0 ); - if( isLeftOfSelected ) rect.adjust( 0, 0, 0, Metrics::Frame_FrameRadius ); - else if( !isLast ) rect.adjust( 0, 0, 0, overlap ); - - } - break; - - default: break; - } - - // color - QColor color; - if( selected ) - { - - #if QT_VERSION >= 0x050000 - bool documentMode = tabOption->documentMode; - #else - bool documentMode = false; - if( const auto tabOptionV3 = qstyleoption_cast( option ) ) - { documentMode = tabOptionV3->documentMode; } - #endif - - // flag passed to QStyleOptionTab is unfortunately not reliable enough - // also need to check on parent widget - const auto tabWidget = ( widget && widget->parentWidget() ) ? qobject_cast( widget->parentWidget() ) : nullptr; - documentMode |= ( tabWidget ? tabWidget->documentMode() : true ); - - color = (documentMode&&!isQtQuickControl&&!hasAlteredBackground(widget)) ? palette.color( QPalette::Window ) : _helper->frameBackgroundColor( palette ); - - } else { - - const auto normal( _helper->alphaColor( palette.color( QPalette::Shadow ), 0.2 ) ); - const auto hover( _helper->alphaColor( _helper->hoverColor( palette ), 0.2 ) ); - if( animated ) color = KColorUtils::mix( normal, hover, opacity ); - else if( mouseOver ) color = hover; - else color = normal; - - } - - // outline - const auto outline( selected ? _helper->alphaColor( palette.color( QPalette::WindowText ), 0.25 ) : QColor() ); - - // render - if( selected ) - { - - QRegion oldRegion( painter->clipRegion() ); - painter->setClipRect( option->rect, Qt::IntersectClip ); - _helper->renderTabBarTab( painter, rect, color, outline, corners ); - painter->setClipRegion( oldRegion ); - - } else { - - _helper->renderTabBarTab( painter, rect, color, outline, corners ); - - } - - return true; - - } - - //___________________________________________________________________________________ - bool Style::drawToolBoxTabLabelControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // rendering is similar to drawPushButtonLabelControl - // cast option and check - const auto toolBoxOption( qstyleoption_cast( option ) ); - if( !toolBoxOption ) return true; - - // copy palette - const auto& palette( option->palette ); - - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - - // text alignment - const int textFlags( _mnemonics->textFlags() | Qt::AlignCenter ); - - // contents rect - const auto rect( subElementRect( SE_ToolBoxTabContents, option, widget ) ); - - // store icon size - const int iconSize( pixelMetric( QStyle::PM_SmallIconSize, option, widget ) ); - - // find contents size and rect - auto contentsRect( rect ); - QSize contentsSize; - if( !toolBoxOption->text.isEmpty() ) - { - contentsSize = option->fontMetrics.size( _mnemonics->textFlags(), toolBoxOption->text ); - if( !toolBoxOption->icon.isNull() ) contentsSize.rwidth() += Metrics::ToolBox_TabItemSpacing; - } - - // icon size - if( !toolBoxOption->icon.isNull() ) - { - - contentsSize.setHeight( qMax( contentsSize.height(), iconSize ) ); - contentsSize.rwidth() += iconSize; - - } - - // adjust contents rect - contentsRect = centerRect( contentsRect, contentsSize ); - - // render icon - if( !toolBoxOption->icon.isNull() ) - { - - // icon rect - QRect iconRect; - if( toolBoxOption->text.isEmpty() ) iconRect = centerRect( contentsRect, iconSize, iconSize ); - else { - - iconRect = contentsRect; - iconRect.setWidth( iconSize ); - iconRect = centerRect( iconRect, iconSize, iconSize ); - contentsRect.setLeft( iconRect.right() + Metrics::ToolBox_TabItemSpacing + 1 ); - - } - - iconRect = visualRect( option, iconRect ); - const QIcon::Mode mode( enabled ? QIcon::Normal : QIcon::Disabled ); - const QPixmap pixmap( toolBoxOption->icon.pixmap( iconSize, mode ) ); - drawItemPixmap( painter, iconRect, textFlags, pixmap ); - - } - - // render text - if( !toolBoxOption->text.isEmpty() ) - { - contentsRect = visualRect( option, contentsRect ); - drawItemText( painter, contentsRect, textFlags, palette, enabled, toolBoxOption->text, QPalette::WindowText ); - } - - return true; - } - - //___________________________________________________________________________________ - bool Style::drawToolBoxTabShapeControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - const auto toolBoxOption( qstyleoption_cast( option ) ); - if( !toolBoxOption ) return true; - - // copy rect and palette - const auto& rect( option->rect ); - const auto tabRect( toolBoxTabContentsRect( option, widget ) ); - - /* - * important: option returns the wrong palette. - * we use the widget palette instead, when set - */ - const auto& palette( widget ? widget->palette() : option->palette ); - - // store flags - const State& flags( option->state ); - const bool enabled( flags&State_Enabled ); - const bool selected( flags&State_Selected ); - const bool mouseOver( enabled && !selected && ( flags&State_MouseOver ) ); - - // update animation state - /* - * the proper widget ( the toolbox tab ) is not passed as argument by Qt. - * What is passed is the toolbox directly. To implement animations properly, - *the painter->device() is used instead - */ - bool isAnimated( false ); - qreal opacity( AnimationData::OpacityInvalid ); - QPaintDevice* device = painter->device(); - if( enabled && device ) - { - _animations->toolBoxEngine().updateState( device, mouseOver ); - isAnimated = _animations->toolBoxEngine().isAnimated( device ); - opacity = _animations->toolBoxEngine().opacity( device ); - } - - // color - QColor outline; - if( selected ) outline = _helper->focusColor( palette ); - else outline = _helper->frameOutlineColor( palette, mouseOver, false, opacity, isAnimated ? AnimationHover:AnimationNone ); - - // render - _helper->renderToolBoxFrame( painter, rect, tabRect.width(), outline ); - - return true; - } - - //___________________________________________________________________________________ - bool Style::drawDockWidgetTitleControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - const auto dockWidgetOption = qstyleoption_cast( option ); - if( !dockWidgetOption ) return true; - - const auto& palette( option->palette ); - const auto& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool reverseLayout( option->direction == Qt::RightToLeft ); - - // cast to v2 to check vertical bar - #if BREEZE_USE_KDE4 - const auto v2 = qstyleoption_cast( option ); - const bool verticalTitleBar( v2 ? v2->verticalTitleBar : false ); - #else - const bool verticalTitleBar( dockWidgetOption->verticalTitleBar ); - #endif - - const auto buttonRect( subElementRect( dockWidgetOption->floatable ? SE_DockWidgetFloatButton : SE_DockWidgetCloseButton, option, widget ) ); - - // get rectangle and adjust to properly accounts for buttons - auto rect( insideMargin( dockWidgetOption->rect, Metrics::Frame_FrameWidth ) ); - if( verticalTitleBar ) - { - - if( buttonRect.isValid() ) rect.setTop( buttonRect.bottom() + 1 ); - - } else if( reverseLayout ) { - - if( buttonRect.isValid() ) rect.setLeft( buttonRect.right() + 1 ); - rect.adjust( 0, 0, -4, 0 ); - - } else { - - if( buttonRect.isValid() ) rect.setRight( buttonRect.left() - 1 ); - rect.adjust( 4, 0, 0, 0 ); - - } - - QString title( dockWidgetOption->title ); - int titleWidth = dockWidgetOption->fontMetrics.size( _mnemonics->textFlags(), title ).width(); - int width = verticalTitleBar ? rect.height() : rect.width(); - if( width < titleWidth ) title = dockWidgetOption->fontMetrics.elidedText( title, Qt::ElideRight, width, Qt::TextShowMnemonic ); - - if( verticalTitleBar ) - { - - QSize size = rect.size(); - size.transpose(); - rect.setSize( size ); - - painter->save(); - painter->translate( rect.left(), rect.top() + rect.width() ); - painter->rotate( -90 ); - painter->translate( -rect.left(), -rect.top() ); - drawItemText( painter, rect, Qt::AlignLeft | Qt::AlignVCenter | _mnemonics->textFlags(), palette, enabled, title, QPalette::WindowText ); - painter->restore(); - - - } else { - - drawItemText( painter, rect, Qt::AlignLeft | Qt::AlignVCenter | _mnemonics->textFlags(), palette, enabled, title, QPalette::WindowText ); - - } - - return true; - - - } - - //______________________________________________________________ - bool Style::drawGroupBoxComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const - { - - // base class method - ParentStyleClass::drawComplexControl( CC_GroupBox, option, painter, widget ); - - // cast option and check - const auto groupBoxOption = qstyleoption_cast( option ); - if( !groupBoxOption ) return true; - - // do nothing if either label is not selected or groupbox is empty - if( !(option->subControls & QStyle::SC_GroupBoxLabel) || groupBoxOption->text.isEmpty() ) - { return true; } - - // store palette and rect - const auto& palette( option->palette ); - - // check focus state - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool hasFocus( enabled && (option->state & State_HasFocus) ); - if( !hasFocus ) return true; - - // alignment - const int textFlags( groupBoxOption->textAlignment | _mnemonics->textFlags() ); - - // update animation state - _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus ); - const bool isFocusAnimated( _animations->widgetStateEngine().isAnimated( widget, AnimationFocus ) ); - const qreal opacity( _animations->widgetStateEngine().opacity( widget, AnimationFocus ) ); - - // get relevant rect - auto textRect = subControlRect( CC_GroupBox, option, SC_GroupBoxLabel, widget ); - textRect = option->fontMetrics.boundingRect( textRect, textFlags, groupBoxOption->text ); - - // focus color - QColor focusColor; - if( isFocusAnimated ) focusColor = _helper->alphaColor( _helper->focusColor( palette ), opacity ); - else if( hasFocus ) focusColor = _helper->focusColor( palette ); - - // render focus - _helper->renderFocusLine( painter, textRect, focusColor ); - - return true; - - } - - //______________________________________________________________ - bool Style::drawToolButtonComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - const auto toolButtonOption( qstyleoption_cast( option ) ); - if( !toolButtonOption ) return true; - - // need to alter palette for focused buttons - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool mouseOver( enabled && (option->state & State_MouseOver) ); - const bool hasFocus( enabled && (option->state & State_HasFocus) ); - const bool sunken( state & (State_On | State_Sunken) ); - const bool flat( state & State_AutoRaise ); - - // update animation state - // mouse over takes precedence over focus - _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); - _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus && !mouseOver ); - - // detect buttons in tabbar, for which special rendering is needed - const bool inTabBar( widget && qobject_cast( widget->parentWidget() ) ); - const bool isMenuTitle( this->isMenuTitle( widget ) ); - if( isMenuTitle ) - { - // copy option to adjust state, and set font as not-bold - QStyleOptionToolButton copy( *toolButtonOption ); - copy.font.setBold( false ); - copy.state = State_Enabled; - - // render - renderMenuTitle( ©, painter, widget ); - return true; - } - - // copy option and alter palette - QStyleOptionToolButton copy( *toolButtonOption ); - - const bool hasPopupMenu( toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup ); - const bool hasInlineIndicator( - toolButtonOption->features&QStyleOptionToolButton::HasMenu - && toolButtonOption->features&QStyleOptionToolButton::PopupDelay - && !hasPopupMenu ); - - const auto buttonRect( subControlRect( CC_ToolButton, option, SC_ToolButton, widget ) ); - const auto menuRect( subControlRect( CC_ToolButton, option, SC_ToolButtonMenu, widget ) ); - - // frame - if( toolButtonOption->subControls & SC_ToolButton ) - { - if( !flat ) copy.rect = buttonRect; - if( inTabBar ) drawTabBarPanelButtonToolPrimitive( ©, painter, widget ); - else drawPrimitive( PE_PanelButtonTool, ©, painter, widget); - } - - // arrow - if( hasPopupMenu ) - { - - copy.rect = menuRect; - if( !flat ) drawPrimitive( PE_IndicatorButtonDropDown, ©, painter, widget ); - - if( sunken && !flat ) copy.rect.translate( 1, 1 ); - drawPrimitive( PE_IndicatorArrowDown, ©, painter, widget ); - - } else if( hasInlineIndicator ) { - - copy.rect = menuRect; - - if( sunken && !flat ) copy.rect.translate( 1, 1 ); - drawPrimitive( PE_IndicatorArrowDown, ©, painter, widget ); - - } - - // contents - { - - // restore state - copy.state = state; - - // define contents rect - auto contentsRect( buttonRect ); - - // detect dock widget title button - // for dockwidget title buttons, do not take out margins, so that icon do not get scaled down - const bool isDockWidgetTitleButton( widget && widget->inherits( "QDockWidgetTitleButton" ) ); - if( isDockWidgetTitleButton ) - { - - // cast to abstract button - // adjust state to have correct icon rendered - const auto button( qobject_cast( widget ) ); - if( button->isChecked() || button->isDown() ) copy.state |= State_On; - - } else if( !inTabBar && hasInlineIndicator ) { - - const int marginWidth( flat ? Metrics::ToolButton_MarginWidth : Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth ); - contentsRect = insideMargin( contentsRect, marginWidth, 0 ); - contentsRect.setRight( contentsRect.right() - Metrics::ToolButton_InlineIndicatorWidth ); - contentsRect = visualRect( option, contentsRect ); - - } - - copy.rect = contentsRect; - - // render - drawControl( CE_ToolButtonLabel, ©, painter, widget); - - } - - return true; - } - - //______________________________________________________________ - bool Style::drawComboBoxComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - const auto comboBoxOption( qstyleoption_cast( option ) ); - if( !comboBoxOption ) return true; - - // rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - - // state - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool mouseOver( enabled && ( state & State_MouseOver ) ); - const bool hasFocus( enabled && ( state & (State_HasFocus | State_Sunken ) ) ); - const bool editable( comboBoxOption->editable ); - const bool sunken( state & (State_On|State_Sunken) ); - bool flat( !comboBoxOption->frame ); - - // frame - if( option->subControls & SC_ComboBoxFrame ) - { - - if( editable ) - { - - flat |= ( rect.height() <= 2*Metrics::Frame_FrameWidth + Metrics::MenuButton_IndicatorWidth ); - if( flat ) - { - - const auto &background = palette.color( QPalette::Base ); - - painter->setBrush( background ); - painter->setPen( Qt::NoPen ); - painter->drawRect( rect ); - - } else { - - drawPrimitive( PE_FrameLineEdit, option, painter, widget ); - - } - - } else { - - // update animation state - // hover takes precedence over focus - _animations->inputWidgetEngine().updateState( widget, AnimationHover, mouseOver ); - _animations->inputWidgetEngine().updateState( widget, AnimationFocus, hasFocus && !mouseOver ); - const AnimationMode mode( _animations->inputWidgetEngine().buttonAnimationMode( widget ) ); - const qreal opacity( _animations->inputWidgetEngine().buttonOpacity( widget ) ); - - if( flat ) { - - // define colors and render - const auto color( _helper->toolButtonColor( palette, mouseOver, hasFocus, sunken, opacity, mode ) ); - _helper->renderToolButtonFrame( painter, rect, color, sunken ); - - } else { - - // define colors - const auto shadow( _helper->shadowColor( palette ) ); - const auto outline( _helper->buttonOutlineColor( palette, mouseOver, hasFocus, opacity, mode ) ); - const auto background( _helper->buttonBackgroundColor( palette, mouseOver, hasFocus, false, opacity, mode ) ); - - // render - _helper->renderButtonFrame( painter, rect, background, outline, shadow, hasFocus, sunken ); - - } - - } - - } - - // arrow - if( option->subControls & SC_ComboBoxArrow ) - { - - // detect empty comboboxes - const auto comboBox = qobject_cast( widget ); - const bool empty( comboBox && !comboBox->count() ); - - // arrow color - QColor arrowColor; - if( editable ) - { - - if( empty || !enabled ) arrowColor = palette.color( QPalette::Disabled, QPalette::Text ); - else { - - // check animation state - const bool subControlHover( enabled && mouseOver && comboBoxOption->activeSubControls&SC_ComboBoxArrow ); - _animations->comboBoxEngine().updateState( widget, AnimationHover, subControlHover ); - - const bool animated( enabled && _animations->comboBoxEngine().isAnimated( widget, AnimationHover ) ); - const qreal opacity( _animations->comboBoxEngine().opacity( widget, AnimationHover ) ); - - // color - const auto normal( _helper->arrowColor( palette, QPalette::WindowText ) ); - const auto hover( _helper->hoverColor( palette ) ); - - if( animated ) - { - arrowColor = KColorUtils::mix( normal, hover, opacity ); - - } else if( subControlHover ) { - - arrowColor = hover; - - } else arrowColor = normal; - - } - - } else if( flat ) { - - if( empty || !enabled ) arrowColor = _helper->arrowColor( palette, QPalette::Disabled, QPalette::WindowText ); - else if( hasFocus && !mouseOver && sunken ) arrowColor = palette.color( QPalette::HighlightedText ); - else arrowColor = _helper->arrowColor( palette, QPalette::WindowText ); - - } else if( empty || !enabled ) arrowColor = _helper->arrowColor( palette, QPalette::Disabled, QPalette::ButtonText ); - else if( hasFocus && !mouseOver ) arrowColor = palette.color( QPalette::HighlightedText ); - else arrowColor = _helper->arrowColor( palette, QPalette::ButtonText ); - - // arrow rect - auto arrowRect( subControlRect( CC_ComboBox, option, SC_ComboBoxArrow, widget ) ); - - // translate for non editable, non flat, sunken comboboxes - if( sunken && !flat && !editable ) arrowRect.translate( 1, 1 ); - - // render - _helper->renderArrow( painter, arrowRect, arrowColor, ArrowDown ); - - } - - return true; - - } - - //______________________________________________________________ - bool Style::drawSpinBoxComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const - { - - const auto spinBoxOption( qstyleoption_cast( option ) ); - if( !spinBoxOption ) return true; - - // store palette and rect - const auto& palette( option->palette ); - const auto& rect( option->rect ); - - - if( option->subControls & SC_SpinBoxFrame ) - { - - // detect flat spinboxes - bool flat( !spinBoxOption->frame ); - flat |= ( rect.height() < 2*Metrics::Frame_FrameWidth + Metrics::SpinBox_ArrowButtonWidth ); - if( flat ) - { - - const auto &background = palette.color( QPalette::Base ); - - painter->setBrush( background ); - painter->setPen( Qt::NoPen ); - painter->drawRect( rect ); - - } else { - - drawPrimitive( PE_FrameLineEdit, option, painter, widget ); - - } - - } - - if( option->subControls & SC_SpinBoxUp ) renderSpinBoxArrow( SC_SpinBoxUp, spinBoxOption, painter, widget ); - if( option->subControls & SC_SpinBoxDown ) renderSpinBoxArrow( SC_SpinBoxDown, spinBoxOption, painter, widget ); - - return true; - - } - - //______________________________________________________________ - bool Style::drawSliderComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - const auto sliderOption( qstyleoption_cast( option ) ); - if( !sliderOption ) return true; - - // copy rect and palette - const auto& rect( option->rect ); - const auto& palette( option->palette ); - - // copy state - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool mouseOver( enabled && ( state & State_MouseOver ) ); - const bool hasFocus( enabled && ( state & State_HasFocus ) ); - - // direction - const bool horizontal( sliderOption->orientation == Qt::Horizontal ); - - // tickmarks - if( StyleConfigData::sliderDrawTickMarks() && ( sliderOption->subControls & SC_SliderTickmarks ) ) - { - const bool upsideDown( sliderOption->upsideDown ); - const int tickPosition( sliderOption->tickPosition ); - const int available( pixelMetric( PM_SliderSpaceAvailable, option, widget ) ); - int interval = sliderOption->tickInterval; - if( interval < 1 ) interval = sliderOption->pageStep; - if( interval >= 1 ) - { - const int fudge( pixelMetric( PM_SliderLength, option, widget ) / 2 ); - int current( sliderOption->minimum ); - - // store tick lines - const auto grooveRect( subControlRect( CC_Slider, sliderOption, SC_SliderGroove, widget ) ); - QList tickLines; - if( horizontal ) - { - - if( tickPosition & QSlider::TicksAbove ) tickLines.append( QLine( rect.left(), grooveRect.top() - Metrics::Slider_TickMarginWidth, rect.left(), grooveRect.top() - Metrics::Slider_TickMarginWidth - Metrics::Slider_TickLength ) ); - if( tickPosition & QSlider::TicksBelow ) tickLines.append( QLine( rect.left(), grooveRect.bottom() + Metrics::Slider_TickMarginWidth, rect.left(), grooveRect.bottom() + Metrics::Slider_TickMarginWidth + Metrics::Slider_TickLength ) ); - - } else { - - if( tickPosition & QSlider::TicksAbove ) tickLines.append( QLine( grooveRect.left() - Metrics::Slider_TickMarginWidth, rect.top(), grooveRect.left() - Metrics::Slider_TickMarginWidth - Metrics::Slider_TickLength, rect.top() ) ); - if( tickPosition & QSlider::TicksBelow ) tickLines.append( QLine( grooveRect.right() + Metrics::Slider_TickMarginWidth, rect.top(), grooveRect.right() + Metrics::Slider_TickMarginWidth + Metrics::Slider_TickLength, rect.top() ) ); - - } - - // colors - const auto base( _helper->separatorColor( palette ) ); - const auto &highlight = palette.color( QPalette::Highlight ); - - while( current <= sliderOption->maximum ) - { - - // adjust color - const auto color( (enabled && current <= sliderOption->sliderPosition) ? highlight:base ); - painter->setPen( color ); - - // calculate positions and draw lines - int position( sliderPositionFromValue( sliderOption->minimum, sliderOption->maximum, current, available ) + fudge ); - foreach( const QLine& tickLine, tickLines ) - { - if( horizontal ) painter->drawLine( tickLine.translated( upsideDown ? (rect.width() - position) : position, 0 ) ); - else painter->drawLine( tickLine.translated( 0, upsideDown ? (rect.height() - position):position ) ); - } - - // go to next position - current += interval; - - } - } - } - - // groove - if( sliderOption->subControls & SC_SliderGroove ) - { - // retrieve groove rect - auto grooveRect( subControlRect( CC_Slider, sliderOption, SC_SliderGroove, widget ) ); - - // base color - const auto grooveColor( _helper->alphaColor( palette.color( QPalette::WindowText ), 0.3 ) ); - - if( !enabled ) _helper->renderSliderGroove( painter, grooveRect, grooveColor ); - else { - - const bool upsideDown( sliderOption->upsideDown ); - - // handle rect - auto handleRect( subControlRect( CC_Slider, sliderOption, SC_SliderHandle, widget ) ); - - // highlight color - const auto &highlight = palette.color( QPalette::Highlight ); - - if( sliderOption->orientation == Qt::Horizontal ) - { - - auto leftRect( grooveRect ); - leftRect.setRight( handleRect.right() - Metrics::Slider_ControlThickness/2 ); - _helper->renderSliderGroove( painter, leftRect, upsideDown ? grooveColor:highlight ); - - auto rightRect( grooveRect ); - rightRect.setLeft( handleRect.left() + Metrics::Slider_ControlThickness/2 ); - _helper->renderSliderGroove( painter, rightRect, upsideDown ? highlight:grooveColor ); - - } else { - - auto topRect( grooveRect ); - topRect.setBottom( handleRect.bottom() - Metrics::Slider_ControlThickness/2 ); - _helper->renderSliderGroove( painter, topRect, upsideDown ? grooveColor:highlight ); - - auto bottomRect( grooveRect ); - bottomRect.setTop( handleRect.top() + Metrics::Slider_ControlThickness/2 ); - _helper->renderSliderGroove( painter, bottomRect, upsideDown ? highlight:grooveColor ); - - } - - } - - } - - // handle - if( sliderOption->subControls & SC_SliderHandle ) - { - - // get rect and center - auto handleRect( subControlRect( CC_Slider, sliderOption, SC_SliderHandle, widget ) ); - - // handle state - const bool handleActive( sliderOption->activeSubControls & SC_SliderHandle ); - const bool sunken( state & (State_On|State_Sunken) ); - - // animation state - _animations->widgetStateEngine().updateState( widget, AnimationHover, handleActive && mouseOver ); - _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus ); - const AnimationMode mode( _animations->widgetStateEngine().buttonAnimationMode( widget ) ); - const qreal opacity( _animations->widgetStateEngine().buttonOpacity( widget ) ); - - // define colors - const auto &background = palette.color( QPalette::Button ); - const auto outline( _helper->sliderOutlineColor( palette, handleActive && mouseOver, hasFocus, opacity, mode ) ); - const auto shadow( _helper->shadowColor( palette ) ); - - // render - _helper->renderSliderHandle( painter, handleRect, background, outline, shadow, sunken ); - - } - - return true; - } - - //______________________________________________________________ - bool Style::drawDialComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - const auto sliderOption( qstyleoption_cast( option ) ); - if( !sliderOption ) return true; - - const auto& palette( option->palette ); - const State& state( option->state ); - const bool enabled( state & State_Enabled ); - const bool mouseOver( enabled && ( state & State_MouseOver ) ); - const bool hasFocus( enabled && ( state & State_HasFocus ) ); - - // do not render tickmarks - if( sliderOption->subControls & SC_DialTickmarks ) - {} - - // groove - if( sliderOption->subControls & SC_DialGroove ) - { - - // groove rect - auto grooveRect( subControlRect( CC_Dial, sliderOption, SC_SliderGroove, widget ) ); - - // groove - const auto grooveColor( KColorUtils::mix( palette.color( QPalette::Window ), palette.color( QPalette::WindowText ), 0.3 ) ); - - // angles - const qreal first( dialAngle( sliderOption, sliderOption->minimum ) ); - const qreal last( dialAngle( sliderOption, sliderOption->maximum ) ); - - // render groove - _helper->renderDialGroove( painter, grooveRect, grooveColor, first, last ); - - if( enabled ) - { - - // highlight - const auto &highlight = palette.color( QPalette::Highlight ); - - // angles - const qreal second( dialAngle( sliderOption, sliderOption->sliderPosition ) ); - - // render contents - _helper->renderDialContents( painter, grooveRect, highlight, first, second ); - - } - - } - - // handle - if( sliderOption->subControls & SC_DialHandle ) - { - - // get handle rect - auto handleRect( subControlRect( CC_Dial, sliderOption, SC_DialHandle, widget ) ); - handleRect = centerRect( handleRect, Metrics::Slider_ControlThickness, Metrics::Slider_ControlThickness ); - - // handle state - const bool handleActive( mouseOver && handleRect.contains( _animations->dialEngine().position( widget ) ) ); - const bool sunken( state & (State_On|State_Sunken) ); - - // animation state - _animations->dialEngine().setHandleRect( widget, handleRect ); - _animations->dialEngine().updateState( widget, AnimationHover, handleActive && mouseOver ); - _animations->dialEngine().updateState( widget, AnimationFocus, hasFocus ); - const auto mode( _animations->dialEngine().buttonAnimationMode( widget ) ); - const qreal opacity( _animations->dialEngine().buttonOpacity( widget ) ); - - // define colors - const auto &background = palette.color( QPalette::Button ); - const auto outline( _helper->sliderOutlineColor( palette, handleActive && mouseOver, hasFocus, opacity, mode ) ); - const auto shadow( _helper->shadowColor( palette ) ); - - // render - _helper->renderSliderHandle( painter, handleRect, background, outline, shadow, sunken ); - - } - - return true; - } - - //______________________________________________________________ - bool Style::drawScrollBarComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const - { - //the animation for QStyle::SC_ScrollBarGroove is special: it will animate - //the opacity of everything else as well, included slider and arrows - qreal opacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); - const bool animated( StyleConfigData::animationsEnabled() && _animations->scrollBarEngine().isAnimated( widget, AnimationHover, QStyle::SC_ScrollBarGroove ) ); - const bool mouseOver( option->state & State_MouseOver ); - - if( opacity == AnimationData::OpacityInvalid ) opacity = 1; - - // render full groove directly, rather than using the addPage and subPage control element methods - if( (!StyleConfigData::animationsEnabled() || mouseOver || animated) && option->subControls & SC_ScrollBarGroove ) - { - // retrieve groove rectangle - auto grooveRect( subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ) ); - - const auto& palette( option->palette ); - const auto color( _helper->alphaColor( palette.color( QPalette::WindowText ), 0.3 * (animated ? opacity : 1) ) ); - const auto& state( option->state ); - const bool horizontal( state & State_Horizontal ); - - if( horizontal ) grooveRect = centerRect( grooveRect, grooveRect.width(), Metrics::ScrollBar_SliderWidth ); - else grooveRect = centerRect( grooveRect, Metrics::ScrollBar_SliderWidth, grooveRect.height() ); - - // render - _helper->renderScrollBarGroove( painter, grooveRect, color ); - } - - // call base class primitive - ParentStyleClass::drawComplexControl( CC_ScrollBar, option, painter, widget ); - - return true; - } - - //______________________________________________________________ - bool Style::drawTitleBarComplexControl( const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const - { - - // cast option and check - const auto titleBarOption( qstyleoption_cast( option ) ); - if( !titleBarOption ) return true; - - // store palette and rect - auto palette( option->palette ); - const auto& rect( option->rect ); - - const State& flags( option->state ); - const bool enabled( flags & State_Enabled ); - const bool active( enabled && ( titleBarOption->titleBarState & Qt::WindowActive ) ); - - if( titleBarOption->subControls & SC_TitleBarLabel ) - { - - // render background - painter->setClipRect( rect ); - const auto outline( active ? QColor():_helper->frameOutlineColor( palette, false, false ) ); - const auto background( _helper->titleBarColor( active ) ); - _helper->renderTabWidgetFrame( painter, rect.adjusted( -1, -1, 1, 3 ), background, outline, CornersTop ); - - const bool useSeparator( - active && - _helper->titleBarColor( active ) != palette.color( QPalette::Window ) && - !( titleBarOption->titleBarState & Qt::WindowMinimized ) ); - - if( useSeparator ) - { - painter->setRenderHint( QPainter::Antialiasing, false ); - painter->setBrush( Qt::NoBrush ); - painter->setPen( palette.color( QPalette::Highlight ) ); - painter->drawLine( rect.bottomLeft(), rect.bottomRight() ); - } - - // render text - palette.setColor( QPalette::WindowText, _helper->titleBarTextColor( active ) ); - const auto textRect( subControlRect( CC_TitleBar, option, SC_TitleBarLabel, widget ) ); - ParentStyleClass::drawItemText( painter, textRect, Qt::AlignCenter, palette, active, titleBarOption->text, QPalette::WindowText ); - - } - - // buttons - static const QList subControls = - { - SC_TitleBarMinButton, - SC_TitleBarMaxButton, - SC_TitleBarCloseButton, - SC_TitleBarNormalButton, - SC_TitleBarSysMenu - }; - - // loop over supported buttons - foreach( const SubControl& subControl, subControls ) - { - - // skip if not requested - if( !( titleBarOption->subControls & subControl ) ) continue; - - // find matching icon - QIcon icon; - switch( subControl ) - { - case SC_TitleBarMinButton: icon = standardIcon( SP_TitleBarMinButton, option, widget ); break; - case SC_TitleBarMaxButton: icon = standardIcon( SP_TitleBarMaxButton, option, widget ); break; - case SC_TitleBarCloseButton: icon = standardIcon( SP_TitleBarCloseButton, option, widget ); break; - case SC_TitleBarNormalButton: icon = standardIcon( SP_TitleBarNormalButton, option, widget ); break; - case SC_TitleBarSysMenu: icon = titleBarOption->icon; break; - default: break; - } - - // check icon - if( icon.isNull() ) continue; - - // define icon rect - auto iconRect( subControlRect( CC_TitleBar, option, subControl, widget ) ); - if( iconRect.isEmpty() ) continue; - - // active state - const bool subControlActive( titleBarOption->activeSubControls & subControl ); - - // mouse over state - const bool mouseOver( - !subControlActive && - widget && - iconRect.translated( widget->mapToGlobal( QPoint( 0,0 ) ) ).contains( QCursor::pos() ) ); - - // adjust iconRect - const int iconWidth( pixelMetric( PM_SmallIconSize, option, widget ) ); - const QSize iconSize( iconWidth, iconWidth ); - iconRect = centerRect( iconRect, iconSize ); - - // set icon mode and state - QIcon::Mode iconMode; - QIcon::State iconState; - - if( !enabled ) - { - iconMode = QIcon::Disabled; - iconState = QIcon::Off; - - } else { - - if( mouseOver ) iconMode = QIcon::Active; - else if( active ) iconMode = QIcon::Selected; - else iconMode = QIcon::Normal; - - iconState = subControlActive ? QIcon::On : QIcon::Off; - - } - - // get pixmap and render - const QPixmap pixmap = icon.pixmap( iconSize, iconMode, iconState ); - painter->drawPixmap( iconRect, pixmap ); - - } - - return true; - - } - - //____________________________________________________________________________________________________ - void Style::renderSpinBoxArrow( const SubControl& subControl, const QStyleOptionSpinBox* option, QPainter* painter, const QWidget* widget ) const + //___________________________________________________________________________________ + bool Style::drawPanelScrollAreaCornerPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { - const auto& palette( option->palette ); - const State& state( option->state ); - - // enable state - bool enabled( state & State_Enabled ); - - // check steps enable step - const bool atLimit( - (subControl == SC_SpinBoxUp && !(option->stepEnabled & QAbstractSpinBox::StepUpEnabled )) || - (subControl == SC_SpinBoxDown && !(option->stepEnabled & QAbstractSpinBox::StepDownEnabled ) ) ); - - // update enabled state accordingly - enabled &= !atLimit; - - // update mouse-over effect - const bool mouseOver( enabled && ( state & State_MouseOver ) ); - - // check animation state - const bool subControlHover( enabled && mouseOver && ( option->activeSubControls & subControl ) ); - _animations->spinBoxEngine().updateState( widget, subControl, subControlHover ); - - const bool animated( enabled && _animations->spinBoxEngine().isAnimated( widget, subControl ) ); - const qreal opacity( _animations->spinBoxEngine().opacity( widget, subControl ) ); - - auto color = _helper->arrowColor( palette, QPalette::Text ); - if( animated ) + // make sure background role matches viewport + const QAbstractScrollArea* scrollArea; + if( ( scrollArea = qobject_cast( widget ) ) && scrollArea->viewport() ) { - auto highlight = _helper->hoverColor( palette ); - color = KColorUtils::mix( color, highlight, opacity ); - - } else if( subControlHover ) { - - color = _helper->hoverColor( palette ); - - } else if( atLimit ) { - - color = _helper->arrowColor( palette, QPalette::Disabled, QPalette::Text ); - - } - - // arrow orientation - ArrowOrientation orientation( ( subControl == SC_SpinBoxUp ) ? ArrowUp:ArrowDown ); - - // arrow rect - const auto arrowRect( subControlRect( CC_SpinBox, option, subControl, widget ) ); - - // render - _helper->renderArrow( painter, arrowRect, color, orientation ); - - } - - //______________________________________________________________________________ - void Style::renderMenuTitle( const QStyleOptionToolButton* option, QPainter* painter, const QWidget* ) const - { - - // render a separator at the bottom - const auto& palette( option->palette ); - const auto color( _helper->separatorColor( palette ) ); - _helper->renderSeparator( painter, QRect( option->rect.bottomLeft()-QPoint( 0, Metrics::MenuItem_MarginHeight), QSize( option->rect.width(), 1 ) ), color ); - - // render text in the center of the rect - // icon is discarded on purpose - painter->setFont( option->font ); - const auto contentsRect = insideMargin( option->rect, Metrics::MenuItem_MarginWidth, Metrics::MenuItem_MarginHeight ); - drawItemText( painter, contentsRect, Qt::AlignCenter, palette, true, option->text, QPalette::WindowText ); - - } - - //______________________________________________________________________________ - qreal Style::dialAngle( const QStyleOptionSlider* sliderOption, int value ) const - { - - // calculate angle at which handle needs to be drawn - qreal angle( 0 ); - if( sliderOption->maximum == sliderOption->minimum ) angle = M_PI / 2; - else { + // need to adjust clipRect in order not to render outside of frame + const int frameWidth( pixelMetric( PM_DefaultFrameWidth, nullptr, scrollArea ) ); + painter->setClipRect( insideMargin( scrollArea->rect(), frameWidth ) ); + painter->setBrush( scrollArea->viewport()->palette().color( scrollArea->viewport()->backgroundRole() ) ); + painter->setPen( Qt::NoPen ); + painter->drawRect( option->rect ); + return true; - qreal fraction( qreal( value - sliderOption->minimum )/qreal( sliderOption->maximum - sliderOption->minimum ) ); - if( !sliderOption->upsideDown ) fraction = 1 - fraction; + } else { - if( sliderOption->dialWrapping ) angle = 1.5*M_PI - fraction*2*M_PI; - else angle = ( M_PI*8 - fraction*10*M_PI )/6; + return false; } - return angle; - } - //______________________________________________________________________________ - const QWidget* Style::scrollBarParent( const QWidget* widget ) const + //___________________________________________________________________________________ + bool Style::drawPanelTipLabelPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { - // check widget and parent - if( !(widget && widget->parentWidget() ) ) return nullptr; - - // try cast to scroll area. Must test both parent and grandparent - QAbstractScrollArea* scrollArea; - if( !(scrollArea = qobject_cast( widget->parentWidget() ) ) ) - { scrollArea = qobject_cast( widget->parentWidget()->parentWidget() ); } - - // check scrollarea - if( scrollArea && - (widget == scrollArea->verticalScrollBar() || - widget == scrollArea->horizontalScrollBar() ) ) - { - - return scrollArea; - - } else if( widget->parentWidget()->inherits( "KTextEditor::View" ) ) { + // force registration of widget + if( widget && widget->window() ) + { _shadowHelper->registerWidget( widget->window(), true ); } - return widget->parentWidget(); + const auto& palette( option->palette ); + const auto &background = palette.color( QPalette::ToolTipBase ); + const auto outline( KColorUtils::mix( palette.color( QPalette::ToolTipBase ), palette.color( QPalette::ToolTipText ), 0.25 ) ); + const bool hasAlpha( _helper->hasAlphaChannel( widget ) ); - } else return nullptr; + _helper->renderMenuFrame( painter, option->rect, background, outline, hasAlpha ); + return true; } - //______________________________________________________________________________ - QColor Style::scrollBarArrowColor( const QStyleOptionSlider* option, const SubControl& control, const QWidget* widget ) const + //___________________________________________________________________________________ + bool Style::drawShapedFrameControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { - const auto& rect( option->rect ); - const auto& palette( option->palette ); - auto color( _helper->arrowColor( palette, QPalette::WindowText ) ); - - bool widgetMouseOver( ( option->state & State_MouseOver ) ); - if( widget ) widgetMouseOver = widget->underMouse(); - #if QT_VERSION >= 0x050000 - // in case this QStyle is used by QQuickControls QStyle wrapper - else if( option->styleObject ) widgetMouseOver = option->styleObject->property("hover").toBool(); + // cast option and check + #if BREEZE_USE_KDE4 + const auto frameOpt = qstyleoption_cast( option ); + #else + const auto frameOpt = qstyleoption_cast( option ); #endif + if( !frameOpt ) return false; - // check enabled state - const bool enabled( option->state & State_Enabled ); - if( !enabled ) { - if( StyleConfigData::animationsEnabled() ) { - // finally, global opacity when ScrollBarShowOnMouseOver - const qreal globalOpacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); - if( globalOpacity >= 0 ) color.setAlphaF( globalOpacity ); - // no mouse over and no animation in progress, don't draw arrows at all - else if( !widgetMouseOver ) return Qt::transparent; - } - return color; - } - - if( - ( control == SC_ScrollBarSubLine && option->sliderValue == option->minimum ) || - ( control == SC_ScrollBarAddLine && option->sliderValue == option->maximum ) ) - { - - // manually disable arrow, to indicate that scrollbar is at limit - color = _helper->arrowColor( palette, QPalette::Disabled, QPalette::WindowText ); - if( StyleConfigData::animationsEnabled() ) { - // finally, global opacity when ScrollBarShowOnMouseOver - const qreal globalOpacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); - if( globalOpacity >= 0 ) color.setAlphaF( globalOpacity ); - // no mouse over and no animation in progress, don't draw arrows at all - else if( !widgetMouseOver ) return Qt::transparent; - } - return color; - } - - const bool mouseOver( _animations->scrollBarEngine().isHovered( widget, control ) ); - const bool animated( _animations->scrollBarEngine().isAnimated( widget, AnimationHover, control ) ); - const qreal opacity( _animations->scrollBarEngine().opacity( widget, control ) ); - - // retrieve mouse position from engine - QPoint position( mouseOver ? _animations->scrollBarEngine().position( widget ) : QPoint( -1, -1 ) ); - if( mouseOver && rect.contains( position ) ) - { - /* - * need to update the arrow controlRect on fly because there is no - * way to get it from the styles directly, outside of repaint events - */ - _animations->scrollBarEngine().setSubControlRect( widget, control, rect ); - } - - - if( rect.intersects( _animations->scrollBarEngine().subControlRect( widget, control ) ) ) + switch( frameOpt->frameShape ) { - auto highlight = _helper->hoverColor( palette ); - if( animated ) + case QFrame::Box: { - color = KColorUtils::mix( color, highlight, opacity ); - - } else if( mouseOver ) { - - color = highlight; - + if( option->state & State_Sunken ) return true; + else break; } - } - - if( StyleConfigData::animationsEnabled() ) { - // finally, global opacity when ScrollBarShowOnMouseOver - const qreal globalOpacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); - if( globalOpacity >= 0 ) color.setAlphaF( globalOpacity ); - // no mouse over and no animation in progress, don't draw arrows at all - else if( !widgetMouseOver ) return Qt::transparent; - } - - return color; - - } - - //____________________________________________________________________________________ - void Style::setTranslucentBackground( QWidget* widget ) const - { - widget->setAttribute( Qt::WA_TranslucentBackground ); - - #ifdef Q_WS_WIN - // FramelessWindowHint is needed on windows to make WA_TranslucentBackground work properly - widget->setWindowFlags( widget->windowFlags() | Qt::FramelessWindowHint ); - #endif - - } - - //____________________________________________________________________________________ - QStyleOptionToolButton Style::separatorMenuItemOption( const QStyleOptionMenuItem* menuItemOption, const QWidget* widget ) const - { - - // separator can have a title and an icon - // in that case they are rendered as sunken flat toolbuttons - QStyleOptionToolButton toolButtonOption; - toolButtonOption.initFrom( widget ); - toolButtonOption.rect = menuItemOption->rect; - toolButtonOption.features = QStyleOptionToolButton::None; - toolButtonOption.state = State_Enabled|State_AutoRaise; - toolButtonOption.subControls = SC_ToolButton; - toolButtonOption.icon = QIcon(); - toolButtonOption.iconSize = QSize(); - toolButtonOption.text = menuItemOption->text; - - toolButtonOption.toolButtonStyle = Qt::ToolButtonTextBesideIcon; - return toolButtonOption; - - } - - //____________________________________________________________________________________ - QIcon Style::toolBarExtensionIcon( StandardPixmap standardPixmap, const QStyleOption* option, const QWidget* widget ) const - { - - // store palette - // due to Qt, it is not always safe to assume that either option, nor widget are defined - QPalette palette; - if( option ) palette = option->palette; - else if( widget ) palette = widget->palette(); - else palette = QApplication::palette(); - - // convenience class to map color to icon mode - struct IconData - { - QColor _color; - QIcon::Mode _mode; - QIcon::State _state; - }; - - // map colors to icon states - const QList iconTypes = - { - { palette.color( QPalette::Active, QPalette::WindowText ), QIcon::Normal, QIcon::Off }, - { palette.color( QPalette::Active, QPalette::WindowText ), QIcon::Selected, QIcon::Off }, - { palette.color( QPalette::Active, QPalette::WindowText ), QIcon::Active, QIcon::Off }, - { palette.color( QPalette::Disabled, QPalette::WindowText ), QIcon::Disabled, QIcon::Off }, - - { palette.color( QPalette::Active, QPalette::HighlightedText ), QIcon::Normal, QIcon::On }, - { palette.color( QPalette::Active, QPalette::HighlightedText ), QIcon::Selected, QIcon::On }, - { palette.color( QPalette::Active, QPalette::WindowText ), QIcon::Active, QIcon::On }, - { palette.color( QPalette::Disabled, QPalette::WindowText ), QIcon::Disabled, QIcon::On } - }; - - // default icon sizes - static const QList iconSizes = { 8, 16, 22, 32, 48 }; - - // decide arrow orientation - const ArrowOrientation orientation( standardPixmap == SP_ToolBarHorizontalExtensionButton ? ArrowRight : ArrowDown ); - - // create icon and fill - QIcon icon; - foreach( const IconData& iconData, iconTypes ) - { - - foreach( const int& iconSize, iconSizes ) + case QFrame::HLine: + case QFrame::VLine: { - // create pixmap - QPixmap pixmap( iconSize, iconSize ); - pixmap.fill( Qt::transparent ); - - // render - QPainter painter( &pixmap ); - - // icon size - const int fixedIconSize( pixelMetric( QStyle::PM_SmallIconSize, option, widget ) ); - const QRect fixedRect( 0, 0, fixedIconSize, fixedIconSize ); - - painter.setWindow( fixedRect ); - painter.translate( standardPixmap == SP_ToolBarHorizontalExtensionButton ? QPoint( 1, 0 ) : QPoint( 0, 1 ) ); - _helper->renderArrow( &painter, fixedRect, iconData._color, orientation ); - painter.end(); - - // add to icon - icon.addPixmap( pixmap, iconData._mode, iconData._state ); - + const auto& rect( option->rect ); + const auto color( _helper->separatorColor( option->palette ) ); + const bool isVertical( frameOpt->frameShape == QFrame::VLine ); + _helper->renderSeparator( painter, rect, color, isVertical ); + return true; } - } - - return icon; - - } - - //____________________________________________________________________________________ - QIcon Style::titleBarButtonIcon( StandardPixmap standardPixmap, const QStyleOption* option, const QWidget* widget ) const - { - - // map standardPixmap to button type - ButtonType buttonType; - switch( standardPixmap ) - { - case SP_TitleBarNormalButton: buttonType = ButtonRestore; break; - case SP_TitleBarMinButton: buttonType = ButtonMinimize; break; - case SP_TitleBarMaxButton: buttonType = ButtonMaximize; break; - case SP_TitleBarCloseButton: - case SP_DockWidgetCloseButton: - buttonType = ButtonClose; - break; - - default: return QIcon(); - } - - // store palette - // due to Qt, it is not always safe to assume that either option, nor widget are defined - QPalette palette; - if( option ) palette = option->palette; - else if( widget ) palette = widget->palette(); - else palette = QApplication::palette(); - - const bool isCloseButton( buttonType == ButtonClose && StyleConfigData::outlineCloseButton() ); - - palette.setCurrentColorGroup( QPalette::Active ); - const auto base( palette.color( QPalette::WindowText ) ); - const auto selected( palette.color( QPalette::HighlightedText ) ); - const auto negative( buttonType == ButtonClose ? _helper->negativeText( palette ):base ); - const auto negativeSelected( buttonType == ButtonClose ? _helper->negativeText( palette ):selected ); - - const bool invertNormalState( isCloseButton ); - - // convenience class to map color to icon mode - struct IconData - { - QColor _color; - bool _inverted; - QIcon::Mode _mode; - QIcon::State _state; - }; - - // map colors to icon states - const QList iconTypes = - { - - // state off icons - { KColorUtils::mix( palette.color( QPalette::Window ), base, 0.5 ), invertNormalState, QIcon::Normal, QIcon::Off }, - { KColorUtils::mix( palette.color( QPalette::Window ), selected, 0.5 ), invertNormalState, QIcon::Selected, QIcon::Off }, - { KColorUtils::mix( palette.color( QPalette::Window ), negative, 0.5 ), true, QIcon::Active, QIcon::Off }, - { KColorUtils::mix( palette.color( QPalette::Window ), base, 0.2 ), invertNormalState, QIcon::Disabled, QIcon::Off }, - - // state on icons - { KColorUtils::mix( palette.color( QPalette::Window ), negative, 0.7 ), true, QIcon::Normal, QIcon::On }, - { KColorUtils::mix( palette.color( QPalette::Window ), negativeSelected, 0.7 ), true, QIcon::Selected, QIcon::On }, - { KColorUtils::mix( palette.color( QPalette::Window ), negative, 0.7 ), true, QIcon::Active, QIcon::On }, - { KColorUtils::mix( palette.color( QPalette::Window ), base, 0.2 ), invertNormalState, QIcon::Disabled, QIcon::On } - - }; - - // default icon sizes - static const QList iconSizes = { 8, 16, 22, 32, 48 }; - - // output icon - QIcon icon; - - foreach( const IconData& iconData, iconTypes ) - { - - foreach( const int& iconSize, iconSizes ) + case QFrame::StyledPanel: { - // create pixmap - QPixmap pixmap( iconSize, iconSize ); - pixmap.fill( Qt::transparent ); - // create painter and render - QPainter painter( &pixmap ); - _helper->renderDecorationButton( &painter, pixmap.rect(), iconData._color, buttonType, iconData._inverted ); + if( isQtQuickControl( option, widget ) ) + { - painter.end(); + // ComboBox popup frame + drawFrameMenuPrimitive( option, painter, widget ); + return true; - // store - icon.addPixmap( pixmap, iconData._mode, iconData._state ); + } else break; } + default: break; + } - return icon; + return false; } - //______________________________________________________________________________ - const QAbstractItemView* Style::itemViewParent( const QWidget* widget ) const + //___________________________________________________________________________________ + bool Style::drawRubberBandControl( const QStyleOption* option, QPainter* painter, const QWidget* ) const { - const QAbstractItemView* itemView( nullptr ); - - // check widget directly - if( ( itemView = qobject_cast( widget ) ) ) return itemView; + const auto& palette( option->palette ); + const auto rect( option->rect ); - // check widget grand-parent - else if( - widget && - widget->parentWidget() && - ( itemView = qobject_cast( widget->parentWidget()->parentWidget() ) ) && - itemView->viewport() == widget->parentWidget() ) - { return itemView; } + auto color = palette.color( QPalette::Highlight ); + painter->setPen( KColorUtils::mix( color, palette.color( QPalette::Active, QPalette::WindowText ) ) ); + color.setAlpha( 50 ); + painter->setBrush( color ); + painter->setClipRegion( rect ); + painter->drawRect( rect.adjusted( 0, 0, -1, -1 ) ); + return true; - // return null otherwise - else return nullptr; } - //____________________________________________________________________ - bool Style::isSelectedItem( const QWidget* widget, const QPoint& localPosition ) const + //____________________________________________________________________________________ + void Style::setTranslucentBackground( QWidget* widget ) const { + widget->setAttribute( Qt::WA_TranslucentBackground ); - // get relevant itemview parent and check - const QAbstractItemView* itemView( itemViewParent( widget ) ); - if( !( itemView && itemView->hasFocus() && itemView->selectionModel() ) ) return false; - - #if QT_VERSION >= 0x050000 - QPoint position = widget->mapTo( itemView, localPosition ); - #else - // qt4 misses a const for mapTo argument, although nothing is actually changed to the passed widget - QPoint position = widget->mapTo( const_cast( itemView ), localPosition ); + #ifdef Q_WS_WIN + // FramelessWindowHint is needed on windows to make WA_TranslucentBackground work properly + widget->setWindowFlags( widget->windowFlags() | Qt::FramelessWindowHint ); #endif - // get matching QModelIndex and check - const QModelIndex index( itemView->indexAt( position ) ); - if( !index.isValid() ) return false; - - // check whether index is selected - return itemView->selectionModel()->isSelected( index ); - } //____________________________________________________________________ @@ -7209,49 +1449,6 @@ #endif } - //____________________________________________________________________ - bool Style::showIconsInMenuItems() const - { - const KConfigGroup g(KSharedConfig::openConfig(), "KDE"); - return g.readEntry("ShowIconsInMenuItems", true); - } - - //____________________________________________________________________ - bool Style::showIconsOnPushButtons() const - { - const KConfigGroup g(KSharedConfig::openConfig(), "KDE"); - return g.readEntry("ShowIconsOnPushButtons", true); - } - - //____________________________________________________________________ - bool Style::isMenuTitle( const QWidget* widget ) const - { - - // check widget - if( !widget ) return false; - - // check property - const QVariant property( widget->property( PropertyNames::menuTitle ) ); - if( property.isValid() ) return property.toBool(); - - // detect menu toolbuttons - QWidget* parent = widget->parentWidget(); - if( qobject_cast( parent ) ) - { - foreach( auto child, parent->findChildren() ) - { - if( child->defaultWidget() != widget ) continue; - const_cast(widget)->setProperty( PropertyNames::menuTitle, true ); - return true; - } - - } - - const_cast(widget)->setProperty( PropertyNames::menuTitle, false ); - return false; - - } - //____________________________________________________________________ bool Style::hasAlteredBackground( const QWidget* widget ) const { diff --git a/kstyle/widgets/checkbox.cpp b/kstyle/widgets/checkbox.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/checkbox.cpp @@ -0,0 +1,255 @@ +#include "breezestyle.h" + +namespace Breeze +{ +//______________________________________________________________________________ +QColor Helper::checkBoxIndicatorColor(const QPalette &palette, bool mouseOver, bool active, qreal opacity, AnimationMode mode) const +{ + QColor color(KColorUtils::mix(palette.color(QPalette::Window), palette.color(QPalette::WindowText), 0.6)); + if (mode == AnimationHover) { + const QColor focus(focusColor(palette)); + const QColor hover(hoverColor(palette)); + if (active) + color = KColorUtils::mix(focus, hover, opacity); + else + color = KColorUtils::mix(color, hover, opacity); + + } else if (mouseOver) { + color = hoverColor(palette); + + } else if (active) { + color = focusColor(palette); + } + + return color; +} + +//______________________________________________________________________________ +void Helper::renderCheckBoxBackground(QPainter *painter, const QRect &rect, const QColor &color, bool sunken) const +{ + // setup painter + painter->setRenderHint(QPainter::Antialiasing, true); + + // copy rect and radius + QRectF frameRect(rect); + frameRect.adjust(3, 3, -3, -3); + + if (sunken) + frameRect.translate(1, 1); + + painter->setPen(Qt::NoPen); + painter->setBrush(color); + painter->drawRect(frameRect); +} + +//______________________________________________________________________________ +void Helper::renderCheckBox(QPainter *painter, const QRect &rect, const QColor &color, const QColor &shadow, bool sunken, CheckBoxState state, qreal animation) const +{ + // setup painter + painter->setRenderHint(QPainter::Antialiasing, true); + + // copy rect and radius + QRectF frameRect(rect); + frameRect.adjust(2, 2, -2, -2); + qreal radius(frameRadius()); + + // shadow + if (sunken) { + frameRect.translate(1, 1); + + } else { + painter->setPen(QPen(shadow, 1)); + painter->setBrush(Qt::NoBrush); + + const qreal shadowRadius(radius + 0.5); + painter->drawRoundedRect(shadowRect(frameRect).adjusted(-0.5, -0.5, 0.5, 0.5), shadowRadius, shadowRadius); + } + + // content + { + painter->setPen(QPen(color, 1)); + painter->setBrush(Qt::NoBrush); + + radius = qMax(radius - 1, qreal(0.0)); + const QRectF contentRect(frameRect.adjusted(0.5, 0.5, -0.5, -0.5)); + painter->drawRoundedRect(contentRect, radius, radius); + } + + // mark + if (state == CheckOn) { + painter->setBrush(color); + painter->setPen(Qt::NoPen); + + const QRectF markerRect(frameRect.adjusted(3, 3, -3, -3)); + painter->drawRect(markerRect); + + } else if (state == CheckPartial) { + QPen pen(color, 2); + pen.setJoinStyle(Qt::MiterJoin); + painter->setPen(pen); + + const QRectF markerRect(frameRect.adjusted(4, 4, -4, -4)); + painter->drawRect(markerRect); + + painter->setPen(Qt::NoPen); + painter->setBrush(color); + painter->setRenderHint(QPainter::Antialiasing, false); + + QPainterPath path; + path.moveTo(markerRect.topLeft()); + path.lineTo(markerRect.right() - 1, markerRect.top()); + path.lineTo(markerRect.left(), markerRect.bottom() - 1); + painter->drawPath(path); + + } else if (state == CheckAnimated) { + const QRectF markerRect(frameRect.adjusted(3, 3, -3, -3)); + QPainterPath path; + path.moveTo(markerRect.topRight()); + path.lineTo(markerRect.center() + animation * (markerRect.topLeft() - markerRect.center())); + path.lineTo(markerRect.bottomLeft()); + path.lineTo(markerRect.center() + animation * (markerRect.bottomRight() - markerRect.center())); + path.closeSubpath(); + + painter->setBrush(color); + painter->setPen(Qt::NoPen); + painter->drawPath(path); + } +} + +//___________________________________________________________________________________________________________________ +QRect Style::checkBoxContentsRect(const QStyleOption *option, const QWidget *) const +{ + return visualRect(option, option->rect.adjusted(Metrics::CheckBox_Size + Metrics::CheckBox_ItemSpacing, 0, 0, 0)); +} + +//______________________________________________________________ +QSize Style::checkBoxSizeFromContents(const QStyleOption *, const QSize &contentsSize, const QWidget *) const +{ + // get contents size + QSize size(contentsSize); + + // add focus height + size = expandSize(size, 0, Metrics::CheckBox_FocusMarginWidth); + + // make sure there is enough height for indicator + size.setHeight(qMax(size.height(), int(Metrics::CheckBox_Size))); + + // Add space for the indicator and the icon + size.rwidth() += Metrics::CheckBox_Size + Metrics::CheckBox_ItemSpacing; + + // also add extra space, to leave room to the right of the label + size.rwidth() += Metrics::CheckBox_ItemSpacing; + + return size; +} + +//___________________________________________________________________________________ +bool Style::drawIndicatorCheckBoxPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // copy rect and palette + const auto &rect(option->rect); + const auto &palette(option->palette); + + // store flags + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool mouseOver(enabled && (state & State_MouseOver)); + const bool sunken(enabled && (state & State_Sunken)); + const bool active((state & (State_On | State_NoChange))); + + // checkbox state + CheckBoxState checkBoxState(CheckOff); + if (state & State_NoChange) + checkBoxState = CheckPartial; + else if (state & State_On) + checkBoxState = CheckOn; + + // detect checkboxes in lists + const bool isSelectedItem(this->isSelectedItem(widget, rect.center())); + + // animation state + _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver); + _animations->widgetStateEngine().updateState(widget, AnimationPressed, checkBoxState != CheckOff); + if (_animations->widgetStateEngine().isAnimated(widget, AnimationPressed)) + checkBoxState = CheckAnimated; + const qreal animation(_animations->widgetStateEngine().opacity(widget, AnimationPressed)); + + QColor color; + if (isSelectedItem) { + color = _helper->checkBoxIndicatorColor(palette, false, enabled && active); + _helper->renderCheckBoxBackground(painter, rect, palette.color(QPalette::Base), sunken); + + } else { + const AnimationMode mode(_animations->widgetStateEngine().isAnimated(widget, AnimationHover) ? AnimationHover : AnimationNone); + const qreal opacity(_animations->widgetStateEngine().opacity(widget, AnimationHover)); + color = _helper->checkBoxIndicatorColor(palette, mouseOver, enabled && active, opacity, mode); + } + + // render + const auto shadow(_helper->shadowColor(palette)); + _helper->renderCheckBox(painter, rect, color, shadow, sunken, checkBoxState, animation); + return true; +} + +//___________________________________________________________________________________ +bool Style::drawCheckBoxLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto buttonOption(qstyleoption_cast(option)); + if (!buttonOption) + return true; + + // copy palette and rect + const auto &palette(option->palette); + const auto &rect(option->rect); + + // store state + const State &state(option->state); + const bool enabled(state & State_Enabled); + + // text alignment + const bool reverseLayout(option->direction == Qt::RightToLeft); + const int textFlags(_mnemonics->textFlags() | Qt::AlignVCenter | (reverseLayout ? Qt::AlignRight : Qt::AlignLeft)); + + // text rect + auto textRect(rect); + + // render icon + if (!buttonOption->icon.isNull()) { + const QIcon::Mode mode(enabled ? QIcon::Normal : QIcon::Disabled); + const QPixmap pixmap(buttonOption->icon.pixmap(buttonOption->iconSize, mode)); + drawItemPixmap(painter, rect, textFlags, pixmap); + + // adjust rect (copied from QCommonStyle) + textRect.setLeft(textRect.left() + buttonOption->iconSize.width() + 4); + textRect = visualRect(option, textRect); + } + + // render text + if (!buttonOption->text.isEmpty()) { + textRect = option->fontMetrics.boundingRect(textRect, textFlags, buttonOption->text); + drawItemText(painter, textRect, textFlags, palette, enabled, buttonOption->text, QPalette::WindowText); + + // check focus state + const bool hasFocus(enabled && (state & State_HasFocus)); + + // update animation state + _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus); + const bool isFocusAnimated(_animations->widgetStateEngine().isAnimated(widget, AnimationFocus)); + const qreal opacity(_animations->widgetStateEngine().opacity(widget, AnimationFocus)); + + // focus color + QColor focusColor; + if (isFocusAnimated) + focusColor = _helper->alphaColor(_helper->focusColor(palette), opacity); + else if (hasFocus) + focusColor = _helper->focusColor(palette); + + // render focus + _helper->renderFocusLine(painter, textRect, focusColor); + } + + return true; +} + +} diff --git a/kstyle/widgets/combobox.cpp b/kstyle/widgets/combobox.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/combobox.cpp @@ -0,0 +1,329 @@ +#include "combobox_p.h" + +#include + +#if BREEZE_HAVE_QTQUICK +#include +#endif + +namespace BreezePrivate +{ +} + +namespace Breeze +{ +//_________________________________________________________ +bool Style::eventFilterComboBoxContainer(QWidget *widget, QEvent *event) +{ + if (event->type() == QEvent::Paint) { + QPainter painter(widget); + auto paintEvent = static_cast(event); + painter.setClipRegion(paintEvent->region()); + + const auto rect(widget->rect()); + const auto &palette(widget->palette()); + const auto background(_helper->frameBackgroundColor(palette)); + const auto outline(_helper->frameOutlineColor(palette)); + + const bool hasAlpha(_helper->hasAlphaChannel(widget)); + if (hasAlpha) { + painter.setCompositionMode(QPainter::CompositionMode_Source); + _helper->renderMenuFrame(&painter, rect, background, outline, true); + + } else { + _helper->renderMenuFrame(&painter, rect, background, outline, false); + } + } + + return false; +} + +//___________________________________________________________________________________________________________________ +QRect Style::comboBoxSubControlRect(const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const +{ + // cast option and check + const auto comboBoxOption(qstyleoption_cast(option)); + if (!comboBoxOption) + return ParentStyleClass::subControlRect(CC_ComboBox, option, subControl, widget); + + const bool editable(comboBoxOption->editable); + const bool flat(editable && !comboBoxOption->frame); + + // copy rect + auto rect(option->rect); + + switch (subControl) { + case SC_ComboBoxFrame: + return flat ? rect : QRect(); + case SC_ComboBoxListBoxPopup: + return rect; + + case SC_ComboBoxArrow: { + // take out frame width + if (!flat) + rect = insideMargin(rect, Metrics::Frame_FrameWidth); + + QRect arrowRect(rect.right() - Metrics::MenuButton_IndicatorWidth + 1, rect.top(), Metrics::MenuButton_IndicatorWidth, rect.height()); + + arrowRect = centerRect(arrowRect, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth); + return visualRect(option, arrowRect); + } + + case SC_ComboBoxEditField: { + QRect labelRect; + const int frameWidth(pixelMetric(PM_ComboBoxFrameWidth, option, widget)); + labelRect = QRect(rect.left(), rect.top(), rect.width() - Metrics::MenuButton_IndicatorWidth, rect.height()); + + // remove margins + if (!flat && rect.height() >= option->fontMetrics.height() + 2 * frameWidth) { + labelRect.adjust(frameWidth, frameWidth, 0, -frameWidth); + } + + return visualRect(option, labelRect); + } + + default: + break; + } + + return ParentStyleClass::subControlRect(CC_ComboBox, option, subControl, widget); +} + +//______________________________________________________________ +QSize Style::comboBoxSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + // cast option and check + const auto comboBoxOption(qstyleoption_cast(option)); + if (!comboBoxOption) + return contentsSize; + + // copy size + QSize size(contentsSize); + + // add relevant margin + const bool flat(!comboBoxOption->frame); + const int frameWidth(pixelMetric(PM_ComboBoxFrameWidth, option, widget)); + if (!flat) + size = expandSize(size, frameWidth); + + // make sure there is enough height for the button + size.setHeight(qMax(size.height(), int(Metrics::MenuButton_IndicatorWidth))); + + // add button width and spacing + size.rwidth() += Metrics::MenuButton_IndicatorWidth + 2; + + return size; +} + +//___________________________________________________________________________________ +bool Style::drawComboBoxLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + const auto comboBoxOption(qstyleoption_cast(option)); + if (!comboBoxOption) + return false; + if (comboBoxOption->editable) + return false; + + // need to alter palette for focused buttons + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool sunken(state & (State_On | State_Sunken)); + const bool mouseOver(enabled && (option->state & State_MouseOver)); + const bool hasFocus(enabled && !mouseOver && (option->state & State_HasFocus)); + const bool flat(!comboBoxOption->frame); + + QPalette::ColorRole textRole; + if (flat) { + if (hasFocus && sunken) + textRole = QPalette::HighlightedText; + else + textRole = QPalette::WindowText; + + } else if (hasFocus) + textRole = QPalette::HighlightedText; + else + textRole = QPalette::ButtonText; + + // change pen color directly + painter->setPen(QPen(option->palette.color(textRole), 1)); + + // translate painter for pressed down comboboxes + if (sunken && !flat) { + painter->translate(1, 1); + } + +#if QT_VERSION >= 0x050000 + if (const auto cb = qstyleoption_cast(option)) { + auto editRect = proxy()->subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget); + painter->save(); + painter->setClipRect(editRect); + if (!cb->currentIcon.isNull()) { + QIcon::Mode mode; + + if ((cb->state & QStyle::State_Selected) && (cb->state & QStyle::State_Active)) { + mode = QIcon::Selected; + } else if (cb->state & QStyle::State_Enabled) { + mode = QIcon::Normal; + } else { + mode = QIcon::Disabled; + } + + QWindow *window = nullptr; + if (widget && widget->window()) { + window = widget->window()->windowHandle(); +#if BREEZE_HAVE_QTQUICK + } else if (QQuickItem *quickItem = qobject_cast(option->styleObject)) { + window = quickItem->window(); +#endif + } + + const auto pixmap = cb->currentIcon.pixmap(window, cb->iconSize, mode); + auto iconRect(editRect); + iconRect.setWidth(cb->iconSize.width() + 4); + iconRect = alignedRect(cb->direction, Qt::AlignLeft | Qt::AlignVCenter, iconRect.size(), editRect); + if (cb->editable) + painter->fillRect(iconRect, option->palette.brush(QPalette::Base)); + proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); + + if (cb->direction == Qt::RightToLeft) + editRect.translate(-4 - cb->iconSize.width(), 0); + else + editRect.translate(cb->iconSize.width() + 4, 0); + } + if (!cb->currentText.isEmpty() && !cb->editable) { + proxy()->drawItemText(painter, editRect.adjusted(1, 0, -1, 0), visualAlignment(cb->direction, Qt::AlignLeft | Qt::AlignVCenter), cb->palette, cb->state & State_Enabled, cb->currentText); + } + painter->restore(); + } +#else + // call base class method + ParentStyleClass::drawControl(CE_ComboBoxLabel, option, painter, widget); +#endif + + return true; +} + +//______________________________________________________________ +bool Style::drawComboBoxComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto comboBoxOption(qstyleoption_cast(option)); + if (!comboBoxOption) + return true; + + // rect and palette + const auto &rect(option->rect); + const auto &palette(option->palette); + + // state + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool mouseOver(enabled && (state & State_MouseOver)); + const bool hasFocus(enabled && (state & (State_HasFocus | State_Sunken))); + const bool editable(comboBoxOption->editable); + const bool sunken(state & (State_On | State_Sunken)); + bool flat(!comboBoxOption->frame); + + // frame + if (option->subControls & SC_ComboBoxFrame) { + if (editable) { + flat |= (rect.height() <= 2 * Metrics::Frame_FrameWidth + Metrics::MenuButton_IndicatorWidth); + if (flat) { + const auto &background = palette.color(QPalette::Base); + + painter->setBrush(background); + painter->setPen(Qt::NoPen); + painter->drawRect(rect); + + } else { + drawPrimitive(PE_FrameLineEdit, option, painter, widget); + } + + } else { + // update animation state + // hover takes precedence over focus + _animations->inputWidgetEngine().updateState(widget, AnimationHover, mouseOver); + _animations->inputWidgetEngine().updateState(widget, AnimationFocus, hasFocus && !mouseOver); + const AnimationMode mode(_animations->inputWidgetEngine().buttonAnimationMode(widget)); + const qreal opacity(_animations->inputWidgetEngine().buttonOpacity(widget)); + + if (flat) { + // define colors and render + const auto color(_helper->toolButtonColor(palette, mouseOver, hasFocus, sunken, opacity, mode)); + _helper->renderToolButtonFrame(painter, rect, color, sunken); + + } else { + // define colors + const auto shadow(_helper->shadowColor(palette)); + const auto outline(_helper->buttonOutlineColor(palette, mouseOver, hasFocus, opacity, mode)); + const auto background(_helper->buttonBackgroundColor(palette, mouseOver, hasFocus, false, opacity, mode)); + + // render + _helper->renderButtonFrame(painter, rect, background, outline, shadow, hasFocus, sunken); + } + } + } + + // arrow + if (option->subControls & SC_ComboBoxArrow) { + // detect empty comboboxes + const auto comboBox = qobject_cast(widget); + const bool empty(comboBox && !comboBox->count()); + + // arrow color + QColor arrowColor; + if (editable) { + if (empty || !enabled) + arrowColor = palette.color(QPalette::Disabled, QPalette::Text); + else { + // check animation state + const bool subControlHover(enabled && mouseOver && comboBoxOption->activeSubControls & SC_ComboBoxArrow); + _animations->comboBoxEngine().updateState(widget, AnimationHover, subControlHover); + + const bool animated(enabled && _animations->comboBoxEngine().isAnimated(widget, AnimationHover)); + const qreal opacity(_animations->comboBoxEngine().opacity(widget, AnimationHover)); + + // color + const auto normal(_helper->arrowColor(palette, QPalette::WindowText)); + const auto hover(_helper->hoverColor(palette)); + + if (animated) { + arrowColor = KColorUtils::mix(normal, hover, opacity); + + } else if (subControlHover) { + arrowColor = hover; + + } else + arrowColor = normal; + } + + } else if (flat) { + if (empty || !enabled) + arrowColor = _helper->arrowColor(palette, QPalette::Disabled, QPalette::WindowText); + else if (hasFocus && !mouseOver && sunken) + arrowColor = palette.color(QPalette::HighlightedText); + else + arrowColor = _helper->arrowColor(palette, QPalette::WindowText); + + } else if (empty || !enabled) + arrowColor = _helper->arrowColor(palette, QPalette::Disabled, QPalette::ButtonText); + else if (hasFocus && !mouseOver) + arrowColor = palette.color(QPalette::HighlightedText); + else + arrowColor = _helper->arrowColor(palette, QPalette::ButtonText); + + // arrow rect + auto arrowRect(subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget)); + + // translate for non editable, non flat, sunken comboboxes + if (sunken && !flat && !editable) + arrowRect.translate(1, 1); + + // render + _helper->renderArrow(painter, arrowRect, arrowColor, ArrowDown); + } + + return true; +} + +} diff --git a/kstyle/widgets/combobox_p.h b/kstyle/widgets/combobox_p.h new file mode 100644 --- /dev/null +++ b/kstyle/widgets/combobox_p.h @@ -0,0 +1,55 @@ +#ifndef COMBOBOX_P_H_INCLUDED +#define COMBOBOX_P_H_INCLUDED + +#include "breezestyle.h" + +#include + +namespace BreezePrivate +{ +//* needed to have spacing added to items in combobox +class ComboBoxItemDelegate : public QItemDelegate +{ +public: + //* constructor + explicit ComboBoxItemDelegate(QAbstractItemView *parent) + : QItemDelegate(parent) + , _proxy(parent->itemDelegate()) + , _itemMargin(Breeze::Metrics::ItemView_ItemMarginWidth) + { + } + + //* paint + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override + { + // call either proxy or parent class + if (_proxy) + _proxy.data()->paint(painter, option, index); + else + QItemDelegate::paint(painter, option, index); + } + + //* size hint for index + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override + { + // get size from either proxy or parent class + auto size(_proxy ? _proxy.data()->sizeHint(option, index) : QItemDelegate::sizeHint(option, index)); + + // adjust and return + if (size.isValid()) { + size.rheight() += _itemMargin * 2; + } + return size; + } + +private: + //* proxy + Breeze::WeakPointer _proxy; + + //* margin + int _itemMargin; +}; + +} + +#endif // COMBOBOX_P_H_INCLUDED diff --git a/kstyle/widgets/dial.cpp b/kstyle/widgets/dial.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/dial.cpp @@ -0,0 +1,196 @@ +#include "breezestyle.h" + +namespace Breeze +{ +//______________________________________________________________________________ +void Helper::renderDialGroove(QPainter *painter, const QRect &rect, const QColor &color, qreal first, qreal last) const +{ + // setup painter + painter->setRenderHint(QPainter::Antialiasing, true); + + const QRectF baseRect(rect); + + // content + if (color.isValid()) { + const qreal penWidth(Metrics::Slider_GrooveThickness); + const QRectF grooveRect(rect.adjusted(penWidth / 2, penWidth / 2, -penWidth / 2, -penWidth / 2)); + + // setup angles + const int angleStart(first * 180 * 16 / M_PI); + const int angleSpan((last - first) * 180 * 16 / M_PI); + + // setup pen + if (angleSpan != 0) { + QPen pen(color, penWidth); + pen.setCapStyle(Qt::RoundCap); + painter->setPen(pen); + painter->setBrush(Qt::NoBrush); + painter->drawArc(grooveRect, angleStart, angleSpan); + } + } +} + +//______________________________________________________________________________ +void Helper::renderDialContents(QPainter *painter, const QRect &rect, const QColor &color, qreal first, qreal second) const +{ + // setup painter + painter->setRenderHint(QPainter::Antialiasing, true); + + const QRectF baseRect(rect); + + // content + if (color.isValid()) { + // setup groove rect + const qreal penWidth(Metrics::Slider_GrooveThickness); + const QRectF grooveRect(rect.adjusted(penWidth / 2, penWidth / 2, -penWidth / 2, -penWidth / 2)); + + // setup angles + const int angleStart(first * 180 * 16 / M_PI); + const int angleSpan((second - first) * 180 * 16 / M_PI); + + // setup pen + if (angleSpan != 0) { + QPen pen(color, penWidth); + pen.setCapStyle(Qt::RoundCap); + painter->setPen(pen); + painter->setBrush(Qt::NoBrush); + painter->drawArc(grooveRect, angleStart, angleSpan); + } + } +} + +//___________________________________________________________________________________________________________________ +QRect Style::dialSubControlRect(const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const +{ + // cast option and check + const auto sliderOption(qstyleoption_cast(option)); + if (!sliderOption) + return ParentStyleClass::subControlRect(CC_Dial, option, subControl, widget); + + // adjust rect to be square, and centered + auto rect(option->rect); + const int dimension(qMin(rect.width(), rect.height())); + rect = centerRect(rect, dimension, dimension); + + switch (subControl) { + case QStyle::SC_DialGroove: + return insideMargin(rect, (Metrics::Slider_ControlThickness - Metrics::Slider_GrooveThickness) / 2); + case QStyle::SC_DialHandle: { + // calculate angle at which handle needs to be drawn + const qreal angle(dialAngle(sliderOption, sliderOption->sliderPosition)); + + // groove rect + const QRectF grooveRect(insideMargin(rect, Metrics::Slider_ControlThickness / 2)); + qreal radius(grooveRect.width() / 2); + + // slider center + QPointF center(grooveRect.center() + QPointF(radius * std::cos(angle), -radius * std::sin(angle))); + + // slider rect + QRect handleRect(0, 0, Metrics::Slider_ControlThickness, Metrics::Slider_ControlThickness); + handleRect.moveCenter(center.toPoint()); + return handleRect; + } + + default: + return ParentStyleClass::subControlRect(CC_Dial, option, subControl, widget); + ; + } +} + +//______________________________________________________________ +bool Style::drawDialComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto sliderOption(qstyleoption_cast(option)); + if (!sliderOption) + return true; + + const auto &palette(option->palette); + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool mouseOver(enabled && (state & State_MouseOver)); + const bool hasFocus(enabled && (state & State_HasFocus)); + + // do not render tickmarks + if (sliderOption->subControls & SC_DialTickmarks) { + } + + // groove + if (sliderOption->subControls & SC_DialGroove) { + // groove rect + auto grooveRect(subControlRect(CC_Dial, sliderOption, SC_SliderGroove, widget)); + + // groove + const auto grooveColor(KColorUtils::mix(palette.color(QPalette::Window), palette.color(QPalette::WindowText), 0.3)); + + // angles + const qreal first(dialAngle(sliderOption, sliderOption->minimum)); + const qreal last(dialAngle(sliderOption, sliderOption->maximum)); + + // render groove + _helper->renderDialGroove(painter, grooveRect, grooveColor, first, last); + + if (enabled) { + // highlight + const auto &highlight = palette.color(QPalette::Highlight); + + // angles + const qreal second(dialAngle(sliderOption, sliderOption->sliderPosition)); + + // render contents + _helper->renderDialContents(painter, grooveRect, highlight, first, second); + } + } + + // handle + if (sliderOption->subControls & SC_DialHandle) { + // get handle rect + auto handleRect(subControlRect(CC_Dial, sliderOption, SC_DialHandle, widget)); + handleRect = centerRect(handleRect, Metrics::Slider_ControlThickness, Metrics::Slider_ControlThickness); + + // handle state + const bool handleActive(mouseOver && handleRect.contains(_animations->dialEngine().position(widget))); + const bool sunken(state & (State_On | State_Sunken)); + + // animation state + _animations->dialEngine().setHandleRect(widget, handleRect); + _animations->dialEngine().updateState(widget, AnimationHover, handleActive && mouseOver); + _animations->dialEngine().updateState(widget, AnimationFocus, hasFocus); + const auto mode(_animations->dialEngine().buttonAnimationMode(widget)); + const qreal opacity(_animations->dialEngine().buttonOpacity(widget)); + + // define colors + const auto &background = palette.color(QPalette::Button); + const auto outline(_helper->sliderOutlineColor(palette, handleActive && mouseOver, hasFocus, opacity, mode)); + const auto shadow(_helper->shadowColor(palette)); + + // render + _helper->renderSliderHandle(painter, handleRect, background, outline, shadow, sunken); + } + + return true; +} + +//______________________________________________________________________________ +qreal Style::dialAngle(const QStyleOptionSlider *sliderOption, int value) const +{ + // calculate angle at which handle needs to be drawn + qreal angle(0); + if (sliderOption->maximum == sliderOption->minimum) + angle = M_PI / 2; + else { + qreal fraction(qreal(value - sliderOption->minimum) / qreal(sliderOption->maximum - sliderOption->minimum)); + if (!sliderOption->upsideDown) + fraction = 1 - fraction; + + if (sliderOption->dialWrapping) + angle = 1.5 * M_PI - fraction * 2 * M_PI; + else + angle = (M_PI * 8 - fraction * 10 * M_PI) / 6; + } + + return angle; +} + +} diff --git a/kstyle/widgets/dockwidget.cpp b/kstyle/widgets/dockwidget.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/dockwidget.cpp @@ -0,0 +1,99 @@ +#include "breezestyle.h" + +namespace Breeze +{ +//____________________________________________________________________________ +bool Style::eventFilterDockWidget(QDockWidget *dockWidget, QEvent *event) +{ + if (event->type() == QEvent::Paint) { + // create painter and clip + QPainter painter(dockWidget); + QPaintEvent *paintEvent = static_cast(event); + painter.setClipRegion(paintEvent->region()); + + // store palette and set colors + const auto &palette(dockWidget->palette()); + const auto background(_helper->frameBackgroundColor(palette)); + const auto outline(_helper->frameOutlineColor(palette)); + + // store rect + const auto rect(dockWidget->rect()); + + // render + if (dockWidget->isFloating()) { + _helper->renderMenuFrame(&painter, rect, background, outline, false); + + } else if (StyleConfigData::dockWidgetDrawFrame() || (dockWidget->features() & QDockWidget::AllDockWidgetFeatures)) { + _helper->renderFrame(&painter, rect, background, outline); + } + } + + return false; +} + +//___________________________________________________________________________________ +bool Style::drawDockWidgetTitleControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto dockWidgetOption = qstyleoption_cast(option); + if (!dockWidgetOption) + return true; + + const auto &palette(option->palette); + const auto &state(option->state); + const bool enabled(state & State_Enabled); + const bool reverseLayout(option->direction == Qt::RightToLeft); + + // cast to v2 to check vertical bar +#if BREEZE_USE_KDE4 + const auto v2 = qstyleoption_cast(option); + const bool verticalTitleBar(v2 ? v2->verticalTitleBar : false); +#else + const bool verticalTitleBar(dockWidgetOption->verticalTitleBar); +#endif + + const auto buttonRect(subElementRect(dockWidgetOption->floatable ? SE_DockWidgetFloatButton : SE_DockWidgetCloseButton, option, widget)); + + // get rectangle and adjust to properly accounts for buttons + auto rect(insideMargin(dockWidgetOption->rect, Metrics::Frame_FrameWidth)); + if (verticalTitleBar) { + if (buttonRect.isValid()) + rect.setTop(buttonRect.bottom() + 1); + + } else if (reverseLayout) { + if (buttonRect.isValid()) + rect.setLeft(buttonRect.right() + 1); + rect.adjust(0, 0, -4, 0); + + } else { + if (buttonRect.isValid()) + rect.setRight(buttonRect.left() - 1); + rect.adjust(4, 0, 0, 0); + } + + QString title(dockWidgetOption->title); + int titleWidth = dockWidgetOption->fontMetrics.size(_mnemonics->textFlags(), title).width(); + int width = verticalTitleBar ? rect.height() : rect.width(); + if (width < titleWidth) + title = dockWidgetOption->fontMetrics.elidedText(title, Qt::ElideRight, width, Qt::TextShowMnemonic); + + if (verticalTitleBar) { + QSize size = rect.size(); + size.transpose(); + rect.setSize(size); + + painter->save(); + painter->translate(rect.left(), rect.top() + rect.width()); + painter->rotate(-90); + painter->translate(-rect.left(), -rect.top()); + drawItemText(painter, rect, Qt::AlignLeft | Qt::AlignVCenter | _mnemonics->textFlags(), palette, enabled, title, QPalette::WindowText); + painter->restore(); + + } else { + drawItemText(painter, rect, Qt::AlignLeft | Qt::AlignVCenter | _mnemonics->textFlags(), palette, enabled, title, QPalette::WindowText); + } + + return true; +} + +} diff --git a/kstyle/widgets/groupbox.cpp b/kstyle/widgets/groupbox.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/groupbox.cpp @@ -0,0 +1,191 @@ +#include "breezestyle.h" + +namespace Breeze +{ +//______________________________________________________________ +QRect Style::groupBoxSubControlRect(const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const +{ + QRect rect = option->rect; + switch (subControl) { + case SC_GroupBoxFrame: + return rect; + + case SC_GroupBoxContents: { + // cast option and check + const auto groupBoxOption = qstyleoption_cast(option); + if (!groupBoxOption) + break; + + // take out frame width + rect = insideMargin(rect, Metrics::Frame_FrameWidth); + + // get state + const bool checkable(groupBoxOption->subControls & QStyle::SC_GroupBoxCheckBox); + const bool emptyText(groupBoxOption->text.isEmpty()); + + // calculate title height + int titleHeight(0); + if (!emptyText) + titleHeight = groupBoxOption->fontMetrics.height(); + if (checkable) + titleHeight = qMax(titleHeight, int(Metrics::CheckBox_Size)); + + // add margin + if (titleHeight > 0) + titleHeight += 2 * Metrics::GroupBox_TitleMarginWidth; + + rect.adjust(0, titleHeight, 0, 0); + return rect; + } + + case SC_GroupBoxCheckBox: + case SC_GroupBoxLabel: { + // cast option and check + const auto groupBoxOption = qstyleoption_cast(option); + if (!groupBoxOption) + break; + + // take out frame width + rect = insideMargin(rect, Metrics::Frame_FrameWidth); + + const bool emptyText(groupBoxOption->text.isEmpty()); + const bool checkable(groupBoxOption->subControls & QStyle::SC_GroupBoxCheckBox); + + // calculate title height + int titleHeight(0); + int titleWidth(0); + if (!emptyText) { + const QFontMetrics fontMetrics = option->fontMetrics; + titleHeight = qMax(titleHeight, fontMetrics.height()); + titleWidth += fontMetrics.size(_mnemonics->textFlags(), groupBoxOption->text).width(); + } + + if (checkable) { + titleHeight = qMax(titleHeight, int(Metrics::CheckBox_Size)); + titleWidth += Metrics::CheckBox_Size; + if (!emptyText) + titleWidth += Metrics::CheckBox_ItemSpacing; + } + + // adjust height + auto titleRect(rect); + titleRect.setHeight(titleHeight); + titleRect.translate(0, Metrics::GroupBox_TitleMarginWidth); + + // center + titleRect = centerRect(titleRect, titleWidth, titleHeight); + + if (subControl == SC_GroupBoxCheckBox) { + // vertical centering + titleRect = centerRect(titleRect, titleWidth, Metrics::CheckBox_Size); + + // horizontal positioning + const QRect subRect(titleRect.topLeft(), QSize(Metrics::CheckBox_Size, titleRect.height())); + return visualRect(option->direction, titleRect, subRect); + + } else { + // vertical centering + QFontMetrics fontMetrics = option->fontMetrics; + titleRect = centerRect(titleRect, titleWidth, fontMetrics.height()); + + // horizontal positioning + auto subRect(titleRect); + if (checkable) + subRect.adjust(Metrics::CheckBox_Size + Metrics::CheckBox_ItemSpacing, 0, 0, 0); + return visualRect(option->direction, titleRect, subRect); + } + } + + default: + break; + } + + return ParentStyleClass::subControlRect(CC_GroupBox, option, subControl, widget); +} + +//______________________________________________________________ +bool Style::drawFrameGroupBoxPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *) const +{ + // cast option and check + const auto frameOption(qstyleoption_cast(option)); + if (!frameOption) + return true; + + // no frame for flat groupboxes +#if BREEZE_USE_KDE4 + QStyleOptionFrameV2 frameOption2(*frameOption); + if (frameOption2.features & QStyleOptionFrameV2::Flat) + return true; +#else + if (frameOption->features & QStyleOptionFrame::Flat) + return true; +#endif + + // normal frame + const auto &palette(option->palette); + const auto background(_helper->frameBackgroundColor(palette)); + const auto outline(_helper->frameOutlineColor(palette)); + + /* + * need to reset painter's clip region in order to paint behind textbox label + * (was taken out in QCommonStyle) + */ + + painter->setClipRegion(option->rect); + _helper->renderFrame(painter, option->rect, background, outline); + + return true; +} + +//______________________________________________________________ +bool Style::drawGroupBoxComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + // base class method + ParentStyleClass::drawComplexControl(CC_GroupBox, option, painter, widget); + + // cast option and check + const auto groupBoxOption = qstyleoption_cast(option); + if (!groupBoxOption) + return true; + + // do nothing if either label is not selected or groupbox is empty + if (!(option->subControls & QStyle::SC_GroupBoxLabel) || groupBoxOption->text.isEmpty()) { + return true; + } + + // store palette and rect + const auto &palette(option->palette); + + // check focus state + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool hasFocus(enabled && (option->state & State_HasFocus)); + if (!hasFocus) + return true; + + // alignment + const int textFlags(groupBoxOption->textAlignment | _mnemonics->textFlags()); + + // update animation state + _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus); + const bool isFocusAnimated(_animations->widgetStateEngine().isAnimated(widget, AnimationFocus)); + const qreal opacity(_animations->widgetStateEngine().opacity(widget, AnimationFocus)); + + // get relevant rect + auto textRect = subControlRect(CC_GroupBox, option, SC_GroupBoxLabel, widget); + textRect = option->fontMetrics.boundingRect(textRect, textFlags, groupBoxOption->text); + + // focus color + QColor focusColor; + if (isFocusAnimated) + focusColor = _helper->alphaColor(_helper->focusColor(palette), opacity); + else if (hasFocus) + focusColor = _helper->focusColor(palette); + + // render focus + _helper->renderFocusLine(painter, textRect, focusColor); + + return true; +} + +} diff --git a/kstyle/widgets/header.cpp b/kstyle/widgets/header.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/header.cpp @@ -0,0 +1,232 @@ +#include "breezestyle.h" + +namespace Breeze +{ +//___________________________________________________________________________________________________________________ +QRect Style::headerArrowRect(const QStyleOption *option, const QWidget *) const +{ + // cast option and check + const auto headerOption(qstyleoption_cast(option)); + if (!headerOption) + return option->rect; + + // check if arrow is necessary + if (headerOption->sortIndicator == QStyleOptionHeader::None) + return QRect(); + + auto arrowRect(insideMargin(option->rect, Metrics::Header_MarginWidth)); + arrowRect.setLeft(arrowRect.right() - Metrics::Header_ArrowSize + 1); + + return visualRect(option, arrowRect); +} + +//___________________________________________________________________________________________________________________ +QRect Style::headerLabelRect(const QStyleOption *option, const QWidget *) const +{ + // cast option and check + const auto headerOption(qstyleoption_cast(option)); + if (!headerOption) + return option->rect; + + // check if arrow is necessary + auto labelRect(insideMargin(option->rect, Metrics::Header_MarginWidth, 0)); + if (headerOption->sortIndicator == QStyleOptionHeader::None) + return labelRect; + + labelRect.adjust(0, 0, -Metrics::Header_ArrowSize - Metrics::Header_ItemSpacing, 0); + return visualRect(option, labelRect); +} + +//______________________________________________________________ +QSize Style::headerSectionSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *) const +{ + // cast option and check + const auto headerOption(qstyleoption_cast(option)); + if (!headerOption) + return contentsSize; + + // get text size + const bool horizontal(headerOption->orientation == Qt::Horizontal); + const bool hasText(!headerOption->text.isEmpty()); + const bool hasIcon(!headerOption->icon.isNull()); + + const QSize textSize(hasText ? headerOption->fontMetrics.size(0, headerOption->text) : QSize()); + const QSize iconSize(hasIcon ? QSize(22, 22) : QSize()); + + // contents width + int contentsWidth(0); + if (hasText) + contentsWidth += textSize.width(); + if (hasIcon) { + contentsWidth += iconSize.width(); + if (hasText) + contentsWidth += Metrics::Header_ItemSpacing; + } + + // contents height + int contentsHeight(headerOption->fontMetrics.height()); + if (hasIcon) + contentsHeight = qMax(contentsHeight, iconSize.height()); + + if (horizontal && headerOption->sortIndicator != QStyleOptionHeader::None) { + // also add space for sort indicator + contentsWidth += Metrics::Header_ArrowSize + Metrics::Header_ItemSpacing; + contentsHeight = qMax(contentsHeight, int(Metrics::Header_ArrowSize)); + } + + // update contents size, add margins and return + const QSize size(contentsSize.expandedTo(QSize(contentsWidth, contentsHeight))); + return expandSize(size, Metrics::Header_MarginWidth); +} + +//___________________________________________________________________________________ +bool Style::drawIndicatorHeaderArrowPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *) const +{ + const auto headerOption(qstyleoption_cast(option)); + const State &state(option->state); + + // arrow orientation + ArrowOrientation orientation(ArrowNone); + if (state & State_UpArrow || (headerOption && headerOption->sortIndicator == QStyleOptionHeader::SortUp)) + orientation = ArrowUp; + else if (state & State_DownArrow || (headerOption && headerOption->sortIndicator == QStyleOptionHeader::SortDown)) + orientation = ArrowDown; + if (orientation == ArrowNone) + return true; + + // invert arrows if requested by (hidden) options + if (StyleConfigData::viewInvertSortIndicator()) + orientation = (orientation == ArrowUp) ? ArrowDown : ArrowUp; + + // state, rect and palette + const auto &rect(option->rect); + const auto &palette(option->palette); + + // define color and polygon for drawing arrow + const auto color = _helper->arrowColor(palette, QPalette::ButtonText); + + // render + _helper->renderArrow(painter, rect, color, orientation); + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawHeaderSectionControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + const auto &rect(option->rect); + const auto &palette(option->palette); + const auto &state(option->state); + const bool enabled(state & State_Enabled); + const bool mouseOver(enabled && (state & State_MouseOver)); + const bool sunken(enabled && (state & (State_On | State_Sunken))); + + const auto headerOption(qstyleoption_cast(option)); + if (!headerOption) + return true; + + const bool horizontal(headerOption->orientation == Qt::Horizontal); + const bool isFirst(horizontal && (headerOption->position == QStyleOptionHeader::Beginning)); + const bool isCorner(widget && widget->inherits("QTableCornerButton")); + const bool reverseLayout(option->direction == Qt::RightToLeft); + + // update animation state + _animations->headerViewEngine().updateState(widget, rect.topLeft(), mouseOver); + const bool animated(enabled && _animations->headerViewEngine().isAnimated(widget, rect.topLeft())); + const qreal opacity(_animations->headerViewEngine().opacity(widget, rect.topLeft())); + + // fill + const auto &normal = palette.color(QPalette::Button); + const auto focus(KColorUtils::mix(normal, _helper->focusColor(palette), 0.2)); + const auto hover(KColorUtils::mix(normal, _helper->hoverColor(palette), 0.2)); + + QColor color; + if (sunken) + color = focus; + else if (animated) + color = KColorUtils::mix(normal, hover, opacity); + else if (mouseOver) + color = hover; + else + color = normal; + + painter->setRenderHint(QPainter::Antialiasing, false); + painter->setBrush(color); + painter->setPen(Qt::NoPen); + painter->drawRect(rect); + + // outline + painter->setBrush(Qt::NoBrush); + painter->setPen(_helper->alphaColor(palette.color(QPalette::WindowText), 0.1)); + + if (isCorner) { + if (reverseLayout) + painter->drawPoint(rect.bottomLeft()); + else + painter->drawPoint(rect.bottomRight()); + + } else if (horizontal) { + painter->drawLine(rect.bottomLeft(), rect.bottomRight()); + + } else { + if (reverseLayout) + painter->drawLine(rect.topLeft(), rect.bottomLeft()); + else + painter->drawLine(rect.topRight(), rect.bottomRight()); + } + + // separators + painter->setPen(_helper->alphaColor(palette.color(QPalette::WindowText), 0.2)); + + if (horizontal) { + if (headerOption->section != 0 || isFirst) { + if (reverseLayout) + painter->drawLine(rect.topLeft(), rect.bottomLeft() - QPoint(0, 1)); + else + painter->drawLine(rect.topRight(), rect.bottomRight() - QPoint(0, 1)); + } + + } else { + if (reverseLayout) + painter->drawLine(rect.bottomLeft() + QPoint(1, 0), rect.bottomRight()); + else + painter->drawLine(rect.bottomLeft(), rect.bottomRight() - QPoint(1, 0)); + } + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawHeaderEmptyAreaControl(const QStyleOption *option, QPainter *painter, const QWidget *) const +{ + // use the same background as in drawHeaderPrimitive + const auto &rect(option->rect); + auto palette(option->palette); + + const bool horizontal(option->state & QStyle::State_Horizontal); + const bool reverseLayout(option->direction == Qt::RightToLeft); + + // fill + painter->setRenderHint(QPainter::Antialiasing, false); + painter->setBrush(palette.color(QPalette::Button)); + painter->setPen(Qt::NoPen); + painter->drawRect(rect); + + // outline + painter->setBrush(Qt::NoBrush); + painter->setPen(_helper->alphaColor(palette.color(QPalette::ButtonText), 0.1)); + + if (horizontal) { + painter->drawLine(rect.bottomLeft(), rect.bottomRight()); + + } else { + if (reverseLayout) + painter->drawLine(rect.topLeft(), rect.bottomLeft()); + else + painter->drawLine(rect.topRight(), rect.bottomRight()); + } + + return true; +} + +} diff --git a/kstyle/widgets/itemview.cpp b/kstyle/widgets/itemview.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/itemview.cpp @@ -0,0 +1,266 @@ +#include "breezestyle.h" + +namespace Breeze +{ +//______________________________________________________________________________ +void Helper::renderSelection(QPainter *painter, const QRect &rect, const QColor &color) const +{ + painter->setRenderHint(QPainter::Antialiasing); + painter->setPen(Qt::NoPen); + painter->setBrush(color); + painter->drawRect(rect); +} + +//______________________________________________________________________________ +void Helper::renderSidePanelFrame(QPainter *painter, const QRect &rect, const QColor &outline, Side side) const +{ + // check color + if (!outline.isValid()) + return; + + // adjust rect + QRectF frameRect(rect); + frameRect.adjust(0.5, 0.5, -0.5, -0.5); + + // setup painter + painter->setRenderHint(QPainter::Antialiasing); + painter->setPen(outline); + + // render + switch (side) { + default: + case SideLeft: + painter->drawLine(frameRect.topRight(), frameRect.bottomRight()); + break; + + case SideTop: + painter->drawLine(frameRect.topLeft(), frameRect.topRight()); + break; + + case SideRight: + painter->drawLine(frameRect.topLeft(), frameRect.bottomLeft()); + break; + + case SideBottom: + painter->drawLine(frameRect.bottomLeft(), frameRect.bottomRight()); + break; + + case AllSides: { + const qreal radius(frameRadius(-1.0)); + painter->drawRoundedRect(frameRect, radius, radius); + break; + } + } +} + +//______________________________________________________________ +QSize Style::itemViewItemSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + // call base class + const QSize size(ParentStyleClass::sizeFromContents(CT_ItemViewItem, option, contentsSize, widget)); + return expandSize(size, Metrics::ItemView_ItemMarginWidth); +} + +//___________________________________________________________________________________ +bool Style::drawPanelItemViewItemPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check +#if BREEZE_USE_KDE4 + const auto viewItemOption = qstyleoption_cast(option); +#else + const auto viewItemOption = qstyleoption_cast(option); +#endif + if (!viewItemOption) + return false; + + // try cast widget + const auto abstractItemView = qobject_cast(widget); + + // store palette and rect + const auto &palette(option->palette); + auto rect(option->rect); + + // store flags + const State &state(option->state); + const bool mouseOver((state & State_MouseOver) && (!abstractItemView || abstractItemView->selectionMode() != QAbstractItemView::NoSelection)); + const bool selected(state & State_Selected); + const bool enabled(state & State_Enabled); + const bool active(state & State_Active); + + const bool hasCustomBackground = viewItemOption->backgroundBrush.style() != Qt::NoBrush && !(state & State_Selected); + const bool hasSolidBackground = !hasCustomBackground || viewItemOption->backgroundBrush.style() == Qt::SolidPattern; +#if BREEZE_USE_KDE4 + const bool hasAlternateBackground(viewItemOption->features & QStyleOptionViewItemV2::Alternate); +#else + const bool hasAlternateBackground(viewItemOption->features & QStyleOptionViewItem::Alternate); +#endif + + // do nothing if no background is to be rendered + if (!(mouseOver || selected || hasCustomBackground || hasAlternateBackground)) { + return true; + } + + // define color group + QPalette::ColorGroup colorGroup; + if (enabled) + colorGroup = active ? QPalette::Active : QPalette::Inactive; + else + colorGroup = QPalette::Disabled; + + // render alternate background + if (hasAlternateBackground) { + painter->setPen(Qt::NoPen); + painter->setBrush(palette.brush(colorGroup, QPalette::AlternateBase)); + painter->drawRect(rect); + } + + // stop here if no highlight is needed + if (!(mouseOver || selected || hasCustomBackground)) { + return true; + } + + // render custom background + if (hasCustomBackground && !hasSolidBackground) { + painter->setBrushOrigin(viewItemOption->rect.topLeft()); + painter->setBrush(viewItemOption->backgroundBrush); + painter->setPen(Qt::NoPen); + painter->drawRect(viewItemOption->rect); + return true; + } + + // render selection + // define color + QColor color; + if (hasCustomBackground && hasSolidBackground) + color = viewItemOption->backgroundBrush.color(); + else + color = palette.color(colorGroup, QPalette::Highlight); + + // change color to implement mouse over + if (mouseOver && !hasCustomBackground) { + if (!selected) + color.setAlphaF(0.2); + else + color = color.lighter(110); + } + + // render + _helper->renderSelection(painter, rect, color); + + return true; +} + +//______________________________________________________________________________ +const QAbstractItemView *Style::itemViewParent(const QWidget *widget) const +{ + const QAbstractItemView *itemView(nullptr); + + // check widget directly + if ((itemView = qobject_cast(widget))) + return itemView; + + // check widget grand-parent + else if (widget && widget->parentWidget() && (itemView = qobject_cast(widget->parentWidget()->parentWidget())) && itemView->viewport() == widget->parentWidget()) { + return itemView; + } + + // return null otherwise + else + return nullptr; +} + +//____________________________________________________________________ +bool Style::isSelectedItem(const QWidget *widget, const QPoint &localPosition) const +{ + // get relevant itemview parent and check + const QAbstractItemView *itemView(itemViewParent(widget)); + if (!(itemView && itemView->hasFocus() && itemView->selectionModel())) + return false; + +#if QT_VERSION >= 0x050000 + QPoint position = widget->mapTo(itemView, localPosition); +#else + // qt4 misses a const for mapTo argument, although nothing is actually changed to the passed widget + QPoint position = widget->mapTo(const_cast(itemView), localPosition); +#endif + + // get matching QModelIndex and check + const QModelIndex index(itemView->indexAt(position)); + if (!index.isValid()) + return false; + + // check whether index is selected + return itemView->selectionModel()->isSelected(index); +} + +//___________________________________________________________________________________ +bool Style::drawIndicatorBranchPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *) const +{ + // copy rect and palette + const auto &rect(option->rect); + const auto &palette(option->palette); + + // state + const State &state(option->state); + const bool reverseLayout(option->direction == Qt::RightToLeft); + + // draw expander + int expanderAdjust = 0; + if (state & State_Children) { + // state + const bool expanderOpen(state & State_Open); + const bool enabled(state & State_Enabled); + const bool mouseOver(enabled && (state & State_MouseOver)); + + // expander rect + int expanderSize = qMin(rect.width(), rect.height()); + expanderSize = qMin(expanderSize, int(Metrics::ItemView_ArrowSize)); + expanderAdjust = expanderSize / 2 + 1; + const auto arrowRect = centerRect(rect, expanderSize, expanderSize); + + // get orientation from option + ArrowOrientation orientation; + if (expanderOpen) + orientation = ArrowDown; + else if (reverseLayout) + orientation = ArrowLeft; + else + orientation = ArrowRight; + + // color + const auto arrowColor(mouseOver ? _helper->hoverColor(palette) : _helper->arrowColor(palette, QPalette::Text)); + + // render + _helper->renderArrow(painter, arrowRect, arrowColor, orientation); + } + + // tree branches + if (!StyleConfigData::viewDrawTreeBranchLines()) + return true; + + const auto center(rect.center()); + const auto lineColor(KColorUtils::mix(palette.color(QPalette::Base), palette.color(QPalette::Text), 0.25)); + painter->setRenderHint(QPainter::Antialiasing, true); + painter->translate(0.5, 0.5); + painter->setPen(QPen(lineColor, 1)); + if (state & (State_Item | State_Children | State_Sibling)) { + const QLineF line(QPointF(center.x(), rect.top()), QPointF(center.x(), center.y() - expanderAdjust - 1)); + painter->drawLine(line); + } + + // The right/left (depending on direction) line gets drawn if we have an item + if (state & State_Item) { + const QLineF line = reverseLayout ? QLineF(QPointF(rect.left(), center.y()), QPointF(center.x() - expanderAdjust, center.y())) : QLineF(QPointF(center.x() + expanderAdjust, center.y()), QPointF(rect.right(), center.y())); + painter->drawLine(line); + } + + // The bottom if we have a sibling + if (state & State_Sibling) { + const QLineF line(QPointF(center.x(), center.y() + expanderAdjust), QPointF(center.x(), rect.bottom())); + painter->drawLine(line); + } + + return true; +} + +} diff --git a/kstyle/widgets/linedit.cpp b/kstyle/widgets/linedit.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/linedit.cpp @@ -0,0 +1,82 @@ +#include "breezestyle.h" + +namespace Breeze +{ +//___________________________________________________________________________________________________________________ +QRect Style::lineEditContentsRect(const QStyleOption *option, const QWidget *widget) const +{ + // cast option and check + const auto frameOption(qstyleoption_cast(option)); + if (!frameOption) + return option->rect; + + // check flatness + const bool flat(frameOption->lineWidth == 0); + if (flat) + return option->rect; + + // copy rect and take out margins + auto rect(option->rect); + + // take out margins if there is enough room + const int frameWidth(pixelMetric(PM_DefaultFrameWidth, option, widget)); + if (rect.height() >= option->fontMetrics.height() + 2 * frameWidth) + return insideMargin(rect, frameWidth); + else + return rect; +} + +//______________________________________________________________ +QSize Style::lineEditSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + // cast option and check + const auto frameOption(qstyleoption_cast(option)); + if (!frameOption) + return contentsSize; + + const bool flat(frameOption->lineWidth == 0); + const int frameWidth(pixelMetric(PM_DefaultFrameWidth, option, widget)); + return flat ? contentsSize : expandSize(contentsSize, frameWidth); +} + +//______________________________________________________________ +bool Style::drawFrameLineEditPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // copy palette and rect + const auto &palette(option->palette); + const auto &rect(option->rect); + + // make sure there is enough room to render frame + if (rect.height() < 2 * Metrics::LineEdit_FrameWidth + option->fontMetrics.height()) { + const auto &background = palette.color(QPalette::Base); + + painter->setPen(Qt::NoPen); + painter->setBrush(background); + painter->drawRect(rect); + return true; + + } else { + // copy state + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool mouseOver(enabled && (state & State_MouseOver)); + const bool hasFocus(enabled && (state & State_HasFocus)); + + // focus takes precedence over mouse over + _animations->inputWidgetEngine().updateState(widget, AnimationFocus, hasFocus); + _animations->inputWidgetEngine().updateState(widget, AnimationHover, mouseOver && !hasFocus); + + // retrieve animation mode and opacity + const AnimationMode mode(_animations->inputWidgetEngine().frameAnimationMode(widget)); + const qreal opacity(_animations->inputWidgetEngine().frameOpacity(widget)); + + // render + const auto &background = palette.color(QPalette::Base); + const auto outline(_helper->frameOutlineColor(palette, mouseOver, hasFocus, opacity, mode)); + _helper->renderFrame(painter, rect, background, outline); + } + + return true; +} + +} diff --git a/kstyle/widgets/mdi.cpp b/kstyle/widgets/mdi.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/mdi.cpp @@ -0,0 +1,308 @@ +#include "breezestyle.h" + +namespace Breeze +{ +//______________________________________________________________________________ +void Helper::renderDecorationButton(QPainter *painter, const QRect &rect, const QColor &color, ButtonType buttonType, bool inverted) const +{ + painter->save(); + painter->setViewport(rect); + painter->setWindow(0, 0, 18, 18); + painter->setRenderHints(QPainter::Antialiasing); + + // initialize pen + QPen pen; + pen.setCapStyle(Qt::RoundCap); + pen.setJoinStyle(Qt::MiterJoin); + + if (inverted) { + // render circle + painter->setPen(Qt::NoPen); + painter->setBrush(color); + painter->drawEllipse(QRectF(0, 0, 18, 18)); + + // take out the inner part + painter->setCompositionMode(QPainter::CompositionMode_DestinationOut); + painter->setBrush(Qt::NoBrush); + pen.setColor(Qt::black); + + } else { + painter->setBrush(Qt::NoBrush); + pen.setColor(color); + } + + pen.setCapStyle(Qt::RoundCap); + pen.setJoinStyle(Qt::MiterJoin); + pen.setWidthF(1.1 * qMax(1.0, 18.0 / rect.width())); + painter->setPen(pen); + + switch (buttonType) { + case ButtonClose: { + painter->drawLine(QPointF(5, 5), QPointF(13, 13)); + painter->drawLine(13, 5, 5, 13); + break; + } + + case ButtonMaximize: { + painter->drawPolyline(QVector {QPointF(4, 11), QPointF(9, 6), QPointF(14, 11)}); + break; + } + + case ButtonMinimize: { + painter->drawPolyline(QVector {QPointF(4, 7), QPointF(9, 12), QPointF(14, 7)}); + break; + } + + case ButtonRestore: { + pen.setJoinStyle(Qt::RoundJoin); + painter->setPen(pen); + painter->drawPolygon(QVector {QPointF(4.5, 9), QPointF(9, 4.5), QPointF(13.5, 9), QPointF(9, 13.5)}); + break; + } + + default: + break; + } + + painter->restore(); +} + +//____________________________________________________________________________ +bool Style::eventFilterMdiSubWindow(QMdiSubWindow *subWindow, QEvent *event) +{ + if (event->type() == QEvent::Paint) { + QPainter painter(subWindow); + QPaintEvent *paintEvent(static_cast(event)); + painter.setClipRegion(paintEvent->region()); + + const auto rect(subWindow->rect()); + const auto background(subWindow->palette().color(QPalette::Window)); + + if (subWindow->isMaximized()) { + // full painting + painter.setPen(Qt::NoPen); + painter.setBrush(background); + painter.drawRect(rect); + + } else { + // framed painting + _helper->renderMenuFrame(&painter, rect, background, QColor()); + } + } + + // continue with normal painting + return false; +} + +//______________________________________________________________ +bool Style::drawTitleBarComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto titleBarOption(qstyleoption_cast(option)); + if (!titleBarOption) + return true; + + // store palette and rect + auto palette(option->palette); + const auto &rect(option->rect); + + const State &flags(option->state); + const bool enabled(flags & State_Enabled); + const bool active(enabled && (titleBarOption->titleBarState & Qt::WindowActive)); + + if (titleBarOption->subControls & SC_TitleBarLabel) { + // render background + painter->setClipRect(rect); + const auto outline(active ? QColor() : _helper->frameOutlineColor(palette, false, false)); + const auto background(_helper->titleBarColor(active)); + _helper->renderTabWidgetFrame(painter, rect.adjusted(-1, -1, 1, 3), background, outline, CornersTop); + + const bool useSeparator(active && _helper->titleBarColor(active) != palette.color(QPalette::Window) && !(titleBarOption->titleBarState & Qt::WindowMinimized)); + + if (useSeparator) { + painter->setRenderHint(QPainter::Antialiasing, false); + painter->setBrush(Qt::NoBrush); + painter->setPen(palette.color(QPalette::Highlight)); + painter->drawLine(rect.bottomLeft(), rect.bottomRight()); + } + + // render text + palette.setColor(QPalette::WindowText, _helper->titleBarTextColor(active)); + const auto textRect(subControlRect(CC_TitleBar, option, SC_TitleBarLabel, widget)); + ParentStyleClass::drawItemText(painter, textRect, Qt::AlignCenter, palette, active, titleBarOption->text, QPalette::WindowText); + } + + // buttons + static const QList subControls = {SC_TitleBarMinButton, SC_TitleBarMaxButton, SC_TitleBarCloseButton, SC_TitleBarNormalButton, SC_TitleBarSysMenu}; + + // loop over supported buttons + foreach (const SubControl &subControl, subControls) { + // skip if not requested + if (!(titleBarOption->subControls & subControl)) + continue; + + // find matching icon + QIcon icon; + switch (subControl) { + case SC_TitleBarMinButton: + icon = standardIcon(SP_TitleBarMinButton, option, widget); + break; + case SC_TitleBarMaxButton: + icon = standardIcon(SP_TitleBarMaxButton, option, widget); + break; + case SC_TitleBarCloseButton: + icon = standardIcon(SP_TitleBarCloseButton, option, widget); + break; + case SC_TitleBarNormalButton: + icon = standardIcon(SP_TitleBarNormalButton, option, widget); + break; + case SC_TitleBarSysMenu: + icon = titleBarOption->icon; + break; + default: + break; + } + + // check icon + if (icon.isNull()) + continue; + + // define icon rect + auto iconRect(subControlRect(CC_TitleBar, option, subControl, widget)); + if (iconRect.isEmpty()) + continue; + + // active state + const bool subControlActive(titleBarOption->activeSubControls & subControl); + + // mouse over state + const bool mouseOver(!subControlActive && widget && iconRect.translated(widget->mapToGlobal(QPoint(0, 0))).contains(QCursor::pos())); + + // adjust iconRect + const int iconWidth(pixelMetric(PM_SmallIconSize, option, widget)); + const QSize iconSize(iconWidth, iconWidth); + iconRect = centerRect(iconRect, iconSize); + + // set icon mode and state + QIcon::Mode iconMode; + QIcon::State iconState; + + if (!enabled) { + iconMode = QIcon::Disabled; + iconState = QIcon::Off; + + } else { + if (mouseOver) + iconMode = QIcon::Active; + else if (active) + iconMode = QIcon::Selected; + else + iconMode = QIcon::Normal; + + iconState = subControlActive ? QIcon::On : QIcon::Off; + } + + // get pixmap and render + const QPixmap pixmap = icon.pixmap(iconSize, iconMode, iconState); + painter->drawPixmap(iconRect, pixmap); + } + + return true; +} + +//____________________________________________________________________________________ +QIcon Style::titleBarButtonIcon(StandardPixmap standardPixmap, const QStyleOption *option, const QWidget *widget) const +{ + // map standardPixmap to button type + ButtonType buttonType; + switch (standardPixmap) { + case SP_TitleBarNormalButton: + buttonType = ButtonRestore; + break; + case SP_TitleBarMinButton: + buttonType = ButtonMinimize; + break; + case SP_TitleBarMaxButton: + buttonType = ButtonMaximize; + break; + case SP_TitleBarCloseButton: + case SP_DockWidgetCloseButton: + buttonType = ButtonClose; + break; + + default: + return QIcon(); + } + + // store palette + // due to Qt, it is not always safe to assume that either option, nor widget are defined + QPalette palette; + if (option) + palette = option->palette; + else if (widget) + palette = widget->palette(); + else + palette = QApplication::palette(); + + const bool isCloseButton(buttonType == ButtonClose && StyleConfigData::outlineCloseButton()); + + palette.setCurrentColorGroup(QPalette::Active); + const auto base(palette.color(QPalette::WindowText)); + const auto selected(palette.color(QPalette::HighlightedText)); + const auto negative(buttonType == ButtonClose ? _helper->negativeText(palette) : base); + const auto negativeSelected(buttonType == ButtonClose ? _helper->negativeText(palette) : selected); + + const bool invertNormalState(isCloseButton); + + // convenience class to map color to icon mode + struct IconData { + QColor _color; + bool _inverted; + QIcon::Mode _mode; + QIcon::State _state; + }; + + // map colors to icon states + const QList iconTypes = { + + // state off icons + {KColorUtils::mix(palette.color(QPalette::Window), base, 0.5), invertNormalState, QIcon::Normal, QIcon::Off}, + {KColorUtils::mix(palette.color(QPalette::Window), selected, 0.5), invertNormalState, QIcon::Selected, QIcon::Off}, + {KColorUtils::mix(palette.color(QPalette::Window), negative, 0.5), true, QIcon::Active, QIcon::Off}, + {KColorUtils::mix(palette.color(QPalette::Window), base, 0.2), invertNormalState, QIcon::Disabled, QIcon::Off}, + + // state on icons + {KColorUtils::mix(palette.color(QPalette::Window), negative, 0.7), true, QIcon::Normal, QIcon::On}, + {KColorUtils::mix(palette.color(QPalette::Window), negativeSelected, 0.7), true, QIcon::Selected, QIcon::On}, + {KColorUtils::mix(palette.color(QPalette::Window), negative, 0.7), true, QIcon::Active, QIcon::On}, + {KColorUtils::mix(palette.color(QPalette::Window), base, 0.2), invertNormalState, QIcon::Disabled, QIcon::On} + + }; + + // default icon sizes + static const QList iconSizes = {8, 16, 22, 32, 48}; + + // output icon + QIcon icon; + + foreach (const IconData &iconData, iconTypes) { + foreach (const int &iconSize, iconSizes) { + // create pixmap + QPixmap pixmap(iconSize, iconSize); + pixmap.fill(Qt::transparent); + + // create painter and render + QPainter painter(&pixmap); + _helper->renderDecorationButton(&painter, pixmap.rect(), iconData._color, buttonType, iconData._inverted); + + painter.end(); + + // store + icon.addPixmap(pixmap, iconData._mode, iconData._state); + } + } + + return icon; +} + +} diff --git a/kstyle/widgets/menu.cpp b/kstyle/widgets/menu.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/menu.cpp @@ -0,0 +1,458 @@ +#include "breezestyle.h" + +#include +#include +#include + +namespace Breeze +{ +//______________________________________________________________________________ +void Helper::renderMenuFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, bool roundCorners) const +{ + // set brush + if (color.isValid()) + painter->setBrush(color); + else + painter->setBrush(Qt::NoBrush); + + if (roundCorners) { + painter->setRenderHint(QPainter::Antialiasing); + QRectF frameRect(rect); + qreal radius(frameRadius()); + + // set pen + if (outline.isValid()) { + painter->setPen(outline); + frameRect.adjust(0.5, 0.5, -0.5, -0.5); + radius = qMax(radius - 1, qreal(0.0)); + + } else + painter->setPen(Qt::NoPen); + + // render + painter->drawRoundedRect(frameRect, radius, radius); + + } else { + painter->setRenderHint(QPainter::Antialiasing, false); + QRect frameRect(rect); + if (outline.isValid()) { + painter->setPen(outline); + frameRect.adjust(0, 0, -1, -1); + + } else + painter->setPen(Qt::NoPen); + + painter->drawRect(frameRect); + } +} + +//______________________________________________________________ +QSize Style::menuItemSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + // cast option and check + const auto menuItemOption = qstyleoption_cast(option); + if (!menuItemOption) + return contentsSize; + + /* + * First calculate the intrinsic size of the item. + * this must be kept consistent with what's in drawMenuItemControl + */ + QSize size(contentsSize); + switch (menuItemOption->menuItemType) { + case QStyleOptionMenuItem::Normal: + case QStyleOptionMenuItem::DefaultItem: + case QStyleOptionMenuItem::SubMenu: { + int iconWidth = 0; + if (showIconsInMenuItems()) + iconWidth = isQtQuickControl(option, widget) ? qMax(pixelMetric(PM_SmallIconSize, option, widget), menuItemOption->maxIconWidth) : menuItemOption->maxIconWidth; + + int leftColumnWidth = 0; + + // add icon width + if (iconWidth > 0) { + leftColumnWidth += iconWidth + Metrics::MenuItem_ItemSpacing; + } + + // add checkbox indicator width + if (menuItemOption->menuHasCheckableItems) { + leftColumnWidth += Metrics::CheckBox_Size + Metrics::MenuItem_ItemSpacing; + } + + // add spacing for accelerator + /* + * Note: + * The width of the accelerator itself is not included here since + * Qt will add that on separately after obtaining the + * sizeFromContents() for each menu item in the menu to be shown + * ( see QMenuPrivate::calcActionRects() ) + */ + const bool hasAccelerator(menuItemOption->text.indexOf(QLatin1Char('\t')) >= 0); + if (hasAccelerator) + size.rwidth() += Metrics::MenuItem_AcceleratorSpace; + + // right column + const int rightColumnWidth = Metrics::MenuButton_IndicatorWidth + Metrics::MenuItem_ItemSpacing; + size.rwidth() += leftColumnWidth + rightColumnWidth; + + // make sure height is large enough for icon and arrow + size.setHeight(qMax(size.height(), int(Metrics::MenuButton_IndicatorWidth))); + size.setHeight(qMax(size.height(), int(Metrics::CheckBox_Size))); + size.setHeight(qMax(size.height(), iconWidth)); + return expandSize(size, Metrics::MenuItem_MarginWidth, Metrics::MenuItem_MarginHeight); + } + + case QStyleOptionMenuItem::Separator: { + if (menuItemOption->text.isEmpty() && menuItemOption->icon.isNull()) { + return expandSize(QSize(0, 1), Metrics::MenuItem_MarginWidth, Metrics::MenuItem_MarginHeight); + + } else { + // build toolbutton option + const QStyleOptionToolButton toolButtonOption(separatorMenuItemOption(menuItemOption, widget)); + + // make sure height is large enough for icon and text + const int iconWidth(menuItemOption->maxIconWidth); + const int textHeight(menuItemOption->fontMetrics.height()); + if (!menuItemOption->icon.isNull()) + size.setHeight(qMax(size.height(), iconWidth)); + if (!menuItemOption->text.isEmpty()) { + size.setHeight(qMax(size.height(), textHeight)); + size.setWidth(qMax(size.width(), menuItemOption->fontMetrics.boundingRect(menuItemOption->text).width())); + } + + return sizeFromContents(CT_ToolButton, &toolButtonOption, size, widget); + } + } + + // for all other cases, return input + default: + return contentsSize; + } +} + +//___________________________________________________________________________________ +bool Style::drawFrameMenuPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // only draw frame for (expanded) toolbars and QtQuick controls + // do nothing for other cases, for which frame is rendered via drawPanelMenuPrimitive + if (qobject_cast(widget)) { + const auto &palette(option->palette); + const auto background(_helper->frameBackgroundColor(palette)); + const auto outline(_helper->frameOutlineColor(palette)); + + const bool hasAlpha(_helper->hasAlphaChannel(widget)); + _helper->renderMenuFrame(painter, option->rect, background, outline, hasAlpha); + + } else if (isQtQuickControl(option, widget)) { + const auto &palette(option->palette); + const auto background(_helper->frameBackgroundColor(palette)); + const auto outline(_helper->frameOutlineColor(palette)); + + const bool hasAlpha(_helper->hasAlphaChannel(widget)); + _helper->renderMenuFrame(painter, option->rect, background, outline, hasAlpha); + } + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawPanelMenuPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + /* + * do nothing if menu is embedded in another widget + * this corresponds to having a transparent background + */ + if (widget && !widget->isWindow()) + return true; + + const auto &palette(option->palette); + const auto outline(_helper->frameOutlineColor(palette)); + const bool hasAlpha(_helper->hasAlphaChannel(widget)); + auto background(_helper->frameBackgroundColor(palette)); + +#if !BREEZE_USE_KDE4 + if (hasAlpha) { + background.setAlphaF(StyleConfigData::menuOpacity() / 100.0); + } +#endif + + _helper->renderMenuFrame(painter, option->rect, background, outline, hasAlpha); + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawMenuItemControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto menuItemOption = qstyleoption_cast(option); + if (!menuItemOption) + return true; + if (menuItemOption->menuItemType == QStyleOptionMenuItem::EmptyArea) + return true; + + // copy rect and palette + const auto &rect(option->rect); + const auto &palette(option->palette); + + // deal with separators + if (menuItemOption->menuItemType == QStyleOptionMenuItem::Separator) { + // normal separator + if (menuItemOption->text.isEmpty() && menuItemOption->icon.isNull()) { + const auto color(_helper->separatorColor(palette)); + _helper->renderSeparator(painter, rect, color); + return true; + + } else { + /* + * separator can have a title and an icon + * in that case they are rendered as menu title buttons + */ + QStyleOptionToolButton copy(separatorMenuItemOption(menuItemOption, widget)); + renderMenuTitle(©, painter, widget); + + return true; + } + } + + // store state + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool selected(enabled && (state & State_Selected)); + const bool sunken(enabled && (state & (State_On | State_Sunken))); + const bool reverseLayout(option->direction == Qt::RightToLeft); + const bool useStrongFocus(StyleConfigData::menuItemDrawStrongFocus()); + + // render hover and focus + if (useStrongFocus && (selected || sunken)) { + const auto color = _helper->focusColor(palette); + const auto outlineColor = _helper->focusOutlineColor(palette); + + Sides sides = nullptr; + if (!menuItemOption->menuRect.isNull()) { + if (rect.top() <= menuItemOption->menuRect.top()) + sides |= SideTop; + if (rect.bottom() >= menuItemOption->menuRect.bottom()) + sides |= SideBottom; + if (rect.left() <= menuItemOption->menuRect.left()) + sides |= SideLeft; + if (rect.right() >= menuItemOption->menuRect.right()) + sides |= SideRight; + } + + _helper->renderFocusRect(painter, rect, color, outlineColor, sides); + } + + // get rect available for contents + auto contentsRect(insideMargin(rect, Metrics::MenuItem_MarginWidth, Metrics::MenuItem_MarginHeight)); + + // define relevant rectangles + // checkbox + QRect checkBoxRect; + if (menuItemOption->menuHasCheckableItems) { + checkBoxRect = QRect(contentsRect.left(), contentsRect.top() + (contentsRect.height() - Metrics::CheckBox_Size) / 2, Metrics::CheckBox_Size, Metrics::CheckBox_Size); + contentsRect.setLeft(checkBoxRect.right() + Metrics::MenuItem_ItemSpacing + 1); + } + + // render checkbox indicator + if (menuItemOption->checkType == QStyleOptionMenuItem::NonExclusive) { + checkBoxRect = visualRect(option, checkBoxRect); + + // checkbox state + + if (useStrongFocus && (selected || sunken)) { + _helper->renderCheckBoxBackground(painter, checkBoxRect, palette.color(QPalette::Window), sunken); + } + + CheckBoxState state(menuItemOption->checked ? CheckOn : CheckOff); + const bool active(menuItemOption->checked); + const auto shadow(_helper->shadowColor(palette)); + const auto color(_helper->checkBoxIndicatorColor(palette, false, enabled && active)); + _helper->renderCheckBox(painter, checkBoxRect, color, shadow, sunken, state); + + } else if (menuItemOption->checkType == QStyleOptionMenuItem::Exclusive) { + checkBoxRect = visualRect(option, checkBoxRect); + + if (useStrongFocus && (selected || sunken)) { + _helper->renderRadioButtonBackground(painter, checkBoxRect, palette.color(QPalette::Window), sunken); + } + + const bool active(menuItemOption->checked); + const auto shadow(_helper->shadowColor(palette)); + const auto color(_helper->checkBoxIndicatorColor(palette, false, enabled && active)); + _helper->renderRadioButton(painter, checkBoxRect, color, shadow, sunken, active ? RadioOn : RadioOff); + } + + // icon + int iconWidth = 0; + const bool showIcon(showIconsInMenuItems()); + if (showIcon) + iconWidth = isQtQuickControl(option, widget) ? qMax(pixelMetric(PM_SmallIconSize, option, widget), menuItemOption->maxIconWidth) : menuItemOption->maxIconWidth; + + QRect iconRect; + if (showIcon && iconWidth > 0) { + iconRect = QRect(contentsRect.left(), contentsRect.top() + (contentsRect.height() - iconWidth) / 2, iconWidth, iconWidth); + contentsRect.setLeft(iconRect.right() + Metrics::MenuItem_ItemSpacing + 1); + const QSize iconSize(pixelMetric(PM_SmallIconSize, option, widget), pixelMetric(PM_SmallIconSize, option, widget)); + iconRect = centerRect(iconRect, iconSize); + } + + if (showIcon && !menuItemOption->icon.isNull()) { + iconRect = visualRect(option, iconRect); + + // icon mode + QIcon::Mode mode; + if (selected && !useStrongFocus) + mode = QIcon::Active; + else if (selected) + mode = QIcon::Selected; + else if (enabled) + mode = QIcon::Normal; + else + mode = QIcon::Disabled; + + // icon state + const QIcon::State iconState(sunken ? QIcon::On : QIcon::Off); + const QPixmap icon = menuItemOption->icon.pixmap(iconRect.size(), mode, iconState); + painter->drawPixmap(iconRect, icon); + } + + // arrow + QRect arrowRect( + contentsRect.right() - Metrics::MenuButton_IndicatorWidth + 1, contentsRect.top() + (contentsRect.height() - Metrics::MenuButton_IndicatorWidth) / 2, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth); + contentsRect.setRight(arrowRect.left() - Metrics::MenuItem_ItemSpacing - 1); + + if (menuItemOption->menuItemType == QStyleOptionMenuItem::SubMenu) { + // apply right-to-left layout + arrowRect = visualRect(option, arrowRect); + + // arrow orientation + const ArrowOrientation orientation(reverseLayout ? ArrowLeft : ArrowRight); + + // color + QColor arrowColor; + if (useStrongFocus && (selected || sunken)) + arrowColor = palette.color(QPalette::HighlightedText); + else if (sunken) + arrowColor = _helper->focusColor(palette); + else if (selected) + arrowColor = _helper->hoverColor(palette); + else + arrowColor = _helper->arrowColor(palette, QPalette::WindowText); + + // render + _helper->renderArrow(painter, arrowRect, arrowColor, orientation); + } + + // text + auto textRect = contentsRect; + if (!menuItemOption->text.isEmpty()) { + // adjust textRect + QString text = menuItemOption->text; + textRect = centerRect(textRect, textRect.width(), option->fontMetrics.size(_mnemonics->textFlags(), text).height()); + textRect = visualRect(option, textRect); + + // set font + painter->setFont(menuItemOption->font); + + // color role + const QPalette::ColorRole role = (useStrongFocus && (selected || sunken)) ? QPalette::HighlightedText : QPalette::WindowText; + + // locate accelerator and render + const int tabPosition(text.indexOf(QLatin1Char('\t'))); + if (tabPosition >= 0) { + const int textFlags(Qt::AlignVCenter | Qt::AlignRight); + QString accelerator(text.mid(tabPosition + 1)); + text = text.left(tabPosition); + drawItemText(painter, textRect, textFlags, palette, enabled, accelerator, role); + } + + // render text + const int textFlags(Qt::AlignVCenter | (reverseLayout ? Qt::AlignRight : Qt::AlignLeft) | _mnemonics->textFlags()); + textRect = option->fontMetrics.boundingRect(textRect, textFlags, text); + drawItemText(painter, textRect, textFlags, palette, enabled, text, role); + + // render hover and focus + if (!useStrongFocus && (selected || sunken)) { + QColor outlineColor; + if (sunken) + outlineColor = _helper->focusColor(palette); + else if (selected) + outlineColor = _helper->hoverColor(palette); + + _helper->renderFocusLine(painter, textRect, outlineColor); + } + } + + return true; +} + +//______________________________________________________________________________ +void Style::renderMenuTitle(const QStyleOptionToolButton *option, QPainter *painter, const QWidget *) const +{ + // render a separator at the bottom + const auto &palette(option->palette); + const auto color(_helper->separatorColor(palette)); + _helper->renderSeparator(painter, QRect(option->rect.bottomLeft() - QPoint(0, Metrics::MenuItem_MarginHeight), QSize(option->rect.width(), 1)), color); + + // render text in the center of the rect + // icon is discarded on purpose + painter->setFont(option->font); + const auto contentsRect = insideMargin(option->rect, Metrics::MenuItem_MarginWidth, Metrics::MenuItem_MarginHeight); + drawItemText(painter, contentsRect, Qt::AlignCenter, palette, true, option->text, QPalette::WindowText); +} + +//____________________________________________________________________________________ +QStyleOptionToolButton Style::separatorMenuItemOption(const QStyleOptionMenuItem *menuItemOption, const QWidget *widget) const +{ + // separator can have a title and an icon + // in that case they are rendered as sunken flat toolbuttons + QStyleOptionToolButton toolButtonOption; + toolButtonOption.initFrom(widget); + toolButtonOption.rect = menuItemOption->rect; + toolButtonOption.features = QStyleOptionToolButton::None; + toolButtonOption.state = State_Enabled | State_AutoRaise; + toolButtonOption.subControls = SC_ToolButton; + toolButtonOption.icon = QIcon(); + toolButtonOption.iconSize = QSize(); + toolButtonOption.text = menuItemOption->text; + + toolButtonOption.toolButtonStyle = Qt::ToolButtonTextBesideIcon; + return toolButtonOption; +} + +//____________________________________________________________________ +bool Style::showIconsInMenuItems() const +{ + const KConfigGroup g(KSharedConfig::openConfig(), "KDE"); + return g.readEntry("ShowIconsInMenuItems", true); +} + +//____________________________________________________________________ +bool Style::isMenuTitle(const QWidget *widget) const +{ + // check widget + if (!widget) + return false; + + // check property + const QVariant property(widget->property(PropertyNames::menuTitle)); + if (property.isValid()) + return property.toBool(); + + // detect menu toolbuttons + QWidget *parent = widget->parentWidget(); + if (qobject_cast(parent)) { + foreach (auto child, parent->findChildren()) { + if (child->defaultWidget() != widget) + continue; + const_cast(widget)->setProperty(PropertyNames::menuTitle, true); + return true; + } + } + + const_cast(widget)->setProperty(PropertyNames::menuTitle, false); + return false; +} + +} diff --git a/kstyle/widgets/menubar.cpp b/kstyle/widgets/menubar.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/menubar.cpp @@ -0,0 +1,105 @@ +#include "breezestyle.h" + +namespace Breeze +{ +//______________________________________________________________ +QSize Style::menuBarItemSizeFromContents(const QStyleOption *, const QSize &contentsSize, const QWidget *) const +{ + return expandSize(contentsSize, Metrics::MenuBarItem_MarginWidth, Metrics::MenuBarItem_MarginHeight); +} + +//___________________________________________________________________________________ +bool Style::drawMenuBarItemControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto menuItemOption = qstyleoption_cast(option); + if (!menuItemOption) + return true; + + // copy rect and palette + const auto &rect(option->rect); + const auto &palette(option->palette); + + // store state + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool selected(enabled && (state & State_Selected)); + const bool sunken(enabled && (state & State_Sunken)); + const bool useStrongFocus(StyleConfigData::menuItemDrawStrongFocus()); + + // render hover and focus + if (useStrongFocus && (selected || sunken)) { + QColor outlineColor; + if (sunken) + outlineColor = _helper->focusColor(palette); + else if (selected) + outlineColor = _helper->hoverColor(palette); + _helper->renderFocusRect(painter, rect, outlineColor); + } + + /* + check if item as an icon, in which case only the icon should be rendered + consistently with comment in QMenuBarPrivate::calcActionRects + */ + if (!menuItemOption->icon.isNull()) { + // icon size is forced to SmallIconSize + const auto iconSize = pixelMetric(QStyle::PM_SmallIconSize, nullptr, widget); + const auto iconRect = centerRect(rect, iconSize, iconSize); + + // decide icon mode and state + QIcon::Mode iconMode; + QIcon::State iconState; + if (!enabled) { + iconMode = QIcon::Disabled; + iconState = QIcon::Off; + + } else { + if (useStrongFocus && sunken) + iconMode = QIcon::Selected; + else if (useStrongFocus && selected) + iconMode = QIcon::Active; + else + iconMode = QIcon::Normal; + + iconState = sunken ? QIcon::On : QIcon::Off; + } + + const auto pixmap = menuItemOption->icon.pixmap(iconSize, iconMode, iconState); + drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); + + // render outline + if (!useStrongFocus && (selected || sunken)) { + QColor outlineColor; + if (sunken) + outlineColor = _helper->focusColor(palette); + else if (selected) + outlineColor = _helper->hoverColor(palette); + + _helper->renderFocusLine(painter, iconRect, outlineColor); + } + + } else { + // get text rect + const int textFlags(Qt::AlignCenter | _mnemonics->textFlags()); + const auto textRect = option->fontMetrics.boundingRect(rect, textFlags, menuItemOption->text); + + // render text + const QPalette::ColorRole role = (useStrongFocus && sunken) ? QPalette::HighlightedText : QPalette::WindowText; + drawItemText(painter, textRect, textFlags, palette, enabled, menuItemOption->text, role); + + // render outline + if (!useStrongFocus && (selected || sunken)) { + QColor outlineColor; + if (sunken) + outlineColor = _helper->focusColor(palette); + else if (selected) + outlineColor = _helper->hoverColor(palette); + + _helper->renderFocusLine(painter, textRect, outlineColor); + } + } + + return true; +} + +} diff --git a/kstyle/widgets/progressbar.cpp b/kstyle/widgets/progressbar.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/progressbar.cpp @@ -0,0 +1,403 @@ +#include "breezestyle.h" + +namespace BreezePrivate +{ +//_______________________________________________________________ +#if !BREEZE_USE_KDE4 +bool isProgressBarHorizontal(const QStyleOptionProgressBar *option) +{ + return option && ((option->state & QStyle::State_Horizontal) || option->orientation == Qt::Horizontal); +} +#endif + +} + +namespace Breeze +{ +//______________________________________________________________________________ +void Helper::renderProgressBarGroove(QPainter *painter, const QRect &rect, const QColor &color) const +{ + // setup painter + painter->setRenderHint(QPainter::Antialiasing, true); + + const QRectF baseRect(rect); + const qreal radius(0.5 * Metrics::ProgressBar_Thickness); + + // content + if (color.isValid()) { + painter->setPen(Qt::NoPen); + painter->setBrush(color); + painter->drawRoundedRect(baseRect, radius, radius); + } +} + +//______________________________________________________________________________ +void Helper::renderProgressBarBusyContents(QPainter *painter, const QRect &rect, const QColor &first, const QColor &second, bool horizontal, bool reverse, int progress) const +{ + // setup painter + painter->setRenderHint(QPainter::Antialiasing, true); + + const QRectF baseRect(rect); + const qreal radius(0.5 * Metrics::ProgressBar_Thickness); + + // setup brush + QPixmap pixmap(horizontal ? 2 * Metrics::ProgressBar_BusyIndicatorSize : 1, horizontal ? 1 : 2 * Metrics::ProgressBar_BusyIndicatorSize); + pixmap.fill(second); + if (horizontal) { + QPainter painter(&pixmap); + painter.setBrush(first); + painter.setPen(Qt::NoPen); + + progress %= 2 * Metrics::ProgressBar_BusyIndicatorSize; + if (reverse) + progress = 2 * Metrics::ProgressBar_BusyIndicatorSize - progress - 1; + painter.drawRect(QRect(0, 0, Metrics::ProgressBar_BusyIndicatorSize, 1).translated(progress, 0)); + + if (progress > Metrics::ProgressBar_BusyIndicatorSize) { + painter.drawRect(QRect(0, 0, Metrics::ProgressBar_BusyIndicatorSize, 1).translated(progress - 2 * Metrics::ProgressBar_BusyIndicatorSize, 0)); + } + + } else { + QPainter painter(&pixmap); + painter.setBrush(first); + painter.setPen(Qt::NoPen); + + progress %= 2 * Metrics::ProgressBar_BusyIndicatorSize; + progress = 2 * Metrics::ProgressBar_BusyIndicatorSize - progress - 1; + painter.drawRect(QRect(0, 0, 1, Metrics::ProgressBar_BusyIndicatorSize).translated(0, progress)); + + if (progress > Metrics::ProgressBar_BusyIndicatorSize) { + painter.drawRect(QRect(0, 0, 1, Metrics::ProgressBar_BusyIndicatorSize).translated(0, progress - 2 * Metrics::ProgressBar_BusyIndicatorSize)); + } + } + + painter->setPen(Qt::NoPen); + painter->setBrush(pixmap); + painter->drawRoundedRect(baseRect, radius, radius); +} + +//___________________________________________________________________________________________________________________ +QRect Style::progressBarGrooveRect(const QStyleOption *option, const QWidget *widget) const +{ + // cast option and check + const auto progressBarOption(qstyleoption_cast(option)); + if (!progressBarOption) + return option->rect; + + // get flags and orientation + const bool textVisible(progressBarOption->textVisible); + const bool busy(progressBarOption->minimum == 0 && progressBarOption->maximum == 0); + +#if BREEZE_USE_KDE4 + const auto progressBarOption2(qstyleoption_cast(option)); + const bool horizontal(!progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal); +#else + const bool horizontal(BreezePrivate::isProgressBarHorizontal(progressBarOption)); +#endif + + // copy rectangle and adjust + auto rect(option->rect); + const int frameWidth(pixelMetric(PM_DefaultFrameWidth, option, widget)); + if (horizontal) + rect = insideMargin(rect, frameWidth, 0); + else + rect = insideMargin(rect, 0, frameWidth); + + if (textVisible && !busy && horizontal) { + auto textRect(subElementRect(SE_ProgressBarLabel, option, widget)); + textRect = visualRect(option, textRect); + rect.setRight(textRect.left() - Metrics::ProgressBar_ItemSpacing - 1); + rect = visualRect(option, rect); + rect = centerRect(rect, rect.width(), Metrics::ProgressBar_Thickness); + + } else if (horizontal) { + rect = centerRect(rect, rect.width(), Metrics::ProgressBar_Thickness); + + } else { + rect = centerRect(rect, Metrics::ProgressBar_Thickness, rect.height()); + } + + return rect; +} + +//___________________________________________________________________________________________________________________ +QRect Style::progressBarContentsRect(const QStyleOption *option, const QWidget *widget) const +{ + // cast option and check + const auto progressBarOption(qstyleoption_cast(option)); + if (!progressBarOption) + return QRect(); + + // get groove rect + const auto rect(progressBarGrooveRect(option, widget)); + + // in busy mode, grooveRect is used + const bool busy(progressBarOption->minimum == 0 && progressBarOption->maximum == 0); + if (busy) + return rect; + + // get orientation +#if BREEZE_USE_KDE4 + const auto progressBarOption2(qstyleoption_cast(option)); + const bool horizontal(!progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal); +#else + const bool horizontal(BreezePrivate::isProgressBarHorizontal(progressBarOption)); +#endif + + // check inverted appearance +#if BREEZE_USE_KDE4 + const bool inverted(progressBarOption2 ? progressBarOption2->invertedAppearance : false); +#else + const bool inverted(progressBarOption->invertedAppearance); +#endif + + // get progress and steps + const qreal progress(progressBarOption->progress - progressBarOption->minimum); + const int steps(qMax(progressBarOption->maximum - progressBarOption->minimum, 1)); + + // Calculate width fraction + const qreal widthFrac = qMin(qreal(1), progress / steps); + + // convert the pixel width + const int indicatorSize(widthFrac * (horizontal ? rect.width() : rect.height())); + + QRect indicatorRect; + if (horizontal) { + indicatorRect = QRect(inverted ? (rect.right() - indicatorSize + 1) : rect.left(), rect.y(), indicatorSize, rect.height()); + indicatorRect = visualRect(option->direction, rect, indicatorRect); + + } else + indicatorRect = QRect(rect.x(), inverted ? rect.top() : (rect.bottom() - indicatorSize + 1), rect.width(), indicatorSize); + + return indicatorRect; +} + +//___________________________________________________________________________________________________________________ +QRect Style::progressBarLabelRect(const QStyleOption *option, const QWidget *) const +{ + // cast option and check + const auto progressBarOption(qstyleoption_cast(option)); + if (!progressBarOption) + return QRect(); + + // get flags and check + const bool textVisible(progressBarOption->textVisible); + const bool busy(progressBarOption->minimum == 0 && progressBarOption->maximum == 0); + if (!textVisible || busy) + return QRect(); + + // get direction and check +#if BREEZE_USE_KDE4 + const auto progressBarOption2(qstyleoption_cast(option)); + const bool horizontal(!progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal); +#else + const bool horizontal(BreezePrivate::isProgressBarHorizontal(progressBarOption)); +#endif + if (!horizontal) + return QRect(); + + int textWidth = qMax(option->fontMetrics.size(_mnemonics->textFlags(), progressBarOption->text).width(), option->fontMetrics.size(_mnemonics->textFlags(), QStringLiteral("100%")).width()); + + auto rect(insideMargin(option->rect, Metrics::Frame_FrameWidth, 0)); + rect.setLeft(rect.right() - textWidth + 1); + rect = visualRect(option, rect); + + return rect; +} + +//______________________________________________________________ +QSize Style::progressBarSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *) const +{ + // cast option + const auto progressBarOption(qstyleoption_cast(option)); + if (!progressBarOption) + return contentsSize; + +#if BREEZE_USE_KDE4 + const auto progressBarOption2(qstyleoption_cast(option)); + const bool horizontal(!progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal); +#else + const bool horizontal(BreezePrivate::isProgressBarHorizontal(progressBarOption)); +#endif + + // make local copy + QSize size(contentsSize); + + if (horizontal) { + // check text visibility + const bool textVisible(progressBarOption->textVisible); + + size.setWidth(qMax(size.width(), int(Metrics::ProgressBar_Thickness))); + size.setHeight(qMax(size.height(), int(Metrics::ProgressBar_Thickness))); + if (textVisible) + size.setHeight(qMax(size.height(), option->fontMetrics.height())); + + } else { + size.setHeight(qMax(size.height(), int(Metrics::ProgressBar_Thickness))); + size.setWidth(qMax(size.width(), int(Metrics::ProgressBar_Thickness))); + } + + return size; +} + +//___________________________________________________________________________________ +bool Style::drawProgressBarControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + const auto progressBarOption(qstyleoption_cast(option)); + if (!progressBarOption) + return true; + + // render groove +#if BREEZE_USE_KDE4 + QStyleOptionProgressBarV2 progressBarOption2 = *progressBarOption; +#else + QStyleOptionProgressBar progressBarOption2 = *progressBarOption; +#endif + progressBarOption2.rect = subElementRect(SE_ProgressBarGroove, progressBarOption, widget); + drawControl(CE_ProgressBarGroove, &progressBarOption2, painter, widget); + +#if QT_VERSION >= 0x050000 + const QObject *styleObject(widget ? widget : progressBarOption->styleObject); +#else + const QObject *styleObject(widget); +#endif + + // enable busy animations + // need to check both widget and passed styleObject, used for QML + if (styleObject && _animations->busyIndicatorEngine().enabled()) { +#if QT_VERSION >= 0x050000 + // register QML object if defined + if (!widget && progressBarOption->styleObject) { + _animations->busyIndicatorEngine().registerWidget(progressBarOption->styleObject); + } +#endif + + _animations->busyIndicatorEngine().setAnimated(styleObject, progressBarOption->maximum == 0 && progressBarOption->minimum == 0); + } + + // check if animated and pass to option + if (_animations->busyIndicatorEngine().isAnimated(styleObject)) { + progressBarOption2.progress = _animations->busyIndicatorEngine().value(); + } + + // render contents + progressBarOption2.rect = subElementRect(SE_ProgressBarContents, progressBarOption, widget); + drawControl(CE_ProgressBarContents, &progressBarOption2, painter, widget); + + // render text + const bool textVisible(progressBarOption->textVisible); + const bool busy(progressBarOption->minimum == 0 && progressBarOption->maximum == 0); + if (textVisible && !busy) { + progressBarOption2.rect = subElementRect(SE_ProgressBarLabel, progressBarOption, widget); + drawControl(CE_ProgressBarLabel, &progressBarOption2, painter, widget); + } + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawProgressBarContentsControl(const QStyleOption *option, QPainter *painter, const QWidget *) const +{ + const auto progressBarOption(qstyleoption_cast(option)); + if (!progressBarOption) + return true; + + // copy rect and palette + auto rect(option->rect); + const auto &palette(option->palette); + + // get direction +#if BREEZE_USE_KDE4 + const auto progressBarOption2(qstyleoption_cast(option)); + const bool horizontal = !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal; + const bool inverted(progressBarOption2 ? progressBarOption2->invertedAppearance : false); +#else + const bool horizontal(BreezePrivate::isProgressBarHorizontal(progressBarOption)); + const bool inverted(progressBarOption->invertedAppearance); +#endif + bool reverse = horizontal && option->direction == Qt::RightToLeft; + if (inverted) + reverse = !reverse; + + // check if anything is to be drawn + const bool busy((progressBarOption->minimum == 0 && progressBarOption->maximum == 0)); + if (busy) { + const qreal progress(_animations->busyIndicatorEngine().value()); + + const auto &first = palette.color(QPalette::Highlight); + const auto second(KColorUtils::mix(palette.color(QPalette::Highlight), palette.color(QPalette::Window), 0.7)); + _helper->renderProgressBarBusyContents(painter, rect, first, second, horizontal, reverse, progress); + + } else { + const QRegion oldClipRegion(painter->clipRegion()); + if (horizontal) { + if (rect.width() < Metrics::ProgressBar_Thickness) { + painter->setClipRect(rect, Qt::IntersectClip); + if (reverse) + rect.setLeft(rect.left() - Metrics::ProgressBar_Thickness + rect.width()); + else + rect.setWidth(Metrics::ProgressBar_Thickness); + } + + } else { + if (rect.height() < Metrics::ProgressBar_Thickness) { + painter->setClipRect(rect, Qt::IntersectClip); + if (reverse) + rect.setHeight(Metrics::ProgressBar_Thickness); + else + rect.setTop(rect.top() - Metrics::ProgressBar_Thickness + rect.height()); + } + } + + auto contentsColor(option->state.testFlag(QStyle::State_Selected) ? palette.color(QPalette::HighlightedText) : palette.color(QPalette::Highlight)); + + _helper->renderProgressBarContents(painter, rect, contentsColor); + painter->setClipRegion(oldClipRegion); + } + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawProgressBarGrooveControl(const QStyleOption *option, QPainter *painter, const QWidget *) const +{ + const auto &palette(option->palette); + const auto color(_helper->alphaColor(palette.color(QPalette::WindowText), 0.3)); + _helper->renderProgressBarGroove(painter, option->rect, color); + return true; +} + +//___________________________________________________________________________________ +bool Style::drawProgressBarLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *) const +{ + // cast option and check + const auto progressBarOption(qstyleoption_cast(option)); + if (!progressBarOption) + return true; + + // get direction and check +#if BREEZE_USE_KDE4 + const auto progressBarOption2(qstyleoption_cast(option)); + const bool horizontal = !progressBarOption2 || progressBarOption2->orientation == Qt::Horizontal; +#else + const bool horizontal(BreezePrivate::isProgressBarHorizontal(progressBarOption)); +#endif + if (!horizontal) + return true; + + // store rect and palette + const auto &rect(option->rect); + const auto &palette(option->palette); + + // store state and direction + const State &state(option->state); + const bool enabled(state & State_Enabled); + + // define text rect + Qt::Alignment hAlign((progressBarOption->textAlignment == Qt::AlignLeft) ? Qt::AlignHCenter : progressBarOption->textAlignment); + drawItemText(painter, rect, Qt::AlignVCenter | hAlign, palette, enabled, progressBarOption->text, QPalette::WindowText); + + return true; +} + +} diff --git a/kstyle/widgets/pushbutton.cpp b/kstyle/widgets/pushbutton.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/pushbutton.cpp @@ -0,0 +1,466 @@ +#include "breezestyle.h" + +namespace Breeze +{ +//____________________________________________________________________ +QColor Helper::buttonFocusOutlineColor(const QPalette &palette) const +{ + return KColorUtils::mix(focusColor(palette), palette.color(QPalette::ButtonText), 0.15); +} + +//____________________________________________________________________ +QColor Helper::buttonHoverOutlineColor(const QPalette &palette) const +{ + return KColorUtils::mix(hoverColor(palette), palette.color(QPalette::ButtonText), 0.15); +} + +//____________________________________________________________________ +QColor Helper::buttonOutlineColor(const QPalette &palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode) const +{ + QColor outline(KColorUtils::mix(palette.color(QPalette::Button), palette.color(QPalette::ButtonText), 0.3)); + if (mode == AnimationHover) { + if (hasFocus) { + const QColor focus(buttonFocusOutlineColor(palette)); + const QColor hover(buttonHoverOutlineColor(palette)); + outline = KColorUtils::mix(focus, hover, opacity); + + } else { + const QColor hover(hoverColor(palette)); + outline = KColorUtils::mix(outline, hover, opacity); + } + + } else if (mouseOver) { + if (hasFocus) + outline = buttonHoverOutlineColor(palette); + else + outline = hoverColor(palette); + + } else if (mode == AnimationFocus) { + const QColor focus(buttonFocusOutlineColor(palette)); + outline = KColorUtils::mix(outline, focus, opacity); + + } else if (hasFocus) { + outline = buttonFocusOutlineColor(palette); + } + + return outline; +} + +//____________________________________________________________________ +QColor Helper::buttonBackgroundColor(const QPalette &palette, bool mouseOver, bool hasFocus, bool sunken, qreal opacity, AnimationMode mode) const +{ + QColor background(sunken ? KColorUtils::mix(palette.color(QPalette::Button), palette.color(QPalette::ButtonText), 0.2) : palette.color(QPalette::Button)); + + if (mode == AnimationHover) { + const QColor focus(focusColor(palette)); + const QColor hover(hoverColor(palette)); + if (hasFocus) + background = KColorUtils::mix(focus, hover, opacity); + + } else if (mouseOver && hasFocus) { + background = hoverColor(palette); + + } else if (mode == AnimationFocus) { + const QColor focus(focusColor(palette)); + background = KColorUtils::mix(background, focus, opacity); + + } else if (hasFocus) { + background = focusColor(palette); + } + + return background; +} + +//______________________________________________________________________________ +void Helper::renderButtonFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, const QColor &shadow, bool hasFocus, bool sunken) const +{ + // setup painter + painter->setRenderHint(QPainter::Antialiasing, true); + + // copy rect + QRectF frameRect(rect); + frameRect.adjust(1, 1, -1, -1); + qreal radius(frameRadius()); + + // shadow + if (sunken) { + frameRect.translate(1, 1); + + } else if (shadow.isValid()) { + const qreal shadowRadius = qMax(radius - 1, qreal(0.0)); + painter->setPen(QPen(shadow, 2)); + painter->setBrush(Qt::NoBrush); + painter->drawRoundedRect(shadowRect(frameRect), shadowRadius, shadowRadius); + } + + if (outline.isValid()) { + QLinearGradient gradient(frameRect.topLeft(), frameRect.bottomLeft()); + gradient.setColorAt(0, outline.lighter(hasFocus ? 103 : 101)); + gradient.setColorAt(1, outline.darker(hasFocus ? 110 : 103)); + painter->setPen(QPen(QBrush(gradient), 1.0)); + + frameRect.adjust(0.5, 0.5, -0.5, -0.5); + radius = qMax(radius - 1, qreal(0.0)); + + } else + painter->setPen(Qt::NoPen); + + // content + if (color.isValid()) { + QLinearGradient gradient(frameRect.topLeft(), frameRect.bottomLeft()); + gradient.setColorAt(0, color.lighter(hasFocus ? 103 : 101)); + gradient.setColorAt(1, color.darker(hasFocus ? 110 : 103)); + painter->setBrush(gradient); + + } else + painter->setBrush(Qt::NoBrush); + + // render + painter->drawRoundedRect(frameRect, radius, radius); +} + +//____________________________________________________________________________ +#if QT_VERSION >= 0x050000 +bool Style::eventFilterCommandLinkButton(QCommandLinkButton *button, QEvent *event) +{ + if (event->type() == QEvent::Paint) { + // painter + QPainter painter(button); + painter.setClipRegion(static_cast(event)->region()); + + const bool isFlat = false; + + // option + QStyleOptionButton option; + option.initFrom(button); + option.features |= QStyleOptionButton::CommandLinkButton; + if (isFlat) + option.features |= QStyleOptionButton::Flat; + option.text = QString(); + option.icon = QIcon(); + + if (button->isChecked()) + option.state |= State_On; + if (button->isDown()) + option.state |= State_Sunken; + + // frame + drawControl(QStyle::CE_PushButton, &option, &painter, button); + + // offset + const int margin(Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth); + QPoint offset(margin, margin); + + if (button->isDown() && !isFlat) + painter.translate(1, 1); + { + offset += QPoint(1, 1); + } + + // state + const State &state(option.state); + const bool enabled(state & State_Enabled); + bool mouseOver(enabled && (state & State_MouseOver)); + bool hasFocus(enabled && (state & State_HasFocus)); + + // icon + if (!button->icon().isNull()) { + const auto pixmapSize(button->icon().actualSize(button->iconSize())); + const QRect pixmapRect(QPoint(offset.x(), button->description().isEmpty() ? (button->height() - pixmapSize.height()) / 2 : offset.y()), pixmapSize); + const QPixmap pixmap(button->icon().pixmap(pixmapSize, enabled ? QIcon::Normal : QIcon::Disabled, button->isChecked() ? QIcon::On : QIcon::Off)); + drawItemPixmap(&painter, pixmapRect, Qt::AlignCenter, pixmap); + + offset.rx() += pixmapSize.width() + Metrics::Button_ItemSpacing; + } + + // text rect + QRect textRect(offset, QSize(button->size().width() - offset.x() - margin, button->size().height() - 2 * margin)); + const QPalette::ColorRole textRole = (enabled && hasFocus && !mouseOver && !isFlat) ? QPalette::HighlightedText : QPalette::ButtonText; + if (!button->text().isEmpty()) { + QFont font(button->font()); + font.setBold(true); + painter.setFont(font); + if (button->description().isEmpty()) { + drawItemText(&painter, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextHideMnemonic, button->palette(), enabled, button->text(), textRole); + + } else { + drawItemText(&painter, textRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextHideMnemonic, button->palette(), enabled, button->text(), textRole); + textRect.setTop(textRect.top() + QFontMetrics(font).height()); + } + + painter.setFont(button->font()); + } + + if (!button->description().isEmpty()) { + drawItemText(&painter, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextWordWrap, button->palette(), enabled, button->description(), textRole); + } + + return true; + } + + // continue with normal painting + return false; +} +#endif + +//___________________________________________________________________________________________________________________ +QRect Style::pushButtonContentsRect(const QStyleOption *option, const QWidget *) const +{ + return insideMargin(option->rect, Metrics::Frame_FrameWidth); +} + +//______________________________________________________________ +QSize Style::pushButtonSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + // cast option and check + const auto buttonOption(qstyleoption_cast(option)); + if (!buttonOption) + return contentsSize; + + // output + QSize size; + + // check text and icon + const bool hasText(!buttonOption->text.isEmpty()); + const bool flat(buttonOption->features & QStyleOptionButton::Flat); + bool hasIcon(!buttonOption->icon.isNull()); + + if (!(hasText || hasIcon)) { + /* + no text nor icon is passed. + assume custom button and use contentsSize as a starting point + */ + size = contentsSize; + + } else { + /* + rather than trying to guess what Qt puts into its contents size calculation, + we recompute the button size entirely, based on button option + this ensures consistency with the rendering stage + */ + + // update has icon to honour showIconsOnPushButtons, when possible + hasIcon &= (showIconsOnPushButtons() || flat || !hasText); + + // text + if (hasText) + size = buttonOption->fontMetrics.size(Qt::TextShowMnemonic, buttonOption->text); + + // icon + if (hasIcon) { + QSize iconSize = buttonOption->iconSize; + if (!iconSize.isValid()) + iconSize = QSize(pixelMetric(PM_SmallIconSize, option, widget), pixelMetric(PM_SmallIconSize, option, widget)); + + size.setHeight(qMax(size.height(), iconSize.height())); + size.rwidth() += iconSize.width(); + + if (hasText) + size.rwidth() += Metrics::Button_ItemSpacing; + } + } + + // menu + const bool hasMenu(buttonOption->features & QStyleOptionButton::HasMenu); + if (hasMenu) { + size.rwidth() += Metrics::MenuButton_IndicatorWidth; + if (hasText || hasIcon) + size.rwidth() += Metrics::Button_ItemSpacing; + } + + // expand with buttons margin + size = expandSize(size, Metrics::Button_MarginWidth); + + // make sure buttons have a minimum width + if (hasText) { + size.setWidth(qMax(size.width(), int(Metrics::Button_MinWidth))); + } + + // finally add frame margins + return expandSize(size, Metrics::Frame_FrameWidth); +} + +//______________________________________________________________ +bool Style::drawPanelButtonCommandPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto buttonOption(qstyleoption_cast(option)); + if (!buttonOption) + return true; + + // rect and palette + const auto &rect(option->rect); + + // button state + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool mouseOver(enabled && (state & State_MouseOver)); + const bool hasFocus((enabled && (state & State_HasFocus)) && !(widget && widget->focusProxy())); + const bool sunken(state & (State_On | State_Sunken)); + const bool flat(buttonOption->features & QStyleOptionButton::Flat); + + // update animation state + // mouse over takes precedence over focus + _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver); + _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus && !mouseOver); + + const AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); + const qreal opacity(_animations->widgetStateEngine().buttonOpacity(widget)); + + if (flat) { + // define colors and render + const auto &palette(option->palette); + const auto color(_helper->toolButtonColor(palette, mouseOver, hasFocus, sunken, opacity, mode)); + _helper->renderToolButtonFrame(painter, rect, color, sunken); + + } else { + // update button color from palette in case button is default + QPalette palette(option->palette); + if (enabled && buttonOption->features & QStyleOptionButton::DefaultButton) { + const auto button(palette.color(QPalette::Button)); + const auto base(palette.color(QPalette::Base)); + palette.setColor(QPalette::Button, KColorUtils::mix(button, base, 0.7)); + } + + const auto shadow(_helper->shadowColor(palette)); + const auto outline(_helper->buttonOutlineColor(palette, mouseOver, hasFocus, opacity, mode)); + const auto background(_helper->buttonBackgroundColor(palette, mouseOver, hasFocus, sunken, opacity, mode)); + + // render + _helper->renderButtonFrame(painter, rect, background, outline, shadow, hasFocus, sunken); + } + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawPushButtonLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto buttonOption(qstyleoption_cast(option)); + if (!buttonOption) + return true; + + // copy rect and palette + const auto &rect(option->rect); + const auto &palette(option->palette); + + // state + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool sunken(state & (State_On | State_Sunken)); + const bool mouseOver(enabled && (option->state & State_MouseOver)); + const bool hasFocus(enabled && !mouseOver && (option->state & State_HasFocus)); + const bool flat(buttonOption->features & QStyleOptionButton::Flat); + + // content + const bool hasText(!buttonOption->text.isEmpty()); + const bool hasIcon((showIconsOnPushButtons() || flat || !hasText) && !buttonOption->icon.isNull()); + + // contents + auto contentsRect(rect); + if (sunken && !flat) + contentsRect.translate(1, 1); + + // color role + QPalette::ColorRole textRole; + if (flat) { + if (hasFocus && sunken) + textRole = QPalette::HighlightedText; + else + textRole = QPalette::WindowText; + + } else if (hasFocus) + textRole = QPalette::HighlightedText; + else + textRole = QPalette::ButtonText; + + // menu arrow + if (buttonOption->features & QStyleOptionButton::HasMenu) { + // define rect + auto arrowRect(contentsRect); + arrowRect.setLeft(contentsRect.right() - Metrics::MenuButton_IndicatorWidth + 1); + arrowRect = centerRect(arrowRect, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth); + + contentsRect.setRight(arrowRect.left() - Metrics::Button_ItemSpacing - 1); + contentsRect.adjust(Metrics::Button_MarginWidth, 0, 0, 0); + + arrowRect = visualRect(option, arrowRect); + + // define color + const auto arrowColor(_helper->arrowColor(palette, textRole)); + _helper->renderArrow(painter, arrowRect, arrowColor, ArrowDown); + } + + // icon size + QSize iconSize; + if (hasIcon) { + iconSize = buttonOption->iconSize; + if (!iconSize.isValid()) { + const int metric(pixelMetric(PM_SmallIconSize, option, widget)); + iconSize = QSize(metric, metric); + } + } + + // text size + const int textFlags(_mnemonics->textFlags() | Qt::AlignCenter); + const QSize textSize(option->fontMetrics.size(textFlags, buttonOption->text)); + + // adjust text and icon rect based on options + QRect iconRect; + QRect textRect; + + if (hasText && !hasIcon) + textRect = contentsRect; + else if (hasIcon && !hasText) + iconRect = contentsRect; + else { + const int contentsWidth(iconSize.width() + textSize.width() + Metrics::Button_ItemSpacing); + iconRect = QRect(QPoint(contentsRect.left() + (contentsRect.width() - contentsWidth) / 2, contentsRect.top() + (contentsRect.height() - iconSize.height()) / 2), iconSize); + textRect = QRect(QPoint(iconRect.right() + Metrics::ToolButton_ItemSpacing + 1, contentsRect.top() + (contentsRect.height() - textSize.height()) / 2), textSize); + } + + // handle right to left + if (iconRect.isValid()) + iconRect = visualRect(option, iconRect); + if (textRect.isValid()) + textRect = visualRect(option, textRect); + + // make sure there is enough room for icon + if (iconRect.isValid()) + iconRect = centerRect(iconRect, iconSize); + + // render icon + if (hasIcon && iconRect.isValid()) { + // icon state and mode + const QIcon::State iconState(sunken ? QIcon::On : QIcon::Off); + QIcon::Mode iconMode; + if (!enabled) + iconMode = QIcon::Disabled; + else if (!flat && hasFocus) + iconMode = QIcon::Selected; + else if (mouseOver && flat) + iconMode = QIcon::Active; + else + iconMode = QIcon::Normal; + + const auto pixmap = buttonOption->icon.pixmap(iconSize, iconMode, iconState); + drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); + } + + // render text + if (hasText && textRect.isValid()) { + drawItemText(painter, textRect, textFlags, palette, enabled, buttonOption->text, textRole); + } + + return true; +} + +//____________________________________________________________________ +bool Style::showIconsOnPushButtons() const +{ + const KConfigGroup g(KSharedConfig::openConfig(), "KDE"); + return g.readEntry("ShowIconsOnPushButtons", true); +} + +} diff --git a/kstyle/widgets/radiobutton.cpp b/kstyle/widgets/radiobutton.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/radiobutton.cpp @@ -0,0 +1,119 @@ +#include "breezestyle.h" + +namespace Breeze +{ +//______________________________________________________________________________ +void Helper::renderRadioButtonBackground(QPainter *painter, const QRect &rect, const QColor &color, bool sunken) const +{ + // setup painter + painter->setRenderHint(QPainter::Antialiasing, true); + + // copy rect + QRectF frameRect(rect); + frameRect.adjust(3, 3, -3, -3); + if (sunken) + frameRect.translate(1, 1); + + painter->setPen(Qt::NoPen); + painter->setBrush(color); + painter->drawEllipse(frameRect); +} + +//______________________________________________________________________________ +void Helper::renderRadioButton(QPainter *painter, const QRect &rect, const QColor &color, const QColor &shadow, bool sunken, RadioButtonState state, qreal animation) const +{ + // setup painter + painter->setRenderHint(QPainter::Antialiasing, true); + + // copy rect + QRectF frameRect(rect); + frameRect.adjust(2, 2, -2, -2); + + // shadow + if (sunken) { + frameRect.translate(1, 1); + + } else { + painter->setPen(QPen(shadow, 1)); + painter->setBrush(Qt::NoBrush); + painter->drawEllipse(shadowRect(frameRect).adjusted(-0.5, -0.5, 0.5, 0.5)); + } + + // content + { + painter->setPen(QPen(color, 1)); + painter->setBrush(Qt::NoBrush); + + const QRectF contentRect(frameRect.adjusted(0.5, 0.5, -0.5, -0.5)); + painter->drawEllipse(contentRect); + } + + // mark + if (state == RadioOn) { + painter->setBrush(color); + painter->setPen(Qt::NoPen); + + const QRectF markerRect(frameRect.adjusted(3, 3, -3, -3)); + painter->drawEllipse(markerRect); + + } else if (state == RadioAnimated) { + painter->setBrush(color); + painter->setPen(Qt::NoPen); + QRectF markerRect(frameRect.adjusted(3, 3, -3, -3)); + + painter->translate(markerRect.center()); + painter->rotate(45); + + markerRect.setWidth(markerRect.width() * animation); + markerRect.translate(-markerRect.center()); + painter->drawEllipse(markerRect); + } +} + +//___________________________________________________________________________________ +bool Style::drawIndicatorRadioButtonPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // copy rect and palette + const auto &rect(option->rect); + const auto &palette(option->palette); + + // store flags + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool mouseOver(enabled && (state & State_MouseOver)); + const bool sunken(state & State_Sunken); + const bool checked(state & State_On); + + // radio button state + RadioButtonState radioButtonState(state & State_On ? RadioOn : RadioOff); + + // detect radiobuttons in lists + const bool isSelectedItem(this->isSelectedItem(widget, rect.center())); + + // animation state + _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver); + _animations->widgetStateEngine().updateState(widget, AnimationPressed, radioButtonState != RadioOff); + if (_animations->widgetStateEngine().isAnimated(widget, AnimationPressed)) + radioButtonState = RadioAnimated; + const qreal animation(_animations->widgetStateEngine().opacity(widget, AnimationPressed)); + + // colors + const auto shadow(_helper->shadowColor(palette)); + QColor color; + if (isSelectedItem) { + color = _helper->checkBoxIndicatorColor(palette, false, enabled && checked); + _helper->renderRadioButtonBackground(painter, rect, palette.color(QPalette::Base), sunken); + + } else { + const AnimationMode mode(_animations->widgetStateEngine().isAnimated(widget, AnimationHover) ? AnimationHover : AnimationNone); + const qreal opacity(_animations->widgetStateEngine().opacity(widget, AnimationHover)); + color = _helper->checkBoxIndicatorColor(palette, mouseOver, enabled && checked, opacity, mode); + } + + // render + _helper->renderRadioButton(painter, rect, color, shadow, sunken, radioButtonState, animation); + + return true; +} + +} diff --git a/kstyle/widgets/scrollbar.cpp b/kstyle/widgets/scrollbar.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/scrollbar.cpp @@ -0,0 +1,514 @@ +#include "breezestyle.h" + +#include + +namespace Breeze +{ +QColor Helper::scrollBarHandleColor(const QPalette &palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode) const +{ + QColor color(alphaColor(palette.color(QPalette::WindowText), 0.5)); + + // hover takes precedence over focus + if (mode == AnimationHover) { + const QColor hover(hoverColor(palette)); + const QColor focus(focusColor(palette)); + if (hasFocus) + color = KColorUtils::mix(focus, hover, opacity); + else + color = KColorUtils::mix(color, hover, opacity); + + } else if (mouseOver) { + color = hoverColor(palette); + + } else if (mode == AnimationFocus) { + const QColor focus(focusColor(palette)); + color = KColorUtils::mix(color, focus, opacity); + + } else if (hasFocus) { + color = focusColor(palette); + } + + return color; +} + +//______________________________________________________________________________ +void Helper::renderScrollBarHandle(QPainter *painter, const QRect &rect, const QColor &color) const +{ + // setup painter + painter->setRenderHint(QPainter::Antialiasing, true); + + const QRectF baseRect(rect); + const qreal radius(0.5 * std::min({baseRect.width(), baseRect.height(), (qreal)Metrics::ScrollBar_SliderWidth})); + + // content + if (color.isValid()) { + painter->setPen(Qt::NoPen); + painter->setBrush(color); + painter->drawRoundedRect(baseRect, radius, radius); + } +} + +//___________________________________________________________________________________________________________________ +QRect Style::scrollBarInternalSubControlRect(const QStyleOptionComplex *option, SubControl subControl) const +{ + const auto &rect = option->rect; + const State &state(option->state); + const bool horizontal(state & State_Horizontal); + + switch (subControl) { + case SC_ScrollBarSubLine: { + int majorSize(scrollBarButtonHeight(_subLineButtons)); + if (horizontal) + return visualRect(option, QRect(rect.left(), rect.top(), majorSize, rect.height())); + else + return visualRect(option, QRect(rect.left(), rect.top(), rect.width(), majorSize)); + } + + case SC_ScrollBarAddLine: { + int majorSize(scrollBarButtonHeight(_addLineButtons)); + if (horizontal) + return visualRect(option, QRect(rect.right() - majorSize + 1, rect.top(), majorSize, rect.height())); + else + return visualRect(option, QRect(rect.left(), rect.bottom() - majorSize + 1, rect.width(), majorSize)); + } + + default: + return QRect(); + } +} + +//___________________________________________________________________________________________________________________ +QRect Style::scrollBarSubControlRect(const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const +{ + // cast option and check + const auto sliderOption(qstyleoption_cast(option)); + if (!sliderOption) + return ParentStyleClass::subControlRect(CC_ScrollBar, option, subControl, widget); + + // get relevant state + const State &state(option->state); + const bool horizontal(state & State_Horizontal); + + switch (subControl) { + case SC_ScrollBarSubLine: + case SC_ScrollBarAddLine: + return scrollBarInternalSubControlRect(option, subControl); + + case SC_ScrollBarGroove: { + auto topRect = visualRect(option, scrollBarInternalSubControlRect(option, SC_ScrollBarSubLine)); + auto bottomRect = visualRect(option, scrollBarInternalSubControlRect(option, SC_ScrollBarAddLine)); + + QPoint topLeftCorner; + QPoint botRightCorner; + + if (horizontal) { + topLeftCorner = QPoint(topRect.right() + 1, topRect.top()); + botRightCorner = QPoint(bottomRect.left() - 1, topRect.bottom()); + + } else { + topLeftCorner = QPoint(topRect.left(), topRect.bottom() + 1); + botRightCorner = QPoint(topRect.right(), bottomRect.top() - 1); + } + + // define rect + return visualRect(option, QRect(topLeftCorner, botRightCorner)); + } + + case SC_ScrollBarSlider: { + // handle RTL here to unreflect things if need be + auto groove = visualRect(option, subControlRect(CC_ScrollBar, option, SC_ScrollBarGroove, widget)); + + if (sliderOption->minimum == sliderOption->maximum) + return groove; + + // Figure out how much room there is + int space(horizontal ? groove.width() : groove.height()); + + // Calculate the portion of this space that the slider should occupy + int sliderSize = space * qreal(sliderOption->pageStep) / (sliderOption->maximum - sliderOption->minimum + sliderOption->pageStep); + sliderSize = qMax(sliderSize, static_cast(Metrics::ScrollBar_MinSliderHeight)); + sliderSize = qMin(sliderSize, space); + + space -= sliderSize; + if (space <= 0) + return groove; + + int pos = qRound(qreal(sliderOption->sliderPosition - sliderOption->minimum) / (sliderOption->maximum - sliderOption->minimum) * space); + if (sliderOption->upsideDown) + pos = space - pos; + if (horizontal) + return visualRect(option, QRect(groove.left() + pos, groove.top(), sliderSize, groove.height())); + else + return visualRect(option, QRect(groove.left(), groove.top() + pos, groove.width(), sliderSize)); + } + + case SC_ScrollBarSubPage: { + // handle RTL here to unreflect things if need be + auto slider = visualRect(option, subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget)); + auto groove = visualRect(option, subControlRect(CC_ScrollBar, option, SC_ScrollBarGroove, widget)); + + if (horizontal) + return visualRect(option, QRect(groove.left(), groove.top(), slider.left() - groove.left(), groove.height())); + else + return visualRect(option, QRect(groove.left(), groove.top(), groove.width(), slider.top() - groove.top())); + } + + case SC_ScrollBarAddPage: { + // handle RTL here to unreflect things if need be + auto slider = visualRect(option, subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget)); + auto groove = visualRect(option, subControlRect(CC_ScrollBar, option, SC_ScrollBarGroove, widget)); + + if (horizontal) + return visualRect(option, QRect(slider.right() + 1, groove.top(), groove.right() - slider.right(), groove.height())); + else + return visualRect(option, QRect(groove.left(), slider.bottom() + 1, groove.width(), groove.bottom() - slider.bottom())); + } + + default: + return ParentStyleClass::subControlRect(CC_ScrollBar, option, subControl, widget); + ; + } +} + +//___________________________________________________________________________________ +bool Style::drawScrollBarSliderControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto sliderOption(qstyleoption_cast(option)); + if (!sliderOption) + return true; + + // copy rect and palette + const auto &rect(option->rect); + const auto &palette(option->palette); + + // try to understand if anywhere the widget is under mouse, not just the handle, use _animations in case of QWidget, option->styleObject in case of QML +#if QT_VERSION >= 0x050000 + bool widgetMouseOver((option->state & State_MouseOver)); + if (widget) + widgetMouseOver = _animations->scrollBarEngine().isHovered(widget, QStyle::SC_ScrollBarGroove); + else if (option->styleObject) + widgetMouseOver = option->styleObject->property("hover").toBool(); +#else + const bool widgetMouseOver(_animations->scrollBarEngine().isHovered(widget, QStyle::SC_ScrollBarGroove)); +#endif + + qreal grooveAnimationOpacity(_animations->scrollBarEngine().opacity(widget, QStyle::SC_ScrollBarGroove)); + if (grooveAnimationOpacity == AnimationData::OpacityInvalid) + grooveAnimationOpacity = (widgetMouseOver ? 1 : 0); + const qreal handleSize = StyleConfigData::animationsEnabled() ? ((Metrics::ScrollBar_SliderWidth / 2.0) * (1 - grooveAnimationOpacity) + Metrics::ScrollBar_SliderWidth * grooveAnimationOpacity) : (int)Metrics::ScrollBar_SliderWidth; + + // define handle rect + QRect handleRect; + const State &state(option->state); + const bool horizontal(state & State_Horizontal); + if (horizontal) + handleRect = centerRect(rect, rect.width(), handleSize); + else + handleRect = centerRect(rect, handleSize, rect.height()); + + const bool enabled(state & State_Enabled); + const bool mouseOver(enabled && (state & State_MouseOver)); + + // check focus from relevant parent + const QWidget *parent(scrollBarParent(widget)); + const bool hasFocus(enabled && ((widget && widget->hasFocus()) || (parent && parent->hasFocus()))); + + // enable animation state + const bool handleActive(sliderOption->activeSubControls & SC_ScrollBarSlider); + _animations->scrollBarEngine().updateState(widget, AnimationFocus, hasFocus); + + _animations->scrollBarEngine().updateState(widget, AnimationHover, mouseOver && handleActive); + + const auto mode(_animations->scrollBarEngine().animationMode(widget, SC_ScrollBarSlider)); + const qreal opacity(_animations->scrollBarEngine().opacity(widget, SC_ScrollBarSlider)); + auto color = _helper->scrollBarHandleColor(palette, mouseOver, hasFocus, opacity, mode); + if (StyleConfigData::animationsEnabled()) { + color.setAlphaF(color.alphaF() * (0.7 + 0.3 * grooveAnimationOpacity)); + } + + _helper->renderScrollBarHandle(painter, handleRect, color); + return true; +} + +//___________________________________________________________________________________ +bool Style::drawScrollBarAddLineControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // do nothing if no buttons are defined + if (_addLineButtons == NoButton) + return true; + + // cast option and check + const auto sliderOption(qstyleoption_cast(option)); + if (!sliderOption) + return true; + + const State &state(option->state); + const bool horizontal(state & State_Horizontal); + const bool reverseLayout(option->direction == Qt::RightToLeft); + + // adjust rect, based on number of buttons to be drawn + const auto rect(scrollBarInternalSubControlRect(sliderOption, SC_ScrollBarAddLine)); + + QColor color; + QStyleOptionSlider copy(*sliderOption); + if (_addLineButtons == DoubleButton) { + if (horizontal) { + // Draw the arrows + const QSize halfSize(rect.width() / 2, rect.height()); + const QRect leftSubButton(rect.topLeft(), halfSize); + const QRect rightSubButton(leftSubButton.topRight() + QPoint(1, 0), halfSize); + + copy.rect = leftSubButton; + color = scrollBarArrowColor(©, reverseLayout ? SC_ScrollBarAddLine : SC_ScrollBarSubLine, widget); + _helper->renderArrow(painter, leftSubButton, color, ArrowLeft); + + copy.rect = rightSubButton; + color = scrollBarArrowColor(©, reverseLayout ? SC_ScrollBarSubLine : SC_ScrollBarAddLine, widget); + _helper->renderArrow(painter, rightSubButton, color, ArrowRight); + + } else { + const QSize halfSize(rect.width(), rect.height() / 2); + const QRect topSubButton(rect.topLeft(), halfSize); + const QRect botSubButton(topSubButton.bottomLeft() + QPoint(0, 1), halfSize); + + copy.rect = topSubButton; + color = scrollBarArrowColor(©, SC_ScrollBarSubLine, widget); + _helper->renderArrow(painter, topSubButton, color, ArrowUp); + + copy.rect = botSubButton; + color = scrollBarArrowColor(©, SC_ScrollBarAddLine, widget); + _helper->renderArrow(painter, botSubButton, color, ArrowDown); + } + + } else if (_addLineButtons == SingleButton) { + copy.rect = rect; + color = scrollBarArrowColor(©, SC_ScrollBarAddLine, widget); + if (horizontal) { + if (reverseLayout) + _helper->renderArrow(painter, rect, color, ArrowLeft); + else + _helper->renderArrow(painter, rect.translated(1, 0), color, ArrowRight); + + } else + _helper->renderArrow(painter, rect.translated(0, 1), color, ArrowDown); + } + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawScrollBarSubLineControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // do nothing if no buttons are set + if (_subLineButtons == NoButton) + return true; + + // cast option and check + const auto sliderOption(qstyleoption_cast(option)); + if (!sliderOption) + return true; + + const State &state(option->state); + const bool horizontal(state & State_Horizontal); + const bool reverseLayout(option->direction == Qt::RightToLeft); + + // colors + const auto &palette(option->palette); + const auto &background = palette.color(QPalette::Window); + + // adjust rect, based on number of buttons to be drawn + const auto rect(scrollBarInternalSubControlRect(sliderOption, SC_ScrollBarSubLine)); + + QColor color; + QStyleOptionSlider copy(*sliderOption); + if (_subLineButtons == DoubleButton) { + if (horizontal) { + // Draw the arrows + const QSize halfSize(rect.width() / 2, rect.height()); + const QRect leftSubButton(rect.topLeft(), halfSize); + const QRect rightSubButton(leftSubButton.topRight() + QPoint(1, 0), halfSize); + + copy.rect = leftSubButton; + color = scrollBarArrowColor(©, reverseLayout ? SC_ScrollBarAddLine : SC_ScrollBarSubLine, widget); + _helper->renderArrow(painter, leftSubButton, color, ArrowLeft); + + copy.rect = rightSubButton; + color = scrollBarArrowColor(©, reverseLayout ? SC_ScrollBarSubLine : SC_ScrollBarAddLine, widget); + _helper->renderArrow(painter, rightSubButton, color, ArrowRight); + + } else { + const QSize halfSize(rect.width(), rect.height() / 2); + const QRect topSubButton(rect.topLeft(), halfSize); + const QRect botSubButton(topSubButton.bottomLeft() + QPoint(0, 1), halfSize); + + copy.rect = topSubButton; + color = scrollBarArrowColor(©, SC_ScrollBarSubLine, widget); + _helper->renderArrow(painter, topSubButton, color, ArrowUp); + + copy.rect = botSubButton; + color = scrollBarArrowColor(©, SC_ScrollBarAddLine, widget); + _helper->renderArrow(painter, botSubButton, color, ArrowDown); + } + + } else if (_subLineButtons == SingleButton) { + copy.rect = rect; + color = scrollBarArrowColor(©, SC_ScrollBarSubLine, widget); + if (horizontal) { + if (reverseLayout) + _helper->renderArrow(painter, rect.translated(1, 0), color, ArrowRight); + else + _helper->renderArrow(painter, rect, color, ArrowLeft); + + } else + _helper->renderArrow(painter, rect, color, ArrowUp); + } + + return true; +} + +//______________________________________________________________ +bool Style::drawScrollBarComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + // the animation for QStyle::SC_ScrollBarGroove is special: it will animate + // the opacity of everything else as well, included slider and arrows + qreal opacity(_animations->scrollBarEngine().opacity(widget, QStyle::SC_ScrollBarGroove)); + const bool animated(StyleConfigData::animationsEnabled() && _animations->scrollBarEngine().isAnimated(widget, AnimationHover, QStyle::SC_ScrollBarGroove)); + const bool mouseOver(option->state & State_MouseOver); + + if (opacity == AnimationData::OpacityInvalid) + opacity = 1; + + // render full groove directly, rather than using the addPage and subPage control element methods + if ((!StyleConfigData::animationsEnabled() || mouseOver || animated) && option->subControls & SC_ScrollBarGroove) { + // retrieve groove rectangle + auto grooveRect(subControlRect(CC_ScrollBar, option, SC_ScrollBarGroove, widget)); + + const auto &palette(option->palette); + const auto color(_helper->alphaColor(palette.color(QPalette::WindowText), 0.3 * (animated ? opacity : 1))); + const auto &state(option->state); + const bool horizontal(state & State_Horizontal); + + if (horizontal) + grooveRect = centerRect(grooveRect, grooveRect.width(), Metrics::ScrollBar_SliderWidth); + else + grooveRect = centerRect(grooveRect, Metrics::ScrollBar_SliderWidth, grooveRect.height()); + + // render + _helper->renderScrollBarGroove(painter, grooveRect, color); + } + + // call base class primitive + ParentStyleClass::drawComplexControl(CC_ScrollBar, option, painter, widget); + + return true; +} + +//______________________________________________________________________________ +const QWidget *Style::scrollBarParent(const QWidget *widget) const +{ + // check widget and parent + if (!(widget && widget->parentWidget())) + return nullptr; + + // try cast to scroll area. Must test both parent and grandparent + QAbstractScrollArea *scrollArea; + if (!(scrollArea = qobject_cast(widget->parentWidget()))) { + scrollArea = qobject_cast(widget->parentWidget()->parentWidget()); + } + + // check scrollarea + if (scrollArea && (widget == scrollArea->verticalScrollBar() || widget == scrollArea->horizontalScrollBar())) { + return scrollArea; + + } else if (widget->parentWidget()->inherits("KTextEditor::View")) { + return widget->parentWidget(); + + } else + return nullptr; +} + +//______________________________________________________________________________ +QColor Style::scrollBarArrowColor(const QStyleOptionSlider *option, const SubControl &control, const QWidget *widget) const +{ + const auto &rect(option->rect); + const auto &palette(option->palette); + auto color(_helper->arrowColor(palette, QPalette::WindowText)); + + bool widgetMouseOver((option->state & State_MouseOver)); + if (widget) + widgetMouseOver = widget->underMouse(); +#if QT_VERSION >= 0x050000 + // in case this QStyle is used by QQuickControls QStyle wrapper + else if (option->styleObject) + widgetMouseOver = option->styleObject->property("hover").toBool(); +#endif + + // check enabled state + const bool enabled(option->state & State_Enabled); + if (!enabled) { + if (StyleConfigData::animationsEnabled()) { + // finally, global opacity when ScrollBarShowOnMouseOver + const qreal globalOpacity(_animations->scrollBarEngine().opacity(widget, QStyle::SC_ScrollBarGroove)); + if (globalOpacity >= 0) + color.setAlphaF(globalOpacity); + // no mouse over and no animation in progress, don't draw arrows at all + else if (!widgetMouseOver) + return Qt::transparent; + } + return color; + } + + if ((control == SC_ScrollBarSubLine && option->sliderValue == option->minimum) || (control == SC_ScrollBarAddLine && option->sliderValue == option->maximum)) { + // manually disable arrow, to indicate that scrollbar is at limit + color = _helper->arrowColor(palette, QPalette::Disabled, QPalette::WindowText); + if (StyleConfigData::animationsEnabled()) { + // finally, global opacity when ScrollBarShowOnMouseOver + const qreal globalOpacity(_animations->scrollBarEngine().opacity(widget, QStyle::SC_ScrollBarGroove)); + if (globalOpacity >= 0) + color.setAlphaF(globalOpacity); + // no mouse over and no animation in progress, don't draw arrows at all + else if (!widgetMouseOver) + return Qt::transparent; + } + return color; + } + + const bool mouseOver(_animations->scrollBarEngine().isHovered(widget, control)); + const bool animated(_animations->scrollBarEngine().isAnimated(widget, AnimationHover, control)); + const qreal opacity(_animations->scrollBarEngine().opacity(widget, control)); + + // retrieve mouse position from engine + QPoint position(mouseOver ? _animations->scrollBarEngine().position(widget) : QPoint(-1, -1)); + if (mouseOver && rect.contains(position)) { + /* + * need to update the arrow controlRect on fly because there is no + * way to get it from the styles directly, outside of repaint events + */ + _animations->scrollBarEngine().setSubControlRect(widget, control, rect); + } + + if (rect.intersects(_animations->scrollBarEngine().subControlRect(widget, control))) { + auto highlight = _helper->hoverColor(palette); + if (animated) { + color = KColorUtils::mix(color, highlight, opacity); + + } else if (mouseOver) { + color = highlight; + } + } + + if (StyleConfigData::animationsEnabled()) { + // finally, global opacity when ScrollBarShowOnMouseOver + const qreal globalOpacity(_animations->scrollBarEngine().opacity(widget, QStyle::SC_ScrollBarGroove)); + if (globalOpacity >= 0) + color.setAlphaF(globalOpacity); + // no mouse over and no animation in progress, don't draw arrows at all + else if (!widgetMouseOver) + return Qt::transparent; + } + + return color; +} + +} diff --git a/kstyle/widgets/slider.cpp b/kstyle/widgets/slider.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/slider.cpp @@ -0,0 +1,296 @@ +#include "breezestyle.h" + +namespace Breeze +{ +QColor Helper::sliderOutlineColor(const QPalette &palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode) const +{ + QColor outline(KColorUtils::mix(palette.color(QPalette::Window), palette.color(QPalette::WindowText), 0.4)); + + // hover takes precedence over focus + if (mode == AnimationHover) { + const QColor hover(hoverColor(palette)); + const QColor focus(focusColor(palette)); + if (hasFocus) + outline = KColorUtils::mix(focus, hover, opacity); + else + outline = KColorUtils::mix(outline, hover, opacity); + + } else if (mouseOver) { + outline = hoverColor(palette); + + } else if (mode == AnimationFocus) { + const QColor focus(focusColor(palette)); + outline = KColorUtils::mix(outline, focus, opacity); + + } else if (hasFocus) { + outline = focusColor(palette); + } + + return outline; +} + +//______________________________________________________________________________ +void Helper::renderSliderGroove(QPainter *painter, const QRect &rect, const QColor &color) const +{ + // setup painter + painter->setRenderHint(QPainter::Antialiasing, true); + + const QRectF baseRect(rect); + const qreal radius(0.5 * Metrics::Slider_GrooveThickness); + + // content + if (color.isValid()) { + painter->setPen(Qt::NoPen); + painter->setBrush(color); + painter->drawRoundedRect(baseRect, radius, radius); + } +} + +//______________________________________________________________________________ +void Helper::renderSliderHandle(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, const QColor &shadow, bool sunken) const +{ + // setup painter + painter->setRenderHint(QPainter::Antialiasing, true); + + // copy rect + QRectF frameRect(rect); + frameRect.adjust(1, 1, -1, -1); + + // shadow + if (shadow.isValid() && !sunken) { + painter->setPen(QPen(shadow, 2)); + painter->setBrush(Qt::NoBrush); + painter->drawEllipse(shadowRect(frameRect)); + } + + // set pen + if (outline.isValid()) { + painter->setPen(outline); + frameRect.adjust(0.5, 0.5, -0.5, -0.5); + + } else + painter->setPen(Qt::NoPen); + + // set brush + if (color.isValid()) + painter->setBrush(color); + else + painter->setBrush(Qt::NoBrush); + + // render + painter->drawEllipse(frameRect); +} + +//___________________________________________________________________________________________________________________ +QRect Style::sliderSubControlRect(const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const +{ + // cast option and check + const auto sliderOption(qstyleoption_cast(option)); + if (!sliderOption) + return ParentStyleClass::subControlRect(CC_Slider, option, subControl, widget); + + switch (subControl) { + case SC_SliderGroove: { + // direction + const bool horizontal(sliderOption->orientation == Qt::Horizontal); + + // get base class rect + auto grooveRect(ParentStyleClass::subControlRect(CC_Slider, option, subControl, widget)); + grooveRect = insideMargin(grooveRect, pixelMetric(PM_DefaultFrameWidth, option, widget)); + + // centering + if (horizontal) + grooveRect = centerRect(grooveRect, grooveRect.width(), Metrics::Slider_GrooveThickness); + else + grooveRect = centerRect(grooveRect, Metrics::Slider_GrooveThickness, grooveRect.height()); + return grooveRect; + } + + default: + return ParentStyleClass::subControlRect(CC_Slider, option, subControl, widget); + } +} + +//______________________________________________________________ +QSize Style::sliderSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *) const +{ + // cast option and check + const auto sliderOption(qstyleoption_cast(option)); + if (!sliderOption) + return contentsSize; + + // store tick position and orientation + const QSlider::TickPosition &tickPosition(sliderOption->tickPosition); + const bool horizontal(sliderOption->orientation == Qt::Horizontal); + const bool disableTicks(!StyleConfigData::sliderDrawTickMarks()); + + // do nothing if no ticks are requested + if (tickPosition == QSlider::NoTicks) + return contentsSize; + + /* + * Qt adds its own tick length directly inside QSlider. + * Take it out and replace by ours, if needed + */ + const int tickLength(disableTicks ? 0 : (Metrics::Slider_TickLength + Metrics::Slider_TickMarginWidth + (Metrics::Slider_GrooveThickness - Metrics::Slider_ControlThickness) / 2)); + + const int builtInTickLength(5); + + QSize size(contentsSize); + if (horizontal) { + if (tickPosition & QSlider::TicksAbove) + size.rheight() += tickLength - builtInTickLength; + if (tickPosition & QSlider::TicksBelow) + size.rheight() += tickLength - builtInTickLength; + + } else { + if (tickPosition & QSlider::TicksAbove) + size.rwidth() += tickLength - builtInTickLength; + if (tickPosition & QSlider::TicksBelow) + size.rwidth() += tickLength - builtInTickLength; + } + + return size; +} + +//______________________________________________________________ +bool Style::drawSliderComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto sliderOption(qstyleoption_cast(option)); + if (!sliderOption) + return true; + + // copy rect and palette + const auto &rect(option->rect); + const auto &palette(option->palette); + + // copy state + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool mouseOver(enabled && (state & State_MouseOver)); + const bool hasFocus(enabled && (state & State_HasFocus)); + + // direction + const bool horizontal(sliderOption->orientation == Qt::Horizontal); + + // tickmarks + if (StyleConfigData::sliderDrawTickMarks() && (sliderOption->subControls & SC_SliderTickmarks)) { + const bool upsideDown(sliderOption->upsideDown); + const int tickPosition(sliderOption->tickPosition); + const int available(pixelMetric(PM_SliderSpaceAvailable, option, widget)); + int interval = sliderOption->tickInterval; + if (interval < 1) + interval = sliderOption->pageStep; + if (interval >= 1) { + const int fudge(pixelMetric(PM_SliderLength, option, widget) / 2); + int current(sliderOption->minimum); + + // store tick lines + const auto grooveRect(subControlRect(CC_Slider, sliderOption, SC_SliderGroove, widget)); + QList tickLines; + if (horizontal) { + if (tickPosition & QSlider::TicksAbove) + tickLines.append(QLine(rect.left(), grooveRect.top() - Metrics::Slider_TickMarginWidth, rect.left(), grooveRect.top() - Metrics::Slider_TickMarginWidth - Metrics::Slider_TickLength)); + if (tickPosition & QSlider::TicksBelow) + tickLines.append(QLine(rect.left(), grooveRect.bottom() + Metrics::Slider_TickMarginWidth, rect.left(), grooveRect.bottom() + Metrics::Slider_TickMarginWidth + Metrics::Slider_TickLength)); + + } else { + if (tickPosition & QSlider::TicksAbove) + tickLines.append(QLine(grooveRect.left() - Metrics::Slider_TickMarginWidth, rect.top(), grooveRect.left() - Metrics::Slider_TickMarginWidth - Metrics::Slider_TickLength, rect.top())); + if (tickPosition & QSlider::TicksBelow) + tickLines.append(QLine(grooveRect.right() + Metrics::Slider_TickMarginWidth, rect.top(), grooveRect.right() + Metrics::Slider_TickMarginWidth + Metrics::Slider_TickLength, rect.top())); + } + + // colors + const auto base(_helper->separatorColor(palette)); + const auto &highlight = palette.color(QPalette::Highlight); + + while (current <= sliderOption->maximum) { + // adjust color + const auto color((enabled && current <= sliderOption->sliderPosition) ? highlight : base); + painter->setPen(color); + + // calculate positions and draw lines + int position(sliderPositionFromValue(sliderOption->minimum, sliderOption->maximum, current, available) + fudge); + foreach (const QLine &tickLine, tickLines) { + if (horizontal) + painter->drawLine(tickLine.translated(upsideDown ? (rect.width() - position) : position, 0)); + else + painter->drawLine(tickLine.translated(0, upsideDown ? (rect.height() - position) : position)); + } + + // go to next position + current += interval; + } + } + } + + // groove + if (sliderOption->subControls & SC_SliderGroove) { + // retrieve groove rect + auto grooveRect(subControlRect(CC_Slider, sliderOption, SC_SliderGroove, widget)); + + // base color + const auto grooveColor(_helper->alphaColor(palette.color(QPalette::WindowText), 0.3)); + + if (!enabled) + _helper->renderSliderGroove(painter, grooveRect, grooveColor); + else { + const bool upsideDown(sliderOption->upsideDown); + + // handle rect + auto handleRect(subControlRect(CC_Slider, sliderOption, SC_SliderHandle, widget)); + + // highlight color + const auto &highlight = palette.color(QPalette::Highlight); + + if (sliderOption->orientation == Qt::Horizontal) { + auto leftRect(grooveRect); + leftRect.setRight(handleRect.right() - Metrics::Slider_ControlThickness / 2); + _helper->renderSliderGroove(painter, leftRect, upsideDown ? grooveColor : highlight); + + auto rightRect(grooveRect); + rightRect.setLeft(handleRect.left() + Metrics::Slider_ControlThickness / 2); + _helper->renderSliderGroove(painter, rightRect, upsideDown ? highlight : grooveColor); + + } else { + auto topRect(grooveRect); + topRect.setBottom(handleRect.bottom() - Metrics::Slider_ControlThickness / 2); + _helper->renderSliderGroove(painter, topRect, upsideDown ? grooveColor : highlight); + + auto bottomRect(grooveRect); + bottomRect.setTop(handleRect.top() + Metrics::Slider_ControlThickness / 2); + _helper->renderSliderGroove(painter, bottomRect, upsideDown ? highlight : grooveColor); + } + } + } + + // handle + if (sliderOption->subControls & SC_SliderHandle) { + // get rect and center + auto handleRect(subControlRect(CC_Slider, sliderOption, SC_SliderHandle, widget)); + + // handle state + const bool handleActive(sliderOption->activeSubControls & SC_SliderHandle); + const bool sunken(state & (State_On | State_Sunken)); + + // animation state + _animations->widgetStateEngine().updateState(widget, AnimationHover, handleActive && mouseOver); + _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus); + const AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); + const qreal opacity(_animations->widgetStateEngine().buttonOpacity(widget)); + + // define colors + const auto &background = palette.color(QPalette::Button); + const auto outline(_helper->sliderOutlineColor(palette, handleActive && mouseOver, hasFocus, opacity, mode)); + const auto shadow(_helper->shadowColor(palette)); + + // render + _helper->renderSliderHandle(painter, handleRect, background, outline, shadow, sunken); + } + + return true; +} + +} diff --git a/kstyle/widgets/spinbox.cpp b/kstyle/widgets/spinbox.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/spinbox.cpp @@ -0,0 +1,168 @@ +#include "breezestyle.h" + +namespace Breeze +{ +//___________________________________________________________________________________________________________________ +QRect Style::spinBoxSubControlRect(const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const +{ + // cast option and check + const auto spinBoxOption(qstyleoption_cast(option)); + if (!spinBoxOption) + return ParentStyleClass::subControlRect(CC_SpinBox, option, subControl, widget); + const bool flat(!spinBoxOption->frame); + + // copy rect + auto rect(option->rect); + + switch (subControl) { + case SC_SpinBoxFrame: + return flat ? QRect() : rect; + + case SC_SpinBoxUp: + case SC_SpinBoxDown: { + // take out frame width + if (!flat && rect.height() >= 2 * Metrics::Frame_FrameWidth + Metrics::SpinBox_ArrowButtonWidth) + rect = insideMargin(rect, Metrics::Frame_FrameWidth); + + QRect arrowRect; + arrowRect = QRect(rect.right() - Metrics::SpinBox_ArrowButtonWidth + 1, rect.top(), Metrics::SpinBox_ArrowButtonWidth, rect.height()); + + const int arrowHeight(qMin(rect.height(), int(Metrics::SpinBox_ArrowButtonWidth))); + arrowRect = centerRect(arrowRect, Metrics::SpinBox_ArrowButtonWidth, arrowHeight); + arrowRect.setHeight(arrowHeight / 2); + if (subControl == SC_SpinBoxDown) + arrowRect.translate(0, arrowHeight / 2); + + return visualRect(option, arrowRect); + } + + case SC_SpinBoxEditField: { + QRect labelRect; + labelRect = QRect(rect.left(), rect.top(), rect.width() - Metrics::SpinBox_ArrowButtonWidth, rect.height()); + + // remove right side line editor margins + const int frameWidth(pixelMetric(PM_SpinBoxFrameWidth, option, widget)); + if (!flat && labelRect.height() >= option->fontMetrics.height() + 2 * frameWidth) { + labelRect.adjust(frameWidth, frameWidth, 0, -frameWidth); + } + + return visualRect(option, labelRect); + } + + default: + break; + } + + return ParentStyleClass::subControlRect(CC_SpinBox, option, subControl, widget); +} + +//______________________________________________________________ +QSize Style::spinBoxSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + // cast option and check + const auto spinBoxOption(qstyleoption_cast(option)); + if (!spinBoxOption) + return contentsSize; + + const bool flat(!spinBoxOption->frame); + + // copy size + QSize size(contentsSize); + + // add editor margins + const int frameWidth(pixelMetric(PM_SpinBoxFrameWidth, option, widget)); + if (!flat) + size = expandSize(size, frameWidth); + + // make sure there is enough height for the button + size.setHeight(qMax(size.height(), int(Metrics::SpinBox_ArrowButtonWidth))); + + // add button width and spacing + size.rwidth() += Metrics::SpinBox_ArrowButtonWidth; + + return size; +} + +//______________________________________________________________ +bool Style::drawSpinBoxComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + const auto spinBoxOption(qstyleoption_cast(option)); + if (!spinBoxOption) + return true; + + // store palette and rect + const auto &palette(option->palette); + const auto &rect(option->rect); + + if (option->subControls & SC_SpinBoxFrame) { + // detect flat spinboxes + bool flat(!spinBoxOption->frame); + flat |= (rect.height() < 2 * Metrics::Frame_FrameWidth + Metrics::SpinBox_ArrowButtonWidth); + if (flat) { + const auto &background = palette.color(QPalette::Base); + + painter->setBrush(background); + painter->setPen(Qt::NoPen); + painter->drawRect(rect); + + } else { + drawPrimitive(PE_FrameLineEdit, option, painter, widget); + } + } + + if (option->subControls & SC_SpinBoxUp) + renderSpinBoxArrow(SC_SpinBoxUp, spinBoxOption, painter, widget); + if (option->subControls & SC_SpinBoxDown) + renderSpinBoxArrow(SC_SpinBoxDown, spinBoxOption, painter, widget); + + return true; +} + +//____________________________________________________________________________________________________ +void Style::renderSpinBoxArrow(const SubControl &subControl, const QStyleOptionSpinBox *option, QPainter *painter, const QWidget *widget) const +{ + const auto &palette(option->palette); + const State &state(option->state); + + // enable state + bool enabled(state & State_Enabled); + + // check steps enable step + const bool atLimit((subControl == SC_SpinBoxUp && !(option->stepEnabled & QAbstractSpinBox::StepUpEnabled)) || (subControl == SC_SpinBoxDown && !(option->stepEnabled & QAbstractSpinBox::StepDownEnabled))); + + // update enabled state accordingly + enabled &= !atLimit; + + // update mouse-over effect + const bool mouseOver(enabled && (state & State_MouseOver)); + + // check animation state + const bool subControlHover(enabled && mouseOver && (option->activeSubControls & subControl)); + _animations->spinBoxEngine().updateState(widget, subControl, subControlHover); + + const bool animated(enabled && _animations->spinBoxEngine().isAnimated(widget, subControl)); + const qreal opacity(_animations->spinBoxEngine().opacity(widget, subControl)); + + auto color = _helper->arrowColor(palette, QPalette::Text); + if (animated) { + auto highlight = _helper->hoverColor(palette); + color = KColorUtils::mix(color, highlight, opacity); + + } else if (subControlHover) { + color = _helper->hoverColor(palette); + + } else if (atLimit) { + color = _helper->arrowColor(palette, QPalette::Disabled, QPalette::Text); + } + + // arrow orientation + ArrowOrientation orientation((subControl == SC_SpinBoxUp) ? ArrowUp : ArrowDown); + + // arrow rect + const auto arrowRect(subControlRect(CC_SpinBox, option, subControl, widget)); + + // render + _helper->renderArrow(painter, arrowRect, color, orientation); +} + +} diff --git a/kstyle/widgets/tabbar.cpp b/kstyle/widgets/tabbar.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/tabbar.cpp @@ -0,0 +1,1022 @@ +#include "tabbar_p.h" + +namespace Breeze +{ +//______________________________________________________________________________ +void Helper::renderTabBarTab(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, Corners corners) const +{ + // setup painter + painter->setRenderHint(QPainter::Antialiasing, true); + + QRectF frameRect(rect); + qreal radius(frameRadius()); + + // pen + if (outline.isValid()) { + painter->setPen(outline); + frameRect.adjust(0.5, 0.5, -0.5, -0.5); + radius = qMax(radius - 1, qreal(0.0)); + + } else + painter->setPen(Qt::NoPen); + + // brush + if (color.isValid()) + painter->setBrush(color); + else + painter->setBrush(Qt::NoBrush); + + // render + QPainterPath path(roundedPath(frameRect, corners, radius)); + painter->drawPath(path); +} + +//______________________________________________________________________________ +void Helper::renderTabWidgetFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, Corners corners) const +{ + painter->setRenderHint(QPainter::Antialiasing); + + QRectF frameRect(rect.adjusted(1, 1, -1, -1)); + qreal radius(frameRadius()); + + // set pen + if (outline.isValid()) { + painter->setPen(outline); + frameRect.adjust(0.5, 0.5, -0.5, -0.5); + radius = qMax(radius - 1, qreal(0.0)); + + } else + painter->setPen(Qt::NoPen); + + // set brush + if (color.isValid()) + painter->setBrush(color); + else + painter->setBrush(Qt::NoBrush); + + // render + QPainterPath path(roundedPath(frameRect, corners, radius)); + painter->drawPath(path); +} + +//____________________________________________________________________ +QRect Style::tabBarTabLeftButtonRect(const QStyleOption *option, const QWidget *) const +{ +// cast option and check +#if BREEZE_USE_KDE4 + const auto tabOption(qstyleoption_cast(option)); +#else + const auto tabOption(qstyleoption_cast(option)); +#endif + if (!tabOption || tabOption->leftButtonSize.isEmpty()) + return QRect(); + + const auto rect(option->rect); + const QSize size(tabOption->leftButtonSize); + QRect buttonRect(QPoint(0, 0), size); + + // vertical positioning + switch (tabOption->shape) { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + buttonRect.moveLeft(rect.left() + Metrics::TabBar_TabMarginWidth); + buttonRect.moveTop((rect.height() - buttonRect.height()) / 2); + buttonRect = visualRect(option, buttonRect); + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + buttonRect.moveBottom(rect.bottom() - Metrics::TabBar_TabMarginWidth); + buttonRect.moveLeft((rect.width() - buttonRect.width()) / 2); + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + buttonRect.moveTop(rect.top() + Metrics::TabBar_TabMarginWidth); + buttonRect.moveLeft((rect.width() - buttonRect.width()) / 2); + break; + + default: + break; + } + + return buttonRect; +} + +//____________________________________________________________________ +QRect Style::tabBarTabRightButtonRect(const QStyleOption *option, const QWidget *) const +{ +// cast option and check +#if BREEZE_USE_KDE4 + const auto tabOption(qstyleoption_cast(option)); +#else + const auto tabOption(qstyleoption_cast(option)); +#endif + if (!tabOption || tabOption->rightButtonSize.isEmpty()) + return QRect(); + + const auto rect(option->rect); + const auto size(tabOption->rightButtonSize); + QRect buttonRect(QPoint(0, 0), size); + + // vertical positioning + switch (tabOption->shape) { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + buttonRect.moveRight(rect.right() - Metrics::TabBar_TabMarginWidth); + buttonRect.moveTop((rect.height() - buttonRect.height()) / 2); + buttonRect = visualRect(option, buttonRect); + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + buttonRect.moveTop(rect.top() + Metrics::TabBar_TabMarginWidth); + buttonRect.moveLeft((rect.width() - buttonRect.width()) / 2); + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + buttonRect.moveBottom(rect.bottom() - Metrics::TabBar_TabMarginWidth); + buttonRect.moveLeft((rect.width() - buttonRect.width()) / 2); + break; + + default: + break; + } + + return buttonRect; +} + +//______________________________________________________________ +QSize Style::tabBarTabSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *) const +{ + const auto tabOption(qstyleoption_cast(option)); + const bool hasText(tabOption && !tabOption->text.isEmpty()); + const bool hasIcon(tabOption && !tabOption->icon.isNull()); +#if BREEZE_USE_KDE4 + const auto tabOptionV3(qstyleoption_cast(option)); + const bool hasLeftButton(tabOptionV3 && !tabOptionV3->leftButtonSize.isEmpty()); + const bool hasRightButton(tabOptionV3 && !tabOptionV3->leftButtonSize.isEmpty()); +#else + const bool hasLeftButton(tabOption && !tabOption->leftButtonSize.isEmpty()); + const bool hasRightButton(tabOption && !tabOption->leftButtonSize.isEmpty()); +#endif + + // calculate width increment for horizontal tabs + int widthIncrement = 0; + if (hasIcon && !(hasText || hasLeftButton || hasRightButton)) + widthIncrement -= 4; + if (hasText && hasIcon) + widthIncrement += Metrics::TabBar_TabItemSpacing; + if (hasLeftButton && (hasText || hasIcon)) + widthIncrement += Metrics::TabBar_TabItemSpacing; + if (hasRightButton && (hasText || hasIcon || hasLeftButton)) + widthIncrement += Metrics::TabBar_TabItemSpacing; + + // add margins + QSize size(contentsSize); + + // compare to minimum size + const bool verticalTabs(tabOption && isVerticalTab(tabOption)); + if (verticalTabs) { + size.rheight() += widthIncrement; + if (hasIcon && !hasText) + size = size.expandedTo(QSize(Metrics::TabBar_TabMinHeight, 0)); + else + size = size.expandedTo(QSize(Metrics::TabBar_TabMinHeight, Metrics::TabBar_TabMinWidth)); + + } else { + size.rwidth() += widthIncrement; + if (hasIcon && !hasText) + size = size.expandedTo(QSize(0, Metrics::TabBar_TabMinHeight)); + else + size = size.expandedTo(QSize(Metrics::TabBar_TabMinWidth, Metrics::TabBar_TabMinHeight)); + } + + return size; +} + +//___________________________________________________________________________________ +bool Style::drawTabBarTabLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // call parent style method + ParentStyleClass::drawControl(CE_TabBarTabLabel, option, painter, widget); + + // store rect and palette + const auto &rect(option->rect); + const auto &palette(option->palette); + + // check focus + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool selected(state & State_Selected); + const bool hasFocus(enabled && selected && (state & State_HasFocus)); + + // update mouse over animation state + _animations->tabBarEngine().updateState(widget, rect.topLeft(), AnimationFocus, hasFocus); + const bool animated(enabled && selected && _animations->tabBarEngine().isAnimated(widget, rect.topLeft(), AnimationFocus)); + const qreal opacity(_animations->tabBarEngine().opacity(widget, rect.topLeft(), AnimationFocus)); + + if (!(hasFocus || animated)) + return true; + + // code is copied from QCommonStyle, but adds focus + // cast option and check + const auto tabOption(qstyleoption_cast(option)); + if (!tabOption || tabOption->text.isEmpty()) + return true; + + // tab option rect + const bool verticalTabs(isVerticalTab(tabOption)); + const int textFlags(Qt::AlignCenter | _mnemonics->textFlags()); + + // text rect + auto textRect(subElementRect(SE_TabBarTabText, option, widget)); + + if (verticalTabs) { + // properly rotate painter + painter->save(); + int newX, newY, newRot; + if (tabOption->shape == QTabBar::RoundedEast || tabOption->shape == QTabBar::TriangularEast) { + newX = rect.width() + rect.x(); + newY = rect.y(); + newRot = 90; + + } else { + newX = rect.x(); + newY = rect.y() + rect.height(); + newRot = -90; + } + + QTransform transform; + transform.translate(newX, newY); + transform.rotate(newRot); + painter->setTransform(transform, true); + } + + // adjust text rect based on font metrics + textRect = option->fontMetrics.boundingRect(textRect, textFlags, tabOption->text); + + // focus color + QColor focusColor; + if (animated) + focusColor = _helper->alphaColor(_helper->focusColor(palette), opacity); + else if (hasFocus) + focusColor = _helper->focusColor(palette); + + // render focus line + _helper->renderFocusLine(painter, textRect, focusColor); + + if (verticalTabs) + painter->restore(); + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawTabBarTabShapeControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + const auto tabOption(qstyleoption_cast(option)); + if (!tabOption) + return true; + + // palette and state + const auto &palette(option->palette); + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool selected(state & State_Selected); + const bool mouseOver(enabled && !selected && (state & State_MouseOver)); + + // check if tab is being dragged + const bool isDragged(widget && selected && painter->device() != widget); + const bool isLocked(widget && _tabBarData->isLocked(widget)); + + // store rect + auto rect(option->rect); + + // update mouse over animation state + _animations->tabBarEngine().updateState(widget, rect.topLeft(), AnimationHover, mouseOver); + const bool animated(enabled && !selected && _animations->tabBarEngine().isAnimated(widget, rect.topLeft(), AnimationHover)); + const qreal opacity(_animations->tabBarEngine().opacity(widget, rect.topLeft(), AnimationHover)); + + // lock state + if (selected && widget && isDragged) + _tabBarData->lock(widget); + else if (widget && selected && _tabBarData->isLocked(widget)) + _tabBarData->release(); + + // tab position + const QStyleOptionTab::TabPosition &position = tabOption->position; + const bool isSingle(position == QStyleOptionTab::OnlyOneTab); + const bool isQtQuickControl(this->isQtQuickControl(option, widget)); + bool isFirst(isSingle || position == QStyleOptionTab::Beginning); + bool isLast(isSingle || position == QStyleOptionTab::End); + bool isLeftOfSelected(!isLocked && tabOption->selectedPosition == QStyleOptionTab::NextIsSelected); + bool isRightOfSelected(!isLocked && tabOption->selectedPosition == QStyleOptionTab::PreviousIsSelected); + + // true if widget is aligned to the frame + // need to check for 'isRightOfSelected' because for some reason the isFirst flag is set when active tab is being moved + isFirst &= !isRightOfSelected; + isLast &= !isLeftOfSelected; + + // swap state based on reverse layout, so that they become layout independent + const bool reverseLayout(option->direction == Qt::RightToLeft); + const bool verticalTabs(isVerticalTab(tabOption)); + if (reverseLayout && !verticalTabs) { + qSwap(isFirst, isLast); + qSwap(isLeftOfSelected, isRightOfSelected); + } + + // overlap + // for QtQuickControls, ovelap is already accounted of in the option. Unlike in the qwidget case + const int overlap(isQtQuickControl ? 0 : Metrics::TabBar_TabOverlap); + + // adjust rect and define corners based on tabbar orientation + Corners corners; + switch (tabOption->shape) { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + if (selected) { + corners = CornerTopLeft | CornerTopRight; + rect.adjust(0, 0, 0, 1); + + } else { + rect.adjust(0, 0, 0, -1); + if (isFirst) + corners |= CornerTopLeft; + if (isLast) + corners |= CornerTopRight; + if (isRightOfSelected) + rect.adjust(-Metrics::Frame_FrameRadius, 0, 0, 0); + if (isLeftOfSelected) + rect.adjust(0, 0, Metrics::Frame_FrameRadius, 0); + else if (!isLast) + rect.adjust(0, 0, overlap, 0); + } + break; + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + if (selected) { + corners = CornerBottomLeft | CornerBottomRight; + rect.adjust(0, -1, 0, 0); + + } else { + rect.adjust(0, 1, 0, 0); + if (isFirst) + corners |= CornerBottomLeft; + if (isLast) + corners |= CornerBottomRight; + if (isRightOfSelected) + rect.adjust(-Metrics::Frame_FrameRadius, 0, 0, 0); + if (isLeftOfSelected) + rect.adjust(0, 0, Metrics::Frame_FrameRadius, 0); + else if (!isLast) + rect.adjust(0, 0, overlap, 0); + } + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + if (selected) { + corners = CornerTopLeft | CornerBottomLeft; + rect.adjust(0, 0, 1, 0); + + } else { + rect.adjust(0, 0, -1, 0); + if (isFirst) + corners |= CornerTopLeft; + if (isLast) + corners |= CornerBottomLeft; + if (isRightOfSelected) + rect.adjust(0, -Metrics::Frame_FrameRadius, 0, 0); + if (isLeftOfSelected) + rect.adjust(0, 0, 0, Metrics::Frame_FrameRadius); + else if (!isLast) + rect.adjust(0, 0, 0, overlap); + } + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + if (selected) { + corners = CornerTopRight | CornerBottomRight; + rect.adjust(-1, 0, 0, 0); + + } else { + rect.adjust(1, 0, 0, 0); + if (isFirst) + corners |= CornerTopRight; + if (isLast) + corners |= CornerBottomRight; + if (isRightOfSelected) + rect.adjust(0, -Metrics::Frame_FrameRadius, 0, 0); + if (isLeftOfSelected) + rect.adjust(0, 0, 0, Metrics::Frame_FrameRadius); + else if (!isLast) + rect.adjust(0, 0, 0, overlap); + } + break; + + default: + break; + } + + // color + QColor color; + if (selected) { +#if QT_VERSION >= 0x050000 + bool documentMode = tabOption->documentMode; +#else + bool documentMode = false; + if (const auto tabOptionV3 = qstyleoption_cast(option)) { + documentMode = tabOptionV3->documentMode; + } +#endif + + // flag passed to QStyleOptionTab is unfortunately not reliable enough + // also need to check on parent widget + const auto tabWidget = (widget && widget->parentWidget()) ? qobject_cast(widget->parentWidget()) : nullptr; + documentMode |= (tabWidget ? tabWidget->documentMode() : true); + + color = (documentMode && !isQtQuickControl && !hasAlteredBackground(widget)) ? palette.color(QPalette::Window) : _helper->frameBackgroundColor(palette); + + } else { + const auto normal(_helper->alphaColor(palette.color(QPalette::Shadow), 0.2)); + const auto hover(_helper->alphaColor(_helper->hoverColor(palette), 0.2)); + if (animated) + color = KColorUtils::mix(normal, hover, opacity); + else if (mouseOver) + color = hover; + else + color = normal; + } + + // outline + const auto outline(selected ? _helper->alphaColor(palette.color(QPalette::WindowText), 0.25) : QColor()); + + // render + if (selected) { + QRegion oldRegion(painter->clipRegion()); + painter->setClipRect(option->rect, Qt::IntersectClip); + _helper->renderTabBarTab(painter, rect, color, outline, corners); + painter->setClipRegion(oldRegion); + + } else { + _helper->renderTabBarTab(painter, rect, color, outline, corners); + } + + return true; +} + +//____________________________________________________________________ +QRect Style::tabWidgetTabBarRect(const QStyleOption *option, const QWidget *widget) const +{ + // cast option and check + const auto tabOption = qstyleoption_cast(option); + if (!tabOption) + return ParentStyleClass::subElementRect(SE_TabWidgetTabBar, option, widget); + + // do nothing if tabbar is hidden + const QSize tabBarSize(tabOption->tabBarSize); + + auto rect(option->rect); + QRect tabBarRect(QPoint(0, 0), tabBarSize); + + Qt::Alignment tabBarAlignment(styleHint(SH_TabBar_Alignment, option, widget)); + + // horizontal positioning + const bool verticalTabs(isVerticalTab(tabOption->shape)); + if (verticalTabs) { + tabBarRect.setHeight(qMin(tabBarRect.height(), rect.height() - 2)); + if (tabBarAlignment == Qt::AlignCenter) + tabBarRect.moveTop(rect.top() + (rect.height() - tabBarRect.height()) / 2); + else + tabBarRect.moveTop(rect.top() + 1); + + } else { + // account for corner rects + // need to re-run visualRect to remove right-to-left handling, since it is re-added on tabBarRect at the end + const auto leftButtonRect(visualRect(option, subElementRect(SE_TabWidgetLeftCorner, option, widget))); + const auto rightButtonRect(visualRect(option, subElementRect(SE_TabWidgetRightCorner, option, widget))); + + rect.setLeft(leftButtonRect.width()); + rect.setRight(rightButtonRect.left() - 1); + + tabBarRect.setWidth(qMin(tabBarRect.width(), rect.width() - 2)); + if (tabBarAlignment == Qt::AlignCenter) + tabBarRect.moveLeft(rect.left() + (rect.width() - tabBarRect.width()) / 2); + else + tabBarRect.moveLeft(rect.left() + 1); + + tabBarRect = visualRect(option, tabBarRect); + } + + // vertical positioning + switch (tabOption->shape) { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + tabBarRect.moveTop(rect.top() + 1); + break; + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + tabBarRect.moveBottom(rect.bottom() - 1); + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + tabBarRect.moveLeft(rect.left() + 1); + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + tabBarRect.moveRight(rect.right() - 1); + break; + + default: + break; + } + + return tabBarRect; +} + +//____________________________________________________________________ +QRect Style::tabWidgetTabContentsRect(const QStyleOption *option, const QWidget *widget) const +{ + // cast option and check + const auto tabOption = qstyleoption_cast(option); + if (!tabOption) + return option->rect; + + // do nothing if tabbar is hidden + if (tabOption->tabBarSize.isEmpty()) + return option->rect; + const auto rect = tabWidgetTabPaneRect(option, widget); + + const bool documentMode(tabOption->lineWidth == 0); + if (documentMode) { + // add margin only to the relevant side + switch (tabOption->shape) { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + return rect.adjusted(0, Metrics::TabWidget_MarginWidth, 0, 0); + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + return rect.adjusted(0, 0, 0, -Metrics::TabWidget_MarginWidth); + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + return rect.adjusted(Metrics::TabWidget_MarginWidth, 0, 0, 0); + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + return rect.adjusted(0, 0, -Metrics::TabWidget_MarginWidth, 0); + + default: + return rect; + } + + } else + return insideMargin(rect, Metrics::TabWidget_MarginWidth); +} + +//____________________________________________________________________ +QRect Style::tabWidgetTabPaneRect(const QStyleOption *option, const QWidget *) const +{ + const auto tabOption = qstyleoption_cast(option); + if (!tabOption || tabOption->tabBarSize.isEmpty()) + return option->rect; + + const int overlap = Metrics::TabBar_BaseOverlap - 1; + const QSize tabBarSize(tabOption->tabBarSize - QSize(overlap, overlap)); + + auto rect(option->rect); + switch (tabOption->shape) { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + rect.adjust(0, tabBarSize.height(), 0, 0); + break; + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + rect.adjust(0, 0, 0, -tabBarSize.height()); + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + rect.adjust(tabBarSize.width(), 0, 0, 0); + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + rect.adjust(0, 0, -tabBarSize.width(), 0); + break; + + default: + return QRect(); + } + + return rect; +} + +//____________________________________________________________________ +QRect Style::tabWidgetCornerRect(SubElement element, const QStyleOption *option, const QWidget *) const +{ + // cast option and check + const auto tabOption = qstyleoption_cast(option); + if (!tabOption) + return option->rect; + + // do nothing if tabbar is hidden + const QSize tabBarSize(tabOption->tabBarSize); + if (tabBarSize.isEmpty()) + return QRect(); + + // do nothing for vertical tabs + const bool verticalTabs(isVerticalTab(tabOption->shape)); + if (verticalTabs) + return QRect(); + + const auto rect(option->rect); + QRect cornerRect; + switch (element) { + case SE_TabWidgetLeftCorner: + cornerRect = QRect(QPoint(0, 0), tabOption->leftCornerWidgetSize); + cornerRect.moveLeft(rect.left()); + break; + + case SE_TabWidgetRightCorner: + cornerRect = QRect(QPoint(0, 0), tabOption->rightCornerWidgetSize); + cornerRect.moveRight(rect.right()); + break; + + default: + break; + } + + // expend height to tabBarSize, if needed, to make sure base is properly rendered + cornerRect.setHeight(qMax(cornerRect.height(), tabBarSize.height() + 1)); + + switch (tabOption->shape) { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + cornerRect.moveTop(rect.top()); + break; + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + cornerRect.moveBottom(rect.bottom()); + break; + + default: + break; + } + + // return cornerRect; + cornerRect = visualRect(option, cornerRect); + return cornerRect; +} + +//______________________________________________________________ +QSize Style::tabWidgetSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + // cast option and check + const auto tabOption = qstyleoption_cast(option); + if (!tabOption) + return expandSize(contentsSize, Metrics::TabWidget_MarginWidth); + + // try find direct children of type QTabBar and QStackedWidget + // this is needed in order to add TabWidget margins only if they are necessary around tabWidget content, not the tabbar + if (!widget) + return expandSize(contentsSize, Metrics::TabWidget_MarginWidth); + QTabBar *tabBar = nullptr; + QStackedWidget *stack = nullptr; + auto children(widget->children()); + foreach (auto child, children) { + if (!tabBar) + tabBar = qobject_cast(child); + if (!stack) + stack = qobject_cast(child); + if (tabBar && stack) + break; + } + + if (!(tabBar && stack)) + return expandSize(contentsSize, Metrics::TabWidget_MarginWidth); + + // tab orientation + const bool verticalTabs(tabOption && isVerticalTab(tabOption->shape)); + if (verticalTabs) { + const int tabBarHeight = tabBar->minimumSizeHint().height(); + const int stackHeight = stack->minimumSizeHint().height(); + if (contentsSize.height() == tabBarHeight && tabBarHeight + 2 * (Metrics::Frame_FrameWidth - 1) >= stackHeight + 2 * Metrics::TabWidget_MarginWidth) + return QSize(contentsSize.width() + 2 * Metrics::TabWidget_MarginWidth, contentsSize.height() + 2 * (Metrics::Frame_FrameWidth - 1)); + else + return expandSize(contentsSize, Metrics::TabWidget_MarginWidth); + + } else { + const int tabBarWidth = tabBar->minimumSizeHint().width(); + const int stackWidth = stack->minimumSizeHint().width(); + if (contentsSize.width() == tabBarWidth && tabBarWidth + 2 * (Metrics::Frame_FrameWidth - 1) >= stackWidth + 2 * Metrics::TabWidget_MarginWidth) + return QSize(contentsSize.width() + 2 * (Metrics::Frame_FrameWidth - 1), contentsSize.height() + 2 * Metrics::TabWidget_MarginWidth); + else + return expandSize(contentsSize, Metrics::TabWidget_MarginWidth); + } +} + +//___________________________________________________________________________________ +bool Style::drawFrameTabWidgetPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ +// cast option and check +#if BREEZE_USE_KDE4 + const auto tabOption(qstyleoption_cast(option)); +#else + const auto tabOption(qstyleoption_cast(option)); +#endif + if (!tabOption) + return true; + + // do nothing if tabbar is hidden + const bool isQtQuickControl(this->isQtQuickControl(option, widget)); + if (tabOption->tabBarSize.isEmpty() && !isQtQuickControl) + return true; + + // adjust rect to handle overlaps + auto rect(option->rect); + + const auto tabBarRect(tabOption->tabBarRect); + const QSize tabBarSize(tabOption->tabBarSize); + Corners corners = AllCorners; + + // adjust corners to deal with oversized tabbars + switch (tabOption->shape) { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + if (isQtQuickControl) + rect.adjust(-1, -1, 1, 0); + if (tabBarSize.width() >= rect.width() - 2 * Metrics::Frame_FrameRadius) + corners &= ~CornersTop; + if (tabBarRect.left() < rect.left() + Metrics::Frame_FrameRadius) + corners &= ~CornerTopLeft; + if (tabBarRect.right() > rect.right() - Metrics::Frame_FrameRadius) + corners &= ~CornerTopRight; + break; + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + if (isQtQuickControl) + rect.adjust(-1, 0, 1, 1); + if (tabBarSize.width() >= rect.width() - 2 * Metrics::Frame_FrameRadius) + corners &= ~CornersBottom; + if (tabBarRect.left() < rect.left() + Metrics::Frame_FrameRadius) + corners &= ~CornerBottomLeft; + if (tabBarRect.right() > rect.right() - Metrics::Frame_FrameRadius) + corners &= ~CornerBottomRight; + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + if (isQtQuickControl) + rect.adjust(-1, 0, 0, 0); + if (tabBarSize.height() >= rect.height() - 2 * Metrics::Frame_FrameRadius) + corners &= ~CornersLeft; + if (tabBarRect.top() < rect.top() + Metrics::Frame_FrameRadius) + corners &= ~CornerTopLeft; + if (tabBarRect.bottom() > rect.bottom() - Metrics::Frame_FrameRadius) + corners &= ~CornerBottomLeft; + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + if (isQtQuickControl) + rect.adjust(0, 0, 1, 0); + if (tabBarSize.height() >= rect.height() - 2 * Metrics::Frame_FrameRadius) + corners &= ~CornersRight; + if (tabBarRect.top() < rect.top() + Metrics::Frame_FrameRadius) + corners &= ~CornerTopRight; + if (tabBarRect.bottom() > rect.bottom() - Metrics::Frame_FrameRadius) + corners &= ~CornerBottomRight; + break; + + default: + break; + } + + // define colors + const auto &palette(option->palette); + const auto background(_helper->frameBackgroundColor(palette)); + const auto outline(_helper->frameOutlineColor(palette)); + _helper->renderTabWidgetFrame(painter, rect, background, outline, corners); + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawFrameTabBarBasePrimitive(const QStyleOption *option, QPainter *painter, const QWidget *) const +{ + // tabbar frame used either for 'separate' tabbar, or in 'document mode' + + // cast option and check + const auto tabOption(qstyleoption_cast(option)); + if (!tabOption) + return true; + + // get rect, orientation, palette + const auto rect(option->rect); + const auto outline(_helper->frameOutlineColor(option->palette)); + + // setup painter + painter->setBrush(Qt::NoBrush); + painter->setRenderHint(QPainter::Antialiasing, false); + painter->setPen(QPen(outline, 1)); + + // render + switch (tabOption->shape) { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + painter->drawLine(rect.bottomLeft() - QPoint(1, 0), rect.bottomRight() + QPoint(1, 0)); + break; + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + painter->drawLine(rect.topLeft() - QPoint(1, 0), rect.topRight() + QPoint(1, 0)); + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + painter->drawLine(rect.topRight() - QPoint(0, 1), rect.bottomRight() + QPoint(1, 0)); + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + painter->drawLine(rect.topLeft() - QPoint(0, 1), rect.bottomLeft() + QPoint(1, 0)); + break; + + default: + break; + } + + return true; +} + +//______________________________________________________________ +bool Style::drawTabBarPanelButtonToolPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // copy palette and rect + auto rect(option->rect); + + // static_cast is safe here since check was already performed in calling function + const QTabBar *tabBar(static_cast(widget->parentWidget())); + + // overlap. + // subtract 1, because of the empty pixel left the tabwidget frame + const int overlap(Metrics::TabBar_BaseOverlap - 1); + + // adjust rect based on tabbar shape + switch (tabBar->shape()) { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + rect.adjust(0, 0, 0, -overlap); + break; + + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + rect.adjust(0, overlap, 0, 0); + break; + + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + rect.adjust(0, 0, -overlap, 0); + break; + + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + rect.adjust(overlap, 0, 0, 0); + break; + + default: + break; + } + + // get the relevant palette + const QWidget *parent(tabBar->parentWidget()); + if (qobject_cast(parent)) + parent = parent->parentWidget(); + const auto &palette(parent ? parent->palette() : QApplication::palette()); + const auto color = hasAlteredBackground(parent) ? _helper->frameBackgroundColor(palette) : palette.color(QPalette::Window); + + // render flat background + painter->setPen(Qt::NoPen); + painter->setBrush(color); + painter->drawRect(rect); + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawIndicatorTabTearPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *) const +{ + // cast option and check + const auto tabOption(qstyleoption_cast(option)); + if (!tabOption) + return true; + + // store palette and rect + const auto &palette(option->palette); + auto rect(option->rect); + + const bool reverseLayout(option->direction == Qt::RightToLeft); + + const auto color(_helper->alphaColor(palette.color(QPalette::WindowText), 0.2)); + painter->setRenderHint(QPainter::Antialiasing, false); + painter->setPen(color); + painter->setBrush(Qt::NoBrush); + switch (tabOption->shape) { + case QTabBar::TriangularNorth: + case QTabBar::RoundedNorth: + rect.adjust(0, 1, 0, 0); + if (reverseLayout) + painter->drawLine(rect.topRight(), rect.bottomRight()); + else + painter->drawLine(rect.topLeft(), rect.bottomLeft()); + break; + + case QTabBar::TriangularSouth: + case QTabBar::RoundedSouth: + rect.adjust(0, 0, 0, -1); + if (reverseLayout) + painter->drawLine(rect.topRight(), rect.bottomRight()); + else + painter->drawLine(rect.topLeft(), rect.bottomLeft()); + break; + + case QTabBar::TriangularWest: + case QTabBar::RoundedWest: + rect.adjust(1, 0, 0, 0); + painter->drawLine(rect.topLeft(), rect.topRight()); + break; + + case QTabBar::TriangularEast: + case QTabBar::RoundedEast: + rect.adjust(0, 0, -1, 0); + painter->drawLine(rect.topLeft(), rect.topRight()); + break; + + default: + break; + } + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawIndicatorTabClosePrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // get icon and check + QIcon icon(standardIcon(SP_TitleBarCloseButton, option, widget)); + if (icon.isNull()) + return false; + + // store state + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool active(state & State_Raised); + const bool sunken(state & State_Sunken); + + // decide icon mode and state + QIcon::Mode iconMode; + QIcon::State iconState; + if (!enabled) { + iconMode = QIcon::Disabled; + iconState = QIcon::Off; + + } else { + if (active) + iconMode = QIcon::Active; + else + iconMode = QIcon::Normal; + + iconState = sunken ? QIcon::On : QIcon::Off; + } + + // icon size + const int iconWidth(pixelMetric(QStyle::PM_SmallIconSize, option, widget)); + const QSize iconSize(iconWidth, iconWidth); + + // get pixmap + const QPixmap pixmap(icon.pixmap(iconSize, iconMode, iconState)); + + // render + drawItemPixmap(painter, option->rect, Qt::AlignCenter, pixmap); + return true; +} + +} diff --git a/kstyle/widgets/tabbar_p.h b/kstyle/widgets/tabbar_p.h new file mode 100644 --- /dev/null +++ b/kstyle/widgets/tabbar_p.h @@ -0,0 +1,42 @@ +#ifndef TABBAR_P_H_INCLUDED +#define TABBAR_P_H_INCLUDED + +#include "breezestyle.h" + +namespace BreezePrivate +{ +// needed to keep track of tabbars when being dragged +class TabBarData : public QObject +{ +public: + //* constructor + explicit TabBarData(QObject *parent) + : QObject(parent) + { + } + + //* assign target tabBar + void lock(const QWidget *widget) + { + _tabBar = widget; + } + + //* true if tabbar is locked + bool isLocked(const QWidget *widget) const + { + return _tabBar && _tabBar.data() == widget; + } + + //* release + void release() + { + _tabBar.clear(); + } + +private: + //* pointer to target tabBar + Breeze::WeakPointer _tabBar; +}; + +} +#endif // TABBAR_P_H_INCLUDED diff --git a/kstyle/widgets/toolbar.cpp b/kstyle/widgets/toolbar.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/toolbar.cpp @@ -0,0 +1,138 @@ +#include "breezestyle.h" + +#include + +namespace Breeze +{ +//___________________________________________________________________________________ +bool Style::drawIndicatorToolBarHandlePrimitive(const QStyleOption *option, QPainter *painter, const QWidget *) const +{ + // do nothing if disabled from options + if (!StyleConfigData::toolBarDrawItemSeparator()) + return true; + + // store rect and palette + auto rect(option->rect); + const auto &palette(option->palette); + + // store state + const State &state(option->state); + const bool separatorIsVertical(state & State_Horizontal); + + // define color and render + const auto color(_helper->separatorColor(palette)); + if (separatorIsVertical) { + rect.setWidth(Metrics::ToolBar_HandleWidth); + rect = centerRect(option->rect, rect.size()); + rect.setWidth(3); + _helper->renderSeparator(painter, rect, color, separatorIsVertical); + + rect.translate(2, 0); + _helper->renderSeparator(painter, rect, color, separatorIsVertical); + + } else { + rect.setHeight(Metrics::ToolBar_HandleWidth); + rect = centerRect(option->rect, rect.size()); + rect.setHeight(3); + _helper->renderSeparator(painter, rect, color, separatorIsVertical); + + rect.translate(0, 2); + _helper->renderSeparator(painter, rect, color, separatorIsVertical); + } + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawIndicatorToolBarSeparatorPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + /* + * do nothing if disabled from options + * also need to check if widget is a combobox, because of Qt hack using 'toolbar' separator primitive + * for rendering separators in comboboxes + */ + if (!(StyleConfigData::toolBarDrawItemSeparator() || qobject_cast(widget))) { + return true; + } + + // store rect and palette + const auto &rect(option->rect); + const auto &palette(option->palette); + + // store state + const State &state(option->state); + const bool separatorIsVertical(state & State_Horizontal); + + // define color and render + const auto color(_helper->separatorColor(palette)); + _helper->renderSeparator(painter, rect, color, separatorIsVertical); + + return true; +} + +//____________________________________________________________________________________ +QIcon Style::toolBarExtensionIcon(StandardPixmap standardPixmap, const QStyleOption *option, const QWidget *widget) const +{ + // store palette + // due to Qt, it is not always safe to assume that either option, nor widget are defined + QPalette palette; + if (option) + palette = option->palette; + else if (widget) + palette = widget->palette(); + else + palette = QApplication::palette(); + + // convenience class to map color to icon mode + struct IconData { + QColor _color; + QIcon::Mode _mode; + QIcon::State _state; + }; + + // map colors to icon states + const QList iconTypes = {{palette.color(QPalette::Active, QPalette::WindowText), QIcon::Normal, QIcon::Off}, + {palette.color(QPalette::Active, QPalette::WindowText), QIcon::Selected, QIcon::Off}, + {palette.color(QPalette::Active, QPalette::WindowText), QIcon::Active, QIcon::Off}, + {palette.color(QPalette::Disabled, QPalette::WindowText), QIcon::Disabled, QIcon::Off}, + + {palette.color(QPalette::Active, QPalette::HighlightedText), QIcon::Normal, QIcon::On}, + {palette.color(QPalette::Active, QPalette::HighlightedText), QIcon::Selected, QIcon::On}, + {palette.color(QPalette::Active, QPalette::WindowText), QIcon::Active, QIcon::On}, + {palette.color(QPalette::Disabled, QPalette::WindowText), QIcon::Disabled, QIcon::On}}; + + // default icon sizes + static const QList iconSizes = {8, 16, 22, 32, 48}; + + // decide arrow orientation + const ArrowOrientation orientation(standardPixmap == SP_ToolBarHorizontalExtensionButton ? ArrowRight : ArrowDown); + + // create icon and fill + QIcon icon; + foreach (const IconData &iconData, iconTypes) { + foreach (const int &iconSize, iconSizes) { + // create pixmap + QPixmap pixmap(iconSize, iconSize); + pixmap.fill(Qt::transparent); + + // render + QPainter painter(&pixmap); + + // icon size + const int fixedIconSize(pixelMetric(QStyle::PM_SmallIconSize, option, widget)); + const QRect fixedRect(0, 0, fixedIconSize, fixedIconSize); + + painter.setWindow(fixedRect); + painter.translate(standardPixmap == SP_ToolBarHorizontalExtensionButton ? QPoint(1, 0) : QPoint(0, 1)); + _helper->renderArrow(&painter, fixedRect, iconData._color, orientation); + painter.end(); + + // add to icon + icon.addPixmap(pixmap, iconData._mode, iconData._state); + } + } + + return icon; +} + +} diff --git a/kstyle/widgets/toolbox.cpp b/kstyle/widgets/toolbox.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/toolbox.cpp @@ -0,0 +1,198 @@ +#include "breezestyle.h" + +namespace Breeze +{ +//______________________________________________________________________________ +void Helper::renderToolBoxFrame(QPainter *painter, const QRect &rect, int tabWidth, const QColor &outline) const +{ + if (!outline.isValid()) + return; + + // round radius + const qreal radius(frameRadius()); + const QSizeF cornerSize(2 * radius, 2 * radius); + + // if rect - tabwidth is even, need to increase tabWidth by 1 unit + // for anti aliasing + if (!((rect.width() - tabWidth) % 2)) + ++tabWidth; + + // adjust rect for antialiasing + QRectF baseRect(rect); + baseRect.adjust(0.5, 0.5, -0.5, -0.5); + + // create path + QPainterPath path; + path.moveTo(0, baseRect.height() - 1); + path.lineTo((baseRect.width() - tabWidth) / 2 - radius, baseRect.height() - 1); + path.arcTo(QRectF(QPointF((baseRect.width() - tabWidth) / 2 - 2 * radius, baseRect.height() - 1 - 2 * radius), cornerSize), 270, 90); + path.lineTo((baseRect.width() - tabWidth) / 2, radius); + path.arcTo(QRectF(QPointF((baseRect.width() - tabWidth) / 2, 0), cornerSize), 180, -90); + path.lineTo((baseRect.width() + tabWidth) / 2 - 1 - radius, 0); + path.arcTo(QRectF(QPointF((baseRect.width() + tabWidth) / 2 - 1 - 2 * radius, 0), cornerSize), 90, -90); + path.lineTo((baseRect.width() + tabWidth) / 2 - 1, baseRect.height() - 1 - radius); + path.arcTo(QRectF(QPointF((baseRect.width() + tabWidth) / 2 - 1, baseRect.height() - 1 - 2 * radius), cornerSize), 180, 90); + path.lineTo(baseRect.width() - 1, baseRect.height() - 1); + + // render + painter->setRenderHints(QPainter::Antialiasing); + painter->setBrush(Qt::NoBrush); + painter->setPen(outline); + painter->translate(baseRect.topLeft()); + painter->drawPath(path); +} + +//____________________________________________________________________ +QRect Style::toolBoxTabContentsRect(const QStyleOption *option, const QWidget *widget) const +{ + // cast option and check + const auto toolBoxOption(qstyleoption_cast(option)); + if (!toolBoxOption) + return option->rect; + + // copy rect + const auto &rect(option->rect); + + int contentsWidth(0); + if (!toolBoxOption->icon.isNull()) { + const int iconSize(pixelMetric(QStyle::PM_SmallIconSize, option, widget)); + contentsWidth += iconSize; + + if (!toolBoxOption->text.isEmpty()) + contentsWidth += Metrics::ToolBox_TabItemSpacing; + } + + if (!toolBoxOption->text.isEmpty()) { + const int textWidth = toolBoxOption->fontMetrics.size(_mnemonics->textFlags(), toolBoxOption->text).width(); + contentsWidth += textWidth; + } + + contentsWidth += 2 * Metrics::ToolBox_TabMarginWidth; + contentsWidth = qMin(contentsWidth, rect.width()); + contentsWidth = qMax(contentsWidth, int(Metrics::ToolBox_TabMinWidth)); + return centerRect(rect, contentsWidth, rect.height()); +} + +//___________________________________________________________________________________ +bool Style::drawToolBoxTabLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // rendering is similar to drawPushButtonLabelControl + // cast option and check + const auto toolBoxOption(qstyleoption_cast(option)); + if (!toolBoxOption) + return true; + + // copy palette + const auto &palette(option->palette); + + const State &state(option->state); + const bool enabled(state & State_Enabled); + + // text alignment + const int textFlags(_mnemonics->textFlags() | Qt::AlignCenter); + + // contents rect + const auto rect(subElementRect(SE_ToolBoxTabContents, option, widget)); + + // store icon size + const int iconSize(pixelMetric(QStyle::PM_SmallIconSize, option, widget)); + + // find contents size and rect + auto contentsRect(rect); + QSize contentsSize; + if (!toolBoxOption->text.isEmpty()) { + contentsSize = option->fontMetrics.size(_mnemonics->textFlags(), toolBoxOption->text); + if (!toolBoxOption->icon.isNull()) + contentsSize.rwidth() += Metrics::ToolBox_TabItemSpacing; + } + + // icon size + if (!toolBoxOption->icon.isNull()) { + contentsSize.setHeight(qMax(contentsSize.height(), iconSize)); + contentsSize.rwidth() += iconSize; + } + + // adjust contents rect + contentsRect = centerRect(contentsRect, contentsSize); + + // render icon + if (!toolBoxOption->icon.isNull()) { + // icon rect + QRect iconRect; + if (toolBoxOption->text.isEmpty()) + iconRect = centerRect(contentsRect, iconSize, iconSize); + else { + iconRect = contentsRect; + iconRect.setWidth(iconSize); + iconRect = centerRect(iconRect, iconSize, iconSize); + contentsRect.setLeft(iconRect.right() + Metrics::ToolBox_TabItemSpacing + 1); + } + + iconRect = visualRect(option, iconRect); + const QIcon::Mode mode(enabled ? QIcon::Normal : QIcon::Disabled); + const QPixmap pixmap(toolBoxOption->icon.pixmap(iconSize, mode)); + drawItemPixmap(painter, iconRect, textFlags, pixmap); + } + + // render text + if (!toolBoxOption->text.isEmpty()) { + contentsRect = visualRect(option, contentsRect); + drawItemText(painter, contentsRect, textFlags, palette, enabled, toolBoxOption->text, QPalette::WindowText); + } + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawToolBoxTabShapeControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto toolBoxOption(qstyleoption_cast(option)); + if (!toolBoxOption) + return true; + + // copy rect and palette + const auto &rect(option->rect); + const auto tabRect(toolBoxTabContentsRect(option, widget)); + + /* + * important: option returns the wrong palette. + * we use the widget palette instead, when set + */ + const auto &palette(widget ? widget->palette() : option->palette); + + // store flags + const State &flags(option->state); + const bool enabled(flags & State_Enabled); + const bool selected(flags & State_Selected); + const bool mouseOver(enabled && !selected && (flags & State_MouseOver)); + + // update animation state + /* + * the proper widget ( the toolbox tab ) is not passed as argument by Qt. + * What is passed is the toolbox directly. To implement animations properly, + *the painter->device() is used instead + */ + bool isAnimated(false); + qreal opacity(AnimationData::OpacityInvalid); + QPaintDevice *device = painter->device(); + if (enabled && device) { + _animations->toolBoxEngine().updateState(device, mouseOver); + isAnimated = _animations->toolBoxEngine().isAnimated(device); + opacity = _animations->toolBoxEngine().opacity(device); + } + + // color + QColor outline; + if (selected) + outline = _helper->focusColor(palette); + else + outline = _helper->frameOutlineColor(palette, mouseOver, false, opacity, isAnimated ? AnimationHover : AnimationNone); + + // render + _helper->renderToolBoxFrame(painter, rect, tabRect.width(), outline); + + return true; +} + +} diff --git a/kstyle/widgets/toolbutton.cpp b/kstyle/widgets/toolbutton.cpp new file mode 100644 --- /dev/null +++ b/kstyle/widgets/toolbutton.cpp @@ -0,0 +1,569 @@ +#include "breezestyle.h" +#include + +namespace Breeze +{ +//____________________________________________________________________ +QColor Helper::toolButtonColor(const QPalette &palette, bool mouseOver, bool hasFocus, bool sunken, qreal opacity, AnimationMode mode) const +{ + QColor outline; + const QColor hoverColor(this->hoverColor(palette)); + const QColor focusColor(this->focusColor(palette)); + const QColor sunkenColor = alphaColor(palette.color(QPalette::WindowText), 0.2); + + // hover takes precedence over focus + if (mode == AnimationHover) { + if (hasFocus) + outline = KColorUtils::mix(focusColor, hoverColor, opacity); + else if (sunken) + outline = sunkenColor; + else + outline = alphaColor(hoverColor, opacity); + + } else if (mouseOver) { + outline = hoverColor; + + } else if (mode == AnimationFocus) { + if (sunken) + outline = KColorUtils::mix(sunkenColor, focusColor, opacity); + else + outline = alphaColor(focusColor, opacity); + + } else if (hasFocus) { + outline = focusColor; + + } else if (sunken) { + outline = sunkenColor; + } + + return outline; +} + +//______________________________________________________________________________ +void Helper::renderToolButtonFrame(QPainter *painter, const QRect &rect, const QColor &color, bool sunken) const +{ + // do nothing for invalid color + if (!color.isValid()) + return; + + // setup painter + painter->setRenderHints(QPainter::Antialiasing); + + const QRectF baseRect(rect); + + if (sunken) { + const qreal radius(frameRadius()); + + painter->setPen(Qt::NoPen); + painter->setBrush(color); + + const QRectF contentRect(baseRect.adjusted(1, 1, -1, -1)); + painter->drawRoundedRect(contentRect, radius, radius); + + } else { + const qreal radius(frameRadius(-0.5)); + + painter->setPen(color); + painter->setBrush(Qt::NoBrush); + const QRectF outlineRect(baseRect.adjusted(1.5, 1.5, -1.5, -1.5)); + painter->drawRoundedRect(outlineRect, radius, radius); + } +} + +//___________________________________________________________________________________________________________________ +QRect Style::toolButtonSubControlRect(const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const +{ + // cast option and check + const auto toolButtonOption = qstyleoption_cast(option); + if (!toolButtonOption) + return ParentStyleClass::subControlRect(CC_ToolButton, option, subControl, widget); + + const bool hasPopupMenu(toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup); + const bool hasInlineIndicator(toolButtonOption->features & QStyleOptionToolButton::HasMenu && toolButtonOption->features & QStyleOptionToolButton::PopupDelay && !hasPopupMenu); + + // store rect + const auto &rect(option->rect); + const int menuButtonWidth(Metrics::MenuButton_IndicatorWidth); + switch (subControl) { + case SC_ToolButtonMenu: { + // check features + if (!(hasPopupMenu || hasInlineIndicator)) + return QRect(); + + // check features + auto menuRect(rect); + menuRect.setLeft(rect.right() - menuButtonWidth + 1); + if (hasInlineIndicator) { + menuRect.setTop(menuRect.bottom() - menuButtonWidth + 1); + } + + return visualRect(option, menuRect); + } + + case SC_ToolButton: { + if (hasPopupMenu) { + auto contentsRect(rect); + contentsRect.setRight(rect.right() - menuButtonWidth); + return visualRect(option, contentsRect); + + } else + return rect; + } + + default: + return QRect(); + } +} + +//______________________________________________________________ +QSize Style::toolButtonSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *) const +{ + // cast option and check + const auto toolButtonOption = qstyleoption_cast(option); + if (!toolButtonOption) + return contentsSize; + + // copy size + QSize size = contentsSize; + + // get relevant state flags + const State &state(option->state); + const bool autoRaise(state & State_AutoRaise); + const bool hasPopupMenu(toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup); + const bool hasInlineIndicator(toolButtonOption->features & QStyleOptionToolButton::HasMenu && toolButtonOption->features & QStyleOptionToolButton::PopupDelay && !hasPopupMenu); + + const int marginWidth(autoRaise ? Metrics::ToolButton_MarginWidth : Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth); + + if (hasInlineIndicator) + size.rwidth() += Metrics::ToolButton_InlineIndicatorWidth; + size = expandSize(size, marginWidth); + + return size; +} + +//______________________________________________________________ +bool Style::drawPanelButtonToolPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // copy palette and rect + const auto &palette(option->palette); + auto rect(option->rect); + + // store relevant flags + const State &state(option->state); + const bool autoRaise(state & State_AutoRaise); + const bool enabled(state & State_Enabled); + const bool sunken(state & (State_On | State_Sunken)); + const bool mouseOver(enabled && (option->state & State_MouseOver)); + const bool hasFocus(enabled && (option->state & (State_HasFocus | State_Sunken))); + + /* + * get animation state + * no need to update, this was already done in drawToolButtonComplexControl + */ + const AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); + const qreal opacity(_animations->widgetStateEngine().buttonOpacity(widget)); + + if (!autoRaise) { + // need to check widget for popup mode, because option is not set properly + const auto toolButton(qobject_cast(widget)); + const bool hasPopupMenu(toolButton && toolButton->popupMode() == QToolButton::MenuButtonPopup); + + // render as push button + const auto shadow(_helper->shadowColor(palette)); + const auto outline(_helper->buttonOutlineColor(palette, mouseOver, hasFocus, opacity, mode)); + const auto background(_helper->buttonBackgroundColor(palette, mouseOver, hasFocus, sunken, opacity, mode)); + + // adjust frame in case of menu + if (hasPopupMenu) { + painter->setClipRect(rect); + rect.adjust(0, 0, Metrics::Frame_FrameRadius + 2, 0); + rect = visualRect(option, rect); + } + + // render + _helper->renderButtonFrame(painter, rect, background, outline, shadow, hasFocus, sunken); + + } else { + const auto color(_helper->toolButtonColor(palette, mouseOver, hasFocus, sunken, opacity, mode)); + _helper->renderToolButtonFrame(painter, rect, color, sunken); + } + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawIndicatorArrowPrimitive(ArrowOrientation orientation, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // store rect and palette + const auto &rect(option->rect); + const auto &palette(option->palette); + + // store state + const State &state(option->state); + const bool enabled(state & State_Enabled); + bool mouseOver(enabled && (state & State_MouseOver)); + bool hasFocus(enabled && (state & State_HasFocus)); + + // detect special buttons + const bool inTabBar(widget && qobject_cast(widget->parentWidget())); + const bool inToolButton(qstyleoption_cast(option)); + + // color + QColor color; + if (inTabBar) { + // for tabbar arrows one uses animations to get the arrow color + /* + * get animation state + * there is no need to update the engine since this was already done when rendering the frame + */ + const AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); + const qreal opacity(_animations->widgetStateEngine().buttonOpacity(widget)); + color = _helper->arrowColor(palette, mouseOver, hasFocus, opacity, mode); + + } else if (mouseOver && !inToolButton) { + color = _helper->hoverColor(palette); + + } else if (inToolButton) { + const bool flat(state & State_AutoRaise); + + // cast option + const QStyleOptionToolButton *toolButtonOption(static_cast(option)); + const bool hasMenu((toolButtonOption->subControls & SC_ToolButtonMenu) || (toolButtonOption->features & QStyleOptionToolButton::HasMenu && toolButtonOption->features & QStyleOptionToolButton::PopupDelay)); + const bool sunken(state & (State_On | State_Sunken)); + if (flat && hasMenu) { + if (sunken && !mouseOver) + color = palette.color(QPalette::HighlightedText); + else { + // for menu arrows in flat toolbutton one uses animations to get the arrow color + // handle arrow over animation + const bool arrowHover(mouseOver && (toolButtonOption->activeSubControls & SC_ToolButtonMenu)); + _animations->toolButtonEngine().updateState(widget, AnimationHover, arrowHover); + + const bool animated(_animations->toolButtonEngine().isAnimated(widget, AnimationHover)); + const qreal opacity(_animations->toolButtonEngine().opacity(widget, AnimationHover)); + + color = _helper->arrowColor(palette, arrowHover, false, opacity, animated ? AnimationHover : AnimationNone); + } + + } else if (flat) { + if (sunken && hasFocus && !mouseOver) + color = palette.color(QPalette::HighlightedText); + else + color = _helper->arrowColor(palette, QPalette::WindowText); + + } else if (hasFocus && !mouseOver) { + color = palette.color(QPalette::HighlightedText); + + } else { + color = _helper->arrowColor(palette, QPalette::ButtonText); + } + + } else + color = _helper->arrowColor(palette, QPalette::WindowText); + + // render + _helper->renderArrow(painter, rect, color, orientation); + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawIndicatorButtonDropDownPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto toolButtonOption(qstyleoption_cast(option)); + if (!toolButtonOption) + return true; + + // store state + const State &state(option->state); + const bool autoRaise(state & State_AutoRaise); + + // do nothing for autoraise buttons + if (autoRaise || !(toolButtonOption->subControls & SC_ToolButtonMenu)) + return true; + + // store palette and rect + const auto &palette(option->palette); + const auto &rect(option->rect); + + // store state + const bool enabled(state & State_Enabled); + const bool hasFocus(enabled && (state & (State_HasFocus | State_Sunken))); + const bool mouseOver(enabled && (state & State_MouseOver)); + const bool sunken(enabled && (state & State_Sunken)); + + // update animation state + // mouse over takes precedence over focus + _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver); + _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus && !mouseOver); + + const AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); + const qreal opacity(_animations->widgetStateEngine().buttonOpacity(widget)); + + // render as push button + const auto shadow(_helper->shadowColor(palette)); + const auto outline(_helper->buttonOutlineColor(palette, mouseOver, hasFocus, opacity, mode)); + const auto background(_helper->buttonBackgroundColor(palette, mouseOver, hasFocus, false, opacity, mode)); + + auto frameRect(rect); + painter->setClipRect(rect); + frameRect.adjust(-Metrics::Frame_FrameRadius - 1, 0, 0, 0); + frameRect = visualRect(option, frameRect); + + // render + _helper->renderButtonFrame(painter, frameRect, background, outline, shadow, hasFocus, sunken); + + // also render separator + auto separatorRect(rect.adjusted(0, 2, -2, -2)); + separatorRect.setWidth(1); + separatorRect = visualRect(option, separatorRect); + if (sunken) + separatorRect.translate(1, 1); + _helper->renderSeparator(painter, separatorRect, outline, true); + + return true; +} + +//___________________________________________________________________________________ +bool Style::drawToolButtonLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto toolButtonOption(qstyleoption_cast(option)); + + // copy rect and palette + const auto &rect = option->rect; + const auto &palette = option->palette; + + // state + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool sunken(state & (State_On | State_Sunken)); + const bool mouseOver(enabled && (option->state & State_MouseOver)); + const bool flat(state & State_AutoRaise); + + // focus flag is set to match the background color in either renderButtonFrame or renderToolButtonFrame + bool hasFocus(false); + if (flat) + hasFocus = enabled && !mouseOver && (option->state & State_HasFocus); + else + hasFocus = enabled && !mouseOver && (option->state & (State_HasFocus | State_Sunken)); + + const bool hasArrow(toolButtonOption->features & QStyleOptionToolButton::Arrow); + const bool hasIcon(!(hasArrow || toolButtonOption->icon.isNull())); + const bool hasText(!toolButtonOption->text.isEmpty()); + + // contents + auto contentsRect(rect); + if (sunken && !flat) + contentsRect.translate(1, 1); + + // icon size + const QSize iconSize(toolButtonOption->iconSize); + + // text size + int textFlags(_mnemonics->textFlags()); + const QSize textSize(option->fontMetrics.size(textFlags, toolButtonOption->text)); + + // adjust text and icon rect based on options + QRect iconRect; + QRect textRect; + + if (hasText && (!(hasArrow || hasIcon) || toolButtonOption->toolButtonStyle == Qt::ToolButtonTextOnly)) { + // text only + textRect = contentsRect; + textFlags |= Qt::AlignCenter; + + } else if ((hasArrow || hasIcon) && (!hasText || toolButtonOption->toolButtonStyle == Qt::ToolButtonIconOnly)) { + // icon only + iconRect = contentsRect; + + } else if (toolButtonOption->toolButtonStyle == Qt::ToolButtonTextUnderIcon) { + const int contentsHeight(iconSize.height() + textSize.height() + Metrics::ToolButton_ItemSpacing); + iconRect = QRect(QPoint(contentsRect.left() + (contentsRect.width() - iconSize.width()) / 2, contentsRect.top() + (contentsRect.height() - contentsHeight) / 2), iconSize); + textRect = QRect(QPoint(contentsRect.left() + (contentsRect.width() - textSize.width()) / 2, iconRect.bottom() + Metrics::ToolButton_ItemSpacing + 1), textSize); + textFlags |= Qt::AlignCenter; + + } else { + const bool leftAlign(widget && widget->property(PropertyNames::toolButtonAlignment).toInt() == Qt::AlignLeft); + if (leftAlign) { + const int marginWidth(Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth + 1); + iconRect = QRect(QPoint(contentsRect.left() + marginWidth, contentsRect.top() + (contentsRect.height() - iconSize.height()) / 2), iconSize); + } else { + const int contentsWidth(iconSize.width() + textSize.width() + Metrics::ToolButton_ItemSpacing); + iconRect = QRect(QPoint(contentsRect.left() + (contentsRect.width() - contentsWidth) / 2, contentsRect.top() + (contentsRect.height() - iconSize.height()) / 2), iconSize); + } + + textRect = QRect(QPoint(iconRect.right() + Metrics::ToolButton_ItemSpacing + 1, contentsRect.top() + (contentsRect.height() - textSize.height()) / 2), textSize); + + // handle right to left layouts + iconRect = visualRect(option, iconRect); + textRect = visualRect(option, textRect); + + textFlags |= Qt::AlignLeft | Qt::AlignVCenter; + } + + // make sure there is enough room for icon + if (iconRect.isValid()) + iconRect = centerRect(iconRect, iconSize); + + // render arrow or icon + if (hasArrow && iconRect.isValid()) { + QStyleOptionToolButton copy(*toolButtonOption); + copy.rect = iconRect; + switch (toolButtonOption->arrowType) { + case Qt::LeftArrow: + drawPrimitive(PE_IndicatorArrowLeft, ©, painter, widget); + break; + case Qt::RightArrow: + drawPrimitive(PE_IndicatorArrowRight, ©, painter, widget); + break; + case Qt::UpArrow: + drawPrimitive(PE_IndicatorArrowUp, ©, painter, widget); + break; + case Qt::DownArrow: + drawPrimitive(PE_IndicatorArrowDown, ©, painter, widget); + break; + default: + break; + } + + } else if (hasIcon && iconRect.isValid()) { + // icon state and mode + const QIcon::State iconState(sunken ? QIcon::On : QIcon::Off); + QIcon::Mode iconMode; + if (!enabled) + iconMode = QIcon::Disabled; + else if ((!flat && hasFocus) || (flat && (state & State_Sunken) && !mouseOver)) + iconMode = QIcon::Selected; + else if (mouseOver && flat) + iconMode = QIcon::Active; + else + iconMode = QIcon::Normal; + + const QPixmap pixmap = toolButtonOption->icon.pixmap(iconSize, iconMode, iconState); + drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); + } + + // render text + if (hasText && textRect.isValid()) { + QPalette::ColorRole textRole(QPalette::ButtonText); + if (flat) + textRole = (((hasFocus && sunken) || (state & State_Sunken)) && !mouseOver) ? QPalette::HighlightedText : QPalette::WindowText; + else if (hasFocus && !mouseOver) + textRole = QPalette::HighlightedText; + + painter->setFont(toolButtonOption->font); + drawItemText(painter, textRect, textFlags, palette, enabled, toolButtonOption->text, textRole); + } + + return true; +} + +//______________________________________________________________ +bool Style::drawToolButtonComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + // cast option and check + const auto toolButtonOption(qstyleoption_cast(option)); + if (!toolButtonOption) + return true; + + // need to alter palette for focused buttons + const State &state(option->state); + const bool enabled(state & State_Enabled); + const bool mouseOver(enabled && (option->state & State_MouseOver)); + const bool hasFocus(enabled && (option->state & State_HasFocus)); + const bool sunken(state & (State_On | State_Sunken)); + const bool flat(state & State_AutoRaise); + + // update animation state + // mouse over takes precedence over focus + _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver); + _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus && !mouseOver); + + // detect buttons in tabbar, for which special rendering is needed + const bool inTabBar(widget && qobject_cast(widget->parentWidget())); + const bool isMenuTitle(this->isMenuTitle(widget)); + if (isMenuTitle) { + // copy option to adjust state, and set font as not-bold + QStyleOptionToolButton copy(*toolButtonOption); + copy.font.setBold(false); + copy.state = State_Enabled; + + // render + renderMenuTitle(©, painter, widget); + return true; + } + + // copy option and alter palette + QStyleOptionToolButton copy(*toolButtonOption); + + const bool hasPopupMenu(toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup); + const bool hasInlineIndicator(toolButtonOption->features & QStyleOptionToolButton::HasMenu && toolButtonOption->features & QStyleOptionToolButton::PopupDelay && !hasPopupMenu); + + const auto buttonRect(subControlRect(CC_ToolButton, option, SC_ToolButton, widget)); + const auto menuRect(subControlRect(CC_ToolButton, option, SC_ToolButtonMenu, widget)); + + // frame + if (toolButtonOption->subControls & SC_ToolButton) { + if (!flat) + copy.rect = buttonRect; + if (inTabBar) + drawTabBarPanelButtonToolPrimitive(©, painter, widget); + else + drawPrimitive(PE_PanelButtonTool, ©, painter, widget); + } + + // arrow + if (hasPopupMenu) { + copy.rect = menuRect; + if (!flat) + drawPrimitive(PE_IndicatorButtonDropDown, ©, painter, widget); + + if (sunken && !flat) + copy.rect.translate(1, 1); + drawPrimitive(PE_IndicatorArrowDown, ©, painter, widget); + + } else if (hasInlineIndicator) { + copy.rect = menuRect; + + if (sunken && !flat) + copy.rect.translate(1, 1); + drawPrimitive(PE_IndicatorArrowDown, ©, painter, widget); + } + + // contents + { + // restore state + copy.state = state; + + // define contents rect + auto contentsRect(buttonRect); + + // detect dock widget title button + // for dockwidget title buttons, do not take out margins, so that icon do not get scaled down + const bool isDockWidgetTitleButton(widget && widget->inherits("QDockWidgetTitleButton")); + if (isDockWidgetTitleButton) { + // cast to abstract button + // adjust state to have correct icon rendered + const auto button(qobject_cast(widget)); + if (button->isChecked() || button->isDown()) + copy.state |= State_On; + + } else if (!inTabBar && hasInlineIndicator) { + const int marginWidth(flat ? Metrics::ToolButton_MarginWidth : Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth); + contentsRect = insideMargin(contentsRect, marginWidth, 0); + contentsRect.setRight(contentsRect.right() - Metrics::ToolButton_InlineIndicatorWidth); + contentsRect = visualRect(option, contentsRect); + } + + copy.rect = contentsRect; + + // render + drawControl(CE_ToolButtonLabel, ©, painter, widget); + } + + return true; +} + +}