Warning, file /frameworks/kiconthemes/src/kiconengine.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0146 QString KIconEngine::iconName()
0147 #else
0148 QString KIconEngine::iconName() const
0149 #endif
0150 {
0151     if (!d->mActualIconName.isEmpty()) {
0152         return d->mActualIconName;
0153     }
0154 
0155     if (!d->mIconLoader) {
0156         return QString();
0157     }
0158 
0159     const QString iconPath = KIconLoaderPrivate::get(d->mIconLoader)->preferredIconPath(mIconName);
0160     if (iconPath.isEmpty()) {
0161         return QString();
0162     }
0163 
0164     d->mActualIconName = QFileInfo(iconPath).completeBaseName();
0165     return d->mActualIconName;
0166 }
0167 
0168 Q_GLOBAL_STATIC_WITH_ARGS(QList<QSize>,
0169                           sSizes,
0170                           (QList<QSize>() << QSize(16, 16) << QSize(22, 22) << QSize(32, 32) << QSize(48, 48) << QSize(64, 64) << QSize(128, 128)
0171                                           << QSize(256, 256)))
0172 
0173 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0174 QList<QSize> KIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state)
0175 #else
0176 QList<QSize> KIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state) const
0177 #endif
0178 {
0179     Q_UNUSED(mode);
0180     Q_UNUSED(state);
0181 
0182     if (!d->mIconLoader) {
0183         return QList<QSize>();
0184     }
0185 
0186     const bool found = d->mIconLoader->hasIcon(mIconName);
0187     return found ? *sSizes : QList<QSize>();
0188 }
0189 
0190 QString KIconEngine::key() const
0191 {
0192     return QStringLiteral("KIconEngine");
0193 }
0194 
0195 QIconEngine *KIconEngine::clone() const
0196 {
0197     return new KIconEngine(mIconName, d->mIconLoader, mOverlays);
0198 }
0199 
0200 bool KIconEngine::read(QDataStream &in)
0201 {
0202     in >> mIconName >> mOverlays;
0203     return true;
0204 }
0205 
0206 bool KIconEngine::write(QDataStream &out) const
0207 {
0208     out << mIconName << mOverlays;
0209     return true;
0210 }
0211 
0212 void KIconEngine::virtual_hook(int id, void *data)
0213 {
0214     if (id == QIconEngine::IsNullHook) {
0215         *reinterpret_cast<bool *>(data) = !d->mIconLoader || !d->mIconLoader->hasIcon(mIconName);
0216     }
0217     if (id == QIconEngine::ScaledPixmapHook) {
0218         auto *info = reinterpret_cast<ScaledPixmapArgument *>(data);
0219         info->pixmap = createPixmap(info->size, info->scale, info->mode, info->state);
0220         return;
0221     }
0222     QIconEngine::virtual_hook(id, data);
0223 }