|
@@ -1,4 +1,12 @@
|
|
-using System;
|
|
|
|
|
|
+using PixiEditor.Helpers;
|
|
|
|
+using PixiEditor.Models.Controllers;
|
|
|
|
+using PixiEditor.Models.Enums;
|
|
|
|
+using PixiEditor.Models.ImageManipulation;
|
|
|
|
+using PixiEditor.Models.Layers;
|
|
|
|
+using PixiEditor.Models.Position;
|
|
|
|
+using PixiEditor.Models.Undo;
|
|
|
|
+using System;
|
|
|
|
+using System.Buffers;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using System.Linq;
|
|
@@ -6,13 +14,6 @@ using System.Text.RegularExpressions;
|
|
using System.Windows;
|
|
using System.Windows;
|
|
using System.Windows.Media;
|
|
using System.Windows.Media;
|
|
using System.Windows.Media.Imaging;
|
|
using System.Windows.Media.Imaging;
|
|
-using PixiEditor.Helpers;
|
|
|
|
-using PixiEditor.Models.Controllers;
|
|
|
|
-using PixiEditor.Models.Enums;
|
|
|
|
-using PixiEditor.Models.ImageManipulation;
|
|
|
|
-using PixiEditor.Models.Layers;
|
|
|
|
-using PixiEditor.Models.Position;
|
|
|
|
-using PixiEditor.Models.Undo;
|
|
|
|
|
|
|
|
namespace PixiEditor.Models.DataHolders
|
|
namespace PixiEditor.Models.DataHolders
|
|
{
|
|
{
|
|
@@ -20,10 +21,31 @@ namespace PixiEditor.Models.DataHolders
|
|
{
|
|
{
|
|
public const string MainSelectedLayerColor = "#505056";
|
|
public const string MainSelectedLayerColor = "#505056";
|
|
public const string SecondarySelectedLayerColor = "#7D505056";
|
|
public const string SecondarySelectedLayerColor = "#7D505056";
|
|
- private static readonly Regex reversedLayerSuffixRegex = new (@"(?:\)([0-9]+)*\()? *([\s\S]+)", RegexOptions.Compiled);
|
|
|
|
|
|
+ private static readonly Regex reversedLayerSuffixRegex = new(@"(?:\)([0-9]+)*\()? *([\s\S]+)", RegexOptions.Compiled);
|
|
private Guid activeLayerGuid;
|
|
private Guid activeLayerGuid;
|
|
|
|
+ private LayerStructure layerStructure;
|
|
|
|
|
|
- public ObservableCollection<Layer> Layers { get; set; } = new ObservableCollection<Layer>();
|
|
|
|
|
|
+ private ObservableCollection<Layer> layers = new();
|
|
|
|
+
|
|
|
|
+ public ObservableCollection<Layer> Layers
|
|
|
|
+ {
|
|
|
|
+ get => layers;
|
|
|
|
+ set
|
|
|
|
+ {
|
|
|
|
+ layers = value;
|
|
|
|
+ Layers.CollectionChanged += Layers_CollectionChanged;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public LayerStructure LayerStructure
|
|
|
|
+ {
|
|
|
|
+ get => layerStructure;
|
|
|
|
+ set
|
|
|
|
+ {
|
|
|
|
+ layerStructure = value;
|
|
|
|
+ RaisePropertyChanged(nameof(LayerStructure));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
public Layer ActiveLayer => Layers.Count > 0 ? Layers.FirstOrDefault(x => x.LayerGuid == ActiveLayerGuid) : null;
|
|
public Layer ActiveLayer => Layers.Count > 0 ? Layers.FirstOrDefault(x => x.LayerGuid == ActiveLayerGuid) : null;
|
|
|
|
|
|
@@ -32,9 +54,12 @@ namespace PixiEditor.Models.DataHolders
|
|
get => activeLayerGuid;
|
|
get => activeLayerGuid;
|
|
set
|
|
set
|
|
{
|
|
{
|
|
- activeLayerGuid = value;
|
|
|
|
- RaisePropertyChanged(nameof(ActiveLayerGuid));
|
|
|
|
- RaisePropertyChanged(nameof(ActiveLayer));
|
|
|
|
|
|
+ if (value != activeLayerGuid)
|
|
|
|
+ {
|
|
|
|
+ activeLayerGuid = value;
|
|
|
|
+ RaisePropertyChanged(nameof(ActiveLayerGuid));
|
|
|
|
+ RaisePropertyChanged(nameof(ActiveLayer));
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -60,6 +85,35 @@ namespace PixiEditor.Models.DataHolders
|
|
LayersChanged?.Invoke(this, new LayersChangedEventArgs(ActiveLayerGuid, LayerAction.SetActive));
|
|
LayersChanged?.Invoke(this, new LayersChangedEventArgs(ActiveLayerGuid, LayerAction.SetActive));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Gets final layer IsVisible taking into consideration group visibility.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="layer">Layer to check.</param>
|
|
|
|
+ /// <returns>True if is visible, false if at least parent is not visible or layer itself is invisible.</returns>
|
|
|
|
+ public bool GetFinalLayerIsVisible(Layer layer)
|
|
|
|
+ {
|
|
|
|
+ if (!layer.IsVisible)
|
|
|
|
+ {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var group = LayerStructure.GetGroupByLayer(layer.LayerGuid);
|
|
|
|
+ bool atLeastOneParentIsInvisible = false;
|
|
|
|
+ GuidStructureItem groupToCheck = group;
|
|
|
|
+ while (groupToCheck != null)
|
|
|
|
+ {
|
|
|
|
+ if (!groupToCheck.IsVisible)
|
|
|
|
+ {
|
|
|
|
+ atLeastOneParentIsInvisible = true;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ groupToCheck = groupToCheck.Parent;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return !atLeastOneParentIsInvisible;
|
|
|
|
+ }
|
|
|
|
+
|
|
public void UpdateLayersColor()
|
|
public void UpdateLayersColor()
|
|
{
|
|
{
|
|
foreach (var layer in Layers)
|
|
foreach (var layer in Layers)
|
|
@@ -75,16 +129,65 @@ namespace PixiEditor.Models.DataHolders
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- public void MoveLayerIndexBy(int layerIndex, int amount)
|
|
|
|
|
|
+ public void MoveLayerInStructure(Guid layerGuid, Guid referenceLayer, bool above = false)
|
|
{
|
|
{
|
|
- MoveLayerProcess(new object[] { layerIndex, amount });
|
|
|
|
|
|
+ var args = new object[] { layerGuid, referenceLayer, above };
|
|
|
|
+
|
|
|
|
+ Layer layer = Layers.First(x => x.LayerGuid == layerGuid);
|
|
|
|
+
|
|
|
|
+ int oldIndex = Layers.IndexOf(layer);
|
|
|
|
+
|
|
|
|
+ var oldLayerStrcutureGroups = LayerStructure.CloneGroups();
|
|
|
|
+
|
|
|
|
+ MoveLayerInStructureProcess(args);
|
|
|
|
+
|
|
|
|
+ AddLayerStructureToUndo(oldLayerStrcutureGroups);
|
|
|
|
|
|
UndoManager.AddUndoChange(new Change(
|
|
UndoManager.AddUndoChange(new Change(
|
|
- MoveLayerProcess,
|
|
|
|
- new object[] { layerIndex + amount, -amount },
|
|
|
|
- MoveLayerProcess,
|
|
|
|
- new object[] { layerIndex, amount },
|
|
|
|
|
|
+ ReverseMoveLayerInStructureProcess,
|
|
|
|
+ new object[] { oldIndex, layerGuid },
|
|
|
|
+ MoveLayerInStructureProcess,
|
|
|
|
+ args,
|
|
"Move layer"));
|
|
"Move layer"));
|
|
|
|
+
|
|
|
|
+ UndoManager.SquashUndoChanges(2, "Move layer");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public void MoveGroupInStructure(Guid groupGuid, Guid referenceLayer, bool above = false)
|
|
|
|
+ {
|
|
|
|
+ var args = new object[] { groupGuid, referenceLayer, above };
|
|
|
|
+
|
|
|
|
+ var topLayer = Layers.First(x => x.LayerGuid == LayerStructure.GetGroupByGuid(groupGuid).EndLayerGuid);
|
|
|
|
+ var bottomLayer = Layers.First(x => x.LayerGuid == LayerStructure.GetGroupByGuid(groupGuid).StartLayerGuid);
|
|
|
|
+
|
|
|
|
+ int indexOfTopLayer = Layers.IndexOf(topLayer);
|
|
|
|
+ Guid oldReferenceLayerGuid;
|
|
|
|
+ bool oldAbove = false;
|
|
|
|
+
|
|
|
|
+ if (indexOfTopLayer + 1 < Layers.Count)
|
|
|
|
+ {
|
|
|
|
+ oldReferenceLayerGuid = topLayer.LayerGuid;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ int indexOfBottomLayer = Layers.IndexOf(bottomLayer);
|
|
|
|
+ oldReferenceLayerGuid = Layers[indexOfBottomLayer - 1].LayerGuid;
|
|
|
|
+ oldAbove = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var oldLayerStructure = LayerStructure.CloneGroups();
|
|
|
|
+
|
|
|
|
+ MoveGroupInStructureProcess(args);
|
|
|
|
+
|
|
|
|
+ AddLayerStructureToUndo(oldLayerStructure);
|
|
|
|
+
|
|
|
|
+ UndoManager.AddUndoChange(new Change(
|
|
|
|
+ MoveGroupInStructureProcess,
|
|
|
|
+ new object[] { groupGuid, oldReferenceLayerGuid, oldAbove },
|
|
|
|
+ MoveGroupInStructureProcess,
|
|
|
|
+ args));
|
|
|
|
+
|
|
|
|
+ UndoManager.SquashUndoChanges(2, "Move group");
|
|
}
|
|
}
|
|
|
|
|
|
public void AddNewLayer(string name, WriteableBitmap bitmap, bool setAsActive = true)
|
|
public void AddNewLayer(string name, WriteableBitmap bitmap, bool setAsActive = true)
|
|
@@ -117,7 +220,7 @@ namespace PixiEditor.Models.DataHolders
|
|
|
|
|
|
if (Layers.Count > 1)
|
|
if (Layers.Count > 1)
|
|
{
|
|
{
|
|
- StorageBasedChange storageChange = new StorageBasedChange(this, new[] { Layers[^1] }, false);
|
|
|
|
|
|
+ StorageBasedChange storageChange = new(this, new[] { Layers[^1] }, false);
|
|
UndoManager.AddUndoChange(
|
|
UndoManager.AddUndoChange(
|
|
storageChange.ToChange(
|
|
storageChange.ToChange(
|
|
RemoveLayerProcess,
|
|
RemoveLayerProcess,
|
|
@@ -126,7 +229,7 @@ namespace PixiEditor.Models.DataHolders
|
|
"Add layer"));
|
|
"Add layer"));
|
|
}
|
|
}
|
|
|
|
|
|
- LayersChanged?.Invoke(this, new LayersChangedEventArgs(Layers[0].LayerGuid, LayerAction.Add));
|
|
|
|
|
|
+ LayersChanged?.Invoke(this, new LayersChangedEventArgs(Layers[^1].LayerGuid, LayerAction.Add));
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
@@ -143,7 +246,7 @@ namespace PixiEditor.Models.DataHolders
|
|
Layers.Insert(index + 1, duplicate);
|
|
Layers.Insert(index + 1, duplicate);
|
|
SetMainActiveLayer(index + 1);
|
|
SetMainActiveLayer(index + 1);
|
|
|
|
|
|
- StorageBasedChange storageChange = new (this, new[] { duplicate }, false);
|
|
|
|
|
|
+ StorageBasedChange storageChange = new(this, new[] { duplicate }, false);
|
|
UndoManager.AddUndoChange(
|
|
UndoManager.AddUndoChange(
|
|
storageChange.ToChange(
|
|
storageChange.ToChange(
|
|
RemoveLayerProcess,
|
|
RemoveLayerProcess,
|
|
@@ -231,18 +334,23 @@ namespace PixiEditor.Models.DataHolders
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- public void RemoveLayer(int layerIndex)
|
|
|
|
|
|
+ public void RemoveLayer(int layerIndex, bool addToUndo = true)
|
|
{
|
|
{
|
|
if (Layers.Count == 0)
|
|
if (Layers.Count == 0)
|
|
{
|
|
{
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ LayerStructure.AssignParent(Layers[layerIndex].LayerGuid, null);
|
|
|
|
+
|
|
bool wasActive = Layers[layerIndex].IsActive;
|
|
bool wasActive = Layers[layerIndex].IsActive;
|
|
|
|
|
|
- StorageBasedChange change = new StorageBasedChange(this, new[] { Layers[layerIndex] });
|
|
|
|
- UndoManager.AddUndoChange(
|
|
|
|
- change.ToChange(RestoreLayersProcess, RemoveLayerProcess, new object[] { Layers[layerIndex].LayerGuid }, "Remove layer"));
|
|
|
|
|
|
+ StorageBasedChange change = new(this, new[] { Layers[layerIndex] });
|
|
|
|
+ if (addToUndo)
|
|
|
|
+ {
|
|
|
|
+ UndoManager.AddUndoChange(
|
|
|
|
+ change.ToChange(RestoreLayersProcess, RemoveLayerProcess, new object[] { Layers[layerIndex].LayerGuid }));
|
|
|
|
+ }
|
|
|
|
|
|
Layers.RemoveAt(layerIndex);
|
|
Layers.RemoveAt(layerIndex);
|
|
if (wasActive)
|
|
if (wasActive)
|
|
@@ -251,9 +359,9 @@ namespace PixiEditor.Models.DataHolders
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- public void RemoveLayer(Layer layer)
|
|
|
|
|
|
+ public void RemoveLayer(Layer layer, bool addToUndo)
|
|
{
|
|
{
|
|
- RemoveLayer(Layers.IndexOf(layer));
|
|
|
|
|
|
+ RemoveLayer(Layers.IndexOf(layer), addToUndo);
|
|
}
|
|
}
|
|
|
|
|
|
public void RemoveActiveLayers()
|
|
public void RemoveActiveLayers()
|
|
@@ -263,18 +371,35 @@ namespace PixiEditor.Models.DataHolders
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ var oldLayerStructure = LayerStructure.CloneGroups();
|
|
|
|
+
|
|
Layer[] layers = Layers.Where(x => x.IsActive).ToArray();
|
|
Layer[] layers = Layers.Where(x => x.IsActive).ToArray();
|
|
int firstIndex = Layers.IndexOf(layers[0]);
|
|
int firstIndex = Layers.IndexOf(layers[0]);
|
|
|
|
|
|
object[] guidArgs = new object[] { layers.Select(x => x.LayerGuid).ToArray() };
|
|
object[] guidArgs = new object[] { layers.Select(x => x.LayerGuid).ToArray() };
|
|
|
|
|
|
- StorageBasedChange change = new StorageBasedChange(this, layers);
|
|
|
|
|
|
+ StorageBasedChange change = new(this, layers);
|
|
|
|
|
|
RemoveLayersProcess(guidArgs);
|
|
RemoveLayersProcess(guidArgs);
|
|
|
|
|
|
|
|
+ AddLayerStructureToUndo(oldLayerStructure);
|
|
|
|
+
|
|
InjectRemoveActiveLayersUndo(guidArgs, change);
|
|
InjectRemoveActiveLayersUndo(guidArgs, change);
|
|
|
|
|
|
|
|
+ UndoManager.SquashUndoChanges(2, "Removed active layers");
|
|
|
|
+
|
|
SetNextLayerAsActive(firstIndex);
|
|
SetNextLayerAsActive(firstIndex);
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public void AddLayerStructureToUndo(ObservableCollection<GuidStructureItem> oldLayerStructureGroups)
|
|
|
|
+ {
|
|
|
|
+ UndoManager.AddUndoChange(
|
|
|
|
+ new Change(
|
|
|
|
+ BuildLayerStructureProcess,
|
|
|
|
+ new[] { oldLayerStructureGroups },
|
|
|
|
+ BuildLayerStructureProcess,
|
|
|
|
+ new[] { LayerStructure.CloneGroups() }));
|
|
}
|
|
}
|
|
|
|
|
|
public Layer MergeLayers(Layer[] layersToMerge, bool nameOfLast, int index)
|
|
public Layer MergeLayers(Layer[] layersToMerge, bool nameOfLast, int index)
|
|
@@ -286,7 +411,7 @@ namespace PixiEditor.Models.DataHolders
|
|
|
|
|
|
string name;
|
|
string name;
|
|
|
|
|
|
- // Wich name should be used
|
|
|
|
|
|
+ // Which name should be used
|
|
if (nameOfLast)
|
|
if (nameOfLast)
|
|
{
|
|
{
|
|
name = layersToMerge[^1].Name;
|
|
name = layersToMerge[^1].Name;
|
|
@@ -298,17 +423,26 @@ namespace PixiEditor.Models.DataHolders
|
|
|
|
|
|
Layer mergedLayer = layersToMerge[0];
|
|
Layer mergedLayer = layersToMerge[0];
|
|
|
|
|
|
|
|
+ var groupParent = LayerStructure.GetGroupByLayer(layersToMerge[^1].LayerGuid);
|
|
|
|
+
|
|
|
|
+ Layer placeholderLayer = new("_placeholder");
|
|
|
|
+ Layers.Insert(index, placeholderLayer);
|
|
|
|
+ LayerStructure.AssignParent(placeholderLayer.LayerGuid, groupParent?.GroupGuid);
|
|
|
|
+
|
|
for (int i = 0; i < layersToMerge.Length - 1; i++)
|
|
for (int i = 0; i < layersToMerge.Length - 1; i++)
|
|
{
|
|
{
|
|
Layer firstLayer = mergedLayer;
|
|
Layer firstLayer = mergedLayer;
|
|
Layer secondLayer = layersToMerge[i + 1];
|
|
Layer secondLayer = layersToMerge[i + 1];
|
|
mergedLayer = firstLayer.MergeWith(secondLayer, name, Width, Height);
|
|
mergedLayer = firstLayer.MergeWith(secondLayer, name, Width, Height);
|
|
- Layers.Remove(layersToMerge[i]);
|
|
|
|
|
|
+ RemoveLayer(layersToMerge[i], false);
|
|
}
|
|
}
|
|
|
|
|
|
- Layers.Remove(layersToMerge[^1]);
|
|
|
|
-
|
|
|
|
Layers.Insert(index, mergedLayer);
|
|
Layers.Insert(index, mergedLayer);
|
|
|
|
+ LayerStructure.AssignParent(mergedLayer.LayerGuid, groupParent?.GroupGuid);
|
|
|
|
+
|
|
|
|
+ RemoveLayer(placeholderLayer, false);
|
|
|
|
+
|
|
|
|
+ RemoveLayer(layersToMerge[^1], false);
|
|
|
|
|
|
SetMainActiveLayer(Layers.IndexOf(mergedLayer));
|
|
SetMainActiveLayer(Layers.IndexOf(mergedLayer));
|
|
|
|
|
|
@@ -324,18 +458,23 @@ namespace PixiEditor.Models.DataHolders
|
|
|
|
|
|
IEnumerable<Layer> undoArgs = layersToMerge;
|
|
IEnumerable<Layer> undoArgs = layersToMerge;
|
|
|
|
|
|
- StorageBasedChange undoChange = new StorageBasedChange(this, undoArgs);
|
|
|
|
|
|
+ var oldLayerStructure = LayerStructure.CloneGroups();
|
|
|
|
+
|
|
|
|
+ StorageBasedChange undoChange = new(this, undoArgs);
|
|
|
|
|
|
int[] indexes = layersToMerge.Select(x => Layers.IndexOf(x)).ToArray();
|
|
int[] indexes = layersToMerge.Select(x => Layers.IndexOf(x)).ToArray();
|
|
|
|
|
|
var layer = MergeLayers(layersToMerge, nameIsLastLayers, Layers.IndexOf(layersToMerge[0]));
|
|
var layer = MergeLayers(layersToMerge, nameIsLastLayers, Layers.IndexOf(layersToMerge[0]));
|
|
|
|
|
|
|
|
+ AddLayerStructureToUndo(oldLayerStructure);
|
|
|
|
+
|
|
UndoManager.AddUndoChange(undoChange.ToChange(
|
|
UndoManager.AddUndoChange(undoChange.ToChange(
|
|
InsertLayersAtIndexesProcess,
|
|
InsertLayersAtIndexesProcess,
|
|
new object[] { indexes[0] },
|
|
new object[] { indexes[0] },
|
|
MergeLayersProcess,
|
|
MergeLayersProcess,
|
|
- new object[] { indexes, nameIsLastLayers, layer.LayerGuid },
|
|
|
|
- "Undo merge layers"));
|
|
|
|
|
|
+ new object[] { indexes, nameIsLastLayers, layer.LayerGuid }));
|
|
|
|
+
|
|
|
|
+ UndoManager.SquashUndoChanges(2, "Undo merge layers");
|
|
|
|
|
|
return layer;
|
|
return layer;
|
|
}
|
|
}
|
|
@@ -345,6 +484,37 @@ namespace PixiEditor.Models.DataHolders
|
|
return BitmapUtils.GetColorAtPointCombined(x, y, Layers.ToArray());
|
|
return BitmapUtils.GetColorAtPointCombined(x, y, Layers.ToArray());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private void BuildLayerStructureProcess(object[] parameters)
|
|
|
|
+ {
|
|
|
|
+ if (parameters.Length > 0 && parameters[0] is ObservableCollection<GuidStructureItem> groups)
|
|
|
|
+ {
|
|
|
|
+ LayerStructure.Groups.CollectionChanged -= Groups_CollectionChanged;
|
|
|
|
+ LayerStructure.Groups = LayerStructure.CloneGroups(groups);
|
|
|
|
+ LayerStructure.Groups.CollectionChanged += Groups_CollectionChanged;
|
|
|
|
+ RaisePropertyChanged(nameof(LayerStructure));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void ReverseMoveLayerInStructureProcess(object[] props)
|
|
|
|
+ {
|
|
|
|
+ int indexTo = (int)props[0];
|
|
|
|
+ Guid layerGuid = (Guid)props[1];
|
|
|
|
+
|
|
|
|
+ Guid layerAtOldIndex = Layers[indexTo].LayerGuid;
|
|
|
|
+
|
|
|
|
+ var startGroup = LayerStructure.GetGroupByLayer(layerGuid);
|
|
|
|
+
|
|
|
|
+ LayerStructure.PreMoveReassignBounds(new GroupData(startGroup?.GroupGuid), layerGuid);
|
|
|
|
+
|
|
|
|
+ Layers.Move(Layers.IndexOf(Layers.First(x => x.LayerGuid == layerGuid)), indexTo);
|
|
|
|
+
|
|
|
|
+ var newGroup = LayerStructure.GetGroupByLayer(layerAtOldIndex);
|
|
|
|
+
|
|
|
|
+ LayerStructure.PostMoveReassignBounds(new GroupData(newGroup?.GroupGuid), layerGuid);
|
|
|
|
+
|
|
|
|
+ RaisePropertyChanged(nameof(LayerStructure));
|
|
|
|
+ }
|
|
|
|
+
|
|
private void InjectRemoveActiveLayersUndo(object[] guidArgs, StorageBasedChange change)
|
|
private void InjectRemoveActiveLayersUndo(object[] guidArgs, StorageBasedChange change)
|
|
{
|
|
{
|
|
Action<Layer[], UndoLayer[]> undoAction = RestoreLayersProcess;
|
|
Action<Layer[], UndoLayer[]> undoAction = RestoreLayersProcess;
|
|
@@ -352,7 +522,7 @@ namespace PixiEditor.Models.DataHolders
|
|
|
|
|
|
if (Layers.Count == 0)
|
|
if (Layers.Count == 0)
|
|
{
|
|
{
|
|
- Layer layer = new Layer("Base Layer");
|
|
|
|
|
|
+ Layer layer = new("Base Layer", 0, 0) { MaxHeight = Height, MaxWidth = Width };
|
|
Layers.Add(layer);
|
|
Layers.Add(layer);
|
|
undoAction = (Layer[] layers, UndoLayer[] undoData) =>
|
|
undoAction = (Layer[] layers, UndoLayer[] undoData) =>
|
|
{
|
|
{
|
|
@@ -434,16 +604,80 @@ namespace PixiEditor.Models.DataHolders
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private void MoveLayerProcess(object[] parameter)
|
|
|
|
|
|
+ private void MoveGroupInStructureProcess(object[] parameter)
|
|
{
|
|
{
|
|
- int layerIndex = (int)parameter[0];
|
|
|
|
- int amount = (int)parameter[1];
|
|
|
|
|
|
+ Guid groupGuid = (Guid)parameter[0];
|
|
|
|
+ Guid referenceLayerGuid = (Guid)parameter[1];
|
|
|
|
+ bool above = (bool)parameter[2];
|
|
|
|
+
|
|
|
|
+ GuidStructureItem group = LayerStructure.GetGroupByGuid(groupGuid);
|
|
|
|
+ GuidStructureItem referenceLayerGroup = LayerStructure.GetGroupByLayer(referenceLayerGuid);
|
|
|
|
+
|
|
|
|
+ Layer referenceLayer = Layers.First(x => x.LayerGuid == referenceLayerGuid);
|
|
|
|
|
|
- Layers.Move(layerIndex, layerIndex + amount);
|
|
|
|
- if (Layers.IndexOf(ActiveLayer) == layerIndex)
|
|
|
|
|
|
+ int layerIndex = Layers.IndexOf(referenceLayer);
|
|
|
|
+ int folderTopIndex = Layers.IndexOf(Layers.First(x => x.LayerGuid == group?.EndLayerGuid));
|
|
|
|
+ int oldIndex = folderTopIndex;
|
|
|
|
+
|
|
|
|
+ if (layerIndex < folderTopIndex)
|
|
{
|
|
{
|
|
- SetMainActiveLayer(layerIndex + amount);
|
|
|
|
|
|
+ int folderBottomIndex = Layers.IndexOf(Layers.First(x => x.LayerGuid == group.StartLayerGuid));
|
|
|
|
+ oldIndex = folderBottomIndex;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ int newIndex = CalculateNewIndex(layerIndex, above, oldIndex);
|
|
|
|
+
|
|
|
|
+ LayerStructure.MoveGroup(groupGuid, newIndex);
|
|
|
|
+
|
|
|
|
+ LayerStructure.ReassignParent(group, referenceLayerGroup);
|
|
|
|
+
|
|
|
|
+ LayerStructure.PostMoveReassignBounds(new GroupData(group?.Parent?.GroupGuid), new GroupData(group?.GroupGuid));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private int CalculateNewIndex(int layerIndex, bool above, int oldIndex)
|
|
|
|
+ {
|
|
|
|
+ int newIndex = layerIndex;
|
|
|
|
+
|
|
|
|
+ int diff = newIndex - oldIndex;
|
|
|
|
+
|
|
|
|
+ if (TriesToMoveAboveBelow(above, diff) || TriesToMoveBelowAbove(above, diff) || (above && newIndex < oldIndex) || (!above && newIndex > oldIndex))
|
|
|
|
+ {
|
|
|
|
+ newIndex += above ? 1 : -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return Math.Clamp(newIndex, 0, Layers.Count - 1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private bool TriesToMoveAboveBelow(bool above, int diff) => above && diff == -1;
|
|
|
|
+
|
|
|
|
+ private bool TriesToMoveBelowAbove(bool above, int diff) => !above && diff == 1;
|
|
|
|
+
|
|
|
|
+ private void MoveLayerInStructureProcess(object[] parameter)
|
|
|
|
+ {
|
|
|
|
+ Guid layer = (Guid)parameter[0];
|
|
|
|
+ Guid referenceLayer = (Guid)parameter[1];
|
|
|
|
+ bool above = (bool)parameter[2];
|
|
|
|
+
|
|
|
|
+ int layerIndex = Layers.IndexOf(Layers.First(x => x.LayerGuid == referenceLayer));
|
|
|
|
+ int oldIndex = Layers.IndexOf(Layers.First(x => x.LayerGuid == layer));
|
|
|
|
+ int newIndex = CalculateNewIndex(layerIndex, above, oldIndex);
|
|
|
|
+
|
|
|
|
+ var startGroup = LayerStructure.GetGroupByLayer(layer);
|
|
|
|
+
|
|
|
|
+ LayerStructure.PreMoveReassignBounds(new GroupData(startGroup?.GroupGuid), layer);
|
|
|
|
+
|
|
|
|
+ Layers.Move(oldIndex, newIndex);
|
|
|
|
+
|
|
|
|
+ var newFolder = LayerStructure.GetGroupByLayer(referenceLayer);
|
|
|
|
+
|
|
|
|
+ LayerStructure.PostMoveReassignBounds(new GroupData(newFolder?.GroupGuid), layer);
|
|
|
|
+
|
|
|
|
+ if (Layers.IndexOf(ActiveLayer) == oldIndex)
|
|
|
|
+ {
|
|
|
|
+ SetMainActiveLayer(newIndex);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ RaisePropertyChanged(nameof(LayerStructure));
|
|
}
|
|
}
|
|
|
|
|
|
private void RestoreLayersProcess(Layer[] layers, UndoLayer[] layersData)
|
|
private void RestoreLayersProcess(Layer[] layers, UndoLayer[] layersData)
|
|
@@ -467,12 +701,42 @@ namespace PixiEditor.Models.DataHolders
|
|
Layer layer = Layers.First(x => x.LayerGuid == layerGuid);
|
|
Layer layer = Layers.First(x => x.LayerGuid == layerGuid);
|
|
int index = Layers.IndexOf(layer);
|
|
int index = Layers.IndexOf(layer);
|
|
bool wasActive = layer.IsActive;
|
|
bool wasActive = layer.IsActive;
|
|
|
|
+
|
|
|
|
+ var layerGroup = LayerStructure.GetGroupByLayer(layer.LayerGuid);
|
|
|
|
+
|
|
|
|
+ LayerStructure.ExpandParentGroups(layerGroup);
|
|
|
|
+
|
|
|
|
+ if (layerGroup?.Parent != null && LayerStructure.GroupContainsOnlyLayer(layer.LayerGuid, layerGroup))
|
|
|
|
+ {
|
|
|
|
+ LayerStructure.PreMoveReassignBounds(new GroupData(layerGroup.Parent.GroupGuid), new GroupData(layerGroup.GroupGuid));
|
|
|
|
+ }
|
|
|
|
+ LayerStructure.AssignParent(Layers[index].LayerGuid, null);
|
|
|
|
+ RemoveGroupsIfEmpty(layer, layerGroup);
|
|
|
|
+
|
|
Layers.Remove(layer);
|
|
Layers.Remove(layer);
|
|
|
|
|
|
if (wasActive || Layers.IndexOf(ActiveLayer) >= index)
|
|
if (wasActive || Layers.IndexOf(ActiveLayer) >= index)
|
|
{
|
|
{
|
|
SetNextLayerAsActive(index);
|
|
SetNextLayerAsActive(index);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ LayersChanged?.Invoke(this, new LayersChangedEventArgs(layerGuid, LayerAction.Remove));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void RemoveGroupsIfEmpty(Layer layer, GuidStructureItem layerGroup)
|
|
|
|
+ {
|
|
|
|
+ if (LayerStructure.GroupContainsOnlyLayer(layer.LayerGuid, layerGroup))
|
|
|
|
+ {
|
|
|
|
+ if (layerGroup.Parent != null)
|
|
|
|
+ {
|
|
|
|
+ layerGroup.Parent.Subgroups.Remove(layerGroup);
|
|
|
|
+ RemoveGroupsIfEmpty(layer, layerGroup.Parent);
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ LayerStructure.Groups.Remove(layerGroup);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -554,4 +818,4 @@ namespace PixiEditor.Models.DataHolders
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-}
|
|
|
|
|
|
+}
|