Jelajahi Sumber

Adding Drawing classes & render test

Eli Arbel 8 tahun lalu
induk
melakukan
b9aa086f03

+ 1 - 0
samples/RenderTest/MainWindow.xaml

@@ -27,6 +27,7 @@
       </TabControl.Transition>
       <TabItem Header="Animations"><pages:AnimationsPage/></TabItem>
       <TabItem Header="Clipping"><pages:ClippingPage/></TabItem>
+      <TabItem Header="Drawing"><pages:DrawingPage/></TabItem>
     </TabControl>
   </DockPanel>
 </Window>

+ 132 - 0
samples/RenderTest/Pages/DrawingPage.xaml

@@ -0,0 +1,132 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+    <UserControl.Styles>
+        <Style>
+            <Style.Resources>
+                <DrawingGroup x:Key="Bulb">
+                    <DrawingGroup.Transform>
+                        <MatrixTransform Matrix="1,0,0,1,0,-1028.4" />
+                    </DrawingGroup.Transform>
+                    <DrawingGroup>
+                        <DrawingGroup.Transform>
+                            <MatrixTransform Matrix="1,0,0,1.25,-10,1031.4" />
+                        </DrawingGroup.Transform>
+                        <GeometryDrawing Brush="#FF7F8C8D"
+                                         Geometry="F1 M24,14 A2,2,0,1,1,20,14 A2,2,0,1,1,24,14 z" />
+                    </DrawingGroup>
+                    <GeometryDrawing Brush="#FFF39C12"
+                                     Geometry="F1 M12,1030.4 C8.134,1030.4 5,1033.6 5,1037.6 5,1040.7 8.125,1043.5 9,1045.4 9.875,1047.2 9,1050.4 9,1050.4 L12,1049.9 15,1050.4 C15,1050.4 14.125,1047.2 15,1045.4 15.875,1043.5 19,1040.7 19,1037.6 19,1033.6 15.866,1030.4 12,1030.4 z" />
+                    <GeometryDrawing Brush="#FFF1C40F"
+                                     Geometry="F1 M12,1030.4 C15.866,1030.4 19,1033.6 19,1037.6 19,1040.7 15.875,1043.5 15,1045.4 14.125,1047.2 15,1050.4 15,1050.4 L12,1049.9 12,1030.4 z" />
+                    <GeometryDrawing Brush="#FFE67E22"
+                                     Geometry="F1 M9,1036.4 L8,1037.4 12,1049.4 16,1037.4 15,1036.4 14,1037.4 13,1036.4 12,1037.4 11,1036.4 10,1037.4 9,1036.4 z M9,1037.4 L10,1038.4 10.5,1037.9 11,1037.4 11.5,1037.9 12,1038.4 12.5,1037.9 13,1037.4 13.5,1037.9 14,1038.4 15,1037.4 15.438,1037.8 12,1048.1 8.5625,1037.8 9,1037.4 z" />
+                    <DrawingGroup>
+                        <DrawingGroup.Transform>
+                            <MatrixTransform Matrix="1,0,0,1,9,1045.4" />
+                        </DrawingGroup.Transform>
+                        <GeometryDrawing Brush="#FFBDC3C7">
+                            <GeometryDrawing.Geometry>
+                                <RectangleGeometry Rect="0,0,6,5" />
+                            </GeometryDrawing.Geometry>
+                        </GeometryDrawing>
+                    </DrawingGroup>
+                    <GeometryDrawing Brush="#FF95A5A6"
+                                     Geometry="F1 M9,1045.4 L9,1050.4 12,1050.4 12,1049.4 15,1049.4 15,1048.4 12,1048.4 12,1047.4 15,1047.4 15,1046.4 12,1046.4 12,1045.4 9,1045.4 z" />
+                    <GeometryDrawing Brush="#FF7F8C8D"
+                                     Geometry="F1 M9,1046.4 L9,1047.4 12,1047.4 12,1046.4 9,1046.4 z M9,1048.4 L9,1049.4 12,1049.4 12,1048.4 9,1048.4 z" />
+                </DrawingGroup>
+            </Style.Resources>
+        </Style>
+    </UserControl.Styles>
+    <Grid RowDefinitions="Auto,Auto,Auto"
+          ColumnDefinitions="Auto,Auto,Auto,Auto">
+        <TextBlock Text="None"
+                   Margin="3" />
+        <Border Grid.Column="0"
+                Grid.Row="1"
+                VerticalAlignment="Top"
+                HorizontalAlignment="Left"
+                BorderThickness="1"
+                BorderBrush="Gray"
+                Margin="5">
+            <DrawingPresenter Drawing="{StyleResource Bulb}" />
+        </Border>
+        <TextBlock Text="Fill"
+                   Margin="3"
+                   Grid.Column="1" />
+        <Border Grid.Column="1"
+                Grid.Row="1"
+                VerticalAlignment="Top"
+                HorizontalAlignment="Left"
+                BorderThickness="1"
+                BorderBrush="Gray"
+                Margin="5">
+            <DrawingPresenter Drawing="{StyleResource Bulb}"
+                              Width="100"
+                              Height="50"
+                              Strech="Fill" />
+        </Border>
+        <TextBlock Text="Uniform"
+                   Margin="3"
+                   Grid.Column="2" />
+        <Border Grid.Column="2"
+                Grid.Row="1"
+                VerticalAlignment="Top"
+                HorizontalAlignment="Left"
+                BorderThickness="1"
+                BorderBrush="Gray"
+                Margin="5">
+            <DrawingPresenter Drawing="{StyleResource Bulb}"
+                              Width="100"
+                              Height="50"
+                              Strech="Uniform" />
+        </Border>
+        <TextBlock Text="UniformToFill"
+                   Margin="3"
+                   Grid.Column="3" />
+        <Border Grid.Column="3"
+                Grid.Row="1"
+                VerticalAlignment="Top"
+                HorizontalAlignment="Left"
+                BorderThickness="1"
+                BorderBrush="Gray"
+                Margin="5">
+            <DrawingPresenter Drawing="{StyleResource Bulb}"
+                              Width="100"
+                              Height="50"
+                              Strech="UniformToFill" />
+        </Border>
+
+        <!-- For comparison -->
+        
+        <Ellipse Grid.Row="2"
+                 Grid.Column="0"
+                 Width="100"
+                 Height="50"
+                 Stretch="None"
+                 Fill="Blue"
+                 Margin="5"/>
+        <Ellipse Grid.Row="2"
+                 Grid.Column="1"
+                 Width="100"
+                 Height="50"
+                 Stretch="Fill"
+                 Fill="Blue"
+                 Margin="5" />
+        <Ellipse Grid.Row="2"
+                 Grid.Column="2"
+                 Width="100"
+                 Height="50"
+                 Stretch="Uniform"
+                 Fill="Blue"
+                 Margin="5" />
+        <Ellipse Grid.Row="2"
+                 Grid.Column="3"
+                 Width="100"
+                 Height="50"
+                 Stretch="UniformToFill"
+                 Fill="Blue"
+                 Margin="5" />
+        
+    </Grid>
+</UserControl>

+ 18 - 0
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);
+        }
+    }
+}

+ 8 - 0
samples/RenderTest/RenderTest.csproj

@@ -51,6 +51,9 @@
     <Compile Include="App.xaml.cs">
       <DependentUpon>App.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Pages\DrawingPage.xaml.cs">
+      <DependentUpon>DrawingPage.xaml</DependentUpon>
+    </Compile>
     <Compile Include="Pages\ClippingPage.xaml.cs">
       <DependentUpon>ClippingPage.xaml</DependentUpon>
     </Compile>
@@ -178,6 +181,11 @@
       <SubType>Designer</SubType>
     </EmbeddedResource>
   </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Pages\DrawingPage.xaml">
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="..\..\build\Serilog.props" />
   <Import Project="..\..\build\Serilog.Sinks.Trace.props" />

+ 58 - 0
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<Drawing> DrawingProperty =
+            AvaloniaProperty.Register<DrawingPresenter, Drawing>(nameof(Drawing));
+
+        [Content]
+        public Drawing Drawing
+        {
+            get => GetValue(DrawingProperty);
+            set => SetValue(DrawingProperty, value);
+        }
+
+        public static readonly StyledProperty<Stretch> StretchProperty =
+            AvaloniaProperty.Register<DrawingPresenter, Stretch>(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);
+                }
+            }
+        }
+    }
+}

+ 16 - 12
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)

+ 9 - 0
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();
+    }
+}

+ 58 - 0
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<Drawing> Children { get; } = new AvaloniaList<Drawing>();
+
+        public static readonly StyledProperty<double> OpacityProperty =
+            AvaloniaProperty.Register<DrawingGroup, double>(nameof(Opacity), 1);
+
+        public double Opacity
+        {
+            get => GetValue(OpacityProperty);
+            set => SetValue(OpacityProperty, value);
+        }
+
+        public static readonly StyledProperty<Transform> TransformProperty =
+            AvaloniaProperty.Register<DrawingGroup, Transform>(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;
+        }
+    }
+}

+ 43 - 0
src/Avalonia.Visuals/Media/GeometryDrawing.cs

@@ -0,0 +1,43 @@
+namespace Avalonia.Media
+{
+    public class GeometryDrawing : Drawing
+    {
+        public static readonly StyledProperty<Geometry> GeometryProperty =
+            AvaloniaProperty.Register<GeometryDrawing, Geometry>(nameof(Geometry));
+
+        public Geometry Geometry
+        {
+            get => GetValue(GeometryProperty);
+            set => SetValue(GeometryProperty, value);
+        }
+
+        public static readonly StyledProperty<IBrush> BrushProperty =
+            AvaloniaProperty.Register<GeometryDrawing, IBrush>(nameof(Brush), Brushes.Transparent);
+
+        public IBrush Brush
+        {
+            get => GetValue(BrushProperty);
+            set => SetValue(BrushProperty, value);
+        }
+
+        public static readonly StyledProperty<Pen> PenProperty =
+            AvaloniaProperty.Register<GeometryDrawing, Pen>(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();
+        }
+    }
+}