source: trunk/src/gui/widgets/qeffects.cpp@ 1021

Last change on this file since 1021 was 846, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 15.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qapplication.h"
43#ifndef QT_NO_EFFECTS
44#include "qdesktopwidget.h"
45#include "qeffects_p.h"
46#include "qevent.h"
47#include "qimage.h"
48#include "qpainter.h"
49#include "qpixmap.h"
50#include "qpointer.h"
51#include "qtimer.h"
52#include "qelapsedtimer.h"
53#include "qdebug.h"
54
55QT_BEGIN_NAMESPACE
56
57/*
58 Internal class to get access to protected QWidget-members
59*/
60
61class QAccessWidget : public QWidget
62{
63 friend class QAlphaWidget;
64 friend class QRollEffect;
65public:
66 QAccessWidget(QWidget* parent=0, Qt::WindowFlags f = 0)
67 : QWidget(parent, f) {}
68};
69
70/*
71 Internal class QAlphaWidget.
72
73 The QAlphaWidget is shown while the animation lasts
74 and displays the pixmap resulting from the alpha blending.
75*/
76
77class QAlphaWidget: public QWidget, private QEffects
78{
79 Q_OBJECT
80public:
81 QAlphaWidget(QWidget* w, Qt::WindowFlags f = 0);
82 ~QAlphaWidget();
83
84 void run(int time);
85
86protected:
87 void paintEvent(QPaintEvent* e);
88 void closeEvent(QCloseEvent*);
89 void alphaBlend();
90 bool eventFilter(QObject *, QEvent *);
91
92protected slots:
93 void render();
94
95private:
96 QPixmap pm;
97 double alpha;
98 QImage backImage;
99 QImage frontImage;
100 QImage mixedImage;
101 QPointer<QAccessWidget> widget;
102 int duration;
103 int elapsed;
104 bool showWidget;
105 QTimer anim;
106 QElapsedTimer checkTime;
107 double windowOpacity;
108};
109
110static QAlphaWidget* q_blend = 0;
111
112/*
113 Constructs a QAlphaWidget.
114*/
115QAlphaWidget::QAlphaWidget(QWidget* w, Qt::WindowFlags f)
116 : QWidget(QApplication::desktop()->screen(QApplication::desktop()->screenNumber(w)), f)
117{
118#ifndef Q_WS_WIN
119 setEnabled(false);
120#endif
121 setAttribute(Qt::WA_NoSystemBackground, true);
122 widget = (QAccessWidget*)w;
123 windowOpacity = w->windowOpacity();
124 alpha = 0;
125}
126
127QAlphaWidget::~QAlphaWidget()
128{
129#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
130 // Restore user-defined opacity value
131 if (widget)
132 widget->setWindowOpacity(windowOpacity);
133#endif
134}
135
136/*
137 \reimp
138*/
139void QAlphaWidget::paintEvent(QPaintEvent*)
140{
141 QPainter p(this);
142 p.drawPixmap(0, 0, pm);
143}
144
145/*
146 Starts the alphablending animation.
147 The animation will take about \a time ms
148*/
149void QAlphaWidget::run(int time)
150{
151 duration = time;
152
153 if (duration < 0)
154 duration = 150;
155
156 if (!widget)
157 return;
158
159 elapsed = 0;
160 checkTime.start();
161
162 showWidget = true;
163#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
164 qApp->installEventFilter(this);
165 widget->setWindowOpacity(0.0);
166 widget->show();
167 connect(&anim, SIGNAL(timeout()), this, SLOT(render()));
168 anim.start(1);
169#else
170 //This is roughly equivalent to calling setVisible(true) without actually showing the widget
171 widget->setAttribute(Qt::WA_WState_ExplicitShowHide, true);
172 widget->setAttribute(Qt::WA_WState_Hidden, false);
173
174 qApp->installEventFilter(this);
175
176 move(widget->geometry().x(),widget->geometry().y());
177 resize(widget->size().width(), widget->size().height());
178
179 frontImage = QPixmap::grabWidget(widget).toImage();
180 backImage = QPixmap::grabWindow(QApplication::desktop()->winId(),
181 widget->geometry().x(), widget->geometry().y(),
182 widget->geometry().width(), widget->geometry().height()).toImage();
183
184 if (!backImage.isNull() && checkTime.elapsed() < duration / 2) {
185 mixedImage = backImage.copy();
186 pm = QPixmap::fromImage(mixedImage);
187 show();
188 setEnabled(false);
189
190 connect(&anim, SIGNAL(timeout()), this, SLOT(render()));
191 anim.start(1);
192 } else {
193 duration = 0;
194 render();
195 }
196#endif
197}
198
199/*
200 \reimp
201*/
202bool QAlphaWidget::eventFilter(QObject *o, QEvent *e)
203{
204 switch (e->type()) {
205 case QEvent::Move:
206 if (o != widget)
207 break;
208 move(widget->geometry().x(),widget->geometry().y());
209 update();
210 break;
211 case QEvent::Hide:
212 case QEvent::Close:
213 if (o != widget)
214 break;
215 case QEvent::MouseButtonPress:
216 case QEvent::MouseButtonDblClick:
217 showWidget = false;
218 render();
219 break;
220 case QEvent::KeyPress: {
221 QKeyEvent *ke = (QKeyEvent*)e;
222 if (ke->key() == Qt::Key_Escape) {
223 showWidget = false;
224 } else {
225 duration = 0;
226 }
227 render();
228 break;
229 }
230 default:
231 break;
232 }
233 return QWidget::eventFilter(o, e);
234}
235
236/*
237 \reimp
238*/
239void QAlphaWidget::closeEvent(QCloseEvent *e)
240{
241 e->accept();
242 if (!q_blend)
243 return;
244
245 showWidget = false;
246 render();
247
248 QWidget::closeEvent(e);
249}
250
251/*
252 Render alphablending for the time elapsed.
253
254 Show the blended widget and free all allocated source
255 if the blending is finished.
256*/
257void QAlphaWidget::render()
258{
259 int tempel = checkTime.elapsed();
260 if (elapsed >= tempel)
261 elapsed++;
262 else
263 elapsed = tempel;
264
265 if (duration != 0)
266 alpha = tempel / double(duration);
267 else
268 alpha = 1;
269
270#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
271 if (alpha >= windowOpacity || !showWidget) {
272 anim.stop();
273 qApp->removeEventFilter(this);
274 widget->setWindowOpacity(windowOpacity);
275 q_blend = 0;
276 deleteLater();
277 } else {
278 widget->setWindowOpacity(alpha);
279 }
280#else
281 if (alpha >= 1 || !showWidget) {
282 anim.stop();
283 qApp->removeEventFilter(this);
284
285 if (widget) {
286 if (!showWidget) {
287#ifdef Q_WS_WIN
288 setEnabled(true);
289 setFocus();
290#endif // Q_WS_WIN
291 widget->hide();
292 } else {
293 //Since we are faking the visibility of the widget
294 //we need to unset the hidden state on it before calling show
295 widget->setAttribute(Qt::WA_WState_Hidden, true);
296 widget->show();
297 lower();
298 }
299 }
300 q_blend = 0;
301 deleteLater();
302 } else {
303 alphaBlend();
304 pm = QPixmap::fromImage(mixedImage);
305 repaint();
306 }
307#endif // defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
308}
309
310/*
311 Calculate an alphablended image.
312*/
313void QAlphaWidget::alphaBlend()
314{
315 const int a = qRound(alpha*256);
316 const int ia = 256 - a;
317
318 const int sw = frontImage.width();
319 const int sh = frontImage.height();
320 const int bpl = frontImage.bytesPerLine();
321 switch(frontImage.depth()) {
322 case 32:
323 {
324 uchar *mixed_data = mixedImage.bits();
325 const uchar *back_data = backImage.bits();
326 const uchar *front_data = frontImage.bits();
327
328 for (int sy = 0; sy < sh; sy++) {
329 quint32* mixed = (quint32*)mixed_data;
330 const quint32* back = (const quint32*)back_data;
331 const quint32* front = (const quint32*)front_data;
332 for (int sx = 0; sx < sw; sx++) {
333 quint32 bp = back[sx];
334 quint32 fp = front[sx];
335
336 mixed[sx] = qRgb((qRed(bp)*ia + qRed(fp)*a)>>8,
337 (qGreen(bp)*ia + qGreen(fp)*a)>>8,
338 (qBlue(bp)*ia + qBlue(fp)*a)>>8);
339 }
340 mixed_data += bpl;
341 back_data += bpl;
342 front_data += bpl;
343 }
344 }
345 default:
346 break;
347 }
348}
349
350/*
351 Internal class QRollEffect
352
353 The QRollEffect widget is shown while the animation lasts
354 and displays a scrolling pixmap.
355*/
356
357class QRollEffect : public QWidget, private QEffects
358{
359 Q_OBJECT
360public:
361 QRollEffect(QWidget* w, Qt::WindowFlags f, DirFlags orient);
362
363 void run(int time);
364
365protected:
366 void paintEvent(QPaintEvent*);
367 void closeEvent(QCloseEvent*);
368
369private slots:
370 void scroll();
371
372private:
373 QPointer<QAccessWidget> widget;
374
375 int currentHeight;
376 int currentWidth;
377 int totalHeight;
378 int totalWidth;
379
380 int duration;
381 int elapsed;
382 bool done;
383 bool showWidget;
384 int orientation;
385
386 QTimer anim;
387 QElapsedTimer checkTime;
388
389 QPixmap pm;
390};
391
392static QRollEffect* q_roll = 0;
393
394/*
395 Construct a QRollEffect widget.
396*/
397QRollEffect::QRollEffect(QWidget* w, Qt::WindowFlags f, DirFlags orient)
398 : QWidget(0, f), orientation(orient)
399{
400#ifndef Q_WS_WIN
401 setEnabled(false);
402#endif
403
404 widget = (QAccessWidget*) w;
405 Q_ASSERT(widget);
406
407 setAttribute(Qt::WA_NoSystemBackground, true);
408
409 if (widget->testAttribute(Qt::WA_Resized)) {
410 totalWidth = widget->width();
411 totalHeight = widget->height();
412 } else {
413 totalWidth = widget->sizeHint().width();
414 totalHeight = widget->sizeHint().height();
415 }
416
417 currentHeight = totalHeight;
418 currentWidth = totalWidth;
419
420 if (orientation & (RightScroll|LeftScroll))
421 currentWidth = 0;
422 if (orientation & (DownScroll|UpScroll))