0032306: Draw Harness, ViewerTest - move window message processing to TKService
[occt.git] / src / ViewerTest / ViewerTest_EventManager.cxx
1 // Created on: 1998-08-27
2 // Created by: Robert COUBLANC
3 // Copyright (c) 1998-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <ViewerTest_EventManager.hxx>
18
19 #include <AIS_AnimationCamera.hxx>
20 #include <AIS_InteractiveContext.hxx>
21 #include <AIS_Shape.hxx>
22 #include <Aspect_Grid.hxx>
23 #include <Draw.hxx>
24 #include <ViewerTest_ContinuousRedrawer.hxx>
25 #include <ViewerTest_V3dView.hxx>
26
27 Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand);
28
29 IMPLEMENT_STANDARD_RTTIEXT(ViewerTest_EventManager,Standard_Transient)
30
31 //=======================================================================
32 //function : GlobalViewAnimation
33 //purpose  :
34 //=======================================================================
35 const Handle(AIS_AnimationCamera)& ViewerTest_EventManager::GlobalViewAnimation()
36 {
37   static Handle(AIS_AnimationCamera) THE_CAMERA_ANIM = new AIS_AnimationCamera ("ViewerTest_EventManager_ViewAnimation", Handle(V3d_View)());
38   THE_CAMERA_ANIM->SetOwnDuration (0.5);
39   return THE_CAMERA_ANIM;
40 }
41
42 //=======================================================================
43 //function : ViewerTest_EventManager
44 //purpose  :
45 //=======================================================================
46 ViewerTest_EventManager::ViewerTest_EventManager (const Handle(V3d_View)&               theView,
47                                                   const Handle(AIS_InteractiveContext)& theCtx)
48 : myCtx  (theCtx),
49   myView (theView),
50   myToPickPnt (Standard_False),
51   myIsTmpContRedraw (Standard_False)
52 {
53   myViewAnimation = GlobalViewAnimation();
54
55   addActionHotKeys (Aspect_VKey_NavForward,        Aspect_VKey_W, Aspect_VKey_W | Aspect_VKeyFlags_SHIFT);
56   addActionHotKeys (Aspect_VKey_NavBackward ,      Aspect_VKey_S, Aspect_VKey_S | Aspect_VKeyFlags_SHIFT);
57   addActionHotKeys (Aspect_VKey_NavSlideLeft,      Aspect_VKey_A, Aspect_VKey_A | Aspect_VKeyFlags_SHIFT);
58   addActionHotKeys (Aspect_VKey_NavSlideRight,     Aspect_VKey_D, Aspect_VKey_D | Aspect_VKeyFlags_SHIFT);
59   addActionHotKeys (Aspect_VKey_NavRollCCW,        Aspect_VKey_Q, Aspect_VKey_Q | Aspect_VKeyFlags_SHIFT);
60   addActionHotKeys (Aspect_VKey_NavRollCW,         Aspect_VKey_E, Aspect_VKey_E | Aspect_VKeyFlags_SHIFT);
61
62   addActionHotKeys (Aspect_VKey_NavSpeedIncrease,  Aspect_VKey_Plus,  Aspect_VKey_Plus  | Aspect_VKeyFlags_SHIFT,
63                                                    Aspect_VKey_Equal,
64                                                    Aspect_VKey_NumpadAdd, Aspect_VKey_NumpadAdd | Aspect_VKeyFlags_SHIFT);
65   addActionHotKeys (Aspect_VKey_NavSpeedDecrease,  Aspect_VKey_Minus, Aspect_VKey_Minus | Aspect_VKeyFlags_SHIFT,
66                                                    Aspect_VKey_NumpadSubtract, Aspect_VKey_NumpadSubtract | Aspect_VKeyFlags_SHIFT);
67
68   addActionHotKeys (Aspect_VKey_NavLookUp,         Aspect_VKey_Up);
69   addActionHotKeys (Aspect_VKey_NavLookDown,       Aspect_VKey_Down);
70   addActionHotKeys (Aspect_VKey_NavLookLeft,       Aspect_VKey_Left);
71   addActionHotKeys (Aspect_VKey_NavLookRight,      Aspect_VKey_Right);
72   addActionHotKeys (Aspect_VKey_NavSlideLeft,      Aspect_VKey_Left  | Aspect_VKeyFlags_SHIFT);
73   addActionHotKeys (Aspect_VKey_NavSlideRight,     Aspect_VKey_Right | Aspect_VKeyFlags_SHIFT);
74   addActionHotKeys (Aspect_VKey_NavSlideUp,        Aspect_VKey_Up    | Aspect_VKeyFlags_SHIFT);
75   addActionHotKeys (Aspect_VKey_NavSlideDown,      Aspect_VKey_Down  | Aspect_VKeyFlags_SHIFT);
76 }
77
78 //=======================================================================
79 //function : ~ViewerTest_EventManager
80 //purpose  :
81 //=======================================================================
82 ViewerTest_EventManager::~ViewerTest_EventManager()
83 {
84   if (!myViewAnimation.IsNull()
85     && myViewAnimation->View() == myView)
86   {
87     myViewAnimation->Stop();
88     myViewAnimation->SetView (Handle(V3d_View)());
89   }
90 }
91
92 //=======================================================================
93 //function : UpdateMouseButtons
94 //purpose  :
95 //=======================================================================
96 bool ViewerTest_EventManager::UpdateMouseButtons (const Graphic3d_Vec2i& thePoint,
97                                                   Aspect_VKeyMouse theButtons,
98                                                   Aspect_VKeyFlags theModifiers,
99                                                   bool theIsEmulated)
100 {
101   SetAllowRotation (!ViewerTest_V3dView::IsCurrentViewIn2DMode());
102
103   if (theButtons == Aspect_VKeyMouse_LeftButton)
104   {
105     if (myToPickPnt && (theModifiers & Aspect_VKeyFlags_CTRL) != 0)
106     {
107       Graphic3d_Vec3d anXYZ;
108       myView->Convert (thePoint.x(), thePoint.y(), anXYZ.x(), anXYZ.y(), anXYZ.z());
109       Draw::Set (myPickPntArgVec[0].ToCString(), anXYZ.x());
110       Draw::Set (myPickPntArgVec[1].ToCString(), anXYZ.y());
111       Draw::Set (myPickPntArgVec[2].ToCString(), anXYZ.z());
112       myToPickPnt = false;
113     }
114   }
115
116   return AIS_ViewController::UpdateMouseButtons (thePoint, theButtons, theModifiers, theIsEmulated);
117 }
118
119 //==============================================================================
120 //function : ProcessExpose
121 //purpose  :
122 //==============================================================================
123 void ViewerTest_EventManager::ProcessExpose()
124 {
125   if (!myView.IsNull())
126   {
127     myView->Invalidate();
128     FlushViewEvents (myCtx, myView, true);
129   }
130 }
131
132 //==============================================================================
133 //function : handleViewRedraw
134 //purpose  :
135 //==============================================================================
136 void ViewerTest_EventManager::handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx,
137                                                 const Handle(V3d_View)& theView)
138 {
139   AIS_ViewController::handleViewRedraw (theCtx, theView);
140
141   // On non-Windows platforms Aspect_Window::InvalidateContent() from rendering thread does not work as expected
142   // as in Tcl event loop the new message might go to sleep with new event remaining in queue.
143   // As a workaround - use dedicated background thread to ping Tcl event loop.
144   if (myToAskNextFrame)
145   {
146     ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
147     if (!myIsTmpContRedraw
148      && (!aRedrawer.IsStarted() || aRedrawer.IsPaused()))
149     {
150       myIsTmpContRedraw = true;
151     #ifndef _WIN32
152       aRedrawer.Start (theView->Window(), 60.0);
153     #endif
154     }
155   }
156   else if (myIsTmpContRedraw)
157   {
158     myIsTmpContRedraw = false;
159   #ifndef _WIN32
160     ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
161     aRedrawer.Pause();
162   #endif
163   }
164 }
165
166 //==============================================================================
167 //function : ProcessConfigure
168 //purpose  :
169 //==============================================================================
170 void ViewerTest_EventManager::ProcessConfigure (bool theIsResized)
171 {
172   if (!myView.IsNull())
173   {
174     if (!theIsResized
175      // track window moves to reverse stereo pair
176      && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_RowInterlaced
177      && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_ColumnInterlaced
178      && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_ChessBoard)
179     {
180       return;
181     }
182
183     myView->MustBeResized();
184     FlushViewEvents (myCtx, myView, true);
185   }
186 }
187
188 //==============================================================================
189 //function : ProcessInput
190 //purpose  :
191 //==============================================================================
192 void ViewerTest_EventManager::ProcessInput()
193 {
194   if (!myView.IsNull())
195   {
196     FlushViewEvents (myCtx, myView, true);
197   }
198 }
199
200 // =======================================================================
201 // function : navigationKeyModifierSwitch
202 // purpose  :
203 // =======================================================================
204 bool ViewerTest_EventManager::navigationKeyModifierSwitch (unsigned int theModifOld,
205                                                            unsigned int theModifNew,
206                                                            double       theTimeStamp)
207 {
208   bool hasActions = false;
209   for (unsigned int aKeyIter = 0; aKeyIter < Aspect_VKey_ModifiersLower; ++aKeyIter)
210   {
211     if (!myKeys.IsKeyDown (aKeyIter))
212     {
213       continue;
214     }
215
216     Aspect_VKey anActionOld = Aspect_VKey_UNKNOWN, anActionNew = Aspect_VKey_UNKNOWN;
217     myNavKeyMap.Find (aKeyIter | theModifOld, anActionOld);
218     myNavKeyMap.Find (aKeyIter | theModifNew, anActionNew);
219     if (anActionOld == anActionNew)
220     {
221       continue;
222     }
223
224     if (anActionOld != Aspect_VKey_UNKNOWN)
225     {
226       myKeys.KeyUp (anActionOld, theTimeStamp);
227     }
228     if (anActionNew != Aspect_VKey_UNKNOWN)
229     {
230       hasActions = true;
231       myKeys.KeyDown (anActionNew, theTimeStamp);
232     }
233   }
234   return hasActions;
235 }
236
237 //=======================================================================
238 //function : KeyDown
239 //purpose  :
240 //=======================================================================
241 void ViewerTest_EventManager::KeyDown (Aspect_VKey theKey,
242                                        double theTime,
243                                        double thePressure)
244 {
245   const unsigned int aModifOld = myKeys.Modifiers();
246   AIS_ViewController::KeyDown (theKey, theTime, thePressure);
247
248   const unsigned int aModifNew = myKeys.Modifiers();
249   if (aModifNew != aModifOld
250    && navigationKeyModifierSwitch (aModifOld, aModifNew, theTime))
251   {
252     // modifier key just pressed
253   }
254
255   Aspect_VKey anAction = Aspect_VKey_UNKNOWN;
256   if (myNavKeyMap.Find (theKey | myKeys.Modifiers(), anAction)
257   &&  anAction != Aspect_VKey_UNKNOWN)
258   {
259     AIS_ViewController::KeyDown (anAction, theTime, thePressure);
260   }
261 }
262
263 //=======================================================================
264 //function : KeyUp
265 //purpose  :
266 //=======================================================================
267 void ViewerTest_EventManager::KeyUp (Aspect_VKey theKey,
268                                      double theTime)
269 {
270   const unsigned int aModifOld = myKeys.Modifiers();
271   AIS_ViewController::KeyUp (theKey, theTime);
272
273   Aspect_VKey anAction = Aspect_VKey_UNKNOWN;
274   if (myNavKeyMap.Find (theKey | myKeys.Modifiers(), anAction)
275   &&  anAction != Aspect_VKey_UNKNOWN)
276   {
277     AIS_ViewController::KeyUp (anAction, theTime);
278     ProcessKeyPress (anAction);
279   }
280
281   const unsigned int aModifNew = myKeys.Modifiers();
282   if (aModifNew != aModifOld
283    && navigationKeyModifierSwitch (aModifOld, aModifNew, theTime))
284   {
285     // modifier key released
286   }
287
288   ProcessKeyPress (theKey | aModifNew);
289 }
290
291 //==============================================================================
292 //function : ProcessKeyPress
293 //purpose  :
294 //==============================================================================
295 void ViewerTest_EventManager::ProcessKeyPress (Aspect_VKey theKey)
296 {
297   if (myCtx.IsNull()
298    || myView.IsNull())
299   {
300     return;
301   }
302
303   switch (theKey)
304   {
305     case Aspect_VKey_Backspace: // AXO
306     {
307       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
308       {
309         myView->SetProj(V3d_XposYnegZpos);
310       }
311       break;
312     }
313     case Aspect_VKey_F:
314     {
315       if (myCtx->NbSelected() > 0)
316       {
317         myCtx->FitSelected (myView);
318       }
319       else
320       {
321         myView->FitAll();
322       }
323       break;
324     }
325     case Aspect_VKey_H: // HLR
326     {
327       std::cout << "HLR\n";
328       myView->SetComputedMode (!myView->ComputedMode());
329       myView->Redraw();
330       break;
331     }
332     case Aspect_VKey_P: // Type of HLR
333     {
334       myCtx->DefaultDrawer()->SetTypeOfHLR (myCtx->DefaultDrawer()->TypeOfHLR() == Prs3d_TOH_Algo
335                                           ? Prs3d_TOH_PolyAlgo
336                                           : Prs3d_TOH_Algo);
337       if (myCtx->NbSelected() == 0)
338       {
339         AIS_ListOfInteractive aListOfShapes;
340         myCtx->DisplayedObjects (aListOfShapes);
341         for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
342         {
343           if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (anIter.Value()))
344           {
345             aShape->SetTypeOfHLR (aShape->TypeOfHLR() == Prs3d_TOH_PolyAlgo
346                                 ? Prs3d_TOH_Algo
347                                 : Prs3d_TOH_PolyAlgo);
348             myCtx->Redisplay (aShape, Standard_False);
349           }
350         }
351       }
352       else
353       {
354         for (myCtx->InitSelected(); myCtx->MoreSelected(); myCtx->NextSelected())
355         {
356           if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (myCtx->SelectedInteractive()))
357           {
358             aShape->SetTypeOfHLR (aShape->TypeOfHLR() == Prs3d_TOH_PolyAlgo
359                                 ? Prs3d_TOH_Algo
360                                 : Prs3d_TOH_PolyAlgo);
361             myCtx->Redisplay (aShape, Standard_False);
362           }
363         }
364       }
365       myCtx->UpdateCurrentViewer();
366       break;
367     }
368     case Aspect_VKey_S | Aspect_VKeyFlags_CTRL:
369     case Aspect_VKey_W | Aspect_VKeyFlags_CTRL:
370     {
371       Standard_Integer aDispMode = AIS_Shaded;
372       if (theKey == (Aspect_VKey_S | Aspect_VKeyFlags_CTRL))
373       {
374         aDispMode = AIS_Shaded;
375         std::cout << "setup Shaded display mode\n";
376       }
377       else
378       {
379         aDispMode = AIS_WireFrame;
380         std::cout << "setup WireFrame display mode\n";
381       }
382
383       if (myCtx->NbSelected() == 0)
384       {
385         myCtx->SetDisplayMode (aDispMode, true);
386       }
387       else
388       {
389         for (myCtx->InitSelected(); myCtx->MoreSelected(); myCtx->NextSelected())
390         {
391           myCtx->SetDisplayMode (myCtx->SelectedInteractive(), aDispMode, false);
392         }
393         myCtx->UpdateCurrentViewer();
394       }
395       break;
396     }
397     case Aspect_VKey_U: // Unset display mode
398     {
399       std::cout << "reset display mode to defaults\n";
400       if (myCtx->NbSelected() == 0)
401       {
402         myCtx->SetDisplayMode (AIS_WireFrame, true);
403       }
404       else
405       {
406         for (myCtx->InitSelected(); myCtx->MoreSelected(); myCtx->NextSelected())
407         {
408           myCtx->UnsetDisplayMode (myCtx->SelectedInteractive(), false);
409         }
410         myCtx->UpdateCurrentViewer();
411       }
412       break;
413     }
414     case Aspect_VKey_T:
415     {
416       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
417       {
418         myView->SetProj (V3d_TypeOfOrientation_Zup_Top);
419       }
420       break;
421     }
422     case Aspect_VKey_B:
423     {
424       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
425       {
426         myView->SetProj (V3d_TypeOfOrientation_Zup_Bottom);
427       }
428       break;
429     }
430     case Aspect_VKey_L:
431     {
432       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
433       {
434         myView->SetProj (V3d_TypeOfOrientation_Zup_Left);
435       }
436       break;
437     }
438     case Aspect_VKey_R:
439     {
440       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
441       {
442         myView->SetProj (V3d_TypeOfOrientation_Zup_Right);
443       }
444       break;
445     }
446     case Aspect_VKey_Comma:
447     {
448       myCtx->HilightNextDetected (myView);
449       break;
450     }
451     case Aspect_VKey_Period:
452     {
453       myCtx->HilightPreviousDetected (myView);
454       break;
455     }
456     case Aspect_VKey_Slash:
457     case Aspect_VKey_NumpadDivide:
458     {
459       Handle(Graphic3d_Camera) aCamera = myView->Camera();
460       if (aCamera->IsStereo())
461       {
462         aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() - 0.01);
463         myView->Redraw();
464       }
465       break;
466     }
467     case Aspect_VKey_NumpadMultiply:
468     {
469       Handle(Graphic3d_Camera) aCamera = myView->Camera();
470       if (aCamera->IsStereo())
471       {
472         aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() + 0.01);
473         myView->Redraw();
474       }
475       break;
476     }
477     case Aspect_VKey_Delete:
478     {
479       if (!myCtx.IsNull()
480         && myCtx->NbSelected() > 0)
481       {
482         Draw_Interprete ("verase");
483       }
484       break;
485     }
486     case Aspect_VKey_Escape:
487     {
488       if (!myCtx.IsNull()
489         && ViewerTest_EventManager::ToCloseViewOnEscape())
490       {
491         Draw_Interprete (ViewerTest_EventManager::ToExitOnCloseView() ? "exit" : "vclose");
492       }
493       break;
494     }
495     case Aspect_VKey_NavSpeedDecrease:
496     case Aspect_VKey_NavSpeedIncrease:
497     {
498       // handle slide speed
499       float aNewSpeed = theKey == Aspect_VKey_NavSpeedDecrease
500                       ? myWalkSpeedRelative * 0.5f
501                       : myWalkSpeedRelative * 2.0f;
502       if (aNewSpeed >= 0.00001f
503        && aNewSpeed <= 10.0f)
504       {
505         if (Abs (aNewSpeed - 0.1f) < 0.001f)
506         {
507           aNewSpeed = 0.1f;
508         }
509         myWalkSpeedRelative = aNewSpeed;
510       }
511       break;
512     }
513   }
514
515   if (theKey >= Aspect_VKey_0
516    && theKey <= Aspect_VKey_7)
517   {
518     const Standard_Integer aSelMode = theKey - Aspect_VKey_0;
519     bool toEnable = true;
520     if (!myCtx.IsNull())
521     {
522       AIS_ListOfInteractive aPrsList;
523       myCtx->DisplayedObjects (aPrsList);
524       for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More() && toEnable; aPrsIter.Next())
525       {
526         TColStd_ListOfInteger aModes;
527         myCtx->ActivatedModes (aPrsIter.Value(), aModes);
528         for (TColStd_ListOfInteger::Iterator aModeIter (aModes); aModeIter.More() && toEnable; aModeIter.Next())
529         {
530           if (aModeIter.Value() == aSelMode)
531           {
532             toEnable = false;
533           }
534         }
535       }
536     }
537     TCollection_AsciiString aCmd = TCollection_AsciiString ("vselmode ") + aSelMode + (toEnable ? " 1" : " 0");
538     Draw_Interprete (aCmd.ToCString());
539   }
540 }