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() { #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; } } private Canvas hostingCanvas = new Canvas(); internal Canvas HostingCanvas { get { return hostingCanvas; } } #region IPlotterElement Members private Plotter2D plotter; public 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) { base.OnChildDesiredSizeChanged(child); InvalidatePosition((FrameworkElement)child); } Vector prevVisualOffset; bool sizeChanged = true; DataRect visibleWhileCreation; protected virtual void Viewport_PropertyChanged(object sender, ExtendedPropertyChangedEventArgs e) { if (e.PropertyName == Viewport2D.VisiblePropertyName) { DataRect visible = (DataRect)e.NewValue; DataRect prevVisible = (DataRect)e.OldValue; InvalidateMeasure(); // todo previous way // 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; // // todo was true //#if false // translateTransform.X += offset.X; // translateTransform.Y += offset.Y; //#else // InvalidateMeasure(); //#endif // } // else // { // visibleWhileCreation = visible; // translateTransform.X = 0; // translateTransform.Y = 0; // InvalidateMeasure(); // } sizeChanged = false; } else if (e.PropertyName == "Output") { sizeChanged = true; 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; 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; public override void BeginBatchAdd() { base.BeginBatchAdd(); invalidatePositionCalls = 0; } public override void EndBatchAdd() { base.EndBatchAdd(); if (plotter == null) return; UpdateContentBounds(Children.Count > 0 && invalidatePositionCalls == 0); } public void UpdateContentBounds() { UpdateContentBounds(true); } private void UpdateContentBounds(bool recalculate) { if (recalculate) { var transform = plotter.Viewport.Transform; 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; 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 } }