OverviewFilesCommitsIssuesDocsReleasesPeers

ifsrenderer-linux / Shared / IFSHistoryTracker.cs

53 lines · csharp ref:
using IFSEngine.Model;

namespace IFSRenderer.Shared;

/// <summary>
/// Snapshot-based undo/redo. Ported verbatim from the WPF app's helper of the same name.
/// </summary>
/// <remarks>
/// States are whole serialized fractals rather than reversible commands, which is why this
/// goes through <see cref="IfsNodesSerializer"/> - and therefore why undo also restores node
/// graph positions, not just parameters.
/// </remarks>
public class IFSHistoryTracker
{
    private Stack<string> UndoStack { get; } = new();
    private Stack<string> RedoStack { get; } = new();

    public bool IsHistoryUndoable => UndoStack.Count > 0;
    public bool IsHistoryRedoable => RedoStack.Count > 0;

    public IFS Undo(IFS current, IEnumerable<TransformPlugin> transforms, IEnumerable<EffectPlugin> postfxs)
    {
        if (!IsHistoryUndoable)
            throw new InvalidOperationException();

        RedoStack.Push(IfsNodesSerializer.SerializeJsonString(current));
        string lastState = UndoStack.Pop();
        return IfsNodesSerializer.DeserializeJsonString(lastState, transforms, postfxs, true);
    }

    public IFS Redo(IFS current, IEnumerable<TransformPlugin> transforms, IEnumerable<EffectPlugin> postfxs)
    {
        if (!IsHistoryRedoable)
            throw new InvalidOperationException();

        UndoStack.Push(IfsNodesSerializer.SerializeJsonString(current));
        string nextState = RedoStack.Pop();
        return IfsNodesSerializer.DeserializeJsonString(nextState, transforms, postfxs, true);
    }

    public void TakeSnapshot(IFS trackedObject)
    {
        RedoStack.Clear();
        UndoStack.Push(IfsNodesSerializer.SerializeJsonString(trackedObject));
    }

    public void Clear()
    {
        UndoStack.Clear();
        RedoStack.Clear();
    }
}