|
@@ -1,5 +1,8 @@
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using PixiEditor.ChangeableDocument.Changeables.Animations;
|
|
using PixiEditor.ChangeableDocument.Changeables.Animations;
|
|
|
|
+using PixiEditor.ChangeableDocument.Changeables.Graph;
|
|
|
|
+using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
|
|
|
|
+using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
|
|
using PixiEditor.ChangeableDocument.Changeables.Interfaces;
|
|
using PixiEditor.ChangeableDocument.Changeables.Interfaces;
|
|
using PixiEditor.DrawingApi.Core.Numerics;
|
|
using PixiEditor.DrawingApi.Core.Numerics;
|
|
using PixiEditor.Numerics;
|
|
using PixiEditor.Numerics;
|
|
@@ -8,14 +11,19 @@ namespace PixiEditor.ChangeableDocument.Changeables;
|
|
|
|
|
|
internal class Document : IChangeable, IReadOnlyDocument, IDisposable
|
|
internal class Document : IChangeable, IReadOnlyDocument, IDisposable
|
|
{
|
|
{
|
|
- IReadOnlyFolder IReadOnlyDocument.StructureRoot => StructureRoot;
|
|
|
|
|
|
+ IReadOnlyNodeGraph IReadOnlyDocument.NodeGraph => NodeGraph;
|
|
IReadOnlySelection IReadOnlyDocument.Selection => Selection;
|
|
IReadOnlySelection IReadOnlyDocument.Selection => Selection;
|
|
IReadOnlyAnimationData IReadOnlyDocument.AnimationData => AnimationData;
|
|
IReadOnlyAnimationData IReadOnlyDocument.AnimationData => AnimationData;
|
|
- IReadOnlyStructureMember? IReadOnlyDocument.FindMember(Guid guid) => FindMember(guid);
|
|
|
|
- bool IReadOnlyDocument.TryFindMember(Guid guid, [NotNullWhen(true)] out IReadOnlyStructureMember? member) => TryFindMember(guid, out member);
|
|
|
|
- IReadOnlyList<IReadOnlyStructureMember> IReadOnlyDocument.FindMemberPath(Guid guid) => FindMemberPath(guid);
|
|
|
|
- IReadOnlyStructureMember IReadOnlyDocument.FindMemberOrThrow(Guid guid) => FindMemberOrThrow(guid);
|
|
|
|
- (IReadOnlyStructureMember, IReadOnlyFolder) IReadOnlyDocument.FindChildAndParentOrThrow(Guid guid) => FindChildAndParentOrThrow(guid);
|
|
|
|
|
|
+ IReadOnlyStructureNode? IReadOnlyDocument.FindMember(Guid guid) => FindMember(guid);
|
|
|
|
+
|
|
|
|
+ bool IReadOnlyDocument.TryFindMember(Guid guid, [NotNullWhen(true)] out IReadOnlyStructureNode? member) =>
|
|
|
|
+ TryFindMember(guid, out member);
|
|
|
|
+
|
|
|
|
+ IReadOnlyList<IReadOnlyStructureNode> IReadOnlyDocument.FindMemberPath(Guid guid) => FindMemberPath(guid);
|
|
|
|
+ IReadOnlyStructureNode IReadOnlyDocument.FindMemberOrThrow(Guid guid) => FindMemberOrThrow(guid);
|
|
|
|
+
|
|
|
|
+ (IReadOnlyStructureNode, IReadOnlyFolderNode) IReadOnlyDocument.FindChildAndParentOrThrow(Guid guid) =>
|
|
|
|
+ FindChildAndParentOrThrow(guid);
|
|
|
|
|
|
IReadOnlyReferenceLayer? IReadOnlyDocument.ReferenceLayer => ReferenceLayer;
|
|
IReadOnlyReferenceLayer? IReadOnlyDocument.ReferenceLayer => ReferenceLayer;
|
|
|
|
|
|
@@ -23,7 +31,8 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
|
|
/// The default size for a new document
|
|
/// The default size for a new document
|
|
/// </summary>
|
|
/// </summary>
|
|
public static VecI DefaultSize { get; } = new VecI(64, 64);
|
|
public static VecI DefaultSize { get; } = new VecI(64, 64);
|
|
- internal Folder StructureRoot { get; } = new() { GuidValue = Guid.Empty };
|
|
|
|
|
|
+
|
|
|
|
+ internal NodeGraph NodeGraph { get; } = new();
|
|
internal Selection Selection { get; } = new();
|
|
internal Selection Selection { get; } = new();
|
|
internal ReferenceLayer? ReferenceLayer { get; set; }
|
|
internal ReferenceLayer? ReferenceLayer { get; set; }
|
|
internal AnimationData AnimationData { get; }
|
|
internal AnimationData AnimationData { get; }
|
|
@@ -32,7 +41,7 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
|
|
public bool VerticalSymmetryAxisEnabled { get; set; }
|
|
public bool VerticalSymmetryAxisEnabled { get; set; }
|
|
public double HorizontalSymmetryAxisY { get; set; }
|
|
public double HorizontalSymmetryAxisY { get; set; }
|
|
public double VerticalSymmetryAxisX { get; set; }
|
|
public double VerticalSymmetryAxisX { get; set; }
|
|
-
|
|
|
|
|
|
+
|
|
public Document()
|
|
public Document()
|
|
{
|
|
{
|
|
AnimationData = new AnimationData(this);
|
|
AnimationData = new AnimationData(this);
|
|
@@ -40,10 +49,10 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
|
|
|
|
|
|
public void Dispose()
|
|
public void Dispose()
|
|
{
|
|
{
|
|
- StructureRoot.Dispose();
|
|
|
|
|
|
+ NodeGraph.Dispose();
|
|
Selection.Dispose();
|
|
Selection.Dispose();
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Creates a surface for layer image.
|
|
/// Creates a surface for layer image.
|
|
/// </summary>
|
|
/// </summary>
|
|
@@ -55,7 +64,7 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
|
|
/// you are lucky enough. Have fun!</remarks>
|
|
/// you are lucky enough. Have fun!</remarks>
|
|
public Surface? GetLayerRasterizedImage(Guid layerGuid, int frame)
|
|
public Surface? GetLayerRasterizedImage(Guid layerGuid, int frame)
|
|
{
|
|
{
|
|
- var layer = (IReadOnlyLayer?)FindMember(layerGuid);
|
|
|
|
|
|
+ var layer = (IReadOnlyLayerNode?)FindMember(layerGuid);
|
|
|
|
|
|
if (layer is null)
|
|
if (layer is null)
|
|
throw new ArgumentException(@"The given guid does not belong to a layer.", nameof(layerGuid));
|
|
throw new ArgumentException(@"The given guid does not belong to a layer.", nameof(layerGuid));
|
|
@@ -70,7 +79,7 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
|
|
|
|
|
|
Surface surface = new Surface(tightBounds.Value.Size);
|
|
Surface surface = new Surface(tightBounds.Value.Size);
|
|
|
|
|
|
- layer.Rasterize(frame).DrawMostUpToDateRegionOn(
|
|
|
|
|
|
+ layer.Execute(frame).DrawMostUpToDateRegionOn(
|
|
tightBounds.Value,
|
|
tightBounds.Value,
|
|
ChunkResolution.Full,
|
|
ChunkResolution.Full,
|
|
surface.DrawingSurface, VecI.Zero);
|
|
surface.DrawingSurface, VecI.Zero);
|
|
@@ -80,7 +89,7 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
|
|
|
|
|
|
public RectI? GetChunkAlignedLayerBounds(Guid layerGuid, int frame)
|
|
public RectI? GetChunkAlignedLayerBounds(Guid layerGuid, int frame)
|
|
{
|
|
{
|
|
- var layer = (IReadOnlyLayer?)FindMember(layerGuid);
|
|
|
|
|
|
+ var layer = (IReadOnlyLayerNode?)FindMember(layerGuid);
|
|
|
|
|
|
if (layer is null)
|
|
if (layer is null)
|
|
throw new ArgumentException(@"The given guid does not belong to a layer.", nameof(layerGuid));
|
|
throw new ArgumentException(@"The given guid does not belong to a layer.", nameof(layerGuid));
|
|
@@ -88,38 +97,45 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
|
|
|
|
|
|
return layer.GetTightBounds(frame);
|
|
return layer.GetTightBounds(frame);
|
|
}
|
|
}
|
|
-
|
|
|
|
- public void ForEveryReadonlyMember(Action<IReadOnlyStructureMember> action) => ForEveryReadonlyMember(StructureRoot, action);
|
|
|
|
|
|
+
|
|
|
|
+ public void ForEveryReadonlyMember(Action<IReadOnlyStructureNode> action) =>
|
|
|
|
+ ForEveryReadonlyMember(NodeGraph, action);
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Performs the specified action on each member of the document
|
|
/// Performs the specified action on each member of the document
|
|
/// </summary>
|
|
/// </summary>
|
|
- public void ForEveryMember(Action<StructureMember> action) => ForEveryMember(StructureRoot, action);
|
|
|
|
|
|
+ public void ForEveryMember(Action<StructureNode> action) => ForEveryMember(NodeGraph, action);
|
|
|
|
|
|
- private void ForEveryReadonlyMember(IReadOnlyFolder folder, Action<IReadOnlyStructureMember> action)
|
|
|
|
|
|
+ private void ForEveryReadonlyMember(IReadOnlyNodeGraph graph, Action<IReadOnlyStructureNode> action)
|
|
{
|
|
{
|
|
- foreach (var child in folder.Children)
|
|
|
|
|
|
+ graph.TryTraverse((node) =>
|
|
{
|
|
{
|
|
- action(child);
|
|
|
|
- if (child is IReadOnlyFolder innerFolder)
|
|
|
|
- ForEveryReadonlyMember(innerFolder, action);
|
|
|
|
- }
|
|
|
|
|
|
+ if (node is not IReadOnlyStructureNode structureNode)
|
|
|
|
+ {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ action(structureNode);
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
- private void ForEveryMember(Folder folder, Action<StructureMember> action)
|
|
|
|
|
|
+ private void ForEveryMember(NodeGraph graph, Action<StructureNode> action)
|
|
{
|
|
{
|
|
- foreach (var child in folder.Children)
|
|
|
|
|
|
+ graph.TryTraverse((node) =>
|
|
{
|
|
{
|
|
- action(child);
|
|
|
|
- if (child is Folder innerFolder)
|
|
|
|
- ForEveryMember(innerFolder, action);
|
|
|
|
- }
|
|
|
|
|
|
+ if (node is not StructureNode structureNode)
|
|
|
|
+ {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ action(structureNode);
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Checks if a member with the <paramref name="guid"/> exists
|
|
/// Checks if a member with the <paramref name="guid"/> exists
|
|
/// </summary>
|
|
/// </summary>
|
|
- /// <param name="guid">The <see cref="StructureMember.GuidValue"/> of the member</param>
|
|
|
|
|
|
+ /// <param name="guid">The <see cref="StructureNode.Id"/> of the member</param>
|
|
/// <returns>True if the member can be found, otherwise false</returns>
|
|
/// <returns>True if the member can be found, otherwise false</returns>
|
|
public bool HasMember(Guid guid)
|
|
public bool HasMember(Guid guid)
|
|
{
|
|
{
|
|
@@ -130,47 +146,78 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Checks if a member with the <paramref name="guid"/> exists and is of type <typeparamref name="T"/>
|
|
/// Checks if a member with the <paramref name="guid"/> exists and is of type <typeparamref name="T"/>
|
|
/// </summary>
|
|
/// </summary>
|
|
- /// <param name="guid">The <see cref="StructureMember.GuidValue"/> of the member</param>
|
|
|
|
|
|
+ /// <param name="guid">The <see cref="StructureNode.Id"/> of the member</param>
|
|
/// <returns>True if the member can be found and is of type <typeparamref name="T"/>, otherwise false</returns>
|
|
/// <returns>True if the member can be found and is of type <typeparamref name="T"/>, otherwise false</returns>
|
|
- public bool HasMember<T>(Guid guid)
|
|
|
|
- where T : StructureMember
|
|
|
|
|
|
+ public bool HasMember<T>(Guid guid)
|
|
|
|
+ where T : StructureNode
|
|
{
|
|
{
|
|
var list = FindMemberPath(guid);
|
|
var list = FindMemberPath(guid);
|
|
return list.Count > 0 && list[0] is T;
|
|
return list.Count > 0 && list[0] is T;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Finds the member with the <paramref name="guid"/> or throws a ArgumentException if not found
|
|
/// Finds the member with the <paramref name="guid"/> or throws a ArgumentException if not found
|
|
/// </summary>
|
|
/// </summary>
|
|
- /// <param name="guid">The <see cref="StructureMember.GuidValue"/> of the member</param>
|
|
|
|
|
|
+ /// <param name="guid">The <see cref="StructureNode.Id"/> of the member</param>
|
|
/// <exception cref="ArgumentException">Thrown if the member could not be found</exception>
|
|
/// <exception cref="ArgumentException">Thrown if the member could not be found</exception>
|
|
- public StructureMember FindMemberOrThrow(Guid guid) => FindMember(guid) ?? throw new ArgumentException($"Could not find member with guid '{guid}'");
|
|
|
|
|
|
+ public StructureNode FindMemberOrThrow(Guid guid) =>
|
|
|
|
+ FindMember(guid) ?? throw new ArgumentException($"Could not find member with guid '{guid}'");
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Finds the member of type <typeparamref name="T"/> with the <paramref name="guid"/> or throws an exception
|
|
/// Finds the member of type <typeparamref name="T"/> with the <paramref name="guid"/> or throws an exception
|
|
/// </summary>
|
|
/// </summary>
|
|
- /// <param name="guid">The <see cref="StructureMember.GuidValue"/> of the member</param>
|
|
|
|
|
|
+ /// <param name="guid">The <see cref="StructureNode.Id"/> of the member</param>
|
|
/// <exception cref="ArgumentException">Thrown if the member could not be found</exception>
|
|
/// <exception cref="ArgumentException">Thrown if the member could not be found</exception>
|
|
/// <exception cref="InvalidCastException">Thrown if the member is not of type <typeparamref name="T"/></exception>
|
|
/// <exception cref="InvalidCastException">Thrown if the member is not of type <typeparamref name="T"/></exception>
|
|
- public T FindMemberOrThrow<T>(Guid guid) where T : StructureMember => (T?)FindMember(guid) ?? throw new ArgumentException($"Could not find member with guid '{guid}'");
|
|
|
|
|
|
+ public T FindMemberOrThrow<T>(Guid guid) where T : StructureNode => (T?)FindMember(guid) ??
|
|
|
|
+ throw new ArgumentException(
|
|
|
|
+ $"Could not find member with guid '{guid}'");
|
|
|
|
+
|
|
|
|
+ public T FindNodeOrThrow<T>(Guid guid) where T : Node => (T?)FindNode(guid) ??
|
|
|
|
+ throw new ArgumentException(
|
|
|
|
+ $"Could not find node with guid '{guid}'");
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Finds the member with the <paramref name="guid"/> or returns null if not found
|
|
/// Finds the member with the <paramref name="guid"/> or returns null if not found
|
|
/// </summary>
|
|
/// </summary>
|
|
- /// <param name="guid">The <see cref="StructureMember.GuidValue"/> of the member</param>
|
|
|
|
- public StructureMember? FindMember(Guid guid)
|
|
|
|
|
|
+ /// <param name="guid">The <see cref="StructureNode.Id"/> of the member</param>
|
|
|
|
+ public StructureNode? FindMember(Guid guid)
|
|
{
|
|
{
|
|
var list = FindMemberPath(guid);
|
|
var list = FindMemberPath(guid);
|
|
return list.Count > 0 ? list[0] : null;
|
|
return list.Count > 0 ? list[0] : null;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Finds the node with the given <paramref name="guid"/>.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="guid">The <see cref="Node.Id"/> of the node.</param>
|
|
|
|
+ /// <returns>The node with the given <paramref name="guid"/> or null if it doesn't exist.</returns>
|
|
|
|
+ public Node? FindNode(Guid guid)
|
|
|
|
+ {
|
|
|
|
+ return NodeGraph.Nodes.FirstOrDefault(x => x.Id == guid);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Tries to find the node with the given <paramref name="id"/> and returns true if it was found.
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="id">The <see cref="Node.Id"/> of the node.</param>
|
|
|
|
+ /// <param name="node">The node.</param>
|
|
|
|
+ /// <typeparam name="T">The type of the node.</typeparam>
|
|
|
|
+ /// <returns>True if the node could be found, otherwise false.</returns>
|
|
|
|
+ public bool TryFindNode<T>(Guid id, out T node) where T : Node
|
|
|
|
+ {
|
|
|
|
+ node = (T?)NodeGraph.Nodes.FirstOrDefault(x => x.Id == id) ?? default;
|
|
|
|
+ return node != null;
|
|
|
|
+ }
|
|
|
|
+
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Tries finding the member with the <paramref name="guid"/> and returns true if it was found
|
|
/// Tries finding the member with the <paramref name="guid"/> and returns true if it was found
|
|
/// </summary>
|
|
/// </summary>
|
|
- /// <param name="guid">The <see cref="StructureMember.GuidValue"/> of the <paramref name="member"/></param>
|
|
|
|
|
|
+ /// <param name="guid">The <see cref="StructureNode.Id"/> of the <paramref name="member"/></param>
|
|
/// <param name="member">The member</param>
|
|
/// <param name="member">The member</param>
|
|
/// <returns>True if the member could be found, otherwise false</returns>
|
|
/// <returns>True if the member could be found, otherwise false</returns>
|
|
- public bool TryFindMember(Guid guid, [NotNullWhen(true)] out StructureMember? member)
|
|
|
|
|
|
+ public bool TryFindMember(Guid guid, [NotNullWhen(true)] out StructureNode? member)
|
|
{
|
|
{
|
|
var list = FindMemberPath(guid);
|
|
var list = FindMemberPath(guid);
|
|
if (list.Count == 0)
|
|
if (list.Count == 0)
|
|
@@ -186,12 +233,12 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Tries finding the member with the <paramref name="guid"/> of type <typeparamref name="T"/> and returns true if it was found
|
|
/// Tries finding the member with the <paramref name="guid"/> of type <typeparamref name="T"/> and returns true if it was found
|
|
/// </summary>
|
|
/// </summary>
|
|
- /// <param name="guid">The <see cref="StructureMember.GuidValue"/> of the <paramref name="member"/></param>
|
|
|
|
|
|
+ /// <param name="guid">The <see cref="StructureNode.Id"/> of the <paramref name="member"/></param>
|
|
/// <param name="member">The member</param>
|
|
/// <param name="member">The member</param>
|
|
- /// <typeparam name="T">The type of the <see cref="StructureMember"/></typeparam>
|
|
|
|
|
|
+ /// <typeparam name="T">The type of the <see cref="StructureNode"/></typeparam>
|
|
/// <returns>True if the member could be found and is of type <typeparamref name="T"/>, otherwise false</returns>
|
|
/// <returns>True if the member could be found and is of type <typeparamref name="T"/>, otherwise false</returns>
|
|
- public bool TryFindMember<T>(Guid guid, [NotNullWhen(true)] out T? member)
|
|
|
|
- where T : IReadOnlyStructureMember
|
|
|
|
|
|
+ public bool TryFindMember<T>(Guid guid, [NotNullWhen(true)] out T? member)
|
|
|
|
+ where T : IReadOnlyStructureNode
|
|
{
|
|
{
|
|
if (!TryFindMember(guid, out var structureMember) || structureMember is not T cast)
|
|
if (!TryFindMember(guid, out var structureMember) || structureMember is not T cast)
|
|
{
|
|
{
|
|
@@ -203,74 +250,94 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
|
|
+
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Finds a member with the <paramref name="childGuid"/> and its parent, throws a ArgumentException if they can't be found
|
|
/// Finds a member with the <paramref name="childGuid"/> and its parent, throws a ArgumentException if they can't be found
|
|
/// </summary>
|
|
/// </summary>
|
|
- /// <param name="childGuid">The <see cref="StructureMember.GuidValue"/> of the member</param>
|
|
|
|
|
|
+ /// <param name="childGuid">The <see cref="StructureNode.Id"/> of the member</param>
|
|
/// <returns>A value tuple consisting of child (<see cref="ValueTuple{T, T}.Item1"/>) and parent (<see cref="ValueTuple{T, T}.Item2"/>)</returns>
|
|
/// <returns>A value tuple consisting of child (<see cref="ValueTuple{T, T}.Item1"/>) and parent (<see cref="ValueTuple{T, T}.Item2"/>)</returns>
|
|
/// <exception cref="ArgumentException">Thrown if the member and parent could not be found</exception>
|
|
/// <exception cref="ArgumentException">Thrown if the member and parent could not be found</exception>
|
|
- public (StructureMember, Folder) FindChildAndParentOrThrow(Guid childGuid)
|
|
|
|
|
|
+ public (StructureNode, FolderNode) FindChildAndParentOrThrow(Guid childGuid)
|
|
{
|
|
{
|
|
var path = FindMemberPath(childGuid);
|
|
var path = FindMemberPath(childGuid);
|
|
if (path.Count < 2)
|
|
if (path.Count < 2)
|
|
throw new ArgumentException("Couldn't find child and parent");
|
|
throw new ArgumentException("Couldn't find child and parent");
|
|
- return (path[0], (Folder)path[1]);
|
|
|
|
|
|
+ return (path[0], (FolderNode)path[1]);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Finds a member with the <paramref name="childGuid"/> and its parent
|
|
/// Finds a member with the <paramref name="childGuid"/> and its parent
|
|
/// </summary>
|
|
/// </summary>
|
|
- /// <param name="childGuid">The <see cref="StructureMember.GuidValue"/> of the member</param>
|
|
|
|
|
|
+ /// <param name="childGuid">The <see cref="StructureNode.Id"/> of the member</param>
|
|
/// <returns>A value tuple consisting of child (<see cref="ValueTuple{T, T}.Item1"/>) and parent (<see cref="ValueTuple{T, T}.Item2"/>)<para>Child and parent can be null if not found!</para></returns>
|
|
/// <returns>A value tuple consisting of child (<see cref="ValueTuple{T, T}.Item1"/>) and parent (<see cref="ValueTuple{T, T}.Item2"/>)<para>Child and parent can be null if not found!</para></returns>
|
|
- public (StructureMember?, Folder?) FindChildAndParent(Guid childGuid)
|
|
|
|
|
|
+ public (StructureNode?, FolderNode?) FindChildAndParent(Guid childGuid)
|
|
{
|
|
{
|
|
var path = FindMemberPath(childGuid);
|
|
var path = FindMemberPath(childGuid);
|
|
return path.Count switch
|
|
return path.Count switch
|
|
{
|
|
{
|
|
1 => (path[0], null),
|
|
1 => (path[0], null),
|
|
- > 1 => (path[0], (Folder)path[1]),
|
|
|
|
|
|
+ > 1 => (path[0], (FolderNode)path[1]),
|
|
_ => (null, null),
|
|
_ => (null, null),
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Finds the path to the member with <paramref name="guid"/>, the first element will be the member
|
|
|
|
|
|
+ /// Finds the path to the node with the given <paramref name="guid"/>.
|
|
/// </summary>
|
|
/// </summary>
|
|
- /// <param name="guid">The <see cref="StructureMember.GuidValue"/> of the member</param>
|
|
|
|
- public List<StructureMember> FindMemberPath(Guid guid)
|
|
|
|
|
|
+ /// <param name="guid">The <see cref="Node.Id"/> of the node.</param>
|
|
|
|
+ /// <returns>The path to the node.</returns>
|
|
|
|
+ public List<Node> FindNodePath(Guid guid)
|
|
{
|
|
{
|
|
- var list = new List<StructureMember>();
|
|
|
|
- if (FillMemberPath(StructureRoot, guid, list))
|
|
|
|
- list.Add(StructureRoot);
|
|
|
|
|
|
+ if (NodeGraph.OutputNode == null) return [];
|
|
|
|
+
|
|
|
|
+ var list = new List<Node>();
|
|
|
|
+ FillNodePath(NodeGraph.OutputNode, guid, list);
|
|
return list;
|
|
return list;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Finds the path to the member with <paramref name="guid"/>, the first element will be the member
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="guid">The <see cref="StructureNode.Id"/> of the member</param>
|
|
|
|
+ public List<StructureNode> FindMemberPath(Guid guid)
|
|
|
|
+ {
|
|
|
|
+ if (NodeGraph.OutputNode == null) return [];
|
|
|
|
+
|
|
|
|
+ var list = new List<Node>();
|
|
|
|
+ FillNodePath(NodeGraph.OutputNode, guid, list);
|
|
|
|
+ return list.Cast<StructureNode>().ToList();
|
|
|
|
+ }
|
|
|
|
|
|
- private bool FillMemberPath(Folder folder, Guid guid, List<StructureMember> toFill)
|
|
|
|
|
|
+ private bool FillNodePath(Node node, Guid guid, List<Node> toFill)
|
|
{
|
|
{
|
|
- if (folder.GuidValue == guid)
|
|
|
|
|
|
+ if (node.Id == guid)
|
|
{
|
|
{
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
- foreach (var member in folder.Children)
|
|
|
|
|
|
+ if (node is StructureNode structureNode)
|
|
{
|
|
{
|
|
- if (member is Layer childLayer && childLayer.GuidValue == guid)
|
|
|
|
- {
|
|
|
|
- toFill.Add(member);
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- if (member is Folder childFolder)
|
|
|
|
|
|
+ toFill.Add(structureNode);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ bool found = false;
|
|
|
|
+
|
|
|
|
+ node.TraverseBackwards((newNode) =>
|
|
|
|
+ {
|
|
|
|
+ if (newNode is StructureNode strNode && newNode.Id == guid)
|
|
{
|
|
{
|
|
- if (FillMemberPath(childFolder, guid, toFill))
|
|
|
|
- {
|
|
|
|
- toFill.Add(childFolder);
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
|
|
+ toFill.Add(strNode);
|
|
|
|
+ found = true;
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
- }
|
|
|
|
- return false;
|
|
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ return found;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public List<Guid> ExtractLayers(IList<Guid> members)
|
|
public List<Guid> ExtractLayers(IList<Guid> members)
|
|
{
|
|
{
|
|
var result = new List<Guid>();
|
|
var result = new List<Guid>();
|
|
@@ -278,31 +345,31 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
|
|
{
|
|
{
|
|
if (TryFindMember(member, out var structureMember))
|
|
if (TryFindMember(member, out var structureMember))
|
|
{
|
|
{
|
|
- if (structureMember is Layer layer && !result.Contains(layer.GuidValue))
|
|
|
|
|
|
+ if (structureMember is LayerNode layer && !result.Contains(layer.Id))
|
|
{
|
|
{
|
|
- result.Add(layer.GuidValue);
|
|
|
|
|
|
+ result.Add(layer.Id);
|
|
}
|
|
}
|
|
- else if (structureMember is Folder folder)
|
|
|
|
|
|
+ else if (structureMember is FolderNode folder)
|
|
{
|
|
{
|
|
ExtractLayers(folder, result);
|
|
ExtractLayers(folder, result);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
- private void ExtractLayers(Folder folder, List<Guid> list)
|
|
|
|
|
|
+ private void ExtractLayers(FolderNode folder, List<Guid> list)
|
|
{
|
|
{
|
|
- foreach (var member in folder.Children)
|
|
|
|
|
|
+ List<Guid> result = new();
|
|
|
|
+ folder.TraverseBackwards(node =>
|
|
{
|
|
{
|
|
- if (member is Layer layer && !list.Contains(layer.GuidValue))
|
|
|
|
- {
|
|
|
|
- list.Add(layer.GuidValue);
|
|
|
|
- }
|
|
|
|
- else if (member is Folder childFolder)
|
|
|
|
|
|
+ if (node is LayerNode layer && !result.Contains(layer.Id))
|
|
{
|
|
{
|
|
- ExtractLayers(childFolder, list);
|
|
|
|
|
|
+ result.Add(layer.Id);
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+ });
|
|
}
|
|
}
|
|
}
|
|
}
|