Browse Source

Added copy paste cels

flabbet 7 months ago
parent
commit
ed4c8a840d

+ 25 - 13
src/PixiEditor/Models/Controllers/ClipboardController.cs

@@ -577,27 +577,29 @@ internal static class ClipboardController
         await CopyIds(nodeIds, ClipboardDataFormats.NodeIdList);
     }
 
-    public static async Task<List<Guid>> GetNodeIds()
+    public static async Task<Guid[]> GetNodeIds()
     {
-        var data = await TryGetDataObject();
-        var nodeIds = GetNodeIds(data);
-        
-        return nodeIds.ToList();
+        return await GetIds(ClipboardDataFormats.NodeIdList);
     }
 
-    public static async Task<Guid[]> GetNodesFromClipboard()
+    public static async Task<Guid[]> GetCelIds()
+    {
+        return await GetIds(ClipboardDataFormats.CelIdList);
+    }
+    
+    public static async Task<Guid[]> GetIds(string format)
     {
         var data = await TryGetDataObject();
-        return GetNodeIds(data);
+        return GetIds(data, format);
     }
 
-    private static Guid[] GetNodeIds(IEnumerable<IDataObject?> data)
+    private static Guid[] GetIds(IEnumerable<IDataObject?> data, string format)
     {
         foreach (var dataObject in data)
         {
-            if (dataObject.Contains(ClipboardDataFormats.NodeIdList))
+            if (dataObject.Contains(format))
             {
-                byte[] nodeIds = (byte[])dataObject.Get(ClipboardDataFormats.NodeIdList);
+                byte[] nodeIds = (byte[])dataObject.Get(format);
                 string nodeIdsString = System.Text.Encoding.UTF8.GetString(nodeIds);
                 return nodeIdsString.Split(';').Select(Guid.Parse).ToArray();
             }
@@ -607,19 +609,29 @@ internal static class ClipboardController
     }
 
     public static async Task<bool> AreNodesInClipboard()
+    {
+        return await AreIdsInClipboard(ClipboardDataFormats.NodeIdList);
+    }
+
+    public static async Task<bool> AreCelsInClipboard()
+    {
+        return await AreIdsInClipboard(ClipboardDataFormats.CelIdList);
+    }
+
+    public static async Task<bool> AreIdsInClipboard(string format)
     {
         var formats = await Clipboard.GetFormatsAsync();
         if (formats == null || formats.Length == 0)
             return false;
-        
-        return formats.Contains(ClipboardDataFormats.NodeIdList);
+
+        return formats.Contains(format);
     }
 
     public static async Task CopyCels(Guid[] celIds)
     {
         await CopyIds(celIds, ClipboardDataFormats.CelIdList);
     }
-    
+
     public static async Task CopyIds(Guid[] ids, string format)
     {
         await Clipboard.ClearAsync();

+ 2 - 1
src/PixiEditor/Models/DocumentModels/Public/DocumentOperationsModule.cs

@@ -1,4 +1,5 @@
-using System.Collections.Immutable;
+using System.Collections;
+using System.Collections.Immutable;
 using System.Reactive.Disposables;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument;

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

@@ -11,7 +11,7 @@ internal interface IAnimationHandler
     public int OnionFramesBindable { get; set; }
     public double OnionOpacityBindable { get; set; }
     public bool IsPlayingBindable { get; set; }
-    public void CreateCel(Guid targetLayerGuid, int frame, Guid? toCloneFrom = null, int? frameToCopyFrom = null);
+    public Guid? CreateCel(Guid targetLayerGuid, int frame, Guid? toCloneFrom = null, int? frameToCopyFrom = null);
     public void SetFrameRate(int newFrameRate);
     public void SetActiveFrame(int newFrame);
     public void SetFrameLength(Guid keyFrameId, int newStartFrame, int newDuration);

+ 6 - 2
src/PixiEditor/ViewModels/Document/AnimationDataViewModel.cs

@@ -129,15 +129,19 @@ internal class AnimationDataViewModel : ObservableObject, IAnimationHandler
 
     public KeyFrameTime ActiveFrameTime => new KeyFrameTime(ActiveFrameBindable, ActiveNormalizedTime);
 
-    public void CreateCel(Guid targetLayerGuid, int frame, Guid? toCloneFrom = null,
+    public Guid? CreateCel(Guid targetLayerGuid, int frame, Guid? toCloneFrom = null,
         int? frameToCopyFrom = null)
     {
         if (!Document.BlockingUpdateableChangeActive)
         {
+            Guid newCelGuid = Guid.NewGuid();
             Internals.ActionAccumulator.AddFinishedActions(new CreateCel_Action(targetLayerGuid,
-                Guid.NewGuid(), Math.Max(1, frame),
+                newCelGuid, Math.Max(1, frame),
                 frameToCopyFrom ?? -1, toCloneFrom ?? Guid.Empty));
+            return newCelGuid;
         }
+        
+        return null;
     }
 
     public void DeleteCels(List<Guid> keyFrameIds)

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

@@ -157,7 +157,7 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
         if (doc is null)
             return;
 
-        List<Guid> toDuplicate = await ClipboardController.GetNodeIds();
+        Guid[] toDuplicate = await ClipboardController.GetNodeIds();
 
         List<Guid> newIds = new();
 
@@ -200,6 +200,56 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
         });
     }
 
+    [Command.Basic("PixiEditor.Clipboard.PasteCels", "PASTE_CELS", "PASTE_CELS_DESCRIPTIVE",
+        CanExecute = "PixiEditor.Clipboard.CanPasteCels", Key = Key.V, Modifiers = KeyModifiers.Control,
+        ShortcutContexts = [typeof(TimelineDockViewModel)], Icon = PixiPerfectIcons.Paste, AnalyticsTrack = true)]
+    public async Task PasteCels()
+    {
+        var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
+        if (doc is null)
+            return;
+
+        var cels = await ClipboardController.GetCelIds();
+
+        if (cels.Length == 0)
+            return;
+
+        using var block = doc.Operations.StartChangeBlock();
+
+        List<Guid> newCels = new();
+
+        int i = 0;
+        foreach (var celId in cels)
+        {
+            ICelHandler cel = doc.AnimationDataViewModel.AllCels.First(x => x.Id == celId);
+            Guid? newCel = doc.AnimationDataViewModel.CreateCel(cel.LayerGuid, doc.AnimationDataViewModel.ActiveFrameBindable + i, cel.LayerGuid,
+                cel.StartFrameBindable);
+            if (newCel != null)
+            {
+                newCels.Add(newCel.Value);
+            }
+
+            i++;
+        }
+
+        doc.Operations.InvokeCustomAction(() =>
+        {
+            foreach (var cel in doc.AnimationDataViewModel.AllCels)
+            {
+                cel.IsSelected = false;
+            }
+
+            foreach (var cel in newCels)
+            {
+                var celInstance = doc.AnimationDataViewModel.AllCels.FirstOrDefault(x => x.Id == cel);
+                if (celInstance != null)
+                {
+                    celInstance.IsSelected = true;
+                }
+            }
+        });
+    }
+
 
     [Command.Basic("PixiEditor.Clipboard.Copy", "COPY", "COPY_DESCRIPTIVE", CanExecute = "PixiEditor.Clipboard.CanCopy",
         Key = Key.C, Modifiers = KeyModifiers.Control,
@@ -324,6 +374,12 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
         return Owner.DocumentIsNotNull(null) && ClipboardController.AreNodesInClipboard().Result;
     }
 
+    [Evaluator.CanExecute("PixiEditor.Clipboard.CanPasteCels")]
+    public bool CanPasteCels()
+    {
+        return Owner.DocumentIsNotNull(null) && ClipboardController.AreCelsInClipboard().Result;
+    }
+
     [Evaluator.CanExecute("PixiEditor.Clipboard.CanPasteColor")]
     public static async Task<bool> CanPasteColor()
     {