a1e5837ce33a18099b3ea56d10535d1ecd7fb50f
[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()
171 {
172   if (!myView.IsNull())
173   {
174     myView->MustBeResized();
175     FlushViewEvents (myCtx, myView, true);
176   }
177 }
178
179 // =======================================================================
180 // function : navigationKeyModifierSwitch
181 // purpose  :
182 // =======================================================================
183 bool ViewerTest_EventManager::navigationKeyModifierSwitch (unsigned int theModifOld,
184                                                            unsigned int theModifNew,
185                                                            double       theTimeStamp)
186 {
187   bool hasActions = false;
188   for (unsigned int aKeyIter = 0; aKeyIter < Aspect_VKey_ModifiersLower; ++aKeyIter)
189   {
190     if (!myKeys.IsKeyDown (aKeyIter))
191     {
192       continue;
193     }
194
195     Aspect_VKey anActionOld = Aspect_VKey_UNKNOWN, anActionNew = Aspect_VKey_UNKNOWN;
196     myNavKeyMap.Find (aKeyIter | theModifOld, anActionOld);
197     myNavKeyMap.Find (aKeyIter | theModifNew, anActionNew);
198     if (anActionOld == anActionNew)
199     {
200       continue;
201     }
202
203     if (anActionOld != Aspect_VKey_UNKNOWN)
204     {
205       myKeys.KeyUp (anActionOld, theTimeStamp);
206     }
207     if (anActionNew != Aspect_VKey_UNKNOWN)
208     {
209       hasActions = true;
210       myKeys.KeyDown (anActionNew, theTimeStamp);
211     }
212   }
213   return hasActions;
214 }
215
216 //=======================================================================
217 //function : KeyDown
218 //purpose  :
219 //=======================================================================
220 void ViewerTest_EventManager::KeyDown (Aspect_VKey theKey,
221                                        double theTime,
222                                        double thePressure)
223 {
224   const unsigned int aModifOld = myKeys.Modifiers();
225   AIS_ViewController::KeyDown (theKey, theTime, thePressure);
226
227   const unsigned int aModifNew = myKeys.Modifiers();
228   if (aModifNew != aModifOld
229    && navigationKeyModifierSwitch (aModifOld, aModifNew, theTime))
230   {
231     // modifier key just pressed
232   }
233
234   Aspect_VKey anAction = Aspect_VKey_UNKNOWN;
235   if (myNavKeyMap.Find (theKey | myKeys.Modifiers(), anAction)
236   &&  anAction != Aspect_VKey_UNKNOWN)
237   {
238     AIS_ViewController::KeyDown (anAction, theTime, thePressure);
239   }
240 }
241
242 //=======================================================================
243 //function : KeyUp
244 //purpose  :
245 //=======================================================================
246 void ViewerTest_EventManager::KeyUp (Aspect_VKey theKey,
247                                      double theTime)
248 {
249   const unsigned int aModifOld = myKeys.Modifiers();
250   AIS_ViewController::KeyUp (theKey, theTime);
251
252   Aspect_VKey anAction = Aspect_VKey_UNKNOWN;
253   if (myNavKeyMap.Find (theKey | myKeys.Modifiers(), anAction)
254   &&  anAction != Aspect_VKey_UNKNOWN)
255   {
256     AIS_ViewController::KeyUp (anAction, theTime);
257     ProcessKeyPress (anAction);
258   }
259
260   const unsigned int aModifNew = myKeys.Modifiers();
261   if (aModifNew != aModifOld
262    && navigationKeyModifierSwitch (aModifOld, aModifNew, theTime))
263   {
264     // modifier key released
265   }
266
267   ProcessKeyPress (theKey | aModifNew);
268 }
269
270 //==============================================================================
271 //function : ProcessKeyPress
272 //purpose  :
273 //==============================================================================
274 void ViewerTest_EventManager::ProcessKeyPress (Aspect_VKey theKey)
275 {
276   if (myCtx.IsNull()
277    || myView.IsNull())
278   {
279     return;
280   }
281
282   switch (theKey)
283   {
284     case Aspect_VKey_Backspace: // AXO
285     {
286       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
287       {
288         myView->SetProj(V3d_XposYnegZpos);
289       }
290       break;
291     }
292     case Aspect_VKey_F:
293     {
294       if (myCtx->NbSelected() > 0)
295       {
296         myCtx->FitSelected (myView);
297       }
298       else
299       {
300         myView->FitAll();
301       }
302       break;
303     }
304     case Aspect_VKey_H: // HLR
305     {
306       std::cout << "HLR\n";
307       myView->SetComputedMode (!myView->ComputedMode());
308       myView->Redraw();
309       break;
310     }
311     case Aspect_VKey_P: // Type of HLR
312     {
313       myCtx->DefaultDrawer()->SetTypeOfHLR (myCtx->DefaultDrawer()->TypeOfHLR() == Prs3d_TOH_Algo
314                                           ? Prs3d_TOH_PolyAlgo
315                                           : Prs3d_TOH_Algo);
316       if (myCtx->NbSelected() == 0)
317       {
318         AIS_ListOfInteractive aListOfShapes;
319         myCtx->DisplayedObjects (aListOfShapes);
320         for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
321         {
322           if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (anIter.Value()))
323           {
324             aShape->SetTypeOfHLR (aShape->TypeOfHLR() == Prs3d_TOH_PolyAlgo
325                                 ? Prs3d_TOH_Algo
326                                 : Prs3d_TOH_PolyAlgo);
327             myCtx->Redisplay (aShape, Standard_False);
328           }
329         }
330       }
331       else
332       {
333         for (myCtx->InitSelected(); myCtx->MoreSelected(); myCtx->NextSelected())
334         {
335           if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (myCtx->SelectedInteractive()))
336           {
337             aShape->SetTypeOfHLR (aShape->TypeOfHLR() == Prs3d_TOH_PolyAlgo
338                                 ? Prs3d_TOH_Algo
339                                 : Prs3d_TOH_PolyAlgo);
340             myCtx->Redisplay (aShape, Standard_False);
341           }
342         }
343       }
344       myCtx->UpdateCurrentViewer();
345       break;
346     }
347     case Aspect_VKey_S | Aspect_VKeyFlags_CTRL:
348     case Aspect_VKey_W | Aspect_VKeyFlags_CTRL:
349     {
350       Standard_Integer aDispMode = AIS_Shaded;
351       if (theKey == (Aspect_VKey_S | Aspect_VKeyFlags_CTRL))
352       {
353         aDispMode = AIS_Shaded;
354         std::cout << "setup Shaded display mode\n";
355       }
356       else
357       {
358         aDispMode = AIS_WireFrame;
359         std::cout << "setup WireFrame display mode\n";
360       }
361
362       if (myCtx->NbSelected() == 0)
363       {
364         myCtx->SetDisplayMode (aDispMode, true);
365       }
366       else
367       {
368         for (myCtx->InitSelected(); myCtx->MoreSelected(); myCtx->NextSelected())
369         {
370           myCtx->SetDisplayMode (myCtx->SelectedInteractive(), aDispMode, false);
371         }
372         myCtx->UpdateCurrentViewer();
373       }
374       break;
375     }
376     case Aspect_VKey_U: // Unset display mode
377     {
378       std::cout << "reset display mode to defaults\n";
379       if (myCtx->NbSelected() == 0)
380       {
381         myCtx->SetDisplayMode (AIS_WireFrame, true);
382       }
383       else
384       {
385         for (myCtx->InitSelected(); myCtx->MoreSelected(); myCtx->NextSelected())
386         {
387           myCtx->UnsetDisplayMode (myCtx->SelectedInteractive(), false);
388         }
389         myCtx->UpdateCurrentViewer();
390       }
391       break;
392     }
393     case Aspect_VKey_T:
394     {
395       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
396       {
397         myView->SetProj (V3d_TypeOfOrientation_Zup_Top);
398       }
399       break;
400     }
401     case Aspect_VKey_B:
402     {
403       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
404       {
405         myView->SetProj (V3d_TypeOfOrientation_Zup_Bottom);
406       }
407       break;
408     }
409     case Aspect_VKey_L:
410     {
411       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
412       {
413         myView->SetProj (V3d_TypeOfOrientation_Zup_Left);
414       }
415       break;
416     }
417     case Aspect_VKey_R:
418     {
419       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
420       {
421         myView->SetProj (V3d_TypeOfOrientation_Zup_Right);
422       }
423       break;
424     }
425     case Aspect_VKey_Comma:
426     {
427       myCtx->HilightNextDetected (myView);
428       break;
429     }
430     case Aspect_VKey_Period:
431     {
432       myCtx->HilightPreviousDetected (myView);
433       break;
434     }
435     case Aspect_VKey_Slash:
436     case Aspect_VKey_NumpadDivide:
437     {
438       Handle(Graphic3d_Camera) aCamera = myView->Camera();
439       if (aCamera->IsStereo())
440       {
441         aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() - 0.01);
442         myView->Redraw();
443       }
444       break;
445     }
446     case Aspect_VKey_NumpadMultiply:
447     {
448       Handle(Graphic3d_Camera) aCamera = myView->Camera();
449       if (aCamera->IsStereo())
450       {
451         aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() + 0.01);
452         myView->Redraw();
453       }
454       break;
455     }
456     case Aspect_VKey_Delete:
457     {
458       if (!myCtx.IsNull()
459         && myCtx->NbSelected() > 0)
460       {
461         Draw_Interprete ("verase");
462       }
463       break;
464     }
465     case Aspect_VKey_Escape:
466     {
467       if (!myCtx.IsNull()
468         && ViewerTest_EventManager::ToCloseViewOnEscape())
469       {
470         Draw_Interprete (ViewerTest_EventManager::ToExitOnCloseView() ? "exit" : "vclose");
471       }
472       break;
473     }
474     case Aspect_VKey_NavSpeedDecrease:
475     case Aspect_VKey_NavSpeedIncrease:
476     {
477       // handle slide speed
478       float aNewSpeed = theKey == Aspect_VKey_NavSpeedDecrease
479                       ? myWalkSpeedRelative * 0.5f
480                       : myWalkSpeedRelative * 2.0f;
481       if (aNewSpeed >= 0.00001f
482        && aNewSpeed <= 10.0f)
483       {
484         if (Abs (aNewSpeed - 0.1f) < 0.001f)
485         {
486           aNewSpeed = 0.1f;
487         }
488         myWalkSpeedRelative = aNewSpeed;
489       }
490       break;
491     }
492   }
493
494   if (theKey >= Aspect_VKey_0
495    && theKey <= Aspect_VKey_7)
496   {
497     const Standard_Integer aSelMode = theKey - Aspect_VKey_0;
498     bool toEnable = true;
499     if (!myCtx.IsNull())
500     {
501       AIS_ListOfInteractive aPrsList;
502       myCtx->DisplayedObjects (aPrsList);
503       for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More() && toEnable; aPrsIter.Next())
504       {
505         TColStd_ListOfInteger aModes;
506         myCtx->ActivatedModes (aPrsIter.Value(), aModes);
507         for (TColStd_ListOfInteger::Iterator aModeIter (aModes); aModeIter.More() && toEnable; aModeIter.Next())
508         {
509           if (aModeIter.Value() == aSelMode)
510           {
511             toEnable = false;
512           }
513         }
514       }
515     }
516     TCollection_AsciiString aCmd = TCollection_AsciiString ("vselmode ") + aSelMode + (toEnable ? " 1" : " 0");
517     Draw_Interprete (aCmd.ToCString());
518   }
519 }