Browse Source

Implemented whole image magic wand tool

CPKreuz 4 years ago
parent
commit
a7b72fb854

+ 12 - 0
PixiEditor/Models/Enums/DocumentScope.cs

@@ -0,0 +1,12 @@
+using System.ComponentModel;
+
+namespace PixiEditor.Models.Enums
+{
+    public enum DocumentScope
+    {
+        [Description("Single Layer")]
+        SingleLayer,
+        [Description("All Layers")]
+        AllLayers
+    }
+}

+ 4 - 4
PixiEditor/Models/ImageManipulation/BitmapUtils.cs

@@ -40,16 +40,16 @@ namespace PixiEditor.Models.ImageManipulation
         /// <param name="height">Height of final bitmap.</param>.
         /// <param name="layers">Layers to combine.</param>
         /// <returns>WriteableBitmap of layered bitmaps.</returns>
-        public static WriteableBitmap CombineLayers(int width, int height, Layer[] layers, LayerStructure structure = null)
+        public static WriteableBitmap CombineLayers(int width, int height, IEnumerable<Layer> layers, LayerStructure structure = null)
         {
             WriteableBitmap finalBitmap = BitmapFactory.New(width, height);
 
             using (finalBitmap.GetBitmapContext())
             {
-                for (int i = 0; i < layers.Length; i++)
+                for (int i = 0; i < layers.Count(); i++)
                 {
-                    float layerOpacity = structure == null ? layers[i].Opacity : LayerStructureUtils.GetFinalLayerOpacity(layers[i], structure);
-                    Layer layer = layers[i];
+                    float layerOpacity = structure == null ? layers.ElementAt(i).Opacity : LayerStructureUtils.GetFinalLayerOpacity(layers.ElementAt(i), structure);
+                    Layer layer = layers.ElementAt(i);
 
                     if (layer.OffsetX < 0 || layer.OffsetY < 0 ||
                         layer.Width + layer.OffsetX > layer.MaxWidth ||

+ 14 - 0
PixiEditor/Models/Tools/ToolSettings/Toolbars/MagicWandToolbar.cs

@@ -0,0 +1,14 @@
+using PixiEditor.Models.Enums;
+using PixiEditor.Models.Tools.ToolSettings.Settings;
+
+namespace PixiEditor.Models.Tools.ToolSettings.Toolbars
+{
+    public class MagicWandToolbar : SelectToolToolbar
+    {
+        public MagicWandToolbar()
+            : base(false)
+        {
+            Settings.Add(new EnumSetting<DocumentScope>(nameof(DocumentScope), "Scope"));
+        }
+    }
+}

+ 84 - 14
PixiEditor/Models/Tools/Tools/MagicWandTool.cs

@@ -3,12 +3,15 @@ using PixiEditor.Helpers.Extensions;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.Enums;
+using PixiEditor.Models.ImageManipulation;
+using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
+using PixiEditor.Models.Tools.ToolSettings;
+using PixiEditor.Models.Tools.ToolSettings.Settings;
 using PixiEditor.Models.Tools.ToolSettings.Toolbars;
 using PixiEditor.ViewModels;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
-using System.Linq;
 using System.Windows.Input;
 
 namespace PixiEditor.Models.Tools.Tools
@@ -16,6 +19,7 @@ namespace PixiEditor.Models.Tools.Tools
     public class MagicWandTool : ReadonlyTool
     {
         private readonly FloodFill floodFill;
+        private SelectionType previousSelectionType;
 
         public override string ImagePath => $"/Images/Tools/{nameof(FloodFill)}Image.png";
 
@@ -25,24 +29,41 @@ namespace PixiEditor.Models.Tools.Tools
 
         private IEnumerable<Coordinates> oldSelection;
 
-        public SelectionType SelectionType { get; set; } = SelectionType.Add;
-
         public override void OnRecordingLeftMouseDown(MouseEventArgs e)
         {
-            SelectionType = Toolbar.GetEnumSetting<SelectionType>("SelectMode").Value;
+            if (e.LeftButton != MouseButtonState.Pressed)
+            {
+                return;
+            }
 
             oldSelection = new ReadOnlyCollection<Coordinates>(ActiveSelection.SelectedPoints);
-        }
 
-        public override void OnStoppedRecordingMouseUp(MouseEventArgs e)
-        {
-            if (ActiveSelection.SelectedPoints.Count <= 1)
+            SelectionType selectionType = Toolbar.GetEnumSetting<SelectionType>("SelectMode").Value;
+            DocumentScope documentScope = Toolbar.GetEnumSetting<DocumentScope>(nameof(DocumentScope)).Value;
+
+            Document document = BitmapManager.ActiveDocument;
+            Layer layer;
+
+            if (documentScope == DocumentScope.SingleLayer)
             {
-                // If we have not selected multiple points, clear the selection
-                ActiveSelection.Clear();
+                layer = BitmapManager.ActiveLayer;
+            }
+            else
+            {
+                layer = new Layer("_CombinedLayers", BitmapUtils.CombineLayers(document.Width, document.Height, document.Layers, document.LayerStructure));
             }
 
-            SelectionHelpers.AddSelectionUndoStep(ViewModelMain.Current.BitmapManager.ActiveDocument, oldSelection, SelectionType);
+            Selection selection = BitmapManager.ActiveDocument.ActiveSelection;
+
+            selection.SetSelection(
+                floodFill.ForestFire(
+                    layer,
+                    new Coordinates((int)document.MouseXOnCanvas, (int)document.MouseYOnCanvas),
+                    System.Windows.Media.Colors.White
+                    ).ChangedPixels.Keys,
+                selectionType);
+
+            SelectionHelpers.AddSelectionUndoStep(ViewModelMain.Current.BitmapManager.ActiveDocument, oldSelection, selectionType);
         }
 
         public MagicWandTool(BitmapManager manager)
@@ -50,14 +71,63 @@ namespace PixiEditor.Models.Tools.Tools
             floodFill = new FloodFill(manager);
             BitmapManager = manager;
 
-            Toolbar = new SelectToolToolbar(false);
+            Toolbar = new MagicWandToolbar();
+
+            var selectionTypeSetting = Toolbar.GetEnumSetting<SelectionType>("SelectMode");
+
+            selectionTypeSetting.ValueChanged += MagicWandTool_ValueChanged;
+
+            UpdateActionDisplay(selectionTypeSetting);
         }
 
         public override void Use(List<Coordinates> pixels)
         {
-            Selection selection = BitmapManager.ActiveDocument.ActiveSelection;
+            return;
+        }
+
+        public override void OnKeyDown(KeyEventArgs e)
+        {
+            if (e.Key != Key.LeftShift || e.IsRepeat)
+            {
+                return;
+            }
+
+            EnumSetting<SelectionType> enumSetting = Toolbar.GetEnumSetting<SelectionType>("SelectMode");
+            previousSelectionType = enumSetting.Value;
+            enumSetting.Value = SelectionType.Add;
+        }
+
+        public override void OnKeyUp(KeyEventArgs e)
+        {
+            if (e.Key != Key.LeftShift)
+            {
+                return;
+            }
+
+            Toolbar.GetEnumSetting<SelectionType>("SelectMode").Value = previousSelectionType;
+        }
 
-            selection.SetSelection(floodFill.ForestFire(BitmapManager.ActiveLayer, pixels.First(), System.Windows.Media.Colors.White).ChangedPixels.Keys, Toolbar.GetEnumSetting<SelectionType>("SelectMode").Value);
+        private void MagicWandTool_ValueChanged(object sender, SettingValueChangedEventArgs<SelectionType> e)
+        {
+            UpdateActionDisplay(sender as EnumSetting<SelectionType>);
+        }
+
+        private void UpdateActionDisplay(EnumSetting<SelectionType> setting)
+        {
+            if (setting.Value == SelectionType.Add)
+            {
+                if (Keyboard.IsKeyDown(Key.LeftShift))
+                {
+                    ActionDisplay = $"Click to flood the selection. Release shift to revert the selection type to {previousSelectionType}";
+                    return;
+                }
+
+                ActionDisplay = "Click to flood the selection";
+            }
+            else
+            {
+                ActionDisplay = $"Click to flood the selection. Hold shift to set the selection type to {nameof(SelectionType.Add)}";
+            }
         }
     }
 }