Document.Layers.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. using PixiEditor.Helpers;
  2. using PixiEditor.Models.Controllers;
  3. using PixiEditor.Models.Enums;
  4. using PixiEditor.Models.Layers;
  5. using PixiEditor.Models.Layers.Utils;
  6. using PixiEditor.Models.Position;
  7. using PixiEditor.Models.Undo;
  8. using SkiaSharp;
  9. using System;
  10. using System.Buffers;
  11. using System.Collections.Generic;
  12. using System.Collections.ObjectModel;
  13. using System.Linq;
  14. using System.Text.RegularExpressions;
  15. using System.Windows;
  16. namespace PixiEditor.Models.DataHolders
  17. {
  18. public partial class Document
  19. {
  20. public const string MainSelectedLayerColor = "#505056";
  21. public const string SecondarySelectedLayerColor = "#7D505056";
  22. private static readonly Regex reversedLayerSuffixRegex = new(@"(?:\)([0-9]+)*\()? *([\s\S]+)", RegexOptions.Compiled);
  23. private Guid activeLayerGuid;
  24. private LayerStructure layerStructure;
  25. private WpfObservableRangeCollection<Layer> layers = new();
  26. public WpfObservableRangeCollection<Layer> Layers
  27. {
  28. get => layers;
  29. set
  30. {
  31. layers = value;
  32. Layers.CollectionChanged += Layers_CollectionChanged;
  33. Renderer.SetNewLayersCollection(value);
  34. }
  35. }
  36. public LayerStructure LayerStructure
  37. {
  38. get => layerStructure;
  39. private set
  40. {
  41. layerStructure = value;
  42. RaisePropertyChanged(nameof(LayerStructure));
  43. }
  44. }
  45. private LayerStackRenderer renderer;
  46. public LayerStackRenderer Renderer
  47. {
  48. get => renderer;
  49. private set
  50. {
  51. renderer = value;
  52. RaisePropertyChanged(nameof(Renderer));
  53. }
  54. }
  55. private Layer referenceLayer;
  56. private SingleLayerRenderer referenceLayerRenderer;
  57. public Layer ReferenceLayer
  58. {
  59. get => referenceLayer;
  60. set
  61. {
  62. referenceLayer = value;
  63. referenceLayerRenderer?.Dispose();
  64. referenceLayerRenderer = referenceLayer == null ? null : new SingleLayerRenderer(referenceLayer, referenceLayer.Width, referenceLayer.Height);
  65. RaisePropertyChanged(nameof(ReferenceLayer));
  66. RaisePropertyChanged(nameof(ReferenceLayerRenderer));
  67. }
  68. }
  69. public SingleLayerRenderer ReferenceLayerRenderer
  70. {
  71. get => referenceLayerRenderer;
  72. }
  73. public Layer ActiveLayer => Layers.Count > 0 ? Layers.FirstOrDefault(x => x.LayerGuid == ActiveLayerGuid) : null;
  74. public Guid ActiveLayerGuid
  75. {
  76. get => activeLayerGuid;
  77. set
  78. {
  79. if (value != activeLayerGuid)
  80. {
  81. activeLayerGuid = value;
  82. RaisePropertyChanged(nameof(ActiveLayerGuid));
  83. RaisePropertyChanged(nameof(ActiveLayer));
  84. }
  85. }
  86. }
  87. public event EventHandler<LayersChangedEventArgs> LayersChanged;
  88. public void SetMainActiveLayer(int index)
  89. {
  90. if (ActiveLayer != null && Layers.IndexOf(ActiveLayer) <= Layers.Count - 1)
  91. {
  92. ActiveLayer.IsActive = false;
  93. }
  94. foreach (var layer in Layers)
  95. {
  96. if (layer.IsActive)
  97. {
  98. layer.IsActive = false;
  99. }
  100. }
  101. ActiveLayerGuid = Layers[index].LayerGuid;
  102. ActiveLayer.IsActive = true;
  103. LayersChanged?.Invoke(this, new LayersChangedEventArgs(ActiveLayerGuid, LayerAction.SetActive));
  104. }
  105. /// <summary>
  106. /// Gets final layer IsVisible taking into consideration group visibility.
  107. /// </summary>
  108. /// <param name="layer">Layer to check.</param>
  109. /// <returns>True if is visible, false if at least parent is not visible or layer itself is invisible.</returns>
  110. public bool GetFinalLayerIsVisible(Layer layer) => LayerStructureUtils.GetFinalLayerIsVisible(layer, LayerStructure);
  111. public void UpdateLayersColor()
  112. {
  113. foreach (var layer in Layers)
  114. {
  115. if (layer.LayerGuid == ActiveLayerGuid)
  116. {
  117. layer.LayerHighlightColor = MainSelectedLayerColor;
  118. }
  119. else
  120. {
  121. layer.LayerHighlightColor = SecondarySelectedLayerColor;
  122. }
  123. }
  124. }
  125. public void MoveLayerInStructure(Guid layerGuid, Guid referenceLayer, bool above = false, bool addToUndo = true)
  126. {
  127. var args = new object[] { layerGuid, referenceLayer, above };
  128. Layer layer = Layers.First(x => x.LayerGuid == layerGuid);
  129. int oldIndex = Layers.IndexOf(layer);
  130. var oldLayerStrcutureGroups = LayerStructure.CloneGroups();
  131. MoveLayerInStructureProcess(args);
  132. AddLayerStructureToUndo(oldLayerStrcutureGroups);
  133. if (!addToUndo) return;
  134. UndoManager.AddUndoChange(new Change(
  135. ReverseMoveLayerInStructureProcess,
  136. new object[] { oldIndex, layerGuid },
  137. MoveLayerInStructureProcess,
  138. args,
  139. "Move layer"));
  140. UndoManager.SquashUndoChanges(2, "Move layer");
  141. }
  142. public void MoveGroupInStructure(Guid groupGuid, Guid referenceLayer, bool above = false)
  143. {
  144. var args = new object[] { groupGuid, referenceLayer, above };
  145. var topLayer = Layers.First(x => x.LayerGuid == LayerStructure.GetGroupByGuid(groupGuid).EndLayerGuid);
  146. var bottomLayer = Layers.First(x => x.LayerGuid == LayerStructure.GetGroupByGuid(groupGuid).StartLayerGuid);
  147. int indexOfTopLayer = Layers.IndexOf(topLayer);
  148. Guid oldReferenceLayerGuid;
  149. bool oldAbove = false;
  150. if (indexOfTopLayer + 1 < Layers.Count)
  151. {
  152. oldReferenceLayerGuid = topLayer.LayerGuid;
  153. }
  154. else
  155. {
  156. int indexOfBottomLayer = Layers.IndexOf(bottomLayer);
  157. oldReferenceLayerGuid = Layers[indexOfBottomLayer - 1].LayerGuid;
  158. oldAbove = true;
  159. }
  160. var oldLayerStructure = LayerStructure.CloneGroups();
  161. MoveGroupInStructureProcess(args);
  162. AddLayerStructureToUndo(oldLayerStructure);
  163. UndoManager.AddUndoChange(new Change(
  164. MoveGroupInStructureProcess,
  165. new object[] { groupGuid, oldReferenceLayerGuid, oldAbove },
  166. MoveGroupInStructureProcess,
  167. args));
  168. UndoManager.SquashUndoChanges(2, "Move group");
  169. }
  170. public void AddNewLayer(string name, Surface bitmap, bool setAsActive = true)
  171. {
  172. AddNewLayer(name, bitmap.Width, bitmap.Height, setAsActive, bitmap);
  173. }
  174. public void AddNewLayer(string name, bool setAsActive = true)
  175. {
  176. AddNewLayer(name, 1, 1, setAsActive);
  177. }
  178. public void AddNewLayer(string name, int width, int height, bool setAsActive = true, Surface bitmap = null)
  179. {
  180. Layer layer;
  181. if (bitmap != null)
  182. {
  183. if (width != bitmap.Width || height != bitmap.Height)
  184. throw new ArgumentException("Inconsistent width and height");
  185. }
  186. if (width <= 0 || height <= 0)
  187. throw new ArgumentException("Dimensions must be greater than 0");
  188. layer = bitmap == null ? new Layer(name, width, height) : new Layer(name, bitmap);
  189. layer.MaxHeight = Height;
  190. layer.MaxWidth = Width;
  191. Layers.Add(layer);
  192. layer.Name = GetLayerSuffix(layer);
  193. if (setAsActive)
  194. {
  195. SetMainActiveLayer(Layers.Count - 1);
  196. }
  197. if (Layers.Count > 1)
  198. {
  199. StorageBasedChange storageChange = new(this, new[] { Layers[^1] }, false);
  200. UndoManager.AddUndoChange(
  201. storageChange.ToChange(
  202. RemoveLayerProcess,
  203. new object[] { Layers[^1].LayerGuid },
  204. RestoreLayersProcess,
  205. "Add layer"));
  206. }
  207. LayersChanged?.Invoke(this, new LayersChangedEventArgs(Layers[^1].LayerGuid, LayerAction.Add));
  208. }
  209. /// <summary>
  210. /// Duplicates the layer at the <paramref name="index"/>.
  211. /// </summary>
  212. /// <param name="index">The index of the layer to duplicate.</param>
  213. /// <returns>The duplicate.</returns>
  214. public Layer DuplicateLayer(int index)
  215. {
  216. Layer duplicate = Layers[index].Clone(true);
  217. duplicate.Name = GetLayerSuffix(duplicate);
  218. Layers.Insert(index + 1, duplicate);
  219. SetMainActiveLayer(index + 1);
  220. StorageBasedChange storageChange = new(this, new[] { duplicate }, false);
  221. UndoManager.AddUndoChange(
  222. storageChange.ToChange(
  223. RemoveLayerProcess,
  224. new object[] { duplicate.LayerGuid },
  225. RestoreLayersProcess,
  226. "Duplicate Layer"));
  227. return duplicate;
  228. }
  229. public void SetNextLayerAsActive(int lastLayerIndex)
  230. {
  231. if (Layers.Count > 0)
  232. {
  233. if (lastLayerIndex == 0)
  234. {
  235. SetMainActiveLayer(0);
  236. }
  237. else
  238. {
  239. SetMainActiveLayer(lastLayerIndex - 1);
  240. }
  241. }
  242. }
  243. public void SetNextSelectedLayerAsActive(Guid lastLayerGuid)
  244. {
  245. var selectedLayers = Layers.Where(x => x.IsActive);
  246. foreach (var layer in selectedLayers)
  247. {
  248. if (layer.LayerGuid != lastLayerGuid)
  249. {
  250. ActiveLayerGuid = layer.LayerGuid;
  251. LayersChanged?.Invoke(this, new LayersChangedEventArgs(ActiveLayerGuid, LayerAction.SetActive));
  252. return;
  253. }
  254. }
  255. }
  256. public void ToggleLayer(int index)
  257. {
  258. if (index < Layers.Count && index >= 0)
  259. {
  260. Layer layer = Layers[index];
  261. if (layer.IsActive && Layers.Count(x => x.IsActive) == 1)
  262. {
  263. return;
  264. }
  265. if (ActiveLayerGuid == layer.LayerGuid)
  266. {
  267. SetNextSelectedLayerAsActive(layer.LayerGuid);
  268. }
  269. layer.IsActive = !layer.IsActive;
  270. }
  271. }
  272. /// <summary>
  273. /// Selects all layers between active layer and layer at given index.
  274. /// </summary>
  275. /// <param name="index">End of range index.</param>
  276. public void SelectLayersRange(int index)
  277. {
  278. DeselectAllExcept(ActiveLayer);
  279. int firstIndex = Layers.IndexOf(ActiveLayer);
  280. int startIndex = Math.Min(index, firstIndex);
  281. for (int i = startIndex; i <= startIndex + Math.Abs(index - firstIndex); i++)
  282. {
  283. Layers[i].IsActive = true;
  284. }
  285. }
  286. public void DeselectAllExcept(Layer exceptLayer)
  287. {
  288. foreach (var layer in Layers)
  289. {
  290. if (layer == exceptLayer)
  291. {
  292. continue;
  293. }
  294. layer.IsActive = false;
  295. }
  296. }
  297. public void RemoveLayer(int layerIndex, bool addToUndo = true)
  298. {
  299. if (Layers.Count == 0)
  300. {
  301. return;
  302. }
  303. LayerStructure.AssignParent(Layers[layerIndex].LayerGuid, null);
  304. bool wasActive = Layers[layerIndex].IsActive;
  305. if (addToUndo)
  306. {
  307. StorageBasedChange change = new(this, new[] { Layers[layerIndex] });
  308. UndoManager.AddUndoChange(
  309. change.ToChange(RestoreLayersProcess, RemoveLayerProcess, new object[] { Layers[layerIndex].LayerGuid }));
  310. }
  311. Layers.RemoveAt(layerIndex);
  312. if (wasActive)
  313. {
  314. SetNextLayerAsActive(layerIndex);
  315. }
  316. }
  317. public void RemoveLayer(Layer layer, bool addToUndo)
  318. {
  319. RemoveLayer(Layers.IndexOf(layer), addToUndo);
  320. }
  321. public void RemoveActiveLayers()
  322. {
  323. if (Layers.Count == 0 || !Layers.Any(x => x.IsActive))
  324. {
  325. return;
  326. }
  327. var oldLayerStructure = LayerStructure.CloneGroups();
  328. Layer[] layers = Layers.Where(x => x.IsActive).ToArray();
  329. int firstIndex = Layers.IndexOf(layers[0]);
  330. object[] guidArgs = new object[] { layers.Select(x => x.LayerGuid).ToArray() };
  331. StorageBasedChange change = new(this, layers);
  332. RemoveLayersProcess(guidArgs);
  333. AddLayerStructureToUndo(oldLayerStructure);
  334. InjectRemoveActiveLayersUndo(guidArgs, change);
  335. UndoManager.SquashUndoChanges(2, "Removed active layers");
  336. SetNextLayerAsActive(firstIndex);
  337. }
  338. public void AddLayerStructureToUndo(WpfObservableRangeCollection<GuidStructureItem> oldLayerStructureGroups)
  339. {
  340. UndoManager.AddUndoChange(
  341. new Change(
  342. BuildLayerStructureProcess,
  343. new object[] { oldLayerStructureGroups },
  344. BuildLayerStructureProcess,
  345. new object[] { LayerStructure.CloneGroups() }, "Reload LayerStructure"));
  346. }
  347. public Layer MergeLayers(Layer[] layersToMerge, bool nameOfLast, int index)
  348. {
  349. if (layersToMerge == null || layersToMerge.Length < 2)
  350. {
  351. throw new ArgumentException("Not enough layers were provided to merge. Minimum amount is 2");
  352. }
  353. string name;
  354. // Which name should be used
  355. if (nameOfLast)
  356. {
  357. name = layersToMerge[^1].Name;
  358. }
  359. else
  360. {
  361. name = layersToMerge[0].Name;
  362. }
  363. Layer mergedLayer = layersToMerge[0];
  364. var groupParent = LayerStructure.GetGroupByLayer(layersToMerge[^1].LayerGuid);
  365. Layer placeholderLayer = new("_placeholder");
  366. Layers.Insert(index, placeholderLayer);
  367. LayerStructure.AssignParent(placeholderLayer.LayerGuid, groupParent?.GroupGuid);
  368. for (int i = 0; i < layersToMerge.Length - 1; i++)
  369. {
  370. Layer firstLayer = mergedLayer;
  371. Layer secondLayer = layersToMerge[i + 1];
  372. mergedLayer = firstLayer.MergeWith(secondLayer, name, Width, Height);
  373. RemoveLayer(layersToMerge[i], false);
  374. }
  375. Layers.Insert(index, mergedLayer);
  376. LayerStructure.AssignParent(mergedLayer.LayerGuid, groupParent?.GroupGuid);
  377. RemoveLayer(placeholderLayer, false);
  378. RemoveLayer(layersToMerge[^1], false);
  379. SetMainActiveLayer(Layers.IndexOf(mergedLayer));
  380. return mergedLayer;
  381. }
  382. public Layer MergeLayers(Layer[] layersToMerge, bool nameIsLastLayers)
  383. {
  384. if (layersToMerge == null || layersToMerge.Length < 2)
  385. {
  386. throw new ArgumentException("Not enough layers were provided to merge. Minimum amount is 2");
  387. }
  388. IEnumerable<Layer> undoArgs = layersToMerge;
  389. var oldLayerStructure = LayerStructure.CloneGroups();
  390. StorageBasedChange undoChange = new(this, undoArgs);
  391. int[] indexes = layersToMerge.Select(x => Layers.IndexOf(x)).ToArray();
  392. var layer = MergeLayers(layersToMerge, nameIsLastLayers, Layers.IndexOf(layersToMerge[0]));
  393. AddLayerStructureToUndo(oldLayerStructure);
  394. UndoManager.AddUndoChange(undoChange.ToChange(
  395. InsertLayersAtIndexesProcess,
  396. new object[] { indexes[0] },
  397. MergeLayersProcess,
  398. new object[] { indexes, nameIsLastLayers, layer.LayerGuid }));
  399. UndoManager.SquashUndoChanges(2, "Undo merge layers");
  400. return layer;
  401. }
  402. public SKColor GetColorAtPoint(int x, int y)
  403. {
  404. return Renderer.FinalSurface.GetSRGBPixel(x, y);
  405. }
  406. private void DisposeLayerBitmaps()
  407. {
  408. foreach (var layer in layers)
  409. {
  410. layer.LayerBitmap.Dispose();
  411. }
  412. referenceLayer?.LayerBitmap.Dispose();
  413. previewLayer?.LayerBitmap.Dispose();
  414. previewLayerRenderer?.Dispose();
  415. referenceLayerRenderer?.Dispose();
  416. renderer?.Dispose();
  417. }
  418. public void BuildLayerStructureProcess(object[] parameters)
  419. {
  420. if (parameters.Length > 0 && parameters[0] is WpfObservableRangeCollection<GuidStructureItem> groups)
  421. {
  422. LayerStructure.Groups.CollectionChanged -= Groups_CollectionChanged;
  423. LayerStructure.Groups = LayerStructure.CloneGroups(groups);
  424. LayerStructure.Groups.CollectionChanged += Groups_CollectionChanged;
  425. RaisePropertyChanged(nameof(LayerStructure));
  426. }
  427. }
  428. private void ReverseMoveLayerInStructureProcess(object[] props)
  429. {
  430. int indexTo = (int)props[0];
  431. Guid layerGuid = (Guid)props[1];
  432. Guid layerAtOldIndex = Layers[indexTo].LayerGuid;
  433. var startGroup = LayerStructure.GetGroupByLayer(layerGuid);
  434. LayerStructure.PreMoveReassignBounds(new GroupData(startGroup?.GroupGuid), layerGuid);
  435. Layers.Move(Layers.IndexOf(Layers.First(x => x.LayerGuid == layerGuid)), indexTo);
  436. var newGroup = LayerStructure.GetGroupByLayer(layerAtOldIndex);
  437. LayerStructure.PostMoveReassignBounds(new GroupData(newGroup?.GroupGuid), layerGuid);
  438. RaisePropertyChanged(nameof(LayerStructure));
  439. }
  440. private void InjectRemoveActiveLayersUndo(object[] guidArgs, StorageBasedChange change)
  441. {
  442. Action<Layer[], UndoLayer[]> undoAction = RestoreLayersProcess;
  443. Action<object[]> redoAction = RemoveLayersProcess;
  444. if (Layers.Count == 0)
  445. {
  446. Layer layer = new("Base Layer", 1, 1) { MaxHeight = Height, MaxWidth = Width };
  447. Layers.Add(layer);
  448. undoAction = (Layer[] layers, UndoLayer[] undoData) =>
  449. {
  450. Layers.RemoveAt(0);
  451. RestoreLayersProcess(layers, undoData);
  452. };
  453. redoAction = (object[] args) =>
  454. {
  455. RemoveLayersProcess(args);
  456. Layers.Add(layer);
  457. };
  458. }
  459. UndoManager.AddUndoChange(
  460. change.ToChange(
  461. undoAction,
  462. redoAction,
  463. guidArgs,
  464. "Remove layers"));
  465. }
  466. private void MergeLayersProcess(object[] args)
  467. {
  468. if (args.Length > 0
  469. && args[0] is int[] indexes
  470. && args[1] is bool nameOfSecond
  471. && args[2] is Guid mergedLayerGuid)
  472. {
  473. Layer[] layers = new Layer[indexes.Length];
  474. for (int i = 0; i < layers.Length; i++)
  475. {
  476. layers[i] = Layers[indexes[i]];
  477. }
  478. Layer layer = MergeLayers(layers, nameOfSecond, indexes[0]);
  479. layer.ChangeGuid(mergedLayerGuid);
  480. }
  481. }
  482. private void InsertLayersAtIndexesProcess(Layer[] layers, UndoLayer[] data, object[] args)
  483. {
  484. if (args.Length > 0 && args[0] is int layerIndex)
  485. {
  486. Layers.RemoveAt(layerIndex);
  487. for (int i = 0; i < layers.Length; i++)
  488. {
  489. Layer layer = layers[i];
  490. layer.IsActive = true;
  491. Layers.Insert(data[i].LayerIndex, layer);
  492. }
  493. ActiveLayerGuid = layers.First(x => x.LayerHighlightColor == MainSelectedLayerColor).LayerGuid;
  494. // Identifying main layer by highlightColor is a bit hacky, but shhh
  495. }
  496. }
  497. /// <summary>
  498. /// Moves offsets of layers by specified vector.
  499. /// </summary>
  500. private void MoveOffsets(IEnumerable<Layer> layers, Coordinates moveVector)
  501. {
  502. foreach (Layer layer in layers)
  503. {
  504. Thickness offset = layer.Offset;
  505. layer.Offset = new Thickness(offset.Left + moveVector.X, offset.Top + moveVector.Y, 0, 0);
  506. }
  507. }
  508. private void MoveOffsetsProcess(object[] arguments)
  509. {
  510. if (arguments.Length > 0 && arguments[0] is IEnumerable<Layer> layers && arguments[1] is Coordinates vector)
  511. {
  512. MoveOffsets(layers, vector);
  513. }
  514. else
  515. {
  516. throw new ArgumentException("Provided arguments were invalid. Expected IEnumerable<Layer> and Coordinates");
  517. }
  518. }
  519. private void MoveGroupInStructureProcess(object[] parameter)
  520. {
  521. Guid groupGuid = (Guid)parameter[0];
  522. Guid referenceLayerGuid = (Guid)parameter[1];
  523. bool above = (bool)parameter[2];
  524. GuidStructureItem group = LayerStructure.GetGroupByGuid(groupGuid);
  525. GuidStructureItem referenceLayerGroup = LayerStructure.GetGroupByLayer(referenceLayerGuid);
  526. Layer referenceLayer = Layers.First(x => x.LayerGuid == referenceLayerGuid);
  527. int layerIndex = Layers.IndexOf(referenceLayer);
  528. int folderTopIndex = Layers.IndexOf(Layers.First(x => x.LayerGuid == group?.EndLayerGuid));
  529. int oldIndex = folderTopIndex;
  530. if (layerIndex < folderTopIndex)
  531. {
  532. int folderBottomIndex = Layers.IndexOf(Layers.First(x => x.LayerGuid == group.StartLayerGuid));
  533. oldIndex = folderBottomIndex;
  534. }
  535. int newIndex = CalculateNewIndex(layerIndex, above, oldIndex);
  536. LayerStructure.MoveGroup(groupGuid, newIndex);
  537. LayerStructure.ReassignParent(group, referenceLayerGroup);
  538. LayerStructure.PostMoveReassignBounds(new GroupData(group?.Parent?.GroupGuid), new GroupData(group?.GroupGuid));
  539. }
  540. private int CalculateNewIndex(int layerIndex, bool above, int oldIndex)
  541. {
  542. int newIndex = layerIndex;
  543. int diff = newIndex - oldIndex;
  544. if (TriesToMoveAboveBelow(above, diff) || TriesToMoveBelowAbove(above, diff) || (above && newIndex < oldIndex) || (!above && newIndex > oldIndex))
  545. {
  546. newIndex += above ? 1 : -1;
  547. }
  548. return Math.Clamp(newIndex, 0, Layers.Count - 1);
  549. }
  550. private bool TriesToMoveAboveBelow(bool above, int diff) => above && diff == -1;
  551. private bool TriesToMoveBelowAbove(bool above, int diff) => !above && diff == 1;
  552. private void MoveLayerInStructureProcess(object[] parameter)
  553. {
  554. Guid layer = (Guid)parameter[0];
  555. Guid referenceLayer = (Guid)parameter[1];
  556. bool above = (bool)parameter[2];
  557. int layerIndex = Layers.IndexOf(Layers.First(x => x.LayerGuid == referenceLayer));
  558. int oldIndex = Layers.IndexOf(Layers.First(x => x.LayerGuid == layer));
  559. int newIndex = CalculateNewIndex(layerIndex, above, oldIndex);
  560. var startGroup = LayerStructure.GetGroupByLayer(layer);
  561. LayerStructure.PreMoveReassignBounds(new GroupData(startGroup?.GroupGuid), layer);
  562. Layers.Move(oldIndex, newIndex);
  563. var newFolder = LayerStructure.GetGroupByLayer(referenceLayer);
  564. LayerStructure.PostMoveReassignBounds(new GroupData(newFolder?.GroupGuid), layer);
  565. if (Layers.IndexOf(ActiveLayer) == oldIndex)
  566. {
  567. SetMainActiveLayer(newIndex);
  568. }
  569. RaisePropertyChanged(nameof(LayerStructure));
  570. }
  571. private void RestoreLayersProcess(Layer[] layers, UndoLayer[] layersData)
  572. {
  573. for (int i = 0; i < layers.Length; i++)
  574. {
  575. Layer layer = layers[i];
  576. Layers.Insert(layersData[i].LayerIndex, layer);
  577. if (layersData[i].IsActive)
  578. {
  579. SetMainActiveLayer(Layers.IndexOf(layer));
  580. }
  581. }
  582. }
  583. private void RemoveLayerProcess(object[] parameters)
  584. {
  585. if (parameters != null && parameters.Length > 0 && parameters[0] is Guid layerGuid)
  586. {
  587. Layer layer = Layers.First(x => x.LayerGuid == layerGuid);
  588. int index = Layers.IndexOf(layer);
  589. bool wasActive = layer.IsActive;
  590. var layerGroup = LayerStructure.GetGroupByLayer(layer.LayerGuid);
  591. LayerStructure.ExpandParentGroups(layerGroup);
  592. if (layerGroup?.Parent != null && LayerStructure.GroupContainsOnlyLayer(layer.LayerGuid, layerGroup))
  593. {
  594. LayerStructure.PreMoveReassignBounds(new GroupData(layerGroup.Parent.GroupGuid), new GroupData(layerGroup.GroupGuid));
  595. }
  596. LayerStructure.AssignParent(Layers[index].LayerGuid, null);
  597. RemoveGroupsIfEmpty(layer, layerGroup);
  598. Layers.Remove(layer);
  599. if (wasActive || Layers.IndexOf(ActiveLayer) >= index)
  600. {
  601. SetNextLayerAsActive(index);
  602. }
  603. LayersChanged?.Invoke(this, new LayersChangedEventArgs(layerGuid, LayerAction.Remove));
  604. }
  605. }
  606. private void RemoveGroupsIfEmpty(Layer layer, GuidStructureItem layerGroup)
  607. {
  608. if (LayerStructure.GroupContainsOnlyLayer(layer.LayerGuid, layerGroup))
  609. {
  610. if (layerGroup.Parent != null)
  611. {
  612. layerGroup.Parent.Subgroups.Remove(layerGroup);
  613. RemoveGroupsIfEmpty(layer, layerGroup.Parent);
  614. }
  615. else
  616. {
  617. LayerStructure.Groups.Remove(layerGroup);
  618. }
  619. }
  620. }
  621. /// <summary>
  622. /// Get's the layers suffix, e.g. "New Layer" becomes "New Layer (1)".
  623. /// </summary>
  624. /// <returns>Name of the layer with suffix.</returns>
  625. private string GetLayerSuffix(Layer layer)
  626. {
  627. Match match = reversedLayerSuffixRegex.Match(layer.Name.Reverse());
  628. int? highestValue = GetHighestSuffix(layer, match.Groups[2].Value, reversedLayerSuffixRegex);
  629. string actualName = match.Groups[2].Value.Reverse();
  630. if (highestValue == null)
  631. {
  632. return actualName;
  633. }
  634. return actualName + $" ({highestValue + 1})";
  635. }
  636. private int? GetHighestSuffix(Layer except, string layerName, Regex regex)
  637. {
  638. int? highestValue = null;
  639. foreach (Layer otherLayer in Layers)
  640. {
  641. if (otherLayer == except)
  642. {
  643. continue;
  644. }
  645. Match otherMatch = regex.Match(otherLayer.Name.Reverse());
  646. if (otherMatch.Groups[2].Value == layerName)
  647. {
  648. SetHighest(otherMatch.Groups[1].Value.Reverse(), ref highestValue);
  649. }
  650. }
  651. return highestValue;
  652. }
  653. /// <returns>Was the parse a sucess.</returns>
  654. private bool SetHighest(string number, ref int? highest, int? defaultValue = 0)
  655. {
  656. bool sucess = int.TryParse(number, out int parsedNumber);
  657. if (sucess)
  658. {
  659. if (highest == null || highest < parsedNumber)
  660. {
  661. highest = parsedNumber;
  662. }
  663. }
  664. else
  665. {
  666. if (highest == null)
  667. {
  668. highest = defaultValue;
  669. }
  670. }
  671. return sucess;
  672. }
  673. private void RemoveLayersProcess(object[] parameters)
  674. {
  675. if (parameters != null && parameters.Length > 0 && parameters[0] is IEnumerable<Guid> layerGuids)
  676. {
  677. object[] args = new object[1];
  678. foreach (var guid in layerGuids)
  679. {
  680. args[0] = guid;
  681. RemoveLayerProcess(args);
  682. }
  683. }
  684. }
  685. }
  686. }