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