diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs index f85049105e..3d928a1bb6 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs @@ -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; diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs index a86a52cdeb..634f4e2711 100644 --- a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs @@ -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; - } - } - /// /// 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); diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index aa82683fef..dadf7a69a6 100644 --- a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -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) diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index 611e1f86fe..ec6099b695 100644 --- a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -64,6 +64,11 @@ namespace BizHawk.Client.EmuHawk [ConfigPersist] public Font TasViewFont { get; set; } = new Font("Arial", 8.25F, FontStyle.Bold, GraphicsUnit.Point, 0); + /// + /// This is meant to be used by Lua. + /// + public bool StopRecordingOnNextEdit = true; + public class TAStudioSettings { public TAStudioSettings() diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.cs index 32892bc021..f900e87713 100644 --- a/src/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.cs +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudio/UndoHistoryForm.cs @@ -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(); }