diff --git a/src/desktopicon.cpp b/src/desktopicon.cpp index 0aa3d315..1c2589f1 100644 --- a/src/desktopicon.cpp +++ b/src/desktopicon.cpp @@ -1,280 +1,349 @@ /* * Copyright 2011 Marco Martin * Copyright 2014 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "desktopicon.h" #include #include #include +#include #include #include #include #include #include - +#include +#include class ManagedTextureNode : public QSGSimpleTextureNode { Q_DISABLE_COPY(ManagedTextureNode) public: ManagedTextureNode(); void setTexture(QSharedPointer texture); private: QSharedPointer m_texture; }; ManagedTextureNode::ManagedTextureNode() {} void ManagedTextureNode::setTexture(QSharedPointer texture) { m_texture = texture; QSGSimpleTextureNode::setTexture(texture.data()); } typedef QHash > > TexturesCache; struct ImageTexturesCachePrivate { TexturesCache cache; }; class ImageTexturesCache { public: ImageTexturesCache(); ~ImageTexturesCache(); /** * @returns the texture for a given @p window and @p image. * * If an @p image id is the same as one already provided before, we won't create * a new texture and return a shared pointer to the existing texture. */ QSharedPointer loadTexture(QQuickWindow *window, const QImage &image, QQuickWindow::CreateTextureOptions options); QSharedPointer loadTexture(QQuickWindow *window, const QImage &image); private: QScopedPointer d; }; ImageTexturesCache::ImageTexturesCache() : d(new ImageTexturesCachePrivate) { } ImageTexturesCache::~ImageTexturesCache() { } QSharedPointer ImageTexturesCache::loadTexture(QQuickWindow *window, const QImage &image, QQuickWindow::CreateTextureOptions options) { qint64 id = image.cacheKey(); QSharedPointer texture = d->cache.value(id).value(window).toStrongRef(); if (!texture) { auto cleanAndDelete = [this, window, id](QSGTexture* texture) { QHash >& textures = (d->cache)[id]; textures.remove(window); if (textures.isEmpty()) d->cache.remove(id); delete texture; }; texture = QSharedPointer(window->createTextureFromImage(image, options), cleanAndDelete); (d->cache)[id][window] = texture.toWeakRef(); } //if we have a cache in an atlas but our request cannot use an atlassed texture //create a new texture and use that //don't use removedFromAtlas() as that requires keeping a reference to the non atlased version if (!(options & QQuickWindow::TextureCanUseAtlas) && texture->isAtlasTexture()) { texture = QSharedPointer(window->createTextureFromImage(image, options)); } return texture; } QSharedPointer ImageTexturesCache::loadTexture(QQuickWindow *window, const QImage &image) { return loadTexture(window, image, 0); } Q_GLOBAL_STATIC(ImageTexturesCache, s_iconImageCache) DesktopIcon::DesktopIcon(QQuickItem *parent) : QQuickItem(parent), m_smooth(false), m_changed(false), m_active(false), m_selected(false) { setFlag(ItemHasContents, true); } DesktopIcon::~DesktopIcon() { } void DesktopIcon::setSource(const QVariant &icon) { - if(icon.canConvert()) { - m_icon = icon.value(); - } else if(icon.canConvert()) { - m_icon = QIcon::fromTheme(icon.toString()); - } else { - m_icon = QIcon(); + if (m_source == icon) { + return; } + m_source = icon; m_changed = true; update(); emit sourceChanged(); } -QIcon DesktopIcon::source() const +QVariant DesktopIcon::source() const { - return m_icon; + return m_source; } void DesktopIcon::setEnabled(const bool enabled) { if (enabled == QQuickItem::isEnabled()) { return; } QQuickItem::setEnabled(enabled); m_changed = true; update(); emit enabledChanged(); } void DesktopIcon::setActive(const bool active) { if (active == m_active) { return; } m_active = active; m_changed = true; update(); emit activeChanged(); } bool DesktopIcon::active() const { return m_active; } bool DesktopIcon::valid() const { - return !m_icon.isNull(); + return !m_source.isNull(); } void DesktopIcon::setSelected(const bool selected) { if (selected == m_selected) { return; } m_selected = selected; m_changed = true; update(); emit selectedChanged(); } bool DesktopIcon::selected() const { return m_selected; } int DesktopIcon::implicitWidth() const { return 32; } int DesktopIcon::implicitHeight() const { return 32; } void DesktopIcon::setSmooth(const bool smooth) { if (smooth == m_smooth) { return; } m_smooth = smooth; m_changed = true; update(); emit smoothChanged(); } bool DesktopIcon::smooth() const { return m_smooth; } QSGNode* DesktopIcon::updatePaintNode(QSGNode* node, QQuickItem::UpdatePaintNodeData* /*data*/) { - if (m_icon.isNull()) { + if (m_source.isNull()) { delete node; return Q_NULLPTR; } if (m_changed || node == 0) { + QImage img; + const QSize size(width(), height()); + + switch(m_source.type()){ + case QVariant::Pixmap: + img = m_source.value().toImage(); + break; + case QVariant::Image: + img = m_source.value(); + break; + case QVariant::Bitmap: + img = m_source.value().toImage(); + break; + case QVariant::Icon: + img = m_source.value().pixmap(size, iconMode(), QIcon::On).toImage(); + break; + case QVariant::String: + img = findIcon(size); + break; + case QVariant::Brush: + case QVariant::Color: + //perhaps fill image instead? + default: + break; + } + + if (img.isNull()){ + img = QImage(size, QImage::Format_Alpha8); + img.fill(Qt::transparent); + } + if (img.size() != size){ + img = img.scaled(size, Qt::IgnoreAspectRatio, m_smooth ? Qt::SmoothTransformation : Qt::FastTransformation ); + } m_changed = false; ManagedTextureNode* mNode = dynamic_cast(node); - if(!mNode) { + if (!mNode) { delete node; mNode = new ManagedTextureNode; } - QIcon::Mode mode = QIcon::Normal; - if (!isEnabled()) { - mode = QIcon::Disabled; - } else if (m_selected) { - mode = QIcon::Selected; - } else if (m_active) { - mode = QIcon::Active; - } - - QImage img; - const QSize size(width(), height()); - if (!size.isEmpty()) { - img = m_icon.pixmap(size, mode, QIcon::On).toImage(); - } mNode->setTexture(s_iconImageCache->loadTexture(window(), img)); mNode->setRect(QRect(QPoint(0,0), size)); node = mNode; } return node; } void DesktopIcon::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { if (newGeometry.size() != oldGeometry.size()) { m_changed = true; update(); } QQuickItem::geometryChanged(newGeometry, oldGeometry); } + +QImage DesktopIcon::findIcon(const QSize &size) +{ + QImage img; + QString iconSource = m_source.toString(); + if (iconSource.startsWith("image://")){ + QUrl iconUrl(iconSource); + QString iconProviderId = iconUrl.host(); + QString iconId = iconUrl.path(); + QSize actualSize; + QQuickImageProvider* imageProvider = dynamic_cast( + qmlEngine(this)->imageProvider(iconProviderId)); + if (!imageProvider) + return img; + switch(imageProvider->imageType()){ + case QQmlImageProviderBase::Image: + img = imageProvider->requestImage(iconId, &actualSize, size); + case QQmlImageProviderBase::Pixmap: + img = imageProvider->requestPixmap(iconId, &actualSize, size).toImage(); + case QQmlImageProviderBase::Texture: + case QQmlImageProviderBase::Invalid: + case QQmlImageProviderBase::ImageResponse: + //will have to investigate this more + break; + } + }else { + if (iconSource.startsWith("qrc:/")){ + iconSource = iconSource.mid(3); + } + QIcon icon(iconSource); + if (icon.isNull()){ + icon = QIcon::fromTheme(iconSource); + } + if (!icon.isNull()){ + img = icon.pixmap(size, iconMode(), QIcon::On).toImage(); + } + } + return img; +} + +QIcon::Mode DesktopIcon::iconMode() const +{ + if (!isEnabled()) { + return QIcon::Disabled; + } else if (m_selected) { + return QIcon::Selected; + } else if (m_active) { + return QIcon::Active; + } + return QIcon::Normal; +} diff --git a/src/desktopicon.h b/src/desktopicon.h index a6bd5f17..3547f7bd 100644 --- a/src/desktopicon.h +++ b/src/desktopicon.h @@ -1,85 +1,86 @@ /* * Copyright 2011 Marco Martin * Copyright 2014 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef QICONITEM_H #define QICONITEM_H #include #include #include class DesktopIcon : public QQuickItem { Q_OBJECT Q_PROPERTY(QVariant source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(bool smooth READ smooth WRITE setSmooth NOTIFY smoothChanged) Q_PROPERTY(int implicitWidth READ implicitWidth CONSTANT) Q_PROPERTY(int implicitHeight READ implicitHeight CONSTANT) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) Q_PROPERTY(bool valid READ valid NOTIFY validChanged) Q_PROPERTY(bool selected READ selected WRITE setSelected NOTIFY selectedChanged) public: DesktopIcon(QQuickItem *parent=0); ~DesktopIcon(); void setSource(const QVariant &source); - QIcon source() const; + QVariant source() const; int implicitWidth() const; int implicitHeight() const; void setSmooth(const bool smooth); bool smooth() const; void setEnabled(bool enabled = true); void setActive(bool active = true); bool active() const; bool valid() const; void setSelected(bool selected = true); bool selected() const; QSGNode* updatePaintNode(QSGNode* node, UpdatePaintNodeData* data) Q_DECL_OVERRIDE; Q_SIGNALS: void sourceChanged(); void smoothChanged(); void enabledChanged(); void activeChanged(); void validChanged(); void selectedChanged(); protected: void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; - + QImage findIcon(const QSize& size); + QIcon::Mode iconMode() const; private: - QIcon m_icon; + QVariant m_source; bool m_smooth; bool m_changed; bool m_active; bool m_selected; }; #endif diff --git a/src/kirigamiplugin.cpp b/src/kirigamiplugin.cpp index dc301ce4..c1722e61 100644 --- a/src/kirigamiplugin.cpp +++ b/src/kirigamiplugin.cpp @@ -1,115 +1,111 @@ /* * Copyright 2009 by Alan Alpert * Copyright 2010 by Ménard Alexis * Copyright 2010 by Marco Martin * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kirigamiplugin.h" #include "enums.h" #include "desktopicon.h" #include "settings.h" #include #include #include QUrl KirigamiPlugin::componentUrl(const QString &fileName) const { foreach (const QString &style, m_stylesFallbackChain) { const QString candidate = QStringLiteral("styles/") + style + QLatin1Char('/') + fileName; if (QFile::exists(resolveFilePath(candidate))) { return QUrl(resolveFileUrl(candidate)); } } return QUrl(resolveFileUrl(fileName)); } void KirigamiPlugin::registerTypes(const char *uri) { Q_ASSERT(uri == QLatin1String("org.kde.kirigami")); const QString style = QString::fromLatin1(qgetenv("QT_QUICK_CONTROLS_STYLE")); #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) if (style.isEmpty() && QFile::exists(resolveFilePath(QStringLiteral("/styles/Desktop")))) { m_stylesFallbackChain.prepend(QStringLiteral("Desktop")); } #endif if (!style.isEmpty() && QFile::exists(resolveFilePath(QStringLiteral("/styles/") + style))) { m_stylesFallbackChain.prepend(style); } //At this point the fallback chain will be selected->Desktop->Fallback //TODO: in this plugin it will end up something similar to //PlasmaCore's ColorScope? qmlRegisterSingletonType(uri, 2, 0, "Settings", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Settings; } ); qmlRegisterUncreatableType(uri, 2, 0, "ApplicationHeaderStyle", "Cannot create objects of type ApplicationHeaderStyle"); qmlRegisterSingletonType(componentUrl(QStringLiteral("Theme.qml")), uri, 2, 0, "Theme"); qmlRegisterSingletonType(componentUrl(QStringLiteral("Units.qml")), uri, 2, 0, "Units"); qmlRegisterType(componentUrl(QStringLiteral("Action.qml")), uri, 2, 0, "Action"); qmlRegisterType(componentUrl(QStringLiteral("AbstractApplicationHeader.qml")), uri, 2, 0, "AbstractApplicationHeader"); qmlRegisterType(componentUrl(QStringLiteral("AbstractApplicationWindow.qml")), uri, 2, 0, "AbstractApplicationWindow"); qmlRegisterType(componentUrl(QStringLiteral("AbstractListItem.qml")), uri, 2, 0, "AbstractListItem"); qmlRegisterType(componentUrl(QStringLiteral("ApplicationHeader.qml")), uri, 2, 0, "ApplicationHeader"); qmlRegisterType(componentUrl(QStringLiteral("ToolBarApplicationHeader.qml")), uri, 2, 0, "ToolBarApplicationHeader"); qmlRegisterType(componentUrl(QStringLiteral("ApplicationWindow.qml")), uri, 2, 0, "ApplicationWindow"); qmlRegisterType(componentUrl(QStringLiteral("BasicListItem.qml")), uri, 2, 0, "BasicListItem"); qmlRegisterType(componentUrl(QStringLiteral("OverlayDrawer.qml")), uri, 2, 0, "OverlayDrawer"); qmlRegisterType(componentUrl(QStringLiteral("ContextDrawer.qml")), uri, 2, 0, "ContextDrawer"); qmlRegisterType(componentUrl(QStringLiteral("GlobalDrawer.qml")), uri, 2, 0, "GlobalDrawer"); qmlRegisterType(componentUrl(QStringLiteral("Heading.qml")), uri, 2, 0, "Heading"); qmlRegisterType(componentUrl(QStringLiteral("Separator.qml")), uri, 2, 0, "Separator"); qmlRegisterType(componentUrl(QStringLiteral("PageRow.qml")), uri, 2, 0, "PageRow"); //The icon is "special: we have to use a wrapper class to QIcon on desktops #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) - if (!m_stylesFallbackChain.isEmpty() && m_stylesFallbackChain.first() == QStringLiteral("Desktop")) { - qmlRegisterType(uri, 2, 0, "Icon"); - } else { - qmlRegisterType(componentUrl(QStringLiteral("Icon.qml")), uri, 2, 0, "Icon"); - } + qmlRegisterType(uri, 2, 0, "Icon"); #else qmlRegisterType(componentUrl(QStringLiteral("Icon.qml")), uri, 2, 0, "Icon"); #endif qmlRegisterType(componentUrl(QStringLiteral("Label.qml")), uri, 2, 0, "Label"); qmlRegisterType(componentUrl(QStringLiteral("OverlaySheet.qml")), uri, 2, 0, "OverlaySheet"); qmlRegisterType(componentUrl(QStringLiteral("Page.qml")), uri, 2, 0, "Page"); qmlRegisterType(componentUrl(QStringLiteral("ScrollablePage.qml")), uri, 2, 0, "ScrollablePage"); qmlRegisterType(componentUrl(QStringLiteral("SplitDrawer.qml")), uri, 2, 0, "SplitDrawer"); qmlRegisterType(componentUrl(QStringLiteral("SwipeListItem.qml")), uri, 2, 0, "SwipeListItem"); //2.1 qmlRegisterType(componentUrl(QStringLiteral("AbstractItemViewHeader.qml")), uri, 2, 1, "AbstractItemViewHeader"); qmlRegisterType(componentUrl(QStringLiteral("ItemViewHeader.qml")), uri, 2, 1, "ItemViewHeader"); qmlProtectModule(uri, 2); } #include "moc_kirigamiplugin.cpp"