diff --git a/src/Perspex.SceneGraph/Media/ArcSegment.cs b/src/Perspex.SceneGraph/Media/ArcSegment.cs new file mode 100644 index 0000000000..35a1bb87c1 --- /dev/null +++ b/src/Perspex.SceneGraph/Media/ArcSegment.cs @@ -0,0 +1,103 @@ +// 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. + +namespace Perspex.Media +{ + public sealed class ArcSegment : PathSegment + { + /// + /// Defines the property. + /// + public static readonly StyledProperty IsLargeArcProperty + = PerspexProperty.Register(nameof(IsLargeArc), false); + + /// + /// Defines the property. + /// + public static readonly StyledProperty PointProperty + = PerspexProperty.Register(nameof(Point)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty RotationAngleProperty + = PerspexProperty.Register(nameof(RotationAngle), 0); + + /// + /// Defines the property. + /// + public static readonly StyledProperty SizeProperty + = PerspexProperty.Register(nameof(Size)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty SweepDirectionProperty + = PerspexProperty.Register(nameof(SweepDirection), SweepDirection.Clockwise); + + /// + /// Gets or sets a value indicating whether this instance is large arc. + /// + /// + /// true if this instance is large arc; otherwise, false. + /// + public bool IsLargeArc + { + get { return GetValue(IsLargeArcProperty); } + set { SetValue(IsLargeArcProperty, value); } + } + + /// + /// Gets or sets the point. + /// + /// + /// The point. + /// + public Point Point + { + get { return GetValue(PointProperty); } + set { SetValue(PointProperty, value); } + } + + /// + /// Gets or sets the rotation angle. + /// + /// + /// The rotation angle. + /// + public double RotationAngle + { + get { return GetValue(RotationAngleProperty); } + set { SetValue(RotationAngleProperty, value); } + } + + /// + /// Gets or sets the size. + /// + /// + /// The size. + /// + public Size Size + { + get { return GetValue(SizeProperty); } + set { SetValue(SizeProperty, value); } + } + + /// + /// Gets or sets the sweep direction. + /// + /// + /// The sweep direction. + /// + public SweepDirection SweepDirection + { + get { return GetValue(SweepDirectionProperty); } + set { SetValue(SweepDirectionProperty, value); } + } + + protected internal override void ApplyTo(StreamGeometryContext ctx) + { + ctx.ArcTo(Point, Size, RotationAngle, IsLargeArc, SweepDirection); + } + } +} \ No newline at end of file diff --git a/src/Perspex.SceneGraph/Media/BezierSegment .cs b/src/Perspex.SceneGraph/Media/BezierSegment .cs new file mode 100644 index 0000000000..7a7ad9827a --- /dev/null +++ b/src/Perspex.SceneGraph/Media/BezierSegment .cs @@ -0,0 +1,65 @@ +// 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. + +namespace Perspex.Media +{ + public sealed class BezierSegment : PathSegment + { + /// + /// Defines the property. + /// + public static readonly StyledProperty Point1Property + = PerspexProperty.Register(nameof(Point1)); + /// + /// Defines the property. + /// + public static readonly StyledProperty Point2Property + = PerspexProperty.Register(nameof(Point2)); + /// + /// Defines the property. + /// + public static readonly StyledProperty Point3Property + = PerspexProperty.Register(nameof(Point3)); + + /// + /// Gets or sets the point1. + /// + /// + /// The point1. + /// + public Point Point1 + { + get { return GetValue(Point1Property); } + set { SetValue(Point1Property, value); } + } + + /// + /// Gets or sets the point2. + /// + /// + /// The point2. + /// + public Point Point2 + { + get { return GetValue(Point2Property); } + set { SetValue(Point2Property, value); } + } + + /// + /// Gets or sets the point3. + /// + /// + /// The point3. + /// + public Point Point3 + { + get { return GetValue(Point3Property); } + set { SetValue(Point3Property, value); } + } + + protected internal override void ApplyTo(StreamGeometryContext ctx) + { + ctx.CubicBezierTo(Point1, Point2, Point3); + } + } +} \ No newline at end of file diff --git a/src/Perspex.SceneGraph/Media/Geometry.cs b/src/Perspex.SceneGraph/Media/Geometry.cs index 806d5321a5..7e48169efe 100644 --- a/src/Perspex.SceneGraph/Media/Geometry.cs +++ b/src/Perspex.SceneGraph/Media/Geometry.cs @@ -36,7 +36,7 @@ namespace Perspex.Media /// /// Gets the platform-specific implementation of the geometry. /// - public IGeometryImpl PlatformImpl + public virtual IGeometryImpl PlatformImpl { get; protected set; diff --git a/src/Perspex.SceneGraph/Media/LineSegment.cs b/src/Perspex.SceneGraph/Media/LineSegment.cs new file mode 100644 index 0000000000..716697b02c --- /dev/null +++ b/src/Perspex.SceneGraph/Media/LineSegment.cs @@ -0,0 +1,31 @@ +// 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. + +namespace Perspex.Media +{ + public sealed class LineSegment : PathSegment + { + /// + /// Defines the property. + /// + public static readonly StyledProperty PointProperty + = PerspexProperty.Register(nameof(Point)); + + /// + /// Gets or sets the point. + /// + /// + /// The point. + /// + public Point Point + { + get { return GetValue(PointProperty); } + set { SetValue(PointProperty, value); } + } + + protected internal override void ApplyTo(StreamGeometryContext ctx) + { + ctx.LineTo(Point); + } + } +} \ No newline at end of file diff --git a/src/Perspex.SceneGraph/Media/PathFigure.cs b/src/Perspex.SceneGraph/Media/PathFigure.cs new file mode 100644 index 0000000000..8ce54d4bd8 --- /dev/null +++ b/src/Perspex.SceneGraph/Media/PathFigure.cs @@ -0,0 +1,102 @@ +// 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 Perspex.Metadata; + +namespace Perspex.Media +{ + public sealed class PathFigure : PerspexObject + { + /// + /// Defines the property. + /// + public static readonly StyledProperty IsClosedProperty + = PerspexProperty.Register(nameof(IsClosed), true); + /// + /// Defines the property. + /// + public static readonly StyledProperty IsFilledProperty + = PerspexProperty.Register(nameof(IsFilled), true); + /// + /// Defines the property. + /// + public static readonly DirectProperty SegmentsProperty + = PerspexProperty.RegisterDirect(nameof(Segments), f => f.Segments, (f, s) => f.Segments = s); + /// + /// Defines the property. + /// + public static readonly StyledProperty StartPointProperty + = PerspexProperty.Register(nameof(StartPoint)); + + /// + /// Initializes a new instance of the class. + /// + public PathFigure() + { + Segments = new PathSegments(); + } + + /// + /// Gets or sets a value indicating whether this instance is closed. + /// + /// + /// true if this instance is closed; otherwise, false. + /// + public bool IsClosed + { + get { return GetValue(IsClosedProperty); } + set { SetValue(IsClosedProperty, value); } + } + + /// + /// Gets or sets a value indicating whether this instance is filled. + /// + /// + /// true if this instance is filled; otherwise, false. + /// + public bool IsFilled + { + get { return GetValue(IsFilledProperty); } + set { SetValue(IsFilledProperty, value); } + } + + /// + /// Gets or sets the segments. + /// + /// + /// The segments. + /// + [Content] + public PathSegments Segments + { + get { return _segments; } + set { SetAndRaise(SegmentsProperty, ref _segments, value); } + } + + /// + /// Gets or sets the start point. + /// + /// + /// The start point. + /// + public Point StartPoint + { + get { return GetValue(StartPointProperty); } + set { SetValue(StartPointProperty, value); } + } + + internal void ApplyTo(StreamGeometryContext ctx) + { + ctx.BeginFigure(StartPoint, IsFilled); + + foreach (var segment in Segments) + { + segment.ApplyTo(ctx); + } + + ctx.EndFigure(IsClosed); + } + + private PathSegments _segments; + } +} \ No newline at end of file diff --git a/src/Perspex.SceneGraph/Media/PathGeometry.cs b/src/Perspex.SceneGraph/Media/PathGeometry.cs new file mode 100644 index 0000000000..245885d4b0 --- /dev/null +++ b/src/Perspex.SceneGraph/Media/PathGeometry.cs @@ -0,0 +1,123 @@ +// 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 Perspex.Collections; +using Perspex.Metadata; +using Perspex.Platform; +using System; + +namespace Perspex.Media +{ + public class PathGeometry : StreamGeometry + { + /// + /// Defines the property. + /// + public static readonly DirectProperty FiguresProperty = + PerspexProperty.RegisterDirect(nameof(Figures), g => g.Figures, (g, f) => g.Figures = f); + + /// + /// Defines the property. + /// + public static readonly StyledProperty FillRuleProperty = + PerspexProperty.Register(nameof(FillRule)); + + static PathGeometry() + { + FiguresProperty.Changed.Subscribe(onNext: v => + { + (v.Sender as PathGeometry)?.OnFiguresChanged(v.OldValue as PathFigures, v.NewValue as PathFigures); + }); + } + + /// + /// Initializes a new instance of the class. + /// + public PathGeometry() + { + Figures = new PathFigures(); + } + + /// + /// Gets or sets the figures. + /// + /// + /// The figures. + /// + [Content] + public PathFigures Figures + { + get { return _figures; } + set { SetAndRaise(FiguresProperty, ref _figures, value); } + } + + /// + /// Gets or sets the fill rule. + /// + /// + /// The fill rule. + /// + public FillRule FillRule + { + get { return GetValue(FillRuleProperty); } + set { SetValue(FillRuleProperty, value); } + } + + public override IGeometryImpl PlatformImpl + { + get + { + PrepareIfNeeded(); + return base.PlatformImpl; + } + + protected set + { + base.PlatformImpl = value; + } + } + + public override Geometry Clone() + { + PrepareIfNeeded(); + + return base.Clone(); + } + + public void PrepareIfNeeded() + { + if (_isDirty) + { + _isDirty = false; + + using (var ctx = Open()) + { + ctx.SetFillRule(FillRule); + foreach (var f in Figures) + { + f.ApplyTo(ctx); + } + } + } + } + + internal void NotifyChanged() + { + _isDirty = true; + } + + private PathFigures _figures; + private IDisposable _figuresObserver = null; + private IDisposable _figuresPropertiesObserver = null; + private bool _isDirty = true; + + private void OnFiguresChanged(PathFigures oldValue, PathFigures newValue) + { + _figuresObserver?.Dispose(); + _figuresPropertiesObserver?.Dispose(); + + _figuresObserver = newValue?.ForEachItem(f => NotifyChanged(), f => NotifyChanged(), () => NotifyChanged()); + _figuresPropertiesObserver = newValue?.TrackItemPropertyChanged(t => NotifyChanged()); + } + } +} \ No newline at end of file diff --git a/src/Perspex.SceneGraph/Media/PathGeometryCollections.cs b/src/Perspex.SceneGraph/Media/PathGeometryCollections.cs new file mode 100644 index 0000000000..d93cedaede --- /dev/null +++ b/src/Perspex.SceneGraph/Media/PathGeometryCollections.cs @@ -0,0 +1,15 @@ +// 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 Perspex.Collections; + +namespace Perspex.Media +{ + public sealed class PathFigures : PerspexList + { + } + + public sealed class PathSegments : PerspexList + { + } +} \ No newline at end of file diff --git a/src/Perspex.SceneGraph/Media/PathSegment.cs b/src/Perspex.SceneGraph/Media/PathSegment.cs new file mode 100644 index 0000000000..523494644b --- /dev/null +++ b/src/Perspex.SceneGraph/Media/PathSegment.cs @@ -0,0 +1,10 @@ +// 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. + +namespace Perspex.Media +{ + public abstract class PathSegment : PerspexObject + { + protected internal abstract void ApplyTo(StreamGeometryContext ctx); + } +} \ No newline at end of file diff --git a/src/Perspex.SceneGraph/Media/QuadraticBezierSegment .cs b/src/Perspex.SceneGraph/Media/QuadraticBezierSegment .cs new file mode 100644 index 0000000000..f347a8ee26 --- /dev/null +++ b/src/Perspex.SceneGraph/Media/QuadraticBezierSegment .cs @@ -0,0 +1,46 @@ +namespace Perspex.Media +{ + public sealed class QuadraticBezierSegment : PathSegment + { + /// + /// Defines the property. + /// + public static readonly StyledProperty Point1Property + = PerspexProperty.Register(nameof(Point1)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty Point2Property + = PerspexProperty.Register(nameof(Point2)); + + /// + /// Gets or sets the point1. + /// + /// + /// The point1. + /// + public Point Point1 + { + get { return GetValue(Point1Property); } + set { SetValue(Point1Property, value); } + } + + /// + /// Gets or sets the point2. + /// + /// + /// The point2. + /// + public Point Point2 + { + get { return GetValue(Point2Property); } + set { SetValue(Point2Property, value); } + } + + protected internal override void ApplyTo(StreamGeometryContext ctx) + { + ctx.QuadraticBezierTo(Point1, Point2); + } + } +} \ No newline at end of file diff --git a/src/Perspex.SceneGraph/Media/TransformGroup.cs b/src/Perspex.SceneGraph/Media/TransformGroup.cs new file mode 100644 index 0000000000..79694bbfc7 --- /dev/null +++ b/src/Perspex.SceneGraph/Media/TransformGroup.cs @@ -0,0 +1,57 @@ +// 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 Perspex.Collections; +using Perspex.Metadata; + +namespace Perspex.Media +{ + public class TransformGroup : Transform + { + /// + /// Defines the property. + /// + public static readonly PerspexProperty ChildrenProperty = + PerspexProperty.Register(nameof(Children)); + + public TransformGroup() + { + Children = new Transforms(); + } + + /// + /// Gets or sets the children. + /// + /// + /// The children. + /// + [Content] + public Transforms Children + { + get { return GetValue(ChildrenProperty); } + set { SetValue(ChildrenProperty, value); } + } + + /// + /// Gets the tranform's . + /// + public override Matrix Value + { + get + { + Matrix result = Matrix.Identity; + + foreach (var t in Children) + { + result *= t.Value; + } + + return result; + } + } + } + + public sealed class Transforms : PerspexList + { + } +} \ No newline at end of file diff --git a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj index ea84ae710e..9c2867c5e9 100644 --- a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj +++ b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj @@ -61,11 +61,14 @@ + + + @@ -75,9 +78,15 @@ + + + + + +