From 4f9dc138da8039ad5590972e96067f4931a49f2a Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 5 Dec 2014 18:39:07 +0100 Subject: [PATCH] Use measure layout algorithm for arrange. --- Perspex.Controls/Window.cs | 1 + Perspex.Layout/LayoutManager.cs | 57 +++++++++++++++++++++++++++++++-- Perspex.Layout/Layoutable.cs | 3 +- 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/Perspex.Controls/Window.cs b/Perspex.Controls/Window.cs index 82c62aafa8..8c250de062 100644 --- a/Perspex.Controls/Window.cs +++ b/Perspex.Controls/Window.cs @@ -37,6 +37,7 @@ namespace Perspex.Controls static Window() { BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White); + AffectsMeasure(Window.ClientSizeProperty); } public Window() diff --git a/Perspex.Layout/LayoutManager.cs b/Perspex.Layout/LayoutManager.cs index 7131d615bc..dbb6db552a 100644 --- a/Perspex.Layout/LayoutManager.cs +++ b/Perspex.Layout/LayoutManager.cs @@ -42,6 +42,11 @@ namespace Perspex.Layout /// private Heap toMeasure = new Heap(HeapType.Minimum); + /// + /// The controls that need to be arranged, sorted by distance to layout root. + /// + private Heap toArrange = new Heap(HeapType.Minimum); + /// /// Initializes a new instance of the class. /// @@ -98,7 +103,7 @@ namespace Perspex.Layout this.measureNeeded = false; } - this.Root.Arrange(new Rect(this.Root.ClientSize)); + this.ExecuteArrange(); System.Diagnostics.Debug.WriteLine(Environment.TickCount + " " + Layoutable.DebugMeasureCount + " " + Layoutable.DebugArrangeCount); } @@ -110,8 +115,11 @@ namespace Perspex.Layout /// The control's distance from the layout root. public void InvalidateMeasure(ILayoutable control, int distance) { + var item = new Item(control, distance); + this.toMeasure.Add(item); + this.toArrange.Add(item); + this.measureNeeded = true; - this.toMeasure.Add(new Item(control, distance)); if (!this.LayoutQueued) { @@ -128,7 +136,7 @@ namespace Perspex.Layout /// The control's distance from the layout root. public void InvalidateArrange(ILayoutable control, int distance) { - //this.toArrange.Add(item); + this.toArrange.Add(new Item(control, distance)); if (!this.LayoutQueued) { @@ -138,6 +146,9 @@ namespace Perspex.Layout } } + /// + /// Executes the measure part of the layout pass. + /// private void ExecuteMeasure() { for (int i = 0; i < MaxTries; ++i) @@ -175,6 +186,46 @@ namespace Perspex.Layout } } + /// + /// Executes the arrange part of the layout pass. + /// + private void ExecuteArrange() + { + for (int i = 0; i < MaxTries; ++i) + { + var arrange = this.toArrange; + + this.toArrange = new Heap(HeapType.Minimum); + + if (!this.Root.IsArrangeValid) + { + this.Root.Arrange(new Rect(this.Root.ClientSize)); + } + else + { + foreach (var item in arrange) + { + if (!item.Control.IsArrangeValid) + { + var parent = item.Control.GetVisualParent(); + + while (parent.PreviousArrange == null) + { + parent = parent.GetVisualParent(); + } + + parent.Arrange(parent.PreviousArrange.Value); + } + } + } + + if (this.toArrange.Count == 0) + { + break; + } + } + } + private class Item : IComparable { public Item(ILayoutable control, int distance) diff --git a/Perspex.Layout/Layoutable.cs b/Perspex.Layout/Layoutable.cs index 036bf94937..76ef481473 100644 --- a/Perspex.Layout/Layoutable.cs +++ b/Perspex.Layout/Layoutable.cs @@ -209,6 +209,7 @@ namespace Perspex.Layout rect); this.ArrangeCore(rect); + this.IsArrangeValid = true; this.previousArrange = rect; } @@ -217,6 +218,7 @@ namespace Perspex.Layout var root = this.GetLayoutRoot(); this.IsMeasureValid = false; + this.IsArrangeValid = false; if (root != null && root.Item1.LayoutManager != null) { @@ -228,7 +230,6 @@ namespace Perspex.Layout { var root = this.GetLayoutRoot(); - this.IsMeasureValid = false; this.IsArrangeValid = false; if (root != null && root.Item1.LayoutManager != null)