2
0

LayersManager.xaml.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  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. }
  67. private static void LayerTreeRootChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  68. {
  69. var manager = (LayersManager)d;
  70. var newRoot = (ObservableCollection<IHasGuid>)e.NewValue;
  71. manager.CachedLayerTreeRoot = newRoot;
  72. return;
  73. //layer tree caching goes after than and disabled for now
  74. if (manager.CachedLayerTreeRoot == null || newRoot == null)
  75. {
  76. manager.CachedLayerTreeRoot = newRoot;
  77. return;
  78. }
  79. if (object.ReferenceEquals(manager.CachedLayerTreeRoot, newRoot))
  80. return;
  81. UpdateCachedTree(manager.CachedLayerTreeRoot, newRoot);
  82. }
  83. private static void UpdateCachedTree(IList<IHasGuid> tree, IList<IHasGuid> newTree)
  84. {
  85. var (lcs1, lcs2) = LongestCommonSubsequence(tree, newTree);
  86. UpdateListUsingLCS(tree, newTree, lcs1);
  87. bool suc = AreCollectionsTheSame(tree, newTree);
  88. for (int i = 0; i < lcs1.Count; i++)
  89. {
  90. var entry = lcs1[i];
  91. if (entry is LayerGroup group)
  92. {
  93. var corrGroup = (LayerGroup)lcs2[i];
  94. UpdateCachedTree(group.Items, corrGroup.Items);
  95. group.StructureData = corrGroup.StructureData;
  96. }
  97. }
  98. }
  99. private static void UpdateListUsingLCS(IList<IHasGuid> list, IList<IHasGuid> newList, IList<IHasGuid> lcs)
  100. {
  101. int oldI = 0;
  102. int newI = 0;
  103. for (int i = 0; i < lcs.Count; i++)
  104. {
  105. Guid curLcsEntry = lcs[i].GuidValue;
  106. while (true)
  107. {
  108. if (curLcsEntry != list[oldI].GuidValue && curLcsEntry != newList[newI].GuidValue)
  109. {
  110. list[oldI] = newList[newI];
  111. oldI++;
  112. newI++;
  113. }
  114. else if (curLcsEntry == list[oldI].GuidValue && curLcsEntry != newList[newI].GuidValue)
  115. {
  116. list.Insert(oldI, newList[newI]);
  117. oldI++;
  118. newI++;
  119. }
  120. else if (curLcsEntry != list[oldI].GuidValue && curLcsEntry == newList[newI].GuidValue)
  121. {
  122. list.RemoveAt(oldI);
  123. }
  124. else
  125. {
  126. oldI++;
  127. newI++;
  128. break;
  129. }
  130. }
  131. }
  132. while (list.Count > oldI)
  133. list.RemoveAt(list.Count - 1);
  134. for (; newI < newList.Count; newI++)
  135. list.Add(newList[newI]);
  136. }
  137. private static bool AreCollectionsTheSame(IList<IHasGuid> coll1, IList<IHasGuid> coll2)
  138. {
  139. if (coll1.Count != coll2.Count)
  140. return false;
  141. for (int i = 0; i < coll1.Count; i++)
  142. {
  143. if (coll1[i].GuidValue != coll2[i].GuidValue)
  144. return false;
  145. }
  146. return true;
  147. }
  148. private static (IList<IHasGuid>, IList<IHasGuid>) LongestCommonSubsequence(IList<IHasGuid> coll1, IList<IHasGuid> coll2)
  149. {
  150. if (AreCollectionsTheSame(coll1, coll2))
  151. return (coll1, coll2);
  152. if (coll1.Count == 0 || coll2.Count == 0)
  153. return (new List<IHasGuid>(), new List<IHasGuid>());
  154. //calculate LCS matrix
  155. int w = coll1.Count;
  156. int h = coll2.Count;
  157. int[,] matrix = new int[w, h];
  158. for (int j = 0; j < h; j++)
  159. {
  160. for (int i = 0; i < w; i++)
  161. {
  162. if (coll1[i].GuidValue == coll2[j].GuidValue)
  163. matrix[i, j] = (i == 0 || j == 0) ? 1 : matrix[i - 1, j - 1] + 1;
  164. else
  165. matrix[i, j] = (i == 0 || j == 0) ? 0 : Math.Max(matrix[i - 1, j], matrix[i, j - 1]);
  166. }
  167. }
  168. //find the actual subsequence
  169. List<IHasGuid> subsequence1 = new();
  170. List<IHasGuid> subsequence2 = new();
  171. int x = w - 1;
  172. int y = h - 1;
  173. while (x >= 0 || y >= 0)
  174. {
  175. if (coll1[x].GuidValue == coll2[y].GuidValue)
  176. {
  177. subsequence1.Add(coll1[x]);
  178. subsequence2.Add(coll2[y]);
  179. if (x == 0 & y == 0)
  180. break;
  181. if (x > 0)
  182. x--;
  183. if (y > 0)
  184. y--;
  185. continue;
  186. }
  187. if (x == 0 && y == 0)
  188. break;
  189. if (x == 0)
  190. {
  191. y--;
  192. continue;
  193. }
  194. if (y == 0)
  195. {
  196. x--;
  197. continue;
  198. }
  199. if (matrix[x - 1, y] > matrix[x, y - 1])
  200. x--;
  201. else
  202. y--;
  203. }
  204. subsequence1.Reverse();
  205. subsequence2.Reverse();
  206. return (subsequence1, subsequence2);
  207. }
  208. private static void ViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  209. {
  210. if (e.NewValue is LayersViewModel vm)
  211. {
  212. LayersManager manager = (LayersManager)d;
  213. vm.Owner.BitmapManager.AddPropertyChangedCallback(nameof(vm.Owner.BitmapManager.ActiveDocument), () =>
  214. {
  215. var doc = vm.Owner.BitmapManager.ActiveDocument;
  216. if (doc != null)
  217. {
  218. if (doc.ActiveLayer != null)
  219. {
  220. manager.SetActiveLayerAsSelectedItem(doc);
  221. }
  222. doc.AddPropertyChangedCallback(nameof(doc.ActiveLayer), () =>
  223. {
  224. manager.SetActiveLayerAsSelectedItem(doc);
  225. });
  226. }
  227. });
  228. }
  229. }
  230. private void SetActiveLayerAsSelectedItem(Document doc)
  231. {
  232. SelectedItem = doc.ActiveLayer;
  233. SetInputOpacity(SelectedItem);
  234. }
  235. private void SetInputOpacity(object item)
  236. {
  237. if (item is Layer layer)
  238. {
  239. numberInput.Value = layer.Opacity * 100f;
  240. }
  241. else if (item is LayerStructureItemContainer container)
  242. {
  243. numberInput.Value = container.Layer.Opacity * 100f;
  244. }
  245. else if (item is LayerGroup group)
  246. {
  247. numberInput.Value = group.StructureData.Opacity * 100f;
  248. }
  249. else if (item is LayerGroupControl groupControl)
  250. {
  251. numberInput.Value = groupControl.GroupData.Opacity * 100f;
  252. }
  253. }
  254. private void LayerStructureItemContainer_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
  255. {
  256. if (sender is LayerStructureItemContainer container && e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
  257. {
  258. Dispatcher.InvokeAsync(() => DragDrop.DoDragDrop(container, container, DragDropEffects.Move));
  259. }
  260. }
  261. private void HandleGroupOpacityChange(GuidStructureItem group, float value)
  262. {
  263. if (LayerCommandsViewModel.Owner?.BitmapManager?.ActiveDocument != null)
  264. {
  265. var doc = LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument;
  266. if (group.Opacity == value)
  267. return;
  268. var processArgs = new object[] { group.GroupGuid, value };
  269. var reverseProcessArgs = new object[] { group.GroupGuid, group.Opacity };
  270. ChangeGroupOpacityProcess(processArgs);
  271. LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument.LayerStructure.ExpandParentGroups(group);
  272. doc.UndoManager.AddUndoChange(
  273. new Change(
  274. ChangeGroupOpacityProcess,
  275. reverseProcessArgs,
  276. ChangeGroupOpacityProcess,
  277. processArgs,
  278. $"Change {group.Name} opacity"), false);
  279. }
  280. }
  281. private void ChangeGroupOpacityProcess(object[] processArgs)
  282. {
  283. if (processArgs.Length > 0 && processArgs[0] is Guid groupGuid && processArgs[1] is float opacity)
  284. {
  285. var structure = LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument.LayerStructure;
  286. var group = structure.GetGroupByGuid(groupGuid);
  287. group.Opacity = opacity;
  288. var layers = structure.GetGroupLayers(group);
  289. 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
  290. numberInput.Value = opacity * 100;
  291. }
  292. }
  293. private void LayerGroup_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
  294. {
  295. if (sender is LayerGroupControl container && e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
  296. {
  297. Dispatcher.InvokeAsync(() => DragDrop.DoDragDrop(container, container, DragDropEffects.Move));
  298. }
  299. }
  300. private void NumberInput_LostFocus(object sender, RoutedEventArgs e)
  301. {
  302. float val = numberInput.Value / 100f;
  303. object item = SelectedItem;
  304. if (item is Layer || item is LayerStructureItemContainer)
  305. {
  306. Layer layer = null;
  307. if (item is Layer lr)
  308. {
  309. layer = lr;
  310. }
  311. else if (item is LayerStructureItemContainer container)
  312. {
  313. layer = container.Layer;
  314. }
  315. HandleLayerOpacityChange(val, layer);
  316. }
  317. else if (item is LayerGroup group)
  318. {
  319. HandleGroupOpacityChange(group.StructureData, val);
  320. }
  321. else if (item is LayerGroupControl groupControl)
  322. {
  323. HandleGroupOpacityChange(groupControl.GroupData, val);
  324. }
  325. ShortcutController.UnblockShortcutExecutionAll();
  326. MoveFocus(new System.Windows.Input.TraversalRequest(System.Windows.Input.FocusNavigationDirection.Next));
  327. }
  328. private void HandleLayerOpacityChange(float val, Layer layer)
  329. {
  330. float oldOpacity = layer.Opacity;
  331. if (oldOpacity == val)
  332. return;
  333. var doc = LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument;
  334. doc.RaisePropertyChange(nameof(doc.LayerStructure));
  335. layer.OpacityUndoTriggerable = val;
  336. doc.LayerStructure.ExpandParentGroups(layer.GuidValue);
  337. doc.RaisePropertyChange(nameof(doc.LayerStructure));
  338. UndoManager undoManager = doc.UndoManager;
  339. undoManager.AddUndoChange(
  340. new Change(
  341. UpdateNumberInputLayerOpacityProcess,
  342. new object[] { oldOpacity },
  343. UpdateNumberInputLayerOpacityProcess,
  344. new object[] { val }));
  345. undoManager.SquashUndoChanges(2);
  346. }
  347. private void UpdateNumberInputLayerOpacityProcess(object[] args)
  348. {
  349. if (args.Length > 0 && args[0] is float opacity)
  350. {
  351. numberInput.Value = opacity * 100;
  352. }
  353. }
  354. private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
  355. {
  356. SetInputOpacity(SelectedItem);
  357. }
  358. private void Grid_Drop(object sender, DragEventArgs e)
  359. {
  360. dropBorder.BorderBrush = Brushes.Transparent;
  361. if (e.Data.GetDataPresent(LayerGroupControl.LayerContainerDataName))
  362. {
  363. HandleLayerDrop(e.Data);
  364. }
  365. if (e.Data.GetDataPresent(LayerGroupControl.LayerGroupControlDataName))
  366. {
  367. HandleGroupControlDrop(e.Data);
  368. }
  369. }
  370. private void HandleLayerDrop(IDataObject data)
  371. {
  372. var doc = LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument;
  373. if (doc.Layers.Count == 0) return;
  374. var layerContainer = (LayerStructureItemContainer)data.GetData(LayerGroupControl.LayerContainerDataName);
  375. var refLayer = doc.Layers[0].GuidValue;
  376. doc.MoveLayerInStructure(layerContainer.Layer.GuidValue, refLayer);
  377. doc.LayerStructure.AssignParent(layerContainer.Layer.GuidValue, null);
  378. }
  379. private void HandleGroupControlDrop(IDataObject data)
  380. {
  381. var doc = LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument;
  382. var groupContainer = (LayerGroupControl)data.GetData(LayerGroupControl.LayerGroupControlDataName);
  383. doc.LayerStructure.MoveGroup(groupContainer.GroupGuid, 0);
  384. }
  385. private void Grid_DragEnter(object sender, DragEventArgs e)
  386. {
  387. ((Border)sender).BorderBrush = LayerItem.HighlightColor;
  388. }
  389. private void Grid_DragLeave(object sender, DragEventArgs e)
  390. {
  391. ((Border)sender).BorderBrush = Brushes.Transparent;
  392. }
  393. private void SelectActiveItem(object sender, System.Windows.Input.MouseButtonEventArgs e)
  394. {
  395. SelectedItem = sender;
  396. }
  397. }
  398. }