Skip to content

Commit 4124dde

Browse files
authored
Add Dark mode support (#842)
* add dark versions of resource files * reload stylesheet on theme change * adjust dock overlay colors for dark mode, refresh dock overlay colors when theme changes * follow application palette instead of system scheme, remove Qt version constraints, add legacy behavior settings * fix text color of focused tab label for highlighting stylesheets * fix missing tab menu icon in focus highlighting stylesheet
1 parent 27f1bef commit 4124dde

29 files changed

Lines changed: 3344 additions & 9 deletions

src/DockManager.cpp

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include <QWindow>
5151
#include <QWindowStateChangeEvent>
5252
#include <QVector>
53+
#include <QStyleHints>
5354

5455
#include "FloatingDockContainer.h"
5556
#include "DockOverlay.h"
@@ -118,6 +119,7 @@ struct DockManagerPrivate
118119
QMap<QString, QMenu*> ViewMenuGroups;
119120
QMenu* ViewMenu;
120121
CDockManager::eViewMenuInsertionOrder MenuInsertionOrder = CDockManager::MenuAlphabeticallySorted;
122+
CDockManager::eStylesheetColorSchemeBehavior StylesheetColorSchemeBehavior = CDockManager::FollowApplicationPalette;
121123
bool RestoringState = false;
122124
QVector<CFloatingDockContainer*> UninitializedFloatingWidgets;
123125
CDockFocusController* FocusController = nullptr;
@@ -129,6 +131,7 @@ struct DockManagerPrivate
129131
QSize ToolBarIconSizeFloating = QSize(24, 24);
130132
CDockWidget::DockWidgetFeatures LockedDockWidgetFeatures;
131133
QSharedPointer<ads::CDockComponentsFactory> ComponentFactory {ads::CDockComponentsFactory::factory()};
134+
bool CurrentStylesheetDark;
132135

133136
/**
134137
* Private data constructor
@@ -215,6 +218,12 @@ void DockManagerPrivate::loadStylesheet()
215218
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
216219
FileName += "_linux";
217220
#endif
221+
if (_this->isDesiredStylesheetDark()) {
222+
CurrentStylesheetDark = true;
223+
FileName += "_dark";
224+
}
225+
else
226+
CurrentStylesheetDark = false;
218227
FileName += ".css";
219228
QFile StyleSheetFile(FileName);
220229
StyleSheetFile.open(QIODevice::ReadOnly);
@@ -655,9 +664,9 @@ void CDockManager::setComponentsFactory(QSharedPointer<ads::CDockComponentsFacto
655664

656665

657666
//============================================================================
658-
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
659667
bool CDockManager::eventFilter(QObject *obj, QEvent *e)
660668
{
669+
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
661670
// Emulate Qt:Tool behaviour.
662671
// Required because on some WMs Tool windows can't be maximized.
663672

@@ -730,12 +739,7 @@ bool CDockManager::eventFilter(QObject *obj, QEvent *e)
730739
QApplication::setActiveWindow(window());
731740
}
732741
}
733-
return Super::eventFilter(obj, e);
734-
}
735742
#else
736-
//============================================================================
737-
bool CDockManager::eventFilter(QObject *obj, QEvent *e)
738-
{
739743
if (e->type() == QEvent::WindowStateChange)
740744
{
741745
QWindowStateChangeEvent* ev = static_cast<QWindowStateChangeEvent*>(e);
@@ -745,9 +749,15 @@ bool CDockManager::eventFilter(QObject *obj, QEvent *e)
745749
QMetaObject::invokeMethod(this, "endLeavingMinimizedState", Qt::QueuedConnection);
746750
}
747751
}
752+
#endif
753+
if (e->type() == QEvent::ApplicationPaletteChange && d->StylesheetColorSchemeBehavior == CDockManager::FollowApplicationPalette)
754+
{
755+
if (d->CurrentStylesheetDark != isDesiredStylesheetDark()) {
756+
d->loadStylesheet();
757+
}
758+
}
748759
return Super::eventFilter(obj, e);
749760
}
750-
#endif
751761

752762

753763
//============================================================================
@@ -1266,6 +1276,18 @@ void CDockManager::setViewMenuInsertionOrder(eViewMenuInsertionOrder Order)
12661276
}
12671277

12681278

1279+
//============================================================================
1280+
void CDockManager::setStylesheetColorSchemeBehavior(eStylesheetColorSchemeBehavior Behavior)
1281+
{
1282+
d->StylesheetColorSchemeBehavior = Behavior;
1283+
1284+
if (d->CurrentStylesheetDark != isDesiredStylesheetDark()) {
1285+
d->loadStylesheet();
1286+
ensurePolished();
1287+
}
1288+
}
1289+
1290+
12691291
//===========================================================================
12701292
bool CDockManager::isRestoringState() const
12711293
{
@@ -1576,6 +1598,28 @@ void CDockManager::raise()
15761598
}
15771599

15781600

1601+
//============================================================================
1602+
bool CDockManager::isApplicationPaletteDark()
1603+
{
1604+
QPalette appPalette = QGuiApplication::palette();
1605+
1606+
// Extract the background and foreground colors
1607+
QColor windowColor = appPalette.color(QPalette::Window);
1608+
QColor textColor = appPalette.color(QPalette::WindowText);
1609+
1610+
// Check lightness values (0.0 = black, 1.0 = white)
1611+
// If text is lighter than the background, the app palette is dark
1612+
return textColor.lightnessF() > windowColor.lightnessF();
1613+
}
1614+
1615+
1616+
//============================================================================
1617+
bool CDockManager::isDesiredStylesheetDark()
1618+
{
1619+
return ((isApplicationPaletteDark() && d->StylesheetColorSchemeBehavior == FollowApplicationPalette) || d->StylesheetColorSchemeBehavior == ForceDark);
1620+
}
1621+
1622+
15791623
} // namespace ads
15801624

15811625
//---------------------------------------------------------------------------

src/DockManager.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,13 @@ public Q_SLOTS:
179179
MenuAlphabeticallySorted
180180
};
181181

182+
enum eStylesheetColorSchemeBehavior
183+
{
184+
ForceLight,
185+
ForceDark,
186+
FollowApplicationPalette
187+
};
188+
182189
/**
183190
* These global configuration flags configure some global dock manager
184191
* settings.
@@ -397,6 +404,16 @@ public Q_SLOTS:
397404
*/
398405
static CIconProvider& iconProvider();
399406

407+
/**
408+
* Returns if current application palette is dark
409+
*/
410+
static bool isApplicationPaletteDark();
411+
412+
/**
413+
* Returns if currently applied stylesheet is supposed to be dark
414+
*/
415+
bool isDesiredStylesheetDark();
416+
400417
/**
401418
* Adds dockwidget into the given area.
402419
* If DockAreaWidget is not null, then the area parameter indicates the area
@@ -617,6 +634,17 @@ public Q_SLOTS:
617634
*/
618635
void setViewMenuInsertionOrder(eViewMenuInsertionOrder Order);
619636

637+
/**
638+
* Define the behavior of stylesheet color scheme selection.
639+
* The stylesheet can be fixed to either light or dark scheme,
640+
* or it can follow the current application palette (default).
641+
* Note: The fixed settings implement legacy behavior (before
642+
* dark scheme was implemented) including problems like missing
643+
* palette change propagation. They are implemented solely
644+
* for compatibility reasons and manual stylesheet switching.
645+
*/
646+
void setStylesheetColorSchemeBehavior(eStylesheetColorSchemeBehavior Behavior);
647+
620648
/**
621649
* This function returns true between the restoringState() and
622650
* stateRestored() signals.

src/DockOverlay.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,14 @@ struct DockOverlayCrossPrivate
129129
break;
130130

131131
case CDockOverlayCross::ArrowColor: return pal.color(QPalette::Active, QPalette::Base);
132-
case CDockOverlayCross::ShadowColor: return QColor(0, 0, 0, 64);
132+
case CDockOverlayCross::ShadowColor:
133+
{
134+
QColor Color = pal.color(QPalette::Active, QPalette::Text);
135+
Color.setAlpha(64);
136+
return Color;
137+
}
138+
break;
139+
133140
default:
134141
return QColor();
135142
}
@@ -146,7 +153,6 @@ struct DockOverlayCrossPrivate
146153
if (!Color.isValid())
147154
{
148155
Color = defaultIconColor(ColorIndex);
149-
IconColors[ColorIndex] = Color;
150156
}
151157
return Color;
152158
}
@@ -907,6 +913,20 @@ void CDockOverlayCross::showEvent(QShowEvent*)
907913
}
908914

909915

916+
//============================================================================
917+
bool CDockOverlayCross::event(QEvent *e)
918+
{
919+
bool Result = QWidget::event(e);
920+
921+
if (e->type() == QEvent::ApplicationPaletteChange)
922+
{
923+
d->UpdateRequired = true;
924+
}
925+
926+
return Result;
927+
}
928+
929+
910930
//============================================================================
911931
void CDockOverlayCross::updatePosition()
912932
{

src/DockOverlay.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ class CDockOverlayCross : public QWidget
273273

274274
protected:
275275
virtual void showEvent(QShowEvent* e) override;
276+
virtual bool event(QEvent* e) override;
276277
void setAreaWidgets(const QHash<DockWidgetArea, QWidget*>& widgets);
277278
}; // CDockOverlayCross
278279

src/ads.qrc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,28 @@
2323
<file>images/minimize-button.svg</file>
2424
<file>images/minimize-button-focused.svg</file>
2525
<file>images/vs-pin-button-disabled.svg</file>
26+
<file>stylesheets/default_dark.css</file>
27+
<file>images/close-button_dark.svg</file>
28+
<file>images/pin-button_dark.svg</file>
29+
<file>images/close-button-disabled_dark.svg</file>
30+
<file>stylesheets/default_linux_dark.css</file>
31+
<file>images/close-button-focused_dark.svg</file>
32+
<file>stylesheets/focus_highlighting_dark.css</file>
33+
<file>stylesheets/focus_highlighting_linux_dark.css</file>
34+
<file>images/tabs-menu-button_dark.svg</file>
35+
<file>images/detach-button_dark.svg</file>
36+
<file>images/detach-button-disabled_dark.svg</file>
37+
<file>images/maximize-button_dark.svg</file>
38+
<file>images/maximize-button-focused_dark.svg</file>
39+
<file>images/restore-button_dark.svg</file>
40+
<file>images/restore-button-focused_dark.svg</file>
41+
<file>images/vs-pin-button_dark.svg</file>
42+
<file>images/vs-pin-button-pinned_dark.svg</file>
43+
<file>images/vs-pin-button-pinned-focused_dark.svg</file>
44+
<file>images/vs-pin-button_45_dark.svg</file>
45+
<file>images/pin-button-big_dark.svg</file>
46+
<file>images/minimize-button_dark.svg</file>
47+
<file>images/minimize-button-focused_dark.svg</file>
48+
<file>images/vs-pin-button-disabled_dark.svg</file>
2649
</qresource>
2750
</RCC>
Lines changed: 139 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)