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