diff options
Diffstat (limited to 'src/imports/controls/imagine/qquickimageselector.cpp')
-rw-r--r-- | src/imports/controls/imagine/qquickimageselector.cpp | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/src/imports/controls/imagine/qquickimageselector.cpp b/src/imports/controls/imagine/qquickimageselector.cpp new file mode 100644 index 00000000..dd8a0c2d --- /dev/null +++ b/src/imports/controls/imagine/qquickimageselector.cpp @@ -0,0 +1,321 @@ +/**************************************************************************** +** +** 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 "qquickimageselector_p.h" + +#include <QtCore/qdir.h> +#include <QtCore/qfileinfo.h> +#include <QtCore/qcache.h> +#include <QtQml/qqmlfile.h> +#include <QtQml/private/qqmlproperty_p.h> +#include <algorithm> + +QT_BEGIN_NAMESPACE + +// input: [focused, pressed] +// => [[focused, pressed], [pressed, focused], [focused], [pressed]] +static QList<QStringList> permutations(const QStringList &input, int count = -1) +{ + if (count == -1) + count = input.count(); + + QList<QStringList> output; + for (int i = 0; i < input.count(); ++i) { + QStringList sub = input.mid(i, count); + + if (count > 1) { + if (i + count > input.count()) + sub += input.mid(0, count - i + 1); + + std::sort(sub.begin(), sub.end()); + do { + if (!sub.isEmpty()) + output += sub; + } while (std::next_permutation(sub.begin(), sub.end())); + } else { + output += sub; + } + + if (count == input.count()) + break; + } + + if (count > 1) + output += permutations(input, --count); + + return output; +} + +static QString findFile(const QDir &dir, const QString &baseName, const QStringList &extensions) +{ + for (const QString &ext : extensions) { + QString filePath = dir.filePath(baseName + QLatin1Char('.') + ext); + if (QFile::exists(filePath)) + return filePath; + } + return QString(); +} + +QQuickImageSelector::QQuickImageSelector(QObject *parent) + : QObject(parent), + m_cache(false), + m_complete(false), + m_separator(QLatin1String("-")) +{ +} + +QUrl QQuickImageSelector::source() const +{ + return m_source; +} + +void QQuickImageSelector::setSource(const QUrl &source) +{ + if (m_property.isValid()) + QQmlPropertyPrivate::write(m_property, source, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); + if (m_source == source) + return; + + m_source = source; + emit sourceChanged(); +} + +QString QQuickImageSelector::name() const +{ + return m_name; +} + +void QQuickImageSelector::setName(const QString &name) +{ + if (m_name == name) + return; + + m_name = name; + if (m_complete) + updateSource(); +} + +QString QQuickImageSelector::path() const +{ + return m_path; +} + +void QQuickImageSelector::setPath(const QString &path) +{ + if (m_path == path) + return; + + m_path = path; + if (m_complete) + updateSource(); +} + +QVariantList QQuickImageSelector::states() const +{ + return m_allStates; +} + +void QQuickImageSelector::setStates(const QVariantList &states) +{ + if (m_allStates == states) + return; + + m_allStates = states; + if (updateActiveStates() && m_complete) + updateSource(); +} + +QString QQuickImageSelector::separator() const +{ + return m_separator; +} + +void QQuickImageSelector::setSeparator(const QString &separator) +{ + if (m_separator == separator) + return; + + m_separator = separator; + if (m_complete) + updateSource(); +} + +bool QQuickImageSelector::cache() const +{ + return m_cache; +} + +void QQuickImageSelector::setCache(bool cache) +{ + m_cache = cache; +} + +void QQuickImageSelector::write(const QVariant &value) +{ + setUrl(value.value<QUrl>()); +} + +void QQuickImageSelector::setTarget(const QQmlProperty &property) +{ + m_property = property; +} + +void QQuickImageSelector::classBegin() +{ +} + +void QQuickImageSelector::componentComplete() +{ + setUrl(m_property.read().value<QUrl>()); + m_complete = true; + updateSource(); +} + +QStringList QQuickImageSelector::fileExtensions() const +{ + static const QStringList extensions = QStringList() << QStringLiteral("png"); + return extensions; +} + +QString QQuickImageSelector::cacheKey() const +{ + if (!m_cache) + return QString(); + + return m_path + m_name + m_activeStates.join(m_separator); +} + +void QQuickImageSelector::updateSource() +{ + static QCache<QString, QString> cache(200); // TODO: cost + + const QString key = cacheKey(); + + QString bestFilePath; + if (m_cache) { + QString *cachedPath = cache.object(key); + if (cachedPath) + bestFilePath = *cachedPath; + } + + if (bestFilePath.isEmpty()) { + QDir dir(m_path); + int bestScore = -1; + + const QStringList extensions = fileExtensions(); + + const QList<QStringList> statePerms = permutations(m_activeStates); + for (const QStringList &perm : statePerms) { + const QString filePath = findFile(dir, m_name + m_separator + perm.join(m_separator), extensions); + if (!filePath.isEmpty()) { + int score = calculateScore(perm); + if (score > bestScore) { + bestScore = score; + bestFilePath = filePath; + } + } + } + + if (bestFilePath.isEmpty()) + bestFilePath = findFile(dir, m_name, extensions); + + if (m_cache) + cache.insert(key, new QString(bestFilePath)); + } + + if (bestFilePath.startsWith(QLatin1Char(':'))) + setSource(QUrl(QLatin1String("qrc") + bestFilePath)); + else + setSource(QUrl::fromLocalFile(bestFilePath)); +} + +void QQuickImageSelector::setUrl(const QUrl &url) +{ + QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(url)); + setName(fileInfo.fileName()); + setPath(fileInfo.path()); +} + +bool QQuickImageSelector::updateActiveStates() +{ + QStringList active; + for (const QVariant &v : qAsConst(m_allStates)) { + const QVariantMap state = v.toMap(); + if (state.isEmpty()) + continue; + auto it = state.begin(); + if (it.value().toBool()) + active += it.key(); + } + + if (m_activeStates == active) + return false; + + m_activeStates = active; + return true; +} + +int QQuickImageSelector::calculateScore(const QStringList &states) const +{ + int score = 0; + for (int i = 0; i < states.count(); ++i) + score += (m_activeStates.count() - m_activeStates.indexOf(states.at(i))) << 1; + return score; +} + +QQuickNinePatchImageSelector::QQuickNinePatchImageSelector(QObject *parent) + : QQuickImageSelector(parent) +{ +} + +QStringList QQuickNinePatchImageSelector::fileExtensions() const +{ + static const QStringList extensions = QStringList() << QStringLiteral("9.png") << QStringLiteral("png"); + return extensions; +} + +QQuickAnimatedImageSelector::QQuickAnimatedImageSelector(QObject *parent) + : QQuickImageSelector(parent) +{ +} + +QStringList QQuickAnimatedImageSelector::fileExtensions() const +{ + static const QStringList extensions = QStringList() << QStringLiteral("webp") << QStringLiteral("gif"); + return extensions; +} + +QT_END_NAMESPACE |