diff --git a/kstyle/CMakeLists.txt b/kstyle/CMakeLists.txt --- a/kstyle/CMakeLists.txt +++ b/kstyle/CMakeLists.txt @@ -5,7 +5,8 @@ Config GuiAddons ConfigWidgets - WindowSystem) + WindowSystem + IconThemes) find_package(Qt5 COMPONENTS Quick) set(BREEZE_HAVE_QTQUICK ${Qt5Quick_FOUND}) @@ -93,15 +94,17 @@ 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::WindowSystem) +target_link_libraries(breeze KF5::ConfigCore KF5::ConfigWidgets KF5::GuiAddons KF5::WindowSystem KF5::IconThemes) target_link_libraries(breeze breezecommon5) if(KF5FrameworkIntegration_FOUND) diff --git a/kstyle/breezehelper.h b/kstyle/breezehelper.h --- a/kstyle/breezehelper.h +++ b/kstyle/breezehelper.h @@ -23,25 +23,30 @@ #include "breeze.h" #include "breezeanimationdata.h" +#include "breezesettings.h" #include "config-breeze.h" #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() @@ -53,6 +58,9 @@ //* pointer to shared config KSharedConfig::Ptr config() const; + //* pointer to kdecoration config + QSharedPointer decorationConfig() const; + //*@name color utilities //@{ @@ -245,6 +253,9 @@ //* generic shadow for ellipses void renderEllipseShadow( QPainter*, const QRectF&, const QColor& ) const; + + //* draw the tools area border + void renderToolsAreaBorder ( QPainter*, const QWidget*, bool menubar = false ) const; //@} @@ -263,6 +274,26 @@ //* 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; + //@} //@name high dpi utility functions @@ -308,6 +339,12 @@ //* configuration KSharedConfig::Ptr _config; + //* KWin configuration + KSharedConfig::Ptr _kwinConfig; + + //* decoration configuration + QSharedPointer _decorationConfig; + //*@name brushes //@{ KStatefulBrush _viewFocusBrush; diff --git a/kstyle/breezehelper.cpp b/kstyle/breezehelper.cpp --- a/kstyle/breezehelper.cpp +++ b/kstyle/breezehelper.cpp @@ -26,7 +26,11 @@ #include #include +#include +#include #include +#include +#include #if BREEZE_HAVE_X11 #include @@ -41,27 +45,66 @@ static const qreal arrowShade = 0.15; //____________________________________________________________________ - Helper::Helper( KSharedConfig::Ptr config ): - _config( std::move( config ) ) - {} + Helper::Helper( KSharedConfig::Ptr config, QObject *parent ) : + _config( std::move( config ) ), + _decorationConfig( new InternalSettings() ), + _kwinConfig( KSharedConfig::openConfig("kwinrc") ), + QObject ( parent ) + { + 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(); + _decorationConfig->load(); + if (qApp && qApp->property("KDE_COLOR_SCHEME_PATH").isValid()) { + const auto path = qApp->property("KDE_COLOR_SCHEME_PATH").toString(); + if (path.isEmpty() || !QFileInfo::exists(path)) goto otherIf; + + KConfig config(path, KConfig::SimpleConfig); + 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 ) ); + } else { +otherIf: + 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 ) ); + } } //____________________________________________________________________ @@ -1604,4 +1647,179 @@ return pixmap.devicePixelRatio(); } + 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; + } + + if (checkToolbarInToolsArea(widget)) { + return true; + } else if (checkMenubarInToolsArea(widget)) { + return true; + } else { + auto parent = widget->parentWidget(); + while (parent != nullptr) { + 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(); + + QList widgets = window->findChildren(QString(), Qt::FindDirectChildrenOnly); + QRect rect = QRect(); + for (auto toolbar : widgets) { + 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()); + } + + 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; + } + + void Helper::renderToolsAreaBorder(QPainter* painter, const QWidget* widget, bool menubar) const { + if (!shouldDrawToolsArea(widget)) return; + + if (!menubar) { + auto rect = toolsAreaToolbarsRect(widget); + + if (rect.bottom() != widget->geometry().bottom()) return; + } + + painter->setPen(toolsAreaBorderColor(widget)); + painter->setRenderHints(QPainter::Antialiasing, false); + painter->setBrush(Qt::NoBrush); + + painter->drawLine( + widget->rect().left()*2, + widget->rect().bottom(), + widget->rect().right()*2, + widget->rect().bottom() + ); + } + + 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; + KConfigGroup kdecorationGroup(_kwinConfig->group("org.kde.kdecoration2")); + auto borderSize = kdecorationGroup.readEntry("BorderSize", "Invalid"); + if (borderSize != "None" && borderSize != "NoSides") { + return false; + } + auto toolbar = qobject_cast(widget); + if (toolbar) { + if (toolbar->isFloating()) { + return false; + } + } + return (widget->window()->palette().color(QPalette::Window) != titleBarColor(true)); + } + + bool Helper::toolsAreaHasContents(const QWidget* widget) const { + QList widgets = widget->window()->findChildren(); + 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.5 + ) + ); + border.setAlpha(255); + return border; + } } diff --git a/kstyle/breezestyle.h b/kstyle/breezestyle.h --- a/kstyle/breezestyle.h +++ b/kstyle/breezestyle.h @@ -60,6 +60,7 @@ class WidgetExplorer; class WindowManager; class BlurHelper; + class ToolsAreaManager; //* convenience typedef for base class #if !BREEZE_HAVE_KSTYLE @@ -275,6 +276,7 @@ bool drawIndicatorToolBarHandlePrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorToolBarSeparatorPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawIndicatorBranchPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawWidgetPrimitive( const QStyleOption*, QPainter*, const QWidget* ) const; //@} @@ -306,6 +308,8 @@ bool drawToolBoxTabLabelControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawToolBoxTabShapeControl( const QStyleOption*, QPainter*, const QWidget* ) const; bool drawDockWidgetTitleControl( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawToolBarControl( const QStyleOption*, QPainter*, const QWidget* ) const; + bool drawMenuBarEmptyAreaControl( const QStyleOption*, QPainter*, const QWidget* ) const; //*@} @@ -497,6 +501,9 @@ //* splitter Factory, to extend splitters hit area SplitterFactory* _splitterFactory = nullptr; + //* signal manager for the tools area + ToolsAreaManager* _toolsAreaManager = nullptr; + //* widget explorer WidgetExplorer* _widgetExplorer = nullptr; diff --git a/kstyle/breezestyle.cpp b/kstyle/breezestyle.cpp --- a/kstyle/breezestyle.cpp +++ b/kstyle/breezestyle.cpp @@ -31,13 +31,17 @@ #include "breezewidgetexplorer.h" #include "breezewindowmanager.h" #include "breezeblurhelper.h" +#include "breezetoolsareamanager.h" #include +#include #include +#include #include #include #include +#include #include #include #include @@ -164,6 +168,7 @@ , _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 @@ -183,6 +188,17 @@ 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 @@ -213,6 +229,7 @@ _mdiWindowShadowFactory->registerWidget( widget ); _shadowHelper->registerWidget( widget ); _splitterFactory->registerWidget( widget ); + _toolsAreaManager->registerWidget ( widget ); // enable mouse over effects for all necessary widgets if( @@ -350,8 +367,9 @@ setTranslucentBackground( widget ); + } else if ( qobject_cast (widget) || qobject_cast (widget) ) { + widget->setAttribute(Qt::WA_StyledBackground); } - // base class polishing ParentStyleClass::polish( widget ); @@ -439,6 +457,7 @@ _windowManager->unregisterWidget( widget ); _splitterFactory->unregisterWidget( widget ); _blurHelper->unregisterWidget( widget ); + _toolsAreaManager->unregisterWidget ( widget ); // remove event filter if( qobject_cast( widget ) || @@ -844,6 +863,7 @@ 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; @@ -860,6 +880,53 @@ } + bool Style::drawWidgetPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { + Q_UNUSED(option) + 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 { @@ -882,10 +949,10 @@ 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_MenuBarEmptyArea: fcn = &Style::drawMenuBarEmptyAreaControl; 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; @@ -1331,6 +1398,12 @@ // reload configuration loadConfiguration(); + // load new titlebar colours into tools area animations + _toolsAreaManager->updateAnimations(); + + // trigger update of tools area + emit _toolsAreaManager->toolbarUpdated(); + } //____________________________________________________________________ @@ -4225,7 +4298,6 @@ // copy rect and palette const auto& rect = option->rect; - const auto& palette = option->palette; // state const State& state( option->state ); @@ -4329,19 +4401,30 @@ else if( mouseOver && flat ) iconMode = QIcon::Active; else iconMode = QIcon::Normal; - const QPixmap pixmap = toolButtonOption->icon.pixmap( iconSize, iconMode, iconState ); + QPixmap pixmap = toolButtonOption->icon.pixmap( iconSize, iconMode, iconState ); + if (_helper->isInToolsArea(widget)) { + KIconLoader::global()->setCustomPalette(widget->palette()); + pixmap = toolButtonOption->icon.pixmap( iconSize, iconMode, iconState ); + KIconLoader::global()->resetPalette(); + } 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 ); @@ -4509,15 +4592,20 @@ // copy rect and palette const auto& rect( option->rect ); - const auto& palette( option->palette ); + auto palette( option->palette ); + + 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 ) ) { @@ -4596,8 +4684,13 @@ } - return true; + if (!_helper->toolsAreaHasToolBar(widget)) { + _helper->renderToolsAreaBorder(painter, widget, true); + } + + painter->restore(); + return true; } @@ -4817,6 +4910,38 @@ return true; } + bool Style::drawToolBarControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + 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::drawMenuBarEmptyAreaControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const + { + if (!_helper->isInToolsArea(widget)) { + return true; + } + + painter->save(); + painter->restore(); + return true; + } + //___________________________________________________________________________________ bool Style::drawProgressBarControl( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const { diff --git a/kstyle/breezetoolsareamanager.h b/kstyle/breezetoolsareamanager.h new file mode 100644 --- /dev/null +++ b/kstyle/breezetoolsareamanager.h @@ -0,0 +1,44 @@ +#ifndef breezetoolsareamanager_h +#define breezetoolsareamanager_h + +#include +#include +#include "breezestyle.h" +#include "breezehelper.h" + +namespace Breeze { + struct ToolsAreaAnimation { + QPointer foregroundColorAnimation; + QPointer backgroundColorAnimation; + bool prevActive; + }; + class ToolsAreaManager: public QObject + { + Q_OBJECT + + public: + explicit ToolsAreaManager(Helper* helper, QObject *parent = nullptr); + ~ToolsAreaManager(); + void registerWidget(QWidget *widget); + void unregisterWidget(QWidget *widget); + void updateAnimations(); + + QColor foreground(const QWidget *widget); + QColor background(const QWidget *widget); + + bool widgetHasCorrectPaletteSet(const QWidget *widget); + + Q_SIGNALS: + void toolbarUpdated(); + + private: + void registerAnimation( QWidget *widget ); + bool animationRunning( const QWidget *widget ); + QSet _registeredWidgets; + Helper* _helper; + + QMap animationMap; + }; +} + +#endif \ No newline at end of file diff --git a/kstyle/breezetoolsareamanager.cpp b/kstyle/breezetoolsareamanager.cpp new file mode 100644 --- /dev/null +++ b/kstyle/breezetoolsareamanager.cpp @@ -0,0 +1,201 @@ +#include "breezetoolsareamanager.h" +#include +#include +#include +#include +#include +#include + +namespace Breeze { + ToolsAreaManager::ToolsAreaManager(Helper *helper, QObject *parent) : QObject(parent), _helper(helper) {} + + ToolsAreaManager::~ToolsAreaManager() {} + + void ToolsAreaManager::updateAnimations() { + for (auto entry : animationMap) { + entry.foregroundColorAnimation->setStartValue(_helper->titleBarTextColor(false)); + entry.foregroundColorAnimation->setEndValue(_helper->titleBarTextColor(true)); + + entry.backgroundColorAnimation->setStartValue(_helper->titleBarColor(false)); + entry.backgroundColorAnimation->setEndValue(_helper->titleBarColor(true)); + + entry.foregroundColorAnimation->setDuration( + _helper->decorationConfig()->animationsEnabled() ? + _helper->decorationConfig()->animationsDuration() : + 0 + ); + entry.backgroundColorAnimation->setDuration( + _helper->decorationConfig()->animationsEnabled() ? + _helper->decorationConfig()->animationsDuration() : + 0 + ); + } + } + + void ToolsAreaManager::registerAnimation(QWidget *widget) { + auto window = widget->window()->windowHandle(); + if (window && !animationMap.contains(window)) { + + auto foregroundColorAnimation = new QVariantAnimation(this); + connect(foregroundColorAnimation, &QVariantAnimation::valueChanged, + this, &ToolsAreaManager::toolbarUpdated); + + auto backgroundColorAnimation = new QVariantAnimation(this); + connect(backgroundColorAnimation, &QVariantAnimation::valueChanged, + this, &ToolsAreaManager::toolbarUpdated); + + foregroundColorAnimation->setStartValue(_helper->titleBarTextColor(false)); + foregroundColorAnimation->setEndValue(_helper->titleBarTextColor(true)); + + backgroundColorAnimation->setStartValue(_helper->titleBarColor(false)); + backgroundColorAnimation->setEndValue(_helper->titleBarColor(true)); + + foregroundColorAnimation->setDuration( + _helper->decorationConfig()->animationsEnabled() ? + _helper->decorationConfig()->animationsDuration() : + 0 + ); + backgroundColorAnimation->setDuration( + _helper->decorationConfig()->animationsEnabled() ? + _helper->decorationConfig()->animationsDuration() : + 0 + ); + + animationMap[window] = ToolsAreaAnimation{ + foregroundColorAnimation, + backgroundColorAnimation, + window->isActive(), + }; + + connect(window, &QWindow::activeChanged, + this, [=]() { + if (animationMap[window].foregroundColorAnimation.isNull() || animationMap[window].backgroundColorAnimation.isNull()) return; + + auto prevActive = animationMap[window].prevActive; + if (prevActive && !window->isActive()) { + animationMap[window].foregroundColorAnimation->setDirection(QAbstractAnimation::Backward); + animationMap[window].backgroundColorAnimation->setDirection(QAbstractAnimation::Backward); + + animationMap[window].foregroundColorAnimation->start(); + animationMap[window].backgroundColorAnimation->start(); + } else if (!prevActive && window->isActive()) { + animationMap[window].foregroundColorAnimation->setDirection(QAbstractAnimation::Forward); + animationMap[window].backgroundColorAnimation->setDirection(QAbstractAnimation::Forward); + + animationMap[window].foregroundColorAnimation->start(); + animationMap[window].backgroundColorAnimation->start(); + } + animationMap[window].prevActive = window->isActive(); + }); + + } + } + + bool ToolsAreaManager::animationRunning(const QWidget *widget) { + auto window = widget->window()->windowHandle(); + if (window && animationMap.contains(window)) { + return ( + animationMap[window].foregroundColorAnimation->state() == QAbstractAnimation::Running + && + animationMap[window].backgroundColorAnimation->state() == QAbstractAnimation::Running + ); + } + return false; + } + + QColor ToolsAreaManager::foreground(const QWidget *widget) { + auto window = widget->window()->windowHandle(); + if (window && animationMap.contains(window) && animationMap[window].foregroundColorAnimation) { + return animationMap[window].foregroundColorAnimation->currentValue().value(); + } + return QColor(); + } + + QColor ToolsAreaManager::background(const QWidget *widget) { + auto window = widget->window()->windowHandle(); + if (window && animationMap.contains(window) && animationMap[window].backgroundColorAnimation) { + return animationMap[window].backgroundColorAnimation->currentValue().value(); + } + return QColor(); + } + + + void ToolsAreaManager::registerWidget(QWidget *widget) + { + auto window = qobject_cast (widget); + if (window) { + connect(this, &ToolsAreaManager::toolbarUpdated, + window, [this, window]() { + if (_helper->toolsAreaHasContents(window)) { + window->setContentsMargins(0,0,0,0); + } else { + window->setContentsMargins(0,1,0,0); + } + }); + } + connect(this, &ToolsAreaManager::toolbarUpdated, + widget, [widget]() { + widget->update(); + }); + auto toolbar = qobject_cast(widget); + if (toolbar) { + connect(this, &ToolsAreaManager::toolbarUpdated, + widget, [=]() { + const auto rect = _helper->toolsAreaToolbarsRect(widget); + if (rect.bottom() != widget->geometry().bottom()) { + toolbar->setContentsMargins(0,0,0,0); + } else { + toolbar->setContentsMargins(0,0,0,4); + } + }); + connect(toolbar, &QToolBar::visibilityChanged, + this, [this]() { + emit toolbarUpdated(); + }); + connect(toolbar, &QToolBar::orientationChanged, + this, [this]() { + emit toolbarUpdated(); + }); + connect(toolbar, &QToolBar::topLevelChanged, + this, [this]() { + emit toolbarUpdated(); + }); + } + connect(widget, &QObject::destroyed, + this, [this, widget]() { + unregisterWidget(widget); + }); + registerAnimation(widget); + _registeredWidgets << widget; + emit toolbarUpdated(); + } + + bool ToolsAreaManager::widgetHasCorrectPaletteSet(const QWidget *widget) + { + if (animationRunning(widget)) return true; + return ( + widget->palette().color(QPalette::Window) == background(widget) + && + widget->palette().color(QPalette::WindowText) == foreground(widget) + ); + } + + void ToolsAreaManager::unregisterWidget(QWidget *widget) + { + if (qobject_cast(widget)) widget->setContentsMargins(0,0,0,0); + _registeredWidgets.remove(widget); + QList toRemove; + for (auto window : animationMap.keys()) { + if (std::none_of(_registeredWidgets.begin(), _registeredWidgets.end(), [window](QWidget *widget) { + return window == widget->window()->windowHandle(); + })) { + delete animationMap[window].foregroundColorAnimation; + delete animationMap[window].backgroundColorAnimation; + toRemove << window; + } + } + for (auto entry : toRemove) { + animationMap.remove(entry); + } + } +} \ No newline at end of file