From b9aa086f034b1aeea93d7cab7c2f08442acab45e Mon Sep 17 00:00:00 2001 From: Eli Arbel Date: Sun, 20 Aug 2017 16:18:09 +0300 Subject: [PATCH] Adding Drawing classes & render test --- samples/RenderTest/MainWindow.xaml | 1 + samples/RenderTest/Pages/DrawingPage.xaml | 132 ++++++++++++++++++ samples/RenderTest/Pages/DrawingPage.xaml.cs | 18 +++ samples/RenderTest/RenderTest.csproj | 8 ++ src/Avalonia.Controls/DrawingPresenter.cs | 58 ++++++++ src/Avalonia.Controls/Shapes/Shape.cs | 28 ++-- src/Avalonia.Visuals/Media/Drawing.cs | 9 ++ src/Avalonia.Visuals/Media/DrawingGroup.cs | 58 ++++++++ src/Avalonia.Visuals/Media/GeometryDrawing.cs | 43 ++++++ 9 files changed, 343 insertions(+), 12 deletions(-) create mode 100644 samples/RenderTest/Pages/DrawingPage.xaml create mode 100644 samples/RenderTest/Pages/DrawingPage.xaml.cs create mode 100644 src/Avalonia.Controls/DrawingPresenter.cs create mode 100644 src/Avalonia.Visuals/Media/Drawing.cs create mode 100644 src/Avalonia.Visuals/Media/DrawingGroup.cs create mode 100644 src/Avalonia.Visuals/Media/GeometryDrawing.cs diff --git a/samples/RenderTest/MainWindow.xaml b/samples/RenderTest/MainWindow.xaml index 1d3001f1b1..9e9a600161 100644 --- a/samples/RenderTest/MainWindow.xaml +++ b/samples/RenderTest/MainWindow.xaml @@ -27,6 +27,7 @@ + \ No newline at end of file diff --git a/samples/RenderTest/Pages/DrawingPage.xaml b/samples/RenderTest/Pages/DrawingPage.xaml new file mode 100644 index 0000000000..a1a75b1962 --- /dev/null +++ b/samples/RenderTest/Pages/DrawingPage.xaml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/RenderTest/Pages/DrawingPage.xaml.cs b/samples/RenderTest/Pages/DrawingPage.xaml.cs new file mode 100644 index 0000000000..3bf9bd545d --- /dev/null +++ b/samples/RenderTest/Pages/DrawingPage.xaml.cs @@ -0,0 +1,18 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace RenderTest.Pages +{ + public class DrawingPage : UserControl + { + public DrawingPage() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/samples/RenderTest/RenderTest.csproj b/samples/RenderTest/RenderTest.csproj index ea5c0bcc58..b7e64f4dae 100644 --- a/samples/RenderTest/RenderTest.csproj +++ b/samples/RenderTest/RenderTest.csproj @@ -51,6 +51,9 @@ App.xaml + + DrawingPage.xaml + ClippingPage.xaml @@ -178,6 +181,11 @@ Designer + + + Designer + + diff --git a/src/Avalonia.Controls/DrawingPresenter.cs b/src/Avalonia.Controls/DrawingPresenter.cs new file mode 100644 index 0000000000..50a884d3bd --- /dev/null +++ b/src/Avalonia.Controls/DrawingPresenter.cs @@ -0,0 +1,58 @@ +using Avalonia.Controls.Shapes; +using Avalonia.Media; +using Avalonia.Metadata; + +namespace Avalonia.Controls +{ + public class DrawingPresenter : Control + { + public static readonly StyledProperty DrawingProperty = + AvaloniaProperty.Register(nameof(Drawing)); + + [Content] + public Drawing Drawing + { + get => GetValue(DrawingProperty); + set => SetValue(DrawingProperty, value); + } + + public static readonly StyledProperty StretchProperty = + AvaloniaProperty.Register(nameof(Stretch), Stretch.Uniform); + + public Stretch Stretch + { + get => GetValue(StretchProperty); + set => SetValue(StretchProperty, value); + } + + static DrawingPresenter() + { + AffectsMeasure(DrawingProperty); + AffectsRender(DrawingProperty); + } + + private Matrix _transform = Matrix.Identity; + + protected override Size MeasureOverride(Size availableSize) + { + if (Drawing == null) return new Size(); + + var (size, transform) = Shape.CalculateSizeAndTransform(availableSize, Drawing.GetBounds(), Stretch); + + _transform = transform; + + return size; + } + + public override void Render(DrawingContext context) + { + if (Drawing != null) + { + using (context.PushPreTransform(_transform)) + { + Drawing.Draw(context); + } + } + } + } +} \ No newline at end of file diff --git a/src/Avalonia.Controls/Shapes/Shape.cs b/src/Avalonia.Controls/Shapes/Shape.cs index 427749263a..c03f4dc563 100644 --- a/src/Avalonia.Controls/Shapes/Shape.cs +++ b/src/Avalonia.Controls/Shapes/Shape.cs @@ -155,11 +155,21 @@ namespace Avalonia.Controls.Shapes { // This should probably use GetRenderBounds(strokeThickness) but then the calculations // will multiply the stroke thickness as well, which isn't correct. - Rect shapeBounds = DefiningGeometry.Bounds; + var (size, transform) = CalculateSizeAndTransform(availableSize, DefiningGeometry.Bounds, Stretch); + + if (_transform != transform) + { + _transform = transform; + _renderedGeometry = null; + } + + return size; + } + + internal static (Size, Matrix) CalculateSizeAndTransform(Size availableSize, Rect shapeBounds, Stretch Stretch) + { Size shapeSize = new Size(shapeBounds.Right, shapeBounds.Bottom); Matrix translate = Matrix.Identity; - double width = Width; - double height = Height; double desiredX = availableSize.Width; double desiredY = availableSize.Height; double sx = 0.0; @@ -226,15 +236,9 @@ namespace Avalonia.Controls.Shapes break; } - var t = translate * Matrix.CreateScale(sx, sy); - - if (_transform != t) - { - _transform = t; - _renderedGeometry = null; - } - - return new Size(shapeSize.Width * sx, shapeSize.Height * sy); + var transform = translate * Matrix.CreateScale(sx, sy); + var size = new Size(shapeSize.Width * sx, shapeSize.Height * sy); + return (size, transform); } private static void AffectsGeometryInvalidate(AvaloniaPropertyChangedEventArgs e) diff --git a/src/Avalonia.Visuals/Media/Drawing.cs b/src/Avalonia.Visuals/Media/Drawing.cs new file mode 100644 index 0000000000..a60c591edc --- /dev/null +++ b/src/Avalonia.Visuals/Media/Drawing.cs @@ -0,0 +1,9 @@ +namespace Avalonia.Media +{ + public abstract class Drawing : AvaloniaObject + { + public abstract void Draw(DrawingContext context); + + public abstract Rect GetBounds(); + } +} \ No newline at end of file diff --git a/src/Avalonia.Visuals/Media/DrawingGroup.cs b/src/Avalonia.Visuals/Media/DrawingGroup.cs new file mode 100644 index 0000000000..623a4bf640 --- /dev/null +++ b/src/Avalonia.Visuals/Media/DrawingGroup.cs @@ -0,0 +1,58 @@ +using Avalonia.Collections; +using Avalonia.Metadata; + +namespace Avalonia.Media +{ + public class DrawingGroup : Drawing + { + [Content] + public AvaloniaList Children { get; } = new AvaloniaList(); + + public static readonly StyledProperty OpacityProperty = + AvaloniaProperty.Register(nameof(Opacity), 1); + + public double Opacity + { + get => GetValue(OpacityProperty); + set => SetValue(OpacityProperty, value); + } + + public static readonly StyledProperty TransformProperty = + AvaloniaProperty.Register(nameof(Transform)); + + public Transform Transform + { + get => GetValue(TransformProperty); + set => SetValue(TransformProperty, value); + } + + public override void Draw(DrawingContext context) + { + using (context.PushPreTransform(Transform?.Value ?? Matrix.Identity)) + using (context.PushOpacity(Opacity)) + { + foreach (var drawing in Children) + { + drawing.Draw(context); + } + } + } + + public override Rect GetBounds() + { + var rect = new Rect(); + + foreach (var drawing in Children) + { + rect = rect.Union(drawing.GetBounds()); + } + + if (Transform != null) + { + rect = rect.TransformToAABB(Transform.Value); + } + + return rect; + } + } +} \ No newline at end of file diff --git a/src/Avalonia.Visuals/Media/GeometryDrawing.cs b/src/Avalonia.Visuals/Media/GeometryDrawing.cs new file mode 100644 index 0000000000..e67e853a84 --- /dev/null +++ b/src/Avalonia.Visuals/Media/GeometryDrawing.cs @@ -0,0 +1,43 @@ +namespace Avalonia.Media +{ + public class GeometryDrawing : Drawing + { + public static readonly StyledProperty GeometryProperty = + AvaloniaProperty.Register(nameof(Geometry)); + + public Geometry Geometry + { + get => GetValue(GeometryProperty); + set => SetValue(GeometryProperty, value); + } + + public static readonly StyledProperty BrushProperty = + AvaloniaProperty.Register(nameof(Brush), Brushes.Transparent); + + public IBrush Brush + { + get => GetValue(BrushProperty); + set => SetValue(BrushProperty, value); + } + + public static readonly StyledProperty PenProperty = + AvaloniaProperty.Register(nameof(Pen)); + + public Pen Pen + { + get => GetValue(PenProperty); + set => SetValue(PenProperty, value); + } + + public override void Draw(DrawingContext context) + { + context.DrawGeometry(Brush, Pen, Geometry); + } + + public override Rect GetBounds() + { + // adding the Pen's stroke thickness here could yield wrong results due to transforms + return Geometry?.GetRenderBounds(0) ?? new Rect(); + } + } +} \ No newline at end of file