1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6*/
7
8#include "kiconengine.h"
9
10#include "kiconloader_p.h"
11#include <kiconloader.h>
12
13#include "kiconcolors.h"
14#include <KIconTheme>
15#include <QFileInfo>
16#include <QPainter>
17#include <qscopeguard.h>
18
19class KIconEnginePrivate
20{
21public:
22 QPointer<KIconLoader> mIconLoader;
23 bool mCustomColors = false;
24 KIconColors mColors;
25 QString mActualIconName;
26};
27
28KIconEngine::KIconEngine(const QString &iconName, KIconLoader *iconLoader, const QStringList &overlays)
29 : mIconName(iconName)
30 , mOverlays(overlays)
31 , d(new KIconEnginePrivate{.mIconLoader: iconLoader, .mCustomColors: false, .mColors: {}, .mActualIconName: {}})
32{
33}
34
35KIconEngine::KIconEngine(const QString &iconName, KIconLoader *iconLoader)
36 : mIconName(iconName)
37 , d(new KIconEnginePrivate{.mIconLoader: iconLoader, .mCustomColors: false, .mColors: {}, .mActualIconName: {}})
38{
39}
40
41KIconEngine::KIconEngine(const QString &iconName, const KIconColors &colors, KIconLoader *iconLoader)
42 : mIconName(iconName)
43 , d(new KIconEnginePrivate{.mIconLoader: iconLoader, .mCustomColors: true, .mColors: colors, .mActualIconName: {}})
44{
45}
46
47KIconEngine::KIconEngine(const QString &iconName, const KIconColors &colors, KIconLoader *iconLoader, const QStringList &overlays)
48 : mIconName(iconName)
49 , mOverlays(overlays)
50 , d(new KIconEnginePrivate{.mIconLoader: iconLoader, .mCustomColors: true, .mColors: colors, .mActualIconName: {}})
51{
52}
53
54KIconEngine::~KIconEngine()
55{
56 delete d;
57}
58
59static inline int qIconModeToKIconState(QIcon::Mode mode)
60{
61 switch (mode) {
62 case QIcon::Normal:
63 return KIconLoader::DefaultState;
64 case QIcon::Active:
65 return KIconLoader::ActiveState;
66 case QIcon::Disabled:
67 return KIconLoader::DisabledState;
68 case QIcon::Selected:
69 return KIconLoader::SelectedState;
70 default:
71 return KIconLoader::DefaultState;
72 }
73}
74
75QSize KIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
76{
77 return QIconEngine::actualSize(size, mode, state);
78}
79
80void KIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
81{
82 if (!d->mIconLoader) {
83 return;
84 }
85
86 const qreal dpr = painter->device()->devicePixelRatioF();
87 const QPixmap pix = createPixmap(size: rect.size() * dpr, scale: dpr, mode, state);
88 painter->drawPixmap(r: rect, pm: pix);
89}
90
91QPixmap KIconEngine::createPixmap(const QSize &size, qreal scale, QIcon::Mode mode, QIcon::State state)
92{
93 Q_UNUSED(state)
94
95 if (scale < 1) {
96 scale = 1;
97 }
98
99 if (size.isEmpty()) {
100 return QPixmap();
101 }
102
103 if (!d->mIconLoader) {
104 QPixmap pm(size);
105 pm.setDevicePixelRatio(scale);
106 pm.fill(fillColor: Qt::transparent);
107 return pm;
108 }
109
110 const QSize scaledSize = size / scale;
111
112 QString iconPath;
113
114 const int kstate = qIconModeToKIconState(mode);
115 QPixmap pix = d->mIconLoader->loadScaledIcon(name: mIconName,
116 group: KIconLoader::Desktop,
117 scale,
118 size: scaledSize,
119 state: kstate,
120 overlays: mOverlays,
121 path_store: &iconPath,
122 canReturnNull: false,
123 colorScheme: d->mCustomColors ? std::make_optional(t&: d->mColors) : std::nullopt);
124
125 if (!iconPath.isEmpty() && !d->mActualIconName.isEmpty()) {
126 d->mActualIconName = QFileInfo(iconPath).completeBaseName();
127 }
128
129 if (pix.size() == size) {
130 return pix;
131 }
132
133 QPixmap pix2(size);
134 pix2.setDevicePixelRatio(scale);
135 pix2.fill(fillColor: QColor(0, 0, 0, 0));
136
137 QPainter painter(&pix2);
138 painter.setRenderHint(hint: QPainter::SmoothPixmapTransform);
139 const QSizeF targetSize = pix.size().scaled(s: scaledSize, mode: Qt::KeepAspectRatio);
140 QRectF targetRect({0, 0}, targetSize);
141 targetRect.moveCenter(p: QRectF(pix2.rect()).center() / scale);
142 painter.drawPixmap(targetRect, pixmap: pix, sourceRect: pix.rect());
143
144 return pix2;
145}
146
147QPixmap KIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
148{
149 return createPixmap(size, scale: 1 /*scale*/, mode, state);
150}
151
152QPixmap KIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
153{
154 return createPixmap(size, scale, mode, state);
155}
156
157QString KIconEngine::iconName()
158{
159 if (!d->mActualIconName.isEmpty()) {
160 return d->mActualIconName;
161 }
162
163 if (!d->mIconLoader) {
164 return QString();
165 }
166
167 const QString iconPath = KIconLoaderPrivate::get(loader: d->mIconLoader)->preferredIconPath(name: mIconName);
168 if (iconPath.isEmpty()) {
169 return QString();
170 }
171
172 d->mActualIconName = QFileInfo(iconPath).completeBaseName();
173 return d->mActualIconName;
174}
175
176Q_GLOBAL_STATIC_WITH_ARGS(QList<QSize>,
177 sSizes,
178 (QList<QSize>() << QSize(16, 16) << QSize(22, 22) << QSize(32, 32) << QSize(48, 48) << QSize(64, 64) << QSize(128, 128)
179 << QSize(256, 256)))
180
181QList<QSize> KIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state)
182{
183 Q_UNUSED(mode);
184 Q_UNUSED(state);
185
186 if (!d->mIconLoader) {
187 return QList<QSize>();
188 }
189
190 const bool found = d->mIconLoader->hasIcon(iconName: mIconName);
191 return found ? *sSizes : QList<QSize>();
192}
193
194QString KIconEngine::key() const
195{
196 return QStringLiteral("KIconEngine");
197}
198
199QIconEngine *KIconEngine::clone() const
200{
201 return new KIconEngine(mIconName, d->mIconLoader, mOverlays);
202}
203
204bool KIconEngine::read(QDataStream &in)
205{
206 in >> mIconName >> mOverlays;
207 return true;
208}
209
210bool KIconEngine::write(QDataStream &out) const
211{
212 out << mIconName << mOverlays;
213 return true;
214}
215
216bool KIconEngine::isNull()
217{
218 return !d->mIconLoader || !d->mIconLoader->hasIcon(iconName: mIconName);
219}
220

source code of kiconthemes/src/kiconengine.cpp