diff --git a/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs b/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs
index 5fc767ef57..c01d1f1ac3 100644
--- a/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs
+++ b/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs
@@ -2,13 +2,14 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
+using System.Linq;
using System.Reactive.Disposables;
using Perspex.Cairo.Media.Imaging;
using Perspex.Media;
-using IBitmap = Perspex.Media.Imaging.IBitmap;
namespace Perspex.Cairo.Media
{
+ using Perspex.Media.Imaging;
using Cairo = global::Cairo;
///
@@ -77,9 +78,9 @@ namespace Perspex.Cairo.Media
public void DrawLine(Pen pen, Point p1, Point p2)
{
var size = new Rect(p1, p2).Size;
+
+ SetPen(pen, size);
- SetBrush(pen.Brush, size);
- _context.LineWidth = pen.Thickness;
_context.MoveTo(p1.ToCairo());
_context.LineTo(p2.ToCairo());
_context.Stroke();
@@ -139,9 +140,9 @@ namespace Perspex.Cairo.Media
public void DrawText(Brush foreground, Point origin, FormattedText text)
{
var layout = ((FormattedTextImpl)text.PlatformImpl).Layout;
- SetBrush(foreground, new Size(0, 0));
-
_context.MoveTo(origin.X, origin.Y);
+
+ SetBrush(foreground, new Size(0, 0));
Pango.CairoHelper.ShowLayout(_context, layout);
}
@@ -195,7 +196,7 @@ namespace Perspex.Cairo.Media
_context.Transform(matrix.Invert().ToCairo());
});
}
-
+
private void SetBrush(Brush brush, Size destinationSize)
{
var solid = brush as SolidColorBrush;
@@ -225,7 +226,23 @@ namespace Perspex.Cairo.Media
private void SetPen(Pen pen, Size destinationSize)
{
SetBrush(pen.Brush, destinationSize);
+ if (pen.DashStyle != null)
+ {
+ if (pen.DashStyle.Dashes != null && pen.DashStyle.Dashes.Count > 0)
+ {
+ var cray = pen.DashStyle.Dashes.ToArray();
+ _context.SetDash(cray, pen.DashStyle.Offset);
+ }
+ }
+
_context.LineWidth = pen.Thickness;
+ _context.MiterLimit = pen.MiterLimit;
+
+ // Line caps and joins are currently broken on Cairo. I've defaulted them to sensible defaults for now.
+ // Cairo does not have StartLineCap, EndLineCap, and DashCap properties, whereas Direct2D does.
+ // TODO: Figure out a solution for this.
+ _context.LineJoin = Cairo.LineJoin.Miter;
+ _context.LineCap = Cairo.LineCap.Butt;
}
}
}
diff --git a/src/Perspex.Controls/Shapes/Shape.cs b/src/Perspex.Controls/Shapes/Shape.cs
index 0ce5b08096..5f5b989602 100644
--- a/src/Perspex.Controls/Shapes/Shape.cs
+++ b/src/Perspex.Controls/Shapes/Shape.cs
@@ -96,7 +96,7 @@ namespace Perspex.Controls.Shapes
if (geometry != null)
{
- var pen = new Pen(Stroke, StrokeThickness, StrokeDashArray);
+ var pen = new Pen(Stroke, StrokeThickness, new DashStyle(StrokeDashArray));
context.DrawGeometry(Fill, pen, geometry);
}
}
diff --git a/src/Perspex.SceneGraph/Media/DashStyle.cs b/src/Perspex.SceneGraph/Media/DashStyle.cs
new file mode 100644
index 0000000000..8ec4d67e32
--- /dev/null
+++ b/src/Perspex.SceneGraph/Media/DashStyle.cs
@@ -0,0 +1,84 @@
+namespace Perspex.Media
+{
+ using Perspex.Animation;
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ public class DashStyle : Animatable
+ {
+ private static DashStyle dash;
+ public static DashStyle Dash
+ {
+ get
+ {
+ if (dashDotDot == null)
+ {
+ dash = new DashStyle(new double[] { 2, 2 }, 1);
+ }
+
+ return dash;
+ }
+ }
+
+
+
+ private static DashStyle dot;
+ public static DashStyle Dot
+ {
+ get
+ {
+ if (dot == null)
+ {
+ dot = new DashStyle(new double[] { 0, 2 }, 0);
+ }
+
+ return dot;
+ }
+ }
+
+ private static DashStyle dashDot;
+ public static DashStyle DashDot
+ {
+ get
+ {
+ if (dashDot == null)
+ {
+ dashDot = new DashStyle(new double[] { 2, 2, 0, 2 }, 1);
+ }
+
+ return dashDot;
+ }
+ }
+
+ private static DashStyle dashDotDot;
+ public static DashStyle DashDotDot
+ {
+ get
+ {
+ if (dashDotDot == null)
+ {
+ dashDotDot = new DashStyle(new double[] { 2, 2, 0, 2, 0, 2 }, 1);
+ }
+
+ return dashDotDot;
+ }
+ }
+
+
+ public DashStyle(IReadOnlyList dashes = null, double offset = 0.0)
+ {
+ this.Dashes = dashes;
+ this.Offset = offset;
+ }
+
+ ///
+ /// Gets and sets the length of alternating dashes and gaps.
+ ///
+ public IReadOnlyList Dashes { get; }
+
+ public double Offset { get; }
+ }
+}
diff --git a/src/Perspex.SceneGraph/Media/Pen.cs b/src/Perspex.SceneGraph/Media/Pen.cs
index 2d200c8a59..b813392ccd 100644
--- a/src/Perspex.SceneGraph/Media/Pen.cs
+++ b/src/Perspex.SceneGraph/Media/Pen.cs
@@ -15,12 +15,20 @@ namespace Perspex.Media
///
/// The brush used to draw.
/// The stroke thickness.
- /// The length of alternating dashes and gaps.
- public Pen(Brush brush, double thickness, IReadOnlyList dashArray = null)
+ public Pen(
+ Brush brush,
+ double thickness = 1.0,
+ DashStyle dashStyle = null, PenLineCap dashCap = PenLineCap.Flat, PenLineCap startLineCap = PenLineCap.Flat,
+ PenLineCap endLineCap = PenLineCap.Flat, PenLineJoin lineJoin = PenLineJoin.Miter, double miterLimit = 10.0)
{
Brush = brush;
Thickness = thickness;
- DashArray = dashArray;
+ StartLineCap = startLineCap;
+ EndLineCap = endLineCap;
+ LineJoin = lineJoin;
+ MiterLimit = miterLimit;
+ DashStyle = dashStyle;
+ DashCap = dashCap;
}
///
@@ -28,12 +36,20 @@ namespace Perspex.Media
///
/// The stroke color.
/// The stroke thickness.
- /// The length of alternating dashes and gaps.
- public Pen(uint color, double thickness, IReadOnlyList dashArray = null)
+ public Pen(
+ uint color,
+ double thickness = 1.0,
+ DashStyle dashStyle = null, PenLineCap dashCap = PenLineCap.Flat, PenLineCap startLineCap = PenLineCap.Flat,
+ PenLineCap endLineCap = PenLineCap.Flat, PenLineJoin lineJoin = PenLineJoin.Miter, double miterLimit = 10.0)
{
Brush = new SolidColorBrush(color);
Thickness = thickness;
- DashArray = dashArray;
+ StartLineCap = startLineCap;
+ EndLineCap = endLineCap;
+ LineJoin = lineJoin;
+ MiterLimit = miterLimit;
+ DashStyle = dashStyle;
+ DashCap = dashCap;
}
///
@@ -41,14 +57,21 @@ namespace Perspex.Media
///
public Brush Brush { get; }
- ///
- /// Gets the length of alternating dashes and gaps.
- ///
- public IReadOnlyList DashArray { get; }
-
///
/// Gets the stroke thickness.
///
- public double Thickness { get; }
+ public double Thickness { get; } = 1.0;
+
+ public DashStyle DashStyle { get; }
+
+ public PenLineCap DashCap { get; }
+
+ public PenLineCap StartLineCap { get; } = PenLineCap.Flat;
+
+ public PenLineCap EndLineCap { get; } = PenLineCap.Flat;
+
+ public PenLineJoin LineJoin { get; } = PenLineJoin.Miter;
+
+ public double MiterLimit { get; } = 10.0;
}
}
diff --git a/src/Perspex.SceneGraph/Media/PenLineCap.cs b/src/Perspex.SceneGraph/Media/PenLineCap.cs
new file mode 100644
index 0000000000..4e1a360e0d
--- /dev/null
+++ b/src/Perspex.SceneGraph/Media/PenLineCap.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Perspex.Media
+{
+ public enum PenLineCap
+ {
+ Flat,
+ Round,
+ Square,
+ Triangle
+ }
+}
diff --git a/src/Perspex.SceneGraph/Media/PenLineJoin.cs b/src/Perspex.SceneGraph/Media/PenLineJoin.cs
new file mode 100644
index 0000000000..9d135fe63f
--- /dev/null
+++ b/src/Perspex.SceneGraph/Media/PenLineJoin.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Perspex.Media
+{
+ public enum PenLineJoin
+ {
+ Bevel,
+ Miter,
+ Round
+ }
+}
diff --git a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj
index 0f75fdb7e1..8841e9a7de 100644
--- a/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj
+++ b/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj
@@ -63,11 +63,14 @@
+
+
+
diff --git a/src/Windows/Perspex.Direct2D1/PrimitiveExtensions.cs b/src/Windows/Perspex.Direct2D1/PrimitiveExtensions.cs
index 04dd597f38..2364521ed0 100644
--- a/src/Windows/Perspex.Direct2D1/PrimitiveExtensions.cs
+++ b/src/Windows/Perspex.Direct2D1/PrimitiveExtensions.cs
@@ -40,6 +40,29 @@ namespace Perspex.Direct2D1
else
return ExtendMode.Wrap;
}
+
+ public static SharpDX.Direct2D1.LineJoin ToDirect2D(this Perspex.Media.PenLineJoin lineJoin)
+ {
+ if (lineJoin == Perspex.Media.PenLineJoin.Round)
+ return LineJoin.Round;
+ else if (lineJoin == Perspex.Media.PenLineJoin.Miter)
+ return LineJoin.Miter;
+ else
+ return LineJoin.Bevel;
+ }
+
+ public static SharpDX.Direct2D1.CapStyle ToDirect2D(this Perspex.Media.PenLineCap lineCap)
+ {
+ if (lineCap == Perspex.Media.PenLineCap.Flat)
+ return CapStyle.Flat;
+ else if (lineCap == Perspex.Media.PenLineCap.Round)
+ return CapStyle.Round;
+ else if (lineCap == Perspex.Media.PenLineCap.Square)
+ return CapStyle.Square;
+ else
+ return CapStyle.Triangle;
+ }
+
///
/// Converts a pen to a Direct2D stroke style.
///
@@ -48,19 +71,26 @@ namespace Perspex.Direct2D1
/// The Direct2D brush.
public static StrokeStyle ToDirect2DStrokeStyle(this Perspex.Media.Pen pen, RenderTarget target)
{
- if (pen.DashArray != null && pen.DashArray.Count > 0)
+ if (pen.DashStyle != null)
{
- var properties = new StrokeStyleProperties
+ if (pen.DashStyle.Dashes != null && pen.DashStyle.Dashes.Count > 0)
{
- DashStyle = DashStyle.Custom,
- };
+ var properties = new StrokeStyleProperties
+ {
+ DashStyle = DashStyle.Custom,
+ DashOffset = (float)pen.DashStyle.Offset,
+ MiterLimit = (float)pen.MiterLimit,
+ LineJoin = pen.LineJoin.ToDirect2D(),
+ StartCap = pen.StartLineCap.ToDirect2D(),
+ EndCap = pen.EndLineCap.ToDirect2D(),
+ DashCap = pen.DashCap.ToDirect2D()
+ };
- return new StrokeStyle(target.Factory, properties, pen.DashArray.Select(x => (float)x).ToArray());
- }
- else
- {
- return null;
+ return new StrokeStyle(target.Factory, properties, pen.DashStyle?.Dashes.Select(x => (float)x).ToArray());
+ }
}
+
+ return null;
}
///