using System; using System.Globalization; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; using System.Windows.Shapes; using miew.Enumerable; using miew.Dag; namespace agree.Wpf.Util { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public partial class DagLayoutPanel : Panel { //public enum LayoutDirection //{ // TopToBottom = 0, // BottomToTop = 1, // LeftToRight = 2, // RightToLeft = 3, //} /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Shape.Stroke - dependency property is adopted by the DagPanel /// Shape.StrokeThickness - dependency property is adopted by the DagPanel /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static DagLayoutPanel() { Shape.StrokeProperty.AddOwner(typeof(DagLayoutPanel), new FrameworkPropertyMetadata( Brushes.Black, 0, (e, o) => { DagLayoutPanel p = (DagLayoutPanel)e; p.InvalidateVisual(); }, null, false)); Shape.StrokeThicknessProperty.AddOwner(typeof(DagLayoutPanel), new FrameworkPropertyMetadata( 1.0, 0, (e, o) => { DagLayoutPanel p = (DagLayoutPanel)e; p.InvalidateVisual(); }, null, false)); } public Brush Stroke { get { return (Brush)GetValue(Shape.StrokeProperty); } set { SetValue(Shape.StrokeProperty, value); } } public Double StrokeThickness { get { return (Double)GetValue(Shape.StrokeThicknessProperty); } set { SetValue(Shape.StrokeThicknessProperty, value); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// DagParents attached property - establish the Dag topology by setting an IList of parents (or none) for each /// Dag node (a FrameworkElement) /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static FrameworkElement[] rg_fe_empty = new FrameworkElement[0]; public static readonly DependencyProperty DagParentsProperty = DependencyProperty.RegisterAttached("DagParents", typeof(IList), typeof(DagLayoutPanel), new FrameworkPropertyMetadata( default(IList), FrameworkPropertyMetadataOptions.AffectsParentMeasure | FrameworkPropertyMetadataOptions.AffectsParentArrange, (d, args) => { FrameworkElement fe = d as FrameworkElement; if (fe != null) { DagLayoutPanel dlp = fe.Parent as DagLayoutPanel; IList new_list = args.NewValue as IList; IList old_list = args.NewValue as IList; if (dlp != null && new_list != null) dlp.ChangeNodeParents(fe, old_list, new_list); } }, (d, o) => { IList rg = o as IList; FrameworkElement fe = d as FrameworkElement; if (fe == null || rg == null) return rg_fe_empty; DagLayoutPanel dlp = fe.Parent as DagLayoutPanel; if (dlp == null) return rg_fe_empty; /// prevent cycles in the dag. LayoutDag.Node cur_node = dlp._dag[fe]; return rg .OfType<FrameworkElement>() .Where(par => par != fe && !cur_node.AllDescendants.Contains(dlp._dag[par])) .ToArray(); }, true)); public static IList GetDagParents(FrameworkElement e) { return e.GetValue(DagParentsProperty) as IList ?? rg_fe_empty; } public static void SetDagParents(FrameworkElement e, IList par) { e.SetValue(DagParentsProperty, par); } static IEnumerable<FrameworkElement> VisibleDagParents(FrameworkElement fe) { HashSet<FrameworkElement> hs = new HashSet<FrameworkElement>(); GetVisibleDagParents(hs, fe); return hs; } static void GetVisibleDagParents(HashSet<FrameworkElement> found, FrameworkElement fe) { IList parents = fe.GetValue(DagParentsProperty) as IList; if (parents == null) return; foreach (FrameworkElement parent in parents.OfType<FrameworkElement>()) { if (parent.Visibility == Visibility.Hidden) GetVisibleDagParents(found, parent); else found.Add(parent); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// DagLevel - read-only, attached dependency property indicates the computed level of the node /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static readonly DependencyPropertyKey DagLevelPropertyKey = DependencyProperty.RegisterAttachedReadOnly( "DagLevel", typeof(int), typeof(DagLayoutPanel), new FrameworkPropertyMetadata(0)); public static readonly DependencyProperty DagLevelProperty = DagLevelPropertyKey.DependencyProperty; }; }