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_hasForeground = true;
714 m_explicitForeground = true;
715 if (m_foreground == foreground)
716 return;
717
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_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_hasForeground = false;
752 m_customForeground = false;
753 m_explicitForeground = false;
754 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(attachedParent());
755 inheritForeground(material ? material->m_foreground : globalForeground, true, 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_hasBackground = true;
795 m_explicitBackground = true;
796 if (m_background == background)
797 return;
798
799 m_customBackground = custom;
800 m_background = background;
801 propagateBackground();
802 backgroundChange();
803
804 // Foreground color depends on the background color if the background is set to primary.
805 if (!m_customBackground && m_background == m_primary)
806 foregroundChange();
807}
808
809void QQuickMaterialStyle::inheritBackground(uint background, bool custom, bool has)
810{
811 if (m_explicitBackground || m_background == background)
812 return;
813
814 m_hasBackground = has;
815 m_customBackground = custom;
816 m_background = background;
817 propagateBackground();
818 backgroundChange();
819 if (!m_customBackground && m_background == m_primary)
820 foregroundChange();
821}
822
823void QQuickMaterialStyle::propagateBackground()
824{
825 const auto styles = attachedChildren();
826 for (QQuickAttachedPropertyPropagator *child : styles) {
827 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
828 if (material)
829 material->inheritBackground(m_background, m_customBackground, m_hasBackground);
830 }
831}
832
833void QQuickMaterialStyle::resetBackground()
834{
835 if (!m_explicitBackground)
836 return;
837
838 m_hasBackground = false;
839 m_customBackground = false;
840 m_explicitBackground = false;
841 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(attachedParent());
842 inheritBackground(material ? material->m_background : globalBackground, true, material ? material->m_hasBackground : false);
843}
844
845void QQuickMaterialStyle::backgroundChange()
846{
847 emit backgroundChanged();
848 emit dialogColorChanged();
849 emit tooltipColorChanged();
850 emit toolBarColorChanged();
851}
852
853int QQuickMaterialStyle::elevation() const
854{
855 return m_elevation;
856}
857
858void QQuickMaterialStyle::setElevation(int elevation)
859{
860 if (m_elevation == elevation)
861 return;
862
863 m_elevation = elevation;
864 elevationChange();
865}
866
867void QQuickMaterialStyle::resetElevation()
868{
869 setElevation(0);
870}
871
872void QQuickMaterialStyle::elevationChange()
873{
874 emit elevationChanged();
875}
876
877QQuickMaterialStyle::RoundedScale QQuickMaterialStyle::roundedScale() const
878{
879 return m_roundedScale;
880}
881
882void QQuickMaterialStyle::setRoundedScale(RoundedScale roundedScale)
883{
884 if (m_roundedScale == roundedScale)
885 return;
886
887 m_roundedScale = roundedScale;
888 emit roundedScaleChanged();
889}
890
891void QQuickMaterialStyle::resetRoundedScale()
892{
893 setRoundedScale(RoundedScale::NotRounded);
894}
895
896QQuickMaterialStyle::ContainerStyle QQuickMaterialStyle::containerStyle() const
897{
898 return m_containerStyle;
899}
900
901void QQuickMaterialStyle::setContainerStyle(ContainerStyle containerStyle)
902{
903 if (m_containerStyle == containerStyle)
904 return;
905
906 m_containerStyle = containerStyle;
907 emit containerStyleChanged();
908}
909
910void QQuickMaterialStyle::resetContainerStyle()
911{
912 setContainerStyle(ContainerStyle::Filled);
913}
914
915QColor QQuickMaterialStyle::primaryColor() const
916{
917 if (m_customPrimary)
918 return QColor::fromRgba(m_primary);
919 if (m_primary > BlueGrey)
920 return QColor();
921 return colors[m_primary][Shade500];
922}
923
924QColor QQuickMaterialStyle::accentColor(Shade shade) const
925{
926 if (m_customAccent)
927 return shade == themeShade() ? QColor::fromRgba(m_accent)
928 : this->shade(QColor::fromRgba(m_accent), shade);
929 if (m_accent > BlueGrey)
930 return QColor();
931 return colors[m_accent][shade];
932}
933
934QColor QQuickMaterialStyle::accentColor() const
935{
936 return accentColor(themeShade());
937}
938
939QColor QQuickMaterialStyle::backgroundColor(Shade shade) const
940{
941 if (!m_hasBackground)
942 return QColor::fromRgba(m_theme == Light ? backgroundColorLight : backgroundColorDark);
943 // The application bars (such as ToolBar) set the background color from the primary color,
944 // and in that case, it's better to validate with the custom primary and use it accordingly.
945 if (m_customBackground || (m_customPrimary && m_background == m_primary))
946 return shade == themeShade() ? QColor::fromRgba(m_background)
947 : this->shade(QColor::fromRgba(m_background), shade);
948 if (m_background > BlueGrey)
949 return QColor();
950 return colors[m_background][shade];
951}
952
953QColor QQuickMaterialStyle::backgroundColor() const
954{
955 return backgroundColor(themeShade());
956}
957
958QColor QQuickMaterialStyle::primaryTextColor() const
959{
960 return QColor::fromRgba(m_theme == Light ? primaryTextColorLight : primaryTextColorDark);
961}
962
963QColor QQuickMaterialStyle::primaryHighlightedTextColor() const
964{
965 if (m_explicitForeground)
966 return primaryTextColor();
967 return QColor::fromRgba(primaryTextColorDark);
968}
969
970QColor QQuickMaterialStyle::secondaryTextColor() const
971{
972 return QColor::fromRgba(m_theme == Light ? secondaryTextColorLight : secondaryTextColorDark);
973}
974
975QColor QQuickMaterialStyle::hintTextColor() const
976{
977 return QColor::fromRgba(m_theme == Light ? hintTextColorLight : hintTextColorDark);
978}
979
980QColor QQuickMaterialStyle::textSelectionColor() const
981{
982 QColor color = accentColor();
983 color.setAlphaF(0.4f);
984 return color;
985}
986
987QColor QQuickMaterialStyle::dropShadowColor() const
988{
989 return QColor::fromRgba(0x40000000);
990}
991
992QColor QQuickMaterialStyle::dividerColor() const
993{
994 return QColor::fromRgba(m_theme == Light ? dividerColorLight : dividerColorDark);
995}
996
997QColor QQuickMaterialStyle::iconColor() const
998{
999 return QColor::fromRgba(m_theme == Light ? iconColorLight : iconColorDark);
1000}
1001
1002QColor QQuickMaterialStyle::iconDisabledColor() const
1003{
1004 return QColor::fromRgba(m_theme == Light ? iconDisabledColorLight : iconDisabledColorDark);
1005}
1006
1007QColor QQuickMaterialStyle::buttonColor(Theme theme, const QVariant &background, const QVariant &accent,
1008 bool enabled, bool flat, bool highlighted, bool checked) const
1009{
1010 if (!enabled && !flat) {
1011 return QColor::fromRgba(m_theme == Light
1012 ? raisedButtonDisabledColorLight : raisedButtonDisabledColorDark);
1013 }
1014
1015 // We don't use theme (and other arguments) here even though we pass it in, as it's
1016 // simpler to just re-use themeShade. We still need the arguments because they allow
1017 // us to be re-called whenever they change.
1018 Shade shade = themeShade();
1019 Q_UNUSED(theme);
1020 Q_UNUSED(background);
1021 Q_UNUSED(accent);
1022
1023 QColor color = Qt::transparent;
1024
1025 if (m_explicitBackground) {
1026 color = backgroundColor(shade);
1027 } else if (highlighted) {
1028 if (m_theme == Light) {
1029 color = accentColor(shade);
1030 if (checked)
1031 color = color.lighter();
1032 } else {
1033 // A highlighted + checked button should become darker.
1034 color = accentColor(checked ? Shade100 : shade);
1035 }
1036 // Flat, highlighted buttons need to have a semi-transparent background,
1037 // otherwise the text won't be visible.
1038 if (flat)
1039 color.setAlphaF(0.25);
1040 } else if (!flat) {
1041 // Even if the elevation is zero, it should still have a background if it's not flat.
1042 color = QColor::fromRgba(m_theme == Light ? raisedButtonColorLight
1043 : raisedButtonColorDark);
1044 }
1045
1046 return color;
1047}
1048
1049QColor QQuickMaterialStyle::frameColor() const
1050{
1051 return QColor::fromRgba(m_theme == Light ? frameColorLight : frameColorDark);
1052}
1053
1054QColor QQuickMaterialStyle::rippleColor() const
1055{
1056 return QColor::fromRgba(m_theme == Light ? rippleColorLight : rippleColorDark);
1057}
1058
1059QColor QQuickMaterialStyle::highlightedRippleColor() const
1060{
1061 QColor pressColor = accentColor();
1062 pressColor.setAlpha(m_theme == Light ? 30 : 50);
1063 return pressColor;
1064}
1065
1066QColor QQuickMaterialStyle::switchUncheckedTrackColor() const
1067{
1068 return QColor::fromRgba(m_theme == Light ? switchUncheckedTrackColorLight : switchUncheckedTrackColorDark);
1069}
1070
1071QColor QQuickMaterialStyle::switchCheckedTrackColor() const
1072{
1073 return accentColor(m_theme == Light ? themeShade() : Shade100);
1074}
1075
1076QColor QQuickMaterialStyle::switchDisabledUncheckedTrackColor() const
1077{
1078 return QColor::fromRgba(m_theme == Light
1079 ? switchDisabledUncheckedTrackColorLight : switchDisabledUncheckedTrackColorDark);
1080}
1081
1082QColor QQuickMaterialStyle::switchDisabledCheckedTrackColor() const
1083{
1084 return QColor::fromRgba(m_theme == Light
1085 ? switchDisabledCheckedTrackColorLight : switchDisabledCheckedTrackColorDark);
1086}
1087
1088QColor QQuickMaterialStyle::switchDisabledUncheckedTrackBorderColor() const
1089{
1090 return QColor::fromRgba(m_theme == Light
1091 ? switchDisabledUncheckedTrackBorderColorLight : switchDisabledUncheckedTrackBorderColorDark);
1092}
1093
1094QColor QQuickMaterialStyle::switchUncheckedHandleColor() const
1095{
1096 return m_theme == Light ? color(Grey, Shade600) : color(Grey, Shade400);
1097}
1098
1099QColor QQuickMaterialStyle::switchUncheckedHoveredHandleColor() const
1100{
1101 const QColor color = switchUncheckedHandleColor();
1102 return m_theme == Light ? color.darker(140) : color.lighter(120);
1103}
1104
1105QColor QQuickMaterialStyle::switchCheckedHandleColor() const
1106{
1107 return m_theme == Light ? QColor::fromRgb(0xFFFFFF) : accentColor(Shade800);
1108}
1109
1110QColor QQuickMaterialStyle::switchDisabledUncheckedHandleColor() const
1111{
1112 if (m_theme == Light)
1113 return QColor::fromRgba(0x611C1B1F);
1114
1115 QColor darkHandleColor = color(Grey, Shade800);
1116 darkHandleColor.setAlphaF(0.38f);
1117 return darkHandleColor;
1118}
1119
1120QColor QQuickMaterialStyle::switchDisabledCheckedHandleColor() const
1121{
1122 return QColor::fromRgb(m_theme == Light ? 0xFFFBFE : 0x1C1B1F);
1123}
1124
1125QColor QQuickMaterialStyle::switchDisabledCheckedIconColor() const
1126{
1127 return QColor::fromRgba(m_theme == Light ? 0x611C1B1F : 0x61E6E1E5);
1128}
1129
1130QColor QQuickMaterialStyle::switchDisabledUncheckedIconColor() const
1131{
1132 return QColor::fromRgba(m_theme == Light
1133 ? switchDisabledUncheckedIconColorLight : switchDisabledUncheckedIconColorDark);
1134}
1135
1136QColor QQuickMaterialStyle::scrollBarColor() const
1137{
1138 return QColor::fromRgba(m_theme == Light ? 0x40000000 : 0x40FFFFFF);
1139}
1140
1141QColor QQuickMaterialStyle::scrollBarHoveredColor() const
1142{
1143 return QColor::fromRgba(m_theme == Light ? 0x60000000 : 0x60FFFFFF);
1144}
1145
1146QColor QQuickMaterialStyle::scrollBarPressedColor() const
1147{
1148 return QColor::fromRgba(m_theme == Light ? 0x80000000 : 0x80FFFFFF);
1149}
1150
1151QColor QQuickMaterialStyle::dialogColor() const
1152{
1153 if (m_hasBackground)
1154 return backgroundColor();
1155 return QColor::fromRgba(m_theme == Light ? dialogColorLight : dialogColorDark);
1156}
1157
1158QColor QQuickMaterialStyle::backgroundDimColor() const
1159{
1160 return QColor::fromRgba(m_theme == Light ? 0x99303030 : 0x99fafafa);
1161}
1162
1163QColor QQuickMaterialStyle::listHighlightColor() const
1164{
1165 return QColor::fromRgba(m_theme == Light ? 0x1e000000 : 0x1effffff);
1166}
1167
1168QColor QQuickMaterialStyle::tooltipColor() const
1169{
1170 if (m_explicitBackground)
1171 return backgroundColor();
1172 return color(Grey, Shade700);
1173}
1174
1175QColor QQuickMaterialStyle::toolBarColor() const
1176{
1177 if (m_explicitBackground)
1178 return backgroundColor();
1179 return primaryColor();
1180}
1181
1182QColor QQuickMaterialStyle::toolTextColor() const
1183{
1184 if (m_hasForeground || m_customPrimary)
1185 return primaryTextColor();
1186
1187 switch (m_primary) {
1188 case Red:
1189 case Pink:
1190 case Purple:
1191 case DeepPurple:
1192 case Indigo:
1193 case Blue:
1194 case Teal:
1195 case DeepOrange:
1196 case Brown:
1197 case BlueGrey:
1198 return QColor::fromRgba(primaryTextColorDark);
1199
1200 case LightBlue:
1201 case Cyan:
1202 case Green:
1203 case LightGreen:
1204 case Lime:
1205 case Yellow:
1206 case Amber:
1207 case Orange:
1208 case Grey:
1209 return QColor::fromRgba(primaryTextColorLight);
1210
1211 default:
1212 break;
1213 }
1214
1215 return primaryTextColor();
1216}
1217
1218QColor QQuickMaterialStyle::spinBoxDisabledIconColor() const
1219{
1220 return QColor::fromRgba(m_theme == Light ? spinBoxDisabledIconColorLight : spinBoxDisabledIconColorDark);
1221}
1222
1223QColor QQuickMaterialStyle::sliderDisabledColor() const
1224{
1225 return QColor::fromRgba(m_theme == Light ? sliderDisabledColorLight : sliderDisabledColorDark);
1226}
1227
1228QColor QQuickMaterialStyle::textFieldFilledContainerColor() const
1229{
1230 return QColor::fromRgba(m_theme == Light ? textFieldFilledContainerColorLight : textFieldFilledContainerColorDark);
1231}
1232
1233QColor QQuickMaterialStyle::color(QQuickMaterialStyle::Color color, QQuickMaterialStyle::Shade shade) const
1234{
1235 int count = sizeof(colors) / sizeof(colors[0]);
1236 if (color < 0 || color >= count)
1237 return QColor();
1238
1239 count = sizeof(colors[0]) / sizeof(colors[0][0]);
1240 if (shade < 0 || shade >= count)
1241 return QColor();
1242
1243 return colors[color][shade];
1244}
1245
1246static QColor lighterShade(const QColor &color, qreal amount)
1247{
1248 QColor hsl = color.toHsl();
1249 hsl.setHslF(hsl.hueF(), hsl.saturationF(),
1250 std::clamp(hsl.lightnessF() + amount, qreal(0.0), qreal(1.0)), color.alphaF());
1251 return hsl.convertTo(color.spec());
1252}
1253
1254static QColor darkerShade(const QColor &color, qreal amount)
1255{
1256 QColor hsl = color.toHsl();
1257 hsl.setHslF(hsl.hueF(), hsl.saturationF(),
1258 std::clamp(hsl.lightnessF() - amount, qreal(0.0), qreal(1.0)), color.alphaF());
1259 return hsl.convertTo(color.spec());
1260}
1261
1262QQuickMaterialStyle::Shade QQuickMaterialStyle::themeShade() const
1263{
1264 return m_theme == Light ? Shade500 : Shade200;
1265}
1266
1267/*
1268 * The following lightness values originate from the Material Design Color Generator project.
1269 *
1270 * The MIT License (MIT)
1271 *
1272 * Copyright (c) 2015 mbitson
1273 *
1274 * Permission is hereby granted, free of charge, to any person obtaining a copy
1275 * of this software and associated documentation files (the "Software"), to deal
1276 * in the Software without restriction, including without limitation the rights
1277 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1278 * copies of the Software, and to permit persons to whom the Software is
1279 * furnished to do so, subject to the following conditions:
1280 *
1281 * The above copyright notice and this permission notice shall be included in all
1282 * copies or substantial portions of the Software.
1283 *
1284 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1285 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1286 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1287 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1288 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1289 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1290 * SOFTWARE.
1291 */
1292
1293// Returns the same color, if shade == themeShade()
1294QColor QQuickMaterialStyle::shade(const QColor &color, Shade shade) const
1295{
1296 switch (shade) {
1297 case Shade50:
1298 return lighterShade(color, m_theme == Light ? 0.52 : 0.26);
1299 case Shade100:
1300 return lighterShade(color, m_theme == Light ? 0.37 : 0.11);
1301 case Shade200:
1302 return m_theme == Light ? lighterShade(color, 0.26) : color;
1303 case Shade300:
1304 return m_theme == Light ? lighterShade(color, 0.12) : darkerShade(color, 0.14);
1305 case Shade400:
1306 return m_theme == Light ? lighterShade(color, 0.06) : darkerShade(color, 0.20);
1307 case Shade500:
1308 return m_theme == Light ? color : darkerShade(color, 0.26);
1309 case Shade600:
1310 return darkerShade(color, m_theme == Light ? 0.06 : 0.32);
1311 case Shade700:
1312 return darkerShade(color, m_theme == Light ? 0.12 : 0.38);
1313 case Shade800:
1314 return darkerShade(color, m_theme == Light ? 0.18 : 0.44);
1315 case Shade900:
1316 return darkerShade(color, m_theme == Light ? 0.24 : 0.50);
1317 case ShadeA100:
1318 return lighterShade(color, m_theme == Light ? 0.54 : 0.28);
1319 case ShadeA200:
1320 return lighterShade(color, m_theme == Light ? 0.37 : 0.11);
1321 case ShadeA400:
1322 return m_theme == Light ? lighterShade(color, 0.06) : darkerShade(color, 0.20);
1323 case ShadeA700:
1324 return darkerShade(color, m_theme == Light ? 0.12 : 0.38);
1325 default:
1326 Q_UNREACHABLE_RETURN(QColor());
1327 }
1328}
1329
1330int QQuickMaterialStyle::touchTarget() const
1331{
1332 // https://material.io/guidelines/components/buttons.html#buttons-style
1333 return globalVariant == Dense ? 44 : 48;
1334}
1335
1336int QQuickMaterialStyle::buttonVerticalPadding() const
1337{
1338 return globalVariant == Dense ? 10 : 14;
1339}
1340
1341// https://m3.material.io/components/buttons/specs#256326ad-f934-40e7-b05f-0bcb41aa4382
1342int QQuickMaterialStyle::buttonLeftPadding(bool flat, bool hasIcon) const
1343{
1344 static const int noIconPadding = globalVariant == Dense ? 12 : 24;
1345 static const int iconPadding = globalVariant == Dense ? 8 : 16;
1346 static const int flatPadding = globalVariant == Dense ? 6 : 12;
1347 return !flat ? (!hasIcon ? noIconPadding : iconPadding) : flatPadding;
1348}
1349
1350int QQuickMaterialStyle::buttonRightPadding(bool flat, bool hasIcon, bool hasText) const
1351{
1352 static const int noTextPadding = globalVariant == Dense ? 8 : 16;
1353 static const int textPadding = globalVariant == Dense ? 12 : 24;
1354 static const int flatNoIconPadding = globalVariant == Dense ? 6 : 12;
1355 static const int flatNoTextPadding = globalVariant == Dense ? 6 : 12;
1356 static const int flatTextPadding = globalVariant == Dense ? 8 : 16;
1357 return !flat
1358 ? (!hasText ? noTextPadding : textPadding)
1359 : (!hasIcon ? flatNoIconPadding : (!hasText ? flatNoTextPadding : flatTextPadding));
1360}
1361
1362int QQuickMaterialStyle::buttonHeight() const
1363{
1364 // https://m3.material.io/components/buttons/specs#256326ad-f934-40e7-b05f-0bcb41aa4382
1365 return globalVariant == Dense ? 32 : 40;
1366}
1367
1368int QQuickMaterialStyle::delegateHeight() const
1369{
1370 // https://material.io/guidelines/components/lists.html#lists-specs
1371 return globalVariant == Dense ? 40 : 48;
1372}
1373
1374int QQuickMaterialStyle::dialogButtonBoxHeight() const
1375{
1376 return globalVariant == Dense ? 48 : 52;
1377}
1378
1379int QQuickMaterialStyle::dialogTitleFontPixelSize() const
1380{
1381 return globalVariant == Dense ? 16 : 24;
1382}
1383
1384// https://m3.material.io/components/dialogs/specs#6771d107-624e-47cc-b6d8-2b7b620ba2f1
1385QQuickMaterialStyle::RoundedScale QQuickMaterialStyle::dialogRoundedScale() const
1386{
1387 return globalVariant == Dense
1388 ? QQuickMaterialStyle::RoundedScale::LargeScale
1389 : QQuickMaterialStyle::RoundedScale::ExtraLargeScale;
1390}
1391
1392int QQuickMaterialStyle::frameVerticalPadding() const
1393{
1394 return globalVariant == Dense ? 8 : 12;
1395}
1396
1397int QQuickMaterialStyle::menuItemHeight() const
1398{
1399 // https://material.io/guidelines/components/menus.html#menus-simple-menus
1400 return globalVariant == Dense ? 32 : 48;
1401}
1402
1403int QQuickMaterialStyle::menuItemVerticalPadding() const
1404{
1405 return globalVariant == Dense ? 8 : 12;
1406}
1407
1408int QQuickMaterialStyle::switchIndicatorWidth() const
1409{
1410 return globalVariant == Dense ? 40 : 52;
1411}
1412
1413int QQuickMaterialStyle::switchIndicatorHeight() const
1414{
1415 return globalVariant == Dense ? 22 : 32;
1416}
1417
1418int QQuickMaterialStyle::switchNormalHandleHeight() const
1419{
1420 return globalVariant == Dense ? 10 : 16;
1421}
1422
1423int QQuickMaterialStyle::switchCheckedHandleHeight() const
1424{
1425 return globalVariant == Dense ? 16 : 24;
1426}
1427
1428int QQuickMaterialStyle::switchLargestHandleHeight() const
1429{
1430 return globalVariant == Dense ? 18 : 28;
1431}
1432
1433int QQuickMaterialStyle::switchDelegateVerticalPadding() const
1434{
1435 // SwitchDelegate's indicator is much larger than the others due to the shadow,
1436 // so we must reduce its padding to ensure its implicitHeight is 40 when dense.
1437 return globalVariant == Dense ? 4 : 8;
1438}
1439
1440int QQuickMaterialStyle::textFieldHeight() const
1441{
1442 // filled: https://m3.material.io/components/text-fields/specs#8c032848-e442-46df-b25d-28f1315f234b
1443 // outlined: https://m3.material.io/components/text-fields/specs#605e24f1-1c1f-4c00-b385-4bf50733a5ef
1444 return globalVariant == Dense ? 44 : 56;
1445}
1446int QQuickMaterialStyle::textFieldHorizontalPadding() const
1447{
1448 return globalVariant == Dense ? 12 : 16;
1449}
1450int QQuickMaterialStyle::textFieldVerticalPadding() const
1451{
1452 return globalVariant == Dense ? 4 : 8;
1453}
1454
1455int QQuickMaterialStyle::tooltipHeight() const
1456{
1457 // https://material.io/guidelines/components/tooltips.html
1458 return globalVariant == Dense ? 22 : 32;
1459}
1460
1461QQuickMaterialStyle::Variant QQuickMaterialStyle::variant()
1462{
1463 return globalVariant;
1464}
1465
1466template <typename Enum>
1467static Enum toEnumValue(const QByteArray &value, bool *ok)
1468{
1469 QMetaEnum enumeration = QMetaEnum::fromType<Enum>();
1470 return static_cast<Enum>(enumeration.keyToValue(value, ok));
1471}
1472
1473static QByteArray resolveSetting(const QByteArray &env, const QSharedPointer<QSettings> &settings, const QString &name)
1474{
1475 QByteArray value = qgetenv(env);
1476#if QT_CONFIG(settings)
1477 if (value.isNull() && !settings.isNull())
1478 value = settings->value(name).toByteArray();
1479#endif
1480 return value;
1481}
1482
1483void QQuickMaterialStyle::initGlobals()
1484{
1485 QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("Material"));
1486
1487 bool ok = false;
1488 QByteArray themeValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_THEME", settings, QStringLiteral("Theme"));
1489 Theme themeEnum = toEnumValue<Theme>(themeValue, &ok);
1490 if (ok)
1491 globalTheme = themeEnum;
1492 else if (!themeValue.isEmpty())
1493 qWarning().nospace().noquote() << "Material: unknown theme value: " << themeValue;
1494
1495 QByteArray variantValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_VARIANT", settings, QStringLiteral("Variant"));
1496 Variant variantEnum = toEnumValue<Variant>(variantValue, &ok);
1497 if (ok)
1498 globalVariant = variantEnum;
1499 else if (!variantValue.isEmpty())
1500 qWarning().nospace().noquote() << "Material: unknown variant value: " << variantValue;
1501
1502 QByteArray primaryValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_PRIMARY", settings, QStringLiteral("Primary"));
1503 Color primaryEnum = toEnumValue<Color>(primaryValue, &ok);
1504 if (ok) {
1505 globalPrimaryCustom = false;
1506 globalPrimary = primaryEnum;
1507 } else {
1508 QColor color = QColor::fromString(primaryValue);
1509 if (color.isValid()) {
1510 globalPrimaryCustom = true;
1511 globalPrimary = color.rgba();
1512 } else if (!primaryValue.isEmpty()) {
1513 qWarning().nospace().noquote() << "Material: unknown primary value: " << primaryValue;
1514 }
1515 }
1516
1517 QByteArray accentValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_ACCENT", settings, QStringLiteral("Accent"));
1518 Color accentEnum = toEnumValue<Color>(accentValue, &ok);
1519 if (ok) {
1520 globalAccentCustom = false;
1521 globalAccent = accentEnum;
1522 } else if (!accentValue.isEmpty()) {
1523 QColor color = QColor::fromString(accentValue);
1524 if (color.isValid()) {
1525 globalAccentCustom = true;
1526 globalAccent = color.rgba();
1527 } else {
1528 qWarning().nospace().noquote() << "Material: unknown accent value: " << accentValue;
1529 }
1530 }
1531
1532 QByteArray foregroundValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_FOREGROUND", settings, QStringLiteral("Foreground"));
1533 Color foregroundEnum = toEnumValue<Color>(foregroundValue, &ok);
1534 if (ok) {
1535 globalForegroundCustom = false;
1536 globalForeground = foregroundEnum;
1537 hasGlobalForeground = true;
1538 } else if (!foregroundValue.isEmpty()) {
1539 QColor color = QColor::fromString(foregroundValue);
1540 if (color.isValid()) {
1541 globalForegroundCustom = true;
1542 globalForeground = color.rgba();
1543 hasGlobalForeground = true;
1544 } else {
1545 qWarning().nospace().noquote() << "Material: unknown foreground value: " << foregroundValue;
1546 }
1547 }
1548
1549 QByteArray backgroundValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_BACKGROUND", settings, QStringLiteral("Background"));
1550 Color backgroundEnum = toEnumValue<Color>(backgroundValue, &ok);
1551 if (ok) {
1552 globalBackgroundCustom = false;
1553 globalBackground = backgroundEnum;
1554 hasGlobalBackground = true;
1555 } else if (!backgroundValue.isEmpty()) {
1556 QColor color = QColor::fromString(backgroundValue);
1557 if (color.isValid()) {
1558 globalBackgroundCustom = true;
1559 globalBackground = color.rgba();
1560 hasGlobalBackground = true;
1561 } else {
1562 qWarning().nospace().noquote() << "Material: unknown background value: " << backgroundValue;
1563 }
1564 }
1565}
1566
1567void QQuickMaterialStyle::attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent)
1568{
1569 Q_UNUSED(oldParent);
1570 QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(newParent);
1571 if (material) {
1572 inheritPrimary(material->m_primary, material->m_customPrimary);
1573 inheritAccent(material->m_accent, material->m_customAccent);
1574 inheritForeground(material->m_foreground, material->m_customForeground, material->m_hasForeground);
1575 inheritBackground(material->m_background, material->m_customBackground, material->m_hasBackground);
1576 inheritTheme(material->theme());
1577 }
1578}
1579
1580bool QQuickMaterialStyle::variantToRgba(const QVariant &var, const char *name, QRgb *rgba, bool *custom) const
1581{
1582 *custom = false;
1583 if (var.metaType().id() == QMetaType::Int) {
1584 int val = var.toInt();
1585 if (val > BlueGrey) {
1586 qmlWarning(parent()) << "unknown Material." << name << " value: " << val;
1587 return false;
1588 }
1589 *rgba = val;
1590 } else {
1591 int val = QMetaEnum::fromType<Color>().keyToValue(var.toByteArray());
1592 if (val != -1) {
1593 *rgba = val;
1594 } else {
1595 QColor color = QColor::fromString(var.toString());
1596 if (!color.isValid()) {
1597 qmlWarning(parent()) << "unknown Material." << name << " value: " << var.toString();
1598 return false;
1599 }
1600 *custom = true;
1601 *rgba = color.rgba();
1602 }
1603 }
1604 return true;
1605}
1606
1607QT_END_NAMESPACE
1608
1609#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