1// Copyright (C) 2017 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 "qquickuniversalstyle_p.h"
5
6#include <QtCore/qdebug.h>
7#if QT_CONFIG(settings)
8#include <QtCore/qsettings.h>
9#endif
10#include <QtQml/qqmlinfo.h>
11#include <QtQuickControls2/private/qquickstyle_p.h>
12
13QT_BEGIN_NAMESPACE
14
15static QRgb qquickuniversal_light_color(QQuickUniversalStyle::SystemColor role)
16{
17 static const QRgb colors[] = {
18 0xFFFFFFFF, // SystemAltHighColor
19 0x33FFFFFF, // SystemAltLowColor
20 0x99FFFFFF, // SystemAltMediumColor
21 0xCCFFFFFF, // SystemAltMediumHighColor
22 0x66FFFFFF, // SystemAltMediumLowColor
23 0xFF000000, // SystemBaseHighColor
24 0x33000000, // SystemBaseLowColor
25 0x99000000, // SystemBaseMediumColor
26 0xCC000000, // SystemBaseMediumHighColor
27 0x66000000, // SystemBaseMediumLowColor
28 0xFF171717, // SystemChromeAltLowColor
29 0xFF000000, // SystemChromeBlackHighColor
30 0x33000000, // SystemChromeBlackLowColor
31 0x66000000, // SystemChromeBlackMediumLowColor
32 0xCC000000, // SystemChromeBlackMediumColor
33 0xFFCCCCCC, // SystemChromeDisabledHighColor
34 0xFF7A7A7A, // SystemChromeDisabledLowColor
35 0xFFCCCCCC, // SystemChromeHighColor
36 0xFFF2F2F2, // SystemChromeLowColor
37 0xFFE6E6E6, // SystemChromeMediumColor
38 0xFFF2F2F2, // SystemChromeMediumLowColor
39 0xFFFFFFFF, // SystemChromeWhiteColor
40 0x19000000, // SystemListLowColor
41 0x33000000 // SystemListMediumColor
42 };
43 return colors[role];
44}
45
46static QRgb qquickuniversal_dark_color(QQuickUniversalStyle::SystemColor role)
47{
48 static const QRgb colors[] = {
49 0xFF000000, // SystemAltHighColor
50 0x33000000, // SystemAltLowColor
51 0x99000000, // SystemAltMediumColor
52 0xCC000000, // SystemAltMediumHighColor
53 0x66000000, // SystemAltMediumLowColor
54 0xFFFFFFFF, // SystemBaseHighColor
55 0x33FFFFFF, // SystemBaseLowColor
56 0x99FFFFFF, // SystemBaseMediumColor
57 0xCCFFFFFF, // SystemBaseMediumHighColor
58 0x66FFFFFF, // SystemBaseMediumLowColor
59 0xFFF2F2F2, // SystemChromeAltLowColor
60 0xFF000000, // SystemChromeBlackHighColor
61 0x33000000, // SystemChromeBlackLowColor
62 0x66000000, // SystemChromeBlackMediumLowColor
63 0xCC000000, // SystemChromeBlackMediumColor
64 0xFF333333, // SystemChromeDisabledHighColor
65 0xFF858585, // SystemChromeDisabledLowColor
66 0xFF767676, // SystemChromeHighColor
67 0xFF171717, // SystemChromeLowColor
68 0xFF1F1F1F, // SystemChromeMediumColor
69 0xFF2B2B2B, // SystemChromeMediumLowColor
70 0xFFFFFFFF, // SystemChromeWhiteColor
71 0x19FFFFFF, // SystemListLowColor
72 0x33FFFFFF // SystemListMediumColor
73 };
74 return colors[role];
75}
76
77static QRgb qquickuniversal_accent_color(QQuickUniversalStyle::Color accent)
78{
79 static const QRgb colors[] = {
80 0xFFA4C400, // Lime
81 0xFF60A917, // Green
82 0xFF008A00, // Emerald
83 0xFF00ABA9, // Teal
84 0xFF1BA1E2, // Cyan
85 0xFF3E65FF, // Cobalt
86 0xFF6A00FF, // Indigo
87 0xFFAA00FF, // Violet
88 0xFFF472D0, // Pink
89 0xFFD80073, // Magenta
90 0xFFA20025, // Crimson
91 0xFFE51400, // Red
92 0xFFFA6800, // Orange
93 0xFFF0A30A, // Amber
94 0xFFE3C800, // Yellow
95 0xFF825A2C, // Brown
96 0xFF6D8764, // Olive
97 0xFF647687, // Steel
98 0xFF76608A, // Mauve
99 0xFF87794E // Taupe
100 };
101 return colors[accent];
102}
103
104static QQuickUniversalStyle::Theme qquickuniversal_effective_theme(QQuickUniversalStyle::Theme theme)
105{
106 if (theme == QQuickUniversalStyle::System)
107 theme = QQuickStylePrivate::isDarkSystemTheme() ? QQuickUniversalStyle::Dark : QQuickUniversalStyle::Light;
108 return theme;
109}
110
111// If no value was inherited from a parent or explicitly set, the "global" values are used.
112// The initial, default values of the globals are hard-coded here, but the environment
113// variables and .conf file override them if specified.
114static QQuickUniversalStyle::Theme GlobalTheme = QQuickUniversalStyle::Light;
115static QRgb GlobalAccent = qquickuniversal_accent_color(accent: QQuickUniversalStyle::Cobalt);
116static QRgb GlobalForeground = qquickuniversal_light_color(role: QQuickUniversalStyle::BaseHigh);
117static QRgb GlobalBackground = qquickuniversal_light_color(role: QQuickUniversalStyle::AltHigh);
118// These represent whether a global foreground/background was set.
119// Each style's m_hasForeground/m_hasBackground are initialized to these values.
120static bool HasGlobalForeground = false;
121static bool HasGlobalBackground = false;
122
123QQuickUniversalStyle::QQuickUniversalStyle(QObject *parent) : QQuickAttachedPropertyPropagator(parent),
124 m_hasForeground(HasGlobalForeground), m_hasBackground(HasGlobalBackground), m_theme(GlobalTheme),
125 m_accent(GlobalAccent), m_foreground(GlobalForeground), m_background(GlobalBackground)
126{
127 initialize();
128}
129
130QQuickUniversalStyle *QQuickUniversalStyle::qmlAttachedProperties(QObject *object)
131{
132 return new QQuickUniversalStyle(object);
133}
134
135QQuickUniversalStyle::Theme QQuickUniversalStyle::theme() const
136{
137 return m_theme;
138}
139
140void QQuickUniversalStyle::setTheme(Theme theme)
141{
142 theme = qquickuniversal_effective_theme(theme);
143 m_explicitTheme = true;
144 if (m_theme == theme)
145 return;
146
147 m_theme = theme;
148 propagateTheme();
149 emit themeChanged();
150 emit paletteChanged();
151 emit foregroundChanged();
152 emit backgroundChanged();
153}
154
155void QQuickUniversalStyle::inheritTheme(Theme theme)
156{
157 if (m_explicitTheme || m_theme == theme)
158 return;
159
160 m_theme = theme;
161 propagateTheme();
162 emit themeChanged();
163 emit paletteChanged();
164 emit foregroundChanged();
165 emit backgroundChanged();
166}
167
168void QQuickUniversalStyle::propagateTheme()
169{
170 const auto styles = attachedChildren();
171 for (QQuickAttachedPropertyPropagator *child : styles) {
172 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(object: child);
173 if (universal)
174 universal->inheritTheme(theme: m_theme);
175 }
176}
177
178void QQuickUniversalStyle::resetTheme()
179{
180 if (!m_explicitTheme)
181 return;
182
183 m_explicitTheme = false;
184 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(object: attachedParent());
185 inheritTheme(theme: universal ? universal->theme() : GlobalTheme);
186}
187
188QVariant QQuickUniversalStyle::accent() const
189{
190 return QColor::fromRgba(rgba: m_accent);
191}
192
193void QQuickUniversalStyle::setAccent(const QVariant &var)
194{
195 QRgb accent = 0;
196 if (!variantToRgba(var, name: "accent", rgba: &accent))
197 return;
198
199 m_explicitAccent = true;
200 if (m_accent == accent)
201 return;
202
203 m_accent = accent;
204 propagateAccent();
205 emit accentChanged();
206}
207
208void QQuickUniversalStyle::inheritAccent(QRgb accent)
209{
210 if (m_explicitAccent || m_accent == accent)
211 return;
212
213 m_accent = accent;
214 propagateAccent();
215 emit accentChanged();
216}
217
218void QQuickUniversalStyle::propagateAccent()
219{
220 const auto styles = attachedChildren();
221 for (QQuickAttachedPropertyPropagator *child : styles) {
222 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(object: child);
223 if (universal)
224 universal->inheritAccent(accent: m_accent);
225 }
226}
227
228void QQuickUniversalStyle::resetAccent()
229{
230 if (!m_explicitAccent)
231 return;
232
233 m_explicitAccent = false;
234 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(object: attachedParent());
235 inheritAccent(accent: universal ? universal->m_accent : GlobalAccent);
236}
237
238QVariant QQuickUniversalStyle::foreground() const
239{
240 if (m_hasForeground)
241 return QColor::fromRgba(rgba: m_foreground);
242 return baseHighColor();
243}
244
245void QQuickUniversalStyle::setForeground(const QVariant &var)
246{
247 QRgb foreground = 0;
248 if (!variantToRgba(var, name: "foreground", rgba: &foreground))
249 return;
250
251 m_hasForeground = true;
252 m_explicitForeground = true;
253 if (m_foreground == foreground)
254 return;
255
256 m_foreground = foreground;
257 propagateForeground();
258 emit foregroundChanged();
259}
260
261void QQuickUniversalStyle::inheritForeground(QRgb foreground, bool has)
262{
263 if (m_explicitForeground || m_foreground == foreground)
264 return;
265
266 m_hasForeground = has;
267 m_foreground = foreground;
268 propagateForeground();
269 emit foregroundChanged();
270}
271
272void QQuickUniversalStyle::propagateForeground()
273{
274 const auto styles = attachedChildren();
275 for (QQuickAttachedPropertyPropagator *child : styles) {
276 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(object: child);
277 if (universal)
278 universal->inheritForeground(foreground: m_foreground, has: m_hasForeground);
279 }
280}
281
282void QQuickUniversalStyle::resetForeground()
283{
284 if (!m_explicitForeground)
285 return;
286
287 m_hasForeground = false;
288 m_explicitForeground = false;
289 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(object: attachedParent());
290 inheritForeground(foreground: universal ? universal->m_foreground : GlobalForeground, has: universal ? universal->m_hasForeground : false);
291}
292
293QVariant QQuickUniversalStyle::background() const
294{
295 if (m_hasBackground)
296 return QColor::fromRgba(rgba: m_background);
297 return altHighColor();
298}
299
300void QQuickUniversalStyle::setBackground(const QVariant &var)
301{
302 QRgb background = 0;
303 if (!variantToRgba(var, name: "background", rgba: &background))
304 return;
305
306 m_hasBackground = true;
307 m_explicitBackground = true;
308 if (m_background == background)
309 return;
310
311 m_background = background;
312 propagateBackground();
313 emit backgroundChanged();
314}
315
316void QQuickUniversalStyle::inheritBackground(QRgb background, bool has)
317{
318 if (m_explicitBackground || m_background == background)
319 return;
320
321 m_hasBackground = has;
322 m_background = background;
323 propagateBackground();
324 emit backgroundChanged();
325}
326
327void QQuickUniversalStyle::propagateBackground()
328{
329 const auto styles = attachedChildren();
330 for (QQuickAttachedPropertyPropagator *child : styles) {
331 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(object: child);
332 if (universal)
333 universal->inheritBackground(background: m_background, has: m_hasBackground);
334 }
335}
336
337void QQuickUniversalStyle::resetBackground()
338{
339 if (!m_explicitBackground)
340 return;
341
342 m_hasBackground = false;
343 m_explicitBackground = false;
344 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(object: attachedParent());
345 inheritBackground(background: universal ? universal->m_background : GlobalBackground, has: universal ? universal->m_hasBackground : false);
346}
347
348QColor QQuickUniversalStyle::color(Color color) const
349{
350 return qquickuniversal_accent_color(accent: color);
351}
352
353QColor QQuickUniversalStyle::altHighColor() const
354{
355 return systemColor(role: AltHigh);
356}
357
358QColor QQuickUniversalStyle::altLowColor() const
359{
360 return systemColor(role: AltLow);
361}
362
363QColor QQuickUniversalStyle::altMediumColor() const
364{
365 return systemColor(role: AltMedium);
366}
367
368QColor QQuickUniversalStyle::altMediumHighColor() const
369{
370 return systemColor(role: AltMediumHigh);
371}
372
373QColor QQuickUniversalStyle::altMediumLowColor() const
374{
375 return systemColor(role: AltMediumLow);
376}
377
378QColor QQuickUniversalStyle::baseHighColor() const
379{
380 return systemColor(role: BaseHigh);
381}
382
383QColor QQuickUniversalStyle::baseLowColor() const
384{
385 return systemColor(role: BaseLow);
386}
387
388QColor QQuickUniversalStyle::baseMediumColor() const
389{
390 return systemColor(role: BaseMedium);
391}
392
393QColor QQuickUniversalStyle::baseMediumHighColor() const
394{
395 return systemColor(role: BaseMediumHigh);
396}
397
398QColor QQuickUniversalStyle::baseMediumLowColor() const
399{
400 return systemColor(role: BaseMediumLow);
401}
402
403QColor QQuickUniversalStyle::chromeAltLowColor() const
404{
405 return systemColor(role: ChromeAltLow);
406}
407
408QColor QQuickUniversalStyle::chromeBlackHighColor() const
409{
410 return systemColor(role: ChromeBlackHigh);
411}
412
413QColor QQuickUniversalStyle::chromeBlackLowColor() const
414{
415 return systemColor(role: ChromeBlackLow);
416}
417
418QColor QQuickUniversalStyle::chromeBlackMediumLowColor() const
419{
420 return systemColor(role: ChromeBlackMediumLow);
421}
422
423QColor QQuickUniversalStyle::chromeBlackMediumColor() const
424{
425 return systemColor(role: ChromeBlackMedium);
426}
427
428QColor QQuickUniversalStyle::chromeDisabledHighColor() const
429{
430 return systemColor(role: ChromeDisabledHigh);
431}
432
433QColor QQuickUniversalStyle::chromeDisabledLowColor() const
434{
435 return systemColor(role: ChromeDisabledLow);
436}
437
438QColor QQuickUniversalStyle::chromeHighColor() const
439{
440 return systemColor(role: ChromeHigh);
441}
442
443QColor QQuickUniversalStyle::chromeLowColor() const
444{
445 return systemColor(role: ChromeLow);
446}
447
448QColor QQuickUniversalStyle::chromeMediumColor() const
449{
450 return systemColor(role: ChromeMedium);
451}
452
453QColor QQuickUniversalStyle::chromeMediumLowColor() const
454{
455 return systemColor(role: ChromeMediumLow);
456}
457
458QColor QQuickUniversalStyle::chromeWhiteColor() const
459{
460 return systemColor(role: ChromeWhite);
461}
462
463QColor QQuickUniversalStyle::listLowColor() const
464{
465 return systemColor(role: ListLow);
466}
467
468QColor QQuickUniversalStyle::listMediumColor() const
469{
470 return systemColor(role: ListMedium);
471}
472
473QColor QQuickUniversalStyle::systemColor(SystemColor role) const
474{
475 return QColor::fromRgba(rgba: m_theme == QQuickUniversalStyle::Dark ? qquickuniversal_dark_color(role) : qquickuniversal_light_color(role));
476}
477
478void QQuickUniversalStyle::attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent)
479{
480 Q_UNUSED(oldParent);
481 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(object: newParent);
482 if (universal) {
483 inheritTheme(theme: universal->theme());
484 inheritAccent(accent: universal->m_accent);
485 inheritForeground(foreground: universal->m_foreground, has: universal->m_hasForeground);
486 inheritBackground(background: universal->m_background, has: universal->m_hasBackground);
487 }
488}
489
490template <typename Enum>
491static Enum toEnumValue(const QByteArray &value, bool *ok)
492{
493 QMetaEnum enumeration = QMetaEnum::fromType<Enum>();
494 return static_cast<Enum>(enumeration.keyToValue(key: value, ok));
495}
496
497static QByteArray resolveSetting(const QByteArray &env, const QSharedPointer<QSettings> &settings, const QString &name)
498{
499 QByteArray value = qgetenv(varName: env);
500#if QT_CONFIG(settings)
501 if (value.isNull() && !settings.isNull())
502 value = settings->value(key: name).toByteArray();
503#endif
504 return value;
505}
506
507void QQuickUniversalStyle::initGlobals()
508{
509 QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("Universal"));
510
511 bool ok = false;
512 QByteArray themeValue = resolveSetting(env: "QT_QUICK_CONTROLS_UNIVERSAL_THEME", settings, QStringLiteral("Theme"));
513 Theme themeEnum = toEnumValue<Theme>(value: themeValue, ok: &ok);
514 if (ok)
515 GlobalTheme = qquickuniversal_effective_theme(theme: themeEnum);
516 else if (!themeValue.isEmpty())
517 qWarning().nospace().noquote() << "Universal: unknown theme value: " << themeValue;
518
519 QByteArray accentValue = resolveSetting(env: "QT_QUICK_CONTROLS_UNIVERSAL_ACCENT", settings, QStringLiteral("Accent"));
520 Color accentEnum = toEnumValue<Color>(value: accentValue, ok: &ok);
521 if (ok) {
522 GlobalAccent = qquickuniversal_accent_color(accent: accentEnum);
523 } else if (!accentValue.isEmpty()) {
524 QColor color = QColor::fromString(name: accentValue);
525 if (color.isValid())
526 GlobalAccent = color.rgba();
527 else
528 qWarning().nospace().noquote() << "Universal: unknown accent value: " << accentValue;
529 }
530
531 QByteArray foregroundValue = resolveSetting(env: "QT_QUICK_CONTROLS_UNIVERSAL_FOREGROUND", settings, QStringLiteral("Foreground"));
532 Color foregroundEnum = toEnumValue<Color>(value: foregroundValue, ok: &ok);
533 if (ok) {
534 GlobalForeground = qquickuniversal_accent_color(accent: foregroundEnum);
535 HasGlobalForeground = true;
536 } else if (!foregroundValue.isEmpty()) {
537 QColor color = QColor::fromString(name: foregroundValue);
538 if (color.isValid()) {
539 GlobalForeground = color.rgba();
540 HasGlobalForeground = true;
541 } else {
542 qWarning().nospace().noquote() << "Universal: unknown foreground value: " << foregroundValue;
543 }
544 }
545
546 QByteArray backgroundValue = resolveSetting(env: "QT_QUICK_CONTROLS_UNIVERSAL_BACKGROUND", settings, QStringLiteral("Background"));
547 Color backgroundEnum = toEnumValue<Color>(value: backgroundValue, ok: &ok);
548 if (ok) {
549 GlobalBackground = qquickuniversal_accent_color(accent: backgroundEnum);
550 HasGlobalBackground = true;
551 } else if (!backgroundValue.isEmpty()) {
552 QColor color = QColor::fromString(name: backgroundValue);
553 if (color.isValid()) {
554 GlobalBackground = color.rgba();
555 HasGlobalBackground = true;
556 } else {
557 qWarning().nospace().noquote() << "Universal: unknown background value: " << backgroundValue;
558 }
559 }
560}
561
562bool QQuickUniversalStyle::variantToRgba(const QVariant &var, const char *name, QRgb *rgba) const
563{
564 if (var.metaType().id() == QMetaType::Int) {
565 int val = var.toInt();
566 if (val < Lime || val > Taupe) {
567 qmlWarning(me: parent()) << "unknown Universal." << name << " value: " << val;
568 return false;
569 }
570 *rgba = qquickuniversal_accent_color(accent: static_cast<Color>(val));
571 } else {
572 int val = QMetaEnum::fromType<Color>().keyToValue(key: var.toByteArray());
573 if (val != -1) {
574 *rgba = qquickuniversal_accent_color(accent: static_cast<Color>(val));
575 } else {
576 QColor color = QColor::fromString(name: var.toString());
577 if (!color.isValid()) {
578 qmlWarning(me: parent()) << "unknown Universal." << name << " value: " << var.toString();
579 return false;
580 }
581 *rgba = color.rgba();
582 }
583 }
584 return true;
585}
586
587QT_END_NAMESPACE
588
589#include "moc_qquickuniversalstyle_p.cpp"
590

source code of qtdeclarative/src/quickcontrols/universal/qquickuniversalstyle.cpp