KDEUI
kfadewidgeteffect.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE project 00002 Copyright (C) 2008 Matthias Kretz <kretz@kde.org> 00003 Copyright (C) 2008 Rafael Fernández López <ereslibre@kde.org> 00004 00005 This program is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) version 3. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 00020 */ 00021 00022 #include "kfadewidgeteffect.h" 00023 #include "kfadewidgeteffect_p.h" 00024 00025 #include <config.h> // for HAVE_XRENDER 00026 00027 #include <QtCore/QEvent> 00028 #include <QtGui/QPaintEngine> 00029 #include <QtGui/QPainter> 00030 00031 #include <kglobalsettings.h> 00032 00033 #if defined(Q_WS_X11) && defined(HAVE_XRENDER) 00034 # include <X11/Xlib.h> 00035 # include <X11/extensions/Xrender.h> 00036 # include <QX11Info> 00037 # undef KeyPress 00038 # undef FocusOut 00039 #endif 00040 00041 KFadeWidgetEffectPrivate::KFadeWidgetEffectPrivate(QWidget *_destWidget) 00042 : destWidget(_destWidget), disabled(false) 00043 { 00044 } 00045 00046 // Code from KFileItemDelegate (Author: Frederik Höglund) 00047 // Fast transitions. Read: 00048 // http://techbase.kde.org/Development/Tutorials/Graphics/Performance 00049 // for further information on why not use setOpacity. 00050 QPixmap KFadeWidgetEffectPrivate::transition(const QPixmap &from, const QPixmap &to, qreal amount) const 00051 { 00052 const int value = int(0xff * amount); 00053 00054 if (value == 0) 00055 return from; 00056 00057 if (value == 1) 00058 return to; 00059 00060 QColor color; 00061 color.setAlphaF(amount); 00062 00063 // If the native paint engine supports Porter/Duff compositing and CompositionMode_Plus 00064 if (from.paintEngine()->hasFeature(QPaintEngine::PorterDuff) && 00065 from.paintEngine()->hasFeature(QPaintEngine::BlendModes)) 00066 { 00067 QPixmap under = from; 00068 QPixmap over = to; 00069 00070 QPainter p; 00071 p.begin(&over); 00072 p.setCompositionMode(QPainter::CompositionMode_DestinationIn); 00073 p.fillRect(over.rect(), color); 00074 p.end(); 00075 00076 p.begin(&under); 00077 p.setCompositionMode(QPainter::CompositionMode_DestinationOut); 00078 p.fillRect(under.rect(), color); 00079 p.setCompositionMode(QPainter::CompositionMode_Plus); 00080 p.drawPixmap(0, 0, over); 00081 p.end(); 00082 00083 return under; 00084 } 00085 #if defined(Q_WS_X11) && defined(HAVE_XRENDER) 00086 else if (from.paintEngine()->hasFeature(QPaintEngine::PorterDuff)) // We have Xrender support 00087 { 00088 // QX11PaintEngine doesn't implement CompositionMode_Plus in Qt 4.3, 00089 // which we need to be able to do a transition from one pixmap to 00090 // another. 00091 // 00092 // In order to avoid the overhead of converting the pixmaps to images 00093 // and doing the operation entirely in software, this function has a 00094 // specialized path for X11 that uses Xrender directly to do the 00095 // transition. This operation can be fully accelerated in HW. 00096 // 00097 // This specialization can be removed when QX11PaintEngine supports 00098 // CompositionMode_Plus. 00099 QPixmap source(to), destination(from); 00100 00101 source.detach(); 00102 destination.detach(); 00103 00104 Display *dpy = QX11Info::display(); 00105 00106 XRenderPictFormat *format = XRenderFindStandardFormat(dpy, PictStandardA8); 00107 XRenderPictureAttributes pa; 00108 pa.repeat = 1; // RepeatNormal 00109 00110 // Create a 1x1 8 bit repeating alpha picture 00111 Pixmap pixmap = XCreatePixmap(dpy, destination.handle(), 1, 1, 8); 00112 Picture alpha = XRenderCreatePicture(dpy, pixmap, format, CPRepeat, &pa); 00113 XFreePixmap(dpy, pixmap); 00114 00115 // Fill the alpha picture with the opacity value 00116 XRenderColor xcolor; 00117 xcolor.alpha = quint16(0xffff * amount); 00118 XRenderFillRectangle(dpy, PictOpSrc, alpha, &xcolor, 0, 0, 1, 1); 00119 00120 // Reduce the alpha of the destination with 1 - opacity 00121 XRenderComposite(dpy, PictOpOutReverse, alpha, None, destination.x11PictureHandle(), 00122 0, 0, 0, 0, 0, 0, destination.width(), destination.height()); 00123 00124 // Add source * opacity to the destination 00125 XRenderComposite(dpy, PictOpAdd, source.x11PictureHandle(), alpha, 00126 destination.x11PictureHandle(), 00127 0, 0, 0, 0, 0, 0, destination.width(), destination.height()); 00128 00129 XRenderFreePicture(dpy, alpha); 00130 return destination; 00131 } 00132 #endif 00133 else 00134 { 00135 // Fall back to using QRasterPaintEngine to do the transition. 00136 QImage under = from.toImage(); 00137 QImage over = to.toImage(); 00138 00139 QPainter p; 00140 p.begin(&over); 00141 p.setCompositionMode(QPainter::CompositionMode_DestinationIn); 00142 p.fillRect(over.rect(), color); 00143 p.end(); 00144 00145 p.begin(&under); 00146 p.setCompositionMode(QPainter::CompositionMode_DestinationOut); 00147 p.fillRect(under.rect(), color); 00148 p.setCompositionMode(QPainter::CompositionMode_Plus); 00149 p.drawImage(0, 0, over); 00150 p.end(); 00151 00152 return QPixmap::fromImage(under); 00153 } 00154 } 00155 00156 KFadeWidgetEffect::KFadeWidgetEffect(QWidget *destWidget) 00157 : QWidget(destWidget ? destWidget->parentWidget() : 0), 00158 d_ptr(new KFadeWidgetEffectPrivate(destWidget)) 00159 { 00160 Q_D(KFadeWidgetEffect); 00161 d->q_ptr = this; 00162 Q_ASSERT(destWidget && destWidget->parentWidget()); 00163 if (!destWidget || !destWidget->parentWidget() || !destWidget->isVisible() || 00164 !(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects)) { 00165 d->disabled = true; 00166 hide(); 00167 return; 00168 } 00169 setGeometry(QRect(destWidget->mapTo(parentWidget(), QPoint(0, 0)), destWidget->size())); 00170 d->oldPixmap = QPixmap::grabWidget(destWidget); 00171 d->timeLine.setFrameRange(0, 255); 00172 d->timeLine.setCurveShape(QTimeLine::EaseOutCurve); 00173 connect(&d->timeLine, SIGNAL(finished()), SLOT(finished())); 00174 connect(&d->timeLine, SIGNAL(frameChanged(int)), SLOT(repaint())); 00175 show(); 00176 } 00177 00178 KFadeWidgetEffect::~KFadeWidgetEffect() 00179 { 00180 delete d_ptr; 00181 } 00182 00183 void KFadeWidgetEffectPrivate::finished() 00184 { 00185 Q_Q(KFadeWidgetEffect); 00186 destWidget->setUpdatesEnabled(false); 00187 q->hide(); 00188 q->deleteLater(); 00189 destWidget->setUpdatesEnabled(true); 00190 } 00191 00192 void KFadeWidgetEffect::start(int duration) 00193 { 00194 Q_D(KFadeWidgetEffect); 00195 if (d->disabled) { 00196 deleteLater(); 00197 return; 00198 } 00199 d->newPixmap = QPixmap::grabWidget(d->destWidget); 00200 d->timeLine.setDuration(duration); 00201 d->timeLine.start(); 00202 } 00203 00204 void KFadeWidgetEffect::paintEvent(QPaintEvent *) 00205 { 00206 Q_D(KFadeWidgetEffect); 00207 QPainter p(this); 00208 p.drawPixmap(rect(), d->transition(d->oldPixmap, d->newPixmap, d->timeLine.currentValue())); 00209 p.end(); 00210 } 00211 00212 #include "moc_kfadewidgeteffect.cpp"
KDE 4.6 API Reference