Commit 509ff6bc authored by Jan Blackquill's avatar Jan Blackquill 🌈

[kstyle] Tools area

Summary: There is now a tools area.

Test Plan:
{F8132249}

{F8132260} (no border drawn when titlebar and content colours are the same)

{F8132252}

{F8132253}

Reviewers: #plasma, #breeze, #vdg, hpereiradacosta, davidre, ngraham

Reviewed By: #breeze, #vdg, hpereiradacosta, ngraham

Subscribers: mart, maartens, abstractdevelop, IlyaBizyaev, davidre, davidedmundson, hpereiradacosta, ngraham, manueljlin, niccolove, ndavis, plasma-devel

Tags: #plasma

Maniphest Tasks: T10201, T11661

Differential Revision: https://phabricator.kde.org/D27669
parent a3453a6b
......@@ -75,8 +75,10 @@ set(breeze_PART_SRCS
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)
......
......@@ -13,13 +13,22 @@
#include <KWindowSystem>
#include <QApplication>
#include <QDBusConnection>
#include <QFileInfo>
#include <QPainter>
#include <QMainWindow>
#include <QMenuBar>
#include <QMdiArea>
#include <QDockWidget>
#include <QWindow>
#if BREEZE_HAVE_QTX11EXTRAS
#include <QX11Info>
#endif
#include <algorithm>
#include <QDialog>
namespace Breeze
{
......@@ -28,14 +37,37 @@ namespace Breeze
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<InternalSettings> Helper::decorationConfig() const
{ return _decorationConfig; }
//____________________________________________________________________
void Helper::loadConfig()
{
......@@ -47,11 +79,18 @@ namespace Breeze
_viewNeutralTextBrush = KStatefulBrush( KColorScheme::View, KColorScheme::NeutralText );
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 ) ) );
}
//____________________________________________________________________
......@@ -1602,4 +1641,42 @@ namespace Breeze
}
return pixmap;
}
bool Helper::shouldDrawToolsArea(const QWidget* widget) const {
if (!widget) {
return false;
}
static bool isAuto = false;
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();
if (qobject_cast<const QDialog*>(widget)) {
return true;
}
if (window) {
auto handle = window->windowHandle();
if (handle) {
auto toolbar = qobject_cast<const QToolBar*>(widget);
if (toolbar) {
if (toolbar->isFloating()) {
return false;
}
}
return true;
}
} else {
return false;
}
}
if (borderSize != "None" && borderSize != "NoSides") {
return false;
}
return true;
}
}
......@@ -10,11 +10,14 @@
#include "breeze.h"
#include "breezemetrics.h"
#include "breezeanimationdata.h"
#include "breezesettings.h"
#include "config-breeze.h"
#include <KColorScheme>
#include <KSharedConfig>
#include <KConfigWatcher>
#include <QToolBar>
#include <QPainterPath>
#include <QIcon>
#include <QWidget>
......@@ -24,12 +27,14 @@ 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()
......@@ -41,6 +46,9 @@ namespace Breeze
//* pointer to shared config
KSharedConfig::Ptr config() const;
//* pointer to kdecoration config
QSharedPointer<InternalSettings> decorationConfig() const;
//*@name color utilities
//@{
......@@ -81,7 +89,7 @@ namespace Breeze
//* titlebar text color
const QColor& titleBarTextColor( bool active ) const
{ return active ? _activeTitleBarTextColor:_inactiveTitleBarTextColor; }
{ 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;
......@@ -263,6 +271,9 @@ namespace Breeze
//* returns true if a given widget supports alpha channel
bool hasAlphaChannel( const QWidget* ) const;
//* returns true if the tools area should be drawn
bool shouldDrawToolsArea ( const QWidget* ) const;
//@}
//* return device pixel ratio for a given pixmap
......@@ -295,6 +306,12 @@ namespace Breeze
//* configuration
KSharedConfig::Ptr _config;
//* KWin configuration
KSharedConfig::Ptr _kwinConfig;
//* decoration configuration
QSharedPointer<InternalSettings> _decorationConfig;
//*@name brushes
//@{
KStatefulBrush _viewFocusBrush;
......@@ -313,6 +330,10 @@ namespace Breeze
QColor _inactiveTitleBarTextColor;
//@}
mutable bool _cachedAutoValid = false;
friend class ToolsAreaManager;
};
}
......
......@@ -92,7 +92,7 @@ namespace Breeze
static constexpr int ScrollBar_DoubleButtonHeight = 2*ScrollBar_Extend;
// toolbars
static constexpr int ToolBar_FrameWidth = 2;
static constexpr int ToolBar_FrameWidth = 6;
static constexpr int ToolBar_HandleExtent = 10;
static constexpr int ToolBar_HandleWidth = 6;
static constexpr int ToolBar_SeparatorWidth = 8;
......
......@@ -17,13 +17,17 @@
#include "breezewidgetexplorer.h"
#include "breezewindowmanager.h"
#include "breezeblurhelper.h"
#include "breezetoolsareamanager.h"
#include <KColorUtils>
#include <KIconLoader>
#include <QApplication>
#include <QBitmap>
#include <QCheckBox>
#include <QComboBox>
#include <QDial>
#include <QDialog>
#include <QDBusConnection>
#include <QDockWidget>
#include <QFormLayout>
......@@ -45,6 +49,7 @@
#include <QToolButton>
#include <QTreeView>
#include <QWidgetAction>
#include <QMdiArea>
#if BREEZE_HAVE_QTQUICK
#include <QQuickWindow>
......@@ -190,6 +195,7 @@ namespace Breeze
, _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
......@@ -209,10 +215,17 @@ namespace Breeze
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
......@@ -243,6 +256,7 @@ namespace Breeze
_mdiWindowShadowFactory->registerWidget( widget );
_shadowHelper->registerWidget( widget );
_splitterFactory->registerWidget( widget );
_toolsAreaManager->registerWidget ( widget );
// enable mouse over effects for all necessary widgets
if(
......@@ -380,13 +394,20 @@ namespace Breeze
setTranslucentBackground( widget );
} else if ( qobject_cast<QMainWindow*> (widget) || qobject_cast<QDialog*> (widget) ) {
widget->setAttribute(Qt::WA_StyledBackground);
}
// base class polishing
ParentStyleClass::polish( widget );
}
//______________________________________________________________
void Style::polish( QApplication *application )
{
_toolsAreaManager->registerApplication(application);
}
//______________________________________________________________
void Style::polishScrollArea( QAbstractScrollArea* scrollArea )
{
......@@ -469,6 +490,7 @@ namespace Breeze
_windowManager->unregisterWidget( widget );
_splitterFactory->unregisterWidget( widget );
_blurHelper->unregisterWidget( widget );
_toolsAreaManager->unregisterWidget ( widget );
// remove event filter
if( qobject_cast<QAbstractScrollArea*>( widget ) ||
......@@ -874,6 +896,7 @@ namespace Breeze
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;
......@@ -890,6 +913,43 @@ namespace Breeze
}
bool Style::drawWidgetPrimitive( const QStyleOption* option, QPainter* painter, const QWidget* widget ) const {
Q_UNUSED(option)
auto parent = widget;
if (!_helper->shouldDrawToolsArea(widget)) {
return true;
}
if (auto mw = qobject_cast<const QMainWindow*>(widget)) {
painter->save();
auto rect = _toolsAreaManager->toolsAreaRect(mw);
if (rect.height() == 0) {
painter->setPen(_helper->separatorColor(_toolsAreaManager->palette()));
painter->drawLine(widget->rect().topLeft(), widget->rect().topRight());
painter->restore();
return true;
}
auto color = _toolsAreaManager->palette().brush(mw->isActiveWindow() ? QPalette::Active : QPalette::Inactive, QPalette::Window);
painter->setPen(Qt::transparent);
painter->setBrush(color);
painter->drawRect(rect);
painter->setPen(_helper->separatorColor(_toolsAreaManager->palette()));
painter->drawLine(rect.bottomLeft(), rect.bottomRight());
painter->restore();
} else if (auto dialog = qobject_cast<const QDialog*>(widget)) {
auto margins = dialog->contentsMargins();
const_cast<QDialog*>(dialog)->setContentsMargins(margins.left(), margins.top(), margins.right(), qMax(margins.bottom(), 1));
painter->setPen(_helper->separatorColor(_toolsAreaManager->palette()));
painter->drawLine(widget->rect().topLeft(), widget->rect().topRight());
}
return true;
}
//______________________________________________________________
void Style::drawControl( ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget ) const
{
......@@ -4300,7 +4360,6 @@ namespace Breeze
// copy rect and palette
const auto& rect = option->rect;
const auto& palette = option->palette;
// state
const State& state( option->state );
......@@ -4425,6 +4484,8 @@ namespace Breeze
if( flat ) textRole = ( ((hasFocus&&sunken) || (state & State_Sunken))&&!mouseOver) ? QPalette::HighlightedText: QPalette::WindowText;
else if( hasFocus&&!mouseOver ) textRole = QPalette::HighlightedText;
auto palette = option->palette;
painter->setFont(toolButtonOption->font);
drawItemText( painter, textRect, textFlags, palette, enabled, toolButtonOption->text, textRole );
......@@ -4589,6 +4650,9 @@ namespace Breeze
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 ) )
{
......@@ -4667,8 +4731,9 @@ namespace Breeze
}
return true;
painter->restore();
return true;
}
......
......@@ -48,6 +48,7 @@ namespace Breeze
class WidgetExplorer;
class WindowManager;
class BlurHelper;
class ToolsAreaManager;
//* convenience typedef for base class
#if !BREEZE_HAVE_KSTYLE
......@@ -83,6 +84,9 @@ namespace Breeze
//* widget unpolishing
void unpolish( QWidget* ) override;
//* application polishing
void polish( QApplication* ) override;
//* polish scrollarea
void polishScrollArea( QAbstractScrollArea* );
......@@ -267,6 +271,7 @@ namespace Breeze
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;
//@}
......@@ -496,6 +501,9 @@ namespace Breeze
//* splitter Factory, to extend splitters hit area
SplitterFactory* _splitterFactory = nullptr;
//* signal manager for the tools area
ToolsAreaManager* _toolsAreaManager = nullptr;
//* widget explorer
WidgetExplorer* _widgetExplorer = nullptr;
......
#include "breezetoolsareamanager.h"
#include <QMainWindow>
#include <QMdiArea>
#include <QMenuBar>
#include <QObject>
#include <QToolBar>
#include <QWidget>
#include <QWindow>
#include <KColorUtils>
const char* colorProperty = "KDE_COLOR_SCHEME_PATH";
namespace Breeze {
ToolsAreaManager::ToolsAreaManager(Helper *helper, QObject *parent) : QObject(parent), _helper(helper)
{
if (qApp && qApp->property(colorProperty).isValid()) {
auto path = qApp->property(colorProperty).toString();
_config = KSharedConfig::openConfig(path);
} else {
_config = KSharedConfig::openConfig();
}
_watcher = KConfigWatcher::create(_config);
connect(_watcher.data(), &KConfigWatcher::configChanged, this, &ToolsAreaManager::configUpdated);
configUpdated();
}
ToolsAreaManager::~ToolsAreaManager() {}
template<class T1, class T2>
void appendIfNotAlreadyExists(T1* list, T2 item) {
for (auto listItem : *list) {
if (listItem == item) {
return;
}
}
list->append(item);
}
void ToolsAreaManager::registerApplication(QApplication *application)
{
_listener = new AppListener;
_listener->manager = this;
if (application->property(colorProperty).isValid()) {
auto path = application->property(colorProperty).toString();
_config = KSharedConfig::openConfig(path);
_watcher = KConfigWatcher::create(_config);
connect(_watcher.data(), &KConfigWatcher::configChanged, this, &ToolsAreaManager::configUpdated);
}
application->installEventFilter(_listener);
configUpdated();
}
QRect ToolsAreaManager::toolsAreaRect(const QMainWindow *window)
{
Q_ASSERT(window);
int itemHeight = window->menuWidget() ? window->menuWidget()->height() : 0;
for (auto item : _windows[const_cast<QMainWindow*>(window)]) {
if (!item.isNull() && item->isVisible() && window->toolBarArea(item) == Qt::TopToolBarArea) {
itemHeight = qMax(item->mapTo(window, item->rect().bottomLeft()).y(), itemHeight);
}
}
if (itemHeight == 0) {
auto win = const_cast<QMainWindow*>(window);
win->setContentsMargins(0, 0, 0, 1);
} else {
auto win = const_cast<QMainWindow*>(window);
win->setContentsMargins(0, 0, 0, 0);
}
return QRect(0, 0, window->width(), itemHeight);
}
bool ToolsAreaManager::tryRegisterToolBar(QPointer<QMainWindow> window, QPointer<QWidget> widget)
{
Q_ASSERT(!widget.isNull());
QPointer<QToolBar> toolbar;
if (!(toolbar = qobject_cast<QToolBar*>(widget))) return false;
if (window->toolBarArea(toolbar) == Qt::TopToolBarArea) {
widget->setPalette(palette());
appendIfNotAlreadyExists(&_windows[window], toolbar);
return true;
}
return false;
}
void ToolsAreaManager::tryUnregisterToolBar(QPointer<QMainWindow> window, QPointer<QWidget> widget)
{
Q_ASSERT(!widget.isNull());
QPointer<QToolBar> toolbar;
if (!(toolbar = qobject_cast<QToolBar*>(widget))) return;
if (window->toolBarArea(toolbar) != Qt::TopToolBarArea) {
widget->setPalette(window->palette());
_windows[window].removeAll(toolbar);
}
}
void ToolsAreaManager::configUpdated()
{
auto active = KColorScheme(QPalette::Active, KColorScheme::Header, _config);
auto inactive = KColorScheme(QPalette::Inactive, KColorScheme::Header, _config);
auto disabled = KColorScheme(QPalette::Disabled, KColorScheme::Header, _config);
_palette = KColorScheme::createApplicationPalette(_config);
_palette.setBrush(QPalette::Active, QPalette::Window, active.background());
_palette.setBrush(QPalette::Active, QPalette::WindowText, active.foreground());
_palette.setBrush(QPalette::Disabled, QPalette::Window, disabled.background());
_palette.setBrush(QPalette::Disabled, QPalette::WindowText, disabled.foreground());
_palette.setBrush(QPalette::Inactive, QPalette::Window, inactive.background());
_palette.setBrush(QPalette::Inactive, QPalette::WindowText, inactive.foreground());
for (auto window : _windows) {
for (auto toolbar : window) {
if (!toolbar.isNull()) {
toolbar->setPalette(_palette);
}
}
}
}
bool AppListener::eventFilter(QObject *watched, QEvent *event)
{
Q_ASSERT(watched);
Q_ASSERT(event);
if (watched != qApp) {
return false;
}
if (event->type() == QEvent::DynamicPropertyChange) {
if (watched != qApp) {
return false;
}
auto ev = static_cast<QDynamicPropertyChangeEvent*>(event);
if (ev->propertyName() == colorProperty) {
if (qApp && qApp->property(colorProperty).isValid()) {
auto path = qApp->property(colorProperty).toString();
manager->_config = KSharedConfig::openConfig(path);
} else {
manager->_config = KSharedConfig::openConfig();
}
manager->_watcher = KConfigWatcher::create(manager->_config);
connect(manager->_watcher.data(), &KConfigWatcher::configChanged, manager, &ToolsAreaManager::configUpdated);
manager->configUpdated();
}
}
return false;
}
bool ToolsAreaManager::eventFilter(QObject *watched, QEvent *event)
{
Q_ASSERT(watched);
Q_ASSERT(event);
QPointer<QObject> parent = watched;
QPointer<QMainWindow> mainWindow = nullptr;
while (parent != nullptr) {
if (qobject_cast<QMainWindow*>(parent)) {
mainWindow = qobject_cast<QMainWindow*>(parent);
break;
}
parent = parent->parent();