0022048: Visualization, AIS_InteractiveContext - single object selection should alway...
[occt.git] / src / IVtkDraw / IVtkDraw_Interactor.cxx
CommitLineData
52f99d93 1// Created on: 2012-05-28
2//
3// Copyright (c) 2011-2014 OPEN CASCADE SAS
4//
5// This file is part of Open CASCADE Technology software library.
6//
7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
9// by the Free Software Foundation, with special exception defined in the file
10// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11// distribution for complete text of the license and disclaimer of any warranty.
12//
13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
15
16#ifdef _WIN32
52f99d93 17#include <windows.h>
18#include <vtkWin32RenderWindowInteractor.h>
19#include <vtkWin32OpenGLRenderWindow.h>
20#endif
21
22#include <IVtkTools_ShapePicker.hxx>
23#include <IVtkTools_SubPolyDataFilter.hxx>
24#include <IVtkTools_DisplayModeFilter.hxx>
25#include <IVtkTools_ShapeObject.hxx>
26#include <IVtkTools_ShapeDataSource.hxx>
27#include <IVtkDraw_Interactor.hxx>
28
29#include <Message.hxx>
30#include <Message_Messenger.hxx>
31
32#include <vtkActor.h>
33#include <vtkActorCollection.h>
34#include <vtkCommand.h>
35#include <vtkObjectFactory.h>
36#include <vtkSmartPointer.h>
37
38#ifndef _WIN32
39#include <X11/X.h>
40#include <X11/Shell.h>
41#include <X11/Xlib.h>
42#include <GL/glx.h>
43#include <vtkXRenderWindowInteractor.h>
44#include <vtkXOpenGLRenderWindow.h>
45#include <X11/Xutil.h>
46#include <tk.h>
47#endif
48
49//===========================================================
50// Function : ClearHighlightAndSelection
51// Purpose :
52//===========================================================
53static void ClearHighlightAndSelection (const Handle(ShapePipelineMap)& theMap,
54 const Standard_Boolean doHighlighting,
55 const Standard_Boolean doSelection)
56{
57 if (!doHighlighting && !doSelection)
58 {
59 return;
60 }
61
62 for (ShapePipelineMap::Iterator anIt (*theMap); anIt.More(); anIt.Next())
63 {
64 const Handle(IVtkDraw_HighlightAndSelectionPipeline)& aPL = anIt.Value();
65
66 if (doHighlighting)
67 {
68 aPL->ClearHighlightFilters();
69 }
70
71 if (doSelection)
72 {
73 aPL->ClearSelectionFilters();
74 }
75 }
76}
77
68858c7d 78vtkStandardNewMacro(IVtkDraw_Interactor)
52f99d93 79
80//===========================================================
81// Function : Constructor
82// Purpose :
83//===========================================================
84IVtkDraw_Interactor::IVtkDraw_Interactor()
85:
86#ifdef _WIN32
87 myWindowId (NULL),
88 myMouseInWindow (0)
89#else
90 myIsLeftButtonPressed (Standard_False)
91#endif
92{ }
93
94//===========================================================
95// Function : Destructor
96// Purpose :
97//===========================================================
98IVtkDraw_Interactor::~IVtkDraw_Interactor()
99{
100}
101
52f99d93 102//===========================================================
103// Function : SetShapePicker
104// Purpose :
105//===========================================================
106void IVtkDraw_Interactor::SetShapePicker (const PSelector& theSelector)
107{
108 mySelector = theSelector;
109}
110
111//===========================================================
112// Function : SetPipelines
113// Purpose :
114//===========================================================
115void IVtkDraw_Interactor::SetPipelines (const Handle(ShapePipelineMap)& thePipelines)
116{
117 myPipelines = thePipelines;
118}
119
120//===========================================================
121// Function : SetOCCWindow
122// Purpose :
123//===========================================================
124void IVtkDraw_Interactor::SetOCCWindow (const Handle(Aspect_Window)& theWindow)
125{
126 myWindow = theWindow;
127}
128
129//===========================================================
130// Function : GetOCCWindow
131// Purpose :
132//===========================================================
133const Handle(Aspect_Window)& IVtkDraw_Interactor::GetOCCWindow() const
134{
135 return myWindow;
136}
137
138//===========================================================
139// Function : IsEnabled
140// Purpose :
141//===========================================================
142Standard_Boolean IVtkDraw_Interactor::IsEnabled() const
143{
dde68833 144 return (Enabled != 0);
52f99d93 145}
146
147//===========================================================
148// Function : Initialize
149// Purpose :
150//===========================================================
151void IVtkDraw_Interactor::Initialize()
152{
153 // Make sure we have a RenderWindow and camera
154 if (!this->RenderWindow)
155 {
156 vtkErrorMacro(<<"No renderer defined!");
157 return;
158 }
159
160 if (this->Initialized)
161 {
162 return;
163 }
164
165 this->Initialized = 1;
166
167 // Get the info we need from the RenderingWindow
168 Standard_Integer *aSize;
169#ifdef _WIN32
170 vtkWin32OpenGLRenderWindow *aRenWin;
171 aRenWin = (vtkWin32OpenGLRenderWindow *)(this->RenderWindow);
172 aRenWin->Start();
173 aSize = aRenWin->GetSize();
174 aRenWin->GetPosition();
175 this->myWindowId = aRenWin->GetWindowId();
176#else
177 vtkXOpenGLRenderWindow *aRenWin;
178 aRenWin = static_cast<vtkXOpenGLRenderWindow *>(this->RenderWindow);
179 this->myDisplayId = aRenWin->GetDisplayId();
180 this->myWindowId = aRenWin->GetWindowId();
181 aSize = aRenWin->GetSize();
182 aRenWin->Start();
183#endif
184
185 this->Enable();
186 this->Size[0] = aSize[0];
187 this->Size[1] = aSize[1];
188}
189
190//===========================================================
191// Function : Enable
192// Purpose :
193//===========================================================
194void IVtkDraw_Interactor::Enable()
195{
196 if (this->Enabled)
197 {
198 return;
199 }
200
201 // Add event handlers
202#ifdef _WIN32
203 SetWindowLongPtr(this->myWindowId, GWLP_USERDATA, (LONG_PTR)this);
204 SetWindowLongPtr(this->myWindowId, GWLP_WNDPROC, (LONG_PTR)WndProc);
205#else
206 #if TCL_MAJOR_VERSION < 8
207 Tk_CreateFileHandler((void*)ConnectionNumber(this->myDisplayId),
208 TK_READABLE, ProcessEvents, (ClientData) this);
209 #else
210 Tk_CreateFileHandler(ConnectionNumber(this->myDisplayId),
211 TK_READABLE, ProcessEvents, (ClientData) this);
212 #endif
213#endif
214
215 this->Enabled = 1;
216 this->Modified();
217}
218
219//===========================================================
220// Function : MoveTo
221// Purpose :
222//===========================================================
223void IVtkDraw_Interactor::MoveTo (Standard_Integer theX, Standard_Integer theY)
224{
225 // Processing highlighting
226 mySelector->Pick (theX, theY, 0.0);
a2f76b15 227 vtkSmartPointer<vtkActorCollection> anActorCollection = mySelector->GetPickedActors();
52f99d93 228
229 if (anActorCollection)
230 {
231 // Highlight picked subshapes
232 ClearHighlightAndSelection (myPipelines, Standard_True, Standard_False);
233 anActorCollection->InitTraversal();
234 while (vtkActor* anActor = anActorCollection->GetNextActor())
235 {
236 IVtkTools_ShapeDataSource* aDataSource = IVtkTools_ShapeObject::GetShapeSource (anActor);
237 if (!aDataSource)
238 {
239 continue;
240 }
241
242 IVtkOCC_Shape::Handle anOccShape = aDataSource->GetShape();
243 if (anOccShape.IsNull())
244 {
245 continue;
246 }
247
248 IVtk_IdType aShapeID = anOccShape->GetId();
249 Handle(Message_Messenger) anOutput = Message::DefaultMessenger();
250 if (!myPipelines->IsBound(aShapeID))
251 {
252 anOutput << "Warning: there is no VTK pipeline registered for highlighted shape" << endl;
253 continue;
254 }
255
256 const Handle(IVtkDraw_HighlightAndSelectionPipeline)& aPL = myPipelines->Find (aShapeID);
257
258 // Add a subpolydata filter to the highlight pipeline for the shape data source.
259 IVtkTools_SubPolyDataFilter* aFilter = aPL->GetHighlightFilter();
260
261 // Set the selected sub-shapes ids to subpolydata filter.
262 IVtk_ShapeIdList aSubShapeIds = mySelector->GetPickedSubShapesIds(aShapeID);
263
264 // Get ids of cells for picked subshapes.
265 IVtk_ShapeIdList aSubIds;
266 IVtk_ShapeIdList::Iterator aMetaIds (aSubShapeIds);
267 for (; aMetaIds.More(); aMetaIds.Next())
268 {
269 IVtk_ShapeIdList aSubSubIds = anOccShape->GetSubIds (aMetaIds.Value());
270 aSubIds.Append (aSubSubIds);
271 }
272
273 aFilter->SetDoFiltering (!aSubIds.IsEmpty());
274 aFilter->SetData (aSubIds);
275 if (!aFilter->GetInput())
276 {
277 aFilter->SetInputConnection (aDataSource->GetOutputPort());
278 }
279 aFilter->Modified();
280 }
281 }
282 this->Render();
283}
284
285//===========================================================
286// Function : OnSelection
287// Purpose :
288//===========================================================
289void IVtkDraw_Interactor::OnSelection()
290{
291 // Processing selection
a2f76b15 292 vtkSmartPointer<vtkActorCollection> anActorCollection = mySelector->GetPickedActors();
52f99d93 293
294 if (anActorCollection)
295 {
296 // Highlight picked subshapes.
297 ClearHighlightAndSelection (myPipelines, Standard_False, Standard_True);
298 anActorCollection->InitTraversal();
299 while (vtkActor* anActor = anActorCollection->GetNextActor())
300 {
301 IVtkTools_ShapeDataSource* aDataSource = IVtkTools_ShapeObject::GetShapeSource (anActor);
302 if (!aDataSource)
303 {
304 continue;
305 }
306
307 IVtkOCC_Shape::Handle anOccShape = aDataSource->GetShape();
308 if (anOccShape.IsNull())
309 {
310 continue;
311 }
312
313 IVtk_IdType aShapeID = anOccShape->GetId();
314 Handle(Message_Messenger) anOutput = Message::DefaultMessenger();
315 if (!myPipelines->IsBound (aShapeID))
316 {
317 anOutput << "Warning: there is no VTK pipeline registered for picked shape" << endl;
318 continue;
319 }
320
321 const Handle(IVtkDraw_HighlightAndSelectionPipeline)& aPL = myPipelines->Find (aShapeID);
322
323 // Add a subpolydata filter to the selection pipeline for the shape data source.
324 IVtkTools_SubPolyDataFilter* aFilter = aPL->GetSelectionFilter();
325
326 // Set the selected sub-shapes ids to subpolydata filter.
327 IVtk_ShapeIdList aSubShapeIds = mySelector->GetPickedSubShapesIds(aShapeID);
328
329 // Get ids of cells for picked subshapes.
330 IVtk_ShapeIdList aSubIds;
331 IVtk_ShapeIdList::Iterator aMetaIds (aSubShapeIds);
332 for (; aMetaIds.More(); aMetaIds.Next())
333 {
334 IVtk_ShapeIdList aSubSubIds = anOccShape->GetSubIds (aMetaIds.Value());
335 aSubIds.Append (aSubSubIds);
336 }
337
338 aFilter->SetDoFiltering (!aSubIds.IsEmpty());
339 aFilter->SetData (aSubIds);
340 if (!aFilter->GetInput())
341 {
342 aFilter->SetInputConnection (aDataSource->GetOutputPort());
343 }
344 aFilter->Modified();
345 }
346 }
347 this->Render();
348}
349
350#ifdef _WIN32
351
352//===========================================================
353// Function : OnMouseMove
354// Purpose :
355//===========================================================
356void IVtkDraw_Interactor::OnMouseMove (HWND theHWnd, UINT theNFlags,
357 Standard_Integer theX,
358 Standard_Integer theY)
359{
360 if (!this->Enabled)
361 {
362 return;
363 }
364
365 this->SetEventInformationFlipY (theX,
366 theY,
367 theNFlags & MK_CONTROL,
368 theNFlags & MK_SHIFT);
369 this->SetAltKey(GetKeyState(VK_MENU) & (~1));
370 if (!this->myMouseInWindow &&
371 (theX >= 0 && theX < this->Size[0] && theY >= 0 && theY < this->Size[1]))
372 {
373 this->InvokeEvent (vtkCommand::EnterEvent, NULL);
374 this->myMouseInWindow = 1;
375 // request WM_MOUSELEAVE generation
376 TRACKMOUSEEVENT aTme;
377 aTme.cbSize = sizeof (TRACKMOUSEEVENT);
378 aTme.dwFlags = TME_LEAVE;
379 aTme.hwndTrack = theHWnd;
380 TrackMouseEvent (&aTme);
381 }
382
383 if (!(theNFlags & MK_LBUTTON))
384 this->MoveTo (theX, this->Size[1] - theY - 1);
385
386 this->InvokeEvent (vtkCommand::MouseMoveEvent, NULL);
387}
388
389//===========================================================
390// Function : OnMouseWheelForward
391// Purpose :
392//===========================================================
393void IVtkDraw_Interactor::OnMouseWheelForward (HWND, UINT theNFlags,
394 Standard_Integer theX,
395 Standard_Integer theY)
396{
397 if (!this->Enabled)
398 {
399 return;
400 }
401
402 this->SetEventInformationFlipY (theX,
403 theY,
404 theNFlags & MK_CONTROL,
405 theNFlags & MK_SHIFT);
406
407 this->SetAltKey (GetKeyState(VK_MENU) & (~1));
408 this->InvokeEvent (vtkCommand::MouseWheelForwardEvent, NULL);
409}
410
411//===========================================================
412// Function : OnMouseWheelBackward
413// Purpose :
414//===========================================================
415void IVtkDraw_Interactor::OnMouseWheelBackward (HWND, UINT theNFlags,
416 Standard_Integer theX,
417 Standard_Integer theY)
418{
419 if (!this->Enabled)
420 {
421 return;
422 }
423
424 this->SetEventInformationFlipY (theX,
425 theY,
426 theNFlags & MK_CONTROL,
427 theNFlags & MK_SHIFT);
428
429 this->SetAltKey (GetKeyState(VK_MENU) & (~1));
430 this->InvokeEvent (vtkCommand::MouseWheelBackwardEvent, NULL);
431}
432
433//===========================================================
434// Function : OnLButtonDown
435// Purpose :
436//===========================================================
437void IVtkDraw_Interactor::OnLButtonDown (HWND theHWnd, UINT theNFlags,
438 Standard_Integer theX,
439 Standard_Integer theY,
440 Standard_Integer theRepeat)
441{
442 if (!this->Enabled)
443 {
444 return;
445 }
446 SetFocus (theHWnd);
447 SetCapture (theHWnd);
448 this->SetEventInformationFlipY (theX,
449 theY,
450 theNFlags & MK_CONTROL,
451 theNFlags & MK_SHIFT,
452 0, theRepeat);
453 this->SetAltKey (GetKeyState(VK_MENU) & (~1));
454
455 OnSelection ();
456
457 this->InvokeEvent (vtkCommand::LeftButtonPressEvent, NULL);
458}
459
460//===========================================================
461// Function : OnLButtonUp
462// Purpose :
463//===========================================================
464void IVtkDraw_Interactor::OnLButtonUp (HWND, UINT theNFlags,
465 Standard_Integer theX,
466 Standard_Integer theY)
467{
468 if (!this->Enabled)
469 {
470 return;
471 }
472
473 this->SetEventInformationFlipY (theX,
474 theY,
475 theNFlags & MK_CONTROL,
476 theNFlags & MK_SHIFT);
477
478 this->SetAltKey (GetKeyState(VK_MENU) & (~1));
479 this->InvokeEvent (vtkCommand::LeftButtonReleaseEvent, NULL);
480 ReleaseCapture();
481}
482
483//===========================================================
484// Function : OnMButtonDown
485// Purpose :
486//===========================================================
487void IVtkDraw_Interactor::OnMButtonDown (HWND theHWnd, UINT theNFlags,
488 Standard_Integer theX,
489 Standard_Integer theY,
490 Standard_Integer theRepeat)
491{
492 if (!this->Enabled)
493 {
494 return;
495 }
496
497 SetFocus (theHWnd);
498 SetCapture (theHWnd);
499 this->SetEventInformationFlipY (theX,
500 theY,
501 theNFlags & MK_CONTROL,
502 theNFlags & MK_SHIFT,
503 0, theRepeat);
504 this->SetAltKey (GetKeyState(VK_MENU) & (~1));
505 this->InvokeEvent (vtkCommand::MiddleButtonPressEvent, NULL);
506}
507
508//===========================================================
509// Function : OnMButtonUp
510// Purpose :
511//===========================================================
512void IVtkDraw_Interactor::OnMButtonUp (HWND, UINT theNFlags,
513 Standard_Integer theX,
514 Standard_Integer theY)
515{
516 if (!this->Enabled)
517 {
518 return;
519 }
520 this->SetEventInformationFlipY (theX,
521 theY,
522 theNFlags & MK_CONTROL,
523 theNFlags & MK_SHIFT);
524
525 this->SetAltKey (GetKeyState(VK_MENU) & (~1));
526 this->InvokeEvent (vtkCommand::MiddleButtonReleaseEvent, NULL);
527 ReleaseCapture();
528}
529
530//===========================================================
531// Function : OnRButtonDown
532// Purpose :
533//===========================================================
534void IVtkDraw_Interactor::OnRButtonDown (HWND theHWnd, UINT theNFlags,
535 Standard_Integer theX,
536 Standard_Integer theY,
537 Standard_Integer theRepeat)
538{
539 if (!this->Enabled)
540 {
541 return;
542 }
543
544 SetFocus(theHWnd);
545 SetCapture(theHWnd);
546 this->SetEventInformationFlipY (theX,
547 theY,
548 theNFlags & MK_CONTROL,
549 theNFlags & MK_SHIFT,
550 0, theRepeat);
551
552 this->SetAltKey (GetKeyState(VK_MENU) & (~1));
553 this->InvokeEvent (vtkCommand::RightButtonPressEvent, NULL);
554}
555
556//===========================================================
557// Function : OnRButtonUp
558// Purpose :
559//===========================================================
560void IVtkDraw_Interactor::OnRButtonUp (HWND, UINT theNFlags,
561 Standard_Integer theX,
562 Standard_Integer theY)
563{
564 if (!this->Enabled)
565 {
566 return;
567 }
568 this->SetEventInformationFlipY (theX,
569 theY,
570 theNFlags & MK_CONTROL,
571 theNFlags & MK_SHIFT);
572
573 this->SetAltKey (GetKeyState(VK_MENU) & (~1));
574 this->InvokeEvent (vtkCommand::RightButtonReleaseEvent, NULL);
575 ReleaseCapture();
576}
577
578//===========================================================
579// Function : OnSize
580// Purpose :
581//===========================================================
582void IVtkDraw_Interactor::OnSize (HWND, UINT,
583 Standard_Integer theX,
584 Standard_Integer theY)
585{
586 this->UpdateSize (theX, theY);
587 if (this->Enabled)
588 {
589 this->InvokeEvent (vtkCommand::ConfigureEvent, NULL);
590 }
591}
592
593//===========================================================
594// Function : OnTimer
595// Purpose :
596//===========================================================
597void IVtkDraw_Interactor::OnTimer (HWND, UINT theTimerId)
598{
599 if (!this->Enabled)
600 {
601 return;
602 }
603
604 Standard_Integer aTid = static_cast<Standard_Integer>(theTimerId);
605 this->InvokeEvent (vtkCommand::TimerEvent, (void*)&aTid);
606
607 // Here we deal with one-shot versus repeating timers
608 if (this->IsOneShotTimer(aTid))
609 {
610 KillTimer (this->myWindowId, aTid); //'cause windows timers are always repeating
611 }
612}
613
614//===========================================================
615// Function : WndProc
616// Purpose :
617//===========================================================
618LRESULT CALLBACK WndProc (HWND theHWnd,UINT theUMsg,
619 WPARAM theWParam,
620 LPARAM theLParam)
621{
622 LRESULT aRes = 0;
623 IVtkDraw_Interactor *anInteractor = 0;
624
625 anInteractor = (IVtkDraw_Interactor *)GetWindowLongPtr (theHWnd, GWLP_USERDATA);
626
627 if (anInteractor && anInteractor->GetReferenceCount() > 0)
628 {
629 anInteractor->Register (anInteractor);
630 aRes = ViewerWindowProc (theHWnd, theUMsg, theWParam, theLParam, anInteractor);
631 anInteractor->UnRegister (anInteractor);
632 }
633
634 return aRes;
635}
636
637//===========================================================
638// Function : ViewerWindowProc
639// Purpose :
640//===========================================================
641LRESULT CALLBACK ViewerWindowProc (HWND theHWnd,
642 UINT theMsg,
643 WPARAM theWParam,
644 LPARAM theLParam,
645 IVtkDraw_Interactor *theInteractor)
646{
647 switch (theMsg)
648 {
649 case WM_CLOSE:
650 theInteractor->GetOCCWindow ()->Unmap ();
651 return 0;
652 case WM_PAINT:
653 theInteractor->Render();
654 break;
655 case WM_SIZE:
896faa72 656 theInteractor->OnSize (theHWnd, (UINT)theWParam, LOWORD(theLParam), HIWORD(theLParam));
52f99d93 657 break;
658 case WM_LBUTTONDBLCLK:
896faa72 659 theInteractor->OnLButtonDown (theHWnd, (UINT)theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y, 1);
52f99d93 660 break;
661 case WM_LBUTTONDOWN:
896faa72 662 theInteractor->OnLButtonDown (theHWnd, (UINT)theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y, 0);
52f99d93 663 break;
664 case WM_LBUTTONUP:
896faa72 665 theInteractor->OnLButtonUp (theHWnd, (UINT)theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y);
52f99d93 666 break;
667 case WM_MBUTTONDBLCLK:
896faa72 668 theInteractor->OnMButtonDown (theHWnd, (UINT)theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y, 1);
52f99d93 669 break;
670 case WM_MBUTTONDOWN:
896faa72 671 theInteractor->OnMButtonDown (theHWnd, (UINT)theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y, 0);
52f99d93 672 break;
673 case WM_MBUTTONUP:
896faa72 674 theInteractor->OnMButtonUp (theHWnd, (UINT)theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y);
52f99d93 675 break;
676 case WM_RBUTTONDBLCLK:
896faa72 677 theInteractor->OnRButtonDown (theHWnd, (UINT)theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y, 1);
52f99d93 678 break;
679 case WM_RBUTTONDOWN:
896faa72 680 theInteractor->OnRButtonDown (theHWnd, (UINT)theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y, 0);
52f99d93 681 break;
682 case WM_RBUTTONUP:
896faa72 683 theInteractor->OnRButtonUp (theHWnd, (UINT)theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y);
52f99d93 684 break;
685 case WM_MOUSELEAVE:
686 {
687 theInteractor->InvokeEvent (vtkCommand::LeaveEvent, NULL);
688 theInteractor->myMouseInWindow = 0;
689 }
690 break;
691 case WM_MOUSEMOVE:
896faa72 692 theInteractor->OnMouseMove (theHWnd, (UINT)theWParam, MAKEPOINTS(theLParam).x, MAKEPOINTS(theLParam).y);
52f99d93 693 break;
694 case WM_MOUSEWHEEL:
695 {
696 POINT pt;
697 pt.x = MAKEPOINTS(theLParam).x;
698 pt.y = MAKEPOINTS(theLParam).y;
699 ::ScreenToClient(theHWnd, &pt);
700 if( GET_WHEEL_DELTA_WPARAM(theWParam) > 0)
701 {
896faa72 702 theInteractor->OnMouseWheelForward (theHWnd, (UINT)theWParam, pt.x, pt.y);
52f99d93 703 }
704 else
705 {
896faa72 706 theInteractor->OnMouseWheelBackward (theHWnd, (UINT)theWParam, pt.x, pt.y);
52f99d93 707 }
708 }
709 break;
710 case WM_TIMER:
896faa72 711 theInteractor->OnTimer (theHWnd, (UINT)theWParam);
52f99d93 712 break;
713 }
714 return DefWindowProc(theHWnd, theMsg, theWParam, theLParam);
715}
716
717#else
718
719//===========================================================
720// Function : GetDisplayId
721// Purpose :
722//===========================================================
723Display* IVtkDraw_Interactor::GetDisplayId() const
724{
725 return myDisplayId;
726}
727
728//===========================================================
729// Function : GetMousePosition
730// Purpose :
731//===========================================================
732void IVtkDraw_Interactor::GetMousePosition (Standard_Integer *theX,
733 Standard_Integer *theY)
734{
735 Window aRoot, aChild;
736 Standard_Integer aRoot_x, aRoot_y;
737 unsigned int aKeys;
738
739 XQueryPointer (this->myDisplayId, this->myWindowId,
740 &aRoot, &aChild, &aRoot_x, &aRoot_y, theX, theY, &aKeys);
741
742}
743
744//===========================================================
745// Function : ViewerMainLoop
746// Purpose :
747//===========================================================
748Standard_Integer IVtkDraw_Interactor::ViewerMainLoop (Standard_Integer theArgNum, const char** /*theArgs*/)
749{
750 Standard_Integer aXp, aYp;
751 Standard_Boolean aPick = theArgNum > 0;
752
753 static XEvent anEvent;
754 XNextEvent (myDisplayId, &anEvent);
755
756 switch (anEvent.type)
757 {
758 case Expose:
759 {
760 if (!this->Enabled)
761 {
762 return aPick;
763 }
764 XEvent aResult;
765 while (XCheckTypedWindowEvent (this->myDisplayId,
766 this->myWindowId,
767 Expose,
768 &aResult))
769 {
770 // just getting the expose configure event
771 anEvent = aResult;
772 }
773
774 this->SetEventSize (anEvent.xexpose.width, anEvent.xexpose.height);
775
776
777 aXp = anEvent.xexpose.x;
778 aYp = this->Size[1] - anEvent.xexpose.y - 1;
779 this->SetEventPosition (aXp, aYp);
780
781 // only render if we are currently accepting events
782 if (this->Enabled)
783 {
784 this->InvokeEvent(vtkCommand::ExposeEvent,NULL);
785 this->Render();
786 }
787 }
788 break;
789
790 case MapNotify:
791 {
792 // only render if we are currently accepting events
793 if (this->Enabled && this->GetRenderWindow()->GetNeverRendered())
794 {
795 this->Render();
796 }
797 }
798 break;
799
800 case ConfigureNotify:
801 {
802 XEvent aResult;
803 while (XCheckTypedWindowEvent(this->myDisplayId,
804 this->myWindowId,
805 ConfigureNotify,
806 &aResult))
807 {
808 // just getting the last configure event
809 anEvent = aResult;
810 }
811 Standard_Integer aWidth = anEvent.xconfigure.width;
812 Standard_Integer aHeight = anEvent.xconfigure.height;
813 if (aWidth != this->Size[0] || aHeight != this->Size[1])
814 {
815 Standard_Boolean toResizeSmaller = aWidth <= this->Size[0] && aHeight <= this->Size[1];
816 this->UpdateSize (aWidth, aHeight);
817 aXp = anEvent.xbutton.x;
818 aYp = anEvent.xbutton.y;
819
820 SetEventPosition (aXp, this->Size[1] - aYp - 1);
821
822 // only render if we are currently accepting events
823 if (Enabled)
824 {
825 this->InvokeEvent(vtkCommand::ConfigureEvent,NULL);
826 if (toResizeSmaller)
827 {
828 // Don't call Render when the window is resized to be larger:
829 //
830 // - if the window is resized to be larger, an Expose event will
831 // be trigged by the X server which will trigger a call to
832 // Render().
833 // - if the window is resized to be smaller, no Expose event will
834 // be trigged by the X server, as no new area become visible.
835 // only in this case, we need to explicitly call Render()
836 // in ConfigureNotify.
837 this->Render();
838 }
839 }
840 }
841 }
842 break;
843
844 case ButtonPress:
845 {
846 if (!this->Enabled)
847 {
848 return aPick;
849 }
850
851 Standard_Integer aCtrl = anEvent.xbutton.state & ControlMask ? 1 : 0;
852 Standard_Integer aShift = anEvent.xbutton.state & ShiftMask ? 1 : 0;
853 Standard_Integer anAlt = anEvent.xbutton.state & Mod1Mask ? 1 : 0;
854 aXp = anEvent.xbutton.x;
855 aYp = anEvent.xbutton.y;
856
857 // check for double click
858 static Standard_Integer aMousePressTime = 0;
859 Standard_Integer aRepeat = 0;
860 // 400 ms threshold by default is probably good to start
861 Standard_Integer anEventTime = static_cast<int>(anEvent.xbutton.time);
862 if ((anEventTime - aMousePressTime) < 400)
863 {
864 aMousePressTime -= 2000; // no double click next time
865 aRepeat = 1;
866 }
867 else
868 {
869 aMousePressTime = anEventTime;
870 }
871
872 this->SetEventInformationFlipY (aXp, aYp, aCtrl, aShift, 0, aRepeat);
873 this->SetAltKey (anAlt);
874
875 switch (anEvent.xbutton.button)
876 {
877 case Button1:
878 this->OnSelection ();
879 this->myIsLeftButtonPressed = 1;
880 this->InvokeEvent (vtkCommand::LeftButtonPressEvent,NULL);
881 break;
882 case Button2:
883 this->InvokeEvent (vtkCommand::MiddleButtonPressEvent,NULL);
884 break;
885 case Button3:
886 this->InvokeEvent (vtkCommand::RightButtonPressEvent,NULL);
887 break;
888 case Button4:
889 this->InvokeEvent (vtkCommand::MouseWheelForwardEvent,NULL);
890 break;
891 case Button5:
892 this->InvokeEvent (vtkCommand::MouseWheelBackwardEvent,NULL);
893 break;
894 }
895 this->Render();
896 }
897 break;
898
899 case ButtonRelease:
900 {
901 if (!this->Enabled)
902 {
903 return aPick;
904 }
905 Standard_Integer aCtrl = anEvent.xbutton.state & ControlMask ? 1 : 0;
906 Standard_Integer aShift = anEvent.xbutton.state & ShiftMask ? 1 : 0;
907 Standard_Integer anAlt = anEvent.xbutton.state & Mod1Mask ? 1 : 0;
908 aXp = anEvent.xbutton.x;
909 aYp = anEvent.xbutton.y;
910
911 this->SetEventInformationFlipY (aXp, aYp, aCtrl, aShift);
912 this->SetAltKey (anAlt);
913 switch (anEvent.xbutton.button)
914 {
915 case Button1:
916 this->InvokeEvent (vtkCommand::LeftButtonReleaseEvent,NULL);
917 this->myIsLeftButtonPressed = False;
918 break;
919 case Button2:
920 this->InvokeEvent (vtkCommand::MiddleButtonReleaseEvent,NULL);
921 break;
922 case Button3:
923 this->InvokeEvent (vtkCommand::RightButtonReleaseEvent,NULL);
924 break;
925 }
926 this->Render();
927 }
928 break;
929
930 case EnterNotify:
931 {
932 if (this->Enabled)
933 {
934 XEnterWindowEvent *anEnterEvent = reinterpret_cast<XEnterWindowEvent *>(&anEvent);
935 this->SetEventInformationFlipY (anEnterEvent->x,
936 anEnterEvent->y,
937 (anEnterEvent->state & ControlMask) != 0,
938 (anEnterEvent->state & ShiftMask) != 0);
939
940 this->SetAltKey (anEvent.xbutton.state & Mod1Mask ? 1 : 0);
941 this->InvokeEvent (vtkCommand::EnterEvent, NULL);
942 }
943 this->Render();
944 }
945 break;
946
947 case LeaveNotify:
948 {
949 if (this->Enabled)
950 {
951 XLeaveWindowEvent *aLeaveEvent = reinterpret_cast<XLeaveWindowEvent *>(&anEvent);
952 this->SetEventInformationFlipY (aLeaveEvent->x,
953 aLeaveEvent->y,
954 (aLeaveEvent->state & ControlMask) != 0,
955 (aLeaveEvent->state & ShiftMask) != 0);
956
957 this->SetAltKey (anEvent.xbutton.state & Mod1Mask ? 1 : 0);
958 this->InvokeEvent(vtkCommand::LeaveEvent, NULL);
959 }
960 this->Render();
961 }
962 break;
963
964 case MotionNotify:
965 {
966 if (!this->Enabled)
967 {
968 return aPick;
969 }
970
971 Standard_Integer aCtrl = anEvent.xbutton.state & ControlMask ? 1 : 0;
972 Standard_Integer aShift = anEvent.xbutton.state & ShiftMask ? 1 : 0;
973 Standard_Integer anAlt = anEvent.xbutton.state & Mod1Mask ? 1 : 0;
974
975 // Note that even though the (x,y) location of the pointer is event structure,
976 // we must call XQueryPointer for the hints (motion event compression) to
977 // work properly.
978 this->GetMousePosition (&aXp, &aYp);
979 this->SetEventInformationFlipY (aXp, aYp, aCtrl, aShift);
980 this->SetAltKey (anAlt);
981 if (!myIsLeftButtonPressed)
982 MoveTo (aXp, this->Size[1]- aYp - 1);
983 this->InvokeEvent (vtkCommand::MouseMoveEvent, NULL);
984 }
985 break;
986 }
987
988 return aPick;
989}
990
991//===========================================================
992// Function : ProcessEvents
993// Purpose :
994//===========================================================
995void IVtkDraw_Interactor::ProcessEvents (ClientData theData, int)
996{
997 IVtkDraw_Interactor *anInteractor = (IVtkDraw_Interactor *)theData;
998 // test for X Event
999 while (XPending(anInteractor->GetDisplayId()))
1000 {
1001 anInteractor->ViewerMainLoop (0, NULL);
1002 }
1003}
1004
1005#endif