source: vendor/trolltech/current/src/widgets/qeffects.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 15.6 KB
Line 
1/****************************************************************************
2** $Id: qeffects.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QEffects functions
5**
6** Created : 000621
7**
8** Copyright (C) 2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the widgets module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qapplication.h"
39#ifndef QT_NO_EFFECTS
40#include "qwidget.h"
41#include "qeffects_p.h"
42#include "qpixmap.h"
43#include "qimage.h"
44#include "qtimer.h"
45#include "qdatetime.h"
46#include "qguardedptr.h"
47#include "qscrollview.h"
48
49/*
50 Internal class to get access to protected QWidget-members
51*/
52
53class QAccessWidget : public QWidget
54{
55 friend class QAlphaWidget;
56 friend class QRollEffect;
57public:
58 QAccessWidget( QWidget* parent=0, const char* name=0, WFlags f = 0 )
59 : QWidget( parent, name, f ) {}
60};
61
62/*
63 Internal class QAlphaWidget.
64
65 The QAlphaWidget is shown while the animation lasts
66 and displays the pixmap resulting from the alpha blending.
67*/
68
69class QAlphaWidget: public QWidget, private QEffects
70{
71 Q_OBJECT
72public:
73 QAlphaWidget( QWidget* w, WFlags f = 0 );
74
75 void run( int time );
76
77protected:
78 void paintEvent( QPaintEvent* e );
79 void closeEvent( QCloseEvent* );
80 bool eventFilter( QObject* o, QEvent* e );
81 void alphaBlend();
82
83protected slots:
84 void render();
85
86private:
87 QPixmap pm;
88 double alpha;
89 QImage back;
90 QImage front;
91 QImage mixed;
92 QGuardedPtr<QAccessWidget> widget;
93 int duration;
94 int elapsed;
95 bool showWidget;
96 QTimer anim;
97 QTime checkTime;
98};
99
100static QAlphaWidget* q_blend = 0;
101
102/*
103 Constructs a QAlphaWidget.
104*/
105QAlphaWidget::QAlphaWidget( QWidget* w, WFlags f )
106 : QWidget( 0, "qt internal alpha effect widget", f )
107{
108 setEnabled( FALSE );
109
110 pm.setOptimization( QPixmap::BestOptim );
111 setBackgroundMode( NoBackground );
112 widget = (QAccessWidget*)w;
113 alpha = 0;
114}
115
116/*
117 \reimp
118*/
119void QAlphaWidget::paintEvent( QPaintEvent* )
120{
121 bitBlt( this, QPoint(0,0), &pm );
122}
123
124/*
125 Starts the alphablending animation.
126 The animation will take about \a time ms
127*/
128void QAlphaWidget::run( int time )
129{
130 duration = time;
131
132 if ( duration < 0 )
133 duration = 150;
134
135 if ( !widget )
136 return;
137
138 elapsed = 0;
139 checkTime.start();
140
141 showWidget = TRUE;
142 qApp->installEventFilter( this );
143
144 widget->setWState( WState_Visible );
145
146 move( widget->geometry().x(),widget->geometry().y() );
147 resize( widget->size().width(), widget->size().height() );
148
149 front = QImage( widget->size(), 32 );
150 front = QPixmap::grabWidget( widget );
151
152 back = QImage( widget->size(), 32 );
153 back = QPixmap::grabWindow( QApplication::desktop()->winId(),
154 widget->geometry().x(), widget->geometry().y(),
155 widget->geometry().width(), widget->geometry().height() );
156
157 if ( !back.isNull() && checkTime.elapsed() < duration / 2 ) {
158 mixed = back.copy();
159 pm = mixed;
160 show();
161
162 connect( &anim, SIGNAL(timeout()), this, SLOT(render()));
163 anim.start( 1 );
164 } else {
165 duration = 0;
166 render();
167 }
168}
169
170/*
171 \reimp
172*/
173bool QAlphaWidget::eventFilter( QObject* o, QEvent* e )
174{
175 switch ( e->type() ) {
176 case QEvent::Move:
177 if ( o != widget )
178 break;
179 move( widget->geometry().x(),widget->geometry().y() );
180 update();
181 break;
182 case QEvent::Hide:
183 case QEvent::Close:
184 if ( o != widget )
185 break;
186 case QEvent::MouseButtonPress:
187#ifndef QT_NO_SCROLLVIEW
188 if ( ::qt_cast<QScrollView*>(o) )
189 break;
190#endif
191 case QEvent::MouseButtonDblClick:
192 setEnabled(TRUE);
193 showWidget = FALSE;
194 render();
195 break;
196 case QEvent::KeyPress:
197 {
198 QKeyEvent *ke = (QKeyEvent*)e;
199 if ( ke->key() == Key_Escape )
200 showWidget = FALSE;
201 else
202 duration = 0;
203 render();
204 break;
205 }
206 default:
207 break;
208 }
209 return QWidget::eventFilter( o, e );
210}
211
212/*
213 \reimp
214*/
215void QAlphaWidget::closeEvent( QCloseEvent *e )
216{
217 e->accept();
218 if ( !q_blend )
219 return;
220
221 showWidget = FALSE;
222 render();
223
224 QWidget::closeEvent( e );
225}
226
227/*
228 Render alphablending for the time elapsed.
229
230 Show the blended widget and free all allocated source
231 if the blending is finished.
232*/
233void QAlphaWidget::render()
234{
235 int tempel = checkTime.elapsed();
236 if ( elapsed >= tempel )
237 elapsed++;
238 else
239 elapsed = tempel;
240
241 if ( duration != 0 )
242 alpha = tempel / double(duration);
243 else
244 alpha = 1;
245 if ( alpha >= 1 || !showWidget) {
246 anim.stop();
247 qApp->removeEventFilter( this );
248
249 if ( widget ) {
250 if ( !showWidget ) {
251 widget->hide();
252 widget->setWState( WState_ForceHide );
253 widget->clearWState( WState_Visible );
254 } else if ( duration ) {
255 BackgroundMode bgm = widget->backgroundMode();
256 QColor erc = widget->eraseColor();
257 const QPixmap *erp = widget->erasePixmap();
258
259 widget->clearWState( WState_Visible );
260 widget->setBackgroundMode( NoBackground );
261 widget->show();
262 if ( bgm != FixedColor && bgm != FixedPixmap ) {
263 widget->clearWState( WState_Visible ); // prevent update in setBackgroundMode
264 widget->setBackgroundMode( bgm );
265 widget->setWState( WState_Visible );
266 }
267 if ( erc.isValid() ) {
268 widget->setEraseColor( erc );
269 } else if ( erp ) {
270 widget->setErasePixmap( *erp );
271 }
272 } else {
273 widget->clearWState( WState_Visible );
274 widget->show();
275 }
276 }
277 q_blend = 0;
278 deleteLater();
279 } else {
280 if (widget)
281 widget->clearWState( WState_ForceHide );
282 alphaBlend();
283 pm = mixed;
284 repaint( FALSE );
285 }
286}
287
288/*
289 Calculate an alphablended image.
290*/
291void QAlphaWidget::alphaBlend()
292{
293 const double ia = 1-alpha;
294 const int sw = front.width();
295 const int sh = front.height();
296 switch( front.depth() ) {
297 case 32:
298 {
299 Q_UINT32** md = (Q_UINT32**)mixed.jumpTable();
300 Q_UINT32** bd = (Q_UINT32**)back.jumpTable();
301 Q_UINT32** fd = (Q_UINT32**)front.jumpTable();
302
303 for (int sy = 0; sy < sh; sy++ ) {
304 Q_UINT32* bl = ((Q_UINT32*)bd[sy]);
305 Q_UINT32* fl = ((Q_UINT32*)fd[sy]);
306 for (int sx = 0; sx < sw; sx++ ) {
307 Q_UINT32 bp = bl[sx];
308 Q_UINT32 fp = fl[sx];
309
310 ((Q_UINT32*)(md[sy]))[sx] = qRgb(int (qRed(bp)*ia + qRed(fp)*alpha),
311 int (qGreen(bp)*ia + qGreen(fp)*alpha),
312 int (qBlue(bp)*ia + qBlue(fp)*alpha) );
313 }
314 }
315 }
316 default:
317 break;
318 }
319}
320
321/*
322 Internal class QRollEffect
323
324 The QRollEffect widget is shown while the animation lasts
325 and displays a scrolling pixmap.
326*/
327
328class QRollEffect : public QWidget, private QEffects
329{
330 Q_OBJECT
331public:
332 QRollEffect( QWidget* w, WFlags f, DirFlags orient );
333
334 void run( int time );
335
336protected:
337 void paintEvent( QPaintEvent* );
338 bool eventFilter( QObject*, QEvent* );
339 void closeEvent( QCloseEvent* );
340
341private slots:
342 void scroll();
343
344private:
345 QGuardedPtr<QAccessWidget> widget;
346
347 int currentHeight;
348 int currentWidth;
349 int totalHeight;
350 int totalWidth;
351
352 int duration;
353 int elapsed;
354 bool done;
355 bool showWidget;
356 int orientation;
357
358 QTimer anim;
359 QTime checkTime;
360
361 QPixmap pm;
362};
363
364static QRollEffect* q_roll = 0;
365
366/*
367 Construct a QRollEffect widget.
368*/
369QRollEffect::QRollEffect( QWidget* w, WFlags f, DirFlags orient )
370 : QWidget( 0, "qt internal roll effect widget", f ), orientation(orient)
371{
372 setEnabled( FALSE );
373 widget = (QAccessWidget*) w;
374 Q_ASSERT( widget );
375
376 setBackgroundMode( NoBackground );
377
378 if ( widget->testWState( WState_Resized ) ) {
379 totalWidth = widget->width();
380 totalHeight = widget->height();
381 } else {
382 totalWidth = widget->sizeHint().width();
383 totalHeight = widget->sizeHint().height();
384 }
385
386 currentHeight = totalHeight;
387 currentWidth = totalWidth;
388
389 if ( orientation & (RightScroll|LeftScroll) )
390 currentWidth = 0;
391 if ( orientation & (DownScroll|UpScroll) )
392 currentHeight = 0;
393
394 pm.setOptimization( QPixmap::BestOptim );
395 pm = QPixmap::grabWidget( widget );
396}
397
398/*
399 \reimp
400*/
401void QRollEffect::paintEvent( QPaintEvent* )
402{
403 int x = orientation & RightScroll ? QMIN(0, currentWidth - totalWidth) : 0;
404 int y = orientation & DownScroll ? QMIN(0, currentHeight - totalHeight) : 0;
405
406 bitBlt( this, x, y, &pm,
407 0, 0, pm.width(), pm.height(), CopyROP, TRUE );
408}
409
410/*
411 \reimp
412*/
413bool QRollEffect::eventFilter( QObject* o, QEvent* e )
414{
415 switch ( e->type() ) {
416 case QEvent::Move:
417 if ( o != widget )
418 break;
419 move( widget->geometry().x(),widget->geometry().y() );
420 update();
421 break;
422 case QEvent::Hide:
423 case QEvent::Close:
424 if ( o != widget || done )
425 break;
426 setEnabled(TRUE);
427 showWidget = FALSE;
428 done = TRUE;
429 scroll();
430 break;
431 case QEvent::MouseButtonPress:
432#ifndef QT_NO_SCROLLVIEW
433 if ( ::qt_cast<QScrollView*>(o) )
434 break;
435#endif
436 case QEvent::MouseButtonDblClick:
437 if ( done )
438 break;
439 setEnabled(TRUE);
440 showWidget = FALSE;
441 done = TRUE;
442 scroll();
443 break;
444 case QEvent::KeyPress:
445 {
446 QKeyEvent *ke = (QKeyEvent*)e;
447 if ( ke->key() == Key_Escape )
448 showWidget = FALSE;
449 done = TRUE;
450 scroll();
451 break;
452 }
453 default:
454 break;
455 }
456 return QWidget::eventFilter( o, e );
457}
458
459/*
460 \reimp
461*/
462void QRollEffect::closeEvent( QCloseEvent *e )
463{
464 e->accept();
465 if ( done )
466 return;
467
468 showWidget = FALSE;
469 done = TRUE;
470 scroll();
471
472 QWidget::closeEvent( e );
473}
474
475/*
476 Start the animation.
477
478 The animation will take about \a time ms, or is
479 calculated if \a time is negative
480*/
481void QRollEffect::run( int time )
482{
483 if ( !widget )
484 return;
485
486 duration = time;
487 elapsed = 0;
488
489 if ( duration < 0 ) {
490 int dist = 0;
491 if ( orientation & (RightScroll|LeftScroll) )
492 dist += totalWidth - currentWidth;
493 if ( orientation & (DownScroll|UpScroll) )
494 dist += totalHeight - currentHeight;
495 duration = QMIN( QMAX( dist/3, 50 ), 120 );
496 }
497
498 connect( &anim, SIGNAL(timeout()), this, SLOT(scroll()));
499
500 widget->setWState( WState_Visible );
501
502 move( widget->geometry().x(),widget->geometry().y() );
503 resize( QMIN( currentWidth, totalWidth ), QMIN( currentHeight, totalHeight ) );
504
505 show();
506
507 qApp->installEventFilter( this );
508
509 showWidget = TRUE;
510 done = FALSE;
511 anim.start( 1 );
512 checkTime.start();
513}
514
515/*
516 Roll according to the time elapsed.
517*/
518void QRollEffect::scroll()
519{
520 if ( !done && widget) {
521 widget->clearWState( WState_ForceHide );
522 int tempel = checkTime.elapsed();
523 if ( elapsed >= tempel )
524 elapsed++;
525 else
526 elapsed = tempel;
527
528 if ( currentWidth != totalWidth ) {
529 currentWidth = totalWidth * (elapsed/duration)
530 + ( 2 * totalWidth * (elapsed%duration) + duration )
531 / ( 2 * duration );
532 // equiv. to int( (totalWidth*elapsed) / duration + 0.5 )
533 done = (currentWidth >= totalWidth);
534 }
535 if ( currentHeight != totalHeight ) {
536 currentHeight = totalHeight * (elapsed/duration)
537 + ( 2 * totalHeight * (elapsed%duration) + duration )
538 / ( 2 * duration );
539 // equiv. to int( (totalHeight*elapsed) / duration + 0.5 )
540 done = (currentHeight >= totalHeight);
541 }
542 done = ( currentHeight >= totalHeight ) &&
543 ( currentWidth >= totalWidth );
544
545 int w = totalWidth;
546 int h = totalHeight;
547 int x = widget->geometry().x();
548 int y = widget->geometry().y();
549
550 if ( orientation & RightScroll || orientation & LeftScroll )
551 w = QMIN( currentWidth, totalWidth );
552 if ( orientation & DownScroll || orientation & UpScroll )
553 h = QMIN( currentHeight, totalHeight );
554
555 setUpdatesEnabled( FALSE );
556 if ( orientation & UpScroll )
557 y = widget->geometry().y() + QMAX( 0, totalHeight - currentHeight );
558 if ( orientation & LeftScroll )
559 x = widget->geometry().x() + QMAX( 0, totalWidth - currentWidth );
560 if ( orientation & UpScroll || orientation & LeftScroll )
561 move( x, y );
562
563 resize( w, h );
564 setUpdatesEnabled( TRUE );
565 repaint( FALSE );
566 }
567 if ( done ) {
568 anim.stop();
569 qApp->removeEventFilter( this );
570 if ( widget ) {
571 if ( !showWidget ) {
572 widget->hide();
573 widget->setWState( WState_ForceHide );
574 widget->clearWState( WState_Visible );
575 } else {
576 BackgroundMode bgm = widget->backgroundMode();
577 QColor erc = widget->eraseColor();
578 const QPixmap *erp = widget->erasePixmap();
579
580 widget->clearWState( WState_Visible );
581 widget->setBackgroundMode( NoBackground );
582 widget->show();
583 if ( bgm != FixedColor && bgm != FixedPixmap ) {
584 widget->clearWState( WState_Visible ); // prevent update in setBackgroundMode
585 widget->setBackgroundMode( bgm );
586 widget->setWState( WState_Visible );
587 }
588 if ( erc.isValid() ) {
589 widget->setEraseColor( erc );
590 } else if ( erp ) {
591 widget->setErasePixmap( *erp );
592 }
593 }
594 }
595 q_roll = 0;
596 deleteLater();
597 }
598}
599
600/*
601 Delete this after timeout
602*/
603
604#include "qeffects.moc"
605
606/*!
607 Scroll widget \a w in \a time ms. \a orient may be 1 (vertical), 2
608 (horizontal) or 3 (diagonal).
609*/
610void qScrollEffect( QWidget* w, QEffects::DirFlags orient, int time )
611{
612 if ( q_roll ) {
613 delete q_roll;
614 q_roll = 0;
615 }
616
617 qApp->sendPostedEvents( w, QEvent::Move );
618 qApp->sendPostedEvents( w, QEvent::Resize );
619#ifdef Q_WS_X11
620 uint flags = Qt::WStyle_Customize | Qt::WNoAutoErase | Qt::WStyle_StaysOnTop
621 | (w->isPopup() ? Qt::WType_Popup : (Qt::WX11BypassWM | Qt::WStyle_Tool));
622#else
623 uint flags = Qt::WStyle_Customize | Qt::WType_Popup | Qt::WX11BypassWM | Qt::WNoAutoErase | Qt::WStyle_StaysOnTop;
624#endif
625
626 // those can popups - they would steal the focus, but are disabled
627 q_roll = new QRollEffect( w, flags, orient );
628 q_roll->run( time );
629}
630
631/*!
632 Fade in widget \a w in \a time ms.
633*/
634void qFadeEffect( QWidget* w, int time )
635{
636 if ( q_blend ) {
637 delete q_blend;
638 q_blend = 0;
639 }
640
641 qApp->sendPostedEvents( w, QEvent::Move );
642 qApp->sendPostedEvents( w, QEvent::Resize );
643
644#ifdef Q_WS_X11
645 uint flags = Qt::WStyle_Customize | Qt::WNoAutoErase | Qt::WStyle_StaysOnTop
646 | (w->isPopup() ? Qt::WType_Popup : (Qt::WX11BypassWM | Qt::WStyle_Tool));
647#else
648 uint flags = Qt::WStyle_Customize | Qt::WType_Popup | Qt::WX11BypassWM | Qt::WNoAutoErase | Qt::WStyle_StaysOnTop;
649#endif
650
651 // those can popups - they would steal the focus, but are disabled
652 q_blend = new QAlphaWidget( w, flags );
653
654 q_blend->run( time );
655}
656#endif //QT_NO_EFFECTS
Note: See TracBrowser for help on using the repository browser.