Files
DynamicDataDisplay/Backup/Charts/Navigation/MouseNavigation.cs
2024-02-23 09:29:44 -05:00

407 lines
9.6 KiB
C#

using System;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using Microsoft.Research.DynamicDataDisplay.Common;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
using System.Diagnostics;
namespace Microsoft.Research.DynamicDataDisplay.Navigation
{
/// <summary>Provides common methods of mouse navigation around viewport</summary>
public class MouseNavigation : NavigationBase
{
/// <summary>
/// Initializes a new instance of the <see cref="MouseNavigation"/> class.
/// </summary>
public MouseNavigation() { }
private AdornerLayer adornerLayer;
protected AdornerLayer AdornerLayer
{
get
{
if (adornerLayer == null)
{
adornerLayer = AdornerLayer.GetAdornerLayer(this);
if (adornerLayer != null)
{
adornerLayer.IsHitTestVisible = false;
}
}
return adornerLayer;
}
}
protected override void OnPlotterAttached(Plotter plotter)
{
base.OnPlotterAttached(plotter);
Mouse.AddMouseDownHandler(Parent, OnMouseDown);
Mouse.AddMouseMoveHandler(Parent, OnMouseMove);
Mouse.AddMouseUpHandler(Parent, OnMouseUp);
Mouse.AddMouseWheelHandler(Parent, OnMouseWheel);
plotter.KeyDown += new KeyEventHandler(OnParentKeyDown);
}
protected override void OnPlotterDetaching(Plotter plotter)
{
plotter.KeyDown -= new KeyEventHandler(OnParentKeyDown);
Mouse.RemoveMouseDownHandler(Parent, OnMouseDown);
Mouse.RemoveMouseMoveHandler(Parent, OnMouseMove);
Mouse.RemoveMouseUpHandler(Parent, OnMouseUp);
Mouse.RemoveMouseWheelHandler(Parent, OnMouseWheel);
base.OnPlotterDetaching(plotter);
}
private void OnParentKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape || e.Key == Key.Back)
{
if (isZooming)
{
isZooming = false;
zoomRect = null;
ReleaseMouseCapture();
RemoveSelectionAdorner();
e.Handled = true;
}
}
}
private void OnMouseWheel(object sender, MouseWheelEventArgs e)
{
if (!e.Handled)
{
Point mousePos = e.GetPosition(this);
int delta = -e.Delta;
MouseWheelZoom(mousePos, delta);
e.Handled = true;
}
}
#if DEBUG
public override string ToString()
{
if (!String.IsNullOrEmpty(Name))
{
return Name;
}
return base.ToString();
}
#endif
bool adornerAdded;
RectangleSelectionAdorner selectionAdorner;
private void AddSelectionAdorner()
{
if (!adornerAdded)
{
AdornerLayer layer = AdornerLayer;
if (layer != null)
{
selectionAdorner = new RectangleSelectionAdorner(this) { Border = zoomRect };
layer.Add(selectionAdorner);
adornerAdded = true;
}
}
}
private void RemoveSelectionAdorner()
{
AdornerLayer layer = AdornerLayer;
if (layer != null)
{
layer.Remove(selectionAdorner);
adornerAdded = false;
}
}
private void UpdateSelectionAdorner()
{
selectionAdorner.Border = zoomRect;
selectionAdorner.InvalidateVisual();
}
Rect? zoomRect = null;
private const double wheelZoomSpeed = 1.2;
private bool shouldKeepRatioWhileZooming;
private bool isZooming = false;
protected bool IsZooming
{
get { return isZooming; }
}
private bool isPanning = false;
protected bool IsPanning
{
get { return isPanning; }
}
private Point panningStartPointInViewport;
protected Point PanningStartPointInViewport
{
get { return panningStartPointInViewport; }
}
private Point zoomStartPoint;
private static bool IsShiftOrCtrl
{
get
{
ModifierKeys currKeys = Keyboard.Modifiers;
return (currKeys | ModifierKeys.Shift) == currKeys ||
(currKeys | ModifierKeys.Control) == currKeys;
}
}
protected virtual bool ShouldStartPanning(MouseButtonEventArgs e)
{
return e.ChangedButton == MouseButton.Left && Keyboard.Modifiers == ModifierKeys.None;
}
protected virtual bool ShouldStartZoom(MouseButtonEventArgs e)
{
return e.ChangedButton == MouseButton.Left && IsShiftOrCtrl;
}
Point panningStartPointInScreen;
protected virtual void StartPanning(MouseButtonEventArgs e)
{
panningStartPointInScreen = e.GetPosition(this);
panningStartPointInViewport = panningStartPointInScreen.ScreenToViewport(Viewport.Transform);
Plotter2D.UndoProvider.CaptureOldValue(Viewport, Viewport2D.VisibleProperty, Viewport.Visible);
isPanning = true;
// not capturing mouse because this made some tools like PointSelector not
// receive MouseUp events on markers;
// Mouse will be captured later, in the first MouseMove handler call.
// CaptureMouse();
Viewport.PanningState = Viewport2DPanningState.Panning;
//e.Handled = true;
}
protected virtual void StartZoom(MouseButtonEventArgs e)
{
zoomStartPoint = e.GetPosition(this);
if (Viewport.Output.Contains(zoomStartPoint))
{
isZooming = true;
AddSelectionAdorner();
CaptureMouse();
shouldKeepRatioWhileZooming = Keyboard.Modifiers == ModifierKeys.Shift;
e.Handled = true;
}
}
private void OnMouseDown(object sender, MouseButtonEventArgs e)
{
// dragging
bool shouldStartDrag = ShouldStartPanning(e);
if (shouldStartDrag)
StartPanning(e);
// zooming
bool shouldStartZoom = ShouldStartZoom(e);
if (shouldStartZoom)
StartZoom(e);
if (!Plotter.IsFocused)
{
//var window = Window.GetWindow(Plotter);
//var focusWithinWindow = FocusManager.GetFocusedElement(window) != null;
Plotter.Focus();
//if (!focusWithinWindow)
//{
// this is done to prevent other tools like PointSelector from getting mouse click event when clicking on plotter
// to activate window it's contained within
e.Handled = true;
//}
}
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (!isPanning && !isZooming) return;
// dragging
if (isPanning && e.LeftButton == MouseButtonState.Pressed)
{
if (!IsMouseCaptured)
{
CaptureMouse();
}
Point endPoint = e.GetPosition(this).ScreenToViewport(Viewport.Transform);
Point loc = Viewport.Visible.Location;
Vector shift = panningStartPointInViewport - endPoint;
loc += shift;
// preventing unnecessary changes, if actually visible hasn't change.
if (shift.X != 0 || shift.Y != 0)
{
Cursor = Cursors.ScrollAll;
DataRect visible = Viewport.Visible;
visible.Location = loc;
Viewport.Visible = visible;
}
e.Handled = true;
}
// zooming
else if (isZooming && e.LeftButton == MouseButtonState.Pressed)
{
Point zoomEndPoint = e.GetPosition(this);
UpdateZoomRect(zoomEndPoint);
e.Handled = true;
}
}
private static bool IsShiftPressed()
{
return Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
}
private void UpdateZoomRect(Point zoomEndPoint)
{
Rect output = Viewport.Output;
Rect tmpZoomRect = new Rect(zoomStartPoint, zoomEndPoint);
tmpZoomRect = Rect.Intersect(tmpZoomRect, output);
shouldKeepRatioWhileZooming = IsShiftPressed();
if (shouldKeepRatioWhileZooming)
{
double currZoomRatio = tmpZoomRect.Width / tmpZoomRect.Height;
double zoomRatio = output.Width / output.Height;
if (currZoomRatio < zoomRatio)
{
double oldHeight = tmpZoomRect.Height;
double height = tmpZoomRect.Width / zoomRatio;
tmpZoomRect.Height = height;
if (!tmpZoomRect.Contains(zoomStartPoint))
{
tmpZoomRect.Offset(0, oldHeight - height);
}
}
else
{
double oldWidth = tmpZoomRect.Width;
double width = tmpZoomRect.Height * zoomRatio;
tmpZoomRect.Width = width;
if (!tmpZoomRect.Contains(zoomStartPoint))
{
tmpZoomRect.Offset(oldWidth - width, 0);
}
}
}
zoomRect = tmpZoomRect;
UpdateSelectionAdorner();
}
private void OnMouseUp(object sender, MouseButtonEventArgs e)
{
OnParentMouseUp(e);
}
protected virtual void OnParentMouseUp(MouseButtonEventArgs e)
{
if (isPanning && e.ChangedButton == MouseButton.Left)
{
isPanning = false;
StopPanning(e);
}
else if (isZooming && e.ChangedButton == MouseButton.Left)
{
isZooming = false;
StopZooming();
}
}
protected virtual void StopZooming()
{
if (zoomRect.HasValue)
{
Rect output = Viewport.Output;
Point p1 = zoomRect.Value.TopLeft.ScreenToViewport(Viewport.Transform);
Point p2 = zoomRect.Value.BottomRight.ScreenToViewport(Viewport.Transform);
DataRect newVisible = new DataRect(p1, p2);
Viewport.Visible = newVisible;
zoomRect = null;
ReleaseMouseCapture();
RemoveSelectionAdorner();
}
}
protected virtual void StopPanning(MouseButtonEventArgs e)
{
Plotter2D.UndoProvider.CaptureNewValue(Plotter2D.Viewport, Viewport2D.VisibleProperty, Viewport.Visible);
if (!Plotter.IsFocused)
{
Plotter2D.Focus();
}
Plotter2D.Viewport.PanningState = Viewport2DPanningState.NotPanning;
ReleaseMouseCapture();
ClearValue(CursorProperty);
}
protected override void OnLostFocus(RoutedEventArgs e)
{
if (isZooming)
{
RemoveSelectionAdorner();
isZooming = false;
}
if (isPanning)
{
Plotter2D.Viewport.PanningState = Viewport2DPanningState.NotPanning;
isPanning = false;
}
ReleaseMouseCapture();
base.OnLostFocus(e);
}
private void MouseWheelZoom(Point mousePos, double wheelRotationDelta)
{
Point zoomTo = mousePos.ScreenToViewport(Viewport.Transform);
double zoomSpeed = Math.Abs(wheelRotationDelta / Mouse.MouseWheelDeltaForOneLine);
zoomSpeed *= wheelZoomSpeed;
if (wheelRotationDelta < 0)
{
zoomSpeed = 1 / zoomSpeed;
}
Viewport.Visible = Viewport.Visible.Zoom(zoomTo, zoomSpeed);
}
}
}