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