Browse Source

Merge pull request #13 from flabbet/dev

Merge dev into master
Krzysztof Krysiński 5 years ago
parent
commit
0bed8a5ec7
54 changed files with 1712 additions and 636 deletions
  1. 19 1
      PixiEditor/Helpers/Behaviours/MouseBehaviour.cs
  2. 45 6
      PixiEditor/Helpers/Behaviours/TextBoxFocusBehavior.cs
  3. 32 0
      PixiEditor/Helpers/Converters/BoolToIntConverter.cs
  4. 3 0
      PixiEditor/Helpers/Converters/ToolSizeToIntConverter.cs
  5. 26 0
      PixiEditor/Helpers/Extensions/DictionaryHelper.cs
  6. BIN
      PixiEditor/Images/BrightnessImage.png
  7. BIN
      PixiEditor/Images/BucketImage.png
  8. BIN
      PixiEditor/Images/CircleImage.png
  9. BIN
      PixiEditor/Images/ColorPickerImage.png
  10. BIN
      PixiEditor/Images/EarserImage.png
  11. BIN
      PixiEditor/Images/LightenImage.png
  12. BIN
      PixiEditor/Images/LineImage.png
  13. BIN
      PixiEditor/Images/PenImage.png
  14. BIN
      PixiEditor/Images/PipetteImage.png
  15. BIN
      PixiEditor/Images/RectangleImage.png
  16. 115 13
      PixiEditor/Models/Colors/ExColor.cs
  17. 100 17
      PixiEditor/Models/Controllers/BitmapOperationsUtility.cs
  18. 11 0
      PixiEditor/Models/Controllers/MouseMovementController.cs
  19. 109 0
      PixiEditor/Models/ImageManipulation/Morphology.cs
  20. 1 0
      PixiEditor/Models/Layers/Layer.cs
  21. 7 5
      PixiEditor/Models/Position/CoordinatesCalculator.cs
  22. 11 81
      PixiEditor/Models/Tools/ShapeTool.cs
  23. 22 3
      PixiEditor/Models/Tools/Tool.cs
  24. 40 0
      PixiEditor/Models/Tools/ToolSettings/Settings/BoolSetting.cs
  25. 32 0
      PixiEditor/Models/Tools/ToolSettings/Settings/ColorSetting.cs
  26. 46 0
      PixiEditor/Models/Tools/ToolSettings/Settings/FloatSetting.cs
  27. 29 0
      PixiEditor/Models/Tools/ToolSettings/Settings/Setting.cs
  28. 46 0
      PixiEditor/Models/Tools/ToolSettings/Settings/SizeSetting.cs
  29. 16 0
      PixiEditor/Models/Tools/ToolSettings/Toolbars/BasicShapeToolbar.cs
  30. 17 0
      PixiEditor/Models/Tools/ToolSettings/Toolbars/BasicToolbar.cs
  31. 15 0
      PixiEditor/Models/Tools/ToolSettings/Toolbars/BrightnessToolToolbar.cs
  32. 11 0
      PixiEditor/Models/Tools/ToolSettings/Toolbars/EmptyToolbar.cs
  33. 49 0
      PixiEditor/Models/Tools/ToolSettings/Toolbars/Toolbar.cs
  34. 27 9
      PixiEditor/Models/Tools/Tools/BrightnessTool.cs
  35. 56 52
      PixiEditor/Models/Tools/Tools/CircleTool.cs
  36. 25 0
      PixiEditor/Models/Tools/Tools/ColorPickerTool.cs
  37. 9 2
      PixiEditor/Models/Tools/Tools/EarserTool.cs
  38. 6 1
      PixiEditor/Models/Tools/Tools/FloodFill.cs
  39. 134 12
      PixiEditor/Models/Tools/Tools/LineTool.cs
  40. 7 5
      PixiEditor/Models/Tools/Tools/PenTool.cs
  41. 68 8
      PixiEditor/Models/Tools/Tools/RectangleTool.cs
  42. 2 2
      PixiEditor/PixiEditor.csproj
  43. 110 98
      PixiEditor/Styles/ThemeStyle.xaml
  44. 76 52
      PixiEditor/ViewModels/ViewModelMain.cs
  45. 1 1
      PixiEditor/Views/MainDrawingPanel.xaml
  46. 4 18
      PixiEditor/Views/MainDrawingPanel.xaml.cs
  47. 219 226
      PixiEditor/Views/MainWindow.xaml
  48. 1 1
      PixiEditor/Views/MenuButton.xaml
  49. 16 8
      PixiEditor/Views/NewFilePopup.xaml
  50. 16 0
      PixiEditor/Views/NumerInput.xaml
  51. 74 0
      PixiEditor/Views/NumerInput.xaml.cs
  52. 17 11
      PixiEditor/Views/SaveFilePopup.xaml
  53. 2 2
      PixiEditorTests/ModelsTests/PositionTests/CoordinatesCalculatorTests.cs
  54. 40 2
      PixiEditorTests/WorkspaceTests/ColorsTests/ExtendedColorTests.cs

+ 19 - 1
PixiEditor/Helpers/Behaviours/MouseBehaviour.cs

@@ -27,6 +27,20 @@ namespace PixiEditor.Helpers.Behaviours {
             set { SetValue(MouseXProperty, value); }
         }
 
+
+
+        public FrameworkElement RelativeTo
+        {
+            get { return (FrameworkElement)GetValue(RelativeToProperty); }
+            set { SetValue(RelativeToProperty, value); }
+        }
+
+        // Using a DependencyProperty as the backing store for RelativeTo.  This enables animation, styling, binding, etc...
+        public static readonly DependencyProperty RelativeToProperty =
+            DependencyProperty.Register("RelativeTo", typeof(FrameworkElement), typeof(MouseBehaviour), new PropertyMetadata(default(FrameworkElement)));
+
+
+
         protected override void OnAttached()
         {
             AssociatedObject.MouseMove += AssociatedObjectOnMouseMove;
@@ -34,7 +48,11 @@ namespace PixiEditor.Helpers.Behaviours {
 
         private void AssociatedObjectOnMouseMove(object sender, MouseEventArgs mouseEventArgs)
         {
-            var pos = mouseEventArgs.GetPosition(AssociatedObject);
+            if(RelativeTo == null)
+            {
+                RelativeTo = AssociatedObject;
+            }
+            var pos = mouseEventArgs.GetPosition(RelativeTo);
             MouseX = pos.X;
             MouseY = pos.Y;
         }

+ 45 - 6
PixiEditor/Helpers/Behaviours/TextBoxNumericFinisherBehavior.cs → PixiEditor/Helpers/Behaviours/TextBoxFocusBehavior.cs

@@ -2,14 +2,49 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
+using System.Text.RegularExpressions;
 using System.Threading.Tasks;
+using System.Windows;
 using System.Windows.Controls;
+using System.Windows.Input;
 using System.Windows.Interactivity;
 
 namespace PixiEditor.Helpers.Behaviours
 {
-    class TextBoxNumericFinisherBehavior : Behavior<TextBox>
+    class TextBoxFocusBehavior : Behavior<TextBox>
     {
+
+        public bool FillSize
+        {
+            get { return (bool)GetValue(FillSizeProperty); }
+            set { SetValue(FillSizeProperty, value); }
+        }
+
+        // Using a DependencyProperty as the backing store for FillSize.  This enables animation, styling, binding, etc...
+        public static readonly DependencyProperty FillSizeProperty =
+            DependencyProperty.Register("FillSize", typeof(bool), typeof(TextBoxFocusBehavior), new PropertyMetadata(false));
+
+
+
+
+
+        public FocusNavigationDirection NextFocusDirection
+        {
+            get { return (FocusNavigationDirection)GetValue(NextFocusDirectionProperty); }
+            set { SetValue(NextFocusDirectionProperty, value); }
+        }
+
+        // Using a DependencyProperty as the backing store for NextFocusDirection.  This enables animation, styling, binding, etc...
+        public static readonly DependencyProperty NextFocusDirectionProperty =
+            DependencyProperty.Register("NextFocusDirection", typeof(FocusNavigationDirection), typeof(TextBoxFocusBehavior), 
+                new PropertyMetadata(FocusNavigationDirection.Up));
+
+
+
+
+
+
+
         private string _oldText; //Value of textbox before editing
         private bool _valueConverted = false; //This bool is used to avoid double convertion if enter is hitted
 
@@ -33,13 +68,17 @@ namespace PixiEditor.Helpers.Behaviours
             if (e.Key != System.Windows.Input.Key.Enter) return;
 
             ConvertValue();
-            AssociatedObject.MoveFocus(new System.Windows.Input.TraversalRequest(System.Windows.Input.FocusNavigationDirection.Next));
+            AssociatedObject.MoveFocus(new TraversalRequest(NextFocusDirection));
         }
 
         private void AssociatedObject_GotKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
         {
-            _valueConverted = false;
-            _oldText = AssociatedObject.Text; //Sets old value when keyboard is focused on object
+            AssociatedObject.SelectAll();
+            if (FillSize)
+            {
+                _valueConverted = false;
+                _oldText = AssociatedObject.Text; //Sets old value when keyboard is focused on object
+            }
         }
 
         private void AssociatedObject_LostKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
@@ -52,8 +91,8 @@ namespace PixiEditor.Helpers.Behaviours
         /// </summary>
         private void ConvertValue()
         {
-            if (_valueConverted == true) return;
-            if (int.TryParse(AssociatedObject.Text, out int result) == true)
+            if (_valueConverted == true || FillSize == false) return;
+            if (int.TryParse(Regex.Replace(AssociatedObject.Text, "\\p{L}", ""), out _) == true)
             {
                 AssociatedObject.Text = string.Format("{0} {1}", AssociatedObject.Text, "px");
             }

+ 32 - 0
PixiEditor/Helpers/Converters/BoolToIntConverter.cs

@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+using System.Windows.Data;
+
+namespace PixiEditor.Helpers.Converters
+{
+    public class BoolToIntConverter : IValueConverter
+    {
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            if (value.ToString() == "0")
+            {
+                return false;
+            }
+            return true;
+        }
+
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            if (value is bool)
+            {
+                if ((bool)value == false)
+                {
+                    return 0;
+                }
+            }
+            return 1;
+        }
+    }
+}

+ 3 - 0
PixiEditor/Helpers/Converters/ToolSizeToIntConverter.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
 using System.Text;
+using System.Text.RegularExpressions;
 using System.Threading.Tasks;
 using System.Windows.Data;
 
@@ -20,6 +21,8 @@ namespace PixiEditor.Helpers
         {
             if (string.IsNullOrWhiteSpace(value as string)) return null;
             string slicedString = value.ToString().Split(' ').First();
+            slicedString = Regex.Replace(slicedString, "\\p{L}", "");
+            if (slicedString == "") return null;
             return int.Parse(slicedString);
         }
     }

+ 26 - 0
PixiEditor/Helpers/Extensions/DictionaryHelper.cs

@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+
+namespace PixiEditor.Helpers.Extensions
+{
+    public static class DictionaryHelper
+    {
+        public static void AddRangeOverride<TKey, TValue>(this IDictionary<TKey, TValue> dict, IDictionary<TKey, TValue> dictToAdd)
+        {
+            foreach (var item in dictToAdd)
+            {
+                dict[item.Key] = item.Value;
+            }
+        }
+
+        public static void AddRangeNewOnly<TKey, TValue>(this IDictionary<TKey, TValue> dict, IDictionary<TKey, TValue> dictToAdd)
+        {
+            foreach (var item in dictToAdd)
+            {
+                if (!dict.ContainsKey(item.Key))
+                {
+                    dict.Add(item.Key, item.Value);
+                }
+            }
+        }
+    }
+}

BIN
PixiEditor/Images/BrightnessImage.png


BIN
PixiEditor/Images/BucketImage.png


BIN
PixiEditor/Images/CircleImage.png


BIN
PixiEditor/Images/ColorPickerImage.png


BIN
PixiEditor/Images/EarserImage.png


BIN
PixiEditor/Images/LightenImage.png


BIN
PixiEditor/Images/LineImage.png


BIN
PixiEditor/Images/PenImage.png


BIN
PixiEditor/Images/PipetteImage.png


BIN
PixiEditor/Images/RectangleImage.png


+ 115 - 13
PixiEditor/Models/Colors/ExColor.cs

@@ -1,4 +1,5 @@
-using System.Windows.Media;
+using System;
+using System.Windows.Media;
 
 namespace PixiEditor.Models.Colors
 {
@@ -15,25 +16,126 @@ namespace PixiEditor.Models.Colors
         /// </returns>
         public static Color ChangeColorBrightness(Color color, float correctionFactor)
         {
-            float red = color.R;
-            float green = color.G;
-            float blue = color.B;
+            Tuple<int, float, float> hsl = RgbToHsl(color.R, color.G, color.B);
+            int h = hsl.Item1;
+            float s = hsl.Item2;
+            float l = hsl.Item3;
 
-            if (correctionFactor < 0)
+            l = Math.Clamp(l + correctionFactor, 0, 100);
+            Color rgb = HslToRGB(h, s, l);
+
+            return Color.FromArgb(color.A, rgb.R, rgb.G, rgb.B);
+        }
+
+
+        /// <summary>
+        /// Converts RGB to HSL
+        /// </summary>
+        /// <param name="r">Red value</param>
+        /// <param name="b">Blue value</param>
+        /// <param name="g">Green value</param>
+        /// <returns>Tuple with 3 values in order: h, s, l0</returns>
+        public static Tuple<int,float,float> RgbToHsl(int r, int g, int b)
+        {
+            int h;
+            float s, l;
+            float dR = (r / 255.0f);
+            float dG = (g / 255.0f);
+            float dB = (b / 255.0f);
+
+            float min = Math.Min(Math.Min(dR, dG), dB);
+            float max = Math.Max(Math.Max(dR, dG), dB);
+            float delta = max - min;
+
+            l = (max + min) / 2;
+
+            if (delta == 0)
             {
-                correctionFactor = 1 + correctionFactor;
-                red *= correctionFactor;
-                green *= correctionFactor;
-                blue *= correctionFactor;
+                h = 0;
+                s = 0.0f;
             }
             else
             {
-                red = (255 - red) * correctionFactor + red;
-                green = (255 - green) * correctionFactor + green;
-                blue = (255 - blue) * correctionFactor + blue;
+                s = (l <= 0.5) ? (delta / (max + min)) : (delta / (2 - max - min));
+
+                float hue;
+
+                if (dR == max)
+                {
+                    hue = ((dG - dB) / 6) / delta;
+                }
+                else if (dG == max)
+                {
+                    hue = (1.0f / 3) + (dB - dR) / 6 / delta;
+                }
+                else
+                {
+                    hue = (2.0f / 3) + (dR - dG) / 6 / delta;
+                }
+
+                if (hue < 0)
+                    hue += 1;
+                if (hue > 1)
+                    hue -= 1;
+
+                h = (int)(hue * 360);
             }
+            return new Tuple<int, float, float>(h, s * 100, l * 100);
+        }
 
-            return Color.FromArgb(color.A, (byte)red, (byte)green, (byte)blue);
+        /// <summary>
+        /// Converts HSL color format to RGB
+        /// </summary>
+        /// <param name="h"></param>
+        /// <param name="s"></param>
+        /// <param name="l"></param>
+        /// <returns>RGB Color</returns>
+        public static Color HslToRGB(int h, float s, float l)
+        {
+            s /= 100;
+            l /= 100;
+            byte r = 0;
+            byte g = 0;
+            byte b = 0;
+
+            if (s == 0)
+            {
+                r = g = b = (byte)(l * 255);
+            }
+            else
+            {
+                float v1, v2;
+                float hue = (float)h / 360;
+
+                v2 = (l < 0.5) ? (l * (1 + s)) : (l + s - (l * s));
+                v1 = 2 * l - v2;
+
+                r = (byte)(255 * HueToRGB(v1, v2, hue + (1.0f / 3)));
+                g = (byte)(255 * HueToRGB(v1, v2, hue));
+                b = (byte)(255 * HueToRGB(v1, v2, hue - (1.0f / 3)));
+            }
+            return Color.FromRgb(r, g, b);
         }
+
+        private static float HueToRGB(float v1, float v2, float hue)
+        {
+            if (hue < 0)
+                hue += 1;
+
+            if (hue > 1)
+                hue -= 1;
+
+            if ((6 * hue) < 1)
+                return (v1 + (v2 - v1) * 6 * hue);
+
+            if ((2 * hue) < 1)
+                return v2;
+
+            if ((3 * hue) < 2)
+                return (v1 + (v2 - v1) * ((2.0f / 3) - hue) * 6);
+
+            return v1;
+        }
+
     }
 }

+ 100 - 17
PixiEditor/Models/Controllers/BitmapOperationsUtility.cs

@@ -18,7 +18,16 @@ namespace PixiEditor.Models.Controllers
     public class BitmapOperationsUtility : NotifyableObject
     {
         public MouseMovementController MouseController { get; set; }
-        public Tool SelectedTool { get; set; }
+        private Tool _selectedTool;
+        public Tool SelectedTool
+        {
+            get => _selectedTool;
+            private set
+            {                
+                _selectedTool = value;
+                RaisePropertyChanged("SelectedTool");
+            }
+        }
 
         private ObservableCollection<Layer> _layers = new ObservableCollection<Layer>();
 
@@ -55,8 +64,8 @@ namespace PixiEditor.Models.Controllers
         public Layer ActiveLayer => Layers.Count > 0 ? Layers[ActiveLayerIndex] : null;
 
         public Color PrimaryColor { get; set; }
-        
-        public int ToolSize { get; set; }
+
+        public int ToolSize => SelectedTool.Toolbar.GetSetting("ToolSize") != null ? (int)SelectedTool.Toolbar.GetSetting("ToolSize").Value : 1;
 
         public event EventHandler<BitmapChangedEventArgs> BitmapChanged;
         public event EventHandler<LayersChangedEventArgs> LayersChanged;
@@ -67,10 +76,33 @@ namespace PixiEditor.Models.Controllers
         public BitmapOperationsUtility()
         {
             MouseController = new MouseMovementController();
+            MouseController.StartedRecordingChanges += MouseController_StartedRecordingChanges;
             MouseController.MousePositionChanged += Controller_MousePositionChanged;
             MouseController.StoppedRecordingChanges += MouseController_StoppedRecordingChanges;
         }
 
+        public void SetActiveTool(Tool tool)
+        {
+            if(PreviewLayer != null)
+            {
+                PreviewLayer.Clear();
+            }
+            if (SelectedTool != null)
+            {
+                SelectedTool.Toolbar.SaveToolbarSettings();
+            }
+            SelectedTool = tool;
+            SelectedTool.Toolbar.LoadSharedSettings();
+        }
+
+        private void MouseController_StartedRecordingChanges(object sender, EventArgs e)
+        {
+            if (PreviewLayer != null)
+            {
+                PreviewLayer.Clear();
+            }
+        }
+
         private void MouseController_StoppedRecordingChanges(object sender, EventArgs e)
         {
             if(SelectedTool.RequiresPreviewLayer)
@@ -87,22 +119,71 @@ namespace PixiEditor.Models.Controllers
             if(SelectedTool != null && SelectedTool.ToolType != ToolType.None && Mouse.LeftButton == MouseButtonState.Pressed)
             {
                 var mouseMove = MouseController.LastMouseMoveCoordinates.ToList();
+                if (Layers.Count == 0 || mouseMove.Count == 0) return;
                 mouseMove.Reverse();
+                UseTool(mouseMove);
+                
+                _lastMousePos = e.NewPosition;
+            }
+            else if(Mouse.LeftButton == MouseButtonState.Released)
+            {
+                HighlightPixels(e.NewPosition);
+            }
+        }
 
-                if (!SelectedTool.RequiresPreviewLayer)
-                {
-                    BitmapPixelChanges changedPixels = SelectedTool.Use(Layers[ActiveLayerIndex], mouseMove.ToArray(), PrimaryColor, ToolSize);
-                    BitmapPixelChanges oldPixelsValues = GetOldPixelsValues(changedPixels.ChangedPixels.Keys.ToArray());
-                    ActiveLayer.ApplyPixels(changedPixels);
-                    BitmapChanged?.Invoke(this, new BitmapChangedEventArgs(changedPixels, oldPixelsValues, ActiveLayerIndex));
-                }
-                else
-                {
-                    UseToolOnPreviewLayer(mouseMove);
-                }
+        private void HighlightPixels(Coordinates newPosition)
+        {
+            if (Layers.Count == 0 || SelectedTool.HideHighlight) return;
+            GeneratePreviewLayer();
+            PreviewLayer.Clear();
+            Coordinates[] highlightArea = CoordinatesCalculator.RectangleToCoordinates(CoordinatesCalculator.CalculateThicknessCenter(newPosition, ToolSize));    
+            PreviewLayer.ApplyPixels(BitmapPixelChanges.FromSingleColoredArray(highlightArea, Color.FromArgb(77,0,0,0)));
+        }
 
-                _lastMousePos = e.NewPosition;
+        private void UseTool(List<Coordinates> mouseMoveCords)
+        {
+            if (SelectedTool.PerformsOperationOnBitmap == false) return;
+            if (Keyboard.IsKeyDown(Key.LeftShift) && !MouseCordsNotInLine(mouseMoveCords))
+            {
+                mouseMoveCords = GetSquareCoordiantes(mouseMoveCords);
+            }
+            if (!SelectedTool.RequiresPreviewLayer)
+            {
+                BitmapPixelChanges changedPixels = SelectedTool.Use(Layers[ActiveLayerIndex], mouseMoveCords.ToArray(), PrimaryColor);
+                BitmapPixelChanges oldPixelsValues = GetOldPixelsValues(changedPixels.ChangedPixels.Keys.ToArray());
+                ActiveLayer.ApplyPixels(changedPixels);
+                BitmapChanged?.Invoke(this, new BitmapChangedEventArgs(changedPixels, oldPixelsValues, ActiveLayerIndex));
+            }
+            else
+            {
+                UseToolOnPreviewLayer(mouseMoveCords);
+            }
+        }
+
+        private bool MouseCordsNotInLine(List<Coordinates> cords)
+        {
+            return cords[0].X == cords[^1].X || cords[0].Y == cords[^1].Y;
+        }
+
+        /// <summary>
+        /// Extracts square from rectangle mouse drag, used to draw symmetric shapes.
+        /// </summary>
+        /// <param name="mouseMoveCords"></param>
+        /// <returns></returns>
+        private List<Coordinates> GetSquareCoordiantes(List<Coordinates> mouseMoveCords)
+        {
+            int xLength = mouseMoveCords[0].Y - mouseMoveCords[^1].Y;
+            int yLength = mouseMoveCords[0].Y - mouseMoveCords[^1].Y;
+            if(mouseMoveCords[^1].Y > mouseMoveCords[0].Y)
+            {
+                xLength *= -1;
+            }
+            if(mouseMoveCords[^1].X > mouseMoveCords[0].X)
+            {
+                xLength *= -1;
             }
+            mouseMoveCords[0] = new Coordinates(mouseMoveCords[^1].X + xLength, mouseMoveCords[^1].Y + yLength);
+            return mouseMoveCords;
         }
 
         private BitmapPixelChanges GetOldPixelsValues(Coordinates[] coordinates)
@@ -111,6 +192,8 @@ namespace PixiEditor.Models.Controllers
             Layers[ActiveLayerIndex].LayerBitmap.Lock();
             for (int i = 0; i < coordinates.Length; i++)
             {
+                if (coordinates[i].X < 0 || coordinates[i].X > Layers[0].Width - 1 || coordinates[i].Y < 0 || coordinates[i].Y > Layers[0].Height - 1) 
+                    continue;
                 values.Add(coordinates[i], Layers[ActiveLayerIndex].LayerBitmap.GetPixel(coordinates[i].X, coordinates[i].Y));
             }
             Layers[ActiveLayerIndex].LayerBitmap.Unlock();
@@ -120,11 +203,11 @@ namespace PixiEditor.Models.Controllers
         private void UseToolOnPreviewLayer(List<Coordinates> mouseMove)
         {
             BitmapPixelChanges changedPixels;
-            if (mouseMove[0] != _lastMousePos)
+            if (mouseMove.Count > 0 && mouseMove[0] != _lastMousePos)
             {
                 GeneratePreviewLayer();
                 PreviewLayer.Clear();
-                changedPixels = SelectedTool.Use(Layers[ActiveLayerIndex], mouseMove.ToArray(), PrimaryColor, ToolSize);
+                changedPixels = SelectedTool.Use(Layers[ActiveLayerIndex], mouseMove.ToArray(), PrimaryColor);
                 PreviewLayer.ApplyPixels(changedPixels);
                 _lastChangedPixels = changedPixels;
             }

+ 11 - 0
PixiEditor/Models/Controllers/MouseMovementController.cs

@@ -9,6 +9,7 @@ namespace PixiEditor.Models.Controllers
     public class MouseMovementController
     {
         public List<Coordinates> LastMouseMoveCoordinates { get; } = new List<Coordinates>();
+        public event EventHandler StartedRecordingChanges;
         public event EventHandler<MouseMovementEventArgs> MousePositionChanged;
         public event EventHandler StoppedRecordingChanges;
         public bool IsRecordingChanges { get; private set; } = false;
@@ -19,6 +20,7 @@ namespace PixiEditor.Models.Controllers
             {
                 LastMouseMoveCoordinates.Clear();
                 IsRecordingChanges = true;
+                StartedRecordingChanges?.Invoke(this, EventArgs.Empty);
             }
         }
         public void RecordMouseMovementChange(Coordinates mouseCoordinates)
@@ -33,6 +35,15 @@ namespace PixiEditor.Models.Controllers
             }
         }
 
+        /// <summary>
+        /// Plain mose move, does not affect mouse drag recordings
+        /// </summary>
+        /// <param name="mouseCoordinates"></param>
+        public void MouseMoved(Coordinates mouseCoordinates)
+        {
+            MousePositionChanged?.Invoke(this, new MouseMovementEventArgs(mouseCoordinates));
+        }
+
         public void StopRecordingMouseMovementChanges()
         {
             if (IsRecordingChanges)

+ 109 - 0
PixiEditor/Models/ImageManipulation/Morphology.cs

@@ -0,0 +1,109 @@
+using PixiEditor.Models.Position;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+
+namespace PixiEditor.Models.ImageManipulation
+{
+    public class Morphology
+    {
+
+        public static Coordinates[] ApplyDilation(Coordinates[] points, int kernelSize, int[,] mask)
+        {
+            int kernelDim = kernelSize;
+
+            //This is the offset of center pixel from border of the kernel
+            int kernelOffset = (kernelDim - 1) / 2;
+            int margin = kernelDim;
+
+            byte[,] byteImg = GetByteArrayForPoints(points, margin);
+            byte[,] outputArray = byteImg.Clone() as byte[,];
+            Coordinates offset = new Coordinates(points.Min(x => x.X) - margin, points.Min(x => x.Y) - margin);
+
+            int width = byteImg.GetLength(0);
+            int height = byteImg.GetLength(1);
+            for (int y = kernelOffset; y < height - kernelOffset; y++)
+            {
+                for (int x = kernelOffset; x < width - kernelOffset; x++)
+                {
+                    byte value = 0;
+
+                    //Apply dilation
+                    for (int ykernel = -kernelOffset; ykernel <= kernelOffset; ykernel++)
+                    {
+                        for (int xkernel = -kernelOffset; xkernel <= kernelOffset; xkernel++)
+                        {
+                            if (mask[xkernel + kernelOffset, ykernel + kernelOffset] == 1)
+                            {
+                                value = Math.Max(value, byteImg[x + xkernel, y + ykernel]);
+                            }
+                            else
+                            {
+                                continue;
+                            }
+                        }
+                    }
+                    //Write processed data into the second array
+                    outputArray[x, y] = value;
+                }
+            }
+            return ToCoordinates(outputArray, offset).Distinct().ToArray();
+        }
+
+        private static Coordinates[] ToCoordinates(byte[,] byteArray, Coordinates offset)
+        {
+            List<Coordinates> output = new List<Coordinates>();
+            int width = byteArray.GetLength(0);
+
+            for (int y = 0; y < byteArray.GetLength(1); y++)
+            {
+                for (int x = 0; x < width; x++)
+                {
+                    if(byteArray[x,y] == 1)
+                    {
+                        output.Add(new Coordinates(x + offset.X, y + offset.Y));
+                    }
+
+                }
+            }
+            return output.ToArray();
+        }
+
+        private static byte[,] GetByteArrayForPoints(Coordinates[] points, int margin)
+        {
+            Tuple<int, int> dimensions = GetDimensionsForPoints(points);
+            int minX = points.Min(x => x.X);
+            int minY = points.Min(x => x.Y);
+            byte[,] array = new byte[dimensions.Item1 + margin * 2, dimensions.Item2 + margin * 2];
+            //Debug.Write("----------\n");
+
+            for (int y = 0; y < dimensions.Item2 + margin; y++)
+            {
+                for (int x = 0; x < dimensions.Item1 + margin; x++)
+                {
+                    Coordinates cords = new Coordinates(x + minX, y + minY);
+                    array[x + margin,y + margin] = points.Contains(cords) ? (byte)1 : (byte)0;
+                }
+            }
+
+            //for (int y = 0; y < array.GetLength(1); y++)
+            //{
+            //    for (int x = 0; x < array.GetLength(0); x++)
+            //    {
+            //        Debug.Write($"{array[x, y]} ");
+            //    }
+            //    Debug.Write("\n");
+            //}
+
+            return array;
+        }
+
+        private static Tuple<int, int> GetDimensionsForPoints(Coordinates[] points)
+        {
+            int width = points.Max(x=> x.X) - points.Min(x => x.X);
+            int height = points.Max(x=> x.Y) - points.Min(x => x.Y);
+            return new Tuple<int, int>(width + 1, height + 1);
+        }
+    }
+}

+ 1 - 0
PixiEditor/Models/Layers/Layer.cs

@@ -87,6 +87,7 @@ namespace PixiEditor.Models.Layers
 
             foreach (var coords in pixels.ChangedPixels)
             {
+                if (coords.Key.X > Width - 1 || coords.Key.X < 0 || coords.Key.Y < 0 || coords.Key.Y > Height - 1) continue;
                 LayerBitmap.SetPixel(Math.Clamp(coords.Key.X, 0, Width - 1), Math.Clamp(coords.Key.Y, 0, Height - 1),
                     coords.Value);
             }

+ 7 - 5
PixiEditor/Models/Position/CoordinatesCalculator.cs

@@ -34,11 +34,8 @@ namespace PixiEditor.Models.Position
 
         public static Coordinates GetCenterPoint(Coordinates startingPoint, Coordinates endPoint)
         {
-            double width = endPoint.X - startingPoint.X + 1;
-            double height = endPoint.Y - startingPoint.Y + 1;
-
-            int x = startingPoint.X + (int)Math.Floor(width / 2);
-            int y = startingPoint.Y + (int)Math.Floor(height / 2);
+            int x = (int)Math.Floor((startingPoint.X + endPoint.X) / 2f);
+            int y = (int)Math.Floor((startingPoint.Y + endPoint.Y) / 2f);
             return new Coordinates(x, y);
         }
 
@@ -56,5 +53,10 @@ namespace PixiEditor.Models.Position
             }
             return coordinates.ToArray();
         }
+
+        public static Coordinates[] RectangleToCoordinates(DoubleCords coordinates)
+        {
+            return RectangleToCoordinates(coordinates.Coords1.X, coordinates.Coords1.Y, coordinates.Coords2.X, coordinates.Coords2.Y);
+        }
     }
 }

+ 11 - 81
PixiEditor/Models/Tools/ShapeTool.cs

@@ -1,7 +1,10 @@
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
+using PixiEditor.Models.Tools.Tools;
+using PixiEditor.Models.Tools.ToolSettings;
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Windows.Input;
 using System.Windows.Media;
 
@@ -11,98 +14,25 @@ namespace PixiEditor.Models.Tools
     {
         public override abstract ToolType ToolType { get; }
 
-        public abstract override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize);
+        public abstract override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color);
 
         public ShapeTool()
         {
             RequiresPreviewLayer = true;
             Cursor = Cursors.Cross;
+            Toolbar = new BasicShapeToolbar();
         }
 
-        protected Coordinates[] BresenhamLine(int x1, int y1, int x2, int y2)
+        protected Coordinates[] GetThickShape(Coordinates[] shape, int thickness)
         {
-            List<Coordinates> coordinates = new List<Coordinates>();
-            if(x1 == x2 && y1 == y2)
+            List<Coordinates> output = new List<Coordinates>();
+            for (int i = 0; i < shape.Length; i++)
             {
-                return new Coordinates[] { new Coordinates(x1, y1) };
+                output.AddRange(CoordinatesCalculator.RectangleToCoordinates(CoordinatesCalculator.CalculateThicknessCenter(shape[i], thickness)));
             }
-
-            int d, dx, dy, ai, bi, xi, yi;
-            int x = x1, y = y1;
-
-            if (x1 < x2)
-            {
-                xi = 1;
-                dx = x2 - x1;
-            }
-            else
-            {
-                xi = -1;
-                dx = x1 - x2;
-            }
-
-            if (y1 < y2)
-            {
-                yi = 1;
-                dy = y2 - y1;
-            }
-            else
-            {
-                yi = -1;
-                dy = y1 - y2;
-            }
-            coordinates.Add(new Coordinates(x, y));
-
-            if (dx > dy)
-            {
-                ai = (dy - dx) * 2;
-                bi = dy * 2;
-                d = bi - dx;
-                
-                while (x != x2)
-                {
-                    
-                    if (d >= 0)
-                    {
-                        x += xi;
-                        y += yi;
-                        d += ai;
-                    }
-                    else
-                    {
-                        d += bi;
-                        x += xi;
-                    }
-                    coordinates.Add(new Coordinates(x, y));
-                }
-            }
-            else
-            {
-                ai = (dx - dy) * 2;
-                bi = dx * 2;
-                d = bi - dy;
-                
-                while (y != y2)
-                {
-                    
-                    if (d >= 0)
-                    {
-                        x += xi;
-                        y += yi;
-                        d += ai;
-                    }
-                    else
-                    {
-                        d += bi;
-                        y += yi;
-                    }
-                    coordinates.Add(new Coordinates(x, y));
-                }
-            }
-
-            return coordinates.ToArray();
-
+            return output.Distinct().ToArray();
         }
+     
 
         protected DoubleCords CalculateCoordinatesForShapeRotation(Coordinates startingCords, Coordinates secondCoordinates)
         {

+ 22 - 3
PixiEditor/Models/Tools/Tool.cs

@@ -1,15 +1,34 @@
-using PixiEditor.Models.Layers;
+using PixiEditor.Helpers;
+using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
+using PixiEditor.Models.Tools.ToolSettings;
 using System.Windows.Input;
 using System.Windows.Media;
 
 namespace PixiEditor.Models.Tools
 {
-    public abstract class Tool
+    public abstract class Tool : NotifyableObject
     {
-        public abstract BitmapPixelChanges Use(Layer layer, Coordinates[] pixels, Color color, int toolSize);
+        public abstract BitmapPixelChanges Use(Layer layer, Coordinates[] pixels, Color color);
         public abstract ToolType ToolType { get; }
+        public string ImagePath => $"/Images/{ToolType}Image.png";
+        public bool PerformsOperationOnBitmap { get; set; } = true;
+        public bool HideHighlight { get; set; } = false;
         public bool RequiresPreviewLayer { get; set; }
+        public string Tooltip { get; set; }
+
+        private bool _isActive = false;
+        public bool IsActive
+        {
+            get { return _isActive; }
+            set 
+            { 
+                _isActive = value;
+                RaisePropertyChanged("IsActive");
+            }
+        }
+
         public Cursor Cursor { get; set; } = Cursors.Arrow;
+        public Toolbar Toolbar { get; set; } = new EmptyToolbar();
     }
 }

+ 40 - 0
PixiEditor/Models/Tools/ToolSettings/Settings/BoolSetting.cs

@@ -0,0 +1,40 @@
+using System.Windows.Controls;
+using System.Windows.Data;
+
+namespace PixiEditor.Models.Tools.ToolSettings.Settings
+{
+    public class BoolSetting : Setting
+    {
+        public BoolSetting(string name, string label = "") : base(name)
+        {
+            Label = label;
+            Value = false;
+            SettingControl = GenerateCheckBox();
+        }
+
+        public BoolSetting(string name, bool isChecked, string label = "") : base(name)
+        {
+            Label = label;
+            Value = isChecked;
+            SettingControl = GenerateCheckBox();
+        }
+
+        private Control GenerateCheckBox()
+        {
+            CheckBox checkBox = new CheckBox()
+            {
+                IsChecked = (bool)Value,
+                VerticalAlignment = System.Windows.VerticalAlignment.Center
+            };
+
+            Binding binding = new Binding("Value")
+            {
+                Mode = BindingMode.TwoWay
+            };
+
+            checkBox.SetBinding(CheckBox.IsCheckedProperty, binding);
+
+            return checkBox;
+        }
+    }
+}

+ 32 - 0
PixiEditor/Models/Tools/ToolSettings/Settings/ColorSetting.cs

@@ -0,0 +1,32 @@
+using System.Windows.Data;
+using System.Windows.Media;
+using Xceed.Wpf.Toolkit;
+
+namespace PixiEditor.Models.Tools.ToolSettings.Settings
+{
+    public class ColorSetting : Setting
+    {
+        public ColorSetting(string name, string label = "") : base(name)
+        {
+            Label = label;
+            SettingControl = GenerateColorPicker();
+            Value = Color.FromArgb(0, 0, 0, 0);
+        }
+
+        private ColorPicker GenerateColorPicker()
+        {
+            ColorPicker picker = new ColorPicker()
+            {
+                UsingAlphaChannel = true,
+                AvailableColorsSortingMode = ColorSortingMode.Alphabetical,
+                Width = 70
+            };
+            Binding binding = new Binding("Value")
+            {
+                Mode = BindingMode.TwoWay,
+            };
+            picker.SetBinding(ColorPicker.SelectedColorProperty, binding);
+            return picker;
+        }
+    }
+}

+ 46 - 0
PixiEditor/Models/Tools/ToolSettings/Settings/FloatSetting.cs

@@ -0,0 +1,46 @@
+using PixiEditor.Views;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+
+namespace PixiEditor.Models.Tools.ToolSettings.Settings
+{
+    public class FloatSetting : Setting
+    {
+
+        public float Min { get; set; }
+        public float Max { get; set; }
+
+        public FloatSetting(string name, float initialValue, string label = "", 
+            float min = float.NegativeInfinity, float max = float.PositiveInfinity) : base(name)
+        {
+            Label = label;
+            Value = initialValue;
+            Min = min;
+            Max = max;
+            SettingControl = GenerateNumberInput();
+        }
+
+        private NumberInput GenerateNumberInput()
+        {
+            NumberInput numbrInput = new NumberInput()
+            {
+                Width = 40,
+                Height = 20,
+                Min = Min,
+                Max = Max
+
+            };
+            Binding binding = new Binding("Value")
+            {
+                Mode = BindingMode.TwoWay,
+            };
+            numbrInput.SetBinding(NumberInput.ValueProperty, binding);
+            return numbrInput;
+        }
+    }
+}

+ 29 - 0
PixiEditor/Models/Tools/ToolSettings/Settings/Setting.cs

@@ -0,0 +1,29 @@
+using PixiEditor.Helpers;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows.Controls;
+
+namespace PixiEditor.Models.Tools.ToolSettings
+{
+    public abstract class Setting : NotifyableObject
+    {
+        public string Name { get; protected set; }
+        public string Label { get; set; }
+        public bool HasLabel => !string.IsNullOrEmpty(Label);
+        private object value;
+        public object Value { get => value;
+            set
+            {
+                this.value = value;
+                RaisePropertyChanged("Value");
+            }
+        }
+        public Control SettingControl { get; set; }
+
+        public Setting(string name)
+        {
+            Name = name;
+        }
+	}
+}

+ 46 - 0
PixiEditor/Models/Tools/ToolSettings/Settings/SizeSetting.cs

@@ -0,0 +1,46 @@
+using PixiEditor.Helpers;
+using PixiEditor.Helpers.Behaviours;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Interactivity;
+
+namespace PixiEditor.Models.Tools.ToolSettings.Settings
+{
+    public class SizeSetting : Setting
+    {
+        public SizeSetting(string name, string label = null) : base(name)
+        {
+            Value = 1;
+            SettingControl = GenerateTextBox();
+            Label = label;
+        }
+
+        private TextBox GenerateTextBox()
+        {
+            TextBox tb = new TextBox()
+            {
+                Style = Application.Current.FindResource("DarkTextBoxStyle") as Style,
+                TextAlignment = TextAlignment.Center,
+                MaxLength = 4,
+                Width = 40,
+                Height = 20
+            };
+            Binding binding = new Binding("Value")
+            {
+                Converter = new ToolSizeToIntConverter(),
+                Mode = BindingMode.TwoWay,
+            };
+            tb.SetBinding(TextBox.TextProperty, binding);
+            TextBoxFocusBehavior behavor = new TextBoxFocusBehavior
+            {
+                FillSize = true
+            };
+            Interaction.GetBehaviors(tb).Add(behavor);
+            return tb;
+        }
+    }
+}

+ 16 - 0
PixiEditor/Models/Tools/ToolSettings/Toolbars/BasicShapeToolbar.cs

@@ -0,0 +1,16 @@
+using PixiEditor.Models.Tools.ToolSettings.Settings;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace PixiEditor.Models.Tools.ToolSettings
+{
+    public class BasicShapeToolbar : BasicToolbar
+    {
+        public BasicShapeToolbar()
+        {
+            Settings.Add(new BoolSetting("Fill", "Fill shape: "));
+            Settings.Add(new ColorSetting("FillColor", "Fill color"));            
+        }
+    }
+}

+ 17 - 0
PixiEditor/Models/Tools/ToolSettings/Toolbars/BasicToolbar.cs

@@ -0,0 +1,17 @@
+using PixiEditor.Models.Tools.ToolSettings.Settings;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Text;
+using System.Windows.Controls;
+
+namespace PixiEditor.Models.Tools.ToolSettings
+{
+    public class BasicToolbar : Toolbar
+    {
+        public BasicToolbar()
+        {
+            Settings.Add(new SizeSetting("ToolSize", "Tool size:"));
+        }
+    }
+}

+ 15 - 0
PixiEditor/Models/Tools/ToolSettings/Toolbars/BrightnessToolToolbar.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 BrightnessToolToolbar : BasicToolbar
+    {
+        public BrightnessToolToolbar(float initialValue)
+        {
+            Settings.Add(new FloatSetting("CorrectionFactor", initialValue, "Strength:", 0f, 100f));
+        }
+    }
+}

+ 11 - 0
PixiEditor/Models/Tools/ToolSettings/Toolbars/EmptyToolbar.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace PixiEditor.Models.Tools.ToolSettings
+{
+    public class EmptyToolbar : Toolbar
+    {
+
+    }
+}

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

@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Windows.Controls;
+
+namespace PixiEditor.Models.Tools.ToolSettings
+{
+    public abstract class Toolbar
+    {
+        public ObservableCollection<Setting> Settings { get; set; } = new ObservableCollection<Setting>();
+        private static List<Setting> _sharedSettings = new List<Setting>();
+
+        public virtual Setting GetSetting(string name)
+        {
+            return Settings.FirstOrDefault(x => x.Name == name);
+        }
+
+        /// <summary>
+        /// Saves current toolbar state, so other toolbars with common settings can load them.
+        /// </summary>
+        public void SaveToolbarSettings()
+        {
+            for (int i = 0; i < Settings.Count; i++)
+            {
+                if(_sharedSettings.Any(x=> x.Name == Settings[i].Name))
+                {
+                    _sharedSettings.First(x => x.Name == Settings[i].Name).Value = Settings[i].Value;
+                }
+                else
+                {
+                    _sharedSettings.Add(Settings[i]);
+                }
+
+
+            }
+        }
+
+        public void LoadSharedSettings()
+        {
+            for (int i = 0; i < _sharedSettings.Count; i++)
+            {
+                if(Settings.Any(x=> x.Name == _sharedSettings[i].Name))
+                {
+                    Settings.First(x => x.Name == _sharedSettings[i].Name).Value = _sharedSettings[i].Value;
+                }
+            }
+        }
+    }
+}

+ 27 - 9
PixiEditor/Models/Tools/Tools/BrightnessTool.cs

@@ -1,6 +1,9 @@
 using PixiEditor.Models.Colors;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
+using PixiEditor.Models.Tools.ToolSettings;
+using PixiEditor.Models.Tools.ToolSettings.Toolbars;
+using System.Collections.Generic;
 using System.Windows.Input;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
@@ -10,24 +13,39 @@ namespace PixiEditor.Models.Tools.Tools
     public class BrightnessTool : Tool
     {
         public override ToolType ToolType => ToolType.Brightness;
-        public const float DarkenFactor = -0.06f;
-        public const float LightenFactor = 0.1f;
+        private const float CorrectionFactor = 5f; //Initial correction factor
+        
+        public BrightnessTool()
+        {
+            Tooltip = "Makes pixel brighter or darker pixel (U)";
+            Toolbar = new BrightnessToolToolbar(CorrectionFactor);
+        }
 
-        public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize)
+        public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color)
         {
+            int toolSize = (int)Toolbar.GetSetting("ToolSize").Value;
+            float correctionFactor = (float)Toolbar.GetSetting("CorrectionFactor").Value;
             if(Keyboard.IsKeyDown(Key.LeftCtrl))
             {
-                return ChangeBrightness(layer, coordinates[0], toolSize, DarkenFactor);
+                return ChangeBrightness(layer, coordinates[0], toolSize, -correctionFactor);
             }
-                return ChangeBrightness(layer, coordinates[0], toolSize, LightenFactor);
+                return ChangeBrightness(layer, coordinates[0], toolSize, correctionFactor);
         }       
 
         private BitmapPixelChanges ChangeBrightness(Layer layer, Coordinates coordinates, int toolSize, float correctionFactor)
         {
-            PenTool pen = new PenTool();
-            Color pixel = layer.LayerBitmap.GetPixel(coordinates.X, coordinates.Y);
-            Color newColor = ExColor.ChangeColorBrightness(Color.FromArgb(pixel.A,pixel.R, pixel.G, pixel.B), correctionFactor);
-            return pen.Draw(coordinates, newColor, toolSize);
+            DoubleCords centeredCoords = CoordinatesCalculator.CalculateThicknessCenter(coordinates, toolSize);
+            Coordinates[] rectangleCoordinates = CoordinatesCalculator.RectangleToCoordinates(centeredCoords.Coords1.X, centeredCoords.Coords1.Y,
+                centeredCoords.Coords2.X, centeredCoords.Coords2.Y);
+            BitmapPixelChanges changes = new BitmapPixelChanges(new Dictionary<Coordinates, Color>());
+
+            for (int i = 0; i < rectangleCoordinates.Length; i++)
+            {
+                Color pixel = layer.LayerBitmap.GetPixel(rectangleCoordinates[i].X, rectangleCoordinates[i].Y);
+                Color newColor = ExColor.ChangeColorBrightness(Color.FromArgb(pixel.A, pixel.R, pixel.G, pixel.B), correctionFactor);
+                changes.ChangedPixels.Add(new Coordinates(rectangleCoordinates[i].X, rectangleCoordinates[i].Y), newColor);
+            }
+            return changes;
         }
     }
 }

+ 56 - 52
PixiEditor/Models/Tools/Tools/CircleTool.cs

@@ -1,5 +1,8 @@
-using PixiEditor.Models.Layers;
+using PixiEditor.Helpers.Extensions;
+using PixiEditor.Models.ImageManipulation;
+using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Windows.Media;
@@ -11,18 +14,43 @@ namespace PixiEditor.Models.Tools.Tools
     {
         public override ToolType ToolType => ToolType.Circle;
 
-        public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize)
+        public CircleTool()
         {
+            Tooltip = "Draws circle on cavnas (C)";
+        }
+
+        public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color)
+        {
+            int thickness = (int)Toolbar.GetSetting("ToolSize").Value;
             DoubleCords fixedCoordinates = CalculateCoordinatesForShapeRotation(coordinates[^1], coordinates[0]);
-            return BitmapPixelChanges.FromSingleColoredArray(CreateEllipse(fixedCoordinates.Coords1, fixedCoordinates.Coords2), color);
+            Coordinates[] outline = CreateEllipse(fixedCoordinates.Coords1, fixedCoordinates.Coords2, thickness);
+            BitmapPixelChanges pixels = BitmapPixelChanges.FromSingleColoredArray(outline, color);
+            if ((bool)Toolbar.GetSetting("Fill").Value)
+            {
+                Color fillColor = (Color)Toolbar.GetSetting("FillColor").Value;
+                pixels.ChangedPixels.AddRangeNewOnly(
+                    BitmapPixelChanges.FromSingleColoredArray(CalculateFillForEllipse(outline), fillColor).ChangedPixels);
+            }
+
+            return pixels;
         }
 
-        public Coordinates[] CreateEllipse(Coordinates startCoordinates, Coordinates endCoordinates)
-        {            
+        public Coordinates[] CreateEllipse(Coordinates startCoordinates, Coordinates endCoordinates, int thickness)
+        {
             Coordinates centerCoordinates = CoordinatesCalculator.GetCenterPoint(startCoordinates, endCoordinates);
             int radiusX = endCoordinates.X - centerCoordinates.X;
             int radiusY = endCoordinates.Y - centerCoordinates.Y;
-            return MidpointEllipse(radiusX, radiusY, centerCoordinates.X, centerCoordinates.Y);
+            List<Coordinates> output = new List<Coordinates>();
+            Coordinates[] ellipse = MidpointEllipse(radiusX, radiusY, centerCoordinates.X, centerCoordinates.Y);
+            if (thickness == 1)
+            {
+                output.AddRange(ellipse);
+            }
+            else
+            {
+                output.AddRange(GetThickShape(ellipse, thickness));
+            }
+            return output.Distinct().ToArray();
         }
 
         public Coordinates[] MidpointEllipse(double rx, double ry, double xc, double yc)
@@ -55,14 +83,14 @@ namespace PixiEditor.Models.Tools.Tools
                 }
             }
 
-            //Yeah, it scares me too
-            d2 = (ry * ry * ((x + 0.5f) * (x + 0.5f))) + (rx * rx * ((y - 1) * (y - 1))) - (rx * rx * ry * ry);
+            //Decision parameter of region 2
+            d2 = ((ry * ry) * ((x + 0.5f) * (x + 0.5f))) + ((rx * rx) * ((y - 1) * (y - 1))) - (rx * rx * ry * ry);
 
-            while(y >= 0)
+            while (y >= 0)
             {
                 outputCoordinates.AddRange(GetRegionPoints(x, xc, y, yc));
 
-                if(d2 > 0)
+                if (d2 > 0)
                 {
                     y--;
                     dy -= (2 * rx * rx);
@@ -82,6 +110,24 @@ namespace PixiEditor.Models.Tools.Tools
 
         }
 
+        private Coordinates[] CalculateFillForEllipse(Coordinates[] outlineCoordinates)
+        {
+            List<Coordinates> finalCoordinates = new List<Coordinates>();
+            int bottom = outlineCoordinates.Max(x => x.Y);
+            int top = outlineCoordinates.Min(x => x.Y);
+            for (int i = top + 1; i < bottom; i++)
+            {
+                var rowCords = outlineCoordinates.Where(x => x.Y == i);
+                int right = rowCords.Max(x => x.X);
+                int left = rowCords.Min(x => x.X);
+                for (int j = left + 1; j < right; j++)
+                {
+                    finalCoordinates.Add(new Coordinates(j, i));
+                }
+            }
+            return finalCoordinates.ToArray();
+        }
+
         private Coordinates[] GetRegionPoints(double x, double xc, double y, double yc)
         {
             Coordinates[] outputCoordinates = new Coordinates[4];
@@ -90,48 +136,6 @@ namespace PixiEditor.Models.Tools.Tools
             outputCoordinates[2] = (new Coordinates((int)x + (int)xc, (int)-y + (int)yc));
             outputCoordinates[3] = (new Coordinates((int)-x + (int)xc, (int)-y + (int)yc));
             return outputCoordinates;
-        }
-
-        public Coordinates[] BresenhamCircle(Coordinates startCoordinates, Coordinates endCoordinates, int size)
-        {
-            List<Coordinates> outputCoordinates = new List<Coordinates>();
-            Coordinates centerCoordinates = CoordinatesCalculator.GetCenterPoint(startCoordinates, endCoordinates);
-            int radius = endCoordinates.X - centerCoordinates.X;
-            int x = 0;
-            int y = radius;
-            int decision = 3 - 2 * radius;
-            outputCoordinates.AddRange(GetPixelsForOctant(centerCoordinates.X, centerCoordinates.Y, x, y));
-
-            while (x <= y)
-            {
-                if (decision <= 0)
-                {
-                    decision = decision + (4 * x) + 6;
-                }
-                else
-                {
-                    decision = decision + (4 * x) - (4 * y) + 10;
-                    y--;
-                }
-                x++;
-                outputCoordinates.AddRange(GetPixelsForOctant(centerCoordinates.X, centerCoordinates.Y, x, y));
-            }
-            return outputCoordinates.Distinct().ToArray();
-        }
-
-        private Coordinates[] GetPixelsForOctant(int xc, int yc, int x, int y)
-        {
-            Coordinates[] outputCords = new Coordinates[8];
-            outputCords[0] = new Coordinates(x + xc, y + yc);
-            outputCords[1] = new Coordinates(x + xc, -y + yc);
-            outputCords[2] = new Coordinates(-x + xc, -y + yc);
-            outputCords[3] = new Coordinates(-x + xc, y + yc);
-            outputCords[4] = new Coordinates(y + xc, x + yc);
-            outputCords[5] = new Coordinates(y + xc, -x + yc);
-            outputCords[6] = new Coordinates(-y + xc, -x + yc);
-            outputCords[7] = new Coordinates(-y + xc, x + yc);
-            return outputCords;
         }
-
     }
 }

+ 25 - 0
PixiEditor/Models/Tools/Tools/ColorPickerTool.cs

@@ -0,0 +1,25 @@
+using PixiEditor.Models.Layers;
+using PixiEditor.Models.Position;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows.Media;
+
+namespace PixiEditor.Models.Tools.Tools
+{
+    public class ColorPickerTool : Tool
+    {
+        public override ToolType ToolType => ToolType.ColorPicker;
+
+        public ColorPickerTool()
+        {
+            PerformsOperationOnBitmap = false;
+            HideHighlight = true;
+        }
+
+        public override BitmapPixelChanges Use(Layer layer, Coordinates[] pixels, Color color)
+        {
+            return new BitmapPixelChanges();
+        }
+    }
+}

+ 9 - 2
PixiEditor/Models/Tools/Tools/EarserTool.cs

@@ -1,5 +1,6 @@
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
+using PixiEditor.Models.Tools.ToolSettings;
 using System;
 using System.Collections.Generic;
 using System.Text;
@@ -11,10 +12,16 @@ namespace PixiEditor.Models.Tools.Tools
     {
         public override ToolType ToolType => ToolType.Earser;
 
-        public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize)
+        public EarserTool()
+        {
+            Tooltip = "Earsers color from pixel (E)";
+            Toolbar = new BasicToolbar();
+        }
+
+        public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color)
         {
             PenTool pen = new PenTool();
-            return pen.Draw(coordinates[0], System.Windows.Media.Colors.Transparent, toolSize);
+            return pen.Draw(coordinates[0], System.Windows.Media.Colors.Transparent, (int)Toolbar.GetSetting("ToolSize").Value);
         }
     }
 }

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

@@ -11,7 +11,12 @@ namespace PixiEditor.Models.Tools.Tools
     {
         public override ToolType ToolType => ToolType.Bucket;
 
-        public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize)
+        public FloodFill()
+        {
+            Tooltip = "Fills area with color (G)";
+        }
+
+        public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color)
         {
             return ForestFire(layer, coordinates[0], color);
         }

+ 134 - 12
PixiEditor/Models/Tools/Tools/LineTool.cs

@@ -1,24 +1,146 @@
-using PixiEditor.Models.Layers;
+using PixiEditor.Models.ImageManipulation;
+using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
+using PixiEditor.Models.Tools.ToolSettings;
+using System;
+using System.Collections.Generic;
+using System.Linq;
 using System.Windows.Media;
-using System.Windows.Media.Imaging;
-
+
 namespace PixiEditor.Models.Tools.Tools
-{
-    public class LineTool : ShapeTool
+{
+	public class LineTool : ShapeTool
     {
+
         public override ToolType ToolType => ToolType.Line;
 
-        public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize)
+        public LineTool()
+        {
+            Tooltip = "Draws line on canvas (L)";
+            Toolbar = new BasicToolbar();
+        }
+
+        public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color)
         {
-            return BitmapPixelChanges.FromSingleColoredArray(CreateLine(coordinates), color);
+            return BitmapPixelChanges.FromSingleColoredArray(CreateLine(coordinates, (int)Toolbar.GetSetting("ToolSize").Value), color);
         }
 
-        public Coordinates[] CreateLine(Coordinates[] coordinates)
+        public Coordinates[] CreateLine(Coordinates[] coordinates, int thickness)
         {
             Coordinates startingCoordinates = coordinates[^1];
-            Coordinates latestCoordinates = coordinates[0];
-            return BresenhamLine(startingCoordinates.X, startingCoordinates.Y, latestCoordinates.X, latestCoordinates.Y);
-        }
-    }
+            Coordinates latestCoordinates = coordinates[0];
+            if(thickness == 1)
+            {
+                return BresenhamLine(startingCoordinates.X, startingCoordinates.Y, latestCoordinates.X, latestCoordinates.Y);
+            }
+            return GetThickShape(BresenhamLine(startingCoordinates.X, startingCoordinates.Y, latestCoordinates.X, latestCoordinates.Y), thickness);
+        }
+
+        private Coordinates[] BresenhamLine(int x1, int y1, int x2, int y2)
+        {
+            List<Coordinates> coordinates = new List<Coordinates>();
+            if (x1 == x2 && y1 == y2)
+            {
+                return new Coordinates[] { new Coordinates(x1, y1) };
+            }
+
+            int d, dx, dy, ai, bi, xi, yi;
+            int x = x1, y = y1;
+
+            if (x1 < x2)
+            {
+                xi = 1;
+                dx = x2 - x1;
+            }
+            else
+            {
+                xi = -1;
+                dx = x1 - x2;
+            }
+
+            if (y1 < y2)
+            {
+                yi = 1;
+                dy = y2 - y1;
+            }
+            else
+            {
+                yi = -1;
+                dy = y1 - y2;
+            }
+            coordinates.Add(new Coordinates(x, y));
+
+            if (dx > dy)
+            {
+                ai = (dy - dx) * 2;
+                bi = dy * 2;
+                d = bi - dx;
+
+                while (x != x2)
+                {
+
+                    if (d >= 0)
+                    {
+                        x += xi;
+                        y += yi;
+                        d += ai;
+                    }
+                    else
+                    {
+                        d += bi;
+                        x += xi;
+                    }
+                    coordinates.Add(new Coordinates(x, y));
+                }
+            }
+            else
+            {
+                ai = (dx - dy) * 2;
+                bi = dx * 2;
+                d = bi - dy;
+
+                while (y != y2)
+                {
+
+                    if (d >= 0)
+                    {
+                        x += xi;
+                        y += yi;
+                        d += ai;
+                    }
+                    else
+                    {
+                        d += bi;
+                        y += yi;
+                    }
+                    coordinates.Add(new Coordinates(x, y));
+                }
+            }
+
+            return coordinates.ToArray();
+
+        }
+
+        private int[,] GetMaskForThickness(int thickness)
+        {
+            if(thickness == 2)
+            {
+                return new int[,] {
+                {0,0,0 },
+                {0,1,1 },
+                {0,1,1 }
+                };
+            }
+            int[,] mask = new int[thickness,thickness];
+
+            for (int i = 0; i < thickness; i++)
+            {
+                for (int j = 0; j < thickness; j++)
+                {
+                    mask[i, j] = 1;
+                }
+            }
+            return mask;
+        }    
+	}
 }

+ 7 - 5
PixiEditor/Models/Tools/Tools/PenTool.cs

@@ -1,8 +1,6 @@
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
-using System;
-using System.Collections.Generic;
-using System.Text;
+using PixiEditor.Models.Tools.ToolSettings;
 using System.Windows.Input;
 using System.Windows.Media;
 
@@ -11,15 +9,19 @@ namespace PixiEditor.Models.Tools.Tools
     public class PenTool : Tool
     {
         public override ToolType ToolType => ToolType.Pen;
+        private int _toolSizeIndex;
 
         public PenTool()
         {
             Cursor = Cursors.Pen;
+            Tooltip = "Standard brush (B)";
+            Toolbar = new BasicToolbar();
+            _toolSizeIndex = Toolbar.Settings.IndexOf(Toolbar.GetSetting("ToolSize"));
         }
 
-        public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize)
+        public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color)
         {
-            return Draw(coordinates[0], color, toolSize);
+            return Draw(coordinates[0], color, (int)Toolbar.Settings[_toolSizeIndex].Value);
         }
 
         public BitmapPixelChanges Draw(Coordinates startingCoords, Color color, int toolSize)

+ 68 - 8
PixiEditor/Models/Tools/Tools/RectangleTool.cs

@@ -1,5 +1,7 @@
-using PixiEditor.Models.Layers;
+using PixiEditor.Helpers.Extensions;
+using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Windows.Media;
@@ -11,18 +13,49 @@ namespace PixiEditor.Models.Tools.Tools
         public override ToolType ToolType => ToolType.Rectangle;
         public bool Filled { get; set; } = false;
 
-        public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize)
+        public RectangleTool()
+        {
+            Tooltip = "Draws rectanlge on cavnas (R)";
+        }
+
+        public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color)
         {
-            return BitmapPixelChanges.FromSingleColoredArray(CreateRectangle(coordinates, toolSize), color);
+            int thickness = (int)Toolbar.GetSetting("ToolSize").Value;
+            BitmapPixelChanges pixels = BitmapPixelChanges.FromSingleColoredArray(CreateRectangle(coordinates, thickness), color);
+            if ((bool)Toolbar.GetSetting("Fill").Value)
+            {
+                Color fillColor = (Color)Toolbar.GetSetting("FillColor").Value;
+                pixels.ChangedPixels.AddRangeOverride(
+                    BitmapPixelChanges.FromSingleColoredArray
+                    (CalculateFillForRectangle(coordinates[^1], coordinates[0], thickness), fillColor).ChangedPixels);
+            }
+            return pixels;
         }
 
-        public Coordinates[] CreateRectangle(Coordinates[] coordinates, int toolSize)
+        public Coordinates[] CreateRectangle(Coordinates[] coordinates, int thickness)
         {
             DoubleCords fixedCoordinates = CalculateCoordinatesForShapeRotation(coordinates[^1], coordinates[0]);
-            return CalculateRectanglePoints(fixedCoordinates, Filled);
+            List<Coordinates> output = new List<Coordinates>();
+            Coordinates[] rectangle =  CalculateRectanglePoints(fixedCoordinates);
+            output.AddRange(rectangle);
+
+            for (int i = 1; i < (int)Math.Floor(thickness / 2f) + 1; i++)
+            {
+                output.AddRange(CalculateRectanglePoints(new DoubleCords(
+                    new Coordinates(fixedCoordinates.Coords1.X - i, fixedCoordinates.Coords1.Y - i),
+                    new Coordinates(fixedCoordinates.Coords2.X + i, fixedCoordinates.Coords2.Y + i))));
+            }
+            for (int i = 1; i < (int)Math.Ceiling(thickness / 2f); i++)
+            {
+                output.AddRange(CalculateRectanglePoints(new DoubleCords(
+                    new Coordinates(fixedCoordinates.Coords1.X + i, fixedCoordinates.Coords1.Y + i),
+                    new Coordinates(fixedCoordinates.Coords2.X - i, fixedCoordinates.Coords2.Y - i))));
+            }
+
+            return output.Distinct().ToArray();
         }
 
-        private Coordinates[] CalculateRectanglePoints(DoubleCords coordinates, bool filled)
+        private Coordinates[] CalculateRectanglePoints(DoubleCords coordinates)
         {
             List<Coordinates> finalCoordinates = new List<Coordinates>();
 
@@ -35,9 +68,36 @@ namespace PixiEditor.Models.Tools.Tools
             {
                 finalCoordinates.Add(new Coordinates(coordinates.Coords1.X, i));
                 finalCoordinates.Add(new Coordinates(coordinates.Coords2.X, i));
-            }
-            finalCoordinates = finalCoordinates.Distinct().ToList();
+            }            
             return finalCoordinates.ToArray();
         }
+
+        private Coordinates[] CalculateFillForRectangle(Coordinates start, Coordinates end, int thickness)
+        {
+            int offset = (int)Math.Ceiling(thickness / 2f);
+            DoubleCords fixedCords = CalculateCoordinatesForShapeRotation(start, end);
+
+            DoubleCords innerCords = new DoubleCords
+            {
+                Coords1 = new Coordinates(fixedCords.Coords1.X + offset, fixedCords.Coords1.Y + offset),
+                Coords2 = new Coordinates(fixedCords.Coords2.X - (offset - 1), fixedCords.Coords2.Y - (offset - 1))
+            };
+
+            int height = innerCords.Coords2.Y - innerCords.Coords1.Y;
+            int width = innerCords.Coords2.X - innerCords.Coords1.X;
+
+            if (height < 1 || width < 1) return Array.Empty<Coordinates>();
+            Coordinates[] filledCoordinates = new Coordinates[width * height];
+            int i = 0;
+            for (int y = 0; y < height; y++)
+            {
+                for (int x = 0; x < width; x++)
+                {
+                    filledCoordinates[i] = new Coordinates(innerCords.Coords1.X + x, innerCords.Coords1.Y + y);
+                    i++;
+                }
+            }
+            return filledCoordinates.Distinct().ToArray();
+        }
     }
 }

+ 2 - 2
PixiEditor/PixiEditor.csproj

@@ -39,10 +39,10 @@
     <Resource Include="Images\CircleImage.png" />
     <Resource Include="Images\Cross.png" />
     <Resource Include="Images\EarserImage.png" />
-    <Resource Include="Images\LightenImage.png" />
+    <Resource Include="Images\BrightnessImage.png" />
     <Resource Include="Images\LineImage.png" />
     <Resource Include="Images\PenImage.png" />
-    <Resource Include="Images\PipetteImage.png" />
+    <Resource Include="Images\ColorPickerImage.png" />
     <Resource Include="Images\RectangleImage.png" />
     <Resource Include="Images\SwapArrows.png" />
     <Resource Include="Images\transparentbg.png" />

+ 110 - 98
PixiEditor/Styles/ThemeStyle.xaml

@@ -1,71 +1,73 @@
-<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
-
-    <Style TargetType="{x:Type Control}">
-        <Setter Property="Foreground" Value="Snow"/>
-    </Style>
-
-    <Style TargetType="Button" x:Key="BaseDarkButton">
-        <Setter Property="Background" Value="#404040"/>
-        <Setter Property="Foreground" Value="White"/>
-        <Setter Property="FontSize" Value="22"/>
-        <Setter Property="SnapsToDevicePixels" Value="True"/>
-        <Setter Property="Template">
-            <Setter.Value>
-                <ControlTemplate TargetType="Button">
-                    <Border Background="{TemplateBinding Background}">
-                        <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
-                    </Border>
-                    <ControlTemplate.Triggers>
-                        <Trigger Property="IsEnabled" Value="False">
-                            <Setter Property="Background" Value="Transparent"/>
-                            <Setter Property="Foreground" Value="Gray"/>
-                            <Setter Property="Cursor" Value="Arrow"/>
-                        </Trigger>
-                        <Trigger Property="IsMouseOver" Value="True">
-                            <Setter Property="Background" Value="#FF515151"/>
-                            <Setter Property="Foreground" Value="White"/>
-                            <Setter Property="Cursor" Value="Hand"/>
-                        </Trigger>
-                        <Trigger Property="IsPressed" Value="True">
-                            <Setter Property="Background" Value="#505050"/>
-                            <Setter Property="Foreground" Value="White"/>
-                        </Trigger>
-                    </ControlTemplate.Triggers>
-                </ControlTemplate>
-            </Setter.Value>
-        </Setter>
-    </Style>
-
-    <Style TargetType="Button"  x:Key="DarkRoundButton" BasedOn="{StaticResource BaseDarkButton}">
-        <Setter Property="Template">
-            <Setter.Value>
-                <ControlTemplate TargetType="Button">
-                    <Border CornerRadius="4" Background="{TemplateBinding Background}">
-                        <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
-                    </Border>
-                    <ControlTemplate.Triggers>
-                        <Trigger Property="IsEnabled" Value="False">
-                            <Setter Property="Background" Value="Transparent"/>
-                            <Setter Property="Foreground" Value="Gray"/>
-                            <Setter Property="Cursor" Value="Arrow"/>
-                        </Trigger>
-                        <Trigger Property="IsMouseOver" Value="True">
-                            <Setter Property="Background" Value="#FF515151"/>
-                            <Setter Property="Foreground" Value="White"/>
-                            <Setter Property="Cursor" Value="Hand"/>
-                        </Trigger>
-                        <Trigger Property="IsPressed" Value="True">
-                            <Setter Property="Background" Value="#505050"/>
-                            <Setter Property="Foreground" Value="White"/>
-                        </Trigger>
-                    </ControlTemplate.Triggers>
-                </ControlTemplate>
-            </Setter.Value>
-        </Setter>
-    </Style>
-
-
+<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+
+    <Style TargetType="{x:Type Control}">
+        <Setter Property="Foreground" Value="Snow"/>
+    </Style>
+
+    <Style TargetType="Button" x:Key="BaseDarkButton">
+        <Setter Property="Background" Value="#404040"/>
+        <Setter Property="Foreground" Value="White"/>
+        <Setter Property="FontSize" Value="22"/>
+        <Setter Property="SnapsToDevicePixels" Value="True"/>
+        <Setter Property="Template">
+            <Setter.Value>
+                <ControlTemplate TargetType="Button">
+                    <Border Background="{TemplateBinding Background}">
+                        <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
+                    </Border>
+                    <ControlTemplate.Triggers>
+                        <Trigger Property="IsEnabled" Value="False">
+                            <Setter Property="Background" Value="Transparent"/>
+                            <Setter Property="Foreground" Value="Gray"/>
+                            <Setter Property="Cursor" Value="Arrow"/>
+                        </Trigger>
+                        <Trigger Property="IsMouseOver" Value="True">
+                            <Setter Property="Background" Value="#FF515151"/>
+                            <Setter Property="Foreground" Value="White"/>
+                            <Setter Property="Cursor" Value="Hand"/>
+                        </Trigger>
+                        <Trigger Property="IsPressed" Value="True">
+                            <Setter Property="Background" Value="#505050"/>
+                            <Setter Property="Foreground" Value="White"/>
+                        </Trigger>
+                    </ControlTemplate.Triggers>
+                </ControlTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>
+
+    <Style TargetType="Button"  x:Key="DarkRoundButton" BasedOn="{StaticResource BaseDarkButton}">
+        <Setter Property="OverridesDefaultStyle" Value="True"/>
+        <Setter Property="Background" Value="#303030"/>
+        <Setter Property="Template">
+            <Setter.Value>
+                <ControlTemplate TargetType="Button">
+                    <Border CornerRadius="4" Background="{TemplateBinding Background}">
+                        <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
+                    </Border>
+                    <ControlTemplate.Triggers>
+                        <Trigger Property="IsEnabled" Value="False">
+                            <Setter Property="Background" Value="Transparent"/>
+                            <Setter Property="Foreground" Value="Gray"/>
+                            <Setter Property="Cursor" Value="Arrow"/>
+                        </Trigger>
+                        <Trigger Property="IsMouseOver" Value="True">
+                            <Setter Property="Background" Value="#FF515151"/>
+                            <Setter Property="Foreground" Value="White"/>
+                            <Setter Property="Cursor" Value="Hand"/>
+                        </Trigger>
+                        <Trigger Property="IsPressed" Value="True">
+                            <Setter Property="Background" Value="#505050"/>
+                            <Setter Property="Foreground" Value="White"/>
+                        </Trigger>
+                    </ControlTemplate.Triggers>
+                </ControlTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>
+
+
     <Style TargetType="Button" x:Key="ImageButtonStyle">
         <Setter Property="OverridesDefaultStyle" Value="True"/>
         <Setter Property="Template">
@@ -82,24 +84,34 @@
                 </ControlTemplate>
             </Setter.Value>
         </Setter>
-    </Style>
-
-
-    <Style TargetType="TextBox" x:Key="DarkTextBoxStyle">
-        <Setter Property="Background" Value="#202020"/>
-        <Setter Property="BorderThickness" Value="1"/>
-        <Setter Property="BorderBrush" Value="#404040"/>
-        <Setter Property="Foreground" Value="Snow"/>
-    </Style>
-
-    <Style TargetType="Button" x:Key="ToolButtonStyle">
-        <Setter Property="Height" Value="42"/>
-        <Setter Property="Width" Value="42"/>
-        <Setter Property="VerticalAlignment" Value="Top"/>
-        <Setter Property="HorizontalAlignment" Value="Center"/>
-        <Setter Property="Margin" Value="0,10,0,0"/>
-    </Style>
-
+    </Style>
+
+
+    <Style TargetType="TextBox" x:Key="DarkTextBoxStyle">
+        <Setter Property="Background" Value="#202020"/>
+        <Setter Property="BorderThickness" Value="1"/>
+        <Setter Property="BorderBrush" Value="#404040"/>
+        <Setter Property="Foreground" Value="Snow"/>
+    </Style>
+
+    <Style TargetType="Button" x:Key="ToolButtonStyle">
+        <Setter Property="Height" Value="32"/>
+        <Setter Property="Width" Value="32"/>
+        <Setter Property="VerticalAlignment" Value="Top"/>
+        <Setter Property="HorizontalAlignment" Value="Center"/>
+        <Setter Property="Margin" Value="0,10,0,0"/>
+        <Setter Property="OverridesDefaultStyle" Value="True"/>
+        <Setter Property="Template">
+            <Setter.Value>
+                <ControlTemplate TargetType="Button">
+                    <Border Name="brd" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}">
+                        <ContentPresenter/>
+                    </Border>
+                </ControlTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>
+
     <Style x:Key="{x:Type ContextMenu}" TargetType="{x:Type ContextMenu}">
         <Setter Property="OverridesDefaultStyle" Value="True"/>
         <Setter Property="SnapsToDevicePixels" Value="True"/>
@@ -113,11 +125,11 @@
             </Setter.Value>
         </Setter>
     </Style>
-    <Style TargetType="MenuItem">
-        <Setter Property="OverridesDefaultStyle" Value="True"/>
-        <Setter Property="Template">
-            <Setter.Value>
-                <ControlTemplate TargetType="MenuItem">
+    <Style TargetType="MenuItem">
+        <Setter Property="OverridesDefaultStyle" Value="True"/>
+        <Setter Property="Template">
+            <Setter.Value>
+                <ControlTemplate TargetType="MenuItem">
                     <Border x:Name="Bd" Background="Transparent" Margin="10 0 10 0">
                         <Grid>
                             <ContentPresenter Margin="6,3,6,3" ContentSource="Header" RecognizesAccessKey="True" />
@@ -130,11 +142,11 @@
                         <Trigger Property="IsEnabled" Value="False">
                             <Setter Property="Foreground" Value="Gray"/>
                         </Trigger>
-                    </ControlTemplate.Triggers>
-                </ControlTemplate>
-            </Setter.Value>
-        </Setter>
-    </Style>
-
-
+                    </ControlTemplate.Triggers>
+                </ControlTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>
+
+
 </ResourceDictionary>

+ 76 - 52
PixiEditor/ViewModels/ViewModelMain.cs

@@ -13,7 +13,8 @@ using PixiEditor.Models.Dialogs;
 using PixiEditor.Models.IO;
 using PixiEditor.Models.Position;
 using PixiEditor.Models.DataHolders;
-using PixiEditor.Views;
+using System.Linq;
+using System.Collections.ObjectModel;
 
 namespace PixiEditor.ViewModels
 {
@@ -40,6 +41,7 @@ namespace PixiEditor.ViewModels
         public RelayCommand MoveToFrontCommand { get; set; }
         public RelayCommand SwapColorsCommand { get; set; }
 
+
         private double _mouseXonCanvas;
 
         public double MouseXOnCanvas //Mouse X coordinate relative to canvas
@@ -95,24 +97,7 @@ namespace PixiEditor.ViewModels
                     RaisePropertyChanged("SelectedTool"); } }
         }        
 
-
-        private int _toolSize;
-
-        public int ToolSize
-        {
-            get { return _toolSize; }
-            set 
-            { 
-                if (_toolSize != value) 
-                { 
-                    _toolSize = value;
-                    BitmapUtility.ToolSize = value;
-                    RaisePropertyChanged("ToolSize"); 
-                } 
-            }
-        }
-
-        public List<Tool> ToolSet { get; set; }
+        public ObservableCollection<Tool> ToolSet { get; set; }
 
         private LayerChanges _undoChanges;
 
@@ -126,6 +111,18 @@ namespace PixiEditor.ViewModels
             }
         }
 
+        private Cursor _toolCursor;
+
+        public Cursor ToolCursor
+        {
+            get { return _toolCursor; }
+            set {
+                _toolCursor = value;
+                RaisePropertyChanged("ToolCursor");
+            }
+        }
+
+
 
         public BitmapOperationsUtility BitmapUtility { get; set; }
         public PixelChangesController ChangesController { get; set; }
@@ -139,7 +136,7 @@ namespace PixiEditor.ViewModels
             BitmapUtility.BitmapChanged += BitmapUtility_BitmapChanged;
             BitmapUtility.MouseController.StoppedRecordingChanges += MouseController_StoppedRecordingChanges;
             ChangesController = new PixelChangesController();
-            SelectToolCommand = new RelayCommand(RecognizeTool);
+            SelectToolCommand = new RelayCommand(SetTool);
             GenerateDrawAreaCommand = new RelayCommand(GenerateDrawArea);
             MouseMoveCommand = new RelayCommand(MouseMove);
             MouseDownCommand = new RelayCommand(MouseDown);
@@ -157,8 +154,8 @@ namespace PixiEditor.ViewModels
             SwapColorsCommand = new RelayCommand(SwapColors);
             KeyDownCommand = new RelayCommand(KeyDown);
             RenameLayerCommand = new RelayCommand(RenameLayer);
-            ToolSet = new List<Tool> { new PixiTools.PenTool(), new PixiTools.FloodFill(), new PixiTools.LineTool(),
-            new PixiTools.CircleTool(), new PixiTools.RectangleTool(), new PixiTools.EarserTool(), new PixiTools.BrightnessTool() };
+            ToolSet = new ObservableCollection<Tool> { new PixiTools.PenTool(), new PixiTools.FloodFill(), new PixiTools.LineTool(),
+            new PixiTools.CircleTool(), new PixiTools.RectangleTool(), new PixiTools.EarserTool(), new PixiTools.ColorPickerTool(), new PixiTools.BrightnessTool() };
             ShortcutController = new ShortcutController
             {
                 Shortcuts = new List<Shortcut> { 
@@ -174,14 +171,18 @@ namespace PixiEditor.ViewModels
                     new Shortcut(Key.U, SelectToolCommand, ToolType.Brightness),
                     new Shortcut(Key.Y, RedoCommand, null, ModifierKeys.Control),
                     new Shortcut(Key.Z, UndoCommand),
-                    new Shortcut(Key.S, UndoCommand, null, ModifierKeys.Control),
+                    new Shortcut(Key.S, SaveFileCommand, null, ModifierKeys.Control),
                     new Shortcut(Key.N, GenerateDrawAreaCommand, null, ModifierKeys.Control),
                 }
             };
             UndoManager.SetMainRoot(this);
             SetActiveTool(ToolType.Pen);
             BitmapUtility.PrimaryColor = PrimaryColor;
-            ToolSize = 1;
+        }
+
+        public void SetTool(object parameter)
+        {
+            SetActiveTool((ToolType)parameter);
         }
 
         public void RenameLayer(object parameter)
@@ -196,8 +197,12 @@ namespace PixiEditor.ViewModels
 
         private void MouseController_StoppedRecordingChanges(object sender, EventArgs e)
         {
-            Tuple<LayerChanges, LayerChanges> changes = ChangesController.PopChanges();
-            UndoManager.AddUndoChange(new Change("UndoChanges", changes.Item2, changes.Item1)); //Item2 is old value
+            if (BitmapUtility.SelectedTool.PerformsOperationOnBitmap)
+            {
+                Tuple<LayerChanges, LayerChanges> changes = ChangesController.PopChanges();
+                if (changes.Item1.PixelChanges.ChangedPixels.Count > 0)
+                    UndoManager.AddUndoChange(new Change("UndoChanges", changes.Item2, changes.Item1)); //Item2 is old value
+            }
         }
 
         private void BitmapUtility_BitmapChanged(object sender, BitmapChangedEventArgs e)
@@ -217,12 +222,20 @@ namespace PixiEditor.ViewModels
         {
             int oldIndex = (int)parameter;
             BitmapUtility.Layers.Move(oldIndex, oldIndex + 1);
+            if(BitmapUtility.ActiveLayerIndex == oldIndex)
+            {
+                BitmapUtility.SetActiveLayer(oldIndex + 1);
+            }
         }
 
         public void MoveLayerToBack(object parameter)
         {
             int oldIndex = (int)parameter;
             BitmapUtility.Layers.Move(oldIndex, oldIndex - 1);
+            if (BitmapUtility.ActiveLayerIndex == oldIndex)
+            {
+                BitmapUtility.SetActiveLayer(oldIndex - 1);
+            }
         }
 
         public bool CanMoveToFront(object property)
@@ -287,30 +300,31 @@ namespace PixiEditor.ViewModels
         }
         #endregion
 
-        /// <summary>
-        /// Recognizes selected tool from UI
-        /// </summary>
-        /// <param name="parameter"></param>
-        private void RecognizeTool(object parameter)
-        {
-            ToolType tool = (ToolType)Enum.Parse(typeof(ToolType), parameter.ToString());
-            SelectedTool = tool;
+        private void SetActiveTool(ToolType tool)
+        {
+            BitmapUtility.SetActiveTool(ToolSet.First(x=> x.ToolType == tool));
+            Tool activeTool = ToolSet.FirstOrDefault(x => x.IsActive);
+            if(activeTool != null)
+            {
+                activeTool.IsActive = false;
+            }
+
+            BitmapUtility.SelectedTool.IsActive = true;
+            SetToolCursor(tool);
         }
 
-        private void SetActiveTool(ToolType tool)
+        private void SetToolCursor(ToolType tool)
         {
-            BitmapUtility.SelectedTool = ToolSet.Find(x=> x.ToolType == tool);
-            Cursor cursor;
             if (tool != ToolType.None && tool != ToolType.ColorPicker)
             {
-               cursor = BitmapUtility.SelectedTool.Cursor;
+                ToolCursor = BitmapUtility.SelectedTool.Cursor;
             }
             else
             {
-                cursor = Cursors.Arrow;
+                ToolCursor = Cursors.Arrow;
             }
-            Mouse.OverrideCursor = cursor;
         }
+
         /// <summary>
         /// When mouse is up stops recording changes.
         /// </summary>
@@ -322,11 +336,12 @@ namespace PixiEditor.ViewModels
 
         private void MouseDown(object parameter)
         {
-            if(SelectedTool == ToolType.ColorPicker)
+            if (BitmapUtility.Layers.Count == 0) return;
+            if(BitmapUtility.SelectedTool.ToolType == ToolType.ColorPicker)
             {
                 ExecuteColorPicker();
             }
-            else if(Mouse.LeftButton == MouseButtonState.Pressed)
+            else if(Mouse.LeftButton == MouseButtonState.Pressed && BitmapUtility.SelectedTool.PerformsOperationOnBitmap)
             {
                 if (!BitmapUtility.MouseController.IsRecordingChanges)
                 {
@@ -345,10 +360,14 @@ namespace PixiEditor.ViewModels
             Coordinates cords = new Coordinates((int)MouseXOnCanvas, (int)MouseYOnCanvas);
             MousePositionConverter.CurrentCoordinates = cords;
 
-                if (BitmapUtility.MouseController.IsRecordingChanges && Mouse.LeftButton == MouseButtonState.Pressed)
-                {
-                    BitmapUtility.MouseController.RecordMouseMovementChange(cords);
-                }
+            if (BitmapUtility.MouseController.IsRecordingChanges && Mouse.LeftButton == MouseButtonState.Pressed)
+            {
+                BitmapUtility.MouseController.RecordMouseMovementChange(cords);
+            }
+            else
+            {
+                BitmapUtility.MouseController.MouseMoved(cords);
+            }
         }
 
 
@@ -373,13 +392,12 @@ namespace PixiEditor.ViewModels
         /// Generates new Layer and sets it as active one
         /// </summary>
         /// <param name="parameter"></param>
-        private void GenerateDrawArea(object parameter)
+        public void GenerateDrawArea(object parameter)
         {
             NewFileDialog newFile = new NewFileDialog();
             if (newFile.ShowDialog())
             {
-                BitmapUtility.Layers.Clear();
-                BitmapUtility.AddNewLayer("Base Layer", newFile.Width, newFile.Height, true);
+                NewDocument(newFile.Width, newFile.Height);
             }
         }
         #region SaveFile
@@ -390,7 +408,7 @@ namespace PixiEditor.ViewModels
         private void SaveFile(object parameter)
         {
             WriteableBitmap bitmap = BitmapUtility.GetCombinedLayersBitmap();
-            if (Exporter.SavePath == null)
+            if (Exporter.SavePath == null || (string)parameter == "AsNew")
             {
                 Exporter.Export(FileType.PNG, bitmap, new Size(bitmap.PixelWidth, bitmap.PixelHeight));
             }
@@ -419,12 +437,18 @@ namespace PixiEditor.ViewModels
             ImportFileDialog dialog = new ImportFileDialog();
             if (dialog.ShowDialog())
             {
-                BitmapUtility.Layers.Clear();
-                BitmapUtility.AddNewLayer("Base Layer", dialog.FileWidth, dialog.FileHeight, true);
+                NewDocument(dialog.FileWidth, dialog.FileHeight);
                 BitmapUtility.ActiveLayer.LayerBitmap = Importer.ImportImage(dialog.FilePath, dialog.FileWidth, dialog.FileHeight);
             }
         }
 
+        private void NewDocument(int width, int height)
+        {
+            BitmapUtility.Layers.Clear();
+            BitmapUtility.AddNewLayer("Base Layer", width, height, true);
+            BitmapUtility.PreviewLayer = null;
+        }
+
         /// <summary>
         /// For now, shows not implemented info, lol.
         /// </summary>

+ 1 - 1
PixiEditor/Views/MainDrawingPanel.xaml

@@ -9,7 +9,7 @@
              xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
              mc:Ignorable="d" 
              d:DesignHeight="450" d:DesignWidth="800" x:Name="mainDrawingPanel">
-    <xctk:Zoombox IsAnimated="False" Name="Zoombox" KeepContentInBounds="True" Loaded="Zoombox_Loaded" DragModifiers="Shift" ZoomModifiers="None" >
+    <xctk:Zoombox Cursor="{Binding Cursor}" IsAnimated="False" Name="Zoombox" KeepContentInBounds="True" Loaded="Zoombox_Loaded" DragModifiers="Shift" ZoomModifiers="None" >
         <i:Interaction.Triggers>
             <i:EventTrigger EventName="MouseMove">
                 <i:InvokeCommandAction Command="{Binding MouseMoveCommand, ElementName=mainDrawingPanel, Mode=OneWay}"/>

+ 4 - 18
PixiEditor/Views/MainDrawingPanel.xaml.cs

@@ -1,19 +1,6 @@
-using PixiEditor.Models;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
+using System.Windows;
 using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
 using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
 using Xceed.Wpf.Toolkit.Zoombox;
 
 namespace PixiEditor.Views
@@ -26,10 +13,9 @@ namespace PixiEditor.Views
         public MainDrawingPanel()
         {
             InitializeComponent();
-        }
-
-
-
+        }
+
+
         public double MouseX
         {
             get { return (double)GetValue(MouseXProperty); }

+ 219 - 226
PixiEditor/Views/MainWindow.xaml

@@ -1,233 +1,226 @@
-<Window x:Class="PixiEditor.MainWindow" MinHeight="1000" MinWidth="1100"
-        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-        xmlns:vm="clr-namespace:PixiEditor.ViewModels"
-        xmlns:vws="clr-namespace:PixiEditor.Views"
-        xmlns:helpers="clr-namespace:PixiEditor.Helpers"
-        xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
-        xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours"
-        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
-        xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
+<Window x:Class="PixiEditor.MainWindow" MinHeight="1000" MinWidth="1100"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:vm="clr-namespace:PixiEditor.ViewModels"
+        xmlns:vws="clr-namespace:PixiEditor.Views"
+        xmlns:helpers="clr-namespace:PixiEditor.Helpers"
+        xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
+        xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours"
+        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
+        xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
         xmlns:xcad="http://schemas.xceed.com/wpf/xaml/avalondock"
         xmlns:ui="clr-namespace:PixiEditor.Helpers.UI"
         xmlns:cmd="http://www.galasoft.ch/mvvmlight"
-        mc:Ignorable="d"
-        Title="PixiEditor" Name="mainWindow" Height="1000" Width="1600" Background="#FF252424" WindowStartupLocation="CenterScreen"  WindowState="Maximized" DataContext="{DynamicResource ViewModelMain}">
-    <Window.Resources>
-        <vm:ViewModelMain x:Key="ViewModelMain"/>
-        <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
-        <helpers:ToolSizeToIntConverter x:Key="ToolSizeToIntConverter"/>
-        <converters:BoolToColorConverter x:Key="BoolToColorConverter"/>
-    </Window.Resources>
-
-    <i:Interaction.Triggers>
-        <i:EventTrigger EventName="KeyDown">
-            <cmd:EventToCommand Command="{Binding KeyDownCommand}" PassEventArgsToCommand="True"/>
-        </i:EventTrigger>
-    </i:Interaction.Triggers>
-    <Grid>
-        <Grid.ColumnDefinitions>
-            <ColumnDefinition Width="60*"/>
-            <ColumnDefinition Width="1420*"/>
-            <ColumnDefinition Width="150*"/>
-        </Grid.ColumnDefinitions>
-        <Grid.RowDefinitions>
-            <RowDefinition Height="30*"/>
-            <RowDefinition Height="908*"/>
-            <RowDefinition Height="30*"/>
-        </Grid.RowDefinitions>
-
-        <Border Grid.ColumnSpan="3" Background="#FF363434" Grid.Row="0" Height="30"/>
-        <WrapPanel Grid.ColumnSpan="2" Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Panel.ZIndex="100">
-            <vws:MenuButton Text="File" Margin="0,0,-140,0">
-                <vws:MenuButton.Item>
-                    <StackPanel>
-                        <Button Style="{StaticResource MenuInsideButtonStyle}" Content="New" Command="{Binding GenerateDrawAreaCommand}"/>
-                        <Button Style="{StaticResource MenuInsideButtonStyle}" Content="Save" Command="{Binding SaveFileCommand}"/>
-                        <Button Style="{StaticResource MenuInsideButtonStyle}" Content="Open" Command="{Binding OpenFileCommand}"/>
-                    </StackPanel>
-                </vws:MenuButton.Item>
-            </vws:MenuButton>
-            <vws:MenuButton Text="Edit" Margin="0,0,-140,0">
-                <vws:MenuButton.Item>
-                    <StackPanel>
-                        <Button Style="{StaticResource MenuInsideButtonStyle}" Content="Undo" Command="{Binding UndoCommand}"/>
-                        <Button Style="{StaticResource MenuInsideButtonStyle}" Content="Redo" Command="{Binding RedoCommand}"/>
-                    </StackPanel>
-                </vws:MenuButton.Item>
-            </vws:MenuButton>
-
-            <vws:MenuButton Text="View" Margin="0,0,-140,0">
-                <vws:MenuButton.Item>
-                    <StackPanel>
-                        <Button Style="{StaticResource MenuInsideButtonStyle}" Content="Recenter" Command="{Binding RecenterZoomboxCommand}" CommandParameter="{Binding ElementName=Zoombox}"/>
-                    </StackPanel>
-                </vws:MenuButton.Item>
-            </vws:MenuButton>
-        </WrapPanel>
-        <Grid Grid.Column="1" Grid.Row="1" Background="#303030" Margin="0,5,5,0">
-            <Grid>
-                <vws:MainDrawingPanel CenterOnStart="True">
-                    <vws:MainDrawingPanel.Item>
-                        <Canvas Width="{Binding BitmapUtility.ActiveLayer.Width}" Height="{Binding BitmapUtility.ActiveLayer.Height}" VerticalAlignment="Center" HorizontalAlignment="Center">
-                            <i:Interaction.Triggers>
-                                <i:EventTrigger EventName="MouseMove">
-                                    <i:InvokeCommandAction Command="{Binding MouseMoveCommand}"/>
-                                </i:EventTrigger>
-                                <i:EventTrigger EventName="MouseDown">
-                                    <i:InvokeCommandAction Command="{Binding MouseDownCommand}"/>
-                                </i:EventTrigger>
-                                <i:EventTrigger EventName="MouseUp">
-                                    <i:InvokeCommandAction Command="{Binding MouseUpCommand}"/>
-                                </i:EventTrigger>
-                            </i:Interaction.Triggers>
-                            <i:Interaction.Behaviors>
-                                <behaviors:MouseBehaviour MouseX="{Binding MouseXOnCanvas, Mode=OneWayToSource}" MouseY="{Binding MouseYOnCanvas, Mode=OneWayToSource}"/>
-                            </i:Interaction.Behaviors>
-                            <Image Source="/Images/transparentbg.png" Height="{Binding BitmapUtility.ActiveLayer.Height}" Width="{Binding BitmapUtility.ActiveLayer.Width}" Opacity="0.9" Stretch="UniformToFill"/>
-                            <Image Source="{Binding BitmapUtility.PreviewLayer.LayerBitmap}" Panel.ZIndex="2" RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="Uniform" Width="{Binding BitmapUtility.PreviewLayer.Width}" Height="{Binding BitmapUtility.PreviewLayer.Height}"/>
-                            <ItemsControl ItemsSource="{Binding BitmapUtility.Layers}">
-                                <ItemsControl.ItemsPanel>
-                                    <ItemsPanelTemplate>
-                                        <Grid/>
-                                    </ItemsPanelTemplate>
-                                </ItemsControl.ItemsPanel>
-                                <ItemsControl.ItemTemplate>
-                                    <DataTemplate>
-                                        <Image Source="{Binding LayerBitmap}" Visibility="{Binding IsVisible, Converter={StaticResource BoolToVisibilityConverter}}" RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="Uniform" Width="{Binding Width}" Height="{Binding Height}"/>
-                                    </DataTemplate>
-                                </ItemsControl.ItemTemplate>
-                            </ItemsControl>
-                        </Canvas>
-                    </vws:MainDrawingPanel.Item>
-                </vws:MainDrawingPanel>
-            </Grid>
-        </Grid>
-
-        <StackPanel Cursor="Arrow" Grid.Row="1" Grid.Column="0" Margin="0,5,5,0" Background="#404040">
-            <TextBox Style="{StaticResource DarkTextBoxStyle}" Margin="0,10,0,0" Text="{Binding ToolSize, Mode=TwoWay,Converter={StaticResource ToolSizeToIntConverter}}" TextAlignment="Center" MaxLength="4">
-                <i:Interaction.Behaviors>
-                    <behaviors:TextBoxNumericFinisherBehavior/>
-                </i:Interaction.Behaviors>
-            </TextBox>
-            <Button Style="{StaticResource ToolButtonStyle}" Command="{Binding SelectToolCommand, Mode=OneWay}" CommandParameter="Pen" ToolTip="Standard brush (B)">
-                <Button.Background>
-                    <ImageBrush ImageSource="/Images/PenImage.png" Stretch="Uniform"/>
-                </Button.Background>
-            </Button>
-            <Button Style="{StaticResource ToolButtonStyle}" Command="{Binding SelectToolCommand, Mode=OneWay}" CommandParameter="Bucket" ToolTip="Fills area with color (G)">
-                <Button.Background>
-                    <ImageBrush ImageSource="/Images/BucketImage.png" Stretch="Uniform"/>
-                </Button.Background>
-            </Button>
-            <Button Style="{StaticResource ToolButtonStyle}" Command="{Binding SelectToolCommand, Mode=OneWay}" CommandParameter="Line" ToolTip="Draws line on canvas (L)">
-                <Button.Background>
-                    <ImageBrush ImageSource="/Images/LineImage.png" Stretch="Uniform"/>
-                </Button.Background>
-            </Button>
-            <Button Style="{StaticResource ToolButtonStyle}" Command="{Binding SelectToolCommand, Mode=OneWay}" CommandParameter="Circle" ToolTip="Draws circle on cavnas (C)">
-                <Button.Background>
-                    <ImageBrush ImageSource="/Images/CircleImage.png" Stretch="Uniform"/>
-                </Button.Background>
-            </Button>
-            <Button Style="{StaticResource ToolButtonStyle}" Command="{Binding SelectToolCommand, Mode=OneWay}" CommandParameter="Rectangle" ToolTip="Draws rectanlge on cavnas (R)">
-                <Button.Background>
-                    <ImageBrush ImageSource="/Images/RectangleImage.png" Stretch="Uniform"/>
-                </Button.Background>
-            </Button>
-            <Button Style="{StaticResource ToolButtonStyle}" Command="{Binding SelectToolCommand, Mode=OneWay}" CommandParameter="ColorPicker" ToolTip="Color picker, sets color from pixel as active (O)">
-                <Button.Background>
-                    <ImageBrush ImageSource="/Images/PipetteImage.png" Stretch="Uniform"/>
-                </Button.Background>
-            </Button>
-            <Button Style="{StaticResource ToolButtonStyle}" Command="{Binding SelectToolCommand, Mode=OneWay}" CommandParameter="Earser" ToolTip="Earser, Earsers color from pixel (E)">
-                <Button.Background>
-                    <ImageBrush ImageSource="/Images/EarserImage.png" Stretch="Uniform"/>
-                </Button.Background>
-            </Button>
-            <Button Style="{StaticResource ToolButtonStyle}" Opacity="1" Command="{Binding SelectToolCommand, Mode=OneWay}" CommandParameter="Brightness" ToolTip="Makes pixel brighter or darker pixel (U)">
-                <Button.Background>
-                    <ImageBrush ImageSource="/Images/LightenImage.png" Stretch="Uniform"/>
-                </Button.Background>
-            </Button>
-        </StackPanel>
-
-        <DockPanel Grid.Column="2" Grid.Row="1" Background="#404040">
-            <Grid DockPanel.Dock="Top" HorizontalAlignment="Center" Width="100"  Margin="0,20,0,0" Height="100">
-                <Rectangle Height="70" Width="70" HorizontalAlignment="Left" VerticalAlignment="Top" Stroke="Black" StrokeThickness="1" Panel.ZIndex="1">
-                    <Rectangle.Fill>
-                        <SolidColorBrush Color="{Binding PrimaryColor, Mode=OneWay}"/>
-                    </Rectangle.Fill>
-                </Rectangle>
-                <xctk:ColorPicker Width="70" Panel.ZIndex="2" Height="70" VerticalAlignment="Top" HorizontalAlignment="Left" UsingAlphaChannel="True" AvailableColorsSortingMode="Alphabetical" ShowDropDownButton="False" Background="Transparent" BorderThickness="0" ShowRecentColors="True" SelectedColor="{Binding PrimaryColor, Mode=TwoWay}"></xctk:ColorPicker>
+        mc:Ignorable="d"
+        Title="PixiEditor" Name="mainWindow" Height="1000" Width="1600" Background="#FF252424" WindowStartupLocation="CenterScreen"  WindowState="Maximized" DataContext="{DynamicResource ViewModelMain}">
+    <Window.Resources>
+        <vm:ViewModelMain x:Key="ViewModelMain"/>
+        <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
+        <helpers:ToolSizeToIntConverter x:Key="ToolSizeToIntConverter"/>
+        <converters:BoolToColorConverter x:Key="BoolToColorConverter"/>
+        <converters:BoolToIntConverter x:Key="BoolToIntConverter"/>
+    </Window.Resources>
+
+    <i:Interaction.Triggers>
+        <i:EventTrigger EventName="KeyDown">
+            <cmd:EventToCommand Command="{Binding KeyDownCommand}" PassEventArgsToCommand="True"/>
+        </i:EventTrigger>
+    </i:Interaction.Triggers>
+    <Grid>
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="37*"/>
+            <ColumnDefinition Width="1416*"/>
+            <ColumnDefinition Width="147*"/>
+        </Grid.ColumnDefinitions>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="30*"/>
+            <RowDefinition Height="29*"/>
+            <RowDefinition Height="895*"/>
+            <RowDefinition Height="30*"/>
+        </Grid.RowDefinitions>
+
+        <Border Grid.ColumnSpan="3" Background="#FF363434" Grid.Row="0"/>
+        <WrapPanel Grid.ColumnSpan="2" Grid.Column="0" Grid.Row="0" Grid.RowSpan="3" Panel.ZIndex="100">
+            <vws:MenuButton Text="File" Margin="0,0,-140,0">
+                <vws:MenuButton.Item>
+                    <StackPanel>
+                        <Button Style="{StaticResource MenuInsideButtonStyle}" Content="New" Command="{Binding GenerateDrawAreaCommand}"/>
+                        <Button Style="{StaticResource MenuInsideButtonStyle}" Content="Export" Command="{Binding SaveFileCommand}"/>
+                        <Button Style="{StaticResource MenuInsideButtonStyle}" Content="Export As..." Command="{Binding SaveFileCommand}" CommandParameter="AsNew"/>
+                        <Button Style="{StaticResource MenuInsideButtonStyle}" Content="Open" Command="{Binding OpenFileCommand}"/>
+                    </StackPanel>
+                </vws:MenuButton.Item>
+            </vws:MenuButton>
+            <vws:MenuButton Text="Edit" Margin="0,0,-140,0">
+                <vws:MenuButton.Item>
+                    <StackPanel>
+                        <Button Style="{StaticResource MenuInsideButtonStyle}" Content="Undo" Command="{Binding UndoCommand}"/>
+                        <Button Style="{StaticResource MenuInsideButtonStyle}" Content="Redo" Command="{Binding RedoCommand}"/>
+                    </StackPanel>
+                </vws:MenuButton.Item>
+            </vws:MenuButton>
+
+            <vws:MenuButton Text="View" Margin="0,0,-140,0">
+                <vws:MenuButton.Item>
+                    <StackPanel>
+                        <Button Style="{StaticResource MenuInsideButtonStyle}" Content="Recenter" Command="{Binding RecenterZoomboxCommand}" CommandParameter="{Binding ElementName=Zoombox}"/>
+                    </StackPanel>
+                </vws:MenuButton.Item>
+            </vws:MenuButton>
+        </WrapPanel>
+        <StackPanel Background="#404040" Orientation="Horizontal" Grid.ColumnSpan="2" Margin="0,30,0,0" Grid.RowSpan="2">
+            <ItemsControl ItemsSource="{Binding BitmapUtility.SelectedTool.Toolbar.Settings}">
+                <ItemsControl.ItemsPanel>
+                    <ItemsPanelTemplate>
+                        <StackPanel Orientation="Horizontal" Margin="10, 0, 0, 0"/>
+                    </ItemsPanelTemplate>
+                </ItemsControl.ItemsPanel>
+                <ItemsControl.ItemTemplate>
+                    <DataTemplate>
+                        <StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="10,0,10,0">
+                            <Label Visibility="{Binding HasLabel, Converter={StaticResource BoolToVisibilityConverter}}" Foreground="White" Content="{Binding Label}"/>
+                            <ContentPresenter Content="{Binding SettingControl}"/>
+                        </StackPanel>
+                    </DataTemplate>
+                </ItemsControl.ItemTemplate>
+            </ItemsControl>
+        </StackPanel>
+        <Grid Grid.Column="1" Grid.Row="2" Background="#303030" Margin="0,7,5,0">
+            <Grid>
+                <vws:MainDrawingPanel x:Name="DrawingPanel" CenterOnStart="True" Cursor="{Binding ToolCursor}">
+                    <i:Interaction.Triggers>
+                        <i:EventTrigger EventName="MouseMove">
+                            <i:InvokeCommandAction Command="{Binding MouseMoveCommand}"/>
+                        </i:EventTrigger>
+                        <i:EventTrigger EventName="MouseUp">
+                            <i:InvokeCommandAction Command="{Binding MouseUpCommand}"/>
+                        </i:EventTrigger>
+                    </i:Interaction.Triggers>
+                    <i:Interaction.Behaviors>
+                        <behaviors:MouseBehaviour RelativeTo="{Binding ElementName=DrawingPanel, Path=Item}" MouseX="{Binding MouseXOnCanvas, Mode=OneWayToSource}" MouseY="{Binding MouseYOnCanvas, Mode=OneWayToSource}"/>
+                    </i:Interaction.Behaviors>
+                    <vws:MainDrawingPanel.Item>
+                        <Canvas Width="{Binding BitmapUtility.ActiveLayer.Width}" Height="{Binding BitmapUtility.ActiveLayer.Height}" VerticalAlignment="Center" HorizontalAlignment="Center">
+                            <i:Interaction.Triggers>
+                                <i:EventTrigger EventName="MouseDown">
+                                    <i:InvokeCommandAction Command="{Binding MouseDownCommand}"/>
+                                </i:EventTrigger>
+                            </i:Interaction.Triggers>
+                            <Image Source="/Images/transparentbg.png" Height="{Binding BitmapUtility.ActiveLayer.Height}" Width="{Binding BitmapUtility.ActiveLayer.Width}" Opacity="0.9" Stretch="UniformToFill"/>
+                            <Image Source="{Binding BitmapUtility.PreviewLayer.LayerBitmap}" Panel.ZIndex="2" RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="Uniform" Width="{Binding BitmapUtility.PreviewLayer.Width}" Height="{Binding BitmapUtility.PreviewLayer.Height}"/>
+                            <ItemsControl ItemsSource="{Binding BitmapUtility.Layers}">
+                                <ItemsControl.ItemsPanel>
+                                    <ItemsPanelTemplate>
+                                        <Grid/>
+                                    </ItemsPanelTemplate>
+                                </ItemsControl.ItemsPanel>
+                                <ItemsControl.ItemTemplate>
+                                    <DataTemplate>
+                                        <Image Source="{Binding LayerBitmap}" Visibility="{Binding IsVisible, Converter={StaticResource BoolToVisibilityConverter}}" RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="Uniform" Width="{Binding Width}" Height="{Binding Height}"/>
+                                    </DataTemplate>
+                                </ItemsControl.ItemTemplate>
+                            </ItemsControl>
+                        </Canvas>
+                    </vws:MainDrawingPanel.Item>
+                </vws:MainDrawingPanel>
+            </Grid>
+        </Grid>
+
+        <StackPanel Orientation="Vertical" Cursor="Arrow" Grid.Row="2" Grid.Column="0" Margin="0,7,5,0" Background="#404040" Grid.RowSpan="2">
+            
+            <ItemsControl ItemsSource="{Binding ToolSet}">
+                <ItemsControl.ItemTemplate>
+                    <DataTemplate>
+                        <Button BorderBrush="White" BorderThickness="{Binding IsActive, Converter={StaticResource BoolToIntConverter}}"
+                                Style="{StaticResource ToolButtonStyle}" 
+                                Command="{Binding Path=DataContext.SelectToolCommand,
+                            RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
+                                CommandParameter="{Binding ToolType}" ToolTip="{Binding Tooltip}">
+                            <Button.Background>
+                                <ImageBrush ImageSource="{Binding ImagePath}" Stretch="Uniform"/>
+                            </Button.Background>
+                        </Button>
+                    </DataTemplate>
+                </ItemsControl.ItemTemplate>
+            </ItemsControl>
+        </StackPanel>
+
+        <DockPanel Grid.Column="2" Background="#404040" Margin="0,30,0,0" Grid.RowSpan="3">
+            <Grid DockPanel.Dock="Top" HorizontalAlignment="Center" Width="100"  Margin="0,20,0,0" Height="100">
+                <Rectangle Height="70" Width="70" HorizontalAlignment="Left" VerticalAlignment="Top" Stroke="Black" StrokeThickness="1" Panel.ZIndex="1">
+                    <Rectangle.Fill>
+                        <SolidColorBrush Color="{Binding PrimaryColor, Mode=OneWay}"/>
+                    </Rectangle.Fill>
+                </Rectangle>
+                <xctk:ColorPicker Width="70" Panel.ZIndex="2" Height="70" VerticalAlignment="Top" HorizontalAlignment="Left" UsingAlphaChannel="True" AvailableColorsSortingMode="Alphabetical" ShowDropDownButton="False" Background="Transparent" BorderThickness="0" ShowRecentColors="True" SelectedColor="{Binding PrimaryColor, Mode=TwoWay}"></xctk:ColorPicker>
                 <Button Opacity="0.3" ToolTip="Swap colors (X)" Command="{Binding SwapColorsCommand}" Width="25" Height="25" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="0 0 0 3" Style="{StaticResource ImageButtonStyle}">
                     <Button.Background>
                         <ImageBrush ImageSource="/Images/SwapArrows.png" Stretch="Fill"/>
                     </Button.Background>
-                </Button>
-                <Rectangle Height="70" Width="70" HorizontalAlignment="Right" VerticalAlignment="Bottom" Stroke="Black" StrokeThickness="1" Margin="0,0,4,5">
-                    <Rectangle.Fill>
-                        <SolidColorBrush Color="{Binding SecondaryColor, Mode=OneWay}"/>
-                    </Rectangle.Fill>
-                </Rectangle>
-                <xctk:ColorPicker Width="70" Height="70" HorizontalAlignment="Right" VerticalAlignment="Bottom" UsingAlphaChannel="True" AvailableColorsSortingMode="Alphabetical" ShowDropDownButton="False" Background="Transparent" BorderThickness="0" ShowRecentColors="True" Margin="0,0,4,5" SelectedColor="{Binding SecondaryColor, Mode=TwoWay}"/>
-            </Grid>
-
-            <xcad:DockingManager Grid.Column="2" Grid.Row="1" DockPanel.Dock="Top">
-                <xcad:DockingManager.Style>
-                    <Style TargetType="xcad:DockingManager">
-                        <Setter Property="Foreground" Value="Snow"/>
-                    </Style>
-                </xcad:DockingManager.Style>
-                <xcad:LayoutRoot x:Name="LayoutRoot">
-                    <xcad:LayoutPanel Orientation="Vertical">
-                        <xcad:LayoutAnchorablePane>
-                            <xcad:LayoutAnchorable ContentId="layers" Title="Layers" CanHide="False" CanClose="False" CanAutoHide="False" CanDockAsTabbedDocument="False" CanFloat="True">
-                                <StackPanel  Orientation="Vertical">
-                                    <Button Command="{Binding NewLayerCommand}" Height="30" Content="New Layer" HorizontalAlignment="Stretch" Margin="5" Style="{StaticResource DarkRoundButton}"/>
-                                    <ItemsControl ItemsSource="{Binding BitmapUtility.Layers}" x:Name="layersItemsControl" AlternationCount="9999">
-                                        <ItemsControl.ItemsPanel>
-                                            <ItemsPanelTemplate>
-                                                <ui:ReversedOrderStackPanel Orientation="Vertical"/>
-                                            </ItemsPanelTemplate>
-                                        </ItemsControl.ItemsPanel>
-                                        <ItemsControl.ItemTemplate>
-                                            <DataTemplate>
-                                                <Border BorderThickness="1" BorderBrush="Gray" MinWidth="60" Background="{Binding IsActive, Mode=TwoWay, Converter={StaticResource BoolToColorConverter}}">
-                                                    <DockPanel>
-                                                        <CheckBox VerticalAlignment="Center" Command="{Binding Path=DataContext.ReloadImageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" IsThreeState="False" IsChecked="{Binding Path=IsVisible}"/>
-                                                        <Button Background="Transparent" Style="{StaticResource BaseDarkButton}" FontSize="16" DockPanel.Dock="Left" Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, 
-                            Path=DataContext.SetActiveLayerCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
-                            Path=(ItemsControl.AlternationIndex)}">
-                                                            <Button.ContextMenu>
-                                                                <ContextMenu>
-                                                                    <MenuItem Header="Delete" Command="{Binding DeleteLayerCommand, Source={StaticResource ViewModelMain}}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
-                            Path=(ItemsControl.AlternationIndex)}"/>
-                                                                    <MenuItem Header="Rename" Command="{Binding RenameLayerCommand, Source={StaticResource ViewModelMain}}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
-                            Path=(ItemsControl.AlternationIndex)}"/>
-                                                                    <MenuItem Header="Move to front" Command="{Binding MoveToFrontCommand, Source={StaticResource ViewModelMain}}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
-                            Path=(ItemsControl.AlternationIndex)}"/>
-                                                                    <MenuItem Header="Move to back" Command="{Binding MoveToBackCommand, Source={StaticResource ViewModelMain}}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
-                            Path=(ItemsControl.AlternationIndex)}"/>
-                                                                </ContextMenu>
-                                                            </Button.ContextMenu>
-                                                            <vws:EditableTextBlock IsEditing="{Binding IsRenaming, Mode=TwoWay}" Text="{Binding Name, Mode=TwoWay}">
-                                                            </vws:EditableTextBlock>
-                                                        </Button>
-                                                    </DockPanel>
-                                                </Border>
-                                            </DataTemplate>
-                                        </ItemsControl.ItemTemplate>
-                                    </ItemsControl>
-                                </StackPanel>
-                            </xcad:LayoutAnchorable>
-                        </xcad:LayoutAnchorablePane>
-                    </xcad:LayoutPanel>
-                </xcad:LayoutRoot>
-            </xcad:DockingManager>
-        </DockPanel>
-
-    </Grid>
-</Window>
+                </Button>
+                <Rectangle Height="70" Width="70" HorizontalAlignment="Right" VerticalAlignment="Bottom" Stroke="Black" StrokeThickness="1" Margin="0,0,4,5">
+                    <Rectangle.Fill>
+                        <SolidColorBrush Color="{Binding SecondaryColor, Mode=OneWay}"/>
+                    </Rectangle.Fill>
+                </Rectangle>
+                <xctk:ColorPicker Width="70" Height="70" HorizontalAlignment="Right" VerticalAlignment="Bottom" UsingAlphaChannel="True" AvailableColorsSortingMode="Alphabetical" ShowDropDownButton="False" Background="Transparent" BorderThickness="0" ShowRecentColors="True" Margin="0,0,4,5" SelectedColor="{Binding SecondaryColor, Mode=TwoWay}"/>
+            </Grid>
+
+            <xcad:DockingManager Grid.Column="2" Grid.Row="1" DockPanel.Dock="Top">
+                <xcad:DockingManager.Style>
+                    <Style TargetType="xcad:DockingManager">
+                        <Setter Property="Foreground" Value="Snow"/>
+                    </Style>
+                </xcad:DockingManager.Style>
+                <xcad:LayoutRoot x:Name="LayoutRoot">
+                    <xcad:LayoutPanel Orientation="Vertical">
+                        <xcad:LayoutAnchorablePane>
+                            <xcad:LayoutAnchorable ContentId="layers" Title="Layers" CanHide="False" CanClose="False" CanAutoHide="False" CanDockAsTabbedDocument="False" CanFloat="True">
+                                <StackPanel  Orientation="Vertical">
+                                    <Button Command="{Binding NewLayerCommand}" Height="30" Content="New Layer" HorizontalAlignment="Stretch" Margin="5" Style="{StaticResource DarkRoundButton}"/>
+                                    <ItemsControl ItemsSource="{Binding BitmapUtility.Layers}" x:Name="layersItemsControl" AlternationCount="9999">
+                                        <ItemsControl.ItemsPanel>
+                                            <ItemsPanelTemplate>
+                                                <ui:ReversedOrderStackPanel Orientation="Vertical"/>
+                                            </ItemsPanelTemplate>
+                                        </ItemsControl.ItemsPanel>
+                                        <ItemsControl.ItemTemplate>
+                                            <DataTemplate>
+                                                <Border BorderThickness="1" BorderBrush="Gray" MinWidth="60" Background="{Binding IsActive, Mode=TwoWay, Converter={StaticResource BoolToColorConverter}}">
+                                                    <DockPanel>
+                                                        <CheckBox VerticalAlignment="Center" Command="{Binding Path=DataContext.ReloadImageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" IsThreeState="False" IsChecked="{Binding Path=IsVisible}"/>
+                                                        <Button Background="Transparent" Style="{StaticResource BaseDarkButton}" FontSize="16" DockPanel.Dock="Left" Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, 
+                            Path=DataContext.SetActiveLayerCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
+                            Path=(ItemsControl.AlternationIndex)}">
+                                                            <Button.ContextMenu>
+                                                                <ContextMenu>
+                                                                    <MenuItem Header="Delete" Command="{Binding DeleteLayerCommand, Source={StaticResource ViewModelMain}}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
+                            Path=(ItemsControl.AlternationIndex)}"/>
+                                                                    <MenuItem Header="Rename" Command="{Binding RenameLayerCommand, Source={StaticResource ViewModelMain}}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
+                            Path=(ItemsControl.AlternationIndex)}"/>
+                                                                    <MenuItem Header="Move to front" Command="{Binding MoveToFrontCommand, Source={StaticResource ViewModelMain}}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
+                            Path=(ItemsControl.AlternationIndex)}"/>
+                                                                    <MenuItem Header="Move to back" Command="{Binding MoveToBackCommand, Source={StaticResource ViewModelMain}}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
+                            Path=(ItemsControl.AlternationIndex)}"/>
+                                                                </ContextMenu>
+                                                            </Button.ContextMenu>
+                                                            <vws:EditableTextBlock IsEditing="{Binding IsRenaming, Mode=TwoWay}" Text="{Binding Name, Mode=TwoWay}">
+                                                            </vws:EditableTextBlock>
+                                                        </Button>
+                                                    </DockPanel>
+                                                </Border>
+                                            </DataTemplate>
+                                        </ItemsControl.ItemTemplate>
+                                    </ItemsControl>
+                                </StackPanel>
+                            </xcad:LayoutAnchorable>
+                        </xcad:LayoutAnchorablePane>
+                    </xcad:LayoutPanel>
+                </xcad:LayoutRoot>
+            </xcad:DockingManager>
+        </DockPanel>
+
+    </Grid>
+</Window>

+ 1 - 1
PixiEditor/Views/MenuButton.xaml

@@ -8,7 +8,7 @@
              xmlns:helpers="clr-namespace:PixiEditor.Helpers"
              xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
              mc:Ignorable="d" 
-             d:DesignHeight="330" d:DesignWidth="200" x:Name="menuButton" DataContext="{DynamicResource MenuButtonViewModel}">
+             d:DesignHeight="40" d:DesignWidth="80" x:Name="menuButton" DataContext="{DynamicResource MenuButtonViewModel}">
     <UserControl.Resources>
         <vm:MenuButtonViewModel x:Key="MenuButtonViewModel"/>
         <Style TargetType="ListViewItem">

+ 16 - 8
PixiEditor/Views/NewFilePopup.xaml

@@ -6,11 +6,13 @@
              xmlns:local="clr-namespace:PixiEditor.Views"
              xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
              xmlns:vm="clr-namespace:PixiEditor.ViewModels"
-             xmlns:helpers="clr-namespace:PixiEditor.Helpers.Behaviours"
-             mc:Ignorable="d" 
+             xmlns:helpers="clr-namespace:PixiEditor.Helpers.Behaviours" 
+             xmlns:converters="clr-namespace:PixiEditor.Helpers"
+        mc:Ignorable="d" 
              d:DesignHeight="600" d:DesignWidth="450" DataContext="{DynamicResource NewFileMenuViewModel}" WindowStyle="None" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" Height="600" Width="450" Name="newFilePopup">
     <Window.Resources>
         <vm:NewFileMenuViewModel x:Key="NewFileMenuViewModel"/>
+        <converters:ToolSizeToIntConverter x:Key="ToolSizeToIntConverter"/>
     </Window.Resources>
     <Border BorderBrush="Black" BorderThickness="1">
         <Grid Background="#404040">
@@ -24,7 +26,8 @@
                         <i:InvokeCommandAction Command="{Binding DragMoveCommand}"/>
                     </i:EventTrigger>
                 </i:Interaction.Triggers>
-                <Button Width="20" Height="20" VerticalAlignment="Top" HorizontalAlignment="Right" BorderThickness="0" Command="{Binding CloseCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
+                <Button Width="20" Height="20" VerticalAlignment="Top" Style="{StaticResource ImageButtonStyle}" Cursor="Hand" HorizontalAlignment="Right" BorderThickness="0" Command="{Binding CloseCommand}" 
+                        CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
                     <Button.Background>
                         <ImageBrush ImageSource="/Images/Cross.png" Stretch="Uniform"/>
                     </Button.Background>
@@ -33,22 +36,27 @@
             <StackPanel HorizontalAlignment="Center" Margin="0,50,0,0" Background="#303030" VerticalAlignment="Top" Grid.Row="1" Width="350" Height="150">
                 <DockPanel Margin="50,35,0,0">
                     <TextBlock Height="30" Foreground="Snow" Text="Height:" TextAlignment="Center" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
-                    <TextBox Height="30" Width="150" Style="{StaticResource DarkTextBoxStyle}" FontSize="16" HorizontalAlignment="Left" TextAlignment="Center" Margin="5,0,0,0" Text="{Binding ElementName=newFilePopup, Path=FileHeight, Mode=TwoWay}" MaxLength="4">
+                    <TextBox Height="30" Width="150" Style="{StaticResource DarkTextBoxStyle}" FontSize="16"
+                             HorizontalAlignment="Left" TextAlignment="Center" 
+                             Margin="5,0,0,0" Text="{Binding ElementName=newFilePopup, Converter={StaticResource ToolSizeToIntConverter}, Path=FileHeight, Mode=TwoWay}" MaxLength="4">
                         <i:Interaction.Behaviors>
-                            <helpers:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9./-]+$" MaxLength="4"/>
+                            <helpers:TextBoxFocusBehavior FillSize="True" NextFocusDirection="Next"/>
                         </i:Interaction.Behaviors>
                     </TextBox>
                 </DockPanel>
                 <DockPanel Margin="50,10,0,0">
                     <TextBlock Height="30" Foreground="Snow" Text="Width:" TextAlignment="Center" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
-                    <TextBox Height="30" Width="150" Style="{StaticResource DarkTextBoxStyle}" FontSize="16" HorizontalAlignment="Left" Margin="10,0,0,0" TextAlignment="Center" Text="{Binding ElementName=newFilePopup, Path=FileWidth, Mode=TwoWay}" MaxLength="4">
+                    <TextBox Height="30" Width="150" Style="{StaticResource DarkTextBoxStyle}" FontSize="16" HorizontalAlignment="Left" Margin="10,0,0,0" TextAlignment="Center"
+                             Text="{Binding ElementName=newFilePopup, Converter={StaticResource ToolSizeToIntConverter}, Path=FileWidth, Mode=TwoWay}" MaxLength="4">
                         <i:Interaction.Behaviors>
-                            <helpers:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9./-]+$" MaxLength="4"/>
+                            <helpers:TextBoxFocusBehavior FillSize="True" NextFocusDirection="Next"/>
                         </i:Interaction.Behaviors>
                     </TextBox>
                 </DockPanel>
             </StackPanel>
-            <Button VerticalAlignment="Bottom" HorizontalAlignment="Right" FontSize="20" Height="30" Width="60" Style="{StaticResource DarkRoundButton}" Content="OK" Margin="0,0,10,10" Grid.Row="1" Command="{Binding OkCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
+            <Button VerticalAlignment="Bottom" HorizontalAlignment="Right" FontSize="20" Height="30" Width="60" 
+                    Style="{StaticResource DarkRoundButton}" Content="OK" Margin="0,0,10,10" Grid.Row="1" 
+                    Command="{Binding OkCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
         </Grid>
     </Border>
 </Window>

+ 16 - 0
PixiEditor/Views/NumerInput.xaml

@@ -0,0 +1,16 @@
+<UserControl x:Class="PixiEditor.Views.NumberInput"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+             xmlns:local="clr-namespace:PixiEditor.Views" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:behaviours="clr-namespace:PixiEditor.Helpers.Behaviours"
+             mc:Ignorable="d" 
+             d:DesignHeight="20" d:DesignWidth="40" x:Name="numberInput">
+    <Grid>
+        <TextBox TextAlignment="Center" Style="{StaticResource DarkTextBoxStyle}" PreviewTextInput="TextBox_PreviewTextInput" Text="{Binding ElementName=numberInput, Path=Value}">
+            <i:Interaction.Behaviors>
+                <behaviours:TextBoxFocusBehavior/>
+            </i:Interaction.Behaviors>
+        </TextBox>
+    </Grid>
+</UserControl>

+ 74 - 0
PixiEditor/Views/NumerInput.xaml.cs

@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace PixiEditor.Views
+{
+    /// <summary>
+    /// Interaction logic for NumerInput.xaml
+    /// </summary>
+    public partial class NumberInput : UserControl
+    {
+
+        public float Value
+        {
+            get { return (float)GetValue(ValueProperty); }
+            set { SetValue(ValueProperty, value); }
+        }
+
+        // Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
+        public static readonly DependencyProperty ValueProperty =
+            DependencyProperty.Register("Value", typeof(float), typeof(NumberInput), 
+                new PropertyMetadata(0f, new PropertyChangedCallback(OnValueChanged)));
+
+        private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+        {
+            NumberInput input = (NumberInput)d;
+            input.Value = Math.Clamp((float)e.NewValue, input.Min, input.Max);
+        }
+
+        public float Min
+        {
+            get { return (float)GetValue(MinProperty); }
+            set { SetValue(MinProperty, value); }
+        }
+
+        // Using a DependencyProperty as the backing store for Min.  This enables animation, styling, binding, etc...
+        public static readonly DependencyProperty MinProperty =
+            DependencyProperty.Register("Min", typeof(float), typeof(NumberInput), new PropertyMetadata(float.NegativeInfinity));
+
+
+
+        public float Max
+        {
+            get { return (float)GetValue(MaxProperty); }
+            set { SetValue(MaxProperty, value); }
+        }
+
+        // Using a DependencyProperty as the backing store for Max.  This enables animation, styling, binding, etc...
+        public static readonly DependencyProperty MaxProperty =
+            DependencyProperty.Register("Max", typeof(float), typeof(NumberInput), new PropertyMetadata(float.PositiveInfinity));
+
+
+        public NumberInput()
+        {
+            InitializeComponent();
+        }
+
+        private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
+        {
+            Regex regex = new Regex("^[.][0-9]+$|^[0-9]*[.]{0,1}[0-9]*$");
+            e.Handled = !regex.IsMatch((sender as TextBox).Text.Insert((sender as TextBox).SelectionStart, e.Text));
+        }
+    }
+}

+ 17 - 11
PixiEditor/Views/SaveFilePopup.xaml

@@ -6,11 +6,14 @@
         xmlns:local="clr-namespace:PixiEditor.Views"
         xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
         xmlns:vm="clr-namespace:PixiEditor.ViewModels"
-        xmlns:helpers="clr-namespace:PixiEditor.Helpers.Behaviours"
+        xmlns:helpers="clr-namespace:PixiEditor.Helpers.Behaviours" xmlns:helpers1="clr-namespace:PixiEditor.Helpers"
         mc:Ignorable="d"
-        Title="SaveFilePopup" Height="250" Width="400" WindowStyle="None" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" Name="saveFilePopup">
+        Title="SaveFilePopup" Height="300" Width="400" WindowStyle="None" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" Name="saveFilePopup">
+    <Window.Resources>
+        <helpers1:ToolSizeToIntConverter x:Key="ToolSizeToIntConverter"/>
+    </Window.Resources>
     <Border BorderBrush="Black" BorderThickness="1">
-    <Grid Background="#303030">
+        <Grid Background="#404040">
         <Grid.RowDefinitions>
             <RowDefinition Height="20*"/>
             <RowDefinition Height="229*"/>
@@ -21,25 +24,28 @@
                     <i:InvokeCommandAction Command="{Binding DragMoveCommand}"/>
                 </i:EventTrigger>
             </i:Interaction.Triggers>
-            <Button Width="20" Height="20" VerticalAlignment="Top" HorizontalAlignment="Right" BorderThickness="0" Command="{Binding CloseButtonCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
+            <Button Width="20" Height="20" Style="{StaticResource ImageButtonStyle}" Cursor="Hand" VerticalAlignment="Top" HorizontalAlignment="Right" BorderThickness="0" 
+                    Command="{Binding CloseButtonCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
                 <Button.Background>
                     <ImageBrush ImageSource="/Images/Cross.png" Stretch="Uniform"/>
                 </Button.Background>
             </Button>
         </Grid>
         <TextBlock Grid.Row="1" Height="30" Width="120" Foreground="Snow" VerticalAlignment="Top" HorizontalAlignment="Center" Text="File settings" TextAlignment="Center" FontSize="20"/>
-        <DockPanel Grid.Row="1" Height="70" Width="320" Margin="0,0,0,100" Background="#2D2D2D">
+        <DockPanel Grid.Row="1" Height="70" Width="320" Margin="0,10,0,100" Background="#303030">
             <TextBlock Foreground="Snow" Width="40" Height="40" HorizontalAlignment="Left" Margin="50,0,0,0" Text="Width:" TextAlignment="Center" Padding="0,11.5,0,0"/>
-            <TextBox Style="{StaticResource DarkTextBoxStyle}" Width="70" Height="20" HorizontalAlignment="Left" Margin="5,0,0,0" Text="{Binding ElementName=saveFilePopup, Path=SaveWidth, Mode=TwoWay}">
+            <TextBox Style="{StaticResource DarkTextBoxStyle}" Width="70" Height="20" HorizontalAlignment="Left" Margin="5,0,0,0" 
+                     Text="{Binding ElementName=saveFilePopup, Converter={StaticResource ToolSizeToIntConverter}, Path=SaveWidth, Mode=TwoWay}">
                 <i:Interaction.Behaviors>
-                    <helpers:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9./-]+$" MaxLength="4"/>
-                </i:Interaction.Behaviors>
+                        <helpers:TextBoxFocusBehavior FillSize="True" NextFocusDirection="Next"/>
+                    </i:Interaction.Behaviors>
             </TextBox>
             <TextBlock Foreground="Snow" Width="40" Height="40"  HorizontalAlignment="Left" Margin="5,0,0,0" Text="Height:" TextAlignment="Center" Padding="0,11.5,0,0"/>
-            <TextBox Style="{StaticResource DarkTextBoxStyle}" Width="70" Height="20" HorizontalAlignment="Left" Margin="5,0,0,0" Text="{Binding ElementName=saveFilePopup, Path=SaveHeight,Mode=TwoWay}">
+            <TextBox Style="{StaticResource DarkTextBoxStyle}" Width="70" Height="20" HorizontalAlignment="Left" 
+                     Margin="5,0,0,0" Text="{Binding ElementName=saveFilePopup, Converter={StaticResource ToolSizeToIntConverter}, Path=SaveHeight,Mode=TwoWay}">
                 <i:Interaction.Behaviors>
-                    <helpers:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9./-]+$" MaxLength="4"/>
-                </i:Interaction.Behaviors>
+                        <helpers:TextBoxFocusBehavior FillSize="True" NextFocusDirection="Next"/>
+                    </i:Interaction.Behaviors>
             </TextBox>
         </DockPanel>
         <Button Grid.Row="1" Foreground="Snow" Height="40" Width="160" Margin="0,50,0,0" Content="Path" Background="#303030" BorderBrush="{Binding PathButtonBorder}" Command="{Binding ChoosePathCommand}"/>

+ 2 - 2
PixiEditorTests/ModelsTests/PositionTests/CoordinatesCalculatorTests.cs

@@ -6,14 +6,14 @@ namespace PixiEditorTests.ModelsTests.PositionTests
     [TestFixture]
     public class CoordinatesCalculatorTests
     {
-        [TestCase(0, 0, 3, 3, 2, 2)]
+        [TestCase(0, 0, 3, 3, 1, 1)]
         [TestCase(0, 0, 2, 2, 1, 1)]
         [TestCase(5, 5, 7, 7, 6, 6)]
         [TestCase(5, 5, 9, 9, 7, 7)]
         public void TestGetCenter(int x1, int y1, int x2, int y2, int expectedX, int expectedY)
         {
             Coordinates center = CoordinatesCalculator.GetCenterPoint(new Coordinates(x1, y1), new Coordinates(x2, y2));
-            Assert.AreEqual(center, new Coordinates(expectedX, expectedY));
+            Assert.AreEqual(new Coordinates(expectedX, expectedY), center);
         }
 
     }

+ 40 - 2
PixiEditorTests/WorkspaceTests/ColorsTests/ExtendedColorTests.cs

@@ -10,18 +10,56 @@ namespace PixiEditorTests.WorkspaceTests.ColorsTests
     [TestFixture]
     public class ExtendedColorTests
     {
+        private const int AcceptableMaringOfError = 1;
+
         [TestCase()]
         public void ChangeColorBrightnessIsNotTheSameTest()
         {
-            Color newColor = ExColor.ChangeColorBrightness(Colors.White, -0.1f);
+            Color newColor = ExColor.ChangeColorBrightness(Colors.White, -1);
             Assert.AreNotEqual(Colors.White, newColor);
         }
 
         [TestCase()]
         public void ChangeColorBrightnessNewValueTest()
         {
-            Color newColor = ExColor.ChangeColorBrightness(Colors.White, -1f);
+            Color newColor = ExColor.ChangeColorBrightness(Colors.White, -100);
             Assert.AreEqual(Colors.Black, newColor);
         }
+
+
+        //Acceptable margin of error is 1
+        [TestCase(0,0,0,0,0,0)]
+        [TestCase(255,255,255,0,0,100)]
+        [TestCase(182,55,55,0,53.6f,46.5f)]
+        [TestCase(20,47,255,233,100,53.9f)]
+        [TestCase(137, 43,226, 271,75.9f,52.7f)]
+        public void RgbToHslTest(int r, int g, int b, int h, float s, float l)
+        {
+            Tuple<int, float, float> hsl = ExColor.RgbToHsl(r, g, b);
+            float marginOfErrorH = Math.Abs(hsl.Item1 - h);
+            float marginOfErrorS = Math.Abs(hsl.Item2 - s);
+            float marginOfErrorL = Math.Abs(hsl.Item3 - l);
+            Assert.LessOrEqual(marginOfErrorH, AcceptableMaringOfError);
+            Assert.LessOrEqual(marginOfErrorS, AcceptableMaringOfError);
+            Assert.LessOrEqual(marginOfErrorL, AcceptableMaringOfError);
+
+        }
+
+        [TestCase(0, 0, 0, 0, 0, 0)]
+        [TestCase(0, 0, 100, 255, 255, 255)]
+        [TestCase(0, 53.6f, 46.5f, 182, 55, 55)]
+        [TestCase(297, 100, 17.1f, 82, 0, 87)]
+        [TestCase(271, 75.9f, 52.7f, 137, 43, 226)]
+        public void HslToRgbTest(int h, float s, float l, int r, int g, int b)
+        {
+            Color rgb = ExColor.HslToRGB(h, s, l);
+            int marginOfErrorR = Math.Abs(rgb.R - r);
+            int marginOfErrorG = Math.Abs(rgb.G - g);
+            int marginOfErrorB = Math.Abs(rgb.B - b);
+            Assert.LessOrEqual(marginOfErrorR, AcceptableMaringOfError);
+            Assert.LessOrEqual(marginOfErrorG, AcceptableMaringOfError);
+            Assert.LessOrEqual(marginOfErrorB, AcceptableMaringOfError);
+
+        }
     }
 }