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