BitmapManager.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. using PixiEditor.Helpers;
  2. using PixiEditor.Models.DataHolders;
  3. using PixiEditor.Models.Events;
  4. using PixiEditor.Models.Layers;
  5. using PixiEditor.Models.Position;
  6. using PixiEditor.Models.Tools;
  7. using PixiEditor.Models.Tools.Tools;
  8. using PixiEditor.Models.Tools.ToolSettings.Settings;
  9. using PixiEditor.ViewModels;
  10. using PixiEditor.ViewModels.SubViewModels.Main;
  11. using SkiaSharp;
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Collections.ObjectModel;
  15. using System.Diagnostics;
  16. using System.Linq;
  17. using System.Windows;
  18. using System.Windows.Input;
  19. namespace PixiEditor.Models.Controllers
  20. {
  21. [DebuggerDisplay("{Documents.Count} Document(s)")]
  22. public class BitmapManager : NotifyableObject
  23. {
  24. private readonly ToolsViewModel _tools;
  25. private int previewLayerSize;
  26. private Document activeDocument;
  27. private Coordinates? startPosition = null;
  28. private int halfSize;
  29. private SKColor _highlightColor;
  30. private PenTool _highlightPen;
  31. private bool hideReferenceLayer;
  32. private bool onlyReferenceLayer;
  33. public BitmapManager(ToolsViewModel tools)
  34. {
  35. _tools = tools;
  36. MouseController = new MouseMovementController();
  37. MouseController.StartedRecordingChanges += MouseController_StartedRecordingChanges;
  38. MouseController.MousePositionChanged += Controller_MousePositionChanged;
  39. MouseController.StoppedRecordingChanges += MouseController_StoppedRecordingChanges;
  40. MouseController.OnMouseDown += MouseController_OnMouseDown;
  41. MouseController.OnMouseUp += MouseController_OnMouseUp;
  42. MouseController.OnMouseDownCoordinates += MouseController_OnMouseDownCoordinates;
  43. BitmapOperations = new BitmapOperationsUtility(this, tools);
  44. ReadonlyToolUtility = new ReadonlyToolUtility();
  45. DocumentChanged += BitmapManager_DocumentChanged;
  46. _highlightPen = new PenTool(this)
  47. {
  48. AutomaticallyResizeCanvas = false
  49. };
  50. _highlightColor = new SKColor(0, 0, 0, 77);
  51. }
  52. public event EventHandler<DocumentChangedEventArgs> DocumentChanged;
  53. public MouseMovementController MouseController { get; set; }
  54. public Layer ActiveLayer => ActiveDocument.ActiveLayer;
  55. public SKColor PrimaryColor { get; set; }
  56. public BitmapOperationsUtility BitmapOperations { get; set; }
  57. public ReadonlyToolUtility ReadonlyToolUtility { get; set; }
  58. #nullable enable
  59. public Document ActiveDocument
  60. {
  61. get => activeDocument;
  62. set
  63. {
  64. activeDocument?.UpdatePreviewImage();
  65. Document? oldDoc = activeDocument;
  66. activeDocument = value;
  67. RaisePropertyChanged(nameof(ActiveDocument));
  68. DocumentChanged?.Invoke(this, new DocumentChangedEventArgs(value, oldDoc));
  69. }
  70. }
  71. #nullable disable
  72. public ObservableCollection<Document> Documents { get; set; } = new ObservableCollection<Document>();
  73. public bool HideReferenceLayer
  74. {
  75. get => hideReferenceLayer;
  76. set => SetProperty(ref hideReferenceLayer, value);
  77. }
  78. public bool OnlyReferenceLayer
  79. {
  80. get => onlyReferenceLayer;
  81. set => SetProperty(ref onlyReferenceLayer, value);
  82. }
  83. public void CloseDocument(Document document)
  84. {
  85. int nextIndex = 0;
  86. if (document == ActiveDocument)
  87. {
  88. nextIndex = Documents.Count > 1 ? Documents.IndexOf(document) : -1;
  89. nextIndex += nextIndex > 0 ? -1 : 0;
  90. }
  91. Documents.Remove(document);
  92. ActiveDocument = nextIndex >= 0 ? Documents[nextIndex] : null;
  93. document.Dispose();
  94. }
  95. public void ExecuteTool(Coordinates newPosition, bool clickedOnCanvas)
  96. {
  97. Tool activeTool = _tools.ActiveTool;
  98. if (activeTool.CanStartOutsideCanvas && !clickedOnCanvas)
  99. {
  100. return;
  101. }
  102. if (startPosition == null)
  103. {
  104. activeTool.OnStart(newPosition);
  105. startPosition = newPosition;
  106. }
  107. if (activeTool is BitmapOperationTool operationTool)
  108. {
  109. BitmapOperations.ExecuteTool(newPosition, MouseController.LastMouseMoveCoordinates, operationTool);
  110. }
  111. else if (activeTool is ReadonlyTool readonlyTool)
  112. {
  113. ReadonlyToolUtility.ExecuteTool(
  114. MouseController.LastMouseMoveCoordinates,
  115. readonlyTool);
  116. }
  117. else
  118. {
  119. throw new InvalidOperationException($"'{activeTool.GetType().Name}' is either not a Tool or can't inherit '{nameof(Tool)}' directly.\nChanges the base type to either '{nameof(BitmapOperationTool)}' or '{nameof(ReadonlyTool)}'");
  120. }
  121. }
  122. public void HighlightPixels(Coordinates newPosition)
  123. {
  124. if (ActiveDocument == null || ActiveDocument.Layers.Count == 0 || _tools.ActiveTool.HideHighlight)
  125. {
  126. return;
  127. }
  128. var previewLayer = ActiveDocument.PreviewLayer;
  129. if (_tools.ToolSize != previewLayerSize || previewLayer.IsReset)
  130. {
  131. previewLayerSize = _tools.ToolSize;
  132. halfSize = (int)Math.Floor(_tools.ToolSize / 2f);
  133. previewLayer.CreateNewBitmap(_tools.ToolSize, _tools.ToolSize);
  134. Coordinates cords = new Coordinates(halfSize, halfSize);
  135. previewLayer.Offset = new Thickness(0, 0, 0, 0);
  136. _highlightPen.Draw(previewLayer, cords, cords, _highlightColor, _tools.ToolSize);
  137. AdjustOffset(newPosition, previewLayer);
  138. }
  139. previewLayer.InvokeLayerBitmapChange();
  140. AdjustOffset(newPosition, previewLayer);
  141. if (newPosition.X > ActiveDocument.Width
  142. || newPosition.Y > ActiveDocument.Height
  143. || newPosition.X < 0 || newPosition.Y < 0)
  144. {
  145. previewLayer.Reset();
  146. previewLayerSize = -1;
  147. }
  148. }
  149. private void BitmapManager_DocumentChanged(object sender, DocumentChangedEventArgs e)
  150. {
  151. e.NewDocument?.GeneratePreviewLayer();
  152. }
  153. private void Controller_MousePositionChanged(object sender, MouseMovementEventArgs e)
  154. {
  155. Tool activeTool = _tools.ActiveTool;
  156. if (activeTool == null)
  157. {
  158. return;
  159. }
  160. activeTool.OnMouseMove(new MouseEventArgs(Mouse.PrimaryDevice, (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds()));
  161. if (!MaybeExecuteTool(e.NewPosition) && Mouse.LeftButton == MouseButtonState.Released)
  162. {
  163. HighlightPixels(e.NewPosition);
  164. }
  165. }
  166. private void MouseController_OnMouseDown(object sender, MouseEventArgs e)
  167. {
  168. _tools.ActiveTool.OnMouseDown(e);
  169. }
  170. private void MouseController_OnMouseUp(object sender, MouseEventArgs e)
  171. {
  172. _tools.ActiveTool.OnMouseUp(e);
  173. }
  174. private void MouseController_OnMouseDownCoordinates(object sender, MouseMovementEventArgs e)
  175. {
  176. MaybeExecuteTool(e.NewPosition);
  177. }
  178. private bool MaybeExecuteTool(Coordinates newPosition)
  179. {
  180. if (Mouse.LeftButton == MouseButtonState.Pressed && !IsDraggingViewport() && ActiveDocument != null)
  181. {
  182. ExecuteTool(newPosition, MouseController.ClickedOnCanvas);
  183. return true;
  184. }
  185. return false;
  186. }
  187. private bool IsDraggingViewport()
  188. {
  189. return _tools.ActiveTool is MoveViewportTool;
  190. }
  191. private void MouseController_StartedRecordingChanges(object sender, EventArgs e)
  192. {
  193. _tools.ActiveTool.OnRecordingLeftMouseDown(new MouseEventArgs(Mouse.PrimaryDevice, (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds()));
  194. if (ActiveDocument != null)
  195. {
  196. ActiveDocument.PreviewLayer.Reset();
  197. }
  198. }
  199. private void MouseController_StoppedRecordingChanges(object sender, EventArgs e)
  200. {
  201. Tool selectedTool = _tools.ActiveTool;
  202. selectedTool.OnStoppedRecordingMouseUp(new MouseEventArgs(Mouse.PrimaryDevice, (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds()));
  203. if (selectedTool is BitmapOperationTool operationTool && operationTool.RequiresPreviewLayer)
  204. {
  205. BitmapOperations.ApplyPreviewLayer();
  206. }
  207. HighlightPixels(MousePositionConverter.CurrentCoordinates);
  208. startPosition = null;
  209. }
  210. private void AdjustOffset(Coordinates newPosition, Layer previewLayer)
  211. {
  212. Coordinates start = newPosition - halfSize;
  213. previewLayer.Offset = new Thickness(start.X, start.Y, 0, 0);
  214. }
  215. }
  216. }