Browse Source

Move tool click select works

flabbet 11 tháng trước cách đây
mục cha
commit
fa2f39732e
28 tập tin đã thay đổi với 144 bổ sung76 xóa
  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<VecD> OnMouseMove;
-    public EventHandler<MouseButton> OnMouseUp;
+    public EventHandler<MouseOnCanvasEventArgs> OnMouseUp;
 
 
     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 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(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;
-        if (!buttonStates[button])
+        if (!buttonStates[args.Button])
             return;
-        buttonStates[button] = false;
+        buttonStates[args.Button] = false;
 
-        OnMouseUp?.Invoke(this, button);
+        OnMouseUp?.Invoke(this, args);
     }
 
     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);
     }
 
-    public void LeftMouseButtonUpInlet()
+    public void LeftMouseButtonUpInlet(VecD argsPositionOnCanvas)
     {
         //update internal state
         LeftMousePressed = false;
 
         //call session events
-        currentSession?.OnLeftMouseButtonUp();
+        currentSession?.OnLeftMouseButtonUp(argsPositionOnCanvas);
     }
 
     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}";
         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 OnOpacitySliderDragged(float newValue) => Internals.ChangeController.OpacitySliderDraggedInlet(newValue);
     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);
     }
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
         internals!.ActionAccumulator.AddFinishedActions(new EndChangeBrightness_Action());
         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);
     }
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
         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());
     }
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
         if (ActiveMode != ShapeToolMode.Transform)
         {
@@ -259,13 +259,13 @@ internal abstract class ComplexShapeToolExecutor<T> : SimpleShapeToolExecutor wh
                 internals!.ActionAccumulator.AddFinishedActions(EndDrawAction());
                 AddMemberToSnapping();
 
-                base.OnLeftMouseButtonUp();
+                base.OnLeftMouseButtonUp(argsPositionOnCanvas);
                 onEnded?.Invoke(this);
                 return;
             }
         }
 
-        base.OnLeftMouseButtonUp();
+        base.OnLeftMouseButtonUp(argsPositionOnCanvas);
     }
 
     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);
     }
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
         internals!.ActionAccumulator.AddFinishedActions(new EndLineBasedPen_Action());
         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));
     }
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
         internals!.ActionAccumulator.AddActions(new ChangeBoundary_Action());
         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 OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
         internals!.ActionAccumulator.AddFinishedActions(new EndSelectLasso_Action());
         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);
     }
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
         if (!startedDrawing)
         {
-            base.OnLeftMouseButtonUp();
+            base.OnLeftMouseButtonUp(argsPositionOnCanvas);
             onEnded!(this);
             return;
         }
 
         document!.LineToolOverlayHandler.Show(startDrawingPos, curPos, true);
-        base.OnLeftMouseButtonUp();
+        base.OnLeftMouseButtonUp(argsPositionOnCanvas);
     }
 
     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.Linq;
+using Drawie.Numerics;
 using PixiEditor.ChangeableDocument.Actions.Generated;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.Enums;
@@ -37,7 +38,7 @@ internal class MagicWandToolExecutor : UpdateableChangeExecutor
         return ExecutionState.Success;
     }
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
         internals!.ActionAccumulator.AddActions(new ChangeBoundary_Action());
         onEnded!(this);

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

@@ -66,7 +66,7 @@ internal class PenToolExecutor : UpdateableChangeExecutor
         internals!.ActionAccumulator.AddActions(action);
     }
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
         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);
     }
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
         IAction action = CreateEndAction(selectShape);
         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);
     }
 
-    public override void OnLeftMouseButtonUp()
+    public override void OnLeftMouseButtonUp(VecD argsPositionOnCanvas)
     {
         internals!.ActionAccumulator.AddFinishedActions(new EndShiftLayer_Action());
         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);
         ActiveMode = ShapeToolMode.Transform;

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

@@ -21,10 +21,12 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
     private bool isInProgress;
     public override ExecutorType Type { get; }
 
-    public override bool BlocksOtherActions => false; 
-    
+    public override bool BlocksOtherActions => false;
+
     private List<Guid> selectedMembers = new();
 
+    private ShapeCorners lastCorners = new();
+
     public TransformSelectedExecutor(bool toolLinked)
     {
         Type = toolLinked ? ExecutorType.ToolLinked : ExecutorType.Regular;
@@ -46,6 +48,7 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
         if (!members.Any())
             return ExecutionState.Error;
 
+        document.TransformHandler.PassthroughPointerPressed += OnLeftMouseButtonDown;
         return SelectMembers(members);
     }
 
@@ -81,15 +84,18 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
         DocumentTransformMode mode = allRaster
             ? DocumentTransformMode.Scale_Rotate_Shear_Perspective
             : DocumentTransformMode.Scale_Rotate_Shear_NoPerspective;
-        
+
         foreach (var structureMemberHandler in members)
         {
             document.SnappingHandler.Remove(structureMemberHandler.Id.ToString());
         }
-        
+
         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(
             new TransformSelected_Action(masterCorners, tool.KeepOriginalImage, memberCorners, false,
                 document.AnimationHandler.ActiveFrameBindable));
@@ -98,6 +104,33 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
         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)
     {
         if (isInProgress)
@@ -105,7 +138,7 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
             internals.ActionAccumulator.AddActions(new EndTransformSelected_Action());
             document!.TransformHandler.HideTransform();
             AddSnappingForMembers(selectedMembers);
-            
+
             selectedMembers.Clear();
             memberCorners.Clear();
             isInProgress = false;
@@ -122,6 +155,12 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
     public bool IsTransforming => isInProgress;
 
     public void OnTransformMoved(ShapeCorners corners)
+    {
+        DoTransform(corners);
+        lastCorners = corners;
+    }
+
+    private void DoTransform(ShapeCorners corners)
     {
         if (!isInProgress)
             return;
@@ -138,7 +177,7 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
     public void OnMidChangeUndo() => document!.TransformHandler.Undo();
 
     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 void OnTransformApplied()
@@ -160,6 +199,7 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
         }
 
         isInProgress = false;
+        document.TransformHandler.PassthroughPointerPressed -= OnLeftMouseButtonDown;
     }
 
     public override void ForceStop()
@@ -175,8 +215,9 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
         AddSnappingForMembers(memberCorners.Keys.ToList());
 
         isInProgress = false;
+        document.TransformHandler.PassthroughPointerPressed -= OnLeftMouseButtonDown;
     }
-    
+
     private void AddSnappingForMembers(List<Guid> 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 OnPrecisePositionChange(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 OnOpacitySliderDragged(float newValue) { }
     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 PreviewPainter? ResultPainter { 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, INodeHandler, 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 HasUndo { 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'}"
                                         BorderThickness="2"
                                         Outputs="{Binding Outputs}"
-                                        IsSelected="{Binding IsSelected}"
+                                        IsSelected="{Binding IsNodeSelected}"
                                         SelectNodeCommand="{Binding SelectNodeCommand,
                                     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);
     }
 
+    public event Action<VecD>? PassthroughPointerPressed;
+
     private bool coverWholeScreen;
     public bool CoverWholeScreen
     {
@@ -110,6 +112,7 @@ internal class DocumentTransformViewModel : ObservableObject, ITransformHandler
         set => SetProperty(ref enableSnapping, value);
     }
     
+    
     private ExecutionTrigger<ShapeCorners> requestedCornersExecutor;
     public ExecutionTrigger<ShapeCorners> RequestCornersExecutor
     {
@@ -124,6 +127,15 @@ internal class DocumentTransformViewModel : ObservableObject, ITransformHandler
         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;
 
     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);
     }
     
-    public bool IsSelected
+    public bool IsNodeSelected
     {
         get => isSelected;
         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);
     }
 
-    private void OnMouseUp(object? sender, MouseButton button)
+    private void OnMouseUp(object? sender, MouseOnCanvasEventArgs args)
     {
+        var button = args.Button;
         bool toLeftRightClick = drawingWithRight == null ||
                                 (button == MouseButton.Left && drawingWithRight.Value) ||
                                 (button == MouseButton.Right && !drawingWithRight.Value);
@@ -284,7 +285,8 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
 
         if (button == MouseButton.Left || rightCanUp)
         {
-            Owner.DocumentManagerSubViewModel.ActiveDocument.EventInlet.OnCanvasLeftMouseButtonUp();
+            Owner.DocumentManagerSubViewModel.ActiveDocument.EventInlet
+                .OnCanvasLeftMouseButtonUp(args.PositionOnCanvas);
         }
 
         drawingWithRight = null;

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

@@ -19,7 +19,7 @@ internal class NodeGraphManagerViewModel : SubViewModel<ViewModelMain>
     public void DeleteSelectedNodes()
     {
         var nodes = Owner.DocumentManagerSubViewModel.ActiveDocument?.NodeGraph.AllNodes
-            .Where(x => x.IsSelected).ToList();
+            .Where(x => x.IsNodeSelected).ToList();
         
         if (nodes == null || nodes.Count == 0)
             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);
 
-    [Settings.Bool("KEEP_ORIGINAL_IMAGE_SETTING")]
+    [Settings.Bool("KEEP_ORIGINAL_IMAGE_SETTING", Notify = nameof(KeepOriginalChanged))]
     public bool KeepOriginalImage => GetValue<bool>();
 
     public override BrushShape BrushShape => BrushShape.Hidden;
@@ -55,7 +55,8 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
 
     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)
@@ -107,4 +108,10 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
         OnDeselecting(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
         };
+        
+        Binding passThroughPointerPressedBinding = new()
+        {
+            Source = Viewport, Path = "Document.TransformViewModel.PassThroughPointerPressedCommand", 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.SnapToAnglesProperty, snapToAnglesBinding);
         transformOverlay.Bind(TransformOverlay.InternalStateProperty, internalStateBinding);
+        transformOverlay.Bind(TransformOverlay.PassthroughPointerPressedCommandProperty, passThroughPointerPressedBinding);
         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
-        ? NodeGraph.AllNodes.Where(x => x.IsSelected).ToList()
+        ? NodeGraph.AllNodes.Where(x => x.IsNodeSelected).ToList()
         : new List<INodeHandler>();
 
     protected override Type StyleKeyOverride => typeof(NodeGraphView);
@@ -478,14 +478,14 @@ internal class NodeGraphView : Zoombox.Zoombox
             ClearSelection();
         }
 
-        viewModel.IsSelected = true;
+        viewModel.IsNodeSelected = true;
     }
 
     private void ClearSelection()
     {
         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),
             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
     {
         get => GetValue(InternalStateProperty);
@@ -231,6 +240,7 @@ internal class TransformOverlay : Overlay
     private VecD lastPointerPos;
     private InfoBox infoBox;
     private VecD lastSize;
+    private bool actuallyMoved = false;
     
     public TransformOverlay()
     {
@@ -298,35 +308,10 @@ internal class TransformOverlay : Overlay
             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
         (Canvas context, VecD size, ShapeCorners corners, VecD origin, float zoomboxScale)
     {
         lastSize = size;
-        // draw transparent background to enable mouse input
-        DrawMouseInputArea(context, size);
 
         handlePen.StrokeWidth = 1 / zoomboxScale;
         blackDashedPen.StrokeWidth = 1 / zoomboxScale;
@@ -480,7 +465,7 @@ internal class TransformOverlay : Overlay
         {
             return;
         }
-
+        
         args.Pointer.Capture(this);
         args.Handled = true;
     }
@@ -496,6 +481,7 @@ internal class TransformOverlay : Overlay
         {
             HandleTransform(pos);
             finalCursor = new Cursor(StandardCursorType.DragMove);
+            actuallyMoved = true;
         }
 
         if (capturedAnchor is not null)
@@ -536,6 +522,11 @@ internal class TransformOverlay : Overlay
         if (e.InitialPressMouseButton != MouseButton.Left)
             return;
 
+        if (!isRotating && !actuallyMoved)
+        {
+            PassthroughPointerPressedCommand?.Execute(e.Point);
+        }
+
         if (isRotating)
         {
             isRotating = false;
@@ -575,6 +566,7 @@ internal class TransformOverlay : Overlay
         mousePosOnStartMove = position;
         originOnStartMove = InternalState.Origin;
         cornersOnStartMove = Corners;
+        actuallyMoved = false;
     }
 
     private void HandleTransform(VecD pos)