0031621: Draw Harness - handle navigation keys
authorkgv <kgv@opencascade.com>
Sat, 20 Jun 2020 11:57:02 +0000 (14:57 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 25 Jun 2020 16:24:58 +0000 (19:24 +0300)
AIS_ViewController::handleNavigationKeys() - added an interface for processing navigation keys.
ViewerTest_EventManager now maps WASD+Arrows navigation keys.
Axonometric view hotkey A has been replaced by Backspace.
Shaded/Wireframe are now mapped with hotkeys W+Ctrl/S+Ctrl.
Hotkey D (reset view to undefined default state) has been removed.

dox/dev_guides/upgrade/upgrade.md
src/AIS/AIS_ViewController.cxx
src/AIS/AIS_ViewController.hxx
src/ViewerTest/ViewerTest_EventManager.cxx
src/ViewerTest/ViewerTest_EventManager.hxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx

index 470b068..68b48e7 100644 (file)
@@ -1979,3 +1979,9 @@ After the change, extended variant:
 Previously, sub-classes of *Message_Printer* have to provide a triplet of *Message_Printer::Send()* methods accepting different string representations: TCollection_AsciiString, TCollection_ExtendedString and Standard_CString.
 *Message_Printer* interface has been changed, so that sub-classes now have to implement only single method *Message_Printer::send()* accepting TCollection_AsciiString argument and having no Endl flag, which has been removed.
 Old three Message_Printer::Send() methods remain defined virtual with unused last argument and redirecting to new send() method by default.
+
+@subsection upgrade_750_draw_hotkeys Draw Harness hotkeys
+
+Draw Harness hotkeys **W** (Wireframe) and **S** (Shaded) have been re-mapped to **Ctrl+W** and **Ctrl+S**.
+Hotkey **A** has been remapped to **Backspace**.
+Hotkeys WASD and Arrays are now mapped for walk-through navigation in 3D Viewer.
index c377d82..736f0ac 100644 (file)
@@ -1756,6 +1756,133 @@ gp_Pnt AIS_ViewController::GravityPoint (const Handle(AIS_InteractiveContext)& t
 }
 
 // =======================================================================
+// function : handleNavigationKeys
+// purpose  :
+// =======================================================================
+AIS_WalkDelta AIS_ViewController::handleNavigationKeys (const Handle(AIS_InteractiveContext)& ,
+                                                        const Handle(V3d_View)& theView)
+{
+  // navigation keys
+  double aCrouchRatio = 1.0, aRunRatio = 1.0;
+  if (myNavigationMode == AIS_NavigationMode_FirstPersonFlight)
+  {
+    aRunRatio = 3.0;
+  }
+
+  const double aRotSpeed = 0.5;
+  const double aWalkSpeedCoef = WalkSpeedRelative();
+  AIS_WalkDelta aWalk = FetchNavigationKeys (aCrouchRatio, aRunRatio);
+  if (aWalk.IsJumping())
+  {
+    // ask more frames
+    setAskNextFrame();
+    theView->Invalidate();
+  }
+  if (aWalk.IsEmpty())
+  {
+    return aWalk;
+  }
+  else if (myGL.OrbitRotation.ToRotate
+        || myGL.OrbitRotation.ToStart)
+  {
+    return aWalk;
+  }
+
+  gp_XYZ aMin, aMax;
+  const Bnd_Box aBndBox = theView->View()->MinMaxValues();
+  if (!aBndBox.IsVoid())
+  {
+    aMin = aBndBox.CornerMin().XYZ();
+    aMax = aBndBox.CornerMax().XYZ();
+  }
+  double aBndDiam = Max (Max (aMax.X() - aMin.X(), aMax.Y() - aMin.Y()), aMax.Z() - aMin.Z());
+  if (aBndDiam <= gp::Resolution())
+  {
+    aBndDiam = 0.001;
+  }
+
+  const double aWalkSpeed = myNavigationMode != AIS_NavigationMode_Orbit
+                         && myNavigationMode != AIS_NavigationMode_FirstPersonFlight
+                          ? theView->View()->UnitFactor() * WalkSpeedAbsolute()
+                          : aWalkSpeedCoef * aBndDiam;
+  const Handle(Graphic3d_Camera)& aCam = theView->View()->IsActiveXR()
+                                       ? theView->View()->BaseXRCamera()
+                                       : theView->Camera();
+
+  // move forward in plane XY and up along Z
+  const gp_Dir anUp = ToLockOrbitZUp() ? gp::DZ() : aCam->OrthogonalizedUp();
+  if (aWalk.ToMove()
+   && myToAllowPanning)
+  {
+    const gp_Vec aSide = -aCam->SideRight();
+    gp_XYZ aFwd = aCam->Direction().XYZ();
+    aFwd -= anUp.XYZ() * (anUp.XYZ() * aFwd);
+
+    gp_XYZ aMoveVec;
+    if (!aWalk[AIS_WalkTranslation_Forward].IsEmpty())
+    {
+      if (!aCam->IsOrthographic())
+      {
+        aMoveVec += aFwd * aWalk[AIS_WalkTranslation_Forward].Value * aWalk[AIS_WalkTranslation_Forward].Pressure * aWalkSpeed;
+      }
+    }
+    if (!aWalk[AIS_WalkTranslation_Side].IsEmpty())
+    {
+      aMoveVec += aSide.XYZ() * aWalk[AIS_WalkTranslation_Side].Value * aWalk[AIS_WalkTranslation_Side].Pressure * aWalkSpeed;
+    }
+    if (!aWalk[AIS_WalkTranslation_Up].IsEmpty())
+    {
+      aMoveVec += anUp.XYZ() * aWalk[AIS_WalkTranslation_Up].Value * aWalk[AIS_WalkTranslation_Up].Pressure * aWalkSpeed;
+    }
+    {
+      if (aCam->IsOrthographic())
+      {
+        if (!aWalk[AIS_WalkTranslation_Forward].IsEmpty())
+        {
+          const double aZoomDelta = aWalk[AIS_WalkTranslation_Forward].Value * aWalk[AIS_WalkTranslation_Forward].Pressure * aWalkSpeedCoef;
+          handleZoom (theView, Aspect_ScrollDelta (aZoomDelta * 100.0), NULL);
+        }
+      }
+
+      gp_Trsf aTrsfTranslate;
+      aTrsfTranslate.SetTranslation (aMoveVec);
+      aCam->Transform (aTrsfTranslate);
+    }
+  }
+
+  if (myNavigationMode == AIS_NavigationMode_Orbit
+   && myToAllowRotation)
+  {
+    if (!aWalk[AIS_WalkRotation_Yaw].IsEmpty())
+    {
+      gp_Trsf aTrsfRot;
+      aTrsfRot.SetRotation (gp_Ax1 (aCam->Eye(), anUp), aWalk[AIS_WalkRotation_Yaw].Value * aRotSpeed);
+      aCam->Transform (aTrsfRot);
+    }
+    if (!aWalk[AIS_WalkRotation_Pitch].IsEmpty())
+    {
+      const gp_Vec aSide = -aCam->SideRight();
+      gp_Trsf aTrsfRot;
+      aTrsfRot.SetRotation (gp_Ax1 (aCam->Eye(), aSide), -aWalk[AIS_WalkRotation_Pitch].Value * aRotSpeed);
+      aCam->Transform (aTrsfRot);
+    }
+    if (!aWalk[AIS_WalkRotation_Roll].IsEmpty()
+     && !ToLockOrbitZUp())
+    {
+      gp_Trsf aTrsfRot;
+      aTrsfRot.SetRotation (gp_Ax1 (aCam->Center(), aCam->Direction()), aWalk[AIS_WalkRotation_Roll].Value * aRotSpeed);
+      aCam->Transform (aTrsfRot);
+    }
+  }
+
+  // ask more frames
+  setAskNextFrame();
+  theView->Invalidate();
+  theView->View()->SynchronizeXRBaseToPosedCamera();
+  return aWalk;
+}
+
+// =======================================================================
 // function : handleCameraActions
 // purpose  :
 // =======================================================================
@@ -2929,7 +3056,7 @@ void AIS_ViewController::HandleViewEvents (const Handle(AIS_InteractiveContext)&
 {
   const bool wasImmediateUpdate = theView->SetImmediateUpdate (false);
 
-  const AIS_WalkDelta aWalk = FetchNavigationKeys (1.0, 1.0);
+  const AIS_WalkDelta aWalk = handleNavigationKeys (theCtx, theView);
   handleXRInput (theCtx, theView, aWalk);
   if (theView->View()->IsActiveXR())
   {
index 119fa8c..eaa12fb 100644 (file)
@@ -490,6 +490,11 @@ public:
 
 public:
 
+  //! Perform navigation.
+  //! This method is expected to be called from rendering thread.
+  Standard_EXPORT virtual AIS_WalkDelta handleNavigationKeys (const Handle(AIS_InteractiveContext)& theCtx,
+                                                              const Handle(V3d_View)& theView);
+
   //! Perform camera actions.
   //! This method is expected to be called from rendering thread.
   Standard_EXPORT virtual void handleCameraActions (const Handle(AIS_InteractiveContext)& theCtx,
index cb97a78..2f732e8 100644 (file)
@@ -50,6 +50,28 @@ ViewerTest_EventManager::ViewerTest_EventManager (const Handle(V3d_View)&
   myIsTmpContRedraw (Standard_False)
 {
   myViewAnimation = GlobalViewAnimation();
+
+  addActionHotKeys (Aspect_VKey_NavForward,        Aspect_VKey_W, Aspect_VKey_W | Aspect_VKeyFlags_SHIFT);
+  addActionHotKeys (Aspect_VKey_NavBackward ,      Aspect_VKey_S, Aspect_VKey_S | Aspect_VKeyFlags_SHIFT);
+  addActionHotKeys (Aspect_VKey_NavSlideLeft,      Aspect_VKey_A, Aspect_VKey_A | Aspect_VKeyFlags_SHIFT);
+  addActionHotKeys (Aspect_VKey_NavSlideRight,     Aspect_VKey_D, Aspect_VKey_D | Aspect_VKeyFlags_SHIFT);
+  addActionHotKeys (Aspect_VKey_NavRollCCW,        Aspect_VKey_Q, Aspect_VKey_Q | Aspect_VKeyFlags_SHIFT);
+  addActionHotKeys (Aspect_VKey_NavRollCW,         Aspect_VKey_E, Aspect_VKey_E | Aspect_VKeyFlags_SHIFT);
+
+  addActionHotKeys (Aspect_VKey_NavSpeedIncrease,  Aspect_VKey_Plus,  Aspect_VKey_Plus  | Aspect_VKeyFlags_SHIFT,
+                                                   Aspect_VKey_Equal,
+                                                   Aspect_VKey_NumpadAdd, Aspect_VKey_NumpadAdd | Aspect_VKeyFlags_SHIFT);
+  addActionHotKeys (Aspect_VKey_NavSpeedDecrease,  Aspect_VKey_Minus, Aspect_VKey_Minus | Aspect_VKeyFlags_SHIFT,
+                                                   Aspect_VKey_NumpadSubtract, Aspect_VKey_NumpadSubtract | Aspect_VKeyFlags_SHIFT);
+
+  addActionHotKeys (Aspect_VKey_NavLookUp,         Aspect_VKey_Up);
+  addActionHotKeys (Aspect_VKey_NavLookDown,       Aspect_VKey_Down);
+  addActionHotKeys (Aspect_VKey_NavLookLeft,       Aspect_VKey_Left);
+  addActionHotKeys (Aspect_VKey_NavLookRight,      Aspect_VKey_Right);
+  addActionHotKeys (Aspect_VKey_NavSlideLeft,      Aspect_VKey_Left  | Aspect_VKeyFlags_SHIFT);
+  addActionHotKeys (Aspect_VKey_NavSlideRight,     Aspect_VKey_Right | Aspect_VKeyFlags_SHIFT);
+  addActionHotKeys (Aspect_VKey_NavSlideUp,        Aspect_VKey_Up    | Aspect_VKeyFlags_SHIFT);
+  addActionHotKeys (Aspect_VKey_NavSlideDown,      Aspect_VKey_Down  | Aspect_VKeyFlags_SHIFT);
 }
 
 //=======================================================================
@@ -153,6 +175,69 @@ void ViewerTest_EventManager::ProcessConfigure()
   }
 }
 
+// =======================================================================
+// function : navigationKeyModifierSwitch
+// purpose  :
+// =======================================================================
+bool ViewerTest_EventManager::navigationKeyModifierSwitch (unsigned int theModifOld,
+                                                           unsigned int theModifNew,
+                                                           double       theTimeStamp)
+{
+  bool hasActions = false;
+  for (unsigned int aKeyIter = 0; aKeyIter < Aspect_VKey_ModifiersLower; ++aKeyIter)
+  {
+    if (!myKeys.IsKeyDown (aKeyIter))
+    {
+      continue;
+    }
+
+    Aspect_VKey anActionOld = Aspect_VKey_UNKNOWN, anActionNew = Aspect_VKey_UNKNOWN;
+    myNavKeyMap.Find (aKeyIter | theModifOld, anActionOld);
+    myNavKeyMap.Find (aKeyIter | theModifNew, anActionNew);
+    if (anActionOld == anActionNew)
+    {
+      continue;
+    }
+
+    if (anActionOld != Aspect_VKey_UNKNOWN)
+    {
+      myKeys.KeyUp (anActionOld, theTimeStamp);
+    }
+    if (anActionNew != Aspect_VKey_UNKNOWN)
+    {
+      hasActions = true;
+      myKeys.KeyDown (anActionNew, theTimeStamp);
+    }
+  }
+  return hasActions;
+}
+
+//=======================================================================
+//function : KeyDown
+//purpose  :
+//=======================================================================
+void ViewerTest_EventManager::KeyDown (Aspect_VKey theKey,
+                                       double theTime,
+                                       double thePressure)
+{
+  const unsigned int aModifOld = myKeys.Modifiers();
+  AIS_ViewController::KeyDown (theKey, theTime, thePressure);
+
+  const unsigned int aModifNew = myKeys.Modifiers();
+  if (aModifNew != aModifOld
+   && navigationKeyModifierSwitch (aModifOld, aModifNew, theTime))
+  {
+    // modifier key just pressed
+  }
+
+  Aspect_VKey anAction = Aspect_VKey_UNKNOWN;
+  if (myNavKeyMap.Find (theKey | myKeys.Modifiers(), anAction)
+  &&  anAction != Aspect_VKey_UNKNOWN)
+  {
+    AIS_ViewController::KeyDown (anAction, theTime, thePressure);
+  }
+}
+
 //=======================================================================
 //function : KeyUp
 //purpose  :
@@ -160,8 +245,25 @@ void ViewerTest_EventManager::ProcessConfigure()
 void ViewerTest_EventManager::KeyUp (Aspect_VKey theKey,
                                      double theTime)
 {
+  const unsigned int aModifOld = myKeys.Modifiers();
   AIS_ViewController::KeyUp (theKey, theTime);
-  ProcessKeyPress (theKey);
+
+  Aspect_VKey anAction = Aspect_VKey_UNKNOWN;
+  if (myNavKeyMap.Find (theKey | myKeys.Modifiers(), anAction)
+  &&  anAction != Aspect_VKey_UNKNOWN)
+  {
+    AIS_ViewController::KeyUp (anAction, theTime);
+    ProcessKeyPress (anAction);
+  }
+
+  const unsigned int aModifNew = myKeys.Modifiers();
+  if (aModifNew != aModifOld
+   && navigationKeyModifierSwitch (aModifOld, aModifNew, theTime))
+  {
+    // modifier key released
+  }
+
+  ProcessKeyPress (theKey | aModifNew);
 }
 
 //==============================================================================
@@ -178,7 +280,7 @@ void ViewerTest_EventManager::ProcessKeyPress (Aspect_VKey theKey)
 
   switch (theKey)
   {
-    case Aspect_VKey_A: // AXO
+    case Aspect_VKey_Backspace: // AXO
     {
       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
       {
@@ -186,14 +288,6 @@ void ViewerTest_EventManager::ProcessKeyPress (Aspect_VKey theKey)
       }
       break;
     }
-    case Aspect_VKey_D: // Reset
-    {
-      if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
-      {
-        myView->Reset();
-      }
-      break;
-    }
     case Aspect_VKey_F:
     {
       if (myCtx->NbSelected() > 0)
@@ -249,11 +343,11 @@ void ViewerTest_EventManager::ProcessKeyPress (Aspect_VKey theKey)
       myCtx->UpdateCurrentViewer();
       break;
     }
-    case Aspect_VKey_S:
-    case Aspect_VKey_W:
+    case Aspect_VKey_S | Aspect_VKeyFlags_CTRL:
+    case Aspect_VKey_W | Aspect_VKeyFlags_CTRL:
     {
       Standard_Integer aDispMode = AIS_Shaded;
-      if (theKey == Aspect_VKey_S)
+      if (theKey == (Aspect_VKey_S | Aspect_VKeyFlags_CTRL))
       {
         aDispMode = AIS_Shaded;
         std::cout << "setup Shaded display mode\n";
@@ -374,6 +468,25 @@ void ViewerTest_EventManager::ProcessKeyPress (Aspect_VKey theKey)
       {
         Draw_Interprete (ViewerTest_EventManager::ToExitOnCloseView() ? "exit" : "vclose");
       }
+      break;
+    }
+    case Aspect_VKey_NavSpeedDecrease:
+    case Aspect_VKey_NavSpeedIncrease:
+    {
+      // handle slide speed
+      float aNewSpeed = theKey == Aspect_VKey_NavSpeedDecrease
+                      ? myWalkSpeedRelative * 0.5f
+                      : myWalkSpeedRelative * 2.0f;
+      if (aNewSpeed >= 0.00001f
+       && aNewSpeed <= 10.0f)
+      {
+        if (Abs (aNewSpeed - 0.1f) < 0.001f)
+        {
+          aNewSpeed = 0.1f;
+        }
+        myWalkSpeedRelative = aNewSpeed;
+      }
+      break;
     }
   }
 
index 8c2be2b..d28de8d 100644 (file)
@@ -82,6 +82,11 @@ public:
                                                    bool theIsEmulated) Standard_OVERRIDE;
 
   //! Release key.
+  Standard_EXPORT virtual void KeyDown (Aspect_VKey theKey,
+                                        double theTime,
+                                        double thePressure = 1.0) Standard_OVERRIDE;
+
+  //! Release key.
   Standard_EXPORT virtual void KeyUp (Aspect_VKey theKey,
                                       double theTime) Standard_OVERRIDE;
 
@@ -98,10 +103,33 @@ public:
   //! Handle KeyPress event.
   Standard_EXPORT void ProcessKeyPress (Aspect_VKey theKey);
 
+protected:
+
+  //! Register hot-keys for specified Action.
+  void addActionHotKeys (Aspect_VKey theAction,
+                         unsigned int theHotKey1 = 0,
+                         unsigned int theHotKey2 = 0,
+                         unsigned int theHotKey3 = 0,
+                         unsigned int theHotKey4 = 0,
+                         unsigned int theHotKey5 = 0)
+  {
+    if (theHotKey1 != 0) { myNavKeyMap.Bind (theHotKey1, theAction); }
+    if (theHotKey2 != 0) { myNavKeyMap.Bind (theHotKey2, theAction); }
+    if (theHotKey3 != 0) { myNavKeyMap.Bind (theHotKey3, theAction); }
+    if (theHotKey4 != 0) { myNavKeyMap.Bind (theHotKey4, theAction); }
+    if (theHotKey5 != 0) { myNavKeyMap.Bind (theHotKey5, theAction); }
+  }
+
+  //! Handle modifier key changes.
+  Standard_EXPORT bool navigationKeyModifierSwitch (unsigned int theModifOld,
+                                                    unsigned int theModifNew,
+                                                    double       theTimeStamp);
+
 private:
 
   Handle(AIS_InteractiveContext) myCtx;
   Handle(V3d_View) myView;
+  NCollection_DataMap<unsigned int, Aspect_VKey> myNavKeyMap; //!< map of Hot-Key (key+modifiers) to Action
 
   TCollection_AsciiString myPickPntArgVec[3];
   Standard_Boolean myToPickPnt;
index fc16d0f..498ec55 100644 (file)
@@ -3021,12 +3021,19 @@ static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
   di << "B : BottomView\n";
   di << "R : RightView\n";
   di << "L : LeftView\n";
-  di << "A : AxonometricView\n";
-  di << "D : ResetView\n";
+  di << "Backspace : AxonometricView\n";
 
   di << "=========================\n";
-  di << "S : Shading\n";
-  di << "W : Wireframe\n";
+  di << "W, S : Fly   forward/backward\n";
+  di << "A, D : Slide left/right\n";
+  di << "Q, E : Bank  left/right\n";
+  di << "-, + : Change flying speed\n";
+  di << "Arrows : look left/right/up/down\n";
+  di << "Arrows+Shift : slide left/right/up/down\n";
+
+  di << "=========================\n";
+  di << "S + Ctrl : Shading\n";
+  di << "W + Ctrl : Wireframe\n";
   di << "H : HiddenLineRemoval\n";
   di << "U : Unset display mode\n";
   di << "Delete : Remove selection from viewer\n";