Warning, file /frameworks/kguiaddons/src/util/kiconutils.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2013 Martin Klapetek <mklapetek@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include <array> 0008 0009 #include "kiconutils.h" 0010 0011 #include <QHash> 0012 #include <QIconEngine> 0013 #include <QPainter> 0014 0015 class KOverlayIconEngine : public QIconEngine 0016 { 0017 public: 0018 KOverlayIconEngine(const QIcon &icon, const QIcon &overlay, Qt::Corner position); 0019 KOverlayIconEngine(const QIcon &icon, const QHash<Qt::Corner, QIcon> &overlays); 0020 KOverlayIconEngine(const QIcon &icon, const QStringList &overlays); 0021 void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override; 0022 QIconEngine *clone() const override; 0023 0024 QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override; 0025 QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override; 0026 0027 void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state) override; 0028 void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state) override; 0029 0030 void virtual_hook(int id, void *data) override; 0031 0032 private: 0033 QIcon m_base; 0034 QHash<Qt::Corner, QIcon> m_overlays; 0035 }; 0036 0037 KOverlayIconEngine::KOverlayIconEngine(const QIcon &icon, const QIcon &overlay, Qt::Corner position) 0038 : QIconEngine() 0039 , m_base(icon) 0040 { 0041 m_overlays.insert(position, overlay); 0042 } 0043 0044 KOverlayIconEngine::KOverlayIconEngine(const QIcon &icon, const QHash<Qt::Corner, QIcon> &overlays) 0045 : QIconEngine() 0046 , m_base(icon) 0047 , m_overlays(overlays) 0048 { 0049 } 0050 0051 KOverlayIconEngine::KOverlayIconEngine(const QIcon &icon, const QStringList &overlays) 0052 : QIconEngine() 0053 , m_base(icon) 0054 { 0055 const std::array<Qt::Corner, 4> indexToCorner{ 0056 Qt::BottomRightCorner, 0057 Qt::BottomLeftCorner, 0058 Qt::TopLeftCorner, 0059 Qt::TopRightCorner, 0060 }; 0061 0062 // static_cast becaue size() returns a qsizetype in Qt6 0063 const int count = std::min(4, static_cast<int>(overlays.size())); 0064 0065 m_overlays.reserve(count); 0066 0067 for (int i = 0; i < count; i++) { 0068 m_overlays.insert(indexToCorner[i], QIcon::fromTheme(overlays.at(i))); 0069 } 0070 } 0071 0072 QIconEngine *KOverlayIconEngine::clone() const 0073 { 0074 return new KOverlayIconEngine(*this); 0075 } 0076 0077 QSize KOverlayIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) 0078 { 0079 return m_base.actualSize(size, mode, state); 0080 } 0081 0082 QPixmap KOverlayIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) 0083 { 0084 QPixmap pixmap(size); 0085 pixmap.fill(Qt::transparent); 0086 QPainter p(&pixmap); 0087 0088 paint(&p, pixmap.rect(), mode, state); 0089 0090 return pixmap; 0091 } 0092 0093 void KOverlayIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state) 0094 { 0095 m_base.addPixmap(pixmap, mode, state); 0096 } 0097 0098 void KOverlayIconEngine::addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state) 0099 { 0100 m_base.addFile(fileName, size, mode, state); 0101 } 0102 0103 void KOverlayIconEngine::virtual_hook(int id, void *data) 0104 { 0105 if (id == QIconEngine::ScaledPixmapHook) { 0106 auto *info = reinterpret_cast<ScaledPixmapArgument *>(data); 0107 0108 QPixmap pixmap(info->size); 0109 pixmap.setDevicePixelRatio(info->scale); 0110 pixmap.fill(Qt::transparent); 0111 0112 QRect rect = pixmap.rect(); 0113 0114 const QRect logicalRect(rect.x() / info->scale, rect.y() / info->scale, rect.width() / info->scale, rect.height() / info->scale); 0115 QPainter p(&pixmap); 0116 paint(&p, logicalRect, info->mode, info->state); 0117 0118 info->pixmap = pixmap; 0119 0120 return; 0121 } 0122 QIconEngine::virtual_hook(id, data); 0123 } 0124 0125 void KOverlayIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) 0126 { 0127 // Paint the base icon as the first layer 0128 m_base.paint(painter, rect, Qt::AlignCenter, mode, state); 0129 0130 if (m_overlays.isEmpty()) { 0131 return; 0132 } 0133 0134 const int width = rect.width(); 0135 const int height = rect.height(); 0136 const int iconSize = qMin(width, height); 0137 // Determine the overlay icon size 0138 int overlaySize; 0139 if (iconSize < 32) { 0140 overlaySize = 8; 0141 } else if (iconSize <= 48) { 0142 overlaySize = 16; 0143 } else if (iconSize <= 64) { 0144 overlaySize = 22; 0145 } else if (iconSize <= 96) { 0146 overlaySize = 32; 0147 } else if (iconSize <= 128) { 0148 overlaySize = 48; 0149 } else { 0150 overlaySize = (int)(iconSize / 4); 0151 } 0152 0153 // Iterate over stored overlays 0154 QHash<Qt::Corner, QIcon>::const_iterator i = m_overlays.constBegin(); 0155 while (i != m_overlays.constEnd()) { 0156 const QPixmap overlayPixmap = i.value().pixmap(overlaySize, overlaySize, mode, state); 0157 if (overlayPixmap.isNull()) { 0158 ++i; 0159 continue; 0160 } 0161 0162 QPoint startPoint; 0163 switch (i.key()) { 0164 case Qt::BottomLeftCorner: 0165 startPoint = QPoint(2, height - overlaySize - 2); 0166 break; 0167 case Qt::BottomRightCorner: 0168 startPoint = QPoint(width - overlaySize - 2, height - overlaySize - 2); 0169 break; 0170 case Qt::TopRightCorner: 0171 startPoint = QPoint(width - overlaySize - 2, 2); 0172 break; 0173 case Qt::TopLeftCorner: 0174 startPoint = QPoint(2, 2); 0175 break; 0176 } 0177 0178 // Draw the overlay pixmap 0179 painter->drawPixmap(startPoint, overlayPixmap); 0180 0181 ++i; 0182 } 0183 } 0184 0185 // ============================================================================ 0186 0187 namespace KIconUtils 0188 { 0189 QIcon addOverlay(const QIcon &icon, const QIcon &overlay, Qt::Corner position) 0190 { 0191 return QIcon(new KOverlayIconEngine(icon, overlay, position)); 0192 } 0193 0194 QIcon addOverlays(const QIcon &icon, const QHash<Qt::Corner, QIcon> &overlays) 0195 { 0196 return QIcon(new KOverlayIconEngine(icon, overlays)); 0197 } 0198 0199 QIcon addOverlays(const QIcon &icon, const QStringList &overlays) 0200 { 0201 if (overlays.count() == 0) { 0202 return icon; 0203 } 0204 0205 return QIcon(new KOverlayIconEngine(icon, overlays)); 0206 } 0207 0208 QIcon addOverlays(const QString &iconName, const QStringList &overlays) 0209 { 0210 const QIcon icon = QIcon::fromTheme(iconName); 0211 0212 if (overlays.count() == 0) { 0213 return icon; 0214 } 0215 0216 return QIcon(new KOverlayIconEngine(icon, overlays)); 0217 } 0218 }