Browse Source

Copy cels wip, commented out icons in search, some translations

flabbet 7 months ago
parent
commit
7477e44ab0

+ 8 - 1
src/PixiEditor/Data/Localization/Languages/en.json

@@ -803,5 +803,12 @@
   "TOGGLE_HUD": "Toggle HUD",
   "OPEN_TIMELINE": "Open timeline",
   "OPEN_NODE_GRAPH": "Open node graph",
-  "TOGGLE_PLAY": "Play/Pause animation"
+  "TOGGLE_PLAY": "Play/Pause animation",
+  "COPY_NODES": "Copy nodes",
+  "COPY_NODES_DESCRIPTIVE": "Copy selected nodes",
+  "PASTE_NODES": "Paste nodes",
+  "PASTE_NODES_DESCRIPTIVE": "Paste copied nodes",
+  "COPY_CELS": "Copy cels",
+  "COPY_CELS_DESCRIPTIVE": "Copy selected cels",
+  "TOGGLE_ONION_SKINNING_DESCRIPTIVE": "Toggle onion skinning"
 }

+ 1 - 0
src/PixiEditor/Helpers/Constants/ClipboardDataFormats.cs

@@ -8,4 +8,5 @@ public static class ClipboardDataFormats
     public const string ImageSlashPng = "image/png";
     public const string DocumentFormat = "PixiEditor.Document";
     public const string NodeIdList = "PixiEditor.NodeIdList";
+    public const string CelIdList = "PixiEditor.CelIdList";
 }

+ 1 - 1
src/PixiEditor/Models/Commands/Search/FileSearchResult.cs

@@ -30,7 +30,7 @@ internal class FileSearchResult : SearchResult
     {
         FilePath = path;
         var drawing = new GeometryDrawing() { Brush = FileExtensionToColorConverter.GetBrush(FilePath) };
-        var geometry = new RectangleGeometry(new Rect(0, 0, 10, 10)) { }; // TODO: Avalonia 11.1 introduces rounded rectangle geometry, let's make this round again then 
+        var geometry = new RectangleGeometry(new Rect(0, 0, 10, 10)) { RadiusX = 2, RadiusY = 2 };
         drawing.Geometry = geometry;
         icon = new DrawingImage(drawing);
         this.asReferenceLayer = asReferenceLayer;

+ 19 - 9
src/PixiEditor/Models/Controllers/ClipboardController.cs

@@ -574,15 +574,7 @@ internal static class ClipboardController
 
     public static async Task CopyNodes(Guid[] nodeIds)
     {
-        await Clipboard.ClearAsync();
-
-        DataObject data = new DataObject();
-
-        byte[] nodeIdsBytes = Encoding.UTF8.GetBytes(string.Join(";", nodeIds.Select(x => x.ToString())));
-
-        data.Set(ClipboardDataFormats.NodeIdList, nodeIdsBytes);
-
-        await Clipboard.SetDataObjectAsync(data);
+        await CopyIds(nodeIds, ClipboardDataFormats.NodeIdList);
     }
 
     public static async Task<List<Guid>> GetNodeIds()
@@ -622,4 +614,22 @@ internal static class ClipboardController
         
         return formats.Contains(ClipboardDataFormats.NodeIdList);
     }
+
+    public static async Task CopyCels(Guid[] celIds)
+    {
+        await CopyIds(celIds, ClipboardDataFormats.CelIdList);
+    }
+    
+    public static async Task CopyIds(Guid[] ids, string format)
+    {
+        await Clipboard.ClearAsync();
+
+        DataObject data = new DataObject();
+
+        byte[] idsBytes = Encoding.UTF8.GetBytes(string.Join(";", ids.Select(x => x.ToString())));
+
+        data.Set(format, idsBytes);
+
+        await Clipboard.SetDataObjectAsync(data);
+    }
 }

+ 30 - 0
src/PixiEditor/ViewModels/SubViewModels/ClipboardViewModel.cs

@@ -230,6 +230,7 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
     [Command.Basic("PixiEditor.Clipboard.CopyNodes", "COPY_NODES", "COPY_NODES_DESCRIPTIVE",
         Key = Key.C, Modifiers = KeyModifiers.Control,
         ShortcutContexts = [typeof(NodeGraphDockViewModel)],
+        CanExecute = "PixiEditor.Clipboard.CanCopyNodes",
         Icon = PixiPerfectIcons.Copy, AnalyticsTrack = true)]
     public async Task CopySelectedNodes()
     {
@@ -243,6 +244,23 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
 
         await ClipboardController.CopyNodes(selectedNodes);
     }
+    
+    [Command.Basic("PixiEditor.Clipboard.CopyCels", "COPY_CELS",
+        "COPY_CELS_DESCRIPTIVE", CanExecute = "PixiEditor.Clipboard.CanCopyCels",
+        ShortcutContexts = [typeof(TimelineDockViewModel)],
+        Key = Key.C, Modifiers = KeyModifiers.Control, Icon = PixiPerfectIcons.Copy, AnalyticsTrack = true)]
+    public async Task CopySelectedCels()
+    {
+        var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
+        if (doc is null)
+            return;
+
+        var selectedCels = doc.AnimationDataViewModel.AllCels.Where(x => x.IsSelected).Select(x => x.Id).ToArray();
+        if (selectedCels.Length == 0)
+            return;
+        
+        await ClipboardController.CopyCels(selectedCels);
+    }
 
 
     [Command.Basic("PixiEditor.Clipboard.CopyPrimaryColorAsHex", CopyColor.PrimaryHEX, "COPY_COLOR_HEX",
@@ -285,6 +303,18 @@ internal class ClipboardViewModel : SubViewModel<ViewModelMain>
             ? ClipboardController.IsImage(data)
             : ClipboardController.IsImageInClipboard().Result;
     }
+    
+    [Evaluator.CanExecute("PixiEditor.Clipboard.CanCopyCels")]
+    public bool CanCopyCels()
+    {
+        return Owner.DocumentIsNotNull(null) && Owner.DocumentManagerSubViewModel.ActiveDocument.AnimationDataViewModel.AllCels.Any(x => x.IsSelected);
+    }
+    
+    [Evaluator.CanExecute("PixiEditor.Clipboard.CanCopyNodes")]
+    public bool CanCopyNodes()
+    {
+        return Owner.DocumentIsNotNull(null) && Owner.DocumentManagerSubViewModel.ActiveDocument.NodeGraph.AllNodes.Any(x => x.IsNodeSelected);
+    }
 
     [Evaluator.CanExecute("PixiEditor.Clipboard.CanPasteNodes")]
     public bool CanPasteNodes()

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

@@ -408,7 +408,7 @@ internal class ColorsViewModel : SubViewModel<ViewModelMain>, IColorsHandler
         PrimaryColor = color.ToColor();
     }
 
-    [Commands_Command.Basic("PixIEditor.Colors.AddPrimaryToPalettes", "ADD_PRIMARY_COLOR_TO_PALETTE",
+    [Commands_Command.Basic("PixiEditor.Colors.AddPrimaryToPalettes", "ADD_PRIMARY_COLOR_TO_PALETTE",
         "ADD_PRIMARY_COLOR_TO_PALETTE_DESCRIPTIVE", CanExecute = "PixiEditor.HasDocument",
         Icon = PixiPerfectIcons.CopyAdd, AnalyticsTrack = true)]
     public void AddPrimaryColorToPalette()

+ 4 - 3
src/PixiEditor/Views/Main/CommandSearch/CommandSearchControl.axaml

@@ -67,9 +67,10 @@
                                             <ColumnDefinition Width="Auto" />
                                         </Grid.ColumnDefinitions>
                                         <StackPanel Orientation="Horizontal">
-                                            <Border Width="25" Margin="0,0,5,0" Padding="1">
+                                            <!--TODO: Below causes heap corruption crash randomly when searching-->
+                                            <!--<Border Width="25" Margin="0,0,5,0" Padding="1">
                                                 <Image HorizontalAlignment="Center" Source="{Binding Icon}" />
-                                            </Border>
+                                            </Border>-->
                                             <TextBlock VerticalAlignment="Center"
                                                        behaviours:TextBlockExtensions.BindableInlines="{Binding TextBlockContent}" />
                                         </StackPanel>
@@ -85,7 +86,7 @@
         </Border>
         <Border Grid.Row="2" BorderThickness="1" BorderBrush="{DynamicResource ThemeBorderMidBrush}"
                 CornerRadius="0,0,5,5" Background="{DynamicResource ThemeBackgroundBrush1}" Padding="3">
-            <ContentPresenter Content="{Binding SelectedResult.Description, Mode=OneWay, ElementName=uc}" />
+            <ContentPresenter Content="{Binding SelectedResult.Description, Mode=OneWay, ElementName=uc, FallbackValue={x:Null}}" />
         </Border>
     </Grid>
 </UserControl>

+ 17 - 9
src/PixiEditor/Views/Main/CommandSearch/CommandSearchControl.axaml.cs

@@ -29,8 +29,9 @@ internal partial class CommandSearchControl : UserControl, INotifyPropertyChange
         set => SetValue(SearchTermProperty, value);
     }
 
-    public static readonly StyledProperty<bool> SelectAllProperty = AvaloniaProperty.Register<CommandSearchControl, bool>(
-        nameof(SelectAll));
+    public static readonly StyledProperty<bool> SelectAllProperty =
+        AvaloniaProperty.Register<CommandSearchControl, bool>(
+            nameof(SelectAll));
 
     public bool SelectAll
     {
@@ -39,6 +40,7 @@ internal partial class CommandSearchControl : UserControl, INotifyPropertyChange
     }
 
     private string warnings = "";
+
     public string Warnings
     {
         get => warnings;
@@ -56,6 +58,7 @@ internal partial class CommandSearchControl : UserControl, INotifyPropertyChange
     public event PropertyChangedEventHandler? PropertyChanged;
 
     private SearchResult? selectedResult;
+
     public SearchResult? SelectedResult
     {
         get => selectedResult;
@@ -71,6 +74,7 @@ internal partial class CommandSearchControl : UserControl, INotifyPropertyChange
     }
 
     private SearchResult? mouseSelectedResult;
+
     public SearchResult? MouseSelectedResult
     {
         get => mouseSelectedResult;
@@ -94,6 +98,8 @@ internal partial class CommandSearchControl : UserControl, INotifyPropertyChange
 
     public CommandSearchControl()
     {
+        InitializeComponent();
+
         ButtonClickedCommand = new RelayCommand(() =>
         {
             Hide();
@@ -101,13 +107,11 @@ internal partial class CommandSearchControl : UserControl, INotifyPropertyChange
             MouseSelectedResult = null;
         });
 
-        InitializeComponent();
-
         PointerPressed += OnPointerDown;
         KeyDown += OnPreviewKeyDown;
         Loaded += (_, _) => UpdateSearchResults();
     }
-    
+
 
     private static void OnIsVisibleChanged(AvaloniaPropertyChangedEventArgs<bool> e)
     {
@@ -142,7 +146,8 @@ internal partial class CommandSearchControl : UserControl, INotifyPropertyChange
     private void UpdateSearchResults()
     {
         Results.Clear();
-        (List<SearchResult> newResults, List<string> warnings) = CommandSearchControlHelper.ConstructSearchResults(SearchTerm);
+        (List<SearchResult> newResults, List<string> warnings) =
+            CommandSearchControlHelper.ConstructSearchResults(SearchTerm);
         foreach (var result in newResults)
             Results.Add(result);
         Warnings = warnings.Aggregate(new StringBuilder(), static (builder, item) =>
@@ -196,13 +201,15 @@ internal partial class CommandSearchControl : UserControl, INotifyPropertyChange
             textBox.SelectionStart = 4;
             textBox.SelectionEnd = 4;
         }
-        else if (e.Key == Key.Space && SearchTerm.StartsWith("rgb") && textBox.CaretIndex > 0 && char.IsDigit(SearchTerm[textBox.CaretIndex - 1]))
+        else if (e.Key == Key.Space && SearchTerm.StartsWith("rgb") && textBox.CaretIndex > 0 &&
+                 char.IsDigit(SearchTerm[textBox.CaretIndex - 1]))
         {
             var prev = textBox.CaretIndex;
             if (SearchTerm.Length == textBox.CaretIndex || SearchTerm[textBox.CaretIndex] != ',')
             {
                 SearchTerm = SearchTerm.Insert(textBox.CaretIndex, ",");
             }
+
             textBox.CaretIndex = prev + 1;
         }
         else if (e is { Key: Key.S, KeyModifiers: KeyModifiers.Control } &&
@@ -269,7 +276,9 @@ internal partial class CommandSearchControl : UserControl, INotifyPropertyChange
         int newIndex = Results.IndexOf(SelectedResult) + delta;
         newIndex = (newIndex % Results.Count + Results.Count) % Results.Count;
 
-        SelectedResult = delta > 0 ? Results.IndexOrNext(x => x.CanExecute, newIndex) : Results.IndexOrPrevious(x => x.CanExecute, newIndex);
+        SelectedResult = delta > 0
+            ? Results.IndexOrNext(x => x.CanExecute, newIndex)
+            : Results.IndexOrPrevious(x => x.CanExecute, newIndex);
 
         newIndex = Results.IndexOf(SelectedResult);
         itemscontrol.ContainerFromIndex(newIndex)?.BringIntoView();
@@ -285,6 +294,5 @@ internal partial class CommandSearchControl : UserControl, INotifyPropertyChange
     {
         CommandSearchControl control = ((CommandSearchControl)e.Sender);
         control.UpdateSearchResults();
-        control.PropertyChanged?.Invoke(control, new PropertyChangedEventArgs(nameof(control.SearchTerm)));
     }
 }