File indexing completed on 2025-03-09 03:40:23
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 QPixmap KIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) 0146 { 0147 return createPixmap(size, scale, mode, state); 0148 } 0149 0150 QString KIconEngine::iconName() 0151 { 0152 if (!d->mActualIconName.isEmpty()) { 0153 return d->mActualIconName; 0154 } 0155 0156 if (!d->mIconLoader) { 0157 return QString(); 0158 } 0159 0160 const QString iconPath = KIconLoaderPrivate::get(d->mIconLoader)->preferredIconPath(mIconName); 0161 if (iconPath.isEmpty()) { 0162 return QString(); 0163 } 0164 0165 d->mActualIconName = QFileInfo(iconPath).completeBaseName(); 0166 return d->mActualIconName; 0167 } 0168 0169 Q_GLOBAL_STATIC_WITH_ARGS(QList<QSize>, 0170 sSizes, 0171 (QList<QSize>() << QSize(16, 16) << QSize(22, 22) << QSize(32, 32) << QSize(48, 48) << QSize(64, 64) << QSize(128, 128) 0172 << QSize(256, 256))) 0173 0174 QList<QSize> KIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state) 0175 { 0176 Q_UNUSED(mode); 0177 Q_UNUSED(state); 0178 0179 if (!d->mIconLoader) { 0180 return QList<QSize>(); 0181 } 0182 0183 const bool found = d->mIconLoader->hasIcon(mIconName); 0184 return found ? *sSizes : QList<QSize>(); 0185 } 0186 0187 QString KIconEngine::key() const 0188 { 0189 return QStringLiteral("KIconEngine"); 0190 } 0191 0192 QIconEngine *KIconEngine::clone() const 0193 { 0194 return new KIconEngine(mIconName, d->mIconLoader, mOverlays); 0195 } 0196 0197 bool KIconEngine::read(QDataStream &in) 0198 { 0199 in >> mIconName >> mOverlays; 0200 return true; 0201 } 0202 0203 bool KIconEngine::write(QDataStream &out) const 0204 { 0205 out << mIconName << mOverlays; 0206 return true; 0207 } 0208 0209 bool KIconEngine::isNull() 0210 { 0211 return !d->mIconLoader || !d->mIconLoader->hasIcon(mIconName); 0212 }