You're breathtaking!

This commit is contained in:
Wojtek Figat
2020-12-07 23:40:54 +01:00
commit 6fb9eee74c
5143 changed files with 1153594 additions and 0 deletions

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}