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