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