1// Copyright (C) 2020 The Qt Company Ltd.
2// Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qicon.h"
6#include "qicon_p.h"
7#include "qiconengine.h"
8#include "qiconengineplugin.h"
9#include "qimagereader.h"
10#include "private/qfactoryloader_p.h"
11#include "private/qiconloader_p.h"
12#include "qpainter.h"
13#include "qfileinfo.h"
14#if QT_CONFIG(mimetype)
15#include <qmimedatabase.h>
16#include <qmimetype.h>
17#endif
18#include "qpixmapcache.h"
19#include "qvariant.h"
20#include "qcache.h"
21#include "qdebug.h"
22#include "qdir.h"
23#include "qpalette.h"
24#include "qmath.h"
25
26#include "private/qhexstring_p.h"
27#include "private/qguiapplication_p.h"
28#include "private/qoffsetstringarray_p.h"
29#include "qpa/qplatformtheme.h"
30
31#ifndef QT_NO_ICON
32QT_BEGIN_NAMESPACE
33
34using namespace Qt::StringLiterals;
35// Convenience class providing a bool read() function.
36namespace {
37class ImageReader
38{
39public:
40 ImageReader(const QString &fileName) : m_reader(fileName), m_atEnd(false) { }
41
42 QByteArray format() const { return m_reader.format(); }
43 bool supportsReadSize() const { return m_reader.supportsOption(option: QImageIOHandler::Size); }
44 QSize size() const { return m_reader.size(); }
45 bool jumpToNextImage() { return m_reader.jumpToNextImage(); }
46 void jumpToImage(int index) { m_reader.jumpToImage(imageNumber: index); }
47
48 bool read(QImage *image)
49 {
50 if (m_atEnd)
51 return false;
52 *image = m_reader.read();
53 if (!image->size().isValid()) {
54 m_atEnd = true;
55 return false;
56 }
57 m_atEnd = !m_reader.jumpToNextImage();
58 return true;
59 }
60
61private:
62 QImageReader m_reader;
63 bool m_atEnd;
64};
65} // namespace
66
67/*!
68 \enum QIcon::Mode
69
70 This enum type describes the mode for which a pixmap is intended
71 to be used. The currently defined modes are:
72
73 \value Normal
74 Display the pixmap when the user is
75 not interacting with the icon, but the
76 functionality represented by the icon is available.
77 \value Disabled
78 Display the pixmap when the
79 functionality represented by the icon is not available.
80 \value Active
81 Display the pixmap when the
82 functionality represented by the icon is available and
83 the user is interacting with the icon, for example, moving the
84 mouse over it or clicking it.
85 \value Selected
86 Display the pixmap when the item represented by the icon is
87 selected.
88*/
89
90/*!
91 \enum QIcon::State
92
93 This enum describes the state for which a pixmap is intended to be
94 used. The \e state can be:
95
96 \value Off Display the pixmap when the widget is in an "off" state
97 \value On Display the pixmap when the widget is in an "on" state
98*/
99
100static int nextSerialNumCounter()
101{
102 Q_CONSTINIT static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
103 return 1 + serial.fetchAndAddRelaxed(valueToAdd: 1);
104}
105
106static void qt_cleanup_icon_cache();
107namespace {
108 struct IconCache : public QCache<QString, QIcon>
109 {
110 IconCache()
111 {
112 // ### note: won't readd if QApplication is re-created!
113 qAddPostRoutine(qt_cleanup_icon_cache);
114 }
115 };
116}
117
118Q_GLOBAL_STATIC(IconCache, qtIconCache)
119
120static void qt_cleanup_icon_cache()
121{
122 qtIconCache()->clear();
123}
124
125QIconPrivate::QIconPrivate(QIconEngine *e)
126 : engine(e), ref(1),
127 serialNum(nextSerialNumCounter()),
128 detach_no(0),
129 is_mask(false)
130{
131}
132
133void QIconPrivate::clearIconCache()
134{
135 qt_cleanup_icon_cache();
136}
137
138/*! \internal
139 Computes the displayDevicePixelRatio for a pixmap.
140
141 If displayDevicePixelRatio is 1.0 the reurned value is 1.0, always.
142
143 For a displayDevicePixelRatio of 2.0 the returned value will be between
144 1.0 and 2.0, depending on requestedSize and actualsize:
145 * If actualsize < requestedSize : 1.0 (not enough pixels for a normal-dpi pixmap)
146 * If actualsize == requestedSize * 2.0 : 2.0 (enough pixels for a high-dpi pixmap)
147 * else : a scaled value between 1.0 and 2.0. (pixel count is between normal-dpi and high-dpi)
148*/
149qreal QIconPrivate::pixmapDevicePixelRatio(qreal displayDevicePixelRatio, const QSize &requestedSize, const QSize &actualSize)
150{
151 QSize targetSize = requestedSize * displayDevicePixelRatio;
152 if ((actualSize.width() == targetSize.width() && actualSize.height() <= targetSize.height()) ||
153 (actualSize.width() <= targetSize.width() && actualSize.height() == targetSize.height())) {
154 // Correctly scaled for dpr, just having different aspect ratio
155 return displayDevicePixelRatio;
156 }
157 qreal scale = 0.5 * (qreal(actualSize.width()) / qreal(targetSize.width()) +
158 qreal(actualSize.height() / qreal(targetSize.height())));
159 return qMax(a: qreal(1.0), b: displayDevicePixelRatio *scale);
160}
161
162QPixmapIconEngine::QPixmapIconEngine()
163{
164}
165
166QPixmapIconEngine::QPixmapIconEngine(const QPixmapIconEngine &other)
167 : QIconEngine(other), pixmaps(other.pixmaps)
168{
169}
170
171QPixmapIconEngine::~QPixmapIconEngine()
172{
173}
174
175void QPixmapIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
176{
177 auto paintDevice = painter->device();
178 qreal dpr = paintDevice ? paintDevice->devicePixelRatio() : qApp->devicePixelRatio();
179 QPixmap px = scaledPixmap(size: rect.size(), mode, state, scale: dpr);
180 painter->drawPixmap(r: rect, pm: px);
181}
182
183static inline qint64 area(const QSize &s) { return qint64(s.width()) * s.height(); }
184
185// Returns the smallest of the two that is still larger than or equal to size.
186// Pixmaps at the correct scale are preferred, pixmaps at lower scale are
187// used as fallbacks. We assume that the pixmap set is complete, in the sense
188// that no 2x pixmap is going to be a better match than a 3x pixmap for the the
189// target scale of 3 (It's OK if 3x pixmaps are missing - we'll fall back to
190// the 2x pixmaps then.)
191static QPixmapIconEngineEntry *bestSizeScaleMatch(const QSize &size, qreal scale, QPixmapIconEngineEntry *pa, QPixmapIconEngineEntry *pb)
192{
193 const auto scaleA = pa->pixmap.devicePixelRatio();
194 const auto scaleB = pb->pixmap.devicePixelRatio();
195 // scale: we can only differentiate on scale if the scale differs
196 if (scaleA != scaleB) {
197
198 // Score the pixmaps: 0 is an exact scale match, positive
199 // scores have more detail than requested, negative scores
200 // have less detail than requested.
201 qreal ascore = scaleA - scale;
202 qreal bscore = scaleB - scale;
203
204 // always prefer positive scores to prevent upscaling
205 if ((ascore < 0) != (bscore < 0))
206 return bscore < 0 ? pa : pb;
207 // Take the one closest to 0
208 return (qAbs(t: ascore) < qAbs(t: bscore)) ? pa : pb;
209 }
210
211 qint64 s = area(s: size * scale);
212 if (pa->size == QSize() && pa->pixmap.isNull()) {
213 pa->pixmap = QPixmap(pa->fileName);
214 pa->size = pa->pixmap.size();
215 }
216 qint64 a = area(s: pa->size);
217 if (pb->size == QSize() && pb->pixmap.isNull()) {
218 pb->pixmap = QPixmap(pb->fileName);
219 pb->size = pb->pixmap.size();
220 }
221 qint64 b = area(s: pb->size);
222 qint64 res = a;
223 if (qMin(a,b) >= s)
224 res = qMin(a,b);
225 else
226 res = qMax(a,b);
227 if (res == a)
228 return pa;
229 return pb;
230}
231
232QPixmapIconEngineEntry *QPixmapIconEngine::tryMatch(const QSize &size, qreal scale, QIcon::Mode mode, QIcon::State state)
233{
234 QPixmapIconEngineEntry *pe = nullptr;
235 for (auto &entry : pixmaps) {
236 if (entry.mode == mode && entry.state == state) {
237 if (pe)
238 pe = bestSizeScaleMatch(size, scale, pa: &entry, pb: pe);
239 else
240 pe = &entry;
241 }
242 }
243 return pe;
244}
245
246
247QPixmapIconEngineEntry *QPixmapIconEngine::bestMatch(const QSize &size, qreal scale, QIcon::Mode mode, QIcon::State state)
248{
249 QPixmapIconEngineEntry *pe = tryMatch(size, scale, mode, state);
250 while (!pe){
251 QIcon::State oppositeState = (state == QIcon::On) ? QIcon::Off : QIcon::On;
252 if (mode == QIcon::Disabled || mode == QIcon::Selected) {
253 QIcon::Mode oppositeMode = (mode == QIcon::Disabled) ? QIcon::Selected : QIcon::Disabled;
254 if ((pe = tryMatch(size, scale, mode: QIcon::Normal, state)))
255 break;
256 if ((pe = tryMatch(size, scale, mode: QIcon::Active, state)))
257 break;
258 if ((pe = tryMatch(size, scale, mode, state: oppositeState)))
259 break;
260 if ((pe = tryMatch(size, scale, mode: QIcon::Normal, state: oppositeState)))
261 break;
262 if ((pe = tryMatch(size, scale, mode: QIcon::Active, state: oppositeState)))
263 break;
264 if ((pe = tryMatch(size, scale, mode: oppositeMode, state)))
265 break;
266 if ((pe = tryMatch(size, scale, mode: oppositeMode, state: oppositeState)))
267 break;
268 } else {
269 QIcon::Mode oppositeMode = (mode == QIcon::Normal) ? QIcon::Active : QIcon::Normal;
270 if ((pe = tryMatch(size, scale, mode: oppositeMode, state)))
271 break;
272 if ((pe = tryMatch(size, scale, mode, state: oppositeState)))
273 break;
274 if ((pe = tryMatch(size, scale, mode: oppositeMode, state: oppositeState)))
275 break;
276 if ((pe = tryMatch(size, scale, mode: QIcon::Disabled, state)))
277 break;
278 if ((pe = tryMatch(size, scale, mode: QIcon::Selected, state)))
279 break;
280 if ((pe = tryMatch(size, scale, mode: QIcon::Disabled, state: oppositeState)))
281 break;
282 if ((pe = tryMatch(size, scale, mode: QIcon::Selected, state: oppositeState)))
283 break;
284 }
285
286 if (!pe)
287 return pe;
288 }
289
290 if (pe->pixmap.isNull()) {
291 // delay-load the image
292 ImageReader imageReader(pe->fileName);
293 QImage image, prevImage;
294 const QSize realSize = size * scale;
295 bool fittingImageFound = false;
296 if (imageReader.supportsReadSize()) {
297 // find the image with the best size without loading the entire image
298 do {
299 fittingImageFound = imageReader.size() == realSize;
300 } while (!fittingImageFound && imageReader.jumpToNextImage());
301 }
302 if (!fittingImageFound) {
303 imageReader.jumpToImage(index: 0);
304 while (imageReader.read(image: &image) && image.size() != realSize)
305 prevImage = image;
306 if (image.isNull())
307 image = prevImage;
308 } else {
309 imageReader.read(image: &image);
310 }
311 if (!image.isNull()) {
312 pe->pixmap.convertFromImage(img: image);
313 if (!pe->pixmap.isNull()) {
314 pe->size = pe->pixmap.size();
315 pe->pixmap.setDevicePixelRatio(scale);
316 }
317 }
318 if (!pe->size.isValid()) {
319 removePixmapEntry(pe);
320 pe = nullptr;
321 }
322 }
323
324 return pe;
325}
326
327QPixmap QPixmapIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
328{
329 return scaledPixmap(size, mode, state, scale: 1.0);
330}
331
332QPixmap QPixmapIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
333{
334 QPixmap pm;
335 QPixmapIconEngineEntry *pe = bestMatch(size, scale, mode, state);
336 if (pe)
337 pm = pe->pixmap;
338 else
339 return pm;
340
341 if (pm.isNull()) {
342 removePixmapEntry(pe);
343 if (pixmaps.isEmpty())
344 return pm;
345 return scaledPixmap(size, mode, state, scale);
346 }
347
348 const auto actualSize = adjustSize(expectedSize: size * scale, size: pm.size());
349 const auto calculatedDpr = QIconPrivate::pixmapDevicePixelRatio(displayDevicePixelRatio: scale, requestedSize: size, actualSize);
350 QString key = "qt_"_L1
351 % HexString<quint64>(pm.cacheKey())
352 % HexString<quint8>(pe->mode)
353 % HexString<quint64>(QGuiApplication::palette().cacheKey())
354 % HexString<uint>(actualSize.width())
355 % HexString<uint>(actualSize.height())
356 % HexString<quint16>(qRound(d: calculatedDpr * 1000));
357
358 if (mode == QIcon::Active) {
359 if (QPixmapCache::find(key: key % HexString<quint8>(mode), pixmap: &pm))
360 return pm; // horray
361 if (QPixmapCache::find(key: key % HexString<quint8>(QIcon::Normal), pixmap: &pm)) {
362 QPixmap active = pm;
363 if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
364 active = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(o: guiApp))->applyQIconStyleHelper(QIcon::Active, basePixmap: pm);
365 if (pm.cacheKey() == active.cacheKey())
366 return pm;
367 }
368 }
369
370 if (!QPixmapCache::find(key: key % HexString<quint8>(mode), pixmap: &pm)) {
371 if (pm.size() != actualSize)
372 pm = pm.scaled(s: actualSize, aspectMode: Qt::IgnoreAspectRatio, mode: Qt::SmoothTransformation);
373 if (pe->mode != mode && mode != QIcon::Normal) {
374 QPixmap generated = pm;
375 if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
376 generated = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(o: guiApp))->applyQIconStyleHelper(mode, basePixmap: pm);
377 if (!generated.isNull())
378 pm = generated;
379 }
380 pm.setDevicePixelRatio(calculatedDpr);
381 QPixmapCache::insert(key: key % HexString<quint8>(mode), pixmap: pm);
382 }
383 return pm;
384}
385
386QSize QPixmapIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
387{
388 QSize actualSize;
389
390 // The returned actual size is the size in device independent pixels,
391 // so we limit the search to scale 1 and assume that e.g. @2x versions
392 // does not proviode extra actual sizes not also provided by the 1x versions.
393 qreal scale = 1;
394
395 if (QPixmapIconEngineEntry *pe = bestMatch(size, scale, mode, state))
396 actualSize = pe->size;
397
398 return adjustSize(expectedSize: size, size: actualSize);
399}
400
401QList<QSize> QPixmapIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state)
402{
403 QList<QSize> sizes;
404 for (QPixmapIconEngineEntry &pe : pixmaps) {
405 if (pe.mode != mode || pe.state != state)
406 continue;
407 if (pe.size.isEmpty() && pe.pixmap.isNull()) {
408 pe.pixmap = QPixmap(pe.fileName);
409 pe.size = pe.pixmap.size();
410 }
411 if (!pe.size.isEmpty() && !sizes.contains(t: pe.size))
412 sizes.push_back(t: pe.size);
413 }
414 return sizes;
415}
416
417void QPixmapIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state)
418{
419 if (!pixmap.isNull()) {
420 QPixmapIconEngineEntry *pe = tryMatch(size: pixmap.size() / pixmap.devicePixelRatio(),
421 scale: pixmap.devicePixelRatio(), mode, state);
422 if (pe && pe->size == pixmap.size() && pe->pixmap.devicePixelRatio() == pixmap.devicePixelRatio()) {
423 pe->pixmap = pixmap;
424 pe->fileName.clear();
425 } else {
426 pixmaps += QPixmapIconEngineEntry(pixmap, mode, state);
427 }
428 }
429}
430
431// Read out original image depth as set by ICOReader
432static inline int origIcoDepth(const QImage &image)
433{
434 const QString s = image.text(QStringLiteral("_q_icoOrigDepth"));
435 return s.isEmpty() ? 32 : s.toInt();
436}
437
438static inline int findBySize(const QList<QImage> &images, const QSize &size)
439{
440 for (qsizetype i = 0; i < images.size(); ++i) {
441 if (images.at(i).size() == size)
442 return i;
443 }
444 return -1;
445}
446
447void QPixmapIconEngine::addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state)
448{
449 if (fileName.isEmpty())
450 return;
451 const QString abs = fileName.startsWith(c: u':') ? fileName : QFileInfo(fileName).absoluteFilePath();
452 const bool ignoreSize = !size.isValid();
453 ImageReader imageReader(abs);
454 const QByteArray format = imageReader.format();
455 if (format.isEmpty()) // Device failed to open or unsupported format.
456 return;
457 QImage image;
458 if (format != "ico") {
459 if (ignoreSize) { // No size specified: Add all images.
460 if (imageReader.supportsReadSize()) {
461 do {
462 pixmaps += QPixmapIconEngineEntry(abs, imageReader.size(), mode, state);
463 } while (imageReader.jumpToNextImage());
464 } else {
465 while (imageReader.read(image: &image))
466 pixmaps += QPixmapIconEngineEntry(abs, image, mode, state);
467 }
468 } else {
469 pixmaps += QPixmapIconEngineEntry(abs, size, mode, state);
470 }
471 return;
472 }
473 // Special case for reading Windows ".ico" files. Historically (QTBUG-39287),
474 // these files may contain low-resolution images. As this information is lost,
475 // ICOReader sets the original format as an image text key value. Read all matching
476 // images into a list trying to find the highest quality per size.
477 QList<QImage> icoImages;
478 while (imageReader.read(image: &image)) {
479 if (ignoreSize || image.size() == size) {
480 const int position = findBySize(images: icoImages, size: image.size());
481 if (position >= 0) { // Higher quality available? -> replace.
482 if (origIcoDepth(image) > origIcoDepth(image: icoImages.at(i: position)))
483 icoImages[position] = image;
484 } else {
485 icoImages.append(t: image);
486 }
487 }
488 }
489 for (const QImage &i : std::as_const(t&: icoImages))
490 pixmaps += QPixmapIconEngineEntry(abs, i, mode, state);
491 if (icoImages.isEmpty() && !ignoreSize) // Add placeholder with the filename and empty pixmap for the size.
492 pixmaps += QPixmapIconEngineEntry(abs, size, mode, state);
493}
494
495bool QPixmapIconEngine::isNull()
496{
497 return pixmaps.isEmpty();
498}
499
500QString QPixmapIconEngine::key() const
501{
502 return "QPixmapIconEngine"_L1;
503}
504
505QIconEngine *QPixmapIconEngine::clone() const
506{
507 return new QPixmapIconEngine(*this);
508}
509
510bool QPixmapIconEngine::read(QDataStream &in)
511{
512 int num_entries;
513 QPixmap pm;
514 QString fileName;
515 QSize sz;
516 uint mode;
517 uint state;
518
519 in >> num_entries;
520 for (int i=0; i < num_entries; ++i) {
521 if (in.atEnd()) {
522 pixmaps.clear();
523 return false;
524 }
525 in >> pm;
526 in >> fileName;
527 in >> sz;
528 in >> mode;
529 in >> state;
530 if (pm.isNull()) {
531 addFile(fileName, size: sz, mode: QIcon::Mode(mode), state: QIcon::State(state));
532 } else {
533 QPixmapIconEngineEntry pe(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
534 pe.pixmap = pm;
535 pixmaps += pe;
536 }
537 }
538 return true;
539}
540
541bool QPixmapIconEngine::write(QDataStream &out) const
542{
543 int num_entries = pixmaps.size();
544 out << num_entries;
545 for (int i=0; i < num_entries; ++i) {
546 if (pixmaps.at(i).pixmap.isNull())
547 out << QPixmap(pixmaps.at(i).fileName);
548 else
549 out << pixmaps.at(i).pixmap;
550 out << pixmaps.at(i).fileName;
551 out << pixmaps.at(i).size;
552 out << (uint) pixmaps.at(i).mode;
553 out << (uint) pixmaps.at(i).state;
554 }
555 return true;
556}
557
558Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, iceLoader,
559 (QIconEngineFactoryInterface_iid, "/iconengines"_L1, Qt::CaseInsensitive))
560
561QFactoryLoader *qt_iconEngineFactoryLoader()
562{
563 return iceLoader();
564}
565
566
567/*!
568 \class QIcon
569
570 \brief The QIcon class provides scalable icons in different modes
571 and states.
572
573 \ingroup painting
574 \ingroup shared
575 \inmodule QtGui
576
577 A QIcon can generate smaller, larger, active, and disabled pixmaps
578 from the set of pixmaps it is given. Such pixmaps are used by Qt
579 UI components to show an icon representing a particular action.
580
581 \section1 Creating an icon from image files
582
583 The simplest way to construct a QIcon is to create one from one or
584 several image files or resources. For example:
585
586 \snippet code/src_gui_image_qicon.cpp 0
587
588 QIcon can store several images for different states, and Qt will
589 select the image that is the closest match for the action's current
590 state.
591
592 \snippet code/src_gui_image_qicon.cpp addFile
593
594 Qt will generate the required icon styles and sizes when needed,
595 e.g. the pixmap for the QIcon::Disabled state might be generated by
596 graying out one of the provided pixmaps.
597
598 To clear the icon, simply set a null icon in its place:
599
600 \snippet code/src_gui_image_qicon.cpp 1
601
602 Use the QImageReader::supportedImageFormats() and
603 QImageWriter::supportedImageFormats() functions to retrieve a
604 complete list of the supported file formats.
605
606 \section1 Creating an icon from a theme or icon library
607
608 The most convenient way to construct an icon is by using the
609 \l{QIcon::}{fromTheme()} factory function. Qt implements access to
610 the native icon library on platforms that support the
611 \l {Freedesktop Icon Theme Specification}. Since Qt 6.7, Qt also
612 provides access to the native icon library on macOS, iOS, and
613 Windows 10 and 11. On Android, Qt can access icons from the Material
614 design system as long as the
615 \l{https://github.com/google/material-design-icons/tree/master/font}
616 {MaterialIcons-Regular} font is available on the system, or bundled
617 as a resource at \c{:/qt-project.org/icons/MaterialIcons-Regular.ttf}
618 with the application.
619
620 \snippet code/src_gui_image_qicon.cpp fromTheme
621
622 Applications can use the same theming specification to provide
623 their own icon library. See below for an example theme description
624 and the corresponding directory structure for the image files.
625 Icons from an application-provided theme take precedence over the
626 native icon library.
627
628 \section1 Icon Engines
629
630 Internally, QIcon instantiates an \l {QIconEngine} {icon engine}
631 backend to handle and render the icon images. The type of icon
632 engine is determined by the first file or pixmap or theme added to a
633 QIcon object. Additional files or pixmaps will then be handled by
634 the same engine.
635
636 Icon engines differ in the way they handle and render icons. The
637 default pixmap-based engine only deals with fixed images, while the
638 QtSvg module provides an icon engine that can re-render the provided
639 vector graphics files at the requested size for better quality. The
640 theme icon engines will typically only provide images from native
641 platform icon library, and ignore any added files or pixmaps.
642
643 In addition, it is possible to provide custom icon engines. This
644 allows applications to customize every aspect of generated
645 icons. With QIconEnginePlugin it is possible to register different
646 icon engines for different file suffixes, making it possible for
647 third parties to provide additional icon engines to those included
648 with Qt.
649
650 \section1 Making Classes that Use QIcon
651
652 If you write your own widgets that have an option to set a small
653 pixmap, consider allowing a QIcon to be set for that pixmap. The
654 Qt class QToolButton is an example of such a widget.
655
656 Provide a method to set a QIcon, and paint the QIcon with
657 \l{QIcon::}{paint}, choosing the appropriate parameters based
658 on the current state of your widget. For example:
659
660 \snippet code/src_gui_image_qicon.cpp 2
661
662 When you retrieve a pixmap using pixmap(QSize, Mode, State), and no
663 pixmap for this given size, mode and state has been added with
664 addFile() or addPixmap(), then QIcon will generate one on the
665 fly. This pixmap generation happens in a QIconEngine. The default
666 engine scales pixmaps down if required, but never up, and it uses
667 the current style to calculate a disabled appearance.
668
669 You might also make use of the \c Active mode, perhaps making your
670 widget \c Active when the mouse is over the widget (see \l
671 QWidget::enterEvent()), while the mouse is pressed pending the
672 release that will activate the function, or when it is the currently
673 selected item. If the widget can be toggled, the "On" mode might be
674 used to draw a different icon.
675
676 \image icon.png QIcon
677
678 \note QIcon needs a QGuiApplication instance before the icon is created.
679
680 \section1 High DPI Icons
681
682 Icons that are provided by the native icon library are usually based
683 on vector graphics, and will automatically be rendered in the appropriate
684 resolution.
685
686 When providing your own image files via \l addFile(), then QIcon will
687 use Qt's \l {High Resolution Versions of Images}{"@nx" high DPI syntax}.
688 This is useful if you have your own custom directory structure and do not
689 use follow \l {Freedesktop Icon Theme Specification}.
690
691 When providing an application theme, then you need to follow the Icon Theme
692 Specification to specify which files to use for different resolutions.
693 To make QIcon use the high DPI version of an image, add an additional entry
694 to the appropriate \c index.theme file:
695
696 \badcode
697 [Icon Theme]
698 Name=Test
699 Comment=Test Theme
700
701 Directories=32x32/actions,32x32@2/actions
702
703 [32x32/actions]
704 Size=32
705 Context=Actions
706 Type=Fixed
707
708 # High DPI version of the entry above.
709 [32x32@2/actions]
710 Size=32
711 Scale=2
712 Type=Fixed
713 \endcode
714
715 Your icon theme directory would then look something like this:
716
717 \badcode
718 ├── 32x32
719 │ └── actions
720 │ └── appointment-new.png
721 ├── 32x32@2
722 │ └── actions
723 │ └── appointment-new.png
724 └── index.theme
725 \endcode
726*/
727
728
729/*!
730 Constructs a null icon.
731*/
732QIcon::QIcon() noexcept
733 : d(nullptr)
734{
735}
736
737/*!
738 Constructs an icon from a \a pixmap.
739 */
740QIcon::QIcon(const QPixmap &pixmap)
741 :d(nullptr)
742{
743 addPixmap(pixmap);
744}
745
746/*!
747 Constructs a copy of \a other. This is very fast.
748*/
749QIcon::QIcon(const QIcon &other)
750 :d(other.d)
751{
752 if (d)
753 d->ref.ref();
754}
755
756/*!
757 \fn QIcon::QIcon(QIcon &&other)
758
759 Move-constructs a QIcon instance, making it point to the same object
760 that \a other was pointing to.
761*/
762
763/*!
764 Constructs an icon from the file with the given \a fileName. The
765 file will be loaded on demand.
766
767 If \a fileName contains a relative path (e.g. the filename only)
768 the relevant file must be found relative to the runtime working
769 directory.
770
771 The file name can refer to an actual file on disk or to
772 one of the application's embedded resources. See the
773 \l{resources.html}{Resource System} overview for details on how to
774 embed images and other resource files in the application's
775 executable.
776
777 Use the QImageReader::supportedImageFormats() and
778 QImageWriter::supportedImageFormats() functions to retrieve a
779 complete list of the supported file formats.
780*/
781QIcon::QIcon(const QString &fileName)
782 : d(nullptr)
783{
784 addFile(fileName);
785}
786
787
788/*!
789 Creates an icon with a specific icon \a engine. The icon takes
790 ownership of the engine.
791*/
792QIcon::QIcon(QIconEngine *engine)
793 :d(new QIconPrivate(engine))
794{
795}
796
797/*!
798 Destroys the icon.
799*/
800QIcon::~QIcon()
801{
802 if (d && !d->ref.deref())
803 delete d;
804}
805
806/*!
807 Assigns the \a other icon to this icon and returns a reference to
808 this icon.
809*/
810QIcon &QIcon::operator=(const QIcon &other)
811{
812 if (other.d)
813 other.d->ref.ref();
814 if (d && !d->ref.deref())
815 delete d;
816 d = other.d;
817 return *this;
818}
819
820/*!
821 \fn QIcon &QIcon::operator=(QIcon &&other)
822
823 Move-assigns \a other to this QIcon instance.
824
825 \since 5.2
826*/
827
828/*!
829 \fn void QIcon::swap(QIcon &other)
830 \memberswap{icon}
831*/
832
833/*!
834 Returns the icon as a QVariant.
835*/
836QIcon::operator QVariant() const
837{
838 return QVariant::fromValue(value: *this);
839}
840
841/*!
842 Returns a number that identifies the contents of this QIcon
843 object. Distinct QIcon objects can have the same key if
844 they refer to the same contents.
845
846 The cacheKey() will change when the icon is altered via
847 addPixmap() or addFile().
848
849 Cache keys are mostly useful in conjunction with caching.
850
851 \sa QPixmap::cacheKey()
852*/
853qint64 QIcon::cacheKey() const
854{
855 if (!d)
856 return 0;
857 return (((qint64) d->serialNum) << 32) | ((qint64) (d->detach_no));
858}
859
860/*!
861 Returns a pixmap with the requested \a size, \a mode, and \a
862 state, generating one if necessary. The pixmap might be smaller than
863 requested, but never larger, unless the device-pixel ratio of the returned
864 pixmap is larger than 1.
865
866 \sa actualSize(), paint()
867*/
868QPixmap QIcon::pixmap(const QSize &size, Mode mode, State state) const
869{
870 if (!d)
871 return QPixmap();
872 const qreal dpr = -1; // don't know target dpr
873 return pixmap(size, devicePixelRatio: dpr, mode, state);
874}
875
876/*!
877 \fn QPixmap QIcon::pixmap(int w, int h, Mode mode = Normal, State state = Off) const
878
879 \overload
880
881 Returns a pixmap of size QSize(\a w, \a h). The pixmap might be smaller than
882 requested, but never larger, unless the device-pixel ratio of the returned
883 pixmap is larger than 1.
884*/
885
886/*!
887 \fn QPixmap QIcon::pixmap(int extent, Mode mode = Normal, State state = Off) const
888
889 \overload
890
891 Returns a pixmap of size QSize(\a extent, \a extent). The pixmap might be smaller
892 than requested, but never larger, unless the device-pixel ratio of the returned
893 pixmap is larger than 1.
894*/
895
896/*!
897 \overload
898 \since 6.0
899
900 Returns a pixmap with the requested \a size, \a devicePixelRatio, \a mode, and \a
901 state, generating one with the given \a mode and \a state if necessary. The pixmap
902 might be smaller than requested, but never larger, unless the device-pixel ratio
903 of the returned pixmap is larger than 1.
904
905 \note Prior to Qt 6.8 this function wronlgy passed the device dependent pixmap size to
906 QIconEngine::scaledPixmap(), since Qt 6.8 it's the device independent size (not scaled
907 with the \a devicePixelRatio).
908
909 \sa actualSize(), paint()
910*/
911QPixmap QIcon::pixmap(const QSize &size, qreal devicePixelRatio, Mode mode, State state) const
912{
913 if (!d)
914 return QPixmap();
915
916 // Use the global devicePixelRatio if the caller does not know the target dpr
917 if (devicePixelRatio == -1)
918 devicePixelRatio = qApp->devicePixelRatio();
919
920 // Handle the simple normal-dpi case
921 if (!(devicePixelRatio > 1.0)) {
922 QPixmap pixmap = d->engine->pixmap(size, mode, state);
923 pixmap.setDevicePixelRatio(1.0);
924 return pixmap;
925 }
926
927 // Try get a pixmap that is big enough to be displayed at device pixel resolution.
928 QPixmap pixmap = d->engine->scaledPixmap(size, mode, state, scale: devicePixelRatio);
929 pixmap.setDevicePixelRatio(d->pixmapDevicePixelRatio(displayDevicePixelRatio: devicePixelRatio, requestedSize: size, actualSize: pixmap.size()));
930 return pixmap;
931}
932
933#if QT_DEPRECATED_SINCE(6, 0)
934/*!
935 \since 5.1
936 \deprecated [6.0] Use pixmap(size, devicePixelRatio) instead.
937
938 Returns a pixmap with the requested \a window \a size, \a mode, and \a
939 state, generating one if necessary.
940
941 The pixmap can be smaller than the requested size. If \a window is on
942 a high-dpi display the pixmap can be larger. In that case it will have
943 a devicePixelRatio larger than 1.
944
945 \sa actualSize(), paint()
946*/
947
948QPixmap QIcon::pixmap(QWindow *window, const QSize &size, Mode mode, State state) const
949{
950 if (!d)
951 return QPixmap();
952
953 qreal devicePixelRatio = window ? window->devicePixelRatio() : qApp->devicePixelRatio();
954 return pixmap(size, devicePixelRatio, mode, state);
955}
956#endif
957
958
959/*! Returns the actual size of the icon for the requested \a size, \a
960 mode, and \a state. The result might be smaller than requested, but
961 never larger. The returned size is in device-independent pixels (This
962 is relevant for high-dpi pixmaps.)
963
964 \sa pixmap(), paint()
965*/
966QSize QIcon::actualSize(const QSize &size, Mode mode, State state) const
967{
968 if (!d)
969 return QSize();
970
971 const qreal devicePixelRatio = qApp->devicePixelRatio();
972
973 // Handle the simple normal-dpi case:
974 if (!(devicePixelRatio > 1.0))
975 return d->engine->actualSize(size, mode, state);
976
977 const QSize actualSize = d->engine->actualSize(size: size * devicePixelRatio, mode, state);
978 return actualSize / d->pixmapDevicePixelRatio(displayDevicePixelRatio: devicePixelRatio, requestedSize: size, actualSize);
979}
980
981#if QT_DEPRECATED_SINCE(6, 0)
982/*!
983 \since 5.1
984 \deprecated [6.0] Use actualSize(size) instead.
985
986 Returns the actual size of the icon for the requested \a window \a size, \a
987 mode, and \a state.
988
989 The pixmap can be smaller than the requested size. The returned size
990 is in device-independent pixels (This is relevant for high-dpi pixmaps.)
991
992 \sa actualSize(), pixmap(), paint()
993*/
994
995QSize QIcon::actualSize(QWindow *window, const QSize &size, Mode mode, State state) const
996{
997 if (!d)
998 return QSize();
999
1000 qreal devicePixelRatio = window ? window->devicePixelRatio() : qApp->devicePixelRatio();
1001
1002 // Handle the simple normal-dpi case:
1003 if (!(devicePixelRatio > 1.0))
1004 return d->engine->actualSize(size, mode, state);
1005
1006 QSize actualSize = d->engine->actualSize(size: size * devicePixelRatio, mode, state);
1007 return actualSize / d->pixmapDevicePixelRatio(displayDevicePixelRatio: devicePixelRatio, requestedSize: size, actualSize);
1008}
1009#endif
1010
1011/*!
1012 Uses the \a painter to paint the icon with specified \a alignment,
1013 required \a mode, and \a state into the rectangle \a rect.
1014
1015 \sa actualSize(), pixmap()
1016*/
1017void QIcon::paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment, Mode mode, State state) const
1018{
1019 if (!d || !painter)
1020 return;
1021
1022 // Copy of QStyle::alignedRect
1023 const QSize size = d->engine->actualSize(size: rect.size(), mode, state);
1024 alignment = QGuiApplicationPrivate::visualAlignment(direction: painter->layoutDirection(), alignment);
1025 int x = rect.x();
1026 int y = rect.y();
1027 int w = size.width();
1028 int h = size.height();
1029 if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
1030 y += rect.size().height()/2 - h/2;
1031 else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
1032 y += rect.size().height() - h;
1033 if ((alignment & Qt::AlignRight) == Qt::AlignRight)
1034 x += rect.size().width() - w;
1035 else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
1036 x += rect.size().width()/2 - w/2;
1037 QRect alignedRect(x, y, w, h);
1038
1039 d->engine->paint(painter, rect: alignedRect, mode, state);
1040}
1041
1042/*!
1043 \fn void QIcon::paint(QPainter *painter, int x, int y, int w, int h, Qt::Alignment alignment,
1044 Mode mode, State state) const
1045
1046 \overload
1047
1048 Paints the icon into the rectangle QRect(\a x, \a y, \a w, \a h).
1049*/
1050
1051/*!
1052 Returns \c true if the icon is empty; otherwise returns \c false.
1053
1054 An icon is empty if it has neither a pixmap nor a filename.
1055
1056 Note: Even a non-null icon might not be able to create valid
1057 pixmaps, eg. if the file does not exist or cannot be read.
1058*/
1059bool QIcon::isNull() const
1060{
1061 return !d || d->engine->isNull();
1062}
1063
1064/*!\internal
1065 */
1066bool QIcon::isDetached() const
1067{
1068 return !d || d->ref.loadRelaxed() == 1;
1069}
1070
1071/*! \internal
1072 */
1073void QIcon::detach()
1074{
1075 if (d) {
1076 if (d->engine->isNull()) {
1077 if (!d->ref.deref())
1078 delete d;
1079 d = nullptr;
1080 return;
1081 } else if (d->ref.loadRelaxed() != 1) {
1082 QIconPrivate *x = new QIconPrivate(d->engine->clone());
1083 if (!d->ref.deref())
1084 delete d;
1085 d = x;
1086 }
1087 ++d->detach_no;
1088 }
1089}
1090
1091/*!
1092 Adds \a pixmap to the icon, as a specialization for \a mode and
1093 \a state.
1094
1095 Custom icon engines are free to ignore additionally added
1096 pixmaps.
1097
1098 \sa addFile()
1099*/
1100void QIcon::addPixmap(const QPixmap &pixmap, Mode mode, State state)
1101{
1102 if (pixmap.isNull())
1103 return;
1104 detach();
1105 if (!d)
1106 d = new QIconPrivate(new QPixmapIconEngine);
1107 d->engine->addPixmap(pixmap, mode, state);
1108}
1109
1110static QIconEngine *iconEngineFromSuffix(const QString &fileName, const QString &suffix)
1111{
1112 if (!suffix.isEmpty()) {
1113 const int index = iceLoader()->indexOf(needle: suffix);
1114 if (index != -1) {
1115 if (QIconEnginePlugin *factory = qobject_cast<QIconEnginePlugin*>(object: iceLoader()->instance(index))) {
1116 return factory->create(filename: fileName);
1117 }
1118 }
1119 }
1120 return nullptr;
1121}
1122
1123/*! Adds an image from the file with the given \a fileName to the
1124 icon, as a specialization for \a size, \a mode and \a state. The
1125 file will be loaded on demand. Note: custom icon engines are free
1126 to ignore additionally added pixmaps.
1127
1128 If \a fileName contains a relative path (e.g. the filename only)
1129 the relevant file must be found relative to the runtime working
1130 directory.
1131
1132 The file name can refer to an actual file on disk or to
1133 one of the application's embedded resources. See the
1134 \l{resources.html}{Resource System} overview for details on how to
1135 embed images and other resource files in the application's
1136 executable.
1137
1138 Use the QImageReader::supportedImageFormats() and
1139 QImageWriter::supportedImageFormats() functions to retrieve a
1140 complete list of the supported file formats.
1141
1142 If a high resolution version of the image exists (identified by
1143 the suffix \c @2x on the base name), it is automatically loaded
1144 and added with the \e{device pixel ratio} set to a value of 2.
1145 This can be disabled by setting the environment variable
1146 \c QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING (see QImageReader).
1147
1148 \note When you add a non-empty filename to a QIcon, the icon becomes
1149 non-null, even if the file doesn't exist or points to a corrupt file.
1150
1151 \sa addPixmap(), QPixmap::devicePixelRatio()
1152 */
1153void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State state)
1154{
1155 if (fileName.isEmpty())
1156 return;
1157 detach();
1158 bool alreadyAdded = false;
1159 if (!d) {
1160
1161 QFileInfo info(fileName);
1162 QString suffix = info.suffix();
1163#if QT_CONFIG(mimetype)
1164 if (suffix.isEmpty())
1165 suffix = QMimeDatabase().mimeTypeForFile(fileInfo: info).preferredSuffix(); // determination from contents
1166#endif // mimetype
1167 QIconEngine *engine = iconEngineFromSuffix(fileName, suffix);
1168 if (engine)
1169 alreadyAdded = !engine->isNull();
1170 d = new QIconPrivate(engine ? engine : new QPixmapIconEngine);
1171 }
1172 if (!alreadyAdded)
1173 d->engine->addFile(fileName, size, mode, state);
1174
1175 if (d->engine->key() == "svg"_L1) // not needed and also not supported
1176 return;
1177
1178 // Check if a "@Nx" file exists and add it.
1179 QString atNxFileName = qt_findAtNxFile(baseFileName: fileName, qApp->devicePixelRatio());
1180 if (atNxFileName != fileName)
1181 d->engine->addFile(fileName: atNxFileName, size, mode, state);
1182}
1183
1184/*!
1185 Returns a list of available icon sizes for the specified \a mode and
1186 \a state.
1187*/
1188QList<QSize> QIcon::availableSizes(Mode mode, State state) const
1189{
1190 if (!d || !d->engine)
1191 return QList<QSize>();
1192 return d->engine->availableSizes(mode, state);
1193}
1194
1195/*!
1196 Returns the name used to create the icon, if available.
1197
1198 Depending on the way the icon was created, it may have an associated
1199 name. This is the case for icons created with fromTheme().
1200
1201 \sa fromTheme(), QIconEngine::iconName()
1202*/
1203QString QIcon::name() const
1204{
1205 if (!d || !d->engine)
1206 return QString();
1207 return d->engine->iconName();
1208}
1209
1210/*!
1211 Sets the search paths for icon themes to \a paths.
1212
1213 The content of \a paths should follow the theme format
1214 documented by setThemeName().
1215
1216 \sa themeSearchPaths(), fromTheme(), setThemeName()
1217*/
1218void QIcon::setThemeSearchPaths(const QStringList &paths)
1219{
1220 QIconLoader::instance()->setThemeSearchPath(paths);
1221}
1222
1223/*!
1224 Returns the search paths for icon themes.
1225
1226 The default search paths will be defined by the platform.
1227 All platforms will also have the resource directory \c{:\icons} as a fallback.
1228
1229 \sa setThemeSearchPaths(), fromTheme(), setThemeName()
1230*/
1231QStringList QIcon::themeSearchPaths()
1232{
1233 return QIconLoader::instance()->themeSearchPaths();
1234}
1235
1236/*!
1237 \since 5.11
1238
1239 Returns the fallback search paths for icons.
1240
1241 The fallback search paths are consulted for standalone
1242 icon files if the \l{themeName()}{current icon theme}
1243 or \l{fallbackThemeName()}{fallback icon theme} do
1244 not provide results for an icon lookup.
1245
1246 If not set, the fallback search paths will be defined
1247 by the platform.
1248
1249 \sa setFallbackSearchPaths(), themeSearchPaths()
1250*/
1251QStringList QIcon::fallbackSearchPaths()
1252{
1253 return QIconLoader::instance()->fallbackSearchPaths();
1254}
1255
1256/*!
1257 \since 5.11
1258
1259 Sets the fallback search paths for icons to \a paths.
1260
1261 The fallback search paths are consulted for standalone
1262 icon files if the \l{themeName()}{current icon theme}
1263 or \l{fallbackThemeName()}{fallback icon theme} do
1264 not provide results for an icon lookup.
1265
1266 For example:
1267
1268 \snippet code/src_gui_image_qicon.cpp 5
1269
1270 \sa fallbackSearchPaths(), setThemeSearchPaths()
1271*/
1272void QIcon::setFallbackSearchPaths(const QStringList &paths)
1273{
1274 QIconLoader::instance()->setFallbackSearchPaths(paths);
1275}
1276
1277/*!
1278 Sets the current icon theme to \a name.
1279
1280 The theme will be will be looked up in themeSearchPaths().
1281
1282 At the moment the only supported icon theme format is the
1283 \l{Freedesktop Icon Theme Specification}. The \a name should
1284 correspond to a directory name in the themeSearchPath()
1285 containing an \c index.theme file describing its contents.
1286
1287 \sa themeSearchPaths(), themeName(),
1288 {Freedesktop Icon Theme Specification}
1289*/
1290void QIcon::setThemeName(const QString &name)
1291{
1292 QIconLoader::instance()->setThemeName(name);
1293}
1294
1295/*!
1296 Returns the name of the current icon theme.
1297
1298 If not set, the current icon theme will be defined by the
1299 platform.
1300
1301 \note Platform icon themes are only implemented on
1302 \l{Freedesktop} based systems at the moment, and the
1303 icon theme depends on your desktop settings.
1304
1305 \sa setThemeName(), themeSearchPaths(), fromTheme(),
1306 hasThemeIcon()
1307*/
1308QString QIcon::themeName()
1309{
1310 return QIconLoader::instance()->themeName();
1311}
1312
1313/*!
1314 \since 5.12
1315
1316 Returns the name of the fallback icon theme.
1317
1318 If not set, the fallback icon theme will be defined by the
1319 platform.
1320
1321 \note Platform fallback icon themes are only implemented on
1322 \l{Freedesktop} based systems at the moment, and the
1323 icon theme depends on your desktop settings.
1324
1325 \sa setFallbackThemeName(), themeName()
1326*/
1327QString QIcon::fallbackThemeName()
1328{
1329 return QIconLoader::instance()->fallbackThemeName();
1330}
1331
1332/*!
1333 \since 5.12
1334
1335 Sets the fallback icon theme to \a name.
1336
1337 The fallback icon theme is consulted for icons not provided by
1338 the \l{themeName()}{current icon theme}, or if the \l{themeName()}
1339 {current icon theme} does not exist.
1340
1341 The \a name should correspond to theme in the same format
1342 as documented by setThemeName(), and will be looked up
1343 in themeSearchPaths().
1344
1345 \note Fallback icon themes should be set before creating
1346 QGuiApplication, to ensure correct initialization.
1347
1348 \sa fallbackThemeName(), themeSearchPaths(), themeName()
1349*/
1350void QIcon::setFallbackThemeName(const QString &name)
1351{
1352 QIconLoader::instance()->setFallbackThemeName(name);
1353}
1354
1355/*!
1356 Returns the QIcon corresponding to \a name in the
1357 \l{themeName()}{current icon theme}.
1358
1359 If the current theme does not provide an icon for \a name,
1360 the \l{fallbackThemeName()}{fallback icon theme} is consulted,
1361 before falling back to looking up standalone icon files in the
1362 \l{QIcon::fallbackSearchPaths()}{fallback icon search path}.
1363 Finally, the platform's native icon library is consulted.
1364
1365 To fetch an icon from the current icon theme:
1366
1367 \snippet code/src_gui_image_qicon.cpp fromTheme
1368
1369 If an \l{themeName()}{icon theme} has not been explicitly
1370 set via setThemeName() a platform defined icon theme will
1371 be used.
1372
1373 \sa themeName(), fallbackThemeName(), setThemeName(), themeSearchPaths(), fallbackSearchPaths(),
1374 {Freedesktop Icon Naming Specification}
1375*/
1376QIcon QIcon::fromTheme(const QString &name)
1377{
1378
1379 if (QIcon *cachedIcon = qtIconCache()->object(key: name))
1380 return *cachedIcon;
1381
1382 if (QDir::isAbsolutePath(path: name))
1383 return QIcon(name);
1384
1385 QIcon icon(new QThemeIconEngine(name));
1386 qtIconCache()->insert(key: name, object: new QIcon(icon));
1387 return icon;
1388}
1389
1390/*!
1391 \overload
1392
1393 Returns the QIcon corresponding to \a name in the
1394 \l{themeName()}{current icon theme}.
1395
1396 If the current theme does not provide an icon for \a name,
1397 the \l{fallbackThemeName()}{fallback icon theme} is consulted,
1398 before falling back to looking up standalone icon files in the
1399 \l{QIcon::fallbackSearchPaths()}{fallback icon search path}.
1400 Finally, the platform's native icon library is consulted.
1401
1402 If no icon is found \a fallback is returned.
1403
1404 This is useful to provide a guaranteed fallback, regardless of
1405 whether the current set of icon themes and fallbacks paths
1406 support the requested icon.
1407
1408 For example:
1409
1410 \snippet code/src_gui_image_qicon.cpp 4
1411
1412 \sa fallbackThemeName(), fallbackSearchPaths()
1413*/
1414QIcon QIcon::fromTheme(const QString &name, const QIcon &fallback)
1415{
1416 QIcon icon = fromTheme(name);
1417
1418 if (icon.isNull() || icon.availableSizes().isEmpty())
1419 return fallback;
1420
1421 return icon;
1422}
1423
1424/*!
1425 Returns \c true if there is an icon available for \a name in the
1426 current icon theme or any of the fallbacks, as described by
1427 fromTheme(), otherwise returns \c false.
1428
1429 \sa themeSearchPaths(), fromTheme(), setThemeName()
1430*/
1431bool QIcon::hasThemeIcon(const QString &name)
1432{
1433 QIcon icon = fromTheme(name);
1434
1435 return icon.name() == name;
1436}
1437
1438static constexpr auto themeIconMapping = qOffsetStringArray(
1439 strings: "address-book-new",
1440 strings: "application-exit",
1441 strings: "appointment-new",
1442 strings: "call-start",
1443 strings: "call-stop",
1444 strings: "contact-new",
1445 strings: "document-new",
1446 strings: "document-open",
1447 strings: "document-open-recent",
1448 strings: "document-page-setup",
1449 strings: "document-print",
1450 strings: "document-print-preview",
1451 strings: "document-properties",
1452 strings: "document-revert",
1453 strings: "document-save",
1454 strings: "document-save-as",
1455 strings: "document-send",
1456 strings: "edit-clear",
1457 strings: "edit-copy",
1458 strings: "edit-cut",
1459 strings: "edit-delete",
1460 strings: "edit-find",
1461 strings: "edit-paste",
1462 strings: "edit-redo",
1463 strings: "edit-select-all",
1464 strings: "edit-undo",
1465 strings: "folder-new",
1466 strings: "format-indent-less",
1467 strings: "format-indent-more",
1468 strings: "format-justify-center",
1469 strings: "format-justify-fill",
1470 strings: "format-justify-left",
1471 strings: "format-justify-right",
1472 strings: "format-text-direction-ltr",
1473 strings: "format-text-direction-rtl",
1474 strings: "format-text-bold",
1475 strings: "format-text-italic",
1476 strings: "format-text-underline",
1477 strings: "format-text-strikethrough",
1478 strings: "go-down",
1479 strings: "go-home",
1480 strings: "go-next",
1481 strings: "go-previous",
1482 strings: "go-up",
1483 strings: "help-about",
1484 strings: "help-faq",
1485 strings: "insert-image",
1486 strings: "insert-link",
1487 strings: "insert-text",
1488 strings: "list-add",
1489 strings: "list-remove",
1490 strings: "mail-forward",
1491 strings: "mail-mark-important",
1492 strings: "mail-mark-read",
1493 strings: "mail-mark-unread",
1494 strings: "mail-message-new",
1495 strings: "mail-reply-all",
1496 strings: "mail-reply-sender",
1497 strings: "mail-send",
1498 strings: "media-eject",
1499 strings: "media-playback-pause",
1500 strings: "media-playback-start",
1501 strings: "media-playback-stop",
1502 strings: "media-record",
1503 strings: "media-seek-backward",
1504 strings: "media-seek-forward",
1505 strings: "media-skip-backward",
1506 strings: "media-skip-forward",
1507 strings: "object-rotate-left",
1508 strings: "object-rotate-right",
1509 strings: "process-stop",
1510 strings: "system-lock-screen",
1511 strings: "system-log-out",
1512 strings: "system-search",
1513 strings: "system-reboot",
1514 strings: "system-shutdown",
1515 strings: "tools-check-spelling",
1516 strings: "view-fullscreen",
1517 strings: "view-refresh",
1518 strings: "view-restore",
1519 strings: "window-close",
1520 strings: "window-new",
1521 strings: "zoom-fit-best",
1522 strings: "zoom-in",
1523 strings: "zoom-out",
1524
1525 strings: "audio-card",
1526 strings: "audio-input-microphone",
1527 strings: "battery",
1528 strings: "camera-photo",
1529 strings: "camera-video",
1530 strings: "camera-web",
1531 strings: "computer",
1532 strings: "drive-harddisk",
1533 strings: "drive-optical",
1534 strings: "input-gaming",
1535 strings: "input-keyboard",
1536 strings: "input-mouse",
1537 strings: "input-tablet",
1538 strings: "media-flash",
1539 strings: "media-optical",
1540 strings: "media-tape",
1541 strings: "multimedia-player",
1542 strings: "network-wired",
1543 strings: "network-wireless",
1544 strings: "phone",
1545 strings: "printer",
1546 strings: "scanner",
1547 strings: "video-display",
1548
1549 strings: "appointment-missed",
1550 strings: "appointment-soon",
1551 strings: "audio-volume-high",
1552 strings: "audio-volume-low",
1553 strings: "audio-volume-medium",
1554 strings: "audio-volume-muted",
1555 strings: "battery-caution",
1556 strings: "battery-low",
1557 strings: "dialog-error",
1558 strings: "dialog-information",
1559 strings: "dialog-password",
1560 strings: "dialog-question",
1561 strings: "dialog-warning",
1562 strings: "folder-drag-accept",
1563 strings: "folder-open",
1564 strings: "folder-visiting",
1565 strings: "image-loading",
1566 strings: "image-missing",
1567 strings: "mail-attachment",
1568 strings: "mail-unread",
1569 strings: "mail-read",
1570 strings: "mail-replied",
1571 strings: "media-playlist-repeat",
1572 strings: "media-playlist-shuffle",
1573 strings: "network-offline",
1574 strings: "printer-printing",
1575 strings: "security-high",
1576 strings: "security-low",
1577 strings: "software-update-available",
1578 strings: "software-update-urgent",
1579 strings: "sync-error",
1580 strings: "sync-synchronizing",
1581 strings: "user-available",
1582 strings: "user-offline",
1583 strings: "weather-clear",
1584 strings: "weather-clear-night",
1585 strings: "weather-few-clouds",
1586 strings: "weather-few-clouds-night",
1587 strings: "weather-fog",
1588 strings: "weather-showers",
1589 strings: "weather-snow",
1590 strings: "weather-storm"
1591);
1592static_assert(QIcon::ThemeIcon::NThemeIcons == QIcon::ThemeIcon(themeIconMapping.count()));
1593
1594static constexpr QLatin1StringView themeIconName(QIcon::ThemeIcon icon)
1595{
1596 using ThemeIconIndex = std::underlying_type_t<QIcon::ThemeIcon>;
1597 const auto index = static_cast<ThemeIconIndex>(icon);
1598 Q_ASSERT(index < themeIconMapping.count());
1599 return QLatin1StringView(themeIconMapping.viewAt(index));
1600}
1601
1602/*!
1603 \enum QIcon::ThemeIcon
1604 \since 6.7
1605
1606 This enum provides access to icons that are provided by most
1607 icon theme implementations.
1608
1609 \value AddressBookNew The icon for the action to create a new address book.
1610 \value ApplicationExit The icon for exiting an application.
1611 \value AppointmentNew The icon for the action to create a new appointment.
1612 \value CallStart The icon for initiating or accepting a call.
1613 \value CallStop The icon for stopping a current call.
1614 \value ContactNew The icon for the action to create a new contact.
1615 \value DocumentNew The icon for the action to create a new document.
1616 \value DocumentOpen The icon for the action to open a document.
1617 \value DocumentOpenRecent The icon for the action to open a document that was recently opened.
1618 \value DocumentPageSetup The icon for the \e{page setup} action.
1619 \value DocumentPrint The icon for the \e{print} action.
1620 \value DocumentPrintPreview The icon for the \e{print preview} action.
1621 \value DocumentProperties The icon for the action to view the properties of a document.
1622 \value DocumentRevert The icon for the action of reverting to a previous version of a document.
1623 \value DocumentSave The icon for the \e{save} action.
1624 \value DocumentSaveAs The icon for the \e{save as} action.
1625 \value DocumentSend The icon for the \e{send} action.
1626 \value EditClear The icon for the \e{clear} action.
1627 \value EditCopy The icon for the \e{copy} action.
1628 \value EditCut The icon for the \e{cut} action.
1629 \value EditDelete The icon for the \e{delete} action.
1630 \value EditFind The icon for the \e{find} action.
1631 \value EditPaste The icon for the \e{paste} action.
1632 \value EditRedo The icon for the \e{redo} action.
1633 \value EditSelectAll The icon for the \e{select all} action.
1634 \value EditUndo The icon for the \e{undo} action.
1635 \value FolderNew The icon for creating a new folder.
1636 \value FormatIndentLess The icon for the \e{decrease indent formatting} action.
1637 \value FormatIndentMore The icon for the \e{increase indent formatting} action.
1638 \value FormatJustifyCenter The icon for the \e{center justification formatting} action.
1639 \value FormatJustifyFill The icon for the \e{fill justification formatting} action.
1640 \value FormatJustifyLeft The icon for the \e{left justification formatting} action.
1641 \value FormatJustifyRight The icon for the \e{right justification} action.
1642 \value FormatTextDirectionLtr The icon for the \e{left-to-right text formatting} action.
1643 \value FormatTextDirectionRtl The icon for the \e{right-to-left formatting} action.
1644 \value FormatTextBold The icon for the \e{bold text formatting} action.
1645 \value FormatTextItalic The icon for the \e{italic text formatting} action.
1646 \value FormatTextUnderline The icon for the \e{underlined text formatting} action.
1647 \value FormatTextStrikethrough The icon for the \e{strikethrough text formatting} action.
1648 \value GoDown The icon for the \e{go down in a list} action.
1649 \value GoHome The icon for the \e{go to home location} action.
1650 \value GoNext The icon for the \e{go to the next item in a list} action.
1651 \value GoPrevious The icon for the \e{go to the previous item in a list} action.
1652 \value GoUp The icon for the \e{go up in a list} action.
1653 \value HelpAbout The icon for the \e{About} item in the Help menu.
1654 \value HelpFaq The icon for the \e{FAQ} item in the Help menu.
1655 \value InsertImage The icon for the \e{insert image} action of an application.
1656 \value InsertLink The icon for the \e{insert link} action of an application.
1657 \value InsertText The icon for the \e{insert text} action of an application.
1658 \value ListAdd The icon for the \e{add to list} action.
1659 \value ListRemove The icon for the \e{remove from list} action.
1660 \value MailForward The icon for the \e{forward} action.
1661 \value MailMarkImportant The icon for the \e{mark as important} action.
1662 \value MailMarkRead The icon for the \e{mark as read} action.
1663 \value MailMarkUnread The icon for the \e{mark as unread} action.
1664 \value MailMessageNew The icon for the \e{compose new mail} action.
1665 \value MailReplyAll The icon for the \e{reply to all} action.
1666 \value MailReplySender The icon for the \e{reply to sender} action.
1667 \value MailSend The icon for the \e{send} action.
1668 \value MediaEject The icon for the \e{eject} action of a media player or file manager.
1669 \value MediaPlaybackPause The icon for the \e{pause} action of a media player.
1670 \value MediaPlaybackStart The icon for the \e{start playback} action of a media player.
1671 \value MediaPlaybackStop The icon for the \e{stop} action of a media player.
1672 \value MediaRecord The icon for the \e{record} action of a media application.
1673 \value MediaSeekBackward The icon for the \e{seek backward} action of a media player.
1674 \value MediaSeekForward The icon for the \e{seek forward} action of a media player.
1675 \value MediaSkipBackward The icon for the \e{skip backward} action of a media player.
1676 \value MediaSkipForward The icon for the \e{skip forward} action of a media player.
1677 \value ObjectRotateLeft The icon for the \e{rotate left} action performed on an object.
1678 \value ObjectRotateRight The icon for the \e{rotate right} action performed on an object.
1679 \value ProcessStop The icon for the \e{stop action in applications with} actions that
1680 may take a while to process, such as web page loading in a browser.
1681 \value SystemLockScreen The icon for the \e{lock screen} action.
1682 \value SystemLogOut The icon for the \e{log out} action.
1683 \value SystemSearch The icon for the \e{search} action.
1684 \value SystemReboot The icon for the \e{reboot} action.
1685 \value SystemShutdown The icon for the \e{shutdown} action.
1686 \value ToolsCheckSpelling The icon for the \e{check spelling} action.
1687 \value ViewFullscreen The icon for the \e{fullscreen} action.
1688 \value ViewRefresh The icon for the \e{refresh} action.
1689 \value ViewRestore The icon for leaving the fullscreen view.
1690 \value WindowClose The icon for the \e{close window} action.
1691 \value WindowNew The icon for the \e{new window} action.
1692 \value ZoomFitBest The icon for the \e{best fit} action.
1693 \value ZoomIn The icon for the \e{zoom in} action.
1694 \value ZoomOut The icon for the \e{zoom out} action.
1695
1696 \value AudioCard The icon for the audio rendering device.
1697 \value AudioInputMicrophone The icon for the microphone audio input device.
1698 \value Battery The icon for the system battery device.
1699 \value CameraPhoto The icon for a digital still camera devices.
1700 \value CameraVideo The icon for a video camera device.
1701 \value CameraWeb The icon for a web camera device.
1702 \value Computer The icon for the computing device as a whole.
1703 \value DriveHarddisk The icon for hard disk drives.
1704 \value DriveOptical The icon for optical media drives such as CD and DVD.
1705 \value InputGaming The icon for the gaming input device.
1706 \value InputKeyboard The icon for the keyboard input device.
1707 \value InputMouse The icon for the mousing input device.
1708 \value InputTablet The icon for graphics tablet input devices.
1709 \value MediaFlash The icon for flash media, such as a memory stick.
1710 \value MediaOptical The icon for physical optical media such as CD and DVD.
1711 \value MediaTape The icon for generic physical tape media.
1712 \value MultimediaPlayer The icon for generic multimedia playing devices.
1713 \value NetworkWired The icon for wired network connections.
1714 \value NetworkWireless The icon for wireless network connections.
1715 \value Phone The icon for phone devices.
1716 \value Printer The icon for a printer device.
1717 \value Scanner The icon for a scanner device.
1718 \value VideoDisplay The icon for the monitor that video gets displayed on.
1719
1720 \value AppointmentMissed The icon for when an appointment was missed.
1721 \value AppointmentSoon The icon for when an appointment will occur soon.
1722 \value AudioVolumeHigh The icon used to indicate high audio volume.
1723 \value AudioVolumeLow The icon used to indicate low audio volume.
1724 \value AudioVolumeMedium The icon used to indicate medium audio volume.
1725 \value AudioVolumeMuted The icon used to indicate the muted state for audio playback.
1726 \value BatteryCaution The icon used when the battery is below 40%.
1727 \value BatteryLow The icon used when the battery is below 20%.
1728 \value DialogError The icon used when a dialog is opened to explain an error
1729 condition to the user.
1730 \value DialogInformation The icon used when a dialog is opened to give information to the
1731 user that may be pertinent to the requested action.
1732 \value DialogPassword The icon used when a dialog requesting the authentication
1733 credentials for a user is opened.
1734 \value DialogQuestion The icon used when a dialog is opened to ask a simple question
1735 to the user.
1736 \value DialogWarning The icon used when a dialog is opened to warn the user of
1737 impending issues with the requested action.
1738 \value FolderDragAccept The icon used for a folder while an acceptable object is being
1739 dragged onto it.
1740 \value FolderOpen The icon used for folders, while their contents are being displayed
1741 within the same window.
1742 \value FolderVisiting The icon used for folders, while their contents are being displayed
1743 in another window.
1744 \value ImageLoading The icon used while another image is being loaded.
1745 \value ImageMissing The icon used when another image could not be loaded.
1746 \value MailAttachment The icon for a message that contains attachments.
1747 \value MailUnread The icon for an unread message.
1748 \value MailRead The icon for a read message.
1749 \value MailReplied The icon for a message that has been replied to.
1750 \value MediaPlaylistRepeat The icon for the repeat mode of a media player.
1751 \value MediaPlaylistShuffle The icon for the shuffle mode of a media player.
1752 \value NetworkOffline The icon used to indicate that the device is not connected to the
1753 network.
1754 \value PrinterPrinting The icon used while a print job is successfully being spooled to a
1755 printing device.
1756 \value SecurityHigh The icon used to indicate that the security level of an item is
1757 known to be high.
1758 \value SecurityLow The icon used to indicate that the security level of an item is
1759 known to be low.
1760 \value SoftwareUpdateAvailable The icon used to indicate that an update is available.
1761 \value SoftwareUpdateUrgent The icon used to indicate that an urgent update is available.
1762 \value SyncError The icon used when an error occurs while attempting to synchronize
1763 data across devices.
1764 \value SyncSynchronizing The icon used while data is successfully synchronizing across
1765 devices.
1766 \value UserAvailable The icon used to indicate that a user is available.
1767 \value UserOffline The icon used to indicate that a user is not available.
1768 \value WeatherClear The icon used to indicate that the sky is clear.
1769 \value WeatherClearNight The icon used to indicate that the sky is clear
1770 during the night.
1771 \value WeatherFewClouds The icon used to indicate that the sky is partly cloudy.
1772 \value WeatherFewCloudsNight The icon used to indicate that the sky is partly cloudy
1773 during the night.
1774 \value WeatherFog The icon used to indicate that the weather is foggy.
1775 \value WeatherShowers The icon used to indicate that rain showers are occurring.
1776 \value WeatherSnow The icon used to indicate that snow is falling.
1777 \value WeatherStorm The icon used to indicate that the weather is stormy.
1778
1779 \omitvalue NThemeIcons
1780
1781 \sa {QIcon#Creating an icon from a theme or icon library},
1782 fromTheme()
1783*/
1784
1785/*!
1786 \since 6.7
1787 \overload
1788
1789 Returns \c true if there is an icon available for \a icon in the
1790 current icon theme or any of the fallbacks, as described by
1791 fromTheme(), otherwise returns \c false.
1792
1793 \sa fromTheme()
1794*/
1795bool QIcon::hasThemeIcon(QIcon::ThemeIcon icon)
1796{
1797 return hasThemeIcon(name: themeIconName(icon));
1798}
1799
1800/*!
1801 \fn QIcon QIcon::fromTheme(QIcon::ThemeIcon icon)
1802 \fn QIcon QIcon::fromTheme(QIcon::ThemeIcon icon, const QIcon &fallback)
1803 \since 6.7
1804 \overload
1805
1806 Returns the QIcon corresponding to \a icon in the
1807 \l{themeName()}{current icon theme}.
1808
1809 If the current theme does not provide an icon for \a icon,
1810 the \l{fallbackThemeName()}{fallback icon theme} is consulted,
1811 before falling back to looking up standalone icon files in the
1812 \l{QIcon::fallbackSearchPaths()}{fallback icon search path}.
1813 Finally, the platform's native icon library is consulted.
1814
1815 If no icon is found and a \a fallback is provided, \a fallback is
1816 returned. This is useful to provide a guaranteed fallback, regardless
1817 of whether the current set of icon themes and fallbacks paths
1818 support the requested icon.
1819
1820 If no icon is found and no \a fallback is provided, a default
1821 constructed, empty QIcon is returned.
1822*/
1823QIcon QIcon::fromTheme(QIcon::ThemeIcon icon)
1824{
1825 return fromTheme(name: themeIconName(icon));
1826}
1827
1828QIcon QIcon::fromTheme(QIcon::ThemeIcon icon, const QIcon &fallback)
1829{
1830 return fromTheme(name: themeIconName(icon), fallback);
1831}
1832
1833/*!
1834 \since 5.6
1835
1836 Indicate that this icon is a mask image(boolean \a isMask), and hence can
1837 potentially be modified based on where it's displayed.
1838 \sa isMask()
1839*/
1840void QIcon::setIsMask(bool isMask)
1841{
1842 if (isMask == (d && d->is_mask))
1843 return;
1844
1845 detach();
1846 if (!d)
1847 d = new QIconPrivate(new QPixmapIconEngine);
1848 d->is_mask = isMask;
1849}
1850
1851/*!
1852 \since 5.6
1853
1854 Returns \c true if this icon has been marked as a mask image.
1855 Certain platforms render mask icons differently (for example,
1856 menu icons on \macos).
1857
1858 \sa setIsMask()
1859*/
1860bool QIcon::isMask() const
1861{
1862 if (!d)
1863 return false;
1864 return d->is_mask;
1865}
1866
1867/*****************************************************************************
1868 QIcon stream functions
1869 *****************************************************************************/
1870#if !defined(QT_NO_DATASTREAM)
1871/*!
1872 \fn QDataStream &operator<<(QDataStream &stream, const QIcon &icon)
1873 \relates QIcon
1874
1875 Writes the given \a icon to the given \a stream as a PNG
1876 image. If the icon contains more than one image, all images will
1877 be written to the stream. Note that writing the stream to a file
1878 will not produce a valid image file.
1879*/
1880
1881QDataStream &operator<<(QDataStream &s, const QIcon &icon)
1882{
1883 if (s.version() >= QDataStream::Qt_4_3) {
1884 if (icon.isNull()) {
1885 s << QString();
1886 } else {
1887 s << icon.d->engine->key();
1888 icon.d->engine->write(out&: s);
1889 }
1890 } else if (s.version() == QDataStream::Qt_4_2) {
1891 if (icon.isNull()) {
1892 s << 0;
1893 } else {
1894 QPixmapIconEngine *engine = static_cast<QPixmapIconEngine *>(icon.d->engine);
1895 int num_entries = engine->pixmaps.size();
1896 s << num_entries;
1897 for (int i=0; i < num_entries; ++i) {
1898 s << engine->pixmaps.at(i).pixmap;
1899 s << engine->pixmaps.at(i).fileName;
1900 s << engine->pixmaps.at(i).size;
1901 s << (uint) engine->pixmaps.at(i).mode;
1902 s << (uint) engine->pixmaps.at(i).state;
1903 }
1904 }
1905 } else {
1906 s << QPixmap(icon.pixmap(w: 22,h: 22));
1907 }
1908 return s;
1909}
1910
1911/*!
1912 \fn QDataStream &operator>>(QDataStream &stream, QIcon &icon)
1913 \relates QIcon
1914
1915 Reads an image, or a set of images, from the given \a stream into
1916 the given \a icon.
1917*/
1918
1919QDataStream &operator>>(QDataStream &s, QIcon &icon)
1920{
1921 if (s.version() >= QDataStream::Qt_4_3) {
1922 icon = QIcon();
1923 QString key;
1924 s >> key;
1925 if (key == "QPixmapIconEngine"_L1) {
1926 icon.d = new QIconPrivate(new QPixmapIconEngine);
1927 icon.d->engine->read(in&: s);
1928 } else if (key == "QIconLoaderEngine"_L1 || key == "QThemeIconEngine"_L1) {
1929 icon.d = new QIconPrivate(new QThemeIconEngine);
1930 icon.d->engine->read(in&: s);
1931 } else {
1932 const int index = iceLoader()->indexOf(needle: key);
1933 if (index != -1) {
1934 if (QIconEnginePlugin *factory = qobject_cast<QIconEnginePlugin*>(object: iceLoader()->instance(index))) {
1935 if (QIconEngine *engine= factory->create()) {
1936 icon.d = new QIconPrivate(engine);
1937 engine->read(in&: s);
1938 } // factory
1939 } // instance
1940 } // index
1941 }
1942 } else if (s.version() == QDataStream::Qt_4_2) {
1943 icon = QIcon();
1944 int num_entries;
1945 QPixmap pm;
1946 QString fileName;
1947 QSize sz;
1948 uint mode;
1949 uint state;
1950
1951 s >> num_entries;
1952 for (int i=0; i < num_entries; ++i) {
1953 s >> pm;
1954 s >> fileName;
1955 s >> sz;
1956 s >> mode;
1957 s >> state;
1958 if (pm.isNull())
1959 icon.addFile(fileName, size: sz, mode: QIcon::Mode(mode), state: QIcon::State(state));
1960 else
1961 icon.addPixmap(pixmap: pm, mode: QIcon::Mode(mode), state: QIcon::State(state));
1962 }
1963 } else {
1964 QPixmap pm;
1965 s >> pm;
1966 icon.addPixmap(pixmap: pm);
1967 }
1968 return s;
1969}
1970
1971#endif //QT_NO_DATASTREAM
1972
1973#ifndef QT_NO_DEBUG_STREAM
1974QDebug operator<<(QDebug dbg, const QIcon &i)
1975{
1976 QDebugStateSaver saver(dbg);
1977 dbg.resetFormat();
1978 dbg.nospace();
1979 dbg << "QIcon(";
1980 if (i.isNull()) {
1981 dbg << "null";
1982 } else {
1983 if (!i.name().isEmpty())
1984 dbg << i.name() << ',';
1985 dbg << "availableSizes[normal,Off]=" << i.availableSizes()
1986 << ",cacheKey=" << Qt::showbase << Qt::hex << i.cacheKey() << Qt::dec << Qt::noshowbase;
1987 }
1988 dbg << ')';
1989 return dbg;
1990}
1991#endif
1992
1993/*!
1994 \fn DataPtr &QIcon::data_ptr()
1995 \internal
1996*/
1997
1998/*!
1999 \typedef QIcon::DataPtr
2000 \internal
2001*/
2002
2003/*!
2004 \internal
2005 \since 5.6
2006 Attempts to find a suitable @Nx file for the given \a targetDevicePixelRatio
2007 Returns the \a baseFileName if no such file was found.
2008
2009 Given base foo.png and a target dpr of 2.5, this function will look for
2010 foo@3x.png, then foo@2x, then fall back to foo.png if not found.
2011
2012 \a sourceDevicePixelRatio will be set to the value of N if the argument is
2013 not \nullptr
2014*/
2015QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRatio,
2016 qreal *sourceDevicePixelRatio)
2017{
2018 if (targetDevicePixelRatio <= 1.0)
2019 return baseFileName;
2020
2021 static bool disableNxImageLoading = !qEnvironmentVariableIsEmpty(varName: "QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING");
2022 if (disableNxImageLoading)
2023 return baseFileName;
2024
2025 int dotIndex = baseFileName.lastIndexOf(c: u'.');
2026 if (dotIndex == -1) { /* no dot */
2027 dotIndex = baseFileName.size(); /* append */
2028 } else if (dotIndex >= 2 && baseFileName[dotIndex - 1] == u'9'
2029 && baseFileName[dotIndex - 2] == u'.') {
2030 // If the file has a .9.* (9-patch image) extension, we must ensure that the @nx goes before it.
2031 dotIndex -= 2;
2032 }
2033
2034 QString atNxfileName = baseFileName;
2035 atNxfileName.insert(i: dotIndex, s: "@2x"_L1);
2036 // Check for @Nx, ..., @3x, @2x file versions,
2037 for (int n = qMin(a: qCeil(v: targetDevicePixelRatio), b: 9); n > 1; --n) {
2038 atNxfileName[dotIndex + 1] = QLatin1Char('0' + n);
2039 if (QFile::exists(fileName: atNxfileName)) {
2040 if (sourceDevicePixelRatio)
2041 *sourceDevicePixelRatio = n;
2042 return atNxfileName;
2043 }
2044 }
2045
2046 return baseFileName;
2047}
2048
2049QT_END_NAMESPACE
2050#endif //QT_NO_ICON
2051

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtbase/src/gui/image/qicon.cpp