0031621: Draw Harness - handle navigation keys
[occt.git] / src / ViewerTest / ViewerTest_EventManager.cxx
old mode 100755 (executable)
new mode 100644 (file)
index 7cffdaf..2f732e8
 // Created on: 1998-08-27
 // Created by: Robert COUBLANC
 // Copyright (c) 1998-1999 Matra Datavision
-// Copyright (c) 1999-2012 OPEN CASCADE SAS
+// Copyright (c) 1999-2014 OPEN CASCADE SAS
 //
-// The content of this file is subject to the Open CASCADE Technology Public
-// License Version 6.5 (the "License"). You may not use the content of this file
-// except in compliance with the License. Please obtain a copy of the License
-// at http://www.opencascade.org and read it completely before using this file.
+// This file is part of Open CASCADE Technology software library.
 //
-// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
-// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
 //
-// The Original Code and all software distributed under the License is
-// distributed on an "AS IS" basis, without warranty of any kind, and the
-// Initial Developer hereby disclaims all such warranties, including without
-// limitation, any warranties of merchantability, fitness for a particular
-// purpose or non-infringement. Please see the License for the specific terms
-// and conditions governing the rights and limitations under the License.
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
 
+#include <ViewerTest_EventManager.hxx>
 
-
-#include <ViewerTest_EventManager.ixx>
+#include <AIS_AnimationCamera.hxx>
 #include <AIS_InteractiveContext.hxx>
-#include <NIS_View.hxx>
+#include <AIS_Shape.hxx>
+#include <Aspect_Grid.hxx>
+#include <Draw.hxx>
+#include <ViewerTest_ContinuousRedrawer.hxx>
+#include <ViewerTest_V3dView.hxx>
+
+Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand);
+
+IMPLEMENT_STANDARD_RTTIEXT(ViewerTest_EventManager,Standard_Transient)
+
+//=======================================================================
+//function : GlobalViewAnimation
+//purpose  :
+//=======================================================================
+const Handle(AIS_AnimationCamera)& ViewerTest_EventManager::GlobalViewAnimation()
+{
+  static Handle(AIS_AnimationCamera) THE_CAMERA_ANIM = new AIS_AnimationCamera ("ViewerTest_EventManager_ViewAnimation", Handle(V3d_View)());
+  return THE_CAMERA_ANIM;
+}
 
 //=======================================================================
 //function : ViewerTest_EventManager
-//purpose  : 
+//purpose  :
 //=======================================================================
+ViewerTest_EventManager::ViewerTest_EventManager (const Handle(V3d_View)&               theView,
+                                                  const Handle(AIS_InteractiveContext)& theCtx)
+: myCtx  (theCtx),
+  myView (theView),
+  myToPickPnt (Standard_False),
+  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);
 
-ViewerTest_EventManager::ViewerTest_EventManager
-        (const Handle(V3d_View)& aView,
-         const Handle(AIS_InteractiveContext)& Ctx)
-  : myView (aView),
-    myCtx  (Ctx),
-    myX    (-1),
-    myY    (-1)
-{}
+  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);
+}
 
 //=======================================================================
-//function : MoveTo
-//purpose  : 
+//function : ~ViewerTest_EventManager
+//purpose  :
 //=======================================================================
-
-void ViewerTest_EventManager::MoveTo(const Standard_Integer XPix, 
-                                    const Standard_Integer YPix)
+ViewerTest_EventManager::~ViewerTest_EventManager()
 {
-  if(!myCtx.IsNull() && !myView.IsNull())
-    myCtx->MoveTo(XPix,YPix,myView);
-  myX = XPix;
-  myY = YPix;
-  const Handle(NIS_View) aView = Handle(NIS_View)::DownCast(myView);
-  if (!aView.IsNull())
-    aView->DynamicHilight (XPix, YPix);
+  if (!myViewAnimation.IsNull()
+    && myViewAnimation->View() == myView)
+  {
+    myViewAnimation->Stop();
+    myViewAnimation->SetView (Handle(V3d_View)());
+  }
 }
 
 //=======================================================================
-//function : Select
-//purpose  : 
+//function : UpdateMouseButtons
+//purpose  :
 //=======================================================================
+bool ViewerTest_EventManager::UpdateMouseButtons (const Graphic3d_Vec2i& thePoint,
+                                                  Aspect_VKeyMouse theButtons,
+                                                  Aspect_VKeyFlags theModifiers,
+                                                  bool theIsEmulated)
+{
+  SetAllowRotation (!ViewerTest_V3dView::IsCurrentViewIn2DMode());
+
+  if (theButtons == Aspect_VKeyMouse_LeftButton)
+  {
+    if (myToPickPnt && (theModifiers & Aspect_VKeyFlags_CTRL) != 0)
+    {
+      Graphic3d_Vec3d anXYZ;
+      myView->Convert (thePoint.x(), thePoint.y(), anXYZ.x(), anXYZ.y(), anXYZ.z());
+      Draw::Set (myPickPntArgVec[0].ToCString(), anXYZ.x());
+      Draw::Set (myPickPntArgVec[1].ToCString(), anXYZ.y());
+      Draw::Set (myPickPntArgVec[2].ToCString(), anXYZ.z());
+      myToPickPnt = false;
+    }
+  }
 
-void ViewerTest_EventManager::Select(const Standard_Integer  XPMin,
-                                    const Standard_Integer  YPMin,
-                                    const Standard_Integer  XPMax,
-                                    const Standard_Integer  YPMax)
+  return AIS_ViewController::UpdateMouseButtons (thePoint, theButtons, theModifiers, theIsEmulated);
+}
+
+//==============================================================================
+//function : ProcessExpose
+//purpose  :
+//==============================================================================
+void ViewerTest_EventManager::ProcessExpose()
 {
-#define IS_FULL_INCLUSION Standard_True
-  if(!myCtx.IsNull() && !myView.IsNull())
-    myCtx->Select(XPMin,YPMin,XPMax,YPMax,myView);
-  const Handle(NIS_View) aView = Handle(NIS_View)::DownCast(myView);
-  if (!aView.IsNull())
-    aView->Select(XPMin,YPMin,XPMax,YPMax, Standard_False, IS_FULL_INCLUSION);
+  if (!myView.IsNull())
+  {
+    myView->Invalidate();
+    FlushViewEvents (myCtx, myView, true);
+  }
 }
 
-//=======================================================================
-//function : ShiftSelect
-//purpose  : 
-//=======================================================================
+//==============================================================================
+//function : handleViewRedraw
+//purpose  :
+//==============================================================================
+void ViewerTest_EventManager::handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx,
+                                                const Handle(V3d_View)& theView)
+{
+  AIS_ViewController::handleViewRedraw (theCtx, theView);
 
-void ViewerTest_EventManager::ShiftSelect(const Standard_Integer  XPMin,
-                                         const Standard_Integer  YPMin,
-                                         const Standard_Integer  XPMax,
-                                         const Standard_Integer  YPMax)
-{ 
-  if(!myCtx.IsNull() && !myView.IsNull())
-    myCtx->AIS_InteractiveContext::ShiftSelect(XPMin,YPMin,XPMax,YPMax,myView,
-                                               Standard_True);
-  const Handle(NIS_View) aView = Handle(NIS_View)::DownCast(myView);
-  if (!aView.IsNull())
-    aView->Select(XPMin,YPMin,XPMax,YPMax, Standard_True, IS_FULL_INCLUSION);
+  // On non-Windows platforms Aspect_Window::InvalidateContent() from rendering thread does not work as expected
+  // as in Tcl event loop the new message might go to sleep with new event remaining in queue.
+  // As a workaround - use dedicated background thread to ping Tcl event loop.
+  if (myToAskNextFrame)
+  {
+    ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
+    if (!myIsTmpContRedraw
+     && (!aRedrawer.IsStarted() || aRedrawer.IsPaused()))
+    {
+      myIsTmpContRedraw = true;
+    #ifndef _WIN32
+      aRedrawer.Start (theView->Window(), 60.0);
+    #endif
+    }
+  }
+  else if (myIsTmpContRedraw)
+  {
+    myIsTmpContRedraw = false;
+  #ifndef _WIN32
+    ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
+    aRedrawer.Pause();
+  #endif
+  }
+}
+
+//==============================================================================
+//function : ProcessConfigure
+//purpose  :
+//==============================================================================
+void ViewerTest_EventManager::ProcessConfigure()
+{
+  if (!myView.IsNull())
+  {
+    myView->MustBeResized();
+    FlushViewEvents (myCtx, myView, true);
+  }
+}
+
+// =======================================================================
+// 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 : Select
-//purpose  : 
+//function : KeyDown
+//purpose  :
 //=======================================================================
-
-void ViewerTest_EventManager::Select()
+void ViewerTest_EventManager::KeyDown (Aspect_VKey theKey,
+                                       double theTime,
+                                       double thePressure)
 {
-  if (!myCtx.IsNull() && !myView.IsNull())
-    myCtx->Select();
-  const Handle(NIS_View) aView = Handle(NIS_View)::DownCast(myView);
-  if (!aView.IsNull())
-    aView->Select(myX, myY);
+  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 : ShiftSelect
-//purpose  : 
+//function : KeyUp
+//purpose  :
 //=======================================================================
+void ViewerTest_EventManager::KeyUp (Aspect_VKey theKey,
+                                     double theTime)
+{
+  const unsigned int aModifOld = myKeys.Modifiers();
+  AIS_ViewController::KeyUp (theKey, theTime);
+
+  Aspect_VKey anAction = Aspect_VKey_UNKNOWN;
+  if (myNavKeyMap.Find (theKey | myKeys.Modifiers(), anAction)
+  &&  anAction != Aspect_VKey_UNKNOWN)
+  {
+    AIS_ViewController::KeyUp (anAction, theTime);
+    ProcessKeyPress (anAction);
+  }
 
-void ViewerTest_EventManager::ShiftSelect()
+  const unsigned int aModifNew = myKeys.Modifiers();
+  if (aModifNew != aModifOld
+   && navigationKeyModifierSwitch (aModifOld, aModifNew, theTime))
+  {
+    // modifier key released
+  }
+
+  ProcessKeyPress (theKey | aModifNew);
+}
+
+//==============================================================================
+//function : ProcessKeyPress
+//purpose  :
+//==============================================================================
+void ViewerTest_EventManager::ProcessKeyPress (Aspect_VKey theKey)
 {
-  if(!myCtx.IsNull() && !myView.IsNull())
-    myCtx->ShiftSelect(Standard_True);
-  const Handle(NIS_View) aView = Handle(NIS_View)::DownCast(myView);
-  if (!aView.IsNull())
-    aView->Select(myX, myY, Standard_True);
+  if (myCtx.IsNull()
+   || myView.IsNull())
+  {
+    return;
+  }
+
+  switch (theKey)
+  {
+    case Aspect_VKey_Backspace: // AXO
+    {
+      if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
+      {
+        myView->SetProj(V3d_XposYnegZpos);
+      }
+      break;
+    }
+    case Aspect_VKey_F:
+    {
+      if (myCtx->NbSelected() > 0)
+      {
+        myCtx->FitSelected (myView);
+      }
+      else
+      {
+        myView->FitAll();
+      }
+      break;
+    }
+    case Aspect_VKey_H: // HLR
+    {
+      std::cout << "HLR\n";
+      myView->SetComputedMode (!myView->ComputedMode());
+      myView->Redraw();
+      break;
+    }
+    case Aspect_VKey_P: // Type of HLR
+    {
+      myCtx->DefaultDrawer()->SetTypeOfHLR (myCtx->DefaultDrawer()->TypeOfHLR() == Prs3d_TOH_Algo
+                                          ? Prs3d_TOH_PolyAlgo
+                                          : Prs3d_TOH_Algo);
+      if (myCtx->NbSelected() == 0)
+      {
+        AIS_ListOfInteractive aListOfShapes;
+        myCtx->DisplayedObjects (aListOfShapes);
+        for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
+        {
+          if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (anIter.Value()))
+          {
+            aShape->SetTypeOfHLR (aShape->TypeOfHLR() == Prs3d_TOH_PolyAlgo
+                                ? Prs3d_TOH_Algo
+                                : Prs3d_TOH_PolyAlgo);
+            myCtx->Redisplay (aShape, Standard_False);
+          }
+        }
+      }
+      else
+      {
+        for (myCtx->InitSelected(); myCtx->MoreSelected(); myCtx->NextSelected())
+        {
+          if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (myCtx->SelectedInteractive()))
+          {
+            aShape->SetTypeOfHLR (aShape->TypeOfHLR() == Prs3d_TOH_PolyAlgo
+                                ? Prs3d_TOH_Algo
+                                : Prs3d_TOH_PolyAlgo);
+            myCtx->Redisplay (aShape, Standard_False);
+          }
+        }
+      }
+      myCtx->UpdateCurrentViewer();
+      break;
+    }
+    case Aspect_VKey_S | Aspect_VKeyFlags_CTRL:
+    case Aspect_VKey_W | Aspect_VKeyFlags_CTRL:
+    {
+      Standard_Integer aDispMode = AIS_Shaded;
+      if (theKey == (Aspect_VKey_S | Aspect_VKeyFlags_CTRL))
+      {
+        aDispMode = AIS_Shaded;
+        std::cout << "setup Shaded display mode\n";
+      }
+      else
+      {
+        aDispMode = AIS_WireFrame;
+        std::cout << "setup WireFrame display mode\n";
+      }
+
+      if (myCtx->NbSelected() == 0)
+      {
+        myCtx->SetDisplayMode (aDispMode, true);
+      }
+      else
+      {
+        for (myCtx->InitSelected(); myCtx->MoreSelected(); myCtx->NextSelected())
+        {
+          myCtx->SetDisplayMode (myCtx->SelectedInteractive(), aDispMode, false);
+        }
+        myCtx->UpdateCurrentViewer();
+      }
+      break;
+    }
+    case Aspect_VKey_U: // Unset display mode
+    {
+      std::cout << "reset display mode to defaults\n";
+      if (myCtx->NbSelected() == 0)
+      {
+        myCtx->SetDisplayMode (AIS_WireFrame, true);
+      }
+      else
+      {
+        for (myCtx->InitSelected(); myCtx->MoreSelected(); myCtx->NextSelected())
+        {
+          myCtx->UnsetDisplayMode (myCtx->SelectedInteractive(), false);
+        }
+        myCtx->UpdateCurrentViewer();
+      }
+      break;
+    }
+    case Aspect_VKey_T:
+    {
+      if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
+      {
+        myView->SetProj (V3d_TypeOfOrientation_Zup_Top);
+      }
+      break;
+    }
+    case Aspect_VKey_B:
+    {
+      if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
+      {
+        myView->SetProj (V3d_TypeOfOrientation_Zup_Bottom);
+      }
+      break;
+    }
+    case Aspect_VKey_L:
+    {
+      if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
+      {
+        myView->SetProj (V3d_TypeOfOrientation_Zup_Left);
+      }
+      break;
+    }
+    case Aspect_VKey_R:
+    {
+      if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
+      {
+        myView->SetProj (V3d_TypeOfOrientation_Zup_Right);
+      }
+      break;
+    }
+    case Aspect_VKey_Comma:
+    {
+      myCtx->HilightNextDetected (myView);
+      break;
+    }
+    case Aspect_VKey_Period:
+    {
+      myCtx->HilightPreviousDetected (myView);
+      break;
+    }
+    case Aspect_VKey_Slash:
+    case Aspect_VKey_NumpadDivide:
+    {
+      Handle(Graphic3d_Camera) aCamera = myView->Camera();
+      if (aCamera->IsStereo())
+      {
+        aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() - 0.01);
+        myView->Redraw();
+      }
+      break;
+    }
+    case Aspect_VKey_NumpadMultiply:
+    {
+      Handle(Graphic3d_Camera) aCamera = myView->Camera();
+      if (aCamera->IsStereo())
+      {
+        aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() + 0.01);
+        myView->Redraw();
+      }
+      break;
+    }
+    case Aspect_VKey_Delete:
+    {
+      if (!myCtx.IsNull()
+        && myCtx->NbSelected() > 0)
+      {
+        Draw_Interprete ("verase");
+      }
+      break;
+    }
+    case Aspect_VKey_Escape:
+    {
+      if (!myCtx.IsNull()
+        && ViewerTest_EventManager::ToCloseViewOnEscape())
+      {
+        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;
+    }
+  }
+
+  if (theKey >= Aspect_VKey_0
+   && theKey <= Aspect_VKey_7)
+  {
+    const Standard_Integer aSelMode = theKey - Aspect_VKey_0;
+    bool toEnable = true;
+    if (!myCtx.IsNull())
+    {
+      AIS_ListOfInteractive aPrsList;
+      myCtx->DisplayedObjects (aPrsList);
+      for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More() && toEnable; aPrsIter.Next())
+      {
+        TColStd_ListOfInteger aModes;
+        myCtx->ActivatedModes (aPrsIter.Value(), aModes);
+        for (TColStd_ListOfInteger::Iterator aModeIter (aModes); aModeIter.More() && toEnable; aModeIter.Next())
+        {
+          if (aModeIter.Value() == aSelMode)
+          {
+            toEnable = false;
+          }
+        }
+      }
+    }
+    TCollection_AsciiString aCmd = TCollection_AsciiString ("vselmode ") + aSelMode + (toEnable ? " 1" : " 0");
+    Draw_Interprete (aCmd.ToCString());
+  }
 }