1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickiconimage_p.h"
5#include "qquickiconimage_p_p.h"
6
7#include <QtCore/qmath.h>
8#include <QtQuick/private/qquickimagebase_p_p.h>
9
10QT_BEGIN_NAMESPACE
11
12QQuickIconImagePrivate::~QQuickIconImagePrivate()
13{
14 icon.entries.clear();
15}
16
17bool QQuickIconImagePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio)
18{
19 if (isThemeIcon) {
20 devicePixelRatio = calculateDevicePixelRatio();
21 return true;
22 }
23
24 return QQuickImagePrivate::updateDevicePixelRatio(targetDevicePixelRatio);
25}
26
27void QQuickIconImagePrivate::updateIcon()
28{
29 Q_Q(QQuickIconImage);
30 // Both geometryChange() and QQuickImageBase::sourceSizeChanged()
31 // (which we connect to updateIcon() in the constructor) can be called as a result
32 // of updateIcon() changing the various sizes, so we must check that we're not recursing.
33 if (updatingIcon)
34 return;
35
36 updatingIcon = true;
37
38 QSize size = sourcesize;
39 // If no size is specified for theme icons, it will use the smallest available size.
40 if (size.width() <= 0)
41 size.setWidth(q->width());
42 if (size.height() <= 0)
43 size.setHeight(q->height());
44
45 const qreal dpr = calculateDevicePixelRatio();
46 const QIconLoaderEngineEntry *entry = QIconLoaderEngine::entryForSize(info: icon, size: size * dpr, scale: qCeil(v: dpr));
47
48 if (entry) {
49 QQmlContext *context = qmlContext(q);
50 const QUrl entryUrl = QUrl::fromLocalFile(localfile: entry->filename);
51 url = context ? context->resolvedUrl(entryUrl) : entryUrl;
52 isThemeIcon = true;
53 } else {
54 url = source;
55 isThemeIcon = false;
56 }
57 q->load();
58
59 updatingIcon = false;
60}
61
62void QQuickIconImagePrivate::updateFillMode()
63{
64 Q_Q(QQuickIconImage);
65 // If we start with a sourceSize of 28x28 and then set sourceSize.width to 24, the fillMode
66 // will change to PreserveAspectFit (because pixmapSize.width() > width()), which causes the
67 // pixmap to be reloaded at its original size of 28x28, which causes the fillMode to change
68 // to Pad (because pixmapSize.width() <= width()), and so on.
69 if (updatingFillMode)
70 return;
71
72 updatingFillMode = true;
73
74 const QSize pixmapSize = QSize(pix.width(), pix.height()) / calculateDevicePixelRatio();
75 if (pixmapSize.width() > q->width() || pixmapSize.height() > q->height())
76 q->setFillMode(QQuickImage::PreserveAspectFit);
77 else
78 q->setFillMode(QQuickImage::Pad);
79
80 updatingFillMode = false;
81}
82
83qreal QQuickIconImagePrivate::calculateDevicePixelRatio() const
84{
85 Q_Q(const QQuickIconImage);
86 return q->window() ? q->window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio();
87}
88
89QQuickIconImage::QQuickIconImage(QQuickItem *parent)
90 : QQuickImage(*(new QQuickIconImagePrivate), parent)
91{
92 setFillMode(Pad);
93}
94
95QString QQuickIconImage::name() const
96{
97 Q_D(const QQuickIconImage);
98 return d->icon.iconName;
99}
100
101void QQuickIconImage::setName(const QString &name)
102{
103 Q_D(QQuickIconImage);
104 if (d->icon.iconName == name)
105 return;
106
107 d->icon.entries.clear();
108 d->icon = QIconLoader::instance()->loadIcon(iconName: name);
109 if (isComponentComplete())
110 d->updateIcon();
111 emit nameChanged();
112}
113
114QColor QQuickIconImage::color() const
115{
116 Q_D(const QQuickIconImage);
117 return d->color;
118}
119
120void QQuickIconImage::setColor(const QColor &color)
121{
122 Q_D(QQuickIconImage);
123 if (d->color == color)
124 return;
125
126 d->color = color;
127 if (isComponentComplete())
128 d->updateIcon();
129 emit colorChanged();
130}
131
132void QQuickIconImage::setSource(const QUrl &source)
133{
134 Q_D(QQuickIconImage);
135 if (d->source == source)
136 return;
137
138 d->source = source;
139 if (isComponentComplete())
140 d->updateIcon();
141 emit sourceChanged(source);
142}
143
144void QQuickIconImage::componentComplete()
145{
146 Q_D(QQuickIconImage);
147 QQuickImage::componentComplete();
148 d->updateIcon();
149 QObjectPrivate::connect(sender: this, signal: &QQuickImageBase::sourceSizeChanged, receiverPrivate: d, slot: &QQuickIconImagePrivate::updateIcon);
150}
151
152void QQuickIconImage::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
153{
154 Q_D(QQuickIconImage);
155 QQuickImage::geometryChange(newGeometry, oldGeometry);
156 if (isComponentComplete() && newGeometry.size() != oldGeometry.size())
157 d->updateIcon();
158}
159
160void QQuickIconImage::itemChange(ItemChange change, const ItemChangeData &value)
161{
162 Q_D(QQuickIconImage);
163 if (change == ItemDevicePixelRatioHasChanged)
164 d->updateIcon();
165 QQuickImage::itemChange(change, value);
166}
167
168void QQuickIconImage::pixmapChange()
169{
170 Q_D(QQuickIconImage);
171 QQuickImage::pixmapChange();
172 d->updateFillMode();
173
174 // Don't apply the color if we're recursing (updateFillMode() can cause us to recurse).
175 if (!d->updatingFillMode && d->color.alpha() > 0) {
176 QImage image = d->pix.image();
177 if (!image.isNull()) {
178 QPainter painter(&image);
179 painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
180 painter.fillRect(image.rect(), color: d->color);
181 d->pix.setImage(image);
182 }
183 }
184}
185
186QT_END_NAMESPACE
187
188#include "moc_qquickiconimage_p.cpp"
189

source code of qtdeclarative/src/quickcontrolsimpl/qquickiconimage.cpp