Merge pull request #4347 from SuuperW/auto_restore
Fixes to seeking and auto restore
This commit is contained in:
commit
b9d78a6046
|
@ -133,6 +133,7 @@ namespace BizHawk.Client.Common
|
|||
Bind("TAStudio", "Show Cursor");
|
||||
Bind("TAStudio", "Toggle Follow Cursor", "Shift+F");
|
||||
Bind("TAStudio", "Toggle Auto-Restore", "Shift+R");
|
||||
Bind("TAStudio", "Seek To Green Arrow", "R");
|
||||
Bind("TAStudio", "Toggle Turbo Seek", "Shift+S");
|
||||
Bind("TAStudio", "Undo", "Ctrl+Z"); // TODO: these are getting not unique enough
|
||||
Bind("TAStudio", "Redo", "Ctrl+Y");
|
||||
|
|
|
@ -102,37 +102,11 @@ namespace BizHawk.Client.Common
|
|||
public void InvisibleEmulation(bool invisible)
|
||||
=> APIs.EmuClient.InvisibleEmulation(invisible);
|
||||
|
||||
[LuaMethodExample("client.seekframe( 100 );")]
|
||||
[LuaMethod("seekframe", "Makes the emulator seek to the frame specified")]
|
||||
[LuaDeprecatedMethod]
|
||||
[LuaMethod("seekframe", "Does nothing. Use the pause/unpause functions instead and a loop that waits for the desired frame.")]
|
||||
public void SeekFrame(int frame)
|
||||
{
|
||||
if (_luaLibsImpl.IsInInputOrMemoryCallback)
|
||||
{
|
||||
throw new InvalidOperationException("client.seekframe() is not allowed during input/memory callbacks");
|
||||
}
|
||||
|
||||
if (frame < Emulator.Frame)
|
||||
{
|
||||
Log("client.seekframe: cannot seek backwards");
|
||||
return;
|
||||
}
|
||||
if (frame == Emulator.Frame) return;
|
||||
|
||||
bool wasPaused = MainForm.EmulatorPaused;
|
||||
|
||||
// can't re-enter lua while doing this
|
||||
_luaLibsImpl.IsUpdateSupressed = true;
|
||||
while (Emulator.Frame != frame)
|
||||
{
|
||||
MainForm.SeekFrameAdvance();
|
||||
}
|
||||
|
||||
_luaLibsImpl.IsUpdateSupressed = false;
|
||||
|
||||
if (!wasPaused)
|
||||
{
|
||||
MainForm.UnpauseEmulator();
|
||||
}
|
||||
Log("Deprecated function client.seekframe() used. Replace the call with pause/unpause functions and a loop that waits for the desired frame.");
|
||||
}
|
||||
|
||||
[LuaMethodExample("local sounds_terrible = client.get_approx_framerate() < 55;")]
|
||||
|
|
|
@ -7,7 +7,6 @@ namespace BizHawk.Client.Common
|
|||
public interface ITasMovie : IMovie, INotifyPropertyChanged, IDisposable
|
||||
{
|
||||
bool BindMarkersToInput { get; set; }
|
||||
bool LastPositionStable { get; set; }
|
||||
|
||||
IMovieChangeLog ChangeLog { get; }
|
||||
IStateManager TasStateManager { get; }
|
||||
|
@ -20,6 +19,7 @@ namespace BizHawk.Client.Common
|
|||
TasLagLog LagLog { get; }
|
||||
IStringLog VerificationLog { get; }
|
||||
int LastEditedFrame { get; }
|
||||
bool LastEditWasRecording { get; }
|
||||
|
||||
Action<int> GreenzoneInvalidated { get; set; }
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (this.IsRecording())
|
||||
{
|
||||
LastEditWasRecording = true;
|
||||
InvalidateAfter(frame);
|
||||
}
|
||||
|
||||
|
@ -82,9 +83,12 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public void ClearFrame(int frame)
|
||||
{
|
||||
string empty = Bk2LogEntryGenerator.EmptyEntry(Session.MovieController);
|
||||
if (GetInputLogEntry(frame) == empty) return;
|
||||
|
||||
ChangeLog.AddGeneralUndo(frame, frame, $"Clear Frame: {frame}");
|
||||
|
||||
SetFrameAt(frame, Bk2LogEntryGenerator.EmptyEntry(Session.MovieController));
|
||||
SetFrameAt(frame, empty);
|
||||
Changes = true;
|
||||
|
||||
InvalidateAfter(frame);
|
||||
|
@ -211,6 +215,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (Log.Count < states.Count + frame)
|
||||
{
|
||||
firstChangedFrame = Log.Count;
|
||||
ExtendMovieForEdit(states.Count + frame - Log.Count);
|
||||
}
|
||||
|
||||
|
@ -224,7 +229,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
|
||||
var entry = Bk2LogEntryGenerator.GenerateLogEntry(states[i]);
|
||||
if (firstChangedFrame == -1 && Log[frame + i] != entry)
|
||||
if ((firstChangedFrame == -1 || firstChangedFrame > frame + i) && Log[frame + i] != entry)
|
||||
{
|
||||
firstChangedFrame = frame + i;
|
||||
}
|
||||
|
@ -234,7 +239,11 @@ namespace BizHawk.Client.Common
|
|||
|
||||
ChangeLog.EndBatch();
|
||||
Changes = true;
|
||||
InvalidateAfter(frame);
|
||||
if (firstChangedFrame != -1)
|
||||
{
|
||||
// TODO: Throw out the undo action if there are no changes.
|
||||
InvalidateAfter(firstChangedFrame);
|
||||
}
|
||||
|
||||
ChangeLog.SetGeneralRedo();
|
||||
return firstChangedFrame;
|
||||
|
|
|
@ -73,6 +73,7 @@ namespace BizHawk.Client.Common
|
|||
public ITasSession TasSession { get; private set; } = new TasSession();
|
||||
|
||||
public int LastEditedFrame { get; private set; } = -1;
|
||||
public bool LastEditWasRecording { get; private set; }
|
||||
public bool LastPositionStable { get; set; } = true;
|
||||
public TasMovieMarkerList Markers { get; private set; }
|
||||
public bool BindMarkersToInput { get; set; }
|
||||
|
@ -129,6 +130,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
|
||||
LastEditedFrame = frame;
|
||||
LastEditWasRecording = false; // We can set it here; it's only used in the GreenzoneInvalidated action.
|
||||
|
||||
if (anyStateInvalidated && IsCountingRerecords)
|
||||
{
|
||||
|
@ -178,14 +180,6 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public void GreenzoneCurrentFrame()
|
||||
{
|
||||
// todo: this isn't working quite right when autorestore is off and we're editing while seeking
|
||||
// but accounting for that requires access to Mainform.IsSeeking
|
||||
if (Emulator.Frame != LastEditedFrame)
|
||||
{
|
||||
// emulated a new frame, current editing segment may change now. taseditor logic
|
||||
LastPositionStable = false;
|
||||
}
|
||||
|
||||
LagLog[Emulator.Frame] = _inputPollable.IsLagFrame;
|
||||
|
||||
// We will forbibly capture a state for the last edited frame (requested by #916 for case of "platforms with analog stick")
|
||||
|
|
|
@ -378,6 +378,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
var playbackBox1 = Tools.TAStudio.TasPlaybackBox;
|
||||
playbackBox1.AutoRestore = !playbackBox1.AutoRestore;
|
||||
break;
|
||||
case "Seek To Green Arrow":
|
||||
if (!Tools.IsLoaded<TAStudio>()) return false;
|
||||
Tools.TAStudio.RestorePosition();
|
||||
break;
|
||||
case "Toggle Turbo Seek":
|
||||
if (!Tools.IsLoaded<TAStudio>()) return false;
|
||||
var playbackBox2 = Tools.TAStudio.TasPlaybackBox;
|
||||
|
|
|
@ -1073,7 +1073,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
/// Accessing this from Lua allows to keep internal code hacks to minimum.
|
||||
/// <list type="bullet">
|
||||
/// <item><description><see cref="ClientLuaLibrary.InvisibleEmulation(bool)"/></description></item>
|
||||
/// <item><description><see cref="ClientLuaLibrary.SeekFrame(int)"/></description></item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public bool InvisibleEmulation { get; set; }
|
||||
|
@ -3258,16 +3257,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
if (PauseOnFrame.Value == Emulator.Frame)
|
||||
{
|
||||
PauseEmulator();
|
||||
if (Tools.IsLoaded<TAStudio>()) Tools.TAStudio.StopSeeking();
|
||||
else PauseOnFrame = null;
|
||||
}
|
||||
else if (Tools.IsLoaded<TAStudio>()
|
||||
&& Tools.TAStudio.LastPositionFrame == Emulator.Frame
|
||||
&& ((ITasMovie) MovieSession.Movie)[Emulator.Frame].Lagged is null)
|
||||
{
|
||||
// haven't yet greenzoned the frame, hence it's after editing
|
||||
// then we want to pause here. taseditor fashion
|
||||
PauseEmulator();
|
||||
PauseOnFrame = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
//
|
||||
this.AutoTabCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.AutoTabCheckBox.AutoSize = true;
|
||||
this.AutoTabCheckBox.Location = new System.Drawing.Point(432, 440);
|
||||
this.AutoTabCheckBox.Location = new System.Drawing.Point(462, 440);
|
||||
this.AutoTabCheckBox.Name = "AutoTabCheckBox";
|
||||
this.AutoTabCheckBox.Size = new System.Drawing.Size(70, 17);
|
||||
this.AutoTabCheckBox.TabIndex = 101;
|
||||
|
@ -79,7 +79,7 @@
|
|||
this.HotkeyTabControl.Location = new System.Drawing.Point(12, 28);
|
||||
this.HotkeyTabControl.Name = "HotkeyTabControl";
|
||||
this.HotkeyTabControl.SelectedIndex = 0;
|
||||
this.HotkeyTabControl.Size = new System.Drawing.Size(729, 396);
|
||||
this.HotkeyTabControl.Size = new System.Drawing.Size(759, 396);
|
||||
this.HotkeyTabControl.TabIndex = 102;
|
||||
this.HotkeyTabControl.SelectedIndexChanged += new System.EventHandler(this.HotkeyTabControl_SelectedIndexChanged);
|
||||
//
|
||||
|
@ -88,7 +88,7 @@
|
|||
this.tabPage1.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabPage1.Name = "tabPage1";
|
||||
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabPage1.Size = new System.Drawing.Size(721, 370);
|
||||
this.tabPage1.Size = new System.Drawing.Size(751, 370);
|
||||
this.tabPage1.TabIndex = 0;
|
||||
this.tabPage1.Text = "For designer";
|
||||
this.tabPage1.UseVisualStyleBackColor = true;
|
||||
|
@ -97,7 +97,7 @@
|
|||
//
|
||||
this.IDB_CANCEL.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.IDB_CANCEL.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.IDB_CANCEL.Location = new System.Drawing.Point(681, 436);
|
||||
this.IDB_CANCEL.Location = new System.Drawing.Point(711, 436);
|
||||
this.IDB_CANCEL.Name = "IDB_CANCEL";
|
||||
this.IDB_CANCEL.Size = new System.Drawing.Size(60, 22);
|
||||
this.IDB_CANCEL.TabIndex = 103;
|
||||
|
@ -109,7 +109,7 @@
|
|||
// IDB_SAVE
|
||||
//
|
||||
this.IDB_SAVE.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.IDB_SAVE.Location = new System.Drawing.Point(615, 436);
|
||||
this.IDB_SAVE.Location = new System.Drawing.Point(645, 436);
|
||||
this.IDB_SAVE.Name = "IDB_SAVE";
|
||||
this.IDB_SAVE.Size = new System.Drawing.Size(60, 22);
|
||||
this.IDB_SAVE.TabIndex = 104;
|
||||
|
@ -123,7 +123,7 @@
|
|||
this.SearchBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.SearchBox.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend;
|
||||
this.SearchBox.Location = new System.Drawing.Point(592, 9);
|
||||
this.SearchBox.Location = new System.Drawing.Point(622, 9);
|
||||
this.SearchBox.Name = "SearchBox";
|
||||
this.SearchBox.Size = new System.Drawing.Size(149, 20);
|
||||
this.SearchBox.TabIndex = 106;
|
||||
|
@ -131,7 +131,7 @@
|
|||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.Location = new System.Drawing.Point(556, 12);
|
||||
this.label1.Location = new System.Drawing.Point(586, 12);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Text = "Find:";
|
||||
//
|
||||
|
@ -152,7 +152,7 @@
|
|||
// MiscButton
|
||||
//
|
||||
this.MiscButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.MiscButton.Location = new System.Drawing.Point(526, 436);
|
||||
this.MiscButton.Location = new System.Drawing.Point(556, 436);
|
||||
this.MiscButton.Menu = this.clearBtnContextMenu;
|
||||
this.MiscButton.Name = "MiscButton";
|
||||
this.MiscButton.Size = new System.Drawing.Size(60, 22);
|
||||
|
@ -198,7 +198,7 @@
|
|||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.IDB_CANCEL;
|
||||
this.ClientSize = new System.Drawing.Size(753, 463);
|
||||
this.ClientSize = new System.Drawing.Size(783, 463);
|
||||
this.Controls.Add(this.MiscButton);
|
||||
this.Controls.Add(this.label3);
|
||||
this.Controls.Add(this.label2);
|
||||
|
|
|
@ -95,7 +95,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
.OrderBy(static kvp => kvp.Value.Ordinal).ThenBy(static kvp => kvp.Value.DisplayName);
|
||||
int x = UIHelper.ScaleX(6);
|
||||
int y = UIHelper.ScaleY(14);
|
||||
int iwOffsetX = UIHelper.ScaleX(110);
|
||||
int iwOffsetX = UIHelper.ScaleX(120);
|
||||
int iwOffsetY = UIHelper.ScaleY(-4);
|
||||
int iwWidth = UIHelper.ScaleX(120);
|
||||
|
||||
|
|
|
@ -143,30 +143,30 @@ namespace BizHawk.Client.EmuHawk
|
|||
throw new InvalidOperationException("tastudio.setplayback() is not allowed during input/memory callbacks");
|
||||
}
|
||||
|
||||
_luaLibsImpl.IsUpdateSupressed = true;
|
||||
|
||||
int f;
|
||||
if (frame is long frameNumber)
|
||||
{
|
||||
f = (int)frameNumber;
|
||||
}
|
||||
else if (frame is double frameNumber2)
|
||||
{
|
||||
f = (int)frameNumber2;
|
||||
}
|
||||
else
|
||||
{
|
||||
f = Tastudio.CurrentTasMovie.Markers.FindIndex((string)frame);
|
||||
if (f == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int markerIndex = Tastudio.CurrentTasMovie.Markers.FindIndex((string)frame);
|
||||
if (markerIndex == -1) return;
|
||||
|
||||
f = Tastudio.CurrentTasMovie.Markers[f].Frame;
|
||||
f = Tastudio.CurrentTasMovie.Markers[markerIndex].Frame;
|
||||
}
|
||||
|
||||
if (0.RangeToExclusive(Tastudio.CurrentTasMovie.InputLogLength).Contains(f))
|
||||
if (f >= 0)
|
||||
{
|
||||
Tastudio.GoToFrame(f, true);
|
||||
_luaLibsImpl.IsUpdateSupressed = true;
|
||||
Tastudio.GoToFrame(f);
|
||||
_luaLibsImpl.IsUpdateSupressed = false;
|
||||
}
|
||||
|
||||
_luaLibsImpl.IsUpdateSupressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
Tastudio.CurrentTasMovie.SetAxisState(_changeList[i].Frame, _changeList[i].Button, _changeList[i].ValueAxis);
|
||||
break;
|
||||
}
|
||||
Tastudio.RefreshForInputChange(_changeList[i].Frame);
|
||||
break;
|
||||
case LuaChangeTypes.InsertFrames:
|
||||
Tastudio.InsertNumFrames(_changeList[i].Frame, _changeList[i].Number);
|
||||
|
@ -341,9 +345,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
_changeList.Clear();
|
||||
Tastudio.JumpToGreenzone();
|
||||
Tastudio.DoAutoRestore();
|
||||
}
|
||||
});
|
||||
|
||||
_luaLibsImpl.IsUpdateSupressed = false;
|
||||
}
|
||||
|
|
|
@ -177,32 +177,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
};
|
||||
}
|
||||
|
||||
private void LoadBranch(TasBranch branch)
|
||||
{
|
||||
if (Tastudio.Settings.OldControlSchemeForBranches && !Tastudio.TasPlaybackBox.RecordingMode)
|
||||
{
|
||||
JumpToBranchToolStripMenuItem_Click(null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
Movie.LoadBranch(branch);
|
||||
Tastudio.LoadState(new(branch.Frame, new MemoryStream(branch.CoreData, false)));
|
||||
|
||||
Movie.TasStateManager.Capture(Tastudio.Emulator.Frame, Tastudio.Emulator.AsStatable());
|
||||
QuickBmpFile.Copy(new BitmapBufferVideoProvider(branch.CoreFrameBuffer), Tastudio.VideoProvider);
|
||||
|
||||
if (Tastudio.Settings.OldControlSchemeForBranches && Tastudio.TasPlaybackBox.RecordingMode)
|
||||
Movie.Truncate(branch.Frame);
|
||||
|
||||
MainForm.PauseOnFrame = null;
|
||||
Tastudio.RefreshDialog();
|
||||
}
|
||||
|
||||
private bool LoadSelectedBranch()
|
||||
{
|
||||
if (SelectedBranch == null) return false;
|
||||
Branches.Current = BranchView.FirstSelectedRowIndex;
|
||||
LoadBranch(SelectedBranch);
|
||||
Tastudio.LoadBranch(SelectedBranch);
|
||||
BranchView.Refresh();
|
||||
Tastudio.MainForm.AddOnScreenMessage($"Loaded branch {Branches.Current + 1}");
|
||||
return true;
|
||||
|
@ -352,7 +331,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
if (_branchUndo == BranchUndo.Load)
|
||||
{
|
||||
LoadBranch(_backupBranch);
|
||||
Tastudio.LoadBranch(_backupBranch);
|
||||
Tastudio.BranchLoadedCallback?.Invoke(Branches.IndexOf(_backupBranch));
|
||||
Tastudio.MainForm.AddOnScreenMessage("Branch Load canceled");
|
||||
}
|
||||
|
|
|
@ -13,10 +13,5 @@ namespace BizHawk.Client.EmuHawk
|
|||
public Action<int> BranchLoadedCallback { get; set; }
|
||||
public Action<int> BranchSavedCallback { get; set; }
|
||||
public Action<int> BranchRemovedCallback { get; set; }
|
||||
|
||||
private void GreenzoneInvalidated(int index)
|
||||
{
|
||||
GreenzoneInvalidatedCallback?.Invoke(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1180,6 +1180,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
this.MinimumSize = new System.Drawing.Size(200, 148);
|
||||
this.Name = "TAStudio";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Deactivate += new System.EventHandler(this.TAStudio_Deactivate);
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Tastudio_Closing);
|
||||
this.Load += new System.EventHandler(this.Tastudio_Load);
|
||||
this.DragDrop += new System.Windows.Forms.DragEventHandler(this.TAStudio_DragDrop);
|
||||
|
|
|
@ -78,27 +78,7 @@
|
|||
public bool Rewind()
|
||||
{
|
||||
int rewindStep = MainForm.IsFastForwarding ? Settings.RewindStepFast : Settings.RewindStep;
|
||||
// copy pasted from TasView_MouseWheel(), just without notch logic
|
||||
if (MainForm.IsSeeking && !MainForm.EmulatorPaused)
|
||||
{
|
||||
MainForm.PauseOnFrame -= rewindStep;
|
||||
|
||||
// that's a weird condition here, but for whatever reason it works best
|
||||
if (Emulator.Frame >= MainForm.PauseOnFrame)
|
||||
{
|
||||
MainForm.PauseEmulator();
|
||||
StopSeeking();
|
||||
GoToFrame(Math.Max(0, Emulator.Frame - rewindStep));
|
||||
}
|
||||
|
||||
RefreshDialog();
|
||||
}
|
||||
else
|
||||
{
|
||||
StopSeeking(); // late breaking memo: don't know whether this is needed
|
||||
GoToFrame(Math.Max(0, Emulator.Frame - rewindStep));
|
||||
}
|
||||
|
||||
WheelSeek(rewindStep);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,10 +24,10 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void UpdateProgressBar()
|
||||
{
|
||||
if (MainForm.PauseOnFrame.HasValue)
|
||||
if (_seekingTo != -1)
|
||||
{
|
||||
int diff = Emulator.Frame - _seekStartFrame.Value;
|
||||
int unit = MainForm.PauseOnFrame.Value - _seekStartFrame.Value;
|
||||
int diff = Emulator.Frame - _seekStartFrame;
|
||||
int unit = _seekingTo - _seekStartFrame;
|
||||
double progress = 0;
|
||||
|
||||
if (diff != 0 && unit != 0)
|
||||
|
@ -94,18 +94,27 @@ namespace BizHawk.Client.EmuHawk
|
|||
refreshNeeded = true;
|
||||
}
|
||||
|
||||
if (Settings.AutoPause)
|
||||
if (Settings.AutoPause && _seekingTo == -1)
|
||||
{
|
||||
if (_doPause && CurrentTasMovie.IsAtEnd()) MainForm.PauseEmulator();
|
||||
_doPause = !CurrentTasMovie.IsAtEnd();
|
||||
}
|
||||
|
||||
if (!_seekingByEdit)
|
||||
{
|
||||
_shouldMoveGreenArrow = true;
|
||||
}
|
||||
|
||||
FastUpdateAfter();
|
||||
RefreshDialog(refreshNeeded, refreshBranches: false);
|
||||
UpdateProgressBar();
|
||||
}
|
||||
|
||||
protected override void FastUpdateAfter()
|
||||
{
|
||||
if (_seekingTo != -1 && Emulator.Frame >= _seekingTo)
|
||||
{
|
||||
StopSeeking();
|
||||
}
|
||||
UpdateProgressBar();
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
// Input Painting
|
||||
private string _startBoolDrawColumn = "";
|
||||
private string _startAxisDrawColumn = "";
|
||||
private bool _drewAxis;
|
||||
private bool _boolPaintState;
|
||||
private int _axisPaintState;
|
||||
private int _axisBackupState;
|
||||
|
@ -26,7 +25,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
private bool _selectionDragState;
|
||||
private bool _suppressContextMenu;
|
||||
private int _startRow;
|
||||
private int _paintingMinFrame = -1;
|
||||
private int _batchEditMinFrame = -1;
|
||||
private bool _batchEditing;
|
||||
private bool _editIsFromLua;
|
||||
|
||||
// Editing analog input
|
||||
private string _axisEditColumn = "";
|
||||
|
@ -56,10 +57,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private bool MouseButtonHeld => _rightClickFrame != -1 || _leftButtonHeld;
|
||||
|
||||
private bool _triggerAutoRestore; // If true, autorestore will be called on mouse up
|
||||
private bool? _autoRestorePaused;
|
||||
private int? _seekStartFrame;
|
||||
private bool _unpauseAfterSeeking;
|
||||
private int _seekStartFrame;
|
||||
private bool _pauseAfterSeeking;
|
||||
|
||||
private readonly Dictionary<string, bool> _alternateRowColor = new();
|
||||
|
||||
|
@ -69,38 +68,21 @@ namespace BizHawk.Client.EmuHawk
|
|||
public AutoPatternBool[] BoolPatterns;
|
||||
public AutoPatternAxis[] AxisPatterns;
|
||||
|
||||
public void JumpToGreenzone(bool OnLeftMouseDown = false)
|
||||
private void StartSeeking(int frame)
|
||||
{
|
||||
if (Emulator.Frame > CurrentTasMovie.LastEditedFrame)
|
||||
{
|
||||
GoToLastEmulatedFrameIfNecessary(CurrentTasMovie.LastEditedFrame, OnLeftMouseDown);
|
||||
}
|
||||
}
|
||||
|
||||
private void StartSeeking(int? frame, bool fromMiddleClick = false)
|
||||
{
|
||||
if (!frame.HasValue)
|
||||
if (frame <= Emulator.Frame)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fromMiddleClick)
|
||||
{
|
||||
if (MainForm.PauseOnFrame != null)
|
||||
{
|
||||
StopSeeking(true); // don't restore rec mode just yet, as with heavy editing checkbox updating causes lag
|
||||
}
|
||||
_seekStartFrame = Emulator.Frame;
|
||||
}
|
||||
_seekStartFrame = Emulator.Frame;
|
||||
_seekingByEdit = false;
|
||||
|
||||
MainForm.PauseOnFrame = frame.Value;
|
||||
int? diff = MainForm.PauseOnFrame - _seekStartFrame;
|
||||
|
||||
WasRecording = CurrentTasMovie.IsRecording() || WasRecording;
|
||||
TastudioPlayMode(); // suspend rec mode until seek ends, to allow mouse editing
|
||||
_seekingTo = frame;
|
||||
MainForm.PauseOnFrame = int.MaxValue; // This being set is how MainForm knows we are seeking, and controls TurboSeek.
|
||||
MainForm.UnpauseEmulator();
|
||||
|
||||
if (diff > TasView.VisibleRows)
|
||||
if (_seekingTo - _seekStartFrame > 1)
|
||||
{
|
||||
MessageStatusLabel.Text = "Seeking...";
|
||||
ProgressBar.Visible = true;
|
||||
|
@ -115,11 +97,12 @@ namespace BizHawk.Client.EmuHawk
|
|||
WasRecording = false;
|
||||
}
|
||||
|
||||
MainForm.PauseOnFrame = null;
|
||||
if (_unpauseAfterSeeking)
|
||||
_seekingByEdit = false;
|
||||
_seekingTo = -1;
|
||||
MainForm.PauseOnFrame = null; // This being unset is how MainForm knows we are not seeking, and controls TurboSeek.
|
||||
if (_pauseAfterSeeking)
|
||||
{
|
||||
MainForm.UnpauseEmulator();
|
||||
_unpauseAfterSeeking = false;
|
||||
MainForm.PauseEmulator();
|
||||
}
|
||||
|
||||
if (CurrentTasMovie != null)
|
||||
|
@ -129,6 +112,23 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
|
||||
private void CancelSeek()
|
||||
{
|
||||
_shouldMoveGreenArrow = true;
|
||||
_seekingByEdit = false;
|
||||
_seekingTo = -1;
|
||||
MainForm.PauseOnFrame = null; // This being unset is how MainForm knows we are not seeking, and controls TurboSeek.
|
||||
_pauseAfterSeeking = false;
|
||||
if (WasRecording)
|
||||
{
|
||||
TastudioRecordMode();
|
||||
WasRecording = false;
|
||||
}
|
||||
|
||||
RefreshDialog();
|
||||
UpdateProgressBar();
|
||||
}
|
||||
|
||||
private Bitmap ts_v_arrow_green_blue => Properties.Resources.ts_v_arrow_green_blue;
|
||||
private Bitmap ts_h_arrow_green_blue => Properties.Resources.ts_h_arrow_green_blue;
|
||||
private Bitmap ts_v_arrow_blue => Properties.Resources.ts_v_arrow_blue;
|
||||
|
@ -167,11 +167,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
if (index == Emulator.Frame)
|
||||
{
|
||||
bitmap = index == MainForm.PauseOnFrame
|
||||
bitmap = index == _seekingTo
|
||||
? TasView.HorizontalOrientation ? ts_v_arrow_green_blue : ts_h_arrow_green_blue
|
||||
: TasView.HorizontalOrientation ? ts_v_arrow_blue : ts_h_arrow_blue;
|
||||
}
|
||||
else if (index == LastPositionFrame)
|
||||
else if (index == RestorePositionFrame)
|
||||
{
|
||||
bitmap = TasView.HorizontalOrientation ?
|
||||
ts_v_arrow_green :
|
||||
|
@ -255,11 +255,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
var record = CurrentTasMovie[index];
|
||||
|
||||
if (MainForm.IsSeeking && MainForm.PauseOnFrame == index)
|
||||
if (_seekingTo == index)
|
||||
{
|
||||
color = Palette.CurrentFrame_InputLog;
|
||||
}
|
||||
else if (!MainForm.IsSeeking && Emulator.Frame == index)
|
||||
else if (_seekingTo == -1 && Emulator.Frame == index)
|
||||
{
|
||||
color = Palette.CurrentFrame_InputLog;
|
||||
}
|
||||
|
@ -378,6 +378,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
if (columnName == FrameColumnName)
|
||||
{
|
||||
CurrentTasMovie.Markers.Add(TasView.SelectionEndIndex!.Value, "");
|
||||
RefreshDialog();
|
||||
}
|
||||
else if (columnName != CursorColumnName)
|
||||
{
|
||||
|
@ -415,13 +416,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
// feos: there's no default value other than neutral, and we can't go arbitrary here, so do nothing for now
|
||||
// autohold is ignored for axes too for the same reasons: lack of demand + ambiguity
|
||||
}
|
||||
|
||||
_triggerAutoRestore = true;
|
||||
TastudioPlayMode(true);
|
||||
JumpToGreenzone();
|
||||
}
|
||||
|
||||
RefreshDialog();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -523,10 +518,16 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
if (MainForm.EmulatorPaused)
|
||||
{
|
||||
var record = CurrentTasMovie[LastPositionFrame];
|
||||
if (!record.Lagged.HasValue && LastPositionFrame > Emulator.Frame)
|
||||
if (_seekingTo != -1)
|
||||
{
|
||||
StartSeeking(LastPositionFrame, true);
|
||||
MainForm.UnpauseEmulator(); // resume seek
|
||||
return;
|
||||
}
|
||||
|
||||
var record = CurrentTasMovie[RestorePositionFrame];
|
||||
if (record.Lagged is null)
|
||||
{
|
||||
RestorePosition();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -543,7 +544,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
_leftButtonHeld = true;
|
||||
_paintingMinFrame = frame;
|
||||
|
||||
// SuuperW: Exit axis editing mode, or re-enter mouse editing
|
||||
if (AxisEditingMode)
|
||||
|
@ -575,8 +575,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
_axisEditYPos = e.Y;
|
||||
_axisPaintState = CurrentTasMovie.GetAxisState(frame, buttonName);
|
||||
|
||||
_triggerAutoRestore = true;
|
||||
TastudioPlayMode(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -584,7 +582,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
if (targetCol.Name is CursorColumnName)
|
||||
{
|
||||
_startCursorDrag = true;
|
||||
GoToFrame(frame, fromLua: false, fromRewinding: false, OnLeftMouseDown: true);
|
||||
GoToFrame(frame, OnLeftMouseDown: true);
|
||||
}
|
||||
else if (targetCol.Name is FrameColumnName)
|
||||
{
|
||||
|
@ -642,9 +640,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
CurrentTasMovie.SetBoolStates(firstSel, lastSel - firstSel + 1, buttonName, !allPressed);
|
||||
_boolPaintState = CurrentTasMovie.BoolIsPressed(lastSel, buttonName);
|
||||
_triggerAutoRestore = true;
|
||||
TastudioPlayMode(true);
|
||||
RefreshDialog();
|
||||
}
|
||||
#if false // to match previous behaviour
|
||||
else if (altOrShift4State is not 0)
|
||||
|
@ -658,9 +653,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
CurrentTasMovie.ToggleBoolState(frame, buttonName);
|
||||
_boolPaintState = CurrentTasMovie.BoolIsPressed(frame, buttonName);
|
||||
_triggerAutoRestore = true;
|
||||
TastudioPlayMode(true);
|
||||
RefreshDialog();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -743,8 +735,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
if (_rightClickAlt || _rightClickControl || _rightClickShift)
|
||||
{
|
||||
JumpToGreenzone();
|
||||
|
||||
// TODO: Turn off ChangeLog.IsRecording and handle the GeneralUndo here.
|
||||
string undoStepName = "Right-Click Edit:";
|
||||
if (_rightClickShift)
|
||||
|
@ -773,29 +763,135 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begins a batch of edits, for auto-restore purposes. Auto-restore will be delayed until EndBatchEdit is called.
|
||||
/// </summary>
|
||||
private void BeginBatchEdit()
|
||||
{
|
||||
_batchEditing = true;
|
||||
}
|
||||
/// <returns>Returns true if the input list was redrawn.</returns>
|
||||
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();
|
||||
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.
|
||||
/// </summary>
|
||||
/// <param name="frame">The frame that was just edited, or the earliest one if multiple were edited.</param>
|
||||
/// <returns>Returns true if the input list was redrawn.</returns>
|
||||
public bool FrameEdited(int frame)
|
||||
{
|
||||
GreenzoneInvalidatedCallback?.Invoke(frame); // lua callback
|
||||
|
||||
if (CurrentTasMovie.LastEditWasRecording)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool needsRefresh = !_batchEditing;
|
||||
if (MouseButtonHeld || _batchEditing)
|
||||
{
|
||||
if (_batchEditMinFrame == -1)
|
||||
{
|
||||
_batchEditMinFrame = frame;
|
||||
}
|
||||
else
|
||||
{
|
||||
_batchEditMinFrame = Math.Min(_batchEditMinFrame, frame);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_editIsFromLua)
|
||||
{
|
||||
// Lua users will want to preserve recording mode.
|
||||
TastudioPlayMode(true);
|
||||
}
|
||||
|
||||
if (Emulator.Frame > frame)
|
||||
{
|
||||
if (_shouldMoveGreenArrow)
|
||||
{
|
||||
RestorePositionFrame = _seekingTo != -1 ? _seekingTo : Emulator.Frame;
|
||||
// Green arrow should not move again until the user changes frame.
|
||||
// This means any state load or unpause/frame advance/seek, that is not caused by an input edit.
|
||||
// This is so that the user can make multiple edits with auto restore off, in any order, before a manual restore.
|
||||
_shouldMoveGreenArrow = false;
|
||||
}
|
||||
|
||||
_seekingByEdit = true; // must be before GoToFrame (it will load a state, and state loading checks _seekingByEdit)
|
||||
GoToFrame(frame);
|
||||
if (Settings.AutoRestoreLastPosition)
|
||||
{
|
||||
RestorePosition();
|
||||
}
|
||||
_seekingByEdit = true; // must be after GoToFrame & RestorePosition too (they'll set _seekingByEdit to false)
|
||||
|
||||
needsRefresh = false; // Refresh will happen via GoToFrame.
|
||||
}
|
||||
_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()
|
||||
{
|
||||
_leftButtonHeld = false;
|
||||
_startCursorDrag = false;
|
||||
_startSelectionDrag = false;
|
||||
_startBoolDrawColumn = "";
|
||||
_startAxisDrawColumn = "";
|
||||
_drewAxis = false;
|
||||
_paintingMinFrame = -1;
|
||||
TasView.ReleaseCurrentCell();
|
||||
|
||||
// Exit axis editing if value was changed with cursor
|
||||
if (AxisEditingMode && _axisPaintState != CurrentTasMovie.GetAxisState(_axisEditRow, _axisEditColumn))
|
||||
{
|
||||
AxisEditRow = -1;
|
||||
_triggerAutoRestore = true;
|
||||
TastudioPlayMode(true);
|
||||
JumpToGreenzone();
|
||||
DoTriggeredAutoRestoreIfNeeded();
|
||||
RefreshDialog();
|
||||
}
|
||||
_axisPaintState = 0;
|
||||
_axisEditYPos = -1;
|
||||
_leftButtonHeld = false;
|
||||
|
||||
if (!AxisEditingMode)
|
||||
{
|
||||
|
@ -847,17 +943,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_startBoolDrawColumn) || _drewAxis)
|
||||
{
|
||||
// If painting up, we have altered frames without loading states (for smoothness)
|
||||
// So now we have to ensure that all the edited frames are invalidated
|
||||
GoToLastEmulatedFrameIfNecessary(_paintingMinFrame);
|
||||
}
|
||||
|
||||
ClearLeftMouseStates();
|
||||
}
|
||||
|
||||
DoTriggeredAutoRestoreIfNeeded();
|
||||
}
|
||||
|
||||
if (e.Button == MouseButtons.Right)
|
||||
|
@ -871,9 +958,31 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
|
||||
EndBatchEdit(); // We didn't call BeginBatchEdit, but implicitly began one with mouse down. We must explicitly end it.
|
||||
|
||||
_suppressContextMenu = false;
|
||||
}
|
||||
|
||||
private void WheelSeek(int count)
|
||||
{
|
||||
if (_seekingTo != -1)
|
||||
{
|
||||
_seekingTo -= count;
|
||||
|
||||
// that's a weird condition here, but for whatever reason it works best
|
||||
if (count > 0 && Emulator.Frame >= _seekingTo)
|
||||
{
|
||||
GoToFrame(Emulator.Frame - count);
|
||||
}
|
||||
|
||||
RefreshDialog();
|
||||
}
|
||||
else
|
||||
{
|
||||
GoToFrame(Emulator.Frame - count);
|
||||
}
|
||||
}
|
||||
|
||||
private void TasView_MouseWheel(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (TasView.RightButtonHeld && TasView?.CurrentCell.RowIndex.HasValue == true)
|
||||
|
@ -885,25 +994,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
notch *= 2;
|
||||
}
|
||||
|
||||
// warning: tastudio rewind hotkey/button logic is copy pasted from here!
|
||||
if (MainForm.IsSeeking && !MainForm.EmulatorPaused)
|
||||
{
|
||||
MainForm.PauseOnFrame -= notch;
|
||||
|
||||
// that's a weird condition here, but for whatever reason it works best
|
||||
if (notch > 0 && Emulator.Frame >= MainForm.PauseOnFrame)
|
||||
{
|
||||
MainForm.PauseEmulator();
|
||||
StopSeeking();
|
||||
GoToFrame(Emulator.Frame - notch);
|
||||
}
|
||||
|
||||
RefreshDialog();
|
||||
}
|
||||
else
|
||||
{
|
||||
GoToFrame(Emulator.Frame - notch);
|
||||
}
|
||||
WheelSeek(notch);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -923,7 +1014,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
else
|
||||
{
|
||||
ClearLeftMouseStates();
|
||||
MarkerControl.AddMarker(TasView.CurrentCell.RowIndex.Value);
|
||||
}
|
||||
}
|
||||
|
@ -944,11 +1034,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
return;
|
||||
}
|
||||
|
||||
if (_paintingMinFrame >= 0)
|
||||
{
|
||||
_paintingMinFrame = Math.Min(_paintingMinFrame, e.NewCell.RowIndex.Value);
|
||||
}
|
||||
|
||||
// skip rerecord counting on drawing entirely, mouse down is enough
|
||||
// avoid introducing another global
|
||||
bool wasCountingRerecords = CurrentTasMovie.IsCountingRerecords;
|
||||
|
@ -975,7 +1060,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
|
||||
if (_startCursorDrag && !MainForm.IsSeeking)
|
||||
if (_startCursorDrag)
|
||||
{
|
||||
GoToFrame(e.NewCell.RowIndex.Value);
|
||||
}
|
||||
|
@ -992,6 +1077,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
|
||||
SetSplicer();
|
||||
RefreshDialog();
|
||||
}
|
||||
else if (_rightClickFrame != -1)
|
||||
{
|
||||
|
@ -1096,9 +1182,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
if (_rightClickAlt || _rightClickControl || _rightClickShift)
|
||||
{
|
||||
_triggerAutoRestore = true;
|
||||
TastudioPlayMode(true);
|
||||
JumpToGreenzone();
|
||||
_suppressContextMenu = true;
|
||||
}
|
||||
}
|
||||
|
@ -1125,12 +1208,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
|
||||
CurrentTasMovie.SetBoolState(i, _startBoolDrawColumn, setVal); // Notice it uses new row, old column, you can only paint across a single column
|
||||
|
||||
if (!_triggerAutoRestore)
|
||||
{
|
||||
TastudioPlayMode(true);
|
||||
JumpToGreenzone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1154,12 +1231,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
|
||||
_triggerAutoRestore = true;
|
||||
TastudioPlayMode(true);
|
||||
RefreshDialog();
|
||||
}
|
||||
|
||||
_drewAxis = true;
|
||||
}
|
||||
|
||||
CurrentTasMovie.IsCountingRerecords = wasCountingRerecords;
|
||||
|
@ -1168,8 +1240,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
TasView.MakeIndexVisible(TasView.CurrentCell.RowIndex.Value); // todo: limit scrolling speed
|
||||
}
|
||||
|
||||
SetTasViewRowCount();
|
||||
}
|
||||
|
||||
private void TasView_MouseMove(object sender, MouseEventArgs e)
|
||||
|
@ -1250,8 +1320,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
return;
|
||||
}
|
||||
|
||||
BeginBatchEdit();
|
||||
|
||||
int value = CurrentTasMovie.GetAxisState(_axisEditRow, _axisEditColumn);
|
||||
int prev = value;
|
||||
string prevTyped = _axisTypedValue;
|
||||
|
||||
var range = ControllerType.Axes[_axisEditColumn];
|
||||
|
@ -1328,10 +1399,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
if (_axisBackupState != _axisPaintState)
|
||||
{
|
||||
CurrentTasMovie.SetAxisState(_axisEditRow, _axisEditColumn, _axisBackupState);
|
||||
_triggerAutoRestore = Emulator.Frame > _axisEditRow;
|
||||
TastudioPlayMode(true);
|
||||
JumpToGreenzone();
|
||||
DoTriggeredAutoRestoreIfNeeded();
|
||||
}
|
||||
|
||||
AxisEditRow = -1;
|
||||
|
@ -1388,17 +1455,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
CurrentTasMovie.SetAxisState(row, _axisEditColumn, value);
|
||||
}
|
||||
|
||||
if (value != prev) // Auto-restore
|
||||
{
|
||||
_triggerAutoRestore = Emulator.Frame > _axisEditRow;
|
||||
TastudioPlayMode(true);
|
||||
JumpToGreenzone();
|
||||
DoTriggeredAutoRestoreIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
RefreshDialog();
|
||||
bool didRefresh = EndBatchEdit();
|
||||
if (!didRefresh && (prevTyped != _axisTypedValue || !AxisEditingMode))
|
||||
{
|
||||
RefreshDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private void TasView_KeyDown(object sender, KeyEventArgs e)
|
||||
|
@ -1429,8 +1492,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
EditAnalogProgrammatically(e);
|
||||
}
|
||||
|
||||
RefreshDialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -422,14 +422,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
_tasClipboard.Add(new TasClipboardEntry(i, line));
|
||||
}
|
||||
|
||||
var rollbackFrame = CurrentTasMovie.CopyOverInput(TasView.SelectionStartIndex ?? 0, _tasClipboard.Select(static x => x.ControllerState));
|
||||
if (rollbackFrame > 0)
|
||||
{
|
||||
GoToLastEmulatedFrameIfNecessary(rollbackFrame);
|
||||
DoAutoRestore();
|
||||
}
|
||||
|
||||
FullRefresh();
|
||||
CurrentTasMovie.CopyOverInput(TasView.SelectionStartIndex ?? 0, _tasClipboard.Select(static x => x.ControllerState));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -465,15 +458,7 @@ 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();
|
||||
}
|
||||
|
||||
FullRefresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -484,9 +469,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();
|
||||
var list = TasView.SelectedRows.ToArray();
|
||||
|
@ -505,16 +487,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
|
||||
Clipboard.SetDataObject(sb.ToString());
|
||||
BeginBatchEdit(); // movie's RemoveFrames may make multiple separate invalidations
|
||||
CurrentTasMovie.RemoveFrames(list);
|
||||
EndBatchEdit();
|
||||
SetSplicer();
|
||||
|
||||
if (needsToRollback)
|
||||
{
|
||||
GoToLastEmulatedFrameIfNecessary(rollBackFrame);
|
||||
DoAutoRestore();
|
||||
}
|
||||
|
||||
FullRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -522,10 +499,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
if (TasView.Focused && TasView.AnyRowsSelected)
|
||||
{
|
||||
var firstWithInput = FirstNonEmptySelectedFrame;
|
||||
bool needsToRollback = firstWithInput.HasValue && firstWithInput < Emulator.Frame;
|
||||
var rollBackFrame = TasView.SelectionStartIndex ?? 0;
|
||||
|
||||
BeginBatchEdit();
|
||||
CurrentTasMovie.ChangeLog.BeginNewBatch($"Clear frames {TasView.SelectionStartIndex}-{TasView.SelectionEndIndex}");
|
||||
foreach (int frame in TasView.SelectedRows)
|
||||
{
|
||||
|
@ -533,14 +507,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
|
||||
CurrentTasMovie.ChangeLog.EndBatch();
|
||||
|
||||
if (needsToRollback)
|
||||
{
|
||||
GoToLastEmulatedFrameIfNecessary(rollBackFrame);
|
||||
DoAutoRestore();
|
||||
}
|
||||
|
||||
FullRefresh();
|
||||
EndBatchEdit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -549,26 +516,19 @@ 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)
|
||||
{
|
||||
// Cannot delete non-existent frames
|
||||
FullRefresh();
|
||||
RefreshDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
BeginBatchEdit(); // movie's RemoveFrames may make multiple separate invalidations
|
||||
CurrentTasMovie.RemoveFrames(TasView.SelectedRows.ToArray());
|
||||
EndBatchEdit();
|
||||
SetTasViewRowCount();
|
||||
SetSplicer();
|
||||
|
||||
if (needsToRollback)
|
||||
{
|
||||
GoToLastEmulatedFrameIfNecessary(rollBackFrame);
|
||||
DoAutoRestore();
|
||||
}
|
||||
|
||||
FullRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -588,48 +548,29 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void CloneFramesXTimes(int timesToClone)
|
||||
{
|
||||
BeginBatchEdit();
|
||||
for (int i = 0; i < timesToClone; i++)
|
||||
{
|
||||
if (TasView.Focused && TasView.AnyRowsSelected)
|
||||
{
|
||||
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))
|
||||
.ToList();
|
||||
|
||||
CurrentTasMovie.InsertInput(insertionFrame, inputLog);
|
||||
|
||||
if (needsToRollback)
|
||||
{
|
||||
GoToLastEmulatedFrameIfNecessary(insertionFrame);
|
||||
DoAutoRestore();
|
||||
}
|
||||
|
||||
FullRefresh();
|
||||
}
|
||||
}
|
||||
EndBatchEdit();
|
||||
}
|
||||
|
||||
private void InsertFrameMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (TasView.Focused && TasView.AnyRowsSelected)
|
||||
{
|
||||
var selectionStart = TasView.SelectionStartIndex;
|
||||
var insertionFrame = selectionStart ?? 0;
|
||||
var needsToRollback = selectionStart < Emulator.Frame;
|
||||
|
||||
CurrentTasMovie.InsertEmptyFrame(insertionFrame);
|
||||
|
||||
if (needsToRollback)
|
||||
{
|
||||
GoToLastEmulatedFrameIfNecessary(insertionFrame);
|
||||
DoAutoRestore();
|
||||
}
|
||||
|
||||
FullRefresh();
|
||||
CurrentTasMovie.InsertEmptyFrame(TasView.SelectionStartIndex ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -650,18 +591,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
if (TasView.Focused && TasView.AnyRowsSelected)
|
||||
{
|
||||
var rollbackFrame = TasView.SelectionEndIndex ?? 0;
|
||||
var needsToRollback = TasView.SelectionStartIndex < Emulator.Frame;
|
||||
|
||||
CurrentTasMovie.Truncate(rollbackFrame);
|
||||
CurrentTasMovie.Truncate(TasView.SelectionEndIndex ?? 0);
|
||||
MarkerControl.MarkerInputRoll.TruncateSelection(CurrentTasMovie.Markers.Count - 1);
|
||||
|
||||
if (needsToRollback)
|
||||
{
|
||||
GoToFrame(rollbackFrame);
|
||||
}
|
||||
|
||||
FullRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1382,7 +1313,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
StartFromNowSeparator.Visible = StartNewProjectFromNowMenuItem.Visible || StartANewProjectFromSaveRamMenuItem.Visible;
|
||||
RemoveMarkersContextMenuItem.Enabled = CurrentTasMovie.Markers.Any(m => TasView.IsRowSelected(m.Frame)); // Disable the option to remove markers if no markers are selected (FCEUX does this).
|
||||
CancelSeekContextMenuItem.Enabled = MainForm.PauseOnFrame.HasValue;
|
||||
CancelSeekContextMenuItem.Enabled = _seekingTo != -1;
|
||||
BranchContextMenuItem.Visible = TasView.CurrentCell?.RowIndex == Emulator.Frame;
|
||||
|
||||
SelectBetweenMarkersContextMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Sel. bet. Markers"];
|
||||
|
@ -1396,8 +1327,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
private void CancelSeekContextMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
MainForm.PauseOnFrame = null;
|
||||
TasView.Refresh();
|
||||
CancelSeek();
|
||||
}
|
||||
|
||||
private void BranchContextMenuItem_Click(object sender, EventArgs e)
|
||||
|
|
|
@ -5,73 +5,36 @@ namespace BizHawk.Client.EmuHawk
|
|||
public partial class TAStudio
|
||||
{
|
||||
/// <summary>
|
||||
/// Only goes to go to the frame if it is an event before current emulation, otherwise it is just a future event that can freely be edited
|
||||
/// Seek to the given frame, past or future, and load a state first if doing so gets us there faster.
|
||||
/// Does nothing if we are already on the given frame.
|
||||
/// </summary>
|
||||
private void GoToLastEmulatedFrameIfNecessary(int frame, bool OnLeftMouseDown = false)
|
||||
public void GoToFrame(int frame, bool OnLeftMouseDown = false)
|
||||
{
|
||||
if (frame != Emulator.Frame) // Don't go to a frame if you are already on it!
|
||||
if (frame == Emulator.Frame)
|
||||
{
|
||||
if (frame <= Emulator.Frame)
|
||||
{
|
||||
if ((MainForm.EmulatorPaused || !MainForm.IsSeeking)
|
||||
&& !CurrentTasMovie.LastPositionStable)
|
||||
{
|
||||
LastPositionFrame = Emulator.Frame;
|
||||
CurrentTasMovie.LastPositionStable = true; // until new frame is emulated
|
||||
}
|
||||
|
||||
GoToFrame(frame, false, false, OnLeftMouseDown);
|
||||
}
|
||||
else
|
||||
{
|
||||
_triggerAutoRestore = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void GoToFrame(int frame, bool fromLua = false, bool fromRewinding = false, bool OnLeftMouseDown = false)
|
||||
{
|
||||
// If seeking to a frame before or at the end of the movie, use StartAtNearestFrameAndEmulate
|
||||
// Otherwise, load the latest state (if not already there) and seek while recording.
|
||||
// Unpausing after a seek may seem like we aren't really seeking at all:
|
||||
// what is the significance of a seek to frame if we don't pause?
|
||||
// Answer: We use this in order to temporarily disable recording mode when the user navigates to a frame. (to avoid recording between whatever is the most recent state and the user-specified frame)
|
||||
// Other answer: turbo seek, navigating while unpaused
|
||||
_pauseAfterSeeking = MainForm.EmulatorPaused || (_seekingTo != -1 && _pauseAfterSeeking);
|
||||
WasRecording = CurrentTasMovie.IsRecording() || WasRecording;
|
||||
TastudioPlayMode();
|
||||
|
||||
if (frame <= CurrentTasMovie.InputLogLength)
|
||||
var closestState = GetPriorStateForFramebuffer(frame);
|
||||
if (frame < Emulator.Frame || closestState.Key > Emulator.Frame)
|
||||
{
|
||||
// Get as close as we can then emulate there
|
||||
StartAtNearestFrameAndEmulate(frame, fromLua, fromRewinding);
|
||||
if (!OnLeftMouseDown) { MaybeFollowCursor(); }
|
||||
LoadState(closestState, true);
|
||||
}
|
||||
else // Emulate to a future frame
|
||||
closestState.Value.Dispose();
|
||||
|
||||
StartSeeking(frame);
|
||||
|
||||
if (!OnLeftMouseDown)
|
||||
{
|
||||
if (frame == Emulator.Frame + 1) // We are at the end of the movie and advancing one frame, therefore we are recording, simply emulate a frame
|
||||
{
|
||||
bool wasPaused = MainForm.EmulatorPaused;
|
||||
MainForm.FrameAdvance();
|
||||
if (!wasPaused)
|
||||
{
|
||||
MainForm.UnpauseEmulator();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TastudioPlayMode();
|
||||
|
||||
var lastState = GetPriorStateForFramebuffer(frame);
|
||||
if (lastState.Key > Emulator.Frame)
|
||||
{
|
||||
LoadState(lastState, true);
|
||||
}
|
||||
|
||||
StartSeeking(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void GoToPreviousFrame()
|
||||
{
|
||||
if (Emulator.Frame > 0)
|
||||
{
|
||||
GoToFrame(Emulator.Frame - 1);
|
||||
MaybeFollowCursor();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,6 +55,17 @@ namespace BizHawk.Client.EmuHawk
|
|||
GoToFrame(next);
|
||||
}
|
||||
|
||||
public void RestorePosition()
|
||||
{
|
||||
if (RestorePositionFrame != -1)
|
||||
{
|
||||
// restore makes no sense without pausing
|
||||
// Pausing here ensures any seek done by GoToFrame pauses after completing.
|
||||
MainForm.PauseEmulator();
|
||||
GoToFrame(RestorePositionFrame);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the given frame visible. If no frame is given, makes the current frame visible.
|
||||
/// </summary>
|
||||
|
|
|
@ -50,7 +50,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
/// Gets a value that separates "restore last position" logic from seeking caused by navigation.
|
||||
/// TASEditor never kills LastPositionFrame, and it only pauses on it, if it hasn't been greenzoned beforehand and middle mouse button was pressed.
|
||||
/// </summary>
|
||||
public int LastPositionFrame { get; private set; }
|
||||
public int RestorePositionFrame { get; private set; }
|
||||
private bool _shouldMoveGreenArrow;
|
||||
private bool _seekingByEdit;
|
||||
|
||||
private int _seekingTo = -1;
|
||||
|
||||
[ConfigPersist]
|
||||
public TAStudioSettings Settings { get; set; } = new TAStudioSettings();
|
||||
|
@ -162,7 +166,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
TasView.QueryItemIcon += TasView_QueryItemIcon;
|
||||
TasView.QueryFrameLag += TasView_QueryFrameLag;
|
||||
TasView.PointedCellChanged += TasView_PointedCellChanged;
|
||||
LastPositionFrame = -1;
|
||||
RestorePositionFrame = -1;
|
||||
|
||||
TasView.MouseLeave += TAStudio_MouseLeave;
|
||||
TasView.CellHovered += (_, e) =>
|
||||
|
@ -549,7 +553,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
movie.InputRollSettingsForSave = () => TasView.UserSettingsSerialized();
|
||||
movie.BindMarkersToInput = Settings.BindMarkersToInput;
|
||||
movie.GreenzoneInvalidated = GreenzoneInvalidated;
|
||||
movie.GreenzoneInvalidated = (f) => _ = FrameEdited(f);
|
||||
movie.ChangeLog.MaxSteps = Settings.MaxUndoSteps;
|
||||
movie.PropertyChanged += TasMovie_OnPropertyChanged;
|
||||
|
||||
|
@ -773,20 +777,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
public IEnumerable<int> GetSelection() => TasView.SelectedRows;
|
||||
|
||||
// Slow but guarantees the entire dialog refreshes
|
||||
private void FullRefresh()
|
||||
{
|
||||
SetTasViewRowCount();
|
||||
TasView.Refresh(); // An extra refresh potentially but we need to guarantee
|
||||
MarkerControl.UpdateValues();
|
||||
BookMarkControl.UpdateValues();
|
||||
|
||||
if (_undoForm != null && !_undoForm.IsDisposed)
|
||||
{
|
||||
_undoForm.UpdateValues();
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshDialog(bool refreshTasView = true, bool refreshBranches = true)
|
||||
{
|
||||
if (_exiting)
|
||||
|
@ -812,41 +802,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 && LastPositionFrame != -1)
|
||||
{
|
||||
if (LastPositionFrame > Emulator.Frame) // Don't unpause if we are already on the desired frame, else runaway seek
|
||||
{
|
||||
StartSeeking(LastPositionFrame);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_autoRestorePaused.HasValue && !_autoRestorePaused.Value)
|
||||
{
|
||||
// this happens when we're holding the left button while unpaused - view scrolls down, new input gets drawn, seek pauses
|
||||
MainForm.UnpauseEmulator();
|
||||
}
|
||||
|
||||
_autoRestorePaused = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
|
@ -856,66 +817,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
return CurrentTasMovie.TasStateManager.GetStateClosestToFrame(frame > 0 ? frame - 1 : 0);
|
||||
}
|
||||
|
||||
private void StartAtNearestFrameAndEmulate(int frame, bool fromLua, bool fromRewinding)
|
||||
{
|
||||
if (frame == Emulator.Frame)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_unpauseAfterSeeking = (fromRewinding || WasRecording) && !MainForm.EmulatorPaused;
|
||||
TastudioPlayMode();
|
||||
var closestState = GetPriorStateForFramebuffer(frame);
|
||||
if (closestState.Value.Length > 0 && (frame < Emulator.Frame || closestState.Key > Emulator.Frame))
|
||||
{
|
||||
LoadState(closestState, true);
|
||||
}
|
||||
closestState.Value.Dispose();
|
||||
|
||||
if (fromLua)
|
||||
{
|
||||
bool wasPaused = MainForm.EmulatorPaused;
|
||||
|
||||
// why not use this? because I'm not letting the form freely run. it all has to be under this loop.
|
||||
// i could use this and then poll StepRunLoop_Core() repeatedly, but.. that's basically what I'm doing
|
||||
// PauseOnFrame = frame;
|
||||
|
||||
while (Emulator.Frame != frame)
|
||||
{
|
||||
MainForm.SeekFrameAdvance();
|
||||
}
|
||||
|
||||
if (!wasPaused)
|
||||
{
|
||||
MainForm.UnpauseEmulator();
|
||||
}
|
||||
|
||||
// lua botting users will want to re-activate record mode automatically -- it should be like nothing ever happened
|
||||
if (WasRecording)
|
||||
{
|
||||
TastudioRecordMode();
|
||||
}
|
||||
|
||||
// now the next section won't happen since we're at the right spot
|
||||
}
|
||||
|
||||
// frame == Emulator.Frame when frame == 0
|
||||
if (frame > Emulator.Frame)
|
||||
{
|
||||
// make seek frame keep up with emulation on fast scrolls
|
||||
if (MainForm.EmulatorPaused || MainForm.IsSeeking || fromRewinding || WasRecording)
|
||||
{
|
||||
StartSeeking(frame);
|
||||
}
|
||||
else
|
||||
{
|
||||
// GUI users may want to be protected from clobbering their video when skipping around...
|
||||
// well, users who are rewinding aren't. (that gets done through the seeking system in the call above)
|
||||
// users who are clicking around.. I don't know.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadState(KeyValuePair<int, Stream> state, bool discardApiHawkSurfaces = false)
|
||||
{
|
||||
StatableEmulator.LoadStateBinary(new BinaryReader(state.Value));
|
||||
|
@ -956,35 +857,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
SplicerStatusLabel.Text = temp;
|
||||
}
|
||||
|
||||
private void DoTriggeredAutoRestoreIfNeeded()
|
||||
{
|
||||
if (_triggerAutoRestore)
|
||||
{
|
||||
TastudioPlayMode(true); // once user started editing, rec mode is unsafe
|
||||
DoAutoRestore();
|
||||
|
||||
_triggerAutoRestore = false;
|
||||
_autoRestorePaused = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void InsertNumFrames(int insertionFrame, int numberOfFrames)
|
||||
{
|
||||
if (insertionFrame <= CurrentTasMovie.InputLogLength)
|
||||
{
|
||||
var needsToRollback = TasView.SelectionStartIndex < Emulator.Frame;
|
||||
|
||||
CurrentTasMovie.InsertEmptyFrame(insertionFrame, numberOfFrames);
|
||||
|
||||
if (needsToRollback)
|
||||
{
|
||||
GoToLastEmulatedFrameIfNecessary(insertionFrame);
|
||||
DoAutoRestore();
|
||||
}
|
||||
else
|
||||
{
|
||||
RefreshForInputChange(insertionFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -992,20 +869,14 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
if (beginningFrame < CurrentTasMovie.InputLogLength)
|
||||
{
|
||||
// movie's RemoveFrames might do multiple separate invalidations
|
||||
BeginBatchEdit();
|
||||
|
||||
int[] framesToRemove = Enumerable.Range(beginningFrame, numberOfFrames).ToArray();
|
||||
CurrentTasMovie.RemoveFrames(framesToRemove);
|
||||
SetSplicer();
|
||||
|
||||
var needsToRollback = beginningFrame < Emulator.Frame;
|
||||
if (needsToRollback)
|
||||
{
|
||||
GoToLastEmulatedFrameIfNecessary(beginningFrame);
|
||||
DoAutoRestore();
|
||||
}
|
||||
else
|
||||
{
|
||||
RefreshForInputChange(beginningFrame);
|
||||
}
|
||||
EndBatchEdit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1013,22 +884,15 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
if (beginningFrame < CurrentTasMovie.InputLogLength)
|
||||
{
|
||||
var needsToRollback = TasView.SelectionStartIndex < Emulator.Frame;
|
||||
BeginBatchEdit();
|
||||
|
||||
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);
|
||||
}
|
||||
EndBatchEdit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1076,7 +940,19 @@ namespace BizHawk.Client.EmuHawk
|
|||
private void TAStudio_MouseLeave(object sender, EventArgs e)
|
||||
{
|
||||
toolTip1.SetToolTip(TasView, null);
|
||||
DoTriggeredAutoRestoreIfNeeded();
|
||||
}
|
||||
|
||||
private void TAStudio_Deactivate(object sender, EventArgs e)
|
||||
{
|
||||
if (_leftButtonHeld)
|
||||
{
|
||||
TasView_MouseUp(this, new(MouseButtons.Left, 0, 0, 0, 0));
|
||||
}
|
||||
if (_rightClickFrame != -1)
|
||||
{
|
||||
_suppressContextMenu = true;
|
||||
TasView_MouseUp(this, new(MouseButtons.Right, 0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
||||
|
@ -1117,8 +993,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
|
||||
CurrentTasMovie.ChangeLog.IsRecording = wasRecording;
|
||||
GoToLastEmulatedFrameIfNecessary(Emulator.Frame - 1);
|
||||
DoAutoRestore();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1251,5 +1125,28 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
TasView.AllColumns.ColumnsChanged();
|
||||
}
|
||||
|
||||
public void LoadBranch(TasBranch branch)
|
||||
{
|
||||
if (Settings.OldControlSchemeForBranches && !TasPlaybackBox.RecordingMode)
|
||||
{
|
||||
GoToFrame(branch.Frame);
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentTasMovie.LoadBranch(branch);
|
||||
LoadState(new(branch.Frame, new MemoryStream(branch.CoreData, false)));
|
||||
|
||||
CurrentTasMovie.TasStateManager.Capture(Emulator.Frame, Emulator.AsStatable());
|
||||
QuickBmpFile.Copy(new BitmapBufferVideoProvider(branch.CoreFrameBuffer), VideoProvider);
|
||||
|
||||
if (Settings.OldControlSchemeForBranches && TasPlaybackBox.RecordingMode)
|
||||
{
|
||||
CurrentTasMovie.Truncate(branch.Frame);
|
||||
}
|
||||
|
||||
CancelSeek();
|
||||
RefreshDialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue