File indexing completed on 2024-04-28 15:27:42

0001 /*
0002  *  SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
0003  *  SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0004  *  SPDX-FileCopyrightText: 2020 Carson Black <uhhadd@gmail.com>
0005  *
0006  *  SPDX-License-Identifier: LGPL-2.0-or-later
0007  */
0008 
0009 #pragma once
0010 
0011 #include <QIcon>
0012 #include <QPointer>
0013 #include <QQuickItem>
0014 #include <QVariant>
0015 
0016 class QNetworkReply;
0017 
0018 namespace Kirigami
0019 {
0020 class PlatformTheme;
0021 }
0022 
0023 /**
0024  * Class for rendering an icon in UI.
0025  */
0026 class Icon : public QQuickItem
0027 {
0028     Q_OBJECT
0029 
0030     /**
0031      * @brief This property holds the source of this icon.
0032      *
0033      * The icon can be pulled from:
0034      * * The Freedesktop standard icon name:
0035      * @include icon/IconThemeSource.qml
0036      * * The filesystem:
0037      * @include icon/FilesystemSource.qml
0038      * * Remote URIs:
0039      * @include icon/InternetSource.qml
0040      * * Custom providers:
0041      * @include icon/CustomSource.qml
0042      * * Your application's bundled resources:
0043      * @include icon/ResourceSource.qml
0044      *
0045      * @note See https://doc.qt.io/qt-5/qtquickcontrols2-icons.html for how to
0046      * bundle icon themes in your application to refer to them by name instead of
0047      * by resource URL.
0048      *
0049      * @note Use `fallback` to provide a fallback theme name for icons.
0050      *
0051      * @note Cuttlefish is a KDE application that lets you view all the icons that
0052      * you can use for your application. It offers a number of useful features such
0053      * as previews of their appearance across different installed themes, previews
0054      * at different sizes, and more. You might find it a useful tool when deciding
0055      * on which icons to use in your application.
0056      */
0057     Q_PROPERTY(QVariant source READ source WRITE setSource NOTIFY sourceChanged)
0058 
0059     /**
0060      * @brief This property holds the name of an icon from the icon theme
0061      * as a fallback for when an icon set with the ``source`` property is not found.
0062      *
0063      * @include icon/Fallback.qml
0064      * @note This will only be loaded if source is unavailable (e.g. it doesn't exist, or network issues have prevented loading).
0065      */
0066     Q_PROPERTY(QString fallback READ fallback WRITE setFallback NOTIFY fallbackChanged)
0067 
0068     /**
0069      * @brief This property holds the name of an icon from the icon theme to show
0070      * while the icon set in `source` is being loaded.
0071      *
0072      * This will only be used if the source image is a type that can have such a
0073      * long loading time that showing a temporary image in its place makes sense
0074      * (e.g. a remote image, or an image from an ImageProvider of the type
0075      * QtQml.QQmlImageProviderBase.ImageResponse).
0076      *
0077      * default: ``"image-png"``
0078      *
0079      * @since KDE Frameworks 5.15
0080      */
0081     Q_PROPERTY(QString placeholder READ placeholder WRITE setPlaceholder NOTIFY placeholderChanged)
0082 
0083     /**
0084      * @brief This property sets whether the icon will use the
0085      * @link QtGui.QIcon.Mode QIcon.Active @endlink mode,
0086      * resulting in a graphical effect being applied when the icon is currently active.
0087      *
0088      * @note This is typically used to indicate when an item is being hovered or pressed.
0089      *
0090      * @image html icon/active.png
0091      *
0092      * The color differences under the default KDE color palette, Breeze. Note
0093      * that a dull highlight background is typically displayed behind active icons and
0094      * it is recommended to add one if you are creating a custom component.
0095      *
0096      * default: ``false``
0097      */
0098     Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
0099 
0100     /**
0101      * @brief This property specifies whether the icon's `source` is valid and is being used.
0102      */
0103     Q_PROPERTY(bool valid READ valid NOTIFY validChanged)
0104 
0105     /**
0106      * @brief This property sets whether the icon will use the
0107      * @link QtGui.QIcon.Mode QIcon.Selected @endlink mode,
0108      * resulting in a graphical effect being applied when the icon is currently selected.
0109      *
0110      * This is typically used to indicate when a list item is currently selected.
0111      *
0112      * @image html icon/selected.png
0113      *
0114      * The color differences under the default KDE color palette, Breeze. Note
0115      * that a blue background is typically displayed behind selected elements.
0116      *
0117      * default: ``false``
0118      */
0119     Q_PROPERTY(bool selected READ selected WRITE setSelected NOTIFY selectedChanged)
0120 
0121     /**
0122      * @brief This property sets whether this icon will be treated as a mask.
0123      *
0124      * When an icon is being used as a mask, all non-transparent colors are replaced
0125      * with the color provided in the Icon's ::color property.
0126      *
0127      * default: ``false``
0128      *
0129      * @see ::color
0130      */
0131     Q_PROPERTY(bool isMask READ isMask WRITE setIsMask NOTIFY isMaskChanged)
0132 
0133     /**
0134      * @brief This property holds the color to use when drawing the icon.
0135      *
0136      * This property is used only when ::isMask is set to true.
0137      * If this property is not set or is `Qt::transparent`, the icon will use
0138      * the text or the selected text color, depending on if ::selected is set to
0139      * true.
0140      *
0141      * default: ``Qt::transparent``
0142      * @see Qt::GlobalColor
0143      */
0144     Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
0145 
0146     /**
0147      * @brief This property specifies the status of the icon.
0148      *
0149      * @note Image loading will not be initiated until the item is shown, so if the Icon is not visible,
0150      * it can only have Null or Loading states.
0151      *
0152      * default: ``Status::Null``
0153      *
0154      * @since KDE Frameworks 5.15
0155      */
0156     Q_PROPERTY(Icon::Status status READ status NOTIFY statusChanged)
0157 
0158     /**
0159      * @brief This property holds the width of the painted area in pixels.
0160      *
0161      * This will be smaller than or equal to the width of the area
0162      * taken up by the Item itself. This can be 0.
0163      *
0164      * default: ``0.0``
0165      *
0166      * @since KDE Frameworks 5.15
0167      */
0168     Q_PROPERTY(qreal paintedWidth READ paintedWidth NOTIFY paintedAreaChanged)
0169 
0170     /**
0171      * @brief This property holds the height of the painted area in pixels.
0172      *
0173      * This will be smaller than or equal to the height of the area
0174      * taken up by the Item itself. This can be 0.
0175      *
0176      * default: ``0.0``
0177      *
0178      * @since KDE Frameworks 5.15
0179      */
0180     Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedAreaChanged)
0181 public:
0182     /**
0183      * @brief This enum indicates the current status of the icon.
0184      */
0185     enum Status {
0186         /**
0187          * @brief No icon source has been set.
0188          */
0189         Null = 0,
0190 
0191         /**
0192          * @brief The icon has been loaded correctly.
0193          */
0194         Ready,
0195 
0196         /**
0197          * @brief The icon is currently being loaded.
0198          */
0199         Loading,
0200 
0201         /**
0202          * @brief There was an error while loading the icon, for instance
0203          * a non existent themed name, or an invalid url.
0204          */
0205         Error,
0206     };
0207     Q_ENUM(Status)
0208 
0209     Icon(QQuickItem *parent = nullptr);
0210     ~Icon() override;
0211 
0212     void setSource(const QVariant &source);
0213     QVariant source() const;
0214 
0215     void setActive(bool active = true);
0216     bool active() const;
0217 
0218     bool valid() const;
0219 
0220     void setSelected(bool selected = true);
0221     bool selected() const;
0222 
0223     void setIsMask(bool mask);
0224     bool isMask() const;
0225 
0226     void setColor(const QColor &color);
0227     QColor color() const;
0228 
0229     QString fallback() const;
0230     void setFallback(const QString &fallback);
0231 
0232     QString placeholder() const;
0233     void setPlaceholder(const QString &placeholder);
0234 
0235     Status status() const;
0236 
0237     qreal paintedWidth() const;
0238     qreal paintedHeight() const;
0239 
0240     QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *data) override;
0241 
0242 Q_SIGNALS:
0243     void sourceChanged();
0244     void activeChanged();
0245     void validChanged();
0246     void selectedChanged();
0247     void isMaskChanged();
0248     void colorChanged();
0249     void fallbackChanged(const QString &fallback);
0250     void placeholderChanged(const QString &placeholder);
0251     void statusChanged();
0252     void paintedAreaChanged();
0253 
0254 protected:
0255 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0256     void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
0257 #else
0258     void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
0259 #endif
0260     QImage findIcon(const QSize &size);
0261     void handleFinished(QNetworkReply *reply);
0262     void handleRedirect(QNetworkReply *reply);
0263     QIcon::Mode iconMode() const;
0264     bool guessMonochrome(const QImage &img);
0265     void setStatus(Status status);
0266     void updatePolish() override;
0267     void updatePaintedGeometry();
0268     void updateIsMaskHeuristic(const QString &iconSource);
0269     void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) override;
0270 
0271 private:
0272     Kirigami::PlatformTheme *m_theme = nullptr;
0273     QPointer<QNetworkReply> m_networkReply;
0274     QHash<int, bool> m_monochromeHeuristics;
0275     QVariant m_source;
0276     Status m_status = Null;
0277     bool m_changed;
0278     bool m_active;
0279     bool m_selected;
0280     bool m_isMask;
0281     bool m_isMaskHeuristic = false;
0282     QImage m_loadedImage;
0283     QColor m_color = Qt::transparent;
0284     QString m_fallback = QStringLiteral("unknown");
0285     QString m_placeholder = QStringLiteral("image-png");
0286     qreal m_paintedWidth = 0.0;
0287     qreal m_paintedHeight = 0.0;
0288 
0289     QImage m_icon;
0290 };