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
This commit is contained in:
Marco Martin 2008-09-30 16:15:00 +00:00
parent 266765dd9b
commit c1a7cb7ce7
3 changed files with 116 additions and 12 deletions

View File

@ -22,6 +22,7 @@
#include <QImage>
#include <QPainter>
#include <QPaintEngine>
#include <QPixmap>
#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

View File

@ -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

View File

@ -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);
}
}
}