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 | |
117 | QT_BEGIN_NAMESPACE |
118 | |
119 | QGraphicsEffectPrivate::~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 | */ |
142 | QGraphicsEffectSource::QGraphicsEffectSource(QGraphicsEffectSourcePrivate &dd, QObject *parent) |
143 | : QObject(dd, parent) |
144 | {} |
145 | |
146 | /*! |
147 | Destroys the effect source. |
148 | */ |
149 | QGraphicsEffectSource::~QGraphicsEffectSource() |
150 | {} |
151 | |
152 | /*! |
153 | Returns the bounding rectangle of the source mapped to the given \a system. |
154 | |
155 | \sa draw() |
156 | */ |
157 | QRectF 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 | */ |
171 | QRectF 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 | */ |
185 | const 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 | */ |
196 | const 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 | */ |
207 | const 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 | */ |
219 | void 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 | */ |
251 | void 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 | */ |
265 | void 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 | */ |
278 | bool 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 | */ |
291 | bool 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 | */ |
311 | QPixmap 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 | */ |
366 | QPixmap 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 | |
374 | QGraphicsEffectSourcePrivate::~QGraphicsEffectSourcePrivate() |
375 | { |
376 | invalidateCache(); |
377 | } |
378 | |
379 | void QGraphicsEffectSourcePrivate::setCachedOffset(const QPoint &offset) |
380 | { |
381 | m_cachedOffset = offset; |
382 | } |
383 | |
384 | void 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 | */ |
399 | QGraphicsEffect::QGraphicsEffect(QObject *parent) |
400 | : QObject(*new QGraphicsEffectPrivate, parent) |
401 | { |
402 | } |
403 | |
404 | /*! |
405 | \internal |
406 | */ |
407 | QGraphicsEffect::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 | */ |
415 | QGraphicsEffect::~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 | */ |
428 | QRectF 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 | */ |
445 | QRectF 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 | */ |
463 | bool QGraphicsEffect::isEnabled() const |
464 | { |
465 | Q_D(const QGraphicsEffect); |
466 | return d->isEnabled; |
467 | } |
468 | |
469 | void 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 | */ |
498 | void 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 | */ |
513 | QGraphicsEffectSource *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 | */ |
529 | void 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 | */ |
588 | void 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 | */ |
613 | QGraphicsColorizeEffect::QGraphicsColorizeEffect(QObject *parent) |
614 | : QGraphicsEffect(*new QGraphicsColorizeEffectPrivate, parent) |
615 | { |
616 | } |
617 | |
618 | /*! |
619 | Destroys the effect. |
620 | */ |
621 | QGraphicsColorizeEffect::~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 | */ |
631 | QColor QGraphicsColorizeEffect::color() const |
632 | { |
633 | Q_D(const QGraphicsColorizeEffect); |
634 | return d->filter->color(); |
635 | } |
636 | |
637 | void 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 | */ |
655 | qreal QGraphicsColorizeEffect::strength() const |
656 | { |
657 | Q_D(const QGraphicsColorizeEffect); |
658 | return d->filter->strength(); |
659 | } |
660 | |
661 | void 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 | */ |
689 | void 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 | */ |
764 | QGraphicsBlurEffect::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 | */ |
774 | QGraphicsBlurEffect::~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 | */ |
790 | qreal QGraphicsBlurEffect::blurRadius() const |
791 | { |
792 | Q_D(const QGraphicsBlurEffect); |
793 | return d->filter->radius(); |
794 | } |
795 | |
796 | void 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 | */ |
824 | QGraphicsBlurEffect::BlurHints QGraphicsBlurEffect::blurHints() const |
825 | { |
826 | Q_D(const QGraphicsBlurEffect); |
827 | return d->filter->blurHints(); |
828 | } |
829 | |
830 | void 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 | */ |
850 | QRectF QGraphicsBlurEffect::boundingRectFor(const QRectF &rect) const |
851 | { |
852 | Q_D(const QGraphicsBlurEffect); |
853 | return d->filter->boundingRectFor(rect); |
854 | } |
855 | |
856 | /*! |
857 | \reimp |
858 | */ |
859 | void 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 | */ |
903 | QGraphicsDropShadowEffect::QGraphicsDropShadowEffect(QObject *parent) |
904 | : QGraphicsEffect(*new QGraphicsDropShadowEffectPrivate, parent) |
905 | { |
906 | } |
907 | |
908 | /*! |
909 | Destroys the effect. |
910 | */ |
911 | QGraphicsDropShadowEffect::~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 | */ |
926 | QPointF QGraphicsDropShadowEffect::offset() const |
927 | { |
928 | Q_D(const QGraphicsDropShadowEffect); |
929 | return d->filter->offset(); |
930 | } |
931 | |
932 | void 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 | */ |
981 | qreal QGraphicsDropShadowEffect::blurRadius() const |
982 | { |
983 | Q_D(const QGraphicsDropShadowEffect); |
984 | return d->filter->blurRadius(); |
985 | } |
986 | |
987 | void 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 | */ |
1014 | QColor QGraphicsDropShadowEffect::color() const |
1015 | { |
1016 | Q_D(const QGraphicsDropShadowEffect); |
1017 | return d->filter->color(); |
1018 | } |
1019 | |
1020 | void 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 | */ |
1041 | QRectF QGraphicsDropShadowEffect::boundingRectFor(const QRectF &rect) const |
1042 | { |
1043 | Q_D(const QGraphicsDropShadowEffect); |
1044 | return d->filter->boundingRectFor(rect); |
1045 | } |
1046 | |
1047 | /*! |
1048 | \reimp |
1049 | */ |
1050 | void 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 | */ |
1093 | QGraphicsOpacityEffect::QGraphicsOpacityEffect(QObject *parent) |
1094 | : QGraphicsEffect(*new QGraphicsOpacityEffectPrivate, parent) |
1095 | { |
1096 | } |
1097 | |
1098 | /*! |
1099 | Destroys the effect. |
1100 | */ |
1101 | QGraphicsOpacityEffect::~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 | */ |
1116 | qreal QGraphicsOpacityEffect::opacity() const |
1117 | { |
1118 | Q_D(const QGraphicsOpacityEffect); |
1119 | return d->opacity; |
1120 | } |
1121 | |
1122 | void 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 | */ |
1160 | QBrush QGraphicsOpacityEffect::opacityMask() const |
1161 | { |
1162 | Q_D(const QGraphicsOpacityEffect); |
1163 | return d->opacityMask; |
1164 | } |
1165 | |
1166 | void 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 | */ |
1189 | void 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 | |
1235 | QT_END_NAMESPACE |
1236 | |
1237 | #include "moc_qgraphicseffect.cpp" |
1238 | #include "moc_qgraphicseffect_p.cpp" |
1239 | |