Browse Source

Separate CheckerBackground control

Krzysztof Krysiński 1 year ago
parent
commit
c804e2d9ba

+ 19 - 13
src/PixiEditor.AvaloniaUI/Views/Main/ViewportControls/Viewport.axaml

@@ -117,6 +117,10 @@
                 </Border>
             </overlays:TogglableFlyout.Child>
         </overlays:TogglableFlyout>
+        <visuals:CheckerBackground CheckerImagePath="/Images/CheckerTile.png"
+                                   RenderTransform="{Binding #zoombox.CanvasTransform}" RenderTransformOrigin="0,0"
+                                   PixelWidth="{Binding Document.Width}" PixelHeight="{Binding Document.Height}"
+                                   Scale="{Binding #zoombox.Scale}"/>
         <visuals:Scene
             Focusable="False" Name="scene"
             RenderTransformOrigin="0,0"
@@ -132,7 +136,6 @@
             FlipY="{Binding FlipY, ElementName=zoombox, Mode=OneWay}"
             FadeOut="{Binding Source={viewModels:ToolVM ColorPickerToolViewModel}, Path=PickOnlyFromReferenceLayer, Mode=OneWay}"
             ui1:RenderOptionsBindable.BitmapInterpolationMode="{Binding Scale, Converter={converters:ScaleToBitmapScalingModeConverter}, ElementName=zoombox}"
-            CheckerImagePath="/Images/CheckerTile.png"
             FlowDirection="LeftToRight">
         </visuals:Scene>
         <zoombox:Zoombox
@@ -158,18 +161,6 @@
                     RenderOptions.BitmapInterpolationMode="None">
                     <Grid>
                         <Panel Width="{Binding Document.Width}" Height="{Binding Document.Height}" />
-                        <Grid IsHitTestVisible="False"
-                              ShowGridLines="True" Width="{Binding Document.Width}" Height="{Binding Document.Height}"
-                              Panel.ZIndex="10"
-                              IsVisible="{Binding GridLinesVisible, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=viewportControls:Viewport}}">
-                            <Grid.Resources>
-                                <converters:ThresholdVisibilityConverter Threshold="10"
-                                                                         x:Key="ThresholdVisibilityConverter" />
-                            </Grid.Resources>
-                            <visuals:GridLines Scale="{Binding Zoombox.Scale}"
-                                               IsVisible="{Binding Zoombox.Scale, Converter={StaticResource ThresholdVisibilityConverter}}"
-                                               Rows="{Binding Document.Width}" Columns="{Binding Document.Height}" />
-                        </Grid>
                         <Rectangle Stroke="{DynamicResource ThemeBackgroundBrush1}" Opacity=".8" ZIndex="2"
                                    IsVisible="{Binding Document.ReferenceLayerViewModel.IsVisibleBindable}">
                             <Rectangle.StrokeThickness>
@@ -202,6 +193,21 @@
                                         ReferenceLayerScale="{Binding ReferenceLayerScale}"
                                         FadeOut="{Binding Source={viewModels:ToolVM ColorPickerToolViewModel}, Path=!PickFromReferenceLayer, Mode=OneWay}"
                                         RenderTransformOrigin="0, 0" RenderTransform="{Binding #zoombox.CanvasTransform}"/>
+
+        <Grid IsHitTestVisible="False" RenderTransformOrigin="0, 0" RenderTransform="{Binding #zoombox.CanvasTransform}"
+              ShowGridLines="True"
+              Panel.ZIndex="10"
+              IsVisible="{Binding GridLinesVisible, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=viewportControls:Viewport}}">
+            <Grid.Resources>
+                <converters:ThresholdVisibilityConverter Threshold="10"
+                                                         x:Key="ThresholdVisibilityConverter" />
+            </Grid.Resources>
+            <visuals:GridLines Scale="{Binding #zoombox.Scale}"
+                               PixelWidth="{Binding Document.Width}" PixelHeight="{Binding Document.Height}"
+                               IsVisible="{Binding #zoombox.Scale, Converter={StaticResource ThresholdVisibilityConverter}}"
+                               Rows="{Binding Document.Width}" Columns="{Binding Document.Height}" />
+        </Grid>
+
         <Grid ZIndex="5" DataContext="{Binding ElementName=vpUc}"
               RenderTransformOrigin="0, 0" RenderTransform="{Binding #zoombox.CanvasTransform}">
             <symmetryOverlay:SymmetryOverlay

+ 1 - 1
src/PixiEditor.AvaloniaUI/Views/Main/ViewportControls/Viewport.axaml.cs

@@ -306,7 +306,7 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
         viewportGrid.AddHandler(PointerPressedEvent, Image_MouseDown, RoutingStrategies.Bubble);
     }
 
-    public Panel? MainImage => zoombox != null ? (Panel?)((Grid?)((Border?)zoombox.AdditionalContent)?.Child)?.Children[1] : null;
+    public Panel? MainImage => zoombox != null ? (Panel?)((Grid?)((Border?)zoombox.AdditionalContent)?.Child)?.Children[0] : null;
     public Scene Scene => scene;
     public Grid BackgroundGrid => viewportGrid;
 

+ 102 - 0
src/PixiEditor.AvaloniaUI/Views/Visuals/CheckerBackground.cs

@@ -0,0 +1,102 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Avalonia.Threading;
+using PixiEditor.AvaloniaUI.Helpers.Converters;
+using Bitmap = Avalonia.Media.Imaging.Bitmap;
+
+namespace PixiEditor.AvaloniaUI.Views.Visuals;
+
+public class CheckerBackground : Control
+{
+    public static readonly StyledProperty<double> ScaleProperty = AvaloniaProperty.Register<CheckerBackground, double>(
+        nameof(Scale));
+
+    public static readonly StyledProperty<string> CheckerImagePathProperty = AvaloniaProperty.Register<Scene, string>(
+        nameof(CheckerImagePath));
+
+    public static readonly StyledProperty<int> PixelWidthProperty = AvaloniaProperty.Register<CheckerBackground, int>(
+        nameof(PixelWidth));
+
+    public static readonly StyledProperty<float> PixelHeightProperty = AvaloniaProperty.Register<CheckerBackground, float>(
+        nameof(PixelHeight));
+
+    public float PixelHeight
+    {
+        get => GetValue(PixelHeightProperty);
+        set => SetValue(PixelHeightProperty, value);
+    }
+
+    public int PixelWidth
+    {
+        get => GetValue(PixelWidthProperty);
+        set => SetValue(PixelWidthProperty, value);
+    }
+
+    public string CheckerImagePath
+    {
+        get => GetValue(CheckerImagePathProperty);
+        set => SetValue(CheckerImagePathProperty, value);
+    }
+
+    public double Scale
+    {
+        get => GetValue(ScaleProperty);
+        set => SetValue(ScaleProperty, value);
+    }
+
+    public Bitmap? CheckerBitmap { get; set; }
+
+    private Brush? _checkerBrush;
+
+
+    static CheckerBackground()
+    {
+        CheckerImagePathProperty.Changed.AddClassHandler<CheckerBackground>(CheckerImagePathChanged);
+    }
+
+    public CheckerBackground()
+    {
+    }
+
+    private static void CheckerImagePathChanged(CheckerBackground control, AvaloniaPropertyChangedEventArgs arg2)
+    {
+        if (arg2.NewValue is string path)
+        {
+            control.CheckerBitmap = ImagePathToBitmapConverter.LoadBitmapFromRelativePath(path);
+            control.CreateCheckerPen();
+        }
+        else
+        {
+            control.CheckerBitmap = null;
+        }
+    }
+
+    private void CreateCheckerPen()
+    {
+
+    }
+
+
+    public override void Render(DrawingContext context)
+    {
+        base.Render(context);
+        if (CheckerBitmap != null)
+        {
+            float checkerScale = (float)ZoomToViewportConverter.ZoomToViewport(16, Scale);
+            _checkerBrush = new ImageBrush(CheckerBitmap)
+            {
+                TileMode = TileMode.Tile,
+                DestinationRect = new RelativeRect(0, 0, checkerScale, checkerScale, RelativeUnit.Absolute),
+            };
+
+            _checkerBrush.Transform = new ScaleTransform(0.5f, 0.5f);
+        }
+        context.PushRenderOptions(new RenderOptions() { BitmapInterpolationMode = BitmapInterpolationMode.None });
+        if (_checkerBrush != null)
+        {
+            context.DrawRectangle(_checkerBrush, null, new Rect(new Size(PixelWidth, PixelHeight)));
+        }
+    }
+}

+ 20 - 2
src/PixiEditor.AvaloniaUI/Views/Visuals/GridLines.cs

@@ -17,6 +17,24 @@ public class GridLines : Control
     public static readonly StyledProperty<int> ColumnsProperty = AvaloniaProperty.Register<GridLines, int>(
         nameof(Columns));
 
+    public static readonly StyledProperty<int> PixelWidthProperty = AvaloniaProperty.Register<GridLines, int>(
+        nameof(PixelWidth));
+
+    public static readonly StyledProperty<int> PixelHeightProperty = AvaloniaProperty.Register<GridLines, int>(
+        nameof(PixelHeight));
+
+    public int PixelHeight
+    {
+        get => GetValue(PixelHeightProperty);
+        set => SetValue(PixelHeightProperty, value);
+    }
+
+    public int PixelWidth
+    {
+        get => GetValue(PixelWidthProperty);
+        set => SetValue(PixelWidthProperty, value);
+    }
+
     public int Columns
     {
         get => GetValue(ColumnsProperty);
@@ -49,8 +67,8 @@ public class GridLines : Control
         // Draw lines in vertical and horizontal directions, size should be relative to the scale
 
         base.Render(context);
-        double width = Bounds.Width;
-        double height = Bounds.Height;
+        double width = PixelWidth;
+        double height = PixelHeight;
 
         double columnWidth = width / Columns;
         double rowHeight = height / Rows;

+ 2 - 42
src/PixiEditor.AvaloniaUI/Views/Visuals/Scene.cs

@@ -42,15 +42,6 @@ internal class Scene : Control
     public static readonly StyledProperty<bool> FadeOutProperty = AvaloniaProperty.Register<Scene, bool>(
         nameof(FadeOut), false);
 
-    public static readonly StyledProperty<string> CheckerImagePathProperty = AvaloniaProperty.Register<Scene, string>(
-        nameof(CheckerImagePath));
-
-    public string CheckerImagePath
-    {
-        get => GetValue(CheckerImagePathProperty);
-        set => SetValue(CheckerImagePathProperty, value);
-    }
-
     public bool FadeOut
     {
         get => GetValue(FadeOutProperty);
@@ -99,8 +90,6 @@ internal class Scene : Control
         set { SetValue(FlipYProperty, value); }
     }
 
-    private Bitmap? _checkerBitmap;
-
     static Scene()
     {
         AffectsRender<Scene>(BoundsProperty, WidthProperty, HeightProperty, ScaleProperty, AngleProperty, FlipXProperty,
@@ -109,7 +98,6 @@ internal class Scene : Control
         FlipXProperty.Changed.AddClassHandler<Scene>(RequestRendering);
         FlipYProperty.Changed.AddClassHandler<Scene>(RequestRendering);
         FadeOutProperty.Changed.AddClassHandler<Scene>(FadeOutChanged);
-        CheckerImagePathProperty.Changed.AddClassHandler<Scene>(CheckerImagePathChanged);
     }
 
     public Scene()
@@ -126,7 +114,7 @@ internal class Scene : Control
         if (Surface == null || Document == null) return;
 
         var operation = new DrawSceneOperation(Surface, Document, ContentPosition, Scale, Angle, FlipX, FlipY, Bounds,
-            Opacity, _checkerBitmap);
+            Opacity);
 
         context.Custom(operation);
     }
@@ -145,18 +133,6 @@ internal class Scene : Control
     {
         scene.Opacity = arg2.NewValue is true ? 0 : 1;
     }
-
-    private static void CheckerImagePathChanged(Scene scene, AvaloniaPropertyChangedEventArgs arg2)
-    {
-        if (arg2.NewValue is string path)
-        {
-            scene._checkerBitmap = ImagePathToBitmapConverter.LoadDrawingApiBitmapFromRelativePath(path);
-        }
-        else
-        {
-            scene._checkerBitmap = null;
-        }
-    }
 }
 
 internal class DrawSceneOperation : SkiaDrawOperation
@@ -169,13 +145,12 @@ internal class DrawSceneOperation : SkiaDrawOperation
     public bool FlipX { get; set; }
     public bool FlipY { get; set; }
 
-    public Bitmap? CheckerBitmap { get; set; }
 
     private SKPaint _paint = new SKPaint();
     private SKPaint _checkerPaint;
 
     public DrawSceneOperation(Surface surface, DocumentViewModel document, VecI contentPosition, double scale,
-        double angle, bool flipX, bool flipY, Rect bounds, double opacity, Bitmap bitmap) : base(bounds)
+        double angle, bool flipX, bool flipY, Rect bounds, double opacity) : base(bounds)
     {
         Surface = surface;
         Document = document;
@@ -184,17 +159,7 @@ internal class DrawSceneOperation : SkiaDrawOperation
         Angle = angle;
         FlipX = flipX;
         FlipY = flipY;
-        CheckerBitmap = bitmap;
         _paint.Color = _paint.Color.WithAlpha((byte)(opacity * 255));
-        if (CheckerBitmap != null)
-        {
-            float checkerScale = (float)ZoomToViewportConverter.ZoomToViewport(16, CalculateFinalScale()) * 0.25f;
-            _checkerPaint = new SKPaint()
-            {
-                Shader = SKShader.CreateBitmap((SKBitmap)CheckerBitmap.Native, SKShaderTileMode.Repeat,
-                    SKShaderTileMode.Repeat, SKMatrix.CreateScale(checkerScale, checkerScale)),
-            };
-        }
     }
 
     public override void Render(ISkiaSharpApiLease lease)
@@ -232,11 +197,6 @@ internal class DrawSceneOperation : SkiaDrawOperation
         canvas.Scale(FlipX ? -1 : 1, FlipY ? -1 : 1, ContentPosition.X, ContentPosition.Y);
         canvas.Translate(ContentPosition.X, ContentPosition.Y);
 
-        if (CheckerBitmap != null)
-        {
-            canvas.DrawRect(surfaceRectToRender.ToSkRect(), _checkerPaint);
-        }
-
         using Image snapshot = Surface.DrawingSurface.Snapshot(surfaceRectToRender);
         canvas.DrawImage((SKImage)snapshot.Native, surfaceRectToRender.X, surfaceRectToRender.Y, _paint);