#nullable enable using System; using System.Collections.Generic; using System.Linq; using Unity.CodeEditor.Rendering; using UnityEngine; namespace Unity.CodeEditor.Platform { internal sealed class PathFigures : List { /// /// Parses the specified path data to a . /// /// The s. /// internal static PathFigures Parse(string pathData) { /* var pathGeometry = new PathGeometry(); using (var context = new PathGeometryContext(pathGeometry)) using (var parser = new PathMarkupParser(context)) { parser.Parse(pathData); } return pathGeometry.Figures!; */ return new PathFigures(); } } internal sealed class PathFigure { internal event EventHandler? SegmentsInvalidated; private PathSegments? _segments; private IDisposable? _segmentsDisposable; private IDisposable? _segmentsPropertiesDisposable; /// /// Initializes a new instance of the class. /// internal PathFigure() { Segments = new PathSegments(); } static PathFigure() { } private void OnSegmentsChanged() { _segmentsDisposable?.Dispose(); _segmentsPropertiesDisposable?.Dispose(); _segments?.ForEach(_ => InvalidateSegments()); //_segmentsPropertiesDisposable = _segments?.TrackItemPropertyChanged(_ => InvalidateSegments()); } private void InvalidateSegments() { SegmentsInvalidated?.Invoke(this, EventArgs.Empty); } /// /// Gets or sets a value indicating whether this instance is closed. /// /// /// true if this instance is closed; otherwise, false. /// internal bool IsClosed { get; set; } /// /// Gets or sets a value indicating whether this instance is filled. /// /// /// true if this instance is filled; otherwise, false. /// internal bool IsFilled { get; set; } /// /// Gets or sets the segments. /// /// /// The segments. /// internal PathSegments? Segments { get { return _segments; } set { _segments = value; OnSegmentsChanged(); } } /// /// Gets or sets the start point. /// /// /// The start point. /// internal Vector2 StartPoint { get; set; } public override string ToString() => FormattableString.Invariant($"M {StartPoint} {string.Join(" ", _segments ?? Enumerable.Empty())}{(IsClosed ? "Z" : "")}"); internal void ApplyTo(StreamGeometryContext ctx) { ctx.BeginFigure(StartPoint, IsFilled); if (Segments != null) { foreach (var segment in Segments) { segment.ApplyTo(ctx); } } ctx.EndFigure(IsClosed); } } internal sealed class PathSegments : List { } internal abstract class PathSegment { internal abstract void ApplyTo(StreamGeometryContext ctx); } internal sealed class LineSegment : PathSegment { /// /// Gets or sets the point. /// /// /// The point. /// internal Vector2 Point { get; set; } internal override void ApplyTo(StreamGeometryContext ctx) { ctx.LineTo(Point); } public override string ToString() => FormattableString.Invariant($"L {Point}"); } internal sealed class ArcSegment : PathSegment { /// /// Gets or sets a value indicating whether this instance is large arc. /// /// /// true if this instance is large arc; otherwise, false. /// internal bool IsLargeArc { get; set; } /// /// Gets or sets the point. /// /// /// The point. /// internal Vector2 Point { get; set; } /// /// Gets or sets the rotation angle. /// /// /// The rotation angle. /// internal double RotationAngle { get; set; } /// /// Gets or sets the size. /// /// /// The size. /// internal Vector2 Size { get; set; } /// /// Gets or sets the sweep direction. /// /// /// The sweep direction. /// internal BackgroundGeometryBuilder.SweepDirection SweepDirection { get; set; } internal override void ApplyTo(StreamGeometryContext ctx) { ctx.ArcTo(Point, Size, RotationAngle, IsLargeArc, SweepDirection); } public override string ToString() => FormattableString.Invariant($"A {Size} {RotationAngle} {(IsLargeArc ? 1 : 0)} {(int)SweepDirection} {Point}"); } /// /// Describes a geometry using drawing commands. /// /// /// This class is used to define the geometry of a . An instance /// of is obtained by calling /// . /// internal class StreamGeometryContext //: IGeometryContext { private readonly IStreamGeometryContextImpl _impl; private Vector2 _currentPoint; /// /// Initializes a new instance of the class. /// /// The platform-specific implementation. internal StreamGeometryContext(IStreamGeometryContextImpl impl) { _impl = impl; } /// /// Sets path's winding rule (default is EvenOdd). You should call this method before any calls to BeginFigure. If you wonder why, ask Direct2D guys about their design decisions. /// /// internal void SetFillRule(FillRule fillRule) { _impl.SetFillRule(fillRule); } /// /// Draws an arc to the specified point. /// /// The destination point. /// The radii of an oval whose perimeter is used to draw the angle. /// The rotation angle (in radians) of the oval that specifies the curve. /// true to draw the arc greater than 180 degrees; otherwise, false. /// /// A value that indicates whether the arc is drawn in the Clockwise or Counterclockwise direction. /// internal void ArcTo(Vector2 point, Vector2 size, double rotationAngle, bool isLargeArc, BackgroundGeometryBuilder.SweepDirection sweepDirection) { _impl.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection); _currentPoint = point; } /// /// Draws an arc to the specified point using polylines, quadratic or cubic Bezier curves /// Significantly more precise when drawing elliptic arcs with extreme width:height ratios. /// /// The destination point. /// The radii of an oval whose perimeter is used to draw the angle. /// The rotation angle (in radians) of the oval that specifies the curve. /// true to draw the arc greater than 180 degrees; otherwise, false. /// /// A value that indicates whether the arc is drawn in the Clockwise or Counterclockwise direction. /// internal void PreciseArcTo(Vector2 point, Vector2 size, double rotationAngle, bool isLargeArc, BackgroundGeometryBuilder.SweepDirection sweepDirection) { //PreciseEllipticArcHelper.ArcTo(this, _currentPoint, point, size, rotationAngle, isLargeArc, sweepDirection); } /// /// Begins a new figure. /// /// The starting point for the figure. /// Whether the figure is filled. internal void BeginFigure(Vector2 startPoint, bool isFilled) { _impl.BeginFigure(startPoint, isFilled); _currentPoint = startPoint; } /// /// Draws a Bezier curve to the specified point. /// /// The first control point used to specify the shape of the curve. /// The second control point used to specify the shape of the curve. /// The destination point for the end of the curve. internal void CubicBezierTo(Vector2 point1, Vector2 point2, Vector2 point3) { _impl.CubicBezierTo(point1, point2, point3); _currentPoint = point3; } /// /// Draws a quadratic Bezier curve to the specified point /// /// The control point used to specify the shape of the curve. /// The destination point for the end of the curve. internal void QuadraticBezierTo(Vector2 control, Vector2 endPoint) { _impl.QuadraticBezierTo(control, endPoint); _currentPoint = endPoint; } /// /// Draws a line to the specified point. /// /// The destination point. internal void LineTo(Vector2 point) { _impl.LineTo(point); _currentPoint = point; } /// /// Ends the figure started by . /// /// Whether the figure is closed. internal void EndFigure(bool isClosed) { _impl.EndFigure(isClosed); } /// /// Finishes the drawing session. /// internal void Dispose() { _impl.Dispose(); } } internal interface IStreamGeometryContextImpl : IGeometryContext { } internal interface IGeometryContext : IDisposable { /// /// Draws an arc to the specified point. /// /// The destination point. /// The radii of an oval whose perimeter is used to draw the angle. /// The rotation angle (in radians) of the oval that specifies the curve. /// true to draw the arc greater than 180 degrees; otherwise, false. /// /// A value that indicates whether the arc is drawn in the Clockwise or Counterclockwise direction. /// void ArcTo(Vector2 point, Vector2 size, double rotationAngle, bool isLargeArc, BackgroundGeometryBuilder.SweepDirection sweepDirection); /// /// Begins a new figure. /// /// The starting point for the figure. /// Whether the figure is filled. void BeginFigure(Vector2 startPoint, bool isFilled = true); /// /// Draws a Bezier curve to the specified point. /// /// The first control point used to specify the shape of the curve. /// The second control point used to specify the shape of the curve. /// The destination point for the end of the curve. void CubicBezierTo(Vector2 point1, Vector2 point2, Vector2 point3); /// /// Draws a quadratic Bezier curve to the specified point /// /// Control point /// DestinationPoint void QuadraticBezierTo(Vector2 control, Vector2 endPoint); /// /// Draws a line to the specified point. /// /// The destination point. void LineTo(Vector2 point); /// /// Ends the figure started by . /// /// Whether the figure is closed. void EndFigure(bool isClosed); /// /// Sets the fill rule. /// /// The fill rule. void SetFillRule(FillRule fillRule); } internal enum FillRule { EvenOdd, NonZero } }