From 28b6de1019d6e11a4c03835e0799f6c82f715ff4 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 30 Jan 2016 16:53:42 +0100 Subject: [PATCH] Make Shapes update their geometry. When a property that affects the Shape's geometry is changed, make sure the DefiningGeometry gets updated. --- src/Perspex.Controls/Shapes/Ellipse.cs | 23 ++++----- src/Perspex.Controls/Shapes/Line.cs | 25 ++-------- src/Perspex.Controls/Shapes/Path.cs | 7 ++- src/Perspex.Controls/Shapes/Polygon.cs | 22 ++------- src/Perspex.Controls/Shapes/Polyline.cs | 22 ++------- src/Perspex.Controls/Shapes/Rectangle.cs | 23 ++++----- src/Perspex.Controls/Shapes/Shape.cs | 59 ++++++++++++++++++++++-- 7 files changed, 88 insertions(+), 93 deletions(-) diff --git a/src/Perspex.Controls/Shapes/Ellipse.cs b/src/Perspex.Controls/Shapes/Ellipse.cs index a542e843a1..627a75e46d 100644 --- a/src/Perspex.Controls/Shapes/Ellipse.cs +++ b/src/Perspex.Controls/Shapes/Ellipse.cs @@ -7,23 +7,16 @@ namespace Perspex.Controls.Shapes { public class Ellipse : Shape { - private Geometry _geometry; - - private Size _geometrySize; - - public override Geometry DefiningGeometry + static Ellipse() { - get - { - if (_geometry == null || _geometrySize != Bounds.Size) - { - var rect = new Rect(Bounds.Size).Deflate(StrokeThickness); - _geometry = new EllipseGeometry(rect); - _geometrySize = Bounds.Size; - } + AffectsGeometry(BoundsProperty); + AffectsGeometry(StrokeThicknessProperty); + } - return _geometry; - } + protected override Geometry CreateDefiningGeometry() + { + var rect = new Rect(Bounds.Size).Deflate(StrokeThickness); + return new EllipseGeometry(rect); } protected override Size MeasureOverride(Size availableSize) diff --git a/src/Perspex.Controls/Shapes/Line.cs b/src/Perspex.Controls/Shapes/Line.cs index 72f0748eec..1b21c2c86f 100644 --- a/src/Perspex.Controls/Shapes/Line.cs +++ b/src/Perspex.Controls/Shapes/Line.cs @@ -1,11 +1,6 @@ // Copyright (c) The Perspex Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Perspex.Media; namespace Perspex.Controls.Shapes @@ -18,13 +13,11 @@ namespace Perspex.Controls.Shapes public static readonly StyledProperty EndPointProperty = PerspexProperty.Register("EndPoint"); - private LineGeometry _geometry; - private Point _startPoint; - private Point _endPoint; - static Line() { StrokeThicknessProperty.OverrideDefaultValue(1); + AffectsGeometry(StartPointProperty); + AffectsGeometry(EndPointProperty); } public Point StartPoint @@ -39,19 +32,9 @@ namespace Perspex.Controls.Shapes set { SetValue(EndPointProperty, value); } } - public override Geometry DefiningGeometry + protected override Geometry CreateDefiningGeometry() { - get - { - if (_geometry == null || StartPoint != _startPoint || EndPoint != _endPoint) - { - _startPoint = StartPoint; - _endPoint = EndPoint; - _geometry = new LineGeometry(_startPoint, _endPoint); - } - - return _geometry; - } + return new LineGeometry(StartPoint, EndPoint); } } } diff --git a/src/Perspex.Controls/Shapes/Path.cs b/src/Perspex.Controls/Shapes/Path.cs index bee94c879b..91c2934c90 100644 --- a/src/Perspex.Controls/Shapes/Path.cs +++ b/src/Perspex.Controls/Shapes/Path.cs @@ -11,12 +11,17 @@ namespace Perspex.Controls.Shapes public static readonly StyledProperty DataProperty = PerspexProperty.Register("Data"); + static Path() + { + AffectsGeometry(DataProperty); + } + public Geometry Data { get { return GetValue(DataProperty); } set { SetValue(DataProperty, value); } } - public override Geometry DefiningGeometry => Data; + protected override Geometry CreateDefiningGeometry() => Data; } } diff --git a/src/Perspex.Controls/Shapes/Polygon.cs b/src/Perspex.Controls/Shapes/Polygon.cs index 4ff24d060f..8fd11c58c9 100644 --- a/src/Perspex.Controls/Shapes/Polygon.cs +++ b/src/Perspex.Controls/Shapes/Polygon.cs @@ -11,24 +11,9 @@ namespace Perspex.Controls.Shapes public static readonly StyledProperty> PointsProperty = PerspexProperty.Register>("Points"); - private Geometry _geometry; - static Polygon() { - PointsProperty.Changed.AddClassHandler(x => x.PointsChanged); - } - - public override Geometry DefiningGeometry - { - get - { - if (_geometry == null) - { - _geometry = new PolylineGeometry(Points, true); - } - - return _geometry; - } + AffectsGeometry(PointsProperty); } public IList Points @@ -37,10 +22,9 @@ namespace Perspex.Controls.Shapes set { SetValue(PointsProperty, value); } } - private void PointsChanged(PerspexPropertyChangedEventArgs e) + protected override Geometry CreateDefiningGeometry() { - _geometry = null; - InvalidateMeasure(); + return new PolylineGeometry(Points, true); } } } diff --git a/src/Perspex.Controls/Shapes/Polyline.cs b/src/Perspex.Controls/Shapes/Polyline.cs index eb0426b77b..9b2c3eaa12 100644 --- a/src/Perspex.Controls/Shapes/Polyline.cs +++ b/src/Perspex.Controls/Shapes/Polyline.cs @@ -11,25 +11,10 @@ namespace Perspex.Controls.Shapes public static readonly StyledProperty> PointsProperty = PerspexProperty.Register>("Points"); - private Geometry _geometry; - static Polyline() { StrokeThicknessProperty.OverrideDefaultValue(1); - PointsProperty.Changed.AddClassHandler(x => x.PointsChanged); - } - - public override Geometry DefiningGeometry - { - get - { - if (_geometry == null) - { - _geometry = new PolylineGeometry(Points, false); - } - - return _geometry; - } + AffectsGeometry(PointsProperty); } public IList Points @@ -38,10 +23,9 @@ namespace Perspex.Controls.Shapes set { SetValue(PointsProperty, value); } } - private void PointsChanged(PerspexPropertyChangedEventArgs e) + protected override Geometry CreateDefiningGeometry() { - _geometry = null; - InvalidateMeasure(); + return new PolylineGeometry(Points, false); } } } diff --git a/src/Perspex.Controls/Shapes/Rectangle.cs b/src/Perspex.Controls/Shapes/Rectangle.cs index c5fbe07163..0210522472 100644 --- a/src/Perspex.Controls/Shapes/Rectangle.cs +++ b/src/Perspex.Controls/Shapes/Rectangle.cs @@ -7,23 +7,16 @@ namespace Perspex.Controls.Shapes { public class Rectangle : Shape { - private Geometry _geometry; - - private Size _geometrySize; - - public override Geometry DefiningGeometry + static Rectangle() { - get - { - if (_geometry == null || _geometrySize != Bounds.Size) - { - var rect = new Rect(Bounds.Size).Deflate(StrokeThickness); - _geometry = new RectangleGeometry(rect); - _geometrySize = Bounds.Size; - } + AffectsGeometry(BoundsProperty); + AffectsGeometry(StrokeThicknessProperty); + } - return _geometry; - } + protected override Geometry CreateDefiningGeometry() + { + var rect = new Rect(Bounds.Size).Deflate(StrokeThickness); + return new RectangleGeometry(rect); } protected override Size MeasureOverride(Size availableSize) diff --git a/src/Perspex.Controls/Shapes/Shape.cs b/src/Perspex.Controls/Shapes/Shape.cs index bb8b99ae70..b0c3412bdf 100644 --- a/src/Perspex.Controls/Shapes/Shape.cs +++ b/src/Perspex.Controls/Shapes/Shape.cs @@ -26,7 +26,7 @@ namespace Perspex.Controls.Shapes PerspexProperty.Register("StrokeThickness"); private Matrix _transform = Matrix.Identity; - + private Geometry _definingGeometry; private Geometry _renderedGeometry; static Shape() @@ -38,9 +38,17 @@ namespace Perspex.Controls.Shapes AffectsMeasure(StrokeThicknessProperty); } - public abstract Geometry DefiningGeometry + public Geometry DefiningGeometry { - get; + get + { + if (_definingGeometry == null) + { + _definingGeometry = CreateDefiningGeometry(); + } + + return _definingGeometry; + } } public Brush Fill @@ -110,6 +118,28 @@ namespace Perspex.Controls.Shapes } } + /// + /// Marks a property as affecting the shape's geometry. + /// + /// The property. + /// + /// After a call to this method in a control's static constructor, any change to the + /// property will cause to be called on the element. + /// + protected static void AffectsGeometry(PerspexProperty property) + { + property.Changed.Subscribe(AffectsGeometryInvalidate); + } + + protected abstract Geometry CreateDefiningGeometry(); + + protected void InvalidateGeometry() + { + this._renderedGeometry = null; + this._definingGeometry = null; + InvalidateMeasure(); + } + protected override Size MeasureOverride(Size availableSize) { // This should probably use GetRenderBounds(strokeThickness) but then the calculations @@ -195,5 +225,28 @@ namespace Perspex.Controls.Shapes return new Size(shapeSize.Width * sx, shapeSize.Height * sy); } + + private static void AffectsGeometryInvalidate(PerspexPropertyChangedEventArgs e) + { + var control = e.Sender as Shape; + + if (control != null) + { + // If the geometry is invalidated when Bounds changes, only invalidate when the Size + // portion changes. + if (e.Property == BoundsProperty) + { + var oldBounds = (Rect)e.OldValue; + var newBounds = (Rect)e.NewValue; + + if (oldBounds.Size == newBounds.Size) + { + return; + } + } + + control.InvalidateGeometry(); + } + } } }