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