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