/Main/src/DynamicDataDisplay/Charts/Navigation/Navigation/MouseNavigation.cs
C# | 235 lines | 188 code | 37 blank | 10 comment | 53 complexity | 9c674772dc6b969ddaa5c98d5655f011 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
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}