blob: d46752f318621d369b6fbe0de5dc4b66a8804c60 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qquickuniversalstyle_p.h"
#include <QtCore/qdebug.h>
#include <QtCore/qsettings.h>
#include <QtQml/qqmlinfo.h>
#include <QtQuickControls2/private/qquickstyle_p.h>
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) : QQuickAttachedObject(parent),
m_hasForeground(HasGlobalForeground), m_hasBackground(HasGlobalBackground), m_theme(GlobalTheme),
m_accent(GlobalAccent), m_foreground(GlobalForeground), m_background(GlobalBackground)
{
init();
}
QQuickUniversalStyle *QQuickUniversalStyle::qmlAttachedProperties(QObject *object)
{
return new QQuickUniversalStyle(object);
}
QQuickUniversalStyle::Theme QQuickUniversalStyle::theme() const
{
return m_theme;
}
void QQuickUniversalStyle::setTheme(Theme theme)
{
theme = qquickuniversal_effective_theme(theme);
m_explicitTheme = true;
if (m_theme == theme)
return;
m_theme = theme;
propagateTheme();
emit themeChanged();
emit paletteChanged();
emit foregroundChanged();
emit backgroundChanged();
}
void QQuickUniversalStyle::inheritTheme(Theme theme)
{
if (m_explicitTheme || m_theme == theme)
return;
m_theme = theme;
propagateTheme();
emit themeChanged();
emit paletteChanged();
emit foregroundChanged();
emit backgroundChanged();
}
void QQuickUniversalStyle::propagateTheme()
{
const auto styles = attachedChildren();
for (QQuickAttachedObject *child : styles) {
QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(child);
if (universal)
universal->inheritTheme(m_theme);
}
}
void QQuickUniversalStyle::resetTheme()
{
if (!m_explicitTheme)
return;
m_explicitTheme = false;
QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(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 (QQuickAttachedObject *child : styles) {
QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(child);
if (universal)
universal->inheritAccent(m_accent);
}
}
void QQuickUniversalStyle::resetAccent()
{
if (!m_explicitAccent)
return;
m_explicitAccent = false;
QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(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 (QQuickAttachedObject *child : styles) {
QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(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<QQuickUniversalStyle *>(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 (QQuickAttachedObject *child : styles) {
QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(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<QQuickUniversalStyle *>(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(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent)
{
Q_UNUSED(oldParent);
QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(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 <typename Enum>
static Enum toEnumValue(const QByteArray &value, bool *ok)
{
QMetaEnum enumeration = QMetaEnum::fromType<Enum>();
return static_cast<Enum>(enumeration.keyToValue(value, ok));
}
static QByteArray resolveSetting(const QByteArray &env, const QSharedPointer<QSettings> &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<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("Universal"));
bool ok = false;
QByteArray themeValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_THEME", settings, QStringLiteral("Theme"));
Theme themeEnum = toEnumValue<Theme>(themeValue, &ok);
if (ok)
GlobalTheme = qquickuniversal_effective_theme(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<Color>(accentValue, &ok);
if (ok) {
GlobalAccent = qquickuniversal_accent_color(accentEnum);
} else if (!accentValue.isEmpty()) {
QColor color(accentValue.constData());
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<Color>(foregroundValue, &ok);
if (ok) {
GlobalForeground = qquickuniversal_accent_color(foregroundEnum);
HasGlobalForeground = true;
} else if (!foregroundValue.isEmpty()) {
QColor color(foregroundValue.constData());
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<Color>(backgroundValue, &ok);
if (ok) {
GlobalBackground = qquickuniversal_accent_color(backgroundEnum);
HasGlobalBackground = true;
} else if (!backgroundValue.isEmpty()) {
QColor color(backgroundValue.constData());
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.type() == QVariant::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<Color>(val));
} else {
int val = QMetaEnum::fromType<Color>().keyToValue(var.toByteArray());
if (val != -1) {
*rgba = qquickuniversal_accent_color(static_cast<Color>(val));
} else {
QColor color(var.toString());
if (!color.isValid()) {
qmlWarning(parent()) << "unknown Universal." << name << " value: " << var.toString();
return false;
}
*rgba = color.rgba();
}
}
return true;
}
QT_END_NAMESPACE