1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the painting module of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
30
#include "qiconengine.h"
31
#include "qiconengineplugin.h"
32
#include "private/qfactoryloader_p.h"
33
#include "qapplication.h"
34
#include "qstyleoption.h"
36
#include "qfileinfo.h"
38
#include "qpixmapcache.h"
45
This enum type describes the mode for which a pixmap is intended
46
to be used. The currently defined modes are:
49
Display the pixmap when the user is
50
not interacting with the icon, but the
51
functionality represented by the icon is available.
53
Display the pixmap when the
54
functionality represented by the icon is not available.
56
Display the pixmap when the
57
functionality represented by the icon is available and
58
the user is interacting with the icon, for example, moving the
59
mouse over it or clicking it.
65
This enum describes the state for which a pixmap is intended to be
66
used. The \e state can be:
68
\value Off Display the pixmap when the widget is in an "off" state
69
\value On Display the pixmap when the widget is in an "on" state
72
static int serialNumCounter = 0;
77
QIconPrivate():ref(1),engine(0),serialNum(++serialNumCounter){}
78
~QIconPrivate() { delete engine; }
85
struct QPixmapIconEngineEntry
87
QPixmapIconEngineEntry():mode(QIcon::Normal), state(QIcon::Off){}
88
QPixmapIconEngineEntry(const QPixmap &pm, QIcon::Mode m = QIcon::Normal, QIcon::State s = QIcon::Off)
89
:pixmap(pm), size(pm.size()), mode(m), state(s){}
90
QPixmapIconEngineEntry(const QString &file, const QSize &sz = QSize(), QIcon::Mode m = QIcon::Normal, QIcon::State s = QIcon::Off)
91
:fileName(file), size(sz), mode(m), state(s){}
97
bool isNull() const {return (fileName.isEmpty() && pixmap.isNull()); }
100
class QPixmapIconEngine : public QIconEngine{
103
~QPixmapIconEngine();
104
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state);
105
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
106
QPixmapIconEngineEntry *bestMatch(const QSize &size, QIcon::Mode mode, QIcon::State state, bool sizeOnly);
107
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state);
108
void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state);
109
void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state);
111
QPixmapIconEngineEntry *tryMatch(const QSize &size, QIcon::Mode mode, QIcon::State state);
112
QVector<QPixmapIconEngineEntry> pixmaps;
115
QPixmapIconEngine::QPixmapIconEngine()
119
QPixmapIconEngine::~QPixmapIconEngine()
123
void QPixmapIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
125
painter->drawPixmap(rect, pixmap(rect.size(), mode, state));
128
static inline int area(const QSize &s) { return s.width() * s.height(); }
130
// returns the smallest of the two that is still larger than or equal to size.
131
static QPixmapIconEngineEntry *bestSizeMatch( const QSize &size, QPixmapIconEngineEntry *pa, QPixmapIconEngineEntry *pb)
134
if (pa->size == QSize() && pa->pixmap.isNull()) {
135
pa->pixmap = QPixmap(pa->fileName);
136
pa->size = pa->pixmap.size();
138
int a = area(pa->size);
139
if (pb->size == QSize() && pb->pixmap.isNull()) {
140
pb->pixmap = QPixmap(pb->fileName);
141
pb->size = pb->pixmap.size();
143
int b = area(pb->size);
154
QPixmapIconEngineEntry *QPixmapIconEngine::tryMatch(const QSize &size, QIcon::Mode mode, QIcon::State state)
156
QPixmapIconEngineEntry *pe = 0;
157
for (int i = 0; i < pixmaps.count(); ++i)
158
if (pixmaps.at(i).mode == mode && pixmaps.at(i).state == state) {
160
pe = bestSizeMatch(size, &pixmaps[i], pe);
168
QPixmapIconEngineEntry *QPixmapIconEngine::bestMatch(const QSize &size, QIcon::Mode mode, QIcon::State state, bool sizeOnly)
170
QPixmapIconEngineEntry *pe = tryMatch(size, mode, state);
172
QIcon::State oppositeState = (state == QIcon::On) ? QIcon::Off : QIcon::On;
173
if (mode == QIcon::Disabled) {
174
if ((pe = tryMatch(size, QIcon::Normal, state)))
176
if ((pe = tryMatch(size, QIcon::Active, state)))
178
if ((pe = tryMatch(size, QIcon::Disabled, oppositeState)))
180
if ((pe = tryMatch(size, QIcon::Normal, oppositeState)))
182
if ((pe = tryMatch(size, QIcon::Active, oppositeState)))
185
QIcon::Mode oppositeMode = (mode == QIcon::Normal) ? QIcon::Active : QIcon::Normal;
186
if ((pe = tryMatch(size, oppositeMode, state)))
188
if ((pe = tryMatch(size, mode, oppositeState)))
190
if ((pe = tryMatch(size, oppositeMode, oppositeState)))
192
if ((pe = tryMatch(size, QIcon::Disabled, state)))
194
if ((pe = tryMatch(size, QIcon::Disabled, oppositeState)))
202
if (sizeOnly ? (pe->size.isNull() || !pe->size.isValid()) : pe->pixmap.isNull()) {
203
pe->pixmap = QPixmap(pe->fileName);
204
if (!pe->pixmap.isNull())
205
pe->size = pe->pixmap.size();
211
QPixmap QPixmapIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
214
QPixmapIconEngineEntry *pe = bestMatch(size, mode, state, false);
221
QSize actualSize = pm.size();
222
if (!actualSize.isNull() && (actualSize.width() > size.width() && actualSize.height() > size.height()))
223
actualSize.scale(size, Qt::KeepAspectRatio);
225
QString key = QLatin1String("$qt_icon_")
226
+ QString::number(pm.serialNumber())
227
+ QString::number(actualSize.width())
229
+ QString::number(actualSize.height())
233
if (mode == QIcon::Active) {
234
if (QPixmapCache::find(key + QString::number(mode), pm))
236
if (QPixmapCache::find(key + QString::number(QIcon::Normal), pm)) {
238
opt.palette = QApplication::palette();
239
QPixmap active = QApplication::style()->generatedIconPixmap(QIcon::Active, pm, &opt);
240
if (pm.serialNumber() == active.serialNumber())
245
if (!QPixmapCache::find(key + QString::number(mode), pm)) {
246
if (pe->mode != mode && mode != QIcon::Normal && pe->mode != QIcon::Disabled) {
248
opt.palette = QApplication::palette();
249
QPixmap generated = QApplication::style()->generatedIconPixmap(mode, pm, &opt);
250
if (!generated.isNull())
253
if (pm.size() != actualSize)
254
pm = pm.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
255
QPixmapCache::insert(key + QString::number(mode), pm);
260
QSize QPixmapIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
263
if (QPixmapIconEngineEntry *pe = bestMatch(size, mode, state, true))
264
actualSize = pe->size;
266
if (actualSize.isNull())
269
if (!actualSize.isNull() && (actualSize.width() > size.width() && actualSize.height() > size.height()))
270
actualSize.scale(size, Qt::KeepAspectRatio);
274
void QPixmapIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state)
276
if (!pixmap.isNull())
277
pixmaps += QPixmapIconEngineEntry(pixmap, mode, state);
280
void QPixmapIconEngine::addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state)
282
if (!fileName.isEmpty()) {
283
QString abs = fileName;
284
if (fileName.at(0) != QLatin1Char(':'))
285
abs = QFileInfo(fileName).absoluteFilePath();
286
pixmaps += QPixmapIconEngineEntry(abs, size, mode, state);
292
#ifndef QT_NO_COMPONENT
293
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
294
(QIconEngineFactoryInterface_iid, QCoreApplication::libraryPaths(), "/iconengines", Qt::CaseInsensitive))
302
\brief The QIcon class provides scalable icons in different modes
309
A QIcon can generate smaller, larger, active, and disabled pixmaps
310
from the set of pixmaps it is given. Such pixmaps are used by Qt
311
widgets to show an icon representing a particular action.
313
The simplest use of QIcon is to create one from a QPixmap file or
314
resource, and then use it, allowing Qt to work out all the required
315
icon styles and sizes. For example:
318
QToolButton *button = new QToolButton;
319
button->setIcon(QIcon("open.xpm"));
322
When you retrieve a pixmap using pixmap(QSize, Mode, State), and no
323
pixmap for this given size, mode and state has been added with
324
addFile() or addPixmap(), then QIcon will generate one on the
325
fly. This pixmap generation happens in a QIconEngine. The default
326
engine scales pixmaps down if required, but never up, and it uses
327
the current style to calculate a disabled appearance. By using
328
custom icon engines, you can customize every aspect of generated
329
icons. With QIconEnginePlugin it is possible to register different
330
icon engines for different file suffixes, so you could provide a SVG
331
icon engine or any other scalable format.
333
\section1 Making Classes that Use QIcon
335
If you write your own widgets that have an option to set a small
336
pixmap, consider allowing a QIcon to be set for that pixmap. The
337
Qt class QToolButton is an example of such a widget.
339
Provide a method to set a QIcon, and when you draw the icon, choose
340
whichever pixmap is appropriate for the current state of your widget.
343
void MyWidget::drawIcon(QPainter *painter, QPoint pos)
345
QPixmap pixmap = icon.pixmap(QSize(22, 22),
346
isEnabled() ? QIcon::Normal
350
painter->drawPixmap(pos, pixmap);
354
You might also make use of the \c Active mode, perhaps making your
355
widget \c Active when the mouse is over the widget (see \l
356
QWidget::enterEvent()), while the mouse is pressed pending the
357
release that will activate the function, or when it is the currently
358
selected item. If the widget can be toggled, the "On" mode might be
359
used to draw a different icon.
363
\sa {fowler}{GUI Design Handbook: Iconic Label}
368
Constructs a null icon.
376
Constructs an icon from a \a pixmap.
378
QIcon::QIcon(const QPixmap &pixmap)
385
Constructs a copy of \a other. This is very fast.
387
QIcon::QIcon(const QIcon &other)
395
Constructs an icon from the file with the given \a fileName. The
396
file will be loaded on demand. If the file does not exist or is of
397
an unknown format, the icon becomes a null icon.
399
If \a fileName contains a relative path (e.g. the filename only)
400
the relevant file must be found relative to the runtime working
403
The file name can be either refer to an actual file on disk or to
404
one of the application's embedded resources. See the
405
\l{resources.html}{Resource System} overview for details on how to
406
embed images and other resource files in the application's
409
QIcon::QIcon(const QString &fileName)
412
QFileInfo info(fileName);
413
QString suffix = info.suffix();
414
if (!suffix.isEmpty())
415
if (QIconEngineFactoryInterface *factory = qobject_cast<QIconEngineFactoryInterface*>(loader()->instance(suffix)))
416
if (QIconEngine *engine = factory->create(fileName)) {
417
d = new QIconPrivate;
426
Creates an icon with a specific icon \a engine. The icon takes
427
ownership of the engine.
429
QIcon::QIcon(QIconEngine *engine)
440
if (d && !d->ref.deref())
445
Assigns the \a other icon to this icon and returns a reference to
448
QIcon &QIcon::operator=(const QIcon &other)
450
QIconPrivate *x = other.d;
453
x = qAtomicSetPtr(&d, x);
454
if (x && !x->ref.deref())
460
Returns the icon as a QVariant.
462
QIcon::operator QVariant() const
464
return QVariant(QVariant::Icon, this);
468
Returns a number that uniquely identifies the contents of this
469
QIcon object. This means that multiple QIcon objects can have
470
the same serial number as long as they refer to the same contents.
472
A null icon always has a serial number of 0.
474
\sa QPixmap::serialNumber()
477
int QIcon::serialNumber() const
479
return d ? d->serialNum : 0;
482
/*! Returns a pixmap with the requested \a size, \a mode, and \a
483
state, generating one if necessary. The pixmap might be smaller than
484
requested, but never larger.
486
\sa actualSize(), paint()
488
QPixmap QIcon::pixmap(const QSize &size, Mode mode, State state) const
492
return d->engine->pixmap(size, mode, state);
496
\fn QPixmap QIcon::pixmap(int w, int h, Mode mode = Normal, State state = Off) const
500
Returns a pixmap of size QSize(\a w, \a h).
504
\fn QPixmap QIcon::pixmap(int extent, Mode mode = Normal, State state = Off) const
508
Returns a pixmap of size QSize(\a extent, \a extent).
511
/*! Returns the actual size of the icon for the requested \a size, \a
512
mode, and \a state. The result might be smaller than requested, but
515
\sa pixmap(), paint()
517
QSize QIcon::actualSize(const QSize &size, Mode mode, State state) const
521
return d->engine->actualSize(size, mode, state);
526
Uses the \a painter to paint the icon with specified \a alignment,
527
required \a mode, and \a state into the rectangle \a rect.
529
\sa actualSize(), pixmap()
531
void QIcon::paint(QPainter *painter, const QRect &rect, Qt::Alignment alignment, Mode mode, State state) const
535
QRect alignedRect = QStyle::alignedRect(painter->layoutDirection(), alignment, d->engine->actualSize(rect.size(), mode, state), rect);
536
d->engine->paint(painter, alignedRect, mode, state);
540
\fn void QIcon::paint(QPainter *painter, int x, int y, int w, int h, Qt::Alignment alignment,
541
Mode mode, State state) const
545
Paints the icon into the rectangle QRect(\a x, \a y, \a w, \a h).
549
Returns true if the icon is empty; otherwise returns false.
551
bool QIcon::isNull() const
558
bool QIcon::isDetached() const
560
return !d || d->ref == 1;
565
Adds \a pixmap to the icon, as a specialization for \a mode and
568
Custom icon engines are free to ignore additionally added
573
void QIcon::addPixmap(const QPixmap &pixmap, Mode mode, State state)
578
d = new QIconPrivate;
579
d->engine = new QPixmapIconEngine;
581
d->engine->addPixmap(pixmap, mode, state);
585
/*! Adds a pixmap from the file with the given \a fileName to the
586
icon, as a specialization for \a size, \a mode and \a state. The
587
file will be loaded on demand. Note: custom icon engines are free
588
to ignore additionally added pixmaps.
590
If \a fileName contains a relative path (e.g. the filename only)
591
the relevant file must be found relative to the runtime working
594
The file name can be either refer to an actual file on disk or to
595
one of the application's embedded resources. See the
596
\l{resources.html}{Resource System} overview for details on how to
597
embed images and other resource files in the application's
602
void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State state)
604
if (fileName.isEmpty())
607
d = new QIconPrivate;
608
d->engine = new QPixmapIconEngine;
610
d->engine->addFile(fileName, size, mode, state);
617
static int widths[2] = { 22, 32 };
618
static int heights[2] = { 22, 32 };
620
static QSize pixmapSize(QIcon::Size which) {
622
if (which == QIcon::Large)
624
return QSize(widths[i], heights[i]);
631
\value Small Use QStyle::pixelMetric(QStyle::PM_SmallIconSize) instead.
632
\value Large Use QStyle::pixelMetric(QStyle::PM_LargeIconSize) instead.
633
\value Automatic N/A.
637
Use pixmap(QSize(...), \a mode, \a state), where the first
638
argument is an appropriate QSize instead of a \l Size value.
642
QPixmap QIcon::pixmap(Size size, Mode mode, State state) const
643
{ return pixmap(::pixmapSize(size), mode, state); }
646
Use pixmap(QSize(...), mode, \a state), where the first argument
647
is an appropriate QSize instead of a \l Size value, and the
648
second argument is QIcon::Normal or QIcon::Disabled, depending on
649
the value of \a enabled.
653
QPixmap QIcon::pixmap(Size size, bool enabled, State state) const
654
{ return pixmap(::pixmapSize(size), enabled ? Normal : Disabled, state); }
657
Use one of the other pixmap() overloads.
659
QPixmap QIcon::pixmap() const
660
{ return pixmap(::pixmapSize(Small), Normal, Off); }
663
The pixmap() function now takes a QSize instead of a QIcon::Size,
664
so there is no need for this function in new code.
666
void QIcon::setPixmapSize(Size which, const QSize &size)
671
widths[i] = size.width();
672
heights[i] = size.height();
676
Use QStyle::pixelMetric() with QStyle::PM_SmallIconSize or
677
QStyle::PM_LargeIconSize as the first argument, depending on \a
680
QSize QIcon::pixmapSize(Size which)
682
return ::pixmapSize(which);
686
\fn void QIcon::reset(const QPixmap &pixmap, Size size)
688
Use the constructor that takes a QPixmap and operator=().
692
\fn void QIcon::setPixmap(const QPixmap &pixmap, Size size, Mode mode, State state)
694
Use addPixmap(\a pixmap, \a mode, \a state) instead. The \a size
695
parameter is ignored.
699
\fn void QIcon::setPixmap(const QString &fileName, Size size, Mode mode, State state)
701
Use addFile(\a fileName, \a mode, \a state) instead. The \a size
702
parameter is ignored.
705
#endif // QT3_SUPPORT