Browse Source

Move tool click select works

flabbet 9 months ago
parent
commit
fa2f39732e
28 changed files with 144 additions and 76 deletions
  1. 15 10
      src/PixiEditor/Models/Controllers/InputDevice/MouseInputFilter.cs
  2. 2 2
      src/PixiEditor/Models/DocumentModels/ChangeExecutionController.cs
  3. 1 1
      src/PixiEditor/Models/DocumentModels/Public/DocumentEventsModule.cs
  4. 1 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/BrightnessToolExecutor.cs
  5. 1 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ColorPickerToolExecutor.cs
  6. 3 3
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ComplexShapeToolExecutor.cs
  7. 1 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/EraserToolExecutor.cs
  8. 1 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/FloodFillToolExecutor.cs
  9. 1 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/LassoToolExecutor.cs
  10. 3 3
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/LineExecutor.cs
  11. 2 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/MagicWandToolExecutor.cs
  12. 1 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/PenToolExecutor.cs
  13. 1 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/SelectToolExecutor.cs
  14. 1 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ShiftLayerExecutor.cs
  15. 1 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/SimpleShapeToolExecutor.cs
  16. 50 9
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/TransformSelectedExecutor.cs
  17. 1 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/UpdateableChangeExecutor.cs
  18. 1 1
      src/PixiEditor/Models/Handlers/INodeHandler.cs
  19. 2 0
      src/PixiEditor/Models/Handlers/ITransformHandler.cs
  20. 1 1
      src/PixiEditor/Styles/Templates/NodeGraphView.axaml
  21. 12 0
      src/PixiEditor/ViewModels/Document/TransformOverlays/DocumentTransformViewModel.cs
  22. 1 1
      src/PixiEditor/ViewModels/Nodes/NodeViewModel.cs
  23. 4 2
      src/PixiEditor/ViewModels/SubViewModels/IoViewModel.cs
  24. 1 1
      src/PixiEditor/ViewModels/SubViewModels/NodeGraphManagerViewModel.cs
  25. 9 2
      src/PixiEditor/ViewModels/Tools/Tools/MoveToolViewModel.cs
  26. 6 0
      src/PixiEditor/Views/Main/ViewportControls/ViewportOverlays.cs
  27. 3 3
      src/PixiEditor/Views/Nodes/NodeGraphView.cs
  28. 18 26
      src/PixiEditor/Views/Overlays/TransformOverlay/TransformOverlay.cs

+ 15 - 10
src/PixiEditor/Models/Controllers/InputDevice/MouseInputFilter.cs

@@ -10,7 +10,7 @@ internal class MouseInputFilter
 {
 {
     public EventHandler<MouseOnCanvasEventArgs> OnMouseDown;
     public EventHandler<MouseOnCanvasEventArgs> OnMouseDown;
     public EventHandler<VecD> OnMouseMove;
     public EventHandler<VecD> OnMouseMove;
-    public EventHandler<MouseButton> OnMouseUp;
+    public EventHandler<MouseOnCanvasEventArgs> OnMouseUp;
 
 
 
 
     private Dictionary<MouseButton, bool> buttonStates = new()
     private Dictionary<MouseButton, bool> buttonStates = new()
@@ -36,23 +36,28 @@ internal class MouseInputFilter
 
 
     public void MouseMoveInlet(object args) => OnMouseMove?.Invoke(this, ((MouseOnCanvasEventArgs)args).PositionOnCanvas);
     public void MouseMoveInlet(object args) => OnMouseMove?.Invoke(this, ((MouseOnCanvasEventArgs)args).PositionOnCanvas);
 
 
-    public void MouseUpInlet(object args) => MouseUpInlet(((MouseOnCanvasEventArgs)args).Button);
+    public void MouseUpInlet(object args) => MouseUpInlet(((MouseOnCanvasEventArgs)args));
     public void MouseUpInlet(object? sender, Point p, MouseButton button) => MouseUpInlet(button);
     public void MouseUpInlet(object? sender, Point p, MouseButton button) => MouseUpInlet(button);
-    public void MouseUpInlet(MouseButton button)
+    public void MouseUpInlet(MouseOnCanvasEventArgs args)
     {
     {
-        if (button is MouseButton.XButton1 or MouseButton.XButton2 or MouseButton.None)
+        if (args.Button is MouseButton.XButton1 or MouseButton.XButton2 or MouseButton.None)
             return;
             return;
-        if (!buttonStates[button])
+        if (!buttonStates[args.Button])
             return;
             return;
-        buttonStates[button] = false;
+        buttonStates[args.Button] = false;
 
 
-        OnMouseUp?.Invoke(this, button);
+        OnMouseUp?.Invoke(this, args);
     }
     }
 
 
     public void DeactivatedInlet(object? sender, EventArgs e)
     public void DeactivatedInlet(object? sender, EventArgs e)
     {
     {
-        MouseUpInlet(MouseButton.Left);
-        MouseUpInlet(MouseButton.Middle);
-        MouseUpInlet(MouseButton.Right);
+        MouseOnCanvasEventArgs argsLeft = new(MouseButton.Left, VecD.Zero);
+        MouseUpInlet(argsLeft);
+        
+        MouseOnCanvasEventArgs argsMiddle = new(MouseButton.Middle, VecD.Zero);
+        MouseUpInlet(argsMiddle);
+        
+        MouseOnCanvasEventArgs argsRight = new(MouseButton.Right, VecD.Zero);
+        MouseUpInlet(argsRight);
     }
     }
 }
 }

+ 2 - 2
src/PixiEditor/Models/DocumentModels/ChangeExecutionController.cs

@@ -210,13 +210,13 @@ internal class ChangeExecutionController
         currentSession?.OnLeftMouseButtonDown(canvasPos);
         currentSession?.OnLeftMouseButtonDown(canvasPos);
     }
     }
 
 
-    public void LeftMouseButtonUpInlet()
+    public void LeftMouseButtonUpInlet(VecD argsPositionOnCanvas)
     {
     {
         //update internal state
         //update internal state
         LeftMousePressed = false;
         LeftMousePressed = false;
 
 
         //call session events
         //call session events
-        currentSession?.OnLeftMouseButtonUp();
+        currentSession?.OnLeftMouseButtonUp(argsPositionOnCanvas);
     }
     }
 
 
     public void TransformMovedInlet(ShapeCorners corners)
     public void TransformMovedInlet(ShapeCorners corners)

+ 1 - 1
src/PixiEditor/Models/DocumentModels/Public/DocumentEventsModule.cs

@@ -39,7 +39,7 @@ internal class DocumentEventsModule
         DocumentsHandler.CoordinatesString = $"X: {(int)newPos.X} Y: {(int)newPos.Y}";
         DocumentsHandler.CoordinatesString = $"X: {(int)newPos.X} Y: {(int)newPos.Y}";
         Internals.ChangeController.MouseMoveInlet(newPos);
         Internals.ChangeController.MouseMoveInlet(newPos);
     }
     }
-    public void OnCanvasLeftMouseButtonUp() => Internals.ChangeController.LeftMouseButtonUpInlet();
+    public void OnCanvasLeftMouseButtonUp(VecD argsPositionOnCanvas) => Internals.ChangeController.LeftMouseButtonUpInlet(argsPositionOnCanvas);
     public void OnOpacitySliderDragStarted() => Internals.ChangeController.OpacitySliderDragStartedInlet();
     public void OnOpacitySliderDragStarted() => Internals.ChangeController.OpacitySliderDragStartedInlet();
     public void OnOpacitySliderDragged(float newValue) => Internals.ChangeController.OpacitySliderDraggedInlet(newValue);
     public void OnOpacitySliderDragged(float newValue) => Internals.ChangeController.OpacitySliderDraggedInlet(newValue);
     public void OnOpacitySliderDragEnded() => Internals.ChangeController.OpacitySliderDragEndedInlet();
     public void OnOpacitySliderDragEnded() => Internals.ChangeController.OpacitySliderDragEndedInlet();

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/BrightnessToolExecutor.cs

@@ -42,7 +42,7 @@ internal class BrightnessToolExecutor : UpdateableChangeExecutor
         internals!.ActionAccumulator.AddActions(action);
         internals!.ActionAccumulator.AddActions(action);
     }
     }
 
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
     {
         internals!.ActionAccumulator.AddFinishedActions(new EndChangeBrightness_Action());
         internals!.ActionAccumulator.AddFinishedActions(new EndChangeBrightness_Action());
         onEnded?.Invoke(this);
         onEnded?.Invoke(this);

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ColorPickerToolExecutor.cs

@@ -42,7 +42,7 @@ internal class ColorPickerToolExecutor : UpdateableChangeExecutor
         colorsViewModel.PrimaryColor = document.PickColor(pos, scope, includeReference, includeCanvas, document.AnimationHandler.ActiveFrameBindable, document.ReferenceLayerHandler.IsTopMost);
         colorsViewModel.PrimaryColor = document.PickColor(pos, scope, includeReference, includeCanvas, document.AnimationHandler.ActiveFrameBindable, document.ReferenceLayerHandler.IsTopMost);
     }
     }
 
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
     {
         onEnded?.Invoke(this);
         onEnded?.Invoke(this);
     }
     }

+ 3 - 3
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ComplexShapeToolExecutor.cs

@@ -250,7 +250,7 @@ internal abstract class ComplexShapeToolExecutor<T> : SimpleShapeToolExecutor wh
         internals!.ActionAccumulator.AddActions(SettingsChangedAction());
         internals!.ActionAccumulator.AddActions(SettingsChangedAction());
     }
     }
 
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
     {
         if (ActiveMode != ShapeToolMode.Transform)
         if (ActiveMode != ShapeToolMode.Transform)
         {
         {
@@ -259,13 +259,13 @@ internal abstract class ComplexShapeToolExecutor<T> : SimpleShapeToolExecutor wh
                 internals!.ActionAccumulator.AddFinishedActions(EndDrawAction());
                 internals!.ActionAccumulator.AddFinishedActions(EndDrawAction());
                 AddMemberToSnapping();
                 AddMemberToSnapping();
 
 
-                base.OnLeftMouseButtonUp();
+                base.OnLeftMouseButtonUp(argsPositionOnCanvas);
                 onEnded?.Invoke(this);
                 onEnded?.Invoke(this);
                 return;
                 return;
             }
             }
         }
         }
 
 
-        base.OnLeftMouseButtonUp();
+        base.OnLeftMouseButtonUp(argsPositionOnCanvas);
     }
     }
 
 
     protected override void StartMode(ShapeToolMode mode)
     protected override void StartMode(ShapeToolMode mode)

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/EraserToolExecutor.cs

@@ -60,7 +60,7 @@ internal class EraserToolExecutor : UpdateableChangeExecutor
         internals!.ActionAccumulator.AddActions(action);
         internals!.ActionAccumulator.AddActions(action);
     }
     }
 
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
     {
         internals!.ActionAccumulator.AddFinishedActions(new EndLineBasedPen_Action());
         internals!.ActionAccumulator.AddFinishedActions(new EndLineBasedPen_Action());
         onEnded?.Invoke(this);
         onEnded?.Invoke(this);

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/FloodFillToolExecutor.cs

@@ -50,7 +50,7 @@ internal class FloodFillToolExecutor : UpdateableChangeExecutor
         internals!.ActionAccumulator.AddActions(new FloodFill_Action(memberGuid, pos, color, considerAllLayers, tolerance, drawOnMask, document!.AnimationHandler.ActiveFrameBindable));
         internals!.ActionAccumulator.AddActions(new FloodFill_Action(memberGuid, pos, color, considerAllLayers, tolerance, drawOnMask, document!.AnimationHandler.ActiveFrameBindable));
     }
     }
 
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
     {
         internals!.ActionAccumulator.AddActions(new ChangeBoundary_Action());
         internals!.ActionAccumulator.AddActions(new ChangeBoundary_Action());
         onEnded!(this);
         onEnded!(this);

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/LassoToolExecutor.cs

@@ -25,7 +25,7 @@ internal sealed class LassoToolExecutor : UpdateableChangeExecutor
 
 
     public override void OnPixelPositionChange(VecI pos) => AddStartAction(pos);
     public override void OnPixelPositionChange(VecI pos) => AddStartAction(pos);
 
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
     {
         internals!.ActionAccumulator.AddFinishedActions(new EndSelectLasso_Action());
         internals!.ActionAccumulator.AddFinishedActions(new EndSelectLasso_Action());
         onEnded!(this);
         onEnded!(this);

+ 3 - 3
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/LineExecutor.cs

@@ -110,17 +110,17 @@ internal abstract class LineExecutor<T> : SimpleShapeToolExecutor where T : ILin
         internals!.ActionAccumulator.AddActions(drawLineAction);
         internals!.ActionAccumulator.AddActions(drawLineAction);
     }
     }
 
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
     {
         if (!startedDrawing)
         if (!startedDrawing)
         {
         {
-            base.OnLeftMouseButtonUp();
+            base.OnLeftMouseButtonUp(argsPositionOnCanvas);
             onEnded!(this);
             onEnded!(this);
             return;
             return;
         }
         }
 
 
         document!.LineToolOverlayHandler.Show(startDrawingPos, curPos, true);
         document!.LineToolOverlayHandler.Show(startDrawingPos, curPos, true);
-        base.OnLeftMouseButtonUp();
+        base.OnLeftMouseButtonUp(argsPositionOnCanvas);
     }
     }
 
 
     public override void OnLineOverlayMoved(VecD start, VecD end)
     public override void OnLineOverlayMoved(VecD start, VecD end)

+ 2 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/MagicWandToolExecutor.cs

@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
+using Drawie.Numerics;
 using PixiEditor.ChangeableDocument.Actions.Generated;
 using PixiEditor.ChangeableDocument.Actions.Generated;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.ChangeableDocument.Enums;
@@ -37,7 +38,7 @@ internal class MagicWandToolExecutor : UpdateableChangeExecutor
         return ExecutionState.Success;
         return ExecutionState.Success;
     }
     }
 
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
     {
         internals!.ActionAccumulator.AddActions(new ChangeBoundary_Action());
         internals!.ActionAccumulator.AddActions(new ChangeBoundary_Action());
         onEnded!(this);
         onEnded!(this);

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/PenToolExecutor.cs

@@ -66,7 +66,7 @@ internal class PenToolExecutor : UpdateableChangeExecutor
         internals!.ActionAccumulator.AddActions(action);
         internals!.ActionAccumulator.AddActions(action);
     }
     }
 
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
     {
         IAction? action = pixelPerfect switch
         IAction? action = pixelPerfect switch
         {
         {

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/SelectToolExecutor.cs

@@ -56,7 +56,7 @@ internal class SelectToolExecutor : UpdateableChangeExecutor
         internals!.ActionAccumulator.AddActions(action);
         internals!.ActionAccumulator.AddActions(action);
     }
     }
 
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
     {
         IAction action = CreateEndAction(selectShape);
         IAction action = CreateEndAction(selectShape);
         internals!.ActionAccumulator.AddFinishedActions(action);
         internals!.ActionAccumulator.AddFinishedActions(action);

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ShiftLayerExecutor.cs

@@ -65,7 +65,7 @@ internal class ShiftLayerExecutor : UpdateableChangeExecutor
         internals!.ActionAccumulator.AddActions(action);
         internals!.ActionAccumulator.AddActions(action);
     }
     }
 
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
     {
         internals!.ActionAccumulator.AddFinishedActions(new EndShiftLayer_Action());
         internals!.ActionAccumulator.AddFinishedActions(new EndShiftLayer_Action());
         onEnded?.Invoke(this);
         onEnded?.Invoke(this);

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/SimpleShapeToolExecutor.cs

@@ -131,7 +131,7 @@ internal abstract class SimpleShapeToolExecutor : UpdateableChangeExecutor,
         }
         }
     }
     }
 
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
     {
         HighlightSnapping(null, null);
         HighlightSnapping(null, null);
         ActiveMode = ShapeToolMode.Transform;
         ActiveMode = ShapeToolMode.Transform;

+ 50 - 9
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/TransformSelectedExecutor.cs

@@ -21,10 +21,12 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
     private bool isInProgress;
     private bool isInProgress;
     public override ExecutorType Type { get; }
     public override ExecutorType Type { get; }
 
 
-    public override bool BlocksOtherActions => false; 
-    
+    public override bool BlocksOtherActions => false;
+
     private List<Guid> selectedMembers = new();
     private List<Guid> selectedMembers = new();
 
 
+    private ShapeCorners lastCorners = new();
+
     public TransformSelectedExecutor(bool toolLinked)
     public TransformSelectedExecutor(bool toolLinked)
     {
     {
         Type = toolLinked ? ExecutorType.ToolLinked : ExecutorType.Regular;
         Type = toolLinked ? ExecutorType.ToolLinked : ExecutorType.Regular;
@@ -46,6 +48,7 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
         if (!members.Any())
         if (!members.Any())
             return ExecutionState.Error;
             return ExecutionState.Error;
 
 
+        document.TransformHandler.PassthroughPointerPressed += OnLeftMouseButtonDown;
         return SelectMembers(members);
         return SelectMembers(members);
     }
     }
 
 
@@ -81,15 +84,18 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
         DocumentTransformMode mode = allRaster
         DocumentTransformMode mode = allRaster
             ? DocumentTransformMode.Scale_Rotate_Shear_Perspective
             ? DocumentTransformMode.Scale_Rotate_Shear_Perspective
             : DocumentTransformMode.Scale_Rotate_Shear_NoPerspective;
             : DocumentTransformMode.Scale_Rotate_Shear_NoPerspective;
-        
+
         foreach (var structureMemberHandler in members)
         foreach (var structureMemberHandler in members)
         {
         {
             document.SnappingHandler.Remove(structureMemberHandler.Id.ToString());
             document.SnappingHandler.Remove(structureMemberHandler.Id.ToString());
         }
         }
-        
+
         selectedMembers = members.Select(m => m.Id).ToList();
         selectedMembers = members.Select(m => m.Id).ToList();
-        
-        document.TransformHandler.ShowTransform(mode, true, masterCorners, Type == ExecutorType.Regular);
+
+        lastCorners = masterCorners;
+        document.TransformHandler.ShowTransform(mode, true, masterCorners,
+            Type == ExecutorType.Regular || tool.KeepOriginalImage);
+
         internals!.ActionAccumulator.AddActions(
         internals!.ActionAccumulator.AddActions(
             new TransformSelected_Action(masterCorners, tool.KeepOriginalImage, memberCorners, false,
             new TransformSelected_Action(masterCorners, tool.KeepOriginalImage, memberCorners, false,
                 document.AnimationHandler.ActiveFrameBindable));
                 document.AnimationHandler.ActiveFrameBindable));
@@ -98,6 +104,33 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
         return ExecutionState.Success;
         return ExecutionState.Success;
     }
     }
 
 
+    public override void OnLeftMouseButtonDown(VecD pos)
+    {
+        var allLayers = document.StructureHelper.GetAllLayers();
+        var topMostWithinClick = allLayers.Where(x =>
+                x is { IsVisibleBindable: true, TightBounds: not null } && x.TightBounds.Value.ContainsInclusive(pos))
+            .OrderByDescending(x => allLayers.IndexOf(x));
+
+        var nonSelected = topMostWithinClick.Where(x => x != document.SelectedStructureMember
+                                                        && !document.SoftSelectedStructureMembers.Contains(x))
+            .ToArray();
+
+        if (nonSelected.Any())
+        {
+            var topMost = nonSelected.First();
+
+            document.Operations.SetSelectedMember(topMost.Id);
+        }
+    }
+
+    public override void OnSettingsChanged(string name, object value)
+    {
+        if (name == nameof(IMoveToolHandler.KeepOriginalImage))
+        {
+            DoTransform(lastCorners);
+        }
+    }
+
     public override void OnMembersSelected(List<Guid> memberGuids)
     public override void OnMembersSelected(List<Guid> memberGuids)
     {
     {
         if (isInProgress)
         if (isInProgress)
@@ -105,7 +138,7 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
             internals.ActionAccumulator.AddActions(new EndTransformSelected_Action());
             internals.ActionAccumulator.AddActions(new EndTransformSelected_Action());
             document!.TransformHandler.HideTransform();
             document!.TransformHandler.HideTransform();
             AddSnappingForMembers(selectedMembers);
             AddSnappingForMembers(selectedMembers);
-            
+
             selectedMembers.Clear();
             selectedMembers.Clear();
             memberCorners.Clear();
             memberCorners.Clear();
             isInProgress = false;
             isInProgress = false;
@@ -122,6 +155,12 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
     public bool IsTransforming => isInProgress;
     public bool IsTransforming => isInProgress;
 
 
     public void OnTransformMoved(ShapeCorners corners)
     public void OnTransformMoved(ShapeCorners corners)
+    {
+        DoTransform(corners);
+        lastCorners = corners;
+    }
+
+    private void DoTransform(ShapeCorners corners)
     {
     {
         if (!isInProgress)
         if (!isInProgress)
             return;
             return;
@@ -138,7 +177,7 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
     public void OnMidChangeUndo() => document!.TransformHandler.Undo();
     public void OnMidChangeUndo() => document!.TransformHandler.Undo();
 
 
     public void OnMidChangeRedo() => document!.TransformHandler.Redo();
     public void OnMidChangeRedo() => document!.TransformHandler.Redo();
-    public bool CanUndo => document!.TransformHandler.HasUndo; 
+    public bool CanUndo => document!.TransformHandler.HasUndo;
     public bool CanRedo => document!.TransformHandler.HasRedo;
     public bool CanRedo => document!.TransformHandler.HasRedo;
 
 
     public void OnTransformApplied()
     public void OnTransformApplied()
@@ -160,6 +199,7 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
         }
         }
 
 
         isInProgress = false;
         isInProgress = false;
+        document.TransformHandler.PassthroughPointerPressed -= OnLeftMouseButtonDown;
     }
     }
 
 
     public override void ForceStop()
     public override void ForceStop()
@@ -175,8 +215,9 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
         AddSnappingForMembers(memberCorners.Keys.ToList());
         AddSnappingForMembers(memberCorners.Keys.ToList());
 
 
         isInProgress = false;
         isInProgress = false;
+        document.TransformHandler.PassthroughPointerPressed -= OnLeftMouseButtonDown;
     }
     }
-    
+
     private void AddSnappingForMembers(List<Guid> memberGuids)
     private void AddSnappingForMembers(List<Guid> memberGuids)
     {
     {
         foreach (Guid memberGuid in memberGuids)
         foreach (Guid memberGuid in memberGuids)

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/UpdateableChangeExecutor.cs

@@ -49,7 +49,7 @@ internal abstract class UpdateableChangeExecutor
     public virtual void OnPixelPositionChange(VecI pos) { }
     public virtual void OnPixelPositionChange(VecI pos) { }
     public virtual void OnPrecisePositionChange(VecD pos) { }
     public virtual void OnPrecisePositionChange(VecD pos) { }
     public virtual void OnLeftMouseButtonDown(VecD pos) { }
     public virtual void OnLeftMouseButtonDown(VecD pos) { }
-    public virtual void OnLeftMouseButtonUp() { }
+    public virtual void OnLeftMouseButtonUp(VecD pos) { }
     public virtual void OnOpacitySliderDragStarted() { }
     public virtual void OnOpacitySliderDragStarted() { }
     public virtual void OnOpacitySliderDragged(float newValue) { }
     public virtual void OnOpacitySliderDragged(float newValue) { }
     public virtual void OnOpacitySliderDragEnded() { }
     public virtual void OnOpacitySliderDragEnded() { }

+ 1 - 1
src/PixiEditor/Models/Handlers/INodeHandler.cs

@@ -22,7 +22,7 @@ public interface INodeHandler : INotifyPropertyChanged
     public ObservableRangeCollection<INodePropertyHandler> Outputs { get; }
     public ObservableRangeCollection<INodePropertyHandler> Outputs { get; }
     public PreviewPainter? ResultPainter { get; set; }
     public PreviewPainter? ResultPainter { get; set; }
     public VecD PositionBindable { get; set; }
     public VecD PositionBindable { get; set; }
-    public bool IsSelected { get; set; }
+    public bool IsNodeSelected { get; set; }
     public void TraverseBackwards(Func<INodeHandler, bool> func);
     public void TraverseBackwards(Func<INodeHandler, bool> func);
     public void TraverseBackwards(Func<INodeHandler, INodeHandler, bool> func);
     public void TraverseBackwards(Func<INodeHandler, INodeHandler, bool> func);
     public void TraverseBackwards(Func<INodeHandler, INodeHandler, INodePropertyHandler, bool> func);
     public void TraverseBackwards(Func<INodeHandler, INodeHandler, INodePropertyHandler, bool> func);

+ 2 - 0
src/PixiEditor/Models/Handlers/ITransformHandler.cs

@@ -15,4 +15,6 @@ internal interface ITransformHandler : IHandler
     public bool Nudge(VecD distance);
     public bool Nudge(VecD distance);
     public bool HasUndo { get; }
     public bool HasUndo { get; }
     public bool HasRedo { get; }
     public bool HasRedo { get; }
+    public bool ShowTransformControls { get; set; }
+    public event Action<VecD> PassthroughPointerPressed;
 }
 }

+ 1 - 1
src/PixiEditor/Styles/Templates/NodeGraphView.axaml

@@ -45,7 +45,7 @@
                                         BorderBrush="{Binding InternalName, Converter={converters:NodeInternalNameToStyleConverter}, ConverterParameter='BorderBrush'}"
                                         BorderBrush="{Binding InternalName, Converter={converters:NodeInternalNameToStyleConverter}, ConverterParameter='BorderBrush'}"
                                         BorderThickness="2"
                                         BorderThickness="2"
                                         Outputs="{Binding Outputs}"
                                         Outputs="{Binding Outputs}"
-                                        IsSelected="{Binding IsSelected}"
+                                        IsSelected="{Binding IsNodeSelected}"
                                         SelectNodeCommand="{Binding SelectNodeCommand,
                                         SelectNodeCommand="{Binding SelectNodeCommand,
                                     RelativeSource={RelativeSource FindAncestor, AncestorType=nodes:NodeGraphView}}"
                                     RelativeSource={RelativeSource FindAncestor, AncestorType=nodes:NodeGraphView}}"
                                         StartDragCommand="{Binding StartDraggingCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=nodes:NodeGraphView}}"
                                         StartDragCommand="{Binding StartDraggingCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=nodes:NodeGraphView}}"

+ 12 - 0
src/PixiEditor/ViewModels/Document/TransformOverlays/DocumentTransformViewModel.cs

@@ -85,6 +85,8 @@ internal class DocumentTransformViewModel : ObservableObject, ITransformHandler
         set => SetProperty(ref showTransformControls, value);
         set => SetProperty(ref showTransformControls, value);
     }
     }
 
 
+    public event Action<VecD>? PassthroughPointerPressed;
+
     private bool coverWholeScreen;
     private bool coverWholeScreen;
     public bool CoverWholeScreen
     public bool CoverWholeScreen
     {
     {
@@ -110,6 +112,7 @@ internal class DocumentTransformViewModel : ObservableObject, ITransformHandler
         set => SetProperty(ref enableSnapping, value);
         set => SetProperty(ref enableSnapping, value);
     }
     }
     
     
+    
     private ExecutionTrigger<ShapeCorners> requestedCornersExecutor;
     private ExecutionTrigger<ShapeCorners> requestedCornersExecutor;
     public ExecutionTrigger<ShapeCorners> RequestCornersExecutor
     public ExecutionTrigger<ShapeCorners> RequestCornersExecutor
     {
     {
@@ -124,6 +127,15 @@ internal class DocumentTransformViewModel : ObservableObject, ITransformHandler
         set => SetProperty(ref actionCompletedCommand, value);
         set => SetProperty(ref actionCompletedCommand, value);
     }
     }
 
 
+    private RelayCommand<VecD>? passThroughPointerPressedCommand; 
+    public RelayCommand<VecD> PassThroughPointerPressedCommand
+    {
+        get
+        {
+            return passThroughPointerPressedCommand ??= new RelayCommand<VecD>(x => PassthroughPointerPressed?.Invoke(x));
+        }
+    }
+
     public event EventHandler<ShapeCorners>? TransformMoved;
     public event EventHandler<ShapeCorners>? TransformMoved;
 
 
     private DocumentTransformMode activeTransformMode = DocumentTransformMode.Scale_Rotate_NoShear_NoPerspective;
     private DocumentTransformMode activeTransformMode = DocumentTransformMode.Scale_Rotate_NoShear_NoPerspective;

+ 1 - 1
src/PixiEditor/ViewModels/Nodes/NodeViewModel.cs

@@ -117,7 +117,7 @@ internal abstract class NodeViewModel : ObservableObject, INodeHandler
         set => SetProperty(ref resultPainter, value);
         set => SetProperty(ref resultPainter, value);
     }
     }
     
     
-    public bool IsSelected
+    public bool IsNodeSelected
     {
     {
         get => isSelected;
         get => isSelected;
         set => SetProperty(ref isSelected, value);
         set => SetProperty(ref isSelected, value);

+ 4 - 2
src/PixiEditor/ViewModels/SubViewModels/IoViewModel.cs

@@ -267,8 +267,9 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
         activeDocument.EventInlet.OnCanvasMouseMove(pos);
         activeDocument.EventInlet.OnCanvasMouseMove(pos);
     }
     }
 
 
-    private void OnMouseUp(object? sender, MouseButton button)
+    private void OnMouseUp(object? sender, MouseOnCanvasEventArgs args)
     {
     {
+        var button = args.Button;
         bool toLeftRightClick = drawingWithRight == null ||
         bool toLeftRightClick = drawingWithRight == null ||
                                 (button == MouseButton.Left && drawingWithRight.Value) ||
                                 (button == MouseButton.Left && drawingWithRight.Value) ||
                                 (button == MouseButton.Right && !drawingWithRight.Value);
                                 (button == MouseButton.Right && !drawingWithRight.Value);
@@ -284,7 +285,8 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
 
 
         if (button == MouseButton.Left || rightCanUp)
         if (button == MouseButton.Left || rightCanUp)
         {
         {
-            Owner.DocumentManagerSubViewModel.ActiveDocument.EventInlet.OnCanvasLeftMouseButtonUp();
+            Owner.DocumentManagerSubViewModel.ActiveDocument.EventInlet
+                .OnCanvasLeftMouseButtonUp(args.PositionOnCanvas);
         }
         }
 
 
         drawingWithRight = null;
         drawingWithRight = null;

+ 1 - 1
src/PixiEditor/ViewModels/SubViewModels/NodeGraphManagerViewModel.cs

@@ -19,7 +19,7 @@ internal class NodeGraphManagerViewModel : SubViewModel<ViewModelMain>
     public void DeleteSelectedNodes()
     public void DeleteSelectedNodes()
     {
     {
         var nodes = Owner.DocumentManagerSubViewModel.ActiveDocument?.NodeGraph.AllNodes
         var nodes = Owner.DocumentManagerSubViewModel.ActiveDocument?.NodeGraph.AllNodes
-            .Where(x => x.IsSelected).ToList();
+            .Where(x => x.IsNodeSelected).ToList();
         
         
         if (nodes == null || nodes.Count == 0)
         if (nodes == null || nodes.Count == 0)
             return;
             return;

+ 9 - 2
src/PixiEditor/ViewModels/Tools/Tools/MoveToolViewModel.cs

@@ -35,7 +35,7 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
 
 
     public override LocalizedString Tooltip => new LocalizedString("MOVE_TOOL_TOOLTIP", Shortcut);
     public override LocalizedString Tooltip => new LocalizedString("MOVE_TOOL_TOOLTIP", Shortcut);
 
 
-    [Settings.Bool("KEEP_ORIGINAL_IMAGE_SETTING")]
+    [Settings.Bool("KEEP_ORIGINAL_IMAGE_SETTING", Notify = nameof(KeepOriginalChanged))]
     public bool KeepOriginalImage => GetValue<bool>();
     public bool KeepOriginalImage => GetValue<bool>();
 
 
     public override BrushShape BrushShape => BrushShape.Hidden;
     public override BrushShape BrushShape => BrushShape.Hidden;
@@ -55,7 +55,8 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
 
 
     public override void UseTool(VecD pos)
     public override void UseTool(VecD pos)
     {
     {
-        ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument?.Tools.UseShiftLayerTool();
+        //ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument?.Tools.UseShiftLayerTool();
+        ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument?.Operations.TransformSelectedArea(true);
     }
     }
 
 
     public override void ModifierKeyChanged(bool ctrlIsDown, bool shiftIsDown, bool altIsDown)
     public override void ModifierKeyChanged(bool ctrlIsDown, bool shiftIsDown, bool altIsDown)
@@ -107,4 +108,10 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
         OnDeselecting(false);
         OnDeselecting(false);
         OnSelected(false);
         OnSelected(false);
     }
     }
+    
+    public void KeepOriginalChanged()
+    {
+        var activeDocument = ViewModelMain.Current.DocumentManagerSubViewModel.ActiveDocument;
+        activeDocument.TransformViewModel.ShowTransformControls = KeepOriginalImage;
+    }
 }
 }

+ 6 - 0
src/PixiEditor/Views/Main/ViewportControls/ViewportOverlays.cs

@@ -285,6 +285,11 @@ internal class ViewportOverlays
         {
         {
             Source = Viewport, Path = "Document.TransformViewModel.InternalState", Mode = BindingMode.TwoWay
             Source = Viewport, Path = "Document.TransformViewModel.InternalState", Mode = BindingMode.TwoWay
         };
         };
+        
+        Binding passThroughPointerPressedBinding = new()
+        {
+            Source = Viewport, Path = "Document.TransformViewModel.PassThroughPointerPressedCommand", Mode = BindingMode.OneWay
+        };
 
 
         Binding zoomboxAngleBinding = new() { Source = Viewport, Path = "Zoombox.Angle", Mode = BindingMode.OneWay };
         Binding zoomboxAngleBinding = new() { Source = Viewport, Path = "Zoombox.Angle", Mode = BindingMode.OneWay };
 
 
@@ -299,6 +304,7 @@ internal class ViewportOverlays
         transformOverlay.Bind(TransformOverlay.CoverWholeScreenProperty, coverWholeScreenBinding);
         transformOverlay.Bind(TransformOverlay.CoverWholeScreenProperty, coverWholeScreenBinding);
         transformOverlay.Bind(TransformOverlay.SnapToAnglesProperty, snapToAnglesBinding);
         transformOverlay.Bind(TransformOverlay.SnapToAnglesProperty, snapToAnglesBinding);
         transformOverlay.Bind(TransformOverlay.InternalStateProperty, internalStateBinding);
         transformOverlay.Bind(TransformOverlay.InternalStateProperty, internalStateBinding);
+        transformOverlay.Bind(TransformOverlay.PassthroughPointerPressedCommandProperty, passThroughPointerPressedBinding);
         transformOverlay.Bind(TransformOverlay.ZoomboxAngleProperty, zoomboxAngleBinding);
         transformOverlay.Bind(TransformOverlay.ZoomboxAngleProperty, zoomboxAngleBinding);
     }
     }
 
 

+ 3 - 3
src/PixiEditor/Views/Nodes/NodeGraphView.cs

@@ -150,7 +150,7 @@ internal class NodeGraphView : Zoombox.Zoombox
     }
     }
 
 
     public List<INodeHandler> SelectedNodes => NodeGraph != null
     public List<INodeHandler> SelectedNodes => NodeGraph != null
-        ? NodeGraph.AllNodes.Where(x => x.IsSelected).ToList()
+        ? NodeGraph.AllNodes.Where(x => x.IsNodeSelected).ToList()
         : new List<INodeHandler>();
         : new List<INodeHandler>();
 
 
     protected override Type StyleKeyOverride => typeof(NodeGraphView);
     protected override Type StyleKeyOverride => typeof(NodeGraphView);
@@ -478,14 +478,14 @@ internal class NodeGraphView : Zoombox.Zoombox
             ClearSelection();
             ClearSelection();
         }
         }
 
 
-        viewModel.IsSelected = true;
+        viewModel.IsNodeSelected = true;
     }
     }
 
 
     private void ClearSelection()
     private void ClearSelection()
     {
     {
         foreach (var node in SelectedNodes)
         foreach (var node in SelectedNodes)
         {
         {
-            node.IsSelected = false;
+            node.IsNodeSelected = false;
         }
         }
     }
     }
 }
 }

+ 18 - 26
src/PixiEditor/Views/Overlays/TransformOverlay/TransformOverlay.cs

@@ -78,6 +78,15 @@ internal class TransformOverlay : Overlay
         AvaloniaProperty.Register<TransformOverlay, TransformState>(nameof(InternalState),
         AvaloniaProperty.Register<TransformOverlay, TransformState>(nameof(InternalState),
             defaultValue: default(TransformState));
             defaultValue: default(TransformState));
 
 
+    public static readonly StyledProperty<ICommand> PassthroughPointerPressedCommandProperty = AvaloniaProperty.Register<TransformOverlay, ICommand>(
+        nameof(PassthroughPointerPressedCommand));
+
+    public ICommand PassthroughPointerPressedCommand
+    {
+        get => GetValue(PassthroughPointerPressedCommandProperty);
+        set => SetValue(PassthroughPointerPressedCommandProperty, value);
+    }
+
     public TransformState InternalState
     public TransformState InternalState
     {
     {
         get => GetValue(InternalStateProperty);
         get => GetValue(InternalStateProperty);
@@ -231,6 +240,7 @@ internal class TransformOverlay : Overlay
     private VecD lastPointerPos;
     private VecD lastPointerPos;
     private InfoBox infoBox;
     private InfoBox infoBox;
     private VecD lastSize;
     private VecD lastSize;
+    private bool actuallyMoved = false;
     
     
     public TransformOverlay()
     public TransformOverlay()
     {
     {
@@ -298,35 +308,10 @@ internal class TransformOverlay : Overlay
             UpdateRotationCursor(lastPointerPos);
             UpdateRotationCursor(lastPointerPos);
     }
     }
 
 
-    private void DrawMouseInputArea(Canvas context, VecD size)
-    {
-        if (CoverWholeScreen)
-        {
-            // TODO: Is it needed? Seems like it makes a hit area for avalonia
-            //context.DrawRect(new RectD(new VecD(-size.X * 50, -size.Y * 50), new VecD(size.X * 101, size.Y * 101)));
-            return;
-        }
-
-        StreamGeometry geometry = new();
-        using (StreamGeometryContext ctx = geometry.Open())
-        {
-            ctx.BeginFigure(TransformHelper.ToPoint(Corners.TopLeft), true);
-            ctx.LineTo(TransformHelper.ToPoint(Corners.TopRight));
-            ctx.LineTo(TransformHelper.ToPoint(Corners.BottomRight));
-            ctx.LineTo(TransformHelper.ToPoint(Corners.BottomLeft));
-            ctx.EndFigure(true);
-        }
-
-        // TODO: Is it needed? Seems like it makes a hit area for avalonia
-        //context.DrawGeometry(Brushes.Transparent, null, geometry);
-    }
-
     private void DrawOverlay
     private void DrawOverlay
         (Canvas context, VecD size, ShapeCorners corners, VecD origin, float zoomboxScale)
         (Canvas context, VecD size, ShapeCorners corners, VecD origin, float zoomboxScale)
     {
     {
         lastSize = size;
         lastSize = size;
-        // draw transparent background to enable mouse input
-        DrawMouseInputArea(context, size);
 
 
         handlePen.StrokeWidth = 1 / zoomboxScale;
         handlePen.StrokeWidth = 1 / zoomboxScale;
         blackDashedPen.StrokeWidth = 1 / zoomboxScale;
         blackDashedPen.StrokeWidth = 1 / zoomboxScale;
@@ -480,7 +465,7 @@ internal class TransformOverlay : Overlay
         {
         {
             return;
             return;
         }
         }
-
+        
         args.Pointer.Capture(this);
         args.Pointer.Capture(this);
         args.Handled = true;
         args.Handled = true;
     }
     }
@@ -496,6 +481,7 @@ internal class TransformOverlay : Overlay
         {
         {
             HandleTransform(pos);
             HandleTransform(pos);
             finalCursor = new Cursor(StandardCursorType.DragMove);
             finalCursor = new Cursor(StandardCursorType.DragMove);
+            actuallyMoved = true;
         }
         }
 
 
         if (capturedAnchor is not null)
         if (capturedAnchor is not null)
@@ -536,6 +522,11 @@ internal class TransformOverlay : Overlay
         if (e.InitialPressMouseButton != MouseButton.Left)
         if (e.InitialPressMouseButton != MouseButton.Left)
             return;
             return;
 
 
+        if (!isRotating && !actuallyMoved)
+        {
+            PassthroughPointerPressedCommand?.Execute(e.Point);
+        }
+
         if (isRotating)
         if (isRotating)
         {
         {
             isRotating = false;
             isRotating = false;
@@ -575,6 +566,7 @@ internal class TransformOverlay : Overlay
         mousePosOnStartMove = position;
         mousePosOnStartMove = position;
         originOnStartMove = InternalState.Origin;
         originOnStartMove = InternalState.Origin;
         cornersOnStartMove = Corners;
         cornersOnStartMove = Corners;
+        actuallyMoved = false;
     }
     }
 
 
     private void HandleTransform(VecD pos)
     private void HandleTransform(VecD pos)