Files
DynamicDataDisplay/Charts/Axes/StackCanvas.cs
2024-02-23 00:46:06 -05:00

238 lines
7.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media;
using System.Diagnostics;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
namespace Microsoft.Research.DynamicDataDisplay.Charts
{
public class StackCanvas : Panel
{
public StackCanvas()
{
//ClipToBounds = true;
}
#region EndCoordinate attached property
[AttachedPropertyBrowsableForChildren]
public static double GetEndCoordinate(DependencyObject obj)
{
return (double)obj.GetValue(EndCoordinateProperty);
}
public static void SetEndCoordinate(DependencyObject obj, double value)
{
obj.SetValue(EndCoordinateProperty, value);
}
public static readonly DependencyProperty EndCoordinateProperty = DependencyProperty.RegisterAttached(
"EndCoordinate",
typeof(double),
typeof(StackCanvas),
new PropertyMetadata(Double.NaN, OnCoordinateChanged));
#endregion
#region Coordinate attached property
[AttachedPropertyBrowsableForChildren]
public static double GetCoordinate(DependencyObject obj)
{
return (double)obj.GetValue(CoordinateProperty);
}
public static void SetCoordinate(DependencyObject obj, double value)
{
obj.SetValue(CoordinateProperty, value);
}
public static readonly DependencyProperty CoordinateProperty = DependencyProperty.RegisterAttached(
"Coordinate",
typeof(double),
typeof(StackCanvas),
new PropertyMetadata(0.0, OnCoordinateChanged));
private static void OnCoordinateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UIElement reference = d as UIElement;
if (reference != null)
{
StackCanvas parent = VisualTreeHelper.GetParent(reference) as StackCanvas;
if (parent != null)
{
parent.InvalidateArrange();
}
}
}
#endregion
#region AxisPlacement property
public AxisPlacement Placement
{
get { return (AxisPlacement)GetValue(PlacementProperty); }
set { SetValue(PlacementProperty, value); }
}
public static readonly DependencyProperty PlacementProperty =
DependencyProperty.Register(
"Placement",
typeof(AxisPlacement),
typeof(StackCanvas),
new FrameworkPropertyMetadata(
AxisPlacement.Bottom,
FrameworkPropertyMetadataOptions.AffectsArrange));
#endregion
private bool IsHorizontal
{
get { return Placement == AxisPlacement.Top || Placement == AxisPlacement.Bottom; }
}
protected override Size MeasureOverride(Size constraint)
{
Size availableSize = constraint;
Size size = new Size();
bool isHorizontal = IsHorizontal;
if (isHorizontal)
{
availableSize.Width = Double.PositiveInfinity;
size.Width = constraint.Width;
}
else
{
availableSize.Height = Double.PositiveInfinity;
size.Height = constraint.Height;
}
// measuring all children and determinimg self width and height
foreach (UIElement element in base.Children)
{
if (element != null)
{
Size childSize = GetChildSize(element, availableSize);
element.Measure(childSize);
Size desiredSize = element.DesiredSize;
if (isHorizontal)
{
size.Height = Math.Max(size.Height, desiredSize.Height);
}
else
{
size.Width = Math.Max(size.Width, desiredSize.Width);
}
}
}
if (Double.IsPositiveInfinity(size.Width)) size.Width = 0;
if (Double.IsPositiveInfinity(size.Height)) size.Height = 0;
return size;
}
private Size GetChildSize(UIElement element, Size availableSize)
{
var coordinate = GetCoordinate(element);
var endCoordinate = GetEndCoordinate(element);
if (coordinate.IsNotNaN() && endCoordinate.IsNotNaN())
{
if (Placement.IsBottomOrTop())
{
availableSize.Width = endCoordinate - coordinate;
}
else
{
availableSize.Height = endCoordinate - coordinate;
}
}
return availableSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
bool isHorizontal = IsHorizontal;
foreach (FrameworkElement element in base.Children)
{
if (element == null)
{
continue;
}
Size elementSize = element.DesiredSize;
double x = 0.0;
double y = 0.0;
switch (Placement)
{
case AxisPlacement.Left:
x = finalSize.Width - elementSize.Width;
break;
case AxisPlacement.Right:
x = 0;
break;
case AxisPlacement.Top:
y = finalSize.Height - elementSize.Height;
break;
case AxisPlacement.Bottom:
y = 0;
break;
default:
break;
}
double coordinate = GetCoordinate(element);
if (!Double.IsNaN(GetEndCoordinate(element)))
{
double endCoordinate = GetEndCoordinate(element);
double size = endCoordinate - coordinate;
if (size < 0)
{
size = -size;
coordinate -= size;
}
if (isHorizontal)
elementSize.Width = size;
else
elementSize.Height = size;
}
// shift for common tick labels, not for major ones.
if (isHorizontal)
{
x = coordinate;
if (element.HorizontalAlignment == HorizontalAlignment.Center)
x = coordinate - elementSize.Width / 2;
}
else
{
if (element.VerticalAlignment == VerticalAlignment.Center)
y = coordinate - elementSize.Height / 2;
else if (element.VerticalAlignment == VerticalAlignment.Bottom)
y = coordinate - elementSize.Height;
else if (element.VerticalAlignment == VerticalAlignment.Top)
y = coordinate;
}
Rect bounds = new Rect(new Point(x, y), elementSize);
element.Arrange(bounds);
}
return finalSize;
}
}
}