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

source code of kiconthemes/src/kiconengine.cpp