-Reverted a change to TasMovieMarker, made Undo/Redo moving markers re-sort the markers list.

-Added file that was supposed to be in previous commit
This commit is contained in:
SuuperW 2015-03-01 15:41:54 +00:00
parent cf081ce1fc
commit 6639bbd127
2 changed files with 441 additions and 1 deletions

View File

@ -0,0 +1,433 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System;
namespace BizHawk.Client.Common
{
public class TasMovieChangeLog
{
List<List<IMovieAction>> History;
int UndoIndex = -1;
private bool RecordingBatch = false;
public bool AutoRecord = true;
public TasMovie Movie;
public TasMovieChangeLog(TasMovie movie)
{
History = new List<List<IMovieAction>>();
Movie = movie;
}
public void ClearLog(int upTo = -1)
{
if (upTo == -1)
upTo = History.Count;
History.RemoveRange(0, upTo);
UndoIndex -= upTo;
if (UndoIndex < -1)
UndoIndex = -1;
if (History.Count == 0)
RecordingBatch = false;
}
private void TruncateLog(int from)
{
UndoIndex -= History.Count - from;
if (UndoIndex < -1)
UndoIndex = -1;
History.RemoveRange(from, History.Count - from);
RecordingBatch = false;
}
/// <summary>
/// All changes made between calling Begin and End will be one Undo.
/// If already recording in a batch, calls EndBatch.
/// </summary>
public void BeginNewBatch()
{
if (RecordingBatch)
EndBatch();
RecordingBatch = true;
History.Add(new List<IMovieAction>());
}
/// <summary>
/// Ends the current undo batch. Future changes will be one undo each.
/// </summary>
public void EndBatch()
{
RecordingBatch = false;
List<IMovieAction> last = History.Last();
last.Capacity = last.Count;
}
/// <summary>
/// Undoes the most recent action batch, if any exist.
/// </summary>
/// <returns>Returns the frame which the movie needs to rewind to.</returns>
public int Undo()
{
if (UndoIndex == -1)
return Movie.InputLogLength;
List<IMovieAction> batch = History[UndoIndex];
for (int i = batch.Count - 1; i >= 0; i--)
batch[i].Undo(Movie);
UndoIndex--;
RecordingBatch = false;
if (!batch.Where(a => a.GetType() != typeof(MovieActionMarker)).Any())
return Movie.InputLogLength;
return PreviousUndoFrame;
}
/// <summary>
/// Redoes the most recent undo, if any exist.
/// </summary>
/// <returns>Returns the frame which the movie needs to rewind to.</returns>
public int Redo()
{
if (UndoIndex == History.Count - 1)
return Movie.InputLogLength;
UndoIndex++;
List<IMovieAction> batch = History[UndoIndex];
for (int i = 0; i < batch.Count; i++)
batch[i].Redo(Movie);
RecordingBatch = false;
if (!batch.Where(a => a.GetType() != typeof(MovieActionMarker)).Any())
return Movie.InputLogLength;
return PreviousUndoFrame;
}
public int PreviousUndoFrame
{
get
{
if (UndoIndex == History.Count - 1)
return Movie.InputLogLength;
return History[UndoIndex + 1].Max(a => a.FirstFrame);
}
}
public int PreviousRedoFrame
{
get
{
if (UndoIndex == -1)
return Movie.InputLogLength;
return History[UndoIndex].Max(a => a.FirstFrame);
}
}
#region "Change History"
private bool AddMovieAction()
{
if (!AutoRecord)
return false;
if (UndoIndex + 1 != History.Count)
TruncateLog(UndoIndex + 1);
if (!RecordingBatch)
{
History.Add(new List<IMovieAction>(1));
UndoIndex += 1;
}
return true;
}
// TODO: These probably aren't the best way to handle undo/redo.
public void AddGeneralUndo(int first, int last)
{
if (AutoRecord)
{
AddMovieAction();
History.Last().Add(new MovieAction(first, last, Movie));
}
}
public void SetGeneralRedo()
{
if (AutoRecord)
{
(History.Last().Last() as MovieAction).SetRedoLog(Movie);
}
}
public void AddBoolToggle(int frame, string button, bool oldState)
{
if (AutoRecord)
{
AddMovieAction();
History.Last().Add(new MovieActionFrameEdit(frame, button, oldState, !oldState));
}
}
public void AddFloatChange(int frame, string button, float oldState, float newState)
{
if (AutoRecord)
{
AddMovieAction();
History.Last().Add(new MovieActionFrameEdit(frame, button, oldState, newState));
}
}
public void AddMarkerChange(TasMovieMarker newMarker, int oldPosition = -1, string old_message = "")
{
if (AutoRecord)
{
AddMovieAction();
History.Last().Add(new MovieActionMarker(newMarker, oldPosition, old_message));
}
}
#endregion
}
#region "Classes"
public interface IMovieAction
{
void Undo(TasMovie movie);
void Redo(TasMovie movie);
int FirstFrame { get; }
int LastFrame { get; }
}
public class MovieAction : IMovieAction
{
public int FirstFrame { get; private set; }
public int LastFrame { get; private set; }
private int undoLength;
private int redoLength;
private int length
{ get { return LastFrame - FirstFrame + 1; } }
private List<string> oldLog;
private List<string> newLog;
public MovieAction(int firstFrame, int lastFrame, TasMovie movie)
{
FirstFrame = firstFrame;
LastFrame = lastFrame;
oldLog = new List<string>(length);
undoLength = Math.Min(lastFrame + 1, movie.InputLogLength) - firstFrame;
for (int i = 0; i < undoLength; i++)
oldLog.Add(movie.GetLogEntries()[FirstFrame + i]);
}
public void SetRedoLog(TasMovie movie)
{
redoLength = Math.Min(LastFrame + 1, movie.InputLogLength) - FirstFrame;
newLog = new List<string>();
for (int i = 0; i < redoLength; i++)
newLog.Add(movie.GetLogEntries()[FirstFrame + i]);
}
public void Undo(TasMovie movie)
{
bool wasRecording = movie.ChangeLog.AutoRecord;
movie.ChangeLog.AutoRecord = false;
if (redoLength != length)
movie.InsertEmptyFrame(movie.InputLogLength, length - redoLength);
for (int i = 0; i < undoLength; i++)
movie.SetFrame(FirstFrame + i, oldLog[i]);
if (undoLength != length)
movie.Truncate(FirstFrame + undoLength);
movie.ChangeLog.AutoRecord = wasRecording;
}
public void Redo(TasMovie movie)
{
bool wasRecording = movie.ChangeLog.AutoRecord;
movie.ChangeLog.AutoRecord = false;
if (undoLength != length)
movie.InsertEmptyFrame(movie.InputLogLength, length - undoLength);
for (int i = 0; i < redoLength; i++)
movie.SetFrame(FirstFrame + i, newLog[i]);
if (redoLength != length)
movie.Truncate(FirstFrame + redoLength);
movie.ChangeLog.AutoRecord = wasRecording;
}
}
public class MovieActionMarker : IMovieAction
{
public int FirstFrame { get; private set; }
public int LastFrame { get; private set; }
private string oldMessage;
private string newMessage;
public MovieActionMarker(TasMovieMarker marker, int oldPosition = -1, string old_message = "")
{
FirstFrame = oldPosition;
if (marker == null)
{
LastFrame = -1;
oldMessage = old_message;
}
else
{
LastFrame = marker.Frame;
if (old_message == "")
oldMessage = marker.Message;
else
oldMessage = old_message;
newMessage = marker.Message;
}
}
public void Undo(TasMovie movie)
{
if (FirstFrame == -1) // Action: Place marker
movie.Markers.Remove(movie.Markers.Get(LastFrame));
else if (LastFrame == -1) // Action: Remove marker
movie.Markers.Add(FirstFrame, oldMessage);
else // Action: Move/rename marker
{
movie.Markers.Move(LastFrame, FirstFrame);
movie.Markers.Get(LastFrame).Message = oldMessage;
}
}
public void Redo(TasMovie movie)
{
if (FirstFrame == -1) // Action: Place marker
movie.Markers.Add(LastFrame, oldMessage);
else if (LastFrame == -1) // Action: Remove marker
movie.Markers.Remove(movie.Markers.Get(FirstFrame));
else // Action: Move/rename marker
{
movie.Markers.Move(FirstFrame, LastFrame);
movie.Markers.Get(LastFrame).Message = newMessage;
}
}
}
public class MovieActionFrameEdit : IMovieAction
{
public int FirstFrame { get; private set; }
public int LastFrame { get { return FirstFrame; } }
private float oldState, newState;
private string buttonName;
private bool isFloat = false;
public MovieActionFrameEdit(int frame, string button, bool oldS, bool newS)
{
oldState = oldS ? 1 : 0;
newState = newS ? 1 : 0;
FirstFrame = frame;
buttonName = button;
}
public MovieActionFrameEdit(int frame, string button, float oldS, float newS)
{
oldState = oldS;
newState = newS;
FirstFrame = 0;
buttonName = button;
isFloat = true;
}
public void Undo(TasMovie movie)
{
bool wasRecording = movie.ChangeLog.AutoRecord;
movie.ChangeLog.AutoRecord = false;
if (isFloat)
movie.SetFloatState(FirstFrame, buttonName, oldState);
else
movie.SetBoolState(FirstFrame, buttonName, oldState == 1);
movie.ChangeLog.AutoRecord = wasRecording;
}
public void Redo(TasMovie movie)
{
bool wasRecording = movie.ChangeLog.AutoRecord;
movie.ChangeLog.AutoRecord = false;
if (isFloat)
movie.SetFloatState(FirstFrame, buttonName, newState);
else
movie.SetBoolState(FirstFrame, buttonName, newState == 1);
movie.ChangeLog.AutoRecord = wasRecording;
}
}
public class MovieActionPaint : IMovieAction
{
public int FirstFrame { get; private set; }
public int LastFrame { get; private set; }
private List<float> oldState;
private float newState;
private string buttonName;
private bool isFloat = false;
public MovieActionPaint(int startFrame, int endFrame, string button, bool newS, TasMovie movie)
{
newState = newS ? 1 : 0;
FirstFrame = startFrame;
LastFrame = endFrame;
buttonName = button;
oldState = new List<float>(endFrame - startFrame + 1);
for (int i = 0; i < endFrame - startFrame + 1; i++)
oldState.Add(movie.BoolIsPressed(startFrame + i, button) ? 1 : 0);
}
public MovieActionPaint(int startFrame, int endFrame, string button, float newS, TasMovie movie)
{
newState = newS;
FirstFrame = startFrame;
LastFrame = endFrame;
buttonName = button;
isFloat = true;
oldState = new List<float>(endFrame - startFrame + 1);
for (int i = 0; i < endFrame - startFrame + 1; i++)
oldState.Add(movie.BoolIsPressed(startFrame + i, button) ? 1 : 0);
}
public void Undo(TasMovie movie)
{
bool wasRecording = movie.ChangeLog.AutoRecord;
movie.ChangeLog.AutoRecord = false;
//if (isFloat)
// movie.SetFloatStates(FirstFrame, LastFrame - FirstFrame + 1, buttonName, oldState);
//else
// movie.SetBoolState(FirstFrame, buttonName, oldState == 1);
movie.ChangeLog.AutoRecord = wasRecording;
}
public void Redo(TasMovie movie)
{
bool wasRecording = movie.ChangeLog.AutoRecord;
movie.ChangeLog.AutoRecord = false;
if (isFloat)
movie.SetFloatStates(FirstFrame, LastFrame - FirstFrame + 1, buttonName, newState);
else
movie.SetBoolStates(FirstFrame, LastFrame - FirstFrame + 1, buttonName, newState == 1);
movie.ChangeLog.AutoRecord = wasRecording;
}
}
#endregion
}

View File

@ -28,7 +28,7 @@ namespace BizHawk.Client.Common
Message = split[1];
}
public virtual int Frame { get; set; }
public virtual int Frame { get; private set; }
public virtual string Message { get; set; }
@ -161,6 +161,13 @@ namespace BizHawk.Client.Common
return removeCount;
}
public void Move(int fromFrame, int toFrame)
{
TasMovieMarker m = Get(fromFrame);
Insert(0, new TasMovieMarker(toFrame, m.Message));
Remove(m);
}
/// <summary>
/// Deletes all markers at or below the given start frame.
/// </summary>