Salome HOME
studyActivated() virtual method has been added
[modules/gui.git] / src / GLViewer / GLViewer_Viewer.cxx
1 // File:      GLViewer_Viewer.cxx
2 // Created:   November, 2004
3 // Author:    OCC team
4 // Copyright (C) CEA 2004
5
6 /***************************************************************************
7 **  Class:   GLViewer_Viewer
8 **  Descr:   Viewer for QAD-based application
9 **  Module:  QAD
10 **  Created: UI team, 05.09.00
11 ****************************************************************************/
12
13 #include "GLViewer_Viewer.h"
14
15 #include "GLViewer_Selector.h"
16 #include "GLViewer_ViewPort.h"
17 #include "GLViewer_ViewFrame.h"
18
19 #include "SUIT_Desktop.h"
20 #include "SUIT_ViewWindow.h"
21
22 #include <qpainter.h>
23 #include <qapplication.h>
24
25 /* used for sketching */
26 static QEvent* l_mbPressEvent = 0;
27
28 /*!
29     Constructor
30 */
31 GLViewer_Viewer::GLViewer_Viewer( const QString& title )
32 : SUIT_ViewModel(),
33 mySelector( 0 ),
34 mySketcher( 0 ),
35 myTransformer( 0 ),
36 mySelMode( NoSelection )
37 {
38 }
39
40 /*!
41     Destructor
42 */
43 GLViewer_Viewer::~GLViewer_Viewer()
44 {
45     delete mySelector;
46 }
47
48 //================================================================
49 // Function : setViewManager
50 // Purpose  : 
51 //================================================================
52 void GLViewer_Viewer::setViewManager(SUIT_ViewManager* theViewManager)
53 {
54   SUIT_ViewModel::setViewManager(theViewManager);
55   if (theViewManager) 
56   {
57     connect(theViewManager, SIGNAL(mousePress(SUIT_ViewWindow*, QMouseEvent*)), 
58             this, SLOT(onMouseEvent(SUIT_ViewWindow*, QMouseEvent*)));
59
60     connect(theViewManager, SIGNAL(mouseMove(SUIT_ViewWindow*, QMouseEvent*)), 
61             this, SLOT(onMouseEvent(SUIT_ViewWindow*, QMouseEvent*)));
62
63     connect(theViewManager, SIGNAL(mouseRelease(SUIT_ViewWindow*, QMouseEvent*)), 
64             this, SLOT(onMouseEvent(SUIT_ViewWindow*, QMouseEvent*)));
65
66     connect(theViewManager, SIGNAL(wheel(SUIT_ViewWindow*, QWheelEvent*)), 
67             this, SLOT(onWheelEvent(SUIT_ViewWindow*, QWheelEvent*)));
68   }
69 }
70
71 /*!
72     Returns the active view. [ public ]
73 */
74 GLViewer_ViewFrame* GLViewer_Viewer::getActiveView() const
75 {
76   SUIT_ViewManager* aMgr = getViewManager();
77   return (GLViewer_ViewFrame*)( aMgr != 0 ? aMgr->getActiveView() : 0 );
78 }
79
80
81 /*!
82     Sets the selection mode for this viewer. [ public ]
83 */
84 void GLViewer_Viewer::setSelectionMode( GLViewer_Viewer::SelectionMode mode )
85 {
86     if ( mySelMode != mode )
87     {
88         mySelMode = mode;
89         onSelectionModeChanged();
90     }
91 }
92
93 /*!
94     Returns selector of this viewer. [ public ]
95 */
96 GLViewer_Selector* GLViewer_Viewer::getSelector() const
97 {
98     if ( !mySelector )
99     {
100         GLViewer_Viewer* mthis = (GLViewer_Viewer*)this;
101         mthis->mySelector = mthis->createSelector();
102         if ( mySelector )
103         {
104             connect( mySelector, SIGNAL( selSelectionDone( bool, SelectionChangeStatus ) ), SLOT( onSelectionDone( bool, SelectionChangeStatus ) ) );
105             connect( mySelector, SIGNAL( selSelectionCancel() ), SLOT( onSelectionCancel() ) );
106         }
107     }
108     return mySelector;
109 }
110
111 /*!
112     Returns the selection mode of this viewer. [ public ]
113 */
114 GLViewer_Viewer::SelectionMode GLViewer_Viewer::getSelectionMode() const
115 {
116     return mySelMode;
117 }
118
119 /*!
120     Handles requests for sketching in the active view. [ virtual public ]
121 */
122 void GLViewer_Viewer::activateSketching( int type )
123 {
124     GLViewer_ViewPort* vp = 0;
125     if ( !getActiveView() || !( vp = getActiveView()->getViewPort() ) )
126         return;
127
128     if ( !vp->isSketchingEnabled() )
129         return;
130
131     /* Finish current sketching */
132     if ( type == NoSketching )
133     {
134         if ( mySketcher )
135         {
136             onSketchingFinished();
137             delete mySketcher;
138             mySketcher = 0;
139         }
140     }
141     /* Activate new sketching */
142     else
143     {
144         activateSketching( NoSketching );  /* concurrency not suported */
145         mySketcher = createSketcher( type );
146         onSketchingStarted();
147     }
148 }
149
150 /*!
151     Handles requests for transformations in the active view. [ virtual public ]
152 */
153 void GLViewer_Viewer::activateTransform( int type )
154 {
155     GLViewer_ViewPort* vp = 0;
156     if ( !getActiveView() || !( vp = getActiveView()->getViewPort() ) )
157         return;
158
159     if ( !vp->isTransformEnabled() )
160         return;
161
162     /* Finish current transform */
163     if ( type == NoTransform )
164     {
165         if ( myTransformer )
166         {
167             onTransformationFinished();
168             delete myTransformer;
169             myTransformer = 0;
170         }
171     }
172     /* Activate new transform */
173     else
174     {
175         activateTransform( NoTransform );  /* concurrency not suported */
176         myTransformer = createTransformer( type );
177         onTransformationStarted();
178         myTransformer->exec();
179     }
180 }
181
182 /*!
183     Creates default transformer. [ virtual protected ]
184 */
185 GLViewer_ViewTransformer* GLViewer_Viewer::createTransformer( int type )
186 {
187     return new GLViewer_ViewTransformer( this, type );
188 }
189
190 /*!
191     Creates default sketcher. [ virtual protected ]
192 */
193 GLViewer_ViewSketcher* GLViewer_Viewer::createSketcher( int type )
194 {
195     return new GLViewer_ViewSketcher( this, type );
196 }
197
198 /*!
199     Returns null by default. [ virtual protected ]
200 */
201 GLViewer_Selector* GLViewer_Viewer::createSelector()
202 {
203     return 0;
204 }
205
206 /*!
207     Unhilights detected entities, lock selection, sets event filter
208     on the whole application. [ virtual protected ]
209 */
210 void GLViewer_Viewer::onTransformationStarted()
211 {
212     unhilightDetected();
213     if ( getSelector() )
214         getSelector()->lock( true );        /* disable selection */
215
216     /*  Watch events: any mouse/key event outside the
217         viewport will be considered as the end of
218         transform */
219     if( !myTransformer )
220         return;
221     //int type = myTransformer->type();
222     qApp->installEventFilter( this );
223 }
224
225 /*!
226     Unlock selection, removes event filter. [ virtual protected ]
227 */
228 void GLViewer_Viewer::onTransformationFinished()
229 {
230     if ( getSelector() )
231         getSelector()->lock( false );           /* enable selection */
232
233     /* Stop watch events */
234     if( !myTransformer )
235         return;
236     //int type = myTransformer->type();
237     qApp->removeEventFilter( this );
238 }
239
240 /*!
241     Unhilights detected entities. [ virtual protected ]
242 */
243 void GLViewer_Viewer::onSketchingStarted()
244 {
245     unhilightDetected();
246 }
247
248 /*!
249     Selection by rectangle. [ virtual protected ]
250 */
251 void GLViewer_Viewer::onSketchingFinished()
252 {
253     if ( !getSelector() )
254         return;
255
256     if( !mySketcher )
257         return;
258     if ( mySketcher->type() == Rect )
259     {
260         QRect* selRect = (QRect*)mySketcher->data();
261         if ( selRect )
262         {
263             bool append = bool( mySketcher->buttonState() & GLViewer_Selector::appendKey() );
264             getSelector()->select( *selRect, append );
265         }
266     }
267 }
268
269 /*!
270     Installed while 'fit area' and 'global panning' operations are active. [ virtual protected ]
271 */
272 bool GLViewer_Viewer::eventFilter( QObject* o, QEvent* e )
273 {
274     if( !getActiveView() )
275         return false;
276
277     if( getActiveView()->getViewPort() == o->parent() ) // for QAD_GLWidget
278       o = o->parent();
279
280     bool mouseClickedOutside = ( e->type() == QEvent::MouseButtonPress &&
281                                  o != getActiveView()->getViewPort() );
282     bool anyKeyPressed = ( e->type() == QEvent::KeyPress );
283     if ( mouseClickedOutside || anyKeyPressed )
284     {   /* terminate all */
285         activateTransform( NoTransform );
286         activateSketching( NoSketching );
287         //cout << "mouseClickedOutside || anyKeyPressed" << endl;
288     }
289     return QObject::eventFilter( o, e );
290 }
291
292 /*!
293     Called when smth is selected in this viewer. [ virtual protected slot ]
294 */
295 void GLViewer_Viewer::onSelectionDone( bool bAdded, SelectionChangeStatus status  )
296 {
297     emit selectionChanged( status );
298 }
299
300 /*!
301     Called when selection is cleared in this viewer. [ virtual protected slot ]
302 */
303 void GLViewer_Viewer::onSelectionCancel()
304 {
305     emit selectionChanged( SCS_Invalid );
306 }
307
308 /*!
309     Listens to key events of the active view. [ virtual protected slot ]
310 */
311 void GLViewer_Viewer::onKeyEvent( SUIT_ViewWindow*, QKeyEvent* )
312 {
313 }
314
315 /*!
316     Listens to mouse events of the active view. [ virtual protected slot ]
317 */
318 void GLViewer_Viewer::onMouseEvent( SUIT_ViewWindow*, QMouseEvent* e )
319 {
320     //cout << "GLViewer_Viewer::onMouseEvent" << endl;
321     switch( e->type() )
322     {
323         case QEvent::MouseButtonPress:
324             handleMousePress( e );
325             break;
326         case QEvent::MouseMove:
327             handleMouseMove( e );
328             break;
329         case QEvent::MouseButtonRelease:
330             handleMouseRelease( e );
331             break;
332         default: break;
333     }
334 }
335
336 /*!
337     Listens to mouse events of the active view. [ virtual protected slot ]
338 */
339 void GLViewer_Viewer::onWheelEvent( SUIT_ViewWindow*, QWheelEvent* e )
340 {
341     //cout << "GLViewer_Viewer::onMouseEvent" << endl;
342     switch( e->type() )
343     {
344         case QEvent::Wheel:
345             handleWheel( e );
346             break;
347         default: break;
348     }
349 }
350
351 /*!
352     Enables / disables rectangle sketching. [ virtual protected ]
353 */
354 void GLViewer_Viewer::onSelectionModeChanged()
355 {
356     bool enable = ( mySelMode == Multiple );    
357     QPtrVector<SUIT_ViewWindow> views = getViewManager()->getViews();
358     for ( int i = 0, n = views.count(); i < n; i++ )
359     {
360         GLViewer_ViewPort* vp = ((GLViewer_ViewFrame*)views[i])->getViewPort();
361         if ( vp )
362             vp->setSketchingEnabled( enable );
363     }
364 }
365
366 /*!
367     Updates all views of this viewer. Use 'flags' to customize update process. [ virtual public ]
368 */
369 void GLViewer_Viewer::update( int flags )
370 {
371     QPtrVector<SUIT_ViewWindow> views = getViewManager()->getViews();
372     for ( int i = 0, n = views.count(); i < n; i++ )
373         ((GLViewer_ViewFrame*)views[i])->onUpdate( flags );
374 }
375
376 /*!
377     Unhilights the currect detected objects. [ virtual private ]
378 */
379 void GLViewer_Viewer::unhilightDetected()
380 {
381     if ( getSelector() )
382         getSelector()->detect( -1, -1 );
383 }
384
385 /*!
386     Mouse press handler. If 'accelKey()' is pressed, activates default
387     transformations( Zoom or Pan ) in the active viewport. [ private ]
388 */
389 void GLViewer_Viewer::handleMousePress( QMouseEvent* e )
390 {
391     /* test accel for transforms */
392     if ( e->state() & GLViewer_ViewTransformer::accelKey() )
393     {
394         ButtonState bs = e->button();
395         if ( bs == GLViewer_ViewTransformer::zoomButton() )
396             activateTransform( Zoom );
397         else if ( bs == GLViewer_ViewTransformer::panButton() )
398             activateTransform( Pan );
399     }
400     else
401     {
402         //checking for other operations before selection in release event
403         startOperations( e );
404     }
405
406     /* we may need it for sketching... */
407     l_mbPressEvent = new QMouseEvent( *e );
408
409     //checking for other operations before selection in release event
410 //    startOperations( e );
411
412     /*e->button() == LeftButton && getSelector() )
413     {
414         bool append = bool ( e->state() & GLViewer_Selector::appendKey() );
415         getSelector()->select( append );
416     }*/
417 }
418
419 /*!
420     Mouse move handler. If dragged with MB1, activates rectangle sketching in
421     the active viewport, otherwise highlights the selectable entities. [ private ]
422 */
423 void GLViewer_Viewer::handleMouseMove( QMouseEvent* e )
424 {
425     /* Highlight for selection */
426     bool dragged = ( e->state() & ( LeftButton | MidButton | RightButton ) );
427     if ( !dragged )
428     {
429         if ( getSelector() )
430             getSelector()->detect( e->x(), e->y() );
431     }
432     /* Try to activate default sketching
433     */
434     else if ( e->state() == GLViewer_ViewSketcher::sketchButton() )
435     {
436         activateSketching( Rect );
437         if ( mySketcher )
438         {
439             /*  Activated OK. We should not forget initial mousepress
440                 event and this mousemove event to start sketching from
441                 the point of initial click */
442             if ( l_mbPressEvent )
443             {
444                 QApplication::sendEvent( getActiveView()->getViewPort(), l_mbPressEvent );
445                 delete l_mbPressEvent;
446                 l_mbPressEvent = 0;
447             }
448             QApplication::sendEvent( getActiveView()->getViewPort(), e );
449         }
450     }
451     
452     //Try to activate other operations
453     updateOperations( e );
454 }
455
456 /*!
457     Mouse move handler. Activates popup of the active view. [ private ]
458 */
459 void GLViewer_Viewer::handleMouseRelease( QMouseEvent* e )
460 {
461     /* selection */
462     /* tmp - in handleMousePress*/  
463     if( e->button() == LeftButton && !(getActiveView()->getViewPort()->currentBlock() & BS_Selection) )
464     {
465         if ( getSelector() )
466         {
467             bool append = bool ( e->state() & GLViewer_Selector::appendKey() );
468             getSelector()->select( append );
469         }
470     }
471
472     //Try to done active operations
473     finishOperations( e );        
474
475     if ( l_mbPressEvent )
476     {
477         delete l_mbPressEvent;
478         l_mbPressEvent = 0;
479     }
480 }
481
482 /*!
483     Wheel rolling handler
484 */
485 void GLViewer_Viewer::handleWheel( QWheelEvent* e )
486 {
487     startOperations( e );
488 }
489
490 /****************************************************************
491 **  Class: GLViewer_ViewTransformer
492 **  Level: Public
493 *****************************************************************/
494 int GLViewer_ViewTransformer::panBtn = Qt::MidButton;
495 int GLViewer_ViewTransformer::zoomBtn = Qt::LeftButton;
496 int GLViewer_ViewTransformer::fitRectBtn = Qt::LeftButton;
497 int GLViewer_ViewTransformer::panGlobalBtn = Qt::LeftButton;
498 int GLViewer_ViewTransformer::acccelKey = Qt::ControlButton;
499
500 /*!
501     Constructor
502 */
503 GLViewer_ViewTransformer::GLViewer_ViewTransformer( GLViewer_Viewer* v, int type )
504 : QObject( 0 ),
505 myViewer( v ),
506 myType( type ),
507 myMajorBtn( NoButton ),
508 myButtonState( 0 )
509 {
510     if ( myType == GLViewer_Viewer::Pan ||
511          myType == GLViewer_Viewer::Zoom ||
512          myType == GLViewer_Viewer::PanGlobal ||
513          myType == GLViewer_Viewer::FitRect )
514     {
515         /* 'long' transforms need this */
516         initTransform( true );
517     }
518 }
519
520 /*!
521     Destructor
522 */
523 GLViewer_ViewTransformer::~GLViewer_ViewTransformer()
524 {
525     if ( myType == GLViewer_Viewer::Pan ||
526          myType == GLViewer_Viewer::Zoom ||
527          myType == GLViewer_Viewer::PanGlobal ||
528          myType == GLViewer_Viewer::FitRect )
529     {
530         /* 'long' transforms need this */
531         initTransform( false );
532     }
533
534     //QAD_Application::getDesktop()->clearInfo();
535 }
536
537 /*!
538     Inits long transformations ( Zoom, Pan etc ) [ protected ]
539
540     Saves viewport state( cursor etc ) and installs event filter to process
541     mouse events if 'init' is true. Restores viewport state if 'init' is false.
542 */
543 void GLViewer_ViewTransformer::initTransform( bool init )
544 {
545     GLViewer_ViewPort* avp = myViewer->getActiveView()->getViewPort();
546     if ( init )
547     {
548         mySavedCursor = avp->cursor();
549         mySavedMouseTrack = avp->hasMouseTracking();
550         avp->setMouseTracking( false );
551         avp->installEventFilter( this );
552     }
553     else
554     {
555         avp->removeEventFilter( this );
556         avp->setMouseTracking( mySavedMouseTrack );
557         avp->setCursor( mySavedCursor );
558     }
559 }
560
561 /*!
562     Runs transfomation. Redefine to add your own 'instant' transforms
563     ( for ex., 'FitAll' is an instant transform ). [ virtual public ]
564 */
565 void GLViewer_ViewTransformer::exec()
566 {
567     GLViewer_ViewPort* avp = myViewer->getActiveView()->getViewPort();
568     if( !avp )
569         return;
570
571     //QAD_Desktop* d = QAD_Application::getDesktop();
572     switch( myType )
573     {
574         case GLViewer_Viewer::Zoom:
575             myMajorBtn = zoomButton();
576             avp->setCursor( *avp->getZoomCursor() );
577             //d->putInfo( myViewer->tr( "PRP_VW_ZOOM" ) );
578             break;
579         case GLViewer_Viewer::Pan:
580             myMajorBtn = panButton();
581             avp->setCursor( *avp->getPanCursor() );
582             //d->putInfo( myViewer->tr( "PRP_VW_PAN" ) );
583             break;
584         case GLViewer_Viewer::PanGlobal:
585             myMajorBtn = panGlobalButton();
586             avp->setCursor( *avp->getPanglCursor() );
587             avp->fitAll( true, false );  /* view is ready now */
588             //d->putInfo( myViewer->tr( "PRP_VW_POINTCENTER" ) );
589             break;
590         case GLViewer_Viewer::FitRect:
591             myMajorBtn = fitRectButton();
592             avp->setCursor( *avp->getHandCursor() );
593             //d->putInfo( myViewer->tr( "PRP_VW_SKETCHAREA" ) );
594             break;
595         case GLViewer_Viewer::Reset:
596             avp->reset(); onTransform( Fin );
597             break;
598         case GLViewer_Viewer::FitAll:
599             avp->fitAll(); onTransform( Fin );
600             break;
601         case GLViewer_Viewer::FitSelect:
602             avp->fitSelect(); onTransform( Fin );
603             break;
604         default: break;
605     }
606 }
607
608 /*!
609     Catches mouse events for the viewport. [ virtual protected ]
610 */
611 bool GLViewer_ViewTransformer::eventFilter( QObject* o, QEvent* e )
612 {
613     switch ( e->type() )
614     {
615         case QEvent::MouseMove:
616         case QEvent::MouseButtonPress:
617         case QEvent::MouseButtonRelease:
618         {
619             TransformState state = EnTrain;
620             QMouseEvent* me = ( QMouseEvent* )e;
621
622             myButtonState = me->state();
623             if ( e->type() == QEvent::MouseButtonPress )
624                 myButtonState |= me->button();  /* add pressed button */
625
626             int mouseOnlyState = ( myButtonState & ( LeftButton | MidButton | RightButton ) );
627             if ( myStart.isNull() )
628             {
629                 state = Debut;
630                 myStart = me->pos();
631                 myMajorBtn = mouseOnlyState;
632             }
633
634             if ( e->type() == QEvent::MouseButtonRelease && mouseOnlyState == myMajorBtn )
635             {
636                 state = Fin;
637             }
638             myCurr = me->pos();
639             onTransform( state );
640             return true;
641         }
642         default: break;
643     }
644     return QObject::eventFilter( o, e );
645 }
646
647 /*!
648     Transforms the viewport. Used for 'non-instant' transforms
649     only( ex. Rotate, Pan etc ). [ virtual protected ]
650 */
651 void GLViewer_ViewTransformer::onTransform( TransformState state )
652 {
653     GLViewer_ViewPort* avp = myViewer->getActiveView()->getViewPort();
654     bool doTrsf = ( myButtonState & myMajorBtn );
655     switch ( myType )
656     {
657         case GLViewer_Viewer::Zoom:
658             if ( state != Fin && doTrsf )
659             {
660                 avp->zoom( myStart.x(), myStart.y(), myCurr.x(), myCurr.y() );
661                 myStart = myCurr;
662             }
663             break;
664         case GLViewer_Viewer::Pan:
665             if ( state != Fin && doTrsf )
666             {
667                 avp->pan( myCurr.x() - myStart.x(), myStart.y() - myCurr.y() );
668                 myStart = myCurr;
669             }
670             break;
671         case GLViewer_Viewer::PanGlobal:
672         {
673             if ( state == Fin )
674             avp->setCenter( myCurr.x(), myCurr.y() );
675             break;
676         }
677         case GLViewer_Viewer::FitRect:
678         {
679             if ( doTrsf )
680             {
681                 QRect rect( QMIN( myStart.x(), myCurr.x() ), QMIN( myStart.y(), myCurr.y() ),
682                             QABS( myStart.x() - myCurr.x() ), QABS( myStart.y() - myCurr.y() ) );
683                 if ( !rect.isEmpty() )
684                 {
685                     switch ( state )
686                     {
687                         case Fin:
688                             avp->fitRect( rect );
689                             break;
690                         default:
691                         {
692                             QPainter p( avp->getPaintDevice() ); // for QAD_GLWidget
693                             p.setPen( Qt::white );
694                             p.setRasterOp( Qt::XorROP );
695                             if ( !myDrawRect.isEmpty() )
696                                 p.drawRect( myDrawRect );    /* erase */
697                             p.drawRect( rect );
698                             myDrawRect = rect;
699                             break;
700                         }
701                     }
702                 }
703             }
704             break;
705         }
706         default:
707             break;
708     }
709
710     if ( state == Fin )
711         myViewer->activateTransform( GLViewer_Viewer::NoTransform );
712 }
713
714 /*!
715     Returns the type of the transformer. [ public ]
716 */
717 int GLViewer_ViewTransformer::type() const
718 {
719     return myType;
720 }
721
722
723 /****************************************************************
724 **  Class: GLViewer_ViewSketcher
725 **  Level: Public
726 *****************************************************************/
727 int GLViewer_ViewSketcher::sketchBtn = LeftButton;
728
729 /*!
730     Constructor
731 */
732 GLViewer_ViewSketcher::GLViewer_ViewSketcher( GLViewer_Viewer* viewer, int type )
733 : QObject( 0 ),
734 myViewer( viewer ),
735 myData( 0 ),
736 myType( type )
737 {
738     if( !myViewer )
739         return;
740     GLViewer_ViewPort* avp = myViewer->getActiveView()->getViewPort();
741     if( !avp )
742         return;
743
744     mySavedCursor = avp->cursor();
745     avp->setCursor( *GLViewer_ViewPort::getHandCursor() );
746     avp->installEventFilter( this );
747
748     if ( myType == GLViewer_Viewer::Rect )
749         myData = new QRect();
750 }
751
752 /*!
753     Destructor
754 */
755 GLViewer_ViewSketcher::~GLViewer_ViewSketcher()
756 {
757     GLViewer_ViewPort* avp = myViewer->getActiveView()->getViewPort();
758     avp->removeEventFilter( this );
759     avp->setCursor( mySavedCursor );
760
761     if ( myType == GLViewer_Viewer::Rect )
762         delete ( QRect* ) myData;
763
764     //QAD_Application::getDesktop()->clearInfo();
765 }
766
767 /*!
768     Catches mouse events for the viewport. [ virtual protected ]
769 */
770 bool GLViewer_ViewSketcher::eventFilter( QObject* o, QEvent* e )
771 {
772     switch ( e->type() )
773     {
774         case QEvent::MouseMove:
775         case QEvent::MouseButtonPress:
776         case QEvent::MouseButtonRelease:
777         {
778             SketchState state = EnTrain;
779             QMouseEvent* me = (QMouseEvent*)e;
780
781             myButtonState = me->state();
782             if ( e->type() == QEvent::MouseButtonPress )
783                 myButtonState |= me->button();  /* add pressed button */
784
785             if ( myStart.isNull() )
786             {
787                 state = Debut;
788                 myStart = me->pos();
789             }
790
791             int mouseOnlyState = ( myButtonState & ( LeftButton | MidButton | RightButton ) );
792             if ( e->type() == QEvent::MouseButtonRelease && mouseOnlyState == sketchButton() )
793             {
794                 state = Fin;
795             }
796             myCurr = me->pos();
797             onSketch( state );
798             return true;
799         }
800         default: break;
801     }
802     return QObject::eventFilter( o, e );
803 }
804
805 /*!
806     Draws in the viewport. [ virtual protected ]
807 */
808 void GLViewer_ViewSketcher::onSketch( SketchState state )
809 {
810     GLViewer_ViewPort* avp = myViewer->getActiveView()->getViewPort();
811     if( !avp )
812         return;
813
814     if( myType == GLViewer_Viewer::Rect )
815     {
816         QRect* sketchRect = ( QRect* )data();
817         if ( myButtonState & sketchButton() )
818         {
819             QRect rect( QMIN( myStart.x(), myCurr.x() ), QMIN( myStart.y(), myCurr.y() ),
820                         QABS( myStart.x() - myCurr.x() ), QABS( myStart.y() - myCurr.y() ) );
821             if ( !rect.isEmpty() )
822             {
823                 QPainter p( avp );
824                 p.setPen( Qt::white );
825                 p.setRasterOp( Qt::XorROP );
826                 if ( !sketchRect->isEmpty() )
827                     p.drawRect( *sketchRect );    /* erase */
828                 *sketchRect = rect;
829                 if ( state != Fin )
830                     p.drawRect( *sketchRect );
831             }
832         }
833     }
834
835     if ( state == Fin )
836     {
837         QApplication::syncX();  /* force rectangle redrawing */
838         myViewer->activateSketching( GLViewer_Viewer::NoSketching );
839     }
840 }