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

source code of qtbase/src/widgets/effects/qgraphicseffect.cpp