1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtWidgets module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40/*!
41 \class QGraphicsEffect
42 \brief The QGraphicsEffect class is the base class for all graphics
43 effects.
44 \since 4.6
45 \ingroup multimedia
46 \ingroup graphicsview-api
47 \inmodule QtWidgets
48
49 Effects alter the appearance of elements by hooking into the rendering
50 pipeline and operating between the source (e.g., a QGraphicsPixmapItem)
51 and the destination device (e.g., QGraphicsView's viewport). Effects can be
52 disabled by calling setEnabled(false). If effects are disabled, the source
53 is rendered directly.
54
55 To add a visual effect to a QGraphicsItem, for example, you can use one of
56 the standard effects, or alternately, create your own effect by creating a
57 subclass of QGraphicsEffect. The effect can then be installed on the item
58 using QGraphicsItem::setGraphicsEffect().
59
60 Qt provides the following standard effects:
61
62 \list
63 \li QGraphicsBlurEffect - blurs the item by a given radius
64 \li QGraphicsDropShadowEffect - renders a dropshadow behind the item
65 \li QGraphicsColorizeEffect - renders the item in shades of any given color
66 \li QGraphicsOpacityEffect - renders the item with an opacity
67 \endlist
68
69 \table
70 \row
71 \li{2,1} \image graphicseffect-plain.png
72 \row
73 \li \image graphicseffect-blur.png
74 \li \image graphicseffect-colorize.png
75 \row
76 \li \image graphicseffect-opacity.png
77 \li \image graphicseffect-drop-shadow.png
78 \endtable
79
80 \image graphicseffect-widget.png
81
82 For more information on how to use each effect, refer to the specific
83 effect's documentation.
84
85 To create your own custom effect, create a subclass of QGraphicsEffect (or
86 any other existing effects) and reimplement the virtual function draw().
87 This function is called whenever the effect needs to redraw. The draw()
88 function takes the painter with which to draw as an argument. For more
89 information, refer to the documenation for draw(). In the draw() function
90 you can call sourcePixmap() to get a pixmap of the graphics effect source
91 which you can then process.
92
93 If your effect changes, use update() to request for a redraw. If your
94 custom effect changes the bounding rectangle of the source, e.g., a radial
95 glow effect may need to apply an extra margin, you can reimplement the
96 virtual boundingRectFor() function, and call updateBoundingRect()
97 to notify the framework whenever this rectangle changes. The virtual
98 sourceChanged() function is called to notify the effects that
99 the source has changed in some way - e.g., if the source is a
100 QGraphicsRectItem and its rectangle parameters have changed.
101
102 \sa QGraphicsItem::setGraphicsEffect(), QWidget::setGraphicsEffect()
103*/
104
105#include "qgraphicseffect_p.h"
106#include "private/qgraphicsitem_p.h"
107
108#include <QtWidgets/qgraphicsitem.h>
109
110#include <QtGui/qimage.h>
111#include <QtGui/qpainter.h>
112#include <QtGui/qpaintengine.h>
113#include <QtCore/qrect.h>
114#include <QtCore/qdebug.h>
115#include <private/qdrawhelper_p.h>
116
117QT_BEGIN_NAMESPACE
118
119QGraphicsEffectPrivate::~QGraphicsEffectPrivate()
120{
121}
122
123/*!
124 \internal
125 \class QGraphicsEffectSource
126 \brief The QGraphicsEffectSource class represents the source on which a
127 QGraphicsEffect is installed on.
128
129 When a QGraphicsEffect is installed on a QGraphicsItem, for example, this
130 class will act as a wrapper around QGraphicsItem. Then, calling update() is
131 effectively the same as calling QGraphicsItem::update().
132
133 QGraphicsEffectSource also provides a pixmap() function which creates a
134 pixmap with the source painted into it.
135
136 \sa QGraphicsItem::setGraphicsEffect(), QWidget::setGraphicsEffect()
137*/
138
139/*!
140 \internal
141*/
142QGraphicsEffectSource::QGraphicsEffectSource(QGraphicsEffectSourcePrivate &dd, QObject *parent)
143 : QObject(dd, parent)
144{}
145
146/*!
147 Destroys the effect source.
148*/
149QGraphicsEffectSource::~QGraphicsEffectSource()
150{}
151
152/*!
153 Returns the bounding rectangle of the source mapped to the given \a system.
154
155 \sa draw()
156*/
157QRectF QGraphicsEffectSource::boundingRect(Qt::CoordinateSystem system) const
158{
159 return d_func()->boundingRect(system);
160}
161
162/*!
163 Returns the bounding rectangle of the source mapped to the given \a system.
164
165 Calling this function with Qt::DeviceCoordinates outside of
166 QGraphicsEffect::draw() will give undefined results, as there is no device
167 context available.
168
169 \sa draw()
170*/
171QRectF QGraphicsEffect::sourceBoundingRect(Qt::CoordinateSystem system) const
172{
173 Q_D(const QGraphicsEffect);
174 if (d->source)
175 return d->source->boundingRect(system);
176 return QRectF();
177}
178
179/*!
180 Returns a pointer to the item if this source is a QGraphicsItem; otherwise
181 returns \nullptr.
182
183 \sa widget()
184*/
185const QGraphicsItem *QGraphicsEffectSource::graphicsItem() const
186{
187 return d_func()->graphicsItem();
188}
189
190/*!
191 Returns a pointer to the widget if this source is a QWidget; otherwise
192 returns \nullptr.
193
194 \sa graphicsItem()
195*/
196const QWidget *QGraphicsEffectSource::widget() const
197{
198 return d_func()->widget();
199}
200
201/*!
202 Returns a pointer to the style options (used when drawing the source) if
203 available; otherwise returns \nullptr.
204
205 \sa graphicsItem(), widget()
206*/
207const QStyleOption *QGraphicsEffectSource::styleOption() const
208{
209 return d_func()->styleOption();
210}
211
212/*!
213 Draws the source using the given \a painter.
214
215 This function should only be called from QGraphicsEffect::draw().
216
217 \sa QGraphicsEffect::draw()
218*/
219void QGraphicsEffectSource::draw(QPainter *painter)
220{
221 Q_D(const QGraphicsEffectSource);
222
223 QPixmap pm;
224 if (QPixmapCache::find(d->m_cacheKey, &pm)) {
225 QTransform restoreTransform;
226 if (d->m_cachedSystem == Qt::DeviceCoordinates) {
227 restoreTransform = painter->worldTransform();
228 painter->setWorldTransform(QTransform());
229 }
230
231 painter->drawPixmap(d->m_cachedOffset, pm);
232
233 if (d->m_cachedSystem == Qt::DeviceCoordinates)
234 painter->setWorldTransform(restoreTransform);
235 } else {
236 d_func()->draw(painter);
237 }
238}
239
240/*!
241 Draws the source directly using the given \a painter.
242
243 This function should only be called from QGraphicsEffect::draw().
244
245 For example:
246
247 \snippet code/src_gui_effects_qgraphicseffect.cpp 0
248
249 \sa QGraphicsEffect::draw()
250*/
251void QGraphicsEffect::drawSource(QPainter *painter)
252{
253 Q_D(const QGraphicsEffect);
254 if (d->source)
255 d->source->draw(painter);
256}
257
258/*!
259 Schedules a redraw of the source. Call this function whenever the source
260 needs to be redrawn.
261
262 \sa QGraphicsEffect::updateBoundingRect(), QWidget::update(),
263 QGraphicsItem::update(),
264*/
265void QGraphicsEffectSource::update()
266{
267 d_func()->update();
268}
269
270/*!
271 Returns \c true if the source effectively is a pixmap, e.g., a
272 QGraphicsPixmapItem.
273
274 This function is useful for optimization purposes. For instance, there's no
275 point in drawing the source in device coordinates to avoid pixmap scaling
276 if this function returns \c true - the source pixmap will be scaled anyways.
277*/
278bool QGraphicsEffectSource::isPixmap() const
279{
280 return d_func()->isPixmap();
281}
282
283/*!
284 Returns \c true if the source effectively is a pixmap, e.g., a
285 QGraphicsPixmapItem.
286
287 This function is useful for optimization purposes. For instance, there's no
288 point in drawing the source in device coordinates to avoid pixmap scaling
289 if this function returns \c true - the source pixmap will be scaled anyways.
290*/
291bool QGraphicsEffect::sourceIsPixmap() const
292{
293 return source() ? source()->isPixmap() : false;
294}
295
296/*!
297 Returns a pixmap with the source painted into it.
298
299 The \a system specifies which coordinate system to be used for the source.
300 The optional \a offset parameter returns the offset where the pixmap should
301 be painted at using the current painter.
302
303 The \a mode determines how much of the effect the pixmap will contain.
304 By default, the pixmap will contain the whole effect.
305
306 The returned pixmap is bound to the current painter's device rectangle when
307 \a system is Qt::DeviceCoordinates.
308
309 \sa QGraphicsEffect::draw(), boundingRect()
310*/
311QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offset, QGraphicsEffect::PixmapPadMode mode) const
312{
313 Q_D(const QGraphicsEffectSource);
314
315 // Shortcut, no cache for childless pixmap items...
316 const QGraphicsItem *item = graphicsItem();
317 if (system == Qt::LogicalCoordinates && mode == QGraphicsEffect::NoPad && item && isPixmap()) {
318 const QGraphicsPixmapItem *pixmapItem = static_cast<const QGraphicsPixmapItem *>(item);
319 if (offset)
320 *offset = pixmapItem->offset().toPoint();
321 return pixmapItem->pixmap();
322 }
323
324 if (Q_UNLIKELY(system == Qt::DeviceCoordinates && item &&
325 !static_cast<const QGraphicsItemEffectSourcePrivate *>(d_func())->info)) {
326 qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context");
327 return QPixmap();
328 }
329
330 QPixmap pm;
331 if (item && d->m_cachedSystem == system && d->m_cachedMode == mode)
332 QPixmapCache::find(d->m_cacheKey, &pm);
333
334 if (pm.isNull()) {
335 pm = d->pixmap(system, &d->m_cachedOffset, mode);
336 d->m_cachedSystem = system;
337 d->m_cachedMode = mode;
338
339 d->invalidateCache();
340 d->m_cacheKey = QPixmapCache::insert(pm);
341 }
342
343 if (offset)
344 *offset = d->m_cachedOffset;
345
346 return pm;
347}
348
349/*!
350 Returns a pixmap with the source painted into it.
351
352 The \a system specifies which coordinate system to be used for the source.
353 The optional \a offset parameter returns the offset where the pixmap should
354 be painted at using the current painter. For control on how the pixmap is
355 padded use the \a mode parameter.
356
357 The returned pixmap is clipped to the current painter's device rectangle when
358 \a system is Qt::DeviceCoordinates.
359
360 Calling this function with Qt::DeviceCoordinates outside of
361 QGraphicsEffect::draw() will give undefined results, as there is no device
362 context available.
363
364 \sa draw(), boundingRect()
365*/
366QPixmap QGraphicsEffect::sourcePixmap(Qt::CoordinateSystem system, QPoint *offset, QGraphicsEffect::PixmapPadMode mode) const
367{
368 Q_D(const QGraphicsEffect);
369 if (d->source)
370 return d->source->pixmap(system, offset, mode);
371 return QPixmap();
372}
373
374QGraphicsEffectSourcePrivate::~QGraphicsEffectSourcePrivate()
375{
376 invalidateCache();
377}
378
379void QGraphicsEffectSourcePrivate::setCachedOffset(const QPoint &offset)
380{
381 m_cachedOffset = offset;
382}
383
384void QGraphicsEffectSourcePrivate::invalidateCache(InvalidateReason reason) const
385{
386 if (m_cachedMode != QGraphicsEffect::PadToEffectiveBoundingRect
387 && (reason == EffectRectChanged
388 || (reason == TransformChanged && m_cachedSystem == Qt::LogicalCoordinates))) {
389 return;
390 }
391
392 QPixmapCache::remove(m_cacheKey);
393}
394
395/*!
396 Constructs a new QGraphicsEffect instance having the
397 specified \a parent.
398*/
399QGraphicsEffect::QGraphicsEffect(QObject *parent)
400 : QObject(*new QGraphicsEffectPrivate, parent)
401{
402}
403
404/*!
405 \internal
406*/
407QGraphicsEffect::QGraphicsEffect(QGraphicsEffectPrivate &dd, QObject *parent)
408 : QObject(dd, parent)
409{
410}
411
412/*!
413 Removes the effect from the source, and destroys the graphics effect.
414*/
415QGraphicsEffect::~QGraphicsEffect()
416{
417 Q_D(QGraphicsEffect);
418 d->setGraphicsEffectSource(nullptr);
419}
420
421/*!
422 Returns the effective bounding rectangle for this effect, i.e., the
423 bounding rectangle of the source in device coordinates, adjusted by
424 any margins applied by the effect itself.
425
426 \sa boundingRectFor(), updateBoundingRect()
427*/
428QRectF QGraphicsEffect::boundingRect() const
429{
430 Q_D(const QGraphicsEffect);
431 if (d->source)
432 return boundingRectFor(d->source->boundingRect());
433 return QRectF();
434}
435
436/*!
437 Returns the effective bounding rectangle for this effect, given the
438 provided \a rect in the device coordinates. When writing
439 you own custom effect, you must call updateBoundingRect() whenever any
440 parameters are changed that may cause this this function to return a
441 different value.
442
443 \sa sourceBoundingRect()
444*/
445QRectF QGraphicsEffect::boundingRectFor(const QRectF &rect) const
446{
447 return rect;
448}
449
450/*!
451 \property QGraphicsEffect::enabled
452 \brief whether the effect is enabled or not.
453
454 If an effect is disabled, the source will be rendered with as normal, with
455 no interference from the effect. If the effect is enabled, the source will
456 be rendered with the effect applied.
457
458 This property is enabled by default.
459
460 Using this property, you can disable certain effects on slow platforms, in
461 order to ensure that the user interface is responsive.
462*/
463bool QGraphicsEffect::isEnabled() const
464{
465 Q_D(const QGraphicsEffect);
466 return d->isEnabled;
467}
468
469void QGraphicsEffect::setEnabled(bool enable)
470{
471 Q_D(QGraphicsEffect);
472 if (d->isEnabled == enable)
473 return;
474
475 d->isEnabled = enable;
476 if (d->source) {
477 d->source->d_func()->effectBoundingRectChanged();
478 d->source->d_func()->invalidateCache();
479 }
480 emit enabledChanged(enable);
481}
482
483/*!
484 \fn void QGraphicsEffect::enabledChanged(bool enabled)
485
486 This signal is emitted whenever the effect is enabled or disabled.
487 The \a enabled parameter holds the effects's new enabled state.
488
489 \sa isEnabled()
490*/
491
492/*!
493 Schedules a redraw of the effect. Call this function whenever the effect
494 needs to be redrawn. This function does not trigger a redraw of the source.
495
496 \sa updateBoundingRect()
497*/
498void QGraphicsEffect::update()
499{
500 Q_D(QGraphicsEffect);
501 if (d->source)
502 d->source->update();
503}
504
505/*!
506 \internal
507
508 Returns a pointer to the source, which provides extra context information
509 that can be useful for the effect.
510
511 \sa draw()
512*/
513QGraphicsEffectSource *QGraphicsEffect::source() const
514{
515 Q_D(const QGraphicsEffect);
516 return d->source;
517}
518
519/*!
520 This function notifies the effect framework when the effect's bounding
521 rectangle has changed. As a custom effect author, you must call this
522 function whenever you change any parameters that will cause the virtual
523 boundingRectFor() function to return a different value.
524
525 This function will call update() if this is necessary.
526
527 \sa boundingRectFor(), boundingRect(), sourceBoundingRect()
528*/
529void QGraphicsEffect::updateBoundingRect()
530{
531 Q_D(QGraphicsEffect);
532 if (d->source) {
533 d->source->d_func()->effectBoundingRectChanged();
534 d->source->d_func()->invalidateCache(QGraphicsEffectSourcePrivate::EffectRectChanged);
535 }
536}
537
538/*!
539 \fn virtual void QGraphicsEffect::draw(QPainter *painter) = 0
540
541 This pure virtual function draws the effect and is called whenever the
542 source needs to be drawn.
543
544 Reimplement this function in a QGraphicsEffect subclass to provide the
545 effect's drawing implementation, using \a painter.
546
547 For example:
548
549 \snippet code/src_gui_effects_qgraphicseffect.cpp 1
550
551 This function should not be called explicitly by the user, since it is
552 meant for reimplementation purposes only.
553*/
554
555/*!
556 \enum QGraphicsEffect::ChangeFlag
557
558 This enum describes what has changed in QGraphicsEffectSource.
559
560 \value SourceAttached The effect is installed on a source.
561 \value SourceDetached The effect is uninstalled on a source.
562 \value SourceBoundingRectChanged The bounding rect of the source has
563 changed.
564 \value SourceInvalidated The visual appearance of the source has changed.
565*/
566
567/*!
568 \enum QGraphicsEffect::PixmapPadMode
569
570 This enum describes how the pixmap returned from sourcePixmap should be
571 padded.
572
573 \value NoPad The pixmap should not receive any additional
574 padding.
575 \value PadToTransparentBorder The pixmap should be padded
576 to ensure it has a completely transparent border.
577 \value PadToEffectiveBoundingRect The pixmap should be padded to
578 match the effective bounding rectangle of the effect.
579*/
580
581/*!
582 This virtual function is called by QGraphicsEffect to notify the effect
583 that the source has changed. If the effect applies any cache, then this
584 cache must be purged in order to reflect the new appearance of the source.
585
586 The \a flags describes what has changed.
587*/
588void QGraphicsEffect::sourceChanged(ChangeFlags flags)
589{
590 Q_UNUSED(flags);
591}
592
593/*!
594 \class QGraphicsColorizeEffect
595 \brief The QGraphicsColorizeEffect class provides a colorize effect.
596 \since 4.6
597 \inmodule QtWidgets
598
599 A colorize effect renders the source with a tint of its color(). The color
600 can be modified using the setColor() function.
601
602 By default, the color is light blue (QColor(0, 0, 192)).
603
604 \image graphicseffect-colorize.png
605
606 \sa QGraphicsDropShadowEffect, QGraphicsBlurEffect, QGraphicsOpacityEffect
607*/
608
609/*!
610 Constructs a new QGraphicsColorizeEffect instance.
611 The \a parent parameter is passed to QGraphicsEffect's constructor.
612*/
613QGraphicsColorizeEffect::QGraphicsColorizeEffect(QObject *parent)
614 : QGraphicsEffect(*new QGraphicsColorizeEffectPrivate, parent)
615{
616}
617
618/*!
619 Destroys the effect.
620*/
621QGraphicsColorizeEffect::~QGraphicsColorizeEffect()
622{
623}
624
625/*!
626 \property QGraphicsColorizeEffect::color
627 \brief the color of the effect.
628
629 By default, the color is light blue (QColor(0, 0, 192)).
630*/
631QColor QGraphicsColorizeEffect::color() const
632{
633 Q_D(const QGraphicsColorizeEffect);
634 return d->filter->color();
635}
636
637void QGraphicsColorizeEffect::setColor(const QColor &color)
638{
639 Q_D(QGraphicsColorizeEffect);
640 if (d->filter->color() == color)
641 return;
642
643 d->filter->setColor(color);
644 update();
645 emit colorChanged(color);
646}
647
648/*!
649 \property QGraphicsColorizeEffect::strength
650 \brief the strength of the effect.
651
652 By default, the strength is 1.0.
653 A strength 0.0 equals to no effect, while 1.0 means full colorization.
654*/
655qreal QGraphicsColorizeEffect::strength() const
656{
657 Q_D(const QGraphicsColorizeEffect);
658 return d->filter->strength();
659}
660
661void QGraphicsColorizeEffect::setStrength(qreal strength)
662{
663 Q_D(QGraphicsColorizeEffect);
664 if (qFuzzyCompare(d->filter->strength(), strength))
665 return;
666
667 d->filter->setStrength(strength);
668 d->opaque = !qFuzzyIsNull(strength);
669 update();
670 emit strengthChanged(strength);
671}
672
673/*! \fn void QGraphicsColorizeEffect::strengthChanged(qreal strength)
674 This signal is emitted whenever setStrength() changes the colorize
675 strength property. \a strength contains the new strength value of
676 the colorize effect.
677 */
678
679/*!
680 \fn void QGraphicsColorizeEffect::colorChanged(const QColor &color)
681
682 This signal is emitted whenever the effect's color changes.
683 The \a color parameter holds the effect's new color.
684*/
685
686/*!
687 \reimp
688*/
689void QGraphicsColorizeEffect::draw(QPainter *painter)
690{
691 Q_D(QGraphicsColorizeEffect);
692
693 if (!d->opaque) {
694 drawSource(painter);
695 return;
696 }
697
698 QPoint offset;
699 if (sourceIsPixmap()) {
700 // No point in drawing in device coordinates (pixmap will be scaled anyways).
701 const QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset, NoPad);
702 if (!pixmap.isNull())
703 d->filter->draw(painter, offset, pixmap);
704
705 return;
706 }
707
708 // Draw pixmap in deviceCoordinates to avoid pixmap scaling.
709 const QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates, &offset);
710 if (pixmap.isNull())
711 return;
712
713 QTransform restoreTransform = painter->worldTransform();
714 painter->setWorldTransform(QTransform());
715 d->filter->draw(painter, offset, pixmap);
716 painter->setWorldTransform(restoreTransform);
717}
718
719/*!
720 \class QGraphicsBlurEffect
721 \brief The QGraphicsBlurEffect class provides a blur effect.
722 \since 4.6
723 \inmodule QtWidgets
724
725 A blur effect blurs the source. This effect is useful for reducing details,
726 such as when the source loses focus and you want to draw attention to other
727 elements. The level of detail can be modified using the setBlurRadius()
728 function. Use setBlurHints() to choose the blur hints.
729
730 By default, the blur radius is 5 pixels. The blur radius is specified in
731 device coordinates.
732
733 \image graphicseffect-blur.png
734
735 \sa QGraphicsDropShadowEffect, QGraphicsColorizeEffect, QGraphicsOpacityEffect
736*/
737
738/*!
739 \enum QGraphicsBlurEffect::BlurHint
740 \since 4.6
741
742 This enum describes the possible hints that can be used to control how
743 blur effects are applied. The hints might not have an effect in all the
744 paint engines.
745
746 \value PerformanceHint Indicates that rendering performance is the most important factor,
747 at the potential cost of lower quality.
748
749 \value QualityHint Indicates that rendering quality is the most important factor,
750 at the potential cost of lower performance.
751
752 \value AnimationHint Indicates that the blur radius is going to be animated, hinting
753 that the implementation can keep a cache of blurred verisons of the source.
754 Do not use this hint if the source is going to be dynamically changing.
755
756 \sa blurHints(), setBlurHints()
757*/
758
759
760/*!
761 Constructs a new QGraphicsBlurEffect instance.
762 The \a parent parameter is passed to QGraphicsEffect's constructor.
763*/
764QGraphicsBlurEffect::QGraphicsBlurEffect(QObject *parent)
765 : QGraphicsEffect(*new QGraphicsBlurEffectPrivate, parent)
766{
767 Q_D(QGraphicsBlurEffect);
768 d->filter->setBlurHints(QGraphicsBlurEffect::PerformanceHint);
769}
770
771/*!
772 Destroys the effect.
773*/
774QGraphicsBlurEffect::~QGraphicsBlurEffect()
775{
776}
777
778/*!
779 \property QGraphicsBlurEffect::blurRadius
780 \brief the blur radius of the effect.
781
782 Using a smaller radius results in a sharper appearance, whereas a bigger
783 radius results in a more blurred appearance.
784
785 By default, the blur radius is 5 pixels.
786
787 The radius is given in device coordinates, meaning it is
788 unaffected by scale.
789*/
790qreal QGraphicsBlurEffect::blurRadius() const
791{
792 Q_D(const QGraphicsBlurEffect);
793 return d->filter->radius();
794}
795
796void QGraphicsBlurEffect::setBlurRadius(qreal radius)
797{
798 Q_D(QGraphicsBlurEffect);
799 if (qFuzzyCompare(d->filter->radius(), radius))
800 return;
801
802 d->filter->setRadius(radius);
803 updateBoundingRect();
804 emit blurRadiusChanged(radius);
805}
806
807/*!
808 \fn void QGraphicsBlurEffect::blurRadiusChanged(qreal radius)
809
810 This signal is emitted whenever the effect's blur radius changes.
811 The \a radius parameter holds the effect's new blur radius.
812*/
813
814/*!
815 \property QGraphicsBlurEffect::blurHints
816 \brief the blur hint of the effect.
817
818 Use the PerformanceHint hint to say that you want a faster blur,
819 the QualityHint hint to say that you prefer a higher quality blur,
820 or the AnimationHint when you want to animate the blur radius.
821
822 By default, the blur hint is PerformanceHint.
823*/
824QGraphicsBlurEffect::BlurHints QGraphicsBlurEffect::blurHints() const
825{
826 Q_D(const QGraphicsBlurEffect);
827 return d->filter->blurHints();
828}
829
830void QGraphicsBlurEffect::setBlurHints(QGraphicsBlurEffect::BlurHints hints)
831{
832 Q_D(QGraphicsBlurEffect);
833 if (d->filter->blurHints() == hints)
834 return;
835
836 d->filter->setBlurHints(hints);
837 emit blurHintsChanged(hints);
838}
839
840/*!
841 \fn void QGraphicsBlurEffect::blurHintsChanged(QGraphicsBlurEffect::BlurHints hints)
842
843 This signal is emitted whenever the effect's blur hints changes.
844 The \a hints parameter holds the effect's new blur hints.
845*/
846
847/*!
848 \reimp
849*/
850QRectF QGraphicsBlurEffect::boundingRectFor(const QRectF &rect) const
851{
852 Q_D(const QGraphicsBlurEffect);
853 return d->filter->boundingRectFor(rect);
854}
855
856/*!
857 \reimp
858*/
859void QGraphicsBlurEffect::draw(QPainter *painter)
860{
861 Q_D(QGraphicsBlurEffect);
862 if (d->filter->radius() < 1) {
863 drawSource(painter);
864 return;
865 }
866
867 PixmapPadMode mode = PadToEffectiveBoundingRect;
868
869 QPoint offset;
870 QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset, mode);
871 if (pixmap.isNull())
872 return;
873
874 d->filter->draw(painter, offset, pixmap);
875}
876
877/*!
878 \class QGraphicsDropShadowEffect
879 \brief The QGraphicsDropShadowEffect class provides a drop shadow effect.
880 \since 4.6
881 \inmodule QtWidgets
882
883 A drop shadow effect renders the source with a drop shadow. The color of
884 the drop shadow can be modified using the setColor() function. The drop
885 shadow offset can be modified using the setOffset() function and the blur
886 radius of the drop shadow can be changed with the setBlurRadius()
887 function.
888
889 By default, the drop shadow is a semi-transparent dark gray
890 (QColor(63, 63, 63, 180)) shadow, blurred with a radius of 1 at an offset
891 of 8 pixels towards the lower right. The drop shadow offset is specified
892 in device coordinates.
893
894 \image graphicseffect-drop-shadow.png
895
896 \sa QGraphicsBlurEffect, QGraphicsColorizeEffect, QGraphicsOpacityEffect
897*/
898
899/*!
900 Constructs a new QGraphicsDropShadowEffect instance.
901 The \a parent parameter is passed to QGraphicsEffect's constructor.
902*/
903QGraphicsDropShadowEffect::QGraphicsDropShadowEffect(QObject *parent)
904 : QGraphicsEffect(*new QGraphicsDropShadowEffectPrivate, parent)
905{
906}
907
908/*!
909 Destroys the effect.
910*/
911QGraphicsDropShadowEffect::~QGraphicsDropShadowEffect()
912{
913}
914
915/*!
916 \property QGraphicsDropShadowEffect::offset
917 \brief the shadow offset in pixels.
918
919 By default, the offset is 8 pixels towards the lower right.
920
921 The offset is given in device coordinates, which means it is
922 unaffected by scale.
923
924 \sa xOffset(), yOffset(), blurRadius(), color()
925*/
926QPointF QGraphicsDropShadowEffect::offset() const
927{
928 Q_D(const QGraphicsDropShadowEffect);
929 return d->filter->offset();
930}
931
932void QGraphicsDropShadowEffect::setOffset(const QPointF &offset)
933{
934 Q_D(QGraphicsDropShadowEffect);
935 if (d->filter->offset() == offset)
936 return;
937
938 d->filter->setOffset(offset);
939 updateBoundingRect();
940 emit offsetChanged(offset);
941}
942
943/*!
944 \property QGraphicsDropShadowEffect::xOffset
945 \brief the horizontal shadow offset in pixels.
946
947 By default, the horizontal shadow offset is 8 pixels.
948
949
950
951 \sa yOffset(), offset()
952*/
953
954/*!
955 \property QGraphicsDropShadowEffect::yOffset
956 \brief the vertical shadow offset in pixels.
957
958 By default, the vertical shadow offset is 8 pixels.
959
960 \sa xOffset(), offset()
961*/
962
963/*!
964 \fn void QGraphicsDropShadowEffect::offsetChanged(const QPointF &offset)
965
966 This signal is emitted whenever the effect's shadow offset changes.
967 The \a offset parameter holds the effect's new shadow offset.
968*/
969
970/*!
971 \property QGraphicsDropShadowEffect::blurRadius
972 \brief the blur radius in pixels of the drop shadow.
973
974 Using a smaller radius results in a sharper shadow, whereas using a bigger
975 radius results in a more blurred shadow.
976
977 By default, the blur radius is 1 pixel.
978
979 \sa color(), offset()
980*/
981qreal QGraphicsDropShadowEffect::blurRadius() const
982{
983 Q_D(const QGraphicsDropShadowEffect);
984 return d->filter->blurRadius();
985}
986
987void QGraphicsDropShadowEffect::setBlurRadius(qreal blurRadius)
988{
989 Q_D(QGraphicsDropShadowEffect);
990 if (qFuzzyCompare(d->filter->blurRadius(), blurRadius))
991 return;
992
993 d->filter->setBlurRadius(blurRadius);
994 updateBoundingRect();
995 emit blurRadiusChanged(blurRadius);
996}
997
998/*!
999 \fn void QGraphicsDropShadowEffect::blurRadiusChanged(qreal blurRadius)
1000
1001 This signal is emitted whenever the effect's blur radius changes.
1002 The \a blurRadius parameter holds the effect's new blur radius.
1003*/
1004
1005/*!
1006 \property QGraphicsDropShadowEffect::color
1007 \brief the color of the drop shadow.
1008
1009 By default, the drop color is a semi-transparent dark gray
1010 (QColor(63, 63, 63, 180)).
1011
1012 \sa offset(), blurRadius()
1013*/
1014QColor QGraphicsDropShadowEffect::color() const
1015{
1016 Q_D(const QGraphicsDropShadowEffect);
1017 return d->filter->color();
1018}
1019
1020void QGraphicsDropShadowEffect::setColor(const QColor &color)
1021{
1022 Q_D(QGraphicsDropShadowEffect);
1023 if (d->filter->color() == color)
1024 return;
1025
1026 d->filter->setColor(color);
1027 update();
1028 emit colorChanged(color);
1029}
1030
1031/*!
1032 \fn void QGraphicsDropShadowEffect::colorChanged(const QColor &color)
1033
1034 This signal is emitted whenever the effect's color changes.
1035 The \a color parameter holds the effect's new color.
1036*/
1037
1038/*!
1039 \reimp
1040*/
1041QRectF QGraphicsDropShadowEffect::boundingRectFor(const QRectF &rect) const
1042{
1043 Q_D(const QGraphicsDropShadowEffect);
1044 return d->filter->boundingRectFor(rect);
1045}
1046
1047/*!
1048 \reimp
1049*/
1050void QGraphicsDropShadowEffect::draw(QPainter *painter)
1051{
1052 Q_D(QGraphicsDropShadowEffect);
1053 if (d->filter->blurRadius() <= 0 && d->filter->offset().isNull()) {
1054 drawSource(painter);
1055 return;
1056 }
1057
1058 PixmapPadMode mode = PadToEffectiveBoundingRect;
1059
1060 // Draw pixmap in device coordinates to avoid pixmap scaling.
1061 QPoint offset;
1062 const QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates, &offset, mode);
1063 if (pixmap.isNull())
1064 return;
1065
1066 QTransform restoreTransform = painter->worldTransform();
1067 painter->setWorldTransform(QTransform());
1068 d->filter->draw(painter, offset, pixmap);
1069 painter->setWorldTransform(restoreTransform);
1070}
1071
1072/*!
1073 \class QGraphicsOpacityEffect
1074 \brief The QGraphicsOpacityEffect class provides an opacity effect.
1075 \since 4.6
1076 \inmodule QtWidgets
1077
1078 An opacity effect renders the source with an opacity. This effect is useful
1079 for making the source semi-transparent, similar to a fade-in/fade-out
1080 sequence. The opacity can be modified using the setOpacity() function.
1081
1082 By default, the opacity is 0.7.
1083
1084 \image graphicseffect-opacity.png
1085
1086 \sa QGraphicsDropShadowEffect, QGraphicsBlurEffect, QGraphicsColorizeEffect
1087*/
1088
1089/*!
1090 Constructs a new QGraphicsOpacityEffect instance.
1091 The \a parent parameter is passed to QGraphicsEffect's constructor.
1092*/
1093QGraphicsOpacityEffect::QGraphicsOpacityEffect(QObject *parent)
1094 : QGraphicsEffect(*new QGraphicsOpacityEffectPrivate, parent)
1095{
1096}
1097
1098/*!
1099 Destroys the effect.
1100*/
1101QGraphicsOpacityEffect::~QGraphicsOpacityEffect()
1102{
1103}
1104
1105/*!
1106 \property QGraphicsOpacityEffect::opacity
1107 \brief the opacity of the effect.
1108
1109 The value should be in the range of 0.0 to 1.0, where 0.0 is
1110 fully transparent and 1.0 is fully opaque.
1111
1112 By default, the opacity is 0.7.
1113
1114 \sa setOpacityMask()
1115*/
1116qreal QGraphicsOpacityEffect::opacity() const
1117{
1118 Q_D(const QGraphicsOpacityEffect);
1119 return d->opacity;
1120}
1121
1122void QGraphicsOpacityEffect::setOpacity(qreal opacity)
1123{
1124 Q_D(QGraphicsOpacityEffect);
1125 opacity = qBound(qreal(0.0), opacity, qreal(1.0));
1126
1127 if (qFuzzyCompare(d->opacity, opacity))
1128 return;
1129
1130 d->opacity = opacity;
1131 if ((d->isFullyTransparent = qFuzzyIsNull(d->opacity)))
1132 d->isFullyOpaque = 0;
1133 else
1134 d->isFullyOpaque = qFuzzyIsNull(d->opacity - 1);
1135 update();
1136 emit opacityChanged(opacity);
1137}
1138
1139/*!
1140 \fn void QGraphicsOpacityEffect::opacityChanged(qreal opacity)
1141
1142 This signal is emitted whenever the effect's opacity changes.
1143 The \a opacity parameter holds the effect's new opacity.
1144*/
1145
1146/*!
1147 \property QGraphicsOpacityEffect::opacityMask
1148 \brief the opacity mask of the effect.
1149
1150 An opacity mask allows you apply opacity to portions of an element.
1151
1152 For example:
1153
1154 \snippet code/src_gui_effects_qgraphicseffect.cpp 2
1155
1156 There is no opacity mask by default.
1157
1158 \sa setOpacity()
1159*/
1160QBrush QGraphicsOpacityEffect::opacityMask() const
1161{
1162 Q_D(const QGraphicsOpacityEffect);
1163 return d->opacityMask;
1164}
1165
1166void QGraphicsOpacityEffect::setOpacityMask(const QBrush &mask)
1167{
1168 Q_D(QGraphicsOpacityEffect);
1169 if (d->opacityMask == mask)
1170 return;
1171
1172 d->opacityMask = mask;
1173 d->hasOpacityMask = (mask.style() != Qt::NoBrush);
1174 update();
1175
1176 emit opacityMaskChanged(mask);
1177}
1178
1179/*!
1180 \fn void QGraphicsOpacityEffect::opacityMaskChanged(const QBrush &mask)
1181
1182 This signal is emitted whenever the effect's opacity mask changes.
1183 The \a mask parameter holds the effect's new opacity mask.
1184*/
1185
1186/*!
1187 \reimp
1188*/
1189void QGraphicsOpacityEffect::draw(QPainter *painter)
1190{
1191 Q_D(QGraphicsOpacityEffect);
1192
1193 // Transparent; nothing to draw.
1194 if (d->isFullyTransparent)
1195 return;
1196
1197 // Opaque; draw directly without going through a pixmap.
1198 if (d->isFullyOpaque && !d->hasOpacityMask) {
1199 drawSource(painter);
1200 return;
1201 }
1202
1203 QPoint offset;
1204 Qt::CoordinateSystem system = sourceIsPixmap() ? Qt::LogicalCoordinates : Qt::DeviceCoordinates;
1205 QPixmap pixmap = sourcePixmap(system, &offset, QGraphicsEffect::NoPad);
1206 if (pixmap.isNull())
1207 return;
1208
1209 painter->save();
1210 painter->setOpacity(d->opacity);
1211
1212 if (d->hasOpacityMask) {
1213 QPainter pixmapPainter(&pixmap);
1214 pixmapPainter.setRenderHints(painter->renderHints());
1215 pixmapPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
1216 if (system == Qt::DeviceCoordinates) {
1217 QTransform worldTransform = painter->worldTransform();
1218 worldTransform *= QTransform::fromTranslate(-offset.x(), -offset.y());
1219 pixmapPainter.setWorldTransform(worldTransform);
1220 pixmapPainter.fillRect(sourceBoundingRect(), d->opacityMask);
1221 } else {
1222 pixmapPainter.translate(-offset);
1223 pixmapPainter.fillRect(pixmap.rect(), d->opacityMask);
1224 }
1225 }
1226
1227 if (system == Qt::DeviceCoordinates)
1228 painter->setWorldTransform(QTransform());
1229
1230 painter->drawPixmap(offset, pixmap);
1231 painter->restore();
1232}
1233
1234
1235QT_END_NAMESPACE
1236
1237#include "moc_qgraphicseffect.cpp"
1238#include "moc_qgraphicseffect_p.cpp"
1239