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
5#include "qicon.h"
6#include "qicon_p.h"
7#include "qiconengine.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
33
34using namespace Qt::StringLiterals;
35// Convenience class providing a bool read() function.
36namespace {
37class ImageReader
38{
39public:
40 ImageReader(const QString &fileName, QSize size)
41 : m_reader(fileName)
42 , m_atEnd(false)
43 {
44 if (m_reader.supportsOption(QImageIOHandler::ScaledSize))
45 m_reader.setScaledSize(size);
46 }
47
48 QByteArray format() const { return m_reader.format(); }
49 bool supportsReadSize() const { return m_reader.supportsOption(QImageIOHandler::Size); }
50 QSize size() const { return m_reader.size(); }
51 bool jumpToNextImage() { return m_reader.jumpToNextImage(); }
52 void jumpToImage(int index) { m_reader.jumpToImage(index); }
53
54 bool read(QImage *image)
55 {
56 if (m_atEnd)
57 return false;
58 *image = m_reader.read();
59 if (!image->size().isValid()) {
60 m_atEnd = true;
61 return false;
62 }
63 m_atEnd = !m_reader.jumpToNextImage();
64 return true;
65 }
66
67private:
68 QImageReader m_reader;
69 bool m_atEnd;
70};
71} // namespace
72
73/*!
74 \enum QIcon::Mode
75
76 This enum type describes the mode for which a pixmap is intended
77 to be used. The currently defined modes are:
78
79 \value Normal
80 Display the pixmap when the user is
81 not interacting with the icon, but the
82 functionality represented by the icon is available.
83 \value Disabled
84 Display the pixmap when the
85 functionality represented by the icon is not available.
86 \value Active
87 Display the pixmap when the
88 functionality represented by the icon is available and
89 the user is interacting with the icon, for example, moving the
90 mouse over it or clicking it.
91 \value Selected
92 Display the pixmap when the item represented by the icon is
93 selected.
94*/
95
96/*!
97 \enum QIcon::State
98
99 This enum describes the state for which a pixmap is intended to be
100 used. The \e state can be:
101
102 \value On Display the pixmap when the widget is in an "on" state
103 \value Off Display the pixmap when the widget is in an "off" state
104*/
105
107{
108 Q_CONSTINIT static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
109 return 1 + serial.fetchAndAddRelaxed(1);
110}
111
112static void qt_cleanup_icon_cache();
113namespace {
114 struct IconCache : public QCache<QString, QIcon>
115 {
116 IconCache()
117 {
118 // ### note: won't readd if QApplication is re-created!
119 qAddPostRoutine(qt_cleanup_icon_cache);
120 }
121 };
122}
123
124Q_GLOBAL_STATIC(IconCache, qtIconCache)
125
127{
128 qtIconCache()->clear();
129}
130
132 : engine(e), ref(1),
134 detach_no(0),
135 is_mask(false)
136{
137}
138
143
144/*! \internal
145 Computes the displayDevicePixelRatio for a pixmap.
146
147 If displayDevicePixelRatio is 1.0 the returned value is 1.0, always.
148
149 For a displayDevicePixelRatio of 2.0 the returned value will be between
150 1.0 and 2.0, depending on requestedSize and actualsize:
151 * If actualsize < requestedSize : 1.0 (not enough pixels for a normal-dpi pixmap)
152 * If actualsize == requestedSize * 2.0 : 2.0 (enough pixels for a high-dpi pixmap)
153 * else : a scaled value between 1.0 and 2.0. (pixel count is between normal-dpi and high-dpi)
154*/
155qreal QIconPrivate::pixmapDevicePixelRatio(qreal displayDevicePixelRatio, const QSize &requestedSize, const QSize &actualSize)
156{
157 QSize targetSize = requestedSize * displayDevicePixelRatio;
158 if ((actualSize.width() == targetSize.width() && actualSize.height() <= targetSize.height()) ||
159 (actualSize.width() <= targetSize.width() && actualSize.height() == targetSize.height())) {
160 // Correctly scaled for dpr, just having different aspect ratio
161 return displayDevicePixelRatio;
162 }
163 qreal scale = 0.5 * (qreal(actualSize.width()) / qreal(targetSize.width()) +
164 qreal(actualSize.height()) / qreal(targetSize.height()));
165 qreal dpr = qMax(qreal(1.0), displayDevicePixelRatio * scale);
166 return qRound(dpr * 100) / 100.0;
167}
168
169QPixmapIconEngine::QPixmapIconEngine()
170{
171}
172
173QPixmapIconEngine::QPixmapIconEngine(const QPixmapIconEngine &other)
174 : QIconEngine(other), pixmaps(other.pixmaps)
175{
176}
177
178QPixmapIconEngine::~QPixmapIconEngine()
179{
180}
181
182void QPixmapIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
183{
184 auto paintDevice = painter->device();
185 qreal dpr = paintDevice ? paintDevice->devicePixelRatio() : qApp->devicePixelRatio();
186 QPixmap px = scaledPixmap(rect.size(), mode, state, dpr);
187 painter->drawPixmap(rect, px);
188}
189
190static inline qint64 area(const QSize &s) { return qint64(s.width()) * s.height(); }
191
192// Returns the smallest of the two that is still larger than or equal to size.
193// Pixmaps at the correct scale are preferred, pixmaps at lower scale are
194// used as fallbacks. We assume that the pixmap set is complete, in the sense
195// that no 2x pixmap is going to be a better match than a 3x pixmap for the the
196// target scale of 3 (It's OK if 3x pixmaps are missing - we'll fall back to
197// the 2x pixmaps then.)
199{
200 const auto scaleA = pa->pixmap.devicePixelRatio();
201 const auto scaleB = pb->pixmap.devicePixelRatio();
202 // scale: we can only differentiate on scale if the scale differs
203 if (scaleA != scaleB) {
204
205 // Score the pixmaps: 0 is an exact scale match, positive
206 // scores have more detail than requested, negative scores
207 // have less detail than requested.
208 qreal ascore = scaleA - scale;
209 qreal bscore = scaleB - scale;
210
211 // always prefer positive scores to prevent upscaling
212 if ((ascore < 0) != (bscore < 0))
213 return bscore < 0 ? pa : pb;
214 // Take the one closest to 0
215 return (qAbs(ascore) < qAbs(bscore)) ? pa : pb;
216 }
217
218 qint64 s = area(size * scale);
219 if (pa->size == QSize() && pa->pixmap.isNull()) {
220 pa->pixmap = QPixmap(pa->fileName);
221 pa->size = pa->pixmap.size();
222 }
223 qint64 a = area(pa->size);
224 if (pb->size == QSize() && pb->pixmap.isNull()) {
225 pb->pixmap = QPixmap(pb->fileName);
226 pb->size = pb->pixmap.size();
227 }
228 qint64 b = area(pb->size);
229 qint64 res = a;
230 if (qMin(a,b) >= s)
231 res = qMin(a,b);
232 else
233 res = qMax(a,b);
234 if (res == a)
235 return pa;
236 return pb;
237}
238
239QPixmapIconEngineEntry *QPixmapIconEngine::tryMatch(const QSize &size, qreal scale, QIcon::Mode mode, QIcon::State state)
240{
241 QPixmapIconEngineEntry *pe = nullptr;
242 for (auto &entry : pixmaps) {
243 if (entry.mode == mode && entry.state == state) {
244 if (pe)
245 pe = bestSizeScaleMatch(size, scale, &entry, pe);
246 else
247 pe = &entry;
248 }
249 }
250 return pe;
251}
252
253
254QPixmapIconEngineEntry *QPixmapIconEngine::bestMatch(const QSize &size, qreal scale, QIcon::Mode mode, QIcon::State state)
255{
256 QPixmapIconEngineEntry *pe = tryMatch(size, scale, mode, state);
257 while (!pe){
258 QIcon::State oppositeState = (state == QIcon::On) ? QIcon::Off : QIcon::On;
259 if (mode == QIcon::Disabled || mode == QIcon::Selected) {
260 QIcon::Mode oppositeMode = (mode == QIcon::Disabled) ? QIcon::Selected : QIcon::Disabled;
261 if ((pe = tryMatch(size, scale, QIcon::Normal, state)))
262 break;
263 if ((pe = tryMatch(size, scale, QIcon::Active, state)))
264 break;
265 if ((pe = tryMatch(size, scale, mode, oppositeState)))
266 break;
267 if ((pe = tryMatch(size, scale, QIcon::Normal, oppositeState)))
268 break;
269 if ((pe = tryMatch(size, scale, QIcon::Active, oppositeState)))
270 break;
271 if ((pe = tryMatch(size, scale, oppositeMode, state)))
272 break;
273 if ((pe = tryMatch(size, scale, oppositeMode, oppositeState)))
274 break;
275 } else {
276 QIcon::Mode oppositeMode = (mode == QIcon::Normal) ? QIcon::Active : QIcon::Normal;
277 if ((pe = tryMatch(size, scale, oppositeMode, state)))
278 break;
279 if ((pe = tryMatch(size, scale, mode, oppositeState)))
280 break;
281 if ((pe = tryMatch(size, scale, oppositeMode, oppositeState)))
282 break;
283 if ((pe = tryMatch(size, scale, QIcon::Disabled, state)))
284 break;
285 if ((pe = tryMatch(size, scale, QIcon::Selected, state)))
286 break;
287 if ((pe = tryMatch(size, scale, QIcon::Disabled, oppositeState)))
288 break;
289 if ((pe = tryMatch(size, scale, QIcon::Selected, oppositeState)))
290 break;
291 }
292
293 if (!pe)
294 return pe;
295 }
296
297 if (pe->pixmap.isNull()) {
298 // delay-load the image
299 QImage image, prevImage;
300 const QSize realSize = size * scale;
301 ImageReader imageReader(pe->fileName, realSize);
302 bool fittingImageFound = false;
303 if (imageReader.supportsReadSize()) {
304 // find the image with the best size without loading the entire image
305 do {
306 fittingImageFound = imageReader.size() == realSize;
307 } while (!fittingImageFound && imageReader.jumpToNextImage());
308 }
309 if (!fittingImageFound) {
310 imageReader.jumpToImage(0);
311 while (imageReader.read(&image) && image.size() != realSize)
312 prevImage = image;
313 if (image.isNull())
314 image = prevImage;
315 } else {
316 imageReader.read(&image);
317 }
318 if (!image.isNull()) {
319 pe->pixmap.convertFromImage(image);
320 if (!pe->pixmap.isNull()) {
321 pe->size = pe->pixmap.size();
322 pe->pixmap.setDevicePixelRatio(scale);
323 }
324 }
325 if (!pe->size.isValid()) {
326 removePixmapEntry(pe);
327 pe = nullptr;
328 }
329 }
330
331 return pe;
332}
333
334QPixmap QPixmapIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
335{
336 return scaledPixmap(size, mode, state, 1.0);
337}
338
339QPixmap QPixmapIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
340{
341 QPixmap pm;
342 QPixmapIconEngineEntry *pe = bestMatch(size, scale, mode, state);
343 if (pe)
344 pm = pe->pixmap;
345 else
346 return pm;
347
348 if (pm.isNull()) {
349 removePixmapEntry(pe);
350 if (pixmaps.isEmpty())
351 return pm;
352 return scaledPixmap(size, mode, state, scale);
353 }
354
355 const auto actualSize = adjustSize(size * scale, pm.size());
356 const auto calculatedDpr = QIconPrivate::pixmapDevicePixelRatio(scale, size, actualSize);
357 QString key = "qt_"_L1
358 % HexString<quint64>(pm.cacheKey())
359 % HexString<quint8>(pe->mode)
360 % HexString<quint64>(QGuiApplication::palette().cacheKey())
361 % HexString<uint>(actualSize.width())
362 % HexString<uint>(actualSize.height())
363 % HexString<quint16>(qRound(calculatedDpr * 1000));
364
365 if (mode == QIcon::Active) {
366 if (QPixmapCache::find(key % HexString<quint8>(mode), &pm))
367 return pm; // horray
368 if (QPixmapCache::find(key % HexString<quint8>(QIcon::Normal), &pm)) {
369 QPixmap active = pm;
370 if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
371 active = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(guiApp))->applyQIconStyleHelper(QIcon::Active, pm);
372 if (pm.cacheKey() == active.cacheKey())
373 return pm;
374 }
375 }
376
377 if (!QPixmapCache::find(key % HexString<quint8>(mode), &pm)) {
378 if (pm.size() != actualSize)
379 pm = pm.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
380 if (pe->mode != mode && mode != QIcon::Normal) {
381 QPixmap generated = pm;
382 if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
383 generated = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(guiApp))->applyQIconStyleHelper(mode, pm);
384 if (!generated.isNull())
385 pm = generated;
386 }
387 pm.setDevicePixelRatio(calculatedDpr);
388 QPixmapCache::insert(key % HexString<quint8>(mode), pm);
389 }
390 return pm;
391}
392
393QSize QPixmapIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
394{
395 QSize actualSize;
396
397 // The returned actual size is the size in device independent pixels,
398 // so we limit the search to scale 1 and assume that e.g. @2x versions
399 // does not proviode extra actual sizes not also provided by the 1x versions.
400 qreal scale = 1;
401
402 if (QPixmapIconEngineEntry *pe = bestMatch(size, scale, mode, state))
403 actualSize = pe->size;
404
405 return adjustSize(size, actualSize);
406}
407
408QList<QSize> QPixmapIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state)
409{
410 QList<QSize> sizes;
411 for (QPixmapIconEngineEntry &pe : pixmaps) {
412 if (pe.mode != mode || pe.state != state)
413 continue;
414 if (pe.size.isEmpty() && pe.pixmap.isNull()) {
415 pe.pixmap = QPixmap(pe.fileName);
416 pe.size = pe.pixmap.size();
417 }
418 if (!pe.size.isEmpty() && !sizes.contains(pe.size))
419 sizes.push_back(pe.size);
420 }
421 return sizes;
422}
423
424void QPixmapIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state)
425{
426 if (!pixmap.isNull()) {
427 QPixmapIconEngineEntry *pe = tryMatch(pixmap.size() / pixmap.devicePixelRatio(),
428 pixmap.devicePixelRatio(), mode, state);
429 if (pe && pe->size == pixmap.size() && pe->pixmap.devicePixelRatio() == pixmap.devicePixelRatio()) {
430 pe->pixmap = pixmap;
431 pe->fileName.clear();
432 } else {
433 pixmaps += QPixmapIconEngineEntry(pixmap, mode, state);
434 }
435 }
436}
437
438// Read out original image depth as set by ICOReader
439static inline int origIcoDepth(const QImage &image)
440{
441 const QString s = image.text(QStringLiteral("_q_icoOrigDepth"));
442 return s.isEmpty() ? 32 : s.toInt();
443}
444
445static inline int findBySize(const QList<QImage> &images, const QSize &size)
446{
447 for (qsizetype i = 0; i < images.size(); ++i) {
448 if (images.at(i).size() == size)
449 return i;
450 }
451 return -1;
452}
453
454void QPixmapIconEngine::addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state)
455{
456 if (fileName.isEmpty())
457 return;
458 const QString abs = fileName.startsWith(u':') ? fileName : QFileInfo(fileName).absoluteFilePath();
459 const bool ignoreSize = !size.isValid();
460 ImageReader imageReader(abs, size);
461 const QByteArray format = imageReader.format();
462 if (format.isEmpty()) // Device failed to open or unsupported format.
463 return;
464 QImage image;
465 if (format != "ico") {
466 if (ignoreSize) { // No size specified: Add all images.
467 if (imageReader.supportsReadSize()) {
468 do {
469 pixmaps += QPixmapIconEngineEntry(abs, imageReader.size(), mode, state);
470 } while (imageReader.jumpToNextImage());
471 } else {
472 while (imageReader.read(&image))
473 pixmaps += QPixmapIconEngineEntry(abs, image, mode, state);
474 }
475 } else {
476 pixmaps += QPixmapIconEngineEntry(abs, size, mode, state);
477 }
478 return;
479 }
480 // Special case for reading Windows ".ico" files. Historically (QTBUG-39287),
481 // these files may contain low-resolution images. As this information is lost,
482 // ICOReader sets the original format as an image text key value. Read all matching
483 // images into a list trying to find the highest quality per size.
484 QList<QImage> icoImages;
485 while (imageReader.read(&image)) {
486 if (ignoreSize || image.size() == size) {
487 const int position = findBySize(icoImages, image.size());
488 if (position >= 0) { // Higher quality available? -> replace.
489 if (origIcoDepth(image) > origIcoDepth(icoImages.at(position)))
490 icoImages[position] = image;
491 } else {
492 icoImages.append(image);
493 }
494 }
495 }
496 for (const QImage &i : std::as_const(icoImages))
497 pixmaps += QPixmapIconEngineEntry(abs, i, mode, state);
498 if (icoImages.isEmpty() && !ignoreSize) // Add placeholder with the filename and empty pixmap for the size.
499 pixmaps += QPixmapIconEngineEntry(abs, size, mode, state);
500}
501
502bool QPixmapIconEngine::isNull()
503{
504 return pixmaps.isEmpty();
505}
506
507QString QPixmapIconEngine::key() const
508{
509 return "QPixmapIconEngine"_L1;
510}
511
512QIconEngine *QPixmapIconEngine::clone() const
513{
514 return new QPixmapIconEngine(*this);
515}
516
517bool QPixmapIconEngine::read(QDataStream &in)
518{
519 int num_entries;
520 QPixmap pm;
521 QString fileName;
522 QSize sz;
523 uint mode;
524 uint state;
525
526 in >> num_entries;
527 for (int i=0; i < num_entries; ++i) {
528 if (in.atEnd()) {
529 pixmaps.clear();
530 return false;
531 }
532 in >> pm;
533 in >> fileName;
534 in >> sz;
535 in >> mode;
536 in >> state;
537 if (pm.isNull()) {
538 addFile(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
539 } else {
540 QPixmapIconEngineEntry pe(fileName, sz, QIcon::Mode(mode), QIcon::State(state));
541 pe.pixmap = pm;
542 pixmaps += pe;
543 }
544 }
545 return true;
546}
547
548bool QPixmapIconEngine::write(QDataStream &out) const
549{
550 int num_entries = pixmaps.size();
551 out << num_entries;
552 for (int i=0; i < num_entries; ++i) {
553 if (pixmaps.at(i).pixmap.isNull())
554 out << QPixmap(pixmaps.at(i).fileName);
555 else
556 out << pixmaps.at(i).pixmap;
557 out << pixmaps.at(i).fileName;
558 out << pixmaps.at(i).size;
559 out << (uint) pixmaps.at(i).mode;
560 out << (uint) pixmaps.at(i).state;
561 }
562 return true;
563}
564
565Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, iceLoader,
566 (QIconEngineFactoryInterface_iid, "/iconengines"_L1, Qt::CaseInsensitive))
567
568QFactoryLoader *qt_iconEngineFactoryLoader()
569{
570 return iceLoader();
571}
572
573
574/*!
575 \class QIcon
576
577 \brief The QIcon class provides scalable icons in different modes
578 and states.
579
580 \ingroup painting
581 \ingroup shared
582 \inmodule QtGui
583
584 A QIcon can generate smaller, larger, active, and disabled pixmaps
585 from the set of pixmaps it is given. Such pixmaps are used by Qt
586 UI components to show an icon representing a particular action.
587
588 \section1 Creating an icon from image files
589
590 The simplest way to construct a QIcon is to create one from one or
591 several image files or resources. For example:
592
593 \snippet code/src_gui_image_qicon.cpp 0
594
595 QIcon can store several images for different states, and Qt will
596 select the image that is the closest match for the action's current
597 state.
598
599 \snippet code/src_gui_image_qicon.cpp addFile
600
601 Qt will generate the required icon styles and sizes when needed,
602 e.g. the pixmap for the QIcon::Disabled state might be generated by
603 graying out one of the provided pixmaps.
604
605 To clear the icon, simply set a null icon in its place:
606
607 \snippet code/src_gui_image_qicon.cpp 1
608
609 Use the QImageReader::supportedImageFormats() and
610 QImageWriter::supportedImageFormats() functions to retrieve a
611 complete list of the supported file formats.
612
613 \note If using an SVG image file, make sure to add it before any non-SVG files,
614 so that the correct \l{Icon Engines}{icon engine} gets selected.
615
616 \section1 Creating an icon from a theme or icon library
617
618 The most convenient way to construct an icon is by using the
619 \l{QIcon::}{fromTheme()} factory function. Qt implements access to
620 the native icon library on platforms that support the
621 \l {Freedesktop Icon Theme Specification}.
622
623 Applications can use the same theming specification to provide
624 their own icon library. See below for an example theme description
625 and the corresponding directory structure for the image files.
626
627 Since Qt 6.7, Qt also provides access to the native icon library on macOS,
628 iOS, and Windows 10 and 11. On Android, Qt can access icons from the Material
629 design system as long as the
630 \l{https://github.com/google/material-design-icons/tree/master/font}
631 {MaterialIcons-Regular} font is available on the system, or bundled
632 as a resource at \c{:/qt-project.org/icons/MaterialIcons-Regular.ttf}
633 with the application.
634
635 \snippet code/src_gui_image_qicon.cpp fromTheme
636
637 Since Qt 6.9, Qt can generate icons from named glyphs in an available icon
638 font. Set the \l{QIcon::themeName()}{theme name} to the family name of the
639 font, and use \l{QIcon::}{fromTheme()} with the name of the glyph.
640
641 \snippet code/src_gui_image_qicon.cpp iconFont
642
643 The icon font can be installed on the system, or bundled as an
644 \l{QFontDatabase::addApplicationFont()}{application font}.
645
646 \section1 Icon Engines
647
648 Internally, QIcon instantiates an \l {QIconEngine} {icon engine}
649 backend to handle and render the icon images. The type of icon
650 engine is determined by the first file or pixmap or theme added to a
651 QIcon object. Additional files or pixmaps will then be handled by
652 the same engine.
653
654 Icon engines differ in the way they handle and render icons. The
655 default pixmap-based engine only deals with fixed images, while the
656 QtSvg module provides an icon engine that can re-render the provided
657 vector graphics files at the requested size for better quality. The
658 theme icon engines will typically only provide images from native
659 platform icon library, and ignore any added files or pixmaps.
660
661 In addition, it is possible to provide custom icon engines. This
662 allows applications to customize every aspect of generated
663 icons. With QIconEnginePlugin it is possible to register different
664 icon engines for different file suffixes, making it possible for
665 third parties to provide additional icon engines to those included
666 with Qt.
667
668 \section1 Using QIcon in the User Interface
669
670 If you write your own widgets that have an option to set a small
671 pixmap, consider allowing a QIcon to be set for that pixmap. The
672 Qt class QToolButton is an example of such a widget.
673
674 Provide a method to set a QIcon, and paint the QIcon with
675 \l{QIcon::}{paint}, choosing the appropriate parameters based
676 on the current state of your widget. For example:
677
678 \snippet code/src_gui_image_qicon.cpp 2
679
680 When you retrieve a pixmap using pixmap(QSize, Mode, State), and no
681 pixmap for this given size, mode and state has been added with
682 addFile() or addPixmap(), then QIcon will generate one on the
683 fly. This pixmap generation happens in a QIconEngine. The default
684 engine scales pixmaps down if required, but never up, and it uses
685 the current style to calculate a disabled appearance.
686
687 You might also make use of the \c Active mode, perhaps making your
688 widget \c Active when the mouse is over the widget (see \l
689 QWidget::enterEvent()), while the mouse is pressed pending the
690 release that will activate the function, or when it is the currently
691 selected item. If the widget can be toggled, the "On" mode might be
692 used to draw a different icon.
693
694 QIcons generated from the native icon library, or from an icon font, use the
695 same glyph for both the \c On and \c Off states of the icon. Applications can
696 change the icon depending on the state of the respective UI control or action.
697 In a Qt Quick application, this can be done with a binding.
698
699 \snippet code/src_gui_image_qicon.qml iconFont
700
701 \image icon.png QIcon
702
703 \note QIcon needs a QGuiApplication instance before the icon is created.
704
705 \section1 High DPI Icons
706
707 Icons that are provided by the native icon library, or generated from the
708 glyph in an icon font, are usually based on vector graphics, and will
709 automatically be rendered in the appropriate resolution.
710
711 When providing your own image files via \l addFile(), then QIcon will
712 use Qt's \l {High Resolution Versions of Images}{"@nx" high DPI syntax}.
713 This is useful if you have your own custom directory structure and do not
714 use follow \l {Freedesktop Icon Theme Specification}.
715
716 When providing an application theme, then you need to follow the Icon Theme
717 Specification to specify which files to use for different resolutions.
718 To make QIcon use the high DPI version of an image, add an additional entry
719 to the appropriate \c index.theme file:
720
721 \badcode
722 [Icon Theme]
723 Name=Test
724 Comment=Test Theme
725
726 Directories=32x32/actions,32x32@2/actions
727
728 [32x32/actions]
729 Size=32
730 Context=Actions
731 Type=Fixed
732
733 # High DPI version of the entry above.
734 [32x32@2/actions]
735 Size=32
736 Scale=2
737 Type=Fixed
738 \endcode
739
740 Your icon theme directory would then look something like this:
741
742 \badcode
743 ├── 32x32
744 │ └── actions
745 │ └── appointment-new.png
746 ├── 32x32@2
747 │ └── actions
748 │ └── appointment-new.png
749 └── index.theme
750 \endcode
751*/
752
753
754/*!
755 Constructs a null icon.
756*/
757QIcon::QIcon() noexcept
758 : d(nullptr)
759{
760}
761
762/*!
763 Constructs an icon from a \a pixmap.
764 */
765QIcon::QIcon(const QPixmap &pixmap)
766 :d(nullptr)
767{
768 addPixmap(pixmap);
769}
770
771/*!
772 Constructs a copy of \a other. This is very fast.
773*/
774QIcon::QIcon(const QIcon &other)
775 :d(other.d)
776{
777 if (d)
778 d->ref.ref();
779}
780
781/*!
782 \fn QIcon::QIcon(QIcon &&other)
783
784 Move-constructs a QIcon instance, making it point to the same object
785 that \a other was pointing to.
786*/
787
788/*!
789 Constructs an icon from the file with the given \a fileName. The
790 file will be loaded on demand.
791
792 If \a fileName contains a relative path (e.g. the filename only)
793 the relevant file must be found relative to the runtime working
794 directory.
795
796 The file name can refer to an actual file on disk or to
797 one of the application's embedded resources. See the
798 \l{resources.html}{Resource System} overview for details on how to
799 embed images and other resource files in the application's
800 executable.
801
802 Use the QImageReader::supportedImageFormats() and
803 QImageWriter::supportedImageFormats() functions to retrieve a
804 complete list of the supported file formats.
805*/
806QIcon::QIcon(const QString &fileName)
807 : d(nullptr)
808{
809 addFile(fileName);
810}
811
812
813/*!
814 Creates an icon with a specific icon \a engine. The icon takes
815 ownership of the engine.
816*/
817QIcon::QIcon(QIconEngine *engine)
818 :d(new QIconPrivate(engine))
819{
820}
821
822/*!
823 Destroys the icon.
824*/
825QIcon::~QIcon()
826{
827 if (d && !d->ref.deref())
828 delete d;
829}
830
831/*!
832 Assigns the \a other icon to this icon and returns a reference to
833 this icon.
834*/
835QIcon &QIcon::operator=(const QIcon &other)
836{
837 if (other.d)
838 other.d->ref.ref();
839 if (d && !d->ref.deref())
840 delete d;
841 d = other.d;
842 return *this;
843}
844
845/*!
846 \fn QIcon &QIcon::operator=(QIcon &&other)
847
848 Move-assigns \a other to this QIcon instance.
849
850 \since 5.2
851*/
852
853/*!
854 \fn void QIcon::swap(QIcon &other)
855 \memberswap{icon}
856*/
857
858/*!
859 Returns the icon as a QVariant.
860*/
861QIcon::operator QVariant() const
862{
863 return QVariant::fromValue(*this);
864}
865
866/*!
867 Returns a number that identifies the contents of this QIcon
868 object. Distinct QIcon objects can have the same key if
869 they refer to the same contents.
870
871 The cacheKey() will change when the icon is altered via
872 addPixmap() or addFile().
873
874 Cache keys are mostly useful in conjunction with caching.
875
876 \sa QPixmap::cacheKey()
877*/
878qint64 QIcon::cacheKey() const
879{
880 if (!d)
881 return 0;
882 return (((qint64) d->serialNum) << 32) | ((qint64) (d->detach_no));
883}
884
885/*!
886 Returns a pixmap with the requested \a size, \a mode, and \a
887 state, generating one if necessary. The pixmap might be smaller than
888 requested, but never larger, unless the device-pixel ratio of the returned
889 pixmap is larger than 1.
890
891 \sa actualSize(), paint()
892*/
893QPixmap QIcon::pixmap(const QSize &size, Mode mode, State state) const
894{
895 if (!d)
896 return QPixmap();
897 const qreal dpr = -1; // don't know target dpr
898 return pixmap(size, dpr, mode, state);
899}
900
901/*!
902 \fn QPixmap QIcon::pixmap(int w, int h, Mode mode = Normal, State state = Off) const
903
904 \overload
905
906 Returns a pixmap of size QSize(\a w, \a h). The pixmap might be smaller than
907 requested, but never larger, unless the device-pixel ratio of the returned
908 pixmap is larger than 1.
909*/
910
911/*!
912 \fn QPixmap QIcon::pixmap(int extent, Mode mode = Normal, State state = Off) const
913
914 \overload
915
916 Returns a pixmap of size QSize(\a extent, \a extent). The pixmap might be smaller
917 than requested, but never larger, unless the device-pixel ratio of the returned
918 pixmap is larger than 1.
919*/
920
921/*!
922 \overload
923 \since 6.0
924
925 Returns a pixmap with the requested \a size, \a devicePixelRatio, \a mode, and \a
926 state, generating one with the given \a mode and \a state if necessary. The pixmap
927 might be smaller than requested, but never larger, unless the device-pixel ratio
928 of the returned pixmap is larger than 1.
929
930 \note The requested devicePixelRatio might not match the returned one. This delays the
931 scaling of the QPixmap until it is drawn later on.
932 \note Prior to Qt 6.8 this function wronlgy passed the device dependent pixmap size to
933 QIconEngine::scaledPixmap(), since Qt 6.8 it's the device independent size (not scaled
934 with the \a devicePixelRatio).
935
936 \sa actualSize(), paint()
937*/
938QPixmap QIcon::pixmap(const QSize &size, qreal devicePixelRatio, Mode mode, State state) const
939{
940 if (!d)
941 return QPixmap();
942
943 // Use the global devicePixelRatio if the caller does not know the target dpr
944 if (devicePixelRatio == -1)
945 devicePixelRatio = qApp->devicePixelRatio();
946
947 QPixmap pixmap = d->engine->scaledPixmap(size, mode, state, devicePixelRatio);
948 // even though scaledPixmap() should return a pixmap with an appropriate size, we
949 // can not rely on it. Therefore we simply set the dpr to a correct size to make
950 // sure the pixmap is not larger than requested.
951 pixmap.setDevicePixelRatio(d->pixmapDevicePixelRatio(devicePixelRatio, size, pixmap.size()));
952 return pixmap;
953}
954
955#if QT_DEPRECATED_SINCE(6, 0)
956/*!
957 \since 5.1
958 \deprecated [6.0] Use pixmap(size, devicePixelRatio) instead.
959
960 Returns a pixmap with the requested \a window \a size, \a mode, and \a
961 state, generating one if necessary.
962
963 The pixmap can be smaller than the requested size. If \a window is on
964 a high-dpi display the pixmap can be larger. In that case it will have
965 a devicePixelRatio larger than 1.
966
967 \sa actualSize(), paint()
968*/
969
970QPixmap QIcon::pixmap(QWindow *window, const QSize &size, Mode mode, State state) const
971{
972 if (!d)
973 return QPixmap();
974
975 qreal devicePixelRatio = window ? window->devicePixelRatio() : qApp->devicePixelRatio();
976 return pixmap(size, devicePixelRatio, mode, state);
977}
978#endif
979
980
981/*! Returns the actual size of the icon for the requested \a size, \a
982 mode, and \a state. The result might be smaller than requested, but
983 never larger. The returned size is in device-independent pixels (This
984 is relevant for high-dpi pixmaps.)
985
986 \sa pixmap(), paint()
987*/
988QSize QIcon::actualSize(const QSize &size, Mode mode, State state) const
989{
990 if (!d)
991 return QSize();
992
993 const qreal devicePixelRatio = qApp->devicePixelRatio();
994
995 // Handle the simple normal-dpi case:
996 if (!(devicePixelRatio > 1.0))
997 return d->engine->actualSize(size, mode, state);
998
999 const QSize actualSize = d->engine->actualSize(size * devicePixelRatio, mode, state);
1000 return actualSize / d->pixmapDevicePixelRatio(devicePixelRatio, size, actualSize);
1001}
1002
1003#if QT_DEPRECATED_SINCE(6, 0)
1004/*!
1005 \since 5.1
1006 \deprecated [6.0] Use actualSize(size) instead.
1007
1008 Returns the actual size of the icon for the requested \a window \a size, \a
1009 mode, and \a state.
1010
1011 The pixmap can be smaller than the requested size. The returned size
1012 is in device-independent pixels (This is relevant for high-dpi pixmaps.)
1013
1014 \sa actualSize(), pixmap(), paint()
1015*/
1016
1017QSize QIcon::actualSize(QWindow *window, const QSize &size, Mode mode, State state) const
1018{
1019 if (!d)
1020 return QSize();
1021
1022 qreal devicePixelRatio = window ? window->devicePixelRatio() : qApp->devicePixelRatio();
1023
1024 // Handle the simple normal-dpi case:
1025 if (!(devicePixelRatio > 1.0))
1026 return d->engine->actualSize(size, mode, state);
1027
1028 QSize actualSize = d->engine->actualSize(size * devicePixelRatio, mode, state);
1029 return actualSize / d->pixmapDevicePixelRatio(devicePixelRatio, size, actualSize);
1030}
1031#endif
1032
1033/*!
1034 Uses the \a painter to paint the icon with specified \a alignment,
1035 required \a mode, and \a state into the rectangle \a rect.
1036
1037 \sa actualSize(), pixmap()
1038*/
1039void QIcon::paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment, Mode mode, State state) const
1040{
1041 if (!d || !painter)
1042 return;
1043
1044 // Copy of QStyle::alignedRect
1045 const QSize size = d->engine->actualSize(rect.size(), mode, state);
1046 alignment = QGuiApplicationPrivate::visualAlignment(painter->layoutDirection(), alignment);
1047 int x = rect.x();
1048 int y = rect.y();
1049 int w = size.width();
1050 int h = size.height();
1051 if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
1052 y += rect.size().height()/2 - h/2;
1053 else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
1054 y += rect.size().height() - h;
1055 if ((alignment & Qt::AlignRight) == Qt::AlignRight)
1056 x += rect.size().width() - w;
1057 else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
1058 x += rect.size().width()/2 - w/2;
1059 QRect alignedRect(x, y, w, h);
1060
1061 d->engine->paint(painter, alignedRect, mode, state);
1062}
1063
1064/*!
1065 \fn void QIcon::paint(QPainter *painter, int x, int y, int w, int h, Qt::Alignment alignment,
1066 Mode mode, State state) const
1067
1068 \overload
1069
1070 Paints the icon into the rectangle QRect(\a x, \a y, \a w, \a h).
1071*/
1072
1073/*!
1074 Returns \c true if the icon is empty; otherwise returns \c false.
1075
1076 An icon is empty if it has neither a pixmap nor a filename.
1077
1078 Note: Even a non-null icon might not be able to create valid
1079 pixmaps, eg. if the file does not exist or cannot be read.
1080*/
1081bool QIcon::isNull() const
1082{
1083 return !d || d->engine->isNull();
1084}
1085
1086/*!\internal
1087 */
1088bool QIcon::isDetached() const
1089{
1090 return !d || d->ref.loadRelaxed() == 1;
1091}
1092
1093/*! \internal
1094 */
1095void QIcon::detach()
1096{
1097 if (d) {
1098 if (d->engine->isNull()) {
1099 if (!d->ref.deref())
1100 delete d;
1101 d = nullptr;
1102 return;
1103 } else if (d->ref.loadRelaxed() != 1) {
1104 QIconPrivate *x = new QIconPrivate(d->engine->clone());
1105 if (!d->ref.deref())
1106 delete d;
1107 d = x;
1108 }
1109 ++d->detach_no;
1110 }
1111}
1112
1113/*!
1114 Adds \a pixmap to the icon, as a specialization for \a mode and
1115 \a state.
1116
1117 Custom icon engines are free to ignore additionally added
1118 pixmaps.
1119
1120 \sa addFile()
1121*/
1122void QIcon::addPixmap(const QPixmap &pixmap, Mode mode, State state)
1123{
1124 if (pixmap.isNull())
1125 return;
1126 detach();
1127 if (!d)
1128 d = new QIconPrivate(new QPixmapIconEngine);
1129 d->engine->addPixmap(pixmap, mode, state);
1130}
1131
1132static QIconEngine *iconEngineFromSuffix(const QString &fileName, const QString &suffix)
1133{
1134 if (!suffix.isEmpty()) {
1135 const int index = iceLoader()->indexOf(suffix);
1136 if (index != -1) {
1137 if (QIconEnginePlugin *factory = qobject_cast<QIconEnginePlugin*>(iceLoader()->instance(index))) {
1138 return factory->create(fileName);
1139 }
1140 }
1141 }
1142 return nullptr;
1143}
1144
1145/*! Adds an image from the file with the given \a fileName to the
1146 icon, as a specialization for \a size, \a mode and \a state. The
1147 file will be loaded on demand. Note: custom icon engines are free
1148 to ignore additionally added pixmaps.
1149
1150 If \a fileName contains a relative path (e.g. the filename only)
1151 the relevant file must be found relative to the runtime working
1152 directory.
1153
1154 The file name can refer to an actual file on disk or to
1155 one of the application's embedded resources. See the
1156 \l{resources.html}{Resource System} overview for details on how to
1157 embed images and other resource files in the application's
1158 executable.
1159
1160 Use the QImageReader::supportedImageFormats() and
1161 QImageWriter::supportedImageFormats() functions to retrieve a
1162 complete list of the supported file formats.
1163
1164 If a high resolution version of the image exists (identified by
1165 the suffix \c @2x on the base name), it is automatically loaded
1166 and added with the \e{device pixel ratio} set to a value of 2.
1167 This can be disabled by setting the environment variable
1168 \c QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING (see QImageReader).
1169
1170 \note When you add a non-empty filename to a QIcon, the icon becomes
1171 non-null, even if the file doesn't exist or points to a corrupt file.
1172
1173 \sa addPixmap(), QPixmap::devicePixelRatio()
1174 */
1175void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State state)
1176{
1177 if (fileName.isEmpty())
1178 return;
1179 detach();
1180 bool alreadyAdded = false;
1181 if (!d) {
1182
1183 QFileInfo info(fileName);
1184 QString suffix = info.suffix();
1185#if QT_CONFIG(mimetype)
1186 if (suffix.isEmpty())
1187 suffix = QMimeDatabase().mimeTypeForFile(info).preferredSuffix(); // determination from contents
1188#endif // mimetype
1189 QIconEngine *engine = iconEngineFromSuffix(fileName, suffix);
1190 if (engine)
1191 alreadyAdded = !engine->isNull();
1192 d = new QIconPrivate(engine ? engine : new QPixmapIconEngine);
1193 }
1194 if (!alreadyAdded)
1195 d->engine->addFile(fileName, size, mode, state);
1196
1197 if (d->engine->key() == "svg"_L1) // not needed and also not supported
1198 return;
1199
1200 // Check if a "@Nx" file exists and add it.
1201 QVarLengthArray<int, 4> devicePixelRatios;
1202 const auto screens = qApp->screens();
1203 for (const auto *screen : screens) {
1204 const auto dpr = qCeil(screen->devicePixelRatio()); // qt_findAtNxFile only supports integer values
1205 if (dpr >= 1 && !devicePixelRatios.contains(dpr))
1206 devicePixelRatios.push_back(dpr);
1207 }
1208 std::sort(devicePixelRatios.begin(), devicePixelRatios.end(), std::greater<int>());
1209 qreal sourceDevicePixelRatio = std::numeric_limits<qreal>::max();
1210 for (const auto dpr : std::as_const(devicePixelRatios)) {
1211 if (dpr >= sourceDevicePixelRatio)
1212 continue;
1213 const QString atNxFileName = qt_findAtNxFile(fileName, dpr, &sourceDevicePixelRatio);
1214 if (atNxFileName != fileName)
1215 d->engine->addFile(atNxFileName, size, mode, state);
1216 }
1217}
1218
1219/*!
1220 Returns a list of available icon sizes for the specified \a mode and
1221 \a state.
1222*/
1223QList<QSize> QIcon::availableSizes(Mode mode, State state) const
1224{
1225 if (!d || !d->engine)
1226 return QList<QSize>();
1227 return d->engine->availableSizes(mode, state);
1228}
1229
1230/*!
1231 Returns the name used to create the icon, if available.
1232
1233 Depending on the way the icon was created, it may have an associated
1234 name. This is the case for icons created with fromTheme().
1235
1236 \sa fromTheme(), QIconEngine::iconName()
1237*/
1238QString QIcon::name() const
1239{
1240 if (!d || !d->engine)
1241 return QString();
1242 return d->engine->iconName();
1243}
1244
1245/*!
1246 Sets the search paths for icon themes to \a paths.
1247
1248 The content of \a paths should follow the theme format
1249 documented by setThemeName().
1250
1251 \sa themeSearchPaths(), fromTheme(), setThemeName()
1252*/
1253void QIcon::setThemeSearchPaths(const QStringList &paths)
1254{
1255 QIconLoader::instance()->setThemeSearchPath(paths);
1256}
1257
1258/*!
1259 Returns the search paths for icon themes.
1260
1261 The default search paths will be defined by the platform.
1262 All platforms will also have the resource directory \c{:\icons} as a fallback.
1263
1264 \sa setThemeSearchPaths(), fromTheme(), setThemeName()
1265*/
1266QStringList QIcon::themeSearchPaths()
1267{
1268 return QIconLoader::instance()->themeSearchPaths();
1269}
1270
1271/*!
1272 \since 5.11
1273
1274 Returns the fallback search paths for icons.
1275
1276 The fallback search paths are consulted for standalone
1277 icon files if the \l{themeName()}{current icon theme}
1278 or \l{fallbackThemeName()}{fallback icon theme} do
1279 not provide results for an icon lookup.
1280
1281 If not set, the fallback search paths will be defined
1282 by the platform.
1283
1284 \sa setFallbackSearchPaths(), themeSearchPaths()
1285*/
1286QStringList QIcon::fallbackSearchPaths()
1287{
1288 return QIconLoader::instance()->fallbackSearchPaths();
1289}
1290
1291/*!
1292 \since 5.11
1293
1294 Sets the fallback search paths for icons to \a paths.
1295
1296 The fallback search paths are consulted for standalone
1297 icon files if the \l{themeName()}{current icon theme}
1298 or \l{fallbackThemeName()}{fallback icon theme} do
1299 not provide results for an icon lookup.
1300
1301 For example:
1302
1303 \snippet code/src_gui_image_qicon.cpp 5
1304
1305 \sa fallbackSearchPaths(), setThemeSearchPaths()
1306*/
1307void QIcon::setFallbackSearchPaths(const QStringList &paths)
1308{
1309 QIconLoader::instance()->setFallbackSearchPaths(paths);
1310}
1311
1312/*!
1313 Sets the current icon theme to \a name.
1314
1315 If the theme matches the name of an installed font that provides named
1316 glyphs, then QIcon::fromTheme calls that match one of the glyphs will
1317 produce an icon for that glyph.
1318
1319 Otherwise, the theme will be looked up in themeSearchPaths(). At the moment
1320 the only supported icon theme format is the \l{Freedesktop Icon Theme
1321 Specification}. The \a name should correspond to a directory name in the
1322 themeSearchPath() containing an \c index.theme file describing its
1323 contents.
1324
1325 \sa themeSearchPaths(), themeName(),
1326 {Freedesktop Icon Theme Specification}
1327*/
1328void QIcon::setThemeName(const QString &name)
1329{
1330 QIconLoader::instance()->setThemeName(name);
1331}
1332
1333/*!
1334 Returns the name of the current icon theme.
1335
1336 If not set, the current icon theme will be defined by the
1337 platform.
1338
1339 \note Platform icon themes are only implemented on
1340 \l{Freedesktop} based systems at the moment, and the
1341 icon theme depends on your desktop settings.
1342
1343 \sa setThemeName(), themeSearchPaths(), fromTheme(),
1344 hasThemeIcon()
1345*/
1346QString QIcon::themeName()
1347{
1348 return QIconLoader::instance()->themeName();
1349}
1350
1351/*!
1352 \since 5.12
1353
1354 Returns the name of the fallback icon theme.
1355
1356 If not set, the fallback icon theme will be defined by the
1357 platform.
1358
1359 \note Platform fallback icon themes are only implemented on
1360 \l{Freedesktop} based systems at the moment, and the
1361 icon theme depends on your desktop settings.
1362
1363 \sa setFallbackThemeName(), themeName()
1364*/
1365QString QIcon::fallbackThemeName()
1366{
1367 return QIconLoader::instance()->fallbackThemeName();
1368}
1369
1370/*!
1371 \since 5.12
1372
1373 Sets the fallback icon theme to \a name.
1374
1375 The fallback icon theme is consulted for icons not provided by
1376 the \l{themeName()}{current icon theme}, or if the \l{themeName()}
1377 {current icon theme} does not exist.
1378
1379 The \a name should correspond to theme in the same format
1380 as documented by setThemeName(), and will be looked up
1381 in themeSearchPaths().
1382
1383 \note Fallback icon themes should be set before creating
1384 QGuiApplication, to ensure correct initialization.
1385
1386 \sa fallbackThemeName(), themeSearchPaths(), themeName()
1387*/
1388void QIcon::setFallbackThemeName(const QString &name)
1389{
1390 QIconLoader::instance()->setFallbackThemeName(name);
1391}
1392
1393/*!
1394 Returns the QIcon corresponding to \a name in the
1395 \l{themeName()}{current icon theme}.
1396
1397 If the current theme does not provide an icon for \a name,
1398 the \l{fallbackThemeName()}{fallback icon theme} is consulted,
1399 before falling back to looking up standalone icon files in the
1400 \l{QIcon::fallbackSearchPaths()}{fallback icon search path}.
1401 Finally, the platform's native icon library is consulted.
1402
1403 To fetch an icon from the current icon theme:
1404
1405 \snippet code/src_gui_image_qicon.cpp fromTheme
1406
1407 If an \l{themeName()}{icon theme} has not been explicitly
1408 set via setThemeName() a platform defined icon theme will
1409 be used.
1410
1411 \sa themeName(), fallbackThemeName(), setThemeName(), themeSearchPaths(), fallbackSearchPaths(),
1412 {Freedesktop Icon Naming Specification}
1413*/
1414QIcon QIcon::fromTheme(const QString &name)
1415{
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:39
int serialNum
Definition qicon_p.h:42
bool is_mask
Definition qicon_p.h:44
QIconPrivate(QIconEngine *e)
Definition qicon.cpp:131
int detach_no
Definition qicon_p.h:43
static void clearIconCache()
Definition qicon.cpp:139
QString fileName() const
If the currently assigned device is a QFile, or if setFileName() has been called, this function retur...
QDataStream & operator>>(QDataStream &s, QKeyCombination &combination)
QDebug operator<<(QDebug dbg, const QFileInfo &fi)
static void qt_cleanup_icon_cache()
Definition qicon.cpp:126
static constexpr auto themeIconMapping
Definition qicon.cpp:1476
static int origIcoDepth(const QImage &image)
Definition qicon.cpp:439
static qint64 area(const QSize &s)
Definition qicon.cpp:190
static int nextSerialNumCounter()
Definition qicon.cpp:106
static QIconEngine * iconEngineFromSuffix(const QString &fileName, const QString &suffix)
Definition qicon.cpp:1132
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:445
static QPixmapIconEngineEntry * bestSizeScaleMatch(const QSize &size, qreal scale, QPixmapIconEngineEntry *pa, QPixmapIconEngineEntry *pb)
Definition qicon.cpp:198
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 } }))