Use undo and invalidation batching where appropriate.
Fixes: Inserting frames, cloning frames, and Lua edits could result in large numbers of undo actions. Also fixes enabled state of undo and redo menu items.
This commit is contained in:
parent
4fedc62c51
commit
2c3eb93ea8
|
@ -314,8 +314,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
_luaLibsImpl.IsUpdateSupressed = true;
|
||||
|
||||
Tastudio.ApiHawkBatchEdit(() =>
|
||||
Tastudio.StopRecordingOnNextEdit = false;
|
||||
Tastudio.CurrentTasMovie.SingleInvalidation(() =>
|
||||
{
|
||||
Tastudio.CurrentTasMovie.ChangeLog.BeginNewBatch("tastudio.applyinputchanges");
|
||||
int size = _changeList.Count;
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
|
@ -345,6 +347,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
_changeList.Clear();
|
||||
Tastudio.CurrentTasMovie.ChangeLog.EndBatch();
|
||||
});
|
||||
|
||||
_luaLibsImpl.IsUpdateSupressed = false;
|
||||
|
|
|
@ -27,7 +27,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
private int _startRow;
|
||||
private int _batchEditMinFrame = -1;
|
||||
private bool _batchEditing;
|
||||
private bool _editIsFromLua;
|
||||
|
||||
// Editing analog input
|
||||
private string _axisEditColumn = "";
|
||||
|
@ -405,10 +404,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
else
|
||||
{
|
||||
BoolPatterns[ControllerType.BoolButtons.IndexOf(buttonName)].Reset();
|
||||
foreach (var index in TasView.SelectedRows)
|
||||
CurrentTasMovie.SingleInvalidation(() =>
|
||||
{
|
||||
CurrentTasMovie.SetBoolState(index, buttonName, BoolPatterns[ControllerType.BoolButtons.IndexOf(buttonName)].GetNextValue());
|
||||
}
|
||||
foreach (var index in TasView.SelectedRows)
|
||||
{
|
||||
CurrentTasMovie.SetBoolState(index, buttonName, BoolPatterns[ControllerType.BoolButtons.IndexOf(buttonName)].GetNextValue());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -783,22 +785,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
return false;
|
||||
}
|
||||
|
||||
public void ApiHawkBatchEdit(Action action)
|
||||
{
|
||||
// This is only caled from Lua.
|
||||
_editIsFromLua = true;
|
||||
BeginBatchEdit();
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndBatchEdit();
|
||||
_editIsFromLua = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables recording mode, ensures we are in the greenzone, and does autorestore if needed.
|
||||
/// If a mouse button is down, only tracks the edit so we can do this stuff on mouse up.
|
||||
|
@ -828,11 +814,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!_editIsFromLua)
|
||||
if (StopRecordingOnNextEdit)
|
||||
{
|
||||
// Lua users will want to preserve recording mode.
|
||||
TastudioPlayMode(true);
|
||||
}
|
||||
StopRecordingOnNextEdit = true;
|
||||
|
||||
if (Emulator.Frame > frame)
|
||||
{
|
||||
|
@ -1098,6 +1085,30 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
else if (_rightClickFrame != -1)
|
||||
{
|
||||
FramePaint(frame, startVal, endVal);
|
||||
}
|
||||
// Left-click
|
||||
else if (TasView.IsPaintDown && !string.IsNullOrEmpty(_startBoolDrawColumn))
|
||||
{
|
||||
BoolPaint(frame, startVal, endVal);
|
||||
}
|
||||
else if (TasView.IsPaintDown && !string.IsNullOrEmpty(_startAxisDrawColumn))
|
||||
{
|
||||
AxisPaint(frame, startVal, endVal);
|
||||
}
|
||||
|
||||
CurrentTasMovie.IsCountingRerecords = wasCountingRerecords;
|
||||
|
||||
if (MouseButtonHeld)
|
||||
{
|
||||
TasView.MakeIndexVisible(TasView.CurrentCell.RowIndex.Value); // todo: limit scrolling speed
|
||||
SetTasViewRowCount(); // refreshes
|
||||
}
|
||||
}
|
||||
|
||||
private void FramePaint(int frame, int startVal, int endVal)
|
||||
{
|
||||
CurrentTasMovie.SingleInvalidation(() => {
|
||||
if (frame > CurrentTasMovie.InputLogLength - _rightClickInput.Length)
|
||||
{
|
||||
frame = CurrentTasMovie.InputLogLength - _rightClickInput.Length;
|
||||
|
@ -1201,11 +1212,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
_suppressContextMenu = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Left-click
|
||||
else if (TasView.IsPaintDown && !string.IsNullOrEmpty(_startBoolDrawColumn))
|
||||
{
|
||||
private void BoolPaint(int frame, int startVal, int endVal)
|
||||
{
|
||||
CurrentTasMovie.SingleInvalidation(() => {
|
||||
CurrentTasMovie.IsCountingRerecords = false;
|
||||
|
||||
for (int i = startVal; i <= endVal; i++) // Inclusive on both ends (drawing up or down)
|
||||
|
@ -1226,9 +1238,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
CurrentTasMovie.SetBoolState(i, _startBoolDrawColumn, setVal); // Notice it uses new row, old column, you can only paint across a single column
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
else if (TasView.IsPaintDown && !string.IsNullOrEmpty(_startAxisDrawColumn))
|
||||
private void AxisPaint(int frame, int startVal, int endVal)
|
||||
{
|
||||
CurrentTasMovie.SingleInvalidation(() =>
|
||||
{
|
||||
CurrentTasMovie.IsCountingRerecords = false;
|
||||
|
||||
|
@ -1249,15 +1264,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
CurrentTasMovie.SetAxisState(i, _startAxisDrawColumn, setVal); // Notice it uses new row, old column, you can only paint across a single column
|
||||
}
|
||||
}
|
||||
|
||||
CurrentTasMovie.IsCountingRerecords = wasCountingRerecords;
|
||||
|
||||
if (MouseButtonHeld)
|
||||
{
|
||||
TasView.MakeIndexVisible(TasView.CurrentCell.RowIndex.Value); // todo: limit scrolling speed
|
||||
SetTasViewRowCount(); // refreshes
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void TasView_MouseMove(object sender, MouseEventArgs e)
|
||||
|
@ -1338,6 +1345,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: properly handle axis editing batches
|
||||
BeginBatchEdit();
|
||||
|
||||
int value = CurrentTasMovie.GetAxisState(_axisEditRow, _axisEditColumn);
|
||||
|
|
|
@ -277,38 +277,21 @@ namespace BizHawk.Client.EmuHawk
|
|||
GreenzoneICheckSeparator.Visible =
|
||||
StateHistoryIntegrityCheckMenuItem.Visible =
|
||||
VersionInfo.DeveloperBuild;
|
||||
|
||||
UndoMenuItem.Enabled = CurrentTasMovie.ChangeLog.CanUndo;
|
||||
RedoMenuItem.Enabled = CurrentTasMovie.ChangeLog.CanRedo;
|
||||
}
|
||||
|
||||
private void UndoMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (CurrentTasMovie.ChangeLog.Undo() < Emulator.Frame)
|
||||
{
|
||||
GoToFrame(CurrentTasMovie.ChangeLog.PreviousUndoFrame);
|
||||
}
|
||||
else
|
||||
{
|
||||
RefreshDialog();
|
||||
}
|
||||
|
||||
// Currently I don't have a way to easily detect when CanUndo changes, so this button should be enabled always.
|
||||
// UndoMenuItem.Enabled = CurrentTasMovie.ChangeLog.CanUndo;
|
||||
RedoMenuItem.Enabled = CurrentTasMovie.ChangeLog.CanRedo;
|
||||
CurrentTasMovie.ChangeLog.Undo();
|
||||
RefreshDialog(); // ?? redundant, except if undoing markers
|
||||
}
|
||||
|
||||
private void RedoMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (CurrentTasMovie.ChangeLog.Redo() < Emulator.Frame)
|
||||
{
|
||||
GoToFrame(CurrentTasMovie.ChangeLog.PreviousRedoFrame);
|
||||
}
|
||||
else
|
||||
{
|
||||
RefreshDialog();
|
||||
}
|
||||
|
||||
// Currently I don't have a way to easily detect when CanUndo changes, so this button should be enabled always.
|
||||
// UndoMenuItem.Enabled = CurrentTasMovie.ChangeLog.CanUndo;
|
||||
RedoMenuItem.Enabled = CurrentTasMovie.ChangeLog.CanRedo;
|
||||
CurrentTasMovie.ChangeLog.Redo();
|
||||
RefreshDialog(); // ?? redundant, except if undoing markers
|
||||
}
|
||||
|
||||
private void ShowUndoHistoryMenuItem_Click(object sender, EventArgs e)
|
||||
|
@ -495,9 +478,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void ClearFramesMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (TasView.Focused && TasView.AnyRowsSelected)
|
||||
if (!TasView.Focused || !TasView.AnyRowsSelected) return;
|
||||
|
||||
CurrentTasMovie.SingleInvalidation(() =>
|
||||
{
|
||||
BeginBatchEdit();
|
||||
CurrentTasMovie.ChangeLog.BeginNewBatch($"Clear frames {TasView.SelectionStartIndex}-{TasView.SelectionEndIndex}");
|
||||
foreach (int frame in TasView.SelectedRows)
|
||||
{
|
||||
|
@ -505,8 +489,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
|
||||
CurrentTasMovie.ChangeLog.EndBatch();
|
||||
EndBatchEdit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void DeleteFramesMenuItem_Click(object sender, EventArgs e)
|
||||
|
@ -544,22 +527,28 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void CloneFramesXTimes(int timesToClone)
|
||||
{
|
||||
BeginBatchEdit();
|
||||
for (int i = 0; i < timesToClone; i++)
|
||||
if (!TasView.Focused || !TasView.AnyRowsSelected) return;
|
||||
|
||||
var framesToInsert = TasView.SelectedRows;
|
||||
var insertionFrame = Math.Min((TasView.SelectionEndIndex ?? 0) + 1, CurrentTasMovie.InputLogLength);
|
||||
|
||||
var inputLog = framesToInsert
|
||||
.Select(CurrentTasMovie.GetInputLogEntry)
|
||||
.ToList();
|
||||
|
||||
CurrentTasMovie.SingleInvalidation(() =>
|
||||
{
|
||||
if (TasView.Focused && TasView.AnyRowsSelected)
|
||||
string batchName = $"Clone {inputLog.Count} frames starting at {TasView.FirstSelectedRowIndex}";
|
||||
if (timesToClone != 1) batchName += $" {timesToClone} times";
|
||||
CurrentTasMovie.ChangeLog.BeginNewBatch(batchName);
|
||||
|
||||
for (int i = 0; i < timesToClone; i++)
|
||||
{
|
||||
var framesToInsert = TasView.SelectedRows;
|
||||
var insertionFrame = Math.Min((TasView.SelectionEndIndex ?? 0) + 1, CurrentTasMovie.InputLogLength);
|
||||
|
||||
var inputLog = framesToInsert
|
||||
.Select(frame => CurrentTasMovie.GetInputLogEntry(frame))
|
||||
.ToList();
|
||||
|
||||
CurrentTasMovie.InsertInput(insertionFrame, inputLog);
|
||||
}
|
||||
}
|
||||
EndBatchEdit();
|
||||
|
||||
CurrentTasMovie.ChangeLog.EndBatch();
|
||||
});
|
||||
}
|
||||
|
||||
private void InsertFrameMenuItem_Click(object sender, EventArgs e)
|
||||
|
|
|
@ -64,6 +64,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
[ConfigPersist]
|
||||
public Font TasViewFont { get; set; } = new Font("Arial", 8.25F, FontStyle.Bold, GraphicsUnit.Point, 0);
|
||||
|
||||
/// <summary>
|
||||
/// This is meant to be used by Lua.
|
||||
/// </summary>
|
||||
public bool StopRecordingOnNextEdit = true;
|
||||
|
||||
public class TAStudioSettings
|
||||
{
|
||||
public TAStudioSettings()
|
||||
|
|
|
@ -85,19 +85,17 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void UndoToHere(int index)
|
||||
{
|
||||
int earliestFrame = int.MaxValue;
|
||||
while (Log.UndoIndex > index)
|
||||
_tastudio.CurrentTasMovie.SingleInvalidation(() =>
|
||||
{
|
||||
int frame = Log.Undo();
|
||||
if (frame < earliestFrame)
|
||||
earliestFrame = frame;
|
||||
}
|
||||
while (Log.UndoIndex > index)
|
||||
{
|
||||
Log.Undo();
|
||||
}
|
||||
});
|
||||
|
||||
UpdateValues();
|
||||
|
||||
// potentially rewind, then update display for TAStudio
|
||||
if (_tastudio.Emulator.Frame > earliestFrame)
|
||||
_tastudio.GoToFrame(earliestFrame);
|
||||
// potentially redundant refresh
|
||||
_tastudio.RefreshDialog();
|
||||
}
|
||||
|
||||
|
@ -136,19 +134,17 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void RedoHereMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
int earliestFrame = int.MaxValue;
|
||||
while (Log.UndoIndex < SelectedItem)
|
||||
_tastudio.CurrentTasMovie.SingleInvalidation(() =>
|
||||
{
|
||||
int frame = Log.Redo();
|
||||
if (earliestFrame < frame)
|
||||
earliestFrame = frame;
|
||||
}
|
||||
while (Log.UndoIndex < SelectedItem)
|
||||
{
|
||||
Log.Redo();
|
||||
}
|
||||
});
|
||||
|
||||
UpdateValues();
|
||||
|
||||
// potentially rewind, then update display for TAStudio
|
||||
if (_tastudio.Emulator.Frame > earliestFrame)
|
||||
_tastudio.GoToFrame(earliestFrame);
|
||||
// potentially redundant refresh
|
||||
_tastudio.RefreshDialog();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue