File indexing completed on 2024-05-12 16:39:55

0001 /*  This file is part of the KDE project
0002     Copyright (C) 2008 Matthias Kretz <kretz@kde.org>
0003     Copyright (C) 2008 Rafael Fernández López <ereslibre@kde.org>
0004 
0005     This program is free software; you can redistribute it and/or
0006     modify it under the terms of the GNU Library General Public
0007     License as published by the Free Software Foundation; either
0008     version 2 of the License, or (at your option) version 3.
0009 
0010     This library is distributed in the hope that it will be useful,
0011     but WITHOUT ANY WARRANTY; without even the implied warranty of
0012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013     Library General Public License for more details.
0014 
0015     You should have received a copy of the GNU Library General Public License
0016     along with this library; see the file COPYING.LIB.  If not, write to
0017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018     Boston, MA 02110-1301, USA.
0019 
0020 */
0021 
0022 #include "KexiFadeWidgetEffect.h"
0023 #include "KexiFadeWidgetEffect_p.h"
0024 
0025 #include <QtCore/QEvent>
0026 #include <QPaintEngine>
0027 #include <QPainter>
0028 #include <QStyle>
0029 
0030 KexiFadeWidgetEffectPrivate::KexiFadeWidgetEffectPrivate(QWidget *_destWidget)
0031     : destWidget(_destWidget), disabled(false), defaultDuration(0)
0032 {
0033 }
0034 
0035 // Code from KFileItemDelegate (Author: Frederik Höglund)
0036 // Fast transitions. Read:
0037 // https://techbase.kde.org/Development/Tutorials/Graphics/Performance
0038 // for further information on why not use setOpacity.
0039 QPixmap KexiFadeWidgetEffectPrivate::transition(const QPixmap &from, const QPixmap &to, qreal amount) const
0040 {
0041     const int value = int(0xff * amount);
0042 
0043     if (value == 0) {
0044         return from;
0045     }
0046 
0047     if (value == 1) {
0048         return to;
0049     }
0050 
0051     QColor color;
0052     color.setAlphaF(amount);
0053 
0054     // If the native paint engine supports Porter/Duff compositing and CompositionMode_Plus
0055     if (from.paintEngine()->hasFeature(QPaintEngine::PorterDuff) &&
0056             from.paintEngine()->hasFeature(QPaintEngine::BlendModes)) {
0057         QPixmap under = from;
0058         QPixmap over  = to;
0059 
0060         QPainter p;
0061         p.begin(&over);
0062         p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
0063         p.fillRect(over.rect(), color);
0064         p.end();
0065 
0066         p.begin(&under);
0067         p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
0068         p.fillRect(under.rect(), color);
0069         p.setCompositionMode(QPainter::CompositionMode_Plus);
0070         p.drawPixmap(0, 0, over);
0071         p.end();
0072 
0073         return under;
0074     } else {
0075         // Fall back to using QRasterPaintEngine to do the transition.
0076         QImage under = from.toImage();
0077         QImage over  = to.toImage();
0078 
0079         QPainter p;
0080         p.begin(&over);
0081         p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
0082         p.fillRect(over.rect(), color);
0083         p.end();
0084 
0085         p.begin(&under);
0086         p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
0087         p.fillRect(under.rect(), color);
0088         p.setCompositionMode(QPainter::CompositionMode_Plus);
0089         p.drawImage(0, 0, over);
0090         p.end();
0091 
0092         return QPixmap::fromImage(under);
0093     }
0094 }
0095 
0096 KexiFadeWidgetEffect::KexiFadeWidgetEffect(QWidget *destWidget, int defaultDuration)
0097     : QWidget(destWidget ? destWidget->parentWidget() : 0),
0098       d(new KexiFadeWidgetEffectPrivate(destWidget))
0099 {
0100     d->defaultDuration = defaultDuration;
0101     Q_ASSERT(destWidget && destWidget->parentWidget());
0102     if (!destWidget || !destWidget->parentWidget() || !destWidget->isVisible() ||
0103             !style()->styleHint(QStyle::SH_Widget_Animate, 0, this)) {
0104         d->disabled = true;
0105         hide();
0106         return;
0107     }
0108     setGeometry(QRect(destWidget->mapTo(parentWidget(), QPoint(0, 0)), destWidget->size()));
0109     d->oldPixmap = destWidget->grab();
0110     d->timeLine.setFrameRange(0, 255);
0111     d->timeLine.setCurveShape(QTimeLine::EaseOutCurve);
0112     connect(&d->timeLine, SIGNAL(finished()), SLOT(finished()));
0113     connect(&d->timeLine, SIGNAL(frameChanged(int)), SLOT(repaint()));
0114     show();
0115 }
0116 
0117 KexiFadeWidgetEffect::~KexiFadeWidgetEffect()
0118 {
0119     delete d;
0120 }
0121 
0122 void KexiFadeWidgetEffect::finished()
0123 {
0124     d->destWidget->setUpdatesEnabled(false);
0125     hide();
0126     deleteLater();
0127     d->destWidget->setUpdatesEnabled(true);
0128 }
0129 
0130 void KexiFadeWidgetEffect::start(int duration)
0131 {
0132     if (d->disabled) {
0133         deleteLater();
0134         return;
0135     }
0136     d->newPixmap = d->destWidget->grab();
0137     d->timeLine.setDuration(duration);
0138     d->timeLine.start();
0139 }
0140 
0141 void KexiFadeWidgetEffect::start()
0142 {
0143     start(d->defaultDuration);
0144 }
0145 
0146 void KexiFadeWidgetEffect::paintEvent(QPaintEvent *)
0147 {
0148     QPainter p(this);
0149     p.drawPixmap(rect(), d->transition(d->oldPixmap, d->newPixmap, d->timeLine.currentValue()));
0150     p.end();
0151 }