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