KGuiAddons

kiconutils.cpp
1/*
2 SPDX-FileCopyrightText: 2013 Martin Klapetek <mklapetek@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6
7#include <array>
8
9#include "kiconutils.h"
10
11#include <QHash>
12#include <QIconEngine>
13#include <QLibraryInfo>
14#include <QPainter>
15#include <QVersionNumber>
16
17class KOverlayIconEngine : public QIconEngine
18{
19public:
20 KOverlayIconEngine(const QIcon &icon, const QIcon &overlay, Qt::Corner position);
21 KOverlayIconEngine(const QIcon &icon, const QHash<Qt::Corner, QIcon> &overlays);
22 KOverlayIconEngine(const QIcon &icon, const QStringList &overlays);
23 void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override;
24 QIconEngine *clone() const override;
25
26 QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
27 QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
28
29 void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state) override;
30 void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state) override;
31
32 void virtual_hook(int id, void *data) override;
33
34private:
35 QIcon m_base;
36 QHash<Qt::Corner, QIcon> m_overlays;
37 qreal m_dpr = 1.0;
38};
39
40KOverlayIconEngine::KOverlayIconEngine(const QIcon &icon, const QIcon &overlay, Qt::Corner position)
41 : QIconEngine()
42 , m_base(icon)
43{
44 m_overlays.insert(position, overlay);
45}
46
47KOverlayIconEngine::KOverlayIconEngine(const QIcon &icon, const QHash<Qt::Corner, QIcon> &overlays)
48 : QIconEngine()
49 , m_base(icon)
50 , m_overlays(overlays)
51{
52}
53
54KOverlayIconEngine::KOverlayIconEngine(const QIcon &icon, const QStringList &overlays)
55 : QIconEngine()
56 , m_base(icon)
57{
58 const std::array<Qt::Corner, 4> indexToCorner{
63 };
64
65 // static_cast becaue size() returns a qsizetype in Qt6
66 const int count = std::min(4, static_cast<int>(overlays.size()));
67
68 m_overlays.reserve(count);
69
70 for (int i = 0; i < count; i++) {
71 m_overlays.insert(indexToCorner[i], QIcon::fromTheme(overlays.at(i)));
72 }
73}
74
75QIconEngine *KOverlayIconEngine::clone() const
76{
77 return new KOverlayIconEngine(*this);
78}
79
80QSize KOverlayIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
81{
82 return m_base.actualSize(size, mode, state);
83}
84
85QPixmap KOverlayIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
86{
87 QPixmap pixmap(size);
88 pixmap.fill(Qt::transparent);
89 QPainter p(&pixmap);
90
91 paint(&p, pixmap.rect(), mode, state);
92
93 return pixmap;
94}
95
96void KOverlayIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state)
97{
98 m_base.addPixmap(pixmap, mode, state);
99}
100
101void KOverlayIconEngine::addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state)
102{
103 m_base.addFile(fileName, size, mode, state);
104}
105
106void KOverlayIconEngine::virtual_hook(int id, void *data)
107{
109 auto *info = reinterpret_cast<ScaledPixmapArgument *>(data);
110
111 QSize phyiscalSize = info->size;
112 // Since https://codereview.qt-project.org/c/qt/qtbase/+/563553 size is in logical pixels
113 if (QLibraryInfo::version() >= QVersionNumber(6, 8, 0)) {
114 phyiscalSize *= info->scale;
115 }
116
117 QPixmap pixmap(phyiscalSize);
118 pixmap.setDevicePixelRatio(info->scale);
119 pixmap.fill(Qt::transparent);
120
121 const QRect logicalRect(0, 0, phyiscalSize.width() / info->scale, phyiscalSize.height() / info->scale);
122 QPainter p(&pixmap);
123
124 m_dpr = info->scale;
125 paint(&p, logicalRect, info->mode, info->state);
126
127 info->pixmap = pixmap;
128
129 return;
130 }
132}
133
134void KOverlayIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
135{
136 m_base.paint(painter, rect, Qt::AlignCenter, mode, state);
137
138 if (m_overlays.isEmpty()) {
139 return;
140 }
141
142 const int width = rect.width();
143 const int height = rect.height();
144 const int iconSize = qMin(width, height);
145 // Determine the overlay icon size
146 int overlaySize;
147 if (iconSize < 32) {
148 overlaySize = 8;
149 } else if (iconSize <= 48) {
150 overlaySize = 16;
151 } else if (iconSize <= 64) {
152 overlaySize = 22;
153 } else if (iconSize <= 96) {
154 overlaySize = 32;
155 } else if (iconSize <= 128) {
156 overlaySize = 48;
157 } else {
158 overlaySize = (int)(iconSize / 4);
159 }
160
161 // Iterate over stored overlays
162 QHash<Qt::Corner, QIcon>::const_iterator i = m_overlays.constBegin();
163 while (i != m_overlays.constEnd()) {
164 const QPixmap overlayPixmap = i.value().pixmap(QSize{overlaySize, overlaySize}, m_dpr, mode, state);
165 if (overlayPixmap.isNull()) {
166 ++i;
167 continue;
168 }
169
170 QPoint startPoint;
171 switch (i.key()) {
173 startPoint = QPoint(2, height - overlaySize - 2);
174 break;
176 startPoint = QPoint(width - overlaySize - 2, height - overlaySize - 2);
177 break;
179 startPoint = QPoint(width - overlaySize - 2, 2);
180 break;
182 startPoint = QPoint(2, 2);
183 break;
184 }
185
186 // Draw the overlay pixmap
187 painter->drawPixmap(startPoint, overlayPixmap);
188
189 ++i;
190 }
191}
192
193// ============================================================================
194
195namespace KIconUtils
196{
197QIcon addOverlay(const QIcon &icon, const QIcon &overlay, Qt::Corner position)
198{
199 return QIcon(new KOverlayIconEngine(icon, overlay, position));
200}
201
202QIcon addOverlays(const QIcon &icon, const QHash<Qt::Corner, QIcon> &overlays)
203{
204 return QIcon(new KOverlayIconEngine(icon, overlays));
205}
206
207QIcon addOverlays(const QIcon &icon, const QStringList &overlays)
208{
209 if (overlays.count() == 0) {
210 return icon;
211 }
212
213 return QIcon(new KOverlayIconEngine(icon, overlays));
214}
215
216QIcon addOverlays(const QString &iconName, const QStringList &overlays)
217{
218 const QIcon icon = QIcon::fromTheme(iconName);
219
220 return addOverlays(icon, overlays);
221}
222}
Provides utility functions for icons.
QIcon addOverlays(const QIcon &icon, const QHash< Qt::Corner, QIcon > &overlays)
Adds overlays over the icon.
QIcon addOverlay(const QIcon &icon, const QIcon &overlay, Qt::Corner position)
Adds the overlay over the icon in the specified position.
QIcon fromTheme(const QString &name)
virtual void virtual_hook(int id, void *data)
QVersionNumber version()
const_reference at(qsizetype i) const const
qsizetype count() const const
qsizetype size() const const
void drawPixmap(const QPoint &point, const QPixmap &pixmap)
bool isNull() const const
int height() const const
int width() const const
int height() const const
void scale(const QSize &size, Qt::AspectRatioMode mode)
int width() const const
AlignCenter
transparent
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Feb 28 2025 11:55:06 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.