@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -1,7 +1,13 @@ |
|||
#!/bin/sh |
|||
rm -rf native |
|||
rm -rf native native.zip |
|||
mkdir -p native |
|||
cd native |
|||
if which curl |
|||
then |
|||
curl `cat ../native.url` -o native.zip |
|||
else |
|||
wget `cat ../native.url` -O native.zip |
|||
unzip native.zip |
|||
fi |
|||
|
|||
unzip native.zip |
|||
chmod -R +x . |
|||
|
|||
@ -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 |