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