From 49582f9dbf0b2a0502bcb37ea5789af5d940ca45 Mon Sep 17 00:00:00 2001 From: kgv Date: Mon, 10 Jun 2019 21:03:41 +0300 Subject: [PATCH] 0030507: Visualization - introduce AIS_ViewController ViewerTest_EventManager now inherits AIS_ViewController. Platform-dependent user input handling within ViewerTest has been revised to process events in common way through AIS_ViewController. The mouse navigation has been changed, so that left mouse clicked without modifers now rotates View. The rubber-band selection can be activated via Alt+LeftMouseButton. Selection is now done on mouse unclick and keyboard short-cuts take effect on unclick. Aspect_Window::SetTitle() - added new method configuring Window title. Introduced new types Aspect_Touch, Aspect_VKey, Aspect_ScrollDelta for processing window events in platform-independent way. --- src/AIS/AIS_DragAction.hxx | 26 + src/AIS/AIS_InteractiveContext.cxx | 9 + src/AIS/AIS_InteractiveContext.hxx | 11 + src/AIS/AIS_InteractiveContext_1.cxx | 37 + src/AIS/AIS_MouseGesture.hxx | 36 + src/AIS/AIS_NavigationMode.hxx | 31 + src/AIS/AIS_RotationMode.hxx | 33 + src/AIS/AIS_ViewController.cxx | 2321 +++++++++++++++++ src/AIS/AIS_ViewController.hxx | 658 +++++ src/AIS/AIS_ViewInputBuffer.hxx | 153 ++ src/AIS/AIS_WalkDelta.hxx | 115 + src/AIS/FILES | 8 + src/Aspect/Aspect_ScrollDelta.hxx | 59 + src/Aspect/Aspect_Touch.hxx | 49 + .../Aspect_TouchMap.hxx} | 17 +- src/Aspect/Aspect_VKey.hxx | 199 ++ src/Aspect/Aspect_VKeyFlags.hxx | 49 + src/Aspect/Aspect_VKeySet.cxx | 150 ++ src/Aspect/Aspect_VKeySet.hxx | 152 ++ src/Aspect/Aspect_Window.hxx | 18 +- src/Aspect/FILES | 7 + src/Cocoa/Cocoa_Window.hxx | 8 + src/Cocoa/Cocoa_Window.mm | 161 ++ src/QABugs/QABugs_1.cxx | 2 - src/V3d/V3d_View.cxx | 30 +- src/V3d/V3d_View.hxx | 18 +- src/ViewerTest/FILES | 3 +- src/ViewerTest/ViewerTest.cxx | 22 +- src/ViewerTest/ViewerTest_EventManager.cxx | 428 +-- src/ViewerTest/ViewerTest_EventManager.hxx | 107 +- src/ViewerTest/ViewerTest_ObjectCommands.cxx | 1 - src/ViewerTest/ViewerTest_V3dView.cxx | 71 + src/ViewerTest/ViewerTest_V3dView.hxx | 53 + src/ViewerTest/ViewerTest_ViewerCommands.cxx | 1490 +++-------- src/ViewerTest/ViewerTest_ViewerCommands_1.mm | 175 +- src/WNT/WNT_Window.cxx | 276 ++ src/WNT/WNT_Window.hxx | 39 +- src/Xw/Xw_Window.cxx | 165 ++ src/Xw/Xw_Window.hxx | 8 + tests/bugs/vis/bug26147 | 4 +- 40 files changed, 5752 insertions(+), 1447 deletions(-) create mode 100644 src/AIS/AIS_DragAction.hxx create mode 100644 src/AIS/AIS_MouseGesture.hxx create mode 100644 src/AIS/AIS_NavigationMode.hxx create mode 100644 src/AIS/AIS_RotationMode.hxx create mode 100644 src/AIS/AIS_ViewController.cxx create mode 100644 src/AIS/AIS_ViewController.hxx create mode 100644 src/AIS/AIS_ViewInputBuffer.hxx create mode 100644 src/AIS/AIS_WalkDelta.hxx create mode 100644 src/Aspect/Aspect_ScrollDelta.hxx create mode 100644 src/Aspect/Aspect_Touch.hxx rename src/{ViewerTest/ViewerTest_EventManager.lxx => Aspect/Aspect_TouchMap.hxx} (65%) create mode 100644 src/Aspect/Aspect_VKey.hxx create mode 100644 src/Aspect/Aspect_VKeyFlags.hxx create mode 100644 src/Aspect/Aspect_VKeySet.cxx create mode 100644 src/Aspect/Aspect_VKeySet.hxx create mode 100644 src/ViewerTest/ViewerTest_V3dView.cxx create mode 100644 src/ViewerTest/ViewerTest_V3dView.hxx diff --git a/src/AIS/AIS_DragAction.hxx b/src/AIS/AIS_DragAction.hxx new file mode 100644 index 0000000000..cf3bf238ba --- /dev/null +++ b/src/AIS/AIS_DragAction.hxx @@ -0,0 +1,26 @@ +// Copyright (c) 2018-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _AIS_DragAction_HeaderFile +#define _AIS_DragAction_HeaderFile + +//! Dragging action. +enum AIS_DragAction +{ + AIS_DragAction_Start, //!< (try) start dragging object + AIS_DragAction_Update, //!< perform dragging (update position) + AIS_DragAction_Stop, //!< stop dragging (save position) + AIS_DragAction_Abort, //!< abort dragging (restore initial position) +}; + +#endif // _AIS_DragAction_HeaderFile diff --git a/src/AIS/AIS_InteractiveContext.cxx b/src/AIS/AIS_InteractiveContext.cxx index 3ce8af6c0e..2d2d2d5f0a 100644 --- a/src/AIS/AIS_InteractiveContext.cxx +++ b/src/AIS/AIS_InteractiveContext.cxx @@ -2524,3 +2524,12 @@ void AIS_InteractiveContext::SetTransformPersistence (const Handle(AIS_Interacti anActiveViewIter.Value()->View()->InvalidateZLayerBoundingBox (aLayerId); } } + +//======================================================================= +//function : GravityPoint +//purpose : +//======================================================================= +gp_Pnt AIS_InteractiveContext::GravityPoint (const Handle(V3d_View)& theView) const +{ + return theView->GravityPoint(); +} diff --git a/src/AIS/AIS_InteractiveContext.hxx b/src/AIS/AIS_InteractiveContext.hxx index 43da8b2ae2..659fb5500f 100644 --- a/src/AIS/AIS_InteractiveContext.hxx +++ b/src/AIS/AIS_InteractiveContext.hxx @@ -557,6 +557,14 @@ public: //! @name Selection management Standard_EXPORT void AddOrRemoveSelected (const Handle(AIS_InteractiveObject)& theObject, const Standard_Boolean theToUpdateViewer); + //! Updates Selected state of specified owner without calling HilightSelected(). + //! Has no effect if Selected state is not changed, and redirects to AddOrRemoveSelected() otherwise. + //! @param theOwner owner object to set selected state + //! @param theIsSelected new selected state + //! @return TRUE if Selected state has been changed + Standard_EXPORT Standard_Boolean SetSelectedState (const Handle(SelectMgr_EntityOwner)& theOwner, + const Standard_Boolean theIsSelected); + //! Highlights selected objects. Standard_EXPORT void HilightSelected (const Standard_Boolean theToUpdateViewer); @@ -816,6 +824,9 @@ public: //! @name common properties //! returns the number of removed structures from the viewers. Standard_EXPORT Standard_Integer PurgeDisplay(); + //! Return rotation gravity point. + Standard_EXPORT virtual gp_Pnt GravityPoint (const Handle(V3d_View)& theView) const; + public: //! @name debug visualization //! Visualization of sensitives - for debugging purposes! diff --git a/src/AIS/AIS_InteractiveContext_1.cxx b/src/AIS/AIS_InteractiveContext_1.cxx index 2d6b9d99c7..caeee2d41f 100644 --- a/src/AIS/AIS_InteractiveContext_1.cxx +++ b/src/AIS/AIS_InteractiveContext_1.cxx @@ -1004,6 +1004,43 @@ void AIS_InteractiveContext::AddOrRemoveSelected (const Handle(SelectMgr_EntityO UpdateCurrentViewer(); } +// ======================================================================= +// function : SetSelectedState +// purpose : +// ======================================================================= +Standard_Boolean AIS_InteractiveContext::SetSelectedState (const Handle(SelectMgr_EntityOwner)& theEntity, + const Standard_Boolean theIsSelected) +{ + if (theEntity.IsNull()) + { + throw Standard_ProgramError ("Internal error: AIS_InteractiveContext::SetSelectedState() called with NO object"); + } + + if (!theEntity->HasSelectable() + || mySelection->IsSelected (theEntity) == theIsSelected) + { + return false; + } + + if (theEntity->IsAutoHilight()) + { + AddOrRemoveSelected (theEntity, false); + return true; + } + + if (theIsSelected) + { + const AIS_SelectStatus aSelStatus = mySelection->AddSelect (theEntity); + theEntity->SetSelected (true); + return aSelStatus == AIS_SS_Added; + } + else + { + const AIS_SelectStatus aSelStatus = mySelection->Select (theEntity); + theEntity->SetSelected (false); + return aSelStatus == AIS_SS_Removed; + } +} //======================================================================= //function : IsSelected diff --git a/src/AIS/AIS_MouseGesture.hxx b/src/AIS/AIS_MouseGesture.hxx new file mode 100644 index 0000000000..ab28f1327f --- /dev/null +++ b/src/AIS/AIS_MouseGesture.hxx @@ -0,0 +1,36 @@ +// Copyright (c) 2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _AIS_MouseGesture_HeaderFile +#define _AIS_MouseGesture_HeaderFile + +#include + +//! Mouse gesture - only one can be active at one moment. +enum AIS_MouseGesture +{ + AIS_MouseGesture_NONE, //!< no active gesture + // + AIS_MouseGesture_SelectRectangle, //!< rectangular selection + AIS_MouseGesture_SelectLasso, //!< polygonal selection + // + AIS_MouseGesture_Zoom, //!< view zoom gesture + AIS_MouseGesture_Pan, //!< view panning gesture + AIS_MouseGesture_RotateOrbit, //!< orbit rotation gesture + AIS_MouseGesture_RotateView, //!< view rotation gesture +}; + +//! Map defining mouse gestures. +typedef NCollection_DataMap AIS_MouseGestureMap; + +#endif // _AIS_MouseGesture_HeaderFile diff --git a/src/AIS/AIS_NavigationMode.hxx b/src/AIS/AIS_NavigationMode.hxx new file mode 100644 index 0000000000..b21cbe0fe8 --- /dev/null +++ b/src/AIS/AIS_NavigationMode.hxx @@ -0,0 +1,31 @@ +// Copyright (c) 2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _AIS_NavigationMode_HeaderFile +#define _AIS_NavigationMode_HeaderFile + +//! Camera navigation mode. +enum AIS_NavigationMode +{ + AIS_NavigationMode_Orbit, //!< orbit rotation + AIS_NavigationMode_FirstPersonFlight, //!< flight rotation (first person) + AIS_NavigationMode_FirstPersonWalk, //!< walking mode (first person) +}; + +enum +{ + AIS_NavigationMode_LOWER = 0, + AIS_NavigationMode_UPPER = AIS_NavigationMode_FirstPersonWalk +}; + +#endif // _V3d_NavigationMode_HeaderFile diff --git a/src/AIS/AIS_RotationMode.hxx b/src/AIS/AIS_RotationMode.hxx new file mode 100644 index 0000000000..7fe55dcbcb --- /dev/null +++ b/src/AIS/AIS_RotationMode.hxx @@ -0,0 +1,33 @@ +// Copyright (c) 2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _AIS_RotationMode_HeaderFile +#define _AIS_RotationMode_HeaderFile + +//! Camera rotation mode. +enum AIS_RotationMode +{ + AIS_RotationMode_BndBoxActive, //!< default OCCT rotation + AIS_RotationMode_PickLast, //!< rotate around last picked point + AIS_RotationMode_PickCenter, //!< rotate around point at the center of window + AIS_RotationMode_CameraAt, //!< rotate around camera center + AIS_RotationMode_BndBoxScene, //!< rotate around scene center +}; + +enum +{ + AIS_RotationMode_LOWER = 0, + AIS_RotationMode_UPPER = AIS_RotationMode_BndBoxScene, +}; + +#endif // _AIS_RotationMode_HeaderFile diff --git a/src/AIS/AIS_ViewController.cxx b/src/AIS/AIS_ViewController.cxx new file mode 100644 index 0000000000..e4403309fa --- /dev/null +++ b/src/AIS/AIS_ViewController.cxx @@ -0,0 +1,2321 @@ +// Copyright (c) 2016-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include "AIS_ViewController.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ======================================================================= +// function : AIS_ViewController +// purpose : +// ======================================================================= +AIS_ViewController::AIS_ViewController() +: myLastEventsTime (0.0), + myToAskNextFrame (false), + myMinCamDistance (1.0), + myRotationMode (AIS_RotationMode_BndBoxActive), + myNavigationMode (AIS_NavigationMode_Orbit), + myMouseAccel (1.0f), + myOrbitAccel (1.0f), + myToShowPanAnchorPoint (true), + myToShowRotateCenter (true), + myToLockOrbitZUp (false), + myToInvertPitch (false), + myToAllowTouchZRotation(false), + myToAllowRotation (true), + myToAllowPanning (true), + myToAllowZooming (true), + myToAllowZFocus (true), + myToAllowHighlight (true), + myToAllowDragging (true), + // + myWalkSpeedAbsolute (1.5f), + myWalkSpeedRelative (0.1f), + myThrustSpeed (0.0f), + myHasThrust (false), + // + myPrevMoveTo (-1, -1), + myHasHlrOnBeforeRotation (false), + // + myMouseClickThreshold (3.0), + myMouseDoubleClickInt (0.4), + myScrollZoomRatio (15.0f), + myMouseActiveGesture (AIS_MouseGesture_NONE), + myMouseActiveIdleRotation (false), + myMouseClickCounter (0), + myMousePressed (Aspect_VKeyMouse_NONE), + myMouseModifiers (Aspect_VKeyFlags_NONE), + myMouseSingleButton (-1), + // + myTouchToleranceScale (1.0f), + myTouchRotationThresholdPx (6.0f), + myTouchZRotationThreshold (float(2.0 * M_PI / 180.0)), + myTouchPanThresholdPx (4.0f), + myTouchZoomThresholdPx (6.0f), + myTouchZoomRatio (0.13f), + // + myNbTouchesLast (0), + myUpdateStartPointPan (true), + myUpdateStartPointRot (true), + myUpdateStartPointZRot (true), + // + myPanPnt3d (Precision::Infinite(), 0.0, 0.0) +{ + myEventTimer.Start(); + + myAnchorPointPrs1 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0)); + myAnchorPointPrs1->SetZLayer (Graphic3d_ZLayerId_Top); + myAnchorPointPrs1->SetMutable (true); + + myAnchorPointPrs2 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0)); + myAnchorPointPrs2->SetZLayer (Graphic3d_ZLayerId_Topmost); + myAnchorPointPrs2->SetMutable (true); + + myRubberBand = new AIS_RubberBand (Quantity_NOC_LIGHTBLUE, Aspect_TOL_SOLID, Quantity_NOC_LIGHTBLUE, 0.4, 1.0); + myRubberBand->SetZLayer (Graphic3d_ZLayerId_TopOSD); + myRubberBand->SetTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER)); + myRubberBand->SetDisplayMode (0); + myRubberBand->SetMutable (true); + + myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_RotateOrbit); + myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Zoom); + myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_SHIFT, AIS_MouseGesture_Pan); + myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT, AIS_MouseGesture_SelectRectangle); + + myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton, AIS_MouseGesture_Zoom); + myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_RotateOrbit); + + myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton, AIS_MouseGesture_Pan); + myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Pan); +} + +// ======================================================================= +// function : ResetViewInput +// purpose : +// ======================================================================= +void AIS_ViewController::ResetViewInput() +{ + myKeys.Reset(); + myMousePressed = Aspect_VKeyMouse_NONE; + myMouseModifiers = Aspect_VKeyFlags_NONE; + myMouseSingleButton = -1; + myUI.Dragging.ToAbort = true; + myMouseActiveGesture = AIS_MouseGesture_NONE; + myMouseClickTimer.Stop(); + myMouseClickCounter = 0; +} + +// ======================================================================= +// function : FlushViewEvents +// purpose : +// ======================================================================= +void AIS_ViewController::FlushViewEvents (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView, + Standard_Boolean theToHandle) +{ + flushBuffers (theCtx, theView); + flushGestures(theCtx, theView); + if (theToHandle) + { + HandleViewEvents (theCtx, theView); + } +} + +// ======================================================================= +// function : flushBuffers +// purpose : +// ======================================================================= +void AIS_ViewController::flushBuffers (const Handle(AIS_InteractiveContext)& , + const Handle(V3d_View)& ) +{ + myToAskNextFrame = false; + + myGL.IsNewGesture = myUI.IsNewGesture; + myUI.IsNewGesture = false; + + myGL.ZoomActions.Clear(); + myGL.ZoomActions.Append (myUI.ZoomActions); + myUI.ZoomActions.Clear(); + + myGL.Orientation.ToFitAll = myUI.Orientation.ToFitAll; + myUI.Orientation.ToFitAll = false; + if (myUI.Orientation.ToSetViewOrient) + { + myUI.Orientation.ToSetViewOrient = false; + myGL.Orientation.ToSetViewOrient = true; + myGL.Orientation.ViewOrient = myUI.Orientation.ViewOrient; + } + + if (myUI.MoveTo.ToHilight) + { + myUI.MoveTo.ToHilight = false; + myGL.MoveTo.ToHilight = true; + myGL.MoveTo.Point = myUI.MoveTo.Point; + } + + { + myGL.Selection.Tool = myUI.Selection.Tool; + myGL.Selection.IsXOR = myUI.Selection.IsXOR; + myGL.Selection.Points = myUI.Selection.Points; + myUI.Selection.IsXOR = false; + if (myUI.Selection.Tool == AIS_ViewSelectionTool_Picking) + { + myUI.Selection.Points.Clear(); + } + } + + if (myUI.Selection.ToApplyTool) + { + myGL.Selection.ToApplyTool = true; + myUI.Selection.ToApplyTool = false; + myUI.Selection.Points.Clear(); + } + + if (myUI.Panning.ToStart) + { + myUI.Panning.ToStart = false; + myGL.Panning.ToStart = true; + myGL.Panning.PointStart = myUI.Panning.PointStart; + } + + if (myUI.Panning.ToPan) + { + myUI.Panning.ToPan = false; + myGL.Panning.ToPan = true; + myGL.Panning.Delta = myUI.Panning.Delta; + } + + if (myUI.Dragging.ToAbort) + { + myUI.Dragging.ToAbort = false; + myGL.Dragging.ToAbort = true; + } + else if (myUI.Dragging.ToStop) + { + myUI.Dragging.ToStop = false; + myGL.Dragging.ToStop = true; + } + else if (myUI.Dragging.ToStart) + { + myUI.Dragging.ToStart = false; + myGL.Dragging.ToStart = true; + myGL.Dragging.PointStart = myUI.Dragging.PointStart; + } + myGL.Dragging.PointTo = myUI.Dragging.PointTo; + + if (myUI.OrbitRotation.ToStart) + { + myUI.OrbitRotation.ToStart = false; + myGL.OrbitRotation.ToStart = true; + myGL.OrbitRotation.PointStart = myUI.OrbitRotation.PointStart; + } + + if (myUI.OrbitRotation.ToRotate) + { + myUI.OrbitRotation.ToRotate = false; + myGL.OrbitRotation.ToRotate = true; + myGL.OrbitRotation.PointTo = myUI.OrbitRotation.PointTo; + } + + if (myUI.ViewRotation.ToStart) + { + myUI.ViewRotation.ToStart = false; + myGL.ViewRotation.ToStart = true; + myGL.ViewRotation.PointStart = myUI.ViewRotation.PointStart; + } + + if (myUI.ViewRotation.ToRotate) + { + myUI.ViewRotation.ToRotate = false; + myGL.ViewRotation.ToRotate = true; + myGL.ViewRotation.PointTo = myUI.ViewRotation.PointTo; + } + + if (myUI.ZRotate.ToRotate) + { + myGL.ZRotate = myUI.ZRotate; + myUI.ZRotate.ToRotate = false; + } +} + +// ======================================================================= +// function : flushGestures +// purpose : +// ======================================================================= +void AIS_ViewController::flushGestures (const Handle(AIS_InteractiveContext)& , + const Handle(V3d_View)& theView) +{ + const Standard_Real aTolScale = myTouchToleranceScale; + const Standard_Integer aTouchNb = myTouchPoints.Extent(); + if (myNbTouchesLast != aTouchNb) + { + myNbTouchesLast = aTouchNb; + myGL.IsNewGesture = true; + } + if (aTouchNb == 1) // touch + { + Aspect_Touch& aTouch = myTouchPoints.ChangeFromIndex (1); + if (myUpdateStartPointRot) + { + // skip rotation if have active dragged object + if (myNavigationMode == AIS_NavigationMode_Orbit) + { + myGL.OrbitRotation.ToStart = true; + myGL.OrbitRotation.PointStart = myStartRotCoord; + } + else + { + myGL.ViewRotation.ToStart = true; + myGL.ViewRotation.PointStart = myStartRotCoord; + } + + myUpdateStartPointRot = false; + theView->Invalidate(); + } + + // rotation + const Standard_Real aRotTouchTol = !aTouch.IsPreciseDevice + ? aTolScale * myTouchRotationThresholdPx + : gp::Resolution(); + if (Abs (aTouch.Delta().x()) + Abs(aTouch.Delta().y()) > aRotTouchTol) + { + const Standard_Real aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel; + if (myNavigationMode == AIS_NavigationMode_Orbit) + { + const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.OrbitRotation.PointStart; + myGL.OrbitRotation.ToRotate = true; + myGL.OrbitRotation.PointTo = myGL.OrbitRotation.PointStart + aRotDelta * aRotAccel; + myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y()); + } + else + { + const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.ViewRotation.PointStart; + myGL.ViewRotation.ToRotate = true; + myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart + aRotDelta * aRotAccel; + myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y()); + } + + aTouch.From = aTouch.To; + } + } + else if (aTouchNb == 2) // pinch + { + Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1); + Aspect_Touch& aLastTouch = myTouchPoints.ChangeFromIndex (2); + const Graphic3d_Vec2d aFrom[2] = { aFirstTouch.From, aLastTouch.From }; + const Graphic3d_Vec2d aTo[2] = { aFirstTouch.To, aLastTouch.To }; + + Graphic3d_Vec2d aPinchCenterStart ((aFrom[0].x() + aFrom[1].x()) / 2.0, + (aFrom[0].y() + aFrom[1].y()) / 2.0); + + Standard_Real aPinchCenterXEnd = (aTo[0].x() + aTo[1].x()) / 2.0; + Standard_Real aPinchCenterYEnd = (aTo[0].y() + aTo[1].y()) / 2.0; + + Standard_Real aPinchCenterXDev = aPinchCenterXEnd - aPinchCenterStart.x(); + Standard_Real aPinchCenterYDev = aPinchCenterYEnd - aPinchCenterStart.y(); + + Standard_Real aStartSize = (aFrom[0] - aFrom[1]).Modulus(); + Standard_Real anEndSize = ( aTo[0] - aTo[1]).Modulus(); + + Standard_Real aDeltaSize = anEndSize - aStartSize; + + bool anIsClearDev = false; + + if (myToAllowTouchZRotation) + { + Standard_Real A1 = aFrom[0].y() - aFrom[1].y(); + Standard_Real B1 = aFrom[1].x() - aFrom[0].x(); + + Standard_Real A2 = aTo[0].y() - aTo[1].y(); + Standard_Real B2 = aTo[1].x() - aTo[0].x(); + + Standard_Real aRotAngle = 0.0; + + Standard_Real aDenomenator = A1*A2 + B1*B2; + if (aDenomenator <= Precision::Confusion()) + { + aRotAngle = 0.0; + } + else + { + Standard_Real aNumerator = A1*B2 - A2*B1; + aRotAngle = ATan (aNumerator / aDenomenator); + } + + if (Abs(aRotAngle) > Standard_Real(myTouchZRotationThreshold)) + { + myGL.ZRotate.ToRotate = true; + myGL.ZRotate.Angle = aRotAngle; + anIsClearDev = true; + } + } + + if (Abs(aDeltaSize) > aTolScale * myTouchZoomThresholdPx) + { + // zoom + aDeltaSize *= Standard_Real(myTouchZoomRatio); + Aspect_ScrollDelta aParams (Graphic3d_Vec2i (aPinchCenterStart), aDeltaSize); + myGL.ZoomActions.Append (aParams); + anIsClearDev = true; + } + + const Standard_Real aPanTouchTol = !aFirstTouch.IsPreciseDevice + ? aTolScale * myTouchPanThresholdPx + : gp::Resolution(); + if (Abs(aPinchCenterXDev) + Abs(aPinchCenterYDev) > aPanTouchTol) + { + // pan + if (myUpdateStartPointPan) + { + myGL.Panning.ToStart = true; + myGL.Panning.PointStart = Graphic3d_Vec2i (myStartPanCoord); + myUpdateStartPointPan = false; + theView->Invalidate(); + } + + myGL.Panning.ToPan = true; + myGL.Panning.Delta.x() = int( aPinchCenterXDev); + myGL.Panning.Delta.y() = int(-aPinchCenterYDev); + anIsClearDev = true; + } + + if (anIsClearDev) + { + aFirstTouch.From = aFirstTouch.To; + aLastTouch .From = aLastTouch.To; + } + } +} + +// ======================================================================= +// function : UpdateViewOrientation +// purpose : +// ======================================================================= +void AIS_ViewController::UpdateViewOrientation (V3d_TypeOfOrientation theOrientation, + bool theToFitAll) +{ + myUI.Orientation.ToFitAll = theToFitAll; + myUI.Orientation.ToSetViewOrient = true; + myUI.Orientation.ViewOrient = theOrientation; +} + +// ======================================================================= +// function : SelectInViewer +// purpose : +// ======================================================================= +void AIS_ViewController::SelectInViewer (const Graphic3d_Vec2i& thePnt, + const bool theIsXOR) +{ + if (myUI.Selection.Tool != AIS_ViewSelectionTool_Picking) + { + myUI.Selection.Tool = AIS_ViewSelectionTool_Picking; + myUI.Selection.Points.Clear(); + } + + myUI.Selection.IsXOR = theIsXOR; + myUI.Selection.Points.Append (thePnt); +} + +// ======================================================================= +// function : SelectInViewer +// purpose : +// ======================================================================= +void AIS_ViewController::SelectInViewer (const NCollection_Sequence& thePnts, + const bool theIsXOR) +{ + myUI.Selection.IsXOR = theIsXOR; + myUI.Selection.Points = thePnts; + myUI.Selection.ToApplyTool = true; + if (thePnts.Length() == 1) + { + myUI.Selection.Tool = AIS_ViewSelectionTool_Picking; + } + else if (thePnts.Length() == 2) + { + myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand; + } + else + { + myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon; + } +} + +// ======================================================================= +// function : UpdateRubberBand +// purpose : +// ======================================================================= +void AIS_ViewController::UpdateRubberBand (const Graphic3d_Vec2i& thePntFrom, + const Graphic3d_Vec2i& thePntTo, + const bool theIsXOR) +{ + myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand; + myUI.Selection.IsXOR = theIsXOR; + myUI.Selection.Points.Clear(); + myUI.Selection.Points.Append (thePntFrom); + myUI.Selection.Points.Append (thePntTo); +} + +// ======================================================================= +// function : UpdatePolySelection +// purpose : +// ======================================================================= +void AIS_ViewController::UpdatePolySelection (const Graphic3d_Vec2i& thePnt, + bool theToAppend) +{ + if (myUI.Selection.Tool != AIS_ViewSelectionTool_Polygon) + { + myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon; + myUI.Selection.Points.Clear(); + } + + if (myUI.Selection.Points.IsEmpty()) + { + myUI.Selection.Points.Append (thePnt); + } + else if (theToAppend + && myUI.Selection.Points.Last() != thePnt) + { + myUI.Selection.Points.Append (thePnt); + } + else + { + myUI.Selection.Points.ChangeLast() = thePnt; + } +} + +// ======================================================================= +// function : UpdateZoom +// purpose : +// ======================================================================= +bool AIS_ViewController::UpdateZoom (const Aspect_ScrollDelta& theDelta) +{ + if (!myUI.ZoomActions.IsEmpty()) + { + if (myUI.ZoomActions.ChangeLast().Point == theDelta.Point) + { + myUI.ZoomActions.ChangeLast().Delta += theDelta.Delta; + return false; + } + } + + myUI.ZoomActions.Append (theDelta); + return true; +} + +// ======================================================================= +// function : UpdateZRotation +// purpose : +// ======================================================================= +bool AIS_ViewController::UpdateZRotation (double theAngle) +{ + if (!ToAllowTouchZRotation()) + { + return false; + } + + myUI.ZRotate.Angle = myUI.ZRotate.ToRotate + ? myUI.ZRotate.Angle + theAngle + : theAngle; + if (myUI.ZRotate.ToRotate) + { + return false; + } + myUI.ZRotate.ToRotate = true; + return true; +} + +// ======================================================================= +// function : UpdateMouseScroll +// purpose : +// ======================================================================= +bool AIS_ViewController::UpdateMouseScroll (const Aspect_ScrollDelta& theDelta) +{ + Aspect_ScrollDelta aDelta = theDelta; + aDelta.Delta *= myScrollZoomRatio; + return UpdateZoom (aDelta); +} + +// ======================================================================= +// function : UpdateMouseClick +// purpose : +// ======================================================================= +bool AIS_ViewController::UpdateMouseClick (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButton, + Aspect_VKeyFlags theModifiers, + bool theIsDoubleClick) +{ + (void )theIsDoubleClick; + if (theButton == Aspect_VKeyMouse_LeftButton) + { + SelectInViewer (thePoint, (theModifiers & Aspect_VKeyFlags_SHIFT) != 0); + return true; + } + return false; +} + +// ======================================================================= +// function : UpdateMouseButtons +// purpose : +// ======================================================================= +bool AIS_ViewController::UpdateMouseButtons (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButtons, + Aspect_VKeyFlags theModifiers, + bool theIsEmulated) +{ + bool toUpdateView = false; + const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold; + if (theButtons == Aspect_VKeyMouse_NONE + && myMouseSingleButton > 0) + { + const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint; + if (double(aDelta.cwiseAbs().maxComp()) < aTolClick) + { + ++myMouseClickCounter; + const bool isDoubleClick = myMouseClickCounter == 2 + && myMouseClickTimer.IsStarted() + && myMouseClickTimer.ElapsedTime() <= myMouseDoubleClickInt; + + myMouseClickTimer.Stop(); + myMouseClickTimer.Reset(); + myMouseClickTimer.Start(); + if (isDoubleClick) + { + myMouseClickCounter = 0; + } + toUpdateView = UpdateMouseClick (thePoint, (Aspect_VKeyMouse )myMouseSingleButton, theModifiers, isDoubleClick) || toUpdateView; + } + else + { + myMouseClickTimer.Stop(); + myMouseClickCounter = 0; + myUI.Dragging.ToStop = true; + toUpdateView = true; + } + myMouseSingleButton = -1; + } + else if (theButtons == Aspect_VKeyMouse_NONE) + { + myMouseSingleButton = -1; + } + else if (myMouseSingleButton == -1) + { + if ((theButtons & Aspect_VKeyMouse_LeftButton) == Aspect_VKeyMouse_LeftButton) + { + myMouseSingleButton = Aspect_VKeyMouse_LeftButton; + } + else if ((theButtons & Aspect_VKeyMouse_RightButton) == Aspect_VKeyMouse_RightButton) + { + myMouseSingleButton = Aspect_VKeyMouse_RightButton; + } + else if ((theButtons & Aspect_VKeyMouse_MiddleButton) == Aspect_VKeyMouse_MiddleButton) + { + myMouseSingleButton = Aspect_VKeyMouse_MiddleButton; + } + else + { + myMouseSingleButton = 0; + } + if (myMouseSingleButton != 0) + { + if (myMouseClickCounter == 1) + { + const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint; + if (double(aDelta.cwiseAbs().maxComp()) >= aTolClick) + { + myMouseClickTimer.Stop(); + myMouseClickCounter = 0; + } + } + myMousePressPoint = thePoint; + } + } + else + { + myMouseSingleButton = 0; + + myUI.Dragging.ToAbort = true; + toUpdateView = true; + } + + const AIS_MouseGesture aPrevGesture = myMouseActiveGesture; + myMouseModifiers = theModifiers; + myMousePressed = theButtons; + if (theIsEmulated + || myNavigationMode != AIS_NavigationMode_FirstPersonWalk) + { + myMouseActiveIdleRotation = false; + myMouseActiveGesture = AIS_MouseGesture_NONE; + if (theButtons != 0) + { + myMousePressPoint = thePoint; + myMouseProgressPoint = myMousePressPoint; + } + + if (myMouseGestureMap.Find (theButtons | theModifiers, myMouseActiveGesture)) + { + switch (myMouseActiveGesture) + { + case AIS_MouseGesture_RotateView: + case AIS_MouseGesture_RotateOrbit: + { + if (myToAllowRotation) + { + myUpdateStartPointRot = true; + } + else + { + myMouseActiveGesture = AIS_MouseGesture_NONE; + } + break; + } + case AIS_MouseGesture_Pan: + { + if (myToAllowPanning) + { + myUpdateStartPointPan = true; + } + else + { + myMouseActiveGesture = AIS_MouseGesture_NONE; + } + break; + } + case AIS_MouseGesture_Zoom: + { + if (!myToAllowZooming) + { + myMouseActiveGesture = AIS_MouseGesture_NONE; + } + break; + } + case AIS_MouseGesture_SelectRectangle: + { + break; + } + case AIS_MouseGesture_SelectLasso: + { + UpdatePolySelection (thePoint, true); + break; + } + case AIS_MouseGesture_NONE: + { + break; + } + } + } + + if (theButtons == Aspect_VKeyMouse_LeftButton + && theModifiers == Aspect_VKeyFlags_NONE + && myToAllowDragging) + { + myUI.Dragging.ToStart = true; + myUI.Dragging.PointStart = thePoint; + } + } + + if (aPrevGesture != myMouseActiveGesture) + { + if (aPrevGesture == AIS_MouseGesture_SelectRectangle + || aPrevGesture == AIS_MouseGesture_SelectLasso) + { + myUI.Selection.ToApplyTool = true; + } + + myUI.IsNewGesture = true; + toUpdateView = true; + } + return toUpdateView; +} + +// ======================================================================= +// function : UpdateMousePosition +// purpose : +// ======================================================================= +bool AIS_ViewController::UpdateMousePosition (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButtons, + Aspect_VKeyFlags theModifiers, + bool theIsEmulated) +{ + myMousePositionLast = thePoint; + if (myMouseSingleButton > 0) + { + const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold; + const Graphic3d_Vec2i aPressDelta = thePoint - myMousePressPoint; + if (double(aPressDelta.cwiseAbs().maxComp()) >= aTolClick) + { + myMouseClickTimer.Stop(); + myMouseClickCounter = 0; + myMouseSingleButton = -1; + } + } + + bool toUpdateView = false; + Graphic3d_Vec2i aDelta = thePoint - myMouseProgressPoint; + if (!theIsEmulated + && myNavigationMode == AIS_NavigationMode_FirstPersonWalk) + { + if (!myMouseActiveIdleRotation + || myMouseActiveGesture != AIS_MouseGesture_RotateView) + { + myMouseActiveIdleRotation = true; + myMouseActiveGesture = AIS_MouseGesture_RotateView; + myMousePressPoint = thePoint; + myMouseProgressPoint = thePoint; + myUpdateStartPointRot = false; + myUI.ViewRotation.ToStart = true; + myUI.ViewRotation.PointStart.SetValues (thePoint.x(), thePoint.y()); + myUI.ViewRotation.ToRotate = false; + aDelta.SetValues (0, 0); + } + } + else + { + if (myMouseActiveIdleRotation + && myMouseActiveGesture == AIS_MouseGesture_RotateView) + { + myMouseActiveGesture = AIS_MouseGesture_NONE; + } + myMouseActiveIdleRotation = false; + } + + if (myMouseModifiers != theModifiers + && UpdateMouseButtons (thePoint, theButtons, theModifiers, theIsEmulated)) + { + toUpdateView = true; + } + + switch (myMouseActiveGesture) + { + case AIS_MouseGesture_SelectRectangle: + { + UpdateRubberBand (myMousePressPoint, thePoint); + toUpdateView = true; + break; + } + case AIS_MouseGesture_SelectLasso: + { + UpdatePolySelection (thePoint, true); + toUpdateView = true; + break; + } + case AIS_MouseGesture_RotateOrbit: + case AIS_MouseGesture_RotateView: + { + if (!myToAllowRotation) + { + break; + } + if (myUpdateStartPointRot) + { + if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit) + { + myUI.OrbitRotation.ToStart = true; + myUI.OrbitRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y()); + } + else + { + myUI.ViewRotation.ToStart = true; + myUI.ViewRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y()); + } + myUpdateStartPointRot = false; + } + + const double aRotTol = theIsEmulated + ? double(myTouchToleranceScale) * myTouchRotationThresholdPx + : 0.0; + if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aRotTol) + { + const double aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel; + const Graphic3d_Vec2i aRotDelta = thePoint - myMousePressPoint; + if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit) + { + myUI.OrbitRotation.ToRotate = true; + myUI.OrbitRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y()) + + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel; + } + else + { + myUI.ViewRotation.ToRotate = true; + myUI.ViewRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y()) + + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel; + } + myUI.Dragging.PointTo = thePoint; + + myMouseProgressPoint = thePoint; + toUpdateView = true; + } + break; + } + case AIS_MouseGesture_Zoom: + { + if (!myToAllowZooming) + { + break; + } + const double aZoomTol = theIsEmulated + ? double(myTouchToleranceScale) * myTouchZoomThresholdPx + : 0.0; + if (double (Abs (aDelta.x())) > aZoomTol) + { + if (UpdateZoom (Aspect_ScrollDelta (aDelta.x()))) + { + toUpdateView = true; + } + myMouseProgressPoint = thePoint; + } + break; + } + case AIS_MouseGesture_Pan: + { + if (!myToAllowPanning) + { + break; + } + const double aPanTol = theIsEmulated + ? double(myTouchToleranceScale) * myTouchPanThresholdPx + : 0.0; + if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aPanTol) + { + if (myUpdateStartPointPan) + { + myUI.Panning.ToStart = true; + myUI.Panning.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y()); + myUpdateStartPointPan = false; + } + + aDelta.y() = -aDelta.y(); + myMouseProgressPoint = thePoint; + if (myUI.Panning.ToPan) + { + myUI.Panning.Delta += aDelta; + } + else + { + myUI.Panning.ToPan = true; + myUI.Panning.Delta = aDelta; + } + toUpdateView = true; + } + break; + } + default: + { + break; + } + } + + if (theButtons == Aspect_VKeyMouse_NONE + && myNavigationMode != AIS_NavigationMode_FirstPersonWalk + && !theIsEmulated + && !HasTouchPoints() + && myToAllowHighlight) + { + myUI.MoveTo.ToHilight = true; + myUI.MoveTo.Point = thePoint; + toUpdateView = true; + } + return toUpdateView; +} + +// ======================================================================= +// function : AddTouchPoint +// purpose : +// ======================================================================= +void AIS_ViewController::AddTouchPoint (Standard_Size theId, + const Graphic3d_Vec2d& thePnt, + Standard_Boolean theClearBefore) +{ + myUI.MoveTo.ToHilight = false; + if (theClearBefore) + { + RemoveTouchPoint ((Standard_Size )-1); + } + + myTouchPoints.Add (theId, Aspect_Touch (thePnt, false)); + if (myTouchPoints.Extent() == 1) + { + myUpdateStartPointRot = true; + myStartRotCoord = thePnt; + if (myToAllowDragging) + { + myUI.Dragging.ToStart = true; + myUI.Dragging.PointStart.SetValues ((int )thePnt.x(), (int )thePnt.y()); + } + } + else if (myTouchPoints.Extent() == 2) + { + myUI.Dragging.ToAbort = true; + + myUpdateStartPointPan = true; + myStartPanCoord = thePnt; + } + myUI.IsNewGesture = true; +} + +// ======================================================================= +// function : RemoveTouchPoint +// purpose : +// ======================================================================= +bool AIS_ViewController::RemoveTouchPoint (Standard_Size theId, + Standard_Boolean theClearSelectPnts) +{ + if (theId == (Standard_Size )-1) + { + myTouchPoints.Clear (false); + } + else + { + const Standard_Integer anOldExtent = myTouchPoints.Extent(); + myTouchPoints.RemoveKey (theId); + if (myTouchPoints.Extent() == anOldExtent) + { + return false; + } + } + + if (myTouchPoints.Extent() == 1) + { + // avoid incorrect transition from pinch to one finger + Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1); + aFirstTouch.To = aFirstTouch.From; + + myStartRotCoord = aFirstTouch.To; + myUpdateStartPointRot = true; + } + else if (myTouchPoints.Extent() == 2) + { + myStartPanCoord = myTouchPoints.FindFromIndex (1).To; + myUpdateStartPointPan = true; + } + else if (myTouchPoints.IsEmpty()) + { + if (theClearSelectPnts) + { + myUI.Selection.ToApplyTool = true; + } + + myUI.Dragging.ToStop = true; + } + myUI.IsNewGesture = true; + return true; +} + +// ======================================================================= +// function : UpdateTouchPoint +// purpose : +// ======================================================================= +void AIS_ViewController::UpdateTouchPoint (Standard_Size theId, + const Graphic3d_Vec2d& thePnt) +{ + if (Aspect_Touch* aTouch = myTouchPoints.ChangeSeek (theId)) + { + aTouch->To = thePnt; + } + else + { + AddTouchPoint (theId, thePnt); + } +} + +// ======================================================================= +// function : SetNavigationMode +// purpose : +// ======================================================================= +void AIS_ViewController::SetNavigationMode (AIS_NavigationMode theMode) +{ + myNavigationMode = theMode; + + // abort rotation + myUI.OrbitRotation.ToStart = false; + myUI.OrbitRotation.ToRotate = false; + myUI.ViewRotation.ToStart = false; + myUI.ViewRotation.ToRotate = false; +} + +// ======================================================================= +// function : KeyDown +// purpose : +// ======================================================================= +void AIS_ViewController::KeyDown (Aspect_VKey theKey, + double theTime, + double thePressure) +{ + myKeys.KeyDown (theKey, theTime, thePressure); +} + +// ======================================================================= +// function : KeyUp +// purpose : +// ======================================================================= +void AIS_ViewController::KeyUp (Aspect_VKey theKey, + double theTime) +{ + myKeys.KeyUp (theKey, theTime); +} + +// ======================================================================= +// function : KeyFromAxis +// purpose : +// ======================================================================= +void AIS_ViewController::KeyFromAxis (Aspect_VKey theNegative, + Aspect_VKey thePositive, + double theTime, + double thePressure) +{ + myKeys.KeyFromAxis (theNegative, thePositive, theTime, thePressure); +} + +// ======================================================================= +// function : FetchNavigationKeys +// purpose : +// ======================================================================= +AIS_WalkDelta AIS_ViewController::FetchNavigationKeys (Standard_Real theCrouchRatio, + Standard_Real theRunRatio) +{ + AIS_WalkDelta aWalk; + + // navigation keys + double aPrevEventTime = 0.0, aNewEventTime = 0.0; + updateEventsTime (aPrevEventTime, aNewEventTime); + + double aDuration = 0.0, aPressure = 1.0; + if (Abs (myThrustSpeed) > gp::Resolution()) + { + if (myHasThrust) + { + aWalk[AIS_WalkTranslation_Forward].Value = myThrustSpeed * (aNewEventTime - aPrevEventTime); + } + myHasThrust = true; + myToAskNextFrame = true; + } + else + { + myHasThrust = false; + } + + aWalk.SetRunning (theRunRatio > 1.0 + && myKeys.IsKeyDown (Aspect_VKey_Shift)); + if (myKeys.HoldDuration (Aspect_VKey_NavJump, aNewEventTime, aDuration)) + { + myKeys.KeyUp (Aspect_VKey_NavJump, aNewEventTime); + aWalk.SetJumping (true); + } + if (!aWalk.IsJumping() + && theCrouchRatio < 1.0 + && myKeys.HoldDuration (Aspect_VKey_NavCrouch, aNewEventTime, aDuration)) + { + aWalk.SetRunning (false); + aWalk.SetCrouching (true); + } + + const double aMaxDuration = aNewEventTime - aPrevEventTime; + const double aRunRatio = aWalk.IsRunning() + ? theRunRatio + : aWalk.IsCrouching() + ? theCrouchRatio + : 1.0; + if (myKeys.HoldDuration (Aspect_VKey_NavForward, aNewEventTime, aDuration, aPressure)) + { + double aProgress = Abs (Min (aMaxDuration, aDuration)); + aProgress *= aRunRatio; + aWalk[AIS_WalkTranslation_Forward].Value += aProgress; + aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure; + aWalk[AIS_WalkTranslation_Forward].Duration = aDuration; + } + if (myKeys.HoldDuration (Aspect_VKey_NavBackward, aNewEventTime, aDuration, aPressure)) + { + double aProgress = Abs (Min (aMaxDuration, aDuration)); + aProgress *= aRunRatio; + aWalk[AIS_WalkTranslation_Forward].Value += -aProgress; + aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure; + aWalk[AIS_WalkTranslation_Forward].Duration = aDuration; + } + if (myKeys.HoldDuration (Aspect_VKey_NavSlideLeft, aNewEventTime, aDuration, aPressure)) + { + double aProgress = Abs (Min (aMaxDuration, aDuration)); + aProgress *= aRunRatio; + aWalk[AIS_WalkTranslation_Side].Value = -aProgress; + aWalk[AIS_WalkTranslation_Side].Pressure = aPressure; + aWalk[AIS_WalkTranslation_Side].Duration = aDuration; + } + if (myKeys.HoldDuration (Aspect_VKey_NavSlideRight, aNewEventTime, aDuration, aPressure)) + { + double aProgress = Abs (Min (aMaxDuration, aDuration)); + aProgress *= aRunRatio; + aWalk[AIS_WalkTranslation_Side].Value = aProgress; + aWalk[AIS_WalkTranslation_Side].Pressure = aPressure; + aWalk[AIS_WalkTranslation_Side].Duration = aDuration; + } + if (myKeys.HoldDuration (Aspect_VKey_NavLookLeft, aNewEventTime, aDuration, aPressure)) + { + double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure; + aWalk[AIS_WalkRotation_Yaw].Value = aProgress; + aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure; + aWalk[AIS_WalkRotation_Yaw].Duration = aDuration; + } + if (myKeys.HoldDuration (Aspect_VKey_NavLookRight, aNewEventTime, aDuration, aPressure)) + { + double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure; + aWalk[AIS_WalkRotation_Yaw].Value = -aProgress; + aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure; + aWalk[AIS_WalkRotation_Yaw].Duration = aDuration; + } + if (myKeys.HoldDuration (Aspect_VKey_NavLookUp, aNewEventTime, aDuration, aPressure)) + { + double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure; + aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? -aProgress : aProgress; + aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure; + aWalk[AIS_WalkRotation_Pitch].Duration = aDuration; + } + if (myKeys.HoldDuration (Aspect_VKey_NavLookDown, aNewEventTime, aDuration, aPressure)) + { + double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure; + aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? aProgress : -aProgress; + aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure; + aWalk[AIS_WalkRotation_Pitch].Duration = aDuration; + } + if (myKeys.HoldDuration (Aspect_VKey_NavRollCCW, aNewEventTime, aDuration, aPressure)) + { + double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure; + aWalk[AIS_WalkRotation_Roll].Value = -aProgress; + aWalk[AIS_WalkRotation_Roll].Pressure = aPressure; + aWalk[AIS_WalkRotation_Roll].Duration = aDuration; + } + if (myKeys.HoldDuration (Aspect_VKey_NavRollCW, aNewEventTime, aDuration, aPressure)) + { + double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure; + aWalk[AIS_WalkRotation_Roll].Value = aProgress; + aWalk[AIS_WalkRotation_Roll].Pressure = aPressure; + aWalk[AIS_WalkRotation_Roll].Duration = aDuration; + } + if (myKeys.HoldDuration (Aspect_VKey_NavSlideUp, aNewEventTime, aDuration, aPressure)) + { + double aProgress = Abs (Min (aMaxDuration, aDuration)); + aWalk[AIS_WalkTranslation_Up].Value = aProgress; + aWalk[AIS_WalkTranslation_Up].Pressure = aPressure; + aWalk[AIS_WalkTranslation_Up].Duration = aDuration; + } + if (myKeys.HoldDuration (Aspect_VKey_NavSlideDown, aNewEventTime, aDuration, aPressure)) + { + double aProgress = Abs (Min (aMaxDuration, aDuration)); + aWalk[AIS_WalkTranslation_Up].Value = -aProgress; + aWalk[AIS_WalkTranslation_Up].Pressure = aPressure; + aWalk[AIS_WalkTranslation_Up].Duration = aDuration; + } + return aWalk; +} + +// ======================================================================= +// function : handlePanning +// purpose : +// ======================================================================= +void AIS_ViewController::handlePanning (const Handle(V3d_View)& theView) +{ + if (!myGL.Panning.ToPan + || !myToAllowPanning) + { + return; + } + + const Handle(Graphic3d_Camera)& aCam = theView->Camera(); + if (aCam->IsOrthographic() + || !hasPanningAnchorPoint()) + { + theView->Pan (myGL.Panning.Delta.x(), myGL.Panning.Delta.y()); + theView->Invalidate(); + return; + } + + Graphic3d_Vec2i aWinSize; + theView->Window()->Size (aWinSize.x(), aWinSize.y()); + + const gp_Dir& aDir = aCam->Direction(); + const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up()); + const gp_XYZ anEyeToPnt = myPanPnt3d.XYZ() - aCam->Eye().XYZ(); + const gp_Pnt aViewDims = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ())); // view dimensions at 3D point + const Graphic3d_Vec2d aDxy (-aViewDims.X() * myGL.Panning.Delta.x() / double(aWinSize.x()), + -aViewDims.X() * myGL.Panning.Delta.y() / double(aWinSize.x())); + + //theView->Translate (aCam, aDxy.x(), aDxy.y()); + gp_Trsf aPanTrsf; + const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x() + + gp_Vec (aCameraCS.YDirection()) * aDxy.y(); + aPanTrsf.SetTranslation (aCameraPan); + aCam->Transform (aPanTrsf); + theView->Invalidate(); +} + +// ======================================================================= +// function : handleZRotate +// purpose : +// ======================================================================= +void AIS_ViewController::handleZRotate (const Handle(V3d_View)& theView) +{ + if (!myGL.ZRotate.ToRotate + || !myToAllowRotation) + { + return; + } + + Graphic3d_Vec2i aViewPort; + theView->Window()->Size (aViewPort.x(), aViewPort.y()); + Graphic3d_Vec2d aRotPnt (0.99 * aViewPort.x(), + 0.5 * aViewPort.y()); + theView->StartRotation (int(aRotPnt.x()), int(aRotPnt.y()), 0.4); + aRotPnt.y() += myGL.ZRotate.Angle * aViewPort.y(); + theView->Rotation (int(aRotPnt.x()), int(aRotPnt.y())); + theView->Invalidate(); +} + +// ======================================================================= +// function : handleZoom +// purpose : +// ======================================================================= +void AIS_ViewController::handleZoom (const Handle(V3d_View)& theView, + const Aspect_ScrollDelta& theParams, + const gp_Pnt* thePnt) +{ + if (!myToAllowZooming) + { + return; + } + + const Handle(Graphic3d_Camera)& aCam = theView->Camera(); + if (thePnt != NULL) + { + const double aViewDist = Max (myMinCamDistance, (thePnt->XYZ() - aCam->Eye().XYZ()).Modulus()); + aCam->SetCenter (aCam->Eye().XYZ() + aCam->Direction().XYZ() * aViewDist); + } + + if (!theParams.HasPoint()) + { + Standard_Real aCoeff = Abs(theParams.Delta) / 100.0 + 1.0; + aCoeff = theParams.Delta > 0.0 ? aCoeff : 1.0 / aCoeff; + theView->SetZoom (aCoeff, true); + theView->Invalidate(); + return; + } + + // integer delta is too rough for small smooth increments + //theView->StartZoomAtPoint (theParams.Point.x(), theParams.Point.y()); + //theView->ZoomAtPoint (0, 0, (int )theParams.Delta, (int )theParams.Delta); + + double aDZoom = Abs (theParams.Delta) / 100.0 + 1.0; + aDZoom = (theParams.Delta > 0.0) ? aDZoom : 1.0 / aDZoom; + if (aDZoom <= 0.0) + { + return; + } + + const Graphic3d_Vec2d aViewDims (aCam->ViewDimensions().X(), aCam->ViewDimensions().Y()); + + // ensure that zoom will not be too small or too big + double aCoef = aDZoom; + if (aViewDims.x() < aCoef * Precision::Confusion()) + { + aCoef = aViewDims.x() / Precision::Confusion(); + } + else if (aViewDims.x() > aCoef * 1e12) + { + aCoef = aViewDims.x() / 1e12; + } + if (aViewDims.y() < aCoef * Precision::Confusion()) + { + aCoef = aViewDims.y() / Precision::Confusion(); + } + else if (aViewDims.y() > aCoef * 1e12) + { + aCoef = aViewDims.y() / 1e12; + } + + Graphic3d_Vec2d aZoomAtPointXYv (0.0, 0.0); + theView->Convert (theParams.Point.x(), theParams.Point.y(), + aZoomAtPointXYv.x(), aZoomAtPointXYv.y()); + Graphic3d_Vec2d aDxy = aZoomAtPointXYv / aCoef; + aCam->SetScale (aCam->Scale() / aCoef); + + const gp_Dir& aDir = aCam->Direction(); + const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up()); + + // pan back to the point + aDxy = aZoomAtPointXYv - aDxy; + if (thePnt != NULL) + { + // zoom at 3D point with perspective projection + const gp_XYZ anEyeToPnt = thePnt->XYZ() - aCam->Eye().XYZ(); + aDxy.SetValues (anEyeToPnt.Dot (aCameraCS.XDirection().XYZ()), + anEyeToPnt.Dot (aCameraCS.YDirection().XYZ())); + + // view dimensions at 3D point + const gp_Pnt aViewDims1 = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ())); + + Graphic3d_Vec2i aWinSize; + theView->Window()->Size (aWinSize.x(), aWinSize.y()); + const Graphic3d_Vec2d aPanFromCenterPx (double(theParams.Point.x()) - 0.5 * double(aWinSize.x()), + double(theParams.Point.y()) - 0.5 * double(aWinSize.y())); + aDxy.x() += -aViewDims1.X() * aPanFromCenterPx.x() / double(aWinSize.x()); + aDxy.y() += aViewDims1.X() * aPanFromCenterPx.y() / double(aWinSize.x()); + } + + //theView->Translate (aCam, aDxy.x(), aDxy.y()); + gp_Trsf aPanTrsf; + const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x() + + gp_Vec (aCameraCS.YDirection()) * aDxy.y(); + aPanTrsf.SetTranslation (aCameraPan); + aCam->Transform (aPanTrsf); + theView->Invalidate(); +} + +// ======================================================================= +// function : handleZFocusScroll +// purpose : +// ======================================================================= +void AIS_ViewController::handleZFocusScroll (const Handle(V3d_View)& theView, + const Aspect_ScrollDelta& theParams) +{ + if (!myToAllowZFocus + || !theView->Camera()->IsStereo()) + { + return; + } + + Standard_Real aFocus = theView->Camera()->ZFocus() + (theParams.Delta > 0.0 ? 0.05 : -0.05); + if (aFocus > 0.2 + && aFocus < 2.0) + { + theView->Camera()->SetZFocus (theView->Camera()->ZFocusType(), aFocus); + theView->Redraw(); + } +} + +// ======================================================================= +// function : handleOrbitRotation +// purpose : +// ======================================================================= +void AIS_ViewController::handleOrbitRotation (const Handle(V3d_View)& theView, + const gp_Pnt& thePnt, + bool theToLockZUp) +{ + if (!myToAllowRotation) + { + return; + } + + const Handle(Graphic3d_Camera)& aCam = theView->Camera(); + if (myGL.OrbitRotation.ToStart) + { + // default alternatives + //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->StartRotation (myGL.RotateAtPoint.x(), myGL.RotateAtPoint.y()); + //theView->Rotate (0.0, 0.0, 0.0, thePnt.X(), thePnt.Y(), thePnt.Z(), true); + + myRotatePnt3d = thePnt; + myCamStartOpUp = aCam->Up(); + myCamStartOpEye = aCam->Eye(); + myCamStartOpCenter = aCam->Center(); + + gp_Trsf aTrsf; + aTrsf.SetTransformation (gp_Ax3 (myRotatePnt3d, aCam->OrthogonalizedUp(), aCam->Direction()), + gp_Ax3 (myRotatePnt3d, gp::DZ(), gp::DX())); + const gp_Quaternion aRot = aTrsf.GetRotation(); + aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], myRotateStartYawPitchRoll[2]); + + aTrsf.Invert(); + myCamStartOpToEye = gp_Vec (myRotatePnt3d, aCam->Eye()).Transformed (aTrsf); + myCamStartOpToCenter = gp_Vec (myRotatePnt3d, aCam->Center()).Transformed (aTrsf); + + theView->Invalidate(); + } + + if (!myGL.OrbitRotation.ToRotate) + { + return; + } + + if (theToLockZUp) + { + // amend camera to exclude roll angle (put camera Up vector to plane containing global Z and view direction) + Graphic3d_Vec2i aWinXY; + theView->Window()->Size (aWinXY.x(), aWinXY.y()); + double aYawAngleDelta = ((myGL.OrbitRotation.PointStart.x() - myGL.OrbitRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5); + double aPitchAngleDelta = -((myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5); + const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0); + const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta; + const double aRoll = 0.0; + + gp_Quaternion aRot; + aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, aRoll); + gp_Trsf aTrsfRot; + aTrsfRot.SetRotation (aRot); + + const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot); + aCam->SetUp (aNewUp); + aCam->SetCenter(myRotatePnt3d.XYZ() + myCamStartOpToCenter.Transformed (aTrsfRot).XYZ()); + aCam->SetEye (myRotatePnt3d.XYZ() + myCamStartOpToEye .Transformed (aTrsfRot).XYZ()); + aCam->OrthogonalizeUp(); + } + else + { + // default alternatives + //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->Rotation (myGL.RotateToPoint.x(), myGL.RotateToPoint.y()); + //theView->Rotate (aDX, aDY, aDZ, myRotatePnt3d.X(), myRotatePnt3d.Y(), myRotatePnt3d.Z(), false); + + // restore previous camera state + aCam->SetUp (myCamStartOpUp); + aCam->SetEye (myCamStartOpEye); + aCam->SetCenter (myCamStartOpCenter); + + Graphic3d_Vec2d aWinXY; + theView->Size (aWinXY.x(), aWinXY.y()); + const Standard_Real rx = (Standard_Real )theView->Convert (aWinXY.x()); + const Standard_Real ry = (Standard_Real )theView->Convert (aWinXY.y()); + + const double THE_2PI = M_PI * 2.0; + double aDX = (myGL.OrbitRotation.PointTo.x() - myGL.OrbitRotation.PointStart.x()) * M_PI / rx; + double aDY = (myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) * M_PI / ry; + + if (aDX > 0.0) { while (aDX > THE_2PI) { aDX -= THE_2PI; } } + else if(aDX < 0.0) { while (aDX < -THE_2PI) { aDX += THE_2PI; } } + if (aDY > 0.0) { while (aDY > THE_2PI) { aDY -= THE_2PI; } } + else if(aDY < 0.0) { while (aDY < -THE_2PI) { aDY += THE_2PI; } } + + // rotate camera around 3 initial axes + gp_Dir aCamDir (aCam->Direction().Reversed()); + gp_Dir aCamUp (aCam->Up()); + gp_Dir aCamSide(aCamUp.Crossed (aCamDir)); + + gp_Trsf aRot[2], aTrsf; + aRot[0].SetRotation (gp_Ax1 (myRotatePnt3d, aCamUp), -aDX); + aRot[1].SetRotation (gp_Ax1 (myRotatePnt3d, aCamSide), aDY); + aTrsf.Multiply (aRot[0]); + aTrsf.Multiply (aRot[1]); + + aCam->Transform (aTrsf); + } + + theView->Invalidate(); +} + +// ======================================================================= +// function : handleViewRotation +// purpose : +// ======================================================================= +void AIS_ViewController::handleViewRotation (const Handle(V3d_View)& theView, + double theYawExtra, + double thePitchExtra, + double theRoll, + bool theToRestartOnIncrement) +{ + if (!myToAllowRotation) + { + return; + } + + const Handle(Graphic3d_Camera)& aCam = theView->Camera(); + const bool toRotateAnyway = Abs (theYawExtra) > gp::Resolution() + || Abs (thePitchExtra) > gp::Resolution() + || Abs (theRoll - myRotateStartYawPitchRoll[2]) > gp::Resolution(); + if (toRotateAnyway + && theToRestartOnIncrement) + { + myGL.ViewRotation.ToStart = true; + myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart; + } + if (myGL.ViewRotation.ToStart) + { + gp_Trsf aTrsf; + aTrsf.SetTransformation (gp_Ax3 (gp::Origin(), aCam->OrthogonalizedUp(), aCam->Direction()), + gp_Ax3 (gp::Origin(), gp::DZ(), gp::DX())); + const gp_Quaternion aRot = aTrsf.GetRotation(); + double aRollDummy = 0.0; + aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], aRollDummy); + } + if (toRotateAnyway) + { + myRotateStartYawPitchRoll[0] += theYawExtra; + myRotateStartYawPitchRoll[1] += thePitchExtra; + myRotateStartYawPitchRoll[2] = theRoll; + myGL.ViewRotation.ToRotate = true; + } + + if (!myGL.ViewRotation.ToRotate) + { + return; + } + + Graphic3d_Vec2i aWinXY; + theView->Window()->Size (aWinXY.x(), aWinXY.y()); + double aYawAngleDelta = ((myGL.ViewRotation.PointStart.x() - myGL.ViewRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5); + double aPitchAngleDelta = -((myGL.ViewRotation.PointStart.y() - myGL.ViewRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5); + const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0); + const double aYawAngleNew = myRotateStartYawPitchRoll[0] + aYawAngleDelta; + gp_Quaternion aRot; + aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, theRoll); + gp_Trsf aTrsfRot; + aTrsfRot.SetRotation (aRot); + + const double aDist = aCam->Distance(); + const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot); + const gp_Dir aNewDir = gp::DX().Transformed (aTrsfRot); + aCam->SetUp (aNewUp); + aCam->SetCenter (aCam->Eye().Translated (gp_Vec (aNewDir) * aDist)); + aCam->OrthogonalizeUp(); + theView->Invalidate(); +} + +// ======================================================================= +// function : PickPoint +// purpose : +// ======================================================================= +bool AIS_ViewController::PickPoint (gp_Pnt& thePnt, + const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView, + const Graphic3d_Vec2i& theCursor, + bool theToStickToPickRay) +{ + ResetPreviousMoveTo(); + + const Handle(StdSelect_ViewerSelector3d)& aSelector = theCtx->MainSelector(); + aSelector->Pick (theCursor.x(), theCursor.y(), theView); + if (aSelector->NbPicked() < 1) + { + return false; + } + + const SelectMgr_SortCriterion& aPicked = aSelector->PickedData (1); + if (theToStickToPickRay + && !Precision::IsInfinite (aPicked.Depth)) + { + thePnt = aSelector->GetManager().DetectedPoint (aPicked.Depth); + } + else + { + thePnt = aSelector->PickedPoint (1); + } + return !Precision::IsInfinite (thePnt.X()) + && !Precision::IsInfinite (thePnt.Y()) + && !Precision::IsInfinite (thePnt.Z()); +} + +// ======================================================================= +// function : GravityPoint +// purpose : +// ======================================================================= +gp_Pnt AIS_ViewController::GravityPoint (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView) +{ + switch (myRotationMode) + { + case AIS_RotationMode_PickLast: + case AIS_RotationMode_PickCenter: + { + Graphic3d_Vec2i aCursor ((int )myGL.OrbitRotation.PointStart.x(), (int )myGL.OrbitRotation.PointStart.y()); + if (myRotationMode == AIS_RotationMode_PickCenter) + { + Graphic3d_Vec2i aViewPort; + theView->Window()->Size (aViewPort.x(), aViewPort.y()); + aCursor = aViewPort / 2; + } + + gp_Pnt aPnt; + if (PickPoint (aPnt, theCtx, theView, aCursor, false)) + { + return aPnt; + } + break; + } + case AIS_RotationMode_CameraAt: + { + const Handle(Graphic3d_Camera)& aCam = theView->Camera(); + return aCam->Center(); + } + case AIS_RotationMode_BndBoxScene: + { + Bnd_Box aBndBox = theView->View()->MinMaxValues (false); + if (!aBndBox.IsVoid()) + { + return (aBndBox.CornerMin().XYZ() + aBndBox.CornerMax().XYZ()) * 0.5; + } + break; + } + case AIS_RotationMode_BndBoxActive: + break; + } + + return theCtx ->GravityPoint (theView); +} + +// ======================================================================= +// function : handleCameraActions +// purpose : +// ======================================================================= +void AIS_ViewController::handleCameraActions (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView, + const AIS_WalkDelta& theWalk) +{ + // apply view actions + if (myGL.Orientation.ToSetViewOrient) + { + theView->SetProj (myGL.Orientation.ViewOrient); + myGL.Orientation.ToFitAll = true; + } + + // apply fit all + if (myGL.Orientation.ToFitAll) + { + const double aFitMargin = 0.01; + theView->FitAll (aFitMargin, false); + theView->Invalidate(); + myGL.Orientation.ToFitAll = false; + } + + if (myGL.IsNewGesture) + { + if (myAnchorPointPrs1->HasInteractiveContext()) + { + theCtx->Remove (myAnchorPointPrs1, false); + if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs1->ZLayer()).IsImmediate()) + { + theView->Invalidate(); + } + else + { + theView->InvalidateImmediate(); + } + } + if (myAnchorPointPrs2->HasInteractiveContext()) + { + theCtx->Remove (myAnchorPointPrs2, false); + if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs2->ZLayer()).IsImmediate()) + { + theView->Invalidate(); + } + else + { + theView->InvalidateImmediate(); + } + } + + if (myHasHlrOnBeforeRotation) + { + myHasHlrOnBeforeRotation = false; + theView->SetComputedMode (true); + theView->Invalidate(); + } + } + + if (myNavigationMode != AIS_NavigationMode_FirstPersonWalk) + { + if (myGL.Panning.ToStart + && myToAllowPanning) + { + gp_Pnt aPanPnt (Precision::Infinite(), 0.0, 0.0); + if (!theView->Camera()->IsOrthographic()) + { + bool toStickToRay = false; + if (myGL.Panning.PointStart.x() >= 0 + && myGL.Panning.PointStart.y() >= 0) + { + PickPoint (aPanPnt, theCtx, theView, myGL.Panning.PointStart, toStickToRay); + } + if (Precision::IsInfinite (aPanPnt.X())) + { + Graphic3d_Vec2i aWinSize; + theView->Window()->Size (aWinSize.x(), aWinSize.y()); + PickPoint (aPanPnt, theCtx, theView, aWinSize / 2, toStickToRay); + } + if (!Precision::IsInfinite (aPanPnt.X()) + && myToShowPanAnchorPoint) + { + gp_Trsf aPntTrsf; + aPntTrsf.SetTranslation (gp_Vec (aPanPnt.XYZ())); + theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf); + } + } + setPanningAnchorPoint (aPanPnt); + } + + if (myToShowPanAnchorPoint + && hasPanningAnchorPoint() + && myGL.Panning.ToPan + && !myGL.IsNewGesture + && !myAnchorPointPrs2->HasInteractiveContext()) + { + theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed); + } + + handlePanning (theView); + handleZRotate (theView); + } + + if ((myNavigationMode == AIS_NavigationMode_Orbit + || myGL.OrbitRotation.ToStart + || myGL.OrbitRotation.ToRotate) + && myToAllowRotation) + { + if (myGL.OrbitRotation.ToStart + && !myHasHlrOnBeforeRotation) + { + myHasHlrOnBeforeRotation = theView->ComputedMode(); + if (myHasHlrOnBeforeRotation) + { + theView->SetComputedMode (false); + } + } + + gp_Pnt aGravPnt; + if (myGL.OrbitRotation.ToStart) + { + aGravPnt = GravityPoint (theCtx, theView); + if (myToShowRotateCenter) + { + gp_Trsf aPntTrsf; + aPntTrsf.SetTranslation (gp_Vec (aGravPnt.XYZ())); + theCtx->SetLocation (myAnchorPointPrs1, aPntTrsf); + theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf); + } + } + + if (myToShowRotateCenter + && myGL.OrbitRotation.ToRotate + && !myGL.IsNewGesture + && !myAnchorPointPrs1->HasInteractiveContext()) + { + theCtx->Display (myAnchorPointPrs1, 0, -1, false, AIS_DS_Displayed); + theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed); + } + handleOrbitRotation (theView, aGravPnt, + myToLockOrbitZUp || myNavigationMode != AIS_NavigationMode_Orbit); + } + + if ((myNavigationMode != AIS_NavigationMode_Orbit + || myGL.ViewRotation.ToStart + || myGL.ViewRotation.ToRotate) + && myToAllowRotation) + { + if (myGL.ViewRotation.ToStart + && !myHasHlrOnBeforeRotation) + { + myHasHlrOnBeforeRotation = theView->ComputedMode(); + if (myHasHlrOnBeforeRotation) + { + theView->SetComputedMode (false); + } + } + + double aRoll = 0.0; + if (!theWalk[AIS_WalkRotation_Roll].IsEmpty() + && !myToLockOrbitZUp) + { + aRoll = (M_PI / 12.0) * theWalk[AIS_WalkRotation_Roll].Pressure; + aRoll *= Min (1000.0 * theWalk[AIS_WalkRotation_Roll].Duration, 100.0) / 100.0; + if (theWalk[AIS_WalkRotation_Roll].Value < 0.0) + { + aRoll = -aRoll; + } + } + + handleViewRotation (theView, theWalk[AIS_WalkRotation_Yaw].Value, theWalk[AIS_WalkRotation_Pitch].Value, aRoll, + myNavigationMode == AIS_NavigationMode_FirstPersonFlight); + } + + if (!myGL.ZoomActions.IsEmpty()) + { + for (NCollection_Sequence::Iterator aZoomIter (myGL.ZoomActions); aZoomIter.More(); aZoomIter.Next()) + { + Aspect_ScrollDelta aZoomParams = aZoomIter.Value(); + if (myToAllowZFocus + && (aZoomParams.Flags & Aspect_VKeyFlags_CTRL) != 0 + && theView->Camera()->IsStereo()) + { + handleZFocusScroll (theView, aZoomParams); + continue; + } + + if (!myToAllowZooming) + { + continue; + } + + if (!theView->Camera()->IsOrthographic()) + { + // what is more natural to user - point on ray or point exactly on geometry in corner cases? + const bool toStickToRay = false; // true; + + gp_Pnt aPnt; + if (aZoomParams.HasPoint() + && PickPoint (aPnt, theCtx, theView, aZoomParams.Point, toStickToRay)) + { + handleZoom (theView, aZoomParams, &aPnt); + continue; + } + + Graphic3d_Vec2i aWinSize; + theView->Window()->Size (aWinSize.x(), aWinSize.y()); + if (PickPoint (aPnt, theCtx, theView, aWinSize / 2, toStickToRay)) + { + aZoomParams.ResetPoint(); // do not pretend to zoom at 'nothing' + handleZoom (theView, aZoomParams, &aPnt); + continue; + } + } + handleZoom (theView, aZoomParams, NULL); + } + myGL.ZoomActions.Clear(); + } +} + +// ======================================================================= +// function : OnSelectionChanged +// purpose : +// ======================================================================= +void AIS_ViewController::OnSelectionChanged (const Handle(AIS_InteractiveContext)& , + const Handle(V3d_View)& ) +{ + // +} + +// ======================================================================= +// function : OnObjectDragged +// purpose : +// ======================================================================= +void AIS_ViewController::OnObjectDragged (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView, + AIS_DragAction theAction) +{ + switch (theAction) + { + case AIS_DragAction_Start: + { + myDragObject.Nullify(); + if (!theCtx->HasDetected()) + { + return; + } + + Handle(AIS_InteractiveObject) aPrs = theCtx->DetectedInteractive(); + if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (aPrs)) + { + if (aManip->HasActiveMode()) + { + myDragObject = aManip; + aManip->StartTransform (myGL.Dragging.PointStart.x(), myGL.Dragging.PointStart.y(), theView); + } + } + return; + } + case AIS_DragAction_Update: + { + if (myDragObject.IsNull()) + { + return; + } + + if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner()) + { + theCtx->SetSelectedState (aGlobOwner, true); + } + if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (myDragObject)) + { + aManip->Transform (myGL.Dragging.PointTo.x(), myGL.Dragging.PointTo.y(), theView); + } + theView->Invalidate(); + return; + } + case AIS_DragAction_Abort: + { + if (myDragObject.IsNull()) + { + return; + } + + myGL.Dragging.PointTo = myGL.Dragging.PointStart; + OnObjectDragged (theCtx, theView, AIS_DragAction_Update); + + if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (myDragObject)) + { + aManip->StopTransform (false); + } + Standard_FALLTHROUGH + } + case AIS_DragAction_Stop: + { + if (myDragObject.IsNull()) + { + return; + } + + if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner()) + { + theCtx->SetSelectedState (aGlobOwner, false); + } + + theView->Invalidate(); + myDragObject.Nullify(); + return; + } + } +} + +// ======================================================================= +// function : contextLazyMoveTo +// purpose : +// ======================================================================= +void AIS_ViewController::contextLazyMoveTo (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView, + const Graphic3d_Vec2i& thePnt) +{ + if (myPrevMoveTo == thePnt) + { + return; + } + + myPrevMoveTo = thePnt; + + Handle(SelectMgr_EntityOwner) aLastPicked = theCtx->DetectedOwner(); + theCtx->MoveTo (thePnt.x(), thePnt.y(), theView, false); + Handle(SelectMgr_EntityOwner) aNewPicked = theCtx->DetectedOwner(); + + if (theView->Viewer()->Grid()->IsActive() + && theView->Viewer()->GridEcho()) + { + if (aNewPicked.IsNull()) + { + Graphic3d_Vec3d aPnt3d; + theView->ConvertToGrid (thePnt.x(), thePnt.y(), aPnt3d[0], aPnt3d[1], aPnt3d[2]); + theView->Viewer()->ShowGridEcho (theView, Graphic3d_Vertex (aPnt3d[0], aPnt3d[1], aPnt3d[2])); + theView->InvalidateImmediate(); + } + else + { + theView->Viewer()->HideGridEcho (theView); + theView->InvalidateImmediate(); + } + } + + if (aLastPicked != aNewPicked + || (!aNewPicked.IsNull() && aNewPicked->IsForcedHilight())) + { + // dynamic highlight affects all Views + for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next()) + { + const Handle(V3d_View)& aView = aViewIter.Value(); + aView->InvalidateImmediate(); + } + } +} + +// ======================================================================= +// function : handleSelectionPick +// purpose : +// ======================================================================= +void AIS_ViewController::handleSelectionPick (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView) +{ + if (myGL.Selection.Tool == AIS_ViewSelectionTool_Picking + && !myGL.Selection.Points.IsEmpty()) + { + for (NCollection_Sequence::Iterator aPntIter (myGL.Selection.Points); aPntIter.More(); aPntIter.Next()) + { + if (!myGL.Selection.IsXOR) + { + theCtx->ClearSelected (false); + } + + const bool hadPrevMoveTo = HasPreviousMoveTo(); + contextLazyMoveTo (theCtx, theView, aPntIter.Value()); + if (!hadPrevMoveTo) + { + ResetPreviousMoveTo(); + } + + if (myGL.Selection.IsXOR) + { + theCtx->ShiftSelect (false); + } + else + { + theCtx->Select (false); + } + + // selection affects all Views + theView->Viewer()->Invalidate(); + + OnSelectionChanged (theCtx, theView); + } + + myGL.Selection.Points.Clear(); + } +} + +// ======================================================================= +// function : handleSelectionPoly +// purpose : +// ======================================================================= +void AIS_ViewController::handleSelectionPoly (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView) +{ + // rubber-band & window polygon selection + if (myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand + || myGL.Selection.Tool == AIS_ViewSelectionTool_Polygon) + { + if (!myGL.Selection.Points.IsEmpty()) + { + myRubberBand->ClearPoints(); + myRubberBand->SetToUpdate(); + + const bool anIsRubber = myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand; + if (anIsRubber) + { + myRubberBand->SetRectangle (myGL.Selection.Points.First().x(), -myGL.Selection.Points.First().y(), + myGL.Selection.Points.Last().x(), -myGL.Selection.Points.Last().y()); + } + else + { + Graphic3d_Vec2i aPrev (IntegerLast(), IntegerLast()); + for (NCollection_Sequence::Iterator aSelIter (myGL.Selection.Points); aSelIter.More(); aSelIter.Next()) + { + Graphic3d_Vec2i aPntNew = Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y()); + if (aPntNew != aPrev) + { + aPrev = aPntNew; + myRubberBand->AddPoint (Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y())); + } + } + } + + myRubberBand->SetPolygonClosed (anIsRubber); + try + { + theCtx->Display (myRubberBand, 0, -1, false, AIS_DS_Displayed); + } + catch (const Standard_Failure& theEx) + { + Message::DefaultMessenger()->Send (TCollection_AsciiString ("Internal error while displaying rubber-band: ") + + theEx.DynamicType()->Name() + ", " + theEx.GetMessageString(), Message_Warning); + myRubberBand->ClearPoints(); + } + if (!theView->Viewer()->ZLayerSettings (myRubberBand->ZLayer()).IsImmediate()) + { + theView->Invalidate(); + } + else + { + theView->InvalidateImmediate(); + } + } + else if (!myRubberBand.IsNull() + && myRubberBand->HasInteractiveContext()) + { + theCtx->Remove (myRubberBand, false); + myRubberBand->ClearPoints(); + } + } + + if (myGL.Selection.ToApplyTool) + { + myGL.Selection.ToApplyTool = false; + if (theCtx->IsDisplayed (myRubberBand)) + { + theCtx->Remove (myRubberBand, false); + { + const NCollection_Sequence& aPoints = myRubberBand->Points(); + if (aPoints.Size() == 4 + && aPoints.Value (1).x() == aPoints.Value (2).x() + && aPoints.Value (3).x() == aPoints.Value (4).x() + && aPoints.Value (1).y() == aPoints.Value (4).y() + && aPoints.Value (2).y() == aPoints.Value (3).y()) + { + const Graphic3d_Vec2i aPnt1 (aPoints.Value (1).x(), -aPoints.Value (1).y()); + const Graphic3d_Vec2i aPnt2 (aPoints.Value (3).x(), -aPoints.Value (3).y()); + theCtx->MainSelector()->AllowOverlapDetection (aPnt1.y() != Min (aPnt1.y(), aPnt2.y())); + if (myGL.Selection.IsXOR) + { + theCtx->ShiftSelect (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y()), + Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y()), + theView, false); + } + else + { + theCtx->Select (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y()), + Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y()), + theView, false); + } + theCtx->MainSelector()->AllowOverlapDetection (false); + } + else if (aPoints.Length() >= 3) + { + TColgp_Array1OfPnt2d aPolyline (1, aPoints.Length()); + TColgp_Array1OfPnt2d::Iterator aPolyIter (aPolyline); + for (NCollection_Sequence::Iterator aSelIter (aPoints); + aSelIter.More(); aSelIter.Next(), aPolyIter.Next()) + { + const Graphic3d_Vec2i& aNewPnt = aSelIter.Value(); + aPolyIter.ChangeValue() = gp_Pnt2d (aNewPnt.x(), -aNewPnt.y()); + } + + theCtx->MainSelector()->AllowOverlapDetection (false); + if (myGL.Selection.IsXOR) + { + theCtx->ShiftSelect (aPolyline, theView, false); + } + else + { + theCtx->Select (aPolyline, theView, false); + } + } + } + + // selection affects all Views + theView->Viewer()->Invalidate(); + + myRubberBand->ClearPoints(); + OnSelectionChanged (theCtx, theView); + } + } +} + +// ======================================================================= +// function : handleDynamicHighlight +// purpose : +// ======================================================================= +void AIS_ViewController::handleDynamicHighlight (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView) +{ + if ((myGL.MoveTo.ToHilight || myGL.Dragging.ToStart) + && myNavigationMode != AIS_NavigationMode_FirstPersonWalk) + { + const Graphic3d_Vec2i& aMoveToPnt = myGL.MoveTo.ToHilight ? myGL.MoveTo.Point : myGL.Dragging.PointStart; + if (myGL.Dragging.ToStart && (!myGL.MoveTo.ToHilight || !myToAllowHighlight) + && !HasPreviousMoveTo()) + { + contextLazyMoveTo (theCtx, theView, aMoveToPnt); + ResetPreviousMoveTo(); + OnObjectDragged (theCtx, theView, AIS_DragAction_Start); + theCtx->ClearDetected(); + } + else if (myToAllowHighlight) + { + if (myPrevMoveTo != aMoveToPnt + || myGL.OrbitRotation.ToRotate + || myGL.ViewRotation.ToRotate + || theView->IsInvalidated()) + { + ResetPreviousMoveTo(); + contextLazyMoveTo (theCtx, theView, aMoveToPnt); + } + if (myGL.Dragging.ToStart) + { + OnObjectDragged (theCtx, theView, AIS_DragAction_Start); + } + } + + myGL.MoveTo.ToHilight = false; + } + + if (!myDragObject.IsNull()) + { + if (myGL.Dragging.ToAbort) + { + OnObjectDragged (theCtx, theView, AIS_DragAction_Abort); + myGL.OrbitRotation.ToRotate = false; + myGL.ViewRotation .ToRotate = false; + } + else if (myGL.Dragging.ToStop) + { + OnObjectDragged (theCtx, theView, AIS_DragAction_Stop); + myGL.OrbitRotation.ToRotate = false; + myGL.ViewRotation .ToRotate = false; + } + else if (myGL.OrbitRotation.ToRotate + || myGL.ViewRotation.ToRotate) + { + OnObjectDragged (theCtx, theView, AIS_DragAction_Update); + myGL.OrbitRotation.ToRotate = false; + myGL.ViewRotation .ToRotate = false; + } + } +} + +// ======================================================================= +// function : handleMoveTo +// purpose : +// ======================================================================= +void AIS_ViewController::handleMoveTo (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView) +{ + handleSelectionPick (theCtx, theView); + handleDynamicHighlight(theCtx, theView); + handleSelectionPoly (theCtx, theView); +} + +// ======================================================================= +// function : handleViewRedraw +// purpose : +// ======================================================================= +void AIS_ViewController::handleViewRedraw (const Handle(AIS_InteractiveContext)& , + const Handle(V3d_View)& theView) +{ + for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next()) + { + const Handle(V3d_View)& aView = aViewIter.Value(); + if (aView->IsInvalidated() + || myToAskNextFrame) + { + if (aView->ComputedMode()) + { + aView->Update(); + } + else + { + aView->Redraw(); + } + } + else if (aView->IsInvalidatedImmediate()) + { + aView->RedrawImmediate(); + } + } + + if (myToAskNextFrame) + { + // ask more frames + theView->Window()->InvalidateContent (Handle(Aspect_DisplayConnection)()); + } +} + +// ======================================================================= +// function : HandleViewEvents +// purpose : +// ======================================================================= +void AIS_ViewController::HandleViewEvents (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView) +{ + handleMoveTo (theCtx, theView); + + const AIS_WalkDelta aWalk = FetchNavigationKeys (1.0, 1.0); + handleCameraActions (theCtx, theView, aWalk); + handleViewRedraw (theCtx, theView); + + // make sure to not process the same events twice + myGL.Reset(); + myToAskNextFrame = false; +} diff --git a/src/AIS/AIS_ViewController.hxx b/src/AIS/AIS_ViewController.hxx new file mode 100644 index 0000000000..e82027d4d4 --- /dev/null +++ b/src/AIS/AIS_ViewController.hxx @@ -0,0 +1,658 @@ +// Copyright (c) 2016-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _AIS_ViewController_HeaderFile +#define _AIS_ViewController_HeaderFile + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +class AIS_InteractiveObject; +class AIS_InteractiveContext; +class AIS_Point; +class AIS_RubberBand; +class V3d_View; + +//! Auxiliary structure for handling viewer events between GUI and Rendering threads. +//! +//! Class implements the following features: +//! - Buffers storing the state of user input (mouse, touches and keyboard). +//! - Mapping mouse/multi-touch input to View camera manipulations (panning/rotating/zooming). +//! - Input events are not applied immediately but queued for separate processing from two working threads +//! UI thread receiving user input and Rendering thread for OCCT 3D Viewer drawing. +class AIS_ViewController +{ +public: + + //! Empty constructor. + Standard_EXPORT AIS_ViewController(); + + //! Return input buffer. + const AIS_ViewInputBuffer& InputBuffer (AIS_ViewInputBufferType theType) const { return theType == AIS_ViewInputBufferType_UI ? myUI : myGL; } + + //! Return input buffer. + AIS_ViewInputBuffer& ChangeInputBuffer (AIS_ViewInputBufferType theType) { return theType == AIS_ViewInputBufferType_UI ? myUI : myGL; } + +public: //! @name global parameters + + //! Return camera rotation mode, AIS_RotationMode_BndBoxActive by default. + AIS_RotationMode RotationMode() const { return myRotationMode; } + + //! Set camera rotation mode. + void SetRotationMode (AIS_RotationMode theMode) { myRotationMode = theMode; } + + //! Return camera navigation mode; AIS_NavigationMode_Orbit by default. + AIS_NavigationMode NavigationMode() const { return myNavigationMode; } + + //! Set camera navigation mode. + Standard_EXPORT void SetNavigationMode (AIS_NavigationMode theMode); + + //! Return mouse input acceleration ratio in First Person mode; 1.0 by default. + float MouseAcceleration() const { return myMouseAccel; } + + //! Set mouse input acceleration ratio. + void SetMouseAcceleration (float theRatio) { myMouseAccel = theRatio; } + + //! Return orbit rotation acceleration ratio; 1.0 by default. + float OrbitAcceleration() const { return myOrbitAccel; } + + //! Set orbit rotation acceleration ratio. + void SetOrbitAcceleration (float theRatio) { myOrbitAccel = theRatio; } + + //! Return TRUE if panning anchor point within perspective projection should be displayed in 3D Viewer; TRUE by default. + bool ToShowPanAnchorPoint() const { return myToShowPanAnchorPoint; } + + //! Set if panning anchor point within perspective projection should be displayed in 3D Viewer. + void SetShowPanAnchorPoint (bool theToShow) { myToShowPanAnchorPoint = theToShow; } + + //! Return TRUE if rotation point should be displayed in 3D Viewer; TRUE by default. + bool ToShowRotateCenter() const { return myToShowRotateCenter; } + + //! Set if rotation point should be displayed in 3D Viewer. + void SetShowRotateCenter (bool theToShow) { myToShowRotateCenter = theToShow; } + + //! Return TRUE if camera up orientation within AIS_NavigationMode_Orbit rotation mode should be forced Z up; FALSE by default. + bool ToLockOrbitZUp() const { return myToLockOrbitZUp; } + + //! Set if camera up orientation within AIS_NavigationMode_Orbit rotation mode should be forced Z up. + void SetLockOrbitZUp (bool theToForceUp) { myToLockOrbitZUp = theToForceUp; } + + //! Return TRUE if z-rotation via two-touches gesture is enabled; FALSE by default. + bool ToAllowTouchZRotation() const { return myToAllowTouchZRotation; } + + //! Set if z-rotation via two-touches gesture is enabled. + void SetAllowTouchZRotation (bool theToEnable) { myToAllowTouchZRotation = theToEnable; } + + //! Return TRUE if camera rotation is allowed; TRUE by default. + bool ToAllowRotation() const { return myToAllowRotation; } + + //! Set if camera rotation is allowed. + void SetAllowRotation (bool theToEnable) { myToAllowRotation = theToEnable; } + + //! Return TRUE if panning is allowed; TRUE by default. + bool ToAllowPanning() const { return myToAllowPanning; } + + //! Set if panning is allowed. + void SetAllowPanning (bool theToEnable) { myToAllowPanning = theToEnable; } + + //! Return TRUE if zooming is allowed; TRUE by default. + bool ToAllowZooming() const { return myToAllowZooming; } + + //! Set if zooming is allowed. + void SetAllowZooming (bool theToEnable) { myToAllowZooming = theToEnable; } + + //! Return TRUE if ZFocus change is allowed; TRUE by default. + bool ToAllowZFocus() const { return myToAllowZFocus; } + + //! Set if ZFocus change is allowed. + void SetAllowZFocus (bool theToEnable) { myToAllowZFocus = theToEnable; } + + //! Return TRUE if dynamic highlight on mouse move is allowed; TRUE by default. + bool ToAllowHighlight() const { return myToAllowHighlight; } + + //! Set if dragging object is allowed. + void SetAllowHighlight (bool theToEnable) { myToAllowHighlight = theToEnable; } + + //! Return TRUE if dragging object is allowed; TRUE by default. + bool ToAllowDragging() const { return myToAllowDragging; } + + //! Set if dynamic highlight on mouse move is allowed. + void SetAllowDragging (bool theToEnable) { myToAllowDragging = theToEnable; } + + //! Return TRUE if pitch direction should be inverted while processing Aspect_VKey_NavLookUp/Aspect_VKey_NavLookDown; FALSE by default. + bool ToInvertPitch() const { return myToInvertPitch; } + + //! Set flag inverting pitch direction. + void SetInvertPitch (bool theToInvert) { myToInvertPitch = theToInvert; } + + //! Return normal walking speed, in m/s; 1.5 by default. + float WalkSpeedAbsolute() const { return myWalkSpeedAbsolute; } + + //! Set normal walking speed, in m/s; 1.5 by default. + void SetWalkSpeedAbsolute (float theSpeed) { myWalkSpeedAbsolute = theSpeed; } + + //! Return walking speed relative to scene bounding box; 0.1 by default. + float WalkSpeedRelative() const { return myWalkSpeedRelative; } + + //! Set walking speed relative to scene bounding box. + void SetWalkSpeedRelative (float theFactor) { myWalkSpeedRelative = theFactor; } + + //! Return active thrust value; 0.0f by default. + float ThrustSpeed() const { return myThrustSpeed; } + + //! Set active thrust value. + void SetThrustSpeed (float theSpeed) { myThrustSpeed = theSpeed; } + + //! Return TRUE if previous position of MoveTo has been defined. + bool HasPreviousMoveTo() const { return myPrevMoveTo != Graphic3d_Vec2i (-1); } + + //! Return previous position of MoveTo event in 3D viewer. + const Graphic3d_Vec2i& PreviousMoveTo() const { return myPrevMoveTo; } + + //! Reset previous position of MoveTo. + void ResetPreviousMoveTo() { myPrevMoveTo = Graphic3d_Vec2i (-1); } + +public: //! @name keyboard input + + //! Return keyboard state. + const Aspect_VKeySet& Keys() const { return myKeys; } + + //! Return keyboard state. + Aspect_VKeySet& ChangeKeys() { return myKeys; } + + //! Press key. + //! @param theKey key pressed + //! @param theTime event timestamp + Standard_EXPORT virtual void KeyDown (Aspect_VKey theKey, + double theTime, + double thePressure = 1.0); + + //! Release key. + //! @param theKey key pressed + //! @param theTime event timestamp + Standard_EXPORT virtual void KeyUp (Aspect_VKey theKey, + double theTime); + + //! Simulate key up/down events from axis value. + Standard_EXPORT virtual void KeyFromAxis (Aspect_VKey theNegative, + Aspect_VKey thePositive, + double theTime, + double thePressure); + + //! Fetch active navigation actions. + Standard_EXPORT AIS_WalkDelta FetchNavigationKeys (Standard_Real theCrouchRatio, + Standard_Real theRunRatio); + +public: //! @name mouse input + + //! Return map defining mouse gestures. + const AIS_MouseGestureMap& MouseGestureMap() const { return myMouseGestureMap; } + + //! Return map defining mouse gestures. + AIS_MouseGestureMap& ChangeMouseGestureMap() { return myMouseGestureMap; } + + //! Return double click interval in seconds; 0.4 by default. + double MouseDoubleClickInterval() const { return myMouseDoubleClickInt; } + + //! Set double click interval in seconds. + void SetMouseDoubleClickInterval (double theSeconds) { myMouseDoubleClickInt = theSeconds; } + + //! Perform selection in 3D viewer. + //! This method is expected to be called from UI thread. + //! @param thePnt picking point + //! @param theIsXOR XOR selection flag + Standard_EXPORT virtual void SelectInViewer (const Graphic3d_Vec2i& thePnt, + const bool theIsXOR = false); + + //! Perform selection in 3D viewer. + //! This method is expected to be called from UI thread. + //! @param thePnts picking point + //! @param theIsXOR XOR selection flag + Standard_EXPORT virtual void SelectInViewer (const NCollection_Sequence& thePnts, + const bool theIsXOR = false); + + //! Update rectangle selection tool. + //! This method is expected to be called from UI thread. + //! @param thePntFrom rectangle first corner + //! @param thePntTo rectangle another corner + //! @param theIsXOR XOR selection flag + Standard_EXPORT virtual void UpdateRubberBand (const Graphic3d_Vec2i& thePntFrom, + const Graphic3d_Vec2i& thePntTo, + const bool theIsXOR = false); + + //! Update polygonal selection tool. + //! This method is expected to be called from UI thread. + //! @param thePnt new point to add to polygon + //! @param theToAppend append new point or update the last point + Standard_EXPORT virtual void UpdatePolySelection (const Graphic3d_Vec2i& thePnt, + bool theToAppend); + + //! Update zoom event (e.g. from mouse scroll). + //! This method is expected to be called from UI thread. + //! @param theDelta mouse cursor position to zoom at and zoom delta + //! @return TRUE if new zoom event has been created or FALSE if existing one has been updated + Standard_EXPORT virtual bool UpdateZoom (const Aspect_ScrollDelta& theDelta); + + //! Update Z rotation event. + //! @param theAngle rotation angle, in radians. + //! @return TRUE if new zoom event has been created or FALSE if existing one has been updated + Standard_EXPORT virtual bool UpdateZRotation (double theAngle); + + //! Update mouse scroll event; redirects to UpdateZoom by default. + //! This method is expected to be called from UI thread. + //! @param theDelta mouse cursor position and delta + //! @return TRUE if new event has been created or FALSE if existing one has been updated + Standard_EXPORT virtual bool UpdateMouseScroll (const Aspect_ScrollDelta& theDelta); + + //! Handle mouse button press/release event. + //! This method is expected to be called from UI thread. + //! @param thePoint mouse cursor position + //! @param theButtons pressed buttons + //! @param theModifiers key modifiers + //! @param theIsEmulated if TRUE then mouse event comes NOT from real mouse + //! but emulated from non-precise input like touch on screen + //! @return TRUE if View should be redrawn + Standard_EXPORT virtual bool UpdateMouseButtons (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButtons, + Aspect_VKeyFlags theModifiers, + bool theIsEmulated); + + //! Handle mouse cursor movement event. + //! This method is expected to be called from UI thread. + //! @param thePoint mouse cursor position + //! @param theButtons pressed buttons + //! @param theModifiers key modifiers + //! @param theIsEmulated if TRUE then mouse event comes NOT from real mouse + //! but emulated from non-precise input like touch on screen + //! @return TRUE if View should be redrawn + Standard_EXPORT virtual bool UpdateMousePosition (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButtons, + Aspect_VKeyFlags theModifiers, + bool theIsEmulated); + + //! Handle mouse button press event. + //! This method is expected to be called from UI thread. + //! @param thePoint mouse cursor position + //! @param theButton pressed button + //! @param theModifiers key modifiers + //! @param theIsEmulated if TRUE then mouse event comes NOT from real mouse + //! but emulated from non-precise input like touch on screen + //! @return TRUE if View should be redrawn + bool PressMouseButton (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButton, + Aspect_VKeyFlags theModifiers, + bool theIsEmulated) + { + return UpdateMouseButtons (thePoint, myMousePressed | theButton, theModifiers, theIsEmulated); + } + + //! Handle mouse button release event. + //! This method is expected to be called from UI thread. + //! @param thePoint mouse cursor position + //! @param theButton released button + //! @param theModifiers key modifiers + //! @param theIsEmulated if TRUE then mouse event comes NOT from real mouse + //! but emulated from non-precise input like touch on screen + //! @return TRUE if View should be redrawn + bool ReleaseMouseButton (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButton, + Aspect_VKeyFlags theModifiers, + bool theIsEmulated) + { + Aspect_VKeyMouse aButtons = myMousePressed & (~theButton); + return UpdateMouseButtons (thePoint, aButtons, theModifiers, theIsEmulated); + } + + //! Handle mouse button click event (emulated by UpdateMouseButtons() while releasing single button). + //! Note that as this method is called by UpdateMouseButtons(), it should be executed from UI thread. + //! Default implementation redirects to SelectInViewer(). + //! This method is expected to be called from UI thread. + //! @param thePoint mouse cursor position + //! @param theButton clicked button + //! @param theModifiers key modifiers + //! @param theIsDoubleClick flag indicating double mouse click + //! @return TRUE if View should be redrawn + Standard_EXPORT virtual bool UpdateMouseClick (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButton, + Aspect_VKeyFlags theModifiers, + bool theIsDoubleClick); + + //! Return currently pressed mouse buttons. + Aspect_VKeyMouse PressedMouseButtons() const { return myMousePressed; } + + //! Return active key modifiers passed with last mouse event. + Aspect_VKeyFlags LastMouseFlags() const { return myMouseModifiers; } + + //! Return last mouse position. + const Graphic3d_Vec2i& LastMousePosition() const { return myMousePositionLast; } + +public: //! @name multi-touch input + + //! Return scale factor for adjusting tolerances for starting multi-touch gestures; 1.0 by default + //! This scale factor is expected to be computed from touch screen resolution. + float TouchToleranceScale() const { return myTouchToleranceScale; } + + //! Set scale factor for adjusting tolerances for starting multi-touch gestures. + void SetTouchToleranceScale (float theTolerance) { myTouchToleranceScale = theTolerance; } + + //! Return TRUE if touches map is not empty. + bool HasTouchPoints() const { return !myTouchPoints.IsEmpty(); } + + //! Add touch point with the given ID. + //! This method is expected to be called from UI thread. + //! @param theId touch unique identifier + //! @param thePnt touch coordinates + //! @param theClearBefore if TRUE previously registered touches will be removed + Standard_EXPORT virtual void AddTouchPoint (Standard_Size theId, + const Graphic3d_Vec2d& thePnt, + Standard_Boolean theClearBefore = false); + + //! Remove touch point with the given ID. + //! This method is expected to be called from UI thread. + //! @param theId touch unique identifier + //! @param theClearSelectPnts if TRUE will initiate clearing of selection points + //! @return TRUE if point has been removed + Standard_EXPORT virtual bool RemoveTouchPoint (Standard_Size theId, + Standard_Boolean theClearSelectPnts = false); + + //! Update touch point with the given ID. + //! If point with specified ID was not registered before, it will be added. + //! This method is expected to be called from UI thread. + //! @param theId touch unique identifier + //! @param thePnt touch coordinates + Standard_EXPORT virtual void UpdateTouchPoint (Standard_Size theId, + const Graphic3d_Vec2d& thePnt); + +public: + + //! Return event time (e.g. current time). + double EventTime() const { return myEventTimer.ElapsedTime(); } + + //! Reset input state (pressed keys, mouse buttons, etc.) e.g. on window focus loss. + //! This method is expected to be called from UI thread. + Standard_EXPORT virtual void ResetViewInput(); + + //! Reset view orientation. + //! This method is expected to be called from UI thread. + Standard_EXPORT virtual void UpdateViewOrientation (V3d_TypeOfOrientation theOrientation, + bool theToFitAll); + + //! Update buffer for rendering thread. + //! This method is expected to be called within synchronization barrier between GUI + //! and Rendering threads (e.g. GUI thread should be locked beforehand to avoid data races). + //! @param theCtx interactive context + //! @param theView active view + //! @param theToHandle if TRUE, the HandleViewEvents() will be called + Standard_EXPORT virtual void FlushViewEvents (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView, + Standard_Boolean theToHandle = Standard_False); + + //! Process events within rendering thread. + Standard_EXPORT virtual void HandleViewEvents (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView); + +public: + + //! Callback called by handleMoveTo() on Selection in 3D Viewer. + //! This method is expected to be called from rendering thread. + Standard_EXPORT virtual void OnSelectionChanged (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView); + + //! Callback called by handleMoveTo() on dragging object in 3D Viewer. + //! This method is expected to be called from rendering thread. + Standard_EXPORT virtual void OnObjectDragged (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView, + AIS_DragAction theAction); + + //! Pick closest point under mouse cursor. + //! This method is expected to be called from rendering thread. + //! @param thePnt [out] result point + //! @param theCtx [in] interactive context + //! @param theView [in] active view + //! @param theCursor [in] mouse cursor + //! @param theToStickToPickRay [in] when TRUE, the result point will lie on picking ray + //! @return TRUE if result has been found + Standard_EXPORT virtual bool PickPoint (gp_Pnt& thePnt, + const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView, + const Graphic3d_Vec2i& theCursor, + bool theToStickToPickRay); + + //! Compute rotation gravity center point depending on rotation mode. + //! This method is expected to be called from rendering thread. + Standard_EXPORT virtual gp_Pnt GravityPoint (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView); + +public: + + //! Perform camera actions. + //! This method is expected to be called from rendering thread. + Standard_EXPORT virtual void handleCameraActions (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView, + const AIS_WalkDelta& theWalk); + + //! Perform moveto/selection/dragging. + //! This method is expected to be called from rendering thread. + Standard_EXPORT virtual void handleMoveTo (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView); + + //! Return TRUE if another frame should be drawn right after this one. + bool toAskNextFrame() const { return myToAskNextFrame; } + + //! Set if another frame should be drawn right after this one. + void setAskNextFrame (bool theToDraw = true) { myToAskNextFrame = theToDraw; } + + //! Return if panning anchor point has been defined. + bool hasPanningAnchorPoint() const { return !Precision::IsInfinite (myPanPnt3d.X()); } + + //! Return active panning anchor point. + const gp_Pnt& panningAnchorPoint() const { return myPanPnt3d; } + + //! Set active panning anchor point. + void setPanningAnchorPoint (const gp_Pnt& thePnt) { myPanPnt3d = thePnt; } + + //! Handle panning event myGL.Panning. + Standard_EXPORT virtual void handlePanning (const Handle(V3d_View)& theView); + + //! Handle Z rotation event myGL.ZRotate. + Standard_EXPORT virtual void handleZRotate (const Handle(V3d_View)& theView); + + //! Return minimal camera distance for zoom operation. + double MinZoomDistance() const { return myMinCamDistance; } + + //! Set minimal camera distance for zoom operation. + void SetMinZoomDistance (double theDist) { myMinCamDistance = theDist; } + + //! Handle zoom event myGL.ZoomActions. + //! This method is expected to be called from rendering thread. + Standard_EXPORT virtual void handleZoom (const Handle(V3d_View)& theView, + const Aspect_ScrollDelta& theParams, + const gp_Pnt* thePnt); + + //! Handle ZScroll event myGL.ZoomActions. + //! This method is expected to be called from rendering thread. + Standard_EXPORT virtual void handleZFocusScroll (const Handle(V3d_View)& theView, + const Aspect_ScrollDelta& theParams); + + //! Handle orbital rotation events myGL.OrbitRotation. + //! @param theView view to modify + //! @param thePnt 3D point to rotate around + //! @param theToLockZUp amend camera to exclude roll angle (put camera Up vector to plane containing global Z and view direction) + Standard_EXPORT virtual void handleOrbitRotation (const Handle(V3d_View)& theView, + const gp_Pnt& thePnt, + bool theToLockZUp); + + //! Handle view direction rotation events myGL.ViewRotation. + //! This method is expected to be called from rendering thread. + //! @param theView camera to modify + //! @param theYawExtra extra yaw increment + //! @param thePitchExtra extra pitch increment + //! @param theRoll roll value + //! @param theToRestartOnIncrement flag indicating flight mode + Standard_EXPORT virtual void handleViewRotation (const Handle(V3d_View)& theView, + double theYawExtra, + double thePitchExtra, + double theRoll, + bool theToRestartOnIncrement); + + //! Handle view redraw. + //! This method is expected to be called from rendering thread. + Standard_EXPORT virtual void handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView); + +protected: + + //! Flush buffers. + Standard_EXPORT virtual void flushBuffers (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView); + + //! Flush touch gestures. + Standard_EXPORT virtual void flushGestures (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView); + + //! Return current and previously fetched event times. + //! This callback is intended to compute delta between sequentially processed events. + //! @param thePrevTime [out] events time fetched previous time by this method + //! @param theCurrTime [out] actual events time + void updateEventsTime (double& thePrevTime, + double& theCurrTime) + { + thePrevTime = myLastEventsTime; + myLastEventsTime = EventTime(); + theCurrTime = myLastEventsTime; + } + + //! Perform selection via mouse click. + //! This method is expected to be called from rendering thread. + Standard_EXPORT virtual void handleSelectionPick (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView); + + //! Perform dynamic highlight on mouse move. + //! This method is expected to be called from rendering thread. + Standard_EXPORT virtual void handleDynamicHighlight (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView); + + //! Perform rubber-band selection. + //! This method is expected to be called from rendering thread. + Standard_EXPORT virtual void handleSelectionPoly (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView); + + //! Lazy AIS_InteractiveContext::MoveTo() with myPrevMoveTo check. + Standard_EXPORT virtual void contextLazyMoveTo (const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView, + const Graphic3d_Vec2i& thePnt); + +protected: + + AIS_ViewInputBuffer myUI; //!< buffer for UI thread + AIS_ViewInputBuffer myGL; //!< buffer for rendering thread + + OSD_Timer myEventTimer; //!< timer for timestamping events + Standard_Real myLastEventsTime; //!< last fetched events timer value for computing delta/progress + Standard_Boolean myToAskNextFrame; //!< flag indicating that another frame should be drawn right after this one + + Standard_Real myMinCamDistance; //!< minimal camera distance for zoom operation + AIS_RotationMode myRotationMode; //!< rotation mode + AIS_NavigationMode myNavigationMode; //!< navigation mode (orbit rotation / first person) + Standard_ShortReal myMouseAccel; //!< mouse input acceleration ratio in First Person mode + Standard_ShortReal myOrbitAccel; //!< Orbit rotation acceleration ratio + Standard_Boolean myToShowPanAnchorPoint; //!< option displaying panning anchor point + Standard_Boolean myToShowRotateCenter; //!< option displaying rotation center point + Standard_Boolean myToLockOrbitZUp; //!< force camera up orientation within AIS_NavigationMode_Orbit rotation mode + Standard_Boolean myToInvertPitch; //!< flag inverting pitch direction while processing Aspect_VKey_NavLookUp/Aspect_VKey_NavLookDown + Standard_Boolean myToAllowTouchZRotation; //!< enable z-rotation two-touches gesture; FALSE by default + Standard_Boolean myToAllowRotation; //!< enable rotation; TRUE by default + Standard_Boolean myToAllowPanning; //!< enable panning; TRUE by default + Standard_Boolean myToAllowZooming; //!< enable zooming; TRUE by default + Standard_Boolean myToAllowZFocus; //!< enable ZFocus change; TRUE by default + Standard_Boolean myToAllowHighlight; //!< enable dynamic highlight on mouse move; TRUE by default + Standard_Boolean myToAllowDragging; //!< enable dragging object; TRUE by default + + Standard_ShortReal myWalkSpeedAbsolute; //!< normal walking speed, in m/s; 1.5 by default + Standard_ShortReal myWalkSpeedRelative; //!< walking speed relative to scene bounding box; 0.1 by default + Standard_ShortReal myThrustSpeed; //!< active thrust value + Standard_Boolean myHasThrust; //!< flag indicating active thrust + + Handle(AIS_RubberBand) myRubberBand; //!< Rubber-band presentation + Handle(AIS_InteractiveObject) myDragObject; //!< currently dragged object + Graphic3d_Vec2i myPrevMoveTo; //!< previous position of MoveTo event in 3D viewer + Standard_Boolean myHasHlrOnBeforeRotation; //!< flag for restoring Computed mode after rotation + +protected: //! @name keyboard input variables + + Aspect_VKeySet myKeys; //!< keyboard state + +protected: //! @name mouse input variables + + Standard_Real myMouseClickThreshold; //!< mouse click threshold in pixels; 3 by default + Standard_Real myMouseDoubleClickInt; //!< double click interval in seconds; 0.4 by default + Standard_ShortReal myScrollZoomRatio; //!< distance ratio for mapping mouse scroll event to zoom; 15.0 by default + + AIS_MouseGestureMap myMouseGestureMap; //!< map defining mouse gestures + AIS_MouseGesture myMouseActiveGesture; //!< initiated mouse gesture (by pressing mouse button) + Standard_Boolean myMouseActiveIdleRotation; //!< flag indicating view idle rotation state + Graphic3d_Vec2i myMousePositionLast; //!< last mouse position + Graphic3d_Vec2i myMousePressPoint; //!< mouse position where active gesture was been initiated + Graphic3d_Vec2i myMouseProgressPoint; //!< gesture progress + OSD_Timer myMouseClickTimer; //!< timer for handling double-click event + Standard_Integer myMouseClickCounter; //!< counter for handling double-click event + Aspect_VKeyMouse myMousePressed; //!< active mouse buttons + Aspect_VKeyFlags myMouseModifiers; //!< active key modifiers passed with last mouse event + Standard_Integer myMouseSingleButton; //!< index of mouse button pressed alone (>0) + +protected: //! @name multi-touch input variables + + Standard_ShortReal myTouchToleranceScale; //!< tolerance scale factor; 1.0 by default + Standard_ShortReal myTouchRotationThresholdPx; //!< threshold for starting one-touch rotation gesture in pixels; 6 by default + Standard_ShortReal myTouchZRotationThreshold; //!< threshold for starting two-touch Z-rotation gesture in radians; 2 degrees by default + Standard_ShortReal myTouchPanThresholdPx; //!< threshold for starting two-touch panning gesture in pixels; 4 by default + Standard_ShortReal myTouchZoomThresholdPx; //!< threshold for starting two-touch zoom (pitch) gesture in pixels; 6 by default + Standard_ShortReal myTouchZoomRatio; //!< distance ratio for mapping two-touch zoom (pitch) gesture from pixels to zoom; 0.13 by default + + Aspect_TouchMap myTouchPoints; //!< map of active touches + Graphic3d_Vec2d myStartPanCoord; //!< touch coordinates at the moment of starting panning gesture + Graphic3d_Vec2d myStartRotCoord; //!< touch coordinates at the moment of starting rotating gesture + Standard_Integer myNbTouchesLast; //!< number of touches within previous gesture flush to track gesture changes + Standard_Boolean myUpdateStartPointPan; //!< flag indicating that new anchor point should be picked for starting panning gesture + Standard_Boolean myUpdateStartPointRot; //!< flag indicating that new gravity point should be picked for starting rotation gesture + Standard_Boolean myUpdateStartPointZRot; //!< flag indicating that new gravity point should be picked for starting Z-rotation gesture + +protected: //! @name rotation/panning transient state variables + + Handle(AIS_Point) myAnchorPointPrs1; //!< anchor point presentation (Graphic3d_ZLayerId_Top) + Handle(AIS_Point) myAnchorPointPrs2; //!< anchor point presentation (Graphic3d_ZLayerId_Topmost) + gp_Pnt myPanPnt3d; //!< active panning anchor point + gp_Pnt myRotatePnt3d; //!< active rotation center of gravity + gp_Dir myCamStartOpUp; //!< camera Up direction at the beginning of rotation + gp_Pnt myCamStartOpEye; //!< camera Eye position at the beginning of rotation + gp_Pnt myCamStartOpCenter; //!< camera Center position at the beginning of rotation + gp_Vec myCamStartOpToCenter; //!< vector from rotation gravity point to camera Center at the beginning of rotation + gp_Vec myCamStartOpToEye; //!< vector from rotation gravity point to camera Eye at the beginning of rotation + Graphic3d_Vec3d myRotateStartYawPitchRoll; //!< camera yaw pitch roll at the beginning of rotation + +}; + +#endif // _AIS_ViewController_HeaderFile diff --git a/src/AIS/AIS_ViewInputBuffer.hxx b/src/AIS/AIS_ViewInputBuffer.hxx new file mode 100644 index 0000000000..48d2705e6c --- /dev/null +++ b/src/AIS/AIS_ViewInputBuffer.hxx @@ -0,0 +1,153 @@ +// Copyright (c) 2016-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _AIS_ViewInputBuffer_HeaderFile +#define _AIS_ViewInputBuffer_HeaderFile + +#include + +#include +#include +#include + +//! Selection mode +enum AIS_ViewSelectionTool +{ + AIS_ViewSelectionTool_Picking, //!< pick to select + AIS_ViewSelectionTool_RubberBand, //!< rubber-band to select + AIS_ViewSelectionTool_Polygon //!< polyline to select +}; + +//! Input buffer type. +enum AIS_ViewInputBufferType +{ + AIS_ViewInputBufferType_UI, //!< input buffer for filling from UI thread + AIS_ViewInputBufferType_GL, //!< input buffer accessible from GL thread +}; + +//! Auxiliary structure defining viewer events +class AIS_ViewInputBuffer +{ +public: + + bool IsNewGesture; //!< transition from one action to another + + NCollection_Sequence ZoomActions; //!< the queue with zoom actions + + struct _orientation + { + bool ToFitAll; //!< perform FitAll operation + bool ToSetViewOrient; //!< set new view orientation + V3d_TypeOfOrientation ViewOrient; //!< new view orientation + + _orientation() : ToFitAll (false), ToSetViewOrient (false), ViewOrient (V3d_Xpos) {} + } Orientation; + + struct _highlighting + { + bool ToHilight; //!< perform dynamic highlighting at specified point + Graphic3d_Vec2i Point; //!< the new point for dynamic highlighting + + _highlighting() : ToHilight (false) {} + } MoveTo; + + struct _selection + { + AIS_ViewSelectionTool Tool; //!< perform selection + bool IsXOR; //!< perform shift selection + NCollection_Sequence + Points; //!< the points for selection + bool ToApplyTool; //!< apply rubber-band selection tool + + _selection() : Tool (AIS_ViewSelectionTool_Picking), IsXOR (false), ToApplyTool (false) {} + } Selection; + + struct _panningParams + { + bool ToStart; //!< start panning + Graphic3d_Vec2i PointStart; //!< panning start point + bool ToPan; //!< perform panning + Graphic3d_Vec2i Delta; //!< panning delta + + _panningParams() : ToStart (false), ToPan (false) {} + } Panning; + + struct _draggingParams + { + bool ToStart; //!< start dragging + bool ToStop; //!< stop dragging + bool ToAbort; //!< abort dragging (restore previous position) + Graphic3d_Vec2i PointStart; //!< drag start point + Graphic3d_Vec2i PointTo; //!< drag end point + + _draggingParams() : ToStart (false), ToStop (false), ToAbort (false) {} + } Dragging; + + struct _orbitRotation + { + bool ToStart; //!< start orbit rotation + Graphic3d_Vec2d PointStart; //!< orbit rotation start point + bool ToRotate; //!< perform orbit rotation + Graphic3d_Vec2d PointTo; //!< orbit rotation end point + + _orbitRotation() : ToStart (false), ToRotate (false) {} + } OrbitRotation; + + struct _viewRotation + { + bool ToStart; //!< start view rotation + Graphic3d_Vec2d PointStart; //!< view rotation start point + bool ToRotate; //!< perform view rotation + Graphic3d_Vec2d PointTo; //!< view rotation end point + + _viewRotation() : ToStart (false), ToRotate (false) {} + } ViewRotation; + + struct _zrotateParams + { + Graphic3d_Vec2i Point; //!< Z rotation start point + double Angle; //!< Z rotation angle + bool ToRotate; //!< start Z rotation + + _zrotateParams() : Angle (0.0), ToRotate (false) {} + } ZRotate; + +public: + + AIS_ViewInputBuffer() + : IsNewGesture (false) {} + + //! Reset events buffer. + void Reset() + { + Orientation.ToFitAll = false; + Orientation.ToSetViewOrient = false; + MoveTo.ToHilight = false; + Selection.ToApplyTool = false; + IsNewGesture = false; + ZoomActions.Clear(); + Panning.ToStart = false; + Panning.ToPan = false; + Dragging.ToStart = false; + Dragging.ToStop = false; + Dragging.ToAbort = false; + OrbitRotation.ToStart = false; + OrbitRotation.ToRotate = false; + ViewRotation.ToStart = false; + ViewRotation.ToRotate = false; + ZRotate.ToRotate = false; + } + +}; + +#endif // _AIS_ViewInputBuffer_HeaderFile diff --git a/src/AIS/AIS_WalkDelta.hxx b/src/AIS/AIS_WalkDelta.hxx new file mode 100644 index 0000000000..40b0eaeb53 --- /dev/null +++ b/src/AIS/AIS_WalkDelta.hxx @@ -0,0 +1,115 @@ +// Copyright (c) 2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _AIS_WalkDelta_HeaderFile +#define _AIS_WalkDelta_HeaderFile + +#include + +//! Walking translation components. +enum AIS_WalkTranslation +{ + AIS_WalkTranslation_Forward = 0, //!< translation delta, Forward walk + AIS_WalkTranslation_Side, //!< translation delta, Side walk + AIS_WalkTranslation_Up, //!< translation delta, Up walk +}; + +//! Walking rotation components. +enum AIS_WalkRotation +{ + AIS_WalkRotation_Yaw = 0, //!< yaw rotation angle + AIS_WalkRotation_Pitch, //!< pitch rotation angle + AIS_WalkRotation_Roll, //!< roll rotation angle +}; + +//! Walking value. +struct AIS_WalkPart +{ + Standard_Real Value; //!< value + Standard_Real Pressure; //!< key pressure + Standard_Real Duration; //!< duration + + //! Return TRUE if delta is empty. + bool IsEmpty() const { return Abs (Value) <= RealSmall(); } + + //! Empty constructor. + AIS_WalkPart() : Value (0.0), Pressure (1.0), Duration (0.0) {} +}; + +//! Walking values. +struct AIS_WalkDelta +{ + //! Empty constructor. + AIS_WalkDelta() + : myIsJumping (false), myIsCrouching (false), myIsRunning (false) {} + + //! Return translation component. + const AIS_WalkPart& operator[] (AIS_WalkTranslation thePart) const { return myTranslation[thePart]; } + + //! Return translation component. + AIS_WalkPart& operator[] (AIS_WalkTranslation thePart) { return myTranslation[thePart]; } + + //! Return rotation component. + const AIS_WalkPart& operator[] (AIS_WalkRotation thePart) const { return myRotation[thePart]; } + + //! Return rotation component. + AIS_WalkPart& operator[] (AIS_WalkRotation thePart) { return myRotation[thePart]; } + + //! Return jumping state. + bool IsJumping() const { return myIsJumping; } + + //! Set jumping state. + void SetJumping (bool theIsJumping) { myIsJumping = theIsJumping; } + + //! Return crouching state. + bool IsCrouching() const { return myIsCrouching; } + + //! Set crouching state. + void SetCrouching (bool theIsCrouching) { myIsCrouching = theIsCrouching; } + + //! Return running state. + bool IsRunning() const { return myIsRunning; } + + //! Set running state. + void SetRunning (bool theIsRunning) { myIsRunning = theIsRunning; } + + //! Return TRUE when both Rotation and Translation deltas are empty. + bool IsEmpty() const { return !ToMove() && !ToRotate(); } + + //! Return TRUE if translation delta is defined. + bool ToMove() const + { + return !myTranslation[AIS_WalkTranslation_Forward].IsEmpty() + || !myTranslation[AIS_WalkTranslation_Side].IsEmpty() + || !myTranslation[AIS_WalkTranslation_Up].IsEmpty(); + } + + //! Return TRUE if rotation delta is defined. + bool ToRotate() const + { + return !myRotation[AIS_WalkRotation_Yaw].IsEmpty() + || !myRotation[AIS_WalkRotation_Pitch].IsEmpty() + || !myRotation[AIS_WalkRotation_Roll].IsEmpty(); + } + +private: + + AIS_WalkPart myTranslation[3]; + AIS_WalkPart myRotation[3]; + bool myIsJumping; + bool myIsCrouching; + bool myIsRunning; + +}; + +#endif // _AIS_WalkDelta_HeaderFile diff --git a/src/AIS/FILES b/src/AIS/FILES index 9a17309969..7d225a6580 100644 --- a/src/AIS/FILES +++ b/src/AIS/FILES @@ -56,6 +56,7 @@ AIS_DimensionSelectionMode.hxx AIS_DisplayMode.hxx AIS_DisplaySpecialSymbol.hxx AIS_DisplayStatus.hxx +AIS_DragAction.hxx AIS_EllipseRadiusDimension.cxx AIS_EllipseRadiusDimension.hxx AIS_EqualDistanceRelation.cxx @@ -106,6 +107,7 @@ AIS_MaxRadiusDimension.cxx AIS_MaxRadiusDimension.hxx AIS_MediaPlayer.cxx AIS_MediaPlayer.hxx +AIS_MouseGesture.hxx AIS_MidPointRelation.cxx AIS_MidPointRelation.hxx AIS_MidPointRelation.lxx @@ -114,6 +116,7 @@ AIS_MinRadiusDimension.hxx AIS_MultipleConnectedInteractive.cxx AIS_MultipleConnectedInteractive.hxx AIS_MultipleConnectedInteractive.lxx +AIS_NavigationMode.hxx AIS_NListOfEntityOwner.hxx AIS_OffsetDimension.cxx AIS_OffsetDimension.hxx @@ -135,6 +138,7 @@ AIS_RadiusDimension.cxx AIS_RadiusDimension.hxx AIS_Relation.cxx AIS_Relation.hxx +AIS_RotationMode.hxx AIS_RubberBand.hxx AIS_RubberBand.cxx AIS_Selection.cxx @@ -175,3 +179,7 @@ AIS_TypeOfAxis.hxx AIS_TypeOfDist.hxx AIS_TypeOfIso.hxx AIS_TypeOfPlane.hxx +AIS_ViewController.cxx +AIS_ViewController.hxx +AIS_ViewInputBuffer.hxx +AIS_WalkDelta.hxx diff --git a/src/Aspect/Aspect_ScrollDelta.hxx b/src/Aspect/Aspect_ScrollDelta.hxx new file mode 100644 index 0000000000..b764522ac0 --- /dev/null +++ b/src/Aspect/Aspect_ScrollDelta.hxx @@ -0,0 +1,59 @@ +// Copyright (c) 2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Aspect_ScrollDelta_HeaderFile +#define _Aspect_ScrollDelta_HeaderFile + +#include +#include +#include + +//! Parameters for mouse scroll action. +struct Aspect_ScrollDelta +{ + + NCollection_Vec2 Point; //!< scale position + Standard_Real Delta; //!< delta in pixels + Aspect_VKeyFlags Flags; //!< key flags + + //! Return true if action has point defined. + bool HasPoint() const + { + return Point.x() >= 0 + && Point.y() >= 0; + } + + //! Reset at point. + void ResetPoint() + { + Point.SetValues (-1, -1); + } + + //! Empty constructor. + Aspect_ScrollDelta() + : Point (-1, -1), Delta (0.0), Flags (Aspect_VKeyFlags_NONE) {} + + //! Constructor. + Aspect_ScrollDelta (const NCollection_Vec2& thePnt, + Standard_Real theValue, + Aspect_VKeyFlags theFlags = Aspect_VKeyFlags_NONE) + : Point (thePnt), Delta (theValue), Flags (theFlags) {} + + //! Constructor with undefined point. + Aspect_ScrollDelta (Standard_Real theValue, + Aspect_VKeyFlags theFlags = Aspect_VKeyFlags_NONE) + : Point (-1, -1), Delta (theValue), Flags (theFlags) {} + +}; + +#endif // _Aspect_ScrollDelta_HeaderFile diff --git a/src/Aspect/Aspect_Touch.hxx b/src/Aspect/Aspect_Touch.hxx new file mode 100644 index 0000000000..6ccf11d9f2 --- /dev/null +++ b/src/Aspect/Aspect_Touch.hxx @@ -0,0 +1,49 @@ +// Copyright (c) 2016-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Aspect_Touch_HeaderFile +#define _Aspect_Touch_HeaderFile + +#include +#include +#include + +//! Structure holding touch position - original and current location. +class Aspect_Touch +{ +public: + + NCollection_Vec2 From; //!< original touch position + NCollection_Vec2 To; //!< current touch position + Standard_Boolean IsPreciseDevice; //!< precise device input (e.g. mouse cursor, NOT emulated from touch screen) + + //! Return values delta. + NCollection_Vec2 Delta() const { return To - From; } + + //! Empty constructor + Aspect_Touch() + : From (0.0, 0.0), To (0.0, 0.0), IsPreciseDevice (false) {} + + //! Constructor with initialization. + Aspect_Touch (const NCollection_Vec2& thePnt, + Standard_Boolean theIsPreciseDevice) + : From (thePnt), To (thePnt), IsPreciseDevice (theIsPreciseDevice) {} + + //! Constructor with initialization. + Aspect_Touch (Standard_Real theX, Standard_Real theY, + Standard_Boolean theIsPreciseDevice) + : From (theX, theY), To (theX, theY), IsPreciseDevice (theIsPreciseDevice) {} + +}; + +#endif // _Aspect_Touch_HeaderFile diff --git a/src/ViewerTest/ViewerTest_EventManager.lxx b/src/Aspect/Aspect_TouchMap.hxx similarity index 65% rename from src/ViewerTest/ViewerTest_EventManager.lxx rename to src/Aspect/Aspect_TouchMap.hxx index 88a8ae00d1..0f4b1d3414 100644 --- a/src/ViewerTest/ViewerTest_EventManager.lxx +++ b/src/Aspect/Aspect_TouchMap.hxx @@ -1,7 +1,4 @@ -// Created on: 1998-08-27 -// Created by: Robert COUBLANC -// Copyright (c) 1998-1999 Matra Datavision -// Copyright (c) 1999-2014 OPEN CASCADE SAS +// Copyright (c) 2016-2019 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // @@ -14,5 +11,13 @@ // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. -inline const Handle(AIS_InteractiveContext)& ViewerTest_EventManager::Context() const -{return myCtx;} +#ifndef _Aspect_TouchMap_HeaderFile +#define _Aspect_TouchMap_HeaderFile + +#include + +#include + +typedef NCollection_IndexedDataMap Aspect_TouchMap; + +#endif // _Aspect_TouchMap_HeaderFile diff --git a/src/Aspect/Aspect_VKey.hxx b/src/Aspect/Aspect_VKey.hxx new file mode 100644 index 0000000000..ff0def5b9c --- /dev/null +++ b/src/Aspect/Aspect_VKey.hxx @@ -0,0 +1,199 @@ +// Copyright (c) 2016-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Aspect_VKey_HeaderFile +#define _Aspect_VKey_HeaderFile + +#include + +//! Define virtual key as integer number to allow extensions. +typedef unsigned int Aspect_VKey; + +//! Enumeration defining virtual keys irrelevant to current keyboard layout for simplified hot-keys management logic. +enum Aspect_VKeyBasic +{ + Aspect_VKey_UNKNOWN = 0, + + // main latin alphabet keys + Aspect_VKey_A = 1, + Aspect_VKey_B, + Aspect_VKey_C, + Aspect_VKey_D, + Aspect_VKey_E, + Aspect_VKey_F, + Aspect_VKey_G, + Aspect_VKey_H, + Aspect_VKey_I, + Aspect_VKey_J, + Aspect_VKey_K, + Aspect_VKey_L, + Aspect_VKey_M, + Aspect_VKey_N, + Aspect_VKey_O, + Aspect_VKey_P, + Aspect_VKey_Q, + Aspect_VKey_R, + Aspect_VKey_S, + Aspect_VKey_T, + Aspect_VKey_U, + Aspect_VKey_V, + Aspect_VKey_W, + Aspect_VKey_X, + Aspect_VKey_Y, + Aspect_VKey_Z, + + Aspect_VKey_0, + Aspect_VKey_1, + Aspect_VKey_2, + Aspect_VKey_3, + Aspect_VKey_4, + Aspect_VKey_5, + Aspect_VKey_6, + Aspect_VKey_7, + Aspect_VKey_8, + Aspect_VKey_9, + + Aspect_VKey_F1, + Aspect_VKey_F2, + Aspect_VKey_F3, + Aspect_VKey_F4, + Aspect_VKey_F5, + Aspect_VKey_F6, + Aspect_VKey_F7, + Aspect_VKey_F8, + Aspect_VKey_F9, + Aspect_VKey_F10, + Aspect_VKey_F11, + Aspect_VKey_F12, + + // standard keys + Aspect_VKey_Up, + Aspect_VKey_Down, + Aspect_VKey_Left, + Aspect_VKey_Right, + Aspect_VKey_Plus, //!< '+' + Aspect_VKey_Minus, //!< '-' + Aspect_VKey_Equal, //!< '=+' + Aspect_VKey_PageUp, + Aspect_VKey_PageDown, + Aspect_VKey_Home, + Aspect_VKey_End, + Aspect_VKey_Escape, + Aspect_VKey_Back, + Aspect_VKey_Enter, + Aspect_VKey_Backspace, + Aspect_VKey_Space, + Aspect_VKey_Delete, + Aspect_VKey_Tilde, + Aspect_VKey_Tab, + Aspect_VKey_Comma, //!< ',' + Aspect_VKey_Period, //!< '.' + Aspect_VKey_Semicolon, //!< ';:' + Aspect_VKey_Slash, //!< '/?' + Aspect_VKey_BracketLeft, //!< '[{' + Aspect_VKey_Backslash, //!< '\|' + Aspect_VKey_BracketRight, //!< ']}' + Aspect_VKey_Apostrophe, //!< ''"' + Aspect_VKey_Numlock, //!< Num Lock key + Aspect_VKey_Scroll, //!< Scroll Lock key + + // numpad keys + Aspect_VKey_Numpad0, + Aspect_VKey_Numpad1, + Aspect_VKey_Numpad2, + Aspect_VKey_Numpad3, + Aspect_VKey_Numpad4, + Aspect_VKey_Numpad5, + Aspect_VKey_Numpad6, + Aspect_VKey_Numpad7, + Aspect_VKey_Numpad8, + Aspect_VKey_Numpad9, + Aspect_VKey_NumpadMultiply, //!< numpad '*' + Aspect_VKey_NumpadAdd, //!< numpad '+' + Aspect_VKey_NumpadSubtract, //!< numpad '-' + Aspect_VKey_NumpadDivide, //!< numpad '/' + + // Multimedia keys + Aspect_VKey_MediaNextTrack, + Aspect_VKey_MediaPreviousTrack, + Aspect_VKey_MediaStop, + Aspect_VKey_MediaPlayPause, + Aspect_VKey_VolumeMute, + Aspect_VKey_VolumeDown, + Aspect_VKey_VolumeUp, + Aspect_VKey_BrowserBack, + Aspect_VKey_BrowserForward, + Aspect_VKey_BrowserRefresh, + Aspect_VKey_BrowserStop, + Aspect_VKey_BrowserSearch, + Aspect_VKey_BrowserFavorites, + Aspect_VKey_BrowserHome, + + // modifier keys, @sa Aspect_VKey_ModifiersLower and Aspect_VKey_ModifiersUpper below + Aspect_VKey_Shift, + Aspect_VKey_Control, + Aspect_VKey_Alt, + Aspect_VKey_Menu, + Aspect_VKey_Meta, + + // virtual navigation keys, @sa Aspect_VKey_NavigationKeysLower and Aspect_VKey_NavigationKeysUpper below + Aspect_VKey_NavInteract, //!< interact + Aspect_VKey_NavForward, //!< go forward + Aspect_VKey_NavBackward, //!< go backward + Aspect_VKey_NavSlideLeft, //!< sidewalk, left + Aspect_VKey_NavSlideRight, //!< sidewalk, right + Aspect_VKey_NavSlideUp, //!< lift up + Aspect_VKey_NavSlideDown, //!< fall down + Aspect_VKey_NavRollCCW, //!< bank left (roll counter-clockwise) + Aspect_VKey_NavRollCW, //!< bank right (roll clockwise) + Aspect_VKey_NavLookLeft, //!< look left (yaw counter-clockwise) + Aspect_VKey_NavLookRight, //!< look right (yaw clockwise) + Aspect_VKey_NavLookUp, //!< look up (pitch clockwise) + Aspect_VKey_NavLookDown, //!< look down (pitch counter-clockwise) + Aspect_VKey_NavCrouch, //!< crouch walking + Aspect_VKey_NavJump, //!< jump + Aspect_VKey_NavThrustForward, //!< increase continuous velocity in forward direction + Aspect_VKey_NavThrustBackward, //!< increase continuous velocity in reversed direction + Aspect_VKey_NavThrustStop, //!< reset continuous velocity + Aspect_VKey_NavSpeedIncrease, //!< increase navigation speed + Aspect_VKey_NavSpeedDecrease, //!< decrease navigation speed +}; + +//! Auxiliary ranges. +enum +{ + Aspect_VKey_Lower = 0, + Aspect_VKey_ModifiersLower = Aspect_VKey_Shift, + Aspect_VKey_ModifiersUpper = Aspect_VKey_Meta, + Aspect_VKey_NavigationKeysLower = Aspect_VKey_NavInteract, + Aspect_VKey_NavigationKeysUpper = Aspect_VKey_NavSpeedDecrease, + Aspect_VKey_Upper = Aspect_VKey_NavSpeedDecrease, + Aspect_VKey_NB = Aspect_VKey_Upper - Aspect_VKey_Lower + 1, + Aspect_VKey_MAX = 255 +}; + +//! Return modifier flags for specified modifier key. +inline Aspect_VKeyFlags Aspect_VKey2Modifier (Aspect_VKey theKey) +{ + switch (theKey) + { + case Aspect_VKey_Shift: return Aspect_VKeyFlags_SHIFT; + case Aspect_VKey_Control: return Aspect_VKeyFlags_CTRL; + case Aspect_VKey_Alt: return Aspect_VKeyFlags_ALT; + case Aspect_VKey_Menu: return Aspect_VKeyFlags_MENU; + case Aspect_VKey_Meta: return Aspect_VKeyFlags_META; + default: return 0; + } +} + +#endif // _Aspect_VKey_HeaderFile diff --git a/src/Aspect/Aspect_VKeyFlags.hxx b/src/Aspect/Aspect_VKeyFlags.hxx new file mode 100644 index 0000000000..865fb71ae0 --- /dev/null +++ b/src/Aspect/Aspect_VKeyFlags.hxx @@ -0,0 +1,49 @@ +// Copyright (c) 2016-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Aspect_VKeyFlags_HeaderFile +#define _Aspect_VKeyFlags_HeaderFile + +//! Key modifier, for combining with general key from Aspect_VKey. +typedef unsigned int Aspect_VKeyFlags; + +//! Key modifier, for combining with general key from Aspect_VKey. +enum +{ + Aspect_VKeyFlags_NONE = 0, + // reserve first 8 bits to combine value with Aspect_VKey + Aspect_VKeyFlags_SHIFT = 1 << 8, //!< Aspect_VKey_Shift + Aspect_VKeyFlags_CTRL = 1 << 9, //!< Aspect_VKey_Control + Aspect_VKeyFlags_ALT = 1 << 10, //!< Aspect_VKey_Alt + Aspect_VKeyFlags_MENU = 1 << 11, //!< Aspect_VKey_Menu + Aspect_VKeyFlags_META = 1 << 12, //!< Aspect_VKey_Meta + + Aspect_VKeyFlags_ALL = Aspect_VKeyFlags_SHIFT | Aspect_VKeyFlags_CTRL | Aspect_VKeyFlags_ALT | Aspect_VKeyFlags_MENU | Aspect_VKeyFlags_META +}; + +//! Mouse buttons, for combining with Aspect_VKey and Aspect_VKeyFlags. +typedef unsigned int Aspect_VKeyMouse; + +//! Mouse button bitmask +enum +{ + Aspect_VKeyMouse_NONE = 0, //!< no buttons + + Aspect_VKeyMouse_LeftButton = 1 << 13, //!< mouse left button + Aspect_VKeyMouse_MiddleButton = 1 << 14, //!< mouse middle button (scroll) + Aspect_VKeyMouse_RightButton = 1 << 15, //!< mouse right button + + Aspect_VKeyMouse_MainButtons = Aspect_VKeyMouse_LeftButton | Aspect_VKeyMouse_MiddleButton | Aspect_VKeyMouse_RightButton +}; + +#endif // _Aspect_VKeyFlags_HeaderFile diff --git a/src/Aspect/Aspect_VKeySet.cxx b/src/Aspect/Aspect_VKeySet.cxx new file mode 100644 index 0000000000..e5c8041624 --- /dev/null +++ b/src/Aspect/Aspect_VKeySet.cxx @@ -0,0 +1,150 @@ +// Copyright (c) 2016-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include "Aspect_VKeySet.hxx" + +IMPLEMENT_STANDARD_RTTIEXT(Aspect_VKeySet, Standard_Transient) + +// ================================================================ +// Function : As1pect_VKeySet +// Purpose : +// ================================================================ +Aspect_VKeySet::Aspect_VKeySet() +: myKeys (0, Aspect_VKey_MAX), + myModifiers (Aspect_VKeyFlags_NONE) +{ + // +} + +// ================================================================ +// Function : Reset +// Purpose : +// ================================================================ +void Aspect_VKeySet::Reset() +{ + Standard_Mutex::Sentry aLock (myLock); + myModifiers = 0; + for (NCollection_Array1::Iterator aKeyIter (myKeys); aKeyIter.More(); aKeyIter.Next()) + { + aKeyIter.ChangeValue().Reset(); + } +} + +// ================================================================ +// Function : KeyDown +// Purpose : +// ================================================================ +void Aspect_VKeySet::KeyDown (Aspect_VKey theKey, + double theTime, + double thePressure) +{ + Standard_Mutex::Sentry aLock (myLock); + if (myKeys[theKey].Status != KeyStatus_Pressed) + { + myKeys[theKey].Status = KeyStatus_Pressed; + myKeys[theKey].TimeDown = theTime; + } + myKeys[theKey].Pressure = thePressure; + + const unsigned int aModif = Aspect_VKey2Modifier (theKey); + myModifiers = myModifiers | aModif; +} + +// ================================================================ +// Function : KeyUp +// Purpose : +// ================================================================ +void Aspect_VKeySet::KeyUp (Aspect_VKey theKey, + double theTime) +{ + Standard_Mutex::Sentry aLock (myLock); + if (myKeys[theKey].Status == KeyStatus_Pressed) + { + myKeys[theKey].Status = KeyStatus_Released; + myKeys[theKey].TimeUp = theTime; + } + + const unsigned int aModif = Aspect_VKey2Modifier (theKey); + if (aModif != 0) + { + myModifiers = myModifiers & ~aModif; + } +} + +// ================================================================ +// Function : KeyFromAxis +// Purpose : +// ================================================================ +void Aspect_VKeySet::KeyFromAxis (Aspect_VKey theNegative, + Aspect_VKey thePositive, + double theTime, + double thePressure) +{ + Standard_Mutex::Sentry aLock (myLock); + if (thePressure != 0) + { + const Aspect_VKey aKeyDown = thePressure > 0 ? thePositive : theNegative; + const Aspect_VKey aKeyUp = thePressure < 0 ? thePositive : theNegative; + + KeyDown (aKeyDown, theTime, Abs (thePressure)); + if (myKeys[aKeyUp].Status == KeyStatus_Pressed) + { + KeyUp (aKeyUp, theTime); + } + } + else + { + if (myKeys[theNegative].Status == KeyStatus_Pressed) + { + KeyUp (theNegative, theTime); + } + if (myKeys[thePositive].Status == KeyStatus_Pressed) + { + KeyUp (thePositive, theTime); + } + } +} + +// ================================================================ +// Function : HoldDuration +// Purpose : +// ================================================================ +bool Aspect_VKeySet::HoldDuration (Aspect_VKey theKey, + double theTime, + double& theDuration, + double& thePressure) +{ + Standard_Mutex::Sentry aLock (myLock); + switch (myKeys[theKey].Status) + { + case KeyStatus_Free: + { + theDuration = 0.0; + return false; + } + case KeyStatus_Released: + { + myKeys[theKey].Status = KeyStatus_Free; + theDuration = myKeys[theKey].TimeUp - myKeys[theKey].TimeDown; + thePressure = myKeys[theKey].Pressure; + return true; + } + case KeyStatus_Pressed: + { + theDuration = theTime - myKeys[theKey].TimeDown; + thePressure = myKeys[theKey].Pressure; + return true; + } + } + return false; +} diff --git a/src/Aspect/Aspect_VKeySet.hxx b/src/Aspect/Aspect_VKeySet.hxx new file mode 100644 index 0000000000..bc7b3121be --- /dev/null +++ b/src/Aspect/Aspect_VKeySet.hxx @@ -0,0 +1,152 @@ +// Copyright (c) 2016-2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Aspect_VKeySet_HeaderFile +#define _Aspect_VKeySet_HeaderFile + +#include + +#include +#include +#include +#include + +//! Structure defining key state. +class Aspect_VKeySet : public Standard_Transient +{ + DEFINE_STANDARD_RTTIEXT(Aspect_VKeySet, Standard_Transient) +public: + + //! Main constructor. + Standard_EXPORT Aspect_VKeySet(); + + //! Return active modifiers. + Aspect_VKeyFlags Modifiers() const + { + Standard_Mutex::Sentry aLock (myLock); + return myModifiers; + } + + //! Return timestamp of press event. + double DownTime (Aspect_VKey theKey) const + { + Standard_Mutex::Sentry aLock (myLock); + return myKeys[theKey].TimeDown; + } + + //! Return timestamp of release event. + double TimeUp (Aspect_VKey theKey) const + { + Standard_Mutex::Sentry aLock (myLock); + return myKeys[theKey].TimeUp; + } + + //! Return TRUE if key is in Free state. + bool IsFreeKey (Aspect_VKey theKey) const + { + Standard_Mutex::Sentry aLock (myLock); + return myKeys[theKey].Status == KeyStatus_Free; + } + + //! Return TRUE if key is in Pressed state. + bool IsKeyDown (Aspect_VKey theKey) const + { + Standard_Mutex::Sentry aLock (myLock); + return myKeys[theKey].Status == KeyStatus_Pressed; + } + +public: + + //! Reset the key state into unpressed state. + Standard_EXPORT void Reset(); + + //! Press key. + //! @param theKey key pressed + //! @param theTime event timestamp + Standard_EXPORT void KeyDown (Aspect_VKey theKey, + double theTime, + double thePressure = 1.0); + + //! Release key. + //! @param theKey key pressed + //! @param theTime event timestamp + Standard_EXPORT void KeyUp (Aspect_VKey theKey, + double theTime); + + //! Simulate key up/down events from axis value. + Standard_EXPORT void KeyFromAxis (Aspect_VKey theNegative, + Aspect_VKey thePositive, + double theTime, + double thePressure); + + //! Return duration of the button in pressed state. + //! @param theKey key to check + //! @param theTime current time (for computing duration from key down time) + //! @param theDuration key press duration + //! @return TRUE if key was in pressed state + bool HoldDuration (Aspect_VKey theKey, + double theTime, + double& theDuration) + { + double aPressure = -1.0; + return HoldDuration (theKey, theTime, theDuration, aPressure); + } + + //! Return duration of the button in pressed state. + //! @param theKey key to check + //! @param theTime current time (for computing duration from key down time) + //! @param theDuration key press duration + //! @param thePressure key pressure + //! @return TRUE if key was in pressed state + Standard_EXPORT bool HoldDuration (Aspect_VKey theKey, + double theTime, + double& theDuration, + double& thePressure); + +private: + + //! Key state. + enum KeyStatus + { + KeyStatus_Free, //!< free status + KeyStatus_Pressed, //!< key is in pressed state + KeyStatus_Released, //!< key has been just released (transient state before KeyStatus_Free) + }; + + //! Structure defining key state. + struct KeyState + { + KeyState() : TimeDown (0.0), TimeUp (0.0), Pressure (1.0), Status (KeyStatus_Free) {} + void Reset() + { + Status = KeyStatus_Free; + TimeDown = 0.0; + TimeUp = 0.0; + Pressure = 1.0; + } + + double TimeDown; //!< time of key press event + double TimeUp; //!< time of key release event + double Pressure; //!< key pressure + KeyStatus Status; //!< key status + }; + +private: + + NCollection_Array1 myKeys; //!< keys state + mutable Standard_Mutex myLock; //!< mutex for thread-safe updates + Aspect_VKeyFlags myModifiers; //!< active modifiers + +}; + +#endif // _Aspect_VKeySet_HeaderFile diff --git a/src/Aspect/Aspect_Window.hxx b/src/Aspect/Aspect_Window.hxx index 2783f74518..5e5289bf46 100644 --- a/src/Aspect/Aspect_Window.hxx +++ b/src/Aspect/Aspect_Window.hxx @@ -16,28 +16,21 @@ #ifndef _Aspect_Window_HeaderFile #define _Aspect_Window_HeaderFile -#include -#include - #include #include #include #include -#include -#include #include #include #include -#include #include +#include +#include +#include +#include class Aspect_DisplayConnection; -class Aspect_WindowDefinitionError; -class Aspect_WindowError; -class Aspect_Background; -class Aspect_GradientBackground; -class Aspect_Window; DEFINE_STANDARD_HANDLE(Aspect_Window, Standard_Transient) //! Defines a window. @@ -109,6 +102,9 @@ public: //! Returns native Window FB config (GLXFBConfig on Xlib) Standard_EXPORT virtual Aspect_FBConfig NativeFBConfig() const = 0; + //! Sets window title. + virtual void SetTitle (const TCollection_AsciiString& theTitle) { (void )theTitle; } + //! Invalidate entire window content. //! //! Implementation is expected to allow calling this method from non-GUI thread, diff --git a/src/Aspect/FILES b/src/Aspect/FILES index c63cdf036f..933f271aac 100755 --- a/src/Aspect/FILES +++ b/src/Aspect/FILES @@ -34,6 +34,9 @@ Aspect_RectangularGrid.cxx Aspect_RectangularGrid.hxx Aspect_RenderingContext.hxx Aspect_SequenceOfColor.hxx +Aspect_ScrollDelta.hxx +Aspect_Touch.hxx +Aspect_TouchMap.hxx Aspect_TypeOfColorScaleData.hxx Aspect_TypeOfColorScaleOrientation.hxx Aspect_TypeOfColorScalePosition.hxx @@ -47,6 +50,10 @@ Aspect_TypeOfResize.hxx Aspect_TypeOfStyleText.hxx Aspect_TypeOfTriedronPosition.hxx Aspect_Units.hxx +Aspect_VKey.hxx +Aspect_VKeyFlags.hxx +Aspect_VKeySet.cxx +Aspect_VKeySet.hxx Aspect_WidthOfLine.hxx Aspect_Window.cxx Aspect_Window.hxx diff --git a/src/Cocoa/Cocoa_Window.hxx b/src/Cocoa/Cocoa_Window.hxx index dcfe0d37cf..694d84d0bf 100644 --- a/src/Cocoa/Cocoa_Window.hxx +++ b/src/Cocoa/Cocoa_Window.hxx @@ -47,6 +47,7 @@ #include #include #include +#include #include class Aspect_WindowDefinitionError; @@ -58,6 +59,10 @@ class Aspect_GradientBackground; //! This class defines Cocoa window class Cocoa_Window : public Aspect_Window { +public: + + //! Convert Carbon virtual key into Aspect_VKey. + Standard_EXPORT static Aspect_VKey VirtualKeyFromNative (Standard_Integer theKey); public: @@ -136,6 +141,9 @@ public: //! Returns nothing on OS X virtual Aspect_FBConfig NativeFBConfig() const Standard_OVERRIDE { return NULL; } + //! Sets window title. + Standard_EXPORT virtual void SetTitle (const TCollection_AsciiString& theTitle) Standard_OVERRIDE; + //! Invalidate entire window content by setting NSView::setNeedsDisplay property. //! Call will be implicitly redirected to the main thread when called from non-GUI thread. Standard_EXPORT virtual void InvalidateContent (const Handle(Aspect_DisplayConnection)& theDisp = NULL) Standard_OVERRIDE; diff --git a/src/Cocoa/Cocoa_Window.mm b/src/Cocoa/Cocoa_Window.mm index 2613a57419..5d6dc98803 100644 --- a/src/Cocoa/Cocoa_Window.mm +++ b/src/Cocoa/Cocoa_Window.mm @@ -403,6 +403,27 @@ void Cocoa_Window::Size (Standard_Integer& theWidth, theHeight = (Standard_Integer )aBounds.size.height; } +// ======================================================================= +// function : SetTitle +// purpose : +// ======================================================================= +void Cocoa_Window::SetTitle (const TCollection_AsciiString& theTitle) +{ + if (myHView == NULL) + { + return; + } + +#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE + (void )theTitle; +#else + NSWindow* aWindow = [myHView window]; + NSString* aTitleNS = [[NSString alloc] initWithUTF8String: theTitle.ToCString()]; + [aWindow setTitle: aTitleNS]; + [aTitleNS release]; +#endif +} + // ======================================================================= // function : InvalidateContent // purpose : @@ -429,3 +450,143 @@ void Cocoa_Window::InvalidateContent (const Handle(Aspect_DisplayConnection)& ) waitUntilDone: NO]; } } + +// ======================================================================= +// function : VirtualKeyFromNative +// purpose : +// ======================================================================= +Aspect_VKey Cocoa_Window::VirtualKeyFromNative (Standard_Integer theKey) +{ + switch (theKey) + { + case 0x00: return Aspect_VKey_A; + case 0x01: return Aspect_VKey_S; + case 0x02: return Aspect_VKey_D; + case 0x03: return Aspect_VKey_F; + case 0x04: return Aspect_VKey_H; + case 0x05: return Aspect_VKey_G; + case 0x06: return Aspect_VKey_Z; + case 0x07: return Aspect_VKey_X; + case 0x08: return Aspect_VKey_C; + case 0x09: return Aspect_VKey_V; + case 0x0A: return Aspect_VKey_UNKNOWN; + case 0x0B: return Aspect_VKey_B; + case 0x0C: return Aspect_VKey_Q; + case 0x0D: return Aspect_VKey_W; + case 0x0E: return Aspect_VKey_E; + case 0x0F: return Aspect_VKey_R; + case 0x10: return Aspect_VKey_Y; + case 0x11: return Aspect_VKey_T; + case 0x12: return Aspect_VKey_1; + case 0x13: return Aspect_VKey_2; + case 0x14: return Aspect_VKey_3; + case 0x15: return Aspect_VKey_4; + case 0x16: return Aspect_VKey_6; + case 0x17: return Aspect_VKey_5; + case 0x18: return Aspect_VKey_Plus; + case 0x19: return Aspect_VKey_9; + case 0x1A: return Aspect_VKey_7; + case 0x1B: return Aspect_VKey_Minus; + case 0x1C: return Aspect_VKey_8; + case 0x1D: return Aspect_VKey_0; + case 0x1E: return Aspect_VKey_BracketRight; + case 0x1F: return Aspect_VKey_O; + case 0x20: return Aspect_VKey_U; + case 0x21: return Aspect_VKey_BracketLeft; + case 0x22: return Aspect_VKey_I; + case 0x23: return Aspect_VKey_P; + case 0x24: return Aspect_VKey_Enter; + case 0x25: return Aspect_VKey_L; + case 0x26: return Aspect_VKey_J; + case 0x27: return Aspect_VKey_Apostrophe; + case 0x28: return Aspect_VKey_K; + case 0x29: return Aspect_VKey_Semicolon; + case 0x2A: return Aspect_VKey_Backslash; + case 0x2B: return Aspect_VKey_Comma; // 43, ',<' + case 0x2C: return Aspect_VKey_Slash; //ST_VK_OEM_2, // 44, '?/' + case 0x2D: return Aspect_VKey_N; + case 0x2E: return Aspect_VKey_M; + case 0x2F: return Aspect_VKey_Period; // 47, '.>' + case 0x30: return Aspect_VKey_Tab; + case 0x31: return Aspect_VKey_Space; + case 0x32: return Aspect_VKey_Tilde; // '~`' + case 0x33: return Aspect_VKey_Backspace; + case 0x34: return Aspect_VKey_UNKNOWN; + case 0x35: return Aspect_VKey_Escape; + case 0x36: return Aspect_VKey_UNKNOWN; // Aspect_VKey_Cmd, right Command + case 0x37: return Aspect_VKey_UNKNOWN; // Aspect_VKey_Cmd, left Command + case 0x38: return Aspect_VKey_Shift; // left shift + case 0x39: return Aspect_VKey_UNKNOWN; + case 0x3A: return Aspect_VKey_Alt; // left alt/option + case 0x3B: return Aspect_VKey_Control; + case 0x3C: return Aspect_VKey_Shift; // right shift + case 0x3D: return Aspect_VKey_Alt; // right alt/option + case 0x3E: return Aspect_VKey_UNKNOWN; + case 0x3F: return Aspect_VKey_UNKNOWN; // Aspect_VKey_Func, fn + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: return Aspect_VKey_UNKNOWN; + case 0x4C: return Aspect_VKey_Enter; // fn + return + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: return Aspect_VKey_UNKNOWN; + case 0x60: return Aspect_VKey_F5; + case 0x61: return Aspect_VKey_F6; + case 0x62: return Aspect_VKey_F7; + case 0x63: return Aspect_VKey_F3; + case 0x64: return Aspect_VKey_F8; + case 0x65: return Aspect_VKey_F9; + //case 0x66: return Aspect_VKey_UNKNOWN; + case 0x67: return Aspect_VKey_F11; + //case 0x68: return Aspect_VKey_UNKNOWN; + //case 0x69: return Aspect_VKey_UNKNOWN; + //case 0x6A: return Aspect_VKey_UNKNOWN; + //case 0x6B: return Aspect_VKey_UNKNOWN; + //case 0x6C: return Aspect_VKey_UNKNOWN; + case 0x6D: return Aspect_VKey_F10; + //case 0x6E: return Aspect_VKey_UNKNOWN; + case 0x6F: return Aspect_VKey_F12; + //case 0x70: return Aspect_VKey_UNKNOWN; + //case 0x71: return Aspect_VKey_UNKNOWN; + //case 0x72: return Aspect_VKey_UNKNOWN; + case 0x73: return Aspect_VKey_Home; + case 0x74: return Aspect_VKey_PageUp; + case 0x75: return Aspect_VKey_Delete; + case 0x76: return Aspect_VKey_F4; + case 0x77: return Aspect_VKey_End; + case 0x78: return Aspect_VKey_F2; + case 0x79: return Aspect_VKey_PageDown; + case 0x7A: return Aspect_VKey_F1; + case 0x7B: return Aspect_VKey_Left; + case 0x7C: return Aspect_VKey_Right; + case 0x7D: return Aspect_VKey_Down; + case 0x7E: return Aspect_VKey_Up; + case 0x7F: return Aspect_VKey_UNKNOWN; + } + return Aspect_VKey_UNKNOWN; +} diff --git a/src/QABugs/QABugs_1.cxx b/src/QABugs/QABugs_1.cxx index 3f8b3b01c4..e4c097ea94 100644 --- a/src/QABugs/QABugs_1.cxx +++ b/src/QABugs/QABugs_1.cxx @@ -57,8 +57,6 @@ extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS(); Standard_EXPORT ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS(); #endif -static TColStd_MapOfInteger theactivatedmodes(8); - #include #include #include diff --git a/src/V3d/V3d_View.cxx b/src/V3d/V3d_View.cxx index b67123ac85..61ae63bd2b 100644 --- a/src/V3d/V3d_View.cxx +++ b/src/V3d/V3d_View.cxx @@ -64,7 +64,8 @@ namespace //purpose : //============================================================================= V3d_View::V3d_View (const Handle(V3d_Viewer)& theViewer, const V3d_TypeOfView theType) -: MyViewer (theViewer.operator->()), +: myIsInvalidatedImmediate (Standard_True), + MyViewer (theViewer.operator->()), SwitchSetFront (Standard_False), myZRotation (Standard_False), myTrihedron (new V3d_Trihedron()), @@ -114,7 +115,8 @@ V3d_View::V3d_View (const Handle(V3d_Viewer)& theViewer, const V3d_TypeOfView th //purpose : //============================================================================= V3d_View::V3d_View (const Handle(V3d_Viewer)& theViewer, const Handle(V3d_View)& theView) -: MyViewer (theViewer.operator->()), +: myIsInvalidatedImmediate (Standard_True), + MyViewer (theViewer.operator->()), SwitchSetFront(Standard_False), myZRotation (Standard_False), MyTrsf (1, 4, 1, 4) @@ -228,6 +230,7 @@ void V3d_View::Update() const return; } + myIsInvalidatedImmediate = Standard_False; myView->Update(); myView->Compute(); myView->Redraw(); @@ -245,6 +248,7 @@ void V3d_View::Redraw() const return; } + myIsInvalidatedImmediate = Standard_False; Handle(Graphic3d_StructureManager) aStructureMgr = MyViewer->StructureManager(); for (Standard_Integer aRetryIter = 0; aRetryIter < 2; ++aRetryIter) { @@ -276,6 +280,7 @@ void V3d_View::RedrawImmediate() const return; } + myIsInvalidatedImmediate = Standard_False; myView->RedrawImmediate(); } @@ -1950,12 +1955,10 @@ Standard_Integer V3d_View::MinMax(Standard_Real& Xmin, } //======================================================================= -//function : Gravity +//function : GravityPoint //purpose : //======================================================================= -void V3d_View::Gravity (Standard_Real& theX, - Standard_Real& theY, - Standard_Real& theZ) const +gp_Pnt V3d_View::GravityPoint() const { Graphic3d_MapOfStructure aSetOfStructures; myView->DisplayedStructures (aSetOfStructures); @@ -2055,9 +2058,8 @@ void V3d_View::Gravity (Standard_Real& theX, { aResult /= aNbPoints; } - theX = aResult.X(); - theY = aResult.Y(); - theZ = aResult.Z(); + + return aResult; } //======================================================================= @@ -2513,8 +2515,10 @@ void V3d_View::StartRotation(const Standard_Integer X, Size(x,y); rx = Standard_Real(Convert(x)); ry = Standard_Real(Convert(y)); - Gravity(gx,gy,gz); - Rotate(0.,0.,0.,gx,gy,gz,Standard_True); + myRotateGravity = GravityPoint(); + Rotate (0.0, 0.0, 0.0, + myRotateGravity.X(), myRotateGravity.Y(), myRotateGravity.Z(), + Standard_True); myZRotation = Standard_False; if( zRotationThreshold > 0. ) { Standard_Real dx = Abs(sx - rx/2.); @@ -2546,7 +2550,9 @@ void V3d_View::Rotation(const Standard_Integer X, dy = (sy - Standard_Real(Y)) * M_PI / ry; } - Rotate(dx, dy, dz, gx, gy, gz, Standard_False); + Rotate (dx, dy, dz, + myRotateGravity.X(), myRotateGravity.Y(), myRotateGravity.Z(), + Standard_False); } //============================================================================= diff --git a/src/V3d/V3d_View.hxx b/src/V3d/V3d_View.hxx index d1e6129bf4..c27d6f8af5 100644 --- a/src/V3d/V3d_View.hxx +++ b/src/V3d/V3d_View.hxx @@ -148,6 +148,12 @@ public: //! Returns true if cached view content has been invalidated. Standard_EXPORT Standard_Boolean IsInvalidated() const; + //! Returns true if immediate layer content has been invalidated. + Standard_Boolean IsInvalidatedImmediate() const { return myIsInvalidatedImmediate; } + + //! Invalidates view content within immediate layer but does not redraw it. + void InvalidateImmediate() { myIsInvalidatedImmediate = Standard_True; } + //! Must be called when the window supporting the //! view changes size. //! if the view is not mapped on a window. @@ -939,6 +945,9 @@ public: //! Fills in the dictionary with statistic performance info. Standard_EXPORT void StatisticInformation (TColStd_IndexedDataMapOfStringString& theDict) const; + //! Returns the Objects number and the gravity center of ALL viewable points in the view + Standard_EXPORT gp_Pnt GravityPoint() const; + DEFINE_STANDARD_RTTIEXT(V3d_View,Standard_Transient) protected: @@ -976,10 +985,6 @@ private: //! the objects contained in the view Standard_EXPORT Standard_Integer MinMax (Standard_Real& Xmin, Standard_Real& Ymin, Standard_Real& Zmin, Standard_Real& Xmax, Standard_Real& Ymax, Standard_Real& Zmax) const; - //! Returns the Objects number and the gravity center - //! of ALL viewable points in the view - Standard_EXPORT void Gravity (Standard_Real& X, Standard_Real& Y, Standard_Real& Z) const; - Standard_EXPORT void Init(); //! Returns a new vertex when the grid is activated. @@ -996,6 +1001,7 @@ protected: Handle(Graphic3d_Camera) myDefaultCamera; Handle(Graphic3d_CView) myView; Standard_Boolean myImmediateUpdate; + mutable Standard_Boolean myIsInvalidatedImmediate; private: @@ -1009,9 +1015,7 @@ private: Standard_Integer sy; Standard_Real rx; Standard_Real ry; - Standard_Real gx; - Standard_Real gy; - Standard_Real gz; + gp_Pnt myRotateGravity; Standard_Boolean myComputedMode; Standard_Boolean SwitchSetFront; Standard_Boolean myZRotation; diff --git a/src/ViewerTest/FILES b/src/ViewerTest/FILES index 148e5e3019..2f929a17f5 100755 --- a/src/ViewerTest/FILES +++ b/src/ViewerTest/FILES @@ -8,10 +8,11 @@ ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx ViewerTest_DoubleMapOfInteractiveAndName.hxx ViewerTest_EventManager.cxx ViewerTest_EventManager.hxx -ViewerTest_EventManager.lxx ViewerTest_FilletCommands.cxx ViewerTest_ObjectCommands.cxx ViewerTest_OpenGlCommands.cxx ViewerTest_RelationCommands.cxx ViewerTest_ViewerCommands.cxx ViewerTest_ViewerCommands_1.mm +ViewerTest_V3dView.cxx +ViewerTest_V3dView.hxx diff --git a/src/ViewerTest/ViewerTest.cxx b/src/ViewerTest/ViewerTest.cxx index 6624596850..1ef047cec2 100644 --- a/src/ViewerTest/ViewerTest.cxx +++ b/src/ViewerTest/ViewerTest.cxx @@ -766,15 +766,7 @@ Standard_EXPORT Standard_Boolean VDisplayAISObject (const TCollection_AsciiStrin return ViewerTest::Display (theName, theObject, Standard_True, theReplaceIfExists); } -static TColStd_MapOfInteger theactivatedmodes(8); -static TColStd_ListOfTransient theEventMgrs; - -static void VwrTst_InitEventMgr(const Handle(V3d_View)& aView, - const Handle(AIS_InteractiveContext)& Ctx) -{ - theEventMgrs.Clear(); - theEventMgrs.Prepend(new ViewerTest_EventManager(aView, Ctx)); -} +static NCollection_List theEventMgrs; static Handle(V3d_View)& a3DView() { @@ -831,17 +823,15 @@ void ViewerTest::UnsetEventManager() void ViewerTest::ResetEventManager() { - const Handle(V3d_View) aView = ViewerTest::CurrentView(); - VwrTst_InitEventMgr(aView, ViewerTest::GetAISContext()); + theEventMgrs.Clear(); + theEventMgrs.Prepend (new ViewerTest_EventManager (ViewerTest::CurrentView(), ViewerTest::GetAISContext())); } Handle(ViewerTest_EventManager) ViewerTest::CurrentEventManager() { - Handle(ViewerTest_EventManager) EM; - if(theEventMgrs.IsEmpty()) return EM; - Handle(Standard_Transient) Tr = theEventMgrs.First(); - EM = Handle(ViewerTest_EventManager)::DownCast (Tr); - return EM; + return !theEventMgrs.IsEmpty() + ? theEventMgrs.First() + : Handle(ViewerTest_EventManager)(); } //======================================================================= diff --git a/src/ViewerTest/ViewerTest_EventManager.cxx b/src/ViewerTest/ViewerTest_EventManager.cxx index 661a078c18..d2e8105451 100644 --- a/src/ViewerTest/ViewerTest_EventManager.cxx +++ b/src/ViewerTest/ViewerTest_EventManager.cxx @@ -17,9 +17,12 @@ #include #include +#include #include -#include -#include +#include +#include + +Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand); IMPLEMENT_STANDARD_RTTIEXT(ViewerTest_EventManager,Standard_Transient) @@ -31,204 +34,309 @@ ViewerTest_EventManager::ViewerTest_EventManager (const Handle(V3d_View)& const Handle(AIS_InteractiveContext)& theCtx) : myCtx (theCtx), myView (theView), - myX (-1), - myY (-1) + myToPickPnt (Standard_False) {} //======================================================================= -//function : MoveTo +//function : UpdateMouseButtons //purpose : //======================================================================= - -void ViewerTest_EventManager::MoveTo (const Standard_Integer theXPix, - const Standard_Integer theYPix) +bool ViewerTest_EventManager::UpdateMouseButtons (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButtons, + Aspect_VKeyFlags theModifiers, + bool theIsEmulated) { - Standard_Real aPnt3d[3] = {0.0, 0.0, 0.0}; - if (!myCtx.IsNull() - && !myView.IsNull()) + SetAllowRotation (!ViewerTest_V3dView::IsCurrentViewIn2DMode()); + + if (theButtons == Aspect_VKeyMouse_LeftButton) { - const Standard_Boolean toEchoGrid = myView->Viewer()->Grid()->IsActive() - && myView->Viewer()->GridEcho(); - switch (myCtx->MoveTo (theXPix, theYPix, myView, !toEchoGrid)) + if (myToPickPnt && (theModifiers & Aspect_VKeyFlags_CTRL) != 0) { - case AIS_SOD_Nothing: - { - if (toEchoGrid) - { - myView->ConvertToGrid (theXPix, theYPix, aPnt3d[0], aPnt3d[1], aPnt3d[2]); - myView->Viewer()->ShowGridEcho (myView, Graphic3d_Vertex (aPnt3d[0], aPnt3d[1], aPnt3d[2])); - myView->RedrawImmediate(); - } - break; - } - default: - { - if (toEchoGrid) - { - myView->Viewer()->HideGridEcho (myView); - myView->RedrawImmediate(); - } - break; - } + 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; } } - myX = theXPix; - myY = theYPix; + return AIS_ViewController::UpdateMouseButtons (thePoint, theButtons, theModifiers, theIsEmulated); } -//======================================================================= -//function : Select +//============================================================================== +//function : ProcessExpose //purpose : -//======================================================================= - -void ViewerTest_EventManager::Select (const Standard_Integer theXPressed, - const Standard_Integer theYPressed, - const Standard_Integer theXMotion, - const Standard_Integer theYMotion, - const Standard_Boolean theIsAutoAllowOverlap) +//============================================================================== +void ViewerTest_EventManager::ProcessExpose() { - if (myView.IsNull() - || myCtx.IsNull() - || Abs (theXPressed - theXMotion) < 2 - || Abs (theYPressed - theYMotion) < 2) - { - return; - } - - if (theIsAutoAllowOverlap) - { - const Standard_Boolean toAllowOverlap = theYPressed != Min (theYPressed, theYMotion); - myCtx->MainSelector()->AllowOverlapDetection (toAllowOverlap); - } - myCtx->Select (Min (theXPressed, theXMotion), - Min (theYPressed, theYMotion), - Max (theXPressed, theXMotion), - Max (theYPressed, theYMotion), - myView, - Standard_False); - - // to restore default state of viewer selector - if (theIsAutoAllowOverlap) + if (!myView.IsNull()) { - myCtx->MainSelector()->AllowOverlapDetection (Standard_False); + myView->Invalidate(); + FlushViewEvents (myCtx, myView, true); } - myView->Redraw(); } -//======================================================================= -//function : ShiftSelect +//============================================================================== +//function : ProcessConfigure //purpose : -//======================================================================= - -void ViewerTest_EventManager::ShiftSelect (const Standard_Integer theXPressed, - const Standard_Integer theYPressed, - const Standard_Integer theXMotion, - const Standard_Integer theYMotion, - const Standard_Boolean theIsAutoAllowOverlap) +//============================================================================== +void ViewerTest_EventManager::ProcessConfigure() { - if (myView.IsNull() - || myCtx.IsNull() - || Abs (theXPressed - theXMotion) < 2 - || Abs (theYPressed - theYMotion) < 2) + if (!myView.IsNull()) { - return; + myView->MustBeResized(); + FlushViewEvents (myCtx, myView, true); } - - if (theIsAutoAllowOverlap) - { - const Standard_Boolean toAllowOverlap = theYPressed != Min (theYPressed, theYMotion); - myCtx->MainSelector()->AllowOverlapDetection (toAllowOverlap); - } - myCtx->ShiftSelect (Min (theXPressed, theXMotion), - Min (theYPressed, theYMotion), - Max (theXPressed, theXMotion), - Max (theYPressed, theYMotion), - myView, - Standard_False); - - // to restore default state of viewer selector - if (theIsAutoAllowOverlap) - { - myCtx->MainSelector()->AllowOverlapDetection (Standard_False); - } - myView->Redraw(); } //======================================================================= -//function : Select +//function : KeyUp //purpose : //======================================================================= - -void ViewerTest_EventManager::Select() +void ViewerTest_EventManager::KeyUp (Aspect_VKey theKey, + double theTime) { - if (myView.IsNull() - || myCtx.IsNull()) - { - return; - } - - myCtx->Select (Standard_False); - myView->Redraw(); + AIS_ViewController::KeyUp (theKey, theTime); + ProcessKeyPress (theKey); } -//======================================================================= -//function : ShiftSelect +//============================================================================== +//function : ProcessKeyPress //purpose : -//======================================================================= - -void ViewerTest_EventManager::ShiftSelect() +//============================================================================== +void ViewerTest_EventManager::ProcessKeyPress (Aspect_VKey theKey) { - if (myView.IsNull() - || myCtx.IsNull()) + if (myCtx.IsNull() + || myView.IsNull()) { return; } - myCtx->ShiftSelect (Standard_False); - myView->Redraw(); -} - -//======================================================================= -//function : Select -//purpose : Selection with polyline -//======================================================================= - -void ViewerTest_EventManager::Select (const TColgp_Array1OfPnt2d& thePolyline) -{ - if (myView.IsNull() - || myCtx.IsNull()) + switch (theKey) { - return; - } - - myCtx->Select (thePolyline, myView, Standard_False); - myView->Redraw(); -} + case Aspect_VKey_A: // AXO + { + if (!ViewerTest_V3dView::IsCurrentViewIn2DMode()) + { + myView->SetProj(V3d_XposYnegZpos); + } + break; + } + case Aspect_VKey_D: // Reset + { + if (!ViewerTest_V3dView::IsCurrentViewIn2DMode()) + { + myView->Reset(); + } + 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: + case Aspect_VKey_W: + { + Standard_Integer aDispMode = AIS_Shaded; + if (theKey == Aspect_VKey_S) + { + aDispMode = AIS_Shaded; + std::cout << "setup Shaded display mode\n"; + } + else + { + aDispMode = AIS_WireFrame; + std::cout << "setup WireFrame display mode\n"; + } -//======================================================================= -//function : ShiftSelect -//purpose : Selection with polyline without erasing of current selection -//======================================================================= + 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"); + } + } + } -void ViewerTest_EventManager::ShiftSelect (const TColgp_Array1OfPnt2d& thePolyline) -{ - if (myView.IsNull() - || myCtx.IsNull()) + if (theKey >= Aspect_VKey_0 + && theKey <= Aspect_VKey_7) { - return; + 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()); } - - myCtx->ShiftSelect (thePolyline, myView, Standard_False); - myView->Redraw(); -} - -//======================================================================= -//function : GetCurrentPosition -//purpose : -//======================================================================= -void ViewerTest_EventManager::GetCurrentPosition (Standard_Integer& theXPix, Standard_Integer& theYPix) const -{ - theXPix = myX; - theYPix = myY; } diff --git a/src/ViewerTest/ViewerTest_EventManager.hxx b/src/ViewerTest/ViewerTest_EventManager.hxx index 05352ce608..25f23db883 100644 --- a/src/ViewerTest/ViewerTest_EventManager.hxx +++ b/src/ViewerTest/ViewerTest_EventManager.hxx @@ -17,76 +17,85 @@ #ifndef _ViewerTest_EventManager_HeaderFile #define _ViewerTest_EventManager_HeaderFile -#include -#include - -#include -#include -#include +#include #include +#include + class AIS_InteractiveContext; class V3d_View; - -class ViewerTest_EventManager; DEFINE_STANDARD_HANDLE(ViewerTest_EventManager, Standard_Transient) //! used to manage mouse event (move,select,shiftselect) //! By default the events are transmitted to interactive context. -class ViewerTest_EventManager : public Standard_Transient +class ViewerTest_EventManager : public Standard_Transient, public AIS_ViewController { - + DEFINE_STANDARD_RTTIEXT(ViewerTest_EventManager, Standard_Transient) public: - - Standard_EXPORT ViewerTest_EventManager(const Handle(V3d_View)& aView, const Handle(AIS_InteractiveContext)& aCtx); - - Standard_EXPORT virtual void MoveTo (const Standard_Integer xpix, const Standard_Integer ypix); - - Standard_EXPORT virtual void Select(); - - Standard_EXPORT virtual void ShiftSelect(); - - Standard_EXPORT virtual void Select (const Standard_Integer theXPressed, const Standard_Integer theYPressed, const Standard_Integer theXMotion, const Standard_Integer theYMotion, const Standard_Boolean theIsAutoAllowOverlap = Standard_True); - - Standard_EXPORT virtual void ShiftSelect (const Standard_Integer theXPressed, const Standard_Integer theYPressed, const Standard_Integer theXMotion, const Standard_Integer theYMotion, const Standard_Boolean theIsAutoAllowOverlap = Standard_True); - - Standard_EXPORT virtual void Select (const TColgp_Array1OfPnt2d& thePolyline); - - Standard_EXPORT virtual void ShiftSelect (const TColgp_Array1OfPnt2d& thePolyline); - - const Handle(AIS_InteractiveContext)& Context() const; - - //! Gets current mouse position. It tracks change of mouse position - //! with mouse drugging or with DRAW command call (vmoveto). - Standard_EXPORT void GetCurrentPosition (Standard_Integer& theXPix, Standard_Integer& theYPix) const; - - - - - DEFINE_STANDARD_RTTIEXT(ViewerTest_EventManager,Standard_Transient) - -protected: + //! Return TRUE if View should be closed on escape. + static Standard_Boolean& ToCloseViewOnEscape() + { + static Standard_Boolean Draw_ToCloseViewOnEsc = Standard_False; + return Draw_ToCloseViewOnEsc; + } + //! Return TRUE if Draw Harness should exit on closing View. + static Standard_Boolean& ToExitOnCloseView() + { + static Standard_Boolean Draw_ToExitOnCloseView = Standard_False; + return Draw_ToExitOnCloseView; + } +public: + //! Main constructor. + Standard_EXPORT ViewerTest_EventManager(const Handle(V3d_View)& aView, const Handle(AIS_InteractiveContext)& aCtx); + + //! Return interactive context. + const Handle(AIS_InteractiveContext)& Context() const { return myCtx; } + + //! Returns TRUE if picking point mode has been enabled (for VPick command). + Standard_Boolean ToPickPoint() const { return myToPickPnt; } + + //! Start picking point for VPick command. + void StartPickPoint (const char* theArgX, + const char* theArgY, + const char* theArgZ) + { + myToPickPnt = Standard_True; + myPickPntArgVec[0] = theArgX; + myPickPntArgVec[1] = theArgY; + myPickPntArgVec[2] = theArgZ; + } + + //! Handle mouse button press/release event. + Standard_EXPORT virtual bool UpdateMouseButtons (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButtons, + Aspect_VKeyFlags theModifiers, + bool theIsEmulated) Standard_OVERRIDE; + + //! Release key. + Standard_EXPORT virtual void KeyUp (Aspect_VKey theKey, + double theTime) Standard_OVERRIDE; + + //! Redraw the View on an Expose Event + Standard_EXPORT virtual void ProcessExpose(); + + //! Resize View. + Standard_EXPORT virtual void ProcessConfigure(); + + //! Handle KeyPress event. + Standard_EXPORT void ProcessKeyPress (Aspect_VKey theKey); private: - Handle(AIS_InteractiveContext) myCtx; Handle(V3d_View) myView; - Standard_Integer myX; - Standard_Integer myY; + TCollection_AsciiString myPickPntArgVec[3]; + Standard_Boolean myToPickPnt; }; - -#include - - - - - #endif // _ViewerTest_EventManager_HeaderFile diff --git a/src/ViewerTest/ViewerTest_ObjectCommands.cxx b/src/ViewerTest/ViewerTest_ObjectCommands.cxx index 954861d568..5b9560c0dc 100644 --- a/src/ViewerTest/ViewerTest_ObjectCommands.cxx +++ b/src/ViewerTest/ViewerTest_ObjectCommands.cxx @@ -159,7 +159,6 @@ extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS(); extern Standard_Boolean VDisplayAISObject (const TCollection_AsciiString& theName, const Handle(AIS_InteractiveObject)& theAISObj, Standard_Boolean theReplaceIfExists = Standard_True); -extern int ViewerMainLoop(Standard_Integer argc, const char** argv); extern Handle(AIS_InteractiveContext)& TheAISContext(); namespace diff --git a/src/ViewerTest/ViewerTest_V3dView.cxx b/src/ViewerTest/ViewerTest_V3dView.cxx new file mode 100644 index 0000000000..cee18f9438 --- /dev/null +++ b/src/ViewerTest/ViewerTest_V3dView.cxx @@ -0,0 +1,71 @@ +// Copyright (c) 2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include + +IMPLEMENT_STANDARD_RTTIEXT(ViewerTest_V3dView, V3d_View) + +// ======================================================================= +// function : ViewerTest_V3dView +// purpose : +// ======================================================================= +ViewerTest_V3dView::ViewerTest_V3dView (const Handle(V3d_Viewer)& theViewer, + const V3d_TypeOfView theType, + bool theIs2dMode) +: V3d_View (theViewer, theType), + myIs2dMode (theIs2dMode) +{ + // +} + +// ======================================================================= +// function : ViewerTest_V3dView +// purpose : +// ======================================================================= +ViewerTest_V3dView::ViewerTest_V3dView (const Handle(V3d_Viewer)& theViewer, + const Handle(V3d_View)& theView) +: V3d_View (theViewer, theView), + myIs2dMode (false) +{ + if (Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (theView)) + { + myIs2dMode = aV3dView->IsViewIn2DMode(); + } +} + +// ======================================================================= +// function : IsCurrentViewIn2DMode +// purpose : +// ======================================================================= +bool ViewerTest_V3dView::IsCurrentViewIn2DMode() +{ + if (Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView())) + { + return aV3dView->IsViewIn2DMode(); + } + return false; +} + +// ======================================================================= +// function : SetCurrentView2DMode +// purpose : +// ======================================================================= +void ViewerTest_V3dView::SetCurrentView2DMode (bool theIs2d) +{ + if (Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView())) + { + aV3dView->SetView2DMode (theIs2d); + } +} diff --git a/src/ViewerTest/ViewerTest_V3dView.hxx b/src/ViewerTest/ViewerTest_V3dView.hxx new file mode 100644 index 0000000000..6eda37acee --- /dev/null +++ b/src/ViewerTest/ViewerTest_V3dView.hxx @@ -0,0 +1,53 @@ +// Copyright (c) 2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _ViewerTest_V3dView_HeaderFile +#define _ViewerTest_V3dView_HeaderFile + +#include + +//! Setting additional flag to store 2D mode of the View to avoid scene rotation by mouse/key events +class ViewerTest_V3dView : public V3d_View +{ + DEFINE_STANDARD_RTTIEXT(ViewerTest_V3dView, V3d_View) +public: + //! Initializes the view. + Standard_EXPORT ViewerTest_V3dView (const Handle(V3d_Viewer)& theViewer, + const V3d_TypeOfView theType = V3d_ORTHOGRAPHIC, + bool theIs2dMode = false); + + //! Initializes the view by copying. + Standard_EXPORT ViewerTest_V3dView (const Handle(V3d_Viewer)& theViewer, + const Handle(V3d_View)& theView); + + //! Returns true if 2D mode is set for the view + bool IsViewIn2DMode() const { return myIs2dMode; } + + //! Sets 2D mode for the view + void SetView2DMode (bool the2dMode) { myIs2dMode = the2dMode; } + +public: + + //! Returns true if active view in 2D mode. + Standard_EXPORT static bool IsCurrentViewIn2DMode(); + + //! Set if active view in 2D mode. + Standard_EXPORT static void SetCurrentView2DMode (bool theIs2d); + +private: + + Standard_Boolean myIs2dMode; //!< 2D mode flag + +}; + +#endif // _ViewerTest_V3dView_HeaderFile diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 523c03bab2..f4801fee97 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -15,80 +15,71 @@ // commercial license or contractual agreement. #include +#include -#include #include #include #include #include -#include -#include -#include -#include +#include #include #include +#include +#include +#include #include -#include +#include +#include +#include +#include #include +#include +#include +#include #include +#include #include -#include +#include #include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include -#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#ifdef _WIN32 -#undef DrawText -#endif - #include #if defined(_WIN32) @@ -103,10 +94,6 @@ #include #endif -// Auxiliary definitions -static const char THE_KEY_DELETE = 127; -static const char THE_KEY_ESCAPE = 27; - //============================================================================== // VIEWER GLOBAL VARIABLES //============================================================================== @@ -117,10 +104,6 @@ Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand); Standard_EXPORT int ViewerMainLoop(Standard_Integer , const char** argv); extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS(); -extern int VErase (Draw_Interpretor& theDI, - Standard_Integer theArgNb, - const char** theArgVec); - #if defined(_WIN32) static Handle(WNT_Window)& VT_GetWindow() { static Handle(WNT_Window) WNTWin; @@ -133,7 +116,6 @@ static Handle(Cocoa_Window)& VT_GetWindow() return aWindow; } extern void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow); -extern void SetCocoaWindowTitle (const Handle(Cocoa_Window)& theWindow, Standard_CString theTitle); extern void GetCocoaScreenResolution (Standard_Integer& theWidth, Standard_Integer& theHeight); #else @@ -156,76 +138,6 @@ static void SetDisplayConnection (const Handle(Aspect_DisplayConnection)& theDis GetDisplayConnection() = theDisplayConnection; } -#if defined(_WIN32) || (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) -Aspect_Handle GetWindowHandle(const Handle(Aspect_Window)& theWindow) -{ - Aspect_Handle aWindowHandle = (Aspect_Handle)NULL; -#if defined(_WIN32) - const Handle (WNT_Window) aWindow = Handle(WNT_Window)::DownCast (theWindow); - if (!aWindow.IsNull()) - return aWindow->HWindow(); -#elif (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) - const Handle (Xw_Window) aWindow = Handle(Xw_Window)::DownCast (theWindow); - if (!aWindow.IsNull()) - return aWindow->XWindow(); -#endif - return aWindowHandle; -} -#endif - -//! Setting additional flag to store 2D mode of the View to avoid scene rotation by mouse/key events -class ViewerTest_V3dView : public V3d_View -{ - DEFINE_STANDARD_RTTI_INLINE(ViewerTest_V3dView, V3d_View) -public: - //! Initializes the view. - ViewerTest_V3dView (const Handle(V3d_Viewer)& theViewer, const V3d_TypeOfView theType = V3d_ORTHOGRAPHIC, - bool theIs2dMode = false) - : V3d_View (theViewer, theType), myIs2dMode (theIs2dMode) {} - - //! Initializes the view by copying. - ViewerTest_V3dView (const Handle(V3d_Viewer)& theViewer, const Handle(V3d_View)& theView) - : V3d_View (theViewer, theView), myIs2dMode (false) - { - if (Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (theView)) - { - myIs2dMode = aV3dView->IsViewIn2DMode(); - } - } - - //! Returns true if 2D mode is set for the view - bool IsViewIn2DMode() const { return myIs2dMode; } - - //! Sets 2D mode for the view - void SetView2DMode (bool the2dMode) { myIs2dMode = the2dMode; } - -public: - - //! Returns true if active view in 2D mode. - static bool IsCurrentViewIn2DMode() - { - if (Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView())) - { - return aV3dView->IsViewIn2DMode(); - } - return false; - } - - //! Set if active view in 2D mode. - static void SetCurrentView2DMode (bool theIs2d) - { - if (Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView())) - { - aV3dView->SetView2DMode (theIs2d); - } - } - -private: - - Standard_Boolean myIs2dMode; //!< 2D mode flag - -}; - NCollection_DoubleMap ViewerTest_myViews; static NCollection_DoubleMap ViewerTest_myContexts; static NCollection_DoubleMap ViewerTest_myDrivers; @@ -245,17 +157,7 @@ static struct // EVENT GLOBAL VARIABLES //============================================================================== -static int Start_Rot = 0; -Standard_Boolean HasHlrOnBeforeRotation = Standard_False; -int X_Motion = 0; // Current cursor position -int Y_Motion = 0; -int X_ButtonPress = 0; // Last ButtonPress position -int Y_ButtonPress = 0; -Standard_Boolean IsDragged = Standard_False; -Standard_Boolean DragFirst = Standard_False; Standard_Boolean TheIsAnimating = Standard_False; -Standard_Boolean Draw_ToExitOnCloseView = Standard_False; -Standard_Boolean Draw_ToCloseViewOnEsc = Standard_False; namespace { @@ -1281,17 +1183,6 @@ namespace } // namespace -Standard_EXPORT const Handle(AIS_RubberBand)& GetRubberBand() -{ - static Handle(AIS_RubberBand) aBand; - if (aBand.IsNull()) - { - aBand = new AIS_RubberBand (Quantity_NOC_LIGHTBLUE, Aspect_TOL_SOLID, Quantity_NOC_LIGHTBLUE, 0.4, 1.0); - aBand->SetDisplayMode (0); - } - return aBand; -} - typedef NCollection_Map ViewerTest_MapOfAISManipulators; Standard_EXPORT ViewerTest_MapOfAISManipulators& GetMapOfAISManipulators() @@ -1529,30 +1420,6 @@ Handle(AIS_InteractiveContext) FindContextByView (const Handle(V3d_View)& theVie return anAISContext; } - -//============================================================================== -//function : SetWindowTitle -//purpose : Set window title -//============================================================================== - -void SetWindowTitle (const Handle(Aspect_Window)& theWindow, - Standard_CString theTitle) -{ -#if defined(_WIN32) - const TCollection_ExtendedString theTitleW (theTitle); - SetWindowTextW ((HWND )Handle(WNT_Window)::DownCast(theWindow)->HWindow(), theTitleW.ToWideString()); -#elif defined(__APPLE__) && !defined(MACOSX_USE_GLX) - SetCocoaWindowTitle (Handle(Cocoa_Window)::DownCast(theWindow), theTitle); -#else - if(GetDisplayConnection()->GetDisplay()) - { - Window aWindow = - Handle(Xw_Window)::DownCast(theWindow)->XWindow(); - XStoreName (GetDisplayConnection()->GetDisplay(), aWindow , theTitle); - } -#endif -} - //============================================================================== //function : IsWindowOverlapped //purpose : Check if theWindow overlapp another view @@ -1853,12 +1720,9 @@ TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft aTitle = aTitle + aViewNames.GetViewName() + "(*)"; // Change name of current active window - if (!ViewerTest::CurrentView().IsNull()) + if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView()) { - TCollection_AsciiString anActiveWindowTitle("3D View - "); - anActiveWindowTitle = anActiveWindowTitle - + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()); - SetWindowTitle (ViewerTest::CurrentView()->Window(), anActiveWindowTitle.ToCString()); + aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView)); } // Create viewer @@ -2036,9 +1900,9 @@ static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const cha } else if (anArgCase == "-exitonclose") { - Draw_ToExitOnCloseView = true; + ViewerTest_EventManager::ToExitOnCloseView() = true; if (anArgIt + 1 < theArgsNb - && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], Draw_ToExitOnCloseView)) + && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToExitOnCloseView())) { ++anArgIt; } @@ -2046,9 +1910,9 @@ static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const cha else if (anArgCase == "-closeonescape" || anArgCase == "-closeonesc") { - Draw_ToCloseViewOnEsc = true; + ViewerTest_EventManager::ToCloseViewOnEscape() = true; if (anArgIt + 1 < theArgsNb - && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], Draw_ToCloseViewOnEsc)) + && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToCloseViewOnEscape())) { ++anArgIt; } @@ -2400,13 +2264,13 @@ static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** arg //function : FindViewIdByWindowHandle //purpose : Find theView Id in the map of views by window handle //============================================================================== -#if defined(_WIN32) || defined(__WIN32__) || (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) -TCollection_AsciiString FindViewIdByWindowHandle(const Aspect_Handle theWindowHandle) +#if defined(_WIN32) || (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) +TCollection_AsciiString FindViewIdByWindowHandle (Aspect_Drawable theWindowHandle) { for (NCollection_DoubleMap::Iterator anIter(ViewerTest_myViews); anIter.More(); anIter.Next()) { - Aspect_Handle aWindowHandle = GetWindowHandle(anIter.Value()->Window()); + Aspect_Drawable aWindowHandle = anIter.Value()->Window()->NativeHandle(); if (aWindowHandle == theWindowHandle) return anIter.Key1(); } @@ -2427,17 +2291,14 @@ void ActivateView (const TCollection_AsciiString& theViewName, Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView); if (!anAISContext.IsNull()) { - if (!ViewerTest::CurrentView().IsNull()) + if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView()) { - TCollection_AsciiString aTitle("3D View - "); - aTitle = aTitle + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()); - SetWindowTitle (ViewerTest::CurrentView()->Window(), aTitle.ToCString()); + aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView)); } ViewerTest::CurrentView (aView); ViewerTest::SetAISContext (anAISContext); - TCollection_AsciiString aTitle = TCollection_AsciiString("3D View - ") + theViewName + "(*)"; - SetWindowTitle (ViewerTest::CurrentView()->Window(), aTitle.ToCString()); + aView->Window()->SetTitle (TCollection_AsciiString("3D View - ") + theViewName + "(*)"); #if defined(_WIN32) VT_GetWindow() = Handle(WNT_Window)::DownCast(ViewerTest::CurrentView()->Window()); #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX) @@ -2559,7 +2420,7 @@ void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const S } } cout << "3D View - " << theViewName << " was deleted.\n"; - if (Draw_ToExitOnCloseView) + if (ViewerTest_EventManager::ToExitOnCloseView()) { Draw_Interprete ("exit"); } @@ -2654,9 +2515,7 @@ static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const && aNameString.IsEmpty() && anArg == "none") { - TCollection_AsciiString aTitle("3D View - "); - aTitle = aTitle + ViewerTest_myViews.Find2(ViewerTest::CurrentView()); - SetWindowTitle (ViewerTest::CurrentView()->Window(), aTitle.ToCString()); + ViewerTest::CurrentView()->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (ViewerTest::CurrentView())); VT_GetWindow().Nullify(); ViewerTest::CurrentView (Handle(V3d_View)()); ViewerTest::ResetEventManager(); @@ -2772,413 +2631,19 @@ static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const } //============================================================================== -//function : VT_ProcessKeyPress -//purpose : Handle KeyPress event from a CString -//============================================================================== -void VT_ProcessKeyPress (const char* buf_ret) -{ - //cout << "KeyPress" << endl; - const Handle(V3d_View) aView = ViewerTest::CurrentView(); - // Letter in alphabetic order - - if (!strcasecmp (buf_ret, "A") - && !ViewerTest_V3dView::IsCurrentViewIn2DMode()) - { - // AXO - aView->SetProj(V3d_XposYnegZpos); - } - else if (!strcasecmp (buf_ret, "D") - && !ViewerTest_V3dView::IsCurrentViewIn2DMode()) - { - // Reset - aView->Reset(); - } - else if (!strcasecmp (buf_ret, "F")) - { - if (ViewerTest::GetAISContext()->NbSelected() > 0) - { - ViewerTest::GetAISContext()->FitSelected (aView); - } - else - { - // FitAll - aView->FitAll(); - } - } - else if (!strcasecmp (buf_ret, "H")) - { - // HLR - std::cout << "HLR" << std::endl; - aView->SetComputedMode (!aView->ComputedMode()); - aView->Redraw(); - } - else if (!strcasecmp (buf_ret, "P")) - { - // Type of HLR - Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext(); - if (aContext->DefaultDrawer()->TypeOfHLR() == Prs3d_TOH_Algo) - aContext->DefaultDrawer()->SetTypeOfHLR(Prs3d_TOH_PolyAlgo); - else - aContext->DefaultDrawer()->SetTypeOfHLR(Prs3d_TOH_Algo); - if (aContext->NbSelected()==0) - { - AIS_ListOfInteractive aListOfShapes; - aContext->DisplayedObjects(aListOfShapes); - for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes); - anIter.More(); anIter.Next()) - { - Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value()); - if (aShape.IsNull()) - continue; - if (aShape->TypeOfHLR() == Prs3d_TOH_PolyAlgo) - aShape->SetTypeOfHLR (Prs3d_TOH_Algo); - else - aShape->SetTypeOfHLR (Prs3d_TOH_PolyAlgo); - aContext->Redisplay (aShape, Standard_False); - } - } - else - { - for (aContext->InitSelected();aContext->MoreSelected();aContext->NextSelected()) - { - Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(aContext->SelectedInteractive()); - if (aShape.IsNull()) - continue; - if(aShape->TypeOfHLR() == Prs3d_TOH_PolyAlgo) - aShape->SetTypeOfHLR (Prs3d_TOH_Algo); - else - aShape->SetTypeOfHLR (Prs3d_TOH_PolyAlgo); - aContext->Redisplay (aShape, Standard_False); - } - } - - aContext->UpdateCurrentViewer(); - - } - else if (!strcasecmp (buf_ret, "S")) - { - std::cout << "setup Shaded display mode" << std::endl; - - Handle(AIS_InteractiveContext) Ctx = ViewerTest::GetAISContext(); - if(Ctx->NbSelected()==0) - Ctx->SetDisplayMode (AIS_Shaded, Standard_True); - else{ - for(Ctx->InitSelected();Ctx->MoreSelected();Ctx->NextSelected()) - Ctx->SetDisplayMode(Ctx->SelectedInteractive(),1,Standard_False); - Ctx->UpdateCurrentViewer(); - } - } - else if (!strcasecmp (buf_ret, "U")) - { - // Unset display mode - std::cout << "reset display mode to defaults" << std::endl; - - Handle(AIS_InteractiveContext) Ctx = ViewerTest::GetAISContext(); - if(Ctx->NbSelected()==0) - Ctx->SetDisplayMode (AIS_WireFrame, Standard_True); - else{ - for(Ctx->InitSelected();Ctx->MoreSelected();Ctx->NextSelected()) - Ctx->UnsetDisplayMode(Ctx->SelectedInteractive(),Standard_False); - Ctx->UpdateCurrentViewer(); - } - - } - else if (!strcasecmp (buf_ret, "T") - && !ViewerTest_V3dView::IsCurrentViewIn2DMode()) - { - // Top - aView->SetProj(V3d_Zpos); - } - else if (!strcasecmp (buf_ret, "B") - && !ViewerTest_V3dView::IsCurrentViewIn2DMode()) - { - // Bottom - aView->SetProj(V3d_Zneg); - } - else if (!strcasecmp (buf_ret, "L") - && !ViewerTest_V3dView::IsCurrentViewIn2DMode()) - { - // Left - aView->SetProj(V3d_Xneg); - } - else if (!strcasecmp (buf_ret, "R") - && !ViewerTest_V3dView::IsCurrentViewIn2DMode()) - { - // Right - aView->SetProj(V3d_Xpos); - } - else if (!strcasecmp (buf_ret, "W")) - { - std::cout << "setup WireFrame display mode" << std::endl; - Handle(AIS_InteractiveContext) Ctx = ViewerTest::GetAISContext(); - if(Ctx->NbSelected()==0) - Ctx->SetDisplayMode (AIS_WireFrame, Standard_True); - else{ - for(Ctx->InitSelected();Ctx->MoreSelected();Ctx->NextSelected()) - Ctx->SetDisplayMode(Ctx->SelectedInteractive(),0,Standard_False); - Ctx->UpdateCurrentViewer(); - } - } - else if (!strcasecmp (buf_ret, ",")) - { - ViewerTest::GetAISContext()->HilightNextDetected(ViewerTest::CurrentView()); - } - else if (!strcasecmp (buf_ret, ".")) - { - ViewerTest::GetAISContext()->HilightPreviousDetected(ViewerTest::CurrentView()); - } - else if (!strcasecmp (buf_ret, "/")) - { - Handle(Graphic3d_Camera) aCamera = aView->Camera(); - if (aCamera->IsStereo()) - { - aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() - 0.01); - aView->Redraw(); - } - } - else if (!strcasecmp (buf_ret, "*")) - { - Handle(Graphic3d_Camera) aCamera = aView->Camera(); - if (aCamera->IsStereo()) - { - aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() + 0.01); - aView->Redraw(); - } - } - else if (*buf_ret == THE_KEY_DELETE) - { - Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext(); - if (!aCtx.IsNull() - && aCtx->NbSelected() > 0) - { - Draw_Interprete ("verase"); - } - } - else if (*buf_ret == THE_KEY_ESCAPE) - { - Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext(); - if (!aCtx.IsNull() - && Draw_ToCloseViewOnEsc) - { - Draw_Interprete (Draw_ToExitOnCloseView ? "exit" : "vclose"); - } - } - else if (*buf_ret >= '0' && *buf_ret <= '7') // Number - { - const Standard_Integer aSelMode = Draw::Atoi (buf_ret); - bool toEnable = true; - if (const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext()) - { - AIS_ListOfInteractive aPrsList; - aCtx->DisplayedObjects (aPrsList); - for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More() && toEnable; aPrsIter.Next()) - { - TColStd_ListOfInteger aModes; - aCtx->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()); - } -} - -//============================================================================== -//function : VT_ProcessExpose -//purpose : Redraw the View on an Expose Event -//============================================================================== -void VT_ProcessExpose() -{ - Handle(V3d_View) aView3d = ViewerTest::CurrentView(); - if (!aView3d.IsNull()) - { - aView3d->Redraw(); - } -} - -//============================================================================== -//function : VT_ProcessConfigure -//purpose : Resize the View on an Configure Event -//============================================================================== -void VT_ProcessConfigure() -{ - Handle(V3d_View) aView3d = ViewerTest::CurrentView(); - if (aView3d.IsNull()) - { - return; - } - - aView3d->MustBeResized(); - aView3d->Update(); - aView3d->Redraw(); -} - -//============================================================================== -//function : VT_ProcessButton1Press -//purpose : Picking -//============================================================================== -Standard_Boolean VT_ProcessButton1Press (Standard_Integer , - const char** theArgVec, - Standard_Boolean theToPick, - Standard_Boolean theIsShift) -{ - if (TheIsAnimating) - { - TheIsAnimating = Standard_False; - return Standard_False; - } - - if (theToPick) - { - Standard_Real X, Y, Z; - ViewerTest::CurrentView()->Convert (X_Motion, Y_Motion, X, Y, Z); - - Draw::Set (theArgVec[1], X); - Draw::Set (theArgVec[2], Y); - Draw::Set (theArgVec[3], Z); - } - - if (theIsShift) - { - ViewerTest::CurrentEventManager()->ShiftSelect(); - } - else - { - ViewerTest::CurrentEventManager()->Select(); - } - - return Standard_False; -} - -//============================================================================== -//function : VT_ProcessButton1Release -//purpose : End selecting -//============================================================================== -void VT_ProcessButton1Release (Standard_Boolean theIsShift) -{ - if (IsDragged) - { - IsDragged = Standard_False; - Handle(ViewerTest_EventManager) EM = ViewerTest::CurrentEventManager(); - if (theIsShift) - { - EM->ShiftSelect (X_ButtonPress, Y_ButtonPress, - X_Motion, Y_Motion); - } - else - { - EM->Select (X_ButtonPress, Y_ButtonPress, - X_Motion, Y_Motion); - } - } -} - -//============================================================================== -//function : VT_ProcessButton3Press -//purpose : Start Rotation -//============================================================================== -void VT_ProcessButton3Press() -{ - if (ViewerTest_V3dView::IsCurrentViewIn2DMode()) - { - return; - } - - Start_Rot = 1; - HasHlrOnBeforeRotation = ViewerTest::CurrentView()->ComputedMode(); - if (HasHlrOnBeforeRotation) - { - ViewerTest::CurrentView()->SetComputedMode (Standard_False); - } - ViewerTest::CurrentView()->StartRotation( X_ButtonPress, Y_ButtonPress ); -} - -//============================================================================== -//function : VT_ProcessButton3Release -//purpose : End rotation -//============================================================================== -void VT_ProcessButton3Release() -{ - if (Start_Rot) - { - Start_Rot = 0; - if (HasHlrOnBeforeRotation) - { - HasHlrOnBeforeRotation = Standard_False; - ViewerTest::CurrentView()->SetComputedMode (Standard_True); - ViewerTest::CurrentView()->Redraw(); - } - } -} - -//============================================================================== -//function : ProcessControlButton1Motion -//purpose : Zoom -//============================================================================== - -#if defined(_WIN32) || ! defined(__APPLE__) || defined(MACOSX_USE_GLX) -static void ProcessControlButton1Motion() -{ - ViewerTest::CurrentView()->Zoom( X_ButtonPress, Y_ButtonPress, X_Motion, Y_Motion); - - X_ButtonPress = X_Motion; - Y_ButtonPress = Y_Motion; -} -#endif - -//============================================================================== -//function : VT_ProcessControlButton2Motion -//purpose : Panning -//============================================================================== -void VT_ProcessControlButton2Motion() -{ - Standard_Integer aDx = X_Motion - X_ButtonPress; - Standard_Integer aDy = Y_Motion - Y_ButtonPress; - - aDy = -aDy; // Xwindow Y axis is from top to Bottom - - ViewerTest::CurrentView()->Pan (aDx, aDy); - - X_ButtonPress = X_Motion; - Y_ButtonPress = Y_Motion; -} - -//============================================================================== -//function : VT_ProcessControlButton3Motion -//purpose : Rotation +//function : GetMousePosition +//purpose : //============================================================================== -void VT_ProcessControlButton3Motion() +void ViewerTest::GetMousePosition (Standard_Integer& theX, + Standard_Integer& theY) { - if (Start_Rot) + if (Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager()) { - ViewerTest::CurrentView()->Rotation (X_Motion, Y_Motion); + theX = aViewCtrl->LastMousePosition().x(); + theY = aViewCtrl->LastMousePosition().y(); } } -//============================================================================== -//function : VT_ProcessMotion -//purpose : -//============================================================================== -void VT_ProcessMotion() -{ - //pre-hilights detected objects at mouse position - - Handle(ViewerTest_EventManager) EM = ViewerTest::CurrentEventManager(); - EM->MoveTo(X_Motion, Y_Motion); -} - - -void ViewerTest::GetMousePosition(Standard_Integer& Xpix,Standard_Integer& Ypix) -{ - Xpix = X_Motion;Ypix=Y_Motion; -} - //============================================================================== //function : VViewProj //purpose : Switch view projection @@ -3491,9 +2956,6 @@ static int VViewProj (Draw_Interpretor& , static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** ) { - - di << "Q : Quit the application\n"; - di << "=========================\n"; di << "F : FitAll\n"; di << "T : TopView\n"; @@ -3506,7 +2968,7 @@ static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** ) di << "=========================\n"; di << "S : Shading\n"; di << "W : Wireframe\n"; - di << "H : HidelLineRemoval\n"; + di << "H : HiddenLineRemoval\n"; di << "U : Unset display mode\n"; di << "Delete : Remove selection from viewer\n"; @@ -3522,338 +2984,220 @@ static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** ) di << "7 : Compound\n"; di << "=========================\n"; - di << "Z : Switch Z clipping On/Off\n"; - di << ", : Hilight next detected\n"; - di << ". : Hilight previous detected\n"; + di << "< : Hilight next detected\n"; + di << "> : Hilight previous detected\n"; return 0; } #ifdef _WIN32 -static Standard_Boolean Ppick = 0; -static Standard_Integer Pargc = 0; -static const char** Pargv = NULL; - - -static LRESULT WINAPI AdvViewerWindowProc( HWND hwnd, - UINT Msg, - WPARAM wParam, - LPARAM lParam ) +static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle, + UINT theMsg, + WPARAM wParam, + LPARAM lParam ) { - if (!ViewerTest_myViews.IsEmpty()) { - - WPARAM fwKeys = wParam; + if (ViewerTest_myViews.IsEmpty()) + { + return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam); + } - switch( Msg ) { + switch (theMsg) + { case WM_CLOSE: - { - // Delete view from map of views - ViewerTest::RemoveView(FindViewIdByWindowHandle(hwnd)); - return 0; - } - break; + { + // Delete view from map of views + ViewerTest::RemoveView (FindViewIdByWindowHandle (theWinHandle)); + return 0; + } case WM_ACTIVATE: - if(LOWORD(wParam) == WA_CLICKACTIVE || LOWORD(wParam) == WA_ACTIVE - || ViewerTest::CurrentView().IsNull()) + { + if (LOWORD(wParam) == WA_CLICKACTIVE + || LOWORD(wParam) == WA_ACTIVE + || ViewerTest::CurrentView().IsNull()) { // Activate inactive window - if(GetWindowHandle(VT_GetWindow()) != hwnd) - { - ActivateView (FindViewIdByWindowHandle(hwnd)); - } - } - break; - - case WM_LBUTTONUP: - if (IsDragged && !DragFirst) - { - if (!GetActiveAISManipulator().IsNull()) - { - GetActiveAISManipulator()->StopTransform(); - ViewerTest::GetAISContext()->ClearSelected (Standard_True); - } - - if (ViewerTest::GetAISContext()->IsDisplayed (GetRubberBand())) - { - ViewerTest::GetAISContext()->Remove (GetRubberBand(), Standard_False); - ViewerTest::GetAISContext()->CurrentViewer()->RedrawImmediate(); - } - - VT_ProcessButton1Release ((fwKeys & MK_SHIFT) != 0); - } - IsDragged = Standard_False; - return ViewerWindowProc( hwnd, Msg, wParam, lParam ); - - case WM_RBUTTONUP: - if (IsDragged && !DragFirst) - { - if (!GetActiveAISManipulator().IsNull()) + if (VT_GetWindow().IsNull() + || (HWND )VT_GetWindow()->HWindow() != theWinHandle) { - GetActiveAISManipulator()->StopTransform (Standard_False); - ViewerTest::GetAISContext()->ClearSelected (Standard_True); + ActivateView (FindViewIdByWindowHandle (theWinHandle)); } - IsDragged = Standard_False; - } - return ViewerWindowProc (hwnd, Msg, wParam, lParam); - - case WM_LBUTTONDOWN: - if (!GetActiveAISManipulator().IsNull()) - { - IsDragged = ( fwKeys == MK_LBUTTON ); - } - else - { - IsDragged = ( fwKeys == MK_LBUTTON || fwKeys == ( MK_LBUTTON | MK_SHIFT ) ); - } - - if (IsDragged) - { - DragFirst = Standard_True; - X_ButtonPress = LOWORD(lParam); - Y_ButtonPress = HIWORD(lParam); - } - return ViewerWindowProc( hwnd, Msg, wParam, lParam ); - - case WM_MOUSEMOVE: - if (IsDragged) - { - X_Motion = LOWORD (lParam); - Y_Motion = HIWORD (lParam); - if (!GetActiveAISManipulator().IsNull()) - { - if (DragFirst) - { - GetActiveAISManipulator()->StartTransform (X_ButtonPress, Y_ButtonPress, ViewerTest::CurrentView()); - } - else - { - GetActiveAISManipulator()->Transform (X_Motion, Y_Motion, ViewerTest::CurrentView()); - ViewerTest::GetAISContext()->CurrentViewer()->Redraw(); - } - } - else - { - bool toRedraw = false; - if (!DragFirst && ViewerTest::GetAISContext()->IsDisplayed (GetRubberBand())) - { - ViewerTest::GetAISContext()->Remove (GetRubberBand(), Standard_False); - toRedraw = true; - } - - RECT aRect; - if (GetClientRect (hwnd, &aRect)) - { - int aHeight = aRect.bottom - aRect.top; - GetRubberBand()->SetRectangle (X_ButtonPress, aHeight - Y_ButtonPress, X_Motion, aHeight - Y_Motion); - ViewerTest::GetAISContext()->Display (GetRubberBand(), 0, -1, Standard_False, AIS_DS_Displayed); - toRedraw = true; - } - if (toRedraw) - { - ViewerTest::GetAISContext()->CurrentViewer()->RedrawImmediate(); - } - } - - DragFirst = Standard_False; } - else - return ViewerWindowProc( hwnd, Msg, wParam, lParam ); break; - + } default: - return ViewerWindowProc( hwnd, Msg, wParam, lParam ); + { + return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam); } - return 0; } - return ViewerWindowProc( hwnd, Msg, wParam, lParam ); + return 0; } - -static LRESULT WINAPI ViewerWindowProc( HWND hwnd, - UINT Msg, - WPARAM wParam, - LPARAM lParam ) +static LRESULT WINAPI ViewerWindowProc (HWND theWinHandle, + UINT theMsg, + WPARAM wParam, + LPARAM lParam) { - static int Up = 1; const Handle(V3d_View)& aView = ViewerTest::CurrentView(); if (aView.IsNull()) { - return DefWindowProcW (hwnd, Msg, wParam, lParam); + return DefWindowProcW (theWinHandle, theMsg, wParam, lParam); } - PAINTSTRUCT ps; - - switch( Msg ) { + switch (theMsg) + { case WM_PAINT: - BeginPaint(hwnd, &ps); - EndPaint(hwnd, &ps); - VT_ProcessExpose(); + { + PAINTSTRUCT aPaint; + BeginPaint(theWinHandle, &aPaint); + EndPaint (theWinHandle, &aPaint); + ViewerTest::CurrentEventManager()->ProcessExpose(); break; - + } case WM_SIZE: - VT_ProcessConfigure(); + { + ViewerTest::CurrentEventManager()->ProcessConfigure(); break; + } case WM_MOVE: case WM_MOVING: case WM_SIZING: + { switch (aView->RenderingParams().StereoMode) { case Graphic3d_StereoMode_RowInterlaced: case Graphic3d_StereoMode_ColumnInterlaced: case Graphic3d_StereoMode_ChessBoard: - VT_ProcessConfigure(); // track window moves to reverse stereo pair + { + // track window moves to reverse stereo pair + aView->MustBeResized(); + aView->Update(); break; + } default: break; } break; - + } + case WM_KEYUP: case WM_KEYDOWN: - if ((wParam != VK_SHIFT) && (wParam != VK_CONTROL)) + { + const Aspect_VKey aVKey = WNT_Window::VirtualKeyFromNative ((Standard_Integer )wParam); + if (aVKey != Aspect_VKey_UNKNOWN) { - char c[2]; - c[0] = (char) wParam; - c[1] = '\0'; - if (wParam == VK_DELETE) - { - c[0] = THE_KEY_DELETE; - } - else if (wParam == VK_ESCAPE) - { - c[0] = THE_KEY_ESCAPE; - } - // comma - else if (wParam == VK_OEM_COMMA) - { - c[0] = ','; - } - // dot - else if (wParam == VK_OEM_PERIOD) - { - c[0] = '.'; - } - else if (wParam == VK_DIVIDE) + const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime(); + if (theMsg == WM_KEYDOWN) { - c[0] = '/'; + ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp); } - // dot - else if (wParam == VK_MULTIPLY) + else { - c[0] = '*'; + ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp); } - VT_ProcessKeyPress (c); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); } break; - + } case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: - Up = 1; - VT_ProcessButton3Release(); - break; - case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: + { + const Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam)); + const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam); + Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE; + switch (theMsg) { - WPARAM fwKeys = wParam; - - Up = 0; - - X_ButtonPress = LOWORD(lParam); - Y_ButtonPress = HIWORD(lParam); - - if (Msg == WM_LBUTTONDOWN) - { - if ((fwKeys & MK_CONTROL) != 0) - { - Ppick = VT_ProcessButton1Press (Pargc, Pargv, Ppick, (fwKeys & MK_SHIFT) != 0); - } - else - { - VT_ProcessButton1Press (Pargc, Pargv, Ppick, (fwKeys & MK_SHIFT) != 0); - } - } - else if (Msg == WM_RBUTTONDOWN) - { - // Start rotation - VT_ProcessButton3Press(); - } + case WM_LBUTTONUP: + case WM_LBUTTONDOWN: + aButton = Aspect_VKeyMouse_LeftButton; + break; + case WM_MBUTTONUP: + case WM_MBUTTONDOWN: + aButton = Aspect_VKeyMouse_MiddleButton; + break; + case WM_RBUTTONUP: + case WM_RBUTTONDOWN: + aButton = Aspect_VKeyMouse_RightButton; + break; } - break; - - case WM_MOUSEWHEEL: - { - int aDelta = GET_WHEEL_DELTA_WPARAM (wParam); - if (wParam & MK_CONTROL) + if (theMsg == WM_LBUTTONDOWN + || theMsg == WM_MBUTTONDOWN + || theMsg == WM_RBUTTONDOWN) { - if (aView->Camera()->IsStereo()) + if (aButton == Aspect_VKeyMouse_LeftButton) { - Standard_Real aFocus = aView->Camera()->ZFocus() + (aDelta > 0 ? 0.05 : -0.05); - if (aFocus > 0.2 - && aFocus < 2.0) - { - aView->Camera()->SetZFocus (aView->Camera()->ZFocusType(), aFocus); - aView->Redraw(); - } + TheIsAnimating = Standard_False; } + + SetFocus (theWinHandle); + SetCapture(theWinHandle); + ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false); } else { - aView->Zoom (0, 0, aDelta / 40, aDelta / 40); + ReleaseCapture(); + ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false); } + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); break; } - - case WM_MOUSEMOVE: + case WM_MOUSEWHEEL: + { + const int aDelta = GET_WHEEL_DELTA_WPARAM (wParam); + const Standard_Real aDeltaF = Standard_Real(aDelta) / Standard_Real(WHEEL_DELTA); + const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam); + Graphic3d_Vec2i aPos (int(short(LOWORD(lParam))), int(short(HIWORD(lParam)))); + POINT aCursorPnt = { aPos.x(), aPos.y() }; + if (ScreenToClient (theWinHandle, &aCursorPnt)) { - //cout << "\t WM_MOUSEMOVE" << endl; - WPARAM fwKeys = wParam; - X_Motion = LOWORD(lParam); - Y_Motion = HIWORD(lParam); + aPos.SetValues (aCursorPnt.x, aCursorPnt.y); + } - if ( Up && - (fwKeys & ( MK_LBUTTON|MK_MBUTTON|MK_RBUTTON )) != 0 ) - { - Up = 0; - X_ButtonPress = LOWORD(lParam); - Y_ButtonPress = HIWORD(lParam); + ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags)); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); + break; + } + case WM_MOUSEMOVE: + { + Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam)); + Aspect_VKeyMouse aButtons = WNT_Window::MouseButtonsFromEvent (wParam); + Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent(wParam); - if ((fwKeys & MK_RBUTTON) != 0) { - // Start rotation - VT_ProcessButton3Press(); - } - } + // don't make a slide-show from input events - fetch the actual mouse cursor position + CURSORINFO aCursor; + aCursor.cbSize = sizeof(aCursor); + if (::GetCursorInfo (&aCursor) != FALSE) + { + POINT aCursorPnt = { aCursor.ptScreenPos.x, aCursor.ptScreenPos.y }; + if (ScreenToClient (theWinHandle, &aCursorPnt)) + { + // as we override mouse position, we need overriding also mouse state + aPos.SetValues (aCursorPnt.x, aCursorPnt.y); + aButtons = WNT_Window::MouseButtonsAsync(); + aFlags = WNT_Window::MouseKeyFlagsAsync(); + } + } - if ((fwKeys & MK_CONTROL) != 0) - { - if ((fwKeys & MK_LBUTTON) != 0) - { - ProcessControlButton1Motion(); - } - else if ((fwKeys & MK_MBUTTON) != 0 - || ((fwKeys & MK_LBUTTON) != 0 - && (fwKeys & MK_RBUTTON) != 0)) - { - VT_ProcessControlButton2Motion(); - } - else if ((fwKeys & MK_RBUTTON) != 0) - { - VT_ProcessControlButton3Motion(); - } - } - else if (GetWindowHandle (VT_GetWindow()) == hwnd) - { - VT_ProcessMotion(); - } + if (VT_GetWindow().IsNull() + || (HWND )VT_GetWindow()->HWindow() != theWinHandle) + { + // mouse move events come also for inactive windows + break; } - break; + ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true); + break; + } default: - return DefWindowProcW (hwnd, Msg, wParam, lParam); + { + return DefWindowProcW (theWinHandle, theMsg, wParam, lParam); } - return 0L; + } + return 0L; } //============================================================================== @@ -3861,32 +3205,33 @@ static LRESULT WINAPI ViewerWindowProc( HWND hwnd, //purpose : Get a Event on the view and dispatch it //============================================================================== - -int ViewerMainLoop(Standard_Integer argc, const char** argv) +int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec) { - Ppick = (argc > 0)? 1 : 0; - Pargc = argc; - Pargv = argv; + Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager(); + if (aViewCtrl.IsNull() + || theNbArgs < 4) + { + return 0; + } - if ( Ppick ) { - MSG msg; - msg.wParam = 1; + aViewCtrl->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]); - cout << "Start picking" << endl; + std::cout << "Start picking\n"; - while ( Ppick == 1 ) { - // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0 - if (GetMessageW (&msg, NULL, 0, 0)) - { - TranslateMessage (&msg); - DispatchMessageW (&msg); - } + MSG aMsg; + aMsg.wParam = 1; + while (aViewCtrl->ToPickPoint()) + { + // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0 + if (GetMessageW (&aMsg, NULL, 0, 0)) + { + TranslateMessage (&aMsg); + DispatchMessageW (&aMsg); } - - cout << "Picking done" << endl; } - return Ppick; + std::cout << "Picking done\n"; + return 0; } #elif !defined(__APPLE__) || defined(MACOSX_USE_GLX) @@ -3907,11 +3252,19 @@ int max( int a, int b ) return b; } -int ViewerMainLoop (Standard_Integer argc, const char** argv) +int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec) { static XEvent aReport; - const Standard_Boolean toPick = argc > 0; - Standard_Boolean toPickMore = toPick; + const Standard_Boolean toPick = theNbArgs > 0; + if (theNbArgs > 0) + { + if (ViewerTest::CurrentEventManager().IsNull()) + { + return 0; + } + ViewerTest::CurrentEventManager()->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]); + } + Display* aDisplay = GetDisplayConnection()->GetDisplay(); XNextEvent (aDisplay, &aReport); @@ -3931,7 +3284,7 @@ int ViewerMainLoop (Standard_Integer argc, const char** argv) case FocusIn: { // Activate inactive view - Window aWindow = GetWindowHandle(VT_GetWindow()); + Window aWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0; if (aWindow != aReport.xfocus.window) { ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window)); @@ -3940,10 +3293,10 @@ int ViewerMainLoop (Standard_Integer argc, const char** argv) } case Expose: { - Window anXWindow = GetWindowHandle (VT_GetWindow()); + Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0; if (anXWindow == aReport.xexpose.window) { - VT_ProcessExpose(); + ViewerTest::CurrentEventManager()->ProcessExpose(); } // remove all the ExposureMask and process them at once @@ -3960,7 +3313,7 @@ int ViewerMainLoop (Standard_Integer argc, const char** argv) case ConfigureNotify: { // remove all the StructureNotifyMask and process them at once - Window anXWindow = GetWindowHandle (VT_GetWindow()); + Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0; for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents) { if (!XCheckWindowEvent (aDisplay, anXWindow, StructureNotifyMask, &aReport)) @@ -3971,106 +3324,92 @@ int ViewerMainLoop (Standard_Integer argc, const char** argv) if (anXWindow == aReport.xconfigure.window) { - VT_ProcessConfigure(); + ViewerTest::CurrentEventManager()->ProcessConfigure(); } break; } case KeyPress: + case KeyRelease: { - KeySym aKeySym; - char aKeyBuf[11]; - XComposeStatus status_in_out; - int aKeyLen = XLookupString ((XKeyEvent* )&aReport, (char* )aKeyBuf, 10, &aKeySym, &status_in_out); - aKeyBuf[aKeyLen] = '\0'; - if (aKeyLen != 0) - { - VT_ProcessKeyPress (aKeyBuf); - } - break; - } - case ButtonPress: - { - X_ButtonPress = aReport.xbutton.x; - Y_ButtonPress = aReport.xbutton.y; - if (aReport.xbutton.button == Button1) + XKeyEvent* aKeyEvent = (XKeyEvent* )&aReport; + const KeySym aKeySym = XLookupKeysym (aKeyEvent, 0); + const Aspect_VKey aVKey = Xw_Window::VirtualKeyFromNative (aKeySym); + if (aVKey != Aspect_VKey_UNKNOWN) { - if (aReport.xbutton.state & ControlMask) + const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime(); + if (aReport.type == KeyPress) { - toPickMore = VT_ProcessButton1Press (argc, argv, toPick, (aReport.xbutton.state & ShiftMask) != 0); + ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp); } else { - IsDragged = Standard_True; - DragFirst = Standard_True; + ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp); } - } - else if (aReport.xbutton.button == Button3) - { - // Start rotation - VT_ProcessButton3Press(); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); } break; } + case ButtonPress: case ButtonRelease: { - if (!IsDragged) + const Graphic3d_Vec2i aPos (aReport.xbutton.x, aReport.xbutton.y); + Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE; + Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE; + if (aReport.xbutton.button == Button1) { - VT_ProcessButton3Release(); - break; + aButton = Aspect_VKeyMouse_LeftButton; } - - Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext(); - if (aContext.IsNull()) + if (aReport.xbutton.button == Button2) { - std::cout << "Error: No active view.\n"; - return 0; + aButton = Aspect_VKeyMouse_MiddleButton; } - - if (!DragFirst - && aContext->IsDisplayed (GetRubberBand())) + if (aReport.xbutton.button == Button3) { - aContext->Remove (GetRubberBand(), Standard_False); - aContext->CurrentViewer()->RedrawImmediate(); + aButton = Aspect_VKeyMouse_RightButton; } - if (aReport.xbutton.button != Button1) + if (aReport.xbutton.state & ControlMask) { - break; + aFlags |= Aspect_VKeyFlags_CTRL; + } + if (aReport.xbutton.state & ShiftMask) + { + aFlags |= Aspect_VKeyFlags_SHIFT; + } + if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt)) + { + aFlags |= Aspect_VKeyFlags_ALT; } - const Standard_Boolean isShiftPressed = (aReport.xbutton.state & ShiftMask) != 0; - if (DragFirst) + if (aReport.xbutton.button == Button4 + || aReport.xbutton.button == Button5) { - if (isShiftPressed) + if (aReport.type != ButtonPress) { - aContext->ShiftSelect (Standard_True); + break; } - else + + const double aDeltaF = (aReport.xbutton.button == Button4 ? 1.0 : -1.0); + ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags)); + } + else if (aReport.type == ButtonPress) + { + if (aButton == Aspect_VKeyMouse_LeftButton) { - aContext->Select (Standard_True); + TheIsAnimating = Standard_False; } + ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false); } else { - if (isShiftPressed) - { - aContext->ShiftSelect (Min (X_ButtonPress, X_Motion), Min (Y_ButtonPress, Y_Motion), - Max (X_ButtonPress, X_Motion), Max (Y_ButtonPress, Y_Motion), - ViewerTest::CurrentView(), Standard_True); - } - else - { - aContext->Select (Min (X_ButtonPress, X_Motion), Min(Y_ButtonPress, Y_Motion), - Max (X_ButtonPress, X_Motion), Max(Y_ButtonPress, Y_Motion), - ViewerTest::CurrentView(), Standard_True); - } + ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false); } - IsDragged = Standard_False; + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); break; } case MotionNotify: { - Window anXWindow = GetWindowHandle (VT_GetWindow()); + Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0; if (anXWindow != aReport.xmotion.window) { break; @@ -4085,55 +3424,41 @@ int ViewerMainLoop (Standard_Integer argc, const char** argv) } } - if (IsDragged) + Graphic3d_Vec2i aPos (aReport.xmotion.x, aReport.xmotion.y); + Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE; + Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE; + if ((aReport.xmotion.state & Button1Mask) != 0) { - if (!DragFirst - && ViewerTest::GetAISContext()->IsDisplayed (GetRubberBand())) - { - ViewerTest::GetAISContext()->Remove (GetRubberBand(), Standard_False); - } - - X_Motion = aReport.xmotion.x; - Y_Motion = aReport.xmotion.y; - DragFirst = Standard_False; + aButtons |= Aspect_VKeyMouse_LeftButton; + } + else if ((aReport.xmotion.state & Button2Mask) != 0) + { + aButtons |= Aspect_VKeyMouse_MiddleButton; + } + else if ((aReport.xmotion.state & Button3Mask) != 0) + { + aButtons |= Aspect_VKeyMouse_RightButton; + } - Window aWindow = GetWindowHandle(VT_GetWindow()); - Window aRoot; - int anX, anY; - unsigned int aWidth, aHeight, aBorderWidth, aDepth; - XGetGeometry (aDisplay, aWindow, &aRoot, &anX, &anY, &aWidth, &aHeight, &aBorderWidth, &aDepth); - GetRubberBand()->SetRectangle (X_ButtonPress, aHeight - Y_ButtonPress, X_Motion, aHeight - Y_Motion); - ViewerTest::GetAISContext()->Display (GetRubberBand(), 0, -1, Standard_False, AIS_DS_Displayed); - ViewerTest::GetAISContext()->CurrentViewer()->RedrawImmediate(); + if (aReport.xmotion.state & ControlMask) + { + aFlags |= Aspect_VKeyFlags_CTRL; } - else + if (aReport.xmotion.state & ShiftMask) { - X_Motion = aReport.xmotion.x; - Y_Motion = aReport.xmotion.y; - if ((aReport.xmotion.state & ControlMask) != 0) - { - if ((aReport.xmotion.state & Button1Mask) != 0) - { - ProcessControlButton1Motion(); - } - else if ((aReport.xmotion.state & Button2Mask) != 0) - { - VT_ProcessControlButton2Motion(); - } - else if ((aReport.xmotion.state & Button3Mask) != 0) - { - VT_ProcessControlButton3Motion(); - } - } - else - { - VT_ProcessMotion(); - } + aFlags |= Aspect_VKeyFlags_SHIFT; } + if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt)) + { + aFlags |= Aspect_VKeyFlags_ALT; + } + + ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); break; } } - return (!toPick || toPickMore) ? 1 : 0; + return (!toPick || ViewerTest::CurrentEventManager()->ToPickPoint()) ? 1 : 0; } //============================================================================== @@ -4224,7 +3549,7 @@ static void OSWindowSetup() XSetWMHints( aDisplay, window, &wmhints); - XSelectInput( aDisplay, window, ExposureMask | KeyPressMask | + XSelectInput( aDisplay, window, ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | StructureNotifyMask | PointerMotionMask | @@ -4468,18 +3793,27 @@ static int VClear(Draw_Interpretor& , Standard_Integer , const char** ) //purpose : //============================================================================== -static int VPick(Draw_Interpretor& di, Standard_Integer argc, const char** argv) -{ if (ViewerTest::CurrentView().IsNull() ) return 1; +static int VPick (Draw_Interpretor& , + Standard_Integer theNbArgs, + const char** theArgVec) +{ + if (ViewerTest::CurrentView().IsNull()) + { + return 1; + } -if ( argc < 4 ) { - di << argv[0] << "Invalid number of arguments\n"; - return 1; -} + if (theNbArgs < 4) + { + std::cout << "Syntax error: Invalid number of arguments\n"; + return 1; + } -while (ViewerMainLoop( argc, argv)) { -} + while (ViewerMainLoop (theNbArgs, theArgVec)) + { + // + } -return 0; + return 0; } namespace @@ -7785,9 +7119,9 @@ static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const } else if (anArg == "-exitonclose") { - Draw_ToExitOnCloseView = true; + ViewerTest_EventManager::ToExitOnCloseView() = true; if (anArgIter + 1 < theArgNb - && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], Draw_ToExitOnCloseView)) + && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToExitOnCloseView())) { ++anArgIter; } @@ -7795,9 +7129,9 @@ static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const else if (anArg == "-closeonescape" || anArg == "-closeonesc") { - Draw_ToCloseViewOnEsc = true; + ViewerTest_EventManager::ToCloseViewOnEscape() = true; if (anArgIter + 1 < theArgNb - && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], Draw_ToCloseViewOnEsc)) + && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToCloseViewOnEscape())) { ++anArgIter; } @@ -7973,71 +7307,93 @@ static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const // pixel positions (x1,y1),...,(xn,yn) // 4) any of these selections with shift button pressed //======================================================================= -static Standard_Integer VSelect (Draw_Interpretor& di, - Standard_Integer argc, - const char ** argv) +static Standard_Integer VSelect (Draw_Interpretor& , + Standard_Integer theNbArgs, + const char** theArgVec) { - if(argc < 3) - { - di << "Usage : " << argv[0] << " x1 y1 [x2 y2 [... xn yn]] [shift_selection = 1|0]\n"; - return 1; - } - - Handle(AIS_InteractiveContext) myAIScontext = ViewerTest::GetAISContext(); - if(myAIScontext.IsNull()) + const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext(); + if (aCtx.IsNull()) { - di << "use 'vinit' command before " << argv[0] << "\n"; + std::cout << "Error: no active View\n"; return 1; } - const Standard_Boolean isShiftSelection = (argc > 3 && !(argc % 2) && (atoi (argv[argc - 1]) == 1)); - Standard_Integer aCoordsNb = isShiftSelection ? argc - 2 : argc - 1; - TCollection_AsciiString anArg; - anArg = isShiftSelection ? argv[argc - 3] : argv[argc - 2]; - anArg.LowerCase(); - if (anArg == "-allowoverlap") + NCollection_Sequence aPnts; + bool isShiftSelection = false, toAllowOverlap = false; + for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter) { - Standard_Boolean isValidated = isShiftSelection ? argc == 8 - : argc == 7; - if (!isValidated) + TCollection_AsciiString anArg (theArgVec[anArgIter]); + anArg.LowerCase(); + if (anArg == "-allowoverlap") + { + toAllowOverlap = true; + if (anArgIter + 1 < theNbArgs + && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toAllowOverlap)) + { + ++anArgIter; + } + } + else if (anArgIter + 1 < theNbArgs + && anArg.IsIntegerValue() + && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue()) { - di << "Wrong number of arguments! -allowoverlap key is applied only for rectangle selection"; + const TCollection_AsciiString anArgNext (theArgVec[++anArgIter]); + aPnts.Append (Graphic3d_Vec2i (anArg.IntegerValue(), anArgNext.IntegerValue())); + } + else if (anArgIter + 1 == theNbArgs + && anArg.IsIntegerValue()) + { + isShiftSelection = anArg.IntegerValue() == 1; + } + else + { + std::cout << "Syntax error at '" << anArg << "'\n"; return 1; } - - Standard_Integer isToAllow = isShiftSelection ? Draw::Atoi(argv[argc - 2]) : Draw::Atoi(argv[argc - 1]); - myAIScontext->MainSelector()->AllowOverlapDetection (isToAllow != 0); - aCoordsNb -= 2; + } + if (toAllowOverlap + && aPnts.Length() != 2) + { + std::cout << "Syntax error: -allowoverlap key is applied only for rectangle selection\n"; + return 1; + } + if (toAllowOverlap) + { + aCtx->MainSelector()->AllowOverlapDetection (toAllowOverlap); } Handle(ViewerTest_EventManager) aCurrentEventManager = ViewerTest::CurrentEventManager(); - aCurrentEventManager->MoveTo(atoi(argv[1]),atoi(argv[2])); - if(aCoordsNb == 2) + if (aPnts.IsEmpty()) { - if(isShiftSelection) - aCurrentEventManager->ShiftSelect(); + if (isShiftSelection) + { + aCtx->ShiftSelect (false); + } else - aCurrentEventManager->Select(); + { + aCtx->Select (false); + } + aCtx->CurrentViewer()->Invalidate(); } - else if(aCoordsNb == 4) + else if (aPnts.Length() == 2) { - if(isShiftSelection) - aCurrentEventManager->ShiftSelect (atoi (argv[1]), atoi (argv[2]), atoi (argv[3]), atoi (argv[4]), Standard_False); - else - aCurrentEventManager->Select (atoi (argv[1]), atoi (argv[2]), atoi (argv[3]), atoi (argv[4]), Standard_False); + if (toAllowOverlap + && aPnts.First().y() < aPnts.Last().y()) + { + std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast()); + } + else if (!toAllowOverlap + && aPnts.First().y() > aPnts.Last().y()) + { + std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast()); + } + aCurrentEventManager->SelectInViewer (aPnts, isShiftSelection); } else { - TColgp_Array1OfPnt2d aPolyline (1,aCoordsNb / 2); - - for(Standard_Integer i=1;i<=aCoordsNb / 2;++i) - aPolyline.SetValue(i,gp_Pnt2d(atoi(argv[2*i-1]),atoi(argv[2*i]))); - - if(isShiftSelection) - aCurrentEventManager->ShiftSelect(aPolyline); - else - aCurrentEventManager->Select(aPolyline); + aCurrentEventManager->SelectInViewer (aPnts, isShiftSelection); } + aCurrentEventManager->FlushViewEvents (aCtx, ViewerTest::CurrentView(), true); return 0; } @@ -8107,7 +7463,10 @@ static Standard_Integer VMoveTo (Draw_Interpretor& theDI, return 1; } - ViewerTest::CurrentEventManager()->MoveTo (aMousePos.x(), aMousePos.y()); + ViewerTest::CurrentEventManager()->ResetPreviousMoveTo(); + ViewerTest::CurrentEventManager()->UpdateMousePosition (aMousePos, Aspect_VKeyMouse_NONE, Aspect_VKeyFlags_NONE, false); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true); + gp_Pnt aTopPnt (RealLast(), RealLast(), RealLast()); const Handle(SelectMgr_EntityOwner)& aDetOwner = aContext->DetectedOwner(); for (Standard_Integer aDetIter = 1; aDetIter <= aContext->MainSelector()->NbPicked(); ++aDetIter) @@ -12845,52 +12204,6 @@ static Standard_Integer VStatProfiler (Draw_Interpretor& theDI, return 0; } -//======================================================================= -//function : VProgressiveMode -//purpose : -//======================================================================= -#if defined(_WIN32) -static Standard_Integer VProgressiveMode (Draw_Interpretor& /*theDI*/, - Standard_Integer /*theNbArgs*/, - const char** /*theArgs*/) -{ - Handle(V3d_View) aView = ViewerTest::CurrentView(); - if (aView.IsNull()) - { - std::cerr << "Error: no active viewer!\n"; - return 1; - } - - std::cout << "Press Enter or Escape key to exit progressive rendering mode" << std::endl; - - for (;;) - { - aView->Redraw(); - - Standard_Boolean toExit = Standard_False; - - MSG aMsg; - while (PeekMessageW (&aMsg, NULL, 0, 0, PM_REMOVE)) - { - if (aMsg.message == WM_KEYDOWN && (aMsg.wParam == 0x0d || aMsg.wParam == 0x1b)) - { - toExit = Standard_True; - } - - TranslateMessage (&aMsg); - DispatchMessageW (&aMsg); - } - - if (toExit) - { - break; - } - } - - return 0; -} -#endif - //======================================================================= //function : VXRotate //purpose : @@ -13065,6 +12378,7 @@ static int VManipulator (Draw_Interpretor& theDi, std::cout << theArgVec[0] << ": AIS object \"" << aName << "\" has been created.\n"; aManipulator = new ViewerTest_AISManipulator(); + aManipulator->SetModeActivationOnDetection (true); aMapAIS.Bind (aManipulator, aName); } else @@ -14492,11 +13806,5 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) "\n\t\t: selMode color of selection mode" "\n\t\t: entity color of etected entity", __FILE__, VDumpSelectionImage, group); - -#if defined(_WIN32) - theCommands.Add("vprogressive", - "vprogressive", - __FILE__, VProgressiveMode, group); -#endif } diff --git a/src/ViewerTest/ViewerTest_ViewerCommands_1.mm b/src/ViewerTest/ViewerTest_ViewerCommands_1.mm index 7d0eb93ad6..f39dc12026 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands_1.mm +++ b/src/ViewerTest/ViewerTest_ViewerCommands_1.mm @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -39,41 +40,8 @@ extern void ActivateView (const TCollection_AsciiString& theViewName, Standard_Boolean theToUpdate = Standard_True); -extern void VT_ProcessExpose(); -extern void VT_ProcessConfigure(); -extern void VT_ProcessKeyPress (const char* theBuffer); -extern void VT_ProcessMotion(); -extern void VT_ProcessButton3Press(); -extern void VT_ProcessButton3Release(); -extern void VT_ProcessControlButton2Motion(); -extern void VT_ProcessControlButton3Motion(); -extern Standard_Boolean VT_ProcessButton1Press (Standard_Integer theArgsNb, - const char** theArgsVec, - Standard_Boolean theToPick, - Standard_Boolean theIsShift); -extern void VT_ProcessButton1Release(Standard_Boolean theIsShift); extern NCollection_DoubleMap ViewerTest_myViews; -extern int X_Motion; // Current cursor position -extern int Y_Motion; -extern int X_ButtonPress; // Last ButtonPress position -extern int Y_ButtonPress; -extern Standard_Boolean IsDragged; - -// ======================================================================= -// function : SetCocoaWindowTitle -// purpose : -// ======================================================================= -void SetCocoaWindowTitle (const Handle(Cocoa_Window)& theWindow, Standard_CString theTitle) -{ - NSView* aView = theWindow->HView(); - NSWindow* aWindow = [aView window]; - - NSString* aTitleNS = [[NSString alloc] initWithUTF8String: theTitle]; - [aWindow setTitle: aTitleNS]; - [aTitleNS release]; - -} // ======================================================================= // function : GetCocoaScreenResolution @@ -170,20 +138,41 @@ void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow) [aView release]; } -// ======================================================================= -// function : getMouseCoords -// purpose : Retrieve cursor position -// ======================================================================= -static void getMouseCoords (NSView* theView, - NSEvent* theEvent, - Standard_Integer& theX, - Standard_Integer& theY) +//! Retrieve cursor position +static Graphic3d_Vec2i getMouseCoords (NSView* theView, + NSEvent* theEvent) { NSPoint aMouseLoc = [theView convertPoint: [theEvent locationInWindow] fromView: nil]; NSRect aBounds = [theView bounds]; + return Graphic3d_Vec2i (Standard_Integer(aMouseLoc.x), + Standard_Integer(aBounds.size.height - aMouseLoc.y)); +} - theX = Standard_Integer(aMouseLoc.x); - theY = Standard_Integer(aBounds.size.height - aMouseLoc.y); +//! Convert key flags from mouse event. +static Aspect_VKeyFlags getMouseKeyFlags (NSEvent* theEvent) +{ + Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE; + if (([theEvent modifierFlags] & NSEventModifierFlagShift) != 0) + { + aFlags |= Aspect_VKeyFlags_SHIFT; + } + if (([theEvent modifierFlags] & NSEventModifierFlagControl) != 0) + { + aFlags |= Aspect_VKeyFlags_CTRL; + } + if (([theEvent modifierFlags] & NSEventModifierFlagOption) != 0) + { + aFlags |= Aspect_VKeyFlags_ALT; + } + if (([theEvent modifierFlags] & NSEventModifierFlagFunction) != 0) + { + //aFlags |= Aspect_VKeyFlags_FUNC; + } + if (([theEvent modifierFlags] & NSEventModifierFlagCommand) != 0) + { + //aFlags |= Aspect_VKeyFlags_CMD; + } + return aFlags; } @implementation ViewerTest_CocoaEventManagerView @@ -195,7 +184,7 @@ static void getMouseCoords (NSView* theView, - (void )setFrameSize: (NSSize )theNewSize { [super setFrameSize: theNewSize]; - VT_ProcessConfigure(); + ViewerTest::CurrentEventManager()->ProcessConfigure(); } // ======================================================================= @@ -205,7 +194,10 @@ static void getMouseCoords (NSView* theView, - (void )drawRect: (NSRect )theDirtyRect { (void )theDirtyRect; - VT_ProcessExpose(); + if (!ViewerTest::CurrentEventManager().IsNull()) + { + ViewerTest::CurrentEventManager()->ProcessExpose(); + } } // ======================================================================= @@ -214,8 +206,11 @@ static void getMouseCoords (NSView* theView, // ======================================================================= - (void )mouseMoved: (NSEvent* )theEvent { - getMouseCoords (self, theEvent, X_Motion, Y_Motion); - VT_ProcessMotion(); + const Graphic3d_Vec2i aPos = getMouseCoords (self, theEvent); + const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent); + const Aspect_VKeyMouse aButtons = ViewerTest::CurrentEventManager()->PressedMouseButtons(); + ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); } // ======================================================================= @@ -233,8 +228,10 @@ static void getMouseCoords (NSView* theView, // ======================================================================= - (void )mouseDown: (NSEvent* )theEvent { - getMouseCoords (self, theEvent, X_ButtonPress, Y_ButtonPress); - VT_ProcessButton1Press (0, NULL, Standard_False, [theEvent modifierFlags] & NSEventModifierFlagShift); + const Graphic3d_Vec2i aPos = getMouseCoords (self, theEvent); + const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent); + ViewerTest::CurrentEventManager()->PressMouseButton (aPos, Aspect_VKeyMouse_LeftButton, aFlags, false); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); } // ======================================================================= @@ -243,23 +240,23 @@ static void getMouseCoords (NSView* theView, // ======================================================================= - (void )mouseUp: (NSEvent* )theEvent { - getMouseCoords (self, theEvent, X_Motion, Y_Motion); - VT_ProcessButton1Release([theEvent modifierFlags] & NSEventModifierFlagShift); + const Graphic3d_Vec2i aPos = getMouseCoords (self, theEvent); + const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent); + ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, Aspect_VKeyMouse_LeftButton, aFlags, false); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); } - // ======================================================================= // function : mouseDragged // purpose : // ======================================================================= - (void )mouseDragged: (NSEvent* )theEvent { - IsDragged = Standard_True; - if ([theEvent modifierFlags] & NSEventModifierFlagControl) - { - getMouseCoords (self, theEvent, X_Motion, Y_Motion); - VT_ProcessControlButton2Motion(); - } + const Graphic3d_Vec2i aPos = getMouseCoords (self, theEvent); + const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent); + const Aspect_VKeyMouse aButtons = ViewerTest::CurrentEventManager()->PressedMouseButtons(); + ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); } // ======================================================================= @@ -268,8 +265,10 @@ static void getMouseCoords (NSView* theView, // ======================================================================= - (void )rightMouseDown: (NSEvent* )theEvent { - getMouseCoords (self, theEvent, X_ButtonPress, Y_ButtonPress); - VT_ProcessButton3Press(); // Start rotation + const Graphic3d_Vec2i aPos = getMouseCoords (self, theEvent); + const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent); + ViewerTest::CurrentEventManager()->PressMouseButton (aPos, Aspect_VKeyMouse_RightButton, aFlags, false); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); } // ======================================================================= @@ -278,8 +277,10 @@ static void getMouseCoords (NSView* theView, // ======================================================================= - (void )rightMouseUp: (NSEvent* )theEvent { - (void )theEvent; - VT_ProcessButton3Release(); + const Graphic3d_Vec2i aPos = getMouseCoords (self, theEvent); + const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent); + ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, Aspect_VKeyMouse_RightButton, aFlags, false); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); } // ======================================================================= @@ -288,11 +289,11 @@ static void getMouseCoords (NSView* theView, // ======================================================================= - (void )rightMouseDragged: (NSEvent* )theEvent { - if ([theEvent modifierFlags] & NSEventModifierFlagControl) - { - getMouseCoords (self, theEvent, X_Motion, Y_Motion); - VT_ProcessControlButton3Motion(); - } + const Graphic3d_Vec2i aPos = getMouseCoords (self, theEvent); + const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent); + const Aspect_VKeyMouse aButtons = ViewerTest::CurrentEventManager()->PressedMouseButtons(); + ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); } // ======================================================================= @@ -301,14 +302,18 @@ static void getMouseCoords (NSView* theView, // ======================================================================= - (void )scrollWheel: (NSEvent* )theEvent { - float aDelta = [theEvent deltaY]; + const Graphic3d_Vec2i aPos = getMouseCoords (self, theEvent); + const Aspect_VKeyFlags aFlags = getMouseKeyFlags (theEvent); + + const Standard_Real aDelta = [theEvent deltaY]; if (Abs (aDelta) < 0.001) { // a lot of values near zero can be generated by touchpad return; } - ViewerTest::CurrentView()->Zoom (0, 0, aDelta, aDelta); + ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDelta, aFlags)); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); } // ======================================================================= @@ -317,14 +322,36 @@ static void getMouseCoords (NSView* theView, // ======================================================================= - (void )keyDown: (NSEvent* )theEvent { - NSString* aStringNs = [theEvent characters]; - if (aStringNs == NULL || [aStringNs length] == 0) + unsigned int aKeyCode = [theEvent keyCode]; + const Aspect_VKey aVKey = Cocoa_Window::VirtualKeyFromNative (aKeyCode); + if (aVKey != Aspect_VKey_UNKNOWN) { - return; + const double aTimeStamp = [theEvent timestamp]; + ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); } - const Standard_CString aString = [aStringNs UTF8String]; - VT_ProcessKeyPress (aString); + //NSString* aStringNs = [theEvent characters]; + //if (aStringNs != NULL && [aStringNs length] != 1) + //{ + // const Standard_CString aString = [aStringNs UTF8String]; + //} +} + +// ======================================================================= +// function : keyUp +// purpose : +// ======================================================================= +- (void )keyUp: (NSEvent* )theEvent +{ + unsigned int aKeyCode = [theEvent keyCode]; + const Aspect_VKey aVKey = Cocoa_Window::VirtualKeyFromNative (aKeyCode); + if (aVKey != Aspect_VKey_UNKNOWN) + { + const double aTimeStamp = [theEvent timestamp]; + ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp); + ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true); + } } @end diff --git a/src/WNT/WNT_Window.cxx b/src/WNT/WNT_Window.cxx index 88ebbea973..992204303d 100644 --- a/src/WNT/WNT_Window.cxx +++ b/src/WNT/WNT_Window.cxx @@ -355,6 +355,16 @@ void WNT_Window::SetPos (const Standard_Integer theX, const Standard_Integer th aYBottom = theY1; } +// ======================================================================= +// function : SetTitle +// purpose : +// ======================================================================= +void WNT_Window::SetTitle (const TCollection_AsciiString& theTitle) +{ + const TCollection_ExtendedString aTitleW (theTitle); + SetWindowTextW ((HWND )myHWindow, aTitleW.ToWideString()); +} + // ======================================================================= // function : InvalidateContent // purpose : @@ -367,4 +377,270 @@ void WNT_Window::InvalidateContent (const Handle(Aspect_DisplayConnection)& ) } } +// ======================================================================= +// function : VirtualKeyFromNative +// purpose : +// ======================================================================= +Aspect_VKey WNT_Window::VirtualKeyFromNative (Standard_Integer theKey) +{ + if (theKey >= Standard_Integer('0') + && theKey <= Standard_Integer('9')) + { + return Aspect_VKey((theKey - Standard_Integer('0')) + Aspect_VKey_0); + } + if (theKey >= Standard_Integer('A') + && theKey <= Standard_Integer('Z')) + { + // main latin alphabet keys + return Aspect_VKey((theKey - Standard_Integer('A')) + Aspect_VKey_A); + } + if (theKey >= VK_F1 + && theKey <= VK_F24) + { + // special keys + if (theKey <= VK_F12) + { + return Aspect_VKey((theKey - VK_F1) + Aspect_VKey_F1); + } + return Aspect_VKey_UNKNOWN; + } + if (theKey >= VK_NUMPAD0 + && theKey <= VK_NUMPAD9) + { + // numpad keys + return Aspect_VKey((theKey - VK_NUMPAD0) + Aspect_VKey_Numpad0); + } + + switch (theKey) + { + case VK_LBUTTON: + case VK_RBUTTON: + case VK_CANCEL: + case VK_MBUTTON: + case VK_XBUTTON1: + case VK_XBUTTON2: + return Aspect_VKey_UNKNOWN; + case VK_BACK: + return Aspect_VKey_Backspace; + case VK_TAB: + return Aspect_VKey_Tab; + case VK_CLEAR: + return Aspect_VKey_UNKNOWN; + case VK_RETURN: + return Aspect_VKey_Enter; + case VK_SHIFT: + return Aspect_VKey_Shift; + case VK_CONTROL: + return Aspect_VKey_Control; + case VK_MENU: + return Aspect_VKey_Alt; //Aspect_VKey_Menu; + case VK_PAUSE: + case VK_CAPITAL: + return Aspect_VKey_UNKNOWN; + case VK_ESCAPE: + return Aspect_VKey_Escape; + case VK_CONVERT: + case VK_NONCONVERT: + case VK_ACCEPT: + case VK_MODECHANGE: + return Aspect_VKey_UNKNOWN; + case VK_SPACE: + return Aspect_VKey_Space; + case VK_PRIOR: + return Aspect_VKey_PageUp; + case VK_NEXT: + return Aspect_VKey_PageDown; + case VK_END: + return Aspect_VKey_End; + case VK_HOME: + return Aspect_VKey_Home; + case VK_LEFT: + return Aspect_VKey_Left; + case VK_UP: + return Aspect_VKey_Up; + case VK_DOWN: + return Aspect_VKey_Down; + case VK_RIGHT: + return Aspect_VKey_Right; + case VK_SELECT: + case VK_PRINT: + case VK_EXECUTE: + case VK_SNAPSHOT: + return Aspect_VKey_UNKNOWN; + case VK_INSERT: + return Aspect_VKey_UNKNOWN; // Aspect_VKey_Insert + case VK_DELETE: + return Aspect_VKey_Delete; + case VK_HELP: + case VK_LWIN: + case VK_RWIN: + case VK_APPS: + case VK_SLEEP: + return Aspect_VKey_UNKNOWN; + case VK_MULTIPLY: + return Aspect_VKey_NumpadMultiply; + case VK_ADD: + return Aspect_VKey_NumpadAdd; + case VK_SEPARATOR: + case VK_DECIMAL: + return Aspect_VKey_UNKNOWN; + case VK_SUBTRACT: + return Aspect_VKey_NumpadSubtract; + case VK_DIVIDE: + return Aspect_VKey_NumpadDivide; + case VK_NUMLOCK: + return Aspect_VKey_Numlock; + case VK_SCROLL: + return Aspect_VKey_Scroll; + case VK_LSHIFT: + case VK_RSHIFT: + case VK_LCONTROL: + case VK_RCONTROL: + case VK_LMENU: + case VK_RMENU: + return Aspect_VKey_UNKNOWN; + case VK_BROWSER_BACK: + return Aspect_VKey_BrowserBack; + case VK_BROWSER_FORWARD: + return Aspect_VKey_BrowserForward; + case VK_BROWSER_REFRESH: + return Aspect_VKey_BrowserRefresh; + case VK_BROWSER_STOP: + return Aspect_VKey_BrowserStop; + case VK_BROWSER_SEARCH: + return Aspect_VKey_BrowserSearch; + case VK_BROWSER_FAVORITES: + return Aspect_VKey_BrowserFavorites; + case VK_BROWSER_HOME: + return Aspect_VKey_BrowserHome; + case VK_VOLUME_MUTE: + return Aspect_VKey_VolumeMute; + case VK_VOLUME_DOWN: + return Aspect_VKey_VolumeDown; + case VK_VOLUME_UP: + return Aspect_VKey_VolumeUp; + case VK_MEDIA_NEXT_TRACK: + return Aspect_VKey_MediaNextTrack; + case VK_MEDIA_PREV_TRACK: + return Aspect_VKey_MediaPreviousTrack; + case VK_MEDIA_STOP: + return Aspect_VKey_MediaStop; + case VK_MEDIA_PLAY_PAUSE: + return Aspect_VKey_MediaPlayPause; + case VK_OEM_1: + return Aspect_VKey_Semicolon; + case VK_OEM_PLUS: + return Aspect_VKey_Plus; + case VK_OEM_COMMA: + return Aspect_VKey_Comma; + case VK_OEM_MINUS: + return Aspect_VKey_Minus; + case VK_OEM_PERIOD: + return Aspect_VKey_Period; + case VK_OEM_2: + return Aspect_VKey_Slash; + case VK_OEM_3: + return Aspect_VKey_Tilde; + case VK_OEM_4: + return Aspect_VKey_BracketLeft; + case VK_OEM_5: + return Aspect_VKey_Backslash; + case VK_OEM_6: + return Aspect_VKey_BracketRight; + case VK_OEM_7: + return Aspect_VKey_Apostrophe; + } + return Aspect_VKey_UNKNOWN; +} + +// ======================================================================= +// function : MouseKeyFlagsFromEvent +// purpose : +// ======================================================================= +Aspect_VKeyFlags WNT_Window::MouseKeyFlagsFromEvent (WPARAM theKeys) +{ + Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE; + if ((theKeys & MK_CONTROL) != 0) + { + aFlags |= Aspect_VKeyFlags_CTRL; + } + if ((theKeys & MK_SHIFT) != 0) + { + aFlags |= Aspect_VKeyFlags_SHIFT; + } + if (GetKeyState (VK_MENU) < 0) + { + aFlags |= Aspect_VKeyFlags_ALT; + } + return aFlags; +} + +// ======================================================================= +// function : MouseKeyFlagsAsync +// purpose : +// ======================================================================= +Aspect_VKeyFlags WNT_Window::MouseKeyFlagsAsync() +{ + Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE; + if ((GetAsyncKeyState (VK_CONTROL) & 0x8000) != 0) + { + aFlags |= Aspect_VKeyFlags_CTRL; + } + if ((GetAsyncKeyState (VK_SHIFT) & 0x8000) != 0) + { + aFlags |= Aspect_VKeyFlags_SHIFT; + } + if ((GetAsyncKeyState (VK_MENU) & 0x8000) != 0) + { + aFlags |= Aspect_VKeyFlags_ALT; + } + return aFlags; +} + +// ======================================================================= +// function : MouseButtonsFromEvent +// purpose : +// ======================================================================= +Aspect_VKeyMouse WNT_Window::MouseButtonsFromEvent (WPARAM theKeys) +{ + Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE; + if ((theKeys & MK_LBUTTON) != 0) + { + aButtons |= Aspect_VKeyMouse_LeftButton; + } + if ((theKeys & MK_MBUTTON) != 0) + { + aButtons |= Aspect_VKeyMouse_MiddleButton; + } + if ((theKeys & MK_RBUTTON) != 0) + { + aButtons |= Aspect_VKeyMouse_RightButton; + } + return aButtons; +} + +// ======================================================================= +// function : MouseButtonsAsync +// purpose : +// ======================================================================= +Aspect_VKeyMouse WNT_Window::MouseButtonsAsync() +{ + Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE; + const bool isSwapped = GetSystemMetrics (SM_SWAPBUTTON) != 0; + + if ((GetAsyncKeyState (!isSwapped ? VK_LBUTTON : VK_RBUTTON) & 0x8000) != 0) + { + aButtons |= Aspect_VKeyMouse_LeftButton; + } + if ((GetAsyncKeyState (VK_MBUTTON) & 0x8000) != 0) + { + aButtons |= Aspect_VKeyMouse_MiddleButton; + } + if ((GetAsyncKeyState (!isSwapped ? VK_RBUTTON : VK_LBUTTON) & 0x8000) != 0) + { + aButtons |= Aspect_VKeyMouse_RightButton; + } + return aButtons; +} + #endif // _WIN32 diff --git a/src/WNT/WNT_Window.hxx b/src/WNT/WNT_Window.hxx index d031ab4703..cbd6a8f8de 100644 --- a/src/WNT/WNT_Window.hxx +++ b/src/WNT/WNT_Window.hxx @@ -17,36 +17,42 @@ #ifndef _WNT_Window_HeaderFile #define _WNT_Window_HeaderFile -#include +#include #if defined(_WIN32) && !defined(OCCT_UWP) -#include -#include +#include +#include #include -#include -#include -#include +#include #include -#include -#include -#include -#include -class WNT_WClass; -class Aspect_WindowDefinitionError; -class Aspect_WindowError; +class WNT_WClass; -class WNT_Window; DEFINE_STANDARD_HANDLE(WNT_Window, Aspect_Window) //! This class defines Windows NT window class WNT_Window : public Aspect_Window { +public: + + //! Convert WInAPI virtual key (VK_ enumeration) into Aspect_VKey. + Standard_EXPORT static Aspect_VKey VirtualKeyFromNative (Standard_Integer theKey); + + //! Convert WPARAM from mouse event to key flags. + Standard_EXPORT static Aspect_VKeyFlags MouseKeyFlagsFromEvent (WPARAM theKeys); + + //! Convert WPARAM from mouse event to mouse buttons bitmask. + Standard_EXPORT static Aspect_VKeyMouse MouseButtonsFromEvent (WPARAM theKeys); + + //! Use GetAsyncKeyState() to fetch actual mouse key flags regardless of event loop. + Standard_EXPORT static Aspect_VKeyFlags MouseKeyFlagsAsync(); + + //! Use GetAsyncKeyState() to fetch actual mouse buttons state regardless of event loop. + Standard_EXPORT static Aspect_VKeyMouse MouseButtonsAsync(); public: - //! Creates a Window defined by his position and size //! in pixles from the Parent Window. //! Trigger: Raises WindowDefinitionError if the Position out of the @@ -115,6 +121,9 @@ public: //! Returns nothing on Windows virtual Aspect_FBConfig NativeFBConfig() const Standard_OVERRIDE { return NULL; } + //! Sets window title. + Standard_EXPORT virtual void SetTitle (const TCollection_AsciiString& theTitle) Standard_OVERRIDE; + //! Invalidate entire window content by calling InvalidateRect() WinAPI function, resulting in WM_PAINT event put into window message loop. //! Method can be called from non-window thread, and system will also automatically aggregate multiple events into single one. Standard_EXPORT virtual void InvalidateContent (const Handle(Aspect_DisplayConnection)& theDisp = NULL) Standard_OVERRIDE; diff --git a/src/Xw/Xw_Window.cxx b/src/Xw/Xw_Window.cxx index b811c5e1e3..3622de9769 100644 --- a/src/Xw/Xw_Window.cxx +++ b/src/Xw/Xw_Window.cxx @@ -22,6 +22,8 @@ #include #include +//#include + #if defined(HAVE_EGL) || defined(HAVE_GLES2) #include #ifndef EGL_OPENGL_ES3_BIT @@ -500,6 +502,18 @@ void Xw_Window::Size (Standard_Integer& theWidth, theHeight = aWinAttr.height; } +// ======================================================================= +// function : SetTitle +// purpose : +// ======================================================================= +void Xw_Window::SetTitle (const TCollection_AsciiString& theTitle) +{ + if (myXWindow != 0) + { + XStoreName (myDisplay->GetDisplay(), myXWindow, theTitle.ToCString()); + } +} + // ======================================================================= // function : InvalidateContent // purpose : @@ -522,4 +536,155 @@ void Xw_Window::InvalidateContent (const Handle(Aspect_DisplayConnection)& theDi XFlush (aDispX); } +// ======================================================================= +// function : VirtualKeyFromNative +// purpose : +// ======================================================================= +Aspect_VKey Xw_Window::VirtualKeyFromNative (unsigned long theKey) +{ + if (theKey >= XK_0 + && theKey <= XK_9) + { + return Aspect_VKey(theKey - XK_0 + Aspect_VKey_0); + } + + if (theKey >= XK_A + && theKey <= XK_Z) + { + return Aspect_VKey(theKey - XK_A + Aspect_VKey_A); + } + + if (theKey >= XK_a + && theKey <= XK_z) + { + return Aspect_VKey(theKey - XK_a + Aspect_VKey_A); + } + + if (theKey >= XK_F1 + && theKey <= XK_F24) + { + if (theKey <= XK_F12) + { + return Aspect_VKey(theKey - XK_F1 + Aspect_VKey_F1); + } + return Aspect_VKey_UNKNOWN; + } + + switch (theKey) + { + case XK_space: + return Aspect_VKey_Space; + case XK_apostrophe: + return Aspect_VKey_Apostrophe; + case XK_comma: + return Aspect_VKey_Comma; + case XK_minus: + return Aspect_VKey_Minus; + case XK_period: + return Aspect_VKey_Period; + case XK_semicolon: + return Aspect_VKey_Semicolon; + case XK_equal: + return Aspect_VKey_Equal; + case XK_bracketleft: + return Aspect_VKey_BracketLeft; + case XK_backslash: + return Aspect_VKey_Backslash; + case XK_bracketright: + return Aspect_VKey_BracketRight; + case XK_BackSpace: + return Aspect_VKey_Backspace; + case XK_Tab: + return Aspect_VKey_Tab; + //case XK_Linefeed: + case XK_Return: + case XK_KP_Enter: + return Aspect_VKey_Enter; + //case XK_Pause: + // return Aspect_VKey_Pause; + case XK_Escape: + return Aspect_VKey_Escape; + case XK_Home: + return Aspect_VKey_Home; + case XK_Left: + return Aspect_VKey_Left; + case XK_Up: + return Aspect_VKey_Up; + case XK_Right: + return Aspect_VKey_Right; + case XK_Down: + return Aspect_VKey_Down; + case XK_Prior: + return Aspect_VKey_PageUp; + case XK_Next: + return Aspect_VKey_PageDown; + case XK_End: + return Aspect_VKey_End; + //case XK_Insert: + // return Aspect_VKey_Insert; + case XK_Menu: + return Aspect_VKey_Menu; + case XK_Num_Lock: + return Aspect_VKey_Numlock; + //case XK_KP_Delete: + // return Aspect_VKey_NumDelete; + case XK_KP_Multiply: + return Aspect_VKey_NumpadMultiply; + case XK_KP_Add: + return Aspect_VKey_NumpadAdd; + //case XK_KP_Separator: + // return Aspect_VKey_Separator; + case XK_KP_Subtract: + return Aspect_VKey_NumpadSubtract; + //case XK_KP_Decimal: + // return Aspect_VKey_Decimal; + case XK_KP_Divide: + return Aspect_VKey_NumpadDivide; + case XK_Shift_L: + case XK_Shift_R: + return Aspect_VKey_Shift; + case XK_Control_L: + case XK_Control_R: + return Aspect_VKey_Control; + //case XK_Caps_Lock: + // return Aspect_VKey_CapsLock; + case XK_Alt_L: + case XK_Alt_R: + return Aspect_VKey_Alt; + //case XK_Super_L: + //case XK_Super_R: + // return Aspect_VKey_Super; + case XK_Delete: + return Aspect_VKey_Delete; + + case 0x1008FF11: // XF86AudioLowerVolume + return Aspect_VKey_VolumeDown; + case 0x1008FF12: // XF86AudioMute + return Aspect_VKey_VolumeMute; + case 0x1008FF13: // XF86AudioRaiseVolume + return Aspect_VKey_VolumeUp; + + case 0x1008FF14: // XF86AudioPlay + return Aspect_VKey_MediaPlayPause; + case 0x1008FF15: // XF86AudioStop + return Aspect_VKey_MediaStop; + case 0x1008FF16: // XF86AudioPrev + return Aspect_VKey_MediaPreviousTrack; + case 0x1008FF17: // XF86AudioNext + return Aspect_VKey_MediaNextTrack; + + case 0x1008FF18: // XF86HomePage + return Aspect_VKey_BrowserHome; + case 0x1008FF26: // XF86Back + return Aspect_VKey_BrowserBack; + case 0x1008FF27: // XF86Forward + return Aspect_VKey_BrowserForward; + case 0x1008FF28: // XF86Stop + return Aspect_VKey_BrowserStop; + case 0x1008FF29: // XF86Refresh + return Aspect_VKey_BrowserRefresh; + } + return Aspect_VKey_UNKNOWN; +} + #endif // Win32 or Mac OS X diff --git a/src/Xw/Xw_Window.hxx b/src/Xw/Xw_Window.hxx index 6ab427370d..5356f07506 100644 --- a/src/Xw/Xw_Window.hxx +++ b/src/Xw/Xw_Window.hxx @@ -20,6 +20,7 @@ #include +#include #include #include #include @@ -38,6 +39,10 @@ class Aspect_GradientBackground; //! This class defines XLib window intended for creation of OpenGL context. class Xw_Window : public Aspect_Window { +public: + + //! Convert X11 virtual key (KeySym) into Aspect_VKey. + Standard_EXPORT static Aspect_VKey VirtualKeyFromNative (unsigned long theKey); public: @@ -111,6 +116,9 @@ public: return myFBConfig; } + //! Sets window title. + Standard_EXPORT virtual void SetTitle (const TCollection_AsciiString& theTitle) Standard_OVERRIDE; + //! Invalidate entire window content through generation of Expose event. //! This method does not aggregate multiple calls into single event - dedicated event will be sent on each call. //! When NULL display connection is specified, the connection specified on window creation will be used. diff --git a/tests/bugs/vis/bug26147 b/tests/bugs/vis/bug26147 index 7f6cefd754..2e3b6571d0 100644 --- a/tests/bugs/vis/bug26147 +++ b/tests/bugs/vis/bug26147 @@ -49,8 +49,8 @@ if {$aNbSelected3 != 4} { vselect 0 0 -vselect 75 230 235 320 -allowoverlap 1 1 -vselect 350 150 380 170 1 +vselect 75 230 235 320 -allowoverlap 1 1 +vselect 350 150 380 170 -allowOverlap 1 1 vnbselected set aNbSelected4 [vnbselected] if {$aNbSelected4 != 13} { -- 2.20.1