From c1a7cb7ce7c4c8a2fb3efc1cd1688794c5a66c18 Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Tue, 30 Sep 2008 16:15:00 +0000 Subject: [PATCH] pixmap fading transition effect in paintutils taken from KFileItemDelegate::Private::transition() now icon widget uses it svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=866344 --- paintutils.cpp | 105 +++++++++++++++++++++++++++++++++++++++++++++++ paintutils.h | 5 +++ widgets/icon.cpp | 18 +++----- 3 files changed, 116 insertions(+), 12 deletions(-) diff --git a/paintutils.cpp b/paintutils.cpp index b8fa88b26..c9941d1b2 100644 --- a/paintutils.cpp +++ b/paintutils.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include "effects/blur.cpp" @@ -113,6 +114,110 @@ QPainterPath roundedRectangle(const QRectF& rect, qreal radius) return path; } +QPixmap transition(const QPixmap &from, const QPixmap &to, qreal amount) +{ + int value = int(0xff * amount); + + if (value == 0) { + return from; + } else if (value == 1) { + return to; + } + + QColor color; + color.setAlphaF(amount); + + // If the native paint engine supports Porter/Duff compositing and CompositionMode_Plus + if (from.paintEngine()->hasFeature(QPaintEngine::PorterDuff) && + from.paintEngine()->hasFeature(QPaintEngine::BlendModes)) { + QPixmap under = from; + QPixmap over = to; + + QPainter p; + p.begin(&over); + p.setCompositionMode(QPainter::CompositionMode_DestinationIn); + p.fillRect(over.rect(), color); + p.end(); + + p.begin(&under); + p.setCompositionMode(QPainter::CompositionMode_DestinationOut); + p.fillRect(under.rect(), color); + p.setCompositionMode(QPainter::CompositionMode_Plus); + p.drawPixmap(0, 0, over); + p.end(); + + return under; + } +#if defined(Q_WS_X11) && defined(HAVE_XRENDER) + // We have Xrender support + else if (from.paintEngine()->hasFeature(QPaintEngine::PorterDuff)) { + // QX11PaintEngine doesn't implement CompositionMode_Plus in Qt 4.3, + // which we need to be able to do a transition from one pixmap to + // another. + // + // In order to avoid the overhead of converting the pixmaps to images + // and doing the operation entirely in software, this function has a + // specialized path for X11 that uses Xrender directly to do the + // transition. This operation can be fully accelerated in HW. + // + // This specialization can be removed when QX11PaintEngine supports + // CompositionMode_Plus. + QPixmap source(to), destination(from); + + source.detach(); + destination.detach(); + + Display *dpy = QX11Info::display(); + + XRenderPictFormat *format = XRenderFindStandardFormat(dpy, PictStandardA8); + XRenderPictureAttributes pa; + pa.repeat = 1; // RepeatNormal + + // Create a 1x1 8 bit repeating alpha picture + Pixmap pixmap = XCreatePixmap(dpy, destination.handle(), 1, 1, 8); + Picture alpha = XRenderCreatePicture(dpy, pixmap, format, CPRepeat, &pa); + XFreePixmap(dpy, pixmap); + + // Fill the alpha picture with the opacity value + XRenderColor xcolor; + xcolor.alpha = quint16(0xffff * amount); + XRenderFillRectangle(dpy, PictOpSrc, alpha, &xcolor, 0, 0, 1, 1); + + // Reduce the alpha of the destination with 1 - opacity + XRenderComposite(dpy, PictOpOutReverse, alpha, None, destination.x11PictureHandle(), + 0, 0, 0, 0, 0, 0, destination.width(), destination.height()); + + // Add source * opacity to the destination + XRenderComposite(dpy, PictOpAdd, source.x11PictureHandle(), alpha, + destination.x11PictureHandle(), + 0, 0, 0, 0, 0, 0, destination.width(), destination.height()); + + XRenderFreePicture(dpy, alpha); + return destination; + } +#endif + else { + // Fall back to using QRasterPaintEngine to do the transition. + QImage under = from.toImage(); + QImage over = to.toImage(); + + QPainter p; + p.begin(&over); + p.setCompositionMode(QPainter::CompositionMode_DestinationIn); + p.fillRect(over.rect(), color); + p.end(); + + p.begin(&under); + p.setCompositionMode(QPainter::CompositionMode_DestinationOut); + p.fillRect(under.rect(), color); + p.setCompositionMode(QPainter::CompositionMode_Plus); + p.drawImage(0, 0, over); + p.end(); + + return QPixmap::fromImage(under); + } +} + } // PaintUtils namespace } // Plasma namespace diff --git a/paintutils.h b/paintutils.h index 986e2e3f2..bda6cbe64 100644 --- a/paintutils.h +++ b/paintutils.h @@ -58,6 +58,11 @@ PLASMA_EXPORT QPixmap shadowText(QString text, */ PLASMA_EXPORT QPainterPath roundedRectangle(const QRectF& rect, qreal radius); +/** + * Blends a pixmap into another + */ +PLASMA_EXPORT QPixmap transition(const QPixmap &from, const QPixmap &to, qreal amount); + } // PaintUtils namespace } // Plasma namespace diff --git a/widgets/icon.cpp b/widgets/icon.cpp index ca144a094..46a8aadee 100644 --- a/widgets/icon.cpp +++ b/widgets/icon.cpp @@ -509,16 +509,6 @@ void Icon::hoverEffect(bool show) d->states |= IconPrivate::HoverState; } - if (d->m_hoverAnimId == -1 && !d->drawBg) { - // we do this only when we don't do the anim, because - // this gets set at animation end when we are animating - if (!show) { - d->states &= ~IconPrivate::HoverState; - } - - return; - } - d->m_fadeIn = show; const int FadeInDuration = 150; @@ -614,13 +604,17 @@ QPixmap IconPrivate::decoration(const QStyleOptionGraphicsItem *option, bool use // We disable the iconeffect here since we cannot get it into sync with // the fade animation. TODO: Enable it when animations are switched off - if (!result.isNull() && useHoverEffect && !drawBg) { + if (!result.isNull() && useHoverEffect) { KIconEffect *effect = KIconLoader::global()->iconEffect(); // Note that in KIconLoader terminology, active = hover. // We're assuming that the icon group is desktop/filemanager, since this // is KFileItemDelegate. if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) { - result = effect->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState); + if (qFuzzyCompare(qreal(1.0), m_hoverAlpha)) { + result = effect->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState); + } else { + result = PaintUtils::transition(result, effect->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState), m_hoverAlpha); + } } }