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