ViewModelMain.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.ComponentModel;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Reflection;
  9. using System.Threading.Tasks;
  10. using System.Windows;
  11. using System.Windows.Input;
  12. using System.Windows.Media;
  13. using System.Windows.Media.Imaging;
  14. using Microsoft.Win32;
  15. using PixiEditor.Helpers;
  16. using PixiEditor.Models.Controllers;
  17. using PixiEditor.Models.Controllers.Shortcuts;
  18. using PixiEditor.Models.DataHolders;
  19. using PixiEditor.Models.Dialogs;
  20. using PixiEditor.Models.Enums;
  21. using PixiEditor.Models.Events;
  22. using PixiEditor.Models.IO;
  23. using PixiEditor.Models.Position;
  24. using PixiEditor.Models.Tools;
  25. using PixiEditor.Models.Tools.Tools;
  26. using PixiEditor.UpdateModule;
  27. namespace PixiEditor.ViewModels
  28. {
  29. public class ViewModelMain : ViewModelBase
  30. {
  31. private const string ConfirmationDialogMessage = "Document was modified. Do you want to save changes?";
  32. private Color _primaryColor = Colors.Black;
  33. private bool _recenterZoombox;
  34. private Color _secondaryColor = Colors.White;
  35. private Selection _selection;
  36. private Cursor _toolCursor;
  37. private LayerChange[] _undoChanges;
  38. private bool _unsavedDocumentModified;
  39. public Action CloseAction { get; set; }
  40. public static ViewModelMain Current { get; set; }
  41. public RelayCommand SelectToolCommand { get; set; } //Command that handles tool switching
  42. public RelayCommand OpenNewFilePopupCommand { get; set; } //Command that generates draw area
  43. public RelayCommand MouseMoveCommand { get; set; } //Command that is used to draw
  44. public RelayCommand MouseDownCommand { get; set; }
  45. public RelayCommand KeyDownCommand { get; set; }
  46. public RelayCommand KeyUpCommand { get; set; }
  47. public RelayCommand ExportFileCommand { get; set; } //Command that is used to save file
  48. public RelayCommand UndoCommand { get; set; }
  49. public RelayCommand RedoCommand { get; set; }
  50. public RelayCommand MouseUpCommand { get; set; }
  51. public RelayCommand OpenFileCommand { get; set; }
  52. public RelayCommand SetActiveLayerCommand { get; set; }
  53. public RelayCommand NewLayerCommand { get; set; }
  54. public RelayCommand DeleteLayerCommand { get; set; }
  55. public RelayCommand RenameLayerCommand { get; set; }
  56. public RelayCommand MoveToBackCommand { get; set; }
  57. public RelayCommand MoveToFrontCommand { get; set; }
  58. public RelayCommand SwapColorsCommand { get; set; }
  59. public RelayCommand DeselectCommand { get; set; }
  60. public RelayCommand SelectAllCommand { get; set; }
  61. public RelayCommand CopyCommand { get; set; }
  62. public RelayCommand DuplicateCommand { get; set; }
  63. public RelayCommand CutCommand { get; set; }
  64. public RelayCommand PasteCommand { get; set; }
  65. public RelayCommand ClipCanvasCommand { get; set; }
  66. public RelayCommand DeletePixelsCommand { get; set; }
  67. public RelayCommand OpenResizePopupCommand { get; set; }
  68. public RelayCommand SelectColorCommand { get; set; }
  69. public RelayCommand RemoveSwatchCommand { get; set; }
  70. public RelayCommand SaveDocumentCommand { get; set; }
  71. public RelayCommand OnStartupCommand { get; set; }
  72. public RelayCommand CloseWindowCommand { get; set; }
  73. public RelayCommand CenterContentCommand { get; set; }
  74. public RelayCommand OpenHyperlinkCommand { get; set; }
  75. public RelayCommand ZoomCommand { get; set; }
  76. public RelayCommand ChangeToolSizeCommand { get; set; }
  77. private double _mouseXonCanvas;
  78. private double _mouseYonCanvas;
  79. public double MouseXOnCanvas //Mouse X coordinate relative to canvas
  80. {
  81. get => _mouseXonCanvas;
  82. set
  83. {
  84. _mouseXonCanvas = value;
  85. RaisePropertyChanged("MouseXOnCanvas");
  86. }
  87. }
  88. public double MouseYOnCanvas //Mouse Y coordinate relative to canvas
  89. {
  90. get => _mouseYonCanvas;
  91. set
  92. {
  93. _mouseYonCanvas = value;
  94. RaisePropertyChanged("MouseYOnCanvas");
  95. }
  96. }
  97. private string _versionText;
  98. public string VersionText
  99. {
  100. get => _versionText;
  101. set
  102. {
  103. _versionText = value;
  104. RaisePropertyChanged(nameof(VersionText));
  105. }
  106. }
  107. public bool RecenterZoombox
  108. {
  109. get => _recenterZoombox;
  110. set
  111. {
  112. _recenterZoombox = value;
  113. RaisePropertyChanged("RecenterZoombox");
  114. }
  115. }
  116. public Color PrimaryColor //Primary color, hooked with left mouse button
  117. {
  118. get => _primaryColor;
  119. set
  120. {
  121. if (_primaryColor != value)
  122. {
  123. _primaryColor = value;
  124. BitmapManager.PrimaryColor = value;
  125. RaisePropertyChanged("PrimaryColor");
  126. }
  127. }
  128. }
  129. public Color SecondaryColor
  130. {
  131. get => _secondaryColor;
  132. set
  133. {
  134. if (_secondaryColor != value)
  135. {
  136. _secondaryColor = value;
  137. RaisePropertyChanged("SecondaryColor");
  138. }
  139. }
  140. }
  141. public ObservableCollection<Tool> ToolSet { get; set; }
  142. public LayerChange[] UndoChanges //This acts like UndoManager process, but it was implemented before process system, so it can be transformed into it
  143. {
  144. get => _undoChanges;
  145. set
  146. {
  147. _undoChanges = value;
  148. for (int i = 0; i < value.Length; i++)
  149. BitmapManager.ActiveDocument.Layers[value[i].LayerIndex].SetPixels(value[i].PixelChanges);
  150. }
  151. }
  152. public Cursor ToolCursor
  153. {
  154. get => _toolCursor;
  155. set
  156. {
  157. _toolCursor = value;
  158. RaisePropertyChanged("ToolCursor");
  159. }
  160. }
  161. private double _zoomPercentage = 100;
  162. public double ZoomPercentage
  163. {
  164. get { return _zoomPercentage; }
  165. set
  166. {
  167. _zoomPercentage = value;
  168. RaisePropertyChanged(nameof(ZoomPercentage));
  169. }
  170. }
  171. public BitmapManager BitmapManager { get; set; }
  172. public PixelChangesController ChangesController { get; set; }
  173. public ShortcutController ShortcutController { get; set; }
  174. public Selection ActiveSelection
  175. {
  176. get => _selection;
  177. set
  178. {
  179. _selection = value;
  180. RaisePropertyChanged("ActiveSelection");
  181. }
  182. }
  183. private bool _restoreToolOnKeyUp = false;
  184. private Tool _lastActionTool;
  185. public UpdateChecker UpdateChecker { get; set; }
  186. public ViewModelMain()
  187. {
  188. BitmapManager = new BitmapManager();
  189. BitmapManager.BitmapOperations.BitmapChanged += BitmapUtility_BitmapChanged;
  190. BitmapManager.MouseController.StoppedRecordingChanges += MouseController_StoppedRecordingChanges;
  191. BitmapManager.DocumentChanged += BitmapManager_DocumentChanged;
  192. ChangesController = new PixelChangesController();
  193. SelectToolCommand = new RelayCommand(SetTool, DocumentIsNotNull);
  194. OpenNewFilePopupCommand = new RelayCommand(OpenNewFilePopup);
  195. MouseMoveCommand = new RelayCommand(MouseMove);
  196. MouseDownCommand = new RelayCommand(MouseDown);
  197. ExportFileCommand = new RelayCommand(ExportFile, CanSave);
  198. UndoCommand = new RelayCommand(Undo, CanUndo);
  199. RedoCommand = new RelayCommand(Redo, CanRedo);
  200. MouseUpCommand = new RelayCommand(MouseUp);
  201. OpenFileCommand = new RelayCommand(Open);
  202. SetActiveLayerCommand = new RelayCommand(SetActiveLayer);
  203. NewLayerCommand = new RelayCommand(NewLayer, CanCreateNewLayer);
  204. DeleteLayerCommand = new RelayCommand(DeleteLayer, CanDeleteLayer);
  205. MoveToBackCommand = new RelayCommand(MoveLayerToBack, CanMoveToBack);
  206. MoveToFrontCommand = new RelayCommand(MoveLayerToFront, CanMoveToFront);
  207. SwapColorsCommand = new RelayCommand(SwapColors);
  208. KeyDownCommand = new RelayCommand(KeyDown);
  209. KeyUpCommand = new RelayCommand(KeyUp);
  210. RenameLayerCommand = new RelayCommand(RenameLayer);
  211. DeselectCommand = new RelayCommand(Deselect, SelectionIsNotEmpty);
  212. SelectAllCommand = new RelayCommand(SelectAll, CanSelectAll);
  213. CopyCommand = new RelayCommand(Copy, SelectionIsNotEmpty);
  214. DuplicateCommand = new RelayCommand(Duplicate, SelectionIsNotEmpty);
  215. CutCommand = new RelayCommand(Cut, SelectionIsNotEmpty);
  216. PasteCommand = new RelayCommand(Paste, CanPaste);
  217. ClipCanvasCommand = new RelayCommand(ClipCanvas, DocumentIsNotNull);
  218. DeletePixelsCommand = new RelayCommand(DeletePixels, SelectionIsNotEmpty);
  219. OpenResizePopupCommand = new RelayCommand(OpenResizePopup, DocumentIsNotNull);
  220. SelectColorCommand = new RelayCommand(SelectColor);
  221. RemoveSwatchCommand = new RelayCommand(RemoveSwatch);
  222. SaveDocumentCommand = new RelayCommand(SaveDocument, DocumentIsNotNull);
  223. OnStartupCommand = new RelayCommand(OnStartup);
  224. CloseWindowCommand = new RelayCommand(CloseWindow);
  225. CenterContentCommand = new RelayCommand(CenterContent, DocumentIsNotNull);
  226. OpenHyperlinkCommand = new RelayCommand(OpenHyperlink);
  227. ZoomCommand = new RelayCommand(ZoomViewport);
  228. ChangeToolSizeCommand = new RelayCommand(ChangeToolSize);
  229. ToolSet = new ObservableCollection<Tool>
  230. {
  231. new MoveTool(), new PenTool(), new SelectTool(), new FloodFill(), new LineTool(),
  232. new CircleTool(), new RectangleTool(), new EraserTool(), new ColorPickerTool(), new BrightnessTool(),
  233. new ZoomTool()
  234. };
  235. ShortcutController = new ShortcutController
  236. {
  237. Shortcuts = new List<Shortcut>
  238. {
  239. //Tools
  240. new Shortcut(Key.B, SelectToolCommand, ToolType.Pen),
  241. new Shortcut(Key.E, SelectToolCommand, ToolType.Eraser),
  242. new Shortcut(Key.O, SelectToolCommand, ToolType.ColorPicker),
  243. new Shortcut(Key.R, SelectToolCommand, ToolType.Rectangle),
  244. new Shortcut(Key.C, SelectToolCommand, ToolType.Circle),
  245. new Shortcut(Key.L, SelectToolCommand, ToolType.Line),
  246. new Shortcut(Key.G, SelectToolCommand, ToolType.Bucket),
  247. new Shortcut(Key.U, SelectToolCommand, ToolType.Brightness),
  248. new Shortcut(Key.V, SelectToolCommand, ToolType.Move),
  249. new Shortcut(Key.M, SelectToolCommand, ToolType.Select),
  250. new Shortcut(Key.Z, SelectToolCommand, ToolType.Zoom),
  251. new Shortcut(Key.OemPlus, ZoomCommand, 115),
  252. new Shortcut(Key.OemMinus, ZoomCommand, 85),
  253. new Shortcut(Key.OemOpenBrackets, ChangeToolSizeCommand, -1),
  254. new Shortcut(Key.OemCloseBrackets, ChangeToolSizeCommand, 1),
  255. //Editor
  256. new Shortcut(Key.X, SwapColorsCommand),
  257. new Shortcut(Key.Y, RedoCommand, modifier: ModifierKeys.Control),
  258. new Shortcut(Key.Z, UndoCommand, modifier: ModifierKeys.Control),
  259. new Shortcut(Key.D, DeselectCommand, modifier: ModifierKeys.Control),
  260. new Shortcut(Key.A, SelectAllCommand, modifier: ModifierKeys.Control),
  261. new Shortcut(Key.C, CopyCommand, modifier: ModifierKeys.Control),
  262. new Shortcut(Key.V, PasteCommand, modifier: ModifierKeys.Control),
  263. new Shortcut(Key.J, DuplicateCommand, modifier: ModifierKeys.Control),
  264. new Shortcut(Key.X, CutCommand, modifier: ModifierKeys.Control),
  265. new Shortcut(Key.Delete, DeletePixelsCommand),
  266. new Shortcut(Key.I, OpenResizePopupCommand, modifier: ModifierKeys.Control | ModifierKeys.Shift),
  267. new Shortcut(Key.C, OpenResizePopupCommand, "canvas", ModifierKeys.Control | ModifierKeys.Shift),
  268. new Shortcut(Key.F11, SystemCommands.MaximizeWindowCommand),
  269. //File
  270. new Shortcut(Key.O, OpenFileCommand, modifier: ModifierKeys.Control),
  271. new Shortcut(Key.S, ExportFileCommand,
  272. modifier: ModifierKeys.Control | ModifierKeys.Shift | ModifierKeys.Alt),
  273. new Shortcut(Key.S, SaveDocumentCommand, modifier: ModifierKeys.Control),
  274. new Shortcut(Key.S, SaveDocumentCommand, "AsNew", ModifierKeys.Control | ModifierKeys.Shift),
  275. new Shortcut(Key.N, OpenNewFilePopupCommand, modifier: ModifierKeys.Control),
  276. }
  277. };
  278. UndoManager.SetMainRoot(this);
  279. SetActiveTool(ToolType.Move);
  280. BitmapManager.PrimaryColor = PrimaryColor;
  281. ActiveSelection = new Selection(Array.Empty<Coordinates>());
  282. Current = this;
  283. InitUpdateChecker();
  284. }
  285. public async Task<bool> CheckForUpdate()
  286. {
  287. return await Task.Run(async () =>
  288. {
  289. bool updateAvailable = await UpdateChecker.CheckUpdateAvailable();
  290. bool updateFileDoesNotExists = !File.Exists($"update-{UpdateChecker.LatestReleaseInfo.TagName}.zip");
  291. if (updateAvailable && updateFileDoesNotExists)
  292. {
  293. VersionText = "Downloading update...";
  294. await UpdateDownloader.DownloadReleaseZip(UpdateChecker.LatestReleaseInfo);
  295. VersionText = "Restart to install update";
  296. return true;
  297. }
  298. return false;
  299. });
  300. }
  301. private void InitUpdateChecker()
  302. {
  303. var assembly = Assembly.GetExecutingAssembly();
  304. FileVersionInfo info = FileVersionInfo.GetVersionInfo(assembly.Location);
  305. UpdateChecker = new UpdateChecker(info.FileVersion);
  306. VersionText = $"Version {info.FileVersion}";
  307. }
  308. private void ZoomViewport(object parameter)
  309. {
  310. double zoom = (int)parameter;
  311. ZoomPercentage = zoom;
  312. ZoomPercentage = 100;
  313. }
  314. private void ChangeToolSize(object parameter)
  315. {
  316. int increment = (int)parameter;
  317. int newSize = BitmapManager.ToolSize + increment;
  318. if (newSize > 0)
  319. {
  320. BitmapManager.ToolSize = newSize;
  321. }
  322. }
  323. private void OpenHyperlink(object parameter)
  324. {
  325. if (parameter == null) return;
  326. string url = (string) parameter;
  327. var processInfo = new ProcessStartInfo()
  328. {
  329. FileName = url,
  330. UseShellExecute = true
  331. };
  332. Process.Start(processInfo);
  333. }
  334. private void CenterContent(object property)
  335. {
  336. BitmapManager.ActiveDocument.CenterContent();
  337. }
  338. private void CloseWindow(object property)
  339. {
  340. if (!(property is CancelEventArgs)) throw new ArgumentException();
  341. ((CancelEventArgs) property).Cancel = true;
  342. ConfirmationType result = ConfirmationType.No;
  343. if (_unsavedDocumentModified)
  344. {
  345. result = ConfirmationDialog.Show(ConfirmationDialogMessage);
  346. if (result == ConfirmationType.Yes) SaveDocument(null);
  347. }
  348. if (result != ConfirmationType.Canceled) ((CancelEventArgs) property).Cancel = false;
  349. }
  350. private async void OnStartup(object parameter)
  351. {
  352. var lastArg = Environment.GetCommandLineArgs().Last();
  353. if (Importer.IsSupportedFile(lastArg) && File.Exists(lastArg))
  354. {
  355. Open(lastArg);
  356. }
  357. else
  358. {
  359. OpenNewFilePopup(null);
  360. }
  361. await CheckForUpdate();
  362. }
  363. private void BitmapManager_DocumentChanged(object sender, DocumentChangedEventArgs e)
  364. {
  365. e.NewDocument.DocumentSizeChanged += ActiveDocument_DocumentSizeChanged;
  366. }
  367. private void Open(object property)
  368. {
  369. OpenFileDialog dialog = new OpenFileDialog
  370. {
  371. Filter = "All Files|*.*|PixiEditor Files | *.pixi|PNG Files|*.png",
  372. DefaultExt = "pixi"
  373. };
  374. if ((bool) dialog.ShowDialog())
  375. {
  376. if (Importer.IsSupportedFile(dialog.FileName))
  377. Open(dialog.FileName);
  378. RecenterZoombox = !RecenterZoombox;
  379. }
  380. }
  381. private void Open(string path)
  382. {
  383. if (_unsavedDocumentModified)
  384. {
  385. var result = ConfirmationDialog.Show(ConfirmationDialogMessage);
  386. if (result == ConfirmationType.Yes)
  387. {
  388. SaveDocument(null);
  389. }
  390. else if (result == ConfirmationType.Canceled)
  391. {
  392. return;
  393. }
  394. }
  395. ResetProgramStateValues();
  396. if (path.EndsWith(".pixi"))
  397. OpenDocument(path);
  398. else
  399. OpenFile(path);
  400. }
  401. private void OpenDocument(string path)
  402. {
  403. BitmapManager.ActiveDocument = Importer.ImportDocument(path);
  404. Exporter.SaveDocumentPath = path;
  405. _unsavedDocumentModified = false;
  406. }
  407. private void SaveDocument(object parameter)
  408. {
  409. bool paramIsAsNew = parameter != null && parameter.ToString()?.ToLower() == "asnew";
  410. if (paramIsAsNew || Exporter.SaveDocumentPath == null)
  411. Exporter.SaveAsEditableFileWithDialog(BitmapManager.ActiveDocument, !paramIsAsNew);
  412. else
  413. Exporter.SaveAsEditableFile(BitmapManager.ActiveDocument, Exporter.SaveDocumentPath);
  414. _unsavedDocumentModified = false;
  415. }
  416. private void RemoveSwatch(object parameter)
  417. {
  418. if (!(parameter is Color)) throw new ArgumentException();
  419. Color color = (Color) parameter;
  420. if (BitmapManager.ActiveDocument.Swatches.Contains(color))
  421. BitmapManager.ActiveDocument.Swatches.Remove(color);
  422. }
  423. private void SelectColor(object parameter)
  424. {
  425. PrimaryColor = parameter as Color? ?? throw new ArgumentException();
  426. }
  427. private void ActiveDocument_DocumentSizeChanged(object sender, DocumentSizeChangedEventArgs e)
  428. {
  429. ActiveSelection = new Selection(Array.Empty<Coordinates>());
  430. RecenterZoombox = !RecenterZoombox;
  431. _unsavedDocumentModified = true;
  432. }
  433. public void AddSwatch(Color color)
  434. {
  435. if (!BitmapManager.ActiveDocument.Swatches.Contains(color))
  436. BitmapManager.ActiveDocument.Swatches.Add(color);
  437. }
  438. private void OpenResizePopup(object parameter)
  439. {
  440. bool isCanvasDialog = (string) parameter == "canvas";
  441. ResizeDocumentDialog dialog = new ResizeDocumentDialog(BitmapManager.ActiveDocument.Width,
  442. BitmapManager.ActiveDocument.Height, isCanvasDialog);
  443. if (dialog.ShowDialog())
  444. {
  445. if (isCanvasDialog)
  446. BitmapManager.ActiveDocument.ResizeCanvas(dialog.Width, dialog.Height, dialog.ResizeAnchor);
  447. else
  448. BitmapManager.ActiveDocument.Resize(dialog.Width, dialog.Height);
  449. }
  450. }
  451. private void DeletePixels(object parameter)
  452. {
  453. BitmapManager.BitmapOperations.DeletePixels(new[] {BitmapManager.ActiveLayer},
  454. ActiveSelection.SelectedPoints.ToArray());
  455. }
  456. public void ClipCanvas(object parameter)
  457. {
  458. BitmapManager.ActiveDocument?.ClipCanvas();
  459. }
  460. public void Duplicate(object parameter)
  461. {
  462. Copy(null);
  463. Paste(null);
  464. }
  465. public void Cut(object parameter)
  466. {
  467. Copy(null);
  468. BitmapManager.ActiveLayer.SetPixels(
  469. BitmapPixelChanges.FromSingleColoredArray(ActiveSelection.SelectedPoints.ToArray(),
  470. Colors.Transparent));
  471. }
  472. public void Paste(object parameter)
  473. {
  474. ClipboardController.PasteFromClipboard();
  475. }
  476. private bool CanPaste(object property)
  477. {
  478. return DocumentIsNotNull(null) && ClipboardController.IsImageInClipboard();
  479. }
  480. private void Copy(object parameter)
  481. {
  482. ClipboardController.CopyToClipboard(BitmapManager.ActiveDocument.Layers.ToArray(),
  483. ActiveSelection.SelectedPoints.ToArray(), BitmapManager.ActiveDocument.Width, BitmapManager.ActiveDocument.Height);
  484. }
  485. public void SelectAll(object parameter)
  486. {
  487. SelectTool select = new SelectTool();
  488. ActiveSelection.SetSelection(select.GetAllSelection(), SelectionType.New);
  489. }
  490. private bool CanSelectAll(object property)
  491. {
  492. return BitmapManager.ActiveDocument != null && BitmapManager.ActiveDocument.Layers.Count > 0;
  493. }
  494. public bool DocumentIsNotNull(object property)
  495. {
  496. return BitmapManager.ActiveDocument != null;
  497. }
  498. public void Deselect(object parameter)
  499. {
  500. ActiveSelection?.Clear();
  501. }
  502. private bool SelectionIsNotEmpty(object property)
  503. {
  504. return ActiveSelection?.SelectedPoints != null && ActiveSelection.SelectedPoints.Count > 0;
  505. }
  506. public void SetTool(object parameter)
  507. {
  508. SetActiveTool((ToolType) parameter);
  509. }
  510. public void RenameLayer(object parameter)
  511. {
  512. BitmapManager.ActiveDocument.Layers[(int) parameter].IsRenaming = true;
  513. }
  514. private void KeyUp(object parameter)
  515. {
  516. KeyEventArgs args = (KeyEventArgs)parameter;
  517. if (_restoreToolOnKeyUp && ShortcutController.LastShortcut != null && ShortcutController.LastShortcut.ShortcutKey == args.Key)
  518. {
  519. _restoreToolOnKeyUp = false;
  520. SetActiveTool(_lastActionTool);
  521. ShortcutController.BlockShortcutExecution = false;
  522. }
  523. }
  524. public void KeyDown(object parameter)
  525. {
  526. KeyEventArgs args = (KeyEventArgs)parameter;
  527. if (args.IsRepeat && !_restoreToolOnKeyUp && ShortcutController.LastShortcut != null && ShortcutController.LastShortcut.Command == SelectToolCommand)
  528. {
  529. _restoreToolOnKeyUp = true;
  530. ShortcutController.BlockShortcutExecution = true;
  531. }
  532. ShortcutController.KeyPressed(args.Key, Keyboard.Modifiers);
  533. }
  534. private void MouseController_StoppedRecordingChanges(object sender, EventArgs e)
  535. {
  536. TriggerNewUndoChange(BitmapManager.SelectedTool);
  537. }
  538. public void TriggerNewUndoChange(Tool toolUsed)
  539. {
  540. if (BitmapManager.IsOperationTool(toolUsed)
  541. && ((BitmapOperationTool) toolUsed).UseDefaultUndoMethod)
  542. {
  543. Tuple<LayerChange, LayerChange>[] changes = ChangesController.PopChanges();
  544. if (changes != null && changes.Length > 0)
  545. {
  546. LayerChange[] newValues = changes.Select(x => x.Item1).ToArray();
  547. LayerChange[] oldValues = changes.Select(x => x.Item2).ToArray();
  548. UndoManager.AddUndoChange(new Change("UndoChanges", oldValues, newValues));
  549. toolUsed.AfterAddedUndo();
  550. }
  551. }
  552. }
  553. private void BitmapUtility_BitmapChanged(object sender, BitmapChangedEventArgs e)
  554. {
  555. ChangesController.AddChanges(new LayerChange(e.PixelsChanged, e.ChangedLayerIndex),
  556. new LayerChange(e.OldPixelsValues, e.ChangedLayerIndex));
  557. _unsavedDocumentModified = true;
  558. if (BitmapManager.IsOperationTool())
  559. AddSwatch(PrimaryColor);
  560. }
  561. public void SwapColors(object parameter)
  562. {
  563. var tmp = PrimaryColor;
  564. PrimaryColor = SecondaryColor;
  565. SecondaryColor = tmp;
  566. }
  567. public void MoveLayerToFront(object parameter)
  568. {
  569. int oldIndex = (int) parameter;
  570. BitmapManager.ActiveDocument.Layers.Move(oldIndex, oldIndex + 1);
  571. if (BitmapManager.ActiveDocument.ActiveLayerIndex == oldIndex) BitmapManager.SetActiveLayer(oldIndex + 1);
  572. }
  573. public void MoveLayerToBack(object parameter)
  574. {
  575. int oldIndex = (int) parameter;
  576. BitmapManager.ActiveDocument.Layers.Move(oldIndex, oldIndex - 1);
  577. if (BitmapManager.ActiveDocument.ActiveLayerIndex == oldIndex) BitmapManager.SetActiveLayer(oldIndex - 1);
  578. }
  579. public bool CanMoveToFront(object property)
  580. {
  581. return DocumentIsNotNull(null) && BitmapManager.ActiveDocument.Layers.Count - 1 > (int) property;
  582. }
  583. public bool CanMoveToBack(object property)
  584. {
  585. return (int) property > 0;
  586. }
  587. public void SetActiveLayer(object parameter)
  588. {
  589. BitmapManager.SetActiveLayer((int) parameter);
  590. }
  591. public void DeleteLayer(object parameter)
  592. {
  593. BitmapManager.RemoveLayer((int) parameter);
  594. }
  595. public bool CanDeleteLayer(object property)
  596. {
  597. return BitmapManager.ActiveDocument != null && BitmapManager.ActiveDocument.Layers.Count > 1;
  598. }
  599. public void SetActiveTool(ToolType tool)
  600. {
  601. Tool foundTool = ToolSet.First(x => x.ToolType == tool);
  602. SetActiveTool(foundTool);
  603. }
  604. public void SetActiveTool(Tool tool)
  605. {
  606. Tool activeTool = ToolSet.FirstOrDefault(x => x.IsActive);
  607. if (activeTool != null) activeTool.IsActive = false;
  608. tool.IsActive = true;
  609. _lastActionTool = BitmapManager.SelectedTool;
  610. BitmapManager.SetActiveTool(tool);
  611. SetToolCursor(tool.ToolType);
  612. }
  613. private void SetToolCursor(ToolType tool)
  614. {
  615. if (tool != ToolType.None)
  616. ToolCursor = BitmapManager.SelectedTool.Cursor;
  617. else
  618. ToolCursor = Cursors.Arrow;
  619. }
  620. /// <summary>
  621. /// When mouse is up stops recording changes.
  622. /// </summary>
  623. /// <param name="parameter"></param>
  624. private void MouseUp(object parameter)
  625. {
  626. BitmapManager.MouseController.StopRecordingMouseMovementChanges();
  627. }
  628. private void MouseDown(object parameter)
  629. {
  630. if (BitmapManager.ActiveDocument.Layers.Count == 0) return;
  631. if (Mouse.LeftButton == MouseButtonState.Pressed)
  632. {
  633. if (!BitmapManager.MouseController.IsRecordingChanges)
  634. {
  635. bool clickedOnCanvas = MouseXOnCanvas >= 0 && MouseXOnCanvas <= BitmapManager.ActiveDocument.Width &&
  636. MouseYOnCanvas >= 0 && MouseYOnCanvas <= BitmapManager.ActiveDocument.Height;
  637. BitmapManager.MouseController.StartRecordingMouseMovementChanges(clickedOnCanvas);
  638. BitmapManager.MouseController.RecordMouseMovementChange(MousePositionConverter.CurrentCoordinates);
  639. }
  640. }
  641. }
  642. /// <summary>
  643. /// Method connected with command, it executes tool "activity"
  644. /// </summary>
  645. /// <param name="parameter"></param>
  646. private void MouseMove(object parameter)
  647. {
  648. Coordinates cords = new Coordinates((int)MouseXOnCanvas, (int)MouseYOnCanvas);
  649. MousePositionConverter.CurrentCoordinates = cords;
  650. if (BitmapManager.MouseController.IsRecordingChanges && Mouse.LeftButton == MouseButtonState.Pressed)
  651. {
  652. BitmapManager.MouseController.RecordMouseMovementChange(cords);
  653. }
  654. BitmapManager.MouseController.MouseMoved(cords);
  655. }
  656. /// <summary>
  657. /// Generates new Layer and sets it as active one
  658. /// </summary>
  659. /// <param name="parameter"></param>
  660. public void OpenNewFilePopup(object parameter)
  661. {
  662. NewFileDialog newFile = new NewFileDialog();
  663. if (newFile.ShowDialog()) NewDocument(newFile.Width, newFile.Height);
  664. }
  665. /// <summary>
  666. /// Opens file from path.
  667. /// </summary>
  668. /// <param name="path"></param>
  669. public void OpenFile(string path)
  670. {
  671. ImportFileDialog dialog = new ImportFileDialog();
  672. if (path != null && File.Exists(path))
  673. dialog.FilePath = path;
  674. if (dialog.ShowDialog())
  675. {
  676. NewDocument(dialog.FileWidth, dialog.FileHeight, false);
  677. BitmapManager.AddNewLayer("Image",Importer.ImportImage(dialog.FilePath, dialog.FileWidth, dialog.FileHeight));
  678. }
  679. }
  680. public void NewDocument(int width, int height, bool addBaseLayer = true)
  681. {
  682. BitmapManager.ActiveDocument = new Document(width, height);
  683. if(addBaseLayer)
  684. BitmapManager.AddNewLayer("Base Layer");
  685. ResetProgramStateValues();
  686. }
  687. /// <summary>
  688. /// Resets most variables and controller, so new documents can be handled.
  689. /// </summary>
  690. public void ResetProgramStateValues()
  691. {
  692. BitmapManager.PreviewLayer = null;
  693. UndoManager.UndoStack.Clear();
  694. UndoManager.RedoStack.Clear();
  695. ActiveSelection = new Selection(Array.Empty<Coordinates>());
  696. RecenterZoombox = !RecenterZoombox;
  697. Exporter.SaveDocumentPath = null;
  698. _unsavedDocumentModified = false;
  699. }
  700. public void NewLayer(object parameter)
  701. {
  702. BitmapManager.AddNewLayer($"New Layer {BitmapManager.ActiveDocument.Layers.Count}");
  703. }
  704. public bool CanCreateNewLayer(object parameter)
  705. {
  706. return BitmapManager.ActiveDocument != null && BitmapManager.ActiveDocument.Layers.Count > 0;
  707. }
  708. #region Undo/Redo
  709. /// <summary>
  710. /// Undo last action
  711. /// </summary>
  712. /// <param name="parameter"></param>
  713. public void Undo(object parameter)
  714. {
  715. Deselect(null);
  716. UndoManager.Undo();
  717. }
  718. /// <summary>
  719. /// Returns true if undo can be done.
  720. /// </summary>
  721. /// <param name="property"></param>
  722. /// <returns></returns>
  723. private bool CanUndo(object property)
  724. {
  725. return UndoManager.CanUndo;
  726. }
  727. /// <summary>
  728. /// Redo last action
  729. /// </summary>
  730. /// <param name="parameter"></param>
  731. public void Redo(object parameter)
  732. {
  733. UndoManager.Redo();
  734. }
  735. /// <summary>
  736. /// Returns true if redo can be done.
  737. /// </summary>
  738. /// <param name="property"></param>
  739. /// <returns></returns>
  740. private bool CanRedo(object property)
  741. {
  742. return UndoManager.CanRedo;
  743. }
  744. #endregion
  745. #region SaveFile
  746. /// <summary>
  747. /// Generates export dialog or saves directly if save data is known.
  748. /// </summary>
  749. /// <param name="parameter"></param>
  750. private void ExportFile(object parameter)
  751. {
  752. WriteableBitmap bitmap = BitmapManager.GetCombinedLayersBitmap();
  753. Exporter.Export(bitmap, new Size(bitmap.PixelWidth, bitmap.PixelHeight));
  754. }
  755. /// <summary>
  756. /// Returns true if file save is possible.
  757. /// </summary>
  758. /// <param name="property"></param>
  759. /// <returns></returns>
  760. private bool CanSave(object property)
  761. {
  762. return BitmapManager.ActiveDocument != null;
  763. }
  764. #endregion
  765. }
  766. }