diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs index 1593a24edb..4a7f3a9422 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/TAStudioLuaLibrary.cs @@ -300,6 +300,11 @@ namespace BizHawk.Client.EmuHawk [LuaMethod("applyinputchanges", "")] public void ApplyInputChanges() { + if (_changeList.Count == 0) + { + return; + } + if (Engaged()) { if (_luaLibsImpl.IsInInputOrMemoryCallback) @@ -309,7 +314,7 @@ namespace BizHawk.Client.EmuHawk _luaLibsImpl.IsUpdateSupressed = true; - if (_changeList.Count > 0) + Tastudio.ApiHawkBatchEdit(() => { int size = _changeList.Count; @@ -327,7 +332,7 @@ namespace BizHawk.Client.EmuHawk Tastudio.CurrentTasMovie.SetAxisState(_changeList[i].Frame, _changeList[i].Button, _changeList[i].ValueAxis); break; } - Tastudio.RefreshForInputChange(_changeList[i].Frame); + Tastudio.FrameEdited(_changeList[i].Frame); break; case LuaChangeTypes.InsertFrames: Tastudio.InsertNumFrames(_changeList[i].Frame, _changeList[i].Number); @@ -341,9 +346,7 @@ namespace BizHawk.Client.EmuHawk } } _changeList.Clear(); - Tastudio.JumpToGreenzone(); - Tastudio.DoAutoRestore(); - } + }); _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 38cd64e404..789beba5c2 100644 --- a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs @@ -25,7 +25,9 @@ namespace BizHawk.Client.EmuHawk private bool _selectionDragState; private bool _suppressContextMenu; private int _startRow; - private int _mouseEditMinFrame = -1; + private int _batchEditMinFrame = -1; + private bool _batchEditing; + private bool _editIsFromLua; // Editing analog input private string _axisEditColumn = ""; @@ -66,14 +68,6 @@ namespace BizHawk.Client.EmuHawk public AutoPatternBool[] BoolPatterns; public AutoPatternAxis[] AxisPatterns; - public void JumpToGreenzone(bool OnLeftMouseDown = false) - { - if (Emulator.Frame > CurrentTasMovie.LastEditedFrame) - { - GoToLastEmulatedFrameIfNecessary(CurrentTasMovie.LastEditedFrame, OnLeftMouseDown); - } - } - private void StartSeeking(int? frame, bool fromMiddleClick = false) { if (!frame.HasValue || frame <= Emulator.Frame) @@ -393,6 +387,7 @@ namespace BizHawk.Client.EmuHawk if (columnName == FrameColumnName) { CurrentTasMovie.Markers.Add(TasView.SelectionEndIndex!.Value, ""); + RefreshDialog(); } else if (columnName != CursorColumnName) { @@ -433,8 +428,6 @@ namespace BizHawk.Client.EmuHawk FrameEdited(CurrentTasMovie.LastEditedFrame); } - - RefreshDialog(); } } @@ -653,7 +646,6 @@ namespace BizHawk.Client.EmuHawk CurrentTasMovie.SetBoolStates(firstSel, lastSel - firstSel + 1, buttonName, !allPressed); _boolPaintState = CurrentTasMovie.BoolIsPressed(lastSel, buttonName); FrameEdited(CurrentTasMovie.LastEditedFrame); - RefreshDialog(); } #if false // to match previous behaviour else if (altOrShift4State is not 0) @@ -668,7 +660,6 @@ namespace BizHawk.Client.EmuHawk CurrentTasMovie.ToggleBoolState(frame, buttonName); _boolPaintState = CurrentTasMovie.BoolIsPressed(frame, buttonName); FrameEdited(CurrentTasMovie.LastEditedFrame); - RefreshDialog(); } } else @@ -685,6 +676,7 @@ namespace BizHawk.Client.EmuHawk { AxisPatterns[ControllerType.Axes.IndexOf(buttonName)].Reset(); CurrentTasMovie.SetAxisState(frame, buttonName, AxisPatterns[ControllerType.Axes.IndexOf(buttonName)].GetNextValue()); + FrameEdited(frame); _patternPaint = true; } else @@ -779,33 +771,93 @@ namespace BizHawk.Client.EmuHawk } } + /// + /// Begins a batch of edits, for auto-restore purposes. Auto-restore will be delayed until EndBatchEdit is called. + /// + private void BeginBatchEdit() + { + _batchEditing = true; + } + /// Returns true if the input list was redrawn. + private bool EndBatchEdit() + { + _batchEditing = false; + if (_batchEditMinFrame != -1) + { + return FrameEdited(_batchEditMinFrame); + } + + return false; + } + + public void ApiHawkBatchEdit(Action action) + { + // This is only caled from Lua. + _editIsFromLua = true; + BeginBatchEdit(); + action(); + 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. /// - private void FrameEdited(int frame) + /// The frame that was just edited, or the earliest one if multiple were edited. + /// Returns true if the input list was redrawn. + public bool FrameEdited(int frame) { - if (MouseButtonHeld) + bool needsRefresh = !_batchEditing; + if (MouseButtonHeld || _batchEditing) { - if (_mouseEditMinFrame == -1) + if (_batchEditMinFrame == -1) { - _mouseEditMinFrame = frame; + _batchEditMinFrame = frame; } else { - _mouseEditMinFrame = Math.Min(_mouseEditMinFrame, frame); + _batchEditMinFrame = Math.Min(_batchEditMinFrame, frame); } } else { - TastudioPlayMode(true); + if (!_editIsFromLua) + { + // Lua users will want to preserve recording mode. + TastudioPlayMode(true); + } + if (Emulator.Frame > frame) { GoToLastEmulatedFrameIfNecessary(frame); - DoAutoRestore(); + if (Settings.AutoRestoreLastPosition && RestorePositionFrame != -1) + { + StartSeeking(RestorePositionFrame); + } + + needsRefresh = false; // Refresh will happen via GoToFrame. } - _mouseEditMinFrame = -1; + _batchEditMinFrame = -1; } + + if (needsRefresh) + { + if (TasView.IsPartiallyVisible(frame) || frame < TasView.FirstVisibleRow) + { + // frame < FirstVisibleRow: Greenzone in visible rows has been invalidated + RefreshDialog(); + return true; + } + else if (TasView.RowCount != CurrentTasMovie.InputLogLength + 1) + { + // Row count must always be kept up to date even if last row is not directly visible. + TasView.RowCount = CurrentTasMovie.InputLogLength + 1; + return true; + } + } + + return false; } private void ClearLeftMouseStates() @@ -822,7 +874,6 @@ namespace BizHawk.Client.EmuHawk { AxisEditRow = -1; FrameEdited(_axisEditRow); - RefreshDialog(); } _axisPaintState = 0; _axisEditYPos = -1; @@ -892,10 +943,7 @@ namespace BizHawk.Client.EmuHawk } } - if (_mouseEditMinFrame != -1) - { - FrameEdited(_mouseEditMinFrame); - } + EndBatchEdit(); // We didn't call BeginBatchEdit, but implicitly began one with mouse down. We must explicitly end it. _suppressContextMenu = false; } @@ -1014,6 +1062,7 @@ namespace BizHawk.Client.EmuHawk } SetSplicer(); + RefreshDialog(); } else if (_rightClickFrame != -1) { @@ -1171,7 +1220,6 @@ namespace BizHawk.Client.EmuHawk CurrentTasMovie.SetAxisState(i, _startAxisDrawColumn, setVal); // Notice it uses new row, old column, you can only paint across a single column FrameEdited(CurrentTasMovie.LastEditedFrame); - RefreshDialog(); } } @@ -1181,8 +1229,6 @@ namespace BizHawk.Client.EmuHawk { TasView.MakeIndexVisible(TasView.CurrentCell.RowIndex.Value); // todo: limit scrolling speed } - - SetTasViewRowCount(); } private void TasView_MouseMove(object sender, MouseEventArgs e) @@ -1405,7 +1451,11 @@ namespace BizHawk.Client.EmuHawk } } - RefreshDialog(); + bool didRefresh = EndBatchEdit(); + if (!didRefresh && (prevTyped != _axisTypedValue || !AxisEditingMode)) + { + RefreshDialog(); + } } private void TasView_KeyDown(object sender, KeyEventArgs e) @@ -1436,8 +1486,6 @@ namespace BizHawk.Client.EmuHawk { EditAnalogProgrammatically(e); } - - RefreshDialog(); } } } diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index aa5adf686f..2e9e601779 100644 --- a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -425,11 +425,8 @@ namespace BizHawk.Client.EmuHawk var rollbackFrame = CurrentTasMovie.CopyOverInput(TasView.SelectionStartIndex ?? 0, _tasClipboard.Select(static x => x.ControllerState)); if (rollbackFrame > 0) { - GoToLastEmulatedFrameIfNecessary(rollbackFrame); - DoAutoRestore(); + FrameEdited(rollbackFrame); } - - RefreshDialog(); } } } @@ -465,15 +462,8 @@ namespace BizHawk.Client.EmuHawk } var selectionStart = TasView.SelectionStartIndex; - var needsToRollback = selectionStart < Emulator.Frame; CurrentTasMovie.InsertInput(selectionStart ?? 0, _tasClipboard.Select(static x => x.ControllerState)); - if (needsToRollback) - { - GoToLastEmulatedFrameIfNecessary(selectionStart!.Value); - DoAutoRestore(); - } - - RefreshDialog(); + FrameEdited(selectionStart!.Value); } } } @@ -485,7 +475,6 @@ namespace BizHawk.Client.EmuHawk if (TasView.Focused && TasView.AnyRowsSelected) { var selectionStart = TasView.SelectionStartIndex; - var needsToRollback = selectionStart < Emulator.Frame; var rollBackFrame = selectionStart ?? 0; _tasClipboard.Clear(); @@ -508,13 +497,7 @@ namespace BizHawk.Client.EmuHawk CurrentTasMovie.RemoveFrames(list); SetSplicer(); - if (needsToRollback) - { - GoToLastEmulatedFrameIfNecessary(rollBackFrame); - DoAutoRestore(); - } - - RefreshDialog(); + FrameEdited(rollBackFrame); } } @@ -536,8 +519,7 @@ namespace BizHawk.Client.EmuHawk if (needsToRollback) { - GoToLastEmulatedFrameIfNecessary(rollBackFrame); - DoAutoRestore(); + FrameEdited(rollBackFrame); } RefreshDialog(); @@ -549,7 +531,6 @@ namespace BizHawk.Client.EmuHawk if (TasView.Focused && TasView.AnyRowsSelected) { var selectionStart = TasView.SelectionStartIndex; - var needsToRollback = selectionStart < Emulator.Frame; var rollBackFrame = selectionStart ?? 0; if (rollBackFrame >= CurrentTasMovie.InputLogLength) { @@ -562,13 +543,7 @@ namespace BizHawk.Client.EmuHawk SetTasViewRowCount(); SetSplicer(); - if (needsToRollback) - { - GoToLastEmulatedFrameIfNecessary(rollBackFrame); - DoAutoRestore(); - } - - RefreshDialog(); + FrameEdited(rollBackFrame); } } @@ -594,7 +569,6 @@ namespace BizHawk.Client.EmuHawk { var framesToInsert = TasView.SelectedRows; var insertionFrame = Math.Min((TasView.SelectionEndIndex ?? 0) + 1, CurrentTasMovie.InputLogLength); - var needsToRollback = TasView.SelectionStartIndex < Emulator.Frame; var inputLog = framesToInsert .Select(frame => CurrentTasMovie.GetInputLogEntry(frame)) @@ -602,13 +576,7 @@ namespace BizHawk.Client.EmuHawk CurrentTasMovie.InsertInput(insertionFrame, inputLog); - if (needsToRollback) - { - GoToLastEmulatedFrameIfNecessary(insertionFrame); - DoAutoRestore(); - } - - RefreshDialog(); + FrameEdited(insertionFrame); } } } @@ -619,17 +587,9 @@ namespace BizHawk.Client.EmuHawk { var selectionStart = TasView.SelectionStartIndex; var insertionFrame = selectionStart ?? 0; - var needsToRollback = selectionStart < Emulator.Frame; CurrentTasMovie.InsertEmptyFrame(insertionFrame); - - if (needsToRollback) - { - GoToLastEmulatedFrameIfNecessary(insertionFrame); - DoAutoRestore(); - } - - RefreshDialog(); + FrameEdited(insertionFrame); } } @@ -651,17 +611,11 @@ namespace BizHawk.Client.EmuHawk if (TasView.Focused && TasView.AnyRowsSelected) { var rollbackFrame = TasView.SelectionEndIndex ?? 0; - var needsToRollback = TasView.SelectionStartIndex < Emulator.Frame; CurrentTasMovie.Truncate(rollbackFrame); MarkerControl.MarkerInputRoll.TruncateSelection(CurrentTasMovie.Markers.Count - 1); - if (needsToRollback) - { - GoToFrame(rollbackFrame); - } - - RefreshDialog(); + FrameEdited(rollbackFrame); } } diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index 419b018fd1..c02b17c8a1 100644 --- a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -800,28 +800,12 @@ namespace BizHawk.Client.EmuHawk } } - public void RefreshForInputChange(int firstChangedFrame) - { - if (TasView.IsPartiallyVisible(firstChangedFrame) || firstChangedFrame < TasView.FirstVisibleRow) - { - RefreshDialog(); - } - } - private void SetTasViewRowCount() { TasView.RowCount = CurrentTasMovie.InputLogLength + 1; _lastRefresh = Emulator.Frame; } - public void DoAutoRestore() - { - if (Settings.AutoRestoreLastPosition && RestorePositionFrame != -1) - { - StartSeeking(RestorePositionFrame); - } - } - /// /// Get a savestate prior to the previous frame so code following the call can frame advance and have a framebuffer. /// If frame is 0, return the initial state. @@ -875,19 +859,8 @@ namespace BizHawk.Client.EmuHawk { if (insertionFrame <= CurrentTasMovie.InputLogLength) { - var needsToRollback = TasView.SelectionStartIndex < Emulator.Frame; - CurrentTasMovie.InsertEmptyFrame(insertionFrame, numberOfFrames); - - if (needsToRollback) - { - GoToLastEmulatedFrameIfNecessary(insertionFrame); - DoAutoRestore(); - } - else - { - RefreshForInputChange(insertionFrame); - } + FrameEdited(insertionFrame); } } @@ -899,16 +872,7 @@ namespace BizHawk.Client.EmuHawk CurrentTasMovie.RemoveFrames(framesToRemove); SetSplicer(); - var needsToRollback = beginningFrame < Emulator.Frame; - if (needsToRollback) - { - GoToLastEmulatedFrameIfNecessary(beginningFrame); - DoAutoRestore(); - } - else - { - RefreshForInputChange(beginningFrame); - } + FrameEdited(beginningFrame); } } @@ -916,22 +880,13 @@ namespace BizHawk.Client.EmuHawk { if (beginningFrame < CurrentTasMovie.InputLogLength) { - var needsToRollback = TasView.SelectionStartIndex < Emulator.Frame; int last = Math.Min(beginningFrame + numberOfFrames, CurrentTasMovie.InputLogLength); for (int i = beginningFrame; i < last; i++) { CurrentTasMovie.ClearFrame(i); } - if (needsToRollback) - { - GoToLastEmulatedFrameIfNecessary(beginningFrame); - DoAutoRestore(); - } - else - { - RefreshForInputChange(beginningFrame); - } + FrameEdited(beginningFrame); } } @@ -1038,8 +993,7 @@ namespace BizHawk.Client.EmuHawk } CurrentTasMovie.ChangeLog.IsRecording = wasRecording; - GoToLastEmulatedFrameIfNecessary(Emulator.Frame - 1); - DoAutoRestore(); + FrameEdited(Emulator.Frame - 1); return true; }