1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D, 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__)
38 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
43 #include <QMouseEvent>
45 #include "SVTK_SpaceMouse.h"
46 #include "SVTK_Event.h"
48 #include "VTKViewer_Algorithm.h"
51 #include <vtkObjectFactory.h>
52 #include <vtkRendererCollection.h>
53 #include <vtkRenderWindow.h>
54 #include <vtkGenericRenderWindowInteractor.h>
55 #include <vtkCallbackCommand.h>
56 #include <vtkCommand.h>
57 #include <vtkPicker.h>
58 #include <vtkCamera.h>
60 static bool GENERATE_SUIT_EVENTS = true;
61 static bool FOCUS_UNDER_MOUSE = false;
63 // workaround about the bug in vtkImplicitPlaneWidget class
64 // that eats mouse button release event
65 // causing clipping plane preview in SMESH sticking up
66 #define Fix_Of_vtkImplicitPlaneWidget_bug
71 QVTK_RenderWindowInteractor
72 ::QVTK_RenderWindowInteractor(QWidget* theParent,
75 myRenderWindow(vtkRenderWindow::New())
77 setAttribute( Qt::WA_PaintOnScreen );
78 setAttribute( Qt::WA_NoSystemBackground );
80 setObjectName(theName);
82 setMouseTracking(true);
84 myRenderWindow->Delete();
85 myRenderWindow->DoubleBufferOn();
87 #if !defined WIN32 && !defined __APPLE__
88 myRenderWindow->SetDisplayId((void*)QX11Info::display());
90 myRenderWindow->SetWindowId((void*)winId());
94 To initialize by vtkGenericRenderWindowInteractor instance
97 QVTK_RenderWindowInteractor
98 ::Initialize(vtkGenericRenderWindowInteractor* theDevice)
101 myDevice->SetRenderWindow( NULL );
103 myDevice = theDevice;
106 theDevice->SetRenderWindow( getRenderWindow() );
112 QVTK_RenderWindowInteractor
113 ::~QVTK_RenderWindowInteractor()
115 #if !defined WIN32 && !defined __APPLE__
116 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
117 SVTK_SpaceMouseX* aSpaceMouse = SVTK_SpaceMouseX::getInstance();
118 if ( aSpaceMouse && aSpaceMouse->isSpaceMouseOn() )
119 aSpaceMouse->close( QX11Info::display() );
121 SVTK_SpaceMouseXCB* aSpaceMouse = SVTK_SpaceMouseXCB::getInstance();
122 if ( aSpaceMouse && aSpaceMouse->isSpaceMouseOn() )
123 aSpaceMouse->close( QX11Info::connection() );
130 \return corresponding render window interactor
132 vtkGenericRenderWindowInteractor*
133 QVTK_RenderWindowInteractor
136 return myDevice.GetPointer();
140 \return corresponding render window
143 QVTK_RenderWindowInteractor
146 return myRenderWindow.GetPointer();
150 Just to simplify usage of its device (vtkGenericRenderWindowInteractor)
153 QVTK_RenderWindowInteractor
154 ::InvokeEvent(unsigned long theEvent, void* theCallData)
156 GetDevice()->InvokeEvent(theEvent,theCallData);
160 Get paint engine for the scene
162 QPaintEngine* QVTK_RenderWindowInteractor::paintEngine() const
168 Need for initial contents display on Win32
171 QVTK_RenderWindowInteractor
175 update(); // needed for initial contents display on Win32
179 To implement final initialization, just before the widget is displayed
182 QVTK_RenderWindowInteractor
185 // Final initialization just before the widget is displayed
186 GetDevice()->SetSize(width(),height());
187 if(!GetDevice()->GetInitialized() && GetDevice()->GetRenderWindow()){
188 GetDevice()->Initialize();
189 GetDevice()->ConfigureEvent();
194 To adjust widget and vtkRenderWindow size
197 QVTK_RenderWindowInteractor
198 ::resize(int w, int h)
200 GetDevice()->UpdateSize(w,h);
204 Custom paint event handler
207 QVTK_RenderWindowInteractor
208 ::paintEvent( QPaintEvent* theEvent )
210 GetDevice()->CreateTimer(VTKI_TIMER_FIRST);
215 Custom resize event handler
218 QVTK_RenderWindowInteractor
219 ::resizeEvent( QResizeEvent* theEvent )
221 int* aSize = getRenderWindow()->GetSize();
222 int aWidth = aSize[0];
223 int aHeight = aSize[1];
225 GetDevice()->UpdateSize(width(),height());
227 if(isVisible() && aWidth && aHeight){
228 if( aWidth != width() || aHeight != height() ) {
229 vtkRendererCollection * aRenderers = getRenderWindow()->GetRenderers();
230 aRenderers->InitTraversal();
232 if(vtkRenderer *aRenderer = aRenderers->GetNextItem()) {
233 vtkCamera *aCamera = aRenderer->GetActiveCamera();
234 double aScale = aCamera->GetParallelScale();
235 if((aWidth - width())*(aHeight - height()) > 0)
236 aCoeff = sqrt(double(aWidth)/double(width())*double(height())/double(aHeight));
238 aCoeff = double(aWidth)/double(width());
239 aCamera->SetParallelScale(aScale*aCoeff);
250 Custom context menu event handler
253 QVTK_RenderWindowInteractor
254 ::contextMenuEvent( QContextMenuEvent* event )
258 Custom mouse move event handler
261 QVTK_RenderWindowInteractor
262 ::mouseMoveEvent( QMouseEvent* event )
264 GetDevice()->SetEventInformationFlipY(event->x(),
266 event->modifiers() & Qt::ControlModifier,
267 event->modifiers() & Qt::ShiftModifier);
268 GetDevice()->MouseMoveEvent();
273 Custom mouse press event handler
276 QVTK_RenderWindowInteractor
277 ::mousePressEvent( QMouseEvent* event )
279 GetDevice()->SetEventInformationFlipY(event->x(),
281 event->modifiers() & Qt::ControlModifier,
282 event->modifiers() & Qt::ShiftModifier);
283 if( event->button() & Qt::LeftButton )
284 GetDevice()->LeftButtonPressEvent();
285 else if( event->button() & Qt::MidButton )
286 GetDevice()->MiddleButtonPressEvent();
287 else if( event->button() & Qt::RightButton )
288 GetDevice()->RightButtonPressEvent();
293 Custom mouse release event handler
296 QVTK_RenderWindowInteractor
297 ::mouseReleaseEvent( QMouseEvent *event )
299 GetDevice()->SetEventInformationFlipY(event->x(),
301 event->modifiers() & Qt::ControlModifier,
302 event->modifiers() & Qt::ShiftModifier);
304 if( event->button() & Qt::LeftButton )
305 GetDevice()->LeftButtonReleaseEvent();
306 else if( event->button() & Qt::MidButton )
307 GetDevice()->MiddleButtonReleaseEvent();
308 else if( event->button() & Qt::RightButton ) {
309 #if defined(Fix_Of_vtkImplicitPlaneWidget_bug)
310 GetDevice()->SetEventInformationFlipY( -99999, -99999,
311 event->modifiers() & Qt::ControlModifier,
312 event->modifiers() & Qt::ShiftModifier);
313 bool blocked = blockSignals( true );
314 GetDevice()->LeftButtonPressEvent();
315 GetDevice()->LeftButtonReleaseEvent();
316 blockSignals( blocked );
317 GetDevice()->SetEventInformationFlipY(event->x(),
319 event->modifiers() & Qt::ControlModifier,
320 event->modifiers() & Qt::ShiftModifier);
322 GetDevice()->RightButtonReleaseEvent();
328 Custom mouse double click event handler
331 QVTK_RenderWindowInteractor
332 ::mouseDoubleClickEvent( QMouseEvent* event )
337 Custom mouse wheel event handler
340 QVTK_RenderWindowInteractor
341 ::wheelEvent( QWheelEvent* event )
345 GetDevice()->SetEventInformationFlipY(event->x(),
347 event->modifiers() & Qt::ControlModifier,
348 event->modifiers() & Qt::ShiftModifier);
349 if ( event->delta()>0)
350 GetDevice()->MouseWheelForwardEvent();
352 GetDevice()->MouseWheelBackwardEvent();
357 Custom key press event handler
360 QVTK_RenderWindowInteractor
361 ::keyPressEvent( QKeyEvent* event )
363 GetDevice()->SetKeyEventInformation(event->modifiers() & Qt::ControlModifier,
364 event->modifiers() & Qt::ShiftModifier,
366 GetDevice()->KeyPressEvent();
367 GetDevice()->CharEvent();
371 Custom key release event handler
374 QVTK_RenderWindowInteractor
375 ::keyReleaseEvent( QKeyEvent * event )
377 GetDevice()->SetKeyEventInformation(event->modifiers() & Qt::ControlModifier,
378 event->modifiers() & Qt::ShiftModifier,
380 GetDevice()->KeyReleaseEvent();
385 Custom enter event handler
388 QVTK_RenderWindowInteractor
389 ::enterEvent( QEvent* event )
391 if(FOCUS_UNDER_MOUSE){
395 GetDevice()->EnterEvent();
399 Custom leave event handler
402 QVTK_RenderWindowInteractor
403 ::leaveEvent( QEvent * )
405 GetDevice()->LeaveEvent();
409 Reimplemented from QWidget in order to set window - receiver
410 of space mouse events.
413 QVTK_RenderWindowInteractor
414 ::focusInEvent( QFocusEvent* event )
416 QWidget::focusInEvent( event );
418 #if !defined WIN32 && !defined __APPLE__
419 // register set space mouse events receiver
420 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
421 SVTK_SpaceMouseX* aSpaceMouse = SVTK_SpaceMouseX::getInstance();
424 if ( !aSpaceMouse->isSpaceMouseOn() )
425 // initialize 3D space mouse driver
426 aSpaceMouse->initialize( QX11Info::display(), winId() );
428 aSpaceMouse->setWindow( QX11Info::display(), winId() );
431 SVTK_SpaceMouseXCB* aSpaceMouse = SVTK_SpaceMouseXCB::getInstance();
434 if ( !aSpaceMouse->isSpaceMouseOn() )
435 // initialize 3D space mouse driver
436 aSpaceMouse->initialize( QX11Info::connection(), winId() );
438 aSpaceMouse->setWindow( QX11Info::connection(), winId() );
445 Reimplemented from QWidget in order to set window - receiver
446 of space mouse events.
449 QVTK_RenderWindowInteractor
450 ::focusOutEvent ( QFocusEvent* event )
452 QWidget::focusOutEvent( event );
454 #if !defined WIN32 && !defined __APPLE__
455 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
456 // unregister set space mouse events receiver
457 SVTK_SpaceMouseX* aSpaceMouse = SVTK_SpaceMouseX::getInstance();
458 if ( aSpaceMouse && aSpaceMouse->isSpaceMouseOn() )
459 aSpaceMouse->setWindow( QX11Info::display(), 0 );
461 SVTK_SpaceMouseXCB* aSpaceMouse = SVTK_SpaceMouseXCB::getInstance();
462 if ( aSpaceMouse && aSpaceMouse->isSpaceMouseOn() )
463 aSpaceMouse->setWindow( QX11Info::connection(), 0 );
468 // TODO (QT5 PORTING) Below is a temporary solution, to allow compiling with Qt 5
469 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
473 To handle native Win32 events (from such devices as SpaceMouse)
475 bool QVTK_RenderWindowInteractor::winEvent( MSG* msg, long* result )
477 // TODO: Implement event handling for SpaceMouse
478 return QWidget::winEvent( msg, result);
481 #elif !defined(__APPLE__)
483 To handle native X11 events (from such devices as SpaceMouse)
486 QVTK_RenderWindowInteractor
487 ::x11Event( XEvent *xEvent )
489 // handle 3d space mouse events
490 if ( SVTK_SpaceMouseX* aSpaceMouse = SVTK_SpaceMouseX::getInstance() )
492 if ( aSpaceMouse->isSpaceMouseOn() && xEvent->type == ClientMessage )
494 SVTK_SpaceMouse::MoveEvent anEvent;
495 int type = aSpaceMouse->translateEvent( QX11Info::display(), xEvent, &anEvent, 1.0, 1.0 );
498 case SVTK_SpaceMouse::SpaceMouseMove:
499 GetDevice()->InvokeEvent( SVTK::SpaceMouseMoveEvent, anEvent.data );
501 case SVTK_SpaceMouse::SpaceButtonPress:
502 GetDevice()->InvokeEvent( SVTK::SpaceMouseButtonEvent, &anEvent.button );
504 case SVTK_SpaceMouse::SpaceButtonRelease:
507 return true; // stop handling the event
511 return QWidget::x11Event( xEvent );
516 #else // QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
518 bool QVTK_RenderWindowInteractor
519 ::nativeEvent(const QByteArray& eventType, void* message, long* result)
522 // TODO: WIN32-related implementation
523 #elif !defined(__APPLE__)
524 if ( eventType == "xcb_generic_event_t" )
526 xcb_generic_event_t* ev = static_cast<xcb_generic_event_t *>(message);
527 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
528 // TODO: this code is never called
529 if ( SVTK_SpaceMouseX* aSpaceMouse = SVTK_SpaceMouseX::getInstance() )
531 if ( SVTK_SpaceMouseXCB* aSpaceMouse = SVTK_SpaceMouseXCB::getInstance() )
534 if ( aSpaceMouse->isSpaceMouseOn() && ev->response_type == XCB_CLIENT_MESSAGE )
536 SVTK_SpaceMouse::MoveEvent anEvent;
537 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
538 // TODO: this code is never called
539 int type = aSpaceMouse->translateEvent( QX11Info::display(), xEvent, &anEvent, 1.0, 1.0 );
541 int type = aSpaceMouse->translateEvent( QX11Info::connection(), (xcb_client_message_event_t*)ev, &anEvent, 1.0, 1.0 );
545 case SVTK_SpaceMouse::SpaceMouseMove:
546 GetDevice()->InvokeEvent( SVTK::SpaceMouseMoveEvent, anEvent.data );
548 case SVTK_SpaceMouse::SpaceButtonPress:
549 GetDevice()->InvokeEvent( SVTK::SpaceMouseButtonEvent, &anEvent.button );
551 case SVTK_SpaceMouse::SpaceButtonRelease:
554 return true; // stop handling the event
559 return QWidget::nativeEvent( eventType, message, result );
565 SVTK_RenderWindowInteractor
566 ::SVTK_RenderWindowInteractor(QWidget* theParent,
567 const char* theName):
568 QVTK_RenderWindowInteractor(theParent,theName),
569 myEventCallbackCommand(vtkCallbackCommand::New())
571 myEventCallbackCommand->Delete();
573 myEventCallbackCommand->SetClientData(this);
576 myEventCallbackCommand->SetCallback(SVTK_RenderWindowInteractor::ProcessEvents);
580 To initialize properly the class
583 SVTK_RenderWindowInteractor
584 ::Initialize(vtkGenericRenderWindowInteractor* theDevice,
585 SVTK_Renderer* theRenderer,
586 SVTK_Selector* theSelector)
588 QVTK_RenderWindowInteractor::Initialize(theDevice);
589 SetRenderer(theRenderer);
590 SetSelector(theSelector);
596 SVTK_RenderWindowInteractor
597 ::~SVTK_RenderWindowInteractor()
599 // Sequence of the destruction call are fixed and should be changed.
600 // vtkRenderWindow instance should be destroyed after all vtkRenderer's
601 GetDevice()->SetInteractorStyle(NULL);
602 while(!myInteractorStyles.empty()){
603 const PInteractorStyle& aStyle = myInteractorStyles.top();
604 aStyle->SetInteractor(NULL);
605 myInteractorStyles.pop();
610 GetDevice()->SetRenderWindow(NULL);
614 To get corresponding SVTK_Renderer instance
617 SVTK_RenderWindowInteractor
620 return myRenderer.GetPointer();
624 To get corresponding SVTK_Renderer device (just to simplify collobaration with SVTK_Renderer)
627 SVTK_RenderWindowInteractor
630 return GetRenderer()->GetDevice();
635 \param theRenderer - new renderer
638 SVTK_RenderWindowInteractor
639 ::SetRenderer(SVTK_Renderer* theRenderer)
641 if(theRenderer == myRenderer.GetPointer())
645 myRenderWindow->RemoveRenderer(getRenderer());
647 myRenderer = theRenderer;
650 myRenderWindow->AddRenderer(getRenderer());
655 Changes interactor style
656 \param theStyle - new interactor style
659 SVTK_RenderWindowInteractor
660 ::InitInteractorStyle(vtkInteractorStyle* theStyle)
662 GetDevice()->SetInteractorStyle(theStyle);
666 To change current interactor style by pushing the new one into the container
669 SVTK_RenderWindowInteractor
670 ::PushInteractorStyle(vtkInteractorStyle* theStyle)
672 myInteractorStyles.push(PInteractorStyle(theStyle));
673 InitInteractorStyle(theStyle);
677 To restore previous interactor style
680 SVTK_RenderWindowInteractor
681 ::PopInteractorStyle()
683 if(GetInteractorStyle())
684 myInteractorStyles.pop();
686 if(GetInteractorStyle())
687 InitInteractorStyle(GetInteractorStyle());
691 To get current interactor style
694 SVTK_RenderWindowInteractor
695 ::GetInteractorStyle()
697 return myInteractorStyles.empty() ? 0 : myInteractorStyles.top().GetPointer();
702 To get current selector
705 SVTK_RenderWindowInteractor
708 return mySelector.GetPointer();
714 \param theSelector - new selector
717 SVTK_RenderWindowInteractor
718 ::SetSelector(SVTK_Selector* theSelector)
720 if(mySelector.GetPointer())
721 mySelector->RemoveObserver(myEventCallbackCommand.GetPointer());
723 mySelector = theSelector;
725 if(mySelector.GetPointer())
726 mySelector->AddObserver(vtkCommand::EndPickEvent,
727 myEventCallbackCommand.GetPointer(),
732 Main process VTK event method
735 SVTK_RenderWindowInteractor
736 ::ProcessEvents(vtkObject* vtkNotUsed(theObject),
737 unsigned long theEvent,
739 void* vtkNotUsed(theCallData))
741 SVTK_RenderWindowInteractor* self = reinterpret_cast<SVTK_RenderWindowInteractor*>(theClientData);
744 case vtkCommand::EndPickEvent:
745 self->onEmitSelectionChanged();
751 To change selection mode (just to simplify collobaration with SVTK_Selector)
754 SVTK_RenderWindowInteractor
755 ::SetSelectionMode(Selection_Mode theMode)
757 mySelector->SetSelectionMode(theMode);
761 To get current selection mode (just to simplify collobaration with SVTK_Selector)
764 SVTK_RenderWindowInteractor
765 ::SelectionMode() const
767 return mySelector->SelectionMode();
772 Emits signal selectionChanged()
775 SVTK_RenderWindowInteractor
776 ::onEmitSelectionChanged()
778 return emit selectionChanged();
783 Custom mouse move event handler
786 SVTK_RenderWindowInteractor
787 ::mouseMoveEvent( QMouseEvent* event )
789 QVTK_RenderWindowInteractor::mouseMoveEvent(event);
791 if(GENERATE_SUIT_EVENTS)
792 emit MouseMove( event );
797 Custom mouse press event handler
800 SVTK_RenderWindowInteractor
801 ::mousePressEvent( QMouseEvent* event )
803 QVTK_RenderWindowInteractor::mousePressEvent(event);
805 if(GENERATE_SUIT_EVENTS)
806 emit MouseButtonPressed( event );
811 Custom mouse release event handler
814 SVTK_RenderWindowInteractor
815 ::mouseReleaseEvent( QMouseEvent *event )
817 SVTK_InteractorStyle* style = 0;
818 bool aRightBtn = event->button() == Qt::RightButton;
819 bool isOperation = false;
820 bool isPolygonalSelection = false;
821 if( aRightBtn && GetInteractorStyle()) {
822 style = dynamic_cast<SVTK_InteractorStyle*>( GetInteractorStyle() );
824 isOperation = style->CurrentState() != VTK_INTERACTOR_STYLE_CAMERA_NONE;
827 QVTK_RenderWindowInteractor::mouseReleaseEvent(event);
830 isPolygonalSelection = style->GetPolygonState() == Finished;
831 style->SetPolygonState( Disable );
834 if ( aRightBtn && !isOperation && !isPolygonalSelection &&
835 !( event->modifiers() & Qt::ControlModifier ) &&
836 !( event->modifiers() & Qt::ShiftModifier ) ) {
837 QContextMenuEvent aEvent( QContextMenuEvent::Mouse,
838 event->pos(), event->globalPos() );
839 emit contextMenuRequested( &aEvent );
841 if(GENERATE_SUIT_EVENTS)
842 emit MouseButtonReleased( event );
847 Custom mouse double click event handler
850 SVTK_RenderWindowInteractor
851 ::mouseDoubleClickEvent( QMouseEvent* event )
853 if( GetInteractorStyle() && event->button() == Qt::LeftButton ) {
854 SVTK_InteractorStyle* style = dynamic_cast<SVTK_InteractorStyle*>( GetInteractorStyle() );
856 style->OnMouseButtonDoubleClick();
859 QVTK_RenderWindowInteractor::mouseDoubleClickEvent(event);
861 if(GENERATE_SUIT_EVENTS)
862 emit MouseDoubleClicked( event );
867 Custom mouse wheel event handler
870 SVTK_RenderWindowInteractor
871 ::wheelEvent( QWheelEvent* event )
873 QVTK_RenderWindowInteractor::wheelEvent(event);
875 if(event->delta() > 0)
876 GetDevice()->InvokeEvent(SVTK::ZoomInEvent,NULL);
878 GetDevice()->InvokeEvent(SVTK::ZoomOutEvent,NULL);
880 if(GENERATE_SUIT_EVENTS)
881 emit WheelMoved( event );
885 Custom key press event handler
888 SVTK_RenderWindowInteractor
889 ::keyPressEvent( QKeyEvent* event )
891 QVTK_RenderWindowInteractor::keyPressEvent(event);
893 if(GENERATE_SUIT_EVENTS)
894 emit KeyPressed( event );
898 Custom key release event handler
901 SVTK_RenderWindowInteractor
902 ::keyReleaseEvent( QKeyEvent * event )
904 QVTK_RenderWindowInteractor::keyReleaseEvent(event);
906 if(GENERATE_SUIT_EVENTS)
907 emit KeyReleased( event );