namespace Editor.ShaderGraph; public class UndoOp { public string name; public string undoBuffer; public string redoBuffer; } public class UndoStack { private readonly List _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 IEnumerable 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; } }