using System;
using static Editor.Label;
using static Sandbox.Scene;
namespace Sandbox.Helpers;
///
/// A system that aims to wrap the main reusable functionality of an undo system
///
public partial class UndoSystem
{
public class Entry
{
public string Name { get; set; }
public Action Undo { get; set; }
public Action Redo { get; set; }
/// [Obsolete]?
public Object Image { get; set; }
public DateTime Timestamp { get; set; }
public bool Locked { get; set; }
}
///
/// Called when an undo is run
///
public Action OnUndo;
///
/// Called when a redo is run
///
public Action OnRedo;
///
/// Backwards stack
///
public Stack Back { get; } = new();
///
/// Forwards stack, gets cleared when a new undo is added
///
public Stack Forward { get; } = new();
///
/// Instigate an undo. Return true if we found a successful undo
///
public bool Undo()
{
if ( !Back.TryPop( out var entry ) )
{
next = initial;
return false;
}
next = entry.Undo;
try
{
entry.Undo?.Invoke();
}
catch ( System.Exception e )
{
Log.Warning( e, $"Error when undoing '{entry.Name}': {e.Message}" );
}
if ( entry.Locked )
{
Back.Push( entry );
return false;
}
Forward.Push( entry );
OnUndo?.Invoke( entry );
return true;
}
///
/// Instigate a redo, returns true if we found a successful undo
///
public bool Redo()
{
if ( !Forward.TryPop( out var entry ) )
return false;
next = entry.Redo;
Back.Push( entry );
entry.Redo?.Invoke();
OnRedo?.Invoke( entry );
return true;
}
///
/// Insert a new undo entry
///
public Entry Insert( string title, Action undo, Action redo = null )
{
var e = new Entry
{
Name = title,
Undo = undo,
Redo = redo,
Timestamp = DateTime.Now,
};
Back.Push( e );
Forward.Clear();
return e;
}
///
/// Provide a function that returns an action to call on undo/redo.
/// This generally is a function that saves and restores the entire state
/// of a project.
///
[Obsolete( "Auto Snapshotting is obsolete and no longer working. If you really want to use snapshotting for Undo, create/restore the snapshots manually in the undo/redo actions provided to UndoSystem.Insert" )]
public void SetSnapshotFunction( Func snapshot )
{
}
///
/// func getsnapshot()
/// {
/// var state = currentstate();
///
/// return () => restorestate( state );
/// }
///
/// startup()
/// {
/// -- give a function that creates undo functions
/// UndoSystem.SetSnapshotter( getsnapshot )
///
/// -- store current snapshot in `next`
/// UndoSystem.Initialize();
/// }
///
/// mainloop()
/// {
/// deleteobject();
///
/// -- store 'next' snapshot as "object deleted" undo
/// -- take a new snapshot and store it in next
/// UndoSystem.Snapshot( "object deleted" );
/// }
///
Action next;
Action initial;
///
/// Should be called after you make a change to your project. The snapshot system
/// is good for self contained projects that can be serialized and deserialized quickly.
///
[Obsolete( "Auto Snapshotting is obsolete and no longer working. If you really want to use snapshotting for Undo, create/restore the snapshots manually in the undo/redo actions provided to UndoSystem.Insert" )]
public void Snapshot( string changeTitle )
{
}
///
/// Clear the history and take an initial snapshot.
/// You should call this right after a load, or a new project.
///
public void Initialize()
{
Back.Clear();
Forward.Clear();
initial = next;
}
}