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

source code of kiconthemes/src/kiconengine.cpp