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