LayersManager.xaml.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. using PixiEditor.Models.Controllers;
  2. using PixiEditor.Models.Controllers.Shortcuts;
  3. using PixiEditor.Models.DataHolders;
  4. using PixiEditor.Models.Layers;
  5. using PixiEditor.Models.Undo;
  6. using PixiEditor.ViewModels.SubViewModels.Main;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Collections.ObjectModel;
  10. using System.Windows;
  11. using System.Windows.Controls;
  12. using System.Windows.Media;
  13. namespace PixiEditor.Views.UserControls.Layers
  14. {
  15. /// <summary>
  16. /// Interaction logic for LayersManager.xaml.
  17. /// </summary>
  18. public partial class LayersManager : UserControl
  19. {
  20. public object SelectedItem
  21. {
  22. get { return (object)GetValue(SelectedItemProperty); }
  23. set { SetValue(SelectedItemProperty, value); }
  24. }
  25. public static readonly DependencyProperty SelectedItemProperty =
  26. DependencyProperty.Register(nameof(SelectedItem), typeof(object), typeof(LayersManager), new PropertyMetadata(0));
  27. public ObservableCollection<IHasGuid> LayerTreeRoot
  28. {
  29. get { return (ObservableCollection<IHasGuid>)GetValue(LayerTreeRootProperty); }
  30. set { SetValue(LayerTreeRootProperty, value); }
  31. }
  32. public static readonly DependencyProperty LayerTreeRootProperty =
  33. DependencyProperty.Register(
  34. nameof(LayerTreeRoot),
  35. typeof(ObservableCollection<IHasGuid>),
  36. typeof(LayersManager),
  37. new PropertyMetadata(default(ObservableCollection<IHasGuid>), LayerTreeRootChanged));
  38. public ObservableCollection<IHasGuid> CachedLayerTreeRoot
  39. {
  40. get { return (ObservableCollection<IHasGuid>)GetValue(CachedLayerTreeRootProperty); }
  41. set { SetValue(CachedLayerTreeRootProperty, value); }
  42. }
  43. public static readonly DependencyProperty CachedLayerTreeRootProperty =
  44. DependencyProperty.Register(
  45. nameof(CachedLayerTreeRoot),
  46. typeof(ObservableCollection<IHasGuid>),
  47. typeof(LayersManager),
  48. new PropertyMetadata(default(ObservableCollection<IHasGuid>)));
  49. public LayersViewModel LayerCommandsViewModel
  50. {
  51. get { return (LayersViewModel)GetValue(LayerCommandsViewModelProperty); }
  52. set { SetValue(LayerCommandsViewModelProperty, value); }
  53. }
  54. public static readonly DependencyProperty LayerCommandsViewModelProperty =
  55. DependencyProperty.Register(nameof(LayerCommandsViewModel), typeof(LayersViewModel), typeof(LayersManager), new PropertyMetadata(default(LayersViewModel), ViewModelChanged));
  56. public bool OpacityInputEnabled
  57. {
  58. get { return (bool)GetValue(OpacityInputEnabledProperty); }
  59. set { SetValue(OpacityInputEnabledProperty, value); }
  60. }
  61. public static readonly DependencyProperty OpacityInputEnabledProperty =
  62. DependencyProperty.Register(nameof(OpacityInputEnabled), typeof(bool), typeof(LayersManager), new PropertyMetadata(false));
  63. public LayersManager()
  64. {
  65. InitializeComponent();
  66. numberInput.OnScrollAction = () => NumberInput_LostFocus(null, null);
  67. }
  68. private static void LayerTreeRootChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  69. {
  70. var manager = (LayersManager)d;
  71. var newRoot = (ObservableCollection<IHasGuid>)e.NewValue;
  72. manager.CachedLayerTreeRoot = newRoot;
  73. return;
  74. //layer tree caching goes after than and disabled for now
  75. /*
  76. if (manager.CachedLayerTreeRoot == null || newRoot == null)
  77. {
  78. manager.CachedLayerTreeRoot = newRoot;
  79. return;
  80. }
  81. if (object.ReferenceEquals(manager.CachedLayerTreeRoot, newRoot))
  82. return;
  83. UpdateCachedTree(manager.CachedLayerTreeRoot, newRoot);*/
  84. }
  85. private static void UpdateCachedTree(IList<IHasGuid> tree, IList<IHasGuid> newTree)
  86. {
  87. var (lcs1, lcs2) = LongestCommonSubsequence(tree, newTree);
  88. UpdateListUsingLCS(tree, newTree, lcs1);
  89. bool suc = AreCollectionsTheSame(tree, newTree);
  90. for (int i = 0; i < lcs1.Count; i++)
  91. {
  92. var entry = lcs1[i];
  93. if (entry is LayerGroup group)
  94. {
  95. var corrGroup = (LayerGroup)lcs2[i];
  96. UpdateCachedTree(group.Items, corrGroup.Items);
  97. group.StructureData = corrGroup.StructureData;
  98. }
  99. }
  100. }
  101. private static void UpdateListUsingLCS(IList<IHasGuid> list, IList<IHasGuid> newList, IList<IHasGuid> lcs)
  102. {
  103. int oldI = 0;
  104. int newI = 0;
  105. for (int i = 0; i < lcs.Count; i++)
  106. {
  107. Guid curLcsEntry = lcs[i].GuidValue;
  108. while (true)
  109. {
  110. if (curLcsEntry != list[oldI].GuidValue && curLcsEntry != newList[newI].GuidValue)
  111. {
  112. list[oldI] = newList[newI];
  113. oldI++;
  114. newI++;
  115. }
  116. else if (curLcsEntry == list[oldI].GuidValue && curLcsEntry != newList[newI].GuidValue)
  117. {
  118. list.Insert(oldI, newList[newI]);
  119. oldI++;
  120. newI++;
  121. }
  122. else if (curLcsEntry != list[oldI].GuidValue && curLcsEntry == newList[newI].GuidValue)
  123. {
  124. list.RemoveAt(oldI);
  125. }
  126. else
  127. {
  128. oldI++;
  129. newI++;
  130. break;
  131. }
  132. }
  133. }
  134. while (list.Count > oldI)
  135. list.RemoveAt(list.Count - 1);
  136. for (; newI < newList.Count; newI++)
  137. list.Add(newList[newI]);
  138. }
  139. private static bool AreCollectionsTheSame(IList<IHasGuid> coll1, IList<IHasGuid> coll2)
  140. {
  141. if (coll1.Count != coll2.Count)
  142. return false;
  143. for (int i = 0; i < coll1.Count; i++)
  144. {
  145. if (coll1[i].GuidValue != coll2[i].GuidValue)
  146. return false;
  147. }
  148. return true;
  149. }
  150. private static (IList<IHasGuid>, IList<IHasGuid>) LongestCommonSubsequence(IList<IHasGuid> coll1, IList<IHasGuid> coll2)
  151. {
  152. if (AreCollectionsTheSame(coll1, coll2))
  153. return (coll1, coll2);
  154. if (coll1.Count == 0 || coll2.Count == 0)
  155. return (new List<IHasGuid>(), new List<IHasGuid>());
  156. //calculate LCS matrix
  157. int w = coll1.Count;
  158. int h = coll2.Count;
  159. int[,] matrix = new int[w, h];
  160. for (int j = 0; j < h; j++)
  161. {
  162. for (int i = 0; i < w; i++)
  163. {
  164. if (coll1[i].GuidValue == coll2[j].GuidValue)
  165. matrix[i, j] = (i == 0 || j == 0) ? 1 : matrix[i - 1, j - 1] + 1;
  166. else
  167. matrix[i, j] = (i == 0 || j == 0) ? 0 : Math.Max(matrix[i - 1, j], matrix[i, j - 1]);
  168. }
  169. }
  170. //find the actual subsequence
  171. List<IHasGuid> subsequence1 = new();
  172. List<IHasGuid> subsequence2 = new();
  173. int x = w - 1;
  174. int y = h - 1;
  175. while (x >= 0 || y >= 0)
  176. {
  177. if (coll1[x].GuidValue == coll2[y].GuidValue)
  178. {
  179. subsequence1.Add(coll1[x]);
  180. subsequence2.Add(coll2[y]);
  181. if (x == 0 & y == 0)
  182. break;
  183. if (x > 0)
  184. x--;
  185. if (y > 0)
  186. y--;
  187. continue;
  188. }
  189. if (x == 0 && y == 0)
  190. break;
  191. if (x == 0)
  192. {
  193. y--;
  194. continue;
  195. }
  196. if (y == 0)
  197. {
  198. x--;
  199. continue;
  200. }
  201. if (matrix[x - 1, y] > matrix[x, y - 1])
  202. x--;
  203. else
  204. y--;
  205. }
  206. subsequence1.Reverse();
  207. subsequence2.Reverse();
  208. return (subsequence1, subsequence2);
  209. }
  210. private static void ViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  211. {
  212. if (e.NewValue is LayersViewModel vm)
  213. {
  214. LayersManager manager = (LayersManager)d;
  215. vm.Owner.BitmapManager.AddPropertyChangedCallback(nameof(vm.Owner.BitmapManager.ActiveDocument), () =>
  216. {
  217. var doc = vm.Owner.BitmapManager.ActiveDocument;
  218. if (doc != null)
  219. {
  220. if (doc.ActiveLayer != null)
  221. {
  222. manager.SetActiveLayerAsSelectedItem(doc);
  223. }
  224. doc.AddPropertyChangedCallback(nameof(doc.ActiveLayer), () =>
  225. {
  226. manager.SetActiveLayerAsSelectedItem(doc);
  227. });
  228. }
  229. });
  230. }
  231. }
  232. private void SetActiveLayerAsSelectedItem(Document doc)
  233. {
  234. SelectedItem = doc.ActiveLayer;
  235. SetInputOpacity(SelectedItem);
  236. }
  237. private void SetInputOpacity(object item)
  238. {
  239. if (item is Layer layer)
  240. {
  241. numberInput.Value = layer.Opacity * 100f;
  242. }
  243. else if (item is LayerStructureItemContainer container)
  244. {
  245. numberInput.Value = container.Layer.Opacity * 100f;
  246. }
  247. else if (item is LayerGroup group)
  248. {
  249. numberInput.Value = group.StructureData.Opacity * 100f;
  250. }
  251. else if (item is LayerGroupControl groupControl)
  252. {
  253. numberInput.Value = groupControl.GroupData.Opacity * 100f;
  254. }
  255. }
  256. private void LayerStructureItemContainer_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
  257. {
  258. if (sender is LayerStructureItemContainer container
  259. && e.LeftButton == System.Windows.Input.MouseButtonState.Pressed && !container.Layer.IsRenaming)
  260. {
  261. Dispatcher.InvokeAsync(() => DragDrop.DoDragDrop(container, container, DragDropEffects.Move));
  262. }
  263. }
  264. private void HandleGroupOpacityChange(GuidStructureItem group, float value)
  265. {
  266. if (LayerCommandsViewModel.Owner?.BitmapManager?.ActiveDocument != null)
  267. {
  268. var doc = LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument;
  269. if (group.Opacity == value)
  270. return;
  271. var processArgs = new object[] { group.GroupGuid, value };
  272. var reverseProcessArgs = new object[] { group.GroupGuid, group.Opacity };
  273. ChangeGroupOpacityProcess(processArgs);
  274. LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument.LayerStructure.ExpandParentGroups(group);
  275. doc.UndoManager.AddUndoChange(
  276. new Change(
  277. ChangeGroupOpacityProcess,
  278. reverseProcessArgs,
  279. ChangeGroupOpacityProcess,
  280. processArgs,
  281. $"Change {group.Name} opacity"), false);
  282. }
  283. }
  284. private void ChangeGroupOpacityProcess(object[] processArgs)
  285. {
  286. if (processArgs.Length > 0 && processArgs[0] is Guid groupGuid && processArgs[1] is float opacity)
  287. {
  288. var structure = LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument.LayerStructure;
  289. var group = structure.GetGroupByGuid(groupGuid);
  290. group.Opacity = opacity;
  291. var layers = structure.GetGroupLayers(group);
  292. layers.ForEach(x => x.Opacity = x.Opacity); // This might seems stupid, but it raises property changed, without setting any value. This is used to trigger converters that use group opacity
  293. numberInput.Value = opacity * 100;
  294. }
  295. }
  296. private void LayerGroup_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
  297. {
  298. if (sender is LayerGroupControl container && e.LeftButton == System.Windows.Input.MouseButtonState.Pressed
  299. && !container.GroupData.IsRenaming)
  300. {
  301. Dispatcher.InvokeAsync(() => DragDrop.DoDragDrop(container, container, DragDropEffects.Move));
  302. }
  303. }
  304. private void NumberInput_LostFocus(object sender, RoutedEventArgs e)
  305. {
  306. float val = numberInput.Value / 100f;
  307. object item = SelectedItem;
  308. if (item is Layer || item is LayerStructureItemContainer)
  309. {
  310. Layer layer = null;
  311. if (item is Layer lr)
  312. {
  313. layer = lr;
  314. }
  315. else if (item is LayerStructureItemContainer container)
  316. {
  317. layer = container.Layer;
  318. }
  319. HandleLayerOpacityChange(val, layer);
  320. }
  321. else if (item is LayerGroup group)
  322. {
  323. HandleGroupOpacityChange(group.StructureData, val);
  324. }
  325. else if (item is LayerGroupControl groupControl)
  326. {
  327. HandleGroupOpacityChange(groupControl.GroupData, val);
  328. }
  329. ShortcutController.UnblockShortcutExecutionAll();
  330. }
  331. private void HandleLayerOpacityChange(float val, Layer layer)
  332. {
  333. float oldOpacity = layer.Opacity;
  334. if (oldOpacity == val)
  335. return;
  336. var doc = LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument;
  337. doc.RaisePropertyChange(nameof(doc.LayerStructure));
  338. layer.OpacityUndoTriggerable = val;
  339. doc.LayerStructure.ExpandParentGroups(layer.GuidValue);
  340. doc.RaisePropertyChange(nameof(doc.LayerStructure));
  341. UndoManager undoManager = doc.UndoManager;
  342. undoManager.AddUndoChange(
  343. new Change(
  344. UpdateNumberInputLayerOpacityProcess,
  345. new object[] { oldOpacity },
  346. UpdateNumberInputLayerOpacityProcess,
  347. new object[] { val }));
  348. undoManager.SquashUndoChanges(2);
  349. }
  350. private void UpdateNumberInputLayerOpacityProcess(object[] args)
  351. {
  352. if (args.Length > 0 && args[0] is float opacity)
  353. {
  354. numberInput.Value = opacity * 100;
  355. }
  356. }
  357. private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
  358. {
  359. SetInputOpacity(SelectedItem);
  360. }
  361. private void Grid_Drop(object sender, DragEventArgs e)
  362. {
  363. dropBorder.BorderBrush = Brushes.Transparent;
  364. if (e.Data.GetDataPresent(LayerGroupControl.LayerContainerDataName))
  365. {
  366. HandleLayerDrop(e.Data);
  367. }
  368. if (e.Data.GetDataPresent(LayerGroupControl.LayerGroupControlDataName))
  369. {
  370. HandleGroupControlDrop(e.Data);
  371. }
  372. }
  373. private void HandleLayerDrop(IDataObject data)
  374. {
  375. var doc = LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument;
  376. if (doc.Layers.Count == 0) return;
  377. var layerContainer = (LayerStructureItemContainer)data.GetData(LayerGroupControl.LayerContainerDataName);
  378. var refLayer = doc.Layers[0].GuidValue;
  379. doc.MoveLayerInStructure(layerContainer.Layer.GuidValue, refLayer);
  380. doc.LayerStructure.AssignParent(layerContainer.Layer.GuidValue, null);
  381. }
  382. private void HandleGroupControlDrop(IDataObject data)
  383. {
  384. var doc = LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument;
  385. var groupContainer = (LayerGroupControl)data.GetData(LayerGroupControl.LayerGroupControlDataName);
  386. doc.LayerStructure.MoveGroup(groupContainer.GroupGuid, 0);
  387. }
  388. private void Grid_DragEnter(object sender, DragEventArgs e)
  389. {
  390. ((Border)sender).BorderBrush = LayerItem.HighlightColor;
  391. }
  392. private void Grid_DragLeave(object sender, DragEventArgs e)
  393. {
  394. ((Border)sender).BorderBrush = Brushes.Transparent;
  395. }
  396. private void SelectActiveItem(object sender, System.Windows.Input.MouseButtonEventArgs e)
  397. {
  398. SelectedItem = sender;
  399. }
  400. }
  401. }