Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickmaterialstyle.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
7
8#include <QtCore/qdebug.h>
9#if QT_CONFIG(settings)
10#include <QtCore/qsettings.h>
11#endif
12#include <QtQml/qqmlinfo.h>
13#include <QtQuickControls2/private/qquickstyle_p.h>
14
15#include <algorithm>
16
17QT_BEGIN_NAMESPACE
18
19static const QRgb colors[][14] = {
20 // Red
21 {
22 0xFFFFEBEE, // Shade50
23 0xFFFFCDD2, // Shade100
24 0xFFEF9A9A, // Shade200
25 0xFFE57373, // Shade300
26 0xFFEF5350, // Shade400
27 0xFFF44336, // Shade500
28 0xFFE53935, // Shade600
29 0xFFD32F2F, // Shade700
30 0xFFC62828, // Shade800
31 0xFFB71C1C, // Shade900
32 0xFFFF8A80, // ShadeA100
33 0xFFFF5252, // ShadeA200
34 0xFFFF1744, // ShadeA400
35 0xFFD50000 // ShadeA700
36 },
37 // Pink
38 {
39 0xFFFCE4EC, // Shade50
40 0xFFF8BBD0, // Shade100
41 0xFFF48FB1, // Shade200
42 0xFFF06292, // Shade300
43 0xFFEC407A, // Shade400
44 0xFFE91E63, // Shade500
45 0xFFD81B60, // Shade600
46 0xFFC2185B, // Shade700
47 0xFFAD1457, // Shade800
48 0xFF880E4F, // Shade900
49 0xFFFF80AB, // ShadeA100
50 0xFFFF4081, // ShadeA200
51 0xFFF50057, // ShadeA400
52 0xFFC51162 // ShadeA700
53 },
54 // Purple
55 {
56 0xFFF3E5F5, // Shade50
57 0xFFE1BEE7, // Shade100
58 0xFFCE93D8, // Shade200
59 0xFFBA68C8, // Shade300
60 0xFFAB47BC, // Shade400
61 0xFF9C27B0, // Shade500
62 0xFF8E24AA, // Shade600
63 0xFF7B1FA2, // Shade700
64 0xFF6A1B9A, // Shade800
65 0xFF4A148C, // Shade900
66 0xFFEA80FC, // ShadeA100
67 0xFFE040FB, // ShadeA200
68 0xFFD500F9, // ShadeA400
69 0xFFAA00FF // ShadeA700
70 },
71 // DeepPurple
72 {
73 0xFFEDE7F6, // Shade50
74 0xFFD1C4E9, // Shade100
75 0xFFB39DDB, // Shade200
76 0xFF9575CD, // Shade300
77 0xFF7E57C2, // Shade400
78 0xFF673AB7, // Shade500
79 0xFF5E35B1, // Shade600
80 0xFF512DA8, // Shade700
81 0xFF4527A0, // Shade800
82 0xFF311B92, // Shade900
83 0xFFB388FF, // ShadeA100
84 0xFF7C4DFF, // ShadeA200
85 0xFF651FFF, // ShadeA400
86 0xFF6200EA // ShadeA700
87 },
88 // Indigo
89 {
90 0xFFE8EAF6, // Shade50
91 0xFFC5CAE9, // Shade100
92 0xFF9FA8DA, // Shade200
93 0xFF7986CB, // Shade300
94 0xFF5C6BC0, // Shade400
95 0xFF3F51B5, // Shade500
96 0xFF3949AB, // Shade600
97 0xFF303F9F, // Shade700
98 0xFF283593, // Shade800
99 0xFF1A237E, // Shade900
100 0xFF8C9EFF, // ShadeA100
101 0xFF536DFE, // ShadeA200
102 0xFF3D5AFE, // ShadeA400
103 0xFF304FFE // ShadeA700
104 },
105 // Blue
106 {
107 0xFFE3F2FD, // Shade50
108 0xFFBBDEFB, // Shade100
109 0xFF90CAF9, // Shade200
110 0xFF64B5F6, // Shade300
111 0xFF42A5F5, // Shade400
112 0xFF2196F3, // Shade500
113 0xFF1E88E5, // Shade600
114 0xFF1976D2, // Shade700
115 0xFF1565C0, // Shade800
116 0xFF0D47A1, // Shade900
117 0xFF82B1FF, // ShadeA100
118 0xFF448AFF, // ShadeA200
119 0xFF2979FF, // ShadeA400
120 0xFF2962FF // ShadeA700
121 },
122 // LightBlue
123 {
124 0xFFE1F5FE, // Shade50
125 0xFFB3E5FC, // Shade100
126 0xFF81D4FA, // Shade200
127 0xFF4FC3F7, // Shade300
128 0xFF29B6F6, // Shade400
129 0xFF03A9F4, // Shade500
130 0xFF039BE5, // Shade600
131 0xFF0288D1, // Shade700
132 0xFF0277BD, // Shade800
133 0xFF01579B, // Shade900
134 0xFF80D8FF, // ShadeA100
135 0xFF40C4FF, // ShadeA200
136 0xFF00B0FF, // ShadeA400
137 0xFF0091EA // ShadeA700
138 },
139 // Cyan
140 {
141 0xFFE0F7FA, // Shade50
142 0xFFB2EBF2, // Shade100
143 0xFF80DEEA, // Shade200
144 0xFF4DD0E1, // Shade300
145 0xFF26C6DA, // Shade400
146 0xFF00BCD4, // Shade500
147 0xFF00ACC1, // Shade600
148 0xFF0097A7, // Shade700
149 0xFF00838F, // Shade800
150 0xFF006064, // Shade900
151 0xFF84FFFF, // ShadeA100
152 0xFF18FFFF, // ShadeA200
153 0xFF00E5FF, // ShadeA400
154 0xFF00B8D4 // ShadeA700
155 },
156 // Teal
157 {
158 0xFFE0F2F1, // Shade50
159 0xFFB2DFDB, // Shade100
160 0xFF80CBC4, // Shade200
161 0xFF4DB6AC, // Shade300
162 0xFF26A69A, // Shade400
163 0xFF009688, // Shade500
164 0xFF00897B, // Shade600
165 0xFF00796B, // Shade700
166 0xFF00695C, // Shade800
167 0xFF004D40, // Shade900
168 0xFFA7FFEB, // ShadeA100
169 0xFF64FFDA, // ShadeA200
170 0xFF1DE9B6, // ShadeA400
171 0xFF00BFA5 // ShadeA700
172 },
173 // Green
174 {
175 0xFFE8F5E9, // Shade50
176 0xFFC8E6C9, // Shade100
177 0xFFA5D6A7, // Shade200
178 0xFF81C784, // Shade300
179 0xFF66BB6A, // Shade400
180 0xFF4CAF50, // Shade500
181 0xFF43A047, // Shade600
182 0xFF388E3C, // Shade700
183 0xFF2E7D32, // Shade800
184 0xFF1B5E20, // Shade900
185 0xFFB9F6CA, // ShadeA100
186 0xFF69F0AE, // ShadeA200
187 0xFF00E676, // ShadeA400
188 0xFF00C853 // ShadeA700
189 },
190 // LightGreen
191 {
192 0xFFF1F8E9, // Shade50
193 0xFFDCEDC8, // Shade100
194 0xFFC5E1A5, // Shade200
195 0xFFAED581, // Shade300
196 0xFF9CCC65, // Shade400
197 0xFF8BC34A, // Shade500
198 0xFF7CB342, // Shade600
199 0xFF689F38, // Shade700
200 0xFF558B2F, // Shade800
201 0xFF33691E, // Shade900
202 0xFFCCFF90, // ShadeA100
203 0xFFB2FF59, // ShadeA200
204 0xFF76FF03, // ShadeA400
205 0xFF64DD17 // ShadeA700
206 },
207 // Lime
208 {
209 0xFFF9FBE7, // Shade50
210 0xFFF0F4C3, // Shade100
211 0xFFE6EE9C, // Shade200
212 0xFFDCE775, // Shade300
213 0xFFD4E157, // Shade400
214 0xFFCDDC39, // Shade500
215 0xFFC0CA33, // Shade600
216 0xFFAFB42B, // Shade700
217 0xFF9E9D24, // Shade800
218 0xFF827717, // Shade900
219 0xFFF4FF81, // ShadeA100
220 0xFFEEFF41, // ShadeA200
221 0xFFC6FF00, // ShadeA400
222 0xFFAEEA00 // ShadeA700
223 },
224 // Yellow
225 {
226 0xFFFFFDE7, // Shade50
227 0xFFFFF9C4, // Shade100
228 0xFFFFF59D, // Shade200
229 0xFFFFF176, // Shade300
230 0xFFFFEE58, // Shade400
231 0xFFFFEB3B, // Shade500
232 0xFFFDD835, // Shade600
233 0xFFFBC02D, // Shade700
234 0xFFF9A825, // Shade800
235 0xFFF57F17, // Shade900
236 0xFFFFFF8D, // ShadeA100
237 0xFFFFFF00, // ShadeA200
238 0xFFFFEA00, // ShadeA400
239 0xFFFFD600 // ShadeA700
240 },
241 // Amber
242 {
243 0xFFFFF8E1, // Shade50
244 0xFFFFECB3, // Shade100
245 0xFFFFE082, // Shade200
246 0xFFFFD54F, // Shade300
247 0xFFFFCA28, // Shade400
248 0xFFFFC107, // Shade500
249 0xFFFFB300, // Shade600
250 0xFFFFA000, // Shade700
251 0xFFFF8F00, // Shade800
252 0xFFFF6F00, // Shade900
253 0xFFFFE57F, // ShadeA100
254 0xFFFFD740, // ShadeA200
255 0xFFFFC400, // ShadeA400
256 0xFFFFAB00 // ShadeA700
257 },
258 // Orange
259 {
260 0xFFFFF3E0, // Shade50
261 0xFFFFE0B2, // Shade100
262 0xFFFFCC80, // Shade200
263 0xFFFFB74D, // Shade300
264 0xFFFFA726, // Shade400
265 0xFFFF9800, // Shade500
266 0xFFFB8C00, // Shade600
267 0xFFF57C00, // Shade700
268 0xFFEF6C00, // Shade800
269 0xFFE65100, // Shade900
270 0xFFFFD180, // ShadeA100
271 0xFFFFAB40, // ShadeA200
272 0xFFFF9100, // ShadeA400
273 0xFFFF6D00 // ShadeA700
274 },
275 // DeepOrange
276 {
277 0xFFFBE9E7, // Shade50
278 0xFFFFCCBC, // Shade100
279 0xFFFFAB91, // Shade200
280 0xFFFF8A65, // Shade300
281 0xFFFF7043, // Shade400
282 0xFFFF5722, // Shade500
283 0xFFF4511E, // Shade600
284 0xFFE64A19, // Shade700
285 0xFFD84315, // Shade800
286 0xFFBF360C, // Shade900
287 0xFFFF9E80, // ShadeA100
288 0xFFFF6E40, // ShadeA200
289 0xFFFF3D00, // ShadeA400
290 0xFFDD2C00 // ShadeA700
291 },
292 // Brown
293 {
294 0xFFEFEBE9, // Shade50
295 0xFFD7CCC8, // Shade100
296 0xFFBCAAA4, // Shade200
297 0xFFA1887F, // Shade300
298 0xFF8D6E63, // Shade400
299 0xFF795548, // Shade500
300 0xFF6D4C41, // Shade600
301 0xFF5D4037, // Shade700
302 0xFF4E342E, // Shade800
303 0xFF3E2723, // Shade900
304 0xFF000000, // ShadeA100
305 0xFF000000, // ShadeA200
306 0xFF000000, // ShadeA400
307 0xFF000000 // ShadeA700
308 },
309 // Grey
310 {
311 0xFFFAFAFA, // Shade50
312 0xFFF5F5F5, // Shade100
313 0xFFEEEEEE, // Shade200
314 0xFFE0E0E0, // Shade300
315 0xFFBDBDBD, // Shade400
316 0xFF9E9E9E, // Shade500
317 0xFF757575, // Shade600
318 0xFF616161, // Shade700
319 0xFF424242, // Shade800
320 0xFF212121, // Shade900
321 0xFF000000, // ShadeA100
322 0xFF000000, // ShadeA200
323 0xFF000000, // ShadeA400
324 0xFF000000 // ShadeA700
325 },
326 // BlueGrey
327 {
328 0xFFECEFF1, // Shade50
329 0xFFCFD8DC, // Shade100
330 0xFFB0BEC5, // Shade200
331 0xFF90A4AE, // Shade300
332 0xFF78909C, // Shade400
333 0xFF607D8B, // Shade500
334 0xFF546E7A, // Shade600
335 0xFF455A64, // Shade700
336 0xFF37474F, // Shade800
337 0xFF263238, // Shade900
338 0xFF000000, // ShadeA100
339 0xFF000000, // ShadeA200
340 0xFF000000, // ShadeA400
341 0xFF000000 // ShadeA700
342 }
343};
344
345// If no value was inherited from a parent or explicitly set, the "global" values are used.
346// The initial, default values of the globals are hard-coded here, but the environment
347// variables and .conf file override them if specified.
348static QQuickMaterialStyle::Theme globalTheme = QQuickMaterialStyle::Light;
349static uint globalPrimary = QQuickMaterialStyle::Indigo;
350static uint globalAccent = QQuickMaterialStyle::Pink;
351static uint globalForeground = 0xDD000000; // primaryTextColorLight
352static uint globalBackground = 0xFFFAFAFA; // backgroundColorLight
353// These represent whether a global foreground/background was set.
354// Each style's m_hasForeground/m_hasBackground are initialized to these values.
355static bool hasGlobalForeground = false;
356static bool hasGlobalBackground = false;
357// These represent whether or not the global color value was specified as one of the
358// values that QColor accepts, as opposed to one of the pre-defined colors like Red.
359static bool globalPrimaryCustom = false;
360static bool globalAccentCustom = false;
361static bool globalForegroundCustom = false;
362static bool globalBackgroundCustom = false;
363// This is global because:
364// 1) The theme needs access to it to determine font sizes.
365// 2) There can only be one variant used for the whole application.
366static QQuickMaterialStyle::Variant globalVariant = QQuickMaterialStyle::Normal;
367static const QRgb backgroundColorLight = 0xFFFFFBFE;
368static const QRgb backgroundColorDark = 0xFF1C1B1F;
369static const QRgb dialogColorLight = 0xFFFFFFFF;
370static const QRgb dialogColorDark = 0xFF424242;
371static const QRgb primaryTextColorLight = 0xDD000000;
372static const QRgb primaryTextColorDark = 0xFFFFFFFF;
373static const QRgb secondaryTextColorLight = 0x89000000;
374static const QRgb secondaryTextColorDark = 0xB2FFFFFF;
375static const QRgb hintTextColorLight = 0x60000000;
376static const QRgb hintTextColorDark = 0x4CFFFFFF;
377static const QRgb dividerColorLight = 0x1E000000;
378static const QRgb dividerColorDark = 0x1EFFFFFF;
379static const QRgb iconColorLight = 0x89000000;
380static const QRgb iconColorDark = 0xFFFFFFFF;
381static const QRgb iconDisabledColorLight = 0x42000000;
382static const QRgb iconDisabledColorDark = 0x4CFFFFFF;
383static const QRgb raisedButtonColorLight = 0xFFD6D7D7;
384static const QRgb raisedButtonColorDark = 0x3FCCCCCC;
385static const QRgb raisedButtonDisabledColorLight = dividerColorLight;
386static const QRgb raisedButtonDisabledColorDark = dividerColorDark;
387static const QRgb frameColorLight = hintTextColorLight;
388static const QRgb frameColorDark = hintTextColorDark;
389static const QRgb rippleColorLight = 0x10000000;
390static const QRgb rippleColorDark = 0x20FFFFFF;
391static const QRgb spinBoxDisabledIconColorLight = 0xFFCCCCCC;
392static const QRgb spinBoxDisabledIconColorDark = 0xFF666666;
393static const QRgb sliderDisabledColorLight = 0xFF9E9E9E;
394static const QRgb sliderDisabledColorDark = 0xFF616161;
395/*
396 https://m3.material.io/components/switch/specs#57a434cd-5fcc-4d79-9bff-12b2a9768789
397
398 light / dark
399 surface: #FFFBFE/#1C1B1F
400 on-surface: #1C1B1F/#E6E1E5
401 surface-variant: #E7E0EC/#49454F
402
403 12% = 1E
404 38% = 61
405
406 handle
407
408 unchecked checked
409 disabled #1C1B1F/#E6E1E5 @ 38% (#611C1B1F/#61E6E1E5) #FFFBFE/#1C1B1F @ 100%
410
411 track
412
413 unchecked checked
414 disabled #E7E0EC/#49454F @ 12% (#1EE7E0EC/#1E49454F) #1C1B1F/#E6E1E5 @ 12% (#1E1C1B1F/#1EE6E1E5)
415
416 track outline
417
418 unchecked checked
419 disabled #1C1B1F/#E6E1E5 @ 12% (#1E1C1B1F/#1EE6E1E5) same as track
420*/
421static const QRgb switchUncheckedTrackColorLight = 0xFFE7E0EC;
422static const QRgb switchUncheckedTrackColorDark = 0x49454F;
431static const QRgb textFieldFilledContainerColorLight = 0xFFE7E0EC;
432static const QRgb textFieldFilledContainerColorDark = 0xFF49454F;
433
434static QQuickMaterialStyle::Theme effectiveTheme(QQuickMaterialStyle::Theme theme)
435{
436 if (theme == QQuickMaterialStyle::System)
437 theme = QQuickStylePrivate::isDarkSystemTheme() ? QQuickMaterialStyle::Dark : QQuickMaterialStyle::Light;
438 return theme;
439}
440
441QQuickMaterialStyle::QQuickMaterialStyle(QObject *parent) : QQuickAttachedPropertyPropagator(parent),
442 m_customPrimary(globalPrimaryCustom),
443 m_customAccent(globalAccentCustom),
444 m_customForeground(globalForegroundCustom),
445 m_customBackground(globalBackgroundCustom),
446 m_hasForeground(hasGlobalForeground),
447 m_hasBackground(hasGlobalBackground),
448 m_systemTheme(globalTheme == System),
449 m_theme(effectiveTheme(globalTheme)),
450 m_primary(globalPrimary),
451 m_accent(globalAccent),
452 m_foreground(globalForeground),
453 m_background(globalBackground)
454{
455 QQuickAttachedPropertyPropagator::initialize();
456}
457
458QQuickMaterialStyle *QQuickMaterialStyle::qmlAttachedProperties(QObject *object)
459{
460 return new QQuickMaterialStyle(object);
461}
462
463QQuickMaterialStyle::Theme QQuickMaterialStyle::theme() const
464{
465 return m_theme;
466}
467
468void QQuickMaterialStyle::setTheme(Theme theme)
469{
470 m_explicitTheme = true;
471
472 // If theme is System: m_theme is set to system's theme (Dark/Light)
473 // and m_systemTheme is set to true.
474 // If theme is Dark/Light: m_theme is set to the input theme (Dark/Light)
475 // and m_systemTheme is set to false.
476 const bool systemThemeChanged = (m_systemTheme != (theme == System));
477 // Check m_theme and m_systemTheme are changed.
478 if ((m_theme == effectiveTheme(theme)) && !systemThemeChanged)
479 return;
480
481 m_theme = effectiveTheme(theme);
482 m_systemTheme = (theme == System);
483 if (systemThemeChanged) {
484 if (m_systemTheme)
485 QQuickMaterialTheme::registerSystemStyle(this);
486 else
487 QQuickMaterialTheme::unregisterSystemStyle(this);
488 }
489
490 propagateTheme();
491 themeChange();
492 if (!m_customAccent)
493 accentChange();
494 if (!m_customBackground)
495 backgroundChange();
496 if (!m_customForeground)
497 foregroundChange();
498}
499
500void QQuickMaterialStyle::inheritTheme(Theme theme)
501{
502 const bool systemThemeChanged = (m_systemTheme != (theme == System));
503 const bool themeChanged = systemThemeChanged || (m_theme != effectiveTheme(theme));
504 if (m_explicitTheme || !themeChanged)
505 return;
506
507 m_theme = effectiveTheme(theme);
508 m_systemTheme = (theme == System);
509
510 propagateTheme();
511 themeChange();
512 if (!m_customAccent)
513 accentChange();
514 if (!m_customBackground)
515 backgroundChange();
516 if (!m_customForeground)
517 foregroundChange();
518}
519
520void QQuickMaterialStyle::propagateTheme()
521{
522 const auto styles = attachedChildren();
523 for (QQuickAttachedPropertyPropagator *child : styles) {
524 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
525 if (material)
526 // m_theme is the effective theme, either Dark or Light.
527 // m_systemTheme indicates whether the theme is set by
528 // the system (true) or manually (false).
529 material->inheritTheme(m_systemTheme ? System : m_theme);
530 }
531}
532
533void QQuickMaterialStyle::resetTheme()
534{
535 if (!m_explicitTheme)
536 return;
537
538 m_explicitTheme = false;
539 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(attachedParent());
540 inheritTheme(material ? material->theme() : globalTheme);
541}
542
543void QQuickMaterialStyle::themeChange()
544{
545 emit themeChanged();
546 emit themeOrAccentChanged();
547 emit primaryHighlightedTextColor();
548 emit dialogColorChanged();
549 emit tooltipColorChanged();
550 emit toolBarColorChanged();
551 emit toolTextColorChanged();
552}
553
554QVariant QQuickMaterialStyle::primary() const
555{
556 return primaryColor();
557}
558
559void QQuickMaterialStyle::setPrimary(const QVariant &var)
560{
561 QRgb primary = 0;
562 bool custom = false;
563 if (!variantToRgba(var, "primary", &primary, &custom))
564 return;
565
566 m_explicitPrimary = true;
567 if (m_primary == primary)
568 return;
569
570 m_customPrimary = custom;
571 m_primary = primary;
572 propagatePrimary();
573 primaryChange();
574}
575
576void QQuickMaterialStyle::inheritPrimary(uint primary, bool custom)
577{
578 if (m_explicitPrimary || m_primary == primary)
579 return;
580
581 m_customPrimary = custom;
582 m_primary = primary;
583 propagatePrimary();
584 primaryChange();
585}
586
587void QQuickMaterialStyle::propagatePrimary()
588{
589 const auto styles = attachedChildren();
590 for (QQuickAttachedPropertyPropagator *child : styles) {
591 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
592 if (material)
593 material->inheritPrimary(m_primary, m_customPrimary);
594 }
595}
596
597void QQuickMaterialStyle::resetPrimary()
598{
599 if (!m_explicitPrimary)
600 return;
601
602 m_customPrimary = false;
603 m_explicitPrimary = false;
604 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(attachedParent());
605 if (material)
606 inheritPrimary(material->m_primary, material->m_customPrimary);
607 else
608 inheritPrimary(globalPrimary, false);
609}
610
611void QQuickMaterialStyle::primaryChange()
612{
613 emit primaryChanged();
614 emit toolBarColorChanged();
615 emit toolTextColorChanged();
616}
617
618QVariant QQuickMaterialStyle::accent() const
619{
620 return accentColor();
621}
622
623void QQuickMaterialStyle::setAccent(const QVariant &var)
624{
625 QRgb accent = 0;
626 bool custom = false;
627 if (!variantToRgba(var, "accent", &accent, &custom))
628 return;
629
630 m_explicitAccent = true;
631 if (m_accent == accent)
632 return;
633
634 m_customAccent = custom;
635 m_accent = accent;
636 propagateAccent();
637 accentChange();
638}
639
640void QQuickMaterialStyle::inheritAccent(uint accent, bool custom)
641{
642 if (m_explicitAccent || m_accent == accent)
643 return;
644
645 m_customAccent = custom;
646 m_accent = accent;
647 propagateAccent();
648 accentChange();
649}
650
651void QQuickMaterialStyle::propagateAccent()
652{
653 const auto styles = attachedChildren();
654 for (QQuickAttachedPropertyPropagator *child : styles) {
655 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
656 if (material)
657 material->inheritAccent(m_accent, m_customAccent);
658 }
659}
660
661void QQuickMaterialStyle::resetAccent()
662{
663 if (!m_explicitAccent)
664 return;
665
666 m_customAccent = false;
667 m_explicitAccent = false;
668 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(attachedParent());
669 if (material)
670 inheritAccent(material->m_accent, material->m_customAccent);
671 else
672 inheritAccent(globalAccent, false);
673}
674
675void QQuickMaterialStyle::accentChange()
676{
677 emit accentChanged();
678 emit themeOrAccentChanged();
679}
680
681QVariant QQuickMaterialStyle::foreground() const
682{
683 if (!m_hasForeground) {
684 if (!m_customBackground && m_background == m_primary) {
685 return toolTextColor();
686 }
687 return QColor::fromRgba(m_theme == Light ? primaryTextColorLight : primaryTextColorDark);
688 }
689 if (m_customForeground)
690 return QColor::fromRgba(m_foreground);
691 if (m_foreground > BlueGrey)
692 return QColor();
693 return QColor::fromRgba(colors[m_foreground][Shade500]);
694}
695
696void QQuickMaterialStyle::setForeground(const QVariant &var)
697{
698 QRgb foreground = 0;
699 bool custom = false;
700 if (!variantToRgba(var, "foreground", &foreground, &custom))
701 return;
702
703 // Reset the foreground if the new color matches the current theme's default.
704 // This allows the color to update dynamically when the theme changes.
705 if (!hasGlobalForeground) {
706 const QRgb themeDefault = (m_theme == Light ? primaryTextColorLight : primaryTextColorDark);
707 if (foreground == themeDefault) {
708 resetForeground();
709 return;
710 }
711 }
712
713 m_explicitForeground = true;
714 if (m_hasForeground && m_foreground == foreground)
715 return;
716
717 m_hasForeground = true;
718 m_customForeground = custom;
719 m_foreground = foreground;
720 propagateForeground();
721 foregroundChange();
722}
723
724void QQuickMaterialStyle::inheritForeground(uint foreground, bool custom, bool has)
725{
726 if (m_explicitForeground || (m_hasForeground == has && m_foreground == foreground))
727 return;
728
729 m_hasForeground = has;
730 m_customForeground = custom;
731 m_foreground = foreground;
732 propagateForeground();
733 foregroundChange();
734}
735
736void QQuickMaterialStyle::propagateForeground()
737{
738 const auto styles = attachedChildren();
739 for (QQuickAttachedPropertyPropagator *child : styles) {
740 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
741 if (material)
742 material->inheritForeground(m_foreground, m_customForeground, m_hasForeground);
743 }
744}
745
746void QQuickMaterialStyle::resetForeground()
747{
748 if (!m_explicitForeground)
749 return;
750
751 m_explicitForeground = false;
752 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(attachedParent());
753 inheritForeground(material ? material->m_foreground : globalForeground,
754 material ? material->m_customForeground : globalForegroundCustom,
755 material ? material->m_hasForeground : false);
756}
757
758void QQuickMaterialStyle::foregroundChange()
759{
760 emit foregroundChanged();
761 emit primaryHighlightedTextColorChanged();
762}
763
764QVariant QQuickMaterialStyle::background() const
765{
766 return backgroundColor();
767}
768
769void QQuickMaterialStyle::setBackground(const QVariant &var)
770{
771 QRgb background = 0;
772 bool custom = false;
773 if (!variantToRgba(var, "background", &background, &custom))
774 return;
775
776 // Reset the background if the new color matches the current theme's default.
777 // This allows the color to update dynamically when the theme changes.
778 if (!hasGlobalBackground) {
779 const QRgb themeDefault = (m_theme == Light ? backgroundColorLight : backgroundColorDark);
780 if (background == themeDefault) {
781 resetBackground();
782 return;
783 }
784 }
785
786 // Do not treat the background as custom if it resolves to the same RGB as the
787 // current primary color. This allows the foreground color to map to
788 // toolTextColor, which is resolved dynamically based on the primary color.
789 if (custom && background == primaryColor().rgb()) {
790 background = m_primary;
791 custom = false;
792 }
793
794 m_explicitBackground = true;
795 if (m_hasBackground && m_background == background)
796 return;
797 m_hasBackground = true;
798 m_customBackground = custom;
799 m_background = background;
800 propagateBackground();
801 backgroundChange();
802
803 // Foreground color depends on the background color if the background is set to primary.
804 if (!m_customBackground && m_background == m_primary)
805 foregroundChange();
806}
807
808void QQuickMaterialStyle::inheritBackground(uint background, bool custom, bool has)
809{
810 if (m_explicitBackground || (m_hasBackground == has && m_background == background))
811 return;
812
813 m_hasBackground = has;
814 m_customBackground = custom;
815 m_background = background;
816 propagateBackground();
817 backgroundChange();
818 if (!m_customBackground && m_background == m_primary)
819 foregroundChange();
820}
821
822void QQuickMaterialStyle::propagateBackground()
823{
824 const auto styles = attachedChildren();
825 for (QQuickAttachedPropertyPropagator *child : styles) {
826 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
827 if (material)
828 material->inheritBackground(m_background, m_customBackground, m_hasBackground);
829 }
830}
831
832void QQuickMaterialStyle::resetBackground()
833{
834 if (!m_explicitBackground)
835 return;
836
837 m_explicitBackground = false;
838 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(attachedParent());
839 inheritBackground(material ? material->m_background : globalBackground,
840 material ? material->m_customBackground : globalBackgroundCustom,
841 material ? material->m_hasBackground : false);
842}
843
844void QQuickMaterialStyle::backgroundChange()
845{
846 emit backgroundChanged();
847 emit dialogColorChanged();
848 emit tooltipColorChanged();
849 emit toolBarColorChanged();
850}
851
852int QQuickMaterialStyle::elevation() const
853{
854 return m_elevation;
855}
856
857void QQuickMaterialStyle::setElevation(int elevation)
858{
859 if (m_elevation == elevation)
860 return;
861
862 m_elevation = elevation;
863 elevationChange();
864}
865
866void QQuickMaterialStyle::resetElevation()
867{
868 setElevation(0);
869}
870
871void QQuickMaterialStyle::elevationChange()
872{
873 emit elevationChanged();
874}
875
876QQuickMaterialStyle::RoundedScale QQuickMaterialStyle::roundedScale() const
877{
878 return m_roundedScale;
879}
880
881void QQuickMaterialStyle::setRoundedScale(RoundedScale roundedScale)
882{
883 if (m_roundedScale == roundedScale)
884 return;
885
886 m_roundedScale = roundedScale;
887 emit roundedScaleChanged();
888}
889
890void QQuickMaterialStyle::resetRoundedScale()
891{
892 setRoundedScale(RoundedScale::NotRounded);
893}
894
895QQuickMaterialStyle::ContainerStyle QQuickMaterialStyle::containerStyle() const
896{
897 return m_containerStyle;
898}
899
900void QQuickMaterialStyle::setContainerStyle(ContainerStyle containerStyle)
901{
902 if (m_containerStyle == containerStyle)
903 return;
904
905 m_containerStyle = containerStyle;
906 emit containerStyleChanged();
907}
908
909void QQuickMaterialStyle::resetContainerStyle()
910{
911 setContainerStyle(ContainerStyle::Filled);
912}
913
914QColor QQuickMaterialStyle::primaryColor() const
915{
916 if (m_customPrimary)
917 return QColor::fromRgba(m_primary);
918 if (m_primary > BlueGrey)
919 return QColor();
920 return colors[m_primary][Shade500];
921}
922
923QColor QQuickMaterialStyle::accentColor(Shade shade) const
924{
925 if (m_customAccent)
926 return shade == themeShade() ? QColor::fromRgba(m_accent)
927 : this->shade(QColor::fromRgba(m_accent), shade);
928 if (m_accent > BlueGrey)
929 return QColor();
930 return colors[m_accent][shade];
931}
932
933QColor QQuickMaterialStyle::accentColor() const
934{
935 return accentColor(themeShade());
936}
937
938QColor QQuickMaterialStyle::backgroundColor(Shade shade) const
939{
940 if (!m_hasBackground)
941 return QColor::fromRgba(m_theme == Light ? backgroundColorLight : backgroundColorDark);
942 // The application bars (such as ToolBar) set the background color from the primary color,
943 // and in that case, it's better to validate with the custom primary and use it accordingly.
944 if (m_customBackground || (m_customPrimary && m_background == m_primary))
945 return shade == themeShade() ? QColor::fromRgba(m_background)
946 : this->shade(QColor::fromRgba(m_background), shade);
947 if (m_background > BlueGrey)
948 return QColor();
949 return colors[m_background][shade];
950}
951
952QColor QQuickMaterialStyle::backgroundColor() const
953{
954 return backgroundColor(themeShade());
955}
956
957QColor QQuickMaterialStyle::primaryTextColor() const
958{
959 return QColor::fromRgba(m_theme == Light ? primaryTextColorLight : primaryTextColorDark);
960}
961
962QColor QQuickMaterialStyle::primaryHighlightedTextColor() const
963{
964 if (m_explicitForeground)
965 return primaryTextColor();
966 return QColor::fromRgba(primaryTextColorDark);
967}
968
969QColor QQuickMaterialStyle::secondaryTextColor() const
970{
971 return QColor::fromRgba(m_theme == Light ? secondaryTextColorLight : secondaryTextColorDark);
972}
973
974QColor QQuickMaterialStyle::hintTextColor() const
975{
976 return QColor::fromRgba(m_theme == Light ? hintTextColorLight : hintTextColorDark);
977}
978
979QColor QQuickMaterialStyle::textSelectionColor() const
980{
981 QColor color = accentColor();
982 color.setAlphaF(0.4f);
983 return color;
984}
985
986QColor QQuickMaterialStyle::dropShadowColor() const
987{
988 return QColor::fromRgba(0x40000000);
989}
990
991QColor QQuickMaterialStyle::dividerColor() const
992{
993 return QColor::fromRgba(m_theme == Light ? dividerColorLight : dividerColorDark);
994}
995
996QColor QQuickMaterialStyle::iconColor() const
997{
998 return QColor::fromRgba(m_theme == Light ? iconColorLight : iconColorDark);
999}
1000
1001QColor QQuickMaterialStyle::iconDisabledColor() const
1002{
1003 return QColor::fromRgba(m_theme == Light ? iconDisabledColorLight : iconDisabledColorDark);
1004}
1005
1006QColor QQuickMaterialStyle::buttonColor(Theme theme, const QVariant &background, const QVariant &accent,
1007 bool enabled, bool flat, bool highlighted, bool checked) const
1008{
1009 if (!enabled && !flat) {
1010 return QColor::fromRgba(m_theme == Light
1011 ? raisedButtonDisabledColorLight : raisedButtonDisabledColorDark);
1012 }
1013
1014 // We don't use theme (and other arguments) here even though we pass it in, as it's
1015 // simpler to just re-use themeShade. We still need the arguments because they allow
1016 // us to be re-called whenever they change.
1017 Shade shade = themeShade();
1018 Q_UNUSED(theme);
1019 Q_UNUSED(background);
1020 Q_UNUSED(accent);
1021
1022 QColor color = Qt::transparent;
1023
1024 if (m_explicitBackground) {
1025 color = backgroundColor(shade);
1026 } else if (highlighted) {
1027 if (m_theme == Light) {
1028 color = accentColor(shade);
1029 if (checked)
1030 color = color.lighter();
1031 } else {
1032 // A highlighted + checked button should become darker.
1033 color = accentColor(checked ? Shade100 : shade);
1034 }
1035 // Flat, highlighted buttons need to have a semi-transparent background,
1036 // otherwise the text won't be visible.
1037 if (flat)
1038 color.setAlphaF(0.25);
1039 } else if (!flat) {
1040 // Even if the elevation is zero, it should still have a background if it's not flat.
1041 color = QColor::fromRgba(m_theme == Light ? raisedButtonColorLight
1042 : raisedButtonColorDark);
1043 }
1044
1045 return color;
1046}
1047
1048QColor QQuickMaterialStyle::frameColor() const
1049{
1050 return QColor::fromRgba(m_theme == Light ? frameColorLight : frameColorDark);
1051}
1052
1053QColor QQuickMaterialStyle::rippleColor() const
1054{
1055 return QColor::fromRgba(m_theme == Light ? rippleColorLight : rippleColorDark);
1056}
1057
1058QColor QQuickMaterialStyle::highlightedRippleColor() const
1059{
1060 QColor pressColor = accentColor();
1061 pressColor.setAlpha(m_theme == Light ? 30 : 50);
1062 return pressColor;
1063}
1064
1065QColor QQuickMaterialStyle::switchUncheckedTrackColor() const
1066{
1067 return QColor::fromRgba(m_theme == Light ? switchUncheckedTrackColorLight : switchUncheckedTrackColorDark);
1068}
1069
1070QColor QQuickMaterialStyle::switchCheckedTrackColor() const
1071{
1072 return accentColor(m_theme == Light ? themeShade() : Shade100);
1073}
1074
1075QColor QQuickMaterialStyle::switchDisabledUncheckedTrackColor() const
1076{
1077 return QColor::fromRgba(m_theme == Light
1078 ? switchDisabledUncheckedTrackColorLight : switchDisabledUncheckedTrackColorDark);
1079}
1080
1081QColor QQuickMaterialStyle::switchDisabledCheckedTrackColor() const
1082{
1083 return QColor::fromRgba(m_theme == Light
1084 ? switchDisabledCheckedTrackColorLight : switchDisabledCheckedTrackColorDark);
1085}
1086
1087QColor QQuickMaterialStyle::switchDisabledUncheckedTrackBorderColor() const
1088{
1089 return QColor::fromRgba(m_theme == Light
1090 ? switchDisabledUncheckedTrackBorderColorLight : switchDisabledUncheckedTrackBorderColorDark);
1091}
1092
1093QColor QQuickMaterialStyle::switchUncheckedHandleColor() const
1094{
1095 return m_theme == Light ? color(Grey, Shade600) : color(Grey, Shade400);
1096}
1097
1098QColor QQuickMaterialStyle::switchUncheckedHoveredHandleColor() const
1099{
1100 const QColor color = switchUncheckedHandleColor();
1101 return m_theme == Light ? color.darker(140) : color.lighter(120);
1102}
1103
1104QColor QQuickMaterialStyle::switchCheckedHandleColor() const
1105{
1106 return m_theme == Light ? QColor::fromRgb(0xFFFFFF) : accentColor(Shade800);
1107}
1108
1109QColor QQuickMaterialStyle::switchDisabledUncheckedHandleColor() const
1110{
1111 if (m_theme == Light)
1112 return QColor::fromRgba(0x611C1B1F);
1113
1114 QColor darkHandleColor = color(Grey, Shade800);
1115 darkHandleColor.setAlphaF(0.38f);
1116 return darkHandleColor;
1117}
1118
1119QColor QQuickMaterialStyle::switchDisabledCheckedHandleColor() const
1120{
1121 return QColor::fromRgb(m_theme == Light ? 0xFFFBFE : 0x1C1B1F);
1122}
1123
1124QColor QQuickMaterialStyle::switchDisabledCheckedIconColor() const
1125{
1126 return QColor::fromRgba(m_theme == Light ? 0x611C1B1F : 0x61E6E1E5);
1127}
1128
1129QColor QQuickMaterialStyle::switchDisabledUncheckedIconColor() const
1130{
1131 return QColor::fromRgba(m_theme == Light
1132 ? switchDisabledUncheckedIconColorLight : switchDisabledUncheckedIconColorDark);
1133}
1134
1135QColor QQuickMaterialStyle::scrollBarColor() const
1136{
1137 return QColor::fromRgba(m_theme == Light ? 0x40000000 : 0x40FFFFFF);
1138}
1139
1140QColor QQuickMaterialStyle::scrollBarHoveredColor() const
1141{
1142 return QColor::fromRgba(m_theme == Light ? 0x60000000 : 0x60FFFFFF);
1143}
1144
1145QColor QQuickMaterialStyle::scrollBarPressedColor() const
1146{
1147 return QColor::fromRgba(m_theme == Light ? 0x80000000 : 0x80FFFFFF);
1148}
1149
1150QColor QQuickMaterialStyle::dialogColor() const
1151{
1152 if (m_hasBackground)
1153 return backgroundColor();
1154 return QColor::fromRgba(m_theme == Light ? dialogColorLight : dialogColorDark);
1155}
1156
1157QColor QQuickMaterialStyle::backgroundDimColor() const
1158{
1159 return QColor::fromRgba(m_theme == Light ? 0x99303030 : 0x99fafafa);
1160}
1161
1162QColor QQuickMaterialStyle::listHighlightColor() const
1163{
1164 return QColor::fromRgba(m_theme == Light ? 0x1e000000 : 0x1effffff);
1165}
1166
1167QColor QQuickMaterialStyle::tooltipColor() const
1168{
1169 if (m_explicitBackground)
1170 return backgroundColor();
1171 return color(Grey, Shade700);
1172}
1173
1174QColor QQuickMaterialStyle::toolBarColor() const
1175{
1176 if (m_explicitBackground)
1177 return backgroundColor();
1178 return primaryColor();
1179}
1180
1181QColor QQuickMaterialStyle::toolTextColor() const
1182{
1183 if (m_hasForeground || m_customPrimary)
1184 return primaryTextColor();
1185
1186 switch (m_primary) {
1187 case Red:
1188 case Pink:
1189 case Purple:
1190 case DeepPurple:
1191 case Indigo:
1192 case Blue:
1193 case Teal:
1194 case DeepOrange:
1195 case Brown:
1196 case BlueGrey:
1197 return QColor::fromRgba(primaryTextColorDark);
1198
1199 case LightBlue:
1200 case Cyan:
1201 case Green:
1202 case LightGreen:
1203 case Lime:
1204 case Yellow:
1205 case Amber:
1206 case Orange:
1207 case Grey:
1208 return QColor::fromRgba(primaryTextColorLight);
1209
1210 default:
1211 break;
1212 }
1213
1214 return primaryTextColor();
1215}
1216
1217QColor QQuickMaterialStyle::spinBoxDisabledIconColor() const
1218{
1219 return QColor::fromRgba(m_theme == Light ? spinBoxDisabledIconColorLight : spinBoxDisabledIconColorDark);
1220}
1221
1222QColor QQuickMaterialStyle::sliderDisabledColor() const
1223{
1224 return QColor::fromRgba(m_theme == Light ? sliderDisabledColorLight : sliderDisabledColorDark);
1225}
1226
1227QColor QQuickMaterialStyle::textFieldFilledContainerColor() const
1228{
1229 return QColor::fromRgba(m_theme == Light ? textFieldFilledContainerColorLight : textFieldFilledContainerColorDark);
1230}
1231
1232QColor QQuickMaterialStyle::color(QQuickMaterialStyle::Color color, QQuickMaterialStyle::Shade shade) const
1233{
1234 int count = sizeof(colors) / sizeof(colors[0]);
1235 if (color < 0 || color >= count)
1236 return QColor();
1237
1238 count = sizeof(colors[0]) / sizeof(colors[0][0]);
1239 if (shade < 0 || shade >= count)
1240 return QColor();
1241
1242 return colors[color][shade];
1243}
1244
1245static QColor lighterShade(const QColor &color, qreal amount)
1246{
1247 QColor hsl = color.toHsl();
1248 hsl.setHslF(hsl.hueF(), hsl.saturationF(),
1249 std::clamp(hsl.lightnessF() + amount, qreal(0.0), qreal(1.0)), color.alphaF());
1250 return hsl.convertTo(color.spec());
1251}
1252
1253static QColor darkerShade(const QColor &color, qreal amount)
1254{
1255 QColor hsl = color.toHsl();
1256 hsl.setHslF(hsl.hueF(), hsl.saturationF(),
1257 std::clamp(hsl.lightnessF() - amount, qreal(0.0), qreal(1.0)), color.alphaF());
1258 return hsl.convertTo(color.spec());
1259}
1260
1261QQuickMaterialStyle::Shade QQuickMaterialStyle::themeShade() const
1262{
1263 return m_theme == Light ? Shade500 : Shade200;
1264}
1265
1266/*
1267 * The following lightness values originate from the Material Design Color Generator project.
1268 *
1269 * The MIT License (MIT)
1270 *
1271 * Copyright (c) 2015 mbitson
1272 *
1273 * Permission is hereby granted, free of charge, to any person obtaining a copy
1274 * of this software and associated documentation files (the "Software"), to deal
1275 * in the Software without restriction, including without limitation the rights
1276 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1277 * copies of the Software, and to permit persons to whom the Software is
1278 * furnished to do so, subject to the following conditions:
1279 *
1280 * The above copyright notice and this permission notice shall be included in all
1281 * copies or substantial portions of the Software.
1282 *
1283 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1284 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1285 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1286 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1287 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1288 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1289 * SOFTWARE.
1290 */
1291
1292// Returns the same color, if shade == themeShade()
1293QColor QQuickMaterialStyle::shade(const QColor &color, Shade shade) const
1294{
1295 switch (shade) {
1296 case Shade50:
1297 return lighterShade(color, m_theme == Light ? 0.52 : 0.26);
1298 case Shade100:
1299 return lighterShade(color, m_theme == Light ? 0.37 : 0.11);
1300 case Shade200:
1301 return m_theme == Light ? lighterShade(color, 0.26) : color;
1302 case Shade300:
1303 return m_theme == Light ? lighterShade(color, 0.12) : darkerShade(color, 0.14);
1304 case Shade400:
1305 return m_theme == Light ? lighterShade(color, 0.06) : darkerShade(color, 0.20);
1306 case Shade500:
1307 return m_theme == Light ? color : darkerShade(color, 0.26);
1308 case Shade600:
1309 return darkerShade(color, m_theme == Light ? 0.06 : 0.32);
1310 case Shade700:
1311 return darkerShade(color, m_theme == Light ? 0.12 : 0.38);
1312 case Shade800:
1313 return darkerShade(color, m_theme == Light ? 0.18 : 0.44);
1314 case Shade900:
1315 return darkerShade(color, m_theme == Light ? 0.24 : 0.50);
1316 case ShadeA100:
1317 return lighterShade(color, m_theme == Light ? 0.54 : 0.28);
1318 case ShadeA200:
1319 return lighterShade(color, m_theme == Light ? 0.37 : 0.11);
1320 case ShadeA400:
1321 return m_theme == Light ? lighterShade(color, 0.06) : darkerShade(color, 0.20);
1322 case ShadeA700:
1323 return darkerShade(color, m_theme == Light ? 0.12 : 0.38);
1324 default:
1325 Q_UNREACHABLE_RETURN(QColor());
1326 }
1327}
1328
1329int QQuickMaterialStyle::touchTarget() const
1330{
1331 // https://material.io/guidelines/components/buttons.html#buttons-style
1332 return globalVariant == Dense ? 44 : 48;
1333}
1334
1335int QQuickMaterialStyle::buttonVerticalPadding() const
1336{
1337 return globalVariant == Dense ? 10 : 14;
1338}
1339
1340// https://m3.material.io/components/buttons/specs#256326ad-f934-40e7-b05f-0bcb41aa4382
1341int QQuickMaterialStyle::buttonLeftPadding(bool flat, bool hasIcon) const
1342{
1343 static const int noIconPadding = globalVariant == Dense ? 12 : 24;
1344 static const int iconPadding = globalVariant == Dense ? 8 : 16;
1345 static const int flatPadding = globalVariant == Dense ? 6 : 12;
1346 return !flat ? (!hasIcon ? noIconPadding : iconPadding) : flatPadding;
1347}
1348
1349int QQuickMaterialStyle::buttonRightPadding(bool flat, bool hasIcon, bool hasText) const
1350{
1351 static const int noTextPadding = globalVariant == Dense ? 8 : 16;
1352 static const int textPadding = globalVariant == Dense ? 12 : 24;
1353 static const int flatNoIconPadding = globalVariant == Dense ? 6 : 12;
1354 static const int flatNoTextPadding = globalVariant == Dense ? 6 : 12;
1355 static const int flatTextPadding = globalVariant == Dense ? 8 : 16;
1356 return !flat
1357 ? (!hasText ? noTextPadding : textPadding)
1358 : (!hasIcon ? flatNoIconPadding : (!hasText ? flatNoTextPadding : flatTextPadding));
1359}
1360
1361int QQuickMaterialStyle::buttonHeight() const
1362{
1363 // https://m3.material.io/components/buttons/specs#256326ad-f934-40e7-b05f-0bcb41aa4382
1364 return globalVariant == Dense ? 32 : 40;
1365}
1366
1367int QQuickMaterialStyle::delegateHeight() const
1368{
1369 // https://material.io/guidelines/components/lists.html#lists-specs
1370 return globalVariant == Dense ? 40 : 48;
1371}
1372
1373int QQuickMaterialStyle::dialogButtonBoxHeight() const
1374{
1375 return globalVariant == Dense ? 48 : 52;
1376}
1377
1378int QQuickMaterialStyle::dialogTitleFontPixelSize() const
1379{
1380 return globalVariant == Dense ? 16 : 24;
1381}
1382
1383// https://m3.material.io/components/dialogs/specs#6771d107-624e-47cc-b6d8-2b7b620ba2f1
1384QQuickMaterialStyle::RoundedScale QQuickMaterialStyle::dialogRoundedScale() const
1385{
1386 return globalVariant == Dense
1387 ? QQuickMaterialStyle::RoundedScale::LargeScale
1388 : QQuickMaterialStyle::RoundedScale::ExtraLargeScale;
1389}
1390
1391int QQuickMaterialStyle::frameVerticalPadding() const
1392{
1393 return globalVariant == Dense ? 8 : 12;
1394}
1395
1396int QQuickMaterialStyle::menuItemHeight() const
1397{
1398 // https://material.io/guidelines/components/menus.html#menus-simple-menus
1399 return globalVariant == Dense ? 32 : 48;
1400}
1401
1402int QQuickMaterialStyle::menuItemVerticalPadding() const
1403{
1404 return globalVariant == Dense ? 8 : 12;
1405}
1406
1407int QQuickMaterialStyle::switchIndicatorWidth() const
1408{
1409 return globalVariant == Dense ? 40 : 52;
1410}
1411
1412int QQuickMaterialStyle::switchIndicatorHeight() const
1413{
1414 return globalVariant == Dense ? 22 : 32;
1415}
1416
1417int QQuickMaterialStyle::switchNormalHandleHeight() const
1418{
1419 return globalVariant == Dense ? 10 : 16;
1420}
1421
1422int QQuickMaterialStyle::switchCheckedHandleHeight() const
1423{
1424 return globalVariant == Dense ? 16 : 24;
1425}
1426
1427int QQuickMaterialStyle::switchLargestHandleHeight() const
1428{
1429 return globalVariant == Dense ? 18 : 28;
1430}
1431
1432int QQuickMaterialStyle::switchDelegateVerticalPadding() const
1433{
1434 // SwitchDelegate's indicator is much larger than the others due to the shadow,
1435 // so we must reduce its padding to ensure its implicitHeight is 40 when dense.
1436 return globalVariant == Dense ? 4 : 8;
1437}
1438
1439int QQuickMaterialStyle::textFieldHeight() const
1440{
1441 // filled: https://m3.material.io/components/text-fields/specs#8c032848-e442-46df-b25d-28f1315f234b
1442 // outlined: https://m3.material.io/components/text-fields/specs#605e24f1-1c1f-4c00-b385-4bf50733a5ef
1443 return globalVariant == Dense ? 44 : 56;
1444}
1445int QQuickMaterialStyle::textFieldHorizontalPadding() const
1446{
1447 return globalVariant == Dense ? 12 : 16;
1448}
1449int QQuickMaterialStyle::textFieldVerticalPadding() const
1450{
1451 return globalVariant == Dense ? 4 : 8;
1452}
1453
1454int QQuickMaterialStyle::tooltipHeight() const
1455{
1456 // https://material.io/guidelines/components/tooltips.html
1457 return globalVariant == Dense ? 22 : 32;
1458}
1459
1460QQuickMaterialStyle::Variant QQuickMaterialStyle::variant()
1461{
1462 return globalVariant;
1463}
1464
1465template <typename Enum>
1466static Enum toEnumValue(const QByteArray &value, bool *ok)
1467{
1468 QMetaEnum enumeration = QMetaEnum::fromType<Enum>();
1469 return static_cast<Enum>(enumeration.keyToValue(value, ok));
1470}
1471
1472static QByteArray resolveSetting(const QByteArray &env, const QSharedPointer<QSettings> &settings, const QString &name)
1473{
1474 QByteArray value = qgetenv(env);
1475#if QT_CONFIG(settings)
1476 if (value.isNull() && !settings.isNull())
1477 value = settings->value(name).toByteArray();
1478#endif
1479 return value;
1480}
1481
1482void QQuickMaterialStyle::initGlobals()
1483{
1484 QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("Material"));
1485
1486 bool ok = false;
1487 QByteArray themeValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_THEME", settings, QStringLiteral("Theme"));
1488 Theme themeEnum = toEnumValue<Theme>(themeValue, &ok);
1489 if (ok)
1490 globalTheme = themeEnum;
1491 else if (!themeValue.isEmpty())
1492 qWarning().nospace().noquote() << "Material: unknown theme value: " << themeValue;
1493
1494 QByteArray variantValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_VARIANT", settings, QStringLiteral("Variant"));
1495 Variant variantEnum = toEnumValue<Variant>(variantValue, &ok);
1496 if (ok)
1497 globalVariant = variantEnum;
1498 else if (!variantValue.isEmpty())
1499 qWarning().nospace().noquote() << "Material: unknown variant value: " << variantValue;
1500
1501 QByteArray primaryValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_PRIMARY", settings, QStringLiteral("Primary"));
1502 Color primaryEnum = toEnumValue<Color>(primaryValue, &ok);
1503 if (ok) {
1504 globalPrimaryCustom = false;
1505 globalPrimary = primaryEnum;
1506 } else {
1507 QColor color = QColor::fromString(primaryValue);
1508 if (color.isValid()) {
1509 globalPrimaryCustom = true;
1510 globalPrimary = color.rgba();
1511 } else if (!primaryValue.isEmpty()) {
1512 qWarning().nospace().noquote() << "Material: unknown primary value: " << primaryValue;
1513 }
1514 }
1515
1516 QByteArray accentValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_ACCENT", settings, QStringLiteral("Accent"));
1517 Color accentEnum = toEnumValue<Color>(accentValue, &ok);
1518 if (ok) {
1519 globalAccentCustom = false;
1520 globalAccent = accentEnum;
1521 } else if (!accentValue.isEmpty()) {
1522 QColor color = QColor::fromString(accentValue);
1523 if (color.isValid()) {
1524 globalAccentCustom = true;
1525 globalAccent = color.rgba();
1526 } else {
1527 qWarning().nospace().noquote() << "Material: unknown accent value: " << accentValue;
1528 }
1529 }
1530
1531 QByteArray foregroundValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_FOREGROUND", settings, QStringLiteral("Foreground"));
1532 Color foregroundEnum = toEnumValue<Color>(foregroundValue, &ok);
1533 if (ok) {
1534 globalForegroundCustom = false;
1535 globalForeground = foregroundEnum;
1536 hasGlobalForeground = true;
1537 } else if (!foregroundValue.isEmpty()) {
1538 QColor color = QColor::fromString(foregroundValue);
1539 if (color.isValid()) {
1540 globalForegroundCustom = true;
1541 globalForeground = color.rgba();
1542 hasGlobalForeground = true;
1543 } else {
1544 qWarning().nospace().noquote() << "Material: unknown foreground value: " << foregroundValue;
1545 }
1546 }
1547
1548 QByteArray backgroundValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_BACKGROUND", settings, QStringLiteral("Background"));
1549 Color backgroundEnum = toEnumValue<Color>(backgroundValue, &ok);
1550 if (ok) {
1551 globalBackgroundCustom = false;
1552 globalBackground = backgroundEnum;
1553 hasGlobalBackground = true;
1554 } else if (!backgroundValue.isEmpty()) {
1555 QColor color = QColor::fromString(backgroundValue);
1556 if (color.isValid()) {
1557 globalBackgroundCustom = true;
1558 globalBackground = color.rgba();
1559 hasGlobalBackground = true;
1560 } else {
1561 qWarning().nospace().noquote() << "Material: unknown background value: " << backgroundValue;
1562 }
1563 }
1564}
1565
1566void QQuickMaterialStyle::attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent)
1567{
1568 Q_UNUSED(oldParent);
1569 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(newParent);
1570 if (material) {
1571 inheritPrimary(material->m_primary, material->m_customPrimary);
1572 inheritAccent(material->m_accent, material->m_customAccent);
1573 inheritForeground(material->m_foreground, material->m_customForeground, material->m_hasForeground);
1574 inheritBackground(material->m_background, material->m_customBackground, material->m_hasBackground);
1575 inheritTheme(material->theme());
1576 }
1577}
1578
1579bool QQuickMaterialStyle::variantToRgba(const QVariant &var, const char *name, QRgb *rgba, bool *custom) const
1580{
1581 *custom = false;
1582 if (var.metaType().id() == QMetaType::Int) {
1583 int val = var.toInt();
1584 if (val > BlueGrey) {
1585 qmlWarning(parent()) << "unknown Material." << name << " value: " << val;
1586 return false;
1587 }
1588 *rgba = val;
1589 } else {
1590 int val = QMetaEnum::fromType<Color>().keyToValue(var.toByteArray());
1591 if (val != -1) {
1592 *rgba = val;
1593 } else {
1594 QColor color = QColor::fromString(var.toString());
1595 if (!color.isValid()) {
1596 qmlWarning(parent()) << "unknown Material." << name << " value: " << var.toString();
1597 return false;
1598 }
1599 *custom = true;
1600 *rgba = color.rgba();
1601 }
1602 }
1603 return true;
1604}
1605
1606QT_END_NAMESPACE
1607
1608#include "moc_qquickmaterialstyle_p.cpp"
static const QRgb raisedButtonColorLight
static const QRgb spinBoxDisabledIconColorLight
static const QRgb textFieldFilledContainerColorDark
static bool globalBackgroundCustom
static QQuickMaterialStyle::Theme effectiveTheme(QQuickMaterialStyle::Theme theme)
static const QRgb rippleColorLight
static const QRgb dividerColorLight
static const QRgb switchDisabledUncheckedTrackBorderColorLight
static const QRgb frameColorLight
static QByteArray resolveSetting(const QByteArray &env, const QSharedPointer< QSettings > &settings, const QString &name)
static const QRgb switchDisabledCheckedTrackColorLight
static Enum toEnumValue(const QByteArray &value, bool *ok)
static const QRgb spinBoxDisabledIconColorDark
static const QRgb sliderDisabledColorDark
static const QRgb primaryTextColorLight
static const QRgb raisedButtonColorDark
static const QRgb iconColorDark
static const QRgb switchDisabledUncheckedIconColorLight
static QColor darkerShade(const QColor &color, qreal amount)
static const QRgb textFieldFilledContainerColorLight
static const QRgb rippleColorDark
static const QRgb switchDisabledCheckedTrackColorDark
static const QRgb switchDisabledUncheckedIconColorDark
static bool globalForegroundCustom
static const QRgb dialogColorDark
static QQuickMaterialStyle::Variant globalVariant
static const QRgb sliderDisabledColorLight
static const QRgb backgroundColorLight
static const QRgb secondaryTextColorLight
static const QRgb switchDisabledUncheckedTrackColorLight
static const QRgb iconColorLight
static const QRgb secondaryTextColorDark
static uint globalBackground
static const QRgb switchDisabledUncheckedTrackColorDark
static const QRgb hintTextColorDark
static const QRgb raisedButtonDisabledColorDark
static const QRgb iconDisabledColorLight
static bool globalPrimaryCustom
static bool hasGlobalBackground
static bool globalAccentCustom
static QColor lighterShade(const QColor &color, qreal amount)
static const QRgb dividerColorDark
static const QRgb switchUncheckedTrackColorLight
static const QRgb dialogColorLight
static const QRgb hintTextColorLight
static uint globalPrimary
static const QRgb iconDisabledColorDark
static const QRgb raisedButtonDisabledColorLight
static const QRgb switchUncheckedTrackColorDark
static bool hasGlobalForeground
static const QRgb backgroundColorDark
static QQuickMaterialStyle::Theme globalTheme
static uint globalForeground
static const QRgb switchDisabledUncheckedTrackBorderColorDark
static const QRgb primaryTextColorDark
static uint globalAccent
static const QRgb frameColorDark