Pārlūkot izejas kodu

Implemented center content

flabbet 5 gadi atpakaļ
vecāks
revīzija
75f2dfc0cc
41 mainītis faili ar 294 papildinājumiem un 248 dzēšanām
  1. 18 18
      PixiEditor/Models/Controllers/BitmapManager.cs
  2. 5 6
      PixiEditor/Models/Controllers/BitmapOperationsUtility.cs
  3. 2 2
      PixiEditor/Models/Controllers/MouseMovementController.cs
  4. 2 2
      PixiEditor/Models/Controllers/ReadonlyToolUtility.cs
  5. 5 5
      PixiEditor/Models/Controllers/Shortcuts/Shortcut.cs
  6. 4 4
      PixiEditor/Models/Controllers/Shortcuts/ShortcutController.cs
  7. 10 11
      PixiEditor/Models/DataHolders/Change.cs
  8. 60 22
      PixiEditor/Models/DataHolders/Document.cs
  9. 3 3
      PixiEditor/Models/DataHolders/LayerChanges.cs
  10. 17 17
      PixiEditor/Models/DataHolders/NotifyableColor.cs
  11. 11 11
      PixiEditor/Models/DataHolders/Selection.cs
  12. 5 5
      PixiEditor/Models/DataHolders/SerializableDocument.cs
  13. 1 2
      PixiEditor/Models/DataHolders/StackEx.cs
  14. 6 8
      PixiEditor/Models/DataHolders/Tuple.cs
  15. 13 13
      PixiEditor/Models/Dialogs/ExportFileDialog.cs
  16. 6 6
      PixiEditor/Models/Dialogs/ImportFileDialog.cs
  17. 4 4
      PixiEditor/Models/Dialogs/NewFileDialog.cs
  18. 10 10
      PixiEditor/Models/Dialogs/ResizeDocumentDialog.cs
  19. 2 2
      PixiEditor/Models/Events/DocumentChangedEventArgs.cs
  20. 4 4
      PixiEditor/Models/Layers/BasicLayer.cs
  21. 27 29
      PixiEditor/Models/Layers/Layer.cs
  22. 6 6
      PixiEditor/Models/Layers/SerializableLayer.cs
  23. 8 15
      PixiEditor/Models/Position/CoordinatesCalculator.cs
  24. 2 2
      PixiEditor/Models/Tools/ShapeTool.cs
  25. 1 1
      PixiEditor/Models/Tools/Tool.cs
  26. 2 2
      PixiEditor/Models/Tools/ToolSettings/Settings/DropdownSetting.cs
  27. 3 3
      PixiEditor/Models/Tools/ToolSettings/Settings/FloatSetting.cs
  28. 6 7
      PixiEditor/Models/Tools/ToolSettings/Settings/Setting.cs
  29. 2 2
      PixiEditor/Models/Tools/Tools/BrightnessTool.cs
  30. 2 2
      PixiEditor/Models/Tools/Tools/CircleTool.cs
  31. 2 2
      PixiEditor/Models/Tools/Tools/ColorPickerTool.cs
  32. 2 2
      PixiEditor/Models/Tools/Tools/EarserTool.cs
  33. 2 2
      PixiEditor/Models/Tools/Tools/FloodFill.cs
  34. 2 2
      PixiEditor/Models/Tools/Tools/LineTool.cs
  35. 6 5
      PixiEditor/Models/Tools/Tools/MoveTool.cs
  36. 1 2
      PixiEditor/Models/Tools/Tools/PenTool.cs
  37. 3 3
      PixiEditor/Models/Tools/Tools/RectangleTool.cs
  38. 1 2
      PixiEditor/Models/Tools/Tools/SelectTool.cs
  39. 8 0
      PixiEditor/PixiEditor.csproj
  40. 18 4
      PixiEditor/ViewModels/ViewModelMain.cs
  41. 2 0
      PixiEditor/Views/MainWindow.xaml

+ 18 - 18
PixiEditor/Models/Controllers/BitmapManager.cs

@@ -16,21 +16,6 @@ namespace PixiEditor.Models.Controllers
 {
     public class BitmapManager : NotifyableObject
     {
-        private Document _activeDocument;
-
-        private Layer _previewLayer;
-        private Tool _selectedTool;
-
-        public BitmapManager()
-        {
-            MouseController = new MouseMovementController();
-            MouseController.StartedRecordingChanges += MouseController_StartedRecordingChanges;
-            MouseController.MousePositionChanged += Controller_MousePositionChanged;
-            MouseController.StoppedRecordingChanges += MouseController_StoppedRecordingChanges;
-            BitmapOperations = new BitmapOperationsUtility(this);
-            ReadonlyToolUtility = new ReadonlyToolUtility(this);
-        }
-
         public MouseMovementController MouseController { get; set; }
 
         public Tool SelectedTool
@@ -75,6 +60,21 @@ namespace PixiEditor.Models.Controllers
             }
         }
 
+        private Document _activeDocument;
+
+        private Layer _previewLayer;
+        private Tool _selectedTool;
+
+        public BitmapManager()
+        {
+            MouseController = new MouseMovementController();
+            MouseController.StartedRecordingChanges += MouseController_StartedRecordingChanges;
+            MouseController.MousePositionChanged += Controller_MousePositionChanged;
+            MouseController.StoppedRecordingChanges += MouseController_StoppedRecordingChanges;
+            BitmapOperations = new BitmapOperationsUtility(this);
+            ReadonlyToolUtility = new ReadonlyToolUtility(this);
+        }
+
         public event EventHandler<LayersChangedEventArgs> LayersChanged;
         public event EventHandler<DocumentChangedEventArgs> DocumentChanged;
 
@@ -180,13 +180,13 @@ namespace PixiEditor.Models.Controllers
 
     public class LayersChangedEventArgs : EventArgs
     {
+        public int LayerAffected { get; set; }
+        public LayerAction LayerChangeType { get; set; }
+
         public LayersChangedEventArgs(int layerAffected, LayerAction layerChangeType)
         {
             LayerAffected = layerAffected;
             LayerChangeType = layerChangeType;
         }
-
-        public int LayerAffected { get; set; }
-        public LayerAction LayerChangeType { get; set; }
     }
 }

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

@@ -14,6 +14,7 @@ namespace PixiEditor.Models.Controllers
 {
     public class BitmapOperationsUtility
     {
+        public BitmapManager Manager { get; set; }
         private LayerChange[] _lastModifiedLayers;
 
         private Coordinates _lastMousePos;
@@ -23,8 +24,6 @@ namespace PixiEditor.Models.Controllers
             Manager = manager;
         }
 
-        public BitmapManager Manager { get; set; }
-
         public event EventHandler<BitmapChangedEventArgs> BitmapChanged;
 
         public void DeletePixels(Layer[] layers, Coordinates[] pixels)
@@ -154,6 +153,10 @@ namespace PixiEditor.Models.Controllers
 
 public class BitmapChangedEventArgs : EventArgs
 {
+    public BitmapPixelChanges PixelsChanged { get; set; }
+    public BitmapPixelChanges OldPixelsValues { get; set; }
+    public int ChangedLayerIndex { get; set; }
+
     public BitmapChangedEventArgs(BitmapPixelChanges pixelsChanged, BitmapPixelChanges oldPixelsValues,
         int changedLayerIndex)
     {
@@ -161,8 +164,4 @@ public class BitmapChangedEventArgs : EventArgs
         OldPixelsValues = oldPixelsValues;
         ChangedLayerIndex = changedLayerIndex;
     }
-
-    public BitmapPixelChanges PixelsChanged { get; set; }
-    public BitmapPixelChanges OldPixelsValues { get; set; }
-    public int ChangedLayerIndex { get; set; }
 }

+ 2 - 2
PixiEditor/Models/Controllers/MouseMovementController.cs

@@ -54,10 +54,10 @@ namespace PixiEditor.Models.Controllers
 
 public class MouseMovementEventArgs : EventArgs
 {
+    public Coordinates NewPosition { get; set; }
+
     public MouseMovementEventArgs(Coordinates mousePosition)
     {
         NewPosition = mousePosition;
     }
-
-    public Coordinates NewPosition { get; set; }
 }

+ 2 - 2
PixiEditor/Models/Controllers/ReadonlyToolUtility.cs

@@ -5,13 +5,13 @@ namespace PixiEditor.Models.Controllers
 {
     public class ReadonlyToolUtility
     {
+        public BitmapManager Manager { get; set; }
+
         public ReadonlyToolUtility(BitmapManager manager)
         {
             Manager = manager;
         }
 
-        public BitmapManager Manager { get; set; }
-
         public void ExecuteTool(Coordinates[] mouseMove, ReadonlyTool tool)
         {
             tool.Use(mouseMove);

+ 5 - 5
PixiEditor/Models/Controllers/Shortcuts/Shortcut.cs

@@ -4,6 +4,11 @@ namespace PixiEditor.Models.Controllers
 {
     public class Shortcut
     {
+        public Key ShortcutKey { get; set; }
+        public ModifierKeys Modifier { get; set; }
+        public ICommand Command { get; set; }
+        public object CommandParameter { get; set; }
+
         public Shortcut(Key shortcutKey, ICommand command, object commandParameter = null,
             ModifierKeys modifier = ModifierKeys.None)
         {
@@ -13,11 +18,6 @@ namespace PixiEditor.Models.Controllers
             CommandParameter = commandParameter;
         }
 
-        public Key ShortcutKey { get; set; }
-        public ModifierKeys Modifier { get; set; }
-        public ICommand Command { get; set; }
-        public object CommandParameter { get; set; }
-
         public void Execute()
         {
             if (Command.CanExecute(CommandParameter)) Command.Execute(CommandParameter);

+ 4 - 4
PixiEditor/Models/Controllers/Shortcuts/ShortcutController.cs

@@ -6,15 +6,15 @@ namespace PixiEditor.Models.Controllers
 {
     public class ShortcutController
     {
+        public static bool BlockShortcutExecution { get; set; }
+
+        public List<Shortcut> Shortcuts { get; set; }
+
         public ShortcutController()
         {
             Shortcuts = new List<Shortcut>();
         }
 
-        public static bool BlockShortcutExecution { get; set; }
-
-        public List<Shortcut> Shortcuts { get; set; }
-
         public void KeyPressed(Key key)
         {
             if (!BlockShortcutExecution)

+ 10 - 11
PixiEditor/Models/DataHolders/Change.cs

@@ -5,6 +5,16 @@ namespace PixiEditor.Models.DataHolders
     [Serializable]
     public class Change
     {
+        public object OldValue { get; set; }
+
+        public object NewValue { get; set; }
+
+        public string Description { get; set; }
+
+        public string Property { get; set; }
+
+        public Action<object[]> ReverseProcess { get; set; }
+        public Action<object[]> Process { get; set; }
         public object[] ProcessArguments;
         public object[] ReverseProcessArguments;
 
@@ -41,16 +51,5 @@ namespace PixiEditor.Models.DataHolders
         public Change()
         {
         }
-
-        public object OldValue { get; set; }
-
-        public object NewValue { get; set; }
-
-        public string Description { get; set; }
-
-        public string Property { get; set; }
-
-        public Action<object[]> ReverseProcess { get; set; }
-        public Action<object[]> Process { get; set; }
     }
 }

+ 60 - 22
PixiEditor/Models/DataHolders/Document.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Linq;
 using System.Windows.Media;
@@ -8,24 +9,13 @@ using PixiEditor.Models.Controllers;
 using PixiEditor.Models.Enums;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
+using PixiEditor.Models.Tools.Tools;
+using PixiEditor.ViewModels;
 
 namespace PixiEditor.Models.DataHolders
 {
     public class Document : NotifyableObject
     {
-        private int _activeLayerIndex;
-        private int _height;
-
-        private ObservableCollection<Layer> _layers = new ObservableCollection<Layer>();
-
-        private int _width;
-
-        public Document(int width, int height)
-        {
-            Width = width;
-            Height = height;
-        }
-
         public int Width
         {
             get => _width;
@@ -69,6 +59,19 @@ namespace PixiEditor.Models.DataHolders
         }
 
         public ObservableCollection<Color> Swatches { get; set; } = new ObservableCollection<Color>();
+        private int _activeLayerIndex;
+        private int _height;
+
+        private ObservableCollection<Layer> _layers = new ObservableCollection<Layer>();
+
+        private int _width;
+
+        public Document(int width, int height)
+        {
+            Width = width;
+            Height = height;
+        }
+
         public event EventHandler<DocumentSizeChangedEventArgs> DocumentSizeChanged;
 
 
@@ -235,10 +238,7 @@ namespace PixiEditor.Models.DataHolders
             Height = newHeight;
         }
 
-        /// <summary>
-        ///     Resizes canvas, so it fits exactly the size of drawn content, without any transparent pixels outside.
-        /// </summary>
-        public void ClipCanvas()
+        private DoubleCords GetEdgePoints()
         {
             Coordinates[] smallestPixels = CoordinatesCalculator.GetSmallestPixels(this);
             Coordinates[] biggestPixels = CoordinatesCalculator.GetBiggestPixels(this);
@@ -247,6 +247,19 @@ namespace PixiEditor.Models.DataHolders
             int smallestY = smallestPixels.Min(x => x.Y);
             int biggestX = biggestPixels.Max(x => x.X);
             int biggestY = biggestPixels.Max(x => x.Y);
+            return new DoubleCords(new Coordinates(smallestX, smallestY), new Coordinates(biggestX, biggestY));
+        }
+
+        /// <summary>
+        ///     Resizes canvas, so it fits exactly the size of drawn content, without any transparent pixels outside.
+        /// </summary>
+        public void ClipCanvas()
+        {
+            var points = GetEdgePoints();
+            int smallestX = points.Coords1.X;
+            int smallestY = points.Coords1.Y;
+            int biggestX = points.Coords2.X;
+            int biggestY = points.Coords2.Y;
 
             if (smallestX == 0 && smallestY == 0 && biggestX == 0 && biggestY == 0)
                 return;
@@ -255,10 +268,40 @@ namespace PixiEditor.Models.DataHolders
             int height = biggestY - smallestY + 1;
             Crop(smallestX, smallestY, width, height);
         }
+
+        public void CenterContent()
+        {
+            var points = GetEdgePoints();
+
+            int smallestX = points.Coords1.X;
+            int smallestY = points.Coords1.Y;
+            int biggestX = points.Coords2.X;
+            int biggestY = points.Coords2.Y;
+
+            if (smallestX == 0 && smallestY == 0 && biggestX == 0 && biggestY == 0)
+                return;
+
+            var contentCenter = CoordinatesCalculator.GetCenterPoint(points.Coords1, points.Coords2);
+            var documentCenter = CoordinatesCalculator.GetCenterPoint(new Coordinates(0, 0),
+                new Coordinates(Width - 1, Height - 1));
+            MoveTool move = new MoveTool
+            {
+                MoveAll = true,
+                RequiresPreviewLayer = false
+            };
+            ViewModelMain.Current.BitmapManager.BitmapOperations.ExecuteTool(documentCenter,
+                new List<Coordinates>(new[] {contentCenter, documentCenter}), move);
+            ViewModelMain.Current.TriggerNewUndoChange(move);
+        }
     }
 
     public class DocumentSizeChangedEventArgs
     {
+        public int OldWidth { get; set; }
+        public int OldHeight { get; set; }
+        public int NewWidth { get; set; }
+        public int NewHeight { get; set; }
+
         public DocumentSizeChangedEventArgs(int oldWidth, int oldHeight, int newWidth, int newHeight)
         {
             OldWidth = oldWidth;
@@ -266,10 +309,5 @@ namespace PixiEditor.Models.DataHolders
             NewWidth = newWidth;
             NewHeight = newHeight;
         }
-
-        public int OldWidth { get; set; }
-        public int OldHeight { get; set; }
-        public int NewWidth { get; set; }
-        public int NewHeight { get; set; }
     }
 }

+ 3 - 3
PixiEditor/Models/DataHolders/LayerChanges.cs

@@ -6,6 +6,9 @@ namespace PixiEditor.Models.DataHolders
 {
     public class LayerChange
     {
+        public BitmapPixelChanges PixelChanges { get; set; }
+        public int LayerIndex { get; set; }
+
         public LayerChange(BitmapPixelChanges pixelChanges, int layerIndex)
         {
             PixelChanges = pixelChanges;
@@ -17,8 +20,5 @@ namespace PixiEditor.Models.DataHolders
             PixelChanges = pixelChanges;
             LayerIndex = ViewModelMain.Current.BitmapManager.ActiveDocument.Layers.IndexOf(layer);
         }
-
-        public BitmapPixelChanges PixelChanges { get; set; }
-        public int LayerIndex { get; set; }
     }
 }

+ 17 - 17
PixiEditor/Models/DataHolders/NotifyableColor.cs

@@ -6,23 +6,6 @@ namespace PixiEditor.Models.DataHolders
 {
     public class NotifyableColor : NotifyableObject
     {
-        private byte _a;
-
-        private byte _b;
-
-
-        private byte _g;
-
-        private byte _r;
-
-        public NotifyableColor(Color color)
-        {
-            A = color.A;
-            R = color.R;
-            G = color.G;
-            B = color.B;
-        }
-
         public byte A
         {
             get => _a;
@@ -67,6 +50,23 @@ namespace PixiEditor.Models.DataHolders
             }
         }
 
+        private byte _a;
+
+        private byte _b;
+
+
+        private byte _g;
+
+        private byte _r;
+
+        public NotifyableColor(Color color)
+        {
+            A = color.A;
+            R = color.R;
+            G = color.G;
+            B = color.B;
+        }
+
         public event EventHandler ColorChanged;
 
         public void SetArgb(byte a, byte r, byte g, byte b)

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

@@ -12,17 +12,6 @@ namespace PixiEditor.Models.DataHolders
 {
     public class Selection : NotifyableObject
     {
-        private readonly Color _selectionBlue;
-        private Layer _selectionLayer;
-
-        public Selection(Coordinates[] selectedPoints)
-        {
-            SelectedPoints = new ObservableCollection<Coordinates>(selectedPoints);
-            SelectionLayer = new Layer("_selectionLayer", ViewModelMain.Current.BitmapManager.ActiveDocument.Width,
-                ViewModelMain.Current.BitmapManager.ActiveDocument.Height);
-            _selectionBlue = Color.FromArgb(127, 142, 202, 255);
-        }
-
         public ObservableCollection<Coordinates> SelectedPoints { get; private set; }
 
         public Layer SelectionLayer
@@ -35,6 +24,17 @@ namespace PixiEditor.Models.DataHolders
             }
         }
 
+        private readonly Color _selectionBlue;
+        private Layer _selectionLayer;
+
+        public Selection(Coordinates[] selectedPoints)
+        {
+            SelectedPoints = new ObservableCollection<Coordinates>(selectedPoints);
+            SelectionLayer = new Layer("_selectionLayer", ViewModelMain.Current.BitmapManager.ActiveDocument.Width,
+                ViewModelMain.Current.BitmapManager.ActiveDocument.Height);
+            _selectionBlue = Color.FromArgb(127, 142, 202, 255);
+        }
+
         public void SetSelection(Coordinates[] selection, SelectionType mode)
         {
             Color _selectionColor = _selectionBlue;

+ 5 - 5
PixiEditor/Models/DataHolders/SerializableDocument.cs

@@ -10,6 +10,11 @@ namespace PixiEditor.Models.DataHolders
     [Serializable]
     public class SerializableDocument
     {
+        public int Width { get; set; }
+        public int Height { get; set; }
+        public SerializableLayer[] Layers { get; set; }
+        public Tuple<byte, byte, byte, byte>[] Swatches { get; set; }
+
         public SerializableDocument(Document document)
         {
             Width = document.Width;
@@ -18,11 +23,6 @@ namespace PixiEditor.Models.DataHolders
             Swatches = document.Swatches.Select(x => new Tuple<byte, byte, byte, byte>(x.A, x.R, x.G, x.B)).ToArray();
         }
 
-        public int Width { get; set; }
-        public int Height { get; set; }
-        public SerializableLayer[] Layers { get; set; }
-        public Tuple<byte, byte, byte, byte>[] Swatches { get; set; }
-
         public Document ToDocument()
         {
             Document document = new Document(Width, Height)

+ 1 - 2
PixiEditor/Models/DataHolders/StackEx.cs

@@ -4,11 +4,10 @@ namespace PixiEditor.Models.DataHolders
 {
     public class StackEx<T>
     {
-        private readonly List<T> items = new List<T>();
-
         public int Count => items.Count;
 
         public T First => items[0];
+        private readonly List<T> items = new List<T>();
 
         public void Clear()
         {

+ 6 - 8
PixiEditor/Models/DataHolders/Tuple.cs

@@ -4,6 +4,12 @@ namespace PixiEditor.Models.DataHolders
 {
     public class Tuple<T1, T2, T3> : IEquatable<object>
     {
+        public T1 Item1 { get; set; }
+
+        public T2 Item2 { get; set; }
+
+        public T3 Item3 { get; set; }
+
         public Tuple(T1 Item1, T2 Item2, T3 Item3)
         {
             this.Item1 = Item1;
@@ -11,18 +17,10 @@ namespace PixiEditor.Models.DataHolders
             this.Item3 = Item3;
         }
 
-        public T1 Item1 { get; set; }
-
-        public T2 Item2 { get; set; }
-
-        public T3 Item3 { get; set; }
-
         public override bool Equals(object obj)
         {
             if (obj == null || obj as Tuple<T1, T2, T3> == null) //if the object is null or the cast fails
-            {
                 return false;
-            }
 
             Tuple<T1, T2, T3> tuple = (Tuple<T1, T2, T3>) obj;
             return Item1.Equals(tuple.Item1) && Item2.Equals(tuple.Item2) && Item3.Equals(tuple.Item3);

+ 13 - 13
PixiEditor/Models/Dialogs/ExportFileDialog.cs

@@ -5,19 +5,6 @@ namespace PixiEditor.Models.Dialogs
 {
     public class ExportFileDialog : CustomDialog
     {
-        private int _fileHeight;
-
-
-        private string _filePath;
-
-        private int _fileWidth;
-
-        public ExportFileDialog(Size fileDimensions)
-        {
-            FileHeight = (int) fileDimensions.Height;
-            FileWidth = (int) fileDimensions.Width;
-        }
-
         public int FileWidth
         {
             get => _fileWidth;
@@ -57,6 +44,19 @@ namespace PixiEditor.Models.Dialogs
             }
         }
 
+        private int _fileHeight;
+
+
+        private string _filePath;
+
+        private int _fileWidth;
+
+        public ExportFileDialog(Size fileDimensions)
+        {
+            FileHeight = (int) fileDimensions.Height;
+            FileWidth = (int) fileDimensions.Width;
+        }
+
         public override bool ShowDialog()
         {
             SaveFilePopup popup = new SaveFilePopup

+ 6 - 6
PixiEditor/Models/Dialogs/ImportFileDialog.cs

@@ -4,12 +4,6 @@ namespace PixiEditor.Models.Dialogs
 {
     internal class ImportFileDialog : CustomDialog
     {
-        private int _fileHeight;
-
-
-        private string _filePath;
-        private int _fileWidth;
-
         public int FileWidth
         {
             get => _fileWidth;
@@ -49,6 +43,12 @@ namespace PixiEditor.Models.Dialogs
             }
         }
 
+        private int _fileHeight;
+
+
+        private string _filePath;
+        private int _fileWidth;
+
         public override bool ShowDialog()
         {
             ImportFilePopup popup = new ImportFilePopup();

+ 4 - 4
PixiEditor/Models/Dialogs/NewFileDialog.cs

@@ -5,10 +5,6 @@ namespace PixiEditor.Models.Dialogs
 {
     public class NewFileDialog : CustomDialog
     {
-        private int _height;
-
-        private int _width;
-
         public int Width
         {
             get => _width;
@@ -35,6 +31,10 @@ namespace PixiEditor.Models.Dialogs
             }
         }
 
+        private int _height;
+
+        private int _width;
+
         public override bool ShowDialog()
         {
             Window popup = new NewFilePopup();

+ 10 - 10
PixiEditor/Models/Dialogs/ResizeDocumentDialog.cs

@@ -5,16 +5,6 @@ namespace PixiEditor.Models.Dialogs
 {
     public class ResizeDocumentDialog : CustomDialog
     {
-        private int _height;
-        private int _width;
-
-        public ResizeDocumentDialog(int currentWidth, int currentHeight, bool openResizeCanvas = false)
-        {
-            Width = currentWidth;
-            Height = currentHeight;
-            OpenResizeCanvas = openResizeCanvas;
-        }
-
         public bool OpenResizeCanvas { get; set; }
         public AnchorPoint ResizeAnchor { get; set; }
 
@@ -44,6 +34,16 @@ namespace PixiEditor.Models.Dialogs
             }
         }
 
+        private int _height;
+        private int _width;
+
+        public ResizeDocumentDialog(int currentWidth, int currentHeight, bool openResizeCanvas = false)
+        {
+            Width = currentWidth;
+            Height = currentHeight;
+            OpenResizeCanvas = openResizeCanvas;
+        }
+
         public override bool ShowDialog()
         {
             return OpenResizeCanvas ? ShowResizeCanvasDialog() : ShowResizeDocumentCanvas();

+ 2 - 2
PixiEditor/Models/Events/DocumentChangedEventArgs.cs

@@ -4,11 +4,11 @@ namespace PixiEditor.Models.Events
 {
     public class DocumentChangedEventArgs
     {
+        public Document NewDocument { get; set; }
+
         public DocumentChangedEventArgs(Document newDocument)
         {
             NewDocument = newDocument;
         }
-
-        public Document NewDocument { get; set; }
     }
 }

+ 4 - 4
PixiEditor/Models/Layers/BasicLayer.cs

@@ -6,10 +6,6 @@ namespace PixiEditor.Models.Layers
     [Serializable]
     public class BasicLayer : NotifyableObject
     {
-        private int _height;
-
-        private int _width;
-
         public int Width
         {
             get => _width;
@@ -29,5 +25,9 @@ namespace PixiEditor.Models.Layers
                 RaisePropertyChanged("Height");
             }
         }
+
+        private int _height;
+
+        private int _width;
     }
 }

+ 27 - 29
PixiEditor/Models/Layers/Layer.cs

@@ -6,31 +6,6 @@ namespace PixiEditor.Models.Layers
 {
     public class Layer : BasicLayer
     {
-        private bool _isActive;
-
-        private bool _isRenaming;
-        private bool _isVisible = true;
-        private WriteableBitmap _layerBitmap;
-
-        private string _name;
-
-        public Layer(string name, int width, int height)
-        {
-            Name = name;
-            Layer layer = LayerGenerator.Generate(width, height);
-            LayerBitmap = layer.LayerBitmap;
-            Width = width;
-            Height = height;
-        }
-
-
-        public Layer(WriteableBitmap layerBitmap)
-        {
-            LayerBitmap = layerBitmap;
-            Width = (int) layerBitmap.Width;
-            Height = (int) layerBitmap.Height;
-        }
-
         public string Name
         {
             get => _name;
@@ -82,6 +57,31 @@ namespace PixiEditor.Models.Layers
             }
         }
 
+        private bool _isActive;
+
+        private bool _isRenaming;
+        private bool _isVisible = true;
+        private WriteableBitmap _layerBitmap;
+
+        private string _name;
+
+        public Layer(string name, int width, int height)
+        {
+            Name = name;
+            Layer layer = LayerGenerator.Generate(width, height);
+            LayerBitmap = layer.LayerBitmap;
+            Width = width;
+            Height = height;
+        }
+
+
+        public Layer(WriteableBitmap layerBitmap)
+        {
+            LayerBitmap = layerBitmap;
+            Width = (int) layerBitmap.Width;
+            Height = (int) layerBitmap.Height;
+        }
+
         /// <summary>
         ///     Applies pixels to layer
         /// </summary>
@@ -89,13 +89,13 @@ namespace PixiEditor.Models.Layers
         public void ApplyPixels(BitmapPixelChanges pixels)
         {
             if (pixels.ChangedPixels == null) return;
-            using (LayerBitmap.GetBitmapContext())
+            using (var ctx = LayerBitmap.GetBitmapContext())
             {
                 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),
+                    ctx.WriteableBitmap.SetPixel(Math.Clamp(coords.Key.X, 0, Width - 1),
                         Math.Clamp(coords.Key.Y, 0, Height - 1),
                         coords.Value);
                 }
@@ -104,9 +104,7 @@ namespace PixiEditor.Models.Layers
 
         public void Clear()
         {
-            LayerBitmap.Lock();
             LayerBitmap.Clear();
-            LayerBitmap.Unlock();
         }
 
         public byte[] ConvertBitmapToBytes()

+ 6 - 6
PixiEditor/Models/Layers/SerializableLayer.cs

@@ -6,6 +6,12 @@ namespace PixiEditor.Models.DataHolders
     [Serializable]
     public class SerializableLayer
     {
+        public string Name { get; set; }
+        public int Width { get; set; }
+        public int Height { get; set; }
+        public byte[] BitmapBytes { get; set; }
+        public bool IsVisible { get; set; }
+
         public SerializableLayer(Layer layer)
         {
             Name = layer.Name;
@@ -14,11 +20,5 @@ namespace PixiEditor.Models.DataHolders
             BitmapBytes = layer.ConvertBitmapToBytes();
             IsVisible = layer.IsVisible;
         }
-
-        public string Name { get; set; }
-        public int Width { get; set; }
-        public int Height { get; set; }
-        public byte[] BitmapBytes { get; set; }
-        public bool IsVisible { get; set; }
     }
 }

+ 8 - 15
PixiEditor/Models/Position/CoordinatesCalculator.cs

@@ -79,35 +79,28 @@ namespace PixiEditor.Models.Position
             return new Coordinates(FindMaxXNonTransparent(bitmap), FindMaxYNonTransparent(bitmap));
         }
 
+
         public static int FindMinYNonTransparent(WriteableBitmap bitmap)
         {
             Color transparent = Color.FromArgb(0, 0, 0, 0);
-            bitmap.Lock();
-            for (int y = 0; y < bitmap.Height; y++)
-            for (int x = 0; x < bitmap.Width; x++)
-                if (bitmap.GetPixel(x, y) != transparent)
-                {
-                    bitmap.Unlock();
+            using var ctx = bitmap.GetBitmapContext(ReadWriteMode.ReadOnly);
+            for (int y = 0; y < ctx.Height; y++)
+            for (int x = 0; x < ctx.Width; x++)
+                if (ctx.WriteableBitmap.GetPixel(x, y) != transparent)
                     return y;
-                }
 
-            bitmap.Unlock();
             return -1;
         }
 
         public static int FindMinXNonTransparent(WriteableBitmap bitmap)
         {
             Color transparent = Color.FromArgb(0, 0, 0, 0);
-            bitmap.Lock();
-            for (int x = 0; x < bitmap.Width; x++)
-            for (int y = 0; y < bitmap.Height; y++)
+            using var ctx = bitmap.GetBitmapContext(ReadWriteMode.ReadOnly);
+            for (int x = 0; x < ctx.Width; x++)
+            for (int y = 0; y < ctx.Height; y++)
                 if (bitmap.GetPixel(x, y) != transparent)
-                {
-                    bitmap.Unlock();
                     return x;
-                }
 
-            bitmap.Unlock();
             return -1;
         }
 

+ 2 - 2
PixiEditor/Models/Tools/ShapeTool.cs

@@ -11,6 +11,8 @@ namespace PixiEditor.Models.Tools
 {
     public abstract class ShapeTool : BitmapOperationTool
     {
+        public abstract override ToolType ToolType { get; }
+
         public ShapeTool()
         {
             RequiresPreviewLayer = true;
@@ -18,8 +20,6 @@ namespace PixiEditor.Models.Tools
             Toolbar = new BasicShapeToolbar();
         }
 
-        public abstract override ToolType ToolType { get; }
-
         public abstract override LayerChange[] Use(Layer layer, Coordinates[] coordinates, Color color);
 
         protected Coordinates[] GetThickShape(Coordinates[] shape, int thickness)

+ 1 - 1
PixiEditor/Models/Tools/Tool.cs

@@ -6,7 +6,6 @@ namespace PixiEditor.Models.Tools
 {
     public abstract class Tool : NotifyableObject
     {
-        private bool _isActive;
         public abstract ToolType ToolType { get; }
         public string ImagePath => $"/Images/{ToolType}Image.png";
         public bool HideHighlight { get; set; } = false;
@@ -24,6 +23,7 @@ namespace PixiEditor.Models.Tools
 
         public Cursor Cursor { get; set; } = Cursors.Arrow;
         public Toolbar Toolbar { get; set; } = new EmptyToolbar();
+        private bool _isActive;
 
         public virtual void OnMouseDown()
         {

+ 2 - 2
PixiEditor/Models/Tools/ToolSettings/Settings/DropdownSetting.cs

@@ -7,6 +7,8 @@ namespace PixiEditor.Models.Tools.ToolSettings.Settings
 {
     public class DropdownSetting : Setting
     {
+        public string[] Values { get; set; }
+
         public DropdownSetting(string name, string[] values, string label) : base(name)
         {
             Values = values;
@@ -15,8 +17,6 @@ namespace PixiEditor.Models.Tools.ToolSettings.Settings
             Label = label;
         }
 
-        public string[] Values { get; set; }
-
 
         private ComboBox GenerateDropdown()
         {

+ 3 - 3
PixiEditor/Models/Tools/ToolSettings/Settings/FloatSetting.cs

@@ -5,6 +5,9 @@ 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)
         {
@@ -15,9 +18,6 @@ namespace PixiEditor.Models.Tools.ToolSettings.Settings
             SettingControl = GenerateNumberInput();
         }
 
-        public float Min { get; set; }
-        public float Max { get; set; }
-
         private NumberInput GenerateNumberInput()
         {
             NumberInput numbrInput = new NumberInput

+ 6 - 7
PixiEditor/Models/Tools/ToolSettings/Settings/Setting.cs

@@ -5,13 +5,6 @@ namespace PixiEditor.Models.Tools.ToolSettings
 {
     public abstract class Setting : NotifyableObject
     {
-        private object value;
-
-        public Setting(string name)
-        {
-            Name = name;
-        }
-
         public string Name { get; protected set; }
         public string Label { get; set; }
         public bool HasLabel => !string.IsNullOrEmpty(Label);
@@ -27,5 +20,11 @@ namespace PixiEditor.Models.Tools.ToolSettings
         }
 
         public Control SettingControl { get; set; }
+        private object value;
+
+        public Setting(string name)
+        {
+            Name = name;
+        }
     }
 }

+ 2 - 2
PixiEditor/Models/Tools/Tools/BrightnessTool.cs

@@ -14,14 +14,14 @@ namespace PixiEditor.Models.Tools.Tools
     {
         private const float CorrectionFactor = 5f; //Initial correction factor
 
+        public override ToolType ToolType => ToolType.Brightness;
+
         public BrightnessTool()
         {
             Tooltip = "Makes pixel brighter or darker pixel (U)";
             Toolbar = new BrightnessToolToolbar(CorrectionFactor);
         }
 
-        public override ToolType ToolType => ToolType.Brightness;
-
         public override LayerChange[] Use(Layer layer, Coordinates[] coordinates, Color color)
         {
             int toolSize = (int) Toolbar.GetSetting("ToolSize").Value;

+ 2 - 2
PixiEditor/Models/Tools/Tools/CircleTool.cs

@@ -10,13 +10,13 @@ namespace PixiEditor.Models.Tools.Tools
 {
     public class CircleTool : ShapeTool
     {
+        public override ToolType ToolType => ToolType.Circle;
+
         public CircleTool()
         {
             Tooltip = "Draws circle on cavnas (C)";
         }
 
-        public override ToolType ToolType => ToolType.Circle;
-
         public override LayerChange[] Use(Layer layer, Coordinates[] coordinates, Color color)
         {
             int thickness = (int) Toolbar.GetSetting("ToolSize").Value;

+ 2 - 2
PixiEditor/Models/Tools/Tools/ColorPickerTool.cs

@@ -7,14 +7,14 @@ namespace PixiEditor.Models.Tools.Tools
 {
     public class ColorPickerTool : ReadonlyTool
     {
+        public override ToolType ToolType => ToolType.ColorPicker;
+
         public ColorPickerTool()
         {
             HideHighlight = true;
             Tooltip = "Swaps primary color with selected on canvas. (O)";
         }
 
-        public override ToolType ToolType => ToolType.ColorPicker;
-
         public override void Use(Coordinates[] coordinates)
         {
             ViewModelMain.Current.PrimaryColor = GetColorUnderMouse();

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

@@ -8,14 +8,14 @@ namespace PixiEditor.Models.Tools.Tools
 {
     public class EarserTool : BitmapOperationTool
     {
+        public override ToolType ToolType => ToolType.Earser;
+
         public EarserTool()
         {
             Tooltip = "Earsers color from pixel (E)";
             Toolbar = new BasicToolbar();
         }
 
-        public override ToolType ToolType => ToolType.Earser;
-
         public override LayerChange[] Use(Layer layer, Coordinates[] coordinates, Color color)
         {
             return Earse(layer, coordinates, (int) Toolbar.GetSetting("ToolSize").Value);

+ 2 - 2
PixiEditor/Models/Tools/Tools/FloodFill.cs

@@ -10,13 +10,13 @@ namespace PixiEditor.Models.Tools.Tools
 {
     public class FloodFill : BitmapOperationTool
     {
+        public override ToolType ToolType => ToolType.Bucket;
+
         public FloodFill()
         {
             Tooltip = "Fills area with color (G)";
         }
 
-        public override ToolType ToolType => ToolType.Bucket;
-
         public override LayerChange[] Use(Layer layer, Coordinates[] coordinates, Color color)
         {
             return new[] {new LayerChange(ForestFire(layer, coordinates[0], color), layer)};

+ 2 - 2
PixiEditor/Models/Tools/Tools/LineTool.cs

@@ -9,14 +9,14 @@ namespace PixiEditor.Models.Tools.Tools
 {
     public class LineTool : ShapeTool
     {
+        public override ToolType ToolType => ToolType.Line;
+
         public LineTool()
         {
             Tooltip = "Draws line on canvas (L)";
             Toolbar = new BasicToolbar();
         }
 
-        public override ToolType ToolType => ToolType.Line;
-
         public override LayerChange[] Use(Layer layer, Coordinates[] coordinates, Color color)
         {
             var pixels =

+ 6 - 5
PixiEditor/Models/Tools/Tools/MoveTool.cs

@@ -16,6 +16,9 @@ namespace PixiEditor.Models.Tools.Tools
 {
     public class MoveTool : BitmapOperationTool
     {
+        public bool MoveAll { get; set; } = false;
+
+        public override ToolType ToolType => ToolType.Move;
         private Layer[] _affectedLayers;
         private Dictionary<Layer, bool> _clearedPixels = new Dictionary<Layer, bool>();
         private BitmapPixelChanges _clearedPixelsChange;
@@ -35,8 +38,6 @@ namespace PixiEditor.Models.Tools.Tools
             UseDefaultUndoMethod = true;
         }
 
-        public override ToolType ToolType => ToolType.Move;
-
         public override void AfterAddedUndo()
         {
             //Inject to default undo system change custom changes made by this tool
@@ -46,10 +47,10 @@ namespace PixiEditor.Models.Tools.Tools
                 Change changes = UndoManager.UndoStack.Peek();
                 int layerIndex = ViewModelMain.Current.BitmapManager.ActiveDocument.Layers.IndexOf(item.Key);
 
-                (changes.OldValue as LayerChange[])[layerIndex].PixelChanges.ChangedPixels
+                ((LayerChange[]) changes.OldValue)[layerIndex].PixelChanges.ChangedPixels
                     .AddRangeOverride(beforeMovePixels.ChangedPixels);
 
-                (changes.NewValue as LayerChange[])[layerIndex].PixelChanges.ChangedPixels
+                ((LayerChange[]) changes.NewValue)[layerIndex].PixelChanges.ChangedPixels
                     .AddRangeOverride(_clearedPixelsChange.ChangedPixels);
             }
         }
@@ -73,7 +74,7 @@ namespace PixiEditor.Models.Tools.Tools
                     _currentSelection = ViewModelMain.Current.ActiveSelection.SelectedPoints.ToArray();
                 }
 
-                if (Keyboard.IsKeyDown(Key.LeftCtrl))
+                if (Keyboard.IsKeyDown(Key.LeftCtrl) || MoveAll)
                     _affectedLayers = ViewModelMain.Current.BitmapManager.ActiveDocument.Layers.Where(x => x.IsVisible)
                         .ToArray();
                 else

+ 1 - 2
PixiEditor/Models/Tools/Tools/PenTool.cs

@@ -9,6 +9,7 @@ namespace PixiEditor.Models.Tools.Tools
 {
     public class PenTool : BitmapOperationTool
     {
+        public override ToolType ToolType => ToolType.Pen;
         private readonly int _toolSizeIndex;
 
         public PenTool()
@@ -19,8 +20,6 @@ namespace PixiEditor.Models.Tools.Tools
             _toolSizeIndex = Toolbar.Settings.IndexOf(Toolbar.GetSetting("ToolSize"));
         }
 
-        public override ToolType ToolType => ToolType.Pen;
-
         public override LayerChange[] Use(Layer layer, Coordinates[] coordinates, Color color)
         {
             var pixels = Draw(coordinates[0], color, (int) Toolbar.Settings[_toolSizeIndex].Value);

+ 3 - 3
PixiEditor/Models/Tools/Tools/RectangleTool.cs

@@ -11,14 +11,14 @@ namespace PixiEditor.Models.Tools.Tools
 {
     public class RectangleTool : ShapeTool
     {
+        public override ToolType ToolType => ToolType.Rectangle;
+        public bool Filled { get; set; } = false;
+
         public RectangleTool()
         {
             Tooltip = "Draws rectanlge on cavnas (R)";
         }
 
-        public override ToolType ToolType => ToolType.Rectangle;
-        public bool Filled { get; set; } = false;
-
         public override LayerChange[] Use(Layer layer, Coordinates[] coordinates, Color color)
         {
             int thickness = (int) Toolbar.GetSetting("ToolSize").Value;

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

@@ -14,6 +14,7 @@ namespace PixiEditor.Models.Tools.Tools
 {
     public class SelectTool : ReadonlyTool
     {
+        public override ToolType ToolType => ToolType.Select;
         private Selection _oldSelection;
         public SelectionType SelectionType = SelectionType.Add;
 
@@ -23,8 +24,6 @@ namespace PixiEditor.Models.Tools.Tools
             Toolbar = new SelectToolToolbar();
         }
 
-        public override ToolType ToolType => ToolType.Select;
-
         public override void OnMouseDown()
         {
             Enum.TryParse((Toolbar.GetSetting("Mode").Value as ComboBoxItem).Content as string, out SelectionType);

+ 8 - 0
PixiEditor/PixiEditor.csproj

@@ -15,6 +15,14 @@
     <ApplicationIcon>..\icon.ico</ApplicationIcon>
   </PropertyGroup>
 
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+
   <ItemGroup>
     <None Remove="Images\AnchorDot.png" />
     <None Remove="Images\ColorCircle.png" />

+ 18 - 4
PixiEditor/ViewModels/ViewModelMain.cs

@@ -83,6 +83,7 @@ namespace PixiEditor.ViewModels
             SaveDocumentCommand = new RelayCommand(SaveDocument, DocumentIsNotNull);
             OnStartupCommand = new RelayCommand(OnStartup);
             CloseWindowCommand = new RelayCommand(CloseWindow);
+            CenterContentCommand = new RelayCommand(CenterContent, DocumentIsNotNull);
             ToolSet = new ObservableCollection<Tool>
             {
                 new MoveTool(), new PenTool(), new SelectTool(), new FloodFill(), new LineTool(),
@@ -164,6 +165,7 @@ namespace PixiEditor.ViewModels
         public RelayCommand SaveDocumentCommand { get; set; }
         public RelayCommand OnStartupCommand { get; set; }
         public RelayCommand CloseWindowCommand { get; set; }
+        public RelayCommand CenterContentCommand { get; set; }
 
         public double MouseXOnCanvas //Mouse X coordinate relative to canvas
         {
@@ -276,6 +278,13 @@ namespace PixiEditor.ViewModels
 
         public ClipboardController ClipboardController { get; set; }
 
+
+
+        private void CenterContent(object property)
+        {
+            BitmapManager.ActiveDocument.CenterContent();
+        }
+
         private void CloseWindow(object property)
         {
             if (!(property is CancelEventArgs)) throw new ArgumentException();
@@ -449,7 +458,7 @@ namespace PixiEditor.ViewModels
 
         public void Deselect(object parameter)
         {
-            if (ActiveSelection != null) ActiveSelection.Clear();
+            ActiveSelection?.Clear();
         }
 
         private bool SelectionIsNotEmpty(object property)
@@ -475,8 +484,13 @@ namespace PixiEditor.ViewModels
 
         private void MouseController_StoppedRecordingChanges(object sender, EventArgs e)
         {
-            if (BitmapManager.IsOperationTool(BitmapManager.SelectedTool)
-                && (BitmapManager.SelectedTool as BitmapOperationTool).UseDefaultUndoMethod)
+           TriggerNewUndoChange(BitmapManager.SelectedTool);
+        }
+
+        public void TriggerNewUndoChange(Tool toolUsed)
+        {
+            if (BitmapManager.IsOperationTool(toolUsed)
+                && ((BitmapOperationTool) toolUsed).UseDefaultUndoMethod)
             {
                 Tuple<LayerChange, LayerChange>[] changes = ChangesController.PopChanges();
                 if (changes != null && changes.Length > 0)
@@ -484,7 +498,7 @@ namespace PixiEditor.ViewModels
                     LayerChange[] newValues = changes.Select(x => x.Item1).ToArray();
                     LayerChange[] oldValues = changes.Select(x => x.Item2).ToArray();
                     UndoManager.AddUndoChange(new Change("UndoChanges", oldValues, newValues));
-                    BitmapManager.SelectedTool.AfterAddedUndo();
+                    toolUsed.AfterAddedUndo();
                 }
             }
         }

+ 2 - 0
PixiEditor/Views/MainWindow.xaml

@@ -100,6 +100,8 @@
                     <MenuItem Header="Resize Canvas..." Command="{Binding OpenResizePopupCommand}"
                               CommandParameter="canvas" InputGestureText="Ctrl+Shift+C" />
                     <MenuItem Header="Clip Canvas" Command="{Binding ClipCanvasCommand}" />
+                    <Separator/>
+                    <MenuItem Header="Center Content" Command="{Binding CenterContentCommand}" />
                 </MenuItem>
             </Menu>
             <StackPanel DockPanel.Dock="Right" VerticalAlignment="Top" Orientation="Horizontal"