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 |
119 | QT_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 | */ |
140 | QGraphicsEffectSource::QGraphicsEffectSource(QGraphicsEffectSourcePrivate &dd, QObject *parent) |
141 | : QObject(dd, parent) |
142 | {} |
143 | |
144 | /*! |
145 | Destroys the effect source. |
146 | */ |
147 | QGraphicsEffectSource::~QGraphicsEffectSource() |
148 | {} |
149 | |
150 | /*! |
151 | Returns the bounding rectangle of the source mapped to the given \a system. |
152 | |
153 | \sa draw() |
154 | */ |
155 | QRectF 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 | */ |
169 | QRectF 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 | */ |
183 | const 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 | */ |
194 | const 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 | */ |
205 | const 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 | */ |
217 | void 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 | */ |
249 | void 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 | */ |
263 | void 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 | */ |
276 | bool 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 | */ |
289 | bool 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 | */ |
309 | QPixmap 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 | */ |
364 | QPixmap 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 | |
372 | QGraphicsEffectSourcePrivate::~QGraphicsEffectSourcePrivate() |
373 | { |
374 | invalidateCache(); |
375 | } |
376 | |
377 | void QGraphicsEffectSourcePrivate::setCachedOffset(const QPoint &offset) |
378 | { |
379 | m_cachedOffset = offset; |
380 | } |
381 | |
382 | void 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 | */ |
397 | QGraphicsEffect::QGraphicsEffect(QObject *parent) |
398 | : QObject(*new QGraphicsEffectPrivate, parent) |
399 | { |
400 | } |
401 | |
402 | /*! |
403 | \internal |
404 | */ |
405 | QGraphicsEffect::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 | */ |
413 | QGraphicsEffect::~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 | */ |
426 | QRectF 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 | */ |
443 | QRectF 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 | */ |
461 | bool QGraphicsEffect::isEnabled() const |
462 | { |
463 | Q_D(const QGraphicsEffect); |
464 | return d->isEnabled; |
465 | } |
466 | |
467 | void 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 | */ |
496 | void 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 | */ |
511 | QGraphicsEffectSource *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 | */ |
527 | void 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 | */ |
586 | void 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 | */ |
610 | QGraphicsColorizeEffect::QGraphicsColorizeEffect(QObject *parent) |
611 | : QGraphicsEffect(*new QGraphicsColorizeEffectPrivate, parent) |
612 | { |
613 | } |
614 | |
615 | /*! |
616 | Destroys the effect. |
617 | */ |
618 | QGraphicsColorizeEffect::~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 | */ |
628 | QColor QGraphicsColorizeEffect::color() const |
629 | { |
630 | Q_D(const QGraphicsColorizeEffect); |
631 | return d->filter->color(); |
632 | } |
633 | |
634 | void 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 | */ |
652 | qreal QGraphicsColorizeEffect::strength() const |
653 | { |
654 | Q_D(const QGraphicsColorizeEffect); |
655 | return d->filter->strength(); |
656 | } |
657 | |
658 | void 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 | */ |
686 | void 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 | */ |
760 | QGraphicsBlurEffect::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 | */ |
770 | QGraphicsBlurEffect::~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 | */ |
786 | qreal QGraphicsBlurEffect::blurRadius() const |
787 | { |
788 | Q_D(const QGraphicsBlurEffect); |
789 | return d->filter->radius(); |
790 | } |
791 | |
792 | void 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 | */ |
820 | QGraphicsBlurEffect::BlurHints QGraphicsBlurEffect::blurHints() const |
821 | { |
822 | Q_D(const QGraphicsBlurEffect); |
823 | return d->filter->blurHints(); |
824 | } |
825 | |
826 | void 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 | */ |
846 | QRectF QGraphicsBlurEffect::boundingRectFor(const QRectF &rect) const |
847 | { |
848 | Q_D(const QGraphicsBlurEffect); |
849 | return d->filter->boundingRectFor(rect); |
850 | } |
851 | |
852 | /*! |
853 | \reimp |
854 | */ |
855 | void 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 | */ |
900 | QGraphicsDropShadowEffect::QGraphicsDropShadowEffect(QObject *parent) |
901 | : QGraphicsEffect(*new QGraphicsDropShadowEffectPrivate, parent) |
902 | { |
903 | } |
904 | |
905 | /*! |
906 | Destroys the effect. |
907 | */ |
908 | QGraphicsDropShadowEffect::~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 | */ |
923 | QPointF QGraphicsDropShadowEffect::offset() const |
924 | { |
925 | Q_D(const QGraphicsDropShadowEffect); |
926 | return d->filter->offset(); |
927 | } |
928 | |
929 | void 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 | */ |
978 | qreal QGraphicsDropShadowEffect::blurRadius() const |
979 | { |
980 | Q_D(const QGraphicsDropShadowEffect); |
981 | return d->filter->blurRadius(); |
982 | } |
983 | |
984 | void 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 | */ |
1011 | QColor QGraphicsDropShadowEffect::color() const |
1012 | { |
1013 | Q_D(const QGraphicsDropShadowEffect); |
1014 | return d->filter->color(); |
1015 | } |
1016 | |
1017 | void 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 | */ |
1038 | QRectF QGraphicsDropShadowEffect::boundingRectFor(const QRectF &rect) const |
1039 | { |
1040 | Q_D(const QGraphicsDropShadowEffect); |
1041 | return d->filter->boundingRectFor(rect); |
1042 | } |
1043 | |
1044 | /*! |
1045 | \reimp |
1046 | */ |
1047 | void 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 | */ |
1091 | QGraphicsOpacityEffect::QGraphicsOpacityEffect(QObject *parent) |
1092 | : QGraphicsEffect(*new QGraphicsOpacityEffectPrivate, parent) |
1093 | { |
1094 | } |
1095 | |
1096 | /*! |
1097 | Destroys the effect. |
1098 | */ |
1099 | QGraphicsOpacityEffect::~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 | */ |
1114 | qreal QGraphicsOpacityEffect::opacity() const |
1115 | { |
1116 | Q_D(const QGraphicsOpacityEffect); |
1117 | return d->opacity; |
1118 | } |
1119 | |
1120 | void 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 | */ |
1158 | QBrush QGraphicsOpacityEffect::opacityMask() const |
1159 | { |
1160 | Q_D(const QGraphicsOpacityEffect); |
1161 | return d->opacityMask; |
1162 | } |
1163 | |
1164 | void 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 | */ |
1187 | void 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 | |
1233 | QT_END_NAMESPACE |
1234 | |
1235 | #endif //QT_NO_GRAPHICSEFFECT |
1236 | |