浏览代码

Added merge selected, WIP shift select

flabbet 4 年之前
父节点
当前提交
dd77837098

+ 5 - 0
PixiEditor/Models/Controllers/BitmapOperationsUtility.cs

@@ -205,6 +205,11 @@ namespace PixiEditor.Models.Controllers
                     Manager.PrimaryColor);
 
                 BitmapPixelChanges[] changes = modifiedLayers.Select(x => x.PixelChanges).ToArray();
+                if (changes.Length == 0)
+                {
+                    return;
+                }
+
                 Manager.ActiveDocument.PreviewLayer.SetPixels(BitmapPixelChanges.CombineOverride(changes));
 
                 if (clearPreviewLayer || previewLayerChanges == null)

+ 42 - 39
PixiEditor/Models/DataHolders/Document/Document.Layers.cs

@@ -135,64 +135,64 @@ namespace PixiEditor.Models.DataHolders
             }
         }
 
-        /// <summary>
-        /// Merges two layers.
-        /// </summary>
-        /// <param name="firstLayer">The lower layer.</param>
-        /// <param name="secondLayer">The upper layer.</param>
-        /// <returns>The merged layer.</returns>
-        public Layer MergeLayers(Layer firstLayer, Layer secondLayer, bool nameOfSecond, int index)
+        public Layer MergeLayers(Layer[] layersToMerge, bool nameOfLast, int index)
         {
+            if (layersToMerge == null || layersToMerge.Length < 2)
+            {
+                throw new ArgumentException("Not enough layers were provided to merge. Minimum amount is 2");
+            }
+
             string name;
 
             // Wich name should be used
-            if (nameOfSecond)
+            if (nameOfLast)
             {
-                name = secondLayer.Name;
+                name = layersToMerge[^1].Name;
             }
             else
             {
-                name = firstLayer.Name;
+                name = layersToMerge[0].Name;
             }
 
-            Layer mergedLayer = firstLayer.MergeWith(secondLayer, name, Width, Height);
+            Layer mergedLayer = null;
 
-            // Insert new layer and remove old
-            Layers.Insert(index, mergedLayer);
-            Layers.Remove(firstLayer);
-            Layers.Remove(secondLayer);
+            for (int i = 0; i < layersToMerge.Length - 1; i++)
+            {
+                Layer firstLayer = layersToMerge[i];
+                Layer secondLayer = layersToMerge[i + 1];
+                mergedLayer = firstLayer.MergeWith(secondLayer, name, Width, Height);
+
+                // Insert new layer and remove old
+                Layers.Insert(index, mergedLayer);
+                Layers.Remove(firstLayer);
+                Layers.Remove(secondLayer);
 
-            SetActiveLayer(Layers.IndexOf(mergedLayer));
+                SetActiveLayer(Layers.IndexOf(mergedLayer));
+            }
 
             return mergedLayer;
         }
 
-        /// <summary>
-        /// Merges two layers.
-        /// </summary>
-        /// <param name="firstIndex">The index of the lower layer.</param>
-        /// <param name="secondIndex">The index of the upper leyer.</param>
-        /// <returns>The merged layer.</returns>
-        public Layer MergeLayers(int firstIndex, int secondIndex, bool nameOfSecond)
+        public Layer MergeLayers(Layer[] layersToMerge, bool nameIsLastLayers)
         {
-            Layer firstLayer = Layers[firstIndex];
-            Layer secondLayer = Layers[secondIndex];
-
-            IEnumerable<Layer> undoArgs = new[] { firstLayer, secondLayer };
-            if (firstIndex > secondIndex)
+            if (layersToMerge == null || layersToMerge.Length < 2)
             {
-                undoArgs = undoArgs.Reverse();
+                throw new ArgumentException("Not enough layers were provided to merge. Minimum amount is 2");
             }
 
+            IEnumerable<Layer> undoArgs = layersToMerge;
+
             StorageBasedChange undoChange = new StorageBasedChange(this, undoArgs);
 
-            var layer = MergeLayers(firstLayer, secondLayer, nameOfSecond, firstIndex);
+            int[] indexes = layersToMerge.Select(x => Layers.IndexOf(x)).ToArray();
+
+            var layer = MergeLayers(layersToMerge, nameIsLastLayers, Layers.IndexOf(layersToMerge[0]));
 
             UndoManager.AddUndoChange(undoChange.ToChange(
                 InsertLayersAtIndexesProcess,
-                new object[] { firstIndex > secondIndex ? firstIndex - 1 : firstIndex },
+                new object[] { indexes[0] },
                 MergeLayersProcess,
-                new object[] { firstIndex, secondIndex, nameOfSecond, layer.LayerGuid },
+                new object[] { indexes, nameIsLastLayers, layer.LayerGuid },
                 "Undo merge layers"));
 
             return layer;
@@ -201,15 +201,18 @@ namespace PixiEditor.Models.DataHolders
         private void MergeLayersProcess(object[] args)
         {
             if (args.Length > 0
-                && args[0] is int firstIndex
-                && args[1] is int secondIndex
-                && args[2] is bool nameOfSecond
-                && args[3] is Guid mergedLayerGuid)
+                && args[0] is int[] indexes
+                && args[1] is bool nameOfSecond
+                && args[2] is Guid mergedLayerGuid)
             {
-                Layer firstLayer = Layers[firstIndex];
-                Layer secondLayer = Layers[secondIndex];
+                Layer[] layers = new Layer[indexes.Length];
+
+                for (int i = 0; i < layers.Length; i++)
+                {
+                    layers[i] = Layers[indexes[i]];
+                }
 
-                Layer layer = MergeLayers(firstLayer, secondLayer, nameOfSecond, firstIndex);
+                Layer layer = MergeLayers(layers, nameOfSecond, indexes[0]);
                 layer.ChangeGuid(mergedLayerGuid);
             }
         }

+ 1 - 1
PixiEditor/Models/DataHolders/Selection.cs

@@ -56,7 +56,7 @@ namespace PixiEditor.Models.DataHolders
 
         public void Clear()
         {
-            SelectionLayer = new Layer("_selectionLayer");
+            SelectionLayer.Clear();
             SelectedPoints.Clear();
         }
     }

+ 10 - 7
PixiEditor/Models/Tools/Tools/SelectTool.cs

@@ -49,13 +49,16 @@ namespace PixiEditor.Models.Tools.Tools
                 ViewModelMain.Current.BitmapManager.ActiveDocument.ActiveSelection.Clear();
             }
 
-            ViewModelMain.Current.BitmapManager.ActiveDocument.UndoManager.AddUndoChange(
-                new Change(
-                    "SelectedPoints",
-                    oldSelection.SelectedPoints,
-                    new ObservableCollection<Coordinates>(ViewModelMain.Current.BitmapManager.ActiveDocument.ActiveSelection.SelectedPoints),
-                    "Select pixels",
-                    ViewModelMain.Current.BitmapManager.ActiveDocument.ActiveSelection));
+            if (oldSelection != null)
+            {
+                ViewModelMain.Current.BitmapManager.ActiveDocument.UndoManager.AddUndoChange(
+                    new Change(
+                        "SelectedPoints",
+                        oldSelection.SelectedPoints,
+                        new ObservableCollection<Coordinates>(ViewModelMain.Current.BitmapManager.ActiveDocument.ActiveSelection.SelectedPoints),
+                        "Select pixels",
+                        ViewModelMain.Current.BitmapManager.ActiveDocument.ActiveSelection));
+            }
         }
 
         public override void Use(Coordinates[] pixels)

+ 39 - 7
PixiEditor/ViewModels/SubViewModels/Main/LayersViewModel.cs

@@ -1,6 +1,8 @@
-using PixiEditor.Helpers;
-using PixiEditor.Models.Layers;
+using System;
+using System.Linq;
 using System.Windows.Input;
+using PixiEditor.Helpers;
+using PixiEditor.Models.Layers;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main
 {
@@ -18,6 +20,8 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
 
         public RelayCommand MoveToFrontCommand { get; set; }
 
+        public RelayCommand MergeSelectedCommand { get; set; }
+
         public RelayCommand MergeWithAboveCommand { get; set; }
 
         public RelayCommand MergeWithBelowCommand { get; set; }
@@ -31,10 +35,16 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
             MoveToBackCommand = new RelayCommand(MoveLayerToBack, CanMoveToBack);
             MoveToFrontCommand = new RelayCommand(MoveLayerToFront, CanMoveToFront);
             RenameLayerCommand = new RelayCommand(RenameLayer);
+            MergeSelectedCommand = new RelayCommand(MergeSelected, CanMergeSelected);
             MergeWithAboveCommand = new RelayCommand(MergeWithAbove, CanMergeWithAbove);
             MergeWithBelowCommand = new RelayCommand(MergeWithBelow, CanMergeWithBelow);
         }
 
+        public bool CanMergeSelected(object obj)
+        {
+            return Owner.BitmapManager.ActiveDocument?.Layers.Count(x => x.IsActive) > 1;
+        }
+
         public void NewLayer(object parameter)
         {
             Owner.BitmapManager.ActiveDocument.AddNewLayer($"New Layer {Owner.BitmapManager.ActiveDocument.Layers.Count}");
@@ -47,14 +57,27 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
 
         public void SetActiveLayer(object parameter)
         {
-            if (Keyboard.IsKeyDown(Key.LeftShift))
+            int index = (int)parameter;
+            if (Keyboard.IsKeyDown(Key.LeftCtrl))
             {
-                Layer layer = Owner.BitmapManager.ActiveDocument.Layers[(int)parameter];
+                Layer layer = Owner.BitmapManager.ActiveDocument.Layers[index];
                 layer.IsActive = !layer.IsActive;
             }
+            else if (Keyboard.IsKeyDown(Key.LeftShift) 
+                && Owner.BitmapManager.ActiveDocument.Layers.Any(x => x.IsActive))
+                {
+                int firstIndex = Owner.BitmapManager.ActiveDocument.Layers.IndexOf(
+                    Owner.BitmapManager.ActiveDocument.Layers.First(x => x.IsActive));
+
+                int increment = index < firstIndex ? -1 : 1;
+                for (int i = firstIndex; i <= Math.Abs(firstIndex - index); i += increment)
+                {
+                    Owner.BitmapManager.ActiveDocument.Layers[i].IsActive = true //TODO finish shift select
+                }
+            }
             else
             {
-                Owner.BitmapManager.ActiveDocument.SetActiveLayer((int)parameter);
+                Owner.BitmapManager.ActiveDocument.SetActiveLayer(index);
             }
         }
 
@@ -107,16 +130,25 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
             return (int)property > 0;
         }
 
+        public void MergeSelected(object parameter)
+        {
+            Owner.BitmapManager.ActiveDocument.MergeLayers(Owner.BitmapManager.ActiveDocument.Layers.Where(x => x.IsActive).ToArray(), false);
+        }
+
         public void MergeWithAbove(object parameter)
         {
             int index = (int)parameter;
-            Owner.BitmapManager.ActiveDocument.MergeLayers(index, index + 1, false);
+            Layer layer1 = Owner.BitmapManager.ActiveDocument.Layers[index];
+            Layer layer2 = Owner.BitmapManager.ActiveDocument.Layers[index + 1];
+            Owner.BitmapManager.ActiveDocument.MergeLayers(new Layer[] { layer1, layer2 }, false);
         }
 
         public void MergeWithBelow(object parameter)
         {
             int index = (int)parameter;
-            Owner.BitmapManager.ActiveDocument.MergeLayers(index - 1, index, true);
+            Layer layer1 = Owner.BitmapManager.ActiveDocument.Layers[index - 1];
+            Layer layer2 = Owner.BitmapManager.ActiveDocument.Layers[index];
+            Owner.BitmapManager.ActiveDocument.MergeLayers(new Layer[] { layer1, layer2 }, true);
         }
 
         public bool CanMergeWithAbove(object propery)

+ 12 - 10
PixiEditor/Views/MainWindow.xaml

@@ -110,29 +110,29 @@
                     <MenuItem Header="_Deselect" Command="{Binding SelectionSubViewModel.DeselectCommand}" InputGestureText="Ctrl+D" />
                 </MenuItem>
                 <MenuItem Header="_Document">
-                    <MenuItem Header="Resize Document..." Command="{Binding DocumentSubViewModel.OpenResizePopupCommand}"
+                    <MenuItem Header="_Resize Document..." Command="{Binding DocumentSubViewModel.OpenResizePopupCommand}"
                               InputGestureText="Ctrl+Shift+I" />
-                    <MenuItem Header="Resize Canvas..." Command="{Binding DocumentSubViewModel.OpenResizePopupCommand}"
+                    <MenuItem Header="_Resize Canvas..." Command="{Binding DocumentSubViewModel.OpenResizePopupCommand}"
                               CommandParameter="canvas" InputGestureText="Ctrl+Shift+C" />
-                    <MenuItem Header="Clip Canvas" Command="{Binding DocumentSubViewModel.ClipCanvasCommand}" />
+                    <MenuItem Header="_Clip Canvas" Command="{Binding DocumentSubViewModel.ClipCanvasCommand}" />
                     <Separator/>
-                    <MenuItem Header="Center Content" Command="{Binding DocumentSubViewModel.CenterContentCommand}" />
+                    <MenuItem Header="_Center Content" Command="{Binding DocumentSubViewModel.CenterContentCommand}" />
                 </MenuItem>
                 <MenuItem Header="_View">
-                    <MenuItem Header="Show Grid Lines" IsChecked="{Binding ViewportSubViewModel.GridLinesEnabled, Mode=TwoWay}"
+                    <MenuItem Header="_Show Grid Lines" IsChecked="{Binding ViewportSubViewModel.GridLinesEnabled, Mode=TwoWay}"
                               IsCheckable="True" InputGestureText="Ctrl+`"/>
                 </MenuItem>
                 <MenuItem Header="_Help">
-                    <MenuItem Header="Documentation" Command="{Binding MiscSubViewModel.OpenHyperlinkCommand}"
+                    <MenuItem Header="_Documentation" Command="{Binding MiscSubViewModel.OpenHyperlinkCommand}"
                               CommandParameter="https://github.com/PixiEditor/PixiEditor/wiki"/>
-                    <MenuItem Header="Repository" Command="{Binding MiscSubViewModel.OpenHyperlinkCommand}"
+                    <MenuItem Header="_Repository" Command="{Binding MiscSubViewModel.OpenHyperlinkCommand}"
                               CommandParameter="https://github.com/PixiEditor/PixiEditor"/>
-                    <MenuItem Header="Shortcuts" Command="{Binding MiscSubViewModel.OpenHyperlinkCommand}"
+                    <MenuItem Header="_Shortcuts" Command="{Binding MiscSubViewModel.OpenHyperlinkCommand}"
                               CommandParameter="https://github.com/PixiEditor/PixiEditor/wiki/Shortcuts"/>
                     <Separator/>
-                    <MenuItem Header="License" Command="{Binding MiscSubViewModel.OpenHyperlinkCommand}"
+                    <MenuItem Header="_License" Command="{Binding MiscSubViewModel.OpenHyperlinkCommand}"
                               CommandParameter="https://github.com/PixiEditor/PixiEditor/blob/master/LICENSE"/>
-                    <MenuItem Header="Third Party Licenses" Command="{Binding MiscSubViewModel.OpenHyperlinkCommand}"
+                    <MenuItem Header="_Third Party Licenses" Command="{Binding MiscSubViewModel.OpenHyperlinkCommand}"
                               CommandParameter="https://github.com/PixiEditor/PixiEditor/wiki/Third-party-licenses"/>
                 </MenuItem>
             </Menu>
@@ -346,6 +346,8 @@
                                                                                   Command="{Binding LayersSubViewModel.MoveToBackCommand, Source={StaticResource ViewModelMain}}"
                                                                                   CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
                                 Path=(ItemsControl.AlternationIndex)}" />
+                                                                        <MenuItem Header="Merge selected"
+                                                                                  Command="{Binding LayersSubViewModel.MergeSelectedCommand, Source={StaticResource ViewModelMain}}"/>
                                                                         <MenuItem Header="Merge with above"
                                                                                   Command="{Binding LayersSubViewModel.MergeWithAboveCommand, Source={StaticResource ViewModelMain}}"
                                                                                   CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},

+ 1 - 1
PixiEditor/Views/UserControls/LayerItem.xaml

@@ -18,7 +18,7 @@
             <behaviors:ClearFocusOnClickBehavior/>
         </i:Interaction.Behaviors>
         <i:Interaction.Triggers>
-            <i:EventTrigger EventName="MouseDown">
+            <i:EventTrigger EventName="MouseLeftButtonDown">
                 <i:InvokeCommandAction Command="{Binding ElementName=uc, 
                             Path=SetActiveLayerCommand}"
                                        CommandParameter="{Binding Path=LayerIndex, ElementName=uc}"/>