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 <QPainter>
14
15class KOverlayIconEngine : public QIconEngine
16{
17public:
18 KOverlayIconEngine(const QIcon &icon, const QIcon &overlay, Qt::Corner position);
19 KOverlayIconEngine(const QIcon &icon, const QHash<Qt::Corner, QIcon> &overlays);
20 KOverlayIconEngine(const QIcon &icon, const QStringList &overlays);
21 void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override;
22 QIconEngine *clone() const override;
23
24 QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
25 QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
26
27 void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state) override;
28 void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state) override;
29
30 void virtual_hook(int id, void *data) override;
31
32private:
33 QIcon m_base;
34 QHash<Qt::Corner, QIcon> m_overlays;
35};
36
37KOverlayIconEngine::KOverlayIconEngine(const QIcon &icon, const QIcon &overlay, Qt::Corner position)
38 : QIconEngine()
39 , m_base(icon)
40{
41 m_overlays.insert(position, overlay);
42}
43
44KOverlayIconEngine::KOverlayIconEngine(const QIcon &icon, const QHash<Qt::Corner, QIcon> &overlays)
45 : QIconEngine()
46 , m_base(icon)
47 , m_overlays(overlays)
48{
49}
50
51KOverlayIconEngine::KOverlayIconEngine(const QIcon &icon, const QStringList &overlays)
52 : QIconEngine()
53 , m_base(icon)
54{
55 const std::array<Qt::Corner, 4> indexToCorner{
60 };
61
62 // static_cast becaue size() returns a qsizetype in Qt6
63 const int count = std::min(4, static_cast<int>(overlays.size()));
64
65 m_overlays.reserve(count);
66
67 for (int i = 0; i < count; i++) {
68 m_overlays.insert(indexToCorner[i], QIcon::fromTheme(overlays.at(i)));
69 }
70}
71
72QIconEngine *KOverlayIconEngine::clone() const
73{
74 return new KOverlayIconEngine(*this);
75}
76
77QSize KOverlayIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
78{
79 return m_base.actualSize(size, mode, state);
80}
81
82QPixmap KOverlayIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
83{
84 QPixmap pixmap(size);
85 pixmap.fill(Qt::transparent);
86 QPainter p(&pixmap);
87
88 paint(&p, pixmap.rect(), mode, state);
89
90 return pixmap;
91}
92
93void KOverlayIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state)
94{
95 m_base.addPixmap(pixmap, mode, state);
96}
97
98void KOverlayIconEngine::addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state)
99{
100 m_base.addFile(fileName, size, mode, state);
101}
102
103void KOverlayIconEngine::virtual_hook(int id, void *data)
104{
106 auto *info = reinterpret_cast<ScaledPixmapArgument *>(data);
107
108 QPixmap pixmap(info->size);
109 pixmap.setDevicePixelRatio(info->scale);
110 pixmap.fill(Qt::transparent);
111
112 QRect rect = pixmap.rect();
113
114 const QRect logicalRect(rect.x() / info->scale, rect.y() / info->scale, rect.width() / info->scale, rect.height() / info->scale);
115 QPainter p(&pixmap);
116 paint(&p, logicalRect, info->mode, info->state);
117
118 info->pixmap = pixmap;
119
120 return;
121 }
123}
124
125void KOverlayIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
126{
127 // Paint the base icon as the first layer
128 m_base.paint(painter, rect, Qt::AlignCenter, mode, state);
129
130 if (m_overlays.isEmpty()) {
131 return;
132 }
133
134 const int width = rect.width();
135 const int height = rect.height();
136 const int iconSize = qMin(width, height);
137 // Determine the overlay icon size
138 int overlaySize;
139 if (iconSize < 32) {
140 overlaySize = 8;
141 } else if (iconSize <= 48) {
142 overlaySize = 16;
143 } else if (iconSize <= 64) {
144 overlaySize = 22;
145 } else if (iconSize <= 96) {
146 overlaySize = 32;
147 } else if (iconSize <= 128) {
148 overlaySize = 48;
149 } else {
150 overlaySize = (int)(iconSize / 4);
151 }
152
153 // Iterate over stored overlays
155 while (i != m_overlays.constEnd()) {
156 const QPixmap overlayPixmap = i.value().pixmap(overlaySize, overlaySize, mode, state);
157 if (overlayPixmap.isNull()) {
158 ++i;
159 continue;
160 }
161
162 QPoint startPoint;
163 switch (i.key()) {
165 startPoint = QPoint(2, height - overlaySize - 2);
166 break;
168 startPoint = QPoint(width - overlaySize - 2, height - overlaySize - 2);
169 break;
171 startPoint = QPoint(width - overlaySize - 2, 2);
172 break;
174 startPoint = QPoint(2, 2);
175 break;
176 }
177
178 // Draw the overlay pixmap
179 painter->drawPixmap(startPoint, overlayPixmap);
180
181 ++i;
182 }
183}
184
185// ============================================================================
186
187namespace KIconUtils
188{
189QIcon addOverlay(const QIcon &icon, const QIcon &overlay, Qt::Corner position)
190{
191 return QIcon(new KOverlayIconEngine(icon, overlay, position));
192}
193
194QIcon addOverlays(const QIcon &icon, const QHash<Qt::Corner, QIcon> &overlays)
195{
196 return QIcon(new KOverlayIconEngine(icon, overlays));
197}
198
199QIcon addOverlays(const QIcon &icon, const QStringList &overlays)
200{
201 if (overlays.count() == 0) {
202 return icon;
203 }
204
205 return QIcon(new KOverlayIconEngine(icon, overlays));
206}
207
208QIcon addOverlays(const QString &iconName, const QStringList &overlays)
209{
210 const QIcon icon = QIcon::fromTheme(iconName);
211
212 if (overlays.count() == 0) {
213 return icon;
214 }
215
216 return QIcon(new KOverlayIconEngine(icon, overlays));
217}
218}
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)
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
AlignCenter
transparent
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:40 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.