diff --git a/Uno.Gallery/Helpers/Canvas/SampleSKCanvasElement.cs b/Uno.Gallery/Helpers/Canvas/SampleSKCanvasElement.cs new file mode 100644 index 000000000..7c6c0ca59 --- /dev/null +++ b/Uno.Gallery/Helpers/Canvas/SampleSKCanvasElement.cs @@ -0,0 +1,134 @@ +#if HAS_UNO_SKIA +using SkiaSharp; +using Uno.WinUI.Graphics2DSK; +using Windows.Foundation; + +namespace Uno.Gallery.Helpers.Canvas; + +public class SampleSKCanvasElement : SKCanvasElement +{ + public static int SampleCount => 3; + + public static DependencyProperty SampleProperty { get; } = DependencyProperty.Register( + nameof(Sample), + typeof(int), + typeof(SampleSKCanvasElement), + new PropertyMetadata(0, (o, args) => ((SampleSKCanvasElement)o).SampleChanged((int)args.NewValue))); + + public int Sample + { + get => (int)GetValue(SampleProperty); + set => SetValue(SampleProperty, value); + } + + private void SampleChanged(int newIndex) + { + Sample = Math.Min(Math.Max(0, newIndex), SampleCount - 1); + Invalidate(); + } + + protected override void RenderOverride(SKCanvas canvas, Size area) + { + var minDim = Math.Min(area.Width, area.Height); + // draw horizontally centered + var x = (area.Width - minDim) / 2; + var y = (area.Height - minDim) / 2; + canvas.Translate((float)x, (float)y); + // rescale to fit the given area, assuming each drawing is 260x260 + canvas.Scale((float)(minDim / 260), (float)(minDim / 260)); + + switch (Sample) + { + case 0: + SkiaDrawing0(canvas); + break; + case 1: + SkiaDrawing1(canvas); + break; + case 2: + SkiaDrawing2(canvas); + break; + } + } + + // https://fiddle.skia.org/c/@shapes + private void SkiaDrawing0(SKCanvas canvas) + { + var paint = new SKPaint(); + paint.Style = SKPaintStyle.Fill; + paint.IsAntialias = true; + paint.StrokeWidth = 4; + paint.Color = new SKColor(0xff4285F4); + + var rect = SKRect.Create(10, 10, 100, 160); + canvas.DrawRect(rect, paint); + + var oval = new SKPath(); + oval.AddRoundRect(rect, 20, 20); + oval.Offset(new SKPoint(40, 80)); + paint.Color = new SKColor(0xffDB4437); + canvas.DrawPath(oval, paint); + + paint.Color = new SKColor(0xff0F9D58); + canvas.DrawCircle(180, 50, 25, paint); + + rect.Offset(80, 50); + paint.Color = new SKColor(0xffF4B400); + paint.Style = SKPaintStyle.Stroke; + canvas.DrawRoundRect(rect, 10, 10, paint); + } + + // https://fiddle.skia.org/c/@bezier_curves + private void SkiaDrawing1(SKCanvas canvas) + { + var paint = new SKPaint(); + paint.Style = SKPaintStyle.Stroke; + paint.StrokeWidth = 8; + paint.Color = new SKColor(0xff4285F4); + paint.IsAntialias = true; + paint.StrokeCap = SKStrokeCap.Round; + + var path = new SKPath(); + path.MoveTo(10, 10); + path.QuadTo(256, 64, 128, 128); + path.QuadTo(10, 192, 250, 250); + canvas.DrawPath(path, paint); + } + + // https://fiddle.skia.org/c/@shader + private void SkiaDrawing2(SKCanvas canvas) + { + var paint = new SKPaint(); + using var pathEffect = SKPathEffect.CreateDiscrete(10.0f, 4.0f); + paint.PathEffect = pathEffect; + SKPoint[] points = + { + new SKPoint(0.0f, 0.0f), + new SKPoint(256.0f, 256.0f) + }; + SKColor[] colors = + { + new SKColor(66, 133, 244), + new SKColor(15, 157, 88) + }; + paint.Shader = SKShader.CreateLinearGradient(points[0], points[1], colors, SKShaderTileMode.Clamp); + paint.IsAntialias = true; + var path = Star(); + canvas.DrawPath(path, paint); + + SKPath Star() + { + const float R = 60.0f, C = 128.0f; + var path = new SKPath(); + path.MoveTo(C + R, C); + for (var i = 1; i < 15; ++i) + { + var a = 0.44879895f * i; + var r = R + R * (i % 2); + path.LineTo((float)(C + r * Math.Cos(a)), (float)(C + r * Math.Sin(a))); + } + return path; + } + } +} +#endif diff --git a/Uno.Gallery/Views/SamplePages/SKCanvasElementPage.xaml b/Uno.Gallery/Views/SamplePages/SKCanvasElementPage.xaml new file mode 100644 index 000000000..24351da9a --- /dev/null +++ b/Uno.Gallery/Views/SamplePages/SKCanvasElementPage.xaml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Uno.Gallery/Views/SamplePages/SKCanvasElementPage.xaml.cs b/Uno.Gallery/Views/SamplePages/SKCanvasElementPage.xaml.cs new file mode 100644 index 000000000..7aa35d04b --- /dev/null +++ b/Uno.Gallery/Views/SamplePages/SKCanvasElementPage.xaml.cs @@ -0,0 +1,53 @@ +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +using Microsoft.UI.Xaml.Data; +using Microsoft.UI.Xaml.Input; +using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Navigation; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; +#if HAS_UNO_SKIA +using Uno.Gallery.Helpers.Canvas; +#endif + +namespace Uno.Gallery.Views.SamplePages; + +#if HAS_UNO_SKIA +[SamplePage(SampleCategory.UIComponents, "SKCanvasElement", Description = "Represents a 2D graphics canvas.", DocumentationLink = "https://platform.uno/docs/articles/controls/SKCanvasElement.html")] +#endif +public sealed partial class SKCanvasElementPage : Page +{ +#if HAS_UNO_SKIA + public int MaxSampleIndex => SampleSKCanvasElement.SampleCount - 1; + + private SampleSKCanvasElement _canvasElement; +#endif + + public SKCanvasElementPage() + { + this.InitializeComponent(); + + this.Loaded += SKCanvasElementPage_Loaded; + } + + private void SKCanvasElementPage_Loaded(object sender, RoutedEventArgs e) + { +#if HAS_UNO_SKIA + var container = (Grid)FindName("SKContainer"); + container.Children.Add(_canvasElement = new SampleSKCanvasElement()); +#endif + } + + private void NextSample_Click(object sender, RoutedEventArgs e) + { +#if HAS_UNO_SKIA + _canvasElement.Sample = (_canvasElement.Sample + 1) % SampleSKCanvasElement.SampleCount; +#endif + } +}