Files
DynamicDataDisplay/Charts/Navigation/AxisNavigation.cs
2024-02-23 00:46:06 -05:00

406 lines
9.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;
using System.Windows.Media;
using Microsoft.Research.DynamicDataDisplay.Charts.Axes;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
using System.Diagnostics;
namespace Microsoft.Research.DynamicDataDisplay.Charts.Navigation
{
public class AxisNavigation : DependencyObject, IPlotterElement
{
public AxisPlacement Placement
{
get { return (AxisPlacement)GetValue(PlacementProperty); }
set { SetValue(PlacementProperty, value); }
}
public static readonly DependencyProperty PlacementProperty = DependencyProperty.Register(
"Placement",
typeof(AxisPlacement),
typeof(AxisNavigation),
new FrameworkPropertyMetadata(AxisPlacement.Left, OnPlacementChanged));
private static void OnPlacementChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
AxisNavigation navigation = (AxisNavigation)d;
navigation.OnPlacementChanged();
}
private Panel listeningPanel;
protected Panel ListeningPanel
{
get { return listeningPanel; }
}
private void OnPlacementChanged()
{
SetListeningPanel();
}
private void SetListeningPanel()
{
if (plotter == null) return;
AxisPlacement placement = Placement;
switch (placement)
{
case AxisPlacement.Left:
listeningPanel = plotter.LeftPanel;
break;
case AxisPlacement.Right:
listeningPanel = plotter.RightPanel;
break;
case AxisPlacement.Top:
listeningPanel = plotter.TopPanel;
break;
case AxisPlacement.Bottom:
listeningPanel = plotter.BottomPanel;
break;
default:
break;
}
}
private CoordinateTransform Transform
{
get { return plotter.Viewport.Transform; }
}
private Panel hostPanel;
#region IPlotterElement Members
void IPlotterElement.OnPlotterAttached(Plotter plotter)
{
this.plotter = (Plotter2D)plotter;
hostPanel = plotter.MainGrid;
//hostPanel.Background = Brushes.Pink;
SetListeningPanel();
if (hostPanel != null)
{
hostPanel.MouseLeftButtonUp += OnMouseLeftButtonUp;
hostPanel.MouseLeftButtonDown += OnMouseLeftButtonDown;
hostPanel.MouseMove += OnMouseMove;
hostPanel.MouseWheel += OnMouseWheel;
hostPanel.MouseRightButtonDown += OnMouseRightButtonDown;
hostPanel.MouseRightButtonUp += OnMouseRightButtonUp;
hostPanel.LostFocus += OnLostFocus;
}
}
private void OnLostFocus(object sender, RoutedEventArgs e)
{
//Debug.WriteLine("Lost Focus");
RevertChanges();
rmbPressed = false;
lmbPressed = false;
e.Handled = true;
}
#region Right button down
DataRect rmbDragStartRect;
private void OnMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
OnMouseRightButtonDown(e);
}
protected virtual void OnMouseRightButtonDown(MouseButtonEventArgs e)
{
rmbInitialPosition = e.GetPosition(listeningPanel);
var foundActivePlotter = UpdateActivePlotter(e);
if (foundActivePlotter)
{
rmbPressed = true;
dragStartInViewport = rmbInitialPosition.ScreenToViewport(activePlotter.Transform);
rmbDragStartRect = activePlotter.Visible;
listeningPanel.Background = fillBrush;
listeningPanel.CaptureMouse();
//e.Handled = true;
}
}
#endregion
#region Right button up
private void OnMouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
OnMouseRightButtonUp(e);
}
protected virtual void OnMouseRightButtonUp(MouseButtonEventArgs e)
{
if (rmbPressed)
{
rmbPressed = false;
RevertChanges();
//e.Handled = true;
}
}
#endregion
private void RevertChanges()
{
listeningPanel.ClearValue(Panel.CursorProperty);
listeningPanel.Background = Brushes.Transparent;
listeningPanel.ReleaseMouseCapture();
}
private const double wheelZoomSpeed = 1.2;
private void OnMouseWheel(object sender, MouseWheelEventArgs e)
{
Point mousePos = e.GetPosition(listeningPanel);
Rect listeningPanelBounds = new Rect(listeningPanel.RenderSize);
if (!listeningPanelBounds.Contains(mousePos))
return;
var foundActivePlotter = UpdateActivePlotter(e);
if (!foundActivePlotter) return;
int delta = -e.Delta;
Point zoomTo = mousePos.ScreenToViewport(activePlotter.Transform);
double zoomSpeed = Math.Abs(delta / Mouse.MouseWheelDeltaForOneLine);
zoomSpeed *= wheelZoomSpeed;
if (delta < 0)
{
zoomSpeed = 1 / zoomSpeed;
}
DataRect visible = activePlotter.Viewport.Visible.Zoom(zoomTo, zoomSpeed);
DataRect oldVisible = activePlotter.Viewport.Visible;
if (Placement.IsBottomOrTop())
{
visible.YMin = oldVisible.YMin;
visible.Height = oldVisible.Height;
}
else
{
visible.XMin = oldVisible.XMin;
visible.Width = oldVisible.Width;
}
activePlotter.Viewport.Visible = visible;
e.Handled = true;
}
private const int RmbZoomScale = 200;
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (lmbPressed)
{
// panning:
if (e.LeftButton == MouseButtonState.Released)
{
lmbPressed = false;
RevertChanges();
return;
}
Point screenMousePos = e.GetPosition(listeningPanel);
Point dataMousePos = screenMousePos.ScreenToViewport(activePlotter.Transform);
DataRect visible = activePlotter.Viewport.Visible;
double delta;
if (Placement.IsBottomOrTop())
{
delta = (dataMousePos - dragStartInViewport).X;
visible.XMin -= delta;
}
else
{
delta = (dataMousePos - dragStartInViewport).Y;
visible.YMin -= delta;
}
if (screenMousePos != lmbInitialPosition)
{
listeningPanel.Cursor = Placement.IsBottomOrTop() ? Cursors.ScrollWE : Cursors.ScrollNS;
}
activePlotter.Viewport.Visible = visible;
e.Handled = true;
}
else if (rmbPressed)
{
// one direction zooming:
if (e.RightButton == MouseButtonState.Released)
{
rmbPressed = false;
RevertChanges();
return;
}
Point screenMousePos = e.GetPosition(listeningPanel);
DataRect visible = activePlotter.Viewport.Visible;
double delta;
bool isHorizontal = Placement.IsBottomOrTop();
if (isHorizontal)
{
delta = (screenMousePos - rmbInitialPosition).X;
}
else
{
delta = (screenMousePos - rmbInitialPosition).Y;
}
if (delta < 0)
delta = 1 / Math.Exp(-delta / RmbZoomScale);
else
delta = Math.Exp(delta / RmbZoomScale);
Point center = dragStartInViewport;
if (isHorizontal)
{
visible = rmbDragStartRect.ZoomX(center, delta);
}
else
{
visible = rmbDragStartRect.ZoomY(center, delta);
}
if (screenMousePos != lmbInitialPosition)
{
listeningPanel.Cursor = Placement.IsBottomOrTop() ? Cursors.ScrollWE : Cursors.ScrollNS;
}
activePlotter.Viewport.Visible = visible;
//e.Handled = true;
}
}
private Point lmbInitialPosition;
protected Point LmbInitialPosition
{
get { return lmbInitialPosition; }
}
private Point rmbInitialPosition;
private readonly SolidColorBrush fillBrush = new SolidColorBrush(Color.FromRgb(255, 228, 209)).MakeTransparent(0.2);
private bool lmbPressed;
private bool rmbPressed;
private Point dragStartInViewport;
private Plotter2D activePlotter;
#region Left button down
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
OnMouseLeftButtonDown(e);
}
protected virtual void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
lmbInitialPosition = e.GetPosition(listeningPanel);
var foundActivePlotter = UpdateActivePlotter(e);
if (foundActivePlotter)
{
lmbPressed = true;
dragStartInViewport = lmbInitialPosition.ScreenToViewport(activePlotter.Transform);
listeningPanel.Background = fillBrush;
listeningPanel.CaptureMouse();
e.Handled = true;
}
}
#endregion
private bool UpdateActivePlotter(MouseEventArgs e)
{
var axes = listeningPanel.Children.OfType<GeneralAxis>();
foreach (var axis in axes)
{
var positionInAxis = e.GetPosition(axis);
Rect axisBounds = new Rect(axis.RenderSize);
if (axisBounds.Contains(positionInAxis))
{
activePlotter = axis.Plotter;
return true;
}
}
return false;
}
#region Left button up
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
OnMouseLeftButtonUp(e);
}
protected virtual void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
if (lmbPressed)
{
lmbPressed = false;
RevertChanges();
e.Handled = true;
}
}
#endregion
public void OnPlotterDetaching(Plotter plotter)
{
if (plotter.MainGrid != null)
{
hostPanel.MouseLeftButtonUp -= OnMouseLeftButtonUp;
hostPanel.MouseLeftButtonDown -= OnMouseLeftButtonDown;
hostPanel.MouseMove -= OnMouseMove;
hostPanel.MouseWheel -= OnMouseWheel;
hostPanel.MouseRightButtonDown -= OnMouseRightButtonDown;
hostPanel.MouseRightButtonUp -= OnMouseRightButtonUp;
hostPanel.LostFocus -= OnLostFocus;
}
listeningPanel = null;
this.plotter = null;
}
private Plotter2D plotter;
Plotter IPlotterElement.Plotter
{
get { return plotter; }
}
#endregion
public override string ToString()
{
return "AxisNavigation: " + Placement;
}
}
}