Salome HOME
Update from BR_V5_DEV 13Feb2009
[modules/gui.git] / src / SVTK / SVTK_RenderWindowInteractor.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 //  SALOME VTKViewer : build VTK viewer into Salome desktop
23 //  File   : 
24 //  Author : 
25 //  Module : SALOME
26 //  $Header$
27 //
28 #include "SVTK_RenderWindowInteractor.h"
29 //#include "SVTK_GenericRenderWindowInteractor.h"
30
31 #include "SVTK_InteractorStyle.h"
32 #include "SVTK_Renderer.h"
33 #include "SVTK_Functor.h"
34 #include "SALOME_Actor.h"
35
36 // QT Includes
37 // Put Qt includes before the X11 includes which #define the symbol None
38 // (see SVTK_SpaceMouse.h) to avoid the compilation error.
39 #ifndef WIN32
40 # include <QX11Info>
41 #endif
42 #include <QMouseEvent>
43
44 #include "SVTK_SpaceMouse.h" 
45 #include "SVTK_Event.h" 
46
47 #include "VTKViewer_Algorithm.h"
48
49 // VTK Includes
50 #include <vtkObjectFactory.h>
51 #include <vtkRendererCollection.h>
52 #include <vtkRenderWindow.h>
53 #include <vtkGenericRenderWindowInteractor.h>
54 #include <vtkCallbackCommand.h>
55 #include <vtkCommand.h>
56 #include <vtkPicker.h>
57 #include <vtkCamera.h>
58
59 using namespace std;
60
61 static bool GENERATE_SUIT_EVENTS = false;
62 static bool FOCUS_UNDER_MOUSE = false;
63
64
65 /*!
66   Constructor
67 */
68 QVTK_RenderWindowInteractor
69 ::QVTK_RenderWindowInteractor(QWidget* theParent, 
70                               const char* theName):
71   QWidget(theParent),
72   myRenderWindow(vtkRenderWindow::New())
73 {
74   setAttribute( Qt::WA_PaintOnScreen );
75   setAttribute( Qt::WA_NoSystemBackground );
76
77   setObjectName(theName);
78
79   setMouseTracking(true);
80
81   myRenderWindow->Delete();
82   myRenderWindow->DoubleBufferOn();
83
84 #ifndef WIN32
85   myRenderWindow->SetDisplayId((void*)QX11Info::display());
86 #endif
87   myRenderWindow->SetWindowId((void*)winId());
88 }
89
90 /*!
91   To initialize by vtkGenericRenderWindowInteractor instance
92 */
93 void 
94 QVTK_RenderWindowInteractor
95 ::Initialize(vtkGenericRenderWindowInteractor* theDevice)
96 {
97   if ( GetDevice() )
98     myDevice->SetRenderWindow( NULL );
99
100   myDevice = theDevice;
101
102   if ( theDevice )
103     theDevice->SetRenderWindow( getRenderWindow() );
104 }
105
106 /*!
107   Destructor
108 */
109 QVTK_RenderWindowInteractor
110 ::~QVTK_RenderWindowInteractor() 
111 {
112 #ifndef WIN32
113   SVTK_SpaceMouse* aSpaceMouse = SVTK_SpaceMouse::getInstance();
114   if ( aSpaceMouse && aSpaceMouse->isSpaceMouseOn() )
115     aSpaceMouse->close( QX11Info::display() );
116 #endif
117 }
118
119
120 /*!
121   \return corresponding render window interactor
122 */
123 vtkGenericRenderWindowInteractor* 
124 QVTK_RenderWindowInteractor
125 ::GetDevice()
126 {
127   return myDevice.GetPointer();
128 }
129
130 /*!
131   \return corresponding render window
132 */
133 vtkRenderWindow*
134 QVTK_RenderWindowInteractor
135 ::getRenderWindow()
136 {
137   return myRenderWindow.GetPointer();
138 }
139
140 /*!
141   Just to simplify usage of its device (vtkGenericRenderWindowInteractor)
142 */
143 void
144 QVTK_RenderWindowInteractor
145 ::InvokeEvent(unsigned long theEvent, void* theCallData)
146 {
147   GetDevice()->InvokeEvent(theEvent,theCallData);
148 }
149
150 /*!
151   Need for initial contents display on Win32
152 */
153 void
154 QVTK_RenderWindowInteractor
155 ::show()
156 {
157   QWidget::show();
158   update(); // needed for initial contents display on Win32
159 }
160
161 /*!
162   To implement final initialization, just before the widget is displayed
163 */
164 void
165 QVTK_RenderWindowInteractor
166 ::polish()
167 {
168   // Final initialization just before the widget is displayed
169   GetDevice()->SetSize(width(),height());
170   if(!GetDevice()->GetInitialized() && GetDevice()->GetRenderWindow()){
171     GetDevice()->Initialize();
172     GetDevice()->ConfigureEvent();
173   }
174 }
175
176 /*!
177   To adjust widget and vtkRenderWindow size
178 */
179 void
180 QVTK_RenderWindowInteractor
181 ::resize(int w, int h) 
182 {
183   GetDevice()->UpdateSize(w,h);
184 }
185
186 /*!
187   Custom paint event handler
188 */
189 void
190 QVTK_RenderWindowInteractor
191 ::paintEvent( QPaintEvent* theEvent ) 
192 {
193   GetDevice()->CreateTimer(VTKI_TIMER_FIRST);
194 }
195
196
197 /*!
198   Custom resize event handler
199 */
200 void
201 QVTK_RenderWindowInteractor
202 ::resizeEvent( QResizeEvent* theEvent )
203 {
204   int* aSize = getRenderWindow()->GetSize();
205   int aWidth = aSize[0];
206   int aHeight = aSize[1];
207
208   GetDevice()->UpdateSize(width(),height());
209
210   if(isVisible() && aWidth && aHeight){
211     if( aWidth != width() || aHeight != height() ) {
212       vtkRendererCollection * aRenderers = getRenderWindow()->GetRenderers();
213       aRenderers->InitTraversal();
214       double aCoeff = 1.0;
215       if(vtkRenderer *aRenderer = aRenderers->GetNextItem()) {
216         vtkCamera *aCamera = aRenderer->GetActiveCamera();
217         double aScale = aCamera->GetParallelScale();
218         if((aWidth - width())*(aHeight - height()) > 0)
219           aCoeff = sqrt(double(aWidth)/double(width())*double(height())/double(aHeight));
220         else
221           aCoeff = double(aWidth)/double(width());
222         aCamera->SetParallelScale(aScale*aCoeff);
223       }
224     }
225   }
226
227   update(); 
228 }
229
230
231
232 /*!
233   Custom context menu event handler
234 */
235 void
236 QVTK_RenderWindowInteractor
237 ::contextMenuEvent( QContextMenuEvent* event )
238 {}
239
240 /*!
241   Custom mouse move event handler
242 */
243 void
244 QVTK_RenderWindowInteractor
245 ::mouseMoveEvent( QMouseEvent* event ) 
246 {
247   GetDevice()->SetEventInformationFlipY(event->x(), 
248                                         event->y(),
249                                         event->modifiers() & Qt::ControlModifier,
250                                         event->modifiers() & Qt::ShiftModifier);
251   GetDevice()->MouseMoveEvent();
252 }
253
254
255 /*!
256   Custom mouse press event handler
257 */
258 void
259 QVTK_RenderWindowInteractor
260 ::mousePressEvent( QMouseEvent* event ) 
261 {
262   GetDevice()->SetEventInformationFlipY(event->x(), 
263                                         event->y(),
264                                         event->modifiers() & Qt::ControlModifier,
265                                         event->modifiers() & Qt::ShiftModifier);
266   if( event->button() & Qt::LeftButton )
267     GetDevice()->LeftButtonPressEvent();
268   else if( event->button() & Qt::MidButton )
269     GetDevice()->MiddleButtonPressEvent();
270   else if( event->button() & Qt::RightButton )
271     GetDevice()->RightButtonPressEvent();
272 }
273
274
275 /*!
276   Custom mouse release event handler
277 */
278 void
279 QVTK_RenderWindowInteractor
280 ::mouseReleaseEvent( QMouseEvent *event )
281 {
282   GetDevice()->SetEventInformationFlipY(event->x(), 
283                                         event->y(),
284                                         event->modifiers() & Qt::ControlModifier,
285                                         event->modifiers() & Qt::ShiftModifier);
286
287   if( event->button() & Qt::LeftButton )
288     GetDevice()->LeftButtonReleaseEvent();
289   else if( event->button() & Qt::MidButton )
290     GetDevice()->MiddleButtonReleaseEvent();
291   else if( event->button() & Qt::RightButton )
292     GetDevice()->RightButtonReleaseEvent();
293 }
294
295
296 /*!
297   Custom mouse double click event handler
298 */
299 void
300 QVTK_RenderWindowInteractor
301 ::mouseDoubleClickEvent( QMouseEvent* event )
302 {}
303
304
305 /*!
306   Custom mouse wheel event handler
307 */
308 void
309 QVTK_RenderWindowInteractor
310 ::wheelEvent( QWheelEvent* event )
311 {
312   activateWindow();
313   setFocus();
314 }
315
316
317 /*!
318   Custom key press event handler
319 */
320 void
321 QVTK_RenderWindowInteractor
322 ::keyPressEvent( QKeyEvent* event ) 
323 {
324   GetDevice()->SetKeyEventInformation(event->modifiers() & Qt::ControlModifier,
325                                       event->modifiers() & Qt::ShiftModifier,
326                                       event->key());
327   GetDevice()->KeyPressEvent();
328   GetDevice()->CharEvent();
329 }
330
331 /*!
332   Custom key release event handler
333 */
334 void
335 QVTK_RenderWindowInteractor
336 ::keyReleaseEvent( QKeyEvent * event ) 
337 {
338   GetDevice()->SetKeyEventInformation(event->modifiers() & Qt::ControlModifier,
339                                       event->modifiers() & Qt::ShiftModifier,
340                                       event->key());
341   GetDevice()->KeyReleaseEvent();
342 }
343
344
345 /*!
346   Custom enter event handler
347 */
348 void  
349 QVTK_RenderWindowInteractor
350 ::enterEvent( QEvent* event )
351 {
352   if(FOCUS_UNDER_MOUSE){
353     activateWindow();
354     setFocus();
355   }
356   GetDevice()->EnterEvent();
357 }
358
359 /*!
360   Custom leave event handler
361 */
362 void  
363 QVTK_RenderWindowInteractor
364 ::leaveEvent( QEvent * )
365 {
366   GetDevice()->LeaveEvent();
367 }
368
369 /*!
370   Reimplemented from QWidget in order to set window - receiver
371   of space mouse events. 
372 */
373 void  
374 QVTK_RenderWindowInteractor
375 ::focusInEvent( QFocusEvent* event )
376 {
377   QWidget::focusInEvent( event );
378
379 #ifndef WIN32
380   // register set space mouse events receiver
381   SVTK_SpaceMouse* aSpaceMouse = SVTK_SpaceMouse::getInstance();
382
383   if ( aSpaceMouse )
384   {
385     if ( !aSpaceMouse->isSpaceMouseOn() )
386       // initialize 3D space mouse driver 
387       aSpaceMouse->initialize( QX11Info::display(), winId() );
388     else
389       aSpaceMouse->setWindow( QX11Info::display(), winId() );
390   }
391 #endif
392 }
393
394 /*!
395   Reimplemented from QWidget in order to set window - receiver
396   of space mouse events. 
397 */
398 void  
399 QVTK_RenderWindowInteractor
400 ::focusOutEvent ( QFocusEvent* event )
401 {
402   QWidget::focusOutEvent( event );
403
404 #ifndef WIN32
405   // unregister set space mouse events receiver
406   SVTK_SpaceMouse* aSpaceMouse = SVTK_SpaceMouse::getInstance();
407   if ( aSpaceMouse && aSpaceMouse->isSpaceMouseOn() )
408     aSpaceMouse->setWindow( QX11Info::display(), 0 );
409 #endif
410 }
411
412
413 #ifdef WIN32
414
415 /*!
416   To handle native Win32 events (from such devices as SpaceMouse)
417 */
418 bool QVTK_RenderWindowInteractor::winEvent( MSG* msg, long* result )
419 {
420   // TODO: Implement event handling for SpaceMouse
421   return QWidget::winEvent( msg, result);
422 }
423
424 #else
425
426 /*!
427   To handle native X11 events (from such devices as SpaceMouse)
428 */
429 bool 
430 QVTK_RenderWindowInteractor
431 ::x11Event( XEvent *xEvent )
432 {
433   // handle 3d space mouse events
434   if ( SVTK_SpaceMouse* aSpaceMouse = SVTK_SpaceMouse::getInstance() )
435   {
436     if ( aSpaceMouse->isSpaceMouseOn() && xEvent->type == ClientMessage )
437     {
438       SVTK_SpaceMouse::MoveEvent anEvent;
439       int type = aSpaceMouse->translateEvent( QX11Info::display(), xEvent, &anEvent, 1.0, 1.0 );
440       switch ( type )
441       {
442       case SVTK_SpaceMouse::SpaceMouseMove:
443               GetDevice()->InvokeEvent( SVTK::SpaceMouseMoveEvent, anEvent.data );
444               break;
445       case SVTK_SpaceMouse::SpaceButtonPress:
446               GetDevice()->InvokeEvent( SVTK::SpaceMouseButtonEvent, &anEvent.button );
447               break;
448       case SVTK_SpaceMouse::SpaceButtonRelease:
449               break;
450       }
451       return true; // stop handling the event
452     }
453   }
454
455   return QWidget::x11Event( xEvent );
456 }
457
458 #endif
459
460 /*!
461   Constructor
462 */
463 SVTK_RenderWindowInteractor
464 ::SVTK_RenderWindowInteractor(QWidget* theParent, 
465                                const char* theName):
466   QVTK_RenderWindowInteractor(theParent,theName),
467   myEventCallbackCommand(vtkCallbackCommand::New())
468 {
469   myEventCallbackCommand->Delete();
470
471   myEventCallbackCommand->SetClientData(this); 
472   myPriority = 0.0;
473
474   myEventCallbackCommand->SetCallback(SVTK_RenderWindowInteractor::ProcessEvents);
475 }
476
477 /*!
478   To initialize properly the class
479 */
480 void
481 SVTK_RenderWindowInteractor
482 ::Initialize(vtkGenericRenderWindowInteractor* theDevice,
483              SVTK_Renderer* theRenderer,
484              SVTK_Selector* theSelector)
485 {
486   QVTK_RenderWindowInteractor::Initialize(theDevice);
487   SetRenderer(theRenderer);
488   SetSelector(theSelector);
489 }
490
491 /*!
492   Destructor
493 */
494 SVTK_RenderWindowInteractor
495 ::~SVTK_RenderWindowInteractor() 
496 {
497   // Sequence of the destruction call are fixed and should be changed.
498   // vtkRenderWindow instance should be destroyed after all vtkRenderer's
499   GetDevice()->SetInteractorStyle(NULL); 
500   while(!myInteractorStyles.empty()){
501     const PInteractorStyle& aStyle = myInteractorStyles.top();
502     aStyle->SetInteractor(NULL);
503     myInteractorStyles.pop();
504   }
505
506   SetRenderer(NULL);
507
508   GetDevice()->SetRenderWindow(NULL);
509 }
510
511 /*!
512   To get corresponding SVTK_Renderer instance
513 */
514 SVTK_Renderer* 
515 SVTK_RenderWindowInteractor
516 ::GetRenderer()
517 {
518   return myRenderer.GetPointer();
519 }
520
521 /*!
522   To get corresponding SVTK_Renderer device (just to simplify collobaration with SVTK_Renderer)
523 */
524 vtkRenderer* 
525 SVTK_RenderWindowInteractor
526 ::getRenderer()
527 {
528   return GetRenderer()->GetDevice();
529 }
530
531 /*!
532   Changes renderer
533   \param theRenderer - new renderer
534 */
535 void
536 SVTK_RenderWindowInteractor
537 ::SetRenderer(SVTK_Renderer* theRenderer)
538 {
539   if(theRenderer == myRenderer.GetPointer())
540     return;
541
542   if(GetRenderer())
543     myRenderWindow->RemoveRenderer(getRenderer());
544
545   myRenderer = theRenderer;
546
547   if(GetRenderer())
548     myRenderWindow->AddRenderer(getRenderer());
549 }
550
551
552 /*!
553   Changes interactor style
554   \param theStyle - new interactor style
555 */
556 void
557 SVTK_RenderWindowInteractor
558 ::InitInteractorStyle(vtkInteractorStyle* theStyle)
559 {
560   GetDevice()->SetInteractorStyle(theStyle); 
561 }
562
563 /*!
564   To change current interactor style by pushing the new one into the container
565 */
566 void
567 SVTK_RenderWindowInteractor
568 ::PushInteractorStyle(vtkInteractorStyle* theStyle)
569 {
570   myInteractorStyles.push(PInteractorStyle(theStyle));
571   InitInteractorStyle(theStyle);
572 }
573
574 /*!
575   To restore previous interactor style
576 */
577 void
578 SVTK_RenderWindowInteractor
579 ::PopInteractorStyle()
580 {
581   if(GetInteractorStyle())
582     myInteractorStyles.pop();
583   
584   if(GetInteractorStyle()) 
585     InitInteractorStyle(GetInteractorStyle());
586 }
587
588 /*!
589   To get current interactor style
590 */
591 vtkInteractorStyle* 
592 SVTK_RenderWindowInteractor
593 ::GetInteractorStyle()
594 {
595   return myInteractorStyles.empty() ? 0 : myInteractorStyles.top().GetPointer();
596 }
597
598
599 /*!
600   To get current selector
601 */
602 SVTK_Selector* 
603 SVTK_RenderWindowInteractor
604 ::GetSelector() 
605
606   return mySelector.GetPointer(); 
607 }
608
609
610 /*!
611   Changes selector
612   \param theSelector - new selector
613 */
614 void
615 SVTK_RenderWindowInteractor
616 ::SetSelector(SVTK_Selector* theSelector)
617
618   if(mySelector.GetPointer())
619     mySelector->RemoveObserver(myEventCallbackCommand.GetPointer());
620
621   mySelector = theSelector; 
622
623   if(mySelector.GetPointer())
624     mySelector->AddObserver(vtkCommand::EndPickEvent, 
625                             myEventCallbackCommand.GetPointer(), 
626                             myPriority);
627 }
628
629 /*!
630   Main process VTK event method
631 */
632 void 
633 SVTK_RenderWindowInteractor
634 ::ProcessEvents(vtkObject* vtkNotUsed(theObject), 
635                 unsigned long theEvent,
636                 void* theClientData, 
637                 void* vtkNotUsed(theCallData))
638 {
639   SVTK_RenderWindowInteractor* self = reinterpret_cast<SVTK_RenderWindowInteractor*>(theClientData);
640
641   switch(theEvent){
642   case vtkCommand::EndPickEvent:
643     self->onEmitSelectionChanged();
644     break;
645   }
646 }
647
648 /*!
649   To change selection mode (just to simplify collobaration with SVTK_Selector)
650 */
651 void
652 SVTK_RenderWindowInteractor
653 ::SetSelectionMode(Selection_Mode theMode)
654 {
655   mySelector->SetSelectionMode(theMode);
656 }
657
658 /*!
659   To get current selection mode (just to simplify collobaration with SVTK_Selector)
660 */
661 Selection_Mode
662 SVTK_RenderWindowInteractor
663 ::SelectionMode() const
664 {
665   return mySelector->SelectionMode();
666 }
667
668
669 /*!
670   Emits signal selectionChanged()
671 */
672 void
673 SVTK_RenderWindowInteractor
674 ::onEmitSelectionChanged()
675 {
676   return emit selectionChanged();
677 }
678
679
680 /*!
681   Custom mouse move event handler
682 */
683 void
684 SVTK_RenderWindowInteractor
685 ::mouseMoveEvent( QMouseEvent* event ) 
686 {
687   QVTK_RenderWindowInteractor::mouseMoveEvent(event);
688
689   if(GENERATE_SUIT_EVENTS)
690     emit MouseMove( event );
691 }
692
693
694 /*!
695   Custom mouse press event handler
696 */
697 void
698 SVTK_RenderWindowInteractor
699 ::mousePressEvent( QMouseEvent* event ) 
700 {
701   QVTK_RenderWindowInteractor::mousePressEvent(event);
702
703   if(GENERATE_SUIT_EVENTS)
704     emit MouseButtonPressed( event );
705 }
706
707
708 /*!
709   Custom mouse release event handler
710 */
711 void
712 SVTK_RenderWindowInteractor
713 ::mouseReleaseEvent( QMouseEvent *event )
714 {
715   bool aRightBtn = event->button() == Qt::RightButton;
716   bool isOperation = false;
717   if( aRightBtn && GetInteractorStyle()) {
718     SVTK_InteractorStyle* style = dynamic_cast<SVTK_InteractorStyle*>( GetInteractorStyle() );
719     if ( style )
720       isOperation = style->CurrentState() != VTK_INTERACTOR_STYLE_CAMERA_NONE;
721   }
722
723   QVTK_RenderWindowInteractor::mouseReleaseEvent(event);
724
725   if ( aRightBtn && !isOperation && !( event->modifiers() & Qt::ControlModifier ) &&
726        !( event->modifiers() & Qt::ShiftModifier ) ) {
727     QContextMenuEvent aEvent( QContextMenuEvent::Mouse,
728                               event->pos(), event->globalPos() );
729     emit contextMenuRequested( &aEvent );
730   }
731   if(GENERATE_SUIT_EVENTS)
732     emit MouseButtonReleased( event );
733 }
734
735
736 /*!
737   Custom mouse double click event handler
738 */
739 void
740 SVTK_RenderWindowInteractor
741 ::mouseDoubleClickEvent( QMouseEvent* event )
742 {
743   QVTK_RenderWindowInteractor::mouseDoubleClickEvent(event);
744
745   if(GENERATE_SUIT_EVENTS)
746     emit MouseDoubleClicked( event );
747 }
748
749
750 /*!
751   Custom mouse wheel event handler
752 */
753 void
754 SVTK_RenderWindowInteractor
755 ::wheelEvent( QWheelEvent* event )
756 {
757   QVTK_RenderWindowInteractor::wheelEvent(event);
758
759   if(event->delta() > 0)
760     GetDevice()->InvokeEvent(SVTK::ZoomInEvent,NULL);
761   else
762     GetDevice()->InvokeEvent(SVTK::ZoomOutEvent,NULL);
763
764   if(GENERATE_SUIT_EVENTS)
765     emit WheelMoved( event );
766 }
767
768 /*!
769   Custom key press event handler
770 */
771 void
772 SVTK_RenderWindowInteractor
773 ::keyPressEvent( QKeyEvent* event ) 
774 {
775   QVTK_RenderWindowInteractor::keyPressEvent(event);
776
777   if(GENERATE_SUIT_EVENTS)
778     emit KeyPressed( event );
779 }
780
781 /*!
782   Custom key release event handler
783 */
784 void
785 SVTK_RenderWindowInteractor
786 ::keyReleaseEvent( QKeyEvent * event ) 
787 {
788   QVTK_RenderWindowInteractor::keyReleaseEvent(event);
789
790   if(GENERATE_SUIT_EVENTS)
791     emit KeyReleased( event );
792 }
793