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
44 QT_BEGIN_NAMESPACE
45
qquickuniversal_light_color(QQuickUniversalStyle::SystemColor role)46 static 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
qquickuniversal_dark_color(QQuickUniversalStyle::SystemColor role)77 static 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
qquickuniversal_accent_color(QQuickUniversalStyle::Color accent)108 static 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
qquickuniversal_effective_theme(QQuickUniversalStyle::Theme theme)135 static 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.
145 static QQuickUniversalStyle::Theme GlobalTheme = QQuickUniversalStyle::Light;
146 static QRgb GlobalAccent = qquickuniversal_accent_color(QQuickUniversalStyle::Cobalt);
147 static QRgb GlobalForeground = qquickuniversal_light_color(QQuickUniversalStyle::BaseHigh);
148 static QRgb GlobalBackground = qquickuniversal_light_color(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.
151 static bool HasGlobalForeground = false;
152 static bool HasGlobalBackground = false;
153
QQuickUniversalStyle(QObject * parent)154 QQuickUniversalStyle::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
qmlAttachedProperties(QObject * object)161 QQuickUniversalStyle *QQuickUniversalStyle::qmlAttachedProperties(QObject *object)
162 {
163 return new QQuickUniversalStyle(object);
164 }
165
theme() const166 QQuickUniversalStyle::Theme QQuickUniversalStyle::theme() const
167 {
168 return m_theme;
169 }
170
setTheme(Theme theme)171 void 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
inheritTheme(Theme theme)186 void 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
propagateTheme()199 void QQuickUniversalStyle::propagateTheme()
200 {
201 const auto styles = attachedChildren();
202 for (QQuickAttachedObject *child : styles) {
203 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(child);
204 if (universal)
205 universal->inheritTheme(m_theme);
206 }
207 }
208
resetTheme()209 void QQuickUniversalStyle::resetTheme()
210 {
211 if (!m_explicitTheme)
212 return;
213
214 m_explicitTheme = false;
215 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(attachedParent());
216 inheritTheme(universal ? universal->theme() : GlobalTheme);
217 }
218
accent() const219 QVariant QQuickUniversalStyle::accent() const
220 {
221 return QColor::fromRgba(m_accent);
222 }
223
setAccent(const QVariant & var)224 void QQuickUniversalStyle::setAccent(const QVariant &var)
225 {
226 QRgb accent = 0;
227 if (!variantToRgba(var, "accent", &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
inheritAccent(QRgb accent)239 void 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
propagateAccent()249 void QQuickUniversalStyle::propagateAccent()
250 {
251 const auto styles = attachedChildren();
252 for (QQuickAttachedObject *child : styles) {
253 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(child);
254 if (universal)
255 universal->inheritAccent(m_accent);
256 }
257 }
258
resetAccent()259 void QQuickUniversalStyle::resetAccent()
260 {
261 if (!m_explicitAccent)
262 return;
263
264 m_explicitAccent = false;
265 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(attachedParent());
266 inheritAccent(universal ? universal->m_accent : GlobalAccent);
267 }
268
foreground() const269 QVariant QQuickUniversalStyle::foreground() const
270 {
271 if (m_hasForeground)
272 return QColor::fromRgba(m_foreground);
273 return baseHighColor();
274 }
275
setForeground(const QVariant & var)276 void QQuickUniversalStyle::setForeground(const QVariant &var)
277 {
278 QRgb foreground = 0;
279 if (!variantToRgba(var, "foreground", &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
inheritForeground(QRgb foreground,bool has)292 void 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
propagateForeground()303 void QQuickUniversalStyle::propagateForeground()
304 {
305 const auto styles = attachedChildren();
306 for (QQuickAttachedObject *child : styles) {
307 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(child);
308 if (universal)
309 universal->inheritForeground(m_foreground, m_hasForeground);
310 }
311 }
312
resetForeground()313 void QQuickUniversalStyle::resetForeground()
314 {
315 if (!m_explicitForeground)
316 return;
317
318 m_hasForeground = false;
319 m_explicitForeground = false;
320 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(attachedParent());
321 inheritForeground(universal ? universal->m_foreground : GlobalForeground, universal ? universal->m_hasForeground : false);
322 }
323
background() const324 QVariant QQuickUniversalStyle::background() const
325 {
326 if (m_hasBackground)
327 return QColor::fromRgba(m_background);
328 return altHighColor();
329 }
330
setBackground(const QVariant & var)331 void QQuickUniversalStyle::setBackground(const QVariant &var)
332 {
333 QRgb background = 0;
334 if (!variantToRgba(var, "background", &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
inheritBackground(QRgb background,bool has)347 void 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
propagateBackground()358 void QQuickUniversalStyle::propagateBackground()
359 {
360 const auto styles = attachedChildren();
361 for (QQuickAttachedObject *child : styles) {
362 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(child);
363 if (universal)
364 universal->inheritBackground(m_background, m_hasBackground);
365 }
366 }
367
resetBackground()368 void QQuickUniversalStyle::resetBackground()
369 {
370 if (!m_explicitBackground)
371 return;
372
373 m_hasBackground = false;
374 m_explicitBackground = false;
375 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(attachedParent());
376 inheritBackground(universal ? universal->m_background : GlobalBackground, universal ? universal->m_hasBackground : false);
377 }
378
color(Color color) const379 QColor QQuickUniversalStyle::color(Color color) const
380 {
381 return qquickuniversal_accent_color(color);
382 }
383
altHighColor() const384 QColor QQuickUniversalStyle::altHighColor() const
385 {
386 return systemColor(AltHigh);
387 }
388
altLowColor() const389 QColor QQuickUniversalStyle::altLowColor() const
390 {
391 return systemColor(AltLow);
392 }
393
altMediumColor() const394 QColor QQuickUniversalStyle::altMediumColor() const
395 {
396 return systemColor(AltMedium);
397 }
398
altMediumHighColor() const399 QColor QQuickUniversalStyle::altMediumHighColor() const
400 {
401 return systemColor(AltMediumHigh);
402 }
403
altMediumLowColor() const404 QColor QQuickUniversalStyle::altMediumLowColor() const
405 {
406 return systemColor(AltMediumLow);
407 }
408
baseHighColor() const409 QColor QQuickUniversalStyle::baseHighColor() const
410 {
411 return systemColor(BaseHigh);
412 }
413
baseLowColor() const414 QColor QQuickUniversalStyle::baseLowColor() const
415 {
416 return systemColor(BaseLow);
417 }
418
baseMediumColor() const419 QColor QQuickUniversalStyle::baseMediumColor() const
420 {
421 return systemColor(BaseMedium);
422 }
423
baseMediumHighColor() const424 QColor QQuickUniversalStyle::baseMediumHighColor() const
425 {
426 return systemColor(BaseMediumHigh);
427 }
428
baseMediumLowColor() const429 QColor QQuickUniversalStyle::baseMediumLowColor() const
430 {
431 return systemColor(BaseMediumLow);
432 }
433
chromeAltLowColor() const434 QColor QQuickUniversalStyle::chromeAltLowColor() const
435 {
436 return systemColor(ChromeAltLow);
437 }
438
chromeBlackHighColor() const439 QColor QQuickUniversalStyle::chromeBlackHighColor() const
440 {
441 return systemColor(ChromeBlackHigh);
442 }
443
chromeBlackLowColor() const444 QColor QQuickUniversalStyle::chromeBlackLowColor() const
445 {
446 return systemColor(ChromeBlackLow);
447 }
448
chromeBlackMediumLowColor() const449 QColor QQuickUniversalStyle::chromeBlackMediumLowColor() const
450 {
451 return systemColor(ChromeBlackMediumLow);
452 }
453
chromeBlackMediumColor() const454 QColor QQuickUniversalStyle::chromeBlackMediumColor() const
455 {
456 return systemColor(ChromeBlackMedium);
457 }
458
chromeDisabledHighColor() const459 QColor QQuickUniversalStyle::chromeDisabledHighColor() const
460 {
461 return systemColor(ChromeDisabledHigh);
462 }
463
chromeDisabledLowColor() const464 QColor QQuickUniversalStyle::chromeDisabledLowColor() const
465 {
466 return systemColor(ChromeDisabledLow);
467 }
468
chromeHighColor() const469 QColor QQuickUniversalStyle::chromeHighColor() const
470 {
471 return systemColor(ChromeHigh);
472 }
473
chromeLowColor() const474 QColor QQuickUniversalStyle::chromeLowColor() const
475 {
476 return systemColor(ChromeLow);
477 }
478
chromeMediumColor() const479 QColor QQuickUniversalStyle::chromeMediumColor() const
480 {
481 return systemColor(ChromeMedium);
482 }
483
chromeMediumLowColor() const484 QColor QQuickUniversalStyle::chromeMediumLowColor() const
485 {
486 return systemColor(ChromeMediumLow);
487 }
488
chromeWhiteColor() const489 QColor QQuickUniversalStyle::chromeWhiteColor() const
490 {
491 return systemColor(ChromeWhite);
492 }
493
listLowColor() const494 QColor QQuickUniversalStyle::listLowColor() const
495 {
496 return systemColor(ListLow);
497 }
498
listMediumColor() const499 QColor QQuickUniversalStyle::listMediumColor() const
500 {
501 return systemColor(ListMedium);
502 }
503
systemColor(SystemColor role) const504 QColor QQuickUniversalStyle::systemColor(SystemColor role) const
505 {
506 return QColor::fromRgba(m_theme == QQuickUniversalStyle::Dark ? qquickuniversal_dark_color(role) : qquickuniversal_light_color(role));
507 }
508
attachedParentChange(QQuickAttachedObject * newParent,QQuickAttachedObject * oldParent)509 void QQuickUniversalStyle::attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent)
510 {
511 Q_UNUSED(oldParent);
512 QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(newParent);
513 if (universal) {
514 inheritTheme(universal->theme());
515 inheritAccent(universal->m_accent);
516 inheritForeground(universal->m_foreground, universal->m_hasForeground);
517 inheritBackground(universal->m_background, universal->m_hasBackground);
518 }
519 }
520
521 template <typename Enum>
toEnumValue(const QByteArray & value,bool * ok)522 static Enum toEnumValue(const QByteArray &value, bool *ok)
523 {
524 QMetaEnum enumeration = QMetaEnum::fromType<Enum>();
525 return static_cast<Enum>(enumeration.keyToValue(value, ok));
526 }
527
resolveSetting(const QByteArray & env,const QSharedPointer<QSettings> & settings,const QString & name)528 static QByteArray resolveSetting(const QByteArray &env, const QSharedPointer<QSettings> &settings, const QString &name)
529 {
530 QByteArray value = qgetenv(env);
531 #if QT_CONFIG(settings)
532 if (value.isNull() && !settings.isNull())
533 value = settings->value(name).toByteArray();
534 #endif
535 return value;
536 }
537
initGlobals()538 void QQuickUniversalStyle::initGlobals()
539 {
540 QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("Universal"));
541
542 bool ok = false;
543 QByteArray themeValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_THEME", settings, QStringLiteral("Theme"));
544 Theme themeEnum = toEnumValue<Theme>(themeValue, &ok);
545 if (ok)
546 GlobalTheme = qquickuniversal_effective_theme(themeEnum);
547 else if (!themeValue.isEmpty())
548 qWarning().nospace().noquote() << "Universal: unknown theme value: " << themeValue;
549
550 QByteArray accentValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_ACCENT", settings, QStringLiteral("Accent"));
551 Color accentEnum = toEnumValue<Color>(accentValue, &ok);
552 if (ok) {
553 GlobalAccent = qquickuniversal_accent_color(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("QT_QUICK_CONTROLS_UNIVERSAL_FOREGROUND", settings, QStringLiteral("Foreground"));
563 Color foregroundEnum = toEnumValue<Color>(foregroundValue, &ok);
564 if (ok) {
565 GlobalForeground = qquickuniversal_accent_color(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("QT_QUICK_CONTROLS_UNIVERSAL_BACKGROUND", settings, QStringLiteral("Background"));
578 Color backgroundEnum = toEnumValue<Color>(backgroundValue, &ok);
579 if (ok) {
580 GlobalBackground = qquickuniversal_accent_color(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
variantToRgba(const QVariant & var,const char * name,QRgb * rgba) const593 bool 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(parent()) << "unknown Universal." << name << " value: " << val;
599 return false;
600 }
601 *rgba = qquickuniversal_accent_color(static_cast<Color>(val));
602 } else {
603 int val = QMetaEnum::fromType<Color>().keyToValue(var.toByteArray());
604 if (val != -1) {
605 *rgba = qquickuniversal_accent_color(static_cast<Color>(val));
606 } else {
607 QColor color(var.toString());
608 if (!color.isValid()) {
609 qmlWarning(parent()) << "unknown Universal." << name << " value: " << var.toString();
610 return false;
611 }
612 *rgba = color.rgba();
613 }
614 }
615 return true;
616 }
617
618 QT_END_NAMESPACE
619