Browse Source

Added selection mode (wip visuals) and delete selected pixels

flabbet 5 years ago
parent
commit
895fd0807b

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

@@ -1,6 +1,9 @@
 using PixiEditor.Models.DataHolders;
+using PixiEditor.Models.Images;
+using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
 using PixiEditor.Models.Tools;
+using PixiEditor.Models.Tools.Tools;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -25,6 +28,22 @@ namespace PixiEditor.Models.Controllers
             Manager = manager;
         }
 
+        public void DeletePixels(Layer[] layers, Coordinates[] pixels)
+        {
+            var changes = BitmapPixelChanges.FromSingleColoredArray(pixels, Color.FromArgb(0,0,0,0));
+            var oldValues = BitmapUtils.GetPixelsForSelection(layers, pixels);
+            LayerChange[] old = new LayerChange[layers.Length];
+            LayerChange[] newChange = new LayerChange[layers.Length];
+            for (int i = 0; i < layers.Length; i++)
+            {
+                old[i] = new LayerChange(
+                    BitmapPixelChanges.FromArrays(pixels, oldValues[layers[i]]), i);
+                newChange[i] = new LayerChange(changes, i);
+                layers[i].ApplyPixels(changes);
+            }
+            UndoManager.AddUndoChange(new Change("UndoChanges", old, newChange, "Deleted pixels"));
+        }
+
         public void ExecuteTool(Coordinates newPos, List<Coordinates> mouseMove, BitmapOperationTool tool)
         {
             if (Manager.ActiveDocument != null && tool != null && tool.ToolType != ToolType.None)

+ 11 - 0
PixiEditor/Models/Enums/SelectionType.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace PixiEditor.Models.Enums
+{
+    public enum SelectionType
+    {
+        New, Add, Substract
+    }
+}

+ 28 - 1
PixiEditor/Models/Images/BitmapUtils.cs

@@ -1,5 +1,8 @@
-using PixiEditor.Models.Layers;
+using PixiEditor.Models.DataHolders;
+using PixiEditor.Models.Layers;
+using PixiEditor.Models.Position;
 using System;
+using System.Collections.Generic;
 using System.Drawing;
 using System.Linq;
 using System.Windows;
@@ -55,5 +58,29 @@ namespace PixiEditor.Models.Images
             finalBitmap.Unlock();
             return finalBitmap;
         }
+
+        public static Dictionary<Layer, System.Windows.Media.Color[]> GetPixelsForSelection(Layer[] layers, Coordinates[] selection)
+        {
+            Dictionary<Layer, System.Windows.Media.Color[]> result = new Dictionary<Layer, System.Windows.Media.Color[]>();
+
+            for (int i = 0; i < layers.Length; i++)
+            {
+                System.Windows.Media.Color[] pixels = new System.Windows.Media.Color[selection.Length];
+                layers[i].LayerBitmap.Lock();
+
+                for (int j = 0; j < pixels.Length; j++)
+                {
+                    Coordinates position = selection[j];
+                    if (position.X < 0 || position.X > layers[i].Width - 1 || position.Y < 0 || position.Y > layers[i].Height - 1)
+                        continue;
+                    pixels[j] = layers[i].LayerBitmap.GetPixel(position.X, position.Y);
+                }
+                layers[i].LayerBitmap.Unlock();
+
+                result[layers[i]] = pixels;
+            }
+
+            return result;
+        }
     }
 }

+ 52 - 0
PixiEditor/Models/Tools/ToolSettings/Settings/DropdownSetting.cs

@@ -0,0 +1,52 @@
+using PixiEditor.Helpers;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+
+namespace PixiEditor.Models.Tools.ToolSettings.Settings
+{
+    public class DropdownSetting : Setting
+    {
+        public string[] Values { get; set; }
+        public DropdownSetting(string name, string[] values, string label) : base(name)
+        {
+            Values = values;
+            SettingControl = GenerateDropdown();
+            Value = ((ComboBox)SettingControl).Items[0];
+            Label = label;
+        }
+
+
+        private ComboBox GenerateDropdown()
+        {
+            ComboBox combobox = new ComboBox()
+            {
+                VerticalAlignment = VerticalAlignment.Center
+            };
+            GenerateItems(combobox);
+
+            Binding binding = new Binding("Value")
+            {
+                Mode = BindingMode.TwoWay
+            };
+            combobox.SetBinding(ComboBox.SelectedValueProperty, binding);
+            return combobox;
+        }
+
+        private void GenerateItems(ComboBox comboBox)
+        {
+            for (int i = 0; i < Values.Length; i++)
+            {
+                ComboBoxItem item = new ComboBoxItem
+                {
+                    Content = Values[i]
+                };
+                comboBox.Items.Add(item);
+            }
+        }
+
+    }
+}

+ 15 - 0
PixiEditor/Models/Tools/ToolSettings/Toolbars/SelectToolToolbar.cs

@@ -0,0 +1,15 @@
+using PixiEditor.Models.Tools.ToolSettings.Settings;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace PixiEditor.Models.Tools.ToolSettings.Toolbars
+{
+    public class SelectToolToolbar : Toolbar
+    {
+        public SelectToolToolbar()
+        {
+            Settings.Add(new DropdownSetting("Mode", new string[] {"New"}, "Selection type"));
+        }
+    }
+}

+ 5 - 0
PixiEditor/Models/Tools/ToolSettings/Toolbars/Toolbar.cs

@@ -14,6 +14,11 @@ namespace PixiEditor.Models.Tools.ToolSettings
             return Settings.FirstOrDefault(x => x.Name == name);
         }
 
+        public virtual Setting[] GetSettings(string name)
+        {
+            return Settings.Where(x => x.Name == name).ToArray();
+        }
+
         /// <summary>
         /// Saves current toolbar state, so other toolbars with common settings can load them.
         /// </summary>

+ 6 - 1
PixiEditor/Models/Tools/Tools/EarserTool.cs

@@ -17,9 +17,14 @@ namespace PixiEditor.Models.Tools.Tools
         }
 
         public override LayerChange[] Use(Layer layer, Coordinates[] coordinates, Color color)
+        {
+            return Earse(layer, coordinates, (int)Toolbar.GetSetting("ToolSize").Value);
+        }
+
+        public LayerChange[] Earse(Layer layer, Coordinates[] coordinates, int toolSize)
         {
             PenTool pen = new PenTool();
-            var pixels = pen.Draw(coordinates[0], System.Windows.Media.Colors.Transparent, (int)Toolbar.GetSetting("ToolSize").Value);
+            var pixels = pen.Draw(coordinates[0], System.Windows.Media.Colors.Transparent, toolSize);
             return new LayerChange[] { new LayerChange(pixels, layer) };
         }
     }

+ 3 - 26
PixiEditor/Models/Tools/Tools/MoveTool.cs

@@ -1,6 +1,7 @@
 using PixiEditor.Helpers.Extensions;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
+using PixiEditor.Models.Images;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
 using PixiEditor.ViewModels;
@@ -79,7 +80,7 @@ namespace PixiEditor.Models.Tools.Tools
                 }
 
                 _startSelection = _currentSelection;
-                _startPixelColors = GetPixelsForSelection(_affectedLayers, _startSelection);
+                _startPixelColors = BitmapUtils.GetPixelsForSelection(_affectedLayers, _startSelection);
             }
 
             LayerChange[] result = new LayerChange[_affectedLayers.Length];
@@ -143,30 +144,6 @@ namespace PixiEditor.Models.Tools.Tools
 
                 _clearedPixels[layer] = true;
             }
-        }
-
-        private Dictionary<Layer, Color[]> GetPixelsForSelection(Layer[] layers, Coordinates[] selection)
-        {
-            Dictionary<Layer, Color[]> result = new Dictionary<Layer, Color[]>();
-
-            for (int i = 0; i < layers.Length; i++)
-            {
-                Color[] pixels = new Color[_startSelection.Length];
-                layers[i].LayerBitmap.Lock();
-
-                for (int j = 0; j < pixels.Length; j++)
-                {
-                    Coordinates position = selection[j];
-                    if (position.X < 0 || position.X > layers[i].Width - 1 || position.Y < 0 || position.Y > layers[i].Height - 1)
-                        continue;
-                    pixels[j] = layers[i].LayerBitmap.GetPixel(position.X, position.Y);
-                }
-                layers[i].LayerBitmap.Unlock();
-
-                result[layers[i]] = pixels;
-            }
-
-            return result;
-        }
+        }       
     }
 }

+ 24 - 1
PixiEditor/Models/Tools/Tools/SelectTool.cs

@@ -1,26 +1,34 @@
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
+using PixiEditor.Models.Enums;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
+using PixiEditor.Models.Tools.ToolSettings.Toolbars;
 using PixiEditor.ViewModels;
+using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Windows.Controls;
 
 namespace PixiEditor.Models.Tools.Tools
 {
     public class SelectTool : ReadonlyTool
     {
         public override ToolType ToolType => ToolType.Select;
+        public SelectionType SelectionType = SelectionType.Add;
 
         Selection _oldSelection = null;
 
         public SelectTool()
         {
             Tooltip = "Selects area. (M)";
+            Toolbar = new SelectToolToolbar();
         }
 
         public override void OnMouseDown()
         {
+            Enum.TryParse((Toolbar.GetSetting("Mode").Value as ComboBoxItem).Content as string, out SelectionType);
+
             _oldSelection = null;
             if (ViewModelMain.Current.ActiveSelection != null && ViewModelMain.Current.ActiveSelection.SelectedPoints != null)
             {
@@ -43,7 +51,22 @@ namespace PixiEditor.Models.Tools.Tools
         private void Select(Coordinates[] pixels)
         {
             Coordinates[] selection = GetRectangleSelectionForPoints(pixels[^1], pixels[0]);
-            ViewModelMain.Current.ActiveSelection = new DataHolders.Selection(selection.ToArray());
+            switch (SelectionType)
+            {
+                case SelectionType.New:
+                    ViewModelMain.Current.ActiveSelection = new Selection(selection.ToArray());
+                    break;
+                case SelectionType.Add:
+                    ViewModelMain.Current.ActiveSelection = new Selection(ViewModelMain.Current.ActiveSelection.
+                        SelectedPoints.Concat(selection).Distinct().ToArray());
+                    break;
+                case SelectionType.Substract:
+                    ViewModelMain.Current.ActiveSelection = new Selection(ViewModelMain.Current.ActiveSelection.
+                        SelectedPoints.Except(selection).ToArray());
+                    break;
+                default:
+                    break;
+            }
         }
 
         public Coordinates[] GetRectangleSelectionForPoints(Coordinates start, Coordinates end)

+ 0 - 2
PixiEditor/Styles/ThemeStyle.xaml

@@ -147,6 +147,4 @@
             </Setter.Value>
         </Setter>
     </Style>
-
-
 </ResourceDictionary>

+ 1 - 2
PixiEditor/Styles/Titlebar.xaml

@@ -1,6 +1,5 @@
 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-                    xmlns:local="clr-namespace:PixiEditor.Styles">
+                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 
     <!--Base style for title bar buttons-->
         <Style x:Key="CaptionButtonStyle" TargetType="Button">

+ 10 - 0
PixiEditor/ViewModels/ViewModelMain.cs

@@ -3,7 +3,9 @@ using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.Dialogs;
 using PixiEditor.Models.Enums;
+using PixiEditor.Models.Images;
 using PixiEditor.Models.IO;
+using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
 using PixiEditor.Models.Tools;
 using PixiEditor.Models.Tools.Tools;
@@ -47,6 +49,7 @@ namespace PixiEditor.ViewModels
         public RelayCommand CutCommand { get; set; }
         public RelayCommand PasteCommand { get; set; }
         public RelayCommand ClipCanvasCommand { get; set; }
+        public RelayCommand DeletePixelsCommand { get; set; }
 
 
         private double _mouseXonCanvas;
@@ -186,6 +189,7 @@ namespace PixiEditor.ViewModels
             CutCommand = new RelayCommand(Cut, SelectionIsNotEmpty);
             PasteCommand = new RelayCommand(Paste, CanPaste);
             ClipCanvasCommand = new RelayCommand(ClipCanvas, DocumentIsNotNull);
+            DeletePixelsCommand = new RelayCommand(DeletePixels, SelectionIsNotEmpty);
             ToolSet = new ObservableCollection<Tool> {new MoveTool(), new PenTool(), new SelectTool(), new FloodFill(), new LineTool(),
             new CircleTool(), new RectangleTool(), new EarserTool(), new ColorPickerTool(), new BrightnessTool()};
             ShortcutController = new ShortcutController
@@ -214,6 +218,7 @@ namespace PixiEditor.ViewModels
                     new Shortcut(Key.V, PasteCommand, modifier: ModifierKeys.Control),
                     new Shortcut(Key.J, DuplicateCommand, modifier: ModifierKeys.Control),
                     new Shortcut(Key.X, CutCommand, modifier: ModifierKeys.Control),
+                    new Shortcut(Key.Delete, DeletePixelsCommand),
                 }
             };
             UndoManager.SetMainRoot(this);
@@ -223,6 +228,11 @@ namespace PixiEditor.ViewModels
             Current = this;
         }
 
+        private void DeletePixels(object parameter)
+        {
+            BitmapManager.BitmapOperations.DeletePixels(new Layer[] { BitmapManager.ActiveLayer }, ActiveSelection.SelectedPoints);
+        }
+
         public void ClipCanvas(object parameter)
         {
             if(BitmapManager.ActiveDocument != null)

+ 2 - 0
PixiEditor/Views/MainWindow.xaml

@@ -74,6 +74,8 @@
                     <MenuItem Header="_Copy" Command="{Binding CopyCommand}" InputGestureText="Ctrl+C"/>
                     <MenuItem Header="_Paste" Command="{Binding PasteCommand}" InputGestureText="Ctrl+V"/>
                     <MenuItem Header="_Duplicate" Command="{Binding DuplicateCommand}" InputGestureText="Ctrl+D"/>
+                    <Separator/>
+                    <MenuItem Header="_Delete Selected" Command="{Binding DeletePixelsCommand}" InputGestureText="Delete"/>
                 </MenuItem>
                 <MenuItem Header="_Select">
                     <MenuItem Header="_Select All" Command="{Binding SelectAllCommand}" InputGestureText="Ctrl+A"/>