406 lines
9.2 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|