Browse Source

BrushOverlay

Krzysztof Krysiński 1 year ago
parent
commit
49ab5886f8

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

@@ -118,15 +118,10 @@
                 </Border>
                 </Border>
             </overlays:TogglableFlyout.Child>
             </overlays:TogglableFlyout.Child>
         </overlays:TogglableFlyout>
         </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
         <visuals:Scene
             Focusable="False" Name="scene"
             Focusable="False" Name="scene"
             RenderTransformOrigin="0,0"
             RenderTransformOrigin="0,0"
             ZIndex="1"
             ZIndex="1"
-            IsHitTestVisible="False"
             Width="{Binding RealDimensions.X, ElementName=vpUc}"
             Width="{Binding RealDimensions.X, ElementName=vpUc}"
             Height="{Binding RealDimensions.Y, ElementName=vpUc}"
             Height="{Binding RealDimensions.Y, ElementName=vpUc}"
             Surface="{Binding TargetBitmap, ElementName=vpUc}"
             Surface="{Binding TargetBitmap, ElementName=vpUc}"
@@ -197,20 +192,21 @@
                                         FadeOut="{Binding Source={viewModels:ToolVM ColorPickerToolViewModel}, Path=!PickFromReferenceLayer, Mode=OneWay}"
                                         FadeOut="{Binding Source={viewModels:ToolVM ColorPickerToolViewModel}, Path=!PickFromReferenceLayer, Mode=OneWay}"
                                         RenderTransformOrigin="0, 0" RenderTransform="{Binding #zoombox.CanvasTransform}"/>
                                         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>-->
-
+        <!--Brush shape overlay is rendered separately, so it doesn't trigger rerender each mouse movement to scene-->
+        <!--I didn't measure it, but I thought that could impact performance-->
+        <brushShapeOverlay:BrushShapeOverlay
+            DataContext="{Binding ElementName=vpUc}"
+            RenderTransformOrigin="0, 0" RenderTransform="{Binding #zoombox.CanvasTransform}"
+            Name="brushShapeOverlay"
+            Focusable="False" ZIndex="6"
+            IsHitTestVisible="False"
+            IsVisible="{Binding !Document.TransformViewModel.TransformActive}"
+            ZoomScale="{Binding #zoombox.Scale}"
+            MouseEventSource="{Binding #vpUc.BackgroundGrid, Mode=OneTime}"
+            MouseReference="{Binding #vpUc.MainImage, Mode=OneTime}"
+            BrushSize="{Binding ToolsSubViewModel.ActiveBasicToolbar.ToolSize, Source={viewModels:MainVM}}"
+            BrushShape="{Binding ToolsSubViewModel.ActiveTool.BrushShape, Source={viewModels:MainVM}, FallbackValue={x:Static brushShapeOverlay:BrushShape.Hidden}}"
+            FlowDirection="LeftToRight" />
         <!--<Grid ZIndex="5" DataContext="{Binding ElementName=vpUc}"
         <!--<Grid ZIndex="5" DataContext="{Binding ElementName=vpUc}"
               RenderTransformOrigin="0, 0" RenderTransform="{Binding #zoombox.CanvasTransform}">
               RenderTransformOrigin="0, 0" RenderTransform="{Binding #zoombox.CanvasTransform}">
             <symmetryOverlay:SymmetryOverlay
             <symmetryOverlay:SymmetryOverlay

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

@@ -15,8 +15,12 @@ using PixiEditor.AvaloniaUI.Helpers.UI;
 using PixiEditor.AvaloniaUI.Models.Controllers.InputDevice;
 using PixiEditor.AvaloniaUI.Models.Controllers.InputDevice;
 using PixiEditor.AvaloniaUI.Models.DocumentModels;
 using PixiEditor.AvaloniaUI.Models.DocumentModels;
 using PixiEditor.AvaloniaUI.Models.Position;
 using PixiEditor.AvaloniaUI.Models.Position;
+using PixiEditor.AvaloniaUI.ViewModels;
 using PixiEditor.AvaloniaUI.ViewModels.Document;
 using PixiEditor.AvaloniaUI.ViewModels.Document;
+using PixiEditor.AvaloniaUI.ViewModels.Tools.ToolSettings.Toolbars;
 using PixiEditor.AvaloniaUI.Views.Overlays;
 using PixiEditor.AvaloniaUI.Views.Overlays;
+using PixiEditor.AvaloniaUI.Views.Overlays.BrushShapeOverlay;
+using PixiEditor.AvaloniaUI.Views.Overlays.SymmetryOverlay;
 using PixiEditor.AvaloniaUI.Views.Visuals;
 using PixiEditor.AvaloniaUI.Views.Visuals;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Core.Surface;
@@ -288,8 +292,11 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
     public Guid GuidValue { get; } = Guid.NewGuid();
     public Guid GuidValue { get; } = Guid.NewGuid();
 
 
     private MouseUpdateController? mouseUpdateController;
     private MouseUpdateController? mouseUpdateController;
+
     private GridLines _gridLinesOverlay;
     private GridLines _gridLinesOverlay;
 
 
+    private SymmetryOverlay _symmetryOverlay;
+
     static Viewport()
     static Viewport()
     {
     {
         DocumentProperty.Changed.Subscribe(OnDocumentChange);
         DocumentProperty.Changed.Subscribe(OnDocumentChange);
@@ -302,7 +309,7 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
     {
     {
         InitializeComponent();
         InitializeComponent();
 
 
-        _gridLinesOverlay = new GridLines();
+        InitBuiltInOverlays();
         MainImage!.Loaded += OnImageLoaded;
         MainImage!.Loaded += OnImageLoaded;
         MainImage.SizeChanged += OnMainImageSizeChanged;
         MainImage.SizeChanged += OnMainImageSizeChanged;
         Loaded += OnLoad;
         Loaded += OnLoad;
@@ -313,6 +320,12 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
         viewportGrid.AddHandler(PointerPressedEvent, Image_MouseDown, RoutingStrategies.Bubble);
         viewportGrid.AddHandler(PointerPressedEvent, Image_MouseDown, RoutingStrategies.Bubble);
     }
     }
 
 
+    private void InitBuiltInOverlays()
+    {
+        _gridLinesOverlay = new GridLines();
+        _symmetryOverlay = new SymmetryOverlay();
+    }
+
     public Panel? MainImage => zoombox != null ? (Panel?)((Grid?)((Border?)zoombox.AdditionalContent)?.Child)?.Children[0] : null;
     public Panel? MainImage => zoombox != null ? (Panel?)((Grid?)((Border?)zoombox.AdditionalContent)?.Child)?.Children[0] : null;
     public Scene Scene => scene;
     public Scene Scene => scene;
     public Grid BackgroundGrid => viewportGrid;
     public Grid BackgroundGrid => viewportGrid;
@@ -338,9 +351,9 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
 
 
     private void InitializeOverlays()
     private void InitializeOverlays()
     {
     {
-        /*brushShapeOverlay.MouseEventSource = BackgroundGrid;
+        brushShapeOverlay.MouseEventSource = BackgroundGrid;
         brushShapeOverlay.MouseReference = MainImage;
         brushShapeOverlay.MouseReference = MainImage;
-        brushShapeOverlay.Initialize();*/
+        brushShapeOverlay.Initialize();
     }
     }
 
 
     private static void OnDocumentChange(AvaloniaPropertyChangedEventArgs<DocumentViewModel> e)
     private static void OnDocumentChange(AvaloniaPropertyChangedEventArgs<DocumentViewModel> e)

+ 6 - 19
src/PixiEditor.AvaloniaUI/Views/Overlays/BrushShapeOverlay/BrushShapeOverlay.cs

@@ -11,11 +11,8 @@ using PixiEditor.DrawingApi.Core.Numerics;
 
 
 namespace PixiEditor.AvaloniaUI.Views.Overlays.BrushShapeOverlay;
 namespace PixiEditor.AvaloniaUI.Views.Overlays.BrushShapeOverlay;
 #nullable enable
 #nullable enable
-internal class BrushShapeOverlay : Control
+internal class BrushShapeOverlay : Overlay
 {
 {
-    public static readonly StyledProperty<double> ZoomboxScaleProperty =
-        AvaloniaProperty.Register<BrushShapeOverlay, double>(nameof(ZoomboxScale), defaultValue: 1.0);
-
     public static readonly StyledProperty<int> BrushSizeProperty =
     public static readonly StyledProperty<int> BrushSizeProperty =
         AvaloniaProperty.Register<BrushShapeOverlay, int>(nameof(BrushSize), defaultValue: 1);
         AvaloniaProperty.Register<BrushShapeOverlay, int>(nameof(BrushSize), defaultValue: 1);
 
 
@@ -52,12 +49,6 @@ internal class BrushShapeOverlay : Control
         set => SetValue(BrushSizeProperty, value);
         set => SetValue(BrushSizeProperty, value);
     }
     }
 
 
-    public double ZoomboxScale
-    {
-        get => (double)GetValue(ZoomboxScaleProperty);
-        set => SetValue(ZoomboxScaleProperty, value);
-    }
-
     private Pen whitePen = new Pen(Brushes.LightGray, 1);
     private Pen whitePen = new Pen(Brushes.LightGray, 1);
     private Point lastMousePos = new();
     private Point lastMousePos = new();
 
 
@@ -67,8 +58,6 @@ internal class BrushShapeOverlay : Control
     {
     {
         AffectsRender<BrushShapeOverlay>(BrushShapeProperty);
         AffectsRender<BrushShapeOverlay>(BrushShapeProperty);
         AffectsRender<BrushShapeOverlay>(BrushSizeProperty);
         AffectsRender<BrushShapeOverlay>(BrushSizeProperty);
-
-        ZoomboxScaleProperty.Changed.Subscribe(OnZoomboxScaleChanged);
     }
     }
 
 
     public BrushShapeOverlay()
     public BrushShapeOverlay()
@@ -167,6 +156,11 @@ internal class BrushShapeOverlay : Control
         }
         }
     }
     }
 
 
+    protected override void ZoomChanged(double newZoom)
+    {
+        whitePen.Thickness = 1.0 / newZoom;
+    }
+
     private static int Mod(int x, int m) => (x % m + m) % m;
     private static int Mod(int x, int m) => (x % m + m) % m;
 
 
     private static PathGeometry ConstructEllipseOutline(RectI rectangle)
     private static PathGeometry ConstructEllipseOutline(RectI rectangle)
@@ -237,11 +231,4 @@ internal class BrushShapeOverlay : Control
         var geometry = new PathGeometry() { Figures = new PathFigures() { figure }};
         var geometry = new PathGeometry() { Figures = new PathFigures() { figure }};
         return geometry;
         return geometry;
     }
     }
-
-    private static void OnZoomboxScaleChanged(AvaloniaPropertyChangedEventArgs<double> e)
-    {
-        var self = (BrushShapeOverlay)e.Sender;
-        double newScale = e.NewValue.Value;
-        self.whitePen.Thickness = 1.0 / newScale;
-    }
 }
 }

+ 3 - 9
src/PixiEditor.AvaloniaUI/Views/Overlays/LineToolOverlay/LineToolOverlay.cs

@@ -42,9 +42,7 @@ internal class LineToolOverlay : Overlay
 
 
     static LineToolOverlay()
     static LineToolOverlay()
     {
     {
-        AffectsRender<LineToolOverlay>(ZoomboxScaleProperty, LineStartProperty, LineEndProperty);
-
-        ZoomboxScaleProperty.Changed.Subscribe(OnZoomboxScaleChanged);
+        AffectsRender<LineToolOverlay>(ZoomScaleProperty, LineStartProperty, LineEndProperty);
     }
     }
 
 
     private Pen blackPen = new Pen(Brushes.Black, 1);
     private Pen blackPen = new Pen(Brushes.Black, 1);
@@ -95,13 +93,9 @@ internal class LineToolOverlay : Overlay
         //mouseUpdateController?.Dispose();
         //mouseUpdateController?.Dispose();
     }
     }
 
 
-    private static void OnZoomboxScaleChanged(AvaloniaPropertyChangedEventArgs<double> args)
+    protected override void ZoomChanged(double newZoom)
     {
     {
-        if (args.Sender is not LineToolOverlay overlay)
-            return;
-
-        double newScale = args.NewValue.Value;
-        overlay.blackPen.Thickness = 1.0 / newScale;
+        blackPen.Thickness = 1.0 / newZoom;
     }
     }
 
 
     public override void Render(DrawingContext context)
     public override void Render(DrawingContext context)

+ 4 - 4
src/PixiEditor.AvaloniaUI/Views/Overlays/Overlay.cs

@@ -10,18 +10,18 @@ public class Overlay : Decorator
 {
 {
     public List<Handle> Handles { get; } = new();
     public List<Handle> Handles { get; } = new();
 
 
-    public static readonly StyledProperty<double> ZoomboxScaleProperty =
+    public static readonly StyledProperty<double> ZoomScaleProperty =
         AvaloniaProperty.Register<Overlay, double>(nameof(ZoomScale), defaultValue: 1.0);
         AvaloniaProperty.Register<Overlay, double>(nameof(ZoomScale), defaultValue: 1.0);
 
 
     public double ZoomScale
     public double ZoomScale
     {
     {
-        get => GetValue(ZoomboxScaleProperty);
-        set => SetValue(ZoomboxScaleProperty, value);
+        get => GetValue(ZoomScaleProperty);
+        set => SetValue(ZoomScaleProperty, value);
     }
     }
 
 
     public Overlay()
     public Overlay()
     {
     {
-        ZoomboxScaleProperty.Changed.Subscribe(OnZoomboxScaleChanged);
+        ZoomScaleProperty.Changed.Subscribe(OnZoomboxScaleChanged);
     }
     }
 
 
     public void AddHandle(Handle handle)
     public void AddHandle(Handle handle)

+ 1 - 1
src/PixiEditor.AvaloniaUI/Views/Overlays/TransformOverlay/TransformOverlay.cs

@@ -107,7 +107,7 @@ internal class TransformOverlay : Overlay
 
 
     static TransformOverlay()
     static TransformOverlay()
     {
     {
-        AffectsRender<TransformOverlay>(RequestedCornersProperty, CornersProperty, ZoomboxScaleProperty, SideFreedomProperty, CornerFreedomProperty, LockRotationProperty, SnapToAnglesProperty, InternalStateProperty, ZoomboxAngleProperty, CoverWholeScreenProperty);
+        AffectsRender<TransformOverlay>(RequestedCornersProperty, CornersProperty, ZoomScaleProperty, SideFreedomProperty, CornerFreedomProperty, LockRotationProperty, SnapToAnglesProperty, InternalStateProperty, ZoomboxAngleProperty, CoverWholeScreenProperty);
 
 
         RequestedCornersProperty.Changed.Subscribe(OnRequestedCorners);
         RequestedCornersProperty.Changed.Subscribe(OnRequestedCorners);
     }
     }

+ 23 - 1
src/PixiEditor.AvaloniaUI/Views/Visuals/Scene.cs

@@ -3,7 +3,9 @@ using System.Collections.Specialized;
 using Avalonia;
 using Avalonia;
 using Avalonia.Animation;
 using Avalonia.Animation;
 using Avalonia.Controls;
 using Avalonia.Controls;
+using Avalonia.Input;
 using Avalonia.Media;
 using Avalonia.Media;
+using Avalonia.Rendering;
 using Avalonia.Rendering.SceneGraph;
 using Avalonia.Rendering.SceneGraph;
 using Avalonia.Skia;
 using Avalonia.Skia;
 using ChunkyImageLib;
 using ChunkyImageLib;
@@ -17,10 +19,11 @@ using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Skia;
 using PixiEditor.DrawingApi.Skia;
 using Image = PixiEditor.DrawingApi.Core.Surface.ImageData.Image;
 using Image = PixiEditor.DrawingApi.Core.Surface.ImageData.Image;
+using Point = Avalonia.Point;
 
 
 namespace PixiEditor.AvaloniaUI.Views.Visuals;
 namespace PixiEditor.AvaloniaUI.Views.Visuals;
 
 
-internal class Scene : Control
+internal class Scene : Control, ICustomHitTest
 {
 {
     public static readonly StyledProperty<Surface> SurfaceProperty = AvaloniaProperty.Register<SurfaceControl, Surface>(
     public static readonly StyledProperty<Surface> SurfaceProperty = AvaloniaProperty.Register<SurfaceControl, Surface>(
         nameof(Surface));
         nameof(Surface));
@@ -233,6 +236,25 @@ internal class Scene : Control
             scene.checkerBitmap = null;
             scene.checkerBitmap = null;
         }
         }
     }
     }
+
+    bool ICustomHitTest.HitTest(Point point)
+    {
+        //TODO: Overlays
+        return false;
+        /*if (ActiveOverlays == null) return false;
+
+        foreach (Overlay overlay in ActiveOverlays)
+        {
+            Point pointInOverlay = point - overlay.Bounds.Position;
+            if (overlay.InputHitTest(pointInOverlay) != null)
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }*/
+    }
 }
 }
 
 
 internal class DrawSceneOperation : SkiaDrawOperation
 internal class DrawSceneOperation : SkiaDrawOperation