You're breathtaking!
This commit is contained in:
104
Source/Editor/Surface/Undo/AddRemoveNodeAction.cs
Normal file
104
Source/Editor/Surface/Undo/AddRemoveNodeAction.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Surface.Undo
|
||||
{
|
||||
/// <summary>
|
||||
/// Add Visject Surface node undo action.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.IUndoAction" />
|
||||
class AddRemoveNodeAction : IUndoAction
|
||||
{
|
||||
private readonly bool _isAdd;
|
||||
private VisjectSurface _surface;
|
||||
private ContextHandle _context;
|
||||
private uint _nodeId;
|
||||
private ushort _groupId;
|
||||
private ushort _typeId;
|
||||
private Vector2 _nodeLocation;
|
||||
private object[] _nodeValues;
|
||||
|
||||
public AddRemoveNodeAction(SurfaceNode node, bool isAdd)
|
||||
{
|
||||
_surface = node.Surface;
|
||||
_context = new ContextHandle(node.Context);
|
||||
_nodeId = node.ID;
|
||||
_isAdd = isAdd;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ActionString => _isAdd ? "Add node" : "Remove node";
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Do()
|
||||
{
|
||||
if (_isAdd)
|
||||
Add();
|
||||
else
|
||||
Remove();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Undo()
|
||||
{
|
||||
if (_isAdd)
|
||||
Remove();
|
||||
else
|
||||
Add();
|
||||
}
|
||||
|
||||
private void Add()
|
||||
{
|
||||
var context = _context.Get(_surface);
|
||||
if (_nodeId == 0)
|
||||
throw new Exception("Node already added.");
|
||||
|
||||
// Create node
|
||||
var node = NodeFactory.CreateNode(context.Surface.NodeArchetypes, _nodeId, context, _groupId, _typeId);
|
||||
if (node == null)
|
||||
throw new Exception("Failed to create node.");
|
||||
context.Nodes.Add(node);
|
||||
|
||||
// Initialize
|
||||
if (node.Values != null && node.Values.Length == _nodeValues.Length)
|
||||
Array.Copy(_nodeValues, node.Values, _nodeValues.Length);
|
||||
else if (_nodeValues != null && _nodeValues.Length != 0)
|
||||
throw new InvalidOperationException("Invalid node values.");
|
||||
node.Location = _nodeLocation;
|
||||
context.OnControlLoaded(node);
|
||||
node.OnSurfaceLoaded();
|
||||
|
||||
context.MarkAsModified();
|
||||
}
|
||||
|
||||
private void Remove()
|
||||
{
|
||||
var context = _context.Get(_surface);
|
||||
var node = context.FindNode(_nodeId);
|
||||
if (node == null)
|
||||
throw new Exception("Missing node to remove.");
|
||||
|
||||
// Cache node state
|
||||
_nodeId = node.ID;
|
||||
_groupId = node.GroupArchetype.GroupID;
|
||||
_typeId = node.Archetype.TypeID;
|
||||
_nodeLocation = node.Location;
|
||||
_nodeValues = (object[])node.Values?.Clone();
|
||||
|
||||
// Remove node
|
||||
context.Nodes.Remove(node);
|
||||
context.OnControlDeleted(node);
|
||||
|
||||
context.MarkAsModified();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_surface = null;
|
||||
_nodeValues = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
55
Source/Editor/Surface/Undo/BoxHandle.cs
Normal file
55
Source/Editor/Surface/Undo/BoxHandle.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEditor.Surface.Elements;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Surface.Undo
|
||||
{
|
||||
/// <summary>
|
||||
/// The helper structure for Surface node box handle.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public struct BoxHandle
|
||||
{
|
||||
private readonly uint _nodeId;
|
||||
private readonly int _boxId;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BoxHandle"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="nodeId">The node identifier.</param>
|
||||
/// <param name="boxId">The box identifier.</param>
|
||||
public BoxHandle(uint nodeId, int boxId)
|
||||
{
|
||||
_nodeId = nodeId;
|
||||
_boxId = boxId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BoxHandle"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="box">The box.</param>
|
||||
public BoxHandle(Box box)
|
||||
{
|
||||
_nodeId = box.ParentNode.ID;
|
||||
_boxId = box.ID;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the box.
|
||||
/// </summary>
|
||||
/// <param name="context">The Surface context.</param>
|
||||
/// <returns>The restored box.</returns>
|
||||
public Box Get(VisjectSurfaceContext context)
|
||||
{
|
||||
var node = context.FindNode(_nodeId);
|
||||
if (node == null)
|
||||
throw new Exception("Missing node.");
|
||||
var box = node.GetBox(_boxId);
|
||||
if (box == null)
|
||||
throw new Exception("Missing box.");
|
||||
return box;
|
||||
}
|
||||
}
|
||||
}
|
||||
134
Source/Editor/Surface/Undo/ConnectBoxesAction.cs
Normal file
134
Source/Editor/Surface/Undo/ConnectBoxesAction.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.Surface.Elements;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.Surface.Undo
|
||||
{
|
||||
/// <summary>
|
||||
/// Edit Visject Surface node boxes connection undo action.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.IUndoAction" />
|
||||
class ConnectBoxesAction : IUndoAction
|
||||
{
|
||||
private VisjectSurface _surface;
|
||||
private ContextHandle _context;
|
||||
private bool _connect;
|
||||
private BoxHandle _input;
|
||||
private BoxHandle _output;
|
||||
private BoxHandle[] _inputBefore;
|
||||
private BoxHandle[] _inputAfter;
|
||||
private BoxHandle[] _outputBefore;
|
||||
private BoxHandle[] _outputAfter;
|
||||
|
||||
public ConnectBoxesAction(InputBox iB, OutputBox oB, bool connect)
|
||||
{
|
||||
_surface = iB.Surface;
|
||||
_context = new ContextHandle(iB.ParentNode.Context);
|
||||
_connect = connect;
|
||||
|
||||
_input = new BoxHandle(iB);
|
||||
_output = new BoxHandle(oB);
|
||||
|
||||
CaptureConnections(iB, out _inputBefore);
|
||||
CaptureConnections(oB, out _outputBefore);
|
||||
}
|
||||
|
||||
public void End()
|
||||
{
|
||||
var context = _context.Get(_surface);
|
||||
var iB = _input.Get(context);
|
||||
var oB = _output.Get(context);
|
||||
|
||||
CaptureConnections(iB, out _inputAfter);
|
||||
CaptureConnections(oB, out _outputAfter);
|
||||
}
|
||||
|
||||
private void CaptureConnections(Box box, out BoxHandle[] connections)
|
||||
{
|
||||
connections = new BoxHandle[box.Connections.Count];
|
||||
for (int i = 0; i < connections.Length; i++)
|
||||
{
|
||||
var other = box.Connections[i];
|
||||
connections[i] = new BoxHandle(other);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ActionString => _connect ? "Connect boxes" : "Disconnect boxes";
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Do()
|
||||
{
|
||||
Execute(_inputAfter, _outputAfter);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Undo()
|
||||
{
|
||||
Execute(_inputBefore, _outputBefore);
|
||||
}
|
||||
|
||||
private void Execute(BoxHandle[] input, BoxHandle[] output)
|
||||
{
|
||||
var context = _context.Get(_surface);
|
||||
var iB = _input.Get(context);
|
||||
var oB = _output.Get(context);
|
||||
|
||||
var toUpdate = new HashSet<Box>();
|
||||
toUpdate.Add(iB);
|
||||
toUpdate.Add(oB);
|
||||
toUpdate.AddRange(iB.Connections);
|
||||
toUpdate.AddRange(oB.Connections);
|
||||
|
||||
for (int i = 0; i < iB.Connections.Count; i++)
|
||||
{
|
||||
var box = iB.Connections[i];
|
||||
box.Connections.Remove(iB);
|
||||
}
|
||||
for (int i = 0; i < oB.Connections.Count; i++)
|
||||
{
|
||||
var box = oB.Connections[i];
|
||||
box.Connections.Remove(oB);
|
||||
}
|
||||
|
||||
iB.Connections.Clear();
|
||||
oB.Connections.Clear();
|
||||
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
{
|
||||
var box = input[i].Get(context);
|
||||
iB.Connections.Add(box);
|
||||
box.Connections.Add(iB);
|
||||
}
|
||||
for (int i = 0; i < output.Length; i++)
|
||||
{
|
||||
var box = output[i].Get(context);
|
||||
oB.Connections.Add(box);
|
||||
box.Connections.Add(oB);
|
||||
}
|
||||
|
||||
toUpdate.AddRange(iB.Connections);
|
||||
toUpdate.AddRange(oB.Connections);
|
||||
|
||||
foreach (var box in toUpdate)
|
||||
{
|
||||
box.OnConnectionsChanged();
|
||||
box.ConnectionTick();
|
||||
}
|
||||
|
||||
context.MarkAsModified();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_surface = null;
|
||||
_inputBefore = null;
|
||||
_inputAfter = null;
|
||||
_outputBefore = null;
|
||||
_outputAfter = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
73
Source/Editor/Surface/Undo/ContextHandle.cs
Normal file
73
Source/Editor/Surface/Undo/ContextHandle.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Surface.Undo
|
||||
{
|
||||
/// <summary>
|
||||
/// The helper structure for Surface context handle.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public struct ContextHandle
|
||||
{
|
||||
private readonly string[] _path;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ContextHandle"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="context">The context.</param>
|
||||
public ContextHandle(VisjectSurfaceContext context)
|
||||
{
|
||||
int count = 0;
|
||||
var parent = context.Parent;
|
||||
while (parent != null)
|
||||
{
|
||||
count++;
|
||||
parent = parent.Parent;
|
||||
}
|
||||
if (count == 0)
|
||||
{
|
||||
// Root context
|
||||
_path = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_path = new string[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
_path[i] = context.Context.SurfaceName;
|
||||
context = context.Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the context.
|
||||
/// </summary>
|
||||
/// <param name="surface">The Surface.</param>
|
||||
/// <returns>The restored context.</returns>
|
||||
public VisjectSurfaceContext Get(VisjectSurface surface)
|
||||
{
|
||||
var context = surface.RootContext;
|
||||
var count = _path?.Length ?? 0;
|
||||
for (int i = count - 1; i >= 0; i--)
|
||||
{
|
||||
var found = false;
|
||||
foreach (var child in context.Children)
|
||||
{
|
||||
if (child.Context.SurfaceName == _path[i])
|
||||
{
|
||||
found = true;
|
||||
context = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
throw new Exception(string.Format("Missing context \'{0}\' in \'{1}\'", _path[i], context.Context.SurfaceName));
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
}
|
||||
}
|
||||
128
Source/Editor/Surface/Undo/EditNodeConnections.cs
Normal file
128
Source/Editor/Surface/Undo/EditNodeConnections.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.Surface.Elements;
|
||||
|
||||
namespace FlaxEditor.Surface.Undo
|
||||
{
|
||||
/// <summary>
|
||||
/// Edit Visject Surface node boxes connections undo action.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.IUndoAction" />
|
||||
class EditNodeConnections : IUndoAction
|
||||
{
|
||||
private VisjectSurface _surface;
|
||||
private ContextHandle _context;
|
||||
private readonly uint _nodeId;
|
||||
private BoxHandle[][] _before;
|
||||
private BoxHandle[][] _after;
|
||||
|
||||
public EditNodeConnections(VisjectSurfaceContext context, SurfaceNode node)
|
||||
{
|
||||
_surface = context.Surface;
|
||||
_context = new ContextHandle(context);
|
||||
_nodeId = node.ID;
|
||||
|
||||
CaptureConnections(node, out _before);
|
||||
}
|
||||
|
||||
public void End()
|
||||
{
|
||||
var context = _context.Get(_surface);
|
||||
var node = context.FindNode(_nodeId);
|
||||
if (node == null)
|
||||
throw new Exception("Missing node");
|
||||
|
||||
CaptureConnections(node, out _after);
|
||||
}
|
||||
|
||||
private void CaptureConnections(SurfaceNode node, out BoxHandle[][] boxesConnections)
|
||||
{
|
||||
var boxes = node.GetBoxes();
|
||||
boxesConnections = new BoxHandle[boxes.Count][];
|
||||
for (int i = 0; i < boxesConnections.Length; i++)
|
||||
{
|
||||
var box = boxes[i];
|
||||
var connections = new BoxHandle[box.Connections.Count];
|
||||
boxesConnections[i] = connections;
|
||||
for (int j = 0; j < connections.Length; j++)
|
||||
{
|
||||
var other = box.Connections[j];
|
||||
connections[j] = new BoxHandle(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ActionString => "Edit connections";
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Do()
|
||||
{
|
||||
Execute(_after);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Undo()
|
||||
{
|
||||
Execute(_before);
|
||||
}
|
||||
|
||||
private void Execute(BoxHandle[][] boxesConnections)
|
||||
{
|
||||
var context = _context.Get(_surface);
|
||||
var node = context.FindNode(_nodeId);
|
||||
if (node == null)
|
||||
throw new Exception("Missing node");
|
||||
|
||||
var toUpdate = new HashSet<Box>();
|
||||
var boxes = node.GetBoxes();
|
||||
|
||||
for (var i = 0; i < boxes.Count; i++)
|
||||
{
|
||||
var box = boxes[i];
|
||||
toUpdate.Add(box);
|
||||
|
||||
for (int j = 0; j < box.Connections.Count; j++)
|
||||
{
|
||||
var other = box.Connections[j];
|
||||
toUpdate.Add(other);
|
||||
other.Connections.Remove(box);
|
||||
}
|
||||
|
||||
box.Connections.Clear();
|
||||
}
|
||||
|
||||
for (var i = 0; i < boxes.Count; i++)
|
||||
{
|
||||
var box = boxes[i];
|
||||
var connections = boxesConnections[i];
|
||||
|
||||
for (int j = 0; j < connections.Length; j++)
|
||||
{
|
||||
var other = connections[j].Get(context);
|
||||
toUpdate.Add(other);
|
||||
box.Connections.Add(other);
|
||||
other.Connections.Add(box);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var box in toUpdate)
|
||||
{
|
||||
box.OnConnectionsChanged();
|
||||
box.ConnectionTick();
|
||||
}
|
||||
|
||||
context.MarkAsModified();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_surface = null;
|
||||
_before = null;
|
||||
_after = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
82
Source/Editor/Surface/Undo/EditNodeValuesAction.cs
Normal file
82
Source/Editor/Surface/Undo/EditNodeValuesAction.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
|
||||
namespace FlaxEditor.Surface.Undo
|
||||
{
|
||||
/// <summary>
|
||||
/// Edit Visject Surface node values collection undo action.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.IUndoAction" />
|
||||
class EditNodeValuesAction : IUndoAction
|
||||
{
|
||||
private VisjectSurface _surface;
|
||||
private ContextHandle _context;
|
||||
private readonly uint _nodeId;
|
||||
private readonly bool _graphEdited;
|
||||
private object[] _before;
|
||||
private object[] _after;
|
||||
|
||||
public EditNodeValuesAction(SurfaceNode node, object[] before, bool graphEdited)
|
||||
{
|
||||
if (before == null)
|
||||
throw new ArgumentNullException(nameof(before));
|
||||
if (node?.Values == null)
|
||||
throw new ArgumentNullException(nameof(node));
|
||||
if (before.Length != node.Values.Length)
|
||||
throw new ArgumentException(nameof(before));
|
||||
|
||||
_surface = node.Surface;
|
||||
_context = new ContextHandle(node.Context);
|
||||
_nodeId = node.ID;
|
||||
_before = before;
|
||||
_after = (object[])node.Values.Clone();
|
||||
_graphEdited = graphEdited;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ActionString => "Edit node";
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Do()
|
||||
{
|
||||
var context = _context.Get(_surface);
|
||||
if (_after == null)
|
||||
throw new Exception("Missing values.");
|
||||
var node = context.FindNode(_nodeId);
|
||||
if (node == null)
|
||||
throw new Exception("Missing node.");
|
||||
|
||||
node.SetIsDuringValuesEditing(true);
|
||||
Array.Copy(_after, node.Values, _after.Length);
|
||||
node.OnValuesChanged();
|
||||
context.MarkAsModified(_graphEdited);
|
||||
node.SetIsDuringValuesEditing(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Undo()
|
||||
{
|
||||
var context = _context.Get(_surface);
|
||||
if (_before == null)
|
||||
throw new Exception("Missing values.");
|
||||
var node = context.FindNode(_nodeId);
|
||||
if (node == null)
|
||||
throw new Exception("Missing node.");
|
||||
|
||||
node.SetIsDuringValuesEditing(true);
|
||||
Array.Copy(_before, node.Values, _before.Length);
|
||||
node.OnValuesChanged();
|
||||
context.MarkAsModified(_graphEdited);
|
||||
node.SetIsDuringValuesEditing(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_surface = null;
|
||||
_before = null;
|
||||
_after = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Source/Editor/Surface/Undo/MoveNodesAction.cs
Normal file
64
Source/Editor/Surface/Undo/MoveNodesAction.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Surface.Undo
|
||||
{
|
||||
/// <summary>
|
||||
/// Move Visject Surface nodes undo action.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.IUndoAction" />
|
||||
class MoveNodesAction : IUndoAction
|
||||
{
|
||||
private VisjectSurface _surface;
|
||||
private ContextHandle _context;
|
||||
private uint[] _nodeIds;
|
||||
private readonly Vector2 _locationDelta;
|
||||
|
||||
public MoveNodesAction(VisjectSurfaceContext context, uint[] nodeIds, Vector2 locationDelta)
|
||||
{
|
||||
_surface = context.Surface;
|
||||
_context = new ContextHandle(context);
|
||||
_nodeIds = nodeIds;
|
||||
_locationDelta = locationDelta;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ActionString => "Move nodes";
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Do()
|
||||
{
|
||||
Apply(_locationDelta);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Undo()
|
||||
{
|
||||
Apply(-_locationDelta);
|
||||
}
|
||||
|
||||
private void Apply(Vector2 delta)
|
||||
{
|
||||
var context = _context.Get(_surface);
|
||||
foreach (var nodeId in _nodeIds)
|
||||
{
|
||||
var node = context.FindNode(nodeId);
|
||||
if (node == null)
|
||||
throw new Exception("Missing node.");
|
||||
|
||||
node.Location += delta;
|
||||
}
|
||||
|
||||
context.MarkAsModified(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_surface = null;
|
||||
_nodeIds = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user