Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit 97d4f1c

Browse files
knocteaarani
andauthored
[GTK] Some Shapes API support (#14235)
* [GTK] Some Shapes API support (1st part) Supported Shapes: - Ellipse - Rectangle - Path Supported Path Segments: - Arc - Line Supported Brushes: - SolidColorBrush Co-authored-by: Afshin Arani <[email protected]> * [GTK] Shapes API support (2nd part) Newly added shapes: - Polygon - Polyline This commit also completes the support for solid-color stroking. Co-authored-by: Afshin Arani <[email protected]> Co-authored-by: Afshin Arani <[email protected]>
1 parent 000000c commit 97d4f1c

File tree

14 files changed

+650
-0
lines changed

14 files changed

+650
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
using Cairo;
3+
using Xamarin.Forms.Platform.GTK.Extensions;
4+
5+
namespace Xamarin.Forms.Platform.GTK.Controls
6+
{
7+
public class EllipseView : ShapeView
8+
{
9+
protected override void Draw(Gdk.Rectangle area, Context cr)
10+
{
11+
double width = _width;
12+
double height = _height;
13+
14+
cr.Translate(width / 2, height / 2);
15+
cr.Scale(width / 2, height / 2);
16+
cr.Arc(0, 0, 1, 0, 2 * Math.PI);
17+
18+
base.Draw(area, cr);
19+
}
20+
}
21+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Cairo;
4+
using Gdk;
5+
using Xamarin.Forms.Platform.GTK.Extensions;
6+
using Xamarin.Forms.Shapes;
7+
8+
namespace Xamarin.Forms.Platform.GTK.Controls
9+
{
10+
public class PathView : ShapeView
11+
{
12+
private PathGeometry _geometry;
13+
14+
public void UpdateGeometry(PathGeometry geometry)
15+
{
16+
_geometry = geometry;
17+
QueueDraw();
18+
}
19+
20+
protected override void Draw(Gdk.Rectangle area, Context cr)
21+
{
22+
cr.FillRule = _geometry.FillRule == Shapes.FillRule.EvenOdd ? Cairo.FillRule.EvenOdd : Cairo.FillRule.Winding;
23+
24+
foreach (var figure in _geometry.Figures)
25+
{
26+
cr.MoveTo(figure.StartPoint.X, figure.StartPoint.Y);
27+
28+
Point lastPoint = figure.StartPoint;
29+
30+
foreach (var segment in figure.Segments)
31+
{
32+
if (segment is LineSegment lineSegment)
33+
{
34+
cr.LineTo(lineSegment.Point.X, lineSegment.Point.Y);
35+
36+
lastPoint = lineSegment.Point;
37+
}
38+
else if (segment is ArcSegment arcSegment)
39+
{
40+
List<Point> points = new List<Point>();
41+
42+
GeometryHelper.FlattenArc(points,
43+
lastPoint,
44+
arcSegment.Point,
45+
arcSegment.Size.Width,
46+
arcSegment.Size.Height,
47+
arcSegment.RotationAngle,
48+
arcSegment.IsLargeArc,
49+
arcSegment.SweepDirection == SweepDirection.CounterClockwise,
50+
1);
51+
52+
for (int i = 0; i < points.Count; i++)
53+
{
54+
cr.LineTo(points[i].X, points[i].Y);
55+
}
56+
57+
if (points.Count > 0)
58+
lastPoint = points[points.Count - 1];
59+
60+
}
61+
}
62+
63+
if (figure.IsClosed)
64+
cr.ClosePath();
65+
}
66+
67+
base.Draw(area, cr);
68+
}
69+
70+
}
71+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System;
2+
using Cairo;
3+
using Xamarin.Forms.Platform.GTK.Extensions;
4+
using Xamarin.Forms.Shapes;
5+
6+
namespace Xamarin.Forms.Platform.GTK.Controls
7+
{
8+
public class PolygonView : ShapeView
9+
{
10+
PointCollection _points;
11+
bool _fillMode;
12+
13+
protected override void Draw(Gdk.Rectangle area, Context cr)
14+
{
15+
16+
cr.FillRule = _fillMode ? Cairo.FillRule.Winding : Cairo.FillRule.EvenOdd;
17+
18+
if (_points != null && _points.Count > 1)
19+
{
20+
cr.MoveTo(_points[0].X, _points[0].Y);
21+
22+
for (int index = 1; index < _points.Count; index++)
23+
cr.LineTo((float)_points[index].X, (float)_points[index].Y);
24+
25+
cr.ClosePath();
26+
}
27+
28+
base.Draw(area, cr);
29+
}
30+
31+
public void UpdatePoints(PointCollection points)
32+
{
33+
_points = points;
34+
QueueDraw();
35+
}
36+
37+
public void UpdateFillMode(bool fillMode)
38+
{
39+
_fillMode = fillMode;
40+
QueueDraw();
41+
}
42+
}
43+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
using Cairo;
3+
using Xamarin.Forms.Platform.GTK.Extensions;
4+
using Xamarin.Forms.Shapes;
5+
6+
namespace Xamarin.Forms.Platform.GTK.Controls
7+
{
8+
public class PolylineView : ShapeView
9+
{
10+
PointCollection _points;
11+
bool _fillMode;
12+
13+
protected override void Draw(Gdk.Rectangle area, Context cr)
14+
{
15+
cr.FillRule = _fillMode ? Cairo.FillRule.Winding : Cairo.FillRule.EvenOdd;
16+
17+
if (_points != null && _points.Count > 1)
18+
{
19+
cr.MoveTo(_points[0].X, _points[0].Y);
20+
21+
for (int index = 1; index < _points.Count; index++)
22+
cr.LineTo((float)_points[index].X, (float)_points[index].Y);
23+
}
24+
25+
base.Draw(area, cr);
26+
}
27+
28+
public void UpdatePoints(PointCollection points)
29+
{
30+
_points = points;
31+
QueueDraw();
32+
}
33+
34+
public void UpdateFillMode(bool fillMode)
35+
{
36+
_fillMode = fillMode;
37+
QueueDraw();
38+
}
39+
}
40+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
using Cairo;
3+
using Xamarin.Forms.Platform.GTK.Extensions;
4+
5+
namespace Xamarin.Forms.Platform.GTK.Controls
6+
{
7+
public class RectangleView : ShapeView
8+
{
9+
protected override void Draw(Gdk.Rectangle area, Context cr)
10+
{
11+
cr.Rectangle(0, 0, _width, _height);
12+
13+
base.Draw(area, cr);
14+
}
15+
}
16+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using System;
2+
using Cairo;
3+
using Xamarin.Forms.Platform.GTK.Extensions;
4+
5+
namespace Xamarin.Forms.Platform.GTK.Controls
6+
{
7+
public class ShapeView : GtkFormsContainer
8+
{
9+
protected Brush _fill, _stroke;
10+
protected int _height, _width;
11+
double? _strokeThickness;
12+
double? _strokeDashOffset, _strokeMiterLimit;
13+
double[] _strokeDashArray;
14+
LineCap? _strokeCap;
15+
LineJoin? _strokeJoin;
16+
17+
public void UpdateFill(Brush brush)
18+
{
19+
_fill = brush;
20+
QueueDraw();
21+
}
22+
23+
public void UpdateStroke(Brush brush)
24+
{
25+
_stroke = brush;
26+
}
27+
28+
public void UpdateSize(int height, int width)
29+
{
30+
_height = height;
31+
_width = width;
32+
QueueDraw();
33+
}
34+
35+
public void UpdateStrokeThickness(double strokeThickness)
36+
{
37+
_strokeThickness = strokeThickness;
38+
QueueDraw();
39+
}
40+
41+
public void UpdateStrokeDashArray(double[] strokeDashArray)
42+
{
43+
if (_strokeThickness.HasValue && strokeDashArray != null && strokeDashArray.Length > 1)
44+
{
45+
double[] strokeDash = new double[strokeDashArray.Length];
46+
47+
for (int i = 0; i < strokeDashArray.Length; i++)
48+
strokeDash[i] = strokeDashArray[i] * _strokeThickness.Value;
49+
50+
_strokeDashArray = strokeDash;
51+
}
52+
QueueDraw();
53+
}
54+
55+
public void UpdateStrokeDashOffset(double strokeDashOffset)
56+
{
57+
if (_strokeThickness.HasValue)
58+
_strokeDashOffset = strokeDashOffset * _strokeThickness.Value;
59+
QueueDraw();
60+
}
61+
62+
public void UpdateStrokeLineCap(LineCap strokeCap)
63+
{
64+
_strokeCap = strokeCap;
65+
QueueDraw();
66+
}
67+
68+
public void UpdateStrokeLineJoin(LineJoin strokeJoin)
69+
{
70+
_strokeJoin = strokeJoin;
71+
QueueDraw();
72+
}
73+
74+
public void UpdateStrokeMiterLimit(float strokeMiterLimit)
75+
{
76+
_strokeMiterLimit = strokeMiterLimit;
77+
QueueDraw();
78+
}
79+
80+
protected override void Draw(Gdk.Rectangle area, Context cr)
81+
{
82+
if (_fill is SolidColorBrush fillBrush)
83+
{
84+
cr.SetSourceRGBA(fillBrush.Color.R, fillBrush.Color.G, fillBrush.Color.B, fillBrush.Color.A);
85+
cr.FillPreserve();
86+
}
87+
else if (_fill != null)
88+
throw new NotImplementedException("Brushes other than SolidColorBrush are not implemented yet");
89+
90+
if (_stroke is SolidColorBrush strokeBrush)
91+
{
92+
if (_strokeCap.HasValue)
93+
cr.LineCap = _strokeCap.Value;
94+
if (_strokeJoin.HasValue)
95+
cr.LineJoin = _strokeJoin.Value;
96+
if (_strokeThickness.HasValue)
97+
cr.LineWidth = _strokeThickness.Value;
98+
if (_strokeDashOffset.HasValue && _strokeDashArray != null)
99+
cr.SetDash(_strokeDashArray, _strokeDashOffset.Value);
100+
if (_strokeMiterLimit.HasValue)
101+
cr.MiterLimit = _strokeMiterLimit.Value;
102+
103+
cr.SetSourceRGBA(strokeBrush.Color.R, strokeBrush.Color.G, strokeBrush.Color.B, strokeBrush.Color.A);
104+
cr.StrokePreserve();
105+
}
106+
else if (_stroke != null)
107+
throw new NotImplementedException("Brushes other than SolidColorBrush are not implemented yet");
108+
109+
}
110+
}
111+
}

Xamarin.Forms.Platform.GTK/Properties/AssemblyInfo.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,9 @@
4949
[assembly: ExportCell(typeof(Xamarin.Forms.ImageCell), typeof(ImageCellRenderer))]
5050
[assembly: ExportCell(typeof(Xamarin.Forms.SwitchCell), typeof(SwitchCellRenderer))]
5151
[assembly: ExportCell(typeof(Xamarin.Forms.ViewCell), typeof(ViewCellRenderer))]
52+
53+
[assembly: ExportRenderer(typeof(Xamarin.Forms.Shapes.Rectangle), typeof(RectangleRenderer))]
54+
[assembly: ExportRenderer(typeof(Xamarin.Forms.Shapes.Ellipse), typeof(EllipseRenderer))]
55+
[assembly: ExportRenderer(typeof(Xamarin.Forms.Shapes.Path), typeof(PathRenderer))]
56+
[assembly: ExportRenderer(typeof(Xamarin.Forms.Shapes.Polygon), typeof(PolygonRenderer))]
57+
[assembly: ExportRenderer(typeof(Xamarin.Forms.Shapes.Polyline), typeof(PolylineRenderer))]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
using System.ComponentModel;
3+
using Xamarin.Forms.Platform.GTK.Controls;
4+
using Xamarin.Forms.Platform.GTK.Extensions;
5+
using Xamarin.Forms.PlatformConfiguration.GTKSpecific;
6+
using Xamarin.Forms.Shapes;
7+
8+
namespace Xamarin.Forms.Platform.GTK.Renderers
9+
{
10+
public class EllipseRenderer : ShapeRenderer<Ellipse, EllipseView>
11+
{
12+
}
13+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using System.ComponentModel;
3+
using Xamarin.Forms.Platform.GTK.Controls;
4+
using Xamarin.Forms.Platform.GTK.Extensions;
5+
using Xamarin.Forms.PlatformConfiguration.GTKSpecific;
6+
using Xamarin.Forms.Shapes;
7+
8+
namespace Xamarin.Forms.Platform.GTK.Renderers
9+
{
10+
public class PathRenderer : ShapeRenderer<Path, PathView>
11+
{
12+
protected override void OnElementChanged(ElementChangedEventArgs<Path> e)
13+
{
14+
base.OnElementChanged(e);
15+
16+
if (e.NewElement != null)
17+
{
18+
SetData(Element.Data);
19+
}
20+
}
21+
22+
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
23+
{
24+
base.OnElementPropertyChanged(sender, e);
25+
26+
if (e.PropertyName == Shapes.Path.DataProperty.PropertyName)
27+
SetData(Element.Data);
28+
}
29+
30+
void SetData(Geometry data)
31+
{
32+
Control.UpdateGeometry(data as PathGeometry);
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)