63 \list |
63 \list |
64 \o QGraphicsBlurEffect - blurs the item by a given radius |
64 \o QGraphicsBlurEffect - blurs the item by a given radius |
65 \o QGraphicsDropShadowEffect - renders a dropshadow behind the item |
65 \o QGraphicsDropShadowEffect - renders a dropshadow behind the item |
66 \o QGraphicsColorizeEffect - renders the item in shades of any given color |
66 \o QGraphicsColorizeEffect - renders the item in shades of any given color |
67 \o QGraphicsOpacityEffect - renders the item with an opacity |
67 \o QGraphicsOpacityEffect - renders the item with an opacity |
68 \o QGraphicsPixelizeEffect - pixelizes the item with any pixel size |
|
69 \o QGraphicsGrayscaleEffect - renders the item in shades of gray |
|
70 \o QGraphicsBloomEffect - applies a blooming / glowing effect |
|
71 \endlist |
68 \endlist |
72 |
69 |
73 \img graphicseffect-effects.png |
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 |
74 \img graphicseffect-widget.png |
81 \img graphicseffect-widget.png |
75 |
82 |
76 For more information on how to use each effect, refer to the specific |
83 For more information on how to use each effect, refer to the specific |
77 effect's documentation. |
84 effect's documentation. |
78 |
85 |
79 To create your own custom effect, create a subclass of QGraphicsEffect (or |
86 To create your own custom effect, create a subclass of QGraphicsEffect (or |
80 any other existing effects) and reimplement the virtual function draw(). |
87 any other existing effects) and reimplement the virtual function draw(). |
81 This function is called whenever the effect needs to redraw. The draw() |
88 This function is called whenever the effect needs to redraw. The draw() |
82 function accepts two arguments: the painter and a pointer to the source |
89 function takes the painter with which to draw as an argument. For more |
83 (QGraphicsEffectSource). The source provides extra context information, |
90 information, refer to the documenation for draw(). In the draw() function |
84 such as a pointer to the item that is rendering the effect, any cached |
91 you can call sourcePixmap() to get a pixmap of the graphics effect source |
85 pixmap data, or the device rectangle bounds. For more information, refer to |
92 which you can then process. |
86 the documenation for draw(). To obtain a pointer to the current source, |
|
87 simply call source(). |
|
88 |
93 |
89 If your effect changes, use update() to request for a redraw. If your |
94 If your effect changes, use update() to request for a redraw. If your |
90 custom effect changes the bounding rectangle of the source, e.g., a radial |
95 custom effect changes the bounding rectangle of the source, e.g., a radial |
91 glow effect may need to apply an extra margin, you can reimplement the |
96 glow effect may need to apply an extra margin, you can reimplement the |
92 virtual boundingRectFor() function, and call updateBoundingRect() to notify |
97 virtual boundingRectFor() function, and call updateBoundingRect() |
93 the framework whenever this rectangle changes. The virtual |
98 to notify the framework whenever this rectangle changes. The virtual |
94 sourceBoundingRectChanged() function is called to notify the effects that |
99 sourceChanged() function is called to notify the effects that |
95 the source's bounding rectangle has changed - e.g., if the source is a |
100 the source has changed in some way - e.g., if the source is a |
96 QGraphicsRectItem and its rectangle parameters have changed. |
101 QGraphicsRectItem and its rectangle parameters have changed. |
97 |
102 |
98 \sa QGraphicsItem::setGraphicsEffect(), QWidget::setGraphicsEffect(), |
103 \sa QGraphicsItem::setGraphicsEffect(), QWidget::setGraphicsEffect() |
99 QGraphicsEffectSource |
|
100 */ |
104 */ |
101 |
105 |
102 #include "qgraphicseffect_p.h" |
106 #include "qgraphicseffect_p.h" |
|
107 #include "private/qgraphicsitem_p.h" |
|
108 |
|
109 #include <QtGui/qgraphicsitem.h> |
103 |
110 |
104 #include <QtGui/qimage.h> |
111 #include <QtGui/qimage.h> |
105 #include <QtGui/qpainter.h> |
112 #include <QtGui/qpainter.h> |
|
113 #include <QtGui/qpaintengine.h> |
106 #include <QtCore/qrect.h> |
114 #include <QtCore/qrect.h> |
107 #include <QtCore/qdebug.h> |
115 #include <QtCore/qdebug.h> |
108 #include <private/qdrawhelper_p.h> |
116 #include <private/qdrawhelper_p.h> |
109 |
117 |
|
118 #ifndef QT_NO_GRAPHICSEFFECT |
110 QT_BEGIN_NAMESPACE |
119 QT_BEGIN_NAMESPACE |
111 |
120 |
112 /*! |
121 /*! |
|
122 \internal |
113 \class QGraphicsEffectSource |
123 \class QGraphicsEffectSource |
114 \brief The QGraphicsEffectSource class represents the source on which a |
124 \brief The QGraphicsEffectSource class represents the source on which a |
115 QGraphicsEffect is installed on. |
125 QGraphicsEffect is installed on. |
116 \since 4.6 |
|
117 |
126 |
118 When a QGraphicsEffect is installed on a QGraphicsItem, for example, this |
127 When a QGraphicsEffect is installed on a QGraphicsItem, for example, this |
119 class will act as a wrapper around QGraphicsItem. Then, calling update() is |
128 class will act as a wrapper around QGraphicsItem. Then, calling update() is |
120 effectively the same as calling QGraphicsItem::update(). |
129 effectively the same as calling QGraphicsItem::update(). |
121 |
130 |
238 { |
277 { |
239 return d_func()->isPixmap(); |
278 return d_func()->isPixmap(); |
240 } |
279 } |
241 |
280 |
242 /*! |
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 /*! |
243 Returns a pixmap with the source painted into it. |
295 Returns a pixmap with the source painted into it. |
244 |
296 |
245 The \a system specifies which coordinate system to be used for the source. |
297 The \a system specifies which coordinate system to be used for the source. |
246 The optional \a offset parameter returns the offset where the pixmap should |
298 The optional \a offset parameter returns the offset where the pixmap should |
247 be painted at using the current painter. |
299 be painted at using the current painter. |
248 |
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 |
249 The returned pixmap is bound to the current painter's device rectangle when |
304 The returned pixmap is bound to the current painter's device rectangle when |
250 \a system is Qt::DeviceCoordinates. |
305 \a system is Qt::DeviceCoordinates. |
251 |
306 |
252 \sa QGraphicsEffect::draw(), boundingRect(), deviceRect() |
307 \sa QGraphicsEffect::draw(), boundingRect() |
253 */ |
308 */ |
254 QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offset) const |
309 QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offset, QGraphicsEffect::PixmapPadMode mode) const |
255 { |
310 { |
256 Q_D(const QGraphicsEffectSource); |
311 Q_D(const QGraphicsEffectSource); |
257 |
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 |
258 QPixmap pm; |
328 QPixmap pm; |
259 if (d->m_cachedSystem == system) |
329 if (d->m_cachedSystem == system && d->m_cachedMode == mode) |
260 QPixmapCache::find(d->m_cacheKey, &pm); |
330 QPixmapCache::find(d->m_cacheKey, &pm); |
261 |
331 |
262 if (pm.isNull()) { |
332 if (pm.isNull()) { |
263 pm = d->pixmap(system, &d->m_cachedOffset); |
333 pm = d->pixmap(system, &d->m_cachedOffset, mode); |
264 d->m_cachedSystem = system; |
334 d->m_cachedSystem = system; |
|
335 d->m_cachedMode = mode; |
265 |
336 |
266 d->invalidateCache(); |
337 d->invalidateCache(); |
267 d->m_cacheKey = QPixmapCache::insert(pm); |
338 d->m_cacheKey = QPixmapCache::insert(pm); |
268 } |
339 } |
269 |
340 |
401 function whenever you change any parameters that will cause the virtual |
518 function whenever you change any parameters that will cause the virtual |
402 boundingRectFor() function to return a different value. |
519 boundingRectFor() function to return a different value. |
403 |
520 |
404 This function will call update() if this is necessary. |
521 This function will call update() if this is necessary. |
405 |
522 |
406 \sa boundingRectFor(), boundingRect() |
523 \sa boundingRectFor(), boundingRect(), sourceBoundingRect() |
407 */ |
524 */ |
408 void QGraphicsEffect::updateBoundingRect() |
525 void QGraphicsEffect::updateBoundingRect() |
409 { |
526 { |
410 Q_D(QGraphicsEffect); |
527 Q_D(QGraphicsEffect); |
411 if (d->source) |
528 if (d->source) { |
412 d->source->d_func()->effectBoundingRectChanged(); |
529 d->source->d_func()->effectBoundingRectChanged(); |
413 } |
530 d->source->d_func()->invalidateCache(QGraphicsEffectSourcePrivate::EffectRectChanged); |
414 |
531 } |
415 /*! |
532 } |
416 \fn virtual void QGraphicsEffect::draw(QPainter *painter, |
533 |
417 QGraphicsEffectSource *source) = 0 |
534 /*! |
|
535 \fn virtual void QGraphicsEffect::draw(QPainter *painter) = 0 |
418 |
536 |
419 This pure virtual function draws the effect and is called whenever the |
537 This pure virtual function draws the effect and is called whenever the |
420 source() needs to be drawn. |
538 source needs to be drawn. |
421 |
539 |
422 Reimplement this function in a QGraphicsEffect subclass to provide the |
540 Reimplement this function in a QGraphicsEffect subclass to provide the |
423 effect's drawing implementation, using \a painter. The \a source parameter |
541 effect's drawing implementation, using \a painter. |
424 is provided for convenience; its value is the same as source(). |
|
425 |
542 |
426 For example: |
543 For example: |
427 |
544 |
428 \snippet doc/src/snippets/code/src_gui_effects_qgraphicseffect.cpp 1 |
545 \snippet doc/src/snippets/code/src_gui_effects_qgraphicseffect.cpp 1 |
429 |
546 |
430 This function should not be called explicitly by the user, since it is |
547 This function should not be called explicitly by the user, since it is |
431 meant for reimplementation purposes only. |
548 meant for reimplementation purposes only. |
432 |
|
433 \sa QGraphicsEffectSource |
|
434 */ |
549 */ |
435 |
550 |
436 /*! |
551 /*! |
437 \enum QGraphicsEffect::ChangeFlag |
552 \enum QGraphicsEffect::ChangeFlag |
438 |
553 |
456 { |
585 { |
457 Q_UNUSED(flags); |
586 Q_UNUSED(flags); |
458 } |
587 } |
459 |
588 |
460 /*! |
589 /*! |
461 \class QGraphicsGrayscaleEffect |
|
462 \brief The QGraphicsGrayscaleEffect class provides a grayscale effect. |
|
463 \since 4.6 |
|
464 |
|
465 A grayscale effect renders the source in shades of gray. |
|
466 |
|
467 \img graphicseffect-grayscale.png |
|
468 |
|
469 \sa QGraphicsDropShadowEffect, QGraphicsBlurEffect, QGraphicsPixelizeEffect, |
|
470 QGraphicsColorizeEffect, QGraphicsOpacityEffect |
|
471 */ |
|
472 |
|
473 /*! |
|
474 Constructs a new QGraphicsGrayscale instance. |
|
475 The \a parent parameter is passed to QGraphicsEffect's constructor. |
|
476 */ |
|
477 QGraphicsGrayscaleEffect::QGraphicsGrayscaleEffect(QObject *parent) |
|
478 : QGraphicsEffect(*new QGraphicsGrayscaleEffectPrivate, parent) |
|
479 { |
|
480 } |
|
481 |
|
482 /*! |
|
483 Destroys the effect. |
|
484 */ |
|
485 QGraphicsGrayscaleEffect::~QGraphicsGrayscaleEffect() |
|
486 { |
|
487 } |
|
488 |
|
489 |
|
490 /*! |
|
491 \property QGraphicsGrayscaleEffect::strength |
|
492 \brief the strength of the effect. |
|
493 |
|
494 By default, the strength is 1.0. |
|
495 A strength 0.0 equals to no effect, while 1.0 means full grayscale. |
|
496 */ |
|
497 qreal QGraphicsGrayscaleEffect::strength() const |
|
498 { |
|
499 Q_D(const QGraphicsGrayscaleEffect); |
|
500 return d->filter->strength(); |
|
501 } |
|
502 |
|
503 void QGraphicsGrayscaleEffect::setStrength(qreal strength) |
|
504 { |
|
505 Q_D(QGraphicsGrayscaleEffect); |
|
506 if (qFuzzyCompare(d->filter->strength(), strength)) |
|
507 return; |
|
508 |
|
509 d->filter->setStrength(strength); |
|
510 d->opaque = !qFuzzyIsNull(strength); |
|
511 update(); |
|
512 emit strengthChanged(strength); |
|
513 } |
|
514 |
|
515 /*! \fn void QGraphicsGrayscaleEffect::strengthChanged(qreal strength) |
|
516 This signal is emitted whenever setStrength() changes the grayscale |
|
517 strength property. \a strength contains the new strength value of |
|
518 the grayscale effect. |
|
519 */ |
|
520 |
|
521 /*! |
|
522 \reimp |
|
523 */ |
|
524 void QGraphicsGrayscaleEffect::draw(QPainter *painter, QGraphicsEffectSource *source) |
|
525 { |
|
526 Q_D(QGraphicsGrayscaleEffect); |
|
527 |
|
528 if (!d->opaque) { |
|
529 source->draw(painter); |
|
530 return; |
|
531 } |
|
532 |
|
533 QPoint offset; |
|
534 if (source->isPixmap()) { |
|
535 // No point in drawing in device coordinates (pixmap will be scaled anyways). |
|
536 const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset); |
|
537 d->filter->draw(painter, offset, pixmap); |
|
538 return; |
|
539 } |
|
540 |
|
541 // Draw pixmap in device coordinates to avoid pixmap scaling; |
|
542 const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); |
|
543 QTransform restoreTransform = painter->worldTransform(); |
|
544 painter->setWorldTransform(QTransform()); |
|
545 d->filter->draw(painter, offset, pixmap); |
|
546 painter->setWorldTransform(restoreTransform); |
|
547 |
|
548 } |
|
549 |
|
550 /*! |
|
551 \class QGraphicsColorizeEffect |
590 \class QGraphicsColorizeEffect |
552 \brief The QGraphicsColorizeEffect class provides a colorize effect. |
591 \brief The QGraphicsColorizeEffect class provides a colorize effect. |
553 \since 4.6 |
592 \since 4.6 |
554 |
593 |
555 A colorize effect renders the source with a tint of its color(). The color |
594 A colorize effect renders the source with a tint of its color(). The color |
641 */ |
679 */ |
642 |
680 |
643 /*! |
681 /*! |
644 \reimp |
682 \reimp |
645 */ |
683 */ |
646 void QGraphicsColorizeEffect::draw(QPainter *painter, QGraphicsEffectSource *source) |
684 void QGraphicsColorizeEffect::draw(QPainter *painter) |
647 { |
685 { |
648 Q_D(QGraphicsColorizeEffect); |
686 Q_D(QGraphicsColorizeEffect); |
649 |
687 |
650 if (!d->opaque) { |
688 if (!d->opaque) { |
651 source->draw(painter); |
689 drawSource(painter); |
652 return; |
690 return; |
653 } |
691 } |
654 |
692 |
655 QPoint offset; |
693 QPoint offset; |
656 if (source->isPixmap()) { |
694 if (sourceIsPixmap()) { |
657 // No point in drawing in device coordinates (pixmap will be scaled anyways). |
695 // No point in drawing in device coordinates (pixmap will be scaled anyways). |
658 const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset); |
696 const QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset, NoPad); |
659 d->filter->draw(painter, offset, pixmap); |
697 d->filter->draw(painter, offset, pixmap); |
660 return; |
698 return; |
661 } |
699 } |
662 |
700 |
663 // Draw pixmap in deviceCoordinates to avoid pixmap scaling. |
701 // Draw pixmap in deviceCoordinates to avoid pixmap scaling. |
664 const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); |
702 const QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates, &offset); |
665 QTransform restoreTransform = painter->worldTransform(); |
703 QTransform restoreTransform = painter->worldTransform(); |
666 painter->setWorldTransform(QTransform()); |
704 painter->setWorldTransform(QTransform()); |
667 d->filter->draw(painter, offset, pixmap); |
705 d->filter->draw(painter, offset, pixmap); |
668 painter->setWorldTransform(restoreTransform); |
706 painter->setWorldTransform(restoreTransform); |
669 } |
707 } |
670 |
708 |
671 /*! |
709 /*! |
672 \class QGraphicsPixelizeEffect |
|
673 \brief The QGraphicsPixelizeEffect class provides a pixelize effect. |
|
674 \since 4.6 |
|
675 |
|
676 A pixelize effect renders the source in lower resolution. This effect is |
|
677 useful for reducing details, like censorship. The resolution can be |
|
678 modified using the setPixelSize() function. |
|
679 |
|
680 By default, the pixel size is 3. |
|
681 |
|
682 \img graphicseffect-pixelize.png |
|
683 |
|
684 \sa QGraphicsDropShadowEffect, QGraphicsBlurEffect, QGraphicsGrayscaleEffect, |
|
685 QGraphicsColorizeEffect, QGraphicsOpacityEffect |
|
686 */ |
|
687 |
|
688 /*! |
|
689 Constructs a new QGraphicsPixelizeEffect instance. |
|
690 The \a parent parameter is passed to QGraphicsEffect's constructor. |
|
691 */ |
|
692 QGraphicsPixelizeEffect::QGraphicsPixelizeEffect(QObject *parent) |
|
693 : QGraphicsEffect(*new QGraphicsPixelizeEffectPrivate, parent) |
|
694 { |
|
695 } |
|
696 |
|
697 /*! |
|
698 Destroys the effect. |
|
699 */ |
|
700 QGraphicsPixelizeEffect::~QGraphicsPixelizeEffect() |
|
701 { |
|
702 } |
|
703 |
|
704 /*! |
|
705 \property QGraphicsPixelizeEffect::pixelSize |
|
706 \brief the size of a pixel in the effect. |
|
707 |
|
708 Setting the pixel size to 2 means two pixels in the source will be used to |
|
709 represent one pixel. Using a bigger size results in lower resolution. |
|
710 |
|
711 By default, the pixel size is 3. |
|
712 */ |
|
713 int QGraphicsPixelizeEffect::pixelSize() const |
|
714 { |
|
715 Q_D(const QGraphicsPixelizeEffect); |
|
716 return d->pixelSize; |
|
717 } |
|
718 |
|
719 void QGraphicsPixelizeEffect::setPixelSize(int size) |
|
720 { |
|
721 Q_D(QGraphicsPixelizeEffect); |
|
722 if (d->pixelSize == size) |
|
723 return; |
|
724 |
|
725 d->pixelSize = size; |
|
726 update(); |
|
727 emit pixelSizeChanged(size); |
|
728 } |
|
729 |
|
730 /*! |
|
731 \fn void QGraphicsPixelizeEffect::pixelSizeChanged(int size) |
|
732 |
|
733 This signal is emitted whenever the effect's pixel size changes. |
|
734 The \a size parameter holds the effect's new pixel size. |
|
735 */ |
|
736 |
|
737 static inline void pixelize(QImage *image, int pixelSize) |
|
738 { |
|
739 Q_ASSERT(pixelSize > 0); |
|
740 Q_ASSERT(image); |
|
741 int width = image->width(); |
|
742 int height = image->height(); |
|
743 for (int y = 0; y < height; y += pixelSize) { |
|
744 int ys = qMin(height - 1, y + pixelSize / 2); |
|
745 QRgb *sbuf = reinterpret_cast<QRgb*>(image->scanLine(ys)); |
|
746 for (int x = 0; x < width; x += pixelSize) { |
|
747 int xs = qMin(width - 1, x + pixelSize / 2); |
|
748 QRgb color = sbuf[xs]; |
|
749 for (int yi = 0; yi < qMin(pixelSize, height - y); ++yi) { |
|
750 QRgb *buf = reinterpret_cast<QRgb*>(image->scanLine(y + yi)); |
|
751 for (int xi = 0; xi < qMin(pixelSize, width - x); ++xi) |
|
752 buf[x + xi] = color; |
|
753 } |
|
754 } |
|
755 } |
|
756 } |
|
757 |
|
758 /*! |
|
759 \reimp |
|
760 */ |
|
761 void QGraphicsPixelizeEffect::draw(QPainter *painter, QGraphicsEffectSource *source) |
|
762 { |
|
763 Q_D(QGraphicsPixelizeEffect); |
|
764 if (d->pixelSize <= 0) { |
|
765 source->draw(painter); |
|
766 return; |
|
767 } |
|
768 |
|
769 QPoint offset; |
|
770 if (source->isPixmap()) { |
|
771 const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset); |
|
772 QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32); |
|
773 pixelize(&image, d->pixelSize); |
|
774 painter->drawImage(offset, image); |
|
775 return; |
|
776 } |
|
777 |
|
778 // Draw pixmap in device coordinates to avoid pixmap scaling. |
|
779 const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); |
|
780 |
|
781 // pixelize routine |
|
782 QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32); |
|
783 pixelize(&image, d->pixelSize); |
|
784 |
|
785 QTransform restoreTransform = painter->worldTransform(); |
|
786 painter->setWorldTransform(QTransform()); |
|
787 painter->drawImage(offset, image); |
|
788 painter->setWorldTransform(restoreTransform); |
|
789 } |
|
790 |
|
791 /*! |
|
792 \class QGraphicsBlurEffect |
710 \class QGraphicsBlurEffect |
793 \brief The QGraphicsBlurEffect class provides a blur effect. |
711 \brief The QGraphicsBlurEffect class provides a blur effect. |
794 \since 4.6 |
712 \since 4.6 |
795 |
713 |
796 A blur effect blurs the source. This effect is useful for reducing details, |
714 A blur effect blurs the source. This effect is useful for reducing details, |
797 such as when the source loses focus and you want to draw attention to other |
715 such as when the source loses focus and you want to draw attention to other |
798 elements. The level of detail can be modified using the setBlurRadius() |
716 elements. The level of detail can be modified using the setBlurRadius() |
799 function. Use setBlurHint() to choose the quality or performance blur hints. |
717 function. Use setBlurHints() to choose the blur hints. |
800 |
718 |
801 By default, the blur radius is 5 pixels. |
719 By default, the blur radius is 5 pixels. |
802 |
720 |
803 \img graphicseffect-blur.png |
721 \img graphicseffect-blur.png |
804 |
722 |
805 \sa QGraphicsDropShadowEffect, QGraphicsPixelizeEffect, QGraphicsGrayscaleEffect, |
723 \sa QGraphicsDropShadowEffect, QGraphicsColorizeEffect, QGraphicsOpacityEffect |
806 QGraphicsColorizeEffect, QGraphicsOpacityEffect |
724 */ |
807 */ |
725 |
|
726 /*! |
|
727 \enum QGraphicsBlurEffect::BlurHint |
|
728 \since 4.6 |
|
729 |
|
730 This enum describes the possible hints that can be used to control how |
|
731 blur effects are applied. The hints might not have an effect in all the |
|
732 paint engines. |
|
733 |
|
734 \value PerformanceHint Indicates that rendering performance is the most important factor, |
|
735 at the potential cost of lower quality. |
|
736 |
|
737 \value QualityHint Indicates that rendering quality is the most important factor, |
|
738 at the potential cost of lower performance. |
|
739 |
|
740 \value AnimationHint Indicates that the blur radius is going to be animated, hinting |
|
741 that the implementation can keep a cache of blurred verisons of the source. |
|
742 Do not use this hint if the source is going to be dynamically changing. |
|
743 |
|
744 \sa blurHints(), setBlurHints() |
|
745 */ |
|
746 |
808 |
747 |
809 /*! |
748 /*! |
810 Constructs a new QGraphicsBlurEffect instance. |
749 Constructs a new QGraphicsBlurEffect instance. |
811 The \a parent parameter is passed to QGraphicsEffect's constructor. |
750 The \a parent parameter is passed to QGraphicsEffect's constructor. |
812 */ |
751 */ |
813 QGraphicsBlurEffect::QGraphicsBlurEffect(QObject *parent) |
752 QGraphicsBlurEffect::QGraphicsBlurEffect(QObject *parent) |
814 : QGraphicsEffect(*new QGraphicsBlurEffectPrivate, parent) |
753 : QGraphicsEffect(*new QGraphicsBlurEffectPrivate, parent) |
815 { |
754 { |
816 Q_D(QGraphicsBlurEffect); |
755 Q_D(QGraphicsBlurEffect); |
817 d->filter->setBlurHint(Qt::PerformanceHint); |
756 d->filter->setBlurHints(QGraphicsBlurEffect::PerformanceHint); |
818 } |
757 } |
819 |
758 |
820 /*! |
759 /*! |
821 Destroys the effect. |
760 Destroys the effect. |
822 */ |
761 */ |
831 Using a smaller radius results in a sharper appearance, whereas a bigger |
770 Using a smaller radius results in a sharper appearance, whereas a bigger |
832 radius results in a more blurred appearance. |
771 radius results in a more blurred appearance. |
833 |
772 |
834 By default, the blur radius is 5 pixels. |
773 By default, the blur radius is 5 pixels. |
835 */ |
774 */ |
836 int QGraphicsBlurEffect::blurRadius() const |
775 qreal QGraphicsBlurEffect::blurRadius() const |
837 { |
776 { |
838 Q_D(const QGraphicsBlurEffect); |
777 Q_D(const QGraphicsBlurEffect); |
839 return d->filter->radius(); |
778 return d->filter->radius(); |
840 } |
779 } |
841 |
780 |
842 void QGraphicsBlurEffect::setBlurRadius(int radius) |
781 void QGraphicsBlurEffect::setBlurRadius(qreal radius) |
843 { |
782 { |
844 Q_D(QGraphicsBlurEffect); |
783 Q_D(QGraphicsBlurEffect); |
845 if (d->filter->radius() == radius) |
784 if (qFuzzyCompare(d->filter->radius(), radius)) |
846 return; |
785 return; |
847 |
786 |
848 d->filter->setRadius(radius); |
787 d->filter->setRadius(radius); |
849 updateBoundingRect(); |
788 updateBoundingRect(); |
850 emit blurRadiusChanged(radius); |
789 emit blurRadiusChanged(radius); |
851 } |
790 } |
852 |
791 |
853 /*! |
792 /*! |
854 \fn void QGraphicsBlurEffect::blurRadiusChanged(int radius) |
793 \fn void QGraphicsBlurEffect::blurRadiusChanged(qreal radius) |
855 |
794 |
856 This signal is emitted whenever the effect's blur radius changes. |
795 This signal is emitted whenever the effect's blur radius changes. |
857 The \a radius parameter holds the effect's new blur radius. |
796 The \a radius parameter holds the effect's new blur radius. |
858 */ |
797 */ |
859 |
798 |
860 /*! |
799 /*! |
861 \property QGraphicsBlurEffect::blurHint |
800 \property QGraphicsBlurEffect::blurHints |
862 \brief the blur hint of the effect. |
801 \brief the blur hint of the effect. |
863 |
802 |
864 Use the Qt::PerformanceHint hint to say that you want a faster blur, |
803 Use the PerformanceHint hint to say that you want a faster blur, |
865 and the Qt::QualityHint hint to say that you prefer a higher quality blur. |
804 the QualityHint hint to say that you prefer a higher quality blur, |
866 |
805 or the AnimationHint when you want to animate the blur radius. |
867 When animating the blur radius it's recommended to use Qt::PerformanceHint. |
806 |
868 |
807 By default, the blur hint is PerformanceHint. |
869 By default, the blur hint is Qt::PerformanceHint. |
808 */ |
870 */ |
809 QGraphicsBlurEffect::BlurHints QGraphicsBlurEffect::blurHints() const |
871 Qt::RenderHint QGraphicsBlurEffect::blurHint() const |
|
872 { |
810 { |
873 Q_D(const QGraphicsBlurEffect); |
811 Q_D(const QGraphicsBlurEffect); |
874 return d->filter->blurHint(); |
812 return d->filter->blurHints(); |
875 } |
813 } |
876 |
814 |
877 void QGraphicsBlurEffect::setBlurHint(Qt::RenderHint hint) |
815 void QGraphicsBlurEffect::setBlurHints(QGraphicsBlurEffect::BlurHints hints) |
878 { |
816 { |
879 Q_D(QGraphicsBlurEffect); |
817 Q_D(QGraphicsBlurEffect); |
880 if (d->filter->blurHint() == hint) |
818 if (d->filter->blurHints() == hints) |
881 return; |
819 return; |
882 |
820 |
883 d->filter->setBlurHint(hint); |
821 d->filter->setBlurHints(hints); |
884 emit blurHintChanged(hint); |
822 emit blurHintsChanged(hints); |
885 } |
823 } |
886 |
824 |
887 /*! |
825 /*! |
888 \fn void QGraphicsBlurEffect::blurHintChanged(Qt::RenderHint hint) |
826 \fn void QGraphicsBlurEffect::blurHintsChanged(QGraphicsBlurEffect::BlurHints hints) |
889 |
827 |
890 This signal is emitted whenever the effect's blur hint changes. |
828 This signal is emitted whenever the effect's blur hints changes. |
891 The \a hint parameter holds the effect's new blur hint. |
829 The \a hints parameter holds the effect's new blur hints. |
892 */ |
830 */ |
893 |
831 |
894 /*! |
832 /*! |
895 \reimp |
833 \reimp |
896 */ |
834 */ |
1219 */ |
1162 */ |
1220 |
1163 |
1221 /*! |
1164 /*! |
1222 \reimp |
1165 \reimp |
1223 */ |
1166 */ |
1224 void QGraphicsOpacityEffect::draw(QPainter *painter, QGraphicsEffectSource *source) |
1167 void QGraphicsOpacityEffect::draw(QPainter *painter) |
1225 { |
1168 { |
1226 Q_D(QGraphicsOpacityEffect); |
1169 Q_D(QGraphicsOpacityEffect); |
1227 |
1170 |
1228 // Transparent; nothing to draw. |
1171 // Transparent; nothing to draw. |
1229 if (d->isFullyTransparent) |
1172 if (d->isFullyTransparent) |
1230 return; |
1173 return; |
1231 |
1174 |
1232 // Opaque; draw directly without going through a pixmap. |
1175 // Opaque; draw directly without going through a pixmap. |
1233 if (d->isFullyOpaque && !d->hasOpacityMask) { |
1176 if (d->isFullyOpaque && !d->hasOpacityMask) { |
1234 source->draw(painter); |
1177 drawSource(painter); |
1235 return; |
1178 return; |
1236 } |
1179 } |
|
1180 |
|
1181 QPoint offset; |
|
1182 Qt::CoordinateSystem system = sourceIsPixmap() ? Qt::LogicalCoordinates : Qt::DeviceCoordinates; |
|
1183 QPixmap pixmap = sourcePixmap(system, &offset, QGraphicsEffect::NoPad); |
|
1184 if (pixmap.isNull()) |
|
1185 return; |
1237 |
1186 |
1238 painter->save(); |
1187 painter->save(); |
1239 painter->setOpacity(d->opacity); |
1188 painter->setOpacity(d->opacity); |
1240 |
1189 |
1241 QPoint offset; |
1190 if (d->hasOpacityMask) { |
1242 if (source->isPixmap()) { |
1191 QPainter pixmapPainter(&pixmap); |
1243 // No point in drawing in device coordinates (pixmap will be scaled anyways). |
1192 pixmapPainter.setRenderHints(painter->renderHints()); |
1244 if (!d->hasOpacityMask) { |
1193 pixmapPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn); |
1245 const QPixmap pixmap = source->pixmap(Qt::LogicalCoordinates, &offset); |
1194 if (system == Qt::DeviceCoordinates) { |
1246 painter->drawPixmap(offset, pixmap); |
1195 QTransform worldTransform = painter->worldTransform(); |
|
1196 worldTransform *= QTransform::fromTranslate(-offset.x(), -offset.y()); |
|
1197 pixmapPainter.setWorldTransform(worldTransform); |
|
1198 pixmapPainter.fillRect(sourceBoundingRect(), d->opacityMask); |
1247 } else { |
1199 } else { |
1248 QRect srcBrect = source->boundingRect().toAlignedRect(); |
|
1249 offset = srcBrect.topLeft(); |
|
1250 QPixmap pixmap(srcBrect.size()); |
|
1251 pixmap.fill(Qt::transparent); |
|
1252 |
|
1253 QPainter pixmapPainter(&pixmap); |
|
1254 pixmapPainter.setRenderHints(painter->renderHints()); |
|
1255 pixmapPainter.translate(-offset); |
1200 pixmapPainter.translate(-offset); |
1256 source->draw(&pixmapPainter); |
1201 pixmapPainter.fillRect(pixmap.rect(), d->opacityMask); |
1257 pixmapPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn); |
|
1258 pixmapPainter.fillRect(srcBrect, d->opacityMask); |
|
1259 pixmapPainter.end(); |
|
1260 |
|
1261 painter->drawPixmap(offset, pixmap); |
|
1262 } |
|
1263 } else { |
|
1264 // Draw pixmap in device coordinates to avoid pixmap scaling; |
|
1265 if (!d->hasOpacityMask) { |
|
1266 const QPixmap pixmap = source->pixmap(Qt::DeviceCoordinates, &offset); |
|
1267 painter->setWorldTransform(QTransform()); |
|
1268 painter->drawPixmap(offset, pixmap); |
|
1269 } else { |
|
1270 QTransform worldTransform = painter->worldTransform(); |
|
1271 |
|
1272 // Calculate source bounding rect in logical and device coordinates. |
|
1273 QRectF srcBrect = source->boundingRect(); |
|
1274 QRect srcDeviceBrect = worldTransform.mapRect(srcBrect).toAlignedRect(); |
|
1275 srcDeviceBrect &= source->deviceRect(); |
|
1276 |
|
1277 offset = srcDeviceBrect.topLeft(); |
|
1278 worldTransform *= QTransform::fromTranslate(-srcDeviceBrect.x(), -srcDeviceBrect.y()); |
|
1279 |
|
1280 QPixmap pixmap(srcDeviceBrect.size()); |
|
1281 pixmap.fill(Qt::transparent); |
|
1282 |
|
1283 QPainter pixmapPainter(&pixmap); |
|
1284 pixmapPainter.setRenderHints(painter->renderHints()); |
|
1285 pixmapPainter.setWorldTransform(worldTransform); |
|
1286 source->draw(&pixmapPainter); |
|
1287 pixmapPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn); |
|
1288 pixmapPainter.fillRect(srcBrect, d->opacityMask); |
|
1289 pixmapPainter.end(); |
|
1290 |
|
1291 painter->setWorldTransform(QTransform()); |
|
1292 painter->drawPixmap(offset, pixmap); |
|
1293 } |
1202 } |
1294 } |
1203 } |
1295 |
1204 |
|
1205 if (system == Qt::DeviceCoordinates) |
|
1206 painter->setWorldTransform(QTransform()); |
|
1207 |
|
1208 painter->drawPixmap(offset, pixmap); |
1296 painter->restore(); |
1209 painter->restore(); |
1297 } |
1210 } |
1298 |
1211 |
1299 /*! |
|
1300 \class QGraphicsBloomEffect |
|
1301 \brief The QGraphicsBloomEffect class provides a bloom/glow effect. |
|
1302 \since 4.6 |
|
1303 |
|
1304 A bloom/glow effect adds fringes of light around bright areas in the source. |
|
1305 |
|
1306 \img graphicseffect-bloom.png |
|
1307 |
|
1308 \sa QGraphicsDropShadowEffect, QGraphicsBlurEffect, QGraphicsPixelizeEffect, |
|
1309 QGraphicsGrayscaleEffect, QGraphicsColorizeEffect |
|
1310 */ |
|
1311 |
|
1312 /*! |
|
1313 Constructs a new QGraphicsBloomEffect instance. |
|
1314 The \a parent parameter is passed to QGraphicsEffect's constructor. |
|
1315 */ |
|
1316 QGraphicsBloomEffect::QGraphicsBloomEffect(QObject *parent) |
|
1317 : QGraphicsEffect(*new QGraphicsBloomEffectPrivate, parent) |
|
1318 { |
|
1319 Q_D(QGraphicsBloomEffect); |
|
1320 for (int i = 0; i < 256; ++i) |
|
1321 d->colorTable[i] = qMin(i + d->brightness, 255); |
|
1322 } |
|
1323 |
|
1324 /*! |
|
1325 Destroys the effect. |
|
1326 */ |
|
1327 QGraphicsBloomEffect::~QGraphicsBloomEffect() |
|
1328 { |
|
1329 } |
|
1330 |
|
1331 /*! |
|
1332 \reimp |
|
1333 */ |
|
1334 QRectF QGraphicsBloomEffect::boundingRectFor(const QRectF &rect) const |
|
1335 { |
|
1336 Q_D(const QGraphicsBloomEffect); |
|
1337 const qreal delta = d->blurFilter.radius() * 2; |
|
1338 return rect.adjusted(-delta, -delta, delta, delta); |
|
1339 } |
|
1340 |
|
1341 /*! |
|
1342 \property QGraphicsBloomEffect::blurRadius |
|
1343 \brief the blur radius in pixels of the effect. |
|
1344 |
|
1345 Using a smaller radius results in a sharper appearance, whereas a bigger |
|
1346 radius results in a more blurred appearance. |
|
1347 |
|
1348 By default, the blur radius is 5 pixels. |
|
1349 |
|
1350 \sa strength(), brightness() |
|
1351 */ |
|
1352 int QGraphicsBloomEffect::blurRadius() const |
|
1353 { |
|
1354 Q_D(const QGraphicsBloomEffect); |
|
1355 return d->blurFilter.radius(); |
|
1356 } |
|
1357 |
|
1358 void QGraphicsBloomEffect::setBlurRadius(int radius) |
|
1359 { |
|
1360 Q_D(QGraphicsBloomEffect); |
|
1361 if (d->blurFilter.radius() == radius) |
|
1362 return; |
|
1363 |
|
1364 d->blurFilter.setRadius(radius); |
|
1365 updateBoundingRect(); |
|
1366 emit blurRadiusChanged(radius); |
|
1367 } |
|
1368 |
|
1369 /*! |
|
1370 \fn void QGraphicsBloomEffect::blurRadiusChanged(int blurRadius) |
|
1371 |
|
1372 This signal is emitted whenever the effect's blur radius changes. |
|
1373 The \a blurRadius parameter holds the effect's new blur radius. |
|
1374 */ |
|
1375 |
|
1376 /*! |
|
1377 \property QGraphicsBloomEffect::blurHint |
|
1378 \brief the blur hint of the effect. |
|
1379 |
|
1380 Use the Qt::PerformanceHint hint to say that you want a faster blur, |
|
1381 and the Qt::QualityHint hint to say that you prefer a higher quality blur. |
|
1382 |
|
1383 When animating the blur radius it's recommended to use Qt::PerformanceHint. |
|
1384 |
|
1385 By default, the blur hint is Qt::PerformanceHint. |
|
1386 */ |
|
1387 Qt::RenderHint QGraphicsBloomEffect::blurHint() const |
|
1388 { |
|
1389 Q_D(const QGraphicsBloomEffect); |
|
1390 return d->blurFilter.blurHint(); |
|
1391 } |
|
1392 |
|
1393 void QGraphicsBloomEffect::setBlurHint(Qt::RenderHint hint) |
|
1394 { |
|
1395 Q_D(QGraphicsBloomEffect); |
|
1396 if (d->blurFilter.blurHint() == hint) |
|
1397 return; |
|
1398 |
|
1399 d->blurFilter.setBlurHint(hint); |
|
1400 emit blurHintChanged(hint); |
|
1401 } |
|
1402 |
|
1403 /*! |
|
1404 \fn void QGraphicsBloomEffect::blurHintChanged(Qt::RenderHint hint) |
|
1405 |
|
1406 This signal is emitted whenever the effect's blur hint changes. |
|
1407 The \a hint parameter holds the effect's new blur hint. |
|
1408 */ |
|
1409 |
|
1410 /*! |
|
1411 \property QGraphicsBloomEffect::brightness |
|
1412 \brief the brightness of the glow. |
|
1413 |
|
1414 The value should be in the range of 0 to 255, where 0 is dark |
|
1415 and 255 is bright. |
|
1416 |
|
1417 By default, the brightness is 70. |
|
1418 |
|
1419 \sa strength(), blurRadius() |
|
1420 */ |
|
1421 int QGraphicsBloomEffect::brightness() const |
|
1422 { |
|
1423 Q_D(const QGraphicsBloomEffect); |
|
1424 return d->brightness; |
|
1425 } |
|
1426 |
|
1427 void QGraphicsBloomEffect::setBrightness(int brightness) |
|
1428 { |
|
1429 Q_D(QGraphicsBloomEffect); |
|
1430 brightness = qBound(0, brightness, 255); |
|
1431 if (d->brightness == brightness) |
|
1432 return; |
|
1433 |
|
1434 d->brightness = brightness; |
|
1435 for (int i = 0; i < 256; ++i) |
|
1436 d->colorTable[i] = qMin(i + brightness, 255); |
|
1437 |
|
1438 update(); |
|
1439 emit brightnessChanged(brightness); |
|
1440 } |
|
1441 |
|
1442 /*! |
|
1443 \fn void QGraphicsBloomEffect::brightnessChanged(int brightness) |
|
1444 |
|
1445 This signal is emitted whenever the effect's brightness changes. |
|
1446 The \a brightness parameter holds the effect's new brightness. |
|
1447 */ |
|
1448 |
|
1449 /*! |
|
1450 \property QGraphicsBloomEffect::strength |
|
1451 \brief the strength of the effect. |
|
1452 |
|
1453 A strength 0.0 equals to no effect, while 1.0 means maximum glow. |
|
1454 |
|
1455 By default, the strength is 0.7. |
|
1456 */ |
|
1457 qreal QGraphicsBloomEffect::strength() const |
|
1458 { |
|
1459 Q_D(const QGraphicsBloomEffect); |
|
1460 return d->strength; |
|
1461 } |
|
1462 |
|
1463 void QGraphicsBloomEffect::setStrength(qreal strength) |
|
1464 { |
|
1465 Q_D(QGraphicsBloomEffect); |
|
1466 strength = qBound(qreal(0.0), strength, qreal(1.0)); |
|
1467 if (qFuzzyCompare(d->strength, strength)) |
|
1468 return; |
|
1469 |
|
1470 d->strength = strength; |
|
1471 update(); |
|
1472 emit strengthChanged(strength); |
|
1473 } |
|
1474 |
|
1475 /*! |
|
1476 \fn void QGraphicsBloomEffect::strengthChanged(qreal strength) |
|
1477 |
|
1478 This signal is emitted whenever the effect's strength changes. |
|
1479 The \a strength parameter holds the effect's new strength. |
|
1480 */ |
|
1481 |
|
1482 extern QPixmap qt_toRasterPixmap(const QPixmap &pixmap); |
|
1483 |
|
1484 /*! |
|
1485 \reimp |
|
1486 */ |
|
1487 void QGraphicsBloomEffect::draw(QPainter *painter, QGraphicsEffectSource *source) |
|
1488 { |
|
1489 Q_D(QGraphicsBloomEffect); |
|
1490 if (d->strength < 0.001) { |
|
1491 source->draw(painter); |
|
1492 return; |
|
1493 } |
|
1494 |
|
1495 QPoint offset; |
|
1496 QPixmap pixmap = qt_toRasterPixmap(source->pixmap(Qt::DeviceCoordinates, &offset)); |
|
1497 |
|
1498 // Blur. |
|
1499 QImage overlay(pixmap.size(), QImage::Format_ARGB32_Premultiplied); |
|
1500 overlay.fill(0); |
|
1501 |
|
1502 QPainter blurPainter(&overlay); |
|
1503 d->blurFilter.draw(&blurPainter, QPointF(), pixmap); |
|
1504 blurPainter.end(); |
|
1505 |
|
1506 // Brighten. |
|
1507 const int numBits = overlay.width() * overlay.height(); |
|
1508 QRgb *bits = reinterpret_cast<QRgb *>(overlay.bits()); |
|
1509 for (int i = 0; i < numBits; ++i) { |
|
1510 const QRgb pixel = INV_PREMUL(bits[i]); |
|
1511 bits[i] = PREMUL(qRgba(d->colorTable[qRed(pixel)], d->colorTable[qGreen(pixel)], |
|
1512 d->colorTable[qBlue(pixel)], qAlpha(pixel))); |
|
1513 } |
|
1514 |
|
1515 // Composite. |
|
1516 QPainter compPainter(&pixmap); |
|
1517 compPainter.setCompositionMode(QPainter::CompositionMode_Overlay); |
|
1518 compPainter.setOpacity(d->strength); |
|
1519 compPainter.drawImage(0, 0, overlay); |
|
1520 compPainter.end(); |
|
1521 |
|
1522 QTransform restoreTransform = painter->worldTransform(); |
|
1523 painter->setWorldTransform(QTransform()); |
|
1524 painter->drawPixmap(offset, pixmap); |
|
1525 painter->setWorldTransform(restoreTransform); |
|
1526 } |
|
1527 |
1212 |
1528 QT_END_NAMESPACE |
1213 QT_END_NAMESPACE |
1529 |
1214 |
|
1215 #endif //QT_NO_GRAPHICSEFFECT |