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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtdeclarative/src/quickcontrols/material/qquickmaterialstyle.cpp