Browse Source

Merge pull request #717 from PixiEditor/fixes/07.01.2025

Fixes/07.01.2025
Krzysztof Krysiński 7 months ago
parent
commit
a860820a6e
27 changed files with 169 additions and 106 deletions
  1. 1 1
      src/Drawie
  2. 1 1
      src/PixiDocks
  3. 1 1
      src/PixiEditor.ChangeableDocument/Changes/Animation/KeyFramesStartPos_UpdateableChange.cs
  4. 0 5
      src/PixiEditor.ChangeableDocument/Changes/NodeGraph/DuplicateNode_Change.cs
  5. 2 2
      src/PixiEditor/Data/Localization/Languages/en.json
  6. 1 1
      src/PixiEditor/Data/ShortcutActionMaps/AsepriteShortcutMap.json
  7. 31 5
      src/PixiEditor/Models/DocumentModels/ActionAccumulator.cs
  8. 22 0
      src/PixiEditor/Models/DocumentModels/Public/ChangeBlock.cs
  9. 6 0
      src/PixiEditor/Models/DocumentModels/Public/DocumentOperationsModule.cs
  10. 2 1
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/TransformSelectedExecutor.cs
  11. 3 10
      src/PixiEditor/Models/Rendering/CanvasUpdater.cs
  12. 17 12
      src/PixiEditor/Models/Rendering/MemberPreviewUpdater.cs
  13. 4 4
      src/PixiEditor/ViewModels/Dock/DocumentPreviewDockViewModel.cs
  14. 3 3
      src/PixiEditor/ViewModels/Dock/LayoutManager.cs
  15. 3 0
      src/PixiEditor/ViewModels/Document/DocumentViewModel.cs
  16. 6 1
      src/PixiEditor/ViewModels/SubViewModels/ClipboardViewModel.cs
  17. 2 2
      src/PixiEditor/ViewModels/SubViewModels/ToolsViewModel.cs
  18. 2 2
      src/PixiEditor/ViewModels/SubViewModels/WindowViewModel.cs
  19. 9 1
      src/PixiEditor/ViewModels/Tools/ToolSettings/Settings/Setting.cs
  20. 1 1
      src/PixiEditor/ViewModels/Tools/ToolSettings/Toolbars/Toolbar.cs
  21. 11 6
      src/PixiEditor/ViewModels/Tools/ToolViewModel.cs
  22. 3 3
      src/PixiEditor/ViewModels/Tools/Tools/MoveToolViewModel.cs
  23. 7 1
      src/PixiEditor/Views/Animations/Timeline.cs
  24. 4 4
      src/PixiEditor/Views/Dock/DocumentPreviewDockView.axaml
  25. 2 2
      src/PixiEditor/Views/Dock/DocumentPreviewDockView.axaml.cs
  26. 5 13
      src/PixiEditor/Views/Main/DocumentPreview.axaml
  27. 20 24
      src/PixiEditor/Views/Main/DocumentPreview.axaml.cs

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit 1dabfdaf8ccb547cee84689c08b4c1762b14c30e
+Subproject commit e9d3a727001548fe5d50793bfb31e5ececbfd8d1

+ 1 - 1
src/PixiDocks

@@ -1 +1 @@
-Subproject commit 0d356fcd1f07aa2b1c274284a3f81d302c593db6
+Subproject commit c843c98b5101129180f859f752f490fce1afc957

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changes/Animation/KeyFramesStartPos_UpdateableChange.cs

@@ -3,7 +3,7 @@ using PixiEditor.ChangeableDocument.ChangeInfos.Animation;
 
 
 namespace PixiEditor.ChangeableDocument.Changes.Animation;
 namespace PixiEditor.ChangeableDocument.Changes.Animation;
 
 
-internal class KeyFramesStartPos_UpdateableChange : UpdateableChange
+internal class KeyFramesStartPos_UpdateableChange : InterruptableUpdateableChange
 {
 {
     public Guid[] KeyFramesGuid { get;  }
     public Guid[] KeyFramesGuid { get;  }
     public int Delta { get; set; }
     public int Delta { get; set; }

+ 0 - 5
src/PixiEditor.ChangeableDocument/Changes/NodeGraph/DuplicateNode_Change.cs

@@ -44,9 +44,4 @@ internal class DuplicateNode_Change : Change
 
 
         return new DeleteNode_ChangeInfo(node.Id);
         return new DeleteNode_ChangeInfo(node.Id);
     }
     }
-
-    public override bool IsMergeableWith(Change other)
-    {
-        return other is DuplicateNode_Change;
-    }
 }
 }

+ 2 - 2
src/PixiEditor/Data/Localization/Languages/en.json

@@ -260,7 +260,7 @@
   "OPEN_STARTUP_WINDOW": "Open startup window",
   "OPEN_STARTUP_WINDOW": "Open startup window",
   "OPEN_SHORTCUT_WINDOW": "Open shortcuts window",
   "OPEN_SHORTCUT_WINDOW": "Open shortcuts window",
   "OPEN_ABOUT_WINDOW": "Open about window",
   "OPEN_ABOUT_WINDOW": "Open about window",
-  "OPEN_NAVIGATION_WINDOW": "Open navigation window",
+  "OPEN_PREVIEW_WINDOW": "Open preview window",
   "ERROR": "Error",
   "ERROR": "Error",
   "INTERNAL_ERROR": "Internal error",
   "INTERNAL_ERROR": "Internal error",
   "ERROR_SAVE_LOCATION": "Couldn't save the file to the specified location",
   "ERROR_SAVE_LOCATION": "Couldn't save the file to the specified location",
@@ -381,7 +381,7 @@
   "PALETTE_TITLE": "Palette",
   "PALETTE_TITLE": "Palette",
   "SWATCHES_TITLE": "Swatches",
   "SWATCHES_TITLE": "Swatches",
   "LAYERS_TITLE": "Layers",
   "LAYERS_TITLE": "Layers",
-  "NAVIGATION_TITLE": "Navigation",
+  "PREVIEW_TITLE": "Preview",
   "NORMAL_BLEND_MODE": "Normal",
   "NORMAL_BLEND_MODE": "Normal",
   "ERASE_BLEND_MODE": "Erase",
   "ERASE_BLEND_MODE": "Erase",
   "DARKEN_BLEND_MODE": "Darken",
   "DARKEN_BLEND_MODE": "Darken",

+ 1 - 1
src/PixiEditor/Data/ShortcutActionMaps/AsepriteShortcutMap.json

@@ -436,7 +436,7 @@
       "Parameters": []
       "Parameters": []
     },
     },
     "TogglePreview": {
     "TogglePreview": {
-      "Command": "PixiEditor.Window.OpenNavigationWindow",
+      "Command": "PixiEditor.Window.OpenPreviewWindow",
       "DefaultShortcut": {
       "DefaultShortcut": {
         "key": "F7",
         "key": "F7",
         "modifiers": null
         "modifiers": null

+ 31 - 5
src/PixiEditor/Models/DocumentModels/ActionAccumulator.cs

@@ -23,6 +23,8 @@ internal class ActionAccumulator
     private CanvasUpdater canvasUpdater;
     private CanvasUpdater canvasUpdater;
     private MemberPreviewUpdater previewUpdater;
     private MemberPreviewUpdater previewUpdater;
 
 
+    private bool isChangeBlockActive = false;
+
     public ActionAccumulator(IDocument doc, DocumentInternalParts internals)
     public ActionAccumulator(IDocument doc, DocumentInternalParts internals)
     {
     {
         this.document = doc;
         this.document = doc;
@@ -32,6 +34,21 @@ internal class ActionAccumulator
         previewUpdater = new(doc, internals);
         previewUpdater = new(doc, internals);
     }
     }
 
 
+    public void StartChangeBlock()
+    {
+        if (isChangeBlockActive)
+            throw new InvalidOperationException("Change block is already active");
+
+        isChangeBlockActive = true;
+    }
+
+    public void EndChangeBlock()
+    {
+        isChangeBlockActive = false;
+        queuedActions.Add((ActionSource.Automated, new ChangeBoundary_Action()));
+        TryExecuteAccumulatedActions();
+    }
+
     public void AddFinishedActions(params IAction[] actions)
     public void AddFinishedActions(params IAction[] actions)
     {
     {
         foreach (var action in actions)
         foreach (var action in actions)
@@ -39,8 +56,11 @@ internal class ActionAccumulator
             queuedActions.Add((ActionSource.User, action));
             queuedActions.Add((ActionSource.User, action));
         }
         }
 
 
-        queuedActions.Add((ActionSource.Automated, new ChangeBoundary_Action()));
-        TryExecuteAccumulatedActions();
+        if (!isChangeBlockActive)
+        {
+            queuedActions.Add((ActionSource.Automated, new ChangeBoundary_Action()));
+            TryExecuteAccumulatedActions();
+        }
     }
     }
 
 
     public void AddActions(params IAction[] actions)
     public void AddActions(params IAction[] actions)
@@ -50,7 +70,10 @@ internal class ActionAccumulator
             queuedActions.Add((ActionSource.User, action));
             queuedActions.Add((ActionSource.User, action));
         }
         }
 
 
-        TryExecuteAccumulatedActions();
+        if (!isChangeBlockActive)
+        {
+            TryExecuteAccumulatedActions();
+        }
     }
     }
 
 
     public void AddActions(ActionSource source, IAction action)
     public void AddActions(ActionSource source, IAction action)
@@ -59,7 +82,7 @@ internal class ActionAccumulator
         TryExecuteAccumulatedActions();
         TryExecuteAccumulatedActions();
     }
     }
 
 
-    private async void TryExecuteAccumulatedActions()
+    internal async Task TryExecuteAccumulatedActions()
     {
     {
         if (executing || queuedActions.Count == 0)
         if (executing || queuedActions.Count == 0)
             return;
             return;
@@ -92,6 +115,8 @@ internal class ActionAccumulator
                 toExecute.Any(static action => action.action is ChangeBoundary_Action or Redo_Action or Undo_Action);
                 toExecute.Any(static action => action.action is ChangeBoundary_Action or Redo_Action or Undo_Action);
             bool viewportRefreshRequest =
             bool viewportRefreshRequest =
                 toExecute.Any(static action => action.action is RefreshViewport_PassthroughAction);
                 toExecute.Any(static action => action.action is RefreshViewport_PassthroughAction);
+            bool changeFrameRequest =
+                toExecute.Any(static action => action.action is SetActiveFrame_PassthroughAction);
             foreach (IChangeInfo info in optimizedChanges)
             foreach (IChangeInfo info in optimizedChanges)
             {
             {
                 internals.Updater.ApplyChangeFromChangeInfo(info);
                 internals.Updater.ApplyChangeFromChangeInfo(info);
@@ -114,7 +139,8 @@ internal class ActionAccumulator
                     undoBoundaryPassed || viewportRefreshRequest);
                     undoBoundaryPassed || viewportRefreshRequest);
             }
             }
 
 
-            previewUpdater.UpdatePreviews(undoBoundaryPassed, affectedAreas.ImagePreviewAreas.Keys, affectedAreas.MaskPreviewAreas.Keys,
+            previewUpdater.UpdatePreviews(undoBoundaryPassed || changeFrameRequest || viewportRefreshRequest, affectedAreas.ImagePreviewAreas.Keys,
+                affectedAreas.MaskPreviewAreas.Keys,
                 affectedAreas.ChangedNodes, affectedAreas.ChangedKeyFrames);
                 affectedAreas.ChangedNodes, affectedAreas.ChangedKeyFrames);
 
 
             // force refresh viewports for better responsiveness
             // force refresh viewports for better responsiveness

+ 22 - 0
src/PixiEditor/Models/DocumentModels/Public/ChangeBlock.cs

@@ -0,0 +1,22 @@
+namespace PixiEditor.Models.DocumentModels.Public;
+
+public class ChangeBlock : IDisposable
+{
+    private ActionAccumulator Accumulator { get; }
+    
+    internal ChangeBlock(ActionAccumulator accumulator)
+    {
+        Accumulator = accumulator;
+        Accumulator.StartChangeBlock();
+    }
+    
+    public async Task ExecuteQueuedActions()
+    {
+        await Accumulator.TryExecuteAccumulatedActions();
+    }
+    
+    public void Dispose()
+    {
+        Accumulator.EndChangeBlock();
+    }
+}

+ 6 - 0
src/PixiEditor/Models/DocumentModels/Public/DocumentOperationsModule.cs

@@ -1,4 +1,5 @@
 using System.Collections.Immutable;
 using System.Collections.Immutable;
+using System.Reactive.Disposables;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument;
 using PixiEditor.ChangeableDocument;
 using PixiEditor.ChangeableDocument.Actions;
 using PixiEditor.ChangeableDocument.Actions;
@@ -33,6 +34,11 @@ internal class DocumentOperationsModule : IDocumentOperations
         Document = document;
         Document = document;
         Internals = internals;
         Internals = internals;
     }
     }
+    
+    public ChangeBlock StartChangeBlock()
+    {
+        return new ChangeBlock(Internals.ActionAccumulator);
+    }
 
 
     /// <summary>
     /// <summary>
     /// Creates a new selection with the size of the document
     /// Creates a new selection with the size of the document

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

@@ -45,7 +45,8 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
 
 
         members = document.SoftSelectedStructureMembers
         members = document.SoftSelectedStructureMembers
             .Append(document.SelectedStructureMember)
             .Append(document.SelectedStructureMember)
-            .Where(static m => m is ILayerHandler).ToList();
+            .Where(static m => m is ILayerHandler)
+            .Distinct().ToList();
 
 
         if (!members.Any())
         if (!members.Any())
             return ExecutionState.Error;
             return ExecutionState.Error;

+ 3 - 10
src/PixiEditor/Models/Rendering/CanvasUpdater.cs

@@ -22,13 +22,6 @@ internal class CanvasUpdater
     private int lastOnionKeyFrames = -1;
     private int lastOnionKeyFrames = -1;
     private double lastOnionOpacity = -1;
     private double lastOnionOpacity = -1;
 
 
-    private static readonly Paint ReplacingPaint = new() { BlendMode = BlendMode.Src };
-
-    private static readonly Paint ClearPaint = new()
-    {
-        BlendMode = BlendMode.Src, Color = Colors.Transparent
-    };
-
     /// <summary>
     /// <summary>
     /// Affected chunks that have not been rerendered yet.
     /// Affected chunks that have not been rerendered yet.
     /// </summary>
     /// </summary>
@@ -65,7 +58,7 @@ internal class CanvasUpdater
     /// </summary>
     /// </summary>
     public async Task UpdateGatheredChunks
     public async Task UpdateGatheredChunks
         (AffectedAreasGatherer chunkGatherer, bool rerenderDelayed)
         (AffectedAreasGatherer chunkGatherer, bool rerenderDelayed)
-    { 
+    {
         await Task.Run(() => Render(chunkGatherer, rerenderDelayed)).ConfigureAwait(true);
         await Task.Run(() => Render(chunkGatherer, rerenderDelayed)).ConfigureAwait(true);
     }
     }
 
 
@@ -157,7 +150,7 @@ internal class CanvasUpdater
     {
     {
         Dictionary<ChunkResolution, HashSet<VecI>> chunksToRerender =
         Dictionary<ChunkResolution, HashSet<VecI>> chunksToRerender =
             FindGlobalChunksToRerender(chunkGatherer, rerenderDelayed);
             FindGlobalChunksToRerender(chunkGatherer, rerenderDelayed);
-        
+
         ChunkResolution onionSkinResolution = chunksToRerender.Min(x => x.Key);
         ChunkResolution onionSkinResolution = chunksToRerender.Min(x => x.Key);
 
 
         bool updatingStoredChunks = false;
         bool updatingStoredChunks = false;
@@ -199,7 +192,7 @@ internal class CanvasUpdater
             if (globalClippingRectangle is not null)
             if (globalClippingRectangle is not null)
                 globalScaledClippingRectangle =
                 globalScaledClippingRectangle =
                     (RectI?)((RectI)globalClippingRectangle).Scale(resolution.Multiplier()).RoundOutwards();
                     (RectI?)((RectI)globalClippingRectangle).Scale(resolution.Multiplier()).RoundOutwards();
-            
+
             foreach (var chunkPos in chunks)
             foreach (var chunkPos in chunks)
             {
             {
                 RenderChunk(chunkPos, resolution);
                 RenderChunk(chunkPos, resolution);

+ 17 - 12
src/PixiEditor/Models/Rendering/MemberPreviewUpdater.cs

@@ -33,10 +33,15 @@ internal class MemberPreviewUpdater
         AnimationKeyFramePreviewRenderer = new AnimationKeyFramePreviewRenderer(internals);
         AnimationKeyFramePreviewRenderer = new AnimationKeyFramePreviewRenderer(internals);
     }
     }
 
 
-    public void UpdatePreviews(bool undoBoundaryPassed, IEnumerable<Guid> membersToUpdate,
+    public void UpdatePreviews(bool rerenderPreviews, IEnumerable<Guid> membersToUpdate,
         IEnumerable<Guid> masksToUpdate, IEnumerable<Guid> nodesToUpdate, IEnumerable<Guid> keyFramesToUpdate)
         IEnumerable<Guid> masksToUpdate, IEnumerable<Guid> nodesToUpdate, IEnumerable<Guid> keyFramesToUpdate)
     {
     {
-        UpdatePreviewPainters(membersToUpdate, masksToUpdate, nodesToUpdate, keyFramesToUpdate, undoBoundaryPassed);
+        if (!rerenderPreviews)
+        {
+            return;
+        }
+
+        UpdatePreviewPainters(membersToUpdate, masksToUpdate, nodesToUpdate, keyFramesToUpdate);
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -45,20 +50,17 @@ internal class MemberPreviewUpdater
     /// <param name="members">Members that should be rendered</param>
     /// <param name="members">Members that should be rendered</param>
     /// <param name="masksToUpdate">Masks that should be rendered</param>
     /// <param name="masksToUpdate">Masks that should be rendered</param>
     private void UpdatePreviewPainters(IEnumerable<Guid> members, IEnumerable<Guid> masksToUpdate,
     private void UpdatePreviewPainters(IEnumerable<Guid> members, IEnumerable<Guid> masksToUpdate,
-        IEnumerable<Guid> nodesToUpdate, IEnumerable<Guid> keyFramesToUpdate, bool undoBoundaryPassed)
+        IEnumerable<Guid> nodesToUpdate, IEnumerable<Guid> keyFramesToUpdate)
     {
     {
         Guid[] memberGuids = members as Guid[] ?? members.ToArray();
         Guid[] memberGuids = members as Guid[] ?? members.ToArray();
         Guid[] maskGuids = masksToUpdate as Guid[] ?? masksToUpdate.ToArray();
         Guid[] maskGuids = masksToUpdate as Guid[] ?? masksToUpdate.ToArray();
         Guid[] nodesGuids = nodesToUpdate as Guid[] ?? nodesToUpdate.ToArray();
         Guid[] nodesGuids = nodesToUpdate as Guid[] ?? nodesToUpdate.ToArray();
         Guid[] keyFramesGuids = keyFramesToUpdate as Guid[] ?? keyFramesToUpdate.ToArray();
         Guid[] keyFramesGuids = keyFramesToUpdate as Guid[] ?? keyFramesToUpdate.ToArray();
 
 
-        if (undoBoundaryPassed)
-        {
-            RenderWholeCanvasPreview();
-        }
-
+        RenderWholeCanvasPreview();
         RenderLayersPreview(memberGuids);
         RenderLayersPreview(memberGuids);
         RenderMaskPreviews(maskGuids);
         RenderMaskPreviews(maskGuids);
+
         RenderAnimationPreviews(memberGuids, keyFramesGuids);
         RenderAnimationPreviews(memberGuids, keyFramesGuids);
 
 
         RenderNodePreviews(nodesGuids);
         RenderNodePreviews(nodesGuids);
@@ -70,7 +72,7 @@ internal class MemberPreviewUpdater
     private void RenderWholeCanvasPreview()
     private void RenderWholeCanvasPreview()
     {
     {
         var previewSize = StructureHelpers.CalculatePreviewSize(internals.Tracker.Document.Size);
         var previewSize = StructureHelpers.CalculatePreviewSize(internals.Tracker.Document.Size);
-        float scaling = (float)previewSize.X / doc.SizeBindable.X;
+        //float scaling = (float)previewSize.X / doc.SizeBindable.X;
 
 
         if (doc.PreviewPainter == null)
         if (doc.PreviewPainter == null)
         {
         {
@@ -78,6 +80,9 @@ internal class MemberPreviewUpdater
                 doc.SizeBindable, internals.Tracker.Document.ProcessingColorSpace);
                 doc.SizeBindable, internals.Tracker.Document.ProcessingColorSpace);
         }
         }
 
 
+        doc.PreviewPainter.DocumentSize = doc.SizeBindable;
+        doc.PreviewPainter.ProcessingColorSpace = internals.Tracker.Document.ProcessingColorSpace;
+        doc.PreviewPainter.FrameTime = doc.AnimationHandler.ActiveFrameTime;
         doc.PreviewPainter.Repaint();
         doc.PreviewPainter.Repaint();
     }
     }
 
 
@@ -241,10 +246,10 @@ internal class MemberPreviewUpdater
         var executionQueue =
         var executionQueue =
             internals.Tracker.Document.NodeGraph
             internals.Tracker.Document.NodeGraph
                 .AllNodes; //internals.Tracker.Document.NodeGraph.CalculateExecutionQueue(outputNode);
                 .AllNodes; //internals.Tracker.Document.NodeGraph.CalculateExecutionQueue(outputNode);
-        
-        if(nodesGuids.Length == 0)
+
+        if (nodesGuids.Length == 0)
             return;
             return;
-        
+
         foreach (var node in executionQueue)
         foreach (var node in executionQueue)
         {
         {
             if (node is null)
             if (node is null)

+ 4 - 4
src/PixiEditor/ViewModels/Dock/NavigationDockViewModel.cs → src/PixiEditor/ViewModels/Dock/DocumentPreviewDockViewModel.cs

@@ -7,12 +7,12 @@ using PixiEditor.ViewModels.SubViewModels;
 
 
 namespace PixiEditor.ViewModels.Dock;
 namespace PixiEditor.ViewModels.Dock;
 
 
-internal class NavigationDockViewModel : DockableViewModel
+internal class DocumentPreviewDockViewModel : DockableViewModel
 {
 {
-    public const string TabId = "Navigator";
+    public const string TabId = "DocumentPreview";
 
 
     public override string Id => TabId;
     public override string Id => TabId;
-    public override string Title => new LocalizedString("NAVIGATION_TITLE");
+    public override string Title => new LocalizedString("PREVIEW_TITLE");
     public override bool CanFloat => true;
     public override bool CanFloat => true;
     public override bool CanClose => true;
     public override bool CanClose => true;
 
 
@@ -32,7 +32,7 @@ internal class NavigationDockViewModel : DockableViewModel
         set => SetProperty(ref documentManagerSubViewModel, value);
         set => SetProperty(ref documentManagerSubViewModel, value);
     }
     }
 
 
-    public NavigationDockViewModel(ColorsViewModel colorsSubViewModel, DocumentManagerViewModel documentManagerViewModel)
+    public DocumentPreviewDockViewModel(ColorsViewModel colorsSubViewModel, DocumentManagerViewModel documentManagerViewModel)
     {
     {
         ColorsSubViewModel = colorsSubViewModel;
         ColorsSubViewModel = colorsSubViewModel;
         DocumentManagerSubViewModel = documentManagerViewModel;
         DocumentManagerSubViewModel = documentManagerViewModel;

+ 3 - 3
src/PixiEditor/ViewModels/Dock/LayoutManager.cs

@@ -33,7 +33,7 @@ internal class LayoutManager
         LayersDockViewModel layersDockViewModel = new(mainViewModel.DocumentManagerSubViewModel);
         LayersDockViewModel layersDockViewModel = new(mainViewModel.DocumentManagerSubViewModel);
         ColorPickerDockViewModel colorPickerDockViewModel = new(mainViewModel.ColorsSubViewModel);
         ColorPickerDockViewModel colorPickerDockViewModel = new(mainViewModel.ColorsSubViewModel);
         ColorSlidersDockViewModel colorSldersDockViewModel = new(mainViewModel.ColorsSubViewModel);
         ColorSlidersDockViewModel colorSldersDockViewModel = new(mainViewModel.ColorsSubViewModel);
-        NavigationDockViewModel navigationDockViewModel =
+        DocumentPreviewDockViewModel documentPreviewDockViewModel =
             new(mainViewModel.ColorsSubViewModel, mainViewModel.DocumentManagerSubViewModel);
             new(mainViewModel.ColorsSubViewModel, mainViewModel.DocumentManagerSubViewModel);
         SwatchesDockViewModel swatchesDockViewModel = new(mainViewModel.DocumentManagerSubViewModel);
         SwatchesDockViewModel swatchesDockViewModel = new(mainViewModel.DocumentManagerSubViewModel);
         PaletteViewerDockViewModel paletteViewerDockViewModel =
         PaletteViewerDockViewModel paletteViewerDockViewModel =
@@ -48,7 +48,7 @@ internal class LayoutManager
         RegisterDockable(layersDockViewModel);
         RegisterDockable(layersDockViewModel);
         RegisterDockable(colorPickerDockViewModel);
         RegisterDockable(colorPickerDockViewModel);
         RegisterDockable(colorSldersDockViewModel);
         RegisterDockable(colorSldersDockViewModel);
-        RegisterDockable(navigationDockViewModel);
+        RegisterDockable(documentPreviewDockViewModel);
         RegisterDockable(swatchesDockViewModel);
         RegisterDockable(swatchesDockViewModel);
         RegisterDockable(paletteViewerDockViewModel);
         RegisterDockable(paletteViewerDockViewModel);
         RegisterDockable(timelineDockViewModel);
         RegisterDockable(timelineDockViewModel);
@@ -101,7 +101,7 @@ internal class LayoutManager
                     SplitDirection = DockingDirection.Bottom,
                     SplitDirection = DockingDirection.Bottom,
                     Second = new DockableArea
                     Second = new DockableArea
                     {
                     {
-                        Id = "NavigatorArea", ActiveDockable = DockContext.CreateDockable(navigationDockViewModel)
+                        Id = "DocumentPreviewArea", ActiveDockable = DockContext.CreateDockable(documentPreviewDockViewModel)
                     }
                     }
                 }
                 }
             }
             }

+ 3 - 0
src/PixiEditor/ViewModels/Document/DocumentViewModel.cs

@@ -807,18 +807,21 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
     {
     {
         softSelectedStructureMembers.Add(member);
         softSelectedStructureMembers.Add(member);
         Internals.ChangeController.MembersSelectedInlet(GetSelectedMembers());
         Internals.ChangeController.MembersSelectedInlet(GetSelectedMembers());
+        OnPropertyChanged(nameof(SoftSelectedStructureMembers));
     }
     }
 
 
     public void RemoveSoftSelectedMember(IStructureMemberHandler member)
     public void RemoveSoftSelectedMember(IStructureMemberHandler member)
     {
     {
         softSelectedStructureMembers.Remove(member);
         softSelectedStructureMembers.Remove(member);
         Internals.ChangeController.MembersSelectedInlet(GetSelectedMembers());
         Internals.ChangeController.MembersSelectedInlet(GetSelectedMembers());
+        OnPropertyChanged(nameof(SoftSelectedStructureMembers));
     }
     }
 
 
     public void ClearSoftSelectedMembers()
     public void ClearSoftSelectedMembers()
     {
     {
         softSelectedStructureMembers.Clear();
         softSelectedStructureMembers.Clear();
         Internals.ChangeController.MembersSelectedInlet(GetSelectedMembers());
         Internals.ChangeController.MembersSelectedInlet(GetSelectedMembers());
+        OnPropertyChanged(nameof(SoftSelectedStructureMembers));
     }
     }
 
 
     #endregion
     #endregion

+ 6 - 1
src/PixiEditor/ViewModels/SubViewModels/ClipboardViewModel.cs

@@ -163,6 +163,8 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
 
 
         Dictionary<Guid, Guid> nodeMapping = new();
         Dictionary<Guid, Guid> nodeMapping = new();
 
 
+        using var block = doc.Operations.StartChangeBlock();
+
         foreach (var nodeId in toDuplicate)
         foreach (var nodeId in toDuplicate)
         {
         {
             Guid? newId = doc.Operations.DuplicateNode(nodeId);
             Guid? newId = doc.Operations.DuplicateNode(nodeId);
@@ -175,10 +177,13 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
 
 
         if (newIds.Count == 0)
         if (newIds.Count == 0)
             return;
             return;
+
+        await block.ExecuteQueuedActions();
         
         
+        ConnectRelatedNodes(doc, nodeMapping);
+
         doc.Operations.InvokeCustomAction(() =>
         doc.Operations.InvokeCustomAction(() =>
         {
         {
-            ConnectRelatedNodes(doc, nodeMapping);
             foreach (var node in doc.NodeGraph.AllNodes)
             foreach (var node in doc.NodeGraph.AllNodes)
             {
             {
                 node.IsNodeSelected = false;
                 node.IsNodeSelected = false;

+ 2 - 2
src/PixiEditor/ViewModels/SubViewModels/ToolsViewModel.cs

@@ -504,7 +504,7 @@ internal class ToolsViewModel : SubViewModel<ViewModelMain>, IToolsHandler
 
 
     private void DocumentOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
     private void DocumentOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
     {
     {
-        if (e.PropertyName == nameof(DocumentViewModel.SelectedStructureMember))
+        if (e.PropertyName is nameof(DocumentViewModel.SelectedStructureMember) or nameof(DocumentViewModel.SoftSelectedStructureMembers))
         {
         {
             UpdateEnabledState();
             UpdateEnabledState();
         }
         }
@@ -530,7 +530,7 @@ internal class ToolsViewModel : SubViewModel<ViewModelMain>, IToolsHandler
                     doc.SelectedStructureMember
                     doc.SelectedStructureMember
                 };
                 };
 
 
-                selectedLayers.AddRange(doc.SoftSelectedStructureMembers);
+                selectedLayers.AddRange(doc.SoftSelectedStructureMembers.Except(selectedLayers));
                 tool.SelectedLayersChanged(selectedLayers.ToArray());
                 tool.SelectedLayersChanged(selectedLayers.ToArray());
             }
             }
         }
         }

+ 2 - 2
src/PixiEditor/ViewModels/SubViewModels/WindowViewModel.cs

@@ -210,8 +210,8 @@ internal class WindowViewModel : SubViewModel<ViewModelMain>
     }
     }
 
 
     [Commands_Command.Internal("PixiEditor.Window.ShowDockWindow")]
     [Commands_Command.Internal("PixiEditor.Window.ShowDockWindow")]
-    [Commands_Command.Basic("PixiEditor.Window.OpenNavigationWindow", "Navigator", "OPEN_NAVIGATION_WINDOW",
-        "OPEN_NAVIGATION_WINDOW")]
+    [Commands_Command.Basic("PixiEditor.Window.OpenPreviewWindow", "DocumentPreview", "OPEN_PREVIEW_WINDOW",
+        "OPEN_PREVIEW_WINDOW")]
     public void ShowDockWindow(string id)
     public void ShowDockWindow(string id)
     {
     {
         Owner.LayoutSubViewModel.LayoutManager.ShowDockable(id);
         Owner.LayoutSubViewModel.LayoutManager.ShowDockable(id);

+ 9 - 1
src/PixiEditor/ViewModels/Tools/ToolSettings/Settings/Setting.cs

@@ -27,7 +27,15 @@ internal abstract class Setting<T> : Setting
 
 
     public new virtual T Value
     public new virtual T Value
     {
     {
-        get => (T)base.Value;
+        get
+        {
+            if(base.Value != null && base.Value is not T value)
+            {
+                return default;
+            }
+            
+            return (T)base.Value;
+        }
         set
         set
         {
         {
             T oldValue = default;
             T oldValue = default;

+ 1 - 1
src/PixiEditor/ViewModels/Tools/ToolSettings/Toolbars/Toolbar.cs

@@ -44,7 +44,7 @@ internal abstract class Toolbar : ObservableObject, IToolbar
     {
     {
         Setting setting = Settings.FirstOrDefault(currentSetting => string.Equals(currentSetting.Name, name, StringComparison.CurrentCultureIgnoreCase));
         Setting setting = Settings.FirstOrDefault(currentSetting => string.Equals(currentSetting.Name, name, StringComparison.CurrentCultureIgnoreCase));
 
 
-        if (setting is null || setting is not T convertedSetting)
+        if (setting is not T convertedSetting)
         {
         {
             return null;
             return null;
         }
         }

+ 11 - 6
src/PixiEditor/ViewModels/Tools/ToolViewModel.cs

@@ -77,9 +77,9 @@ internal abstract class ToolViewModel : ObservableObject, IToolHandler
             OnPropertyChanged(nameof(ActionDisplay));
             OnPropertyChanged(nameof(ActionDisplay));
         }
         }
     }
     }
-    
+
     public string IconOverwrite { get; set; }
     public string IconOverwrite { get; set; }
-    
+
     public string IconToUse => IconOverwrite ?? DefaultIcon;
     public string IconToUse => IconOverwrite ?? DefaultIcon;
 
 
     private bool isActive;
     private bool isActive;
@@ -110,6 +110,11 @@ internal abstract class ToolViewModel : ObservableObject, IToolHandler
         if (layers.Length is > 1 or 0)
         if (layers.Length is > 1 or 0)
         {
         {
             CanBeUsedOnActiveLayer = SupportedLayerTypes == null;
             CanBeUsedOnActiveLayer = SupportedLayerTypes == null;
+            if (IsActive)
+            {
+                OnSelectedLayersChanged(layers);
+            }
+
             return;
             return;
         }
         }
 
 
@@ -151,7 +156,7 @@ internal abstract class ToolViewModel : ObservableObject, IToolHandler
     public virtual void ModifierKeyChanged(bool ctrlIsDown, bool shiftIsDown, bool altIsDown) { }
     public virtual void ModifierKeyChanged(bool ctrlIsDown, bool shiftIsDown, bool altIsDown) { }
 
 
     public virtual void UseTool(VecD pos) { }
     public virtual void UseTool(VecD pos) { }
-    
+
     protected virtual void OnSelected(bool restoring) { }
     protected virtual void OnSelected(bool restoring) { }
 
 
     public void OnToolSelected(bool restoring)
     public void OnToolSelected(bool restoring)
@@ -179,7 +184,7 @@ internal abstract class ToolViewModel : ObservableObject, IToolHandler
     protected virtual void OnDeselecting(bool transient)
     protected virtual void OnDeselecting(bool transient)
     {
     {
     }
     }
-    
+
     public virtual void OnPostUndo() { }
     public virtual void OnPostUndo() { }
     public virtual void OnPostRedo() { }
     public virtual void OnPostRedo() { }
     public virtual void OnActiveFrameChanged(int newFrame) { }
     public virtual void OnActiveFrameChanged(int newFrame) { }
@@ -209,8 +214,8 @@ internal abstract class ToolViewModel : ObservableObject, IToolHandler
         {
         {
             toolbarSetting.ResetOverwrite();
             toolbarSetting.ResetOverwrite();
         }
         }
-        
-        if(toolset.IconOverwrites.TryGetValue(this, out var icon))
+
+        if (toolset.IconOverwrites.TryGetValue(this, out var icon))
         {
         {
             IconOverwrite = icon;
             IconOverwrite = icon;
         }
         }

+ 3 - 3
src/PixiEditor/ViewModels/Tools/Tools/MoveToolViewModel.cs

@@ -100,7 +100,7 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
     {
     {
         if (IsActive)
         if (IsActive)
         {
         {
-            OnSelected(false);
+           OnToolSelected(false);
         }
         }
     }
     }
 
 
@@ -108,7 +108,7 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
     {
     {
         if (IsActive)
         if (IsActive)
         {
         {
-            OnSelected(false);
+            OnToolSelected(false);
         }
         }
     }
     }
 
 
@@ -124,7 +124,7 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
 
 
     private void UpdateSelection()
     private void UpdateSelection()
     {
     {
-        OnDeselecting(false);
+        OnToolDeselected(false);
         OnToolSelected(false);
         OnToolSelected(false);
     }
     }
 
 

+ 7 - 1
src/PixiEditor/Views/Animations/Timeline.cs

@@ -191,6 +191,7 @@ internal class Timeline : TemplatedControl, INotifyPropertyChanged
     private bool shouldClearNextSelection = true;
     private bool shouldClearNextSelection = true;
     private CelViewModel clickedCel;
     private CelViewModel clickedCel;
     private bool dragged;
     private bool dragged;
+    private Guid[] draggedKeyFrames;
     private int dragStartFrame;
     private int dragStartFrame;
 
 
     public event PropertyChangedEventHandler? PropertyChanged;
     public event PropertyChangedEventHandler? PropertyChanged;
@@ -229,6 +230,8 @@ internal class Timeline : TemplatedControl, INotifyPropertyChanged
         
         
         Guid[] ids = SelectedKeyFrames.Select(x => x.Id).ToArray();
         Guid[] ids = SelectedKeyFrames.Select(x => x.Id).ToArray();
         
         
+        draggedKeyFrames = ids;
+        
         ChangeKeyFramesLengthCommand.Execute((ids, delta, false));
         ChangeKeyFramesLengthCommand.Execute((ids, delta, false));
         return true;
         return true;
     }
     }
@@ -237,7 +240,10 @@ internal class Timeline : TemplatedControl, INotifyPropertyChanged
     {
     {
         if (dragged)
         if (dragged)
         {
         {
-            ChangeKeyFramesLengthCommand.Execute((SelectedKeyFrames.Select(x => x.Id).ToArray(), 0, true));
+            if (draggedKeyFrames.Length > 0)
+            {
+                ChangeKeyFramesLengthCommand.Execute((draggedKeyFrames.ToArray(), 0, true));
+            }
         }
         }
         clickedCel = null;
         clickedCel = null;
     }
     }

+ 4 - 4
src/PixiEditor/Views/Dock/NavigationDockView.axaml → src/PixiEditor/Views/Dock/DocumentPreviewDockView.axaml

@@ -6,11 +6,11 @@
              xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
              xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
              xmlns:dock="clr-namespace:PixiEditor.ViewModels.Dock"
              xmlns:dock="clr-namespace:PixiEditor.ViewModels.Dock"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
-             x:DataType="dock:NavigationDockViewModel"
-             x:Class="PixiEditor.Views.Dock.NavigationDockView">
+             x:DataType="dock:DocumentPreviewDockViewModel"
+             x:Class="PixiEditor.Views.Dock.DocumentPreviewDockView">
     <Design.DataContext>
     <Design.DataContext>
-        <dock:NavigationDockViewModel/>
+        <dock:DocumentPreviewDockViewModel/>
     </Design.DataContext>
     </Design.DataContext>
-    <main:Navigation Document="{Binding DocumentManagerSubViewModel.ActiveDocument}"
+    <main:DocumentPreview Document="{Binding DocumentManagerSubViewModel.ActiveDocument}"
                      PrimaryColor="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay, Converter={converters:GenericColorToMediaColorConverter}}"/>
                      PrimaryColor="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay, Converter={converters:GenericColorToMediaColorConverter}}"/>
 </UserControl>
 </UserControl>

+ 2 - 2
src/PixiEditor/Views/Dock/NavigationDockView.axaml.cs → src/PixiEditor/Views/Dock/DocumentPreviewDockView.axaml.cs

@@ -2,9 +2,9 @@
 
 
 namespace PixiEditor.Views.Dock;
 namespace PixiEditor.Views.Dock;
 
 
-public partial class NavigationDockView : UserControl
+public partial class DocumentPreviewDockView : UserControl
 {
 {
-    public NavigationDockView()
+    public DocumentPreviewDockView()
     {
     {
         InitializeComponent();
         InitializeComponent();
     }
     }

+ 5 - 13
src/PixiEditor/Views/Main/Navigation.axaml → src/PixiEditor/Views/Main/DocumentPreview.axaml

@@ -9,7 +9,7 @@
              xmlns:ui="clr-namespace:PixiEditor.Extensions.UI;assembly=PixiEditor.Extensions"
              xmlns:ui="clr-namespace:PixiEditor.Extensions.UI;assembly=PixiEditor.Extensions"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              Name="uc"
              Name="uc"
-             x:Class="PixiEditor.Views.Main.Navigation">
+             x:Class="PixiEditor.Views.Main.DocumentPreview">
      <Grid>
      <Grid>
         <Grid.RowDefinitions>
         <Grid.RowDefinitions>
             <RowDefinition Height="*"/>
             <RowDefinition Height="*"/>
@@ -26,14 +26,6 @@
                 x:Name="viewport"
                 x:Name="viewport"
                 Document="{Binding Document, ElementName=uc}"
                 Document="{Binding Document, ElementName=uc}"
                 Background="{Binding ActiveItem.Value, ElementName=backgroundButton}"/>
                 Background="{Binding ActiveItem.Value, ElementName=backgroundButton}"/>
-            <Border 
-                    x:Name="colorCursor" Width="1" Height="1"
-                    Margin="{Binding ColorCursorPosition, ElementName=uc}"
-                    HorizontalAlignment="Left" VerticalAlignment="Top"
-                    BorderBrush="{DynamicResource ThemeBorderLowBrush}" BorderThickness=".1"
-                    IsVisible="{Binding IsPointerOver, ElementName=imageGrid}">
-                <Border BorderThickness=".1" BorderBrush="White"/>
-            </Border>
         </Grid>
         </Grid>
 
 
         <Grid Grid.Row="1">
         <Grid Grid.Row="1">
@@ -41,16 +33,16 @@
                 <SolidColorBrush Color="{Binding ColorCursorColor, ElementName=uc, FallbackValue=Black}"/>
                 <SolidColorBrush Color="{Binding ColorCursorColor, ElementName=uc, FallbackValue=Black}"/>
             </Grid.Background>
             </Grid.Background>
         </Grid>
         </Grid>
-        <StackPanel Margin="10, 0, 0, 0" Grid.Row="2" Orientation="Horizontal" MinHeight="30"
-                    Background="{DynamicResource ThemeBackgroundBrush}" MaxHeight="60">
+        <StackPanel Margin="10, 0, 0, 0" Grid.Row="2" Orientation="Horizontal" Height="30"
+                    Background="{DynamicResource ThemeBackgroundBrush}">
             <StackPanel.Styles>
             <StackPanel.Styles>
                 <Style Selector="TextBlock">
                 <Style Selector="TextBlock">
                     <Setter Property="VerticalAlignment" Value="Center"/>
                     <Setter Property="VerticalAlignment" Value="Center"/>
                 </Style>
                 </Style>
             </StackPanel.Styles>
             </StackPanel.Styles>
 
 
-            <TextBlock Text="{Binding ColorCursorPosition.Left, ElementName=uc, StringFormat='X: {0}'}"/>
-            <TextBlock Text="{Binding ColorCursorPosition.Top, ElementName=uc, StringFormat='Y: {0}'}"/>
+            <TextBlock Text="{Binding ColorCursorPosition.X, ElementName=uc, StringFormat='X: {0}'}"/>
+            <TextBlock Text="{Binding ColorCursorPosition.Y, ElementName=uc, StringFormat='Y: {0}'}"/>
 
 
             <TextBlock VerticalAlignment="Center" Margin="10, 0, 0, 0">
             <TextBlock VerticalAlignment="Center" Margin="10, 0, 0, 0">
                 <TextBlock.Text>
                 <TextBlock.Text>

+ 20 - 24
src/PixiEditor/Views/Main/Navigation.axaml.cs → src/PixiEditor/Views/Main/DocumentPreview.axaml.cs

@@ -1,11 +1,9 @@
-using System.Threading.Tasks;
-using Avalonia;
+using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Controls;
 using Avalonia.Input;
 using Avalonia.Input;
 using Avalonia.Interactivity;
 using Avalonia.Interactivity;
 using Avalonia.Media;
 using Avalonia.Media;
 using PixiEditor.Helpers;
 using PixiEditor.Helpers;
-using Drawie.Backend.Core.Numerics;
 using PixiEditor.Models.Controllers.InputDevice;
 using PixiEditor.Models.Controllers.InputDevice;
 using PixiEditor.Models.Tools;
 using PixiEditor.Models.Tools;
 using Drawie.Numerics;
 using Drawie.Numerics;
@@ -15,19 +13,16 @@ using Point = Avalonia.Point;
 
 
 namespace PixiEditor.Views.Main;
 namespace PixiEditor.Views.Main;
 
 
-internal partial class Navigation : UserControl
+internal partial class DocumentPreview : UserControl
 {
 {
     public static readonly StyledProperty<DocumentViewModel> DocumentProperty =
     public static readonly StyledProperty<DocumentViewModel> DocumentProperty =
-        AvaloniaProperty.Register<Navigation, DocumentViewModel>(nameof(Document));
-
-    public static readonly StyledProperty<Thickness> ColorCursorPositionProperty =
-        AvaloniaProperty.Register<Navigation, Thickness>(nameof(ColorCursorPosition));
+        AvaloniaProperty.Register<DocumentPreview, DocumentViewModel>(nameof(Document));
 
 
     public static readonly StyledProperty<Color> ColorCursorColorProperty =
     public static readonly StyledProperty<Color> ColorCursorColorProperty =
-        AvaloniaProperty.Register<Navigation, Color>(nameof(ColorCursorColor));
+        AvaloniaProperty.Register<DocumentPreview, Color>(nameof(ColorCursorColor));
 
 
     public static readonly StyledProperty<Color> PrimaryColorProperty =
     public static readonly StyledProperty<Color> PrimaryColorProperty =
-        AvaloniaProperty.Register<Navigation, Color>(nameof(PrimaryColor));
+        AvaloniaProperty.Register<DocumentPreview, Color>(nameof(PrimaryColor));
 
 
     public DocumentViewModel Document
     public DocumentViewModel Document
     {
     {
@@ -35,12 +30,6 @@ internal partial class Navigation : UserControl
         set => SetValue(DocumentProperty, value);
         set => SetValue(DocumentProperty, value);
     }
     }
 
 
-    public Thickness ColorCursorPosition
-    {
-        get => GetValue(ColorCursorPositionProperty);
-        private set => SetValue(ColorCursorPositionProperty, value);
-    }
-
     public Color ColorCursorColor
     public Color ColorCursorColor
     {
     {
         get => GetValue(ColorCursorColorProperty);
         get => GetValue(ColorCursorColorProperty);
@@ -52,10 +41,19 @@ internal partial class Navigation : UserControl
         get => GetValue(PrimaryColorProperty);
         get => GetValue(PrimaryColorProperty);
         set => SetValue(PrimaryColorProperty, value);
         set => SetValue(PrimaryColorProperty, value);
     }
     }
+
+    public static readonly StyledProperty<VecI> ColorCursorPositionProperty = AvaloniaProperty.Register<DocumentPreview, VecI>(
+        nameof(ColorCursorPosition));
+
+    public VecI ColorCursorPosition
+    {
+        get => GetValue(ColorCursorPositionProperty);
+        set => SetValue(ColorCursorPositionProperty, value);
+    }
     
     
     private MouseUpdateController mouseUpdateController;
     private MouseUpdateController mouseUpdateController;
 
 
-    public Navigation()
+    public DocumentPreview()
     {
     {
         InitializeComponent();
         InitializeComponent();
         
         
@@ -81,7 +79,7 @@ internal partial class Navigation : UserControl
     {
     {
         if (ViewModelMain.Current != null)
         if (ViewModelMain.Current != null)
         {
         {
-            ViewModelMain.Current.ActionDisplays[nameof(Navigation)] = null;
+            ViewModelMain.Current.ActionDisplays[nameof(DocumentPreview)] = null;
         }
         }
     }
     }
 
 
@@ -89,7 +87,7 @@ internal partial class Navigation : UserControl
     {
     {
         if (ViewModelMain.Current != null)
         if (ViewModelMain.Current != null)
         {
         {
-            ViewModelMain.Current.ActionDisplays[nameof(Navigation)] = "NAVIGATOR_PICK_ACTION_DISPLAY";
+            ViewModelMain.Current.ActionDisplays[nameof(DocumentPreview)] = "NAVIGATOR_PICK_ACTION_DISPLAY";
         }
         }
     }
     }
 
 
@@ -153,15 +151,13 @@ internal partial class Navigation : UserControl
         if (x < 0 || x > Document.Width || y < 0 || y > Document.Height)
         if (x < 0 || x > Document.Width || y < 0 || y > Document.Height)
             return;
             return;
         
         
-        Thickness newPos = new Thickness(x, y, 0, 0);
-
-        if (ColorCursorPosition == newPos)
+        if (x == ColorCursorPosition.X && y == ColorCursorPosition.Y)
         {
         {
             return;
             return;
         }
         }
 
 
-        ColorCursorPosition = newPos;
-
+        ColorCursorPosition = new VecI(x, y);
+        
         var color = Document.PickColor(new(x, y), DocumentScope.AllLayers, false, true, Document.AnimationDataViewModel.ActiveFrameBindable);
         var color = Document.PickColor(new(x, y), DocumentScope.AllLayers, false, true, Document.AnimationDataViewModel.ActiveFrameBindable);
         ColorCursorColor = Color.FromArgb(color.A, color.R, color.G, color.B);
         ColorCursorColor = Color.FromArgb(color.A, color.R, color.G, color.B);
     }
     }