1 // Copyright (C) 2007-2024 CEA, EDF, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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, or (at your option) any later version.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SALOME VTKViewer : build VTK viewer into Salome desktop
27 #include "SVTK_RenderWindowInteractor.h"
29 #include "SVTK_InteractorStyle.h"
30 #include "SVTK_Renderer.h"
31 #include "SVTK_Functor.h"
32 #include "SALOME_Actor.h"
35 // Put Qt includes before the X11 includes which #define the symbol None
36 // (see SVTK_SpaceMouse.h) to avoid the compilation error.
37 #if !defined(WIN32) && !defined(__APPLE__)
41 #include <QMouseEvent>
43 #include "SVTK_SpaceMouse.h"
44 #include "SVTK_Event.h"
46 #include "VTKViewer_Algorithm.h"
49 #include <vtkObjectFactory.h>
50 #include <vtkRendererCollection.h>
51 #include <vtkRenderWindow.h>
52 #include <vtkGenericRenderWindowInteractor.h>
53 #include <vtkCallbackCommand.h>
54 #include <vtkCommand.h>
55 #include <vtkPicker.h>
56 #include <vtkCamera.h>
58 static bool GENERATE_SUIT_EVENTS = true;
59 static bool FOCUS_UNDER_MOUSE = false;
61 // workaround about the bug in vtkImplicitPlaneWidget class
62 // that eats mouse button release event
63 // causing clipping plane preview in SMESH sticking up
64 #define Fix_Of_vtkImplicitPlaneWidget_bug
69 QVTK_RenderWindowInteractor
70 ::QVTK_RenderWindowInteractor(QWidget* theParent,
73 myRenderWindow(vtkRenderWindow::New())
75 setAttribute( Qt::WA_PaintOnScreen );
76 setAttribute( Qt::WA_NoSystemBackground );
78 setObjectName(theName);
80 setMouseTracking(true);
82 myRenderWindow->Delete();
83 myRenderWindow->DoubleBufferOn();
85 #if !defined WIN32 && !defined __APPLE__
86 myRenderWindow->SetDisplayId((void*)QX11Info::display());
88 myRenderWindow->SetWindowId((void*)winId());
92 To initialize by vtkGenericRenderWindowInteractor instance
95 QVTK_RenderWindowInteractor
96 ::Initialize(vtkGenericRenderWindowInteractor* theDevice)
99 myDevice->SetRenderWindow( NULL );
101 myDevice = theDevice;
104 theDevice->SetRenderWindow( getRenderWindow() );
110 QVTK_RenderWindowInteractor
111 ::~QVTK_RenderWindowInteractor()
113 #if !defined WIN32 && !defined __APPLE__
114 SVTK_SpaceMouseXCB* aSpaceMouse = SVTK_SpaceMouseXCB::getInstance();
115 if ( aSpaceMouse && aSpaceMouse->isSpaceMouseOn() )
116 aSpaceMouse->close( QX11Info::connection() );
122 \return corresponding render window interactor
124 vtkGenericRenderWindowInteractor*
125 QVTK_RenderWindowInteractor
128 return myDevice.GetPointer();
132 \return corresponding render window
135 QVTK_RenderWindowInteractor
138 return myRenderWindow.GetPointer();
142 Just to simplify usage of its device (vtkGenericRenderWindowInteractor)
145 QVTK_RenderWindowInteractor
146 ::InvokeEvent(unsigned long theEvent, void* theCallData)
148 GetDevice()->InvokeEvent(theEvent,theCallData);
152 Get paint engine for the scene
154 QPaintEngine* QVTK_RenderWindowInteractor::paintEngine() const
160 Need for initial contents display on Win32
163 QVTK_RenderWindowInteractor
167 update(); // needed for initial contents display on Win32
171 To implement final initialization, just before the widget is displayed
174 QVTK_RenderWindowInteractor
177 // Final initialization just before the widget is displayed
178 GetDevice()->SetSize(width(),height());
179 if(!GetDevice()->GetInitialized() && GetDevice()->GetRenderWindow()){
180 GetDevice()->Initialize();
181 GetDevice()->ConfigureEvent();
186 To adjust widget and vtkRenderWindow size
189 QVTK_RenderWindowInteractor
190 ::resize(int w, int h)
192 GetDevice()->UpdateSize(w,h);
196 Custom paint event handler
199 QVTK_RenderWindowInteractor
200 ::paintEvent( QPaintEvent* /*theEvent*/ )
202 GetDevice()->CreateTimer(VTKI_TIMER_FIRST);
207 Custom resize event handler
210 QVTK_RenderWindowInteractor
211 ::resizeEvent( QResizeEvent* /*theEvent*/ )
213 int* aSize = getRenderWindow()->GetSize();
214 int aWidth = aSize[0];
215 int aHeight = aSize[1];
217 GetDevice()->UpdateSize(width(),height());
219 if(isVisible() && aWidth && aHeight){
220 if( aWidth != width() || aHeight != height() ) {
221 vtkRendererCollection * aRenderers = getRenderWindow()->GetRenderers();
222 aRenderers->InitTraversal();
224 if(vtkRenderer *aRenderer = aRenderers->GetNextItem()) {
225 vtkCamera *aCamera = aRenderer->GetActiveCamera();
226 double aScale = aCamera->GetParallelScale();
227 if((aWidth - width())*(aHeight - height()) > 0)
228 aCoeff = sqrt(double(aWidth)/double(width())*double(height())/double(aHeight));
230 aCoeff = double(aWidth)/double(width());
231 aCamera->SetParallelScale(aScale*aCoeff);
242 Custom context menu event handler
245 QVTK_RenderWindowInteractor
246 ::contextMenuEvent( QContextMenuEvent* /*event*/ )
250 Custom mouse move event handler
253 QVTK_RenderWindowInteractor
254 ::mouseMoveEvent( QMouseEvent* event )
256 GetDevice()->SetEventInformationFlipY(event->x(),
258 event->modifiers() & Qt::ControlModifier,
259 event->modifiers() & Qt::ShiftModifier);
260 GetDevice()->MouseMoveEvent();
265 Custom mouse press event handler
268 QVTK_RenderWindowInteractor
269 ::mousePressEvent( QMouseEvent* event )
271 GetDevice()->SetEventInformationFlipY(event->x(),
273 event->modifiers() & Qt::ControlModifier,
274 event->modifiers() & Qt::ShiftModifier);
275 if( event->button() & Qt::LeftButton )
276 GetDevice()->LeftButtonPressEvent();
277 else if( event->button() & Qt::MidButton )
278 GetDevice()->MiddleButtonPressEvent();
279 else if( event->button() & Qt::RightButton )
280 GetDevice()->RightButtonPressEvent();
285 Custom mouse release event handler
288 QVTK_RenderWindowInteractor
289 ::mouseReleaseEvent( QMouseEvent *event )
291 GetDevice()->SetEventInformationFlipY(event->x(),
293 event->modifiers() & Qt::ControlModifier,
294 event->modifiers() & Qt::ShiftModifier);
296 if( event->button() & Qt::LeftButton )
297 GetDevice()->LeftButtonReleaseEvent();
298 else if( event->button() & Qt::MidButton )
299 GetDevice()->MiddleButtonReleaseEvent();
300 else if( event->button() & Qt::RightButton ) {
301 #if defined(Fix_Of_vtkImplicitPlaneWidget_bug)
302 GetDevice()->SetEventInformationFlipY( -99999, -99999,
303 event->modifiers() & Qt::ControlModifier,
304 event->modifiers() & Qt::ShiftModifier);
305 bool blocked = blockSignals( true );
306 GetDevice()->LeftButtonPressEvent();
307 GetDevice()->LeftButtonReleaseEvent();
308 blockSignals( blocked );
309 GetDevice()->SetEventInformationFlipY(event->x(),
311 event->modifiers() & Qt::ControlModifier,
312 event->modifiers() & Qt::ShiftModifier);
314 GetDevice()->RightButtonReleaseEvent();
320 Custom mouse double click event handler
323 QVTK_RenderWindowInteractor
324 ::mouseDoubleClickEvent( QMouseEvent* /*event*/ )
329 Custom mouse wheel event handler
332 QVTK_RenderWindowInteractor
333 ::wheelEvent( QWheelEvent* event )
337 GetDevice()->SetEventInformationFlipY(event->x(),
339 event->modifiers() & Qt::ControlModifier,
340 event->modifiers() & Qt::ShiftModifier);
341 if ( event->delta()>0)
342 GetDevice()->MouseWheelForwardEvent();
344 GetDevice()->MouseWheelBackwardEvent();
349 Custom key press event handler
352 QVTK_RenderWindowInteractor
353 ::keyPressEvent( QKeyEvent* event )
355 GetDevice()->SetKeyEventInformation(event->modifiers() & Qt::ControlModifier,
356 event->modifiers() & Qt::ShiftModifier,
358 GetDevice()->KeyPressEvent();
359 GetDevice()->CharEvent();
363 Custom key release event handler
366 QVTK_RenderWindowInteractor
367 ::keyReleaseEvent( QKeyEvent * event )
369 GetDevice()->SetKeyEventInformation(event->modifiers() & Qt::ControlModifier,
370 event->modifiers() & Qt::ShiftModifier,
372 GetDevice()->KeyReleaseEvent();
377 Custom enter event handler
380 QVTK_RenderWindowInteractor
381 ::enterEvent( QEvent* /*event*/ )
383 if(FOCUS_UNDER_MOUSE){
387 GetDevice()->EnterEvent();
391 Custom leave event handler
394 QVTK_RenderWindowInteractor
395 ::leaveEvent( QEvent * )
397 GetDevice()->LeaveEvent();
401 Reimplemented from QWidget in order to set window - receiver
402 of space mouse events.
405 QVTK_RenderWindowInteractor
406 ::focusInEvent( QFocusEvent* event )
408 QWidget::focusInEvent( event );
410 #if !defined WIN32 && !defined __APPLE__
411 // register set space mouse events receiver
412 SVTK_SpaceMouseXCB* aSpaceMouse = SVTK_SpaceMouseXCB::getInstance();
415 if ( !aSpaceMouse->isSpaceMouseOn() )
416 // initialize 3D space mouse driver
417 aSpaceMouse->initialize( QX11Info::connection(), winId() );
419 aSpaceMouse->setWindow( QX11Info::connection(), winId() );
425 Reimplemented from QWidget in order to set window - receiver
426 of space mouse events.
429 QVTK_RenderWindowInteractor
430 ::focusOutEvent ( QFocusEvent* event )
432 QWidget::focusOutEvent( event );
434 #if !defined WIN32 && !defined __APPLE__
435 SVTK_SpaceMouseXCB* aSpaceMouse = SVTK_SpaceMouseXCB::getInstance();
436 if ( aSpaceMouse && aSpaceMouse->isSpaceMouseOn() )
437 aSpaceMouse->setWindow( QX11Info::connection(), 0 );
441 bool QVTK_RenderWindowInteractor
442 ::nativeEvent(const QByteArray& eventType, void* message, long* result)
445 // TODO: WIN32-related implementation
446 #elif !defined(__APPLE__)
447 if ( eventType == "xcb_generic_event_t" )
449 xcb_generic_event_t* ev = static_cast<xcb_generic_event_t *>(message);
450 if ( SVTK_SpaceMouseXCB* aSpaceMouse = SVTK_SpaceMouseXCB::getInstance() )
452 if ( aSpaceMouse->isSpaceMouseOn() && ev->response_type == XCB_CLIENT_MESSAGE )
454 SVTK_SpaceMouse::MoveEvent anEvent;
455 int type = aSpaceMouse->translateEvent( QX11Info::connection(), (xcb_client_message_event_t*)ev, &anEvent, 1.0, 1.0 );
458 case SVTK_SpaceMouse::SpaceMouseMove:
459 GetDevice()->InvokeEvent( SVTK::SpaceMouseMoveEvent, anEvent.data );
461 case SVTK_SpaceMouse::SpaceButtonPress:
462 GetDevice()->InvokeEvent( SVTK::SpaceMouseButtonEvent, &anEvent.button );
464 case SVTK_SpaceMouse::SpaceButtonRelease:
467 return true; // stop handling the event
472 return QWidget::nativeEvent( eventType, message, result );
478 SVTK_RenderWindowInteractor
479 ::SVTK_RenderWindowInteractor(QWidget* theParent,
480 const char* theName):
481 QVTK_RenderWindowInteractor(theParent,theName),
482 myEventCallbackCommand(vtkCallbackCommand::New())
484 myEventCallbackCommand->Delete();
486 myEventCallbackCommand->SetClientData(this);
489 myEventCallbackCommand->SetCallback(SVTK_RenderWindowInteractor::ProcessEvents);
493 To initialize properly the class
496 SVTK_RenderWindowInteractor
497 ::Initialize(vtkGenericRenderWindowInteractor* theDevice,
498 SVTK_Renderer* theRenderer,
499 SVTK_Selector* theSelector)
501 QVTK_RenderWindowInteractor::Initialize(theDevice);
502 SetRenderer(theRenderer);
503 SetSelector(theSelector);
509 SVTK_RenderWindowInteractor
510 ::~SVTK_RenderWindowInteractor()
512 // Sequence of the destruction call are fixed and should be changed.
513 // vtkRenderWindow instance should be destroyed after all vtkRenderer's
514 GetDevice()->SetInteractorStyle(NULL);
515 while(!myInteractorStyles.empty()){
516 const PInteractorStyle& aStyle = myInteractorStyles.top();
517 aStyle->SetInteractor(NULL);
518 myInteractorStyles.pop();
523 To get corresponding SVTK_Renderer instance
526 SVTK_RenderWindowInteractor
529 return myRenderer.GetPointer();
533 To get corresponding SVTK_Renderer device (just to simplify collobaration with SVTK_Renderer)
536 SVTK_RenderWindowInteractor
539 return GetRenderer()->GetDevice();
544 \param theRenderer - new renderer
547 SVTK_RenderWindowInteractor
548 ::SetRenderer(SVTK_Renderer* theRenderer)
550 if(theRenderer == myRenderer.GetPointer())
554 myRenderWindow->RemoveRenderer(getRenderer());
556 myRenderer = theRenderer;
559 myRenderWindow->AddRenderer(getRenderer());
564 Changes interactor style
565 \param theStyle - new interactor style
568 SVTK_RenderWindowInteractor
569 ::InitInteractorStyle(vtkInteractorStyle* theStyle)
571 GetDevice()->SetInteractorStyle(theStyle);
575 To change current interactor style by pushing the new one into the container
578 SVTK_RenderWindowInteractor
579 ::PushInteractorStyle(vtkInteractorStyle* theStyle)
581 myInteractorStyles.push(PInteractorStyle(theStyle));
582 InitInteractorStyle(theStyle);
586 To restore previous interactor style
589 SVTK_RenderWindowInteractor
590 ::PopInteractorStyle()
592 if(GetInteractorStyle())
593 myInteractorStyles.pop();
595 if(GetInteractorStyle())
596 InitInteractorStyle(GetInteractorStyle());
600 To get current interactor style
603 SVTK_RenderWindowInteractor
604 ::GetInteractorStyle()
606 return myInteractorStyles.empty() ? 0 : myInteractorStyles.top().GetPointer();
611 To get current selector
614 SVTK_RenderWindowInteractor
617 return mySelector.GetPointer();
623 \param theSelector - new selector
626 SVTK_RenderWindowInteractor
627 ::SetSelector(SVTK_Selector* theSelector)
629 if(mySelector.GetPointer())
630 mySelector->RemoveObserver(myEventCallbackCommand.GetPointer());
632 mySelector = theSelector;
634 if(mySelector.GetPointer())
635 mySelector->AddObserver(vtkCommand::EndPickEvent,
636 myEventCallbackCommand.GetPointer(),
641 Main process VTK event method
644 SVTK_RenderWindowInteractor
645 ::ProcessEvents(vtkObject* vtkNotUsed(theObject),
646 unsigned long theEvent,
648 void* vtkNotUsed(theCallData))
650 SVTK_RenderWindowInteractor* self = reinterpret_cast<SVTK_RenderWindowInteractor*>(theClientData);
653 case vtkCommand::EndPickEvent:
654 self->onEmitSelectionChanged();
660 To change selection mode (just to simplify collobaration with SVTK_Selector)
663 SVTK_RenderWindowInteractor
664 ::SetSelectionMode(Selection_Mode theMode)
666 mySelector->SetSelectionMode(theMode);
670 To get current selection mode (just to simplify collobaration with SVTK_Selector)
673 SVTK_RenderWindowInteractor
674 ::SelectionMode() const
676 return mySelector->SelectionMode();
681 Emits signal selectionChanged()
684 SVTK_RenderWindowInteractor
685 ::onEmitSelectionChanged()
687 return emit selectionChanged();
692 Custom mouse move event handler
695 SVTK_RenderWindowInteractor
696 ::mouseMoveEvent( QMouseEvent* event )
698 QVTK_RenderWindowInteractor::mouseMoveEvent(event);
700 if(GENERATE_SUIT_EVENTS)
701 emit MouseMove( event );
706 Custom mouse press event handler
709 SVTK_RenderWindowInteractor
710 ::mousePressEvent( QMouseEvent* event )
712 QVTK_RenderWindowInteractor::mousePressEvent(event);
714 if(GENERATE_SUIT_EVENTS)
715 emit MouseButtonPressed( event );
720 Custom mouse release event handler
723 SVTK_RenderWindowInteractor
724 ::mouseReleaseEvent( QMouseEvent *event )
726 SVTK_InteractorStyle* style = 0;
727 bool aRightBtn = event->button() == Qt::RightButton;
728 bool isOperation = false;
729 bool isPolygonalSelection = false;
730 if( aRightBtn && GetInteractorStyle()) {
731 style = dynamic_cast<SVTK_InteractorStyle*>( GetInteractorStyle() );
733 isOperation = style->CurrentState() != VTK_INTERACTOR_STYLE_CAMERA_NONE;
736 QVTK_RenderWindowInteractor::mouseReleaseEvent(event);
739 isPolygonalSelection = style->GetPolygonState() == Finished;
740 style->SetPolygonState( Disable );
743 if ( aRightBtn && !isOperation && !isPolygonalSelection &&
744 !( event->modifiers() & Qt::ControlModifier ) &&
745 !( event->modifiers() & Qt::ShiftModifier ) ) {
746 QContextMenuEvent aEvent( QContextMenuEvent::Mouse,
747 event->pos(), event->globalPos() );
748 emit contextMenuRequested( &aEvent );
750 if(GENERATE_SUIT_EVENTS)
751 emit MouseButtonReleased( event );
756 Custom mouse double click event handler
759 SVTK_RenderWindowInteractor
760 ::mouseDoubleClickEvent( QMouseEvent* event )
762 if( GetInteractorStyle() && event->button() == Qt::LeftButton ) {
763 SVTK_InteractorStyle* style = dynamic_cast<SVTK_InteractorStyle*>( GetInteractorStyle() );
765 style->OnMouseButtonDoubleClick();
768 QVTK_RenderWindowInteractor::mouseDoubleClickEvent(event);
770 if(GENERATE_SUIT_EVENTS)
771 emit MouseDoubleClicked( event );
776 Custom mouse wheel event handler
779 SVTK_RenderWindowInteractor
780 ::wheelEvent( QWheelEvent* event )
782 QVTK_RenderWindowInteractor::wheelEvent(event);
784 if(event->delta() > 0)
785 GetDevice()->InvokeEvent(SVTK::ZoomInEvent,NULL);
787 GetDevice()->InvokeEvent(SVTK::ZoomOutEvent,NULL);
789 if(GENERATE_SUIT_EVENTS)
790 emit WheelMoved( event );
794 Custom key press event handler
797 SVTK_RenderWindowInteractor
798 ::keyPressEvent( QKeyEvent* event )
800 QVTK_RenderWindowInteractor::keyPressEvent(event);
802 if(GENERATE_SUIT_EVENTS)
803 emit KeyPressed( event );
807 Custom key release event handler
810 SVTK_RenderWindowInteractor
811 ::keyReleaseEvent( QKeyEvent * event )
813 QVTK_RenderWindowInteractor::keyReleaseEvent(event);
815 if(GENERATE_SUIT_EVENTS)
816 emit KeyReleased( event );