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