From 7fe1f7e814499424c67e146f2fc36ca4769e68fa Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sun, 14 Dec 2014 21:33:43 +0100 Subject: [PATCH] Some work on Paths. Make paths with Stretch != None correctly fill the Path control's available size. Added a Path_Tick_Scaled test with a path from MahApps.Metro to test this. --- .../Media/StreamGeometryContextImpl.cs | 5 ++ .../Perspex.Cairo/Media/StreamGeometryImpl.cs | 13 ++++ Perspex.Controls/Shapes/Shape.cs | 45 +++++++++--- Perspex.SceneGraph/Matrix.cs | 10 +++ Perspex.SceneGraph/Media/Geometry.cs | 22 +++++- Perspex.SceneGraph/Media/MatrixTransform.cs | 34 +++++++++ Perspex.SceneGraph/Media/PathMarkupParser.cs | 66 ++++++++++-------- Perspex.SceneGraph/Media/RectangleGeometry.cs | 6 ++ Perspex.SceneGraph/Media/StreamGeometry.cs | 11 +++ .../Media/StreamGeometryContext.cs | 5 ++ Perspex.SceneGraph/Perspex.SceneGraph.csproj | 1 + Perspex.SceneGraph/Platform/IGeometryImpl.cs | 2 + .../Platform/IStreamGeometryContextImpl.cs | 2 + .../Platform/IStreamGeometryImpl.cs | 2 + Perspex.SceneGraph/Point.cs | 10 +++ .../Shapes/Path/Path_Tick_Scaled.expected.png | Bin 0 -> 5069 bytes .../Shapes/PathTests.cs | 24 +++++++ .../Perspex.Direct2D1/Media/GeometryImpl.cs | 44 ++++++++++-- .../Media/StreamGeometryContextImpl.cs | 10 +++ .../Media/StreamGeometryImpl.cs | 33 +++++++-- 20 files changed, 295 insertions(+), 50 deletions(-) create mode 100644 Perspex.SceneGraph/Media/MatrixTransform.cs create mode 100644 TestFiles/Direct2D1/Shapes/Path/Path_Tick_Scaled.expected.png diff --git a/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs b/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs index 864fe7d41f..12e15ad503 100644 --- a/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs +++ b/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs @@ -20,6 +20,11 @@ namespace Perspex.Cairo.Media // TODO: Implement } + public void BezierTo(Point point1, Point point2, Point point3) + { + // TODO: Implement + } + public void LineTo(Point point) { // TODO: Implement diff --git a/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs b/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs index 89aef0d408..70150a17d9 100644 --- a/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs +++ b/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs @@ -23,6 +23,19 @@ namespace Perspex.Cairo.Media get { return new Rect(); } } + // TODO: Implement + public Matrix Transform + { + get { return Matrix.Identity; } + set { } + } + + public IStreamGeometryImpl Clone() + { + // TODO: Implement + return new StreamGeometryImpl(); + } + public Rect GetRenderBounds(double strokeThickness) { // TODO: Implement diff --git a/Perspex.Controls/Shapes/Shape.cs b/Perspex.Controls/Shapes/Shape.cs index 09c37facc0..271e575682 100644 --- a/Perspex.Controls/Shapes/Shape.cs +++ b/Perspex.Controls/Shapes/Shape.cs @@ -24,6 +24,8 @@ namespace Perspex.Controls.Shapes public static readonly PerspexProperty StrokeThicknessProperty = PerspexProperty.Register("StrokeThickness"); + private Matrix transform = Matrix.Identity; + public abstract Geometry DefiningGeometry { get; @@ -37,7 +39,18 @@ namespace Perspex.Controls.Shapes public Geometry RenderedGeometry { - get { return this.DefiningGeometry; } + get + { + var result = this.DefiningGeometry; + + if (result != null) + { + result = result.Clone(); + result.Transform = new MatrixTransform(this.transform); + } + + return result; + } } public Stretch Stretch @@ -60,15 +73,19 @@ namespace Perspex.Controls.Shapes public override void Render(IDrawingContext context) { - if (this.RenderedGeometry != null) + var geometry = this.RenderedGeometry; + + if (geometry != null) { - context.DrawGeometry(this.Fill, new Pen(this.Stroke, this.StrokeThickness), this.RenderedGeometry); + context.DrawGeometry(this.Fill, new Pen(this.Stroke, this.StrokeThickness), geometry); } } protected override Size MeasureOverride(Size availableSize) { - Rect shapeBounds = this.RenderedGeometry.GetRenderBounds(this.StrokeThickness); + Rect shapeBounds = this.DefiningGeometry.GetRenderBounds(this.StrokeThickness); + Size shapeSize = new Size(shapeBounds.Right, shapeBounds.Bottom); + Matrix translate = Matrix.Identity; double width = this.Width; double height = this.Height; double desiredX = availableSize.Width; @@ -76,24 +93,30 @@ namespace Perspex.Controls.Shapes double sx = 0.0; double sy = 0.0; + if (this.Stretch != Stretch.None) + { + shapeSize = shapeBounds.Size; + translate = Matrix.Translation(-(Vector)shapeBounds.Position); + } + if (double.IsInfinity(availableSize.Width)) { - desiredX = shapeBounds.Right; + desiredX = shapeSize.Width; } if (double.IsInfinity(availableSize.Height)) { - desiredY = shapeBounds.Bottom; + desiredY = shapeSize.Height; } if (shapeBounds.Width > 0) { - sx = desiredX / shapeBounds.Right; + sx = desiredX / shapeBounds.Width; } if (shapeBounds.Height > 0) { - sy = desiredY / shapeBounds.Bottom; + sy = desiredY / shapeBounds.Height; } if (double.IsInfinity(availableSize.Width)) @@ -131,8 +154,10 @@ namespace Perspex.Controls.Shapes break; } - double finalX = (width > 0) ? width : shapeBounds.Right * sx; - double finalY = (height > 0) ? height : shapeBounds.Bottom * sy; + this.transform = translate * Matrix.Scaling(sx, sy); + + double finalX = (width > 0) ? width : shapeSize.Width * sx; + double finalY = (height > 0) ? height : shapeSize.Width * sy; return new Size(finalX, finalY); } } diff --git a/Perspex.SceneGraph/Matrix.cs b/Perspex.SceneGraph/Matrix.cs index a262081e02..6d055918fa 100644 --- a/Perspex.SceneGraph/Matrix.cs +++ b/Perspex.SceneGraph/Matrix.cs @@ -106,6 +106,16 @@ namespace Perspex return new Matrix(cos, sin, -sin, cos, 0, 0); } + public static Matrix Scaling(double x, double y) + { + return Scaling(new Vector(x, y)); + } + + public static Matrix Scaling(Vector scale) + { + return new Matrix(scale.X, 0, 0, scale.Y, 0, 0); + } + public static Matrix Translation(Vector v) { return Translation(v.X, v.Y); diff --git a/Perspex.SceneGraph/Media/Geometry.cs b/Perspex.SceneGraph/Media/Geometry.cs index 192842aa28..b0c971576f 100644 --- a/Perspex.SceneGraph/Media/Geometry.cs +++ b/Perspex.SceneGraph/Media/Geometry.cs @@ -6,10 +6,22 @@ namespace Perspex.Media { + using System; using Perspex.Platform; - public abstract class Geometry + public abstract class Geometry : PerspexObject { + public static readonly PerspexProperty TransformProperty = + PerspexProperty.Register("Transform"); + + static Geometry() + { + TransformProperty.Changed.Subscribe(x => + { + ((Geometry)x.Sender).PlatformImpl.Transform = ((ITransform)x.NewValue).Value; + }); + } + public abstract Rect Bounds { get; @@ -21,6 +33,14 @@ namespace Perspex.Media protected set; } + public ITransform Transform + { + get { return this.GetValue(TransformProperty); } + set { this.SetValue(TransformProperty, value); } + } + + public abstract Geometry Clone(); + public Rect GetRenderBounds(double strokeThickness) { return this.PlatformImpl.GetRenderBounds(strokeThickness); diff --git a/Perspex.SceneGraph/Media/MatrixTransform.cs b/Perspex.SceneGraph/Media/MatrixTransform.cs new file mode 100644 index 0000000000..4db9b26ec0 --- /dev/null +++ b/Perspex.SceneGraph/Media/MatrixTransform.cs @@ -0,0 +1,34 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2013 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Media +{ + public class MatrixTransform : Transform + { + public static readonly PerspexProperty MatrixProperty = + PerspexProperty.Register("Matrix", Matrix.Identity); + + public MatrixTransform() + { + } + + public MatrixTransform(Matrix matrix) + { + this.Matrix = matrix; + } + + public Matrix Matrix + { + get { return this.GetValue(MatrixProperty); } + set { this.SetValue(MatrixProperty, value); } + } + + public override Matrix Value + { + get { return this.Matrix; } + } + } +} diff --git a/Perspex.SceneGraph/Media/PathMarkupParser.cs b/Perspex.SceneGraph/Media/PathMarkupParser.cs index 866160732d..3ec2741330 100644 --- a/Perspex.SceneGraph/Media/PathMarkupParser.cs +++ b/Perspex.SceneGraph/Media/PathMarkupParser.cs @@ -85,7 +85,15 @@ namespace Perspex.Media this.context.EndFigure(false); } - point = ReadPoint(reader); + if (command == Command.Move) + { + point = ReadPoint(reader); + } + else + { + point = ReadRelativePoint(reader, point); + } + this.context.BeginFigure(point, true); openFigure = true; break; @@ -100,34 +108,34 @@ namespace Perspex.Media this.context.LineTo(point); break; - ////case Command.HorizontalLine: - //// point.X = ReadDouble(reader); - //// this.context.LineTo(point, true, false); - //// break; - - ////case Command.HorizontalLineRelative: - //// point.X += ReadDouble(reader); - //// this.context.LineTo(point, true, false); - //// break; - - ////case Command.VerticalLine: - //// point.Y = ReadDouble(reader); - //// this.context.LineTo(point, true, false); - //// break; - - ////case Command.VerticalLineRelative: - //// point.Y += ReadDouble(reader); - //// this.context.LineTo(point, true, false); - //// break; - - ////case Command.CubicBezierCurve: - ////{ - //// Point point1 = ReadPoint(reader); - //// Point point2 = ReadPoint(reader); - //// point = ReadPoint(reader); - //// this.context.BezierTo(point1, point2, point, true, false); - //// break; - ////} + case Command.HorizontalLine: + point = point.WithX(ReadDouble(reader)); + this.context.LineTo(point); + break; + + case Command.HorizontalLineRelative: + point = new Point(point.X + ReadDouble(reader), point.Y); + this.context.LineTo(point); + break; + + case Command.VerticalLine: + point = point.WithY(ReadDouble(reader)); + this.context.LineTo(point); + break; + + case Command.VerticalLineRelative: + point = new Point(point.X, point.Y + ReadDouble(reader)); + this.context.LineTo(point); + break; + + case Command.CubicBezierCurve: + { + Point point1 = ReadPoint(reader); + Point point2 = ReadPoint(reader); + point = ReadPoint(reader); + this.context.BezierTo(point1, point2, point); + break; + } case Command.Close: this.context.EndFigure(true); diff --git a/Perspex.SceneGraph/Media/RectangleGeometry.cs b/Perspex.SceneGraph/Media/RectangleGeometry.cs index c47478489e..6d89919e26 100644 --- a/Perspex.SceneGraph/Media/RectangleGeometry.cs +++ b/Perspex.SceneGraph/Media/RectangleGeometry.cs @@ -6,6 +6,7 @@ namespace Perspex.Media { + using System; using Perspex.Platform; using Splat; @@ -32,5 +33,10 @@ namespace Perspex.Media { get { return this.PlatformImpl.Bounds; } } + + public override Geometry Clone() + { + return new RectangleGeometry(this.Bounds); + } } } diff --git a/Perspex.SceneGraph/Media/StreamGeometry.cs b/Perspex.SceneGraph/Media/StreamGeometry.cs index 79f0934ebb..be0abcc07e 100644 --- a/Perspex.SceneGraph/Media/StreamGeometry.cs +++ b/Perspex.SceneGraph/Media/StreamGeometry.cs @@ -6,6 +6,7 @@ namespace Perspex.Media { + using System; using Perspex.Platform; using Splat; @@ -34,9 +35,19 @@ namespace Perspex.Media } } + public override Geometry Clone() + { + return new StreamGeometry(((IStreamGeometryImpl)this.PlatformImpl).Clone()); + } + public StreamGeometryContext Open() { return new StreamGeometryContext(((IStreamGeometryImpl)this.PlatformImpl).Open()); } + + private StreamGeometry(IGeometryImpl impl) + { + this.PlatformImpl = impl; + } } } diff --git a/Perspex.SceneGraph/Media/StreamGeometryContext.cs b/Perspex.SceneGraph/Media/StreamGeometryContext.cs index c7641ee4e9..84677cb066 100644 --- a/Perspex.SceneGraph/Media/StreamGeometryContext.cs +++ b/Perspex.SceneGraph/Media/StreamGeometryContext.cs @@ -23,6 +23,11 @@ namespace Perspex.Media this.impl.BeginFigure(startPoint, isFilled); } + public void BezierTo(Point point1, Point point2, Point point3) + { + this.impl.BezierTo(point1, point2, point3); + } + public void LineTo(Point point) { this.impl.LineTo(point); diff --git a/Perspex.SceneGraph/Perspex.SceneGraph.csproj b/Perspex.SceneGraph/Perspex.SceneGraph.csproj index b070c4bef2..d82ece6791 100644 --- a/Perspex.SceneGraph/Perspex.SceneGraph.csproj +++ b/Perspex.SceneGraph/Perspex.SceneGraph.csproj @@ -59,6 +59,7 @@ + diff --git a/Perspex.SceneGraph/Platform/IGeometryImpl.cs b/Perspex.SceneGraph/Platform/IGeometryImpl.cs index c9aafd92f4..02f4bf8fbd 100644 --- a/Perspex.SceneGraph/Platform/IGeometryImpl.cs +++ b/Perspex.SceneGraph/Platform/IGeometryImpl.cs @@ -10,6 +10,8 @@ namespace Perspex.Platform { Rect Bounds { get; } + Matrix Transform { get; set; } + Rect GetRenderBounds(double strokeThickness); } } diff --git a/Perspex.SceneGraph/Platform/IStreamGeometryContextImpl.cs b/Perspex.SceneGraph/Platform/IStreamGeometryContextImpl.cs index cb58199f72..dc783491e1 100644 --- a/Perspex.SceneGraph/Platform/IStreamGeometryContextImpl.cs +++ b/Perspex.SceneGraph/Platform/IStreamGeometryContextImpl.cs @@ -12,6 +12,8 @@ namespace Perspex.Platform { void BeginFigure(Point startPoint, bool isFilled); + void BezierTo(Point point1, Point point2, Point point3); + void LineTo(Point point); void EndFigure(bool isClosed); diff --git a/Perspex.SceneGraph/Platform/IStreamGeometryImpl.cs b/Perspex.SceneGraph/Platform/IStreamGeometryImpl.cs index 0f7065ff22..8424306615 100644 --- a/Perspex.SceneGraph/Platform/IStreamGeometryImpl.cs +++ b/Perspex.SceneGraph/Platform/IStreamGeometryImpl.cs @@ -8,6 +8,8 @@ namespace Perspex.Platform { public interface IStreamGeometryImpl : IGeometryImpl { + IStreamGeometryImpl Clone(); + IStreamGeometryContextImpl Open(); } } diff --git a/Perspex.SceneGraph/Point.cs b/Perspex.SceneGraph/Point.cs index 08e665d5e7..1a60774440 100644 --- a/Perspex.SceneGraph/Point.cs +++ b/Perspex.SceneGraph/Point.cs @@ -124,5 +124,15 @@ namespace Perspex { return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", this.x, this.y); } + + public Point WithX(double x) + { + return new Point(x, this.y); + } + + public Point WithY(double y) + { + return new Point(this.x, y); + } } } diff --git a/TestFiles/Direct2D1/Shapes/Path/Path_Tick_Scaled.expected.png b/TestFiles/Direct2D1/Shapes/Path/Path_Tick_Scaled.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..8a3ec1f4f12476505ffeeed26a037a524ce9bc06 GIT binary patch literal 5069 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 + this.transformed = new TransformedGeometry( + factory, + this.DefiningGeometry, + value.ToDirect2D()); + } + } + } } public abstract Rect GetRenderBounds(double strokeThickness); diff --git a/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs b/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs index ddd903f1ec..53f98a24da 100644 --- a/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs +++ b/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs @@ -23,6 +23,16 @@ namespace Perspex.Direct2D1.Media this.sink.BeginFigure(startPoint.ToSharpDX(), isFilled ? FigureBegin.Filled : FigureBegin.Hollow); } + public void BezierTo(Point point1, Point point2, Point point3) + { + this.sink.AddBezier(new BezierSegment + { + Point1 = point1.ToSharpDX(), + Point2 = point2.ToSharpDX(), + Point3 = point3.ToSharpDX(), + }); + } + public void LineTo(Point point) { this.sink.AddLine(point.ToSharpDX()); diff --git a/Windows/Perspex.Direct2D1/Media/StreamGeometryImpl.cs b/Windows/Perspex.Direct2D1/Media/StreamGeometryImpl.cs index 7452a74024..41f0a91a68 100644 --- a/Windows/Perspex.Direct2D1/Media/StreamGeometryImpl.cs +++ b/Windows/Perspex.Direct2D1/Media/StreamGeometryImpl.cs @@ -9,33 +9,54 @@ namespace Perspex.Direct2D1.Media using System; using Perspex.Media; using Perspex.Platform; + using SharpDX; using SharpDX.Direct2D1; using Splat; + using D2DGeometry = SharpDX.Direct2D1.Geometry; public class StreamGeometryImpl : GeometryImpl, IStreamGeometryImpl { - private PathGeometry geometry; + private PathGeometry path; public StreamGeometryImpl() { Factory factory = Locator.Current.GetService(); - this.geometry = new PathGeometry(factory); - this.Geometry = this.geometry; + this.path = new PathGeometry(factory); } public override Rect Bounds { - get { return this.geometry.GetBounds().ToPerspex(); } + get { return this.path.GetBounds().ToPerspex(); } + } + + public override D2DGeometry DefiningGeometry + { + get { return this.path; } + } + + public IStreamGeometryImpl Clone() + { + Factory factory = Locator.Current.GetService(); + var result = new PathGeometry(factory); + var sink = result.Open(); + this.path.Stream(sink); + sink.Close(); + return new StreamGeometryImpl(result); } public override Rect GetRenderBounds(double strokeThickness) { - return this.geometry.GetWidenedBounds((float)strokeThickness).ToPerspex(); + return this.path.GetWidenedBounds((float)strokeThickness).ToPerspex(); } public IStreamGeometryContextImpl Open() { - return new StreamGeometryContextImpl(this.geometry.Open()); + return new StreamGeometryContextImpl(this.path.Open()); + } + + protected StreamGeometryImpl(PathGeometry geometry) + { + this.path = geometry; } } }