1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "qquickuniversalstyle_p.h"
38
39#include <QtCore/qdebug.h>
40#include <QtCore/qsettings.h>
41#include <QtQml/qqmlinfo.h>
42#include <QtQuickControls2/private/qquickstyle_p.h>
43
44QT_BEGIN_NAMESPACE
45
46static QRgb qquickuniversal_light_color(QQuickUniversalStyle::SystemColor role)
47{
48 static const QRgb colors[] = {
49 0xFFFFFFFF, // SystemAltHighColor
50 0x33FFFFFF, // SystemAltLowColor
51 0x99FFFFFF, // SystemAltMediumColor
52 0xCCFFFFFF, // SystemAltMediumHighColor
53 0x66FFFFFF, // SystemAltMediumLowColor
54 0xFF000000, // SystemBaseHighColor
55 0x33000000, // SystemBaseLowColor
56 0x99000000, // SystemBaseMediumColor
57 0xCC000000, // SystemBaseMediumHighColor
58 0x66000000, // SystemBaseMediumLowColor
59 0xFF171717, // SystemChromeAltLowColor
60 0xFF000000, // SystemChromeBlackHighColor
61 0x33000000, // SystemChromeBlackLowColor
62 0x66000000, // SystemChromeBlackMediumLowColor
63 0xCC000000, // SystemChromeBlackMediumColor
64 0xFFCCCCCC, // SystemChromeDisabledHighColor
65 0xFF7A7A7A, // SystemChromeDisabledLowColor
66 0xFFCCCCCC, // SystemChromeHighColor
67 0xFFF2F2F2, // SystemChromeLowColor
68 0xFFE6E6E6, // SystemChromeMediumColor
69 0xFFF2F2F2, // SystemChromeMediumLowColor
70 0xFFFFFFFF, // SystemChromeWhiteColor
71 0x19000000, // SystemListLowColor
72 0x33000000 // SystemListMediumColor
73 };
74 return colors[role];
75}
76
77static QRgb qquickuniversal_dark_color(QQuickUniversalStyle::SystemColor role)
78{
79 static const QRgb colors[] = {
80 0xFF000000, // SystemAltHighColor
81 0x33000000, // SystemAltLowColor
82 0x99000000, // SystemAltMediumColor
83 0xCC000000, // SystemAltMediumHighColor
84 0x66000000, // SystemAltMediumLowColor
85 0xFFFFFFFF, // SystemBaseHighColor
86 0x33FFFFFF, // SystemBaseLowColor
87 0x99FFFFFF, // SystemBaseMediumColor
88 0xCCFFFFFF, // SystemBaseMediumHighColor
89 0x66FFFFFF, // SystemBaseMediumLowColor
90 0xFFF2F2F2, // SystemChromeAltLowColor
91 0xFF000000, // SystemChromeBlackHighColor
92 0x33000000, // SystemChromeBlackLowColor
93 0x66000000, // SystemChromeBlackMediumLowColor
94 0xCC000000, // SystemChromeBlackMediumColor
95 0xFF333333, // SystemChromeDisabledHighColor
96 0xFF858585, // SystemChromeDisabledLowColor
97 0xFF767676, // SystemChromeHighColor
98 0xFF171717, // SystemChromeLowColor
99 0xFF1F1F1F, // SystemChromeMediumColor
100 0xFF2B2B2B, // SystemChromeMediumLowColor
101 0xFFFFFFFF, // SystemChromeWhiteColor
102 0x19FFFFFF, // SystemListLowColor
103 0x33FFFFFF // SystemListMediumColor
104 };
105 return colors[role];
106}
107
108static QRgb qquickuniversal_accent_color(QQuickUniversalStyle::Color accent)
109{
110 static const QRgb colors[] = {
111 0xFFA4C400, // Lime
112 0xFF60A917, // Green
113 0xFF008A00, // Emerald
114 0xFF00ABA9, // Teal
115 0xFF1BA1E2, // Cyan
116 0xFF3E65FF, // Cobalt
117 0xFF6A00FF, // Indigo
118 0xFFAA00FF, // Violet
119 0xFFF472D0, // Pink
120 0xFFD80073, // Magenta
121 0xFFA20025, // Crimson
122 0xFFE51400, // Red
123 0xFFFA6800, // Orange
124 0xFFF0A30A, // Amber
125 0xFFE3C800, // Yellow
126 0xFF825A2C, // Brown
127 0xFF6D8764, // Olive
128 0xFF647687, // Steel
129 0xFF76608A, // Mauve
130 0xFF87794E // Taupe
131 };
132 return colors[accent];
133}
134
135static QQuickUniversalStyle::Theme qquickuniversal_effective_theme(QQuickUniversalStyle::Theme theme)
136{
137 if (theme == QQuickUniversalStyle::System)
138 theme = QQuickStylePrivate::isDarkSystemTheme() ? QQuickUniversalStyle::Dark : QQuickUniversalStyle::Light;
139 return theme;
140}
141
142// If no value was inherited from a parent or explicitly set, the "global" values are used.
143// The initial, default values of the globals are hard-coded here, but the environment
144// variables and .conf file override them if specified.
145static QQuickUniversalStyle::Theme GlobalTheme = QQuickUniversalStyle::Light;
146static QRgb GlobalAccent = qquickuniversal_accent_color(accent: QQuickUniversalStyle::Cobalt);
147static QRgb GlobalForeground = qquickuniversal_light_color(role: QQuickUniversalStyle::BaseHigh);
148static QRgb GlobalBackground = qquickuniversal_light_color(role: QQuickUniversalStyle::AltHigh);
149// These represent whether a global foreground/background was set.
150// Each style's m_hasForeground/m_hasBackground are initialized to these values.
151static bool HasGlobalForeground = false;
152static bool HasGlobalBackground = false;
153
154QQuickUniversalStyle::QQuickUniversalStyle(QObject *parent) : QQuickAttachedObject(parent),
155 m_hasForeground(HasGlobalForeground), m_hasBackground(HasGlobalBackground), m_theme(GlobalTheme),
156 m_accent(GlobalAccent), m_foreground(GlobalForeground), m_background(GlobalBackground)
157{
158 init();
159}
160
161QQuickUniversalStyle *QQuickUniversalStyle::qmlAttachedProperties(QObject *object)
162{
163 return new QQuickUniversalStyle(object);
164}
165
166QQuickUniversalStyle::Theme QQuickUniversalStyle::theme() const
167{
168 return m_theme;
169}
170
171void QQuickUniversalStyle::setTheme(Theme theme)
172{
173 theme = qquickuniversal_effective_theme(theme);
174 m_explicitTheme = true;
175 if (m_theme == theme)
176 return;
177
178 m_theme = theme;
179 propagateTheme();
180 emit themeChanged();
181 emit paletteChanged();
182 emit foregroundChanged();
183 emit backgroundChanged();
184}
185
186void QQuickUniversalStyle::inheritTheme(Theme theme)
187{
188 if (m_explicitTheme || m_theme == theme)
189 return;
190
191 m_theme = theme;
192 propagateTheme();
193 emit themeChanged();
194 emit paletteChanged();
195 emit foregroundChanged();
196 emit backgroundChanged();
197}
198
199void QQuickUniversalStyle::propagateTheme()
200{
201 const auto styles = attachedChildren();
202 for (QQuickAttachedObject *child : styles) {
203 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(object: child);
204 if (universal)
205 universal->inheritTheme(theme: m_theme);
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 (QQuickAttachedObject *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 (QQuickAttachedObject *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 (QQuickAttachedObject *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(QQuickAttachedObject *newParent, QQuickAttachedObject *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 = qquickuniversal_effective_theme(theme: 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(accentValue.constData());
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(foregroundValue.constData());
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(backgroundValue.constData());
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.type() == QVariant::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(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

source code of qtquickcontrols2/src/imports/controls/universal/qquickuniversalstyle.cpp