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 | |
19 | class KIconEnginePrivate |
20 | { |
21 | public: |
22 | QPointer<KIconLoader> mIconLoader; |
23 | bool mCustomColors = false; |
24 | KIconColors mColors; |
25 | QString mActualIconName; |
26 | }; |
27 | |
28 | KIconEngine::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 | |
35 | KIconEngine::KIconEngine(const QString &iconName, KIconLoader *iconLoader) |
36 | : mIconName(iconName) |
37 | , d(new KIconEnginePrivate{.mIconLoader: iconLoader, .mCustomColors: false, .mColors: {}, .mActualIconName: {}}) |
38 | { |
39 | } |
40 | |
41 | KIconEngine::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 | |
47 | KIconEngine::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 | |
54 | KIconEngine::~KIconEngine() |
55 | { |
56 | delete d; |
57 | } |
58 | |
59 | static 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 | |
75 | QSize KIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) |
76 | { |
77 | return QIconEngine::actualSize(size, mode, state); |
78 | } |
79 | |
80 | void 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 | |
91 | QPixmap 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 | |
147 | QPixmap KIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) |
148 | { |
149 | return createPixmap(size, scale: 1 /*scale*/, mode, state); |
150 | } |
151 | |
152 | QPixmap KIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) |
153 | { |
154 | return createPixmap(size, scale, mode, state); |
155 | } |
156 | |
157 | QString 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 | |
176 | Q_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 | |
181 | QList<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 | |
194 | QString KIconEngine::key() const |
195 | { |
196 | return QStringLiteral("KIconEngine" ); |
197 | } |
198 | |
199 | QIconEngine *KIconEngine::clone() const |
200 | { |
201 | return new KIconEngine(mIconName, d->mIconLoader, mOverlays); |
202 | } |
203 | |
204 | bool KIconEngine::read(QDataStream &in) |
205 | { |
206 | in >> mIconName >> mOverlays; |
207 | return true; |
208 | } |
209 | |
210 | bool KIconEngine::write(QDataStream &out) const |
211 | { |
212 | out << mIconName << mOverlays; |
213 | return true; |
214 | } |
215 | |
216 | bool KIconEngine::isNull() |
217 | { |
218 | return !d->mIconLoader || !d->mIconLoader->hasIcon(iconName: mIconName); |
219 | } |
220 | |