File indexing completed on 2024-09-08 12:18:04
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #include "kiconengine.h" 0009 0010 #include "kiconloader_p.h" 0011 #include <kiconloader.h> 0012 0013 #include "kiconcolors.h" 0014 #include <KIconTheme> 0015 #include <QFileInfo> 0016 #include <QPainter> 0017 #include <qscopeguard.h> 0018 0019 class KIconEnginePrivate 0020 { 0021 public: 0022 QPointer<KIconLoader> mIconLoader; 0023 bool mCustomColors = false; 0024 KIconColors mColors; 0025 QString mActualIconName; 0026 }; 0027 0028 KIconEngine::KIconEngine(const QString &iconName, KIconLoader *iconLoader, const QStringList &overlays) 0029 : mIconName(iconName) 0030 , mOverlays(overlays) 0031 , d(new KIconEnginePrivate{iconLoader, false, {}, {}}) 0032 { 0033 } 0034 0035 KIconEngine::KIconEngine(const QString &iconName, KIconLoader *iconLoader) 0036 : mIconName(iconName) 0037 , d(new KIconEnginePrivate{iconLoader, false, {}, {}}) 0038 { 0039 } 0040 0041 KIconEngine::KIconEngine(const QString &iconName, const KIconColors &colors, KIconLoader *iconLoader) 0042 : mIconName(iconName) 0043 , d(new KIconEnginePrivate{iconLoader, true, colors, {}}) 0044 { 0045 } 0046 0047 KIconEngine::~KIconEngine() 0048 { 0049 delete d; 0050 } 0051 0052 static inline int qIconModeToKIconState(QIcon::Mode mode) 0053 { 0054 switch (mode) { 0055 case QIcon::Normal: 0056 return KIconLoader::DefaultState; 0057 case QIcon::Active: 0058 return KIconLoader::ActiveState; 0059 case QIcon::Disabled: 0060 return KIconLoader::DisabledState; 0061 case QIcon::Selected: 0062 return KIconLoader::SelectedState; 0063 default: 0064 return KIconLoader::DefaultState; 0065 } 0066 } 0067 0068 QSize KIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) 0069 { 0070 return QIconEngine::actualSize(size, mode, state); 0071 } 0072 0073 void KIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) 0074 { 0075 if (!d->mIconLoader) { 0076 return; 0077 } 0078 0079 const qreal dpr = painter->device()->devicePixelRatioF(); 0080 const QPixmap pix = createPixmap(rect.size() * dpr, dpr, mode, state); 0081 painter->drawPixmap(rect, pix); 0082 } 0083 0084 QPixmap KIconEngine::createPixmap(const QSize &size, qreal scale, QIcon::Mode mode, QIcon::State state) 0085 { 0086 Q_UNUSED(state) 0087 0088 if (scale < 1) { 0089 scale = 1; 0090 } 0091 0092 if (size.isEmpty()) { 0093 return QPixmap(); 0094 } 0095 0096 if (!d->mIconLoader) { 0097 QPixmap pm(size); 0098 pm.setDevicePixelRatio(scale); 0099 pm.fill(Qt::transparent); 0100 return pm; 0101 } 0102 0103 const QSize scaledSize = size / scale; 0104 0105 QString iconPath; 0106 0107 const int kstate = qIconModeToKIconState(mode); 0108 QPixmap pix = d->mIconLoader->loadScaledIcon(mIconName, 0109 KIconLoader::Desktop, 0110 scale, 0111 scaledSize, 0112 kstate, 0113 mOverlays, 0114 &iconPath, 0115 false, 0116 d->mCustomColors ? std::make_optional(d->mColors) : std::nullopt); 0117 0118 if (!iconPath.isEmpty() && !d->mActualIconName.isEmpty()) { 0119 d->mActualIconName = QFileInfo(iconPath).completeBaseName(); 0120 } 0121 0122 if (pix.size() == size) { 0123 return pix; 0124 } 0125 0126 QPixmap pix2(size); 0127 pix2.setDevicePixelRatio(scale); 0128 pix2.fill(QColor(0, 0, 0, 0)); 0129 0130 QPainter painter(&pix2); 0131 painter.setRenderHint(QPainter::SmoothPixmapTransform); 0132 const QSizeF targetSize = pix.size().scaled(scaledSize, Qt::KeepAspectRatio); 0133 QRectF targetRect({0, 0}, targetSize); 0134 targetRect.moveCenter(QRectF(pix2.rect()).center() / scale); 0135 painter.drawPixmap(targetRect, pix, pix.rect()); 0136 0137 return pix2; 0138 } 0139 0140 QPixmap KIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) 0141 { 0142 return createPixmap(size, 1 /*scale*/, mode, state); 0143 } 0144 0145 QString KIconEngine::iconName() const 0146 { 0147 if (!d->mActualIconName.isEmpty()) { 0148 return d->mActualIconName; 0149 } 0150 0151 if (!d->mIconLoader) { 0152 return QString(); 0153 } 0154 0155 const QString iconPath = KIconLoaderPrivate::get(d->mIconLoader)->preferredIconPath(mIconName); 0156 if (iconPath.isEmpty()) { 0157 return QString(); 0158 } 0159 0160 d->mActualIconName = QFileInfo(iconPath).completeBaseName(); 0161 return d->mActualIconName; 0162 } 0163 0164 Q_GLOBAL_STATIC_WITH_ARGS(QList<QSize>, 0165 sSizes, 0166 (QList<QSize>() << QSize(16, 16) << QSize(22, 22) << QSize(32, 32) << QSize(48, 48) << QSize(64, 64) << QSize(128, 128) 0167 << QSize(256, 256))) 0168 0169 QList<QSize> KIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state) const 0170 { 0171 Q_UNUSED(mode); 0172 Q_UNUSED(state); 0173 0174 if (!d->mIconLoader) { 0175 return QList<QSize>(); 0176 } 0177 0178 const bool found = d->mIconLoader->hasIcon(mIconName); 0179 return found ? *sSizes : QList<QSize>(); 0180 } 0181 0182 QString KIconEngine::key() const 0183 { 0184 return QStringLiteral("KIconEngine"); 0185 } 0186 0187 QIconEngine *KIconEngine::clone() const 0188 { 0189 return new KIconEngine(mIconName, d->mIconLoader, mOverlays); 0190 } 0191 0192 bool KIconEngine::read(QDataStream &in) 0193 { 0194 in >> mIconName >> mOverlays; 0195 return true; 0196 } 0197 0198 bool KIconEngine::write(QDataStream &out) const 0199 { 0200 out << mIconName << mOverlays; 0201 return true; 0202 } 0203 0204 void KIconEngine::virtual_hook(int id, void *data) 0205 { 0206 if (id == QIconEngine::IsNullHook) { 0207 *reinterpret_cast<bool *>(data) = !d->mIconLoader || !d->mIconLoader->hasIcon(mIconName); 0208 } 0209 if (id == QIconEngine::ScaledPixmapHook) { 0210 auto *info = reinterpret_cast<ScaledPixmapArgument *>(data); 0211 info->pixmap = createPixmap(info->size, info->scale, info->mode, info->state); 0212 return; 0213 } 0214 QIconEngine::virtual_hook(id, data); 0215 }