Salome HOME
Moved some functionality to VTKViewer_Utilities.h
[modules/kernel.git] / src / OCCViewer / OCCViewer_ViewPort.cxx
1 //  SALOME OCCViewer : build OCC Viewer into Salome desktop
2 //
3 //  Copyright (C) 2003  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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : OCCViewer_ViewPort.cxx
25 //  Author : Nicolas REJNERI
26 //  Module : SALOME
27 //  $Header$
28
29 #include <stdlib.h>
30
31 #if !defined WNT
32 #define QT_CLEAN_NAMESPACE         /* avoid definition of INT32 and INT8 */
33 #endif
34
35 #include "OCCViewer_ViewPort.h"
36
37 #include "QAD.h"
38 #include "QAD_Tools.h"
39 #include "QAD_Desktop.h"
40 #include "QAD_MessageBox.h"
41
42 #if !defined WNT
43 #include <GL/glx.h>
44 #include <X11/Xlib.h>
45 #include <X11/Xutil.h>
46 #include <X11/Xatom.h>
47 #include <X11/Xmu/StdCmap.h>
48 #undef QT_CLEAN_NAMESPACE
49 #include <Xw_Window.hxx>
50 #include <Graphic3d_GraphicDevice.hxx>
51
52 #include <qpixmap.h>
53 #include <qintdict.h>
54
55 #include "utilities.h"
56
57 using namespace std;
58
59 /* XPM */
60 const char* imageZoomCursor[] = { 
61 "32 32 3 1",
62 ". c None",
63 "a c #000000",
64 "# c #ffffff",
65 "................................",
66 "................................",
67 ".#######........................",
68 "..aaaaaaa.......................",
69 "................................",
70 ".............#####..............",
71 "...........##.aaaa##............",
72 "..........#.aa.....a#...........",
73 ".........#.a.........#..........",
74 ".........#a..........#a.........",
75 "........#.a...........#.........",
76 "........#a............#a........",
77 "........#a............#a........",
78 "........#a............#a........",
79 "........#a............#a........",
80 ".........#...........#.a........",
81 ".........#a..........#a.........",
82 ".........##.........#.a.........",
83 "........#####.....##.a..........",
84 ".......###aaa#####.aa...........",
85 "......###aa...aaaaa.......#.....",
86 ".....###aa................#a....",
87 "....###aa.................#a....",
88 "...###aa...............#######..",
89 "....#aa.................aa#aaaa.",
90 ".....a....................#a....",
91 "..........................#a....",
92 "...........................a....",
93 "................................",
94 "................................",
95 "................................",
96 "................................"};
97
98 const char* imageRotateCursor[] = { 
99 "32 32 3 1",
100 ". c None",
101 "a c #000000",
102 "# c #ffffff",
103 "................................",
104 "................................",
105 "................................",
106 "................................",
107 "........#.......................",
108 ".......#.a......................",
109 "......#######...................",
110 ".......#aaaaa#####..............",
111 "........#..##.a#aa##........##..",
112 ".........a#.aa..#..a#.....##.aa.",
113 ".........#.a.....#...#..##.aa...",
114 ".........#a.......#..###.aa.....",
115 "........#.a.......#a..#aa.......",
116 "........#a.........#..#a........",
117 "........#a.........#a.#a........",
118 "........#a.........#a.#a........",
119 "........#a.........#a.#a........",
120 ".........#.........#a#.a........",
121 "........##a........#a#a.........",
122 "......##.a#.......#.#.a.........",
123 "....##.aa..##.....##.a..........",
124 "..##.aa.....a#####.aa...........",
125 "...aa.........aaa#a.............",
126 "................#.a.............",
127 "...............#.a..............",
128 "..............#.a...............",
129 "...............a................",
130 "................................",
131 "................................",
132 "................................",
133 "................................",
134 "................................"};
135
136 struct CMapEntry {
137   CMapEntry();
138   ~CMapEntry();
139   Colormap cmap;
140   bool alloc;
141   XStandardColormap     scmap;
142 };
143
144 CMapEntry::CMapEntry()
145 {
146   cmap = 0;
147   alloc = false;
148   scmap.colormap = 0;
149 }
150
151 CMapEntry::~CMapEntry()
152 {
153   if ( alloc )
154     XFreeColormap( QPaintDevice::x11AppDisplay(), cmap );
155 }
156
157 static QIntDict<CMapEntry> *cmap_dict = 0;
158 static bool mesa_gl = false;
159
160 static void cleanup_cmaps()
161 {
162   if ( !cmap_dict )
163     return;
164   cmap_dict->setAutoDelete(true);
165   delete cmap_dict;
166   cmap_dict = 0;
167 }
168
169 static Colormap choose_cmap(Display *dpy, XVisualInfo *vi)
170 {
171   if ( !cmap_dict ) 
172     {
173       cmap_dict = new QIntDict<CMapEntry>;
174       const char *v = glXQueryServerString( dpy, vi->screen, GLX_VERSION );
175       mesa_gl = strstr(v,"Mesa") != 0;
176       qAddPostRoutine( cleanup_cmaps );
177     }
178   
179   CMapEntry *x = cmap_dict->find( (long)vi->visualid );
180   if ( x )                                      // found colormap for visual
181     return x->cmap;
182   
183   x = new CMapEntry();
184   
185   XStandardColormap *c;
186   int n, i;
187   
188 #ifdef DEBUG
189   MESSAGE( "Choosing cmap for vID = " << vi->visualid );
190 #endif
191   
192   if ( vi->visualid == XVisualIDFromVisual( (Visual*)QPaintDevice::x11AppVisual() ) ) 
193     {
194 #ifdef DEBUG
195       MESSAGE( "Using x11AppColormap" );
196 #endif
197       return QPaintDevice::x11AppColormap();
198     }
199   
200   if ( mesa_gl ) 
201     {   
202       Atom hp_cmaps = XInternAtom( dpy, "_HP_RGB_SMOOTH_MAP_LIST", true );
203       if ( hp_cmaps && vi->visual->c_class == TrueColor && vi->depth == 8 ) 
204         {
205           if ( XGetRGBColormaps(dpy, RootWindow(dpy,vi->screen), &c, &n, hp_cmaps) ) 
206             {
207               i = 0;
208               while ( i < n && x->cmap == 0 ) 
209                 {
210                   if ( c[i].visualid == vi->visual->visualid ) 
211                     {
212                       x->cmap = c[i].colormap;
213                       x->scmap = c[i];
214                       // Using HP_RGB scmap
215                     }
216                   i++;
217                 }
218               XFree( (char *)c );
219             }
220         }
221     }
222   
223 #if !defined(_OS_SOLARIS_)
224   if ( !x->cmap ) 
225     {
226       if ( XmuLookupStandardColormap(dpy,vi->screen,vi->visualid,vi->depth,
227                                      XA_RGB_DEFAULT_MAP,false,true) ) 
228         {
229           if ( XGetRGBColormaps(dpy,RootWindow(dpy,vi->screen),&c,&n,
230                                 XA_RGB_DEFAULT_MAP) ) 
231             {
232               i = 0;
233               while ( i < n && x->cmap == 0 ) 
234                 {
235                   if ( c[i].visualid == vi->visualid ) 
236                     {
237                       x->cmap = c[i].colormap;
238                       x->scmap = c[i];
239                       // Using RGB_DEFAULT scmap
240                     }
241                   i++;
242                 }
243               XFree( (char *)c );
244             }
245         }
246     }
247 #endif
248   if ( !x->cmap ) 
249     {                           
250       // no shared cmap found
251       x->cmap = XCreateColormap( dpy, RootWindow(dpy,vi->screen), vi->visual,
252                                  AllocNone );
253       x->alloc = true;
254       // Allocating cmap
255     }
256   
257   cmap_dict->insert( (long)vi->visualid, x ); // associate cmap with visualid
258   return x->cmap;
259 }       
260 #endif
261
262 /* statics */
263 int             OCCViewer_ViewPort::nCounter    = 0;
264 QCursor*        OCCViewer_ViewPort::defCursor   = NULL;
265 QCursor*        OCCViewer_ViewPort::handCursor  = NULL;
266 QCursor*        OCCViewer_ViewPort::panCursor   = NULL;
267 QCursor*        OCCViewer_ViewPort::zoomCursor  = NULL;
268 QCursor*        OCCViewer_ViewPort::rotCursor   = NULL;
269 QCursor*        OCCViewer_ViewPort::glPanCursor = NULL;
270
271 /*!
272     Creates the necessary viewport cursors [ static ]
273 */
274 void OCCViewer_ViewPort::createCursors ()
275 {
276   defCursor    = new QCursor ( ArrowCursor );
277   handCursor   = new QCursor ( PointingHandCursor );
278   panCursor    = new QCursor ( SizeAllCursor  );
279   zoomCursor   = new QCursor (QPixmap(imageZoomCursor));
280   rotCursor    = new QCursor (QPixmap(imageRotateCursor));
281   glPanCursor  = new QCursor (CrossCursor);
282 //  QAD_ResourceMgr* rmgr = QAD_Desktop::getResourceManager();
283 //  zoomCursor = new QCursor ( rmgr->loadPixmap( "QAD", tr("ICON_CURSOR_ZOOM") ));
284 //  rotCursor = new QCursor ( rmgr->loadPixmap( "QAD", tr("ICON_CURSOR_ROTATE") ));
285 }
286
287 /*!
288     Destroys the viewport cursors [ static ]
289 */
290 void OCCViewer_ViewPort::destroyCursors ()
291 {
292   if ( defCursor ) delete defCursor;
293   defCursor = 0;
294   if ( handCursor ) delete handCursor;
295   handCursor = 0;
296   if ( panCursor ) delete panCursor;
297   panCursor = 0;
298   if ( zoomCursor ) delete zoomCursor;
299   zoomCursor = 0;
300   if ( rotCursor ) delete rotCursor;
301   rotCursor = 0;
302   if ( glPanCursor ) delete glPanCursor;
303   glPanCursor = 0;
304 }
305
306 /*!
307     Sets new default cursor [ static ]
308 */
309 void OCCViewer_ViewPort::setDefaultCursor(const QCursor& newCursor) 
310 {
311   if ( !defCursor ) defCursor = new QCursor; 
312   *defCursor = newCursor; 
313 }
314
315 /*!
316     Sets new cursor for drawing rectangle in the viewport [ static ]
317 */
318 void OCCViewer_ViewPort::setHandCursor(const QCursor& newCursor) 
319
320   if ( !handCursor ) handCursor = new QCursor;
321   *handCursor = newCursor; 
322 }
323
324 /*!
325     Sets new cursor for panning [ static ]
326 */
327 void OCCViewer_ViewPort::setPanCursor(const QCursor& newCursor) 
328
329   if ( !panCursor ) panCursor = new QCursor;
330   *panCursor = newCursor; 
331 }
332
333 /*!
334     Sets new cursor for zooming [ static ]
335 */
336 void OCCViewer_ViewPort::setZoomCursor(const QCursor& newCursor) 
337
338   if ( !zoomCursor ) zoomCursor = new QCursor;
339   *zoomCursor = newCursor; 
340 }
341
342 /*!
343     Sets new cursor for rotating [ static ]
344 */
345 void OCCViewer_ViewPort::setRotCursor(const QCursor& newCursor) 
346
347   if ( !rotCursor ) rotCursor = new QCursor;
348   *rotCursor = newCursor; 
349 }
350
351 /*!
352     Sets new cursor for global panning [ static ]
353 */
354 void OCCViewer_ViewPort::setGlPanCursor(const QCursor& newCursor) 
355
356   if ( !glPanCursor ) glPanCursor = new QCursor;
357   *glPanCursor = newCursor; 
358 }
359
360 /*!
361     Constructor
362 */
363 OCCViewer_ViewPort::OCCViewer_ViewPort(QWidget* parent) : 
364   QWidget( parent, 0, WRepaintNoErase | WResizeNoErase)
365 {
366   initialize();
367 }
368
369 /*!
370     Destructor
371 */
372 OCCViewer_ViewPort::~OCCViewer_ViewPort()
373 {
374   cleanup();
375 }
376
377 /*!
378     Initializes viewport
379 */
380 void OCCViewer_ViewPort::initialize()
381 {
382   /* initialize cursors */
383   if ( nCounter++ == 0 ) createCursors();
384
385 #if !defined WNT
386
387   XVisualInfo* pVisualInfo;
388   if ( x11Display() ) 
389     {
390       /* Initialization with the default VisualID
391        */
392       //NRI Visual *v = DefaultVisual(x11Display(), DefaultScreen(x11Display()));
393       //NRI int visualID = XVisualIDFromVisual(v);
394
395           /*  Here we use the settings from 
396               Optimizer_ViewInfo::TxglCreateWindow()
397           */
398       int visualAttr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 1, 
399                            GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
400                            GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER,
401                            None };
402
403       pVisualInfo = ::glXChooseVisual (x11Display(), DefaultScreen(x11Display()), visualAttr);
404           
405       if ( isVisible() ) hide();
406           
407       XSetWindowAttributes a;
408           
409       a.colormap = choose_cmap( x11Display(), pVisualInfo );        /* find best colormap */
410       a.background_pixel = backgroundColor().pixel();
411       a.border_pixel = black.pixel();
412       Window p = RootWindow( x11Display(), DefaultScreen(x11Display()) ); 
413       if ( parentWidget() ) p = parentWidget()->winId();
414           
415       Window w = XCreateWindow( x11Display(), p,  x(), y(), width(), height(),
416                                 0, pVisualInfo->depth, InputOutput,  pVisualInfo->visual,
417                                 CWBackPixel | CWBorderPixel | CWColormap, &a );
418       Window *cmw;
419       Window *cmwret;
420       int count;
421       if ( XGetWMColormapWindows( x11Display(), topLevelWidget()->winId(), &cmwret, &count ) )
422         {
423           cmw = new Window[count+1];
424           memcpy( (char *)cmw, (char *)cmwret, sizeof(Window)*count );
425           XFree( (char *)cmwret );
426           int i;
427               
428           for (i = 0; i < count; i++) 
429             {
430               if ( cmw[i] == winId() ) /* replace old window */
431                 {               
432                   cmw[i] = w;
433                   break;
434                 }
435             }
436               
437           if ( i >= count )                      /* append new window */
438             cmw[count++] = w;
439         } 
440       else 
441         {
442           count = 1;
443           cmw = new Window[count];
444           cmw[0] = w;
445         }
446           
447       /* Creating new window (with good VisualID) for this widget
448            */
449       create(w);
450       XSetWMColormapWindows( x11Display(), topLevelWidget()->winId(), cmw, count );
451       delete [] cmw;
452           
453       if ( isVisible() ) show();
454           
455       if ( pVisualInfo ) {
456         XFree( (char *)pVisualInfo );
457       }
458           
459       XFlush(x11Display());
460       //                XSync(x11Display(), false);
461       //                XSynchronize(x11Display(), true);
462     } 
463 #endif  // !defined WNT
464   
465   myOriginalViewport = NULL;    
466   myCursorIsHand = false;
467   myCursor = *defCursor;
468   myHasWindow = false;
469   myDrawRect = false;
470   myStartX = myStartY = myCurrX = myCurrY =0;
471   myPaintersRedrawing = false;
472   myEnableDrawMode = true;
473   
474   setTransformRequested ( NOTHING );
475   setTransformInProcess ( false );
476   
477   setMouseTracking( true );
478   setBackgroundMode(NoBackground);
479
480   setFocus();
481 }
482
483 /*!
484     Cleans up the viewport
485 */
486 void OCCViewer_ViewPort::cleanup()
487 {
488   if ( --nCounter == 0 ) 
489     destroyCursors();
490 }
491
492 /*!
493     Sets the original view for the viewport   
494 */
495 void OCCViewer_ViewPort::setOriginalView( OCCViewer_ViewPort* viewport, 
496                                           const QRect& magnify )
497 {
498   myOriginalViewport = viewport;
499   myMagnifyRect = magnify;
500 }
501
502 /*!
503     Returns the original view or null
504 */
505 OCCViewer_ViewPort* OCCViewer_ViewPort::getOriginalView() const
506 {
507   return myOriginalViewport;
508 }
509
510 /*!
511     Returns the 'magnify' rect ( used for 'magnify' operation )
512 */
513 const QRect& OCCViewer_ViewPort::getMagnifyRect() const
514 {
515   return myMagnifyRect;
516 }
517
518 /*!
519     Returns the sketched rect ( used for multiple selection )
520 */
521 const QRect& OCCViewer_ViewPort::getSelectionRect() const
522 {
523   return myRect;
524 }
525
526 /*!
527     Returns 'true' if the viewport has a native window
528 */
529 bool OCCViewer_ViewPort::hasWindow() const
530 {
531   return myHasWindow;
532 }
533
534 /*!
535     Must be called if native window was changed 
536 */
537 void OCCViewer_ViewPort::windowChanged() 
538 {
539   myHasWindow = false;
540 }
541
542 /*!
543     Sets the default cursor active    
544 */
545 void OCCViewer_ViewPort::setDefaultCursorOn()
546 {
547   setCursor ( *OCCViewer_ViewPort::defCursor );
548 }
549
550 /*!
551     Sets the 'hand' cursor active    
552 */
553 void OCCViewer_ViewPort::setHandCursorOn()
554 {
555   setCursor ( *OCCViewer_ViewPort::handCursor );
556 }
557
558 /*!
559     Sets the panning cursor active    
560 */
561 void OCCViewer_ViewPort::setPanCursorOn()
562 {
563   setCursor( *OCCViewer_ViewPort::panCursor );
564 }
565
566 /*!
567     Sets the zooming cursor active    
568 */
569 void OCCViewer_ViewPort::setZoomCursorOn()
570 {
571   setCursor( *OCCViewer_ViewPort::zoomCursor );
572 }
573
574 /*!
575     Sets the rotating cursor active    
576 */
577 void OCCViewer_ViewPort::setRotCursorOn()
578 {
579   setCursor( *OCCViewer_ViewPort::rotCursor );
580 }
581
582 /*!
583     Sets the global panning cursor active    
584 */
585 void OCCViewer_ViewPort::setGlPanCursorOn()
586 {
587   setCursor( *OCCViewer_ViewPort::glPanCursor );
588 }
589
590 /*!
591     Returns the default background color
592 */
593 QColor OCCViewer_ViewPort::backgroundColor() const
594 {
595   return Qt::white;
596 }
597
598 /*!
599     Activates 'zoom' transformation
600 */
601 void OCCViewer_ViewPort::activateZoom()
602 {
603   if ( !transformRequested() && !myCursorIsHand )
604     myCursor = cursor();                /* save old cursor */
605   
606   if ( myOperation != ZOOMVIEW ) {
607     setTransformRequested ( ZOOMVIEW );         
608     setCursor( *zoomCursor );
609   }
610 }
611
612 /*!
613     Activates 'panning' transformation
614 */
615 void OCCViewer_ViewPort::activatePanning()
616 {
617   if ( !transformRequested() && !myCursorIsHand )
618     myCursor = cursor();                /* save old cursor */
619   
620   if ( myOperation != PANVIEW ) {
621     setTransformRequested ( PANVIEW );
622     setCursor( *panCursor );
623   }
624 }
625
626 /*!
627     Activates 'rotation' transformation
628 */
629 void OCCViewer_ViewPort::activateRotation()
630 {
631   if ( !transformRequested() && !myCursorIsHand )
632     myCursor = cursor();                /* save old cursor */
633   
634   if ( myOperation != ROTATE ) {
635     setTransformRequested ( ROTATE );
636     setCursor( *rotCursor );    
637   }
638 }
639
640 /*!
641     Activates 'fit' transformation
642 */
643 void OCCViewer_ViewPort::activateWindowFit()
644 {
645   if ( !transformRequested() && !myCursorIsHand )
646     myCursor = cursor();                /* save old cursor */
647
648   if ( myOperation != WINDOWFIT ) {
649     setTransformRequested ( WINDOWFIT );                
650     setCursor ( *handCursor );
651     myCursorIsHand = true;
652   }
653 //  setTransformInProcess( true );              
654 //  emit vpTransformationStarted ( WINDOWFIT );
655 }
656
657 /*!
658     Activates 'global panning' transformation
659 */
660 void OCCViewer_ViewPort::activateGlobalPanning()
661 {
662   if ( !transformRequested() && !myCursorIsHand )
663     myCursor = cursor();                /* save old cursor */
664   
665   if ( myOperation != PANGLOBAL ) 
666     {
667       fitAll(); /* fits view before selecting a new scene center */
668       setTransformRequested ( PANGLOBAL );
669       setCursor( *glPanCursor );
670     }
671 //  setTransformInProcess( true );              
672 //  emit vpTransformationStarted ( PANGLOBAL );
673 }
674
675 /*!
676     Sets the viewport to its initial state
677     ( no transformations in process etc. )
678 */
679 void OCCViewer_ViewPort::resetState()
680 {
681   myDrawRect = false;
682   
683   /* make rectangle empty (left > right) */
684   myRect.setLeft(2);
685   myRect.setRight(0);
686   
687   if ( transformRequested() || myCursorIsHand ) 
688     setCursor( myCursor );
689   myCursorIsHand = false;
690   
691   if ( transformRequested() ) 
692     emit vpTransformationFinished (myOperation);
693   
694   setTransformInProcess( false );               
695   setTransformRequested ( NOTHING );    
696   QAD_Application::getDesktop()->putInfo( tr("INF_READY") );
697 }
698
699 /*!
700     Enable/disable user's ability to sketch a rect in the viewport
701 */
702 void OCCViewer_ViewPort::enableDrawMode(bool bEnable )
703 {
704   myEnableDrawMode = bEnable;
705 }
706
707 /*!
708     Returns 'true' if user can sketch a rect in the viewport
709 */
710 bool OCCViewer_ViewPort::enableDrawMode() const
711 {
712   return myEnableDrawMode;
713 }
714
715 /*!
716     Sets the active operation 'op'
717 */
718 void OCCViewer_ViewPort::setTransformRequested ( OperationType op )
719 {    
720   myOperation = op;
721   setMouseTracking ( myOperation == NOTHING );  
722 }
723
724 /*!
725     Mouse event handler
726 */
727 void OCCViewer_ViewPort::mousePressEvent (QMouseEvent* event)
728 {
729   myStartX = event->x();
730   myStartY = event->y();
731   switch ( myOperation )
732     {
733     case WINDOWFIT:
734       if ( event->button() == Qt::LeftButton )
735         emit vpTransformationStarted ( WINDOWFIT );
736       break;    
737 //      return;
738     case PANGLOBAL:
739       if ( event->button() == Qt::LeftButton )
740         emit vpTransformationStarted ( PANGLOBAL );
741       break;    
742 //      return;
743       
744     case ZOOMVIEW:
745       if ( event->button() == Qt::LeftButton )
746         emit vpTransformationStarted ( ZOOMVIEW );
747       break;
748       
749     case PANVIEW:
750       if ( event->button() == Qt::LeftButton )
751         emit vpTransformationStarted ( PANVIEW );
752       break;
753
754     case ROTATE:
755       if ( event->button() == Qt::LeftButton )
756         {
757           startRotation(myStartX, myStartY);
758           emit vpTransformationStarted ( ROTATE );
759         }
760       break;
761       
762     default:
763       
764       /*        Try to activate a transformation
765        */
766       if ( (event->state() == Qt::ControlButton) &&
767            (event->button() == Qt::LeftButton) )
768         {
769                                 /* MB1 + CTRL = Zooming */
770           activateZoom();
771         }
772       else if ( (event->state() == Qt::ControlButton) &&
773                 (event->button() == Qt::MidButton) )
774         {
775                                 /* MB2 + CTRL = Panning */
776           activatePanning();
777         }
778       else if ( (event->state() == Qt::ControlButton) &&
779                 (event->button() == Qt::RightButton) )
780         {
781                                 /* MB3 + CTRL = Rotation */
782           activateRotation();
783           startRotation(myStartX, myStartY);
784         }
785       
786       /* notify that we start a transformation */
787       if ( transformRequested() ) 
788         emit vpTransformationStarted ( myOperation );
789     }
790   
791   if ( transformRequested() ) 
792     setTransformInProcess( true );              
793   
794   /*  NOTE: this signal must be emitted at the end 
795       because we must to detect a transformation first
796   */
797   emit vpMousePress (event);
798 }
799
800 /*!
801     Mouse event handler 
802 */
803 void OCCViewer_ViewPort::mouseMoveEvent (QMouseEvent* event)
804 {
805   myCurrX = event->x();
806   myCurrY = event->y();
807   switch (myOperation)
808     {
809     case ROTATE:
810       rotate(myCurrX, myCurrY);
811       break;
812       
813     case ZOOMVIEW:
814       zoom(myStartX, myStartY, myCurrX, myCurrY);
815       myStartX = myCurrX;
816       myStartY = myCurrY;
817       break;
818       
819     case PANVIEW:
820       pan(myCurrX - myStartX, myStartY - myCurrY);
821       myStartX = myCurrX;
822       myStartY = myCurrY;
823       break;
824       
825 /*    case WINDOWFIT:
826       myDrawRect = true;
827       repaint();
828       break;
829 */      
830     case PANGLOBAL:
831       break;
832       
833     default:
834       if ( event->state() == Qt::LeftButton ||
835            event->state() == ( Qt::LeftButton | Qt::ShiftButton) )
836         {
837           myDrawRect = myEnableDrawMode;
838           if ( myDrawRect ) 
839             {
840               repaint( visibleRect(), false);
841               if ( !myCursorIsHand )
842                 {   /* we are going to sketch a rectangle */                                        
843                   myCursorIsHand = true;                
844                   myCursor = cursor();
845                   setCursor ( *handCursor );
846                 }
847             }
848         }
849     }
850   emit vpMouseMove( event );                    
851 }
852
853 /*!
854     Mouse event handler 
855 */
856 void OCCViewer_ViewPort::mouseReleaseEvent (QMouseEvent* event)
857 {
858   if ( !transformRequested() && (event->button() == Qt::RightButton) )
859     {
860       QPopupMenu* popup = createPopup();
861       if ( popup ) {
862         QAD_Tools::checkPopup( popup );
863         if ( popup->count()>0 ) {
864           popup->exec( QCursor::pos() );
865         }
866         destroyPopup();
867       }
868       return;
869     }
870   
871   switch ( myOperation )
872     {
873     case NOTHING:
874       break;
875     case ROTATE:
876       endRotation();
877       resetState();
878       break;
879       
880     case PANVIEW:
881     case ZOOMVIEW:
882       resetState();
883       break;
884       
885     case PANGLOBAL:
886       if ( event->button() == Qt::LeftButton )
887         {
888           setCenter( event->x(), event->y() );
889           resetState();
890         }
891       break;
892       
893     case WINDOWFIT:
894       if ( event->state() == Qt::LeftButton )
895         {
896           myCurrX = event->x();
897           myCurrY = event->y();
898           QRect rect = QAD_Tools::makeRect(myStartX, myStartY, myCurrX, myCurrY);
899           if ( !rect.isEmpty() ) fitWindow(rect);
900           resetState();
901         }
902       break;
903     }
904   
905   // NOTE: viewer 3D detects a rectangle of selection using this event
906   // so we must emit it BEFORE resetting the selection rectangle
907   emit vpMouseRelease  (event);         
908   
909   if ( event->button() == Qt::LeftButton && myDrawRect )
910     {
911       myDrawRect = false;
912       repaint(visibleRect(), false);
913       resetState(); 
914     }
915 }
916
917 /*!
918     Mouse event handler 
919 */
920 void OCCViewer_ViewPort::mouseDoubleClickEvent(QMouseEvent *event)
921 {
922   emit vpMouseDoubleClick (event);
923 }
924
925 /*!
926     Key event handler 
927 */
928 void OCCViewer_ViewPort::keyPressEvent(QKeyEvent *event)
929 {
930   emit vpKeyPress (event);
931 }
932
933 /*!
934     Key event handler 
935 */
936 void OCCViewer_ViewPort::keyReleaseEvent(QKeyEvent *event)
937 {
938   emit vpKeyRelease (event);
939 }
940
941 /*!
942     Called when the viewport gets the focus
943 */
944 void OCCViewer_ViewPort::focusInEvent(QFocusEvent *event)
945 {
946   emit vpFocusIn (event);
947 }
948
949 /*!
950     Called when the viewport loses the focus
951 */
952 void OCCViewer_ViewPort::focusOutEvent(QFocusEvent *event)
953 {
954   emit vpFocusOut (event);
955 }
956         
957 /*!
958     Resizes the viewport
959 */
960 void OCCViewer_ViewPort::resizeEvent (QResizeEvent* event)
961 {
962   windowResize();
963 }
964
965 /*!
966     Updates the viewport
967 */
968 void OCCViewer_ViewPort::update(int x, int y, int w, int h)
969 {
970   if ( !myHasWindow )
971     myHasWindow = setWindow();
972   if ( myHasWindow) 
973     repaint(x, y, w, h, true);
974 }
975
976 /*!
977     Repaints the viewport    
978 */
979 void OCCViewer_ViewPort::paintEvent (QPaintEvent *ev)
980 {
981   emit vpPaint (ev);
982   if ( myDrawRect )     
983     {
984       QPainter thePainter(this);
985       thePainter.setRasterOp(Qt::XorROP);
986       thePainter.setPen(Qt::white);
987       QRect aRect = QAD_Tools::makeRect(myStartX, myStartY, myCurrX, myCurrY);
988       if ( !myRect.isEmpty() )
989         thePainter.drawRect( myRect );
990       thePainter.drawRect(aRect);
991       myRect = aRect;
992     }
993
994   if ( myPaintersRedrawing )
995     {
996       QPainter thePainter(this);
997       emit vpDrawExternal  (&thePainter);
998       myPaintersRedrawing = false;
999     }
1000 }
1001
1002 /*!
1003   Forces to redraw the viewport by an external painter     
1004 */
1005 void OCCViewer_ViewPort::redrawPainters()
1006 {
1007   myPaintersRedrawing = true;
1008   repaint();
1009 }