0d345201a1bf503921d4eb337d80f1016162c3e5
[occt.git] / src / AIS / AIS_ViewController.cxx
1 // Copyright (c) 2016-2019 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include "AIS_ViewController.hxx"
15
16 #include <AIS_AnimationCamera.hxx>
17 #include <AIS_InteractiveContext.hxx>
18 #include <AIS_Manipulator.hxx>
19 #include <AIS_Point.hxx>
20 #include <AIS_RubberBand.hxx>
21 #include <Aspect_Grid.hxx>
22 #include <Geom_CartesianPoint.hxx>
23 #include <Message.hxx>
24 #include <Message_Messenger.hxx>
25 #include <gp_Quaternion.hxx>
26 #include <V3d_View.hxx>
27
28 // =======================================================================
29 // function : AIS_ViewController
30 // purpose  :
31 // =======================================================================
32 AIS_ViewController::AIS_ViewController()
33 : myLastEventsTime    (0.0),
34   myToAskNextFrame    (false),
35   myMinCamDistance    (1.0),
36   myRotationMode      (AIS_RotationMode_BndBoxActive),
37   myNavigationMode    (AIS_NavigationMode_Orbit),
38   myMouseAccel           (1.0f),
39   myOrbitAccel           (1.0f),
40   myToShowPanAnchorPoint (true),
41   myToShowRotateCenter   (true),
42   myToLockOrbitZUp       (false),
43   myToInvertPitch        (false),
44   myToAllowTouchZRotation(false),
45   myToAllowRotation      (true),
46   myToAllowPanning       (true),
47   myToAllowZooming       (true),
48   myToAllowZFocus        (true),
49   myToAllowHighlight     (true),
50   myToAllowDragging      (true),
51   myToStickToRayOnZoom   (true),
52   myToStickToRayOnRotation (true),
53   //
54   myWalkSpeedAbsolute (1.5f),
55   myWalkSpeedRelative (0.1f),
56   myThrustSpeed (0.0f),
57   myHasThrust (false),
58   //
59   myViewAnimation (new AIS_AnimationCamera ("AIS_ViewController_ViewAnimation", Handle(V3d_View)())),
60   myPrevMoveTo (-1, -1),
61   myHasHlrOnBeforeRotation (false),
62   //
63   myMouseClickThreshold (3.0),
64   myMouseDoubleClickInt (0.4),
65   myScrollZoomRatio     (15.0f),
66   myMouseActiveGesture  (AIS_MouseGesture_NONE),
67   myMouseActiveIdleRotation (false),
68   myMouseClickCounter   (0),
69   myMousePressed        (Aspect_VKeyMouse_NONE),
70   myMouseModifiers      (Aspect_VKeyFlags_NONE),
71   myMouseSingleButton   (-1),
72   myMouseStopDragOnUnclick (false),
73   //
74   myTouchToleranceScale      (1.0f),
75   myTouchRotationThresholdPx (6.0f),
76   myTouchZRotationThreshold  (float(2.0 * M_PI / 180.0)),
77   myTouchPanThresholdPx      (4.0f),
78   myTouchZoomThresholdPx     (6.0f),
79   myTouchZoomRatio           (0.13f),
80   //
81   myNbTouchesLast (0),
82   myUpdateStartPointPan  (true),
83   myUpdateStartPointRot  (true),
84   myUpdateStartPointZRot (true),
85   //
86   myPanPnt3d (Precision::Infinite(), 0.0, 0.0)
87 {
88   myEventTimer.Start();
89
90   myAnchorPointPrs1 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
91   myAnchorPointPrs1->SetZLayer (Graphic3d_ZLayerId_Top);
92   myAnchorPointPrs1->SetMutable (true);
93
94   myAnchorPointPrs2 = new AIS_Point (new Geom_CartesianPoint (0.0, 0.0, 0.0));
95   myAnchorPointPrs2->SetZLayer (Graphic3d_ZLayerId_Topmost);
96   myAnchorPointPrs2->SetMutable (true);
97
98   myRubberBand = new AIS_RubberBand (Quantity_NOC_LIGHTBLUE, Aspect_TOL_SOLID, Quantity_NOC_LIGHTBLUE, 0.4, 1.0);
99   myRubberBand->SetZLayer (Graphic3d_ZLayerId_TopOSD);
100   myRubberBand->SetTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_UPPER));
101   myRubberBand->SetDisplayMode (0);
102   myRubberBand->SetMutable (true);
103
104   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton,                           AIS_MouseGesture_RotateOrbit);
105   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_CTRL,   AIS_MouseGesture_Zoom);
106   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_SHIFT,  AIS_MouseGesture_Pan);
107   myMouseGestureMap.Bind (Aspect_VKeyMouse_LeftButton | Aspect_VKeyFlags_ALT,    AIS_MouseGesture_SelectRectangle);
108
109   myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton,                          AIS_MouseGesture_Zoom);
110   myMouseGestureMap.Bind (Aspect_VKeyMouse_RightButton | Aspect_VKeyFlags_CTRL,  AIS_MouseGesture_RotateOrbit);
111
112   myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton,                         AIS_MouseGesture_Pan);
113   myMouseGestureMap.Bind (Aspect_VKeyMouse_MiddleButton | Aspect_VKeyFlags_CTRL, AIS_MouseGesture_Pan);
114 }
115
116 // =======================================================================
117 // function : ~AIS_ViewController
118 // purpose  :
119 // =======================================================================
120 AIS_ViewController::~AIS_ViewController()
121 {
122   //
123 }
124
125 // =======================================================================
126 // function : ResetViewInput
127 // purpose  :
128 // =======================================================================
129 void AIS_ViewController::ResetViewInput()
130 {
131   myKeys.Reset();
132   myMousePressed      = Aspect_VKeyMouse_NONE;
133   myMouseModifiers    = Aspect_VKeyFlags_NONE;
134   myMouseSingleButton = -1;
135   myUI.Dragging.ToAbort = true;
136   myMouseActiveGesture = AIS_MouseGesture_NONE;
137   myMouseClickTimer.Stop();
138   myMouseClickCounter = 0;
139 }
140
141 // =======================================================================
142 // function : FlushViewEvents
143 // purpose  :
144 // =======================================================================
145 void AIS_ViewController::FlushViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
146                                           const Handle(V3d_View)& theView,
147                                           Standard_Boolean theToHandle)
148 {
149   flushBuffers (theCtx, theView);
150   flushGestures(theCtx, theView);
151   if (theToHandle)
152   {
153     HandleViewEvents (theCtx, theView);
154   }
155 }
156
157 // =======================================================================
158 // function : flushBuffers
159 // purpose  :
160 // =======================================================================
161 void AIS_ViewController::flushBuffers (const Handle(AIS_InteractiveContext)& ,
162                                        const Handle(V3d_View)& )
163 {
164   myToAskNextFrame = false;
165
166   myGL.IsNewGesture = myUI.IsNewGesture;
167   myUI.IsNewGesture = false;
168
169   myGL.ZoomActions.Clear();
170   myGL.ZoomActions.Append (myUI.ZoomActions);
171   myUI.ZoomActions.Clear();
172
173   myGL.Orientation.ToFitAll = myUI.Orientation.ToFitAll;
174   myUI.Orientation.ToFitAll = false;
175   if (myUI.Orientation.ToSetViewOrient)
176   {
177     myUI.Orientation.ToSetViewOrient = false;
178     myGL.Orientation.ToSetViewOrient = true;
179     myGL.Orientation.ViewOrient      = myUI.Orientation.ViewOrient;
180   }
181
182   if (myUI.MoveTo.ToHilight)
183   {
184     myUI.MoveTo.ToHilight = false;
185     myGL.MoveTo.ToHilight = true;
186     myGL.MoveTo.Point     = myUI.MoveTo.Point;
187   }
188
189   {
190     myGL.Selection.Tool   = myUI.Selection.Tool;
191     myGL.Selection.IsXOR  = myUI.Selection.IsXOR;
192     myGL.Selection.Points = myUI.Selection.Points;
193     myUI.Selection.IsXOR  = false;
194     if (myUI.Selection.Tool == AIS_ViewSelectionTool_Picking)
195     {
196       myUI.Selection.Points.Clear();
197     }
198   }
199
200   if (myUI.Selection.ToApplyTool)
201   {
202     myGL.Selection.ToApplyTool = true;
203     myUI.Selection.ToApplyTool = false;
204     myUI.Selection.Points.Clear();
205   }
206
207   if (myUI.Panning.ToStart)
208   {
209     myUI.Panning.ToStart = false;
210     myGL.Panning.ToStart = true;
211     myGL.Panning.PointStart = myUI.Panning.PointStart;
212   }
213
214   if (myUI.Panning.ToPan)
215   {
216     myUI.Panning.ToPan = false;
217     myGL.Panning.ToPan = true;
218     myGL.Panning.Delta = myUI.Panning.Delta;
219   }
220
221   if (myUI.Dragging.ToAbort)
222   {
223     myUI.Dragging.ToAbort = false;
224     myGL.Dragging.ToAbort = true;
225   }
226   else if (myUI.Dragging.ToStop)
227   {
228     myUI.Dragging.ToStop = false;
229     myGL.Dragging.ToStop = true;
230   }
231   else if (myUI.Dragging.ToStart)
232   {
233     myUI.Dragging.ToStart = false;
234     myGL.Dragging.ToStart = true;
235     myGL.Dragging.PointStart = myUI.Dragging.PointStart;
236   }
237   myGL.Dragging.PointTo = myUI.Dragging.PointTo;
238
239   if (myUI.OrbitRotation.ToStart)
240   {
241     myUI.OrbitRotation.ToStart    = false;
242     myGL.OrbitRotation.ToStart    = true;
243     myGL.OrbitRotation.PointStart = myUI.OrbitRotation.PointStart;
244   }
245
246   if (myUI.OrbitRotation.ToRotate)
247   {
248     myUI.OrbitRotation.ToRotate = false;
249     myGL.OrbitRotation.ToRotate = true;
250     myGL.OrbitRotation.PointTo  = myUI.OrbitRotation.PointTo;
251   }
252
253   if (myUI.ViewRotation.ToStart)
254   {
255     myUI.ViewRotation.ToStart    = false;
256     myGL.ViewRotation.ToStart    = true;
257     myGL.ViewRotation.PointStart = myUI.ViewRotation.PointStart;
258   }
259
260   if (myUI.ViewRotation.ToRotate)
261   {
262     myUI.ViewRotation.ToRotate = false;
263     myGL.ViewRotation.ToRotate = true;
264     myGL.ViewRotation.PointTo  = myUI.ViewRotation.PointTo;
265   }
266
267   if (myUI.ZRotate.ToRotate)
268   {
269     myGL.ZRotate = myUI.ZRotate;
270     myUI.ZRotate.ToRotate = false;
271   }
272 }
273
274 // =======================================================================
275 // function : flushGestures
276 // purpose  :
277 // =======================================================================
278 void AIS_ViewController::flushGestures (const Handle(AIS_InteractiveContext)& ,
279                                         const Handle(V3d_View)& theView)
280 {
281   const Standard_Real    aTolScale = myTouchToleranceScale;
282   const Standard_Integer aTouchNb  = myTouchPoints.Extent();
283   if (myNbTouchesLast != aTouchNb)
284   {
285     myNbTouchesLast = aTouchNb;
286     myGL.IsNewGesture = true;
287   }
288   if (aTouchNb == 1) // touch
289   {
290     Aspect_Touch& aTouch = myTouchPoints.ChangeFromIndex (1);
291     if (myUpdateStartPointRot)
292     {
293       // skip rotation if have active dragged object
294       if (myNavigationMode == AIS_NavigationMode_Orbit)
295       {
296         myGL.OrbitRotation.ToStart = true;
297         myGL.OrbitRotation.PointStart = myStartRotCoord;
298       }
299       else
300       {
301         myGL.ViewRotation.ToStart = true;
302         myGL.ViewRotation.PointStart = myStartRotCoord;
303       }
304
305       myUpdateStartPointRot = false;
306       theView->Invalidate();
307     }
308
309     // rotation
310     const Standard_Real aRotTouchTol = !aTouch.IsPreciseDevice
311                                      ? aTolScale * myTouchRotationThresholdPx
312                                      : gp::Resolution();
313     if (Abs (aTouch.Delta().x()) + Abs(aTouch.Delta().y()) > aRotTouchTol)
314     {
315       const Standard_Real aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
316       if (myNavigationMode == AIS_NavigationMode_Orbit)
317       {
318         const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.OrbitRotation.PointStart;
319         myGL.OrbitRotation.ToRotate = true;
320         myGL.OrbitRotation.PointTo  = myGL.OrbitRotation.PointStart + aRotDelta * aRotAccel;
321         myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
322       }
323       else
324       {
325         const Graphic3d_Vec2d aRotDelta = aTouch.To - myGL.ViewRotation.PointStart;
326         myGL.ViewRotation.ToRotate = true;
327         myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart + aRotDelta * aRotAccel;
328         myGL.Dragging.PointTo.SetValues ((int )aTouch.To.x(), (int )aTouch.To.y());
329       }
330
331       aTouch.From = aTouch.To;
332     }
333   }
334   else if (aTouchNb == 2) // pinch
335   {
336     Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
337     Aspect_Touch& aLastTouch  = myTouchPoints.ChangeFromIndex (2);
338     const Graphic3d_Vec2d aFrom[2] = { aFirstTouch.From, aLastTouch.From };
339     const Graphic3d_Vec2d aTo[2]   = { aFirstTouch.To,   aLastTouch.To   };
340
341     Graphic3d_Vec2d aPinchCenterStart ((aFrom[0].x() + aFrom[1].x()) / 2.0,
342                                        (aFrom[0].y() + aFrom[1].y()) / 2.0);
343
344     Standard_Real aPinchCenterXEnd = (aTo[0].x() + aTo[1].x()) / 2.0;
345     Standard_Real aPinchCenterYEnd = (aTo[0].y() + aTo[1].y()) / 2.0;
346
347     Standard_Real aPinchCenterXDev = aPinchCenterXEnd - aPinchCenterStart.x();
348     Standard_Real aPinchCenterYDev = aPinchCenterYEnd - aPinchCenterStart.y();
349
350     Standard_Real aStartSize = (aFrom[0] - aFrom[1]).Modulus();
351     Standard_Real anEndSize  = (  aTo[0] -   aTo[1]).Modulus();
352
353     Standard_Real aDeltaSize = anEndSize - aStartSize;
354
355     bool anIsClearDev = false;
356
357     if (myToAllowTouchZRotation)
358     {
359       Standard_Real A1 = aFrom[0].y() - aFrom[1].y();
360       Standard_Real B1 = aFrom[1].x() - aFrom[0].x();
361
362       Standard_Real A2 = aTo[0].y() - aTo[1].y();
363       Standard_Real B2 = aTo[1].x() - aTo[0].x();
364
365       Standard_Real aRotAngle = 0.0;
366
367       Standard_Real aDenomenator = A1*A2 + B1*B2;
368       if (aDenomenator <= Precision::Confusion())
369       {
370         aRotAngle = 0.0;
371       }
372       else
373       {
374         Standard_Real aNumerator = A1*B2 - A2*B1;
375         aRotAngle = ATan (aNumerator / aDenomenator);
376       }
377
378       if (Abs(aRotAngle) > Standard_Real(myTouchZRotationThreshold))
379       {
380         myGL.ZRotate.ToRotate = true;
381         myGL.ZRotate.Angle = aRotAngle;
382         anIsClearDev = true;
383       }
384     }
385
386     if (Abs(aDeltaSize) > aTolScale * myTouchZoomThresholdPx)
387     {
388       // zoom
389       aDeltaSize *= Standard_Real(myTouchZoomRatio);
390       Aspect_ScrollDelta aParams (Graphic3d_Vec2i (aPinchCenterStart), aDeltaSize);
391       myGL.ZoomActions.Append (aParams);
392       anIsClearDev = true;
393     }
394
395     const Standard_Real aPanTouchTol = !aFirstTouch.IsPreciseDevice
396                                      ? aTolScale * myTouchPanThresholdPx
397                                      : gp::Resolution();
398     if (Abs(aPinchCenterXDev) + Abs(aPinchCenterYDev) > aPanTouchTol)
399     {
400       // pan
401       if (myUpdateStartPointPan)
402       {
403         myGL.Panning.ToStart = true;
404         myGL.Panning.PointStart = Graphic3d_Vec2i (myStartPanCoord);
405         myUpdateStartPointPan = false;
406         theView->Invalidate();
407       }
408
409       myGL.Panning.ToPan = true;
410       myGL.Panning.Delta.x() = int( aPinchCenterXDev);
411       myGL.Panning.Delta.y() = int(-aPinchCenterYDev);
412       anIsClearDev = true;
413     }
414
415     if (anIsClearDev)
416     {
417       aFirstTouch.From = aFirstTouch.To;
418       aLastTouch .From = aLastTouch.To;
419     }
420   }
421 }
422
423 // =======================================================================
424 // function : UpdateViewOrientation
425 // purpose  :
426 // =======================================================================
427 void AIS_ViewController::UpdateViewOrientation (V3d_TypeOfOrientation theOrientation,
428                                                 bool theToFitAll)
429 {
430   myUI.Orientation.ToFitAll = theToFitAll;
431   myUI.Orientation.ToSetViewOrient = true;
432   myUI.Orientation.ViewOrient = theOrientation;
433 }
434
435 // =======================================================================
436 // function : SelectInViewer
437 // purpose  :
438 // =======================================================================
439 void AIS_ViewController::SelectInViewer (const Graphic3d_Vec2i& thePnt,
440                                          const bool theIsXOR)
441 {
442   if (myUI.Selection.Tool != AIS_ViewSelectionTool_Picking)
443   {
444     myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
445     myUI.Selection.Points.Clear();
446   }
447
448   myUI.Selection.IsXOR = theIsXOR;
449   myUI.Selection.Points.Append (thePnt);
450 }
451
452 // =======================================================================
453 // function : SelectInViewer
454 // purpose  :
455 // =======================================================================
456 void AIS_ViewController::SelectInViewer (const NCollection_Sequence<Graphic3d_Vec2i>& thePnts,
457                                          const bool theIsXOR)
458 {
459   myUI.Selection.IsXOR = theIsXOR;
460   myUI.Selection.Points = thePnts;
461   myUI.Selection.ToApplyTool = true;
462   if (thePnts.Length() == 1)
463   {
464     myUI.Selection.Tool = AIS_ViewSelectionTool_Picking;
465   }
466   else if (thePnts.Length() == 2)
467   {
468     myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
469   }
470   else
471   {
472     myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
473   }
474 }
475
476 // =======================================================================
477 // function : UpdateRubberBand
478 // purpose  :
479 // =======================================================================
480 void AIS_ViewController::UpdateRubberBand (const Graphic3d_Vec2i& thePntFrom,
481                                            const Graphic3d_Vec2i& thePntTo,
482                                            const bool theIsXOR)
483 {
484   myUI.Selection.Tool = AIS_ViewSelectionTool_RubberBand;
485   myUI.Selection.IsXOR = theIsXOR;
486   myUI.Selection.Points.Clear();
487   myUI.Selection.Points.Append (thePntFrom);
488   myUI.Selection.Points.Append (thePntTo);
489 }
490
491 // =======================================================================
492 // function : UpdatePolySelection
493 // purpose  :
494 // =======================================================================
495 void AIS_ViewController::UpdatePolySelection (const Graphic3d_Vec2i& thePnt,
496                                               bool theToAppend)
497 {
498   if (myUI.Selection.Tool != AIS_ViewSelectionTool_Polygon)
499   {
500     myUI.Selection.Tool = AIS_ViewSelectionTool_Polygon;
501     myUI.Selection.Points.Clear();
502   }
503
504   if (myUI.Selection.Points.IsEmpty())
505   {
506     myUI.Selection.Points.Append (thePnt);
507   }
508   else if (theToAppend
509         && myUI.Selection.Points.Last() != thePnt)
510   {
511     myUI.Selection.Points.Append (thePnt);
512   }
513   else
514   {
515     myUI.Selection.Points.ChangeLast() = thePnt;
516   }
517 }
518
519 // =======================================================================
520 // function : UpdateZoom
521 // purpose  :
522 // =======================================================================
523 bool AIS_ViewController::UpdateZoom (const Aspect_ScrollDelta& theDelta)
524 {
525   if (!myUI.ZoomActions.IsEmpty())
526   {
527     if (myUI.ZoomActions.ChangeLast().Point == theDelta.Point)
528     {
529       myUI.ZoomActions.ChangeLast().Delta += theDelta.Delta;
530       return false;
531     }
532   }
533
534   myUI.ZoomActions.Append (theDelta);
535   return true;
536 }
537
538 // =======================================================================
539 // function : UpdateZRotation
540 // purpose  :
541 // =======================================================================
542 bool AIS_ViewController::UpdateZRotation (double theAngle)
543 {
544   if (!ToAllowTouchZRotation())
545   {
546     return false;
547   }
548
549   myUI.ZRotate.Angle = myUI.ZRotate.ToRotate
550                      ? myUI.ZRotate.Angle + theAngle
551                      : theAngle;
552   if (myUI.ZRotate.ToRotate)
553   {
554     return false;
555   }
556   myUI.ZRotate.ToRotate = true;
557   return true;
558 }
559
560 // =======================================================================
561 // function : UpdateMouseScroll
562 // purpose  :
563 // =======================================================================
564 bool AIS_ViewController::UpdateMouseScroll (const Aspect_ScrollDelta& theDelta)
565 {
566   Aspect_ScrollDelta aDelta = theDelta;
567   aDelta.Delta *= myScrollZoomRatio;
568   return UpdateZoom (aDelta);
569 }
570
571 // =======================================================================
572 // function : UpdateMouseClick
573 // purpose  :
574 // =======================================================================
575 bool AIS_ViewController::UpdateMouseClick (const Graphic3d_Vec2i& thePoint,
576                                            Aspect_VKeyMouse theButton,
577                                            Aspect_VKeyFlags theModifiers,
578                                            bool theIsDoubleClick)
579 {
580   (void )theIsDoubleClick;
581   if (theButton == Aspect_VKeyMouse_LeftButton)
582   {
583     SelectInViewer (thePoint, (theModifiers & Aspect_VKeyFlags_SHIFT) != 0);
584     return true;
585   }
586   return false;
587 }
588
589 // =======================================================================
590 // function : UpdateMouseButtons
591 // purpose  :
592 // =======================================================================
593 bool AIS_ViewController::UpdateMouseButtons (const Graphic3d_Vec2i& thePoint,
594                                              Aspect_VKeyMouse theButtons,
595                                              Aspect_VKeyFlags theModifiers,
596                                              bool theIsEmulated)
597 {
598   bool toUpdateView = false;
599   const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
600   if (theButtons == Aspect_VKeyMouse_NONE
601    && myMouseSingleButton > 0)
602   {
603     const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
604     if (double(aDelta.cwiseAbs().maxComp()) < aTolClick)
605     {
606       ++myMouseClickCounter;
607       const bool isDoubleClick = myMouseClickCounter == 2
608                               && myMouseClickTimer.IsStarted()
609                               && myMouseClickTimer.ElapsedTime() <= myMouseDoubleClickInt;
610
611       myMouseClickTimer.Stop();
612       myMouseClickTimer.Reset();
613       myMouseClickTimer.Start();
614       if (isDoubleClick)
615       {
616         myMouseClickCounter = 0;
617       }
618       toUpdateView = UpdateMouseClick (thePoint, (Aspect_VKeyMouse )myMouseSingleButton, theModifiers, isDoubleClick) || toUpdateView;
619     }
620     else
621     {
622       myMouseClickTimer.Stop();
623       myMouseClickCounter = 0;
624       myMouseStopDragOnUnclick = false;
625       myUI.Dragging.ToStop = true;
626       toUpdateView = true;
627     }
628     myMouseSingleButton = -1;
629   }
630   else if (theButtons == Aspect_VKeyMouse_NONE)
631   {
632     myMouseSingleButton = -1;
633     if (myMouseStopDragOnUnclick)
634     {
635       myMouseStopDragOnUnclick = false;
636       myUI.Dragging.ToStop = true;
637       toUpdateView = true;
638     }
639   }
640   else if (myMouseSingleButton == -1)
641   {
642     if ((theButtons & Aspect_VKeyMouse_LeftButton) == Aspect_VKeyMouse_LeftButton)
643     {
644       myMouseSingleButton = Aspect_VKeyMouse_LeftButton;
645     }
646     else if ((theButtons & Aspect_VKeyMouse_RightButton) == Aspect_VKeyMouse_RightButton)
647     {
648       myMouseSingleButton = Aspect_VKeyMouse_RightButton;
649     }
650     else if ((theButtons & Aspect_VKeyMouse_MiddleButton) == Aspect_VKeyMouse_MiddleButton)
651     {
652       myMouseSingleButton = Aspect_VKeyMouse_MiddleButton;
653     }
654     else
655     {
656       myMouseSingleButton = 0;
657     }
658     if (myMouseSingleButton != 0)
659     {
660       if (myMouseClickCounter == 1)
661       {
662         const Graphic3d_Vec2i aDelta = thePoint - myMousePressPoint;
663         if (double(aDelta.cwiseAbs().maxComp()) >= aTolClick)
664         {
665           myMouseClickTimer.Stop();
666           myMouseClickCounter = 0;
667         }
668       }
669       myMousePressPoint = thePoint;
670     }
671   }
672   else
673   {
674     myMouseSingleButton = 0;
675
676     myUI.Dragging.ToAbort = true;
677     toUpdateView = true;
678   }
679
680   const AIS_MouseGesture aPrevGesture = myMouseActiveGesture;
681   myMouseModifiers = theModifiers;
682   myMousePressed   = theButtons;
683   if (theIsEmulated
684    || myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
685   {
686     myMouseActiveIdleRotation = false;
687     myMouseActiveGesture = AIS_MouseGesture_NONE;
688     if (theButtons != 0)
689     {
690       myMousePressPoint    = thePoint;
691       myMouseProgressPoint = myMousePressPoint;
692     }
693
694     if (myMouseGestureMap.Find (theButtons | theModifiers, myMouseActiveGesture))
695     {
696       switch (myMouseActiveGesture)
697       {
698         case AIS_MouseGesture_RotateView:
699         case AIS_MouseGesture_RotateOrbit:
700         {
701           if (myToAllowRotation)
702           {
703             myUpdateStartPointRot = true;
704           }
705           else
706           {
707             myMouseActiveGesture = AIS_MouseGesture_NONE;
708           }
709           break;
710         }
711         case AIS_MouseGesture_Pan:
712         {
713           if (myToAllowPanning)
714           {
715             myUpdateStartPointPan = true;
716           }
717           else
718           {
719             myMouseActiveGesture = AIS_MouseGesture_NONE;
720           }
721           break;
722         }
723         case AIS_MouseGesture_Zoom:
724         case AIS_MouseGesture_ZoomWindow:
725         {
726           if (!myToAllowZooming)
727           {
728             myMouseActiveGesture = AIS_MouseGesture_NONE;
729           }
730           break;
731         }
732         case AIS_MouseGesture_SelectRectangle:
733         {
734           break;
735         }
736         case AIS_MouseGesture_SelectLasso:
737         {
738           UpdatePolySelection (thePoint, true);
739           break;
740         }
741         case AIS_MouseGesture_NONE:
742         {
743           break;
744         }
745       }
746     }
747
748     if (theButtons == Aspect_VKeyMouse_LeftButton
749      && theModifiers == Aspect_VKeyFlags_NONE
750      && myToAllowDragging)
751     {
752       myUI.Dragging.ToStart = true;
753       myUI.Dragging.PointStart = thePoint;
754     }
755   }
756
757   if (aPrevGesture != myMouseActiveGesture)
758   {
759     if (aPrevGesture == AIS_MouseGesture_SelectRectangle
760      || aPrevGesture == AIS_MouseGesture_SelectLasso
761      || aPrevGesture == AIS_MouseGesture_ZoomWindow)
762     {
763       myUI.Selection.ToApplyTool = true;
764     }
765
766     myUI.IsNewGesture = true;
767     toUpdateView = true;
768   }
769   return toUpdateView;
770 }
771
772 // =======================================================================
773 // function : UpdateMousePosition
774 // purpose  :
775 // =======================================================================
776 bool AIS_ViewController::UpdateMousePosition (const Graphic3d_Vec2i& thePoint,
777                                               Aspect_VKeyMouse theButtons,
778                                               Aspect_VKeyFlags theModifiers,
779                                               bool theIsEmulated)
780 {
781   myMousePositionLast = thePoint;
782   if (myMouseSingleButton > 0)
783   {
784     const double aTolClick = (theIsEmulated ? myTouchToleranceScale : 1.0) * myMouseClickThreshold;
785     const Graphic3d_Vec2i aPressDelta = thePoint - myMousePressPoint;
786     if (double(aPressDelta.cwiseAbs().maxComp()) >= aTolClick)
787     {
788       myMouseClickTimer.Stop();
789       myMouseClickCounter = 0;
790       myMouseSingleButton = -1;
791       myMouseStopDragOnUnclick = true;
792     }
793   }
794
795   bool toUpdateView = false;
796   Graphic3d_Vec2i aDelta = thePoint - myMouseProgressPoint;
797   if (!theIsEmulated
798     && myNavigationMode == AIS_NavigationMode_FirstPersonWalk)
799   {
800     if (!myMouseActiveIdleRotation
801       || myMouseActiveGesture != AIS_MouseGesture_RotateView)
802     {
803       myMouseActiveIdleRotation = true;
804       myMouseActiveGesture = AIS_MouseGesture_RotateView;
805       myMousePressPoint     = thePoint;
806       myMouseProgressPoint  = thePoint;
807       myUpdateStartPointRot = false;
808       myUI.ViewRotation.ToStart = true;
809       myUI.ViewRotation.PointStart.SetValues (thePoint.x(), thePoint.y());
810       myUI.ViewRotation.ToRotate = false;
811       aDelta.SetValues (0, 0);
812     }
813   }
814   else
815   {
816     if (myMouseActiveIdleRotation
817      && myMouseActiveGesture == AIS_MouseGesture_RotateView)
818     {
819       myMouseActiveGesture = AIS_MouseGesture_NONE;
820     }
821     myMouseActiveIdleRotation = false;
822   }
823
824   if (myMouseModifiers != theModifiers
825    && UpdateMouseButtons (thePoint, theButtons, theModifiers, theIsEmulated))
826   {
827     toUpdateView = true;
828   }
829
830   switch (myMouseActiveGesture)
831   {
832     case AIS_MouseGesture_SelectRectangle:
833     case AIS_MouseGesture_ZoomWindow:
834     {
835       UpdateRubberBand (myMousePressPoint, thePoint);
836       if (myMouseActiveGesture == AIS_MouseGesture_ZoomWindow)
837       {
838         myUI.Selection.Tool = AIS_ViewSelectionTool_ZoomWindow;
839       }
840       toUpdateView = true;
841       break;
842     }
843     case AIS_MouseGesture_SelectLasso:
844     {
845       UpdatePolySelection (thePoint, true);
846       toUpdateView = true;
847       break;
848     }
849     case AIS_MouseGesture_RotateOrbit:
850     case AIS_MouseGesture_RotateView:
851     {
852       if (!myToAllowRotation)
853       {
854         break;
855       }
856       if (myUpdateStartPointRot)
857       {
858         if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
859         {
860           myUI.OrbitRotation.ToStart = true;
861           myUI.OrbitRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
862         }
863         else
864         {
865           myUI.ViewRotation.ToStart = true;
866           myUI.ViewRotation.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
867         }
868         myUpdateStartPointRot = false;
869       }
870
871       const double aRotTol = theIsEmulated
872                            ? double(myTouchToleranceScale) * myTouchRotationThresholdPx
873                            : 0.0;
874       if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aRotTol)
875       {
876         const double aRotAccel = myNavigationMode == AIS_NavigationMode_FirstPersonWalk ? myMouseAccel : myOrbitAccel;
877         const Graphic3d_Vec2i aRotDelta = thePoint - myMousePressPoint;
878         if (myMouseActiveGesture == AIS_MouseGesture_RotateOrbit)
879         {
880           myUI.OrbitRotation.ToRotate = true;
881           myUI.OrbitRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
882                                      + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
883         }
884         else
885         {
886           myUI.ViewRotation.ToRotate = true;
887           myUI.ViewRotation.PointTo = Graphic3d_Vec2d (myMousePressPoint.x(), myMousePressPoint.y())
888                                     + Graphic3d_Vec2d (aRotDelta.x(), aRotDelta.y()) * aRotAccel;
889         }
890         myUI.Dragging.PointTo = thePoint;
891
892         myMouseProgressPoint = thePoint;
893         toUpdateView = true;
894       }
895       break;
896     }
897     case AIS_MouseGesture_Zoom:
898     {
899       if (!myToAllowZooming)
900       {
901         break;
902       }
903       const double aZoomTol = theIsEmulated
904                             ? double(myTouchToleranceScale) * myTouchZoomThresholdPx
905                             : 0.0;
906       if (double (Abs (aDelta.x())) > aZoomTol)
907       {
908         if (UpdateZoom (Aspect_ScrollDelta (aDelta.x())))
909         {
910           toUpdateView = true;
911         }
912         myMouseProgressPoint = thePoint;
913       }
914       break;
915     }
916     case AIS_MouseGesture_Pan:
917     {
918       if (!myToAllowPanning)
919       {
920         break;
921       }
922       const double aPanTol = theIsEmulated
923                            ? double(myTouchToleranceScale) * myTouchPanThresholdPx
924                            : 0.0;
925       if (double (Abs (aDelta.x()) + Abs (aDelta.y())) > aPanTol)
926       {
927         if (myUpdateStartPointPan)
928         {
929           myUI.Panning.ToStart = true;
930           myUI.Panning.PointStart.SetValues (myMousePressPoint.x(), myMousePressPoint.y());
931           myUpdateStartPointPan = false;
932         }
933
934         aDelta.y() = -aDelta.y();
935         myMouseProgressPoint = thePoint;
936         if (myUI.Panning.ToPan)
937         {
938           myUI.Panning.Delta += aDelta;
939         }
940         else
941         {
942           myUI.Panning.ToPan = true;
943           myUI.Panning.Delta = aDelta;
944         }
945         toUpdateView = true;
946       }
947       break;
948     }
949     default:
950     {
951       break;
952     }
953   }
954
955   if (theButtons == Aspect_VKeyMouse_NONE
956   &&  myNavigationMode != AIS_NavigationMode_FirstPersonWalk
957   && !theIsEmulated
958   && !HasTouchPoints()
959   &&  myToAllowHighlight)
960   {
961     myUI.MoveTo.ToHilight = true;
962     myUI.MoveTo.Point = thePoint;
963     toUpdateView = true;
964   }
965   return toUpdateView;
966 }
967
968 // =======================================================================
969 // function : AddTouchPoint
970 // purpose  :
971 // =======================================================================
972 void AIS_ViewController::AddTouchPoint (Standard_Size theId,
973                                         const Graphic3d_Vec2d& thePnt,
974                                         Standard_Boolean theClearBefore)
975 {
976   myUI.MoveTo.ToHilight = false;
977   if (theClearBefore)
978   {
979     RemoveTouchPoint ((Standard_Size )-1);
980   }
981
982   myTouchPoints.Add (theId, Aspect_Touch (thePnt, false));
983   if (myTouchPoints.Extent() == 1)
984   {
985     myUpdateStartPointRot = true;
986     myStartRotCoord = thePnt;
987     if (myToAllowDragging)
988     {
989       myUI.Dragging.ToStart = true;
990       myUI.Dragging.PointStart.SetValues ((int )thePnt.x(), (int )thePnt.y());
991     }
992   }
993   else if (myTouchPoints.Extent() == 2)
994   {
995     myUI.Dragging.ToAbort = true;
996
997     myUpdateStartPointPan = true;
998     myStartPanCoord = thePnt;
999   }
1000   myUI.IsNewGesture = true;
1001 }
1002
1003 // =======================================================================
1004 // function : RemoveTouchPoint
1005 // purpose  :
1006 // =======================================================================
1007 bool AIS_ViewController::RemoveTouchPoint (Standard_Size theId,
1008                                            Standard_Boolean theClearSelectPnts)
1009 {
1010   if (theId == (Standard_Size )-1)
1011   {
1012     myTouchPoints.Clear (false);
1013   }
1014   else
1015   {
1016     const Standard_Integer anOldExtent = myTouchPoints.Extent();
1017     myTouchPoints.RemoveKey (theId);
1018     if (myTouchPoints.Extent() == anOldExtent)
1019     {
1020       return false;
1021     }
1022   }
1023
1024   if (myTouchPoints.Extent() == 1)
1025   {
1026     // avoid incorrect transition from pinch to one finger
1027     Aspect_Touch& aFirstTouch = myTouchPoints.ChangeFromIndex (1);
1028     aFirstTouch.To = aFirstTouch.From;
1029
1030     myStartRotCoord = aFirstTouch.To;
1031     myUpdateStartPointRot = true;
1032   }
1033   else if (myTouchPoints.Extent() == 2)
1034   {
1035     myStartPanCoord = myTouchPoints.FindFromIndex (1).To;
1036     myUpdateStartPointPan = true;
1037   }
1038   else if (myTouchPoints.IsEmpty())
1039   {
1040     if (theClearSelectPnts)
1041     {
1042       myUI.Selection.ToApplyTool = true;
1043     }
1044
1045     myUI.Dragging.ToStop = true;
1046   }
1047   myUI.IsNewGesture = true;
1048   return true;
1049 }
1050
1051 // =======================================================================
1052 // function : UpdateTouchPoint
1053 // purpose  :
1054 // =======================================================================
1055 void AIS_ViewController::UpdateTouchPoint (Standard_Size theId,
1056                                            const Graphic3d_Vec2d& thePnt)
1057 {
1058   if (Aspect_Touch* aTouch = myTouchPoints.ChangeSeek (theId))
1059   {
1060     aTouch->To = thePnt;
1061   }
1062   else
1063   {
1064     AddTouchPoint (theId, thePnt);
1065   }
1066 }
1067
1068 // =======================================================================
1069 // function : SetNavigationMode
1070 // purpose  :
1071 // =======================================================================
1072 void AIS_ViewController::SetNavigationMode (AIS_NavigationMode theMode)
1073 {
1074   myNavigationMode = theMode;
1075
1076   // abort rotation
1077   myUI.OrbitRotation.ToStart  = false;
1078   myUI.OrbitRotation.ToRotate = false;
1079   myUI.ViewRotation.ToStart   = false;
1080   myUI.ViewRotation.ToRotate  = false;
1081 }
1082
1083 // =======================================================================
1084 // function : KeyDown
1085 // purpose  :
1086 // =======================================================================
1087 void AIS_ViewController::KeyDown (Aspect_VKey theKey,
1088                                   double theTime,
1089                                   double thePressure)
1090 {
1091   myKeys.KeyDown (theKey, theTime, thePressure);
1092 }
1093
1094 // =======================================================================
1095 // function : KeyUp
1096 // purpose  :
1097 // =======================================================================
1098 void AIS_ViewController::KeyUp (Aspect_VKey theKey,
1099                                 double theTime)
1100 {
1101   myKeys.KeyUp (theKey, theTime);
1102 }
1103
1104 // =======================================================================
1105 // function : KeyFromAxis
1106 // purpose  :
1107 // =======================================================================
1108 void AIS_ViewController::KeyFromAxis (Aspect_VKey theNegative,
1109                                       Aspect_VKey thePositive,
1110                                       double theTime,
1111                                       double thePressure)
1112 {
1113   myKeys.KeyFromAxis (theNegative, thePositive, theTime, thePressure);
1114 }
1115
1116 // =======================================================================
1117 // function : FetchNavigationKeys
1118 // purpose  :
1119 // =======================================================================
1120 AIS_WalkDelta AIS_ViewController::FetchNavigationKeys (Standard_Real theCrouchRatio,
1121                                                        Standard_Real theRunRatio)
1122 {
1123   AIS_WalkDelta aWalk;
1124
1125   // navigation keys
1126   double aPrevEventTime = 0.0, aNewEventTime = 0.0;
1127   updateEventsTime (aPrevEventTime, aNewEventTime);
1128
1129   double aDuration = 0.0, aPressure = 1.0;
1130   if (Abs (myThrustSpeed) > gp::Resolution())
1131   {
1132     if (myHasThrust)
1133     {
1134       aWalk[AIS_WalkTranslation_Forward].Value = myThrustSpeed * (aNewEventTime - aPrevEventTime);
1135     }
1136     myHasThrust = true;
1137     myToAskNextFrame = true;
1138   }
1139   else
1140   {
1141     myHasThrust = false;
1142   }
1143
1144   aWalk.SetRunning (theRunRatio > 1.0
1145                  && myKeys.IsKeyDown (Aspect_VKey_Shift));
1146   if (myKeys.HoldDuration (Aspect_VKey_NavJump, aNewEventTime, aDuration))
1147   {
1148     myKeys.KeyUp (Aspect_VKey_NavJump, aNewEventTime);
1149     aWalk.SetJumping (true);
1150   }
1151   if (!aWalk.IsJumping()
1152    && theCrouchRatio < 1.0
1153    && myKeys.HoldDuration (Aspect_VKey_NavCrouch, aNewEventTime, aDuration))
1154   {
1155     aWalk.SetRunning (false);
1156     aWalk.SetCrouching (true);
1157   }
1158
1159   const double aMaxDuration = aNewEventTime - aPrevEventTime;
1160   const double aRunRatio = aWalk.IsRunning()
1161                          ? theRunRatio
1162                          : aWalk.IsCrouching()
1163                           ? theCrouchRatio
1164                           : 1.0;
1165   if (myKeys.HoldDuration (Aspect_VKey_NavForward, aNewEventTime, aDuration, aPressure))
1166   {
1167     double aProgress = Abs (Min (aMaxDuration, aDuration));
1168     aProgress *= aRunRatio;
1169     aWalk[AIS_WalkTranslation_Forward].Value += aProgress;
1170     aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1171     aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1172   }
1173   if (myKeys.HoldDuration (Aspect_VKey_NavBackward, aNewEventTime, aDuration, aPressure))
1174   {
1175     double aProgress = Abs (Min (aMaxDuration, aDuration));
1176     aProgress *= aRunRatio;
1177     aWalk[AIS_WalkTranslation_Forward].Value += -aProgress;
1178     aWalk[AIS_WalkTranslation_Forward].Pressure = aPressure;
1179     aWalk[AIS_WalkTranslation_Forward].Duration = aDuration;
1180   }
1181   if (myKeys.HoldDuration (Aspect_VKey_NavSlideLeft, aNewEventTime, aDuration, aPressure))
1182   {
1183     double aProgress = Abs (Min (aMaxDuration, aDuration));
1184     aProgress *= aRunRatio;
1185     aWalk[AIS_WalkTranslation_Side].Value = -aProgress;
1186     aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1187     aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1188   }
1189   if (myKeys.HoldDuration (Aspect_VKey_NavSlideRight, aNewEventTime, aDuration, aPressure))
1190   {
1191     double aProgress = Abs (Min (aMaxDuration, aDuration));
1192     aProgress *= aRunRatio;
1193     aWalk[AIS_WalkTranslation_Side].Value = aProgress;
1194     aWalk[AIS_WalkTranslation_Side].Pressure = aPressure;
1195     aWalk[AIS_WalkTranslation_Side].Duration = aDuration;
1196   }
1197   if (myKeys.HoldDuration (Aspect_VKey_NavLookLeft, aNewEventTime, aDuration, aPressure))
1198   {
1199     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1200     aWalk[AIS_WalkRotation_Yaw].Value = aProgress;
1201     aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1202     aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1203   }
1204   if (myKeys.HoldDuration (Aspect_VKey_NavLookRight, aNewEventTime, aDuration, aPressure))
1205   {
1206     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1207     aWalk[AIS_WalkRotation_Yaw].Value = -aProgress;
1208     aWalk[AIS_WalkRotation_Yaw].Pressure = aPressure;
1209     aWalk[AIS_WalkRotation_Yaw].Duration = aDuration;
1210   }
1211   if (myKeys.HoldDuration (Aspect_VKey_NavLookUp, aNewEventTime, aDuration, aPressure))
1212   {
1213     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1214     aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? -aProgress : aProgress;
1215     aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1216     aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1217   }
1218   if (myKeys.HoldDuration (Aspect_VKey_NavLookDown, aNewEventTime, aDuration, aPressure))
1219   {
1220     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1221     aWalk[AIS_WalkRotation_Pitch].Value = !myToInvertPitch ? aProgress : -aProgress;
1222     aWalk[AIS_WalkRotation_Pitch].Pressure = aPressure;
1223     aWalk[AIS_WalkRotation_Pitch].Duration = aDuration;
1224   }
1225   if (myKeys.HoldDuration (Aspect_VKey_NavRollCCW, aNewEventTime, aDuration, aPressure))
1226   {
1227     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1228     aWalk[AIS_WalkRotation_Roll].Value = -aProgress;
1229     aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1230     aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1231   }
1232   if (myKeys.HoldDuration (Aspect_VKey_NavRollCW, aNewEventTime, aDuration, aPressure))
1233   {
1234     double aProgress = Abs (Min (aMaxDuration, aDuration)) * aPressure;
1235     aWalk[AIS_WalkRotation_Roll].Value = aProgress;
1236     aWalk[AIS_WalkRotation_Roll].Pressure = aPressure;
1237     aWalk[AIS_WalkRotation_Roll].Duration = aDuration;
1238   }
1239   if (myKeys.HoldDuration (Aspect_VKey_NavSlideUp, aNewEventTime, aDuration, aPressure))
1240   {
1241     double aProgress = Abs (Min (aMaxDuration, aDuration));
1242     aWalk[AIS_WalkTranslation_Up].Value = aProgress;
1243     aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1244     aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1245   }
1246   if (myKeys.HoldDuration (Aspect_VKey_NavSlideDown, aNewEventTime, aDuration, aPressure))
1247   {
1248     double aProgress = Abs (Min (aMaxDuration, aDuration));
1249     aWalk[AIS_WalkTranslation_Up].Value = -aProgress;
1250     aWalk[AIS_WalkTranslation_Up].Pressure = aPressure;
1251     aWalk[AIS_WalkTranslation_Up].Duration = aDuration;
1252   }
1253   return aWalk;
1254 }
1255
1256 // =======================================================================
1257 // function : AbortViewAnimation
1258 // purpose  :
1259 // =======================================================================
1260 void AIS_ViewController::AbortViewAnimation()
1261 {
1262   if (!myViewAnimation.IsNull()
1263    && !myViewAnimation->IsStopped())
1264   {
1265     myViewAnimation->Stop();
1266     myViewAnimation->SetView (Handle(V3d_View)());
1267   }
1268 }
1269
1270 // =======================================================================
1271 // function : handlePanning
1272 // purpose  :
1273 // =======================================================================
1274 void AIS_ViewController::handlePanning (const Handle(V3d_View)& theView)
1275 {
1276   if (!myGL.Panning.ToPan
1277    || !myToAllowPanning)
1278   {
1279     return;
1280   }
1281
1282   AbortViewAnimation();
1283
1284   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1285   if (aCam->IsOrthographic()
1286   || !hasPanningAnchorPoint())
1287   {
1288     theView->Pan (myGL.Panning.Delta.x(), myGL.Panning.Delta.y());
1289     theView->Invalidate();
1290     return;
1291   }
1292
1293   Graphic3d_Vec2i aWinSize;
1294   theView->Window()->Size (aWinSize.x(), aWinSize.y());
1295
1296   const gp_Dir& aDir = aCam->Direction();
1297   const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1298   const gp_XYZ anEyeToPnt = myPanPnt3d.XYZ() - aCam->Eye().XYZ();
1299   const gp_Pnt aViewDims = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ())); // view dimensions at 3D point
1300   const Graphic3d_Vec2d aDxy (-aViewDims.X() * myGL.Panning.Delta.x() / double(aWinSize.x()),
1301                               -aViewDims.X() * myGL.Panning.Delta.y() / double(aWinSize.x()));
1302
1303   //theView->Translate (aCam, aDxy.x(), aDxy.y());
1304   gp_Trsf aPanTrsf;
1305   const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1306                           + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1307   aPanTrsf.SetTranslation (aCameraPan);
1308   aCam->Transform (aPanTrsf);
1309   theView->Invalidate();
1310 }
1311
1312 // =======================================================================
1313 // function : handleZRotate
1314 // purpose  :
1315 // =======================================================================
1316 void AIS_ViewController::handleZRotate (const Handle(V3d_View)& theView)
1317 {
1318   if (!myGL.ZRotate.ToRotate
1319    || !myToAllowRotation)
1320   {
1321     return;
1322   }
1323
1324   AbortViewAnimation();
1325
1326   Graphic3d_Vec2i aViewPort;
1327   theView->Window()->Size (aViewPort.x(), aViewPort.y());
1328   Graphic3d_Vec2d aRotPnt (0.99 * aViewPort.x(),
1329                            0.5  * aViewPort.y());
1330   theView->StartRotation (int(aRotPnt.x()), int(aRotPnt.y()), 0.4);
1331   aRotPnt.y() += myGL.ZRotate.Angle * aViewPort.y();
1332   theView->Rotation (int(aRotPnt.x()), int(aRotPnt.y()));
1333   theView->Invalidate();
1334 }
1335
1336 // =======================================================================
1337 // function : handleZoom
1338 // purpose  :
1339 // =======================================================================
1340 void AIS_ViewController::handleZoom (const Handle(V3d_View)& theView,
1341                                      const Aspect_ScrollDelta& theParams,
1342                                      const gp_Pnt* thePnt)
1343 {
1344   if (!myToAllowZooming)
1345   {
1346     return;
1347   }
1348
1349   AbortViewAnimation();
1350
1351   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1352   if (thePnt != NULL)
1353   {
1354     const double aViewDist = Max (myMinCamDistance, (thePnt->XYZ() - aCam->Eye().XYZ()).Modulus());
1355     aCam->SetCenter (aCam->Eye().XYZ() + aCam->Direction().XYZ() * aViewDist);
1356   }
1357
1358   if (!theParams.HasPoint())
1359   {
1360     Standard_Real aCoeff = Abs(theParams.Delta) / 100.0 + 1.0;
1361     aCoeff = theParams.Delta > 0.0 ? aCoeff : 1.0 / aCoeff;
1362     theView->SetZoom (aCoeff, true);
1363     theView->Invalidate();
1364     return;
1365   }
1366
1367   // integer delta is too rough for small smooth increments
1368   //theView->StartZoomAtPoint (theParams.Point.x(), theParams.Point.y());
1369   //theView->ZoomAtPoint (0, 0, (int )theParams.Delta, (int )theParams.Delta);
1370
1371   double aDZoom = Abs (theParams.Delta) / 100.0 + 1.0;
1372   aDZoom = (theParams.Delta > 0.0) ? aDZoom : 1.0 / aDZoom;
1373   if (aDZoom <= 0.0)
1374   {
1375     return;
1376   }
1377
1378   const Graphic3d_Vec2d aViewDims (aCam->ViewDimensions().X(), aCam->ViewDimensions().Y());
1379
1380   // ensure that zoom will not be too small or too big
1381   double aCoef = aDZoom;
1382   if (aViewDims.x() < aCoef * Precision::Confusion())
1383   {
1384     aCoef = aViewDims.x() / Precision::Confusion();
1385   }
1386   else if (aViewDims.x() > aCoef * 1e12)
1387   {
1388     aCoef = aViewDims.x() / 1e12;
1389   }
1390   if (aViewDims.y() < aCoef * Precision::Confusion())
1391   {
1392     aCoef = aViewDims.y() / Precision::Confusion();
1393   }
1394   else if (aViewDims.y() > aCoef * 1e12)
1395   {
1396     aCoef = aViewDims.y() / 1e12;
1397   }
1398
1399   Graphic3d_Vec2d aZoomAtPointXYv (0.0, 0.0);
1400   theView->Convert (theParams.Point.x(), theParams.Point.y(),
1401                     aZoomAtPointXYv.x(), aZoomAtPointXYv.y());
1402   Graphic3d_Vec2d aDxy = aZoomAtPointXYv / aCoef;
1403   aCam->SetScale (aCam->Scale() / aCoef);
1404
1405   const gp_Dir& aDir = aCam->Direction();
1406   const gp_Ax3 aCameraCS (aCam->Center(), aDir.Reversed(), aDir ^ aCam->Up());
1407
1408   // pan back to the point
1409   aDxy = aZoomAtPointXYv - aDxy;
1410   if (thePnt != NULL)
1411   {
1412     // zoom at 3D point with perspective projection
1413     const gp_XYZ anEyeToPnt = thePnt->XYZ() - aCam->Eye().XYZ();
1414     aDxy.SetValues (anEyeToPnt.Dot (aCameraCS.XDirection().XYZ()),
1415                     anEyeToPnt.Dot (aCameraCS.YDirection().XYZ()));
1416
1417     // view dimensions at 3D point
1418     const gp_Pnt aViewDims1 = aCam->ViewDimensions (anEyeToPnt.Dot (aCam->Direction().XYZ()));
1419
1420     Graphic3d_Vec2i aWinSize;
1421     theView->Window()->Size (aWinSize.x(), aWinSize.y());
1422     const Graphic3d_Vec2d aPanFromCenterPx (double(theParams.Point.x()) - 0.5 * double(aWinSize.x()),
1423                                             double(aWinSize.y() - theParams.Point.y() - 1) - 0.5 * double(aWinSize.y()));
1424     aDxy.x() += -aViewDims1.X() * aPanFromCenterPx.x() / double(aWinSize.x());
1425     aDxy.y() += -aViewDims1.Y() * aPanFromCenterPx.y() / double(aWinSize.y());
1426   }
1427
1428   //theView->Translate (aCam, aDxy.x(), aDxy.y());
1429   gp_Trsf aPanTrsf;
1430   const gp_Vec aCameraPan = gp_Vec (aCameraCS.XDirection()) * aDxy.x()
1431                           + gp_Vec (aCameraCS.YDirection()) * aDxy.y();
1432   aPanTrsf.SetTranslation (aCameraPan);
1433   aCam->Transform (aPanTrsf);
1434   theView->Invalidate();
1435 }
1436
1437 // =======================================================================
1438 // function : handleZFocusScroll
1439 // purpose  :
1440 // =======================================================================
1441 void AIS_ViewController::handleZFocusScroll (const Handle(V3d_View)& theView,
1442                                              const Aspect_ScrollDelta& theParams)
1443 {
1444   if (!myToAllowZFocus
1445    || !theView->Camera()->IsStereo())
1446   {
1447     return;
1448   }
1449
1450   Standard_Real aFocus = theView->Camera()->ZFocus() + (theParams.Delta > 0.0 ? 0.05 : -0.05);
1451   if (aFocus > 0.2
1452    && aFocus < 2.0)
1453   {
1454     theView->Camera()->SetZFocus (theView->Camera()->ZFocusType(), aFocus);
1455     theView->Redraw();
1456   }
1457 }
1458
1459 // =======================================================================
1460 // function : handleOrbitRotation
1461 // purpose  :
1462 // =======================================================================
1463 void AIS_ViewController::handleOrbitRotation (const Handle(V3d_View)& theView,
1464                                               const gp_Pnt& thePnt,
1465                                               bool theToLockZUp)
1466 {
1467   if (!myToAllowRotation)
1468   {
1469     return;
1470   }
1471
1472   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1473   if (myGL.OrbitRotation.ToStart)
1474   {
1475     // default alternatives
1476     //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->StartRotation (myGL.RotateAtPoint.x(), myGL.RotateAtPoint.y());
1477     //theView->Rotate (0.0, 0.0, 0.0, thePnt.X(), thePnt.Y(), thePnt.Z(), true);
1478
1479     myRotatePnt3d      = thePnt;
1480     myCamStartOpUp     = aCam->Up();
1481     myCamStartOpDir    = aCam->Direction();
1482     myCamStartOpEye    = aCam->Eye();
1483     myCamStartOpCenter = aCam->Center();
1484
1485     gp_Trsf aTrsf;
1486     aTrsf.SetTransformation (gp_Ax3 (myRotatePnt3d, aCam->OrthogonalizedUp(), aCam->Direction()),
1487                              gp_Ax3 (myRotatePnt3d, gp::DZ(), gp::DX()));
1488     const gp_Quaternion aRot = aTrsf.GetRotation();
1489     aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], myRotateStartYawPitchRoll[2]);
1490
1491     aTrsf.Invert();
1492     myCamStartOpToEye    = gp_Vec (myRotatePnt3d, aCam->Eye()).Transformed (aTrsf);
1493     myCamStartOpToCenter = gp_Vec (myRotatePnt3d, aCam->Center()).Transformed (aTrsf);
1494
1495     theView->Invalidate();
1496   }
1497
1498   if (!myGL.OrbitRotation.ToRotate)
1499   {
1500     return;
1501   }
1502
1503   AbortViewAnimation();
1504   if (theToLockZUp)
1505   {
1506     // amend camera to exclude roll angle (put camera Up vector to plane containing global Z and view direction)
1507     Graphic3d_Vec2i aWinXY;
1508     theView->Window()->Size (aWinXY.x(), aWinXY.y());
1509     double aYawAngleDelta   =  ((myGL.OrbitRotation.PointStart.x() - myGL.OrbitRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1510     double aPitchAngleDelta = -((myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1511     const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1512     const double aYawAngleNew   = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1513     const double aRoll = 0.0;
1514
1515     gp_Quaternion aRot;
1516     aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, aRoll);
1517     gp_Trsf aTrsfRot;
1518     aTrsfRot.SetRotation (aRot);
1519
1520     const gp_Dir aNewUp = gp::DZ().Transformed (aTrsfRot);
1521     aCam->SetUp (aNewUp);
1522     aCam->SetEyeAndCenter (myRotatePnt3d.XYZ() + myCamStartOpToEye   .Transformed (aTrsfRot).XYZ(),
1523                            myRotatePnt3d.XYZ() + myCamStartOpToCenter.Transformed (aTrsfRot).XYZ());
1524
1525     aCam->OrthogonalizeUp();
1526   }
1527   else
1528   {
1529     // default alternatives
1530     //if (myRotationMode == AIS_RotationMode_BndBoxActive) theView->Rotation (myGL.RotateToPoint.x(), myGL.RotateToPoint.y());
1531     //theView->Rotate (aDX, aDY, aDZ, myRotatePnt3d.X(), myRotatePnt3d.Y(), myRotatePnt3d.Z(), false);
1532
1533     // restore previous camera state
1534     aCam->SetEyeAndCenter (myCamStartOpEye, myCamStartOpCenter);
1535     aCam->SetUp (myCamStartOpUp);
1536     aCam->SetDirectionFromEye (myCamStartOpDir);
1537
1538     Graphic3d_Vec2d aWinXY;
1539     theView->Size (aWinXY.x(), aWinXY.y());
1540     const Standard_Real rx = (Standard_Real )theView->Convert (aWinXY.x());
1541     const Standard_Real ry = (Standard_Real )theView->Convert (aWinXY.y());
1542
1543     const double THE_2PI = M_PI * 2.0;
1544     double aDX = (myGL.OrbitRotation.PointTo.x() - myGL.OrbitRotation.PointStart.x()) * M_PI / rx;
1545     double aDY = (myGL.OrbitRotation.PointStart.y() - myGL.OrbitRotation.PointTo.y()) * M_PI / ry;
1546
1547     if     (aDX > 0.0) { while (aDX >  THE_2PI) { aDX -= THE_2PI; } }
1548     else if(aDX < 0.0) { while (aDX < -THE_2PI) { aDX += THE_2PI; } }
1549     if     (aDY > 0.0) { while (aDY >  THE_2PI) { aDY -= THE_2PI; } }
1550     else if(aDY < 0.0) { while (aDY < -THE_2PI) { aDY += THE_2PI; } }
1551
1552     // rotate camera around 3 initial axes
1553     gp_Dir aCamDir (aCam->Direction().Reversed());
1554     gp_Dir aCamUp  (aCam->Up());
1555     gp_Dir aCamSide(aCamUp.Crossed (aCamDir));
1556
1557     gp_Trsf aRot[2], aTrsf;
1558     aRot[0].SetRotation (gp_Ax1 (myRotatePnt3d, aCamUp),  -aDX);
1559     aRot[1].SetRotation (gp_Ax1 (myRotatePnt3d, aCamSide), aDY);
1560     aTrsf.Multiply (aRot[0]);
1561     aTrsf.Multiply (aRot[1]);
1562
1563     aCam->Transform (aTrsf);
1564   }
1565
1566   theView->Invalidate();
1567 }
1568
1569 // =======================================================================
1570 // function : handleViewRotation
1571 // purpose  :
1572 // =======================================================================
1573 void AIS_ViewController::handleViewRotation (const Handle(V3d_View)& theView,
1574                                              double theYawExtra,
1575                                              double thePitchExtra,
1576                                              double theRoll,
1577                                              bool theToRestartOnIncrement)
1578 {
1579   if (!myToAllowRotation)
1580   {
1581     return;
1582   }
1583
1584   const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1585   const bool toRotateAnyway = Abs (theYawExtra)   > gp::Resolution()
1586                            || Abs (thePitchExtra) > gp::Resolution()
1587                            || Abs (theRoll - myRotateStartYawPitchRoll[2]) > gp::Resolution();
1588   if (toRotateAnyway
1589    && theToRestartOnIncrement)
1590   {
1591     myGL.ViewRotation.ToStart = true;
1592     myGL.ViewRotation.PointTo = myGL.ViewRotation.PointStart;
1593   }
1594   if (myGL.ViewRotation.ToStart)
1595   {
1596     gp_Trsf aTrsf;
1597     aTrsf.SetTransformation (gp_Ax3 (gp::Origin(), aCam->OrthogonalizedUp(), aCam->Direction()),
1598                              gp_Ax3 (gp::Origin(), gp::DZ(), gp::DX()));
1599     const gp_Quaternion aRot = aTrsf.GetRotation();
1600     double aRollDummy = 0.0;
1601     aRot.GetEulerAngles (gp_YawPitchRoll, myRotateStartYawPitchRoll[0], myRotateStartYawPitchRoll[1], aRollDummy);
1602   }
1603   if (toRotateAnyway)
1604   {
1605     myRotateStartYawPitchRoll[0] += theYawExtra;
1606     myRotateStartYawPitchRoll[1] += thePitchExtra;
1607     myRotateStartYawPitchRoll[2]  = theRoll;
1608     myGL.ViewRotation.ToRotate = true;
1609   }
1610
1611   if (!myGL.ViewRotation.ToRotate)
1612   {
1613     return;
1614   }
1615
1616   AbortViewAnimation();
1617
1618   Graphic3d_Vec2i aWinXY;
1619   theView->Window()->Size (aWinXY.x(), aWinXY.y());
1620   double aYawAngleDelta   =  ((myGL.ViewRotation.PointStart.x() - myGL.ViewRotation.PointTo.x()) / double (aWinXY.x())) * (M_PI * 0.5);
1621   double aPitchAngleDelta = -((myGL.ViewRotation.PointStart.y() - myGL.ViewRotation.PointTo.y()) / double (aWinXY.y())) * (M_PI * 0.5);
1622   const double aPitchAngleNew = Max (Min (myRotateStartYawPitchRoll[1] + aPitchAngleDelta, M_PI * 0.5 - M_PI / 180.0), -M_PI * 0.5 + M_PI / 180.0);
1623   const double aYawAngleNew   = myRotateStartYawPitchRoll[0] + aYawAngleDelta;
1624   gp_Quaternion aRot;
1625   aRot.SetEulerAngles (gp_YawPitchRoll, aYawAngleNew, aPitchAngleNew, theRoll);
1626   gp_Trsf aTrsfRot;
1627   aTrsfRot.SetRotation (aRot);
1628
1629   const gp_Dir aNewUp  = gp::DZ().Transformed (aTrsfRot);
1630   const gp_Dir aNewDir = gp::DX().Transformed (aTrsfRot);
1631   aCam->SetUp (aNewUp);
1632   aCam->SetDirectionFromEye (aNewDir);
1633   aCam->OrthogonalizeUp();
1634   theView->Invalidate();
1635 }
1636
1637 // =======================================================================
1638 // function : PickPoint
1639 // purpose  :
1640 // =======================================================================
1641 bool AIS_ViewController::PickPoint (gp_Pnt& thePnt,
1642                                     const Handle(AIS_InteractiveContext)& theCtx,
1643                                     const Handle(V3d_View)& theView,
1644                                     const Graphic3d_Vec2i& theCursor,
1645                                     bool theToStickToPickRay)
1646 {
1647   ResetPreviousMoveTo();
1648
1649   const Handle(StdSelect_ViewerSelector3d)& aSelector = theCtx->MainSelector();
1650   aSelector->Pick (theCursor.x(), theCursor.y(), theView);
1651   if (aSelector->NbPicked() < 1)
1652   {
1653     return false;
1654   }
1655
1656   const SelectMgr_SortCriterion& aPicked = aSelector->PickedData (1);
1657   if (theToStickToPickRay
1658   && !Precision::IsInfinite (aPicked.Depth))
1659   {
1660     thePnt = aSelector->GetManager().DetectedPoint (aPicked.Depth);
1661   }
1662   else
1663   {
1664     thePnt = aSelector->PickedPoint (1);
1665   }
1666   return !Precision::IsInfinite (thePnt.X())
1667       && !Precision::IsInfinite (thePnt.Y())
1668       && !Precision::IsInfinite (thePnt.Z());
1669 }
1670
1671 // =======================================================================
1672 // function : GravityPoint
1673 // purpose  :
1674 // =======================================================================
1675 gp_Pnt AIS_ViewController::GravityPoint (const Handle(AIS_InteractiveContext)& theCtx,
1676                                          const Handle(V3d_View)& theView)
1677 {
1678   switch (myRotationMode)
1679   {
1680     case AIS_RotationMode_PickLast:
1681     case AIS_RotationMode_PickCenter:
1682     {
1683       Graphic3d_Vec2i aCursor ((int )myGL.OrbitRotation.PointStart.x(), (int )myGL.OrbitRotation.PointStart.y());
1684       if (myRotationMode == AIS_RotationMode_PickCenter)
1685       {
1686         Graphic3d_Vec2i aViewPort;
1687         theView->Window()->Size (aViewPort.x(), aViewPort.y());
1688         aCursor = aViewPort / 2;
1689       }
1690
1691       gp_Pnt aPnt;
1692       if (PickPoint (aPnt, theCtx, theView, aCursor, myToStickToRayOnRotation))
1693       {
1694         return aPnt;
1695       }
1696       break;
1697     }
1698     case AIS_RotationMode_CameraAt:
1699     {
1700       const Handle(Graphic3d_Camera)& aCam = theView->Camera();
1701       return aCam->Center();
1702     }
1703     case AIS_RotationMode_BndBoxScene:
1704     {
1705       Bnd_Box aBndBox = theView->View()->MinMaxValues (false);
1706       if (!aBndBox.IsVoid())
1707       {
1708         return (aBndBox.CornerMin().XYZ() + aBndBox.CornerMax().XYZ()) * 0.5;
1709       }
1710       break;
1711     }
1712     case AIS_RotationMode_BndBoxActive:
1713       break;
1714   }
1715
1716   return theCtx ->GravityPoint (theView);
1717 }
1718
1719 // =======================================================================
1720 // function : handleCameraActions
1721 // purpose  :
1722 // =======================================================================
1723 void AIS_ViewController::handleCameraActions (const Handle(AIS_InteractiveContext)& theCtx,
1724                                               const Handle(V3d_View)& theView,
1725                                               const AIS_WalkDelta& theWalk)
1726 {
1727   // apply view actions
1728   if (myGL.Orientation.ToSetViewOrient)
1729   {
1730     theView->SetProj (myGL.Orientation.ViewOrient);
1731     myGL.Orientation.ToFitAll = true;
1732   }
1733
1734   // apply fit all
1735   if (myGL.Orientation.ToFitAll)
1736   {
1737     const double aFitMargin = 0.01;
1738     theView->FitAll (aFitMargin, false);
1739     theView->Invalidate();
1740     myGL.Orientation.ToFitAll = false;
1741   }
1742
1743   if (myGL.IsNewGesture)
1744   {
1745     if (myAnchorPointPrs1->HasInteractiveContext())
1746     {
1747       theCtx->Remove (myAnchorPointPrs1, false);
1748       if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs1->ZLayer()).IsImmediate())
1749       {
1750         theView->Invalidate();
1751       }
1752       else
1753       {
1754         theView->InvalidateImmediate();
1755       }
1756     }
1757     if (myAnchorPointPrs2->HasInteractiveContext())
1758     {
1759       theCtx->Remove (myAnchorPointPrs2, false);
1760       if (!theView->Viewer()->ZLayerSettings (myAnchorPointPrs2->ZLayer()).IsImmediate())
1761       {
1762         theView->Invalidate();
1763       }
1764       else
1765       {
1766         theView->InvalidateImmediate();
1767       }
1768     }
1769
1770     if (myHasHlrOnBeforeRotation)
1771     {
1772       myHasHlrOnBeforeRotation = false;
1773       theView->SetComputedMode (true);
1774       theView->Invalidate();
1775     }
1776   }
1777
1778   if (myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
1779   {
1780     if (myGL.Panning.ToStart
1781      && myToAllowPanning)
1782     {
1783       gp_Pnt aPanPnt (Precision::Infinite(), 0.0, 0.0);
1784       if (!theView->Camera()->IsOrthographic())
1785       {
1786         bool toStickToRay = false;
1787         if (myGL.Panning.PointStart.x() >= 0
1788          && myGL.Panning.PointStart.y() >= 0)
1789         {
1790           PickPoint (aPanPnt, theCtx, theView, myGL.Panning.PointStart, toStickToRay);
1791         }
1792         if (Precision::IsInfinite (aPanPnt.X()))
1793         {
1794           Graphic3d_Vec2i aWinSize;
1795           theView->Window()->Size (aWinSize.x(), aWinSize.y());
1796           PickPoint (aPanPnt, theCtx, theView, aWinSize / 2, toStickToRay);
1797         }
1798         if (!Precision::IsInfinite (aPanPnt.X())
1799           && myToShowPanAnchorPoint)
1800         {
1801           gp_Trsf aPntTrsf;
1802           aPntTrsf.SetTranslation (gp_Vec (aPanPnt.XYZ()));
1803           theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
1804         }
1805       }
1806       setPanningAnchorPoint (aPanPnt);
1807     }
1808
1809     if (myToShowPanAnchorPoint
1810     &&  hasPanningAnchorPoint()
1811     &&  myGL.Panning.ToPan
1812     && !myGL.IsNewGesture
1813     && !myAnchorPointPrs2->HasInteractiveContext())
1814     {
1815       theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
1816     }
1817
1818     handlePanning (theView);
1819     handleZRotate (theView);
1820   }
1821
1822   if ((myNavigationMode == AIS_NavigationMode_Orbit
1823     || myGL.OrbitRotation.ToStart
1824     || myGL.OrbitRotation.ToRotate)
1825    && myToAllowRotation)
1826   {
1827     if (myGL.OrbitRotation.ToStart
1828     && !myHasHlrOnBeforeRotation)
1829     {
1830       myHasHlrOnBeforeRotation = theView->ComputedMode();
1831       if (myHasHlrOnBeforeRotation)
1832       {
1833         theView->SetComputedMode (false);
1834       }
1835     }
1836
1837     gp_Pnt aGravPnt;
1838     if (myGL.OrbitRotation.ToStart)
1839     {
1840       aGravPnt = GravityPoint (theCtx, theView);
1841       if (myToShowRotateCenter)
1842       {
1843         gp_Trsf aPntTrsf;
1844         aPntTrsf.SetTranslation (gp_Vec (aGravPnt.XYZ()));
1845         theCtx->SetLocation (myAnchorPointPrs1, aPntTrsf);
1846         theCtx->SetLocation (myAnchorPointPrs2, aPntTrsf);
1847       }
1848     }
1849
1850     if (myToShowRotateCenter
1851     &&  myGL.OrbitRotation.ToRotate
1852     && !myGL.IsNewGesture
1853     && !myAnchorPointPrs1->HasInteractiveContext())
1854     {
1855       theCtx->Display (myAnchorPointPrs1, 0, -1, false, AIS_DS_Displayed);
1856       theCtx->Display (myAnchorPointPrs2, 0, -1, false, AIS_DS_Displayed);
1857     }
1858     handleOrbitRotation (theView, aGravPnt,
1859                          myToLockOrbitZUp || myNavigationMode != AIS_NavigationMode_Orbit);
1860   }
1861
1862   if ((myNavigationMode != AIS_NavigationMode_Orbit
1863     || myGL.ViewRotation.ToStart
1864     || myGL.ViewRotation.ToRotate)
1865    && myToAllowRotation)
1866   {
1867     if (myGL.ViewRotation.ToStart
1868     && !myHasHlrOnBeforeRotation)
1869     {
1870       myHasHlrOnBeforeRotation = theView->ComputedMode();
1871       if (myHasHlrOnBeforeRotation)
1872       {
1873         theView->SetComputedMode (false);
1874       }
1875     }
1876
1877     double aRoll = 0.0;
1878     if (!theWalk[AIS_WalkRotation_Roll].IsEmpty()
1879      && !myToLockOrbitZUp)
1880     {
1881       aRoll = (M_PI / 12.0) * theWalk[AIS_WalkRotation_Roll].Pressure;
1882       aRoll *= Min (1000.0  * theWalk[AIS_WalkRotation_Roll].Duration, 100.0) / 100.0;
1883       if (theWalk[AIS_WalkRotation_Roll].Value < 0.0)
1884       {
1885         aRoll = -aRoll;
1886       }
1887     }
1888
1889     handleViewRotation (theView, theWalk[AIS_WalkRotation_Yaw].Value, theWalk[AIS_WalkRotation_Pitch].Value, aRoll,
1890                         myNavigationMode == AIS_NavigationMode_FirstPersonFlight);
1891   }
1892
1893   if (!myGL.ZoomActions.IsEmpty())
1894   {
1895     for (NCollection_Sequence<Aspect_ScrollDelta>::Iterator aZoomIter (myGL.ZoomActions); aZoomIter.More(); aZoomIter.Next())
1896     {
1897       Aspect_ScrollDelta aZoomParams = aZoomIter.Value();
1898       if (myToAllowZFocus
1899        && (aZoomParams.Flags & Aspect_VKeyFlags_CTRL) != 0
1900        && theView->Camera()->IsStereo())
1901       {
1902         handleZFocusScroll (theView, aZoomParams);
1903         continue;
1904       }
1905
1906       if (!myToAllowZooming)
1907       {
1908         continue;
1909       }
1910
1911       if (!theView->Camera()->IsOrthographic())
1912       {
1913         gp_Pnt aPnt;
1914         if (aZoomParams.HasPoint()
1915          && PickPoint (aPnt, theCtx, theView, aZoomParams.Point, myToStickToRayOnZoom))
1916         {
1917           handleZoom (theView, aZoomParams, &aPnt);
1918           continue;
1919         }
1920
1921         Graphic3d_Vec2i aWinSize;
1922         theView->Window()->Size (aWinSize.x(), aWinSize.y());
1923         if (PickPoint (aPnt, theCtx, theView, aWinSize / 2, myToStickToRayOnZoom))
1924         {
1925           aZoomParams.ResetPoint(); // do not pretend to zoom at 'nothing'
1926           handleZoom (theView, aZoomParams, &aPnt);
1927           continue;
1928         }
1929       }
1930       handleZoom (theView, aZoomParams, NULL);
1931     }
1932     myGL.ZoomActions.Clear();
1933   }
1934 }
1935
1936 // =======================================================================
1937 // function : OnSelectionChanged
1938 // purpose  :
1939 // =======================================================================
1940 void AIS_ViewController::OnSelectionChanged (const Handle(AIS_InteractiveContext)& ,
1941                                              const Handle(V3d_View)& )
1942 {
1943   //
1944 }
1945
1946 // =======================================================================
1947 // function : OnObjectDragged
1948 // purpose  :
1949 // =======================================================================
1950 void AIS_ViewController::OnObjectDragged (const Handle(AIS_InteractiveContext)& theCtx,
1951                                           const Handle(V3d_View)& theView,
1952                                           AIS_DragAction theAction)
1953 {
1954   switch (theAction)
1955   {
1956     case AIS_DragAction_Start:
1957     {
1958       myDragObject.Nullify();
1959       if (!theCtx->HasDetected())
1960       {
1961         return;
1962       }
1963
1964       Handle(AIS_InteractiveObject) aPrs = theCtx->DetectedInteractive();
1965       if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (aPrs))
1966       {
1967         if (aManip->HasActiveMode())
1968         {
1969           myDragObject = aManip;
1970           aManip->StartTransform (myGL.Dragging.PointStart.x(), myGL.Dragging.PointStart.y(), theView);
1971         }
1972       }
1973       return;
1974     }
1975     case AIS_DragAction_Update:
1976     {
1977       if (myDragObject.IsNull())
1978       {
1979         return;
1980       }
1981
1982       if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
1983       {
1984         theCtx->SetSelectedState (aGlobOwner, true);
1985       }
1986       if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (myDragObject))
1987       {
1988         aManip->Transform (myGL.Dragging.PointTo.x(), myGL.Dragging.PointTo.y(), theView);
1989       }
1990       theView->Invalidate();
1991       return;
1992     }
1993     case AIS_DragAction_Abort:
1994     {
1995       if (myDragObject.IsNull())
1996       {
1997         return;
1998       }
1999
2000       myGL.Dragging.PointTo = myGL.Dragging.PointStart;
2001       OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
2002
2003       if (Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (myDragObject))
2004       {
2005         aManip->StopTransform (false);
2006       }
2007       Standard_FALLTHROUGH
2008     }
2009     case AIS_DragAction_Stop:
2010     {
2011       if (myDragObject.IsNull())
2012       {
2013         return;
2014       }
2015
2016       if (Handle(SelectMgr_EntityOwner) aGlobOwner = myDragObject->GlobalSelOwner())
2017       {
2018         theCtx->SetSelectedState (aGlobOwner, false);
2019       }
2020
2021       theView->Invalidate();
2022       myDragObject.Nullify();
2023       return;
2024     }
2025   }
2026 }
2027
2028 // =======================================================================
2029 // function : contextLazyMoveTo
2030 // purpose  :
2031 // =======================================================================
2032 void AIS_ViewController::contextLazyMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2033                                             const Handle(V3d_View)& theView,
2034                                             const Graphic3d_Vec2i& thePnt)
2035 {
2036   if (myPrevMoveTo == thePnt)
2037   {
2038     return;
2039   }
2040
2041   myPrevMoveTo = thePnt;
2042
2043   Handle(SelectMgr_EntityOwner) aLastPicked = theCtx->DetectedOwner();
2044   theCtx->MoveTo (thePnt.x(), thePnt.y(), theView, false);
2045   Handle(SelectMgr_EntityOwner) aNewPicked = theCtx->DetectedOwner();
2046
2047   if (theView->Viewer()->Grid()->IsActive()
2048    && theView->Viewer()->GridEcho())
2049   {
2050     if (aNewPicked.IsNull())
2051     {
2052       Graphic3d_Vec3d aPnt3d;
2053       theView->ConvertToGrid (thePnt.x(), thePnt.y(), aPnt3d[0], aPnt3d[1], aPnt3d[2]);
2054       theView->Viewer()->ShowGridEcho (theView, Graphic3d_Vertex (aPnt3d[0], aPnt3d[1], aPnt3d[2]));
2055       theView->InvalidateImmediate();
2056     }
2057     else
2058     {
2059       theView->Viewer()->HideGridEcho (theView);
2060       theView->InvalidateImmediate();
2061     }
2062   }
2063
2064   if (aLastPicked != aNewPicked
2065    || (!aNewPicked.IsNull() && aNewPicked->IsForcedHilight()))
2066   {
2067     // dynamic highlight affects all Views
2068     for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2069     {
2070       const Handle(V3d_View)& aView = aViewIter.Value();
2071       aView->InvalidateImmediate();
2072     }
2073   }
2074 }
2075
2076 // =======================================================================
2077 // function : handleSelectionPick
2078 // purpose  :
2079 // =======================================================================
2080 void AIS_ViewController::handleSelectionPick (const Handle(AIS_InteractiveContext)& theCtx,
2081                                               const Handle(V3d_View)& theView)
2082 {
2083   if (myGL.Selection.Tool == AIS_ViewSelectionTool_Picking
2084   && !myGL.Selection.Points.IsEmpty())
2085   {
2086     for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aPntIter (myGL.Selection.Points); aPntIter.More(); aPntIter.Next())
2087     {
2088       const bool hadPrevMoveTo = HasPreviousMoveTo();
2089       contextLazyMoveTo (theCtx, theView, aPntIter.Value());
2090       if (!hadPrevMoveTo)
2091       {
2092         ResetPreviousMoveTo();
2093       }
2094
2095       if (myGL.Selection.IsXOR)
2096       {
2097         theCtx->ShiftSelect (false);
2098       }
2099       else
2100       {
2101         theCtx->Select (false);
2102       }
2103
2104       // selection affects all Views
2105       theView->Viewer()->Invalidate();
2106
2107       OnSelectionChanged (theCtx, theView);
2108     }
2109
2110     myGL.Selection.Points.Clear();
2111   }
2112 }
2113
2114 // =======================================================================
2115 // function : handleSelectionPoly
2116 // purpose  :
2117 // =======================================================================
2118 void AIS_ViewController::handleSelectionPoly (const Handle(AIS_InteractiveContext)& theCtx,
2119                                               const Handle(V3d_View)& theView)
2120 {
2121   // rubber-band & window polygon selection
2122   if (myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand
2123    || myGL.Selection.Tool == AIS_ViewSelectionTool_Polygon
2124    || myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow)
2125   {
2126     if (!myGL.Selection.Points.IsEmpty())
2127     {
2128       myRubberBand->ClearPoints();
2129       myRubberBand->SetToUpdate();
2130
2131       const bool anIsRubber = myGL.Selection.Tool == AIS_ViewSelectionTool_RubberBand
2132                            || myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow;
2133       if (anIsRubber)
2134       {
2135         myRubberBand->SetRectangle (myGL.Selection.Points.First().x(), -myGL.Selection.Points.First().y(),
2136                                     myGL.Selection.Points.Last().x(),  -myGL.Selection.Points.Last().y());
2137       }
2138       else
2139       {
2140         Graphic3d_Vec2i aPrev (IntegerLast(), IntegerLast());
2141         for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (myGL.Selection.Points); aSelIter.More(); aSelIter.Next())
2142         {
2143           Graphic3d_Vec2i aPntNew = Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y());
2144           if (aPntNew != aPrev)
2145           {
2146             aPrev = aPntNew;
2147             myRubberBand->AddPoint (Graphic3d_Vec2i (aSelIter.Value().x(), -aSelIter.Value().y()));
2148           }
2149         }
2150       }
2151
2152       myRubberBand->SetPolygonClosed (anIsRubber);
2153       try
2154       {
2155         theCtx->Display (myRubberBand, 0, -1, false, AIS_DS_Displayed);
2156       }
2157       catch (const Standard_Failure& theEx)
2158       {
2159         Message::DefaultMessenger()->Send (TCollection_AsciiString ("Internal error while displaying rubber-band: ")
2160                                         + theEx.DynamicType()->Name() + ", " + theEx.GetMessageString(), Message_Warning);
2161         myRubberBand->ClearPoints();
2162       }
2163       if (!theView->Viewer()->ZLayerSettings (myRubberBand->ZLayer()).IsImmediate())
2164       {
2165         theView->Invalidate();
2166       }
2167       else
2168       {
2169         theView->InvalidateImmediate();
2170       }
2171     }
2172     else if (!myRubberBand.IsNull()
2173            && myRubberBand->HasInteractiveContext())
2174     {
2175       theCtx->Remove (myRubberBand, false);
2176       myRubberBand->ClearPoints();
2177     }
2178   }
2179
2180   if (myGL.Selection.ToApplyTool)
2181   {
2182     myGL.Selection.ToApplyTool = false;
2183     if (theCtx->IsDisplayed (myRubberBand))
2184     {
2185       theCtx->Remove (myRubberBand, false);
2186       {
2187         const NCollection_Sequence<Graphic3d_Vec2i>& aPoints = myRubberBand->Points();
2188         if (aPoints.Size() == 4
2189          && aPoints.Value (1).x() == aPoints.Value (2).x()
2190          && aPoints.Value (3).x() == aPoints.Value (4).x()
2191          && aPoints.Value (1).y() == aPoints.Value (4).y()
2192          && aPoints.Value (2).y() == aPoints.Value (3).y())
2193         {
2194           const Graphic3d_Vec2i aPnt1 (aPoints.Value (1).x(), -aPoints.Value (1).y());
2195           const Graphic3d_Vec2i aPnt2 (aPoints.Value (3).x(), -aPoints.Value (3).y());
2196           if (myGL.Selection.Tool == AIS_ViewSelectionTool_ZoomWindow)
2197           {
2198             theView->WindowFitAll (aPnt1.x(), aPnt1.y(), aPnt2.x(), aPnt2.y());
2199             theView->Invalidate();
2200           }
2201           else
2202           {
2203             theCtx->MainSelector()->AllowOverlapDetection (aPnt1.y() != Min (aPnt1.y(), aPnt2.y()));
2204             if (myGL.Selection.IsXOR)
2205             {
2206               theCtx->ShiftSelect (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y()),
2207                                    Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y()),
2208                                    theView, false);
2209             }
2210             else
2211             {
2212               theCtx->Select (Min (aPnt1.x(), aPnt2.x()), Min (aPnt1.y(), aPnt2.y()),
2213                               Max (aPnt1.x(), aPnt2.x()), Max (aPnt1.y(), aPnt2.y()),
2214                               theView, false);
2215             }
2216             theCtx->MainSelector()->AllowOverlapDetection (false);
2217           }
2218         }
2219         else if (aPoints.Length() >= 3)
2220         {
2221           TColgp_Array1OfPnt2d aPolyline (1, aPoints.Length());
2222           TColgp_Array1OfPnt2d::Iterator aPolyIter (aPolyline);
2223           for (NCollection_Sequence<Graphic3d_Vec2i>::Iterator aSelIter (aPoints);
2224                aSelIter.More(); aSelIter.Next(), aPolyIter.Next())
2225           {
2226             const Graphic3d_Vec2i& aNewPnt = aSelIter.Value();
2227             aPolyIter.ChangeValue() = gp_Pnt2d (aNewPnt.x(), -aNewPnt.y());
2228           }
2229
2230           if (myGL.Selection.IsXOR)
2231           {
2232             theCtx->ShiftSelect (aPolyline, theView, false);
2233           }
2234           else
2235           {
2236             theCtx->Select (aPolyline, theView, false);
2237           }
2238           theCtx->MainSelector()->AllowOverlapDetection (false);
2239         }
2240       }
2241
2242       myRubberBand->ClearPoints();
2243       if (myGL.Selection.Tool != AIS_ViewSelectionTool_ZoomWindow)
2244       {
2245         // selection affects all Views
2246         theView->Viewer()->Invalidate();
2247         OnSelectionChanged (theCtx, theView);
2248       }
2249     }
2250   }
2251 }
2252
2253 // =======================================================================
2254 // function : handleDynamicHighlight
2255 // purpose  :
2256 // =======================================================================
2257 void AIS_ViewController::handleDynamicHighlight (const Handle(AIS_InteractiveContext)& theCtx,
2258                                                  const Handle(V3d_View)& theView)
2259 {
2260   if ((myGL.MoveTo.ToHilight || myGL.Dragging.ToStart)
2261    && myNavigationMode != AIS_NavigationMode_FirstPersonWalk)
2262   {
2263     const Graphic3d_Vec2i& aMoveToPnt = myGL.MoveTo.ToHilight ? myGL.MoveTo.Point : myGL.Dragging.PointStart;
2264     if (myGL.Dragging.ToStart && (!myGL.MoveTo.ToHilight || !myToAllowHighlight)
2265      && !HasPreviousMoveTo())
2266     {
2267       contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2268       ResetPreviousMoveTo();
2269       OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2270       theCtx->ClearDetected();
2271     }
2272     else if (myToAllowHighlight)
2273     {
2274       if (myPrevMoveTo != aMoveToPnt
2275        || myGL.OrbitRotation.ToRotate
2276        || myGL.ViewRotation.ToRotate
2277        || theView->IsInvalidated())
2278       {
2279         ResetPreviousMoveTo();
2280         contextLazyMoveTo (theCtx, theView, aMoveToPnt);
2281       }
2282       if (myGL.Dragging.ToStart)
2283       {
2284         OnObjectDragged (theCtx, theView, AIS_DragAction_Start);
2285       }
2286     }
2287
2288     myGL.MoveTo.ToHilight = false;
2289   }
2290
2291   if (!myDragObject.IsNull())
2292   {
2293     if (myGL.Dragging.ToAbort)
2294     {
2295       OnObjectDragged (theCtx, theView, AIS_DragAction_Abort);
2296       myGL.OrbitRotation.ToRotate = false;
2297       myGL.ViewRotation .ToRotate = false;
2298     }
2299     else if (myGL.Dragging.ToStop)
2300     {
2301       OnObjectDragged (theCtx, theView, AIS_DragAction_Stop);
2302       myGL.OrbitRotation.ToRotate = false;
2303       myGL.ViewRotation .ToRotate = false;
2304     }
2305     else if (myGL.OrbitRotation.ToRotate
2306           || myGL.ViewRotation.ToRotate)
2307     {
2308       OnObjectDragged (theCtx, theView, AIS_DragAction_Update);
2309       myGL.OrbitRotation.ToRotate = false;
2310       myGL.ViewRotation .ToRotate = false;
2311     }
2312   }
2313 }
2314
2315 // =======================================================================
2316 // function : handleMoveTo
2317 // purpose  :
2318 // =======================================================================
2319 void AIS_ViewController::handleMoveTo (const Handle(AIS_InteractiveContext)& theCtx,
2320                                        const Handle(V3d_View)& theView)
2321 {
2322   handleSelectionPick   (theCtx, theView);
2323   handleDynamicHighlight(theCtx, theView);
2324   handleSelectionPoly   (theCtx, theView);
2325 }
2326
2327 // =======================================================================
2328 // function : handleViewRedraw
2329 // purpose  :
2330 // =======================================================================
2331 void AIS_ViewController::handleViewRedraw (const Handle(AIS_InteractiveContext)& ,
2332                                            const Handle(V3d_View)& theView)
2333 {
2334   // manage animation state
2335   if (!myViewAnimation.IsNull()
2336    && !myViewAnimation->IsStopped())
2337   {
2338     myViewAnimation->UpdateTimer();
2339     ResetPreviousMoveTo();
2340     setAskNextFrame();
2341   }
2342
2343   for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
2344   {
2345     const Handle(V3d_View)& aView = aViewIter.Value();
2346     if (aView->IsInvalidated()
2347      || myToAskNextFrame)
2348     {
2349       if (aView->ComputedMode())
2350       {
2351         aView->Update();
2352       }
2353       else
2354       {
2355         aView->Redraw();
2356       }
2357     }
2358     else if (aView->IsInvalidatedImmediate())
2359     {
2360       aView->RedrawImmediate();
2361     }
2362   }
2363
2364   if (myToAskNextFrame)
2365   {
2366     // ask more frames
2367     theView->Window()->InvalidateContent (Handle(Aspect_DisplayConnection)());
2368   }
2369 }
2370
2371 // =======================================================================
2372 // function : HandleViewEvents
2373 // purpose  :
2374 // =======================================================================
2375 void AIS_ViewController::HandleViewEvents (const Handle(AIS_InteractiveContext)& theCtx,
2376                                            const Handle(V3d_View)& theView)
2377 {
2378   handleMoveTo (theCtx, theView);
2379
2380   const AIS_WalkDelta aWalk = FetchNavigationKeys (1.0, 1.0);
2381   handleCameraActions (theCtx, theView, aWalk);
2382   handleViewRedraw (theCtx, theView);
2383
2384   // make sure to not process the same events twice
2385   myGL.Reset();
2386   myToAskNextFrame = false;
2387 }