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