diff options
Diffstat (limited to 'src/quickcontrols2/qquickstyle.cpp')
-rw-r--r-- | src/quickcontrols2/qquickstyle.cpp | 699 |
1 files changed, 0 insertions, 699 deletions
diff --git a/src/quickcontrols2/qquickstyle.cpp b/src/quickcontrols2/qquickstyle.cpp deleted file mode 100644 index 6e1f17b1..00000000 --- a/src/quickcontrols2/qquickstyle.cpp +++ /dev/null @@ -1,699 +0,0 @@ -/**************************************************************************** -** -** 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 "qquickstyle.h" -#include "qquickstyle_p.h" - -#include <QtCore/qdir.h> -#include <QtCore/qfile.h> -#include <QtCore/qdebug.h> -#include <QtCore/qsettings.h> -#include <QtCore/qfileselector.h> -#include <QtCore/qlibraryinfo.h> -#include <QtCore/qloggingcategory.h> -#include <QtCore/qmetaobject.h> -#include <QtGui/qcolor.h> -#include <QtGui/qfont.h> -#include <QtGui/qpalette.h> -#include <QtGui/private/qguiapplication_p.h> -#include <QtGui/qpa/qplatformtheme.h> -#include <QtQml/private/qqmlmetatype_p.h> -#include <QtQml/qqmlengine.h> -#include <QtQml/qqmlfile.h> - -#include <functional> - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcQtQuickControlsStyle, "qt.quick.controls.style") - -/*! - \class QQuickStyle - \brief The QQuickStyle class allows configuring the application style. - \inmodule QtQuickControls2 - \since 5.7 - - QQuickStyle provides API for querying and configuring the application - \l {Styling Qt Quick Controls}{styles} of Qt Quick Controls. - - \code - #include <QGuiApplication> - #include <QQmlApplicationEngine> - #include <QQuickStyle> - - int main(int argc, char *argv[]) - { - QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - QGuiApplication app(argc, argv); - - QQuickStyle::setStyle("Material"); - - QQmlApplicationEngine engine; - engine.load(QUrl("qrc:/main.qml")); - - return app.exec(); - } - \endcode - - \note The style must be configured \b before loading QML that imports - Qt Quick Controls. It is not possible to change the style after the QML - types have been registered. - - The style can also be specified as a path to a custom style, such as - \c ":/mystyle". See \l {Creating a Custom Style} for more details about - building custom styles. Custom styles do not need to implement all controls. - By default, the styling system uses the \l {Default style} as a fallback - for controls that a custom style does not provide. It is possible to - specify a different fallback style to customize or extend one of the - built-in styles. - - \code - QQuickStyle::setStyle(":/mystyle"); - QQuickStyle::setFallbackStyle("Material"); - \endcode - - \sa {Styling Qt Quick Controls} -*/ - -static QStringList envPathList(const QByteArray &var) -{ - QStringList paths; - if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(var))) { - const QByteArray value = qgetenv(var); - paths += QString::fromLocal8Bit(value).split(QDir::listSeparator(), Qt::SkipEmptyParts); - } - return paths; -} - -static QStringList defaultImportPathList() -{ - QStringList importPaths; - importPaths.reserve(3); -#ifdef Q_OS_ANDROID - // androiddeployqt puts the QML files inside a resource file and they are not - // showing up in the Qml2ImportsPath as a result - importPaths += QStringLiteral(":/android_rcc_bundle/qml"); -#else -# ifndef QT_STATIC - importPaths += QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); -# endif -#endif - importPaths += envPathList("QML2_IMPORT_PATH"); - importPaths += QStringLiteral(":/qt-project.org/imports"); - importPaths += QCoreApplication::applicationDirPath(); - return importPaths; -} - -struct QQuickStyleSpec -{ - QQuickStyleSpec() : custom(false), resolved(false) { } - - QString name() - { - if (!resolved) - resolve(); - return style.mid(style.lastIndexOf(QLatin1Char('/')) + 1); - } - - QString path() - { - if (!resolved) - resolve(); - QString s = style; - if (QQmlFile::isLocalFile(s)) - s = QQmlFile::urlToLocalFileOrQrc(s); - return s.left(s.lastIndexOf(QLatin1Char('/')) + 1); - } - - void setStyle(const QString &s) - { - style = s; - resolved = false; - resolve(); - } - - void setFallbackStyle(const QString &fallback, const QByteArray &method) - { - fallbackStyle = fallback; - fallbackMethod = method; - } - - static QString findStyle(const QString &path, const QString &name) - { - QDir dir(path); - if (!dir.exists()) - return QString(); - - if (name.isEmpty()) - return dir.absolutePath() + QLatin1Char('/'); - - const QStringList entries = dir.entryList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot); - for (const QString &entry : entries) { - if (entry.compare(name, Qt::CaseInsensitive) == 0) - return dir.absoluteFilePath(entry); - } - - return QString(); - } - - void resolve(const QUrl &baseUrl = QUrl()) - { - qCDebug(lcQtQuickControlsStyle) << "resolving style with baseUrl" << baseUrl; - - if (style.isEmpty()) - style = QGuiApplicationPrivate::styleOverride; - if (style.isEmpty()) - style = QString::fromLocal8Bit(qgetenv("QT_QUICK_CONTROLS_STYLE")); - if (fallbackStyle.isEmpty()) - setFallbackStyle(QString::fromLocal8Bit(qgetenv("QT_QUICK_CONTROLS_FALLBACK_STYLE")), "QT_QUICK_CONTROLS_FALLBACK_STYLE"); -#if QT_CONFIG(settings) - if (style.isEmpty() || fallbackStyle.isEmpty()) { - QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("Controls")); - if (settings) { - if (style.isEmpty()) - style = settings->value(QStringLiteral("Style")).toString(); - if (fallbackStyle.isEmpty()) - setFallbackStyle(settings->value(QStringLiteral("FallbackStyle")).toString(), ":/qtquickcontrols2.conf"); - } - } -#endif - - // resolve a path relative to the config - QString configPath = QFileInfo(resolveConfigFilePath()).path(); - QString stylePath = findStyle(configPath, style); - if (!stylePath.isEmpty()) { - style = stylePath; - resolved = true; - } - - custom = style.contains(QLatin1Char('/')); - - if (baseUrl.isValid()) { - QString path = QQmlFile::urlToLocalFileOrQrc(baseUrl); - QString stylePath = findStyle(path, style); - if (!stylePath.isEmpty()) { - style = stylePath; - resolved = true; - } - } - - if (QGuiApplication::instance()) { - if (!custom) { - const QStringList stylePaths = QQuickStylePrivate::stylePaths(); - for (const QString &path : stylePaths) { - QString stylePath = findStyle(path, style); - if (!stylePath.isEmpty()) { - custom = !stylePath.startsWith(QQmlFile::urlToLocalFileOrQrc(baseUrl)); - style = stylePath; - resolved = true; - break; - } - } - } - resolved = true; - } - - qCDebug(lcQtQuickControlsStyle).nospace() << "done resolving:" - << "\n custom=" << custom - << "\n resolved=" << resolved - << "\n style=" << style - << "\n fallbackStyle=" << fallbackStyle - << "\n fallbackMethod=" << fallbackMethod - << "\n configFilePath=" << configFilePath - << "\n customStylePaths=" << customStylePaths; - } - - void reset() - { - custom = false; - resolved = false; - style.clear(); - fallbackStyle.clear(); - fallbackMethod.clear(); - configFilePath.clear(); - } - - QString resolveConfigFilePath() - { - if (configFilePath.isEmpty()) { - configFilePath = QFile::decodeName(qgetenv("QT_QUICK_CONTROLS_CONF")); - if (configFilePath.isEmpty() || !QFile::exists(configFilePath)) { - if (!configFilePath.isEmpty()) - qWarning("QT_QUICK_CONTROLS_CONF=%s: No such file", qPrintable(configFilePath)); - - configFilePath = QStringLiteral(":/qtquickcontrols2.conf"); - } - } - return configFilePath; - } - - // Is this a custom style defined by the user and not "built-in" style? - bool custom; - // Did we manage to find a valid style path? - bool resolved; - // The full path to the style. - QString style; - // The built-in style to use if the requested style cannot be found. - QString fallbackStyle; - // A description of the way in which fallbackStyle was set, used in e.g. warning messages shown to the user. - QByteArray fallbackMethod; - // The path to the qtquickcontrols2.conf file. - QString configFilePath; - // An extra list of directories where we search for available styles before any other directories. - QStringList customStylePaths; -}; - -Q_GLOBAL_STATIC(QQuickStyleSpec, styleSpec) - -static QStringList parseStylePathsWithColon(const QString &var) -{ - QStringList paths; - const QChar colon = QLatin1Char(':'); - int currentIndex = 0; - - do { - int nextColonIndex = -1; - QString path; - - if (var.at(currentIndex) == colon) { - // This is either a list separator, or a qrc path. - if (var.at(currentIndex + 1) == colon) { - // It's a double colon (list separator followed by qrc path); - // find the end of the path. - nextColonIndex = var.indexOf(colon, currentIndex + 2); - path = var.mid(currentIndex + 1, - nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex - 1); - } else { - // It's a single colon. - nextColonIndex = var.indexOf(colon, currentIndex + 1); - if (currentIndex == 0) { - // If we're at the start of the string, then it's a qrc path. - path = var.mid(currentIndex, - nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex); - } else { - // Otherwise, it's a separator. - path = var.mid(currentIndex + 1, - nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex - 1); - } - } - } else { - // It's a file path. - nextColonIndex = var.indexOf(colon, currentIndex); - path = var.mid(currentIndex, - nextColonIndex == -1 ? -1 : nextColonIndex - currentIndex); - } - - paths += path; - currentIndex = nextColonIndex; - - // Keep going until we can't find any more colons, - // or we're at the last character. - } while (currentIndex != -1 && currentIndex < var.size() - 1); - - return paths; -} - -QStringList QQuickStylePrivate::stylePaths(bool resolve) -{ - // user-requested style path - QStringList paths; - if (resolve) { - QString path = styleSpec()->path(); - if (path.endsWith(QLatin1Char('/'))) - path.chop(1); - if (!path.isEmpty()) - paths += path; - } - - if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE_PATH"))) { - const QString value = QString::fromLocal8Bit(qgetenv("QT_QUICK_CONTROLS_STYLE_PATH")); - const QChar listSeparator = QDir::listSeparator(); - if (listSeparator == QLatin1Char(':')) { - // Split manually to avoid breaking paths on systems where : is the list separator, - // since it's also used for qrc paths. - paths += parseStylePathsWithColon(value); - } else { - // Fast/simpler path for systems where something other than : is used as - // the list separator (such as ';'). - const QStringList customPaths = value.split(listSeparator, Qt::SkipEmptyParts); - paths += customPaths; - } - } - - // system/custom style paths - paths += styleSpec()->customStylePaths; - paths += envPathList("QT_QUICK_CONTROLS_STYLE_PATH"); - - // built-in import paths - const QString targetPath = QStringLiteral("QtQuick/Controls.2"); - const QStringList importPaths = defaultImportPathList(); - for (const QString &importPath : importPaths) { - QDir dir(importPath); - if (dir.cd(targetPath)) - paths += dir.absolutePath(); - } - - paths.removeDuplicates(); - return paths; -} - -QString QQuickStylePrivate::fallbackStyle() -{ - return styleSpec()->fallbackStyle; -} - -bool QQuickStylePrivate::isCustomStyle() -{ - return styleSpec()->custom; -} - -void QQuickStylePrivate::init(const QUrl &baseUrl) -{ - QQuickStyleSpec *spec = styleSpec(); - spec->resolve(baseUrl); - - if (!spec->fallbackStyle.isEmpty()) { - QString fallbackStyle; - const QStringList stylePaths = QQuickStylePrivate::stylePaths(); - for (const QString &path : stylePaths) { - fallbackStyle = spec->findStyle(path, spec->fallbackStyle); - if (!fallbackStyle.isEmpty()) - break; - } - if (fallbackStyle.isEmpty()) { - if (spec->fallbackStyle.compare(QStringLiteral("Default")) != 0) { - qWarning() << "ERROR: unable to locate fallback style" << spec->fallbackStyle; - qInfo().nospace().noquote() << spec->fallbackMethod << ": the fallback style must be the name of one of the built-in Qt Quick Controls 2 styles."; - } - spec->fallbackStyle.clear(); - } - } -} - -void QQuickStylePrivate::reset() -{ - if (styleSpec()) - styleSpec()->reset(); -} - -QString QQuickStylePrivate::configFilePath() -{ - return styleSpec()->resolveConfigFilePath(); -} - -QSharedPointer<QSettings> QQuickStylePrivate::settings(const QString &group) -{ -#ifndef QT_NO_SETTINGS - const QString filePath = QQuickStylePrivate::configFilePath(); - if (QFile::exists(filePath)) { - QFileSelector selector; - QSettings *settings = new QSettings(selector.select(filePath), QSettings::IniFormat); - if (!group.isEmpty()) - settings->beginGroup(group); - return QSharedPointer<QSettings>(settings); - } -#endif // QT_NO_SETTINGS - return QSharedPointer<QSettings>(); -} - -#if QT_CONFIG(settings) -static void readValue(const QSharedPointer<QSettings> &settings, const QString &name, std::function<void(const QVariant &)> setValue) -{ - const QVariant var = settings->value(name); - if (var.isValid()) - setValue(var); -} - -template <typename Enum> -static Enum toEnumValue(const QVariant &var) -{ - // ### TODO: expose QFont enums to the meta object system using Q_ENUM - //QMetaEnum enumeration = QMetaEnum::fromType<Enum>(); - //bool ok = false; - //int value = enumeration.keyToValue(var.toByteArray(), &ok); - //if (!ok) - // value = var.toInt(); - //return static_cast<Enum>(value); - - return static_cast<Enum>(var.toInt()); -} - -const QFont *QQuickStylePrivate::readFont(const QSharedPointer<QSettings> &settings) -{ - const QVariant var = settings->value(QStringLiteral("Font")); - if (var.isValid()) - return new QFont(var.value<QFont>()); - - QFont f; - settings->beginGroup(QStringLiteral("Font")); - readValue(settings, QStringLiteral("Family"), [&f](const QVariant &var) { f.setFamily(var.toString()); }); - readValue(settings, QStringLiteral("PointSize"), [&f](const QVariant &var) { f.setPointSizeF(var.toReal()); }); - readValue(settings, QStringLiteral("PixelSize"), [&f](const QVariant &var) { f.setPixelSize(var.toInt()); }); - readValue(settings, QStringLiteral("StyleHint"), [&f](const QVariant &var) { f.setStyleHint(toEnumValue<QFont::StyleHint>(var.toInt())); }); - readValue(settings, QStringLiteral("Weight"), [&f](const QVariant &var) { f.setWeight(toEnumValue<QFont::Weight>(var)); }); - readValue(settings, QStringLiteral("Style"), [&f](const QVariant &var) { f.setStyle(toEnumValue<QFont::Style>(var.toInt())); }); - settings->endGroup(); - return new QFont(f); -} - -static void readColorGroup(const QSharedPointer<QSettings> &settings, QPalette::ColorGroup group, QPalette *palette) -{ - const QStringList keys = settings->childKeys(); - if (keys.isEmpty()) - return; - - static const int index = QPalette::staticMetaObject.indexOfEnumerator("ColorRole"); - Q_ASSERT(index != -1); - QMetaEnum metaEnum = QPalette::staticMetaObject.enumerator(index); - - for (const QString &key : keys) { - bool ok = false; - int role = metaEnum.keyToValue(key.toUtf8(), &ok); - if (ok) - palette->setColor(group, static_cast<QPalette::ColorRole>(role), settings->value(key).value<QColor>()); - } -} - -const QPalette *QQuickStylePrivate::readPalette(const QSharedPointer<QSettings> &settings) -{ - QPalette p; - settings->beginGroup(QStringLiteral("Palette")); - readColorGroup(settings, QPalette::All, &p); - - settings->beginGroup(QStringLiteral("Normal")); - readColorGroup(settings, QPalette::Normal, &p); - settings->endGroup(); - - settings->beginGroup(QStringLiteral("Disabled")); - readColorGroup(settings, QPalette::Disabled, &p); - settings->endGroup(); - return new QPalette(p); -} -#endif // QT_CONFIG(settings) - -static bool qt_is_dark_system_theme() -{ - if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { - if (const QPalette *systemPalette = theme->palette(QPlatformTheme::SystemPalette)) { - const QColor &textColor = systemPalette->color(QPalette::WindowText); - return textColor.red() > 128 && textColor.blue() > 128 && textColor.green() > 128; - } - } - return false; -} - -bool QQuickStylePrivate::isDarkSystemTheme() -{ - static bool dark = qt_is_dark_system_theme(); - return dark; -} - -/*! - Returns the name of the application style. - - \note The application style can be specified by passing a \c -style command - line argument. Therefore \c name() may not return a fully resolved - value if called before constructing a QGuiApplication. -*/ -QString QQuickStyle::name() -{ - return styleSpec()->name(); -} - -/*! - Returns the path of an overridden application style, or an empty - string if the style is one of the built-in Qt Quick Controls 2 styles. - - \note The application style can be specified by passing a \c -style command - line argument. Therefore \c path() may not return a fully resolved - value if called before constructing a QGuiApplication. -*/ -QString QQuickStyle::path() -{ - return styleSpec()->path(); -} - -/*! - Sets the application style to \a style. - - \note The style must be configured \b before loading QML that imports Qt Quick Controls. - It is not possible to change the style after the QML types have been registered. - - \sa setFallbackStyle(), {Using Styles in Qt Quick Controls} -*/ -void QQuickStyle::setStyle(const QString &style) -{ - qCDebug(lcQtQuickControlsStyle) << "setStyle called with" << style; - - if (QQmlMetaType::matchingModuleVersion( - QStringLiteral("QtQuick.Controls"), QTypeRevision::fromVersion(2, 0)).isValid()) { - qWarning() << "ERROR: QQuickStyle::setStyle() must be called before loading QML that imports Qt Quick Controls 2."; - return; - } - - styleSpec()->setStyle(style); -} - -/*! - \since 5.8 - Sets the application fallback style to \a style. - - \note The fallback style must be the name of one of the built-in Qt Quick Controls styles, e.g. "Material". - - \note The style must be configured \b before loading QML that imports Qt Quick Controls. - It is not possible to change the style after the QML types have been registered. - - The fallback style can be also specified by setting the \c QT_QUICK_CONTROLS_FALLBACK_STYLE - \l {Supported Environment Variables in Qt Quick Controls}{environment variable}. - - \sa setStyle(), {Using Styles in Qt Quick Controls} -*/ -void QQuickStyle::setFallbackStyle(const QString &style) -{ - if (QQmlMetaType::matchingModuleVersion( - QStringLiteral("QtQuick.Controls"), QTypeRevision::fromVersion(2, 0)).isValid()) { - qWarning() << "ERROR: QQuickStyle::setFallbackStyle() must be called before loading QML that imports Qt Quick Controls 2."; - return; - } - - styleSpec()->setFallbackStyle(style, "QQuickStyle::setFallbackStyle()"); -} - -/*! - \since 5.9 - Returns the names of the available styles. - - \note The method must be called \b after creating an instance of QGuiApplication. - - \sa stylePathList(), addStylePath() -*/ -QStringList QQuickStyle::availableStyles() -{ - QStringList styles; - if (!QGuiApplication::instance()) { - qWarning() << "ERROR: QQuickStyle::availableStyles() must be called after creating an instance of QGuiApplication."; - return styles; - } - - const QStringList stylePaths = QQuickStylePrivate::stylePaths(); - for (const QString &path : stylePaths) { - const QList<QFileInfo> entries = QDir(path).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); - for (const QFileInfo &entry : entries) { - const QString name = entry.fileName(); - if (!name.endsWith(QLatin1String(".dSYM")) && name != QLatin1String("designer")) - styles += name; - } - } - styles.prepend(QStringLiteral("Default")); - styles.removeDuplicates(); - return styles; -} - -/*! - \since 5.12 - - Returns the list of directories where Qt Quick Controls 2 searches for available styles. - - By default, the list contains paths specified in the \c QT_QUICK_CONTROLS_STYLE_PATH - environment variable, and any existing \c QtQuick/Controls.2 sub-directories in - \l QQmlEngine::importPathList(). - - \sa addStylePath(), availableStyles() -*/ -QStringList QQuickStyle::stylePathList() -{ - return QQuickStylePrivate::stylePaths(); -} - -/*! - \since 5.12 - - Adds \a path as a directory where Qt Quick Controls 2 searches for available styles. - - The \a path may be any local filesystem directory or \l {The Qt Resource System}{Qt Resource} directory. - For example, the following paths are all valid: - - \list - \li \c {/path/to/styles/} - \li \c {file:///path/to/styles/} - \li \c {:/path/to/styles/} - \li \c {qrc:/path/to/styles/}) - \endlist - - The \a path will be converted into \l {QDir::canonicalPath}{canonical form} before it is added to - the style path list. - - The newly added \a path will be first in the stylePathList(). - - \sa stylePathList(), availableStyles() -*/ -void QQuickStyle::addStylePath(const QString &path) -{ - if (path.isEmpty()) - return; - - const QUrl url = QUrl(path); - if (url.isRelative() || url.scheme() == QLatin1String("file") - || (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path - styleSpec()->customStylePaths.prepend(QDir(path).canonicalPath()); - } else if (url.scheme() == QLatin1String("qrc")) { - styleSpec()->customStylePaths.prepend(QLatin1Char(':') + url.path()); - } else { - styleSpec()->customStylePaths.prepend(path); - } -} - -QT_END_NAMESPACE |