Editor/UndoStack.cs
using Sandbox.Diagnostics;
using System.Collections.Generic;
using System.Linq;
namespace SpriteTools;
public class UndoOp
{
public string name;
public string undoBuffer;
public string redoBuffer;
}
public class UndoStack
{
private readonly List<UndoOp> _undoStack = new();
private int _undoLevel = 0;
private bool _redoPending = false;
public bool CanUndo => _undoLevel != 0 && !_redoPending;
public bool CanRedo => _undoLevel != _undoStack.Count && !_redoPending;
public string UndoName => CanUndo ? $"Undo {_undoStack[_undoLevel - 1].name}" : null;
public string RedoName => CanRedo ? $"Redo {_undoStack[_undoLevel].name}" : null;
public int UndoLevel => _undoLevel;
public UndoOp MostRecent => _undoStack.LastOrDefault();
public IEnumerable<string> Names => _undoStack.Select(x => x.name);
public void PushUndo(string name, string buffer)
{
Assert.False(_redoPending, $"Pending Redo ({UndoName})");
_redoPending = true;
if (_undoStack.Count > _undoLevel)
{
var count = _undoStack.Count - _undoLevel;
_undoStack.RemoveRange(_undoStack.Count - count, count);
}
_undoStack.Add(new() { name = name, undoBuffer = buffer });
_undoLevel++;
}
public void PushRedo(string buffer)
{
Assert.True(_redoPending);
_redoPending = false;
_undoStack[_undoLevel - 1].redoBuffer = buffer;
}
public UndoOp Undo()
{
if (_redoPending)
{
Log.Warning("Pending Redo!");
return null;
}
if (_undoStack.Count > 0 && _undoLevel > 0)
{
_undoLevel--;
return _undoStack[_undoLevel];
}
return null;
}
public UndoOp Redo()
{
if (_redoPending)
{
Log.Warning("Pending Redo!");
return null;
}
if (_undoStack.Count > 0 && _undoLevel <= _undoStack.Count - 1)
{
_undoLevel++;
return _undoStack[_undoLevel - 1];
}
return null;
}
public UndoOp SetUndoLevel(int undoLevel)
{
if (_redoPending)
{
Log.Warning("Pending Redo!");
return null;
}
if (_undoLevel == undoLevel + 1)
return null;
if (_undoStack.Count > 0 && undoLevel <= _undoStack.Count - 1)
{
_undoLevel = undoLevel + 1;
return _undoStack[_undoLevel - 1];
}
return null;
}
public void Clear()
{
_undoStack.Clear();
_undoLevel = 0;
_redoPending = false;
}
public void PopMostRecent()
{
if (_undoStack.Count > 0)
{
_undoStack.RemoveAt(_undoStack.Count - 1);
_undoLevel = _undoStack.Count;
}
}
}