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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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