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"
33 #include "ViewerTools_ScreenScaling.h"
36 // Put Qt includes before the X11 includes which #define the symbol None
37 // (see SVTK_SpaceMouse.h) to avoid the compilation error.
38 #if !defined(WIN32) && !defined(__APPLE__)
42 #include <QMouseEvent>
44 #include "SVTK_SpaceMouse.h"
45 #include "SVTK_Event.h"
47 #include "VTKViewer_Algorithm.h"
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>
59 static bool GENERATE_SUIT_EVENTS = true;
60 static bool FOCUS_UNDER_MOUSE = false;
62 // workaround about the bug in vtkImplicitPlaneWidget class
63 // that eats mouse button release event
64 // causing clipping plane preview in SMESH sticking up
65 #define Fix_Of_vtkImplicitPlaneWidget_bug
70 QVTK_RenderWindowInteractor
71 ::QVTK_RenderWindowInteractor(QWidget* theParent,
74 myRenderWindow(vtkRenderWindow::New())
76 setAttribute( Qt::WA_PaintOnScreen );
77 setAttribute( Qt::WA_NoSystemBackground );
79 setObjectName(theName);
81 setMouseTracking(true);
83 myRenderWindow->Delete();
84 myRenderWindow->DoubleBufferOn();
86 #if !defined WIN32 && !defined __APPLE__
87 myRenderWindow->SetDisplayId((void*)QX11Info::display());
89 myRenderWindow->SetWindowId((void*)winId());
93 To initialize by vtkGenericRenderWindowInteractor instance
96 QVTK_RenderWindowInteractor
97 ::Initialize(vtkGenericRenderWindowInteractor* theDevice)
100 myDevice->SetRenderWindow( NULL );
102 myDevice = theDevice;
105 theDevice->SetRenderWindow( getRenderWindow() );
111 QVTK_RenderWindowInteractor
112 ::~QVTK_RenderWindowInteractor()
114 #if !defined WIN32 && !defined __APPLE__
115 SVTK_SpaceMouseXCB* aSpaceMouse = SVTK_SpaceMouseXCB::getInstance();
116 if ( aSpaceMouse && aSpaceMouse->isSpaceMouseOn() )
117 aSpaceMouse->close( QX11Info::connection() );
123 \return corresponding render window interactor
125 vtkGenericRenderWindowInteractor*
126 QVTK_RenderWindowInteractor
129 return myDevice.GetPointer();
133 \return corresponding render window
136 QVTK_RenderWindowInteractor
139 return myRenderWindow.GetPointer();
143 Just to simplify usage of its device (vtkGenericRenderWindowInteractor)
146 QVTK_RenderWindowInteractor
147 ::InvokeEvent(unsigned long theEvent, void* theCallData)
149 GetDevice()->InvokeEvent(theEvent,theCallData);
153 Get paint engine for the scene
155 QPaintEngine* QVTK_RenderWindowInteractor::paintEngine() const
161 Need for initial contents display on Win32
164 QVTK_RenderWindowInteractor
168 update(); // needed for initial contents display on Win32
172 To implement final initialization, just before the widget is displayed
175 QVTK_RenderWindowInteractor
178 // Final initialization just before the widget is displayed
179 const double pixelRatio = ViewerTools_ScreenScaling::getPR();
180 GetDevice()->SetSize(width() * pixelRatio, height() * pixelRatio);
181 if(!GetDevice()->GetInitialized() && GetDevice()->GetRenderWindow()){
182 GetDevice()->Initialize();
183 GetDevice()->ConfigureEvent();
188 To adjust widget and vtkRenderWindow size
191 QVTK_RenderWindowInteractor
192 ::resize(int w, int h)
194 GetDevice()->UpdateSize(w,h);
198 Custom paint event handler
201 QVTK_RenderWindowInteractor
202 ::paintEvent( QPaintEvent* /*theEvent*/ )
204 GetDevice()->CreateTimer(VTKI_TIMER_FIRST);
209 Custom resize event handler
212 QVTK_RenderWindowInteractor
213 ::resizeEvent( QResizeEvent* /* theEvent */ )
216 int* aSize = getRenderWindow()->GetSize();
217 int aWidth = aSize[0];
218 int aHeight = aSize[1];
220 const double pixelRatio = ViewerTools_ScreenScaling::getPR();
221 GetDevice()->UpdateSize(width() * pixelRatio, height() * pixelRatio);
223 if(isVisible() && aWidth && aHeight){
224 if( aWidth != width() || aHeight != height() ) {
225 vtkRendererCollection * aRenderers = getRenderWindow()->GetRenderers();
226 aRenderers->InitTraversal();
228 if(vtkRenderer *aRenderer = aRenderers->GetNextItem()) {
229 vtkCamera *aCamera = aRenderer->GetActiveCamera();
230 double aScale = aCamera->GetParallelScale();
231 if((aWidth - width())*(aHeight - height()) > 0)
232 aCoeff = sqrt(double(aWidth)/double(width())*double(height())/double(aHeight));
234 aCoeff = double(aWidth)/double(width());
235 aCamera->SetParallelScale(aScale*aCoeff);
246 Custom context menu event handler
249 QVTK_RenderWindowInteractor
250 ::contextMenuEvent( QContextMenuEvent* /*event*/ )
254 Custom mouse move event handler
257 QVTK_RenderWindowInteractor
258 ::mouseMoveEvent( QMouseEvent* event )
260 GetDevice()->SetEventInformationFlipY(event->x(),
262 event->modifiers() & Qt::ControlModifier,
263 event->modifiers() & Qt::ShiftModifier);
264 GetDevice()->MouseMoveEvent();
269 Custom mouse press event handler
272 QVTK_RenderWindowInteractor
273 ::mousePressEvent( QMouseEvent* event )
275 GetDevice()->SetEventInformationFlipY(event->x(),
277 event->modifiers() & Qt::ControlModifier,
278 event->modifiers() & Qt::ShiftModifier);
279 if( event->button() & Qt::LeftButton )
280 GetDevice()->LeftButtonPressEvent();
281 else if( event->button() & Qt::MidButton )
282 GetDevice()->MiddleButtonPressEvent();
283 else if( event->button() & Qt::RightButton )
284 GetDevice()->RightButtonPressEvent();
289 Custom mouse release event handler
292 QVTK_RenderWindowInteractor
293 ::mouseReleaseEvent( QMouseEvent *event )
295 GetDevice()->SetEventInformationFlipY(event->x(),
297 event->modifiers() & Qt::ControlModifier,
298 event->modifiers() & Qt::ShiftModifier);
300 if( event->button() & Qt::LeftButton )
301 GetDevice()->LeftButtonReleaseEvent();
302 else if( event->button() & Qt::MidButton )
303 GetDevice()->MiddleButtonReleaseEvent();
304 else if( event->button() & Qt::RightButton ) {
305 #if defined(Fix_Of_vtkImplicitPlaneWidget_bug)
306 GetDevice()->SetEventInformationFlipY( -99999, -99999,
307 event->modifiers() & Qt::ControlModifier,
308 event->modifiers() & Qt::ShiftModifier);
309 bool blocked = blockSignals( true );
310 GetDevice()->LeftButtonPressEvent();
311 GetDevice()->LeftButtonReleaseEvent();
312 blockSignals( blocked );
313 GetDevice()->SetEventInformationFlipY(event->x(),
315 event->modifiers() & Qt::ControlModifier,
316 event->modifiers() & Qt::ShiftModifier);
318 GetDevice()->RightButtonReleaseEvent();
324 Custom mouse double click event handler
327 QVTK_RenderWindowInteractor
328 ::mouseDoubleClickEvent( QMouseEvent* /*event*/ )
333 Custom mouse wheel event handler
336 QVTK_RenderWindowInteractor
337 ::wheelEvent( QWheelEvent* event )
341 GetDevice()->SetEventInformationFlipY(event->x(),
343 event->modifiers() & Qt::ControlModifier,
344 event->modifiers() & Qt::ShiftModifier);
345 if ( event->delta()>0)
346 GetDevice()->MouseWheelForwardEvent();
348 GetDevice()->MouseWheelBackwardEvent();
353 Custom key press event handler
356 QVTK_RenderWindowInteractor
357 ::keyPressEvent( QKeyEvent* event )
359 GetDevice()->SetKeyEventInformation(event->modifiers() & Qt::ControlModifier,
360 event->modifiers() & Qt::ShiftModifier,
362 GetDevice()->KeyPressEvent();
363 GetDevice()->CharEvent();
367 Custom key release event handler
370 QVTK_RenderWindowInteractor
371 ::keyReleaseEvent( QKeyEvent * event )
373 GetDevice()->SetKeyEventInformation(event->modifiers() & Qt::ControlModifier,
374 event->modifiers() & Qt::ShiftModifier,
376 GetDevice()->KeyReleaseEvent();
381 Custom enter event handler
384 QVTK_RenderWindowInteractor
385 ::enterEvent( QEvent* /*event*/ )
387 if(FOCUS_UNDER_MOUSE){
391 GetDevice()->EnterEvent();
395 Custom leave event handler
398 QVTK_RenderWindowInteractor
399 ::leaveEvent( QEvent * )
401 GetDevice()->LeaveEvent();
405 Reimplemented from QWidget in order to set window - receiver
406 of space mouse events.
409 QVTK_RenderWindowInteractor
410 ::focusInEvent( QFocusEvent* event )
412 QWidget::focusInEvent( event );
414 #if !defined WIN32 && !defined __APPLE__
415 // register set space mouse events receiver
416 SVTK_SpaceMouseXCB* aSpaceMouse = SVTK_SpaceMouseXCB::getInstance();
419 if ( !aSpaceMouse->isSpaceMouseOn() )
420 // initialize 3D space mouse driver
421 aSpaceMouse->initialize( QX11Info::connection(), winId() );
423 aSpaceMouse->setWindow( QX11Info::connection(), winId() );
429 Reimplemented from QWidget in order to set window - receiver
430 of space mouse events.
433 QVTK_RenderWindowInteractor
434 ::focusOutEvent ( QFocusEvent* event )
436 QWidget::focusOutEvent( event );
438 #if !defined WIN32 && !defined __APPLE__
439 SVTK_SpaceMouseXCB* aSpaceMouse = SVTK_SpaceMouseXCB::getInstance();
440 if ( aSpaceMouse && aSpaceMouse->isSpaceMouseOn() )
441 aSpaceMouse->setWindow( QX11Info::connection(), 0 );
445 bool QVTK_RenderWindowInteractor
446 ::nativeEvent(const QByteArray& eventType, void* message, long* result)
449 // TODO: WIN32-related implementation
450 #elif !defined(__APPLE__)
451 if ( eventType == "xcb_generic_event_t" )
453 xcb_generic_event_t* ev = static_cast<xcb_generic_event_t *>(message);
454 if ( SVTK_SpaceMouseXCB* aSpaceMouse = SVTK_SpaceMouseXCB::getInstance() )
456 if ( aSpaceMouse->isSpaceMouseOn() && ev->response_type == XCB_CLIENT_MESSAGE )
458 SVTK_SpaceMouse::MoveEvent anEvent;
459 int type = aSpaceMouse->translateEvent( QX11Info::connection(), (xcb_client_message_event_t*)ev, &anEvent, 1.0, 1.0 );
462 case SVTK_SpaceMouse::SpaceMouseMove:
463 GetDevice()->InvokeEvent( SVTK::SpaceMouseMoveEvent, anEvent.data );
465 case SVTK_SpaceMouse::SpaceButtonPress:
466 GetDevice()->InvokeEvent( SVTK::SpaceMouseButtonEvent, &anEvent.button );
468 case SVTK_SpaceMouse::SpaceButtonRelease:
471 return true; // stop handling the event
476 return QWidget::nativeEvent( eventType, message, result );
482 SVTK_RenderWindowInteractor
483 ::SVTK_RenderWindowInteractor(QWidget* theParent,
484 const char* theName):
485 QVTK_RenderWindowInteractor(theParent,theName),
486 myEventCallbackCommand(vtkCallbackCommand::New())
488 myEventCallbackCommand->Delete();
490 myEventCallbackCommand->SetClientData(this);
493 myEventCallbackCommand->SetCallback(SVTK_RenderWindowInteractor::ProcessEvents);
497 To initialize properly the class
500 SVTK_RenderWindowInteractor
501 ::Initialize(vtkGenericRenderWindowInteractor* theDevice,
502 SVTK_Renderer* theRenderer,
503 SVTK_Selector* theSelector)
505 QVTK_RenderWindowInteractor::Initialize(theDevice);
506 SetRenderer(theRenderer);
507 SetSelector(theSelector);
513 SVTK_RenderWindowInteractor
514 ::~SVTK_RenderWindowInteractor()
516 // Sequence of the destruction call are fixed and should be changed.
517 // vtkRenderWindow instance should be destroyed after all vtkRenderer's
518 GetDevice()->SetInteractorStyle(NULL);
519 while(!myInteractorStyles.empty()){
520 const PInteractorStyle& aStyle = myInteractorStyles.top();
521 aStyle->SetInteractor(NULL);
522 myInteractorStyles.pop();
527 To get corresponding SVTK_Renderer instance
530 SVTK_RenderWindowInteractor
533 return myRenderer.GetPointer();
537 To get corresponding SVTK_Renderer device (just to simplify collobaration with SVTK_Renderer)
540 SVTK_RenderWindowInteractor
543 return GetRenderer()->GetDevice();
548 \param theRenderer - new renderer
551 SVTK_RenderWindowInteractor
552 ::SetRenderer(SVTK_Renderer* theRenderer)
554 if(theRenderer == myRenderer.GetPointer())
558 myRenderWindow->RemoveRenderer(getRenderer());
560 myRenderer = theRenderer;
563 myRenderWindow->AddRenderer(getRenderer());
568 Changes interactor style
569 \param theStyle - new interactor style
572 SVTK_RenderWindowInteractor
573 ::InitInteractorStyle(vtkInteractorStyle* theStyle)
575 GetDevice()->SetInteractorStyle(theStyle);
579 To change current interactor style by pushing the new one into the container
582 SVTK_RenderWindowInteractor
583 ::PushInteractorStyle(vtkInteractorStyle* theStyle)
585 myInteractorStyles.push(PInteractorStyle(theStyle));
586 InitInteractorStyle(theStyle);
590 To restore previous interactor style
593 SVTK_RenderWindowInteractor
594 ::PopInteractorStyle()
596 if(GetInteractorStyle())
597 myInteractorStyles.pop();
599 if(GetInteractorStyle())
600 InitInteractorStyle(GetInteractorStyle());
604 To get current interactor style
607 SVTK_RenderWindowInteractor
608 ::GetInteractorStyle()
610 return myInteractorStyles.empty() ? 0 : myInteractorStyles.top().GetPointer();
615 To get current selector
618 SVTK_RenderWindowInteractor
621 return mySelector.GetPointer();
627 \param theSelector - new selector
630 SVTK_RenderWindowInteractor
631 ::SetSelector(SVTK_Selector* theSelector)
633 if(mySelector.GetPointer())
634 mySelector->RemoveObserver(myEventCallbackCommand.GetPointer());
636 mySelector = theSelector;
638 if(mySelector.GetPointer())
639 mySelector->AddObserver(vtkCommand::EndPickEvent,
640 myEventCallbackCommand.GetPointer(),
645 Main process VTK event method
648 SVTK_RenderWindowInteractor
649 ::ProcessEvents(vtkObject* vtkNotUsed(theObject),
650 unsigned long theEvent,
652 void* vtkNotUsed(theCallData))
654 SVTK_RenderWindowInteractor* self = reinterpret_cast<SVTK_RenderWindowInteractor*>(theClientData);
657 case vtkCommand::EndPickEvent:
658 self->onEmitSelectionChanged();
664 To change selection mode (just to simplify collobaration with SVTK_Selector)
667 SVTK_RenderWindowInteractor
668 ::SetSelectionMode(Selection_Mode theMode)
670 mySelector->SetSelectionMode(theMode);
674 To get current selection mode (just to simplify collobaration with SVTK_Selector)
677 SVTK_RenderWindowInteractor
678 ::SelectionMode() const
680 return mySelector->SelectionMode();
685 Emits signal selectionChanged()
688 SVTK_RenderWindowInteractor
689 ::onEmitSelectionChanged()
691 return emit selectionChanged();
696 Custom mouse move event handler
699 SVTK_RenderWindowInteractor
700 ::mouseMoveEvent( QMouseEvent* event )
702 event = static_cast<QMouseEvent*>(ViewerTools_ScreenScaling::getDpiAwareEvent(event));
703 QVTK_RenderWindowInteractor::mouseMoveEvent(event);
705 if(GENERATE_SUIT_EVENTS)
706 emit MouseMove( event );
711 Custom mouse press event handler
714 SVTK_RenderWindowInteractor
715 ::mousePressEvent( QMouseEvent* event )
717 event = static_cast<QMouseEvent*>(ViewerTools_ScreenScaling::getDpiAwareEvent(event));
718 QVTK_RenderWindowInteractor::mousePressEvent(event);
720 if(GENERATE_SUIT_EVENTS)
721 emit MouseButtonPressed( event );
726 Custom mouse release event handler
729 SVTK_RenderWindowInteractor
730 ::mouseReleaseEvent( QMouseEvent *event )
732 SVTK_InteractorStyle* style = 0;
733 bool aRightBtn = event->button() == Qt::RightButton;
734 bool isOperation = false;
735 bool isPolygonalSelection = false;
736 if( aRightBtn && GetInteractorStyle()) {
737 style = dynamic_cast<SVTK_InteractorStyle*>( GetInteractorStyle() );
739 isOperation = style->CurrentState() != VTK_INTERACTOR_STYLE_CAMERA_NONE;
742 event = static_cast<QMouseEvent*>(ViewerTools_ScreenScaling::getDpiAwareEvent(event));
743 QVTK_RenderWindowInteractor::mouseReleaseEvent(event);
746 isPolygonalSelection = style->GetPolygonState() == Finished;
747 style->SetPolygonState( Disable );
750 if ( aRightBtn && !isOperation && !isPolygonalSelection &&
751 !( event->modifiers() & Qt::ControlModifier ) &&
752 !( event->modifiers() & Qt::ShiftModifier ) ) {
753 // We need to pass unscaled coordinates to get a menu painted in a right place.
754 const double pixelRatio = ViewerTools_ScreenScaling::getPR();
755 QContextMenuEvent aEvent( QContextMenuEvent::Mouse,
756 event->pos() / pixelRatio, event->globalPos() / pixelRatio);
757 emit contextMenuRequested( &aEvent );
759 if(GENERATE_SUIT_EVENTS)
760 emit MouseButtonReleased( event );
765 Custom mouse double click event handler
768 SVTK_RenderWindowInteractor
769 ::mouseDoubleClickEvent( QMouseEvent* event )
771 event = static_cast<QMouseEvent*>(ViewerTools_ScreenScaling::getDpiAwareEvent(event));
773 if( GetInteractorStyle() && event->button() == Qt::LeftButton ) {
774 SVTK_InteractorStyle* style = dynamic_cast<SVTK_InteractorStyle*>( GetInteractorStyle() );
776 style->OnMouseButtonDoubleClick();
779 QVTK_RenderWindowInteractor::mouseDoubleClickEvent(event);
781 if(GENERATE_SUIT_EVENTS)
782 emit MouseDoubleClicked( event );
787 Custom mouse wheel event handler
790 SVTK_RenderWindowInteractor
791 ::wheelEvent( QWheelEvent* event )
793 event = static_cast<QWheelEvent*>(ViewerTools_ScreenScaling::getDpiAwareEvent(event));
795 QVTK_RenderWindowInteractor::wheelEvent(event);
797 if(event->delta() > 0)
798 GetDevice()->InvokeEvent(SVTK::ZoomInEvent,NULL);
800 GetDevice()->InvokeEvent(SVTK::ZoomOutEvent,NULL);
802 if(GENERATE_SUIT_EVENTS)
803 emit WheelMoved( event );
807 Custom key press event handler
810 SVTK_RenderWindowInteractor
811 ::keyPressEvent( QKeyEvent* event )
813 QVTK_RenderWindowInteractor::keyPressEvent(event);
815 if(GENERATE_SUIT_EVENTS)
816 emit KeyPressed( event );
820 Custom key release event handler
823 SVTK_RenderWindowInteractor
824 ::keyReleaseEvent( QKeyEvent * event )
826 QVTK_RenderWindowInteractor::keyReleaseEvent(event);
828 if(GENERATE_SUIT_EVENTS)
829 emit KeyReleased( event );