PageRenderTime 24ms CodeModel.GetById 10ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/Main/src/DynamicDataDisplay/Charts/Navigation/Navigation/MouseNavigation.cs

#
C# | 235 lines | 188 code | 37 blank | 10 comment | 53 complexity | 9c674772dc6b969ddaa5c98d5655f011 MD5 | raw file
  1using System;
  2using System.Windows;
  3using System.Windows.Documents;
  4using System.Windows.Input;
  5
  6
  7namespace Microsoft.Research.DynamicDataDisplay.Navigation
  8{
  9    /// <summary>Provides common methods of mouse navigation around viewport</summary>
 10	public class MouseNavigation : NavigationBase {
 11		private AdornerLayer adornerLayer;
 12		protected AdornerLayer AdornerLayer {
 13			get {
 14				if (adornerLayer == null) {
 15					adornerLayer = AdornerLayer.GetAdornerLayer(this);
 16					if (adornerLayer != null) {
 17						adornerLayer.IsHitTestVisible = false;
 18					}
 19				}
 20
 21				return adornerLayer;
 22			}
 23		}
 24
 25		protected override void OnViewportChanged() {
 26			base.OnViewportChanged();
 27
 28			//Mouse.AddPreviewMouseDownHandler(Parent, (MouseButtonEventHandler)OnMouseDown);
 29			//Mouse.AddPreviewMouseMoveHandler(Parent, (MouseEventHandler)OnMouseMove);
 30			//Mouse.AddPreviewMouseUpHandler(Parent, (MouseButtonEventHandler)OnMouseUp);
 31
 32			Mouse.AddMouseDownHandler(Parent, OnMouseDown);
 33			Mouse.AddMouseMoveHandler(Parent, OnMouseMove);
 34			Mouse.AddMouseUpHandler(Parent, OnMouseUp);
 35
 36			Mouse.AddMouseWheelHandler(Parent, OnMouseWheel);
 37		}
 38
 39		private void OnMouseWheel(object sender, MouseWheelEventArgs e) {
 40			if (!e.Handled) {
 41				Point mousePos = e.GetPosition(this);
 42				int delta = -e.Delta;
 43				MouseWheelZoom(mousePos, delta);
 44			}
 45		}
 46
 47#if DEBUG
 48		public override string ToString()
 49		{
 50			if (!String.IsNullOrEmpty(Name)) {
 51				return Name;
 52			}
 53			return base.ToString();
 54		}
 55#endif
 56
 57		bool adornerAdded;
 58		RectangleSelectionAdorner selectionAdorner;
 59		private void AddSelectionAdorner() {
 60			if (!adornerAdded) {
 61				AdornerLayer layer = AdornerLayer;
 62				if (layer != null) {
 63					selectionAdorner = new RectangleSelectionAdorner(this) { Border = zoomRect };
 64
 65					layer.Add(selectionAdorner);
 66					adornerAdded = true;
 67				}
 68			}
 69		}
 70
 71		private void RemoveSelectionAdorner() {
 72			AdornerLayer layer = AdornerLayer;
 73			if (layer != null) {
 74				layer.Remove(selectionAdorner);
 75				adornerAdded = false;
 76			}
 77		}
 78
 79		private void UpdateSelectionAdorner() {
 80			selectionAdorner.Border = zoomRect;
 81			selectionAdorner.InvalidateVisual();
 82		}
 83
 84		Rect? zoomRect = null;
 85		private const double wheelZoomSpeed = 1.2;
 86		private bool shouldKeepRatioWhileZooming;
 87		private bool isZooming;
 88		private bool isDragging;
 89		private Point dragStartPointInVisible;
 90		private Point zoomStartPoint;
 91
 92		private static bool IsShiftOrCtrl {
 93			get {
 94				ModifierKeys currKeys = Keyboard.Modifiers;
 95				return (currKeys | ModifierKeys.Shift) == currKeys ||
 96					(currKeys | ModifierKeys.Control) == currKeys;
 97			}
 98		}
 99
100		private void OnMouseDown(object sender, MouseButtonEventArgs e) {
101			// dragging
102			bool shouldStartDrag = e.ChangedButton == MouseButton.Left && Keyboard.Modifiers == ModifierKeys.None;
103
104			if (shouldStartDrag) {
105				Point dragStartPointInOutput = e.GetPosition(this);
106				dragStartPointInVisible = dragStartPointInOutput.Transform(Viewport.Output, Viewport.Visible);
107
108				isDragging = true;
109				CaptureMouse();
110			}
111
112			bool shouldStartZoom = e.ChangedButton == MouseButton.Left && IsShiftOrCtrl;
113			if (shouldStartZoom) {
114				// zooming
115
116				zoomStartPoint = e.GetPosition(this);
117				if (Viewport.Output.Contains(zoomStartPoint)) {
118					isZooming = true;
119					AddSelectionAdorner();
120					CaptureMouse();
121					shouldKeepRatioWhileZooming = Keyboard.Modifiers == ModifierKeys.Shift;
122				}
123			}
124
125			((IInputElement) Parent).Focus();
126		}
127
128		private void OnMouseMove(object sender, MouseEventArgs e) {
129			if (!isDragging && !isZooming) return;
130
131			// dragging
132			if (isDragging && e.LeftButton == MouseButtonState.Pressed) {
133				Point endPoint = e.GetPosition(this).Transform(Viewport.Output, Viewport.Visible);
134
135				Point loc = Viewport.Visible.Location;
136				Vector shift = dragStartPointInVisible - endPoint;
137				loc += shift;
138
139				if (shift.X != 0 || shift.Y != 0) {
140					Rect visible = Viewport.Visible;
141
142					visible.Location = loc;
143					Viewport.Visible = visible;
144				}
145			}
146			// zooming
147			else if (isZooming && e.LeftButton == MouseButtonState.Pressed) {
148				Point zoomEndPoint = e.GetPosition(this);
149				UpdateZoomRect(zoomEndPoint);
150			}
151		}
152
153		private static bool IsShiftPressed() {
154			return Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
155		}
156
157		private void UpdateZoomRect(Point zoomEndPoint) {
158			Rect output = Viewport.Output;
159			Rect tmpZoomRect = new Rect(zoomStartPoint, zoomEndPoint);
160			tmpZoomRect = Rect.Intersect(tmpZoomRect, output);
161
162			shouldKeepRatioWhileZooming = IsShiftPressed();
163			if (shouldKeepRatioWhileZooming) {
164				double currZoomRatio = tmpZoomRect.Width / tmpZoomRect.Height;
165				double zoomRatio = output.Width / output.Height;
166				if (currZoomRatio < zoomRatio) {
167					double oldHeight = tmpZoomRect.Height;
168					double height = tmpZoomRect.Width / zoomRatio;
169					tmpZoomRect.Height = height;
170					if (!tmpZoomRect.Contains(zoomStartPoint)) {
171						tmpZoomRect.Offset(0, oldHeight - height);
172					}
173				}
174				else {
175					double oldWidth = tmpZoomRect.Width;
176					double width = tmpZoomRect.Height * zoomRatio;
177					tmpZoomRect.Width = width;
178					if (!tmpZoomRect.Contains(zoomStartPoint)) {
179						tmpZoomRect.Offset(oldWidth - width, 0);
180					}
181				}
182			}
183
184			zoomRect = tmpZoomRect;
185			UpdateSelectionAdorner();
186		}
187
188		private void OnMouseUp(object sender, MouseButtonEventArgs e) {
189			if (isDragging && e.ChangedButton == MouseButton.Left) {
190				isDragging = false;
191				ReleaseMouseCapture();
192				Point endPoint = e.GetPosition(this).Transform(Viewport.Output, Viewport.Visible);
193
194				// focusing on LMB click
195				if (endPoint == dragStartPointInVisible) {
196					//Keyboard.Focus(Parent as IInputElement);
197				}
198			}
199			else if (isZooming && e.ChangedButton == MouseButton.Left) {
200				isZooming = false;
201				if (zoomRect.HasValue) {
202					Rect output = Viewport.Output;
203
204					Point p1 = zoomRect.Value.TopLeft.Transform(output, Viewport.Visible);
205					Point p2 = zoomRect.Value.BottomRight.Transform(output, Viewport.Visible);
206					Rect newVisible = new Rect(p1, p2);
207					Viewport.Visible = newVisible;
208
209					zoomRect = null;
210					ReleaseMouseCapture();
211					RemoveSelectionAdorner();
212				}
213			}
214		}
215
216		protected override void OnLostFocus(RoutedEventArgs e) {
217			if (isZooming) {
218				RemoveSelectionAdorner();
219			}
220			ReleaseMouseCapture();
221			base.OnLostFocus(e);
222		}
223
224		private void MouseWheelZoom(Point mousePos, int wheelRotationDelta) {
225			Point zoomTo = mousePos.Transform(Viewport.Output, Viewport.Visible);
226
227			double zoomSpeed = Math.Abs(wheelRotationDelta / Mouse.MouseWheelDeltaForOneLine);
228			zoomSpeed *= wheelZoomSpeed;
229			if (wheelRotationDelta < 0) {
230				zoomSpeed = 1 / zoomSpeed;
231			}
232			Viewport.Visible = Viewport.Visible.Zoom(zoomTo, zoomSpeed);
233		}
234	}
235}