// Copyright (C) 2017 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qquickuniversalstyle_p.h" #include "qquickuniversaltheme_p.h" #include #if QT_CONFIG(settings) #include #endif #include #include QT_BEGIN_NAMESPACE static QRgb qquickuniversal_light_color(QQuickUniversalStyle::SystemColor role) { static const QRgb colors[] = { 0xFFFFFFFF, // SystemAltHighColor 0x33FFFFFF, // SystemAltLowColor 0x99FFFFFF, // SystemAltMediumColor 0xCCFFFFFF, // SystemAltMediumHighColor 0x66FFFFFF, // SystemAltMediumLowColor 0xFF000000, // SystemBaseHighColor 0x33000000, // SystemBaseLowColor 0x99000000, // SystemBaseMediumColor 0xCC000000, // SystemBaseMediumHighColor 0x66000000, // SystemBaseMediumLowColor 0xFF171717, // SystemChromeAltLowColor 0xFF000000, // SystemChromeBlackHighColor 0x33000000, // SystemChromeBlackLowColor 0x66000000, // SystemChromeBlackMediumLowColor 0xCC000000, // SystemChromeBlackMediumColor 0xFFCCCCCC, // SystemChromeDisabledHighColor 0xFF7A7A7A, // SystemChromeDisabledLowColor 0xFFCCCCCC, // SystemChromeHighColor 0xFFF2F2F2, // SystemChromeLowColor 0xFFE6E6E6, // SystemChromeMediumColor 0xFFF2F2F2, // SystemChromeMediumLowColor 0xFFFFFFFF, // SystemChromeWhiteColor 0x19000000, // SystemListLowColor 0x33000000 // SystemListMediumColor }; return colors[role]; } static QRgb qquickuniversal_dark_color(QQuickUniversalStyle::SystemColor role) { static const QRgb colors[] = { 0xFF000000, // SystemAltHighColor 0x33000000, // SystemAltLowColor 0x99000000, // SystemAltMediumColor 0xCC000000, // SystemAltMediumHighColor 0x66000000, // SystemAltMediumLowColor 0xFFFFFFFF, // SystemBaseHighColor 0x33FFFFFF, // SystemBaseLowColor 0x99FFFFFF, // SystemBaseMediumColor 0xCCFFFFFF, // SystemBaseMediumHighColor 0x66FFFFFF, // SystemBaseMediumLowColor 0xFFF2F2F2, // SystemChromeAltLowColor 0xFF000000, // SystemChromeBlackHighColor 0x33000000, // SystemChromeBlackLowColor 0x66000000, // SystemChromeBlackMediumLowColor 0xCC000000, // SystemChromeBlackMediumColor 0xFF333333, // SystemChromeDisabledHighColor 0xFF858585, // SystemChromeDisabledLowColor 0xFF767676, // SystemChromeHighColor 0xFF171717, // SystemChromeLowColor 0xFF1F1F1F, // SystemChromeMediumColor 0xFF2B2B2B, // SystemChromeMediumLowColor 0xFFFFFFFF, // SystemChromeWhiteColor 0x19FFFFFF, // SystemListLowColor 0x33FFFFFF // SystemListMediumColor }; return colors[role]; } static QRgb qquickuniversal_accent_color(QQuickUniversalStyle::Color accent) { static const QRgb colors[] = { 0xFFA4C400, // Lime 0xFF60A917, // Green 0xFF008A00, // Emerald 0xFF00ABA9, // Teal 0xFF1BA1E2, // Cyan 0xFF3E65FF, // Cobalt 0xFF6A00FF, // Indigo 0xFFAA00FF, // Violet 0xFFF472D0, // Pink 0xFFD80073, // Magenta 0xFFA20025, // Crimson 0xFFE51400, // Red 0xFFFA6800, // Orange 0xFFF0A30A, // Amber 0xFFE3C800, // Yellow 0xFF825A2C, // Brown 0xFF6D8764, // Olive 0xFF647687, // Steel 0xFF76608A, // Mauve 0xFF87794E // Taupe }; return colors[accent]; } static QQuickUniversalStyle::Theme qquickuniversal_effective_theme(QQuickUniversalStyle::Theme theme) { if (theme == QQuickUniversalStyle::System) theme = QQuickStylePrivate::isDarkSystemTheme() ? QQuickUniversalStyle::Dark : QQuickUniversalStyle::Light; return theme; } // If no value was inherited from a parent or explicitly set, the "global" values are used. // The initial, default values of the globals are hard-coded here, but the environment // variables and .conf file override them if specified. static QQuickUniversalStyle::Theme GlobalTheme = QQuickUniversalStyle::Light; static QRgb GlobalAccent = qquickuniversal_accent_color(QQuickUniversalStyle::Cobalt); static QRgb GlobalForeground = qquickuniversal_light_color(QQuickUniversalStyle::BaseHigh); static QRgb GlobalBackground = qquickuniversal_light_color(QQuickUniversalStyle::AltHigh); // These represent whether a global foreground/background was set. // Each style's m_hasForeground/m_hasBackground are initialized to these values. static bool HasGlobalForeground = false; static bool HasGlobalBackground = false; QQuickUniversalStyle::QQuickUniversalStyle(QObject *parent) : QQuickAttachedPropertyPropagator(parent) , m_hasForeground(HasGlobalForeground) , m_hasBackground(HasGlobalBackground) , m_usingSystemTheme(GlobalTheme == System) , m_theme(qquickuniversal_effective_theme(GlobalTheme)) , m_accent(GlobalAccent) , m_foreground(GlobalForeground) , m_background(GlobalBackground) { initialize(); } QQuickUniversalStyle *QQuickUniversalStyle::qmlAttachedProperties(QObject *object) { return new QQuickUniversalStyle(object); } QQuickUniversalStyle::Theme QQuickUniversalStyle::theme() const { return m_theme; } void QQuickUniversalStyle::setTheme(Theme theme) { m_explicitTheme = true; // If theme is System: m_theme is set to the system's theme (Dark/Light) // and m_usingSystemTheme is set to true. // If theme is Dark/Light: m_theme is set to the input theme (Dark/Light) // and m_usingSystemTheme is set to false. const bool systemThemeChanged = (m_usingSystemTheme != (theme == System)); const Theme effectiveTheme = qquickuniversal_effective_theme(theme); // Check m_theme and m_usingSystemTheme have changed. if ((m_theme == effectiveTheme) && !systemThemeChanged) return; m_theme = effectiveTheme; m_usingSystemTheme = (theme == System); if (systemThemeChanged) { if (m_usingSystemTheme) QQuickUniversalTheme::registerSystemStyle(this); else QQuickUniversalTheme::unregisterSystemStyle(this); } propagateTheme(); emit themeChanged(); emit paletteChanged(); emit foregroundChanged(); emit backgroundChanged(); } void QQuickUniversalStyle::inheritTheme(Theme theme) { const bool systemThemeChanged = (m_usingSystemTheme != (theme == System)); const Theme effectiveTheme = qquickuniversal_effective_theme(theme); const bool hasThemeChanged = systemThemeChanged || (m_theme != effectiveTheme); if (m_explicitTheme || !hasThemeChanged) return; m_theme = effectiveTheme; m_usingSystemTheme = (theme == System); propagateTheme(); emit themeChanged(); emit paletteChanged(); emit foregroundChanged(); emit backgroundChanged(); } void QQuickUniversalStyle::propagateTheme() { const auto styles = attachedChildren(); for (QQuickAttachedPropertyPropagator *child : styles) { QQuickUniversalStyle *universal = qobject_cast(child); if (universal) { // m_theme is the effective theme; either Dark or Light. // m_usingSystemTheme indicates whether the theme is set by // the system (true) or manually (false). universal->inheritTheme(m_theme); } } } void QQuickUniversalStyle::resetTheme() { if (!m_explicitTheme) return; m_explicitTheme = false; QQuickUniversalStyle *universal = qobject_cast(attachedParent()); inheritTheme(universal ? universal->theme() : GlobalTheme); } QVariant QQuickUniversalStyle::accent() const { return QColor::fromRgba(m_accent); } void QQuickUniversalStyle::setAccent(const QVariant &var) { QRgb accent = 0; if (!variantToRgba(var, "accent", &accent)) return; m_explicitAccent = true; if (m_accent == accent) return; m_accent = accent; propagateAccent(); emit accentChanged(); } void QQuickUniversalStyle::inheritAccent(QRgb accent) { if (m_explicitAccent || m_accent == accent) return; m_accent = accent; propagateAccent(); emit accentChanged(); } void QQuickUniversalStyle::propagateAccent() { const auto styles = attachedChildren(); for (QQuickAttachedPropertyPropagator *child : styles) { QQuickUniversalStyle *universal = qobject_cast(child); if (universal) universal->inheritAccent(m_accent); } } void QQuickUniversalStyle::resetAccent() { if (!m_explicitAccent) return; m_explicitAccent = false; QQuickUniversalStyle *universal = qobject_cast(attachedParent()); inheritAccent(universal ? universal->m_accent : GlobalAccent); } QVariant QQuickUniversalStyle::foreground() const { if (m_hasForeground) return QColor::fromRgba(m_foreground); return baseHighColor(); } void QQuickUniversalStyle::setForeground(const QVariant &var) { QRgb foreground = 0; if (!variantToRgba(var, "foreground", &foreground)) return; m_hasForeground = true; m_explicitForeground = true; if (m_foreground == foreground) return; m_foreground = foreground; propagateForeground(); emit foregroundChanged(); } void QQuickUniversalStyle::inheritForeground(QRgb foreground, bool has) { if (m_explicitForeground || m_foreground == foreground) return; m_hasForeground = has; m_foreground = foreground; propagateForeground(); emit foregroundChanged(); } void QQuickUniversalStyle::propagateForeground() { const auto styles = attachedChildren(); for (QQuickAttachedPropertyPropagator *child : styles) { QQuickUniversalStyle *universal = qobject_cast(child); if (universal) universal->inheritForeground(m_foreground, m_hasForeground); } } void QQuickUniversalStyle::resetForeground() { if (!m_explicitForeground) return; m_hasForeground = false; m_explicitForeground = false; QQuickUniversalStyle *universal = qobject_cast(attachedParent()); inheritForeground(universal ? universal->m_foreground : GlobalForeground, universal ? universal->m_hasForeground : false); } QVariant QQuickUniversalStyle::background() const { if (m_hasBackground) return QColor::fromRgba(m_background); return altHighColor(); } void QQuickUniversalStyle::setBackground(const QVariant &var) { QRgb background = 0; if (!variantToRgba(var, "background", &background)) return; m_hasBackground = true; m_explicitBackground = true; if (m_background == background) return; m_background = background; propagateBackground(); emit backgroundChanged(); } void QQuickUniversalStyle::inheritBackground(QRgb background, bool has) { if (m_explicitBackground || m_background == background) return; m_hasBackground = has; m_background = background; propagateBackground(); emit backgroundChanged(); } void QQuickUniversalStyle::propagateBackground() { const auto styles = attachedChildren(); for (QQuickAttachedPropertyPropagator *child : styles) { QQuickUniversalStyle *universal = qobject_cast(child); if (universal) universal->inheritBackground(m_background, m_hasBackground); } } void QQuickUniversalStyle::resetBackground() { if (!m_explicitBackground) return; m_hasBackground = false; m_explicitBackground = false; QQuickUniversalStyle *universal = qobject_cast(attachedParent()); inheritBackground(universal ? universal->m_background : GlobalBackground, universal ? universal->m_hasBackground : false); } QColor QQuickUniversalStyle::color(Color color) const { return qquickuniversal_accent_color(color); } QColor QQuickUniversalStyle::altHighColor() const { return systemColor(AltHigh); } QColor QQuickUniversalStyle::altLowColor() const { return systemColor(AltLow); } QColor QQuickUniversalStyle::altMediumColor() const { return systemColor(AltMedium); } QColor QQuickUniversalStyle::altMediumHighColor() const { return systemColor(AltMediumHigh); } QColor QQuickUniversalStyle::altMediumLowColor() const { return systemColor(AltMediumLow); } QColor QQuickUniversalStyle::baseHighColor() const { return systemColor(BaseHigh); } QColor QQuickUniversalStyle::baseLowColor() const { return systemColor(BaseLow); } QColor QQuickUniversalStyle::baseMediumColor() const { return systemColor(BaseMedium); } QColor QQuickUniversalStyle::baseMediumHighColor() const { return systemColor(BaseMediumHigh); } QColor QQuickUniversalStyle::baseMediumLowColor() const { return systemColor(BaseMediumLow); } QColor QQuickUniversalStyle::chromeAltLowColor() const { return systemColor(ChromeAltLow); } QColor QQuickUniversalStyle::chromeBlackHighColor() const { return systemColor(ChromeBlackHigh); } QColor QQuickUniversalStyle::chromeBlackLowColor() const { return systemColor(ChromeBlackLow); } QColor QQuickUniversalStyle::chromeBlackMediumLowColor() const { return systemColor(ChromeBlackMediumLow); } QColor QQuickUniversalStyle::chromeBlackMediumColor() const { return systemColor(ChromeBlackMedium); } QColor QQuickUniversalStyle::chromeDisabledHighColor() const { return systemColor(ChromeDisabledHigh); } QColor QQuickUniversalStyle::chromeDisabledLowColor() const { return systemColor(ChromeDisabledLow); } QColor QQuickUniversalStyle::chromeHighColor() const { return systemColor(ChromeHigh); } QColor QQuickUniversalStyle::chromeLowColor() const { return systemColor(ChromeLow); } QColor QQuickUniversalStyle::chromeMediumColor() const { return systemColor(ChromeMedium); } QColor QQuickUniversalStyle::chromeMediumLowColor() const { return systemColor(ChromeMediumLow); } QColor QQuickUniversalStyle::chromeWhiteColor() const { return systemColor(ChromeWhite); } QColor QQuickUniversalStyle::listLowColor() const { return systemColor(ListLow); } QColor QQuickUniversalStyle::listMediumColor() const { return systemColor(ListMedium); } QColor QQuickUniversalStyle::systemColor(SystemColor role) const { return QColor::fromRgba(m_theme == QQuickUniversalStyle::Dark ? qquickuniversal_dark_color(role) : qquickuniversal_light_color(role)); } void QQuickUniversalStyle::attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent) { Q_UNUSED(oldParent); QQuickUniversalStyle *universal = qobject_cast(newParent); if (universal) { inheritTheme(universal->theme()); inheritAccent(universal->m_accent); inheritForeground(universal->m_foreground, universal->m_hasForeground); inheritBackground(universal->m_background, universal->m_hasBackground); } } template static Enum toEnumValue(const QByteArray &value, bool *ok) { QMetaEnum enumeration = QMetaEnum::fromType(); return static_cast(enumeration.keyToValue(value, ok)); } static QByteArray resolveSetting(const QByteArray &env, const QSharedPointer &settings, const QString &name) { QByteArray value = qgetenv(env); #if QT_CONFIG(settings) if (value.isNull() && !settings.isNull()) value = settings->value(name).toByteArray(); #endif return value; } void QQuickUniversalStyle::initGlobals() { QSharedPointer settings = QQuickStylePrivate::settings(QStringLiteral("Universal")); bool ok = false; QByteArray themeValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_THEME", settings, QStringLiteral("Theme")); Theme themeEnum = toEnumValue(themeValue, &ok); if (ok) GlobalTheme = themeEnum; else if (!themeValue.isEmpty()) qWarning().nospace().noquote() << "Universal: unknown theme value: " << themeValue; QByteArray accentValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_ACCENT", settings, QStringLiteral("Accent")); Color accentEnum = toEnumValue(accentValue, &ok); if (ok) { GlobalAccent = qquickuniversal_accent_color(accentEnum); } else if (!accentValue.isEmpty()) { QColor color = QColor::fromString(accentValue); if (color.isValid()) GlobalAccent = color.rgba(); else qWarning().nospace().noquote() << "Universal: unknown accent value: " << accentValue; } QByteArray foregroundValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_FOREGROUND", settings, QStringLiteral("Foreground")); Color foregroundEnum = toEnumValue(foregroundValue, &ok); if (ok) { GlobalForeground = qquickuniversal_accent_color(foregroundEnum); HasGlobalForeground = true; } else if (!foregroundValue.isEmpty()) { QColor color = QColor::fromString(foregroundValue); if (color.isValid()) { GlobalForeground = color.rgba(); HasGlobalForeground = true; } else { qWarning().nospace().noquote() << "Universal: unknown foreground value: " << foregroundValue; } } QByteArray backgroundValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_BACKGROUND", settings, QStringLiteral("Background")); Color backgroundEnum = toEnumValue(backgroundValue, &ok); if (ok) { GlobalBackground = qquickuniversal_accent_color(backgroundEnum); HasGlobalBackground = true; } else if (!backgroundValue.isEmpty()) { QColor color = QColor::fromString(backgroundValue); if (color.isValid()) { GlobalBackground = color.rgba(); HasGlobalBackground = true; } else { qWarning().nospace().noquote() << "Universal: unknown background value: " << backgroundValue; } } } bool QQuickUniversalStyle::variantToRgba(const QVariant &var, const char *name, QRgb *rgba) const { if (var.metaType().id() == QMetaType::Int) { int val = var.toInt(); if (val < Lime || val > Taupe) { qmlWarning(parent()) << "unknown Universal." << name << " value: " << val; return false; } *rgba = qquickuniversal_accent_color(static_cast(val)); } else { int val = QMetaEnum::fromType().keyToValue(var.toByteArray()); if (val != -1) { *rgba = qquickuniversal_accent_color(static_cast(val)); } else { QColor color = QColor::fromString(var.toString()); if (!color.isValid()) { qmlWarning(parent()) << "unknown Universal." << name << " value: " << var.toString(); return false; } *rgba = color.rgba(); } } return true; } QT_END_NAMESPACE #include "moc_qquickuniversalstyle_p.cpp"