1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickfluentwinui3theme_p.h"
5
6#include <QtCore/qoperatingsystemversion.h>
7#include <QtGui/private/qguiapplication_p.h>
8#include <QtGui/qpa/qplatformtheme.h>
9#include <QtGui/qguiapplication.h>
10#include <QtGui/qstylehints.h>
11#include <QtGui/QAccessibilityHints>
12#include <QtGui/qcolor.h>
13#include <QtGui/qfontdatabase.h>
14#include <QtQuickTemplates2/private/qquicktheme_p.h>
15
16QT_BEGIN_NAMESPACE
17
18// If on a Windows11 or above, the platform theme will be used to populate the palette
19// We need to fallback to hardcoded colors when using the style on other platforms,
20// that's why we need the following
21// The colors for Windows 11 are taken from the official WinUI3 Figma style at
22// https://www.figma.com/community/file/1159947337437047524
23// Try to keep these consistent with the widget windows11 style
24enum WinUI3Color {
25 solidBackground, // Solid background color used for the bottom most layer
26 acrylicBackgroundDefault, // Acrylic background for popups/tooltips
27 textPrimary, // Color for UI labels and static text
28 textSecondary, // Color for text in pressed controls
29 textDisabled, // Color for disabled text
30 textOnAccentPrimary, // Color of text on controls filled in accent color
31 textOnAccentSecondary, // Color of text on sunken controls in accent color
32 textOnAccentDisabled, // Color of text on disabled controls in accent color
33 controlDefault, // Color for standard controls
34 controlDisabled, // Color for disabled controls
35 controlStrokeDefault, // Color for gradient stops in elevations (pressed or disabled state)
36 controlStrokeSecondary, // Color for gradient stops in elevations
37 controlStrokeAccentDefault, // Color for gradient stops in elevations for accent controls
38 controlStrokeAccentSecondary, // Color for gradient stops in elevations for accent controls
39 accentDefault, // Default color for accent fills on controls
40 accentDisabled, // Default color for accent fills on disabled controls
41 accentSecondary, // Color for accent fills on hovered controls
42 inputActive, // Color for active text input backgrounds
43};
44
45const static QColor WINUI3ColorsLight [] {
46 QColor(0xF3,0xF3,0xF3,0xFF), //solidBackgroundColor
47 QColor(0xFC,0xFC,0xFC,0xFF), //acrylicBackgroundDefault
48 QColor(0x00,0x00,0x00,0xE4), //textPrimary
49 QColor(0x00,0x00,0x00,0x9E), //textSecondary
50 QColor(0x00,0x00,0x00,0x5C), //textDisabled
51 QColor(0xFF,0xFF,0xFF,0xFF), //textOnAccentPrimary
52 QColor(0xFF,0xFF,0xFF,0x7F), //textOnAccentSecondary
53 QColor(0xFF,0xFF,0xFF,0xFF), //textOnAccentDisabled
54 QColor(0xFF,0xFF,0xFF,0xB3), //controlDefault
55 QColor(0xF9,0xF9,0xF9,0x4D), //controlDisabled
56 QColor(0x00,0x00,0x00,0x0F), //controlStrokeDefault
57 QColor(0x00,0x00,0x00,0x29), //controlStrokeSecondary
58 QColor(0xFF,0xFF,0xFF,0x14), //controlStrokeAccentDefault
59 QColor(0x00,0x00,0x00,0x66), //controlStrokeAccentSecondary
60 QColor(0x00,0x5F,0xB8,0xFF), //accentDefault
61 QColor(0x00,0x00,0x00,0x37), //accentDisabled
62 QColor(0x00,0x5F,0xB8,0xE6), //accentSecondary
63 QColor(0xFF,0xFF,0xFF,0xFF) //inputActive
64};
65
66const static QColor WINUI3ColorsDark[] {
67 QColor(0x20,0x20,0x20,0xFF), //solidBackgroundColor
68 QColor(0x2C,0x2C,0x2C,0xFF), //acrylicBackgroundDefault
69 QColor(0xFF,0xFF,0xFF,0xFF), //textPrimary
70 QColor(0xFF,0xFF,0xFF,0xC5), //textSecondary
71 QColor(0xFF,0xFF,0xFF,0x5D), //textDisabled
72 QColor(0x00,0x00,0x00,0xFF), //textOnAccentPrimary
73 QColor(0x00,0x00,0x00,0x80), //textOnAccentSecondary
74 QColor(0xFF,0xFF,0xFF,0x87), //textOnAccentDisabled
75 QColor(0xFF,0xFF,0xFF,0x0F), //controlDefault
76 QColor(0xFF,0xFF,0xFF,0x11), //controlDisabled
77 QColor(0xFF,0xFF,0xFF,0x12), //controlStrokeDefault
78 QColor(0xFF,0xFF,0xFF,0x18), //controlStrokeSecondary
79 QColor(0xFF,0xFF,0xFF,0x14), //controlStrokeAccentDefault
80 QColor(0x00,0x00,0x00,0x23), //controlStrokeAccentSecondary
81 QColor(0x60,0xCD,0xFF,0xFF), //accentDefault
82 QColor(0xFF,0xFF,0xFF,0x28), //accentDisabled
83 QColor(0x60,0xCD,0xFF,0xE6), // accentSecondary
84 QColor(0x1E,0x1E,0x1E,0xB3) // inputActive
85};
86
87const static QColor* WINUI3Colors[] {
88 WINUI3ColorsLight,
89 WINUI3ColorsDark
90};
91
92// Function to populate the palette with WinUI3 theme-specific colors
93static void populateWinUI3Palette(QPalette &palette)
94{
95 const auto colorSchemeIndex = QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Light ? 0 : 1;
96
97 palette.setColor(acg: QPalette::All, acr: QPalette::Window, acolor: WINUI3Colors[colorSchemeIndex][solidBackground]);
98
99 palette.setColor(acg: QPalette::All, acr: QPalette::Base, acolor: WINUI3Colors[colorSchemeIndex][controlDefault]);
100 palette.setColor(acg: QPalette::Active, acr: QPalette::Base, acolor: WINUI3Colors[colorSchemeIndex][inputActive]);
101 palette.setColor(acg: QPalette::Disabled, acr: QPalette::Base, acolor: WINUI3Colors[colorSchemeIndex][controlDisabled]);
102
103 palette.setColor(acg: QPalette::All, acr: QPalette::WindowText, acolor: WINUI3Colors[colorSchemeIndex][textPrimary]);
104 palette.setColor(acg: QPalette::Disabled, acr: QPalette::WindowText, acolor: WINUI3Colors[colorSchemeIndex][textDisabled]);
105
106 palette.setColor(acg: QPalette::All, acr: QPalette::Text, acolor: WINUI3Colors[colorSchemeIndex][textPrimary]);
107 palette.setColor(acg: QPalette::Disabled, acr: QPalette::Text, acolor: WINUI3Colors[colorSchemeIndex][textDisabled]);
108
109 palette.setColor(acg: QPalette::All, acr: QPalette::PlaceholderText, acolor: WINUI3Colors[colorSchemeIndex][textSecondary]);
110 palette.setColor(acg: QPalette::Disabled, acr: QPalette::PlaceholderText, acolor: WINUI3Colors[colorSchemeIndex][textDisabled]);
111
112 palette.setColor(acg: QPalette::All, acr: QPalette::Button, acolor: WINUI3Colors[colorSchemeIndex][controlDefault]);
113 palette.setColor(acg: QPalette::Disabled, acr: QPalette::Button, acolor: WINUI3Colors[colorSchemeIndex][controlDisabled]);
114 palette.setColor(acg: QPalette::All, acr: QPalette::ButtonText, acolor: WINUI3Colors[colorSchemeIndex][textPrimary]);
115 palette.setColor(acg: QPalette::Disabled, acr: QPalette::ButtonText, acolor: WINUI3Colors[colorSchemeIndex][textDisabled]);
116
117 palette.setColor(acg: QPalette::All, acr: QPalette::ToolTipBase, acolor: WINUI3Colors[colorSchemeIndex][acrylicBackgroundDefault]);
118 palette.setColor(acg: QPalette::All, acr: QPalette::ToolTipText, acolor: WINUI3Colors[colorSchemeIndex][textPrimary]);
119 palette.setColor(acg: QPalette::Disabled, acr: QPalette::ToolTipText, acolor: WINUI3Colors[colorSchemeIndex][textDisabled]);
120
121 palette.setColor(acg: QPalette::Disabled, acr: QPalette::Accent, acolor: WINUI3Colors[colorSchemeIndex][accentDisabled]);
122 palette.setColor(acg: QPalette::Disabled, acr: QPalette::Highlight, acolor: WINUI3Colors[colorSchemeIndex][accentDisabled]);
123
124 palette.setColor(acg: QPalette::All, acr: QPalette::HighlightedText, acolor: Qt::white);
125
126 palette.setColor(acg: QPalette::All, acr: QPalette::Light, acolor: WINUI3Colors[colorSchemeIndex][controlStrokeAccentDefault]);
127 palette.setColor(acg: QPalette::All, acr: QPalette::Midlight, acolor: WINUI3Colors[colorSchemeIndex][controlStrokeDefault]);
128 palette.setColor(acg: QPalette::All, acr: QPalette::Dark, acolor: WINUI3Colors[colorSchemeIndex][controlStrokeSecondary]);
129 palette.setColor(acg: QPalette::All, acr: QPalette::Mid, acolor: WINUI3Colors[colorSchemeIndex][controlStrokeAccentSecondary]);
130}
131
132static void populateWinUI3Fonts(QQuickTheme *theme)
133{
134 QFont systemFont;
135 QFont toolBarFont;
136 QFont toolTipFont;
137
138 const QLatin1String segoeUiFamilyName("Segoe UI Variable");
139 if (QFontDatabase::families().contains(str: segoeUiFamilyName)) {
140 const QFont segoeFont(segoeUiFamilyName);
141 const QStringList families{segoeFont.family()};
142 systemFont.setFamilies(families);
143 toolBarFont.setFamilies(families);
144 }
145 systemFont.setWeight(QFont::Weight::Normal);
146 toolBarFont.setWeight(QFont::Weight::Normal);
147 toolTipFont.setWeight(QFont::Weight::Normal);
148
149 systemFont.setPixelSize(14);
150 toolBarFont.setPixelSize(12);
151 toolTipFont.setPixelSize(12);
152
153 theme->setFont(scope: QQuickTheme::System, font: systemFont);
154 theme->setFont(scope: QQuickTheme::ToolBar, font: toolBarFont);
155 theme->setFont(scope: QQuickTheme::ToolTip, font: toolTipFont);
156}
157
158QPalette QQuickFluentWinUI3Theme::initializeDefaultPalette()
159{
160 QPalette palette;
161
162 const auto *styleHints = QGuiApplication::styleHints();
163 const auto highContrastTheme = styleHints->accessibility()->contrastPreference() == Qt::ContrastPreference::HighContrast;
164 // HighContrast themes use system colors only
165 if (!highContrastTheme) {
166 populateWinUI3Palette(palette);
167
168 // Resolve against the platform palette
169 if (auto platformTheme = QGuiApplicationPrivate::platformTheme()) {
170 const auto platformPalette = platformTheme->palette();
171 if (platformPalette)
172 palette = palette.resolve(other: *platformPalette);
173 }
174 const auto colorSchemeIndex = styleHints->colorScheme() == Qt::ColorScheme::Light ? 0 : 1;
175 // Ensure specific roles are set
176 if (!palette.isBrushSet(cg: QPalette::Active, cr: QPalette::Accent))
177 palette.setColor(acg: QPalette::Active, acr: QPalette::Accent, acolor: WINUI3Colors[colorSchemeIndex][accentDefault]);
178
179 if (!palette.isBrushSet(cg: QPalette::Inactive, cr: QPalette::Highlight))
180 palette.setColor(acg: QPalette::Inactive, acr: QPalette::Highlight, acolor: palette.accent().color());
181
182 palette.setColor(acg: QPalette::Disabled, acr: QPalette::Accent, acolor: WINUI3Colors[colorSchemeIndex][accentDisabled]);
183 palette.setColor(acg: QPalette::Disabled, acr: QPalette::Highlight, acolor: WINUI3Colors[colorSchemeIndex][accentDisabled]);
184 }
185 // WinUI3 sets the inactive accent color to the same as the active one
186 palette.setColor(acg: QPalette::Inactive, acr: QPalette::Accent, acolor: palette.accent().color());
187 palette.setColor(acg: QPalette::Inactive, acr: QPalette::Highlight, acolor: palette.highlight().color());
188
189 // Finally QGuiApp::palette() should take precedence over style palette
190 palette = QGuiApplication::palette().resolve(other: palette);
191
192 return palette;
193}
194
195void QQuickFluentWinUI3Theme::initialize(QQuickTheme *theme)
196{
197 populateWinUI3Fonts(theme);
198
199 QPalette systemPalette = initializeDefaultPalette();
200 theme->setPalette(scope: QQuickTheme::System, palette: systemPalette);
201}
202
203QT_END_NAMESPACE
204

source code of qtdeclarative/src/quickcontrols/fluentwinui3/qquickfluentwinui3theme.cpp