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

318 lines
7.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Windows;
using System.Windows.Controls;
using System.Diagnostics;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
using System.Windows.Threading;
using d3 = Microsoft.Research.DynamicDataDisplay;
using Microsoft.Research.DynamicDataDisplay.Common;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
public class ViewportHostPanel : ViewportPanel, IPlotterElement
{
static ViewportHostPanel()
{
EventManager.RegisterClassHandler(typeof(ViewportHostPanel), d3.Plotter.PlotterChangedEvent, new PlotterChangedEventHandler(OnPlotterChanged));
}
public ViewportHostPanel()
{
this.RenderTransform = translateTransform;
#if false
// for debug purposes
Width = 100;
Height = 100;
Background = Brushes.PaleGreen.MakeTransparent(0.2);
#endif
}
private static void OnPlotterChanged(object sender, PlotterChangedEventArgs e)
{
ViewportHostPanel owner = (ViewportHostPanel)sender;
if (owner.plotter != null && e.PreviousPlotter != null)
{
owner.viewport.PropertyChanged -= owner.Viewport_PropertyChanged;
owner.viewport = null;
owner.plotter = null;
}
if (owner.plotter == null && e.CurrentPlotter != null)
{
owner.plotter = (Plotter2D)e.CurrentPlotter;
owner.viewport = owner.plotter.Viewport;
owner.viewport.PropertyChanged += owner.Viewport_PropertyChanged;
}
}
TranslateTransform translateTransform = new TranslateTransform();
private Canvas hostingCanvas = new Canvas();
internal Canvas HostingCanvas
{
get { return hostingCanvas; }
}
#region IPlotterElement Members
private Plotter2D plotter;
protected Plotter2D Plotter
{
get { return plotter; }
}
Viewport2D viewport;
public virtual void OnPlotterAttached(Plotter plotter)
{
this.plotter = (Plotter2D)plotter;
viewport = this.plotter.Viewport;
if (!IsMarkersHost)
{
plotter.CentralGrid.Children.Add(hostingCanvas);
}
if (Parent == null)
{
hostingCanvas.Children.Add(this);
}
this.plotter.Viewport.PropertyChanged += Viewport_PropertyChanged;
}
public virtual void OnPlotterDetaching(Plotter plotter)
{
this.plotter.Viewport.PropertyChanged -= Viewport_PropertyChanged;
if (!IsMarkersHost)
{
plotter.CentralGrid.Children.Remove(hostingCanvas);
}
hostingCanvas.Children.Remove(this);
this.plotter = null;
}
Plotter IPlotterElement.Plotter
{
get { return plotter; }
}
protected override void OnChildDesiredSizeChanged(UIElement child)
{
InvalidatePosition((FrameworkElement)child);
}
Vector prevVisualOffset;
bool sizeChanged = true;
DataRect visibleWhileCreation;
protected virtual void Viewport_PropertyChanged(object sender, ExtendedPropertyChangedEventArgs e)
{
if (e.PropertyName == "Visible")
{
DataRect visible = (DataRect)e.NewValue;
DataRect prevVisible = (DataRect)e.OldValue;
if (prevVisible.Size.EqualsApproximately(visible.Size) && !sizeChanged)
{
var transform = viewport.Transform;
Point prevLocation = prevVisible.Location.ViewportToScreen(transform);
Point location = visible.Location.ViewportToScreen(transform);
Vector offset = prevLocation - location;
translateTransform.X += offset.X;
translateTransform.Y += offset.Y;
}
else
{
visibleWhileCreation = visible;
translateTransform.X = 0;
translateTransform.Y = 0;
InvalidateMeasure();
}
sizeChanged = false;
}
else if (e.PropertyName == "Output")
{
sizeChanged = true;
translateTransform.X = 0;
translateTransform.Y = 0;
InvalidateMeasure();
}
prevVisualOffset = VisualOffset;
}
#endregion
protected internal override void OnChildAdded(FrameworkElement child)
{
if (plotter == null) return;
InvalidatePosition(child);
//Dispatcher.BeginInvoke(((Action)(()=> InvalidatePosition(child))), DispatcherPriority.ApplicationIdle);
}
private DataRect overallViewportBounds = DataRect.Empty;
internal DataRect OverallViewportBounds
{
get { return overallViewportBounds; }
set { overallViewportBounds = value; }
}
private BoundsUnionMode boundsUnionMode;
internal BoundsUnionMode BoundsUnionMode
{
get { return boundsUnionMode; }
set { boundsUnionMode = value; }
}
protected override void InvalidatePosition(FrameworkElement child)
{
invalidatePositionCalls++;
if (viewport == null) return;
if (child.Visibility != Visibility.Visible)
return;
var transform = viewport.Transform.WithScreenOffset(-translateTransform.X, -translateTransform.Y);
Size elementSize = GetElementSize(child, AvailableSize, transform);
child.Measure(elementSize);
Rect bounds = GetElementScreenBounds(transform, child);
child.Arrange(bounds);
var viewportBounds = Viewport2D.GetContentBounds(this);
if (!viewportBounds.IsEmpty)
overallViewportBounds = viewportBounds;
UniteWithBounds(transform, bounds);
if (!InBatchAdd)
{
Viewport2D.SetContentBounds(this, overallViewportBounds);
ContentBoundsChanged.Raise(this);
}
}
private void UniteWithBounds(CoordinateTransform transform, Rect bounds)
{
var childViewportBounds = bounds.ScreenToViewport(transform);
if (boundsUnionMode == BoundsUnionMode.Bounds)
overallViewportBounds.Union(childViewportBounds);
else
{
overallViewportBounds.Union(childViewportBounds.GetCenter());
}
}
int invalidatePositionCalls = 0;
internal override void BeginBatchAdd()
{
base.BeginBatchAdd();
invalidatePositionCalls = 0;
}
internal override void EndBatchAdd()
{
base.EndBatchAdd();
if (plotter == null) return;
if (Children.Count > 0 && invalidatePositionCalls == 0)
{
var transform = plotter.Viewport.Transform.WithScreenOffset(-translateTransform.X, -translateTransform.Y);
overallViewportBounds = DataRect.Empty;
foreach (FrameworkElement child in Children)
{
if (child != null)
{
if (child.Visibility != Visibility.Visible)
continue;
Rect bounds = GetElementScreenBounds(transform, child);
UniteWithBounds(transform, bounds);
}
}
}
Viewport2D.SetContentBounds(this, overallViewportBounds);
ContentBoundsChanged.Raise(this);
}
protected override Size ArrangeOverride(Size finalSize)
{
if (plotter == null)
return finalSize;
var transform = plotter.Viewport.Transform.WithScreenOffset(-translateTransform.X, -translateTransform.Y);
overallViewportBounds = DataRect.Empty;
foreach (UIElement child in InternalChildren)
{
if (child != null)
{
if (child.Visibility != Visibility.Visible)
continue;
Rect bounds = GetElementScreenBounds(transform, child);
child.Arrange(bounds);
UniteWithBounds(transform, bounds);
}
}
if (!InBatchAdd)
{
Viewport2D.SetContentBounds(this, overallViewportBounds);
ContentBoundsChanged.Raise(this);
}
return finalSize;
}
public event EventHandler ContentBoundsChanged;
protected override Size MeasureOverride(Size availableSize)
{
AvailableSize = availableSize;
if (plotter == null)
{
if (availableSize.Width.IsInfinite() || availableSize.Height.IsInfinite())
return new Size();
return availableSize;
}
var transform = plotter.Viewport.Transform;
foreach (FrameworkElement child in InternalChildren)
{
if (child != null)
{
Size elementSize = GetElementSize(child, availableSize, transform);
child.Measure(elementSize);
}
}
if (availableSize.Width.IsInfinite())
availableSize.Width = 0;
if (availableSize.Height.IsInfinite())
availableSize.Height = 0;
return availableSize;
}
}
public enum BoundsUnionMode
{
Center,
Bounds
}
}