diff --git a/kstyle/CMakeLists.txt b/kstyle/CMakeLists.txt index 27a81fe4..b0552959 100644 --- a/kstyle/CMakeLists.txt +++ b/kstyle/CMakeLists.txt @@ -1,133 +1,136 @@ ################# Qt/KDE ################# find_package(Qt5 REQUIRED CONFIG COMPONENTS Widgets DBus) find_package(KF5 REQUIRED COMPONENTS I18n Config GuiAddons IconThemes ConfigWidgets - WindowSystem) + WindowSystem + IconThemes) find_package(Qt5 COMPONENTS Quick) set(BREEZE_HAVE_QTQUICK ${Qt5Quick_FOUND}) find_package( KF5FrameworkIntegration CONFIG ) set_package_properties(KF5FrameworkIntegration PROPERTIES DESCRIPTION "KF5 Framework Integration" URL "https://projects.kde.org/projects/frameworks/frameworkintegration" TYPE OPTIONAL PURPOSE "Required to use KStyle convenience functionalities in style") set(BREEZE_HAVE_KSTYLE ${KF5FrameworkIntegration_FOUND}) find_package(XCB COMPONENTS XCB) set_package_properties(XCB PROPERTIES DESCRIPTION "X protocol C-language Binding" URL "https://xcb.freedesktop.org" TYPE OPTIONAL PURPOSE "Required to pass style properties to native Windows on X11 Platform" ) find_package(KF5Wayland CONFIG) set(BREEZE_HAVE_KWAYLAND ${KF5Wayland_FOUND}) if(UNIX AND NOT APPLE) set(BREEZE_HAVE_X11 ${XCB_XCB_FOUND}) if (XCB_XCB_FOUND) find_package(Qt5 REQUIRED CONFIG COMPONENTS X11Extras) endif() else() set(BREEZE_HAVE_X11 FALSE) endif() ################# includes ################# include_directories( animations debug ) include_directories(${CMAKE_SOURCE_DIR}/libbreezecommon) include_directories(${CMAKE_BINARY_DIR}/libbreezecommon) ################# configuration ################# configure_file(config-breeze.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-breeze.h ) ########### next target ############### set(breeze_PART_SRCS animations/breezeanimation.cpp animations/breezeanimations.cpp animations/breezeanimationdata.cpp animations/breezebaseengine.cpp animations/breezebusyindicatordata.cpp animations/breezebusyindicatorengine.cpp animations/breezedialdata.cpp animations/breezedialengine.cpp animations/breezeenabledata.cpp animations/breezegenericdata.cpp animations/breezeheaderviewdata.cpp animations/breezeheaderviewengine.cpp animations/breezescrollbardata.cpp animations/breezescrollbarengine.cpp animations/breezespinboxengine.cpp animations/breezespinboxdata.cpp animations/breezestackedwidgetdata.cpp animations/breezestackedwidgetengine.cpp animations/breezetabbarengine.cpp animations/breezetabbardata.cpp animations/breezetoolboxengine.cpp animations/breezetransitiondata.cpp animations/breezetransitionwidget.cpp animations/breezewidgetstateengine.cpp animations/breezewidgetstatedata.cpp debug/breezewidgetexplorer.cpp breezeaddeventfilter.cpp breezeblurhelper.cpp breezeframeshadow.cpp breezehelper.cpp breezemdiwindowshadow.cpp breezemnemonics.cpp breezepropertynames.cpp breezeshadowhelper.cpp breezesplitterproxy.cpp breezestyle.cpp breezestyleplugin.cpp breezetileset.cpp breezewindowmanager.cpp + breezetoolsareamanager.cpp ) +kconfig_add_kcfg_files(breeze_PART_SRCS ../kdecoration/breezesettings.kcfgc) kconfig_add_kcfg_files(breeze_PART_SRCS breezestyleconfigdata.kcfgc) add_library(breeze MODULE ${breeze_PART_SRCS}) target_link_libraries(breeze Qt5::Core Qt5::Gui Qt5::Widgets Qt5::DBus) if( BREEZE_HAVE_QTQUICK ) target_link_libraries(breeze Qt5::Quick) endif() -target_link_libraries(breeze KF5::ConfigCore KF5::ConfigWidgets KF5::GuiAddons KF5::IconThemes KF5::WindowSystem) +target_link_libraries(breeze KF5::ConfigCore KF5::ConfigWidgets KF5::GuiAddons KF5::WindowSystem KF5::IconThemes) target_link_libraries(breeze breezecommon5) if(KF5FrameworkIntegration_FOUND) target_link_libraries(breeze KF5::Style) endif() if (WIN32) # As stated in https://docs.microsoft.com/en-us/cpp/c-runtime-library/math-constants M_PI only gets defined # when if _USE_MATH_DEFINES is defined target_compile_definitions(breeze PRIVATE _USE_MATH_DEFINES _BSD_SOURCE) endif() if(BREEZE_HAVE_X11) target_link_libraries(breeze ${XCB_LIBRARIES}) target_link_libraries(breeze Qt5::X11Extras) endif() if(BREEZE_HAVE_KWAYLAND) target_link_libraries(breeze KF5::WaylandClient) endif() ########### install files ############### install(TARGETS breeze DESTINATION ${QT_PLUGIN_INSTALL_DIR}/styles/) install(FILES breeze.themerc DESTINATION ${DATA_INSTALL_DIR}/kstyle/themes) ########### subdirectories ############### add_subdirectory(config) diff --git a/kstyle/breeze.kcfg b/kstyle/breeze.kcfg index ad96ad2f..9159eb9b 100644 --- a/kstyle/breeze.kcfg +++ b/kstyle/breeze.kcfg @@ -1,195 +1,199 @@ 255 25 255 ShadowLarge 0, 0, 0 true true 10 100 false true 800 0 0 MN_AUTO true true true true false false false false false true + + true + + WD_FULL true true 12 false false 100 diff --git a/kstyle/breezehelper.cpp b/kstyle/breezehelper.cpp index aaf3369a..380bcfff 100644 --- a/kstyle/breezehelper.cpp +++ b/kstyle/breezehelper.cpp @@ -1,1616 +1,1868 @@ /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * *************************************************************************/ #include "breezehelper.h" #include "breeze.h" #include "breezestyleconfigdata.h" #include #include #include #include +#include +#include #include +#include +#include +#include +#include +#include #if BREEZE_HAVE_X11 #include #endif #include +#include + namespace Breeze { //* contrast for arrow and treeline rendering static const qreal arrowShade = 0.15; //____________________________________________________________________ - Helper::Helper( KSharedConfig::Ptr config ): - _config( std::move( config ) ) - {} + Helper::Helper( KSharedConfig::Ptr config, QObject *parent ) : + QObject ( parent ), + _config( std::move( config ) ), + _kwinConfig( KSharedConfig::openConfig("kwinrc") ), + _decorationConfig( new InternalSettings() ) + { + if (qApp) { + connect(qApp, &QApplication::paletteChanged, this, [=]() { + if (qApp->property("KDE_COLOR_SCHEME_PATH").isValid()) { + const auto path = qApp->property("KDE_COLOR_SCHEME_PATH").toString(); + KConfig config(path, KConfig::SimpleConfig); + KConfigGroup group( config.group("WM") ); + const QPalette palette( QApplication::palette() ); + _activeTitleBarColor = group.readEntry( "activeBackground", palette.color( QPalette::Active, QPalette::Highlight ) ); + _activeTitleBarTextColor = group.readEntry( "activeForeground", palette.color( QPalette::Active, QPalette::HighlightedText ) ); + _inactiveTitleBarColor = group.readEntry( "inactiveBackground", palette.color( QPalette::Disabled, QPalette::Highlight ) ); + _inactiveTitleBarTextColor = group.readEntry( "inactiveForeground", palette.color( QPalette::Disabled, QPalette::HighlightedText ) ); + } + }); + } + } //____________________________________________________________________ KSharedConfig::Ptr Helper::config() const { return _config; } + + //____________________________________________________________________ + QSharedPointer Helper::decorationConfig() const + { return _decorationConfig; } + //____________________________________________________________________ void Helper::loadConfig() { _viewFocusBrush = KStatefulBrush( KColorScheme::View, KColorScheme::FocusColor ); _viewHoverBrush = KStatefulBrush( KColorScheme::View, KColorScheme::HoverColor ); _viewNegativeTextBrush = KStatefulBrush( KColorScheme::View, KColorScheme::NegativeText ); const QPalette palette( QApplication::palette() ); - const KConfigGroup group( _config->group( "WM" ) ); - _activeTitleBarColor = group.readEntry( "activeBackground", palette.color( QPalette::Active, QPalette::Highlight ) ); - _activeTitleBarTextColor = group.readEntry( "activeForeground", palette.color( QPalette::Active, QPalette::HighlightedText ) ); - _inactiveTitleBarColor = group.readEntry( "inactiveBackground", palette.color( QPalette::Disabled, QPalette::Highlight ) ); - _inactiveTitleBarTextColor = group.readEntry( "inactiveForeground", palette.color( QPalette::Disabled, QPalette::HighlightedText ) ); + _config->reparseConfiguration(); + _kwinConfig->reparseConfiguration(); + _cachedAutoValid = false; + _decorationConfig->load(); + KConfig config(qApp->property("KDE_COLOR_SCHEME_PATH").toString(), KConfig::SimpleConfig); + KConfigGroup appGroup( config.group("WM") ); + KConfigGroup globalGroup( _config->group("WM") ); + _activeTitleBarColor = appGroup.readEntry( "activeBackground", globalGroup.readEntry( "activeBackground", palette.color( QPalette::Active, QPalette::Highlight ) ) ); + _activeTitleBarTextColor = appGroup.readEntry( "activeForeground", globalGroup.readEntry( "activeForeground", palette.color( QPalette::Active, QPalette::HighlightedText ) ) ); + _inactiveTitleBarColor = appGroup.readEntry( "inactiveBackground", globalGroup.readEntry( "inactiveBackground", palette.color( QPalette::Disabled, QPalette::Highlight ) ) ); + _inactiveTitleBarTextColor = appGroup.readEntry( "inactiveForeground", globalGroup.readEntry( "inactiveForeground", palette.color( QPalette::Disabled, QPalette::HighlightedText ) ) ); } //____________________________________________________________________ QColor Helper::frameOutlineColor( 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.25 ) ); // focus takes precedence over hover if( mode == AnimationFocus ) { const QColor focus( focusColor( palette ) ); const QColor hover( hoverColor( palette ) ); if( mouseOver ) outline = KColorUtils::mix( hover, focus, opacity ); else outline = KColorUtils::mix( outline, focus, opacity ); } else if( hasFocus ) { outline = focusColor( palette ); } else if( mode == AnimationHover ) { const QColor hover( hoverColor( palette ) ); outline = KColorUtils::mix( outline, hover, opacity ); } else if( mouseOver ) { outline = hoverColor( palette ); } return outline; } //____________________________________________________________________ QColor Helper::focusOutlineColor( const QPalette& palette ) const { return KColorUtils::mix( focusColor( palette ), palette.color( QPalette::WindowText ), 0.15 ); } //____________________________________________________________________ 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 { QColor outline( palette.color( QPalette::Inactive, QPalette::Highlight ) ); const QColor &focus = palette.color( QPalette::Active, QPalette::Highlight ); if( mode == AnimationFocus ) { outline = KColorUtils::mix( outline, focus, opacity ); } else if( hasFocus ) { outline = focus; } return outline; } //____________________________________________________________________ QColor Helper::frameBackgroundColor( const QPalette& palette, QPalette::ColorGroup group ) const { return KColorUtils::mix( palette.color( group, QPalette::Window ), palette.color( group, QPalette::Base ), 0.3 ); } //____________________________________________________________________ QColor Helper::arrowColor( const QPalette& palette, QPalette::ColorGroup group, QPalette::ColorRole role ) const { switch( role ) { case QPalette::Text: return KColorUtils::mix( palette.color( group, QPalette::Text ), palette.color( group, QPalette::Base ), arrowShade ); case QPalette::WindowText: return KColorUtils::mix( palette.color( group, QPalette::WindowText ), palette.color( group, QPalette::Window ), arrowShade ); case QPalette::ButtonText: return KColorUtils::mix( palette.color( group, QPalette::ButtonText ), palette.color( group, QPalette::Button ), arrowShade ); default: return palette.color( group, role ); } } //____________________________________________________________________ QColor Helper::arrowColor( const QPalette& palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode ) const { QColor outline( arrowColor( palette, QPalette::WindowText ) ); if( mode == AnimationHover ) { const QColor focus( focusColor( palette ) ); const QColor hover( hoverColor( 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::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 ); } //______________________________________________________________________________ QPalette Helper::disabledPalette( const QPalette& source, qreal ratio ) const { QPalette copy( source ); const QList roles = { QPalette::Background, QPalette::Highlight, QPalette::WindowText, QPalette::ButtonText, QPalette::Text, QPalette::Button }; foreach( const QPalette::ColorRole& role, roles ) { copy.setColor( role, KColorUtils::mix( source.color( QPalette::Active, role ), source.color( QPalette::Disabled, role ), 1.0-ratio ) ); } return copy; } //____________________________________________________________________ QColor Helper::alphaColor( QColor color, qreal alpha ) const { if( alpha >= 0 && alpha < 1.0 ) { color.setAlphaF( alpha*color.alphaF() ); } return color; } //______________________________________________________________________________ void Helper::renderDebugFrame( QPainter* painter, const QRect& rect ) const { painter->save(); painter->setRenderHints( QPainter::Antialiasing ); painter->setBrush( Qt::NoBrush ); painter->setPen( Qt::red ); painter->drawRect( strokedRect( rect ) ); painter->restore(); } //______________________________________________________________________________ void Helper::renderFocusRect( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline, Sides sides ) const { if( !color.isValid() ) return; painter->save(); painter->setRenderHints( QPainter::Antialiasing ); painter->setBrush( color ); if( !( outline.isValid() && sides ) ) { painter->setPen( Qt::NoPen ); painter->drawRect( rect ); } else { painter->setClipRect( rect ); QRectF copy( strokedRect( rect ) ); const qreal radius( frameRadius( PenWidth::Frame, -1 ) ); if( !(sides&SideTop) ) copy.adjust( 0, -radius, 0, 0 ); if( !(sides&SideBottom) ) copy.adjust( 0, 0, 0, radius ); if( !(sides&SideLeft) ) copy.adjust( -radius, 0, 0, 0 ); if( !(sides&SideRight) ) copy.adjust( 0, 0, radius, 0 ); painter->setPen( outline ); // painter->setBrush( Qt::NoBrush ); painter->drawRoundedRect( copy, radius, radius ); } painter->restore(); } //______________________________________________________________________________ void Helper::renderFocusLine( QPainter* painter, const QRect& rect, const QColor& color ) const { if( !color.isValid() ) return; painter->save(); painter->setRenderHint( QPainter::Antialiasing, false ); painter->setBrush( Qt::NoBrush ); painter->setPen( color ); painter->translate( 0, 2 ); painter->drawLine( rect.bottomLeft(), rect.bottomRight() ); painter->restore(); } //______________________________________________________________________________ void Helper::renderFrame( QPainter* painter, const QRect& rect, const QColor& color, const QColor& outline ) const { painter->setRenderHint( QPainter::Antialiasing ); QRectF frameRect( rect.adjusted( 1, 1, -1, -1 ) ); qreal radius( frameRadius( PenWidth::NoPen, -1 ) ); // set pen if( outline.isValid() ) { painter->setPen( outline ); frameRect = strokedRect( frameRect ); radius = frameRadiusForNewPenWidth( radius, PenWidth::Frame ); } else { painter->setPen( Qt::NoPen ); } // set brush if( color.isValid() ) painter->setBrush( color ); else painter->setBrush( Qt::NoBrush ); // render painter->drawRoundedRect( frameRect, radius, radius ); } //______________________________________________________________________________ void Helper::renderSidePanelFrame( QPainter* painter, const QRect& rect, const QColor& outline, Side side ) const { // check color if( !outline.isValid() ) return; // adjust rect QRectF frameRect( strokedRect( rect ) ); // 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( PenWidth::Frame, -1 ) ); painter->drawRoundedRect( frameRect, radius, radius ); break; } } } //______________________________________________________________________________ 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( PenWidth::NoPen, -1 ) ); // set pen if( outline.isValid() ) { painter->setPen( outline ); frameRect = strokedRect( frameRect ); radius = frameRadiusForNewPenWidth( radius, PenWidth::Frame ); } 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 ); } } //______________________________________________________________________________ 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( PenWidth::NoPen, -1 ) ); // shadow if( sunken ) { frameRect.translate( 1, 1 ); } else { renderRoundedRectShadow( painter, frameRect, shadow, radius ); } 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 = strokedRect( frameRect ); radius = frameRadiusForNewPenWidth( radius, PenWidth::Frame ); } 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 { // do nothing for invalid color if( !color.isValid() ) return; // setup painter painter->setRenderHints( QPainter::Antialiasing ); const QRectF baseRect( rect.adjusted( 1, 1, -1, -1 ) ); if( sunken ) { const qreal radius( frameRadius( PenWidth::NoPen ) ); painter->setPen( Qt::NoPen ); painter->setBrush( color ); painter->drawRoundedRect( baseRect, radius, radius ); } else { const qreal radius( frameRadius( PenWidth::Frame ) ); painter->setPen( color ); painter->setBrush( Qt::NoBrush ); const QRectF outlineRect( strokedRect( baseRect ) ); 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( PenWidth::Frame ) ); 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( strokedRect( rect ) ); // 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( PenWidth::NoPen, -1 ) ); // set pen if( outline.isValid() ) { painter->setPen( outline ); frameRect = strokedRect( frameRect ); radius = frameRadiusForNewPenWidth( radius, PenWidth::Frame ); } 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( PenWidth::NoPen, -1 ) ); // shadow if( sunken ) { frameRect.translate(1, 1); } else { renderRoundedRectShadow( painter, frameRect, shadow, radius ); } // content { painter->setPen( QPen( color, PenWidth::Frame ) ); painter->setBrush( Qt::NoBrush ); radius = frameRadiusForNewPenWidth( radius, PenWidth::Frame ); const QRectF contentRect( strokedRect( frameRect ) ); 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 { renderEllipseShadow( painter, frameRect, shadow ); } // content { painter->setPen( QPen( color, PenWidth::Frame ) ); painter->setBrush( Qt::NoBrush ); const QRectF contentRect( strokedRect( frameRect ) ); 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( !sunken ) { renderEllipseShadow( painter, frameRect, shadow ); } // set pen if( outline.isValid() ) { painter->setPen( outline ); frameRect = strokedRect( frameRect ); } 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::renderScrollBarBorder( QPainter* painter, const QRect& rect, const QColor& color ) const { // content if( color.isValid() ) { painter->setPen( Qt::NoPen ); painter->setBrush( color ); painter->drawRect( rect ); } } //______________________________________________________________________________ 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( PenWidth::NoPen, -1 ) ); // pen if( outline.isValid() ) { painter->setPen( outline ); frameRect = strokedRect( frameRect ); radius = frameRadiusForNewPenWidth( radius, PenWidth::Frame ); } 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 ) { /* The inner points of the normal arrows are not on half pixels because * they need to have an even width (up/down) or height (left/right). * An even width/height makes them easier to align with other UI elements. */ case ArrowUp: arrow = QVector{QPointF( -4.5, 1.5 ), QPointF( 0, -3 ), QPointF( 4.5, 1.5 )}; break; case ArrowDown: arrow = QVector{QPointF( -4.5, -1.5 ), QPointF( 0, 3 ), QPointF( 4.5, -1.5 )}; break; case ArrowLeft: arrow = QVector{QPointF( 1.5, -4.5 ), QPointF( -3, 0 ), QPointF( 1.5, 4.5 )}; break; case ArrowRight: arrow = QVector{QPointF( -1.5, -4.5 ), QPointF( 3, 0 ), QPointF( -1.5, 4.5 )}; break; case ArrowDown_Small: arrow = QVector{QPointF( 1.5, 3.5 ), QPointF( 3.5, 5.5 ), QPointF( 5.5, 3.5 )}; break; default: break; } painter->save(); painter->setRenderHints( QPainter::Antialiasing ); painter->translate( QRectF( rect ).center() ); painter->setBrush( Qt::NoBrush ); QPen pen( color, PenWidth::Symbol ); pen.setCapStyle(Qt::SquareCap); pen.setJoinStyle(Qt::MiterJoin); painter->setPen( pen ); painter->drawPolyline( arrow ); 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( PenWidth::Symbol*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(); } //______________________________________________________________________________ void Helper::renderRoundedRectShadow( QPainter* painter, const QRectF& rect, const QColor& color, qreal radius ) const { if( !color.isValid() ) return; painter->save(); qreal translation = 0.5 * PenWidth::Shadow; // Translate for the pen /* Clipping prevents shadows from being visible inside checkboxes. * Clipping away unneeded parts here also improves performance by 40-60% * versus using just an outline of a rectangle. * Tested by looking at the paint analyser in GammaRay. */ // Right side QRegion clip( rect.right() - std::ceil( radius ), rect.top(), std::ceil( radius ) + PenWidth::Shadow, rect.height() ); // Bottom side clip = clip.united( QRegion( rect.left(), rect.bottom() - std::ceil( radius ), rect.width(), std::ceil( radius ) + PenWidth::Shadow ) ); painter->setClipRegion( clip ); painter->setPen( color ); painter->setBrush( Qt::NoBrush ); painter->drawRoundedRect( rect.translated( translation, translation ), radius, radius ); painter->restore(); } //______________________________________________________________________________ void Helper::renderEllipseShadow( QPainter* painter, const QRectF& rect, const QColor& color ) const { if( !color.isValid() ) return; painter->save(); // Clipping does not improve performance here qreal adjustment = 0.5 * PenWidth::Shadow; // Adjust for the pen qreal radius = rect.width() / 2 - adjustment; /* The right side is offset by +0.5 for the visible part of the shadow. * The other sides are offset by +0.5 or -0.5 because of the pen. */ QRectF shadowRect = rect.adjusted( adjustment, adjustment, adjustment, -adjustment ); painter->translate( rect.center() ); painter->rotate( 45 ); painter->translate( -rect.center() ); painter->setPen( color ); painter->setBrush( Qt::NoBrush ); painter->drawRoundedRect( shadowRect, radius, radius ); painter->restore(); } //______________________________________________________________________________ bool Helper::isX11() { #if BREEZE_HAVE_X11 static const bool s_isX11 = KWindowSystem::isPlatformX11(); return s_isX11; #endif return false; } //______________________________________________________________________________ bool Helper::isWayland() { static const bool s_isWayland = KWindowSystem::isPlatformWayland(); return s_isWayland; } //______________________________________________________________________________ QRectF Helper::strokedRect( const QRectF &rect, const int penWidth ) const { /* With a pen stroke width of 1, the rectangle should have each of its * sides moved inwards by half a pixel. This allows the stroke to be * pixel perfect instead of blurry from sitting between pixels and * prevents the rectangle with a stroke from becoming larger than the * original size of the rectangle. */ qreal adjustment = 0.5 * penWidth; return QRectF( rect ).adjusted( adjustment, adjustment, -adjustment, -adjustment ); } QRectF Helper::strokedRect( const QRect &rect, const int penWidth ) const { return strokedRect(QRectF(rect), penWidth); } //______________________________________________________________________________ QPainterPath Helper::roundedPath( const QRectF& rect, Corners corners, qreal radius ) const { QPainterPath path; // simple cases if( corners == 0 ) { path.addRect( rect ); return path; } if( corners == AllCorners ) { path.addRoundedRect( rect, radius, radius ); return path; } const QSizeF cornerSize( 2*radius, 2*radius ); // rotate counterclockwise // top left corner if( corners & CornerTopLeft ) { path.moveTo( rect.topLeft() + QPointF( radius, 0 ) ); path.arcTo( QRectF( rect.topLeft(), cornerSize ), 90, 90 ); } else path.moveTo( rect.topLeft() ); // bottom left corner if( corners & CornerBottomLeft ) { path.lineTo( rect.bottomLeft() - QPointF( 0, radius ) ); path.arcTo( QRectF( rect.bottomLeft() - QPointF( 0, 2*radius ), cornerSize ), 180, 90 ); } else path.lineTo( rect.bottomLeft() ); // bottom right corner if( corners & CornerBottomRight ) { path.lineTo( rect.bottomRight() - QPointF( radius, 0 ) ); path.arcTo( QRectF( rect.bottomRight() - QPointF( 2*radius, 2*radius ), cornerSize ), 270, 90 ); } else path.lineTo( rect.bottomRight() ); // top right corner if( corners & CornerTopRight ) { path.lineTo( rect.topRight() + QPointF( 0, radius ) ); path.arcTo( QRectF( rect.topRight() - QPointF( 2*radius, 0 ), cornerSize ), 0, 90 ); } else path.lineTo( rect.topRight() ); path.closeSubpath(); return path; } //________________________________________________________________________________________________________ bool Helper::compositingActive() const { #if BREEZE_HAVE_X11 if( isX11() ) { return QX11Info::isCompositingManagerRunning( QX11Info::appScreen() ); } #endif // use KWindowSystem return KWindowSystem::compositingActive(); } //____________________________________________________________________ bool Helper::hasAlphaChannel( const QWidget* widget ) const { return compositingActive() && widget && widget->testAttribute( Qt::WA_TranslucentBackground ); } //______________________________________________________________________________________ qreal Helper::devicePixelRatio( const QPixmap& pixmap ) const { return pixmap.devicePixelRatio(); } QPixmap Helper::coloredIcon(const QIcon& icon, const QPalette& palette, const QSize &size, QIcon::Mode mode, QIcon::State state) { const QPalette activePalette = KIconLoader::global()->customPalette(); const bool changePalette = activePalette != palette; if (changePalette) { KIconLoader::global()->setCustomPalette(palette); } const QPixmap pixmap = icon.pixmap(size, mode, state); if (changePalette) { if (activePalette == QPalette()) { KIconLoader::global()->resetPalette(); } else { KIconLoader::global()->setCustomPalette(activePalette); } } return pixmap; } + + bool Helper::isInToolsArea(const QWidget* widget) const + { + if (!shouldDrawToolsArea(widget)) return false; + + auto grabMainWindow = [](const QWidget *widget) { + auto window = qobject_cast(widget->window()); + return window; + }; + auto checkToolbarInToolsArea = [this, grabMainWindow](const QWidget* widget) { + auto toolbar = qobject_cast(widget); + if (!toolbar) return false; + + QMainWindow* window = grabMainWindow(widget); + if (window) { + auto rect = toolsAreaToolbarsRect(widget); + if (widget->parentWidget() != widget->window()) return false; + if (toolbar->isFloating()) return false; + if (toolbar->orientation() == Qt::Vertical) return false; + if (window->toolBarArea(const_cast(toolbar)) != Qt::TopToolBarArea) return false; + if (window->width() != rect.width()) return false; + } + + return true; + }; + auto checkMenubarInToolsArea = [grabMainWindow](const QWidget *widget) { + QMainWindow* window = grabMainWindow(widget); + if (window) { + if (window->menuWidget() == widget) { + return true; + } + } + + return false; + }; + + if (!widget) return false; + + if (!widget->isVisible()) { + return false; + } + if (widget->window()->windowType() == Qt::Dialog) { + return false; + } + + auto parent = widget; + while (parent != nullptr) { + if (qobject_cast(parent) || qobject_cast(parent)) { + return false; + } + if (checkToolbarInToolsArea(parent)) { + return true; + } + if (checkMenubarInToolsArea(parent)) { + return true; + } + parent = parent->parentWidget(); + } + + return false; + } + + QRect Helper::toolsAreaToolbarsRect (const QWidget* widget) const { + auto window = qobject_cast(widget->window()); + if (!window) return QRect(); + + auto handle = window->windowHandle(); + if (handle) { + if (_invalidateCachedRects) { + _cachedRects.clear(); + _invalidateCachedRects = false; + } + auto key = _cachedRects.constFind(handle); + if (key != _cachedRects.constEnd()) { + return *key; + } + } + + QList widgets = window->findChildren(QString(), Qt::FindDirectChildrenOnly); + QRect rect = QRect(); + for (auto toolbar : widgets) { + auto isInSubWindow = false; + QWidget* parent = toolbar->parentWidget(); + while (parent != nullptr) { + if (qobject_cast(parent) || qobject_cast(parent)) { + isInSubWindow = true; + break; + } + parent = parent->parentWidget(); + } + if (!isInSubWindow) { + if (window->toolBarArea(toolbar) == Qt::TopToolBarArea) { + rect = rect.united(toolbar->geometry()); + } + } + } + QList menuWidgets = window->findChildren(QString(), Qt::FindDirectChildrenOnly); + for (auto menubar : menuWidgets) { + rect = rect.united(menubar->geometry()); + } + + if (handle) { + _cachedRects.insert(handle, rect); + } + return rect; + } + + bool Helper::toolsAreaHasToolBar (const QWidget* widget) const { + if (!shouldDrawToolsArea(widget)) return false; + + auto mainWindow = qobject_cast(widget->window()); + if (mainWindow == nullptr) { + return false; + } + + QList widgets = mainWindow->findChildren(QString(), Qt::FindDirectChildrenOnly); + for (auto widget : widgets) { + if (isInToolsArea(widget) == true) { + return true; + } + } + + return false; + } + + QToolBar* Helper::grabToolBarForToolsArea(const QWidget *widget) const { + auto mainWindow = qobject_cast(widget->window()); + if (mainWindow == nullptr) { + return nullptr; + } + + QList widgets = mainWindow->findChildren(QString(), Qt::FindDirectChildrenOnly); + for (auto widget : widgets) { + if (isInToolsArea(widget)) { + return widget; + } + } + + return nullptr; + } + + bool Helper::shouldDrawToolsArea(const QWidget* widget) const { + if (!widget) return false; + if (!_toolsAreaEnabled) return false; + static bool isAuto; + static QString borderSize; + if (!_cachedAutoValid) { + KConfigGroup kdecorationGroup(_kwinConfig->group("org.kde.kdecoration2")); + isAuto = kdecorationGroup.readEntry("BorderSizeAuto", true); + borderSize = kdecorationGroup.readEntry("BorderSize", "Normal"); + _cachedAutoValid = true; + } + if (isAuto) { + auto window = widget->window(); + auto dialogAuto = false; + if (qobject_cast(widget)) { + auto handle = window->windowHandle(); + if (handle) { + dialogAuto = widget->width() == handle->frameGeometry().width(); + } + return true; + } + if (window) { + auto handle = window->windowHandle(); + if (handle) { + if (dialogAuto || handle->frameGeometry().width() != toolsAreaToolbarsRect(widget).width()) { + return false; + } else { + auto toolbar = qobject_cast(widget); + if (toolbar) { + if (toolbar->isFloating()) { + return false; + } + } + return true; + } + } + } else { + return false; + } + } + if (borderSize != "None" && borderSize != "NoSides") { + return false; + } + auto toolbar = qobject_cast(widget); + if (toolbar) { + if (toolbar->isFloating()) { + return false; + } + } + return true; + } + + bool Helper::toolsAreaHasContents(const QWidget* widget) const { + QList widgets = widget->window()->findChildren(QString(), Qt::FindDirectChildrenOnly); + for (auto widget : widgets) { + if (isInToolsArea(widget)) { + return true; + } + } + return false; + } + + QColor Helper::toolsAreaBorderColor(const QWidget* widget) const { + QColor border( + KColorUtils::mix( + titleBarColor(widget->isActiveWindow()), + titleBarTextColor(widget->isActiveWindow()), + 0.2 + ) + ); + border.setAlpha(255); + return border; + } } diff --git a/kstyle/breezehelper.h b/kstyle/breezehelper.h index efc1341b..4d7a9018 100644 --- a/kstyle/breezehelper.h +++ b/kstyle/breezehelper.h @@ -1,318 +1,363 @@ #ifndef breeze_helper_h #define breeze_helper_h /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * *************************************************************************/ #include "breeze.h" #include "breezeanimationdata.h" +#include "breezesettings.h" #include "config-breeze.h" #include #include +#include +#include #include #include #include namespace Breeze { //* breeze style helper class. /** contains utility functions used at multiple places in both breeze style and breeze window decoration */ - class Helper + class Helper : public QObject { + Q_OBJECT + public: //* constructor - explicit Helper( KSharedConfig::Ptr ); + explicit Helper( KSharedConfig::Ptr, QObject *parent = nullptr ); //* destructor virtual ~Helper() {} //* load configuration virtual void loadConfig(); //* pointer to shared config KSharedConfig::Ptr config() const; + //* pointer to kdecoration config + QSharedPointer decorationConfig() const; + //*@name color utilities //@{ //* add alpha channel multiplier to color QColor alphaColor( QColor color, qreal alpha ) const; //* mouse over color QColor hoverColor( const QPalette& palette ) const { return _viewHoverBrush.brush( palette ).color(); } //* focus color QColor focusColor( const QPalette& palette ) const { return _viewFocusBrush.brush( palette ).color(); } //* negative text color (used for close button) QColor negativeText( const QPalette& palette ) const { return _viewNegativeTextBrush.brush( palette ).color(); } //* shadow QColor shadowColor( const QPalette& palette ) const { return alphaColor( palette.color( QPalette::Shadow ), 0.15 ); } //* titlebar color const QColor& titleBarColor( bool active ) const { return active ? _activeTitleBarColor:_inactiveTitleBarColor; } //* titlebar text color const QColor& titleBarTextColor( bool active ) const { return active ? _activeTitleBarTextColor:_inactiveTitleBarTextColor; } //* frame outline color, using animations QColor frameOutlineColor( const QPalette&, bool mouseOver = false, bool hasFocus = false, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; //* focus outline color, using animations QColor focusOutlineColor( const QPalette& ) const; //* hover outline color, using animations QColor hoverOutlineColor( const QPalette& ) const; //* focus outline color, using animations QColor buttonFocusOutlineColor( const QPalette& ) const; //* hover outline color, using animations QColor buttonHoverOutlineColor( const QPalette& ) const; //* side panel outline color, using animations QColor sidePanelOutlineColor( const QPalette&, bool hasFocus = false, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; //* frame background color QColor frameBackgroundColor( const QPalette& palette ) const { return frameBackgroundColor( palette, palette.currentColorGroup() ); } //* frame background color QColor frameBackgroundColor( const QPalette&, QPalette::ColorGroup ) const; //* arrow outline color QColor arrowColor( const QPalette&, QPalette::ColorGroup, QPalette::ColorRole ) const; //* arrow outline color QColor arrowColor( const QPalette& palette, QPalette::ColorRole role ) const { return arrowColor( palette, palette.currentColorGroup(), role ); } //* arrow outline color, using animations QColor arrowColor( const QPalette&, bool mouseOver, bool hasFocus, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; //* button outline color, using animations QColor buttonOutlineColor( const QPalette&, bool mouseOver, bool hasFocus, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; //* button panel color, using animations QColor buttonBackgroundColor( const QPalette&, bool mouseOver, bool hasFocus, bool sunken, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; //* tool button color QColor toolButtonColor( const QPalette&, bool mouseOver, bool hasFocus, bool sunken, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; //* slider outline color, using animations QColor sliderOutlineColor( const QPalette&, bool mouseOver, bool hasFocus, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; //* scrollbar handle color, using animations QColor scrollBarHandleColor( const QPalette&, bool mouseOver, bool hasFocus, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; //* checkbox indicator, using animations QColor checkBoxIndicatorColor( const QPalette&, bool mouseOver, bool active, qreal opacity = AnimationData::OpacityInvalid, AnimationMode = AnimationNone ) const; //* separator color QColor separatorColor( const QPalette& ) const; //* merge active and inactive palettes based on ratio, for smooth enable state change transition QPalette disabledPalette( const QPalette&, qreal ratio ) const; //@} //*@name rendering utilities //@{ //* debug frame void renderDebugFrame( QPainter*, const QRect& ) const; //* focus rect void renderFocusRect( QPainter*, const QRect&, const QColor&, const QColor& outline = QColor(), Sides = {} ) const; //* focus line void renderFocusLine( QPainter*, const QRect&, const QColor& ) const; //* generic frame void renderFrame( QPainter*, const QRect&, const QColor& color, const QColor& outline = QColor() ) const; //* side panel frame void renderSidePanelFrame( QPainter*, const QRect&, const QColor& outline, Side ) const; //* menu frame void renderMenuFrame( QPainter*, const QRect&, const QColor& color, const QColor& outline, bool roundCorners = true ) const; //* button frame void renderButtonFrame( QPainter*, const QRect&, const QColor& color, const QColor& outline, const QColor& shadow, bool focus, bool sunken ) const; //* toolbutton frame void renderToolButtonFrame( QPainter*, const QRect&, const QColor& color, bool sunken ) const; //* toolbutton frame void renderToolBoxFrame( QPainter*, const QRect&, int tabWidth, const QColor& color ) const; //* tab widget frame void renderTabWidgetFrame( QPainter*, const QRect&, const QColor& color, const QColor& outline, Corners ) const; //* selection frame void renderSelection( QPainter*, const QRect&, const QColor& ) const; //* separator void renderSeparator( QPainter*, const QRect&, const QColor&, bool vertical = false ) const; //* checkbox void renderCheckBoxBackground( QPainter*, const QRect&, const QColor& color, bool sunken ) const; //* checkbox void renderCheckBox( QPainter*, const QRect&, const QColor& color, const QColor& shadow, bool sunken, CheckBoxState state, qreal animation = AnimationData::OpacityInvalid ) const; //* radio button void renderRadioButtonBackground( QPainter*, const QRect&, const QColor& color, bool sunken ) const; //* radio button void renderRadioButton( QPainter*, const QRect&, const QColor& color, const QColor& shadow, bool sunken, RadioButtonState state, qreal animation = AnimationData::OpacityInvalid ) const; //* slider groove void renderSliderGroove( QPainter*, const QRect&, const QColor& ) const; //* slider handle void renderSliderHandle( QPainter*, const QRect&, const QColor&, const QColor& outline, const QColor& shadow, bool sunken ) const; //* dial groove void renderDialGroove( QPainter*, const QRect&, const QColor&, qreal first, qreal last ) const; //* dial groove void renderDialContents( QPainter*, const QRect&, const QColor&, qreal first, qreal second ) const; //* progress bar groove void renderProgressBarGroove( QPainter*, const QRect&, const QColor& ) const; //* progress bar contents void renderProgressBarContents( QPainter* painter, const QRect& rect, const QColor& color ) const { return renderProgressBarGroove( painter, rect, color ); } //* progress bar contents (animated) void renderProgressBarBusyContents( QPainter* painter, const QRect& rect, const QColor& first, const QColor& second, bool horizontal, bool reverse, int progress ) const; //* scrollbar groove void renderScrollBarGroove( QPainter* painter, const QRect& rect, const QColor& color ) const { return renderScrollBarHandle( painter, rect, color ); } //* scrollbar handle void renderScrollBarHandle( QPainter*, const QRect&, const QColor& ) const; //* toolbar handle void renderToolBarHandle( QPainter* painter, const QRect& rect, const QColor& color ) const { return renderProgressBarGroove( painter, rect, color ); } //* separator between scrollbar and contents void renderScrollBarBorder( QPainter*, const QRect&, const QColor& ) const; //* tabbar tab void renderTabBarTab( QPainter*, const QRect&, const QColor& color, const QColor& outline, Corners ) const; //* generic arrow void renderArrow( QPainter*, const QRect&, const QColor&, ArrowOrientation ) const; //* generic button (for mdi decorations, tabs and dock widgets) void renderDecorationButton( QPainter*, const QRect&, const QColor&, ButtonType, bool inverted ) const; //* generic shadow for rounded rectangles void renderRoundedRectShadow ( QPainter*, const QRectF&, const QColor&, qreal radius = Metrics::Frame_FrameRadius - 0.5 ) const; //* generic shadow for ellipses void renderEllipseShadow( QPainter*, const QRectF&, const QColor& ) const; //@} //*@name compositing utilities //@{ //* true if style was compiled for and is running on X11 static bool isX11(); //* true if running on platform Wayland static bool isWayland(); //* returns true if compositing is active bool compositingActive() const; //* returns true if a given widget supports alpha channel bool hasAlphaChannel( const QWidget* ) const; + //* returns true if widget is in the tools area + bool isInToolsArea( const QWidget* ) const; + + //* returns false if tools area is empty + bool toolsAreaHasContents ( const QWidget* ) const; + + //* returns true if tools area has a toolbar + bool toolsAreaHasToolBar ( const QWidget* ) const; + + //* returns true if the tools area should be drawn + bool shouldDrawToolsArea ( const QWidget* ) const; + + //* returns the tools area border color + QColor toolsAreaBorderColor ( const QWidget* ) const; + + //* returns the united rectangle of all toolbars in the tools area + QRect toolsAreaToolbarsRect (const QWidget* widget) const; + + QToolBar* grabToolBarForToolsArea ( const QWidget* ) const; + + void setToolsAreaEnabled(bool enabled) + { _toolsAreaEnabled = enabled; }; + //@} //* return device pixel ratio for a given pixmap virtual qreal devicePixelRatio( const QPixmap& ) const; //* frame radius constexpr qreal frameRadius( const int penWidth = PenWidth::NoPen, const qreal bias = 0 ) const { return qMax( Metrics::Frame_FrameRadius - (0.5 * penWidth) + bias, 0.0 ); } //* frame radius with new pen width constexpr qreal frameRadiusForNewPenWidth( const qreal oldRadius, const int penWidth ) const { return qMax( oldRadius - (0.5 * penWidth), 0.0 ); } //* return a QRectF with the appropriate size for a rectangle with a pen stroke QRectF strokedRect( const QRectF &rect, const int penWidth = PenWidth::Frame ) const; //* return a QRectF with the appropriate size for a rectangle with a pen stroke QRectF strokedRect( const QRect &rect, const int penWidth = PenWidth::Frame ) const; QPixmap coloredIcon(const QIcon &icon, const QPalette& palette, const QSize &size, QIcon::Mode mode = QIcon::Normal, QIcon::State state = QIcon::Off); protected: //* return rounded path in a given rect, with only selected corners rounded, and for a given radius QPainterPath roundedPath( const QRectF&, Corners, qreal ) const; private: //* configuration KSharedConfig::Ptr _config; + //* KWin configuration + KSharedConfig::Ptr _kwinConfig; + + //* decoration configuration + QSharedPointer _decorationConfig; + //*@name brushes //@{ KStatefulBrush _viewFocusBrush; KStatefulBrush _viewHoverBrush; KStatefulBrush _viewNegativeTextBrush; //@} //*@name windeco colors //@{ QColor _activeTitleBarColor; QColor _activeTitleBarTextColor; QColor _inactiveTitleBarColor; QColor _inactiveTitleBarTextColor; //@} + bool _toolsAreaEnabled; + + mutable QHash _cachedRects; + mutable bool _invalidateCachedRects; + mutable bool _cachedAutoValid = false; + + friend class ToolsAreaManager; + }; } #endif diff --git a/kstyle/breezestyle.cpp b/kstyle/breezestyle.cpp index ccb98c7d..02974515 100644 --- a/kstyle/breezestyle.cpp +++ b/kstyle/breezestyle.cpp @@ -1,7134 +1,7250 @@ /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * *************************************************************************/ #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 "breezetoolsareamanager.h" #include +#include #include +#include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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; }; //_______________________________________________________________ bool isProgressBarHorizontal( const QStyleOptionProgressBar* option ) { return option && ( (option->state & QStyle::State_Horizontal ) || option->orientation == Qt::Horizontal ); } } namespace Breeze { //______________________________________________________________ Style::Style(): _helper( new Helper( StyleConfigData::self()->sharedConfig() ) ) , _shadowHelper( new ShadowHelper( this, *_helper ) ) , _animations( new Animations( this ) ) , _mnemonics( new Mnemonics( this ) ) , _blurHelper( new BlurHelper( this ) ) , _windowManager( new WindowManager( this ) ) , _frameShadowFactory( new FrameShadowFactory( this ) ) , _mdiWindowShadowFactory( new MdiWindowShadowFactory( this ) ) , _splitterFactory( new SplitterFactory( this ) ) + , _toolsAreaManager ( new ToolsAreaManager( _helper, this ) ) , _widgetExplorer( new WidgetExplorer( this ) ) , _tabBarData( new BreezePrivate::TabBarData( this ) ) #if BREEZE_HAVE_KSTYLE , SH_ArgbDndWindow( newStyleHint( QStringLiteral( "SH_ArgbDndWindow" ) ) ) , CE_CapacityBar( newControlElement( QStringLiteral( "CE_CapacityBar" ) ) ) #endif { // use DBus connection to update on breeze configuration change auto dbus = QDBusConnection::sessionBus(); dbus.connect( QString(), QStringLiteral( "/BreezeStyle" ), QStringLiteral( "org.kde.Breeze.Style" ), QStringLiteral( "reparseConfiguration" ), this, SLOT(configurationChanged()) ); dbus.connect( QString(), QStringLiteral( "/BreezeDecoration" ), QStringLiteral( "org.kde.Breeze.Style" ), QStringLiteral( "reparseConfiguration" ), this, SLOT(configurationChanged()) ); + + dbus.connect( QString(), + QStringLiteral( "/KGlobalSettings" ), + QStringLiteral( "org.kde.KGlobalSettings" ), + QStringLiteral( "notifyChange" ), this, SLOT(configurationChanged()) ); + + dbus.connect( QString(), + QStringLiteral( "/KWin" ), + QStringLiteral( "org.kde.KWin" ), + QStringLiteral( "reloadConfig" ), this, SLOT(configurationChanged())); + #if QT_VERSION < 0x050D00 // Check if Qt version < 5.13 this->addEventFilter(qApp); #else connect(qApp, &QApplication::paletteChanged, this, &Style::configurationChanged); #endif // call the slot directly; this initial call will set up things that also // need to be reset when the system palette changes loadConfiguration(); } //______________________________________________________________ Style::~Style() { delete _shadowHelper; delete _helper; } //______________________________________________________________ void Style::polish( QWidget* widget ) { if( !widget ) return; // register widget to animations _animations->registerWidget( widget ); _windowManager->registerWidget( widget ); _frameShadowFactory->registerWidget( widget, *_helper ); _mdiWindowShadowFactory->registerWidget( widget ); _shadowHelper->registerWidget( widget ); _splitterFactory->registerWidget( widget ); + _toolsAreaManager->registerWidget ( widget ); // enable mouse over effects for all necessary widgets if( qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || widget->inherits( "KTextEditor::View" ) ) { widget->setAttribute( Qt::WA_Hover ); } // enforce translucency for drag and drop window if( widget->testAttribute( Qt::WA_X11NetWmWindowTypeDND ) && _helper->compositingActive() ) { widget->setAttribute( Qt::WA_TranslucentBackground ); widget->clearMask(); } // scrollarea polishing is somewhat complex. It is moved to a dedicated method polishScrollArea( qobject_cast( widget ) ); if( auto itemView = qobject_cast( widget ) ) { // enable mouse over effects in itemviews' viewport itemView->viewport()->setAttribute( Qt::WA_Hover ); } else if( auto groupBox = qobject_cast( widget ) ) { // checkable group boxes if( groupBox->isCheckable() ) { groupBox->setAttribute( Qt::WA_Hover ); } } else if( qobject_cast( widget ) && qobject_cast( widget->parent() ) ) { widget->setAttribute( Qt::WA_Hover ); } else if( qobject_cast( widget ) && qobject_cast( widget->parent() ) ) { widget->setAttribute( Qt::WA_Hover ); } else if( qobject_cast( widget ) && widget->parent() && widget->parent()->inherits( "KTitleWidget" ) ) { widget->setAutoFillBackground( false ); if( !StyleConfigData::titleWidgetDrawFrame() ) { widget->setBackgroundRole( QPalette::Window ); } } if( qobject_cast( widget ) ) { // remove opaque painting for scrollbars widget->setAttribute( Qt::WA_OpaquePaintEvent, false ); } else if( widget->inherits( "KTextEditor::View" ) ) { addEventFilter( widget ); } else if( auto toolButton = qobject_cast( widget ) ) { if( toolButton->autoRaise() ) { // for flat toolbuttons, adjust foreground and background role accordingly widget->setBackgroundRole( QPalette::NoRole ); widget->setForegroundRole( QPalette::WindowText ); } if( widget->parentWidget() && widget->parentWidget()->parentWidget() && widget->parentWidget()->parentWidget()->inherits( "Gwenview::SideBarGroup" ) ) { widget->setProperty( PropertyNames::toolButtonAlignment, Qt::AlignLeft ); } } else if( qobject_cast( widget ) ) { // add event filter on dock widgets // and alter palette widget->setAutoFillBackground( false ); widget->setContentsMargins( Metrics::Frame_FrameWidth, Metrics::Frame_FrameWidth, Metrics::Frame_FrameWidth, Metrics::Frame_FrameWidth ); addEventFilter( widget ); } else if( qobject_cast( widget ) ) { widget->setAutoFillBackground( false ); addEventFilter( widget ); } else if( qobject_cast( widget ) ) { widget->setBackgroundRole( QPalette::NoRole ); widget->setAutoFillBackground( false ); } else if( widget->parentWidget() && widget->parentWidget()->parentWidget() && qobject_cast( widget->parentWidget()->parentWidget()->parentWidget() ) ) { widget->setBackgroundRole( QPalette::NoRole ); widget->setAutoFillBackground( false ); widget->parentWidget()->setAutoFillBackground( false ); } else if( qobject_cast( widget ) ) { setTranslucentBackground( widget ); if ( _helper->hasAlphaChannel( widget ) && StyleConfigData::menuOpacity() < 100 ) { _blurHelper->registerWidget( widget->window() ); } } else if( qobject_cast( widget ) ) { addEventFilter( widget ); } else if( auto comboBox = qobject_cast( widget ) ) { if( !hasParent( widget, "QWebView" ) ) { auto itemView( comboBox->view() ); if( itemView && itemView->itemDelegate() && itemView->itemDelegate()->inherits( "QComboBoxDelegate" ) ) { itemView->setItemDelegate( new BreezePrivate::ComboBoxItemDelegate( itemView ) ); } } } else if( widget->inherits( "QComboBoxPrivateContainer" ) ) { addEventFilter( widget ); setTranslucentBackground( widget ); } else if( widget->inherits( "QTipLabel" ) ) { setTranslucentBackground( widget ); + } else if ( qobject_cast (widget) || qobject_cast (widget) ) { + widget->setAttribute(Qt::WA_StyledBackground); } - // base class polishing ParentStyleClass::polish( widget ); } //______________________________________________________________ void Style::polishScrollArea( QAbstractScrollArea* scrollArea ) { // check argument if( !scrollArea ) return; // enable mouse over effect in sunken scrollareas that support focus if( scrollArea->frameShadow() == QFrame::Sunken && scrollArea->focusPolicy()&Qt::StrongFocus ) { scrollArea->setAttribute( Qt::WA_Hover ); } if( scrollArea->viewport() && scrollArea->inherits( "KItemListContainer" ) && scrollArea->frameShape() == QFrame::NoFrame ) { scrollArea->viewport()->setBackgroundRole( QPalette::Window ); scrollArea->viewport()->setForegroundRole( QPalette::WindowText ); } // add event filter, to make sure proper background is rendered behind scrollbars addEventFilter( scrollArea ); // force side panels as flat, on option if( scrollArea->inherits( "KDEPrivate::KPageListView" ) || scrollArea->inherits( "KDEPrivate::KPageTreeView" ) ) { scrollArea->setProperty( PropertyNames::sidePanelView, true ); } // for all side view panels, unbold font (design choice) if( scrollArea->property( PropertyNames::sidePanelView ).toBool() ) { // upbold list font auto font( scrollArea->font() ); font.setBold( false ); scrollArea->setFont( font ); } // disable autofill background for flat (== NoFrame) scrollareas, with QPalette::Window as a background // this fixes flat scrollareas placed in a tinted widget, such as groupboxes, tabwidgets or framed dock-widgets if( !(scrollArea->frameShape() == QFrame::NoFrame || scrollArea->backgroundRole() == QPalette::Window ) ) { return; } // get viewport and check background role auto viewport( scrollArea->viewport() ); if( !( viewport && viewport->backgroundRole() == QPalette::Window ) ) return; // change viewport autoFill background. // do the same for all children if the background role is QPalette::Window viewport->setAutoFillBackground( false ); QList children( viewport->findChildren() ); foreach( QWidget* child, children ) { if( child->parent() == viewport && child->backgroundRole() == QPalette::Window ) { child->setAutoFillBackground( false ); } } /* QTreeView animates expanding/collapsing branches. It paints them into a temp pixmap whose background is unconditionally filled with the palette's *base* color which is usually different from the window's color cf. QTreeViewPrivate::renderTreeToPixmapForAnimation() */ if( auto treeView = qobject_cast( scrollArea ) ) { if (treeView->isAnimated()) { QPalette pal( treeView->palette() ); pal.setColor( QPalette::Active, QPalette::Base, treeView->palette().color( treeView->backgroundRole() ) ); treeView->setPalette(pal); } } } //_______________________________________________________________ void Style::unpolish( QWidget* widget ) { // register widget to animations _animations->unregisterWidget( widget ); _frameShadowFactory->unregisterWidget( widget ); _mdiWindowShadowFactory->unregisterWidget( widget ); _shadowHelper->unregisterWidget( widget ); _windowManager->unregisterWidget( widget ); _splitterFactory->unregisterWidget( widget ); _blurHelper->unregisterWidget( widget ); + _toolsAreaManager->unregisterWidget ( widget ); // remove event filter if( qobject_cast( widget ) || qobject_cast( widget ) || qobject_cast( widget ) || widget->inherits( "QComboBoxPrivateContainer" ) ) { widget->removeEventFilter( this ); } ParentStyleClass::unpolish( widget ); } //______________________________________________________________ int Style::pixelMetric( PixelMetric metric, const QStyleOption* option, const QWidget* widget ) const { // handle special cases switch( metric ) { // frame width case PM_DefaultFrameWidth: if( qobject_cast( widget ) ) return Metrics::Menu_FrameWidth; if( qobject_cast( widget ) ) return Metrics::LineEdit_FrameWidth; else if( isQtQuickControl( option, widget ) ) { const QString &elementType = option->styleObject->property( "elementType" ).toString(); if( elementType == QLatin1String( "edit" ) || elementType == QLatin1String( "spinbox" ) ) { return Metrics::LineEdit_FrameWidth; } else if( elementType == QLatin1String( "combobox" ) ) { return Metrics::ComboBox_FrameWidth; } } // fallback return Metrics::Frame_FrameWidth; case PM_ComboBoxFrameWidth: { const auto comboBoxOption( qstyleoption_cast< const QStyleOptionComboBox*>( option ) ); return comboBoxOption && comboBoxOption->editable ? Metrics::LineEdit_FrameWidth : Metrics::ComboBox_FrameWidth; } case PM_SpinBoxFrameWidth: return Metrics::SpinBox_FrameWidth; case PM_ToolBarFrameWidth: return Metrics::ToolBar_FrameWidth; case PM_ToolTipLabelFrameWidth: return Metrics::ToolTip_FrameWidth; // layout case PM_LayoutLeftMargin: case PM_LayoutTopMargin: case PM_LayoutRightMargin: case PM_LayoutBottomMargin: { /* * use either Child margin or TopLevel margin, * depending on widget type */ if( ( option && ( option->state & QStyle::State_Window ) ) || ( widget && widget->isWindow() ) ) { return Metrics::Layout_TopLevelMarginWidth; } else if( widget && widget->inherits( "KPageView" ) ) { return 0; } else { return Metrics::Layout_ChildMarginWidth; } } case PM_LayoutHorizontalSpacing: return Metrics::Layout_DefaultSpacing; case PM_LayoutVerticalSpacing: return Metrics::Layout_DefaultSpacing; // buttons case PM_ButtonMargin: { // needs special case for kcalc buttons, to prevent the application to set too small margins if( widget && widget->inherits( "KCalcButton" ) ) return Metrics::Button_MarginWidth + 4; else return Metrics::Button_MarginWidth; } case PM_ButtonDefaultIndicator: return 0; case PM_ButtonShiftHorizontal: return 0; case PM_ButtonShiftVertical: return 0; // menubars case PM_MenuBarPanelWidth: return 0; case PM_MenuBarHMargin: return 0; case PM_MenuBarVMargin: return 0; case PM_MenuBarItemSpacing: return 0; case PM_MenuDesktopFrameWidth: return 0; // menu buttons case PM_MenuButtonIndicator: return Metrics::MenuButton_IndicatorWidth; // toolbars case PM_ToolBarHandleExtent: return Metrics::ToolBar_HandleExtent; case PM_ToolBarSeparatorExtent: return Metrics::ToolBar_SeparatorWidth; case PM_ToolBarExtensionExtent: return pixelMetric( PM_SmallIconSize, option, widget ) + 2*Metrics::ToolButton_MarginWidth; case PM_ToolBarItemMargin: return 0; case PM_ToolBarItemSpacing: return Metrics::ToolBar_ItemSpacing; // tabbars case PM_TabBarTabShiftVertical: return 0; case PM_TabBarTabShiftHorizontal: return 0; case PM_TabBarTabOverlap: return Metrics::TabBar_TabOverlap; case PM_TabBarBaseOverlap: return Metrics::TabBar_BaseOverlap; case PM_TabBarTabHSpace: return 2*Metrics::TabBar_TabMarginWidth; case PM_TabBarTabVSpace: return 2*Metrics::TabBar_TabMarginHeight; case PM_TabCloseIndicatorWidth: case PM_TabCloseIndicatorHeight: return pixelMetric( PM_SmallIconSize, option, widget ); // scrollbars case PM_ScrollBarExtent: return Metrics::ScrollBar_Extend; case PM_ScrollBarSliderMin: return Metrics::ScrollBar_MinSliderHeight; // title bar case PM_TitleBarHeight: return 2*Metrics::TitleBar_MarginWidth + pixelMetric( PM_SmallIconSize, option, widget ); // sliders case PM_SliderThickness: return Metrics::Slider_ControlThickness; case PM_SliderControlThickness: return Metrics::Slider_ControlThickness; case PM_SliderLength: return Metrics::Slider_ControlThickness; // checkboxes and radio buttons case PM_IndicatorWidth: return Metrics::CheckBox_Size; case PM_IndicatorHeight: return Metrics::CheckBox_Size; case PM_ExclusiveIndicatorWidth: return Metrics::CheckBox_Size; case PM_ExclusiveIndicatorHeight: return Metrics::CheckBox_Size; // list heaaders case PM_HeaderMarkSize: return Metrics::Header_ArrowSize; case PM_HeaderMargin: return Metrics::Header_MarginWidth; // dock widget // return 0 here, since frame is handled directly in polish case PM_DockWidgetFrameWidth: return 0; case PM_DockWidgetTitleMargin: return Metrics::Frame_FrameWidth; case PM_DockWidgetTitleBarButtonMargin: return Metrics::ToolButton_MarginWidth; case PM_SplitterWidth: return Metrics::Splitter_SplitterWidth; case PM_DockWidgetSeparatorExtent: return Metrics::Splitter_SplitterWidth; // fallback default: return ParentStyleClass::pixelMetric( metric, option, widget ); } } //______________________________________________________________ int Style::styleHint( StyleHint hint, const QStyleOption* option, const QWidget* widget, QStyleHintReturn* returnData ) const { switch( hint ) { case SH_RubberBand_Mask: { if( auto mask = qstyleoption_cast( returnData ) ) { mask->region = option->rect; /* * need to check on widget before removing inner region * in order to still preserve rubberband in MainWindow and QGraphicsView * in QMainWindow because it looks better * in QGraphicsView because the painting fails completely otherwise */ if( widget && ( qobject_cast( widget->parent() ) || qobject_cast( widget->parent() ) || qobject_cast( widget->parent() ) ) ) { return true; } // also check if widget's parent is some itemView viewport if( widget && widget->parent() && qobject_cast( widget->parent()->parent() ) && static_cast( widget->parent()->parent() )->viewport() == widget->parent() ) { return true; } // mask out center mask->region -= insideMargin( option->rect, 1 ); return true; } return false; } case SH_ComboBox_ListMouseTracking: return true; case SH_MenuBar_MouseTracking: return true; case SH_Menu_MouseTracking: return true; case SH_Menu_SubMenuPopupDelay: return 150; case SH_Menu_SloppySubMenus: return true; // TODO Qt6: drop deprecated SH_Widget_Animate case SH_Widget_Animate: return StyleConfigData::animationsEnabled(); case SH_Menu_SupportsSections: return true; case SH_Widget_Animation_Duration: return StyleConfigData::animationsEnabled() ? StyleConfigData::animationsDuration() : 0; case SH_DialogButtonBox_ButtonsHaveIcons: return true; case SH_GroupBox_TextLabelVerticalAlignment: return Qt::AlignVCenter; case SH_TabBar_Alignment: return StyleConfigData::tabBarDrawCenteredTabs() ? Qt::AlignCenter:Qt::AlignLeft; case SH_ToolBox_SelectedPageTitleBold: return false; case SH_ScrollBar_MiddleClickAbsolutePosition: return true; case SH_ScrollView_FrameOnlyAroundContents: return false; case SH_FormLayoutFormAlignment: return Qt::AlignLeft | Qt::AlignTop; case SH_FormLayoutLabelAlignment: return Qt::AlignRight; case SH_FormLayoutFieldGrowthPolicy: return QFormLayout::ExpandingFieldsGrow; case SH_FormLayoutWrapPolicy: return QFormLayout::DontWrapRows; case SH_MessageBox_TextInteractionFlags: return Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse; case SH_ProgressDialog_CenterCancelButton: return false; case SH_MessageBox_CenterButtons: return false; case SH_RequestSoftwareInputPanel: return RSIP_OnMouseClick; case SH_TitleBar_NoBorder: return true; case SH_DockWidget_ButtonsHaveFrame: return false; default: return ParentStyleClass::styleHint( hint, option, widget, returnData ); } } //______________________________________________________________ QRect Style::subElementRect( SubElement element, const QStyleOption* option, const QWidget* widget ) const { switch( element ) { case SE_PushButtonContents: return pushButtonContentsRect( option, widget ); case SE_CheckBoxContents: return checkBoxContentsRect( option, widget ); case SE_RadioButtonContents: return checkBoxContentsRect( option, widget ); case SE_LineEditContents: return lineEditContentsRect( option, widget ); case SE_ProgressBarGroove: return progressBarGrooveRect( option, widget ); case SE_ProgressBarContents: return progressBarContentsRect( option, widget ); case SE_ProgressBarLabel: return progressBarLabelRect( option, widget ); case SE_FrameContents: return frameContentsRect( option, widget ); case SE_HeaderArrow: return headerArrowRect( option, widget ); case SE_HeaderLabel: return headerLabelRect( option, widget ); case SE_TabBarTabLeftButton: return tabBarTabLeftButtonRect( option, widget ); case SE_TabBarTabRightButton: return tabBarTabRightButtonRect( option, widget ); case SE_TabWidgetTabBar: return tabWidgetTabBarRect( option, widget ); case SE_TabWidgetTabContents: return tabWidgetTabContentsRect( option, widget ); case SE_TabWidgetTabPane: return tabWidgetTabPaneRect( option, widget ); case SE_TabWidgetLeftCorner: return tabWidgetCornerRect( SE_TabWidgetLeftCorner, option, widget ); case SE_TabWidgetRightCorner: return tabWidgetCornerRect( SE_TabWidgetRightCorner, option, widget ); case SE_ToolBoxTabContents: return toolBoxTabContentsRect( option, widget ); // fallback default: return ParentStyleClass::subElementRect( element, option, widget ); } } //______________________________________________________________ QRect Style::subControlRect( ComplexControl element, const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget ) const { switch( element ) { case CC_GroupBox: return groupBoxSubControlRect( option, subControl, widget ); case CC_ToolButton: return toolButtonSubControlRect( option, subControl, widget ); case CC_ComboBox: return comboBoxSubControlRect( option, subControl, widget ); case CC_SpinBox: return spinBoxSubControlRect( option, subControl, widget ); case CC_ScrollBar: return scrollBarSubControlRect( option, subControl, widget ); case CC_Dial: return dialSubControlRect( option, subControl, widget ); case CC_Slider: return sliderSubControlRect( option, subControl, widget ); // fallback default: return ParentStyleClass::subControlRect( element, option, subControl, widget ); } } //______________________________________________________________ QSize Style::sizeFromContents( ContentsType element, const QStyleOption* option, const QSize& size, const QWidget* widget ) const { switch( element ) { case CT_CheckBox: return checkBoxSizeFromContents( option, size, widget ); case CT_RadioButton: return checkBoxSizeFromContents( option, size, widget ); case CT_LineEdit: return lineEditSizeFromContents( option, size, widget ); case CT_ComboBox: return comboBoxSizeFromContents( option, size, widget ); case CT_SpinBox: return spinBoxSizeFromContents( option, size, widget ); case CT_Slider: return sliderSizeFromContents( option, size, widget ); case CT_PushButton: return pushButtonSizeFromContents( option, size, widget ); case CT_ToolButton: return toolButtonSizeFromContents( option, size, widget ); case CT_MenuBar: return defaultSizeFromContents( option, size, widget ); case CT_MenuBarItem: return menuBarItemSizeFromContents( option, size, widget ); case CT_MenuItem: return menuItemSizeFromContents( option, size, widget ); case CT_ProgressBar: return progressBarSizeFromContents( option, size, widget ); case CT_TabWidget: return tabWidgetSizeFromContents( option, size, widget ); case CT_TabBarTab: return tabBarTabSizeFromContents( option, size, widget ); case CT_HeaderSection: return headerSectionSizeFromContents( option, size, widget ); case CT_ItemViewItem: return itemViewItemSizeFromContents( option, size, widget ); // fallback default: return ParentStyleClass::sizeFromContents( element, option, size, widget ); } } //______________________________________________________________ QStyle::SubControl Style::hitTestComplexControl( ComplexControl control, const QStyleOptionComplex* option, const QPoint& point, const QWidget* widget ) const { switch( control ) { case CC_ScrollBar: { auto grooveRect = subControlRect( CC_ScrollBar, option, SC_ScrollBarGroove, widget ); if( grooveRect.contains( point ) ) { // Must be either page up/page down, or just click on the slider. auto sliderRect = subControlRect( CC_ScrollBar, option, SC_ScrollBarSlider, widget ); if( sliderRect.contains( point ) ) return SC_ScrollBarSlider; else if( preceeds( point, sliderRect, option ) ) return SC_ScrollBarSubPage; else return SC_ScrollBarAddPage; } // This is one of the up/down buttons. First, decide which one it is. if( preceeds( point, grooveRect, option ) ) { if( _subLineButtons == DoubleButton ) { auto buttonRect = scrollBarInternalSubControlRect( option, SC_ScrollBarSubLine ); return scrollBarHitTest( buttonRect, point, option ); } else return SC_ScrollBarSubLine; } if( _addLineButtons == DoubleButton ) { auto buttonRect = scrollBarInternalSubControlRect( option, SC_ScrollBarAddLine ); return scrollBarHitTest( buttonRect, point, option ); } else return SC_ScrollBarAddLine; } // fallback default: return ParentStyleClass::hitTestComplexControl( control, option, point, widget ); } } //______________________________________________________________ void Style::drawPrimitive( PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { StylePrimitive fcn; switch( element ) { case PE_PanelButtonCommand: fcn = &Style::drawPanelButtonCommandPrimitive; break; case PE_PanelButtonTool: fcn = &Style::drawPanelButtonToolPrimitive; break; case PE_PanelScrollAreaCorner: fcn = &Style::drawPanelScrollAreaCornerPrimitive; break; case PE_PanelMenu: fcn = &Style::drawPanelMenuPrimitive; break; case PE_PanelTipLabel: fcn = &Style::drawPanelTipLabelPrimitive; break; case PE_PanelItemViewItem: fcn = &Style::drawPanelItemViewItemPrimitive; break; case PE_IndicatorCheckBox: fcn = &Style::drawIndicatorCheckBoxPrimitive; break; case PE_IndicatorRadioButton: fcn = &Style::drawIndicatorRadioButtonPrimitive; break; case PE_IndicatorButtonDropDown: fcn = &Style::drawIndicatorButtonDropDownPrimitive; break; case PE_IndicatorTabClose: fcn = &Style::drawIndicatorTabClosePrimitive; break; case PE_IndicatorTabTear: fcn = &Style::drawIndicatorTabTearPrimitive; break; case PE_IndicatorArrowUp: fcn = &Style::drawIndicatorArrowUpPrimitive; break; case PE_IndicatorArrowDown: fcn = &Style::drawIndicatorArrowDownPrimitive; break; case PE_IndicatorArrowLeft: fcn = &Style::drawIndicatorArrowLeftPrimitive; break; case PE_IndicatorArrowRight: fcn = &Style::drawIndicatorArrowRightPrimitive; break; case PE_IndicatorHeaderArrow: fcn = &Style::drawIndicatorHeaderArrowPrimitive; break; case PE_IndicatorToolBarHandle: fcn = &Style::drawIndicatorToolBarHandlePrimitive; break; case PE_IndicatorToolBarSeparator: fcn = &Style::drawIndicatorToolBarSeparatorPrimitive; break; case PE_IndicatorBranch: fcn = &Style::drawIndicatorBranchPrimitive; break; case PE_FrameStatusBar: fcn = &Style::emptyPrimitive; break; case PE_Frame: fcn = &Style::drawFramePrimitive; break; case PE_FrameLineEdit: fcn = &Style::drawFrameLineEditPrimitive; break; case PE_FrameMenu: fcn = &Style::drawFrameMenuPrimitive; break; case PE_FrameGroupBox: fcn = &Style::drawFrameGroupBoxPrimitive; break; case PE_FrameTabWidget: fcn = &Style::drawFrameTabWidgetPrimitive; break; case PE_FrameTabBarBase: fcn = &Style::drawFrameTabBarBasePrimitive; break; case PE_FrameWindow: fcn = &Style::drawFrameWindowPrimitive; break; case PE_FrameFocusRect: fcn = _frameFocusPrimitive; break; + case PE_Widget: fcn = &Style::drawWidgetPrimitive; break; // fallback default: break; } painter->save(); // call function if implemented if( !( fcn && fcn( *this, option, painter, widget ) ) ) { ParentStyleClass::drawPrimitive( element, option, painter, widget ); } painter->restore(); } + bool Style::drawWidgetPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { + Q_UNUSED(option) + auto parent = widget; + while (parent != nullptr) { + if (qobject_cast(parent) || qobject_cast(parent)) return true; + parent = parent->parentWidget(); + } + if (qobject_cast(widget) || qobject_cast (widget)) { + if (!_helper->toolsAreaHasContents(widget) && _helper->shouldDrawToolsArea(widget)) { + painter->save(); + painter->setPen(_helper->toolsAreaBorderColor(widget)); + painter->setRenderHints(QPainter::Antialiasing, false); + painter->setBrush(Qt::NoBrush); + + painter->drawLine( + widget->rect().left()*2, + widget->rect().top(), + widget->rect().right()*2, + widget->rect().top() + ); + painter->restore(); + } else if (_helper->shouldDrawToolsArea(widget)) { + auto rect = _helper->toolsAreaToolbarsRect(widget); + + painter->save(); + { + painter->setBrush(_helper->titleBarColor(widget->isActiveWindow())); + painter->setPen(Qt::NoPen); + + painter->drawRect(rect); + } + painter->restore(); + + painter->save(); + { + painter->setPen(_helper->toolsAreaBorderColor(widget)); + painter->setBrush(Qt::NoBrush); + painter->setRenderHints(QPainter::Antialiasing, false); + + painter->drawLine( + rect.left()*2, + rect.bottom(), + rect.right()*2, + rect.bottom() + ); + } + painter->restore(); + } + } + return true; + } + //______________________________________________________________ void Style::drawControl( ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { StyleControl fcn; #if BREEZE_HAVE_KSTYLE if( element == CE_CapacityBar ) { fcn = &Style::drawProgressBarControl; } else #endif switch( element ) { case CE_PushButtonBevel: fcn = &Style::drawPanelButtonCommandPrimitive; break; case CE_PushButtonLabel: fcn = &Style::drawPushButtonLabelControl; break; case CE_CheckBoxLabel: fcn = &Style::drawCheckBoxLabelControl; break; case CE_RadioButtonLabel: fcn = &Style::drawCheckBoxLabelControl; break; case CE_ToolButtonLabel: fcn = &Style::drawToolButtonLabelControl; break; case CE_ComboBoxLabel: fcn = &Style::drawComboBoxLabelControl; break; case CE_MenuBarEmptyArea: fcn = &Style::emptyControl; break; case CE_MenuBarItem: fcn = &Style::drawMenuBarItemControl; break; case CE_MenuItem: fcn = &Style::drawMenuItemControl; break; - case CE_ToolBar: fcn = &Style::emptyControl; break; + case CE_ToolBar: fcn = &Style::drawToolBarControl; break; case CE_ProgressBar: fcn = &Style::drawProgressBarControl; break; case CE_ProgressBarContents: fcn = &Style::drawProgressBarContentsControl; break; case CE_ProgressBarGroove: fcn = &Style::drawProgressBarGrooveControl; break; case CE_ProgressBarLabel: fcn = &Style::drawProgressBarLabelControl; break; case CE_ScrollBarSlider: fcn = &Style::drawScrollBarSliderControl; break; case CE_ScrollBarAddLine: fcn = &Style::drawScrollBarAddLineControl; break; case CE_ScrollBarSubLine: fcn = &Style::drawScrollBarSubLineControl; break; case CE_ScrollBarAddPage: fcn = &Style::emptyControl; break; case CE_ScrollBarSubPage: fcn = &Style::emptyControl; break; case CE_ShapedFrame: fcn = &Style::drawShapedFrameControl; break; case CE_RubberBand: fcn = &Style::drawRubberBandControl; break; case CE_SizeGrip: fcn = &Style::emptyControl; break; case CE_HeaderSection: fcn = &Style::drawHeaderSectionControl; break; case CE_HeaderEmptyArea: fcn = &Style::drawHeaderEmptyAreaControl; break; case CE_TabBarTabLabel: fcn = &Style::drawTabBarTabLabelControl; break; case CE_TabBarTabShape: fcn = &Style::drawTabBarTabShapeControl; break; case CE_ToolBoxTabLabel: fcn = &Style::drawToolBoxTabLabelControl; break; case CE_ToolBoxTabShape: fcn = &Style::drawToolBoxTabShapeControl; break; case CE_DockWidgetTitle: fcn = &Style::drawDockWidgetTitleControl; break; // fallback default: break; } painter->save(); // call function if implemented if( !( fcn && fcn( *this, option, painter, widget ) ) ) { ParentStyleClass::drawControl( element, option, painter, widget ); } painter->restore(); } //______________________________________________________________ void Style::drawComplexControl( ComplexControl element, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget ) const { StyleComplexControl fcn; switch( element ) { case CC_GroupBox: fcn = &Style::drawGroupBoxComplexControl; break; case CC_ToolButton: fcn = &Style::drawToolButtonComplexControl; break; case CC_ComboBox: fcn = &Style::drawComboBoxComplexControl; break; case CC_SpinBox: fcn = &Style::drawSpinBoxComplexControl; break; case CC_Slider: fcn = &Style::drawSliderComplexControl; break; case CC_Dial: fcn = &Style::drawDialComplexControl; break; case CC_ScrollBar: fcn = &Style::drawScrollBarComplexControl; break; case CC_TitleBar: fcn = &Style::drawTitleBarComplexControl; break; // fallback default: break; } painter->save(); // call function if implemented if( !( fcn && fcn( *this, option, painter, widget ) ) ) { ParentStyleClass::drawComplexControl( element, option, painter, widget ); } painter->restore(); } //___________________________________________________________________________________ void Style::drawItemText( QPainter* painter, const QRect& rect, int flags, const QPalette& palette, bool enabled, const QString &text, QPalette::ColorRole textRole ) const { // hide mnemonics if requested if( !_mnemonics->enabled() && ( flags&Qt::TextShowMnemonic ) && !( flags&Qt::TextHideMnemonic ) ) { flags &= ~Qt::TextShowMnemonic; flags |= Qt::TextHideMnemonic; } // make sure vertical alignment is defined // fallback on Align::VCenter if not if( !(flags&Qt::AlignVertical_Mask) ) flags |= Qt::AlignVCenter; if( _animations->widgetEnabilityEngine().enabled() ) { /* * check if painter engine is registered to WidgetEnabilityEngine, and animated * if yes, merge the palettes. Note: a static_cast is safe here, since only the address * of the pointer is used, not the actual content. */ const QWidget* widget( static_cast( painter->device() ) ); if( _animations->widgetEnabilityEngine().isAnimated( widget, AnimationEnable ) ) { const QPalette copy( _helper->disabledPalette( palette, _animations->widgetEnabilityEngine().opacity( widget, AnimationEnable ) ) ); return ParentStyleClass::drawItemText( painter, rect, flags, copy, enabled, text, textRole ); } } // fallback return ParentStyleClass::drawItemText( painter, rect, flags, palette, enabled, text, textRole ); } //_____________________________________________________________________ bool Style::eventFilter( QObject *object, QEvent *event ) { if( auto dockWidget = qobject_cast( object ) ) { return eventFilterDockWidget( dockWidget, event ); } else if( auto subWindow = qobject_cast( object ) ) { return eventFilterMdiSubWindow( subWindow, event ); } else if( auto commandLinkButton = qobject_cast( object ) ) { return eventFilterCommandLinkButton( commandLinkButton, event ); } #if QT_VERSION < 0x050D00 // Check if Qt version < 5.13 else if( object == qApp && event->type() == QEvent::ApplicationPaletteChange ) { configurationChanged(); } #endif // cast to QWidget QWidget *widget = static_cast( object ); if( widget->inherits( "QAbstractScrollArea" ) || widget->inherits( "KTextEditor::View" ) ) { return eventFilterScrollArea( widget, event ); } else if( widget->inherits( "QComboBoxPrivateContainer" ) ) { return eventFilterComboBoxContainer( widget, event ); } // fallback return ParentStyleClass::eventFilter( object, event ); } //____________________________________________________________________________ bool Style::eventFilterScrollArea( QWidget* widget, QEvent* event ) { switch( event->type() ) { case QEvent::Paint: { // get scrollarea viewport auto scrollArea( qobject_cast( widget ) ); QWidget* viewport; if( !( scrollArea && (viewport = scrollArea->viewport()) ) ) break; // get scrollarea horizontal and vertical containers QWidget* child( nullptr ); QList children; if( ( child = scrollArea->findChild( "qt_scrollarea_vcontainer" ) ) && child->isVisible() ) { children.append( child ); } if( ( child = scrollArea->findChild( "qt_scrollarea_hcontainer" ) ) && child->isVisible() ) { children.append( child ); } if( children.empty() ) break; if( !scrollArea->styleSheet().isEmpty() ) break; // make sure proper background is rendered behind the containers QPainter painter( scrollArea ); painter.setClipRegion( static_cast( event )->region() ); painter.setPen( Qt::NoPen ); // decide background color const QPalette::ColorRole role( viewport->backgroundRole() ); QColor background; if( role == QPalette::Window && hasAlteredBackground( viewport ) ) background = _helper->frameBackgroundColor( viewport->palette() ); else background = viewport->palette().color( role ); painter.setBrush( background ); // render foreach( auto* child, children ) { painter.drawRect( child->geometry() ); } } break; case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: { // case event QMouseEvent* mouseEvent( static_cast( event ) ); // get frame framewidth const int frameWidth( pixelMetric( PM_DefaultFrameWidth, nullptr, widget ) ); // find list of scrollbars QList scrollBars; if( auto scrollArea = qobject_cast( widget ) ) { if( scrollArea->horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff ) scrollBars.append( scrollArea->horizontalScrollBar() ); if( scrollArea->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff )scrollBars.append( scrollArea->verticalScrollBar() ); } else if( widget->inherits( "KTextEditor::View" ) ) { scrollBars = widget->findChildren(); } // loop over found scrollbars foreach( QScrollBar* scrollBar, scrollBars ) { if( !( scrollBar && scrollBar->isVisible() ) ) continue; QPoint offset; if( scrollBar->orientation() == Qt::Horizontal ) offset = QPoint( 0, frameWidth ); else offset = QPoint( QApplication::isLeftToRight() ? frameWidth : -frameWidth, 0 ); // map position to scrollarea QPoint position( scrollBar->mapFrom( widget, mouseEvent->pos() - offset ) ); // check if contains if( !scrollBar->rect().contains( position ) ) continue; // copy event, send and return QMouseEvent copy( mouseEvent->type(), position, mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers()); QCoreApplication::sendEvent( scrollBar, © ); event->setAccepted( true ); return true; } break; } default: break; } return ParentStyleClass::eventFilter( widget, event ); } //_________________________________________________________ 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; } //____________________________________________________________________________ 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(_helper->coloredIcon(button->icon(), button->palette(), 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; } //_____________________________________________________________________ void Style::configurationChanged() { // reload StyleConfigData::self()->load(); // reload configuration loadConfiguration(); + // load new titlebar colours into tools area animations + _toolsAreaManager->updateAnimations(); + + // trigger update of tools area + emit _toolsAreaManager->toolbarUpdated(); + } //____________________________________________________________________ QIcon Style::standardIconImplementation( StandardPixmap standardPixmap, const QStyleOption* option, const QWidget* widget ) const { // lookup cache if( _iconCache.contains( standardPixmap ) ) return _iconCache.value( standardPixmap ); QIcon icon; switch( standardPixmap ) { case SP_TitleBarNormalButton: case SP_TitleBarMinButton: case SP_TitleBarMaxButton: case SP_TitleBarCloseButton: case SP_DockWidgetCloseButton: icon = titleBarButtonIcon( standardPixmap, option, widget ); break; case SP_ToolBarHorizontalExtensionButton: case SP_ToolBarVerticalExtensionButton: icon = toolBarExtensionIcon( standardPixmap, option, widget ); break; default: break; } if( icon.isNull() ) { // do not cache parent style icon, since it may change at runtime return ParentStyleClass::standardIcon( standardPixmap, option, widget ); } else { const_cast(&_iconCache)->insert( standardPixmap, icon ); return icon; } } //_____________________________________________________________________ void Style::loadConfiguration() { // load helper configuration _helper->loadConfig(); + _helper->setToolsAreaEnabled(StyleConfigData::toolsAreaEnabled() ); // reinitialize engines _animations->setupEngines(); _windowManager->initialize(); // mnemonics _mnemonics->setMode( StyleConfigData::mnemonicsMode() ); // splitter proxy _splitterFactory->setEnabled( StyleConfigData::splitterProxyEnabled() ); // reset shadow tiles _shadowHelper->loadConfig(); // set mdiwindow factory shadow tiles _mdiWindowShadowFactory->setShadowHelper( _shadowHelper ); // clear icon cache _iconCache.clear(); // scrollbar buttons switch( StyleConfigData::scrollBarAddLineButtons() ) { case 0: _addLineButtons = NoButton; break; case 1: _addLineButtons = SingleButton; break; default: case 2: _addLineButtons = DoubleButton; break; } switch( StyleConfigData::scrollBarSubLineButtons() ) { case 0: _subLineButtons = NoButton; break; case 1: _subLineButtons = SingleButton; break; default: case 2: _subLineButtons = DoubleButton; break; } // frame focus if( StyleConfigData::viewDrawFocusIndicator() ) _frameFocusPrimitive = &Style::drawFrameFocusRectPrimitive; else _frameFocusPrimitive = &Style::emptyPrimitive; // widget explorer _widgetExplorer->setEnabled( StyleConfigData::widgetExplorerEnabled() ); _widgetExplorer->setDrawWidgetRects( StyleConfigData::drawWidgetRects() ); } //___________________________________________________________________________________________________________________ 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 { // 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; } //___________________________________________________________________________________________________________________ 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 ); const bool horizontal( BreezePrivate::isProgressBarHorizontal( progressBarOption ) ); // 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 const bool horizontal( BreezePrivate::isProgressBarHorizontal( progressBarOption ) ); // check inverted appearance const bool inverted( progressBarOption->invertedAppearance ); // 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::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 const bool horizontal( BreezePrivate::isProgressBarHorizontal( progressBarOption ) ); 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 const auto tabOption( qstyleoption_cast( option ) ); 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 const auto tabOption( qstyleoption_cast( option ) ); 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; size.rwidth() += Metrics::Button_ItemSpacing; 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 int marginWidth( autoRaise ? Metrics::ToolButton_MarginWidth : Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth ); 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.boundingRect( menuItemOption->text ).width() ) ); } 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; const bool horizontal( BreezePrivate::isProgressBarHorizontal( progressBarOption ) ); // 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() ); const bool hasLeftButton( tabOption && !tabOption->leftButtonSize.isEmpty() ); const bool hasRightButton( tabOption && !tabOption->leftButtonSize.isEmpty() ); // 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; const bool isInputWidget( ( widget && widget->testAttribute( Qt::WA_Hover ) ) || ( isQtQuickControl( option, widget ) && option->styleObject->property( "elementType" ).toString() == QStringLiteral( "edit") ) ); 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 ( option->styleObject && option->styleObject->property("elementType") == QLatin1String("button") ) { return true; } 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( frameOption->features & QStyleOptionFrame::Flat ) return true; // 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 const auto tabOption( qstyleoption_cast( option ) ); 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 ( hasAlpha ) { background.setAlphaF(StyleConfigData::menuOpacity() / 100.0); } _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 const auto viewItemOption = qstyleoption_cast( option ); 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; const bool hasAlternateBackground( viewItemOption->features & QStyleOptionViewItem::Alternate ); // 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; // 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 ) ); // colors const auto shadow( _helper->shadowColor( palette ) ); const AnimationMode mode( _animations->widgetStateEngine().isAnimated( widget, AnimationHover ) ? AnimationHover:AnimationNone ); const qreal opacity( _animations->widgetStateEngine().opacity( widget, AnimationHover ) ); QColor background = itemViewParent( widget ) ? palette.color( QPalette::Base ) : palette.color( QPalette::Window ); QColor color = _helper->checkBoxIndicatorColor( palette, mouseOver, enabled && active, opacity, mode ); // render _helper->renderCheckBoxBackground( painter, rect, background, sunken ); _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 ); // 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 ) ); const AnimationMode mode( _animations->widgetStateEngine().isAnimated( widget, AnimationHover ) ? AnimationHover:AnimationNone ); const qreal opacity( _animations->widgetStateEngine().opacity( widget, AnimationHover ) ); QColor background = itemViewParent( widget ) ? palette.color( QPalette::Base ) : palette.color( QPalette::Window ); QColor color = _helper->checkBoxIndicatorColor( palette, mouseOver, enabled && checked, opacity, mode ); // render _helper->renderRadioButtonBackground( painter, rect, background, sunken ); _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(_helper->coloredIcon(icon, option->palette, 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 = _helper->coloredIcon(buttonOption->icon, buttonOption->palette, 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 = _helper->coloredIcon(toolButtonOption->icon, toolButtonOption->palette, 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; + auto palette = option->palette; + + if (_helper->isInToolsArea(widget)) { + palette.setColor(QPalette::ButtonText, _helper->titleBarTextColor(widget->isActiveWindow())); + palette.setColor(QPalette::WindowText, _helper->titleBarTextColor(widget->isActiveWindow())); + } + 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(_helper->coloredIcon(buttonOption->icon, buttonOption->palette, 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 (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( !enabled ) mode = QIcon::Disabled; else if( !flat && hasFocus ) mode = QIcon::Selected; else if( mouseOver && flat ) mode = QIcon::Active; else mode = QIcon::Normal; const QPixmap pixmap = _helper->coloredIcon(cb->currentIcon,cb->palette, 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(); } 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 ); + auto palette( option->palette ); + + if (_helper->isInToolsArea(widget)) { + palette.setColor(QPalette::WindowText, _helper->titleBarTextColor(widget->isActiveWindow())); + } // 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() ); + painter->save(); + painter->setRenderHints( QPainter::Antialiasing ); + // 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 = _helper->coloredIcon(menuItemOption->icon, menuItemOption->palette, iconRect.size(), 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; + painter->restore(); + 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 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->renderCheckBoxBackground( painter, checkBoxRect, palette.color( QPalette::Window ), sunken ); _helper->renderCheckBox( painter, checkBoxRect, color, shadow, sunken, state ); } else if( menuItemOption->checkType == QStyleOptionMenuItem::Exclusive ) { checkBoxRect = visualRect( option, checkBoxRect ); const bool active( menuItemOption->checked ); const auto shadow( _helper->shadowColor( palette ) ); const auto color( _helper->checkBoxIndicatorColor( palette, false, enabled && active ) ); _helper->renderRadioButtonBackground( painter, checkBoxRect, palette.color( QPalette::Window ), sunken ); _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 = _helper->coloredIcon(menuItemOption->icon, menuItemOption->palette, 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::drawToolBarControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + Q_UNUSED(option) + Q_UNUSED(painter) + auto toolbar = const_cast(widget); + + if (!_helper->isInToolsArea(widget)) { + if (_toolsAreaManager->widgetHasCorrectPaletteSet(toolbar)) { + toolbar->setPalette(toolbar->parentWidget()->palette()); + } + return true; + } + + if (!_toolsAreaManager->widgetHasCorrectPaletteSet(widget)) { + auto palette = toolbar->palette(); + palette.setColor( QPalette::Window, _toolsAreaManager->background(widget) ); + palette.setColor( QPalette::WindowText, _toolsAreaManager->foreground(widget) ); + toolbar->setPalette(palette); + } + + 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 QStyleOptionProgressBar progressBarOption2 = *progressBarOption; progressBarOption2.rect = subElementRect( SE_ProgressBarGroove, progressBarOption, widget ); drawControl( CE_ProgressBarGroove, &progressBarOption2, painter, widget ); const QObject* styleObject( widget ? widget:progressBarOption->styleObject ); // enable busy animations // need to check both widget and passed styleObject, used for QML if( styleObject && _animations->busyIndicatorEngine().enabled() ) { // register QML object if defined if( !widget && progressBarOption->styleObject ) { _animations->busyIndicatorEngine().registerWidget( progressBarOption->styleObject ); } _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 const bool horizontal( BreezePrivate::isProgressBarHorizontal( progressBarOption ) ); const bool inverted( progressBarOption->invertedAppearance ); 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 const bool horizontal( BreezePrivate::isProgressBarHorizontal( progressBarOption ) ); 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 ); // need to make it center due to the thin line separator QRect rect = option->rect; if( option->state & State_Horizontal ) { rect.setTop(PenWidth::Frame); } else if (option->direction == Qt::RightToLeft) { rect.setRight(rect.right() - PenWidth::Frame); } else { rect.setLeft(PenWidth::Frame); } //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 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(); qreal grooveAnimationOpacity( _animations->scrollBarEngine().opacity( widget, QStyle::SC_ScrollBarGroove ) ); if( grooveAnimationOpacity == AnimationData::OpacityInvalid ) grooveAnimationOpacity = (widgetMouseOver ? 1 : 0); // define handle rect QRect handleRect; const State& state( option->state ); const bool horizontal( state & State_Horizontal ); if( horizontal ) handleRect = centerRect( rect, rect.width(), Metrics::ScrollBar_SliderWidth ); else handleRect = centerRect( rect, Metrics::ScrollBar_SliderWidth, 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 auto rect( scrollBarInternalSubControlRect( sliderOption, SC_ScrollBarAddLine ) ); // need to make it center due to the thin line separator if( option->state & State_Horizontal ) { rect.setTop(PenWidth::Frame); } else if (option->direction == Qt::RightToLeft) { rect.setRight(rect.right() - PenWidth::Frame); } else { rect.setLeft(PenWidth::Frame); } 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 ); // adjust rect, based on number of buttons to be drawn auto rect( scrollBarInternalSubControlRect( sliderOption, SC_ScrollBarSubLine ) ); // need to make it center due to the thin line separator if( option->state & State_Horizontal ) { rect.setTop(PenWidth::Frame); } else if (option->direction == Qt::RightToLeft) { rect.setRight(rect.right() - PenWidth::Frame); } else { rect.setLeft(PenWidth::Frame); } 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 const auto frameOpt = qstyleoption_cast( option ); 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 { painter->save(); painter->setRenderHints( QPainter::Antialiasing ); const auto& palette( option->palette ); auto color = palette.color( QPalette::Highlight ); QPen pen = KColorUtils::mix( color, palette.color( QPalette::Active, QPalette::WindowText ) ); pen.setJoinStyle(Qt::RoundJoin); painter->setPen( pen ); color.setAlpha( 51 ); // 20% opacity painter->setBrush( color ); painter->drawRect( _helper->strokedRect( option->rect ) ); painter->restore(); 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 ) { bool documentMode = tabOption->documentMode; // 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(_helper->coloredIcon(toolBoxOption->icon, toolBoxOption->palette, iconRect.size(), 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 const bool verticalTitleBar( dockWidgetOption->verticalTitleBar ); 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 ); drawIndicatorArrowPrimitive( ArrowDown_Small, ©, 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 = 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; QRect separatorRect; if ( option->state & State_Horizontal ) { separatorRect = QRect(0, 0, option->rect.width(), 1); } else { separatorRect = alignedRect(option->direction, Qt::AlignLeft, QSize(PenWidth::Frame, option->rect.height()), option->rect); } _helper->renderScrollBarBorder( painter, separatorRect, _helper->alphaColor( option->palette.color( QPalette::Text ), 0.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 ) ); // need to make it center due to the thin line separator if( option->state & State_Horizontal ) { grooveRect.setTop(PenWidth::Frame); } else if (option->direction == Qt::RightToLeft) { grooveRect.setRight(grooveRect.right() - PenWidth::Frame); } else { grooveRect.setLeft(PenWidth::Frame); } 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 = _helper->coloredIcon(icon, option->palette, iconSize, iconMode, iconState); painter->drawPixmap( iconRect, pixmap ); } 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 ); } //______________________________________________________________________________ void Style::renderMenuTitle( const QStyleOptionToolButton* option, QPainter* painter, const QWidget* ) const { // render a background rect for the title const auto& palette( option->palette ); QColor bgColor = palette.color( QPalette::Text ); bgColor.setAlphaF(0.04); const auto separatorColor( _helper->separatorColor( palette ) ); _helper->renderMenuFrame( painter, option->rect, bgColor, separatorColor, true ); // render text in the center of the rect // icon is discarded on purpose // make text the same size as a level 4 heading so it looks more title-ish auto font = option->font; font.setPointSize( qRound( font.pointSize() * 1.1 ) ); painter->setFont( 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 { 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; } //______________________________________________________________________________ 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(); // in case this QStyle is used by QQuickControls QStyle wrapper else if( option->styleObject ) widgetMouseOver = option->styleObject->property("hover").toBool(); // 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; } //____________________________________________________________________________________ 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 ) { // 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; } //____________________________________________________________________________________ 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; } //______________________________________________________________________________ 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; QPoint position = widget->mapTo( itemView, localPosition ); // 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::isQtQuickControl( const QStyleOption* option, const QWidget* widget ) const { #if BREEZE_HAVE_QTQUICK const bool is = (widget == nullptr) && option && option->styleObject && option->styleObject->inherits( "QQuickItem" ); if ( is ) _windowManager->registerQuickItem( static_cast( option->styleObject ) ); return is; #else Q_UNUSED( widget ); Q_UNUSED( option ); return false; #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 { // check widget if( !widget ) return false; // check property const QVariant property( widget->property( PropertyNames::alteredBackground ) ); if( property.isValid() ) return property.toBool(); // check if widget is of relevant type bool hasAlteredBackground( false ); if( const auto groupBox = qobject_cast( widget ) ) hasAlteredBackground = !groupBox->isFlat(); else if( const auto tabWidget = qobject_cast( widget ) ) hasAlteredBackground = !tabWidget->documentMode(); else if( qobject_cast( widget ) ) hasAlteredBackground = true; else if( StyleConfigData::dockWidgetDrawFrame() && qobject_cast( widget ) ) hasAlteredBackground = true; if( widget->parentWidget() && !hasAlteredBackground ) hasAlteredBackground = this->hasAlteredBackground( widget->parentWidget() ); const_cast(widget)->setProperty( PropertyNames::alteredBackground, hasAlteredBackground ); return hasAlteredBackground; } } diff --git a/kstyle/breezestyle.h b/kstyle/breezestyle.h index 8ee94841..11e85c8d 100644 --- a/kstyle/breezestyle.h +++ b/kstyle/breezestyle.h @@ -1,588 +1,594 @@ #ifndef breezestyle_h #define breezestyle_h /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * *************************************************************************/ #include "breeze.h" #include "config-breeze.h" #include "breezehelper.h" #if BREEZE_HAVE_KSTYLE #include #endif #include #include #include #include #include #include #include #include #include #include #include namespace BreezePrivate { class TabBarData; } namespace Breeze { class Animations; class FrameShadowFactory; class Helper; class MdiWindowShadowFactory; class Mnemonics; class ShadowHelper; class SplitterFactory; class WidgetExplorer; class WindowManager; class BlurHelper; + class ToolsAreaManager; //* convenience typedef for base class #if !BREEZE_HAVE_KSTYLE using ParentStyleClass = QCommonStyle; #else using ParentStyleClass = KStyle; #endif //* base class for breeze style /** it is responsible to draw all the primitives to be displayed on screen, on request from Qt paint engine */ class Style: public ParentStyleClass { Q_OBJECT /* this tells kde applications that custom style elements are supported, using the kstyle mechanism */ Q_CLASSINFO ("X-KDE-CustomElements", "true") public: //* constructor explicit Style(); //* destructor ~Style() override; //* needed to avoid warnings at compilation time using ParentStyleClass::polish; using ParentStyleClass::unpolish; //* widget polishing void polish( QWidget* ) override; //* widget unpolishing void unpolish( QWidget* ) override; //* polish scrollarea void polishScrollArea( QAbstractScrollArea* ); //* pixel metrics int pixelMetric(PixelMetric, const QStyleOption* = nullptr, const QWidget* = nullptr) const override; //* style hints int styleHint(StyleHint, const QStyleOption* = nullptr, const QWidget* = nullptr, QStyleHintReturn* = nullptr) const override; //* returns rect corresponding to one widget's subelement QRect subElementRect( SubElement, const QStyleOption*, const QWidget* ) const override; //* returns rect corresponding to one widget's subcontrol QRect subControlRect( ComplexControl, const QStyleOptionComplex*, SubControl, const QWidget* ) const override; //* returns size matching contents QSize sizeFromContents( ContentsType, const QStyleOption*, const QSize&, const QWidget* ) const override; //* returns which subcontrol given QPoint corresponds to SubControl hitTestComplexControl( ComplexControl, const QStyleOptionComplex*, const QPoint&, const QWidget* ) const override; //* primitives void drawPrimitive( PrimitiveElement, const QStyleOption*, QPainter*, const QWidget* ) const override; //* controls void drawControl( ControlElement, const QStyleOption*, QPainter*, const QWidget* ) const override; //* complex controls void drawComplexControl( ComplexControl, const QStyleOptionComplex*, QPainter*, const QWidget* ) const override; //* generic text rendering void drawItemText( QPainter*, const QRect&, int alignment, const QPalette&, bool enabled, const QString&, QPalette::ColorRole = QPalette::NoRole) const override; //*@name event filters //@{ bool eventFilter(QObject *, QEvent *) override; bool eventFilterScrollArea( QWidget*, QEvent* ); bool eventFilterComboBoxContainer( QWidget*, QEvent* ); bool eventFilterDockWidget( QDockWidget*, QEvent* ); bool eventFilterMdiSubWindow( QMdiSubWindow*, QEvent* ); bool eventFilterCommandLinkButton( QCommandLinkButton*, QEvent* ); //* install event filter to object, in a unique way void addEventFilter( QObject* object ) { object->removeEventFilter( this ); object->installEventFilter( this ); } //@} protected Q_SLOTS: //* update configuration void configurationChanged(); //* standard icons QIcon standardIconImplementation( StandardPixmap, const QStyleOption*, const QWidget* ) const; protected: //* standard icons QIcon standardIcon( StandardPixmap pixmap, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override { return standardIconImplementation( pixmap, option, widget ); } private: //* load configuration void loadConfiguration(); //*@name subelementRect specialized functions //@{ //* default implementation. Does not change anything QRect defaultSubElementRect( const QStyleOption* option, const QWidget* ) const { return option->rect; } QRect pushButtonContentsRect( const QStyleOption*, const QWidget* ) const; QRect checkBoxContentsRect( const QStyleOption*, const QWidget* ) const; QRect lineEditContentsRect( const QStyleOption*, const QWidget* ) const; QRect progressBarGrooveRect( const QStyleOption*, const QWidget* ) const; QRect progressBarContentsRect( const QStyleOption*, const QWidget* ) const; QRect progressBarLabelRect( const QStyleOption*, const QWidget* ) const; QRect frameContentsRect( const QStyleOption*, const QWidget* ) const; QRect headerArrowRect( const QStyleOption*, const QWidget* ) const; QRect headerLabelRect( const QStyleOption*, const QWidget* ) const; QRect tabBarTabLeftButtonRect( const QStyleOption*, const QWidget* ) const; QRect tabBarTabRightButtonRect( const QStyleOption*, const QWidget* ) const; QRect tabWidgetTabBarRect( const QStyleOption*, const QWidget* ) const; QRect tabWidgetTabContentsRect( const QStyleOption*, const QWidget* ) const; QRect tabWidgetTabPaneRect( const QStyleOption*, const QWidget* ) const; QRect tabWidgetCornerRect( SubElement, const QStyleOption*, const QWidget* widget ) const; QRect toolBoxTabContentsRect( const QStyleOption*, const QWidget* ) const; QRect genericLayoutItemRect( const QStyleOption*, const QWidget* ) const; //@} //*@name subcontrol Rect specialized functions //@{ QRect groupBoxSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; QRect toolButtonSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; QRect comboBoxSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; QRect spinBoxSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; QRect scrollBarInternalSubControlRect( const QStyleOptionComplex*, SubControl ) const; QRect scrollBarSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; QRect dialSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; QRect sliderSubControlRect( const QStyleOptionComplex*, SubControl, const QWidget* ) const; //@} //*@name sizeFromContents //@{ QSize defaultSizeFromContents( const QStyleOption*, const QSize& size, const QWidget* ) const { return size; } QSize checkBoxSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize lineEditSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize comboBoxSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize spinBoxSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize sliderSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize pushButtonSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize toolButtonSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize menuBarItemSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize menuItemSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize progressBarSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize tabWidgetSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize tabBarTabSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize headerSectionSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; QSize itemViewItemSizeFromContents( const QStyleOption*, const QSize&, const QWidget* ) const; //@} //*@name primitives specialized functions //@{ bool emptyPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const { return true; } bool drawFramePrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawFrameLineEditPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawFrameFocusRectPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawFrameMenuPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawFrameGroupBoxPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawFrameTabWidgetPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawFrameTabBarBasePrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawFrameWindowPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorArrowUpPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { return drawIndicatorArrowPrimitive( ArrowUp, option, painter, widget ); } bool drawIndicatorArrowDownPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { return drawIndicatorArrowPrimitive( ArrowDown, option, painter, widget ); } bool drawIndicatorArrowLeftPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { return drawIndicatorArrowPrimitive( ArrowLeft, option, painter, widget ); } bool drawIndicatorArrowRightPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { return drawIndicatorArrowPrimitive( ArrowRight, option, painter, widget ); } bool drawIndicatorArrowPrimitive( ArrowOrientation, const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorHeaderArrowPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawPanelButtonCommandPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawPanelButtonToolPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawTabBarPanelButtonToolPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawPanelScrollAreaCornerPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawPanelMenuPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawPanelTipLabelPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawPanelItemViewItemPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorCheckBoxPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorRadioButtonPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorButtonDropDownPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorTabClosePrimitive( const QStyleOption*, QPainter* painter, const QWidget* widget ) const; bool drawIndicatorTabTearPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorToolBarHandlePrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorToolBarSeparatorPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorBranchPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawWidgetPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; //@} //*@name controls specialized functions //@{ bool emptyControl( const QStyleOption*, QPainter*, const QWidget* ) const { return true; } bool drawPushButtonLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawToolButtonLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawCheckBoxLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawComboBoxLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawMenuBarItemControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawMenuItemControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawProgressBarControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawProgressBarContentsControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawProgressBarGrooveControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawProgressBarLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawScrollBarSliderControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawScrollBarAddLineControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawScrollBarSubLineControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawShapedFrameControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawRubberBandControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawHeaderSectionControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawHeaderEmptyAreaControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawTabBarTabLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawTabBarTabShapeControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawToolBoxTabLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawToolBoxTabShapeControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawDockWidgetTitleControl( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawToolBarControl( const QStyleOption*, QPainter*, const QWidget* ) const; //*@} //*@name complex ontrols specialized functions //@{ bool drawGroupBoxComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; bool drawToolButtonComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; bool drawComboBoxComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; bool drawSpinBoxComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; bool drawSliderComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; bool drawDialComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; bool drawScrollBarComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; bool drawTitleBarComplexControl( const QStyleOptionComplex*, QPainter*, const QWidget* ) const; //@} //!*@name various utility functions //@{ //* spinbox arrows void renderSpinBoxArrow( const SubControl&, const QStyleOptionSpinBox*, QPainter*, const QWidget*) const; //* menu title void renderMenuTitle( const QStyleOptionToolButton*, QPainter*, const QWidget* ) const; //* return dial angle based on option and value qreal dialAngle( const QStyleOptionSlider*, int ) const; //* returns relevant scrollbar parent /** needed to detect parent focus */ const QWidget* scrollBarParent( const QWidget* ) const; //* returns true if given scrollbar arrow is animated QColor scrollBarArrowColor( const QStyleOptionSlider*, const SubControl&, const QWidget* ) const; //* scrollbar buttons enum ScrollBarButtonType { NoButton, SingleButton, DoubleButton }; //* returns height for scrollbar buttons depending of button types int scrollBarButtonHeight( const ScrollBarButtonType& type ) const { switch( type ) { case NoButton: return Metrics::ScrollBar_NoButtonHeight; case SingleButton: return Metrics::ScrollBar_SingleButtonHeight; case DoubleButton: return Metrics::ScrollBar_DoubleButtonHeight; default: return 0; } } //@} //* translucent background void setTranslucentBackground( QWidget* ) const; /** separator can have a title and an icon in that case they are rendered as sunken flat toolbuttons return toolbutton option that matches named separator menu items */ QStyleOptionToolButton separatorMenuItemOption( const QStyleOptionMenuItem*, const QWidget* ) const; //* create toolbar extension icon QIcon toolBarExtensionIcon( StandardPixmap, const QStyleOption*, const QWidget* ) const; //* create title bar button icon QIcon titleBarButtonIcon( StandardPixmap, const QStyleOption*, const QWidget* ) const; //* returns item view parent if any /** needed to have correct color on focused checkboxes and radiobuttons */ const QAbstractItemView* itemViewParent( const QWidget* ) const; //* returns true if a given widget is a selected item in a focused list /** This is necessary to have the correct colors used for e.g. checkboxes and radiobuttons in lists @param widget The widget to be checked @param position Used to find the relevant QModelIndex */ bool isSelectedItem( const QWidget*, const QPoint& ) const; //* return true if option corresponds to QtQuick control bool isQtQuickControl( const QStyleOption*, const QWidget* ) const; //@} //* adjust rect based on provided margins QRect insideMargin( const QRect& r, int margin ) const { return insideMargin( r, margin, margin ); } //* adjust rect based on provided margins QRect insideMargin( const QRect& r, int marginWidth, int marginHeight ) const { return r.adjusted( marginWidth, marginHeight, -marginWidth, -marginHeight ); } //* expand size based on margins QSize expandSize( const QSize& size, int margin ) const { return expandSize( size, margin, margin ); } //* expand size based on margins QSize expandSize( const QSize& size, int marginWidth, int marginHeight ) const { return size + 2*QSize( marginWidth, marginHeight ); } //* returns true for vertical tabs bool isVerticalTab( const QStyleOptionTab* option ) const { return isVerticalTab( option->shape ); } bool isVerticalTab( const QTabBar::Shape& shape ) const { return shape == QTabBar::RoundedEast || shape == QTabBar::RoundedWest || shape == QTabBar::TriangularEast || shape == QTabBar::TriangularWest; } //* right to left alignment handling using ParentStyleClass::visualRect; QRect visualRect(const QStyleOption* opt, const QRect& subRect) const { return ParentStyleClass::visualRect(opt->direction, opt->rect, subRect); } //* centering QRect centerRect(const QRect &rect, const QSize& size ) const { return centerRect( rect, size.width(), size.height() ); } QRect centerRect(const QRect &rect, int width, int height) const { return QRect(rect.left() + (rect.width() - width)/2, rect.top() + (rect.height() - height)/2, width, height); } /* Checks whether the point is before the bound rect for bound of given orientation. This is needed to implement custom number of buttons in scrollbars, as well as proper mouse-hover */ inline bool preceeds( const QPoint&, const QRect&, const QStyleOption* ) const; //* return which arrow button is hit by point for scrollbar double buttons inline QStyle::SubControl scrollBarHitTest( const QRect&, const QPoint&, const QStyleOption* ) const; //! return true if one of the widget's parent inherits requested type inline bool hasParent( const QWidget*, const char* ) const; //* return true if one of the widget's parent inherits requested type template bool hasParent( const QWidget* ) const; //* return true if icons should be shown in menus bool showIconsInMenuItems() const; //* return true if icons should be shown on buttons bool showIconsOnPushButtons() const; //* return true if passed widget is a menu title (KMenu::addTitle) bool isMenuTitle( const QWidget* ) const; //* return true if passed widget is a menu title (KMenu::addTitle) bool hasAlteredBackground( const QWidget* ) const; //*@name scrollbar button types (for addLine and subLine ) //@{ ScrollBarButtonType _addLineButtons = SingleButton; ScrollBarButtonType _subLineButtons = SingleButton; //@} //* helper Helper* _helper = nullptr; //* shadow helper ShadowHelper* _shadowHelper = nullptr; //* animations Animations* _animations = nullptr; //* keyboard accelerators Mnemonics* _mnemonics = nullptr; //* blur helper BlurHelper* _blurHelper = nullptr; //* window manager WindowManager* _windowManager = nullptr; //* frame shadows FrameShadowFactory* _frameShadowFactory = nullptr; //* mdi window shadows MdiWindowShadowFactory* _mdiWindowShadowFactory = nullptr; //* splitter Factory, to extend splitters hit area SplitterFactory* _splitterFactory = nullptr; + //* signal manager for the tools area + ToolsAreaManager* _toolsAreaManager = nullptr; + //* widget explorer WidgetExplorer* _widgetExplorer = nullptr; //* tabbar data BreezePrivate::TabBarData* _tabBarData = nullptr; //* icon hash using IconCache = QHash; IconCache _iconCache; //* pointer to primitive specialized function using StylePrimitive = std::function; StylePrimitive _frameFocusPrimitive; //* pointer to control specialized function using StyleControl = std::function; //* pointer to control specialized function using StyleComplexControl = std::function; //*@name custom elements //@{ //* use Argb Drag and Drop Window QStyle::StyleHint SH_ArgbDndWindow; //! styled painting for KCapacityBar QStyle::ControlElement CE_CapacityBar; //@} }; //_________________________________________________________________________ bool Style::preceeds( const QPoint& point, const QRect& bound, const QStyleOption* option ) const { if( option->state&QStyle::State_Horizontal) { if( option->direction == Qt::LeftToRight) return point.x() < bound.right(); else return point.x() > bound.x(); } else return point.y() < bound.y(); } //_________________________________________________________________________ QStyle::SubControl Style::scrollBarHitTest( const QRect& rect, const QPoint& point, const QStyleOption* option ) const { if( option->state & QStyle::State_Horizontal) { if( option->direction == Qt::LeftToRight ) return point.x() < rect.center().x() ? QStyle::SC_ScrollBarSubLine : QStyle::SC_ScrollBarAddLine; else return point.x() > rect.center().x() ? QStyle::SC_ScrollBarSubLine : QStyle::SC_ScrollBarAddLine; } else return point.y() < rect.center().y() ? QStyle::SC_ScrollBarSubLine : QStyle::SC_ScrollBarAddLine; } //_________________________________________________________________________ bool Style::hasParent( const QWidget* widget, const char* className ) const { if( !widget ) return false; while( (widget = widget->parentWidget()) ) { if( widget->inherits( className ) ) return true; } return false; } //_________________________________________________________________________ template< typename T > bool Style::hasParent( const QWidget* widget ) const { if( !widget ) return false; while( (widget = widget->parentWidget()) ) { if( qobject_cast( widget ) ) return true; } return false; } } #endif diff --git a/kstyle/breezetoolsareamanager.cpp b/kstyle/breezetoolsareamanager.cpp new file mode 100644 index 00000000..8533c69c --- /dev/null +++ b/kstyle/breezetoolsareamanager.cpp @@ -0,0 +1,254 @@ +#include "breezetoolsareamanager.h" +#include +#include +#include +#include +#include +#include +#include + +namespace Breeze { + ToolsAreaManager::ToolsAreaManager(Helper *helper, QObject *parent) : QObject(parent), _helper(helper) {} + + ToolsAreaManager::~ToolsAreaManager() { + for (auto &x: _connections) { + disconnect(x); + } + } + + void ToolsAreaManager::updateAnimations() { + for (auto entry : animationMap) { + entry.foregroundColorAnimation->setStartValue(_helper->titleBarTextColor(false)); + entry.foregroundColorAnimation->setEndValue(_helper->titleBarTextColor(true)); + + entry.backgroundColorAnimation->setStartValue(_helper->titleBarColor(false)); + entry.backgroundColorAnimation->setEndValue(_helper->titleBarColor(true)); + + entry.foregroundColorAnimation->setDuration( + _helper->decorationConfig()->animationsEnabled() ? + _helper->decorationConfig()->animationsDuration() : + 0 + ); + entry.backgroundColorAnimation->setDuration( + _helper->decorationConfig()->animationsEnabled() ? + _helper->decorationConfig()->animationsDuration() : + 0 + ); + } + } + + void ToolsAreaManager::registerAnimation(QWidget *widget) { + auto window = widget->window()->windowHandle(); + if (window && !animationMap.contains(window)) { + + auto foregroundColorAnimation = new QVariantAnimation(this); + _connections << connect(foregroundColorAnimation, &QVariantAnimation::valueChanged, + this, &ToolsAreaManager::toolbarUpdated); + + auto backgroundColorAnimation = new QVariantAnimation(this); + _connections << connect(backgroundColorAnimation, &QVariantAnimation::valueChanged, + this, &ToolsAreaManager::toolbarUpdated); + + foregroundColorAnimation->setStartValue(_helper->titleBarTextColor(false)); + foregroundColorAnimation->setEndValue(_helper->titleBarTextColor(true)); + + backgroundColorAnimation->setStartValue(_helper->titleBarColor(false)); + backgroundColorAnimation->setEndValue(_helper->titleBarColor(true)); + + foregroundColorAnimation->setDuration( + _helper->decorationConfig()->animationsEnabled() ? + _helper->decorationConfig()->animationsDuration() : + 0 + ); + backgroundColorAnimation->setDuration( + _helper->decorationConfig()->animationsEnabled() ? + _helper->decorationConfig()->animationsDuration() : + 0 + ); + + animationMap[window] = ToolsAreaAnimation{ + foregroundColorAnimation, + backgroundColorAnimation, + window->isActive(), + }; + + _connections << connect(window, &QWindow::activeChanged, + this, [=]() { + if (animationMap[window].foregroundColorAnimation.isNull() || animationMap[window].backgroundColorAnimation.isNull()) return; + + auto prevActive = animationMap[window].prevActive; + if (prevActive && !window->isActive()) { + animationMap[window].foregroundColorAnimation->setDirection(QAbstractAnimation::Backward); + animationMap[window].backgroundColorAnimation->setDirection(QAbstractAnimation::Backward); + + animationMap[window].foregroundColorAnimation->start(); + animationMap[window].backgroundColorAnimation->start(); + } else if (!prevActive && window->isActive()) { + animationMap[window].foregroundColorAnimation->setDirection(QAbstractAnimation::Forward); + animationMap[window].backgroundColorAnimation->setDirection(QAbstractAnimation::Forward); + + animationMap[window].foregroundColorAnimation->start(); + animationMap[window].backgroundColorAnimation->start(); + } + animationMap[window].prevActive = window->isActive(); + }); + + } + } + + bool ToolsAreaManager::animationRunning(const QWidget *widget) { + auto window = widget->window()->windowHandle(); + if (window && animationMap.contains(window)) { + return ( + animationMap[window].foregroundColorAnimation->state() == QAbstractAnimation::Running + && + animationMap[window].backgroundColorAnimation->state() == QAbstractAnimation::Running + ); + } + return false; + } + + QColor ToolsAreaManager::foreground(const QWidget *widget) { + auto window = widget->window()->windowHandle(); + if (window && animationMap.contains(window) && animationMap[window].foregroundColorAnimation) { + return animationMap[window].foregroundColorAnimation->currentValue().value(); + } + return QColor(); + } + + QColor ToolsAreaManager::background(const QWidget *widget) { + auto window = widget->window()->windowHandle(); + if (window && animationMap.contains(window) && animationMap[window].backgroundColorAnimation) { + return animationMap[window].backgroundColorAnimation->currentValue().value(); + } + return QColor(); + } + + void ToolsAreaManager::registerWindow(QWindow *window) + { + if (!_registeredWindows.contains(window)) { + auto geoUpdate = [=]() { + _helper->_invalidateCachedRects = true; + emit toolbarUpdated(); + }; + _connections << connect(window, &QWindow::widthChanged, geoUpdate); + _connections << connect(window, &QWindow::heightChanged, geoUpdate); + _connections << connect(window, &QWindow::destroyed, geoUpdate); + _registeredWindows << window; + } + } + + bool ToolsAreaManager::eventFilter(QObject *watched, QEvent *event) + { + Q_UNUSED(watched) + if (event->type() == QEvent::Move) { + auto moveEvent = static_cast(event); + if (moveEvent->oldPos() != moveEvent->pos()) { + Q_EMIT toolbarUpdated(); + } + } + return false; + } + + void ToolsAreaManager::registerWidget(QWidget *widget) + { + auto win = widget->window(); + if (win) { + auto handle = win->windowHandle(); + if (handle) { + registerWindow(handle); + } + } + auto window = qobject_cast (widget); + if (window) { + _connections << connect(this, &ToolsAreaManager::toolbarUpdated, + window, [this, window]() { + if (_helper->toolsAreaHasContents(window)) { + window->setContentsMargins(0,0,0,0); + } else { + window->setContentsMargins(0,1,0,0); + } + }); + } + _connections << connect(this, &ToolsAreaManager::toolbarUpdated, + widget, [widget, this]() { + widget->update(); + auto win = widget->window(); + if (win) { + auto handle = win->windowHandle(); + if (handle) { + _helper->_cachedRects.remove(handle); + widget->update(); + } + } + }); + auto toolbar = qobject_cast(widget); + if (toolbar) { + _connections << connect(this, &ToolsAreaManager::toolbarUpdated, + widget, [=]() { + const auto rect = _helper->toolsAreaToolbarsRect(widget); + if (rect.bottom() != widget->geometry().bottom()) { + toolbar->setContentsMargins(0,0,0,0); + } else { + toolbar->setContentsMargins(0,0,0,4); + } + }); + _connections << connect(toolbar, &QToolBar::visibilityChanged, + this, [this]() { + emit toolbarUpdated(); + }); + _connections << connect(toolbar, &QToolBar::orientationChanged, + this, [this]() { + emit toolbarUpdated(); + }); + _connections << connect(toolbar, &QToolBar::topLevelChanged, + this, [this]() { + emit toolbarUpdated(); + }); + if (!toolbar->property("__breezeEventFilter").isValid()) { + toolbar->installEventFilter(this); + } + } + _connections << connect(widget, &QObject::destroyed, + this, [this, widget]() { + unregisterWidget(widget); + }); + registerAnimation(widget); + _registeredWidgets << widget; + emit toolbarUpdated(); + } + + bool ToolsAreaManager::widgetHasCorrectPaletteSet(const QWidget *widget) + { + if (animationRunning(widget)) return true; + return ( + widget->palette().color(QPalette::Window) == background(widget) + && + widget->palette().color(QPalette::WindowText) == foreground(widget) + ); + } + + void ToolsAreaManager::unregisterWidget(QWidget *widget) + { + if (qobject_cast(widget)) { + widget->setContentsMargins(0,0,0,0); + if (widget->property("__breezeEventFilter").isValid()) { + widget->removeEventFilter(this); + } + } + _registeredWidgets.remove(widget); + QList toRemove; + for (auto window : animationMap.keys()) { + if (std::none_of(_registeredWidgets.begin(), _registeredWidgets.end(), [window](QWidget *widget) { + return window == widget->window()->windowHandle(); + })) { + delete animationMap[window].foregroundColorAnimation; + delete animationMap[window].backgroundColorAnimation; + toRemove << window; + } + } + for (auto entry : toRemove) { + animationMap.remove(entry); + } + } +} \ No newline at end of file diff --git a/kstyle/breezetoolsareamanager.h b/kstyle/breezetoolsareamanager.h new file mode 100644 index 00000000..c1387d54 --- /dev/null +++ b/kstyle/breezetoolsareamanager.h @@ -0,0 +1,50 @@ +#ifndef breezetoolsareamanager_h +#define breezetoolsareamanager_h + +#include +#include +#include "breezestyle.h" +#include "breezehelper.h" + +namespace Breeze { + struct ToolsAreaAnimation { + QPointer foregroundColorAnimation; + QPointer backgroundColorAnimation; + bool prevActive; + }; + class ToolsAreaManager: public QObject + { + Q_OBJECT + + public: + explicit ToolsAreaManager(Helper* helper, QObject *parent = nullptr); + ~ToolsAreaManager(); + void registerWidget(QWidget *widget); + void unregisterWidget(QWidget *widget); + void updateAnimations(); + + QColor foreground(const QWidget *widget); + QColor background(const QWidget *widget); + + bool widgetHasCorrectPaletteSet(const QWidget *widget); + + protected: + bool eventFilter(QObject *watched, QEvent *event) override; + + Q_SIGNALS: + void toolbarUpdated(); + + private: + void registerWindow ( QWindow *window ); + void registerAnimation( QWidget *widget ); + bool animationRunning( const QWidget *widget ); + QSet _registeredWidgets; + QSet _registeredWindows; + QList _connections; + Helper* _helper; + + QMap animationMap; + }; +} + +#endif \ No newline at end of file diff --git a/kstyle/config/breezestyleconfig.cpp b/kstyle/config/breezestyleconfig.cpp index a573d0b5..5ea81dad 100644 --- a/kstyle/config/breezestyleconfig.cpp +++ b/kstyle/config/breezestyleconfig.cpp @@ -1,162 +1,166 @@ /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * *************************************************************************/ #include "breezestyleconfig.h" #include "../breeze.h" #include "../config-breeze.h" #include "breezestyleconfigdata.h" #include #include extern "C" { Q_DECL_EXPORT QWidget* allocate_kstyle_config(QWidget* parent) { return new Breeze::StyleConfig(parent); } } namespace Breeze { //__________________________________________________________________ StyleConfig::StyleConfig(QWidget* parent): QWidget(parent) { setupUi(this); // load setup from configData load(); connect( _tabBarDrawCenteredTabs, &QAbstractButton::toggled, this, &StyleConfig::updateChanged ); connect( _toolBarDrawItemSeparator, &QAbstractButton::toggled, this, &StyleConfig::updateChanged ); connect( _viewDrawFocusIndicator, &QAbstractButton::toggled, this, &StyleConfig::updateChanged ); connect( _dockWidgetDrawFrame, &QAbstractButton::toggled, this, &StyleConfig::updateChanged ); connect( _titleWidgetDrawFrame, &QAbstractButton::toggled, this, &StyleConfig::updateChanged ); connect( _sidePanelDrawFrame, &QAbstractButton::toggled, this, &StyleConfig::updateChanged ); connect( _menuItemDrawThinFocus, &QAbstractButton::toggled, this, &StyleConfig::updateChanged ); connect( _sliderDrawTickMarks, &QAbstractButton::toggled, this, &StyleConfig::updateChanged ); connect( _splitterProxyEnabled, &QAbstractButton::toggled, this, &StyleConfig::updateChanged ); + connect( _toolsAreaEnabled, &QAbstractButton::toggled, this, &StyleConfig::updateChanged ); connect( _mnemonicsMode, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) ); connect( _animationsEnabled, &QAbstractButton::toggled, this, &StyleConfig::updateChanged ); connect( _animationsDuration, SIGNAL(valueChanged(int)), SLOT(updateChanged()) ); connect( _scrollBarAddLineButtons, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) ); connect( _scrollBarSubLineButtons, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) ); connect( _windowDragMode, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) ); connect( _menuOpacity, &QAbstractSlider::valueChanged, this, &StyleConfig::updateChanged ); } //__________________________________________________________________ void StyleConfig::save() { StyleConfigData::setTabBarDrawCenteredTabs( _tabBarDrawCenteredTabs->isChecked() ); StyleConfigData::setToolBarDrawItemSeparator( _toolBarDrawItemSeparator->isChecked() ); StyleConfigData::setViewDrawFocusIndicator( _viewDrawFocusIndicator->isChecked() ); StyleConfigData::setDockWidgetDrawFrame( _dockWidgetDrawFrame->isChecked() ); StyleConfigData::setTitleWidgetDrawFrame( _titleWidgetDrawFrame->isChecked() ); StyleConfigData::setSidePanelDrawFrame( _sidePanelDrawFrame->isChecked() ); StyleConfigData::setMenuItemDrawStrongFocus( !_menuItemDrawThinFocus->isChecked() ); StyleConfigData::setSliderDrawTickMarks( _sliderDrawTickMarks->isChecked() ); StyleConfigData::setSplitterProxyEnabled( _splitterProxyEnabled->isChecked() ); + StyleConfigData::setToolsAreaEnabled( _toolsAreaEnabled->isChecked() ); StyleConfigData::setMnemonicsMode( _mnemonicsMode->currentIndex() ); StyleConfigData::setScrollBarAddLineButtons( _scrollBarAddLineButtons->currentIndex() ); StyleConfigData::setScrollBarSubLineButtons( _scrollBarSubLineButtons->currentIndex() ); StyleConfigData::setAnimationsEnabled( _animationsEnabled->isChecked() ); StyleConfigData::setAnimationsDuration( _animationsDuration->value() ); StyleConfigData::setWindowDragMode( _windowDragMode->currentIndex() ); StyleConfigData::setMenuOpacity( _menuOpacity->value() ); StyleConfigData::self()->save(); // emit dbus signal QDBusMessage message( QDBusMessage::createSignal( QStringLiteral( "/BreezeStyle" ), QStringLiteral( "org.kde.Breeze.Style" ), QStringLiteral( "reparseConfiguration" ) ) ); QDBusConnection::sessionBus().send(message); } //__________________________________________________________________ void StyleConfig::defaults() { StyleConfigData::self()->setDefaults(); load(); } //__________________________________________________________________ void StyleConfig::reset() { // reparse configuration StyleConfigData::self()->load(); load(); } //__________________________________________________________________ void StyleConfig::updateChanged() { bool modified( false ); // check if any value was modified if( _tabBarDrawCenteredTabs->isChecked() != StyleConfigData::tabBarDrawCenteredTabs() ) modified = true; else if( _toolBarDrawItemSeparator->isChecked() != StyleConfigData::toolBarDrawItemSeparator() ) modified = true; else if( _viewDrawFocusIndicator->isChecked() != StyleConfigData::viewDrawFocusIndicator() ) modified = true; else if( _dockWidgetDrawFrame->isChecked() != StyleConfigData::dockWidgetDrawFrame() ) modified = true; else if( _titleWidgetDrawFrame->isChecked() != StyleConfigData::titleWidgetDrawFrame() ) modified = true; else if( _sidePanelDrawFrame->isChecked() != StyleConfigData::sidePanelDrawFrame() ) modified = true; else if( _menuItemDrawThinFocus->isChecked() == StyleConfigData::menuItemDrawStrongFocus() ) modified = true; else if( _sliderDrawTickMarks->isChecked() != StyleConfigData::sliderDrawTickMarks() ) modified = true; else if( _mnemonicsMode->currentIndex() != StyleConfigData::mnemonicsMode() ) modified = true; else if( _scrollBarAddLineButtons->currentIndex() != StyleConfigData::scrollBarAddLineButtons() ) modified = true; else if( _scrollBarSubLineButtons->currentIndex() != StyleConfigData::scrollBarSubLineButtons() ) modified = true; else if( _splitterProxyEnabled->isChecked() != StyleConfigData::splitterProxyEnabled() ) modified = true; + else if( _toolsAreaEnabled->isChecked() != StyleConfigData::toolsAreaEnabled() ) modified = true; else if( _animationsEnabled->isChecked() != StyleConfigData::animationsEnabled() ) modified = true; else if( _animationsDuration->value() != StyleConfigData::animationsDuration() ) modified = true; else if( _windowDragMode->currentIndex() != StyleConfigData::windowDragMode() ) modified = true; else if( _menuOpacity->value() != StyleConfigData::menuOpacity() ) modified = true; emit changed(modified); } //__________________________________________________________________ void StyleConfig::load() { _tabBarDrawCenteredTabs->setChecked( StyleConfigData::tabBarDrawCenteredTabs() ); _toolBarDrawItemSeparator->setChecked( StyleConfigData::toolBarDrawItemSeparator() ); _viewDrawFocusIndicator->setChecked( StyleConfigData::viewDrawFocusIndicator() ); _dockWidgetDrawFrame->setChecked( StyleConfigData::dockWidgetDrawFrame() ); _titleWidgetDrawFrame->setChecked( StyleConfigData::titleWidgetDrawFrame() ); _sidePanelDrawFrame->setChecked( StyleConfigData::sidePanelDrawFrame() ); _menuItemDrawThinFocus->setChecked( !StyleConfigData::menuItemDrawStrongFocus() ); _sliderDrawTickMarks->setChecked( StyleConfigData::sliderDrawTickMarks() ); _mnemonicsMode->setCurrentIndex( StyleConfigData::mnemonicsMode() ); _splitterProxyEnabled->setChecked( StyleConfigData::splitterProxyEnabled() ); + _toolsAreaEnabled->setChecked( StyleConfigData::toolsAreaEnabled() ); _scrollBarAddLineButtons->setCurrentIndex( StyleConfigData::scrollBarAddLineButtons() ); _scrollBarSubLineButtons->setCurrentIndex( StyleConfigData::scrollBarSubLineButtons() ); _animationsEnabled->setChecked( StyleConfigData::animationsEnabled() ); _animationsDuration->setValue( StyleConfigData::animationsDuration() ); _windowDragMode->setCurrentIndex( StyleConfigData::windowDragMode() ); _menuOpacity->setValue( StyleConfigData::menuOpacity() ); } } diff --git a/kstyle/config/ui/breezestyleconfig.ui b/kstyle/config/ui/breezestyleconfig.ui index 30fb9131..2f2f7adc 100644 --- a/kstyle/config/ui/breezestyleconfig.ui +++ b/kstyle/config/ui/breezestyleconfig.ui @@ -1,579 +1,586 @@ BreezeStyleConfig 0 0 562 264 0 0 0 0 0 0 0 General - + 0 0 W&indows' drag mode: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter _windowDragMode Draw focus indicator in lists - + &Keyboard accelerators visibility: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter _mnemonicsMode - + Always Hide Keyboard Accelerators Show Keyboard Accelerators When Needed Always Show Keyboard Accelerators - + Qt::Horizontal 65 20 - + Drag windows from titlebar only Drag windows from titlebar, menubar and toolbars Drag windows from all empty areas - + Qt::Vertical 20 49 Center tabbar tabs Draw toolbar item separators Draw slider tick marks Enable extended resize handles + + + + Visually merge toolbars and menubars into window titlebar + + + Animations false A&nimations duration: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter _animationsDuration false ms 500 Enable animations Qt::Horizontal 40 20 Qt::Vertical 20 40 Frames Draw frame around dockable panels Draw frame around page titles Draw frame around side panels Draw a thin line to indicate focus in menus and menubars Qt::Vertical 20 117 Scrollbars Qt::Horizontal 40 20 Bottom arrow button t&ype: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter _scrollBarAddLineButtons &Top arrow button type: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter _scrollBarSubLineButtons No Buttons One Button Two Buttons No Buttons One Button Two Buttons Qt::Vertical 20 40 Transparency Qt::Vertical 20 40 Transparent Qt::Horizontal 40 20 0 0 Opaque Menu: 0 100 1 10 100 Qt::Horizontal false false QSlider::TicksBelow 10 Qt::Horizontal QSizePolicy::Fixed 40 20 Qt::Horizontal QSizePolicy::Preferred 542 20 tabWidget _tabBarDrawCenteredTabs _toolBarDrawItemSeparator _sliderDrawTickMarks _splitterProxyEnabled _mnemonicsMode _windowDragMode _animationsEnabled _animationsDuration _dockWidgetDrawFrame _titleWidgetDrawFrame _sidePanelDrawFrame _menuItemDrawThinFocus _scrollBarSubLineButtons _scrollBarAddLineButtons _animationsEnabled toggled(bool) _animationsDurationLabel setEnabled(bool) 90 64 84 98 _animationsEnabled toggled(bool) _animationsDuration setEnabled(bool) 161 64 208 98