public static APath ToAPath(this Geometry geometry, Context context) { APath path = new APath(); float density = context.Resources.DisplayMetrics.Density; if (geometry is LineGeometry) { LineGeometry lineGeometry = geometry as LineGeometry; path.MoveTo( density * (float)lineGeometry.StartPoint.X, density * (float)lineGeometry.StartPoint.Y); path.LineTo( density * (float)lineGeometry.EndPoint.X, density * (float)lineGeometry.EndPoint.Y); } else if (geometry is RectangleGeometry) { FormsRectangle rect = (geometry as RectangleGeometry).Rect; path.AddRect( density * (float)rect.Left, density * (float)rect.Top, density * (float)rect.Right, density * (float)rect.Bottom, APath.Direction.Cw); } else if (geometry is EllipseGeometry) { EllipseGeometry ellipseGeometry = geometry as EllipseGeometry; path.AddOval(new RectF( density * (float)(ellipseGeometry.Center.X - ellipseGeometry.RadiusX), density * (float)(ellipseGeometry.Center.Y - ellipseGeometry.RadiusY), density * (float)(ellipseGeometry.Center.X + ellipseGeometry.RadiusX), density * (float)(ellipseGeometry.Center.Y + ellipseGeometry.RadiusY)), APath.Direction.Cw); } else if (geometry is GeometryGroup) { GeometryGroup geometryGroup = geometry as GeometryGroup; path.SetFillType(geometryGroup.FillRule == FillRule.Nonzero ? APath.FillType.Winding : APath.FillType.EvenOdd); foreach (Geometry child in geometryGroup.Children) { APath childPath = child.ToAPath(context); path.AddPath(childPath); } } else if (geometry is PathGeometry) { PathGeometry pathGeometry = geometry as PathGeometry; path.SetFillType(pathGeometry.FillRule == FillRule.Nonzero ? APath.FillType.Winding : APath.FillType.EvenOdd); foreach (PathFigure pathFigure in pathGeometry.Figures) { path.MoveTo( density * (float)pathFigure.StartPoint.X, density * (float)pathFigure.StartPoint.Y); Point lastPoint = pathFigure.StartPoint; foreach (PathSegment pathSegment in pathFigure.Segments) { // LineSegment if (pathSegment is LineSegment) { LineSegment lineSegment = pathSegment as LineSegment; path.LineTo( density * (float)lineSegment.Point.X, density * (float)lineSegment.Point.Y); lastPoint = lineSegment.Point; } // PolylineSegment else if (pathSegment is PolyLineSegment) { PolyLineSegment polylineSegment = pathSegment as PolyLineSegment; PointCollection points = polylineSegment.Points; for (int i = 0; i < points.Count; i++) { path.LineTo( density * (float)points[i].X, density * (float)points[i].Y); } lastPoint = points[points.Count - 1]; } // BezierSegment else if (pathSegment is BezierSegment) { BezierSegment bezierSegment = pathSegment as BezierSegment; path.CubicTo( density * (float)bezierSegment.Point1.X, density * (float)bezierSegment.Point1.Y, density * (float)bezierSegment.Point2.X, density * (float)bezierSegment.Point2.Y, density * (float)bezierSegment.Point3.X, density * (float)bezierSegment.Point3.Y); lastPoint = bezierSegment.Point3; } // PolyBezierSegment else if (pathSegment is PolyBezierSegment) { PolyBezierSegment polyBezierSegment = pathSegment as PolyBezierSegment; PointCollection points = polyBezierSegment.Points; if (points.Count >= 3) { for (int i = 0; i < points.Count; i += 3) { path.CubicTo( density * (float)points[i + 0].X, density * (float)points[i + 0].Y, density * (float)points[i + 1].X, density * (float)points[i + 1].Y, density * (float)points[i + 2].X, density * (float)points[i + 2].Y); } } lastPoint = points[points.Count - 1]; } // QuadraticBezierSegment else if (pathSegment is QuadraticBezierSegment) { QuadraticBezierSegment bezierSegment = pathSegment as QuadraticBezierSegment; path.QuadTo( density * (float)bezierSegment.Point1.X, density * (float)bezierSegment.Point1.Y, density * (float)bezierSegment.Point2.X, density * (float)bezierSegment.Point2.Y); lastPoint = bezierSegment.Point2; } // PolyQuadraticBezierSegment else if (pathSegment is PolyQuadraticBezierSegment) { PolyQuadraticBezierSegment polyBezierSegment = pathSegment as PolyQuadraticBezierSegment; PointCollection points = polyBezierSegment.Points; if (points.Count >= 2) { for (int i = 0; i < points.Count; i += 2) { path.QuadTo( density * (float)points[i + 0].X, density * (float)points[i + 0].Y, density * (float)points[i + 1].X, density * (float)points[i + 1].Y); } } lastPoint = points[points.Count - 1]; } // ArcSegment else if (pathSegment is ArcSegment) { ArcSegment arcSegment = pathSegment as ArcSegment; List <Point> points = new List <Point>(); GeometryHelper.FlattenArc( points, lastPoint, arcSegment.Point, arcSegment.Size.Width, arcSegment.Size.Height, arcSegment.RotationAngle, arcSegment.IsLargeArc, arcSegment.SweepDirection == SweepDirection.CounterClockwise, 1); for (int i = 0; i < points.Count; i++) { path.LineTo( density * (float)points[i].X, density * (float)points[i].Y); } if (points.Count > 0) { lastPoint = points[points.Count - 1]; } } } if (pathFigure.IsClosed) { path.Close(); } } } return(path); }
public static PathData ToCGPath(this Geometry geometry, Transform renderTransform = null) { PathData pathData = new PathData { Data = new CGPath() }; CGAffineTransform transform; if (renderTransform == null) { transform = CGAffineTransform.MakeIdentity(); } else { transform = renderTransform.ToCGAffineTransform(); } if (geometry is LineGeometry) { LineGeometry lineGeometry = geometry as LineGeometry; pathData.Data.MoveToPoint(transform, lineGeometry.StartPoint.ToPointF()); pathData.Data.AddLineToPoint(transform, lineGeometry.EndPoint.ToPointF()); } else if (geometry is RectangleGeometry) { var rect = (geometry as RectangleGeometry).Rect; pathData.Data.AddRect(transform, new CGRect(rect.X, rect.Y, rect.Width, rect.Height)); } else if (geometry is EllipseGeometry) { EllipseGeometry ellipseGeometry = geometry as EllipseGeometry; CGRect rect = new CGRect( ellipseGeometry.Center.X - ellipseGeometry.RadiusX, ellipseGeometry.Center.Y - ellipseGeometry.RadiusY, ellipseGeometry.RadiusX * 2, ellipseGeometry.RadiusY * 2); pathData.Data.AddEllipseInRect(transform, rect); } else if (geometry is GeometryGroup) { GeometryGroup geometryGroup = geometry as GeometryGroup; pathData.IsNonzeroFillRule = geometryGroup.FillRule == FillRule.Nonzero; foreach (Geometry child in geometryGroup.Children) { PathData pathChild = child.ToCGPath(renderTransform); pathData.Data.AddPath(pathChild.Data); } } else if (geometry is PathGeometry) { PathGeometry pathGeometry = geometry as PathGeometry; pathData.IsNonzeroFillRule = pathGeometry.FillRule == FillRule.Nonzero; foreach (PathFigure pathFigure in pathGeometry.Figures) { pathData.Data.MoveToPoint(transform, pathFigure.StartPoint.ToPointF()); Point lastPoint = pathFigure.StartPoint; foreach (PathSegment pathSegment in pathFigure.Segments) { // LineSegment if (pathSegment is LineSegment) { LineSegment lineSegment = pathSegment as LineSegment; pathData.Data.AddLineToPoint(transform, lineSegment.Point.ToPointF()); lastPoint = lineSegment.Point; } // PolyLineSegment else if (pathSegment is PolyLineSegment) { PolyLineSegment polylineSegment = pathSegment as PolyLineSegment; PointCollection points = polylineSegment.Points; for (int i = 0; i < points.Count; i++) { pathData.Data.AddLineToPoint(transform, points[i].ToPointF()); } lastPoint = points[points.Count - 1]; } // BezierSegment if (pathSegment is BezierSegment) { BezierSegment bezierSegment = pathSegment as BezierSegment; pathData.Data.AddCurveToPoint( transform, bezierSegment.Point1.ToPointF(), bezierSegment.Point2.ToPointF(), bezierSegment.Point3.ToPointF()); lastPoint = bezierSegment.Point3; } // PolyBezierSegment else if (pathSegment is PolyBezierSegment) { PolyBezierSegment polyBezierSegment = pathSegment as PolyBezierSegment; PointCollection points = polyBezierSegment.Points; if (points.Count >= 3) { for (int i = 0; i < points.Count; i += 3) { pathData.Data.AddCurveToPoint( transform, points[i].ToPointF(), points[i + 1].ToPointF(), points[i + 2].ToPointF()); } } lastPoint = points[points.Count - 1]; } // QuadraticBezierSegment if (pathSegment is QuadraticBezierSegment) { QuadraticBezierSegment bezierSegment = pathSegment as QuadraticBezierSegment; pathData.Data.AddQuadCurveToPoint( transform, new nfloat(bezierSegment.Point1.X), new nfloat(bezierSegment.Point1.Y), new nfloat(bezierSegment.Point2.X), new nfloat(bezierSegment.Point2.Y)); lastPoint = bezierSegment.Point2; } // PolyQuadraticBezierSegment else if (pathSegment is PolyQuadraticBezierSegment) { PolyQuadraticBezierSegment polyBezierSegment = pathSegment as PolyQuadraticBezierSegment; PointCollection points = polyBezierSegment.Points; if (points.Count >= 2) { for (int i = 0; i < points.Count; i += 2) { pathData.Data.AddQuadCurveToPoint( transform, new nfloat(points[i + 0].X), new nfloat(points[i + 0].Y), new nfloat(points[i + 1].X), new nfloat(points[i + 1].Y)); } } lastPoint = points[points.Count - 1]; } // ArcSegment else if (pathSegment is ArcSegment) { ArcSegment arcSegment = pathSegment as ArcSegment; List <Point> points = new List <Point>(); GeometryHelper.FlattenArc( points, lastPoint, arcSegment.Point, arcSegment.Size.Width, arcSegment.Size.Height, arcSegment.RotationAngle, arcSegment.IsLargeArc, arcSegment.SweepDirection == SweepDirection.CounterClockwise, 1); CGPoint[] cgpoints = new CGPoint[points.Count]; for (int i = 0; i < points.Count; i++) { cgpoints[i] = transform.TransformPoint(points[i].ToPointF()); } pathData.Data.AddLines(cgpoints); lastPoint = points.Count > 0 ? points[points.Count - 1] : Point.Zero; } } if (pathFigure.IsClosed) { pathData.Data.CloseSubpath(); } } } return(pathData); }
IView CreateSampleCursorSelection() { var layout = new Microsoft.Maui.Controls.Layout2.GridLayout() { ColumnSpacing = 5, RowSpacing = 8, BackgroundColor = Colors.LightGreen }; layout.AddRowDefinition(new RowDefinition() { Height = new GridLength(50) }); layout.AddColumnDefinition(new ColumnDefinition() { Width = new GridLength(150) }); layout.AddColumnDefinition(new ColumnDefinition() { Width = new GridLength(80) }); layout.AddColumnDefinition(new ColumnDefinition() { Width = new GridLength(80) }); Entry targetEntry = new() { Placeholder = "Selectable Text" }; Entry forPosition = new() { Keyboard = Keyboard.Numeric, Placeholder = "CursorPos" }; forPosition.TextChanged += (sender, args) => { if (!int.TryParse(args.NewTextValue, out int newPos)) { return; } targetEntry.CursorPosition = newPos; }; Entry forSelectionLen = new() { Keyboard = Keyboard.Numeric, Placeholder = "SelectionLen" }; forSelectionLen.TextChanged += (sender, args) => { if (!int.TryParse(args.NewTextValue, out int newSelectionLen)) { return; } targetEntry.SelectionLength = newSelectionLen; }; layout.Add(targetEntry); layout.Add(forPosition); layout.SetColumn(forPosition, 1); layout.Add(forSelectionLen); layout.SetColumn(forSelectionLen, 2); return(layout); } IView CreateTransformations() { var label = new Button { BackgroundColor = Colors.Red, TextColor = Colors.White, Text = "Transformations", }; var rotationSlider = new Slider { Minimum = -360, Maximum = 360 }; rotationSlider.ValueChanged += (sender, e) => label.Rotation = e.NewValue; var verticalStack = new VerticalStackLayout { rotationSlider, label, }; return(verticalStack); } IView CreateAnimations() { var image = new Image { Source = "dotnet_bot.png", VerticalOptions = LayoutOptions.CenterAndExpand }; var animateButton = new Button { Text = "Animate", VerticalOptions = LayoutOptions.End }; animateButton.Clicked += async(sender, args) => { await image.RotateTo(360, 2000); image.Rotation = 0; }; var verticalStack = new VerticalStackLayout { image, animateButton, }; return(verticalStack); } IView CreateShapes() { var ellipse = new Ellipse { Fill = new SolidColorBrush(Colors.Red), Stroke = new SolidColorBrush(Colors.Blue), StrokeThickness = 4, HeightRequest = 120, WidthRequest = 200 }; var line = new Line { X1 = 0, Y1 = 0, X2 = 80, Y2 = 90, Fill = new SolidColorBrush(Colors.Red), Stroke = new SolidColorBrush(Colors.Green), StrokeThickness = 4, StrokeDashArray = new double[] { 2, 2 }, HeightRequest = 200, WidthRequest = 200 }; Geometry pathData = (Geometry) new PathGeometryConverter().ConvertFromInvariantString("M15.999996,0L31.999999,13.000001 15.999996,26.199999 0,13.000001z"); var path = new Microsoft.Maui.Controls.Shapes.Path { Data = pathData, Fill = new SolidColorBrush(Colors.Pink), Stroke = new SolidColorBrush(Colors.Red), StrokeThickness = 1, HeightRequest = 100, WidthRequest = 100 }; var polyline = new Polyline { Points = new[] { new Point(10, 10), new Point(100, 50), new Point(50, 90) }, Stroke = new SolidColorBrush(Colors.Black), StrokeThickness = 2, StrokeDashArray = new double[] { 1, 1, 1, 1 }, HeightRequest = 100, WidthRequest = 100 }; var polygon = new Polygon { Points = new[] { new Point(10, 10), new Point(100, 50), new Point(50, 90) }, Fill = new SolidColorBrush(Colors.LightBlue), Stroke = new SolidColorBrush(Colors.Black), StrokeThickness = 2, StrokeDashArray = new double[] { 2, 2 }, HeightRequest = 100, WidthRequest = 100 }; var rectangle = new Microsoft.Maui.Controls.Shapes.Rectangle { RadiusX = 12, RadiusY = 6, Fill = new LinearGradientBrush(new GradientStopCollection { new GradientStop(Colors.Green, 0), new GradientStop(Colors.Blue, 1) }, new Point(0, 0), new Point(1, 0)), Stroke = new SolidColorBrush(Colors.Purple), StrokeThickness = 8, StrokeDashArray = new float[] { 2, 2 }, HeightRequest = 120, WidthRequest = 200 }; var verticalStack = new VerticalStackLayout { ellipse, line, path, polyline, polygon, rectangle }; return(verticalStack); } void AddTextResizeDemo(Microsoft.Maui.ILayout layout) { var resizeTestButton = new Button { Text = "Resize Test" }; var resizeTestLabel = new Label { Text = "Short Text", BackgroundColor = Colors.LightBlue, HorizontalOptions = LayoutOptions.Start }; var explicitWidthTestLabel = new Label { Text = "Short Text", BackgroundColor = Colors.LightGreen, WidthRequest = 200 }; var widthAndHeightTestLabel = new Label { Text = "Short Text", BackgroundColor = Colors.MediumSeaGreen, WidthRequest = 150, HeightRequest = 40 }; resizeTestButton.Clicked += (sender, args) => { if (resizeTestLabel.Text == "Short Text") { resizeTestLabel.Text = LoremIpsum; explicitWidthTestLabel.Text = LoremIpsum; widthAndHeightTestLabel.Text = LoremIpsum; } else { resizeTestLabel.Text = "Short Text"; explicitWidthTestLabel.Text = "Short Text"; widthAndHeightTestLabel.Text = "Short Text"; } }; layout.Add(resizeTestButton); layout.Add(resizeTestLabel); layout.Add(widthAndHeightTestLabel); layout.Add(explicitWidthTestLabel); } void SetupVisibilityTest() { var layout = new VerticalStackLayout() { BackgroundColor = Colors.BurlyWood }; var button1 = new Button { Text = "Controls", Margin = new Thickness(0, 40) }; var button2 = new Button { Text = "MAUI" }; var controlsLabel = new Label { Text = "Controls Label" }; controlsLabel.IsVisible = true; var alwaysVisible = new Label { Text = "Always visible" }; var mauiLabel = new VisibilityLabel() { Text = "Core Label" }; button1.Clicked += (sender, args) => { controlsLabel.IsVisible = !controlsLabel.IsVisible; }; button2.Clicked += (sender, args) => { switch ((mauiLabel as IFrameworkElement).Visibility) { case Visibility.Visible: mauiLabel.SetVisibility(Visibility.Hidden); break; case Visibility.Hidden: mauiLabel.SetVisibility(Visibility.Collapsed); break; case Visibility.Collapsed: mauiLabel.SetVisibility(Visibility.Visible); break; } }; layout.Add(button1); layout.Add(button2); layout.Add(controlsLabel); layout.Add(mauiLabel); layout.Add(alwaysVisible); Content = layout; } class TestDrawable : IDrawable {