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};
38
39KOverlayIconEngine::KOverlayIconEngine(const QIcon &icon, const QIcon &overlay, Qt::Corner position)
40 : QIconEngine()
41 , m_base(icon)
42{
43 m_overlays.insert(position, overlay);
44}
45
46KOverlayIconEngine::KOverlayIconEngine(const QIcon &icon, const QHash<Qt::Corner, QIcon> &overlays)
47 : QIconEngine()
48 , m_base(icon)
49 , m_overlays(overlays)
50{
51}
52
53KOverlayIconEngine::KOverlayIconEngine(const QIcon &icon, const QStringList &overlays)
54 : QIconEngine()
55 , m_base(icon)
56{
57 const std::array<Qt::Corner, 4> indexToCorner{
62 };
63
64 // static_cast becaue size() returns a qsizetype in Qt6
65 const int count = std::min(4, static_cast<int>(overlays.size()));
66
67 m_overlays.reserve(count);
68
69 for (int i = 0; i < count; i++) {
70 m_overlays.insert(indexToCorner[i], QIcon::fromTheme(overlays.at(i)));
71 }
72}
73
74QIconEngine *KOverlayIconEngine::clone() const
75{
76 return new KOverlayIconEngine(*this);
77}
78
79QSize KOverlayIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
80{
81 return m_base.actualSize(size, mode, state);
82}
83
84QPixmap KOverlayIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
85{
86 QPixmap pixmap(size);
87 pixmap.fill(Qt::transparent);
88 QPainter p(&pixmap);
89
90 paint(&p, pixmap.rect(), mode, state);
91
92 return pixmap;
93}
94
95void KOverlayIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state)
96{
97 m_base.addPixmap(pixmap, mode, state);
98}
99
100void KOverlayIconEngine::addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state)
101{
102 m_base.addFile(fileName, size, mode, state);
103}
104
105void KOverlayIconEngine::virtual_hook(int id, void *data)
106{
108 auto *info = reinterpret_cast<ScaledPixmapArgument *>(data);
109
110 QSize phyiscalSize = info->size;
111 // Since https://codereview.qt-project.org/c/qt/qtbase/+/563553 size is in logical pixels
112 if (QLibraryInfo::version() >= QVersionNumber(6, 8, 0)) {
113 phyiscalSize *= info->scale;
114 }
115
116 QPixmap pixmap(phyiscalSize);
117 pixmap.setDevicePixelRatio(info->scale);
118 pixmap.fill(Qt::transparent);
119
120 QRect rect = pixmap.rect();
121
122 const QRect logicalRect(rect.x() / info->scale, rect.y() / info->scale, rect.width() / info->scale, rect.height() / info->scale);
123 QPainter p(&pixmap);
124 paint(&p, logicalRect, info->mode, info->state);
125
126 info->pixmap = pixmap;
127
128 return;
129 }
131}
132
133void KOverlayIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
134{
135 // Paint the base icon as the first layer
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
163 while (i != m_overlays.constEnd()) {
164 const QPixmap overlayPixmap = i.value().pixmap(overlaySize, overlaySize, 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 if (overlays.count() == 0) {
221 return icon;
222 }
223
224 return QIcon(new KOverlayIconEngine(icon, overlays));
225}
226}
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.
const_iterator constBegin() const const
const_iterator constEnd() const const
bool isEmpty() const const
QSize actualSize(QWindow *window, const QSize &size, Mode mode, State state) const const
void addFile(const QString &fileName, const QSize &size, Mode mode, State state)
void addPixmap(const QPixmap &pixmap, Mode mode, State state)
QIcon fromTheme(const QString &name)
void paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment, Mode mode, State state) const const
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)
void fill(const QColor &color)
bool isNull() const const
QRect rect() const const
void setDevicePixelRatio(qreal scaleFactor)
int height() const const
int width() const const
int x() const const
int y() const const
void scale(const QSize &size, Qt::AspectRatioMode mode)
AlignCenter
transparent
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:02:22 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.