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