diff --git a/Perspex.Layout/ILayoutable.cs b/Perspex.Layout/ILayoutable.cs index 2918d7bc8f..bca24c69f7 100644 --- a/Perspex.Layout/ILayoutable.cs +++ b/Perspex.Layout/ILayoutable.cs @@ -35,9 +35,9 @@ namespace Perspex.Layout Rect? PreviousArrange { get; } - void Measure(Size availableSize); + void Measure(Size availableSize, bool force = false); - void Arrange(Rect rect); + void Arrange(Rect rect, bool force = false); void InvalidateMeasure(); diff --git a/Perspex.Layout/LayoutManager.cs b/Perspex.Layout/LayoutManager.cs index dbb6db552a..03112af180 100644 --- a/Perspex.Layout/LayoutManager.cs +++ b/Perspex.Layout/LayoutManager.cs @@ -174,7 +174,7 @@ namespace Perspex.Layout parent = parent.GetVisualParent(); } - parent.Measure(parent.PreviousMeasure.Value); + parent.Measure(parent.PreviousMeasure.Value, true); } } } @@ -214,7 +214,7 @@ namespace Perspex.Layout parent = parent.GetVisualParent(); } - parent.Arrange(parent.PreviousArrange.Value); + parent.Arrange(parent.PreviousArrange.Value, true); } } } diff --git a/Perspex.Layout/Layoutable.cs b/Perspex.Layout/Layoutable.cs index 76ef481473..5bcfbc0959 100644 --- a/Perspex.Layout/Layoutable.cs +++ b/Perspex.Layout/Layoutable.cs @@ -166,27 +166,30 @@ namespace Perspex.Layout public static int DebugMeasureCount { get; set; } public static int DebugArrangeCount { get; set; } - public void Measure(Size availableSize) + public void Measure(Size availableSize, bool force = false) { if (double.IsNaN(availableSize.Width) || double.IsNaN(availableSize.Height)) { throw new InvalidOperationException("Cannot call Measure using a size with NaN values."); } - ++DebugMeasureCount; + if (force || this.previousMeasure != availableSize) + { + ++DebugMeasureCount; - this.DesiredSize = this.MeasureCore(availableSize).Constrain(availableSize); - this.IsMeasureValid = true; - this.previousMeasure = availableSize; + this.DesiredSize = this.MeasureCore(availableSize).Constrain(availableSize); + this.IsMeasureValid = true; + this.previousMeasure = availableSize; - this.Log().Debug( - "Measure of {0} (#{1:x8}) requested {2} ", - this.GetType().Name, - this.GetHashCode(), - this.DesiredSize); + this.Log().Debug( + "Measure of {0} (#{1:x8}) requested {2} ", + this.GetType().Name, + this.GetHashCode(), + this.DesiredSize); + } } - public void Arrange(Rect rect) + public void Arrange(Rect rect, bool force = false) { if (rect.Width < 0 || rect.Height < 0 || double.IsInfinity(rect.Width) || double.IsInfinity(rect.Height) || @@ -200,17 +203,21 @@ namespace Perspex.Layout throw new InvalidOperationException("Arrange called before Measure."); } - ++DebugArrangeCount; + if (force || this.previousArrange != rect) + { + ++DebugArrangeCount; - this.Log().Debug( - "Arrange of {0} (#{1:x8}) gave {2} ", - this.GetType().Name, - this.GetHashCode(), - rect); + this.Log().Debug( + "Arrange of {0} (#{1:x8}) gave {2} ", + this.GetType().Name, + this.GetHashCode(), + rect); + + this.ArrangeCore(rect); + this.previousArrange = rect; + } - this.ArrangeCore(rect); this.IsArrangeValid = true; - this.previousArrange = rect; } public void InvalidateMeasure() @@ -219,6 +226,8 @@ namespace Perspex.Layout this.IsMeasureValid = false; this.IsArrangeValid = false; + this.previousMeasure = null; + this.previousArrange = null; if (root != null && root.Item1.LayoutManager != null) { @@ -231,6 +240,7 @@ namespace Perspex.Layout var root = this.GetLayoutRoot(); this.IsArrangeValid = false; + this.previousArrange = null; if (root != null && root.Item1.LayoutManager != null) { diff --git a/Perspex.SceneGraph/Point.cs b/Perspex.SceneGraph/Point.cs index 8e000e9d34..4a8f2d2de3 100644 --- a/Perspex.SceneGraph/Point.cs +++ b/Perspex.SceneGraph/Point.cs @@ -50,6 +50,28 @@ namespace Perspex get { return this.y; } } + /// + /// Checks for equality between two s. + /// + /// The first point. + /// The second point. + /// True if the points are equal; otherwise false. + public static bool operator ==(Point left, Point right) + { + return left.X == right.X && left.Y == right.Y; + } + + /// + /// Checks for unequality between two s. + /// + /// The first point. + /// The second point. + /// True if the points are unequal; otherwise false. + public static bool operator !=(Point left, Point right) + { + return !(left == right); + } + public static Point operator +(Point a, Point b) { return new Point(a.x + b.x, a.y + b.y); @@ -65,6 +87,28 @@ namespace Perspex return new Vector(p.x, p.y); } + public override bool Equals(object obj) + { + if (obj is Point) + { + var other = (Point)obj; + return this.X == other.X && this.Y == other.Y; + } + + return false; + } + + public override int GetHashCode() + { + unchecked + { + int hash = 17; + hash = (hash * 23) + this.x.GetHashCode(); + hash = (hash * 23) + this.y.GetHashCode(); + return hash; + } + } + /// /// Returns the string representation of the point. /// diff --git a/Perspex.SceneGraph/Rect.cs b/Perspex.SceneGraph/Rect.cs index 88f8abfe6b..3ab160bace 100644 --- a/Perspex.SceneGraph/Rect.cs +++ b/Perspex.SceneGraph/Rect.cs @@ -191,6 +191,28 @@ namespace Perspex get { return this.width == 0 && this.height == 0; } } + /// + /// Checks for equality between two s. + /// + /// The first rect. + /// The second rect. + /// True if the rects are equal; otherwise false. + public static bool operator ==(Rect left, Rect right) + { + return left.Position == right.Position && left.Size == right.Size; + } + + /// + /// Checks for unequality between two s. + /// + /// The first rect. + /// The second rect. + /// True if the rects are unequal; otherwise false. + public static bool operator !=(Rect left, Rect right) + { + return !(left == right); + } + public static Rect operator *(Rect rect, Vector scale) { double centerX = rect.x + rect.width / 2; @@ -261,6 +283,33 @@ namespace Perspex this.Size.Deflate(thickness)); } + public override bool Equals(object obj) + { + if (obj is Rect) + { + var other = (Rect)obj; + return this.X == other.X && + this.X == other.X && + this.Width == other.Width && + this.Height == other.Height; + } + + return false; + } + + public override int GetHashCode() + { + unchecked + { + int hash = 17; + hash = (hash * 23) + this.X.GetHashCode(); + hash = (hash * 23) + this.Y.GetHashCode(); + hash = (hash * 23) + this.Width.GetHashCode(); + hash = (hash * 23) + this.Height.GetHashCode(); + return hash; + } + } + public Rect Intersect(Rect rect) { double x = Math.Max(this.x, rect.x); diff --git a/Perspex.SceneGraph/Size.cs b/Perspex.SceneGraph/Size.cs index 23e4cab500..958d34dcb7 100644 --- a/Perspex.SceneGraph/Size.cs +++ b/Perspex.SceneGraph/Size.cs @@ -120,6 +120,28 @@ namespace Perspex Math.Max(0, this.height - thickness.Top - thickness.Bottom)); } + public override bool Equals(object obj) + { + if (obj is Size) + { + var other = (Size)obj; + return this.Width == other.Width && this.Height == other.Height; + } + + return false; + } + + public override int GetHashCode() + { + unchecked + { + int hash = 17; + hash = (hash * 23) + this.Width.GetHashCode(); + hash = (hash * 23) + this.Height.GetHashCode(); + return hash; + } + } + /// /// Inflates the size by a . ///