@ -0,0 +1,37 @@ |
|||||
|
using OmniXaml.TypeConversion; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Globalization; |
||||
|
|
||||
|
namespace Perspex.Markup.Xaml.Converters |
||||
|
{ |
||||
|
public class PointsListTypeConverter : ITypeConverter |
||||
|
{ |
||||
|
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType) |
||||
|
{ |
||||
|
return sourceType == typeof(string); |
||||
|
} |
||||
|
|
||||
|
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value) |
||||
|
{ |
||||
|
string strValue = (string)value; |
||||
|
string[] pointStrs = strValue.Split(new[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); |
||||
|
var result = new List<Point>(pointStrs.Length); |
||||
|
foreach (var pointStr in pointStrs) |
||||
|
{ |
||||
|
result.Add(Point.Parse(pointStr, culture)); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using Perspex.Media; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Perspex.Controls.Shapes |
||||
|
{ |
||||
|
public class Polygon : Shape |
||||
|
{ |
||||
|
public static readonly PerspexProperty<IList<Point>> PointsProperty = |
||||
|
PerspexProperty.Register<Polygon, IList<Point>>("Points"); |
||||
|
|
||||
|
public IList<Point> Points |
||||
|
{ |
||||
|
get { return GetValue(PointsProperty); } |
||||
|
set { SetValue(PointsProperty, value); } |
||||
|
} |
||||
|
|
||||
|
public override Geometry DefiningGeometry => new PolylineGeometry(Points, true); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using Perspex.Media; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Perspex.Controls.Shapes |
||||
|
{ |
||||
|
public class Polyline: Shape |
||||
|
{ |
||||
|
public static readonly PerspexProperty<IList<Point>> PointsProperty = |
||||
|
PerspexProperty.Register<Polyline, IList<Point>>("Points"); |
||||
|
|
||||
|
static Polyline() |
||||
|
{ |
||||
|
StrokeThicknessProperty.OverrideDefaultValue<Polyline>(1); |
||||
|
} |
||||
|
|
||||
|
public IList<Point> Points |
||||
|
{ |
||||
|
get { return GetValue(PointsProperty); } |
||||
|
set { SetValue(PointsProperty, value); } |
||||
|
} |
||||
|
|
||||
|
public override Geometry DefiningGeometry => new PolylineGeometry(Points, false); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,79 @@ |
|||||
|
using Perspex.Platform; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Perspex.Media |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents the geometry of an polyline or polygon.
|
||||
|
/// </summary>
|
||||
|
public class PolylineGeometry : Geometry |
||||
|
{ |
||||
|
private IList<Point> _points; |
||||
|
private bool _isFilled; |
||||
|
|
||||
|
public PolylineGeometry(IList<Point> points, bool isFilled) |
||||
|
{ |
||||
|
_points = points; |
||||
|
_isFilled = isFilled; |
||||
|
IPlatformRenderInterface factory = PerspexLocator.Current.GetService<IPlatformRenderInterface>(); |
||||
|
IStreamGeometryImpl impl = factory.CreateStreamGeometry(); |
||||
|
|
||||
|
using (IStreamGeometryContextImpl context = impl.Open()) |
||||
|
{ |
||||
|
if (points.Count > 0) |
||||
|
{ |
||||
|
context.BeginFigure(points[0], isFilled); |
||||
|
for (int i = 1; i < points.Count; i++) |
||||
|
{ |
||||
|
context.LineTo(points[i]); |
||||
|
} |
||||
|
context.EndFigure(isFilled); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
PlatformImpl = impl; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override Rect Bounds |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
double xMin = double.MaxValue, yMin = double.MaxValue; |
||||
|
double xMax = double.MinValue, yMax = double.MinValue; |
||||
|
foreach (var point in _points) |
||||
|
{ |
||||
|
if (point.X < xMin) |
||||
|
{ |
||||
|
xMin = point.X; |
||||
|
} |
||||
|
else if (point.X > xMax) |
||||
|
{ |
||||
|
xMax = point.X; |
||||
|
} |
||||
|
|
||||
|
if (point.Y < yMin) |
||||
|
{ |
||||
|
yMin = point.Y; |
||||
|
} |
||||
|
else if (point.Y > yMax) |
||||
|
{ |
||||
|
yMax = point.Y; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return new Rect(xMin, yMin, xMax - xMin, yMax - yMin); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override Geometry Clone() |
||||
|
{ |
||||
|
return new PolylineGeometry(new List<Point>(_points), _isFilled); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,76 @@ |
|||||
|
// 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.Controls; |
||||
|
using Perspex.Controls.Shapes; |
||||
|
using Perspex.Media; |
||||
|
using Xunit; |
||||
|
|
||||
|
#if PERSPEX_CAIRO
|
||||
|
namespace Perspex.Cairo.RenderTests.Shapes |
||||
|
#elif PERSPEX_SKIA
|
||||
|
namespace Perspex.Skia.RenderTests |
||||
|
#else
|
||||
|
namespace Perspex.Direct2D1.RenderTests.Shapes |
||||
|
#endif
|
||||
|
{ |
||||
|
public class PolygonTests : TestBase |
||||
|
{ |
||||
|
public PolygonTests() |
||||
|
: base(@"Shapes\Polygon") |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
#if PERSPEX_CAIRO
|
||||
|
[Fact(Skip = "Caused by cairo bug")] |
||||
|
#else
|
||||
|
[Fact] |
||||
|
#endif
|
||||
|
public void Polygon_1px_Stroke() |
||||
|
{ |
||||
|
Decorator target = new Decorator |
||||
|
{ |
||||
|
Padding = new Thickness(8), |
||||
|
Width = 200, |
||||
|
Height = 200, |
||||
|
Child = new Polygon |
||||
|
{ |
||||
|
Stroke = Brushes.DarkBlue, |
||||
|
Stretch = Stretch.Uniform, |
||||
|
Fill = Brushes.Violet, |
||||
|
Points = new [] { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) }, |
||||
|
StrokeThickness = 1 |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
RenderToFile(target); |
||||
|
CompareImages(); |
||||
|
} |
||||
|
|
||||
|
#if PERSPEX_CAIRO
|
||||
|
[Fact(Skip = "Caused by cairo bug")] |
||||
|
#else
|
||||
|
[Fact] |
||||
|
#endif
|
||||
|
public void Polygon_NonUniformFill() |
||||
|
{ |
||||
|
Decorator target = new Decorator |
||||
|
{ |
||||
|
Padding = new Thickness(8), |
||||
|
Width = 400, |
||||
|
Height = 200, |
||||
|
Child = new Polygon |
||||
|
{ |
||||
|
Stroke = Brushes.DarkBlue, |
||||
|
Stretch = Stretch.Fill, |
||||
|
Fill = Brushes.Violet, |
||||
|
Points = new[] { new Point(5, 0), new Point(8, 8), new Point(0, 3), new Point(10, 3), new Point(2, 8) }, |
||||
|
StrokeThickness = 5, |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
RenderToFile(target); |
||||
|
CompareImages(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,83 @@ |
|||||
|
// 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.Controls; |
||||
|
using Perspex.Controls.Shapes; |
||||
|
using Perspex.Media; |
||||
|
using Xunit; |
||||
|
|
||||
|
#if PERSPEX_CAIRO
|
||||
|
namespace Perspex.Cairo.RenderTests.Shapes |
||||
|
#elif PERSPEX_SKIA
|
||||
|
namespace Perspex.Skia.RenderTests |
||||
|
#else
|
||||
|
namespace Perspex.Direct2D1.RenderTests.Shapes |
||||
|
#endif
|
||||
|
{ |
||||
|
public class PolylineTests : TestBase |
||||
|
{ |
||||
|
public PolylineTests() |
||||
|
: base(@"Shapes\Polyline") |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
#if PERSPEX_CAIRO
|
||||
|
[Fact(Skip = "Caused by cairo bug")] |
||||
|
#else
|
||||
|
[Fact] |
||||
|
#endif
|
||||
|
public void Polyline_1px_Stroke() |
||||
|
{ |
||||
|
var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3), |
||||
|
new Point(9, 1), new Point(10, 0), new Point(15, 0) }; |
||||
|
|
||||
|
Decorator target = new Decorator |
||||
|
{ |
||||
|
Padding = new Thickness(8), |
||||
|
Width = 400, |
||||
|
Height = 200, |
||||
|
Child = new Polyline |
||||
|
{ |
||||
|
Stroke = Brushes.Brown, |
||||
|
Points = polylinePoints, |
||||
|
Stretch = Stretch.Uniform, |
||||
|
StrokeThickness = 1 |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
RenderToFile(target); |
||||
|
CompareImages(); |
||||
|
} |
||||
|
|
||||
|
#if PERSPEX_CAIRO
|
||||
|
[Fact(Skip = "Caused by cairo bug")] |
||||
|
#else
|
||||
|
[Fact] |
||||
|
#endif
|
||||
|
public void Polyline_10px_Stroke_PenLineJoin() |
||||
|
{ |
||||
|
var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3), |
||||
|
new Point(9, 1), new Point(10, 0), new Point(15, 0) }; |
||||
|
|
||||
|
Decorator target = new Decorator |
||||
|
{ |
||||
|
Padding = new Thickness(8), |
||||
|
Width = 400, |
||||
|
Height = 200, |
||||
|
Child = new Polyline |
||||
|
{ |
||||
|
Stroke = Brushes.Brown, |
||||
|
Points = polylinePoints, |
||||
|
Stretch = Stretch.Uniform, |
||||
|
StrokeJoin = PenLineJoin.Round, |
||||
|
StrokeStartLineCap = PenLineCap.Round, |
||||
|
StrokeEndLineCap = PenLineCap.Round, |
||||
|
StrokeThickness = 10 |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
RenderToFile(target); |
||||
|
CompareImages(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
Before Width: | Height: | Size: 618 B After Width: | Height: | Size: 624 B |
|
After Width: | Height: | Size: 629 B |
|
After Width: | Height: | Size: 621 B |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 618 B After Width: | Height: | Size: 624 B |
|
After Width: | Height: | Size: 629 B |
|
After Width: | Height: | Size: 621 B |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 618 B After Width: | Height: | Size: 624 B |
|
After Width: | Height: | Size: 629 B |
|
After Width: | Height: | Size: 621 B |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 2.9 KiB |