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

Last change on this file since 64 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 15.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qapplication.h"
43#ifndef QT_NO_EFFECTS
44#include "qdatetime.h"
45#include "qdesktopwidget.h"
46#include "qeffects_p.h"
47#include "qevent.h"
48#include "qimage.h"
49#include "qpainter.h"
50#include "qpixmap.h"
51#include "qpointer.h"
52#include "qtimer.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 QTime 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#ifdef Q_WS_WIN
130 // Restore user-defined opacity value
131 if (widget && QSysInfo::WindowsVersion >= QSysInfo::WV_2000 && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)
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)
164 if (QSysInfo::WindowsVersion >= QSysInfo::WV_2000 && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) {
165 qApp->installEventFilter(this);
166 widget->setWindowOpacity(0.0);
167 widget->show();
168 connect(&anim, SIGNAL(timeout()), this, SLOT(render()));
169 anim.start(1);
170 } else
171#endif
172 {
173 //This is roughly equivalent to calling setVisible(true) without actually showing the widget
174 widget->setAttribute(Qt::WA_WState_ExplicitShowHide, true);
175 widget->setAttribute(Qt::WA_WState_Hidden, false);
176
177 qApp->installEventFilter(this);
178
179 move(widget->geometry().x(),widget->geometry().y());
180 resize(widget->size().width(), widget->size().height());
181
182 frontImage = QPixmap::grabWidget(widget).toImage();
183 backImage = QPixmap::grabWindow(QApplication::desktop()->winId(),
184 widget->geometry().x(), widget->geometry().y(),
185 widget->geometry().width(), widget->geometry().height()).toImage();
186
187 if (!backImage.isNull() && checkTime.elapsed() < duration / 2) {
188 mixedImage = backImage.copy();
189 pm = QPixmap::fromImage(mixedImage);
190 show();
191 setEnabled(false);
192
193 connect(&anim, SIGNAL(timeout()), this, SLOT(render()));
194 anim.start(1);
195 } else {
196 duration = 0;
197 render();
198 }
199 }
200}
201
202/*
203 \reimp
204*/
205bool QAlphaWidget::eventFilter(QObject *o, QEvent *e)
206{
207 switch (e->type()) {
208 case QEvent::Move:
209 if (o != widget)
210 break;
211 move(widget->geometry().x(),widget->geometry().y());
212 update();
213 break;
214 case QEvent::Hide:
215 case QEvent::Close:
216 if (o != widget)
217 break;
218 case QEvent::MouseButtonPress:
219 case QEvent::MouseButtonDblClick:
220 showWidget = false;
221 render();
222 break;
223 case QEvent::KeyPress: {
224 QKeyEvent *ke = (QKeyEvent*)e;
225 if (ke->key() == Qt::Key_Escape) {
226 showWidget = false;
227 } else {
228 duration = 0;
229 }
230 render();
231 break;
232 }
233 default:
234 break;
235 }
236 return QWidget::eventFilter(o, e);
237}
238
239/*
240 \reimp
241*/
242void QAlphaWidget::closeEvent(QCloseEvent *e)
243{
244 e->accept();
245 if (!q_blend)
246 return;
247
248 showWidget = false;
249 render();
250
251 QWidget::closeEvent(e);
252}
253
254/*
255 Render alphablending for the time elapsed.
256
257 Show the blended widget and free all allocated source
258 if the blending is finished.
259*/
260void QAlphaWidget::render()
261{
262 int tempel = checkTime.elapsed();
263 if (elapsed >= tempel)
264 elapsed++;
265 else
266 elapsed = tempel;
267
268 if (duration != 0)
269 alpha = tempel / double(duration);
270 else
271 alpha = 1;
272
273#if defined(Q_OS_WIN)
274 if (QSysInfo::WindowsVersion >= QSysInfo::WV_2000 && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) {
275 if (alpha >= windowOpacity || !showWidget) {
276 anim.stop();
277 qApp->removeEventFilter(this);
278 widget->setWindowOpacity(windowOpacity);
279 q_blend = 0;
280 deleteLater();
281 } else {
282 widget->setWindowOpacity(alpha);
283 }
284 } else
285#endif
286 if (alpha >= 1 || !showWidget) {
287 anim.stop();
288 qApp->removeEventFilter(this);
289
290 if (widget) {
291 if (!showWidget) {
292#ifdef Q_WS_WIN
293 setEnabled(true);
294 setFocus();
295#endif
296 widget->hide();
297 } else {
298 //Since we are faking the visibility of the widget
299 //we need to unset the hidden state on it before calling show
300 widget->setAttribute(Qt::WA_WState_Hidden, true);
301 widget->show();
302 lower();
303 }
304 }
305 q_blend = 0;
306 deleteLater();
307 } else {
308 alphaBlend();
309 pm = QPixmap::fromImage(mixedImage);
310 repaint();
311 }
312}
313
314/*
315 Calculate an alphablended image.
316*/
317void QAlphaWidget::alphaBlend()
318{
319 const int a = qRound(alpha*256);
320 const int ia = 256 - a;
321
322 const int sw = frontImage.width();
323 const int sh = frontImage.height();
324 const int bpl = frontImage.bytesPerLine();
325 switch(frontImage.depth()) {
326 case 32:
327 {
328 uchar *mixed_data = mixedImage.bits();
329 const uchar *back_data = backImage.bits();
330 const uchar *front_data = frontImage.bits();
331
332 for (int sy = 0; sy < sh; sy++) {
333 quint32* mixed = (quint32*)mixed_data;
334 const quint32* back = (const quint32*)back_data;
335 const quint32* front = (const quint32*)front_data;
336 for (int sx = 0; sx < sw; sx++) {
337 quint32 bp = back[sx];
338 quint32 fp = front[sx];
339
340 mixed[sx] = qRgb((qRed(bp)*ia + qRed(fp)*a)>>8,
341 (qGreen(bp)*ia + qGreen(fp)*a)>>8,
342 (qBlue(bp)*ia + qBlue(fp)*a)>>8);
343 }
344 mixed_data += bpl;
345 back_data += bpl;
346 front_data += bpl;
347 }
348 }
349 default:
350 break;
351 }
352}
353
354/*
355 Internal class QRollEffect
356
357 The QRollEffect widget is shown while the animation lasts
358 and displays a scrolling pixmap.
359*/
360
361class QRollEffect : public QWidget, private QEffects
362{
363 Q_OBJECT
364public:
365 QRollEffect(QWidget* w, Qt::WindowFlags f, DirFlags orient);
366
367 void run(int time);
368
369protected:
370 void paintEvent(QPaintEvent*);
371 void closeEvent(QCloseEvent*);
372
373private slots:
374 void scroll();
375
376private:
377 QPointer<QAccessWidget> widget;
378
379 int currentHeight;
380 int currentWidth;
381 int totalHeight;
382 int totalWidth;
383
384 int duration;
385 int elapsed;
386 bool done;
387 bool showWidget;
388 int orientation;
389
390 QTimer anim;
391 QTime checkTime;
392
393 QPixmap pm;
394};
395
396static QRollEffect* q_roll = 0;
397
398/*
399 Construct a QRollEffect widget.
400*/
401QRollEffect::QRollEffect(QWidget* w, Qt::WindowFlags f, DirFlags orient)
402 : QWidget(0, f), orientation(orient)
403{
404#ifndef Q_WS_WIN
405 setEnabled(false);
406#endif
407
408 widget = (QAccessWidget*) w;
409 Q_ASSERT(widget);
410
411 setAttribute(Qt::WA_NoSystemBackground, true);
412
413 if (widget->testAttribute(Qt::WA_Resized)) {
414 totalWidth = widget->width();
415 totalHeight = widget->height();
416 } else {
417 totalWidth = widget->sizeHint().width();
418 totalHeight = widget->sizeHint().height();
419 }
420
421 currentHeight = totalHeight;
422 currentWidth = totalWidth;
423
424 if (orientation & (RightScroll|LeftScroll))
425 currentWidth = 0;
426 if (orientation & (DownScroll|UpScroll))
427 currentHeight = 0;
428
429 pm = QPixmap::grabWidget(widget);
430}
431
432/*
433 \reimp
434*/
435void QRollEffect::paintEvent(QPaintEvent*)
436{
437 int x = orientation & RightScroll ? qMin(0, currentWidth - totalWidth) : 0;
438 int y = orientation & DownScroll ? qMin(0, currentHeight - totalHeight) : 0;
439
440 QPainter p(this);
441 p.drawPixmap(x, y, pm);
442}
443
444/*
445 \reimp
446*/
447void QRollEffect::closeEvent(QCloseEvent *e)
448{
449 e->accept();
450 if (done)
451 return;
452
453 showWidget = false;
454 done = true;
455 scroll();
456
457 QWidget::closeEvent(e);
458}
459
460/*
461 Start the animation.
462
463 The animation will take about \a time ms, or is
464 calculated if \a time is negative
465*/
466void QRollEffect::run(int time)
467{
468 if (!widget)
469 return;
470
471 duration = time;
472 elapsed = 0;
473
474 if (duration < 0) {
475 int dist = 0;
476 if (orientation & (RightScroll|LeftScroll))
477 dist += totalWidth - currentWidth;
478 if (orientation & (DownScroll|UpScroll))
479 dist += totalHeight - currentHeight;
480 duration = qMin(qMax(dist/3, 50), 120);
481 }
482
483 connect(&anim, SIGNAL(timeout()), this, SLOT(scroll()));
484
485 move(widget->geometry().x(),widget->geometry().y());
486 resize(qMin(currentWidth, totalWidth), qMin(currentHeight, totalHeight));
487
488 //This is roughly equivalent to calling setVisible(true) without actually showing the widget
489 widget->setAttribute(Qt::WA_WState_ExplicitShowHide, true);
490 widget->setAttribute(Qt::WA_WState_Hidden, false);
491
492 show();
493 setEnabled(false);
494
495 qApp->installEventFilter(this);
496
497 showWidget = true;
498 done = false;
499 anim.start(1);
500 checkTime.start();
501}
502
503/*
504 Roll according to the time elapsed.
505*/
506void QRollEffect::scroll()
507{
508 if (!done && widget) {
509 int tempel = checkTime.elapsed();
510 if (elapsed >= tempel)
511 elapsed++;
512 else
513 elapsed = tempel;
514
515 if (currentWidth != totalWidth) {
516 currentWidth = totalWidth * (elapsed/duration)
517 + (2 * totalWidth * (elapsed%duration) + duration)
518 / (2 * duration);
519 // equiv. to int((totalWidth*elapsed) / duration + 0.5)
520 done = (currentWidth >= totalWidth);
521 }
522 if (currentHeight != totalHeight) {
523 currentHeight = totalHeight * (elapsed/duration)
524 + (2 * totalHeight * (elapsed%duration) + duration)
525 / (2 * duration);
526 // equiv. to int((totalHeight*elapsed) / duration + 0.5)
527 done = (currentHeight >= totalHeight);
528 }
529 done = (currentHeight >= totalHeight) &&
530 (currentWidth >= totalWidth);
531
532 int w = totalWidth;
533 int h = totalHeight;
534 int x = widget->geometry().x();
535 int y = widget->geometry().y();
536
537 if (orientation & RightScroll || orientation & LeftScroll)
538 w = qMin(currentWidth, totalWidth);
539 if (orientation & DownScroll || orientation & UpScroll)
540 h = qMin(currentHeight, totalHeight);
541
542 setUpdatesEnabled(false);
543 if (orientation & UpScroll)
544 y = widget->geometry().y() + qMax(0, totalHeight - currentHeight);
545 if (orientation & LeftScroll)
546 x = widget->geometry().x() + qMax(0, totalWidth - currentWidth);
547 if (orientation & UpScroll || orientation & LeftScroll)
548 move(x, y);
549
550 resize(w, h);
551 setUpdatesEnabled(true);
552 repaint();
553 }
554 if (done) {
555 anim.stop();
556 qApp->removeEventFilter(this);
557 if (widget) {
558 if (!showWidget) {
559#ifdef Q_WS_WIN
560 setEnabled(true);
561 setFocus();
562#endif
563 widget->hide();
564 } else {
565 //Since we are faking the visibility of the widget
566 //we need to unset the hidden state on it before calling show
567 widget->setAttribute(Qt::WA_WState_Hidden, true);
568 widget->show();
569 lower();
570 }
571 }
572 q_roll = 0;
573 deleteLater();
574 }
575}
576
577/*!
578 Scroll widget \a w in \a time ms. \a orient may be 1 (vertical), 2
579 (horizontal) or 3 (diagonal).
580*/
581void qScrollEffect(QWidget* w, QEffects::DirFlags orient, int time)
582{
583 if (q_roll) {
584 q_roll->deleteLater();
585 q_roll = 0;
586 }
587
588 if (!w)
589 return;
590
591 qApp->sendPostedEvents(w, QEvent::Move);
592 qApp->sendPostedEvents(w, QEvent::Resize);
593 Qt::WindowFlags flags = Qt::ToolTip;
594
595 // those can be popups - they would steal the focus, but are disabled
596 q_roll = new QRollEffect(w, flags, orient);
597 q_roll->run(time);
598}
599
600/*!
601 Fade in widget \a w in \a time ms.
602*/
603void qFadeEffect(QWidget* w, int time)
604{
605 if (q_blend) {
606 q_blend->deleteLater();
607 q_blend = 0;
608 }
609
610 if (!w)
611 return;
612
613 qApp->sendPostedEvents(w, QEvent::Move);
614 qApp->sendPostedEvents(w, QEvent::Resize);
615
616 Qt::WindowFlags flags = Qt::ToolTip;
617
618 // those can be popups - they would steal the focus, but are disabled
619 q_blend = new QAlphaWidget(w, flags);
620
621 q_blend->run(time);
622}
623
624QT_END_NAMESPACE
625
626/*
627 Delete this after timeout
628*/
629
630#include "qeffects.moc"
631
632#endif //QT_NO_EFFECTS
Note: See TracBrowser for help on using the repository browser.