ViewModelMain.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. using PixiEditor.Helpers;
  2. using PixiEditor.Models.Controllers;
  3. using PixiEditor.Models.DataHolders;
  4. using PixiEditor.Models.Dialogs;
  5. using PixiEditor.Models.Enums;
  6. using PixiEditor.Models.Images;
  7. using PixiEditor.Models.IO;
  8. using PixiEditor.Models.Layers;
  9. using PixiEditor.Models.Position;
  10. using PixiEditor.Models.Tools;
  11. using PixiEditor.Models.Tools.Tools;
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Collections.ObjectModel;
  15. using System.Linq;
  16. using System.Windows;
  17. using System.Windows.Input;
  18. using System.Windows.Media;
  19. using System.Windows.Media.Imaging;
  20. namespace PixiEditor.ViewModels
  21. {
  22. class ViewModelMain : ViewModelBase
  23. {
  24. public static ViewModelMain Current { get; set; } = null;
  25. public RelayCommand SelectToolCommand { get; set; } //Command that handles tool switching
  26. public RelayCommand GenerateDrawAreaCommand { get; set; } //Command that generates draw area
  27. public RelayCommand MouseMoveCommand { get; set; } //Command that is used to draw
  28. public RelayCommand MouseDownCommand { get; set; }
  29. public RelayCommand KeyDownCommand { get; set; }
  30. public RelayCommand SaveFileCommand { get; set; } //Command that is used to save file
  31. public RelayCommand UndoCommand { get; set; }
  32. public RelayCommand RedoCommand { get; set; }
  33. public RelayCommand MouseUpCommand { get; set; }
  34. public RelayCommand RecenterZoomboxCommand { get; set; }
  35. public RelayCommand OpenFileCommand { get; set; }
  36. public RelayCommand SetActiveLayerCommand { get; set; }
  37. public RelayCommand NewLayerCommand { get; set; }
  38. public RelayCommand ReloadImageCommand { get; set; }
  39. public RelayCommand DeleteLayerCommand { get; set; }
  40. public RelayCommand RenameLayerCommand { get; set; }
  41. public RelayCommand MoveToBackCommand { get; set; }
  42. public RelayCommand MoveToFrontCommand { get; set; }
  43. public RelayCommand SwapColorsCommand { get; set; }
  44. public RelayCommand DeselectCommand { get; set; }
  45. public RelayCommand SelectAllCommand { get; set; }
  46. public RelayCommand CopyCommand { get; set; }
  47. public RelayCommand DuplicateCommand { get; set; }
  48. public RelayCommand CutCommand { get; set; }
  49. public RelayCommand PasteCommand { get; set; }
  50. public RelayCommand ClipCanvasCommand { get; set; }
  51. public RelayCommand DeletePixelsCommand { get; set; }
  52. private double _mouseXonCanvas;
  53. public double MouseXOnCanvas //Mouse X coordinate relative to canvas
  54. {
  55. get => _mouseXonCanvas;
  56. set { _mouseXonCanvas = value; RaisePropertyChanged("MouseXonCanvas"); }
  57. }
  58. private double _mouseYonCanvas;
  59. public double MouseYOnCanvas //Mouse Y coordinate relative to canvas
  60. {
  61. get => _mouseYonCanvas;
  62. set { _mouseYonCanvas = value; RaisePropertyChanged("MouseYonCanvas"); }
  63. }
  64. private Color _primaryColor = Colors.Black;
  65. public Color PrimaryColor //Primary color, hooked with left mouse button
  66. {
  67. get => _primaryColor;
  68. set
  69. {
  70. if (_primaryColor != value)
  71. {
  72. _primaryColor = value;
  73. BitmapManager.PrimaryColor = value;
  74. RaisePropertyChanged("PrimaryColor");
  75. }
  76. }
  77. }
  78. private Color _secondaryColor = Colors.White;
  79. public Color SecondaryColor
  80. {
  81. get => _secondaryColor;
  82. set { if (_secondaryColor != value) { _secondaryColor = value; RaisePropertyChanged("SecondaryColor"); } }
  83. }
  84. private ToolType _selectedTool;
  85. public ToolType SelectedTool
  86. {
  87. get { return _selectedTool; }
  88. set
  89. {
  90. if (_selectedTool != value)
  91. {
  92. _selectedTool = value;
  93. SetActiveTool(value);
  94. RaisePropertyChanged("SelectedTool");
  95. }
  96. }
  97. }
  98. public ObservableCollection<Tool> ToolSet { get; set; }
  99. private LayerChange[] _undoChanges;
  100. public LayerChange[] UndoChanges
  101. {
  102. get { return _undoChanges; }
  103. set
  104. {
  105. _undoChanges = value;
  106. for (int i = 0; i < value.Length; i++)
  107. {
  108. BitmapManager.ActiveDocument.Layers[value[i].LayerIndex].ApplyPixels(value[i].PixelChanges);
  109. }
  110. }
  111. }
  112. private Cursor _toolCursor;
  113. public Cursor ToolCursor
  114. {
  115. get { return _toolCursor; }
  116. set
  117. {
  118. _toolCursor = value;
  119. RaisePropertyChanged("ToolCursor");
  120. }
  121. }
  122. public BitmapManager BitmapManager { get; set; }
  123. public PixelChangesController ChangesController { get; set; }
  124. public ShortcutController ShortcutController { get; set; }
  125. private Selection _selection = null;
  126. public Selection ActiveSelection
  127. {
  128. get => _selection;
  129. set
  130. {
  131. _selection = value;
  132. RaisePropertyChanged("ActiveSelection");
  133. }
  134. }
  135. public ClipboardController ClipboardController { get; set; }
  136. public ViewModelMain()
  137. {
  138. FilesManager.InitializeTempDirectories();
  139. BitmapManager = new BitmapManager();
  140. BitmapManager.BitmapOperations.BitmapChanged += BitmapUtility_BitmapChanged;
  141. BitmapManager.MouseController.StoppedRecordingChanges += MouseController_StoppedRecordingChanges;
  142. ChangesController = new PixelChangesController();
  143. SelectToolCommand = new RelayCommand(SetTool, DocumentIsNotNull);
  144. GenerateDrawAreaCommand = new RelayCommand(GenerateDrawArea);
  145. MouseMoveCommand = new RelayCommand(MouseMove);
  146. MouseDownCommand = new RelayCommand(MouseDown);
  147. SaveFileCommand = new RelayCommand(SaveFile, CanSave);
  148. UndoCommand = new RelayCommand(Undo, CanUndo);
  149. RedoCommand = new RelayCommand(Redo, CanRedo);
  150. MouseUpCommand = new RelayCommand(MouseUp);
  151. RecenterZoomboxCommand = new RelayCommand(RecenterZoombox);
  152. OpenFileCommand = new RelayCommand(OpenFile);
  153. SetActiveLayerCommand = new RelayCommand(SetActiveLayer);
  154. NewLayerCommand = new RelayCommand(NewLayer, CanCreateNewLayer);
  155. DeleteLayerCommand = new RelayCommand(DeleteLayer, CanDeleteLayer);
  156. MoveToBackCommand = new RelayCommand(MoveLayerToBack, CanMoveToBack);
  157. MoveToFrontCommand = new RelayCommand(MoveLayerToFront, CanMoveToFront);
  158. SwapColorsCommand = new RelayCommand(SwapColors);
  159. KeyDownCommand = new RelayCommand(KeyDown);
  160. RenameLayerCommand = new RelayCommand(RenameLayer);
  161. DeselectCommand = new RelayCommand(Deselect, SelectionIsNotEmpty);
  162. SelectAllCommand = new RelayCommand(SelectAll, CanSelectAll);
  163. CopyCommand = new RelayCommand(Copy, SelectionIsNotEmpty);
  164. DuplicateCommand = new RelayCommand(Duplicate, SelectionIsNotEmpty);
  165. CutCommand = new RelayCommand(Cut, SelectionIsNotEmpty);
  166. PasteCommand = new RelayCommand(Paste, CanPaste);
  167. ClipCanvasCommand = new RelayCommand(ClipCanvas, DocumentIsNotNull);
  168. DeletePixelsCommand = new RelayCommand(DeletePixels, SelectionIsNotEmpty);
  169. ToolSet = new ObservableCollection<Tool> {new MoveTool(), new PenTool(), new SelectTool(), new FloodFill(), new LineTool(),
  170. new CircleTool(), new RectangleTool(), new EarserTool(), new ColorPickerTool(), new BrightnessTool()};
  171. ShortcutController = new ShortcutController
  172. {
  173. Shortcuts = new List<Shortcut> {
  174. new Shortcut(Key.B, SelectToolCommand, ToolType.Pen),
  175. new Shortcut(Key.X, SwapColorsCommand),
  176. new Shortcut(Key.O, OpenFileCommand, modifier: ModifierKeys.Control),
  177. new Shortcut(Key.E, SelectToolCommand, ToolType.Earser),
  178. new Shortcut(Key.O, SelectToolCommand, ToolType.ColorPicker),
  179. new Shortcut(Key.R, SelectToolCommand, ToolType.Rectangle),
  180. new Shortcut(Key.C, SelectToolCommand, ToolType.Circle),
  181. new Shortcut(Key.L, SelectToolCommand, ToolType.Line),
  182. new Shortcut(Key.G, SelectToolCommand, ToolType.Bucket),
  183. new Shortcut(Key.U, SelectToolCommand, ToolType.Brightness),
  184. new Shortcut(Key.V, SelectToolCommand, ToolType.Move),
  185. new Shortcut(Key.M, SelectToolCommand, ToolType.Select),
  186. new Shortcut(Key.Y, RedoCommand, modifier: ModifierKeys.Control),
  187. new Shortcut(Key.Z, UndoCommand),
  188. new Shortcut(Key.S, SaveFileCommand, modifier: ModifierKeys.Control),
  189. new Shortcut(Key.N, GenerateDrawAreaCommand, modifier: ModifierKeys.Control),
  190. new Shortcut(Key.S, SaveFileCommand, "AsNew", ModifierKeys.Control | ModifierKeys.Shift),
  191. new Shortcut(Key.D, DeselectCommand, modifier: ModifierKeys.Control),
  192. new Shortcut(Key.A, SelectAllCommand, modifier: ModifierKeys.Control),
  193. new Shortcut(Key.C, CopyCommand, modifier: ModifierKeys.Control),
  194. new Shortcut(Key.V, PasteCommand, modifier: ModifierKeys.Control),
  195. new Shortcut(Key.J, DuplicateCommand, modifier: ModifierKeys.Control),
  196. new Shortcut(Key.X, CutCommand, modifier: ModifierKeys.Control),
  197. new Shortcut(Key.Delete, DeletePixelsCommand),
  198. }
  199. };
  200. UndoManager.SetMainRoot(this);
  201. ClipboardController = new ClipboardController();
  202. SetActiveTool(ToolType.Move);
  203. BitmapManager.PrimaryColor = PrimaryColor;
  204. Current = this;
  205. }
  206. private void DeletePixels(object parameter)
  207. {
  208. BitmapManager.BitmapOperations.DeletePixels(new Layer[] { BitmapManager.ActiveLayer },
  209. ActiveSelection.SelectedPoints.ToArray());
  210. }
  211. public void ClipCanvas(object parameter)
  212. {
  213. if(BitmapManager.ActiveDocument != null)
  214. BitmapManager.ActiveDocument.ClipCanvas();
  215. }
  216. public void Duplicate(object parameter)
  217. {
  218. Copy(null);
  219. Paste(null);
  220. }
  221. public void Cut(object parameter)
  222. {
  223. Copy(null);
  224. BitmapManager.ActiveLayer.
  225. ApplyPixels(BitmapPixelChanges.FromSingleColoredArray(ActiveSelection.SelectedPoints.ToArray(), Colors.Transparent));
  226. }
  227. public void Paste(object parameter)
  228. {
  229. ClipboardController.PasteFromClipboard();
  230. }
  231. private bool CanPaste(object property)
  232. {
  233. return DocumentIsNotNull(null) && ClipboardController.IsImageInClipboard();
  234. }
  235. private void Copy(object parameter)
  236. {
  237. ClipboardController.CopyToClipboard(BitmapManager.ActiveDocument.Layers.ToArray(),
  238. ActiveSelection.SelectedPoints.ToArray());
  239. }
  240. public void SelectAll(object parameter)
  241. {
  242. SelectTool select = new SelectTool();
  243. select.Use(select.GetAllSelection());
  244. }
  245. private bool CanSelectAll(object property)
  246. {
  247. return BitmapManager.ActiveDocument != null && BitmapManager.ActiveDocument.Layers.Count > 0;
  248. }
  249. private bool DocumentIsNotNull(object property)
  250. {
  251. return BitmapManager.ActiveDocument != null;
  252. }
  253. public void Deselect(object parameter)
  254. {
  255. ActiveSelection.Clear();
  256. }
  257. private bool SelectionIsNotEmpty(object property)
  258. {
  259. return ActiveSelection != null && ActiveSelection.SelectedPoints != null;
  260. }
  261. public void SetTool(object parameter)
  262. {
  263. SetActiveTool((ToolType)parameter);
  264. }
  265. public void RenameLayer(object parameter)
  266. {
  267. BitmapManager.ActiveDocument.Layers[(int)parameter].IsRenaming = true;
  268. }
  269. public void KeyDown(object parameter)
  270. {
  271. ShortcutController.KeyPressed(((KeyEventArgs)parameter).Key);
  272. }
  273. private void MouseController_StoppedRecordingChanges(object sender, EventArgs e)
  274. {
  275. if (BitmapManager.IsOperationTool(BitmapManager.SelectedTool)
  276. && (BitmapManager.SelectedTool as BitmapOperationTool).UseDefaultUndoMethod)
  277. {
  278. Tuple<LayerChange, LayerChange>[] changes = ChangesController.PopChanges();
  279. if (changes != null && changes.Length > 0)
  280. {
  281. LayerChange[] newValues = changes.Select(x => x.Item1).ToArray();
  282. LayerChange[] oldValues = changes.Select(x => x.Item2).ToArray();
  283. UndoManager.AddUndoChange(new Change("UndoChanges", oldValues, newValues));
  284. BitmapManager.SelectedTool.AfterAddedUndo();
  285. }
  286. }
  287. }
  288. private void BitmapUtility_BitmapChanged(object sender, BitmapChangedEventArgs e)
  289. {
  290. ChangesController.AddChanges(new LayerChange(e.PixelsChanged, e.ChangedLayerIndex),
  291. new LayerChange(e.OldPixelsValues, e.ChangedLayerIndex));
  292. }
  293. public void SwapColors(object parameter)
  294. {
  295. var tmp = PrimaryColor;
  296. PrimaryColor = SecondaryColor;
  297. SecondaryColor = tmp;
  298. }
  299. public void MoveLayerToFront(object parameter)
  300. {
  301. int oldIndex = (int)parameter;
  302. BitmapManager.ActiveDocument.Layers.Move(oldIndex, oldIndex + 1);
  303. if (BitmapManager.ActiveDocument.ActiveLayerIndex == oldIndex)
  304. {
  305. BitmapManager.SetActiveLayer(oldIndex + 1);
  306. }
  307. }
  308. public void MoveLayerToBack(object parameter)
  309. {
  310. int oldIndex = (int)parameter;
  311. BitmapManager.ActiveDocument.Layers.Move(oldIndex, oldIndex - 1);
  312. if (BitmapManager.ActiveDocument.ActiveLayerIndex == oldIndex)
  313. {
  314. BitmapManager.SetActiveLayer(oldIndex - 1);
  315. }
  316. }
  317. public bool CanMoveToFront(object property)
  318. {
  319. return DocumentIsNotNull(null) && BitmapManager.ActiveDocument.Layers.Count - 1 > (int)property;
  320. }
  321. public bool CanMoveToBack(object property)
  322. {
  323. return (int)property > 0;
  324. }
  325. public void SetActiveLayer(object parameter)
  326. {
  327. BitmapManager.SetActiveLayer((int)parameter);
  328. }
  329. public void DeleteLayer(object parameter)
  330. {
  331. BitmapManager.RemoveLayer((int)parameter);
  332. }
  333. public bool CanDeleteLayer(object property)
  334. {
  335. return BitmapManager.ActiveDocument != null && BitmapManager.ActiveDocument.Layers.Count > 1;
  336. }
  337. #region Undo/Redo
  338. /// <summary>
  339. /// Undo last action
  340. /// </summary>
  341. /// <param name="parameter"></param>
  342. public void Undo(object parameter)
  343. {
  344. Deselect(null);
  345. UndoManager.Undo();
  346. }
  347. /// <summary>
  348. /// Returns true if undo can be done.
  349. /// </summary>
  350. /// <param name="property"></param>
  351. /// <returns></returns>
  352. private bool CanUndo(object property)
  353. {
  354. return UndoManager.CanUndo;
  355. }
  356. /// <summary>
  357. /// Redo last action
  358. /// </summary>
  359. /// <param name="parameter"></param>
  360. public void Redo(object parameter)
  361. {
  362. UndoManager.Redo();
  363. }
  364. /// <summary>
  365. /// Returns true if redo can be done.
  366. /// </summary>
  367. /// <param name="property"></param>
  368. /// <returns></returns>
  369. private bool CanRedo(object property)
  370. {
  371. return UndoManager.CanRedo;
  372. }
  373. #endregion
  374. private void SetActiveTool(ToolType tool)
  375. {
  376. Tool foundTool = ToolSet.First(x => x.ToolType == tool);
  377. Tool activeTool = ToolSet.FirstOrDefault(x => x.IsActive);
  378. if (activeTool != null)
  379. {
  380. activeTool.IsActive = false;
  381. }
  382. foundTool.IsActive = true;
  383. BitmapManager.SetActiveTool(foundTool);
  384. SetToolCursor(tool);
  385. }
  386. private void SetToolCursor(ToolType tool)
  387. {
  388. if (tool != ToolType.None)
  389. {
  390. ToolCursor = BitmapManager.SelectedTool.Cursor;
  391. }
  392. else
  393. {
  394. ToolCursor = Cursors.Arrow;
  395. }
  396. }
  397. /// <summary>
  398. /// When mouse is up stops recording changes.
  399. /// </summary>
  400. /// <param name="parameter"></param>
  401. private void MouseUp(object parameter)
  402. {
  403. BitmapManager.MouseController.StopRecordingMouseMovementChanges();
  404. }
  405. private void MouseDown(object parameter)
  406. {
  407. if (BitmapManager.ActiveDocument.Layers.Count == 0) return;
  408. if (Mouse.LeftButton == MouseButtonState.Pressed)
  409. {
  410. if (!BitmapManager.MouseController.IsRecordingChanges)
  411. {
  412. BitmapManager.MouseController.StartRecordingMouseMovementChanges();
  413. BitmapManager.MouseController.RecordMouseMovementChange(MousePositionConverter.CurrentCoordinates);
  414. }
  415. }
  416. }
  417. /// <summary>
  418. /// Method connected with command, it executes tool "activity"
  419. /// </summary>
  420. /// <param name="parameter"></param>
  421. private void MouseMove(object parameter)
  422. {
  423. Coordinates cords = new Coordinates((int)MouseXOnCanvas, (int)MouseYOnCanvas);
  424. MousePositionConverter.CurrentCoordinates = cords;
  425. if (BitmapManager.MouseController.IsRecordingChanges && Mouse.LeftButton == MouseButtonState.Pressed)
  426. {
  427. BitmapManager.MouseController.RecordMouseMovementChange(cords);
  428. }
  429. else
  430. {
  431. BitmapManager.MouseController.MouseMoved(cords);
  432. }
  433. }
  434. /// <summary>
  435. /// Generates new Layer and sets it as active one
  436. /// </summary>
  437. /// <param name="parameter"></param>
  438. public void GenerateDrawArea(object parameter)
  439. {
  440. NewFileDialog newFile = new NewFileDialog();
  441. if (newFile.ShowDialog())
  442. {
  443. NewDocument(newFile.Width, newFile.Height);
  444. }
  445. }
  446. #region SaveFile
  447. /// <summary>
  448. /// Generates export dialog or saves directly if save data is known.
  449. /// </summary>
  450. /// <param name="parameter"></param>
  451. private void SaveFile(object parameter)
  452. {
  453. WriteableBitmap bitmap = BitmapManager.GetCombinedLayersBitmap();
  454. if (Exporter.SavePath == null || (string)parameter == "AsNew")
  455. {
  456. Exporter.Export(FileType.PNG, bitmap, new Size(bitmap.PixelWidth, bitmap.PixelHeight));
  457. }
  458. else
  459. {
  460. Exporter.ExportWithoutDialog(FileType.PNG, bitmap);
  461. }
  462. }
  463. /// <summary>
  464. /// Returns true if file save is possible.
  465. /// </summary>
  466. /// <param name="property"></param>
  467. /// <returns></returns>
  468. private bool CanSave(object property)
  469. {
  470. return BitmapManager.ActiveDocument != null;
  471. }
  472. #endregion
  473. /// <summary>
  474. /// Opens file from path.
  475. /// </summary>
  476. /// <param name="parameter"></param>
  477. public void OpenFile(object parameter)
  478. {
  479. ImportFileDialog dialog = new ImportFileDialog();
  480. if (dialog.ShowDialog())
  481. {
  482. NewDocument(dialog.FileWidth, dialog.FileHeight);
  483. BitmapManager.ActiveDocument.ActiveLayer.LayerBitmap = Importer.ImportImage(dialog.FilePath, dialog.FileWidth, dialog.FileHeight);
  484. }
  485. }
  486. private void NewDocument(int width, int height)
  487. {
  488. BitmapManager.ActiveDocument = new Models.DataHolders.Document(width, height);
  489. BitmapManager.AddNewLayer("Base Layer", width, height, true);
  490. BitmapManager.PreviewLayer = null;
  491. UndoManager.UndoStack.Clear();
  492. UndoManager.RedoStack.Clear();
  493. ActiveSelection = new Selection(Array.Empty<Coordinates>());
  494. }
  495. /// <summary>
  496. /// For now, shows not implemented info, lol.
  497. /// </summary>
  498. /// <param name="parameter"></param>
  499. public void RecenterZoombox(object parameter)
  500. {
  501. MessageBox.Show("This feature is not implemented yet.", "Feature not implemented", MessageBoxButton.OK, MessageBoxImage.Information);
  502. }
  503. public void NewLayer(object parameter)
  504. {
  505. BitmapManager.AddNewLayer($"New Layer {BitmapManager.ActiveDocument.Layers.Count}", BitmapManager.ActiveDocument.Width, BitmapManager.ActiveDocument.Height);
  506. }
  507. public bool CanCreateNewLayer(object parameter)
  508. {
  509. return BitmapManager.ActiveDocument != null && BitmapManager.ActiveDocument.Layers.Count > 0;
  510. }
  511. }
  512. }