File indexing completed on 2024-05-19 12:54:43
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 <QCoreApplication> 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), 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 destWidget->updateGeometry(); 0109 destWidget->repaint(); 0110 setGeometry(QRect(destWidget->mapTo(parentWidget(), QPoint(0, 0)), destWidget->size())); 0111 d->oldPixmap = destWidget->grab(); 0112 d->timeLine.setFrameRange(0, 255); 0113 d->timeLine.setCurveShape(QTimeLine::EaseOutCurve); 0114 connect(&d->timeLine, SIGNAL(finished()), SLOT(finished())); 0115 connect(&d->timeLine, SIGNAL(frameChanged(int)), SLOT(repaint())); 0116 show(); 0117 } 0118 0119 KexiFadeWidgetEffect::~KexiFadeWidgetEffect() 0120 { 0121 delete d; 0122 } 0123 0124 void KexiFadeWidgetEffect::finished() 0125 { 0126 d->destWidget->setUpdatesEnabled(false); 0127 hide(); 0128 deleteLater(); 0129 d->destWidget->setUpdatesEnabled(true); 0130 } 0131 0132 void KexiFadeWidgetEffect::start(int duration) 0133 { 0134 if (d->disabled) { 0135 deleteLater(); 0136 return; 0137 } 0138 d->destWidget->updateGeometry(); 0139 d->destWidget->update(); 0140 qApp->processEvents(); 0141 hide(); 0142 d->newPixmap = d->destWidget->grab(); 0143 d->timeLine.setDuration(duration); 0144 show(); 0145 raise(); 0146 d->timeLine.start(); 0147 } 0148 0149 void KexiFadeWidgetEffect::start() 0150 { 0151 start(d->defaultDuration); 0152 } 0153 0154 void KexiFadeWidgetEffect::paintEvent(QPaintEvent *) 0155 { 0156 QPainter p(this); 0157 p.drawPixmap(rect(), d->transition(d->oldPixmap, d->newPixmap, d->timeLine.currentValue())); 0158 p.end(); 0159 }