diff --git a/src/BizHawk.Client.Common/movie/interfaces/ITasMovie.cs b/src/BizHawk.Client.Common/movie/interfaces/ITasMovie.cs index 4a551990632..3cd2a49e992 100644 --- a/src/BizHawk.Client.Common/movie/interfaces/ITasMovie.cs +++ b/src/BizHawk.Client.Common/movie/interfaces/ITasMovie.cs @@ -32,22 +32,34 @@ public interface ITasMovie : IMovie, INotifyPropertyChanged, IDisposable /// void ClearFrame(int frame); + void ClearFrameMPR(int frame, int startOffset, int currentControlLength); + void GreenzoneCurrentFrame(); void ToggleBoolState(int frame, string buttonName); void SetAxisState(int frame, string buttonName, int val); void SetAxisStates(int frame, int count, string buttonName, int val); void SetBoolState(int frame, string buttonName, bool val); void SetBoolStates(int frame, int count, string buttonName, bool val); + void InsertInput(int frame, string inputState); void InsertInput(int frame, IEnumerable inputLog); void InsertInput(int frame, IEnumerable inputStates); - + void InsertInputMPR(int frame, IEnumerable inputLog, int startOffset, int currentControlLength); + void InsertEmptyFrameMPR(int frame, int startOffset, int currentControlLength, int count = 1); + void InsertEmptyFramesMPR(int frame, int startOffset, int currentControlLength, int count = 1); void InsertEmptyFrame(int frame, int count = 1); + int CopyOverInput(int frame, IEnumerable inputStates); + int CopyOverInputMPR(int frame, IEnumerable inputStates, int startOffset, int currentControlLength); + int CopyOverDestInputMPR(int frame, IEnumerable frames, int startOffset, int currentControlLength, int sourceStartOffset); void RemoveFrame(int frame); void RemoveFrames(ICollection frames); void RemoveFrames(int removeStart, int removeUpTo); + void RemoveFramesMPR(ICollection frames, int startOffset, int currentControlLength); + + void TruncateFramesMPR(int frame, int startOffset, int currentControlLength); + void SetFrame(int frame, string source); void LoadBranch(TasBranch branch); diff --git a/src/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs b/src/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs index f92ce87f32b..55939ac2c52 100644 --- a/src/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs +++ b/src/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs @@ -61,6 +61,56 @@ public override void Truncate(int frame) } } + public void TruncateFramesMPR(int frame, int startOffset, int currentControlLength) + { + bool endBatch = ChangeLog.BeginNewBatch($"Truncate Movie: {frame}", true); + ChangeLog.AddGeneralUndo(frame, InputLogLength - 1); + + char[] curFrame; + + if (frame < Log.Count) + { + //clear inputs for that controller until end of movie. + for (int i = frame; i < Log.Count; i++) + { + curFrame = Log[i].ToCharArray(); + for (int j = startOffset; j < startOffset + currentControlLength; j++) + { + curFrame[j] = '.'; + } + SetFrameAt(i, new string(curFrame)); + } + + //Find last row with empty inputThen remove range then insert range + int lastEmptyFrame = Log.Count - 1; + string noInput = Bk2LogEntryGenerator.EmptyEntry(Session.MovieController); + for (int i = Log.Count - 1; i >= frame; i--) + { + if (noInput == Log[i]) + { + lastEmptyFrame = i; + } + } + //truncate if there is empty input across all controllers past the frame selected for truncation + if (lastEmptyFrame >= frame) + { + Log.RemoveRange(lastEmptyFrame, Log.Count - lastEmptyFrame); + } + Changes = true; + } + + LagLog.RemoveFrom(frame); + TasStateManager.InvalidateAfter(frame); + GreenzoneInvalidated(frame); + Markers.TruncateAt(frame); + + ChangeLog.SetGeneralRedo(); + if (endBatch) + { + ChangeLog.EndBatch(); + } + } + public override void PokeFrame(int frame, IController source) { ChangeLog.AddGeneralUndo(frame, frame, $"Set Frame At: {frame}"); @@ -92,6 +142,23 @@ public void ClearFrame(int frame) ChangeLog.SetGeneralRedo(); } + public void ClearFrameMPR(int frame, int startOffset, int currentControlLength) + { + ChangeLog.AddGeneralUndo(frame, frame, $"Clear Frame: {frame}"); + + char[] curFrame = Log[frame].ToCharArray(); + for (int j = startOffset; j < startOffset + currentControlLength; j++) + { + curFrame[j] = '.'; + } + + SetFrameAt(frame, new string(curFrame)); + Changes = true; + + InvalidateAfter(frame); + ChangeLog.SetGeneralRedo(); + } + private void ShiftBindedMarkers(int frame, int offset) { if (BindMarkersToInput) @@ -128,6 +195,123 @@ public void RemoveFrames(ICollection frames) } } + public void RemoveFramesMPR(ICollection frames, int startOffset, int currentControlLength) + { + if (frames.Count > 0) + { + // Separate the given frames into contiguous blocks + // and process each block independently + List framesToDelete = frames + .Where(fr => fr >= 0 && fr < InputLogLength) + .Order().ToList(); + // f is the current index for framesToDelete + int f = 0; + int numDeleted = 0; + while (numDeleted != framesToDelete.Count) + { + int startFrame; + var prevFrame = startFrame = framesToDelete[f]; + f++; + for (; f < framesToDelete.Count; f++) + { + var frame = framesToDelete[f]; + if (frame - 1 != prevFrame) + { + f--; + break; + } + prevFrame = frame; + } + + // Each block is logged as an individual ChangeLog entry + RemoveFramesMPR(startFrame - numDeleted >= 0 ? startFrame - numDeleted : 0, prevFrame + 1 - numDeleted, startOffset, currentControlLength); + numDeleted += prevFrame + 1 - startFrame; + } + } + } + + + + /// + /// Remove all frames between removeStart and removeUpTo (excluding removeUpTo). + /// + /// The first frame to remove. + /// The frame after the last frame to remove. + public void RemoveFramesMPR(int removeStart, int removeUpTo, int startOffset, int currentControlLength) + { + // Log.GetRange() might be preferrable, but Log's type complicates that. + string[] removedInputs = new string[removeUpTo - removeStart]; + + // Pre-process removed markers for the ChangeLog. + List removedMarkers = new List(); + if (BindMarkersToInput) + { + bool wasRecording = ChangeLog.IsRecording; + ChangeLog.IsRecording = false; + + // O(n^2) removal time, but removing many binded markers in a deleted section is probably rare. + removedMarkers = Markers.Where(m => m.Frame >= removeStart && m.Frame < removeUpTo).ToList(); + foreach (var marker in removedMarkers) + { + Markers.Remove(marker); + } + + ChangeLog.IsRecording = wasRecording; + } + + List lines = new List(); + char[] framePrevious = Log[removeStart].ToCharArray(); + string frameNext = string.Empty; + + int removeNum = removeUpTo - removeStart; + + for (int i = removeStart; i < Log.Count; i++) + { + if (i + removeNum >= Log.Count) + { + //leave frames from other controllers but leave current one empty. + framePrevious = Log[i].ToCharArray(); + for (int j = startOffset; j < startOffset + currentControlLength; j++) + { + framePrevious[j] = '.'; + } + lines.Add(new string(framePrevious)); + } + else + { + //takes characters from the controller and shifts then, leaving other controllers alone. + framePrevious = Log[i].ToCharArray(); + frameNext = Log[i + removeNum]; + for (int j = startOffset; j < startOffset + currentControlLength; j++) + { + framePrevious[j] = frameNext[j]; + } + lines.Add(new string(framePrevious)); + } + } + + //replace from inital delete frame to end + Log.RemoveRange(removeStart, Log.Count - removeStart); //check -1 + Log.InsertRange(removeStart, lines); + + //og + //Log.RemoveRange(removeStart, removeUpTo - removeStart); + + ShiftBindedMarkers(removeUpTo, removeStart - removeUpTo); + + Changes = true; + InvalidateAfter(removeStart); + + ChangeLog.AddRemoveFrames( + removeStart, + removeUpTo, + removedInputs.ToList(), + removedMarkers, + $"Remove frames {removeStart}-{removeUpTo - 1}" + ); + } + + /// /// Remove all frames between removeStart and removeUpTo (excluding removeUpTo). /// @@ -172,6 +356,7 @@ public void RemoveFrames(int removeStart, int removeUpTo) ); } + public void InsertInput(int frame, string inputState) { var inputLog = new List { inputState }; @@ -186,7 +371,58 @@ public void InsertInput(int frame, IEnumerable inputLog) Changes = true; InvalidateAfter(frame); - + + ChangeLog.AddInsertInput(frame, inputLog.ToList(), $"Insert {inputLog.Count()} frame(s) at {frame}"); + } + + public void InsertInputMPR(int frame, IEnumerable inputLog, int startOffset, int currentControlLength) + { + //insert it at end since the inputs have to shift + Log.InsertRange(Log.Count, Enumerable.Repeat(Bk2LogEntryGenerator.EmptyEntry(Session.MovieController), inputLog.Count())); + + List lines = new List(); + string framePrevious = string.Empty; + char[] frameNext = Log[frame].ToCharArray(); + int addNewCount = inputLog.Count(); + int index = 0; + + foreach (string newInputs in inputLog.ToList()) + { + frameNext = Log[index + frame].ToCharArray(); + + for (int j = startOffset; j < startOffset + currentControlLength; j++) + { + frameNext[j] = newInputs[j]; + } + lines.Add(new string(frameNext)); + index++; + } + + for (int i = frame; i < Log.Count; i++) + { + if (i + addNewCount >= Log.Count) + { + break; + } + //takes characters from the controller and shifts then, leaving other controllers alone. + framePrevious = Log[i]; + frameNext = Log[i + addNewCount].ToCharArray(); + for (int j = startOffset; j < startOffset + currentControlLength; j++) + { + frameNext[j] = framePrevious[j]; + } + lines.Add(new string(frameNext)); + + } + + Log.RemoveRange(frame, Log.Count - frame); + Log.InsertRange(frame, lines); + + ShiftBindedMarkers(frame, inputLog.Count()); + + Changes = true; + InvalidateAfter(frame); + ChangeLog.AddInsertInput(frame, inputLog.ToList(), $"Insert {inputLog.Count()} frame(s) at {frame}"); } @@ -207,7 +443,7 @@ public int CopyOverInput(int frame, IEnumerable inputStates) { int firstChangedFrame = -1; ChangeLog.BeginNewBatch($"Copy Over Input: {frame}"); - + var states = inputStates.ToList(); if (Log.Count < states.Count + frame) @@ -241,6 +477,106 @@ public int CopyOverInput(int frame, IEnumerable inputStates) return firstChangedFrame; } + public int CopyOverInputMPR(int frame, IEnumerable inputStates, int startOffset, int currentControlLength) + { + int firstChangedFrame = -1; + ChangeLog.BeginNewBatch($"Copy Over Input: {frame}"); + + var states = inputStates.ToList(); + + if (Log.Count < states.Count + frame) + { + ExtendMovieForEdit(states.Count + frame - Log.Count); + } + int addNewCount = inputStates.Count(); + + ChangeLog.AddGeneralUndo(frame, frame + states.Count - 1, $"Copy Over Input: {frame}"); + + + char[] inputFrame; + char[] logFrame; + List lines = new List(); + for (int i = 0; i < states.Count; i++) + { + if (Log.Count <= frame + i) + { + break; + } + + var entry = Bk2LogEntryGenerator.GenerateLogEntry(states[i]); + if (firstChangedFrame == -1 && Log[frame + i] != entry) + { + firstChangedFrame = frame + i; + } + + logFrame = Log[frame + i].ToCharArray(); + inputFrame = entry.ToCharArray(); + for (int j = startOffset; j < startOffset + currentControlLength; j++) + { + logFrame[j] = inputFrame[j]; + } + Log[frame + i] = new string(logFrame); + } + + ChangeLog.EndBatch(); + Changes = true; + InvalidateAfter(frame); + + ChangeLog.SetGeneralRedo(); + return firstChangedFrame; + } + + public int CopyOverDestInputMPR(int frame, IEnumerable inputStates, int startOffset, int currentControlLength, int destStartOffset) + { + int firstChangedFrame = -1; + ChangeLog.BeginNewBatch($"Copy Over Input: {frame}"); + + var states = inputStates.ToList(); + + if (Log.Count < states.Count + frame) + { + ExtendMovieForEdit(states.Count + frame - Log.Count); + } + int addNewCount = inputStates.Count(); + + ChangeLog.AddGeneralUndo(frame, frame + states.Count - 1, $"Copy Over Input: {frame}"); + + char[] inputFrame; + char[] logFrame; + List lines = new List(); + + int offsetDifference = destStartOffset - startOffset; + for (int i = 0; i < states.Count; i++) + { + if (Log.Count <= frame + i) + { + break; + } + + var entry = states[i]; + if (firstChangedFrame == -1 && Log[frame + i] != entry) + { + firstChangedFrame = frame + i; + } + + logFrame = Log[frame + i].ToCharArray(); + inputFrame = entry.ToCharArray(); + for (int j = startOffset; j < startOffset + currentControlLength; j++) + { + logFrame[j] = inputFrame[j + offsetDifference]; + } + + Log[frame + i] = new string(logFrame); + } + + ChangeLog.EndBatch(); + Changes = true; + InvalidateAfter(frame); + + ChangeLog.SetGeneralRedo(); + return firstChangedFrame; + } + public void InsertEmptyFrame(int frame, int count = 1) { frame = Math.Min(frame, Log.Count); @@ -255,6 +591,106 @@ public void InsertEmptyFrame(int frame, int count = 1) ChangeLog.AddInsertFrames(frame, count, $"Insert {count} empty frame(s) at {frame}"); } + public void InsertEmptyFrameMPR(int frame, int startOffset, int currentControlLength, int count = 1) + { + frame = Math.Min(frame, Log.Count); + + //insert it at end since the inputs have to shift + Log.InsertRange(Log.Count, Enumerable.Repeat(Bk2LogEntryGenerator.EmptyEntry(Session.MovieController), count)); + + List lines = new List(); + string framePrevious = string.Empty; + char[] frameNext = Log[frame].ToCharArray(); + + //inserted empty controller first + for (int j = startOffset; j < startOffset + currentControlLength; j++) + { + frameNext[j] = '.'; + } + + lines.Add(new string(frameNext)); + + for (int i = frame; i < Log.Count; i++) + { + { + if (i + 1 == Log.Count) + { + lines.Add(Log[i]); + } + else + { + //takes characters from the controller and shifts then, leaving other controllers alone. + framePrevious = Log[i]; + frameNext = Log[i + 1].ToCharArray(); + for (int j = startOffset; j < startOffset + currentControlLength; j++) + { + frameNext[j] = framePrevious[j]; + } + lines.Add(new string(frameNext)); + } + } + } + Log.RemoveRange(frame, Log.Count - frame - 1); + Log.InsertRange(frame, lines); + + ShiftBindedMarkers(frame, count); + + Changes = true; + InvalidateAfter(frame); + + ChangeLog.AddInsertFrames(frame, count, $"Insert {count} empty frame(s) at {frame}"); + } + + //For multiple Frame Inputs. Complex enough to have a separate func and make it faster. + public void InsertEmptyFramesMPR(int frame, int startOffset, int currentControlLength, int addNewCount = 1) + { + frame = Math.Min(frame, Log.Count); + + //insert it at end since the inputs have to shift + Log.InsertRange(Log.Count, Enumerable.Repeat(Bk2LogEntryGenerator.EmptyEntry(Session.MovieController), addNewCount)); + + List lines = new List(); + string framePrevious = string.Empty; + char[] frameNext = Log[frame].ToCharArray(); + + for (int i = 0; i < addNewCount; i++) + { + frameNext = Log[i + frame].ToCharArray(); + for (int j = startOffset; j < startOffset + currentControlLength; j++) + { + frameNext[j] = '.'; + } + lines.Add(new string(frameNext)); + } + + for (int i = frame; i < Log.Count; i++) + { + if (i + addNewCount >= Log.Count) + { + break; + } + //takes characters from the controller and shifts then, leaving other controllers alone. + framePrevious = Log[i]; + frameNext = Log[i + addNewCount].ToCharArray(); + for (int j = startOffset; j < startOffset + currentControlLength; j++) + { + frameNext[j] = framePrevious[j]; + } + lines.Add(new string(frameNext)); + + } + Log.RemoveRange(frame, Log.Count - frame); + Log.InsertRange(frame, lines); + + ShiftBindedMarkers(frame, addNewCount); + + Changes = true; + InvalidateAfter(frame); + + ChangeLog.AddInsertFrames(frame, addNewCount, $"Insert {addNewCount} empty frame(s) at {frame}"); + } + + private void ExtendMovieForEdit(int numFrames) { bool endBatch = ChangeLog.BeginNewBatch("Auto-Extend Movie", true); diff --git a/src/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/src/BizHawk.Client.EmuHawk/MainForm.Designer.cs index 83c877d3f83..b3fb5b2c934 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -196,6 +196,7 @@ private void InitializeComponent() this.RamSearchMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); this.LuaConsoleMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); this.TAStudioMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.TAStudioMPRToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.HexEditorMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); this.TraceLoggerMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); this.DebuggerMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); @@ -1333,6 +1334,7 @@ private void InitializeComponent() this.RamSearchMenuItem, this.LuaConsoleMenuItem, this.TAStudioMenuItem, + this.TAStudioMPRToolStripMenuItem, this.HexEditorMenuItem, this.TraceLoggerMenuItem, this.DebuggerMenuItem, @@ -1376,6 +1378,13 @@ private void InitializeComponent() this.TAStudioMenuItem.Text = "&TAStudio"; this.TAStudioMenuItem.Click += new System.EventHandler(this.TAStudioMenuItem_Click); // + // TAStudioMPRToolStripMenuItem + // + this.TAStudioMPRToolStripMenuItem.Name = "TAStudioMPRToolStripMenuItem"; + this.TAStudioMPRToolStripMenuItem.Size = new System.Drawing.Size(191, 22); + this.TAStudioMPRToolStripMenuItem.Text = "TAStudioMPR"; + this.TAStudioMPRToolStripMenuItem.Click += new System.EventHandler(this.TAStudioMenuItem_Click); + // // HexEditorMenuItem // this.HexEditorMenuItem.Text = "&Hex Editor"; @@ -2779,5 +2788,6 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripSeparator toolStripSeparator25; private ToolStripMenuItemEx DisableResizeWithFramebufferMenuItem; private ToolStripSeparatorEx toolStripSeparator26; + private System.Windows.Forms.ToolStripMenuItem TAStudioMPRToolStripMenuItem; } } diff --git a/src/BizHawk.Client.EmuHawk/MainForm.Events.cs b/src/BizHawk.Client.EmuHawk/MainForm.Events.cs index b1dc69b7e5b..2c85f4d78ef 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -1125,7 +1125,8 @@ private void TAStudioMenuItem_Click(object sender, EventArgs e) { return; } - Tools.Load(); + if (sender == TAStudioMPRToolStripMenuItem) Tools.Load(); + else Tools.Load(); } private void HexEditorMenuItem_Click(object sender, EventArgs e) diff --git a/src/BizHawk.Client.EmuHawk/MainForm.Hotkey.cs b/src/BizHawk.Client.EmuHawk/MainForm.Hotkey.cs index fe016b73092..3405aa4ce29 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.Hotkey.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.Hotkey.cs @@ -349,102 +349,198 @@ void SelectAndLoadFromSlot(int slot) break; // TAStudio - case "Add Branch": - if (!Tools.IsLoaded()) return false; + case "Add Branch" when Tools.IsLoaded(): Tools.TAStudio.AddBranchExternal(); break; - case "Delete Branch": - if (!Tools.IsLoaded()) return false; + case "Add Branch" when Tools.IsLoaded(): + Tools.TAStudioMPR.AddBranchExternal(); + break; + case "Add Branch": + return false; + case "Delete Branch" when Tools.IsLoaded(): Tools.TAStudio.RemoveBranchExternal(); break; - case "Show Cursor": - if (!Tools.IsLoaded()) return false; + case "Delete Branch" when Tools.IsLoaded(): + Tools.TAStudioMPR.RemoveBranchExternal(); + break; + case "Delete Branch": + return false; + case "Show Cursor" when Tools.IsLoaded(): Tools.TAStudio.SetVisibleFrame(); Tools.TAStudio.RefreshDialog(); break; - case "Toggle Follow Cursor": - if (!Tools.IsLoaded()) return false; + case "Show Cursor" when Tools.IsLoaded(): + Tools.TAStudioMPR.SetVisibleFrame(); + Tools.TAStudioMPR.RefreshDialog(); + break; + case "Show Cursor": + return false; + case "Toggle Follow Cursor" when Tools.IsLoaded(): var playbackBox = Tools.TAStudio.TasPlaybackBox; playbackBox.FollowCursor = !playbackBox.FollowCursor; break; - case "Toggle Auto-Restore": - if (!Tools.IsLoaded()) return false; + case "Toggle Follow Cursor" when Tools.IsLoaded(): + var playbackBox3 = Tools.TAStudioMPR.TasPlaybackBoxMPR; + playbackBox3.FollowCursor = !playbackBox3.FollowCursor; + break; + case "Toggle Follow Cursor": + return false; + case "Toggle Auto-Restore" when Tools.IsLoaded(): var playbackBox1 = Tools.TAStudio.TasPlaybackBox; playbackBox1.AutoRestore = !playbackBox1.AutoRestore; break; - case "Toggle Turbo Seek": - if (!Tools.IsLoaded()) return false; + case "Toggle Auto-Restore" when Tools.IsLoaded(): + var playbackBox4 = Tools.TAStudioMPR.TasPlaybackBoxMPR; + playbackBox4.AutoRestore = !playbackBox4.AutoRestore; + break; + case "Toggle Auto-Restore": + return false; + case "Toggle Turbo Seek" when Tools.IsLoaded(): var playbackBox2 = Tools.TAStudio.TasPlaybackBox; playbackBox2.TurboSeek = !playbackBox2.TurboSeek; break; - case "Undo": - if (!Tools.IsLoaded()) return false; + case "Toggle Turbo Seek" when Tools.IsLoaded(): + var playbackBox5 = Tools.TAStudioMPR.TasPlaybackBoxMPR; + playbackBox5.TurboSeek = !playbackBox5.TurboSeek; + break; + case "Toggle Turbo Seek": + return false; + case "Undo" when Tools.IsLoaded(): Tools.TAStudio.UndoExternal(); break; - case "Redo": - if (!Tools.IsLoaded()) return false; + case "Undo" when Tools.IsLoaded(): + Tools.TAStudioMPR.UndoExternal(); + break; + case "Undo": + return false; + case "Redo" when Tools.IsLoaded(): Tools.TAStudio.RedoExternal(); break; - case "Sel. bet. Markers": - if (!Tools.IsLoaded()) return false; + case "Redo" when Tools.IsLoaded(): + Tools.TAStudioMPR.RedoExternal(); + break; + case "Redo": + return false; + case "Sel. bet. Markers" when Tools.IsLoaded(): Tools.TAStudio.SelectBetweenMarkersExternal(); break; - case "Select All": - if (!Tools.IsLoaded()) return false; + case "Sel. bet. Markers" when Tools.IsLoaded(): + Tools.TAStudioMPR.SelectBetweenMarkersExternal(); + break; + case "Sel. bet. Markers": + return false; + case "Select All" when Tools.IsLoaded(): Tools.TAStudio.SelectAllExternal(); break; - case "Reselect Clip.": - if (!Tools.IsLoaded()) return false; + case "Select All" when Tools.IsLoaded(): + Tools.TAStudioMPR.SelectAllExternal(); + break; + case "Select All": + return false; + case "Reselect Clip." when Tools.IsLoaded(): Tools.TAStudio.ReselectClipboardExternal(); break; - case "Clear Frames": - if (!Tools.IsLoaded()) return false; + case "Reselect Clip." when Tools.IsLoaded(): + Tools.TAStudioMPR.ReselectClipboardExternal(); + break; + case "Reselect Clip.": + return false; + case "Clear Frames" when Tools.IsLoaded(): Tools.TAStudio.ClearFramesExternal(); break; - case "Insert Frame": - if (!Tools.IsLoaded()) return false; + case "Clear Frames" when Tools.IsLoaded(): + Tools.TAStudioMPR.ClearFramesExternal(); + break; + case "Clear Frames": + return false; + case "Insert Frame" when Tools.IsLoaded(): Tools.TAStudio.InsertFrameExternal(); break; - case "Insert # Frames": - if (!Tools.IsLoaded()) return false; + case "Insert Frame" when Tools.IsLoaded(): + Tools.TAStudioMPR.InsertFrameExternal(); + break; + case "Insert Frame": + return false; + case "Insert # Frames" when Tools.IsLoaded(): Tools.TAStudio.InsertNumFramesExternal(); break; - case "Delete Frames": - if (!Tools.IsLoaded()) return false; + case "Insert # Frames" when Tools.IsLoaded(): + Tools.TAStudioMPR.InsertNumFramesExternal(); + break; + case "Insert # Frames": + return false; + case "Delete Frames" when Tools.IsLoaded(): Tools.TAStudio.DeleteFramesExternal(); break; - case "Clone Frames": - if (!Tools.IsLoaded()) return false; + case "Delete Frames" when Tools.IsLoaded(): + Tools.TAStudioMPR.DeleteFramesExternal(); + break; + case "Delete Frames": + return false; + case "Clone Frames" when Tools.IsLoaded(): Tools.TAStudio.CloneFramesExternal(); break; - case "Clone # Times": - if (!Tools.IsLoaded()) return false; + case "Clone Frames" when Tools.IsLoaded(): + Tools.TAStudioMPR.CloneFramesExternal(); + break; + case "Clone Frames": + return false; + case "Clone # Times" when Tools.IsLoaded(): Tools.TAStudio.CloneFramesXTimesExternal(); break; - case "Analog Increment": - if (!Tools.IsLoaded()) return false; + case "Clone # Times" when Tools.IsLoaded(): + Tools.TAStudioMPR.CloneFramesXTimesExternal(); + break; + case "Clone # Times": + return false; + case "Analog Increment" when Tools.IsLoaded(): Tools.TAStudio.AnalogIncrementByOne(); break; - case "Analog Decrement": - if (!Tools.IsLoaded()) return false; + case "Analog Increment" when Tools.IsLoaded(): + Tools.TAStudioMPR.AnalogIncrementByOne(); + break; + case "Analog Increment": + return false; + case "Analog Decrement" when Tools.IsLoaded(): Tools.TAStudio.AnalogDecrementByOne(); break; - case "Analog Incr. by 10": - if (!Tools.IsLoaded()) return false; + case "Analog Decrement" when Tools.IsLoaded(): + Tools.TAStudioMPR.AnalogDecrementByOne(); + break; + case "Analog Decrement": + return false; + case "Analog Incr. by 10" when Tools.IsLoaded(): Tools.TAStudio.AnalogIncrementByTen(); break; - case "Analog Decr. by 10": - if (!Tools.IsLoaded()) return false; + case "Analog Incr. by 10" when Tools.IsLoaded(): + Tools.TAStudioMPR.AnalogIncrementByTen(); + break; + case "Analog Incr. by 10": + return false; + case "Analog Decr. by 10" when Tools.IsLoaded(): Tools.TAStudio.AnalogDecrementByTen(); break; - case "Analog Maximum": - if (!Tools.IsLoaded()) return false; + case "Analog Decr. by 10" when Tools.IsLoaded(): + Tools.TAStudioMPR.AnalogDecrementByTen(); + break; + case "Analog Decr. by 10": + return false; + case "Analog Maximum" when Tools.IsLoaded(): Tools.TAStudio.AnalogMax(); break; - case "Analog Minimum": - if (!Tools.IsLoaded()) return false; + case "Analog Maximum" when Tools.IsLoaded(): + Tools.TAStudioMPR.AnalogMax(); + break; + case "Analog Maximum": + return false; + case "Analog Minimum" when Tools.IsLoaded(): Tools.TAStudio.AnalogMin(); break; + case "Analog Minimum" when Tools.IsLoaded(): + Tools.TAStudioMPR.AnalogMin(); + break; + case "Analog Minimum": + return false; // SNES case "Toggle BG 1": diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/BookmarksBranchesBoxMPR.Designer.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/BookmarksBranchesBoxMPR.Designer.cs new file mode 100644 index 00000000000..a44101bb17b --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/BookmarksBranchesBoxMPR.Designer.cs @@ -0,0 +1,262 @@ +namespace BizHawk.Client.EmuHawk +{ + partial class BookmarksBranchesBoxMPR + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.BookmarksBranchesGroupBox = new System.Windows.Forms.GroupBox(); + this.UndoBranchButton = new System.Windows.Forms.Button(); + this.JumpToBranchButton = new System.Windows.Forms.Button(); + this.UpdateBranchButton = new System.Windows.Forms.Button(); + this.AddWithTextBranchButton = new System.Windows.Forms.Button(); + this.AddBranchButton = new System.Windows.Forms.Button(); + this.LoadBranchButton = new System.Windows.Forms.Button(); + this.BranchView = new BizHawk.Client.EmuHawk.InputRoll(); + this.BranchesContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.AddBranchContextMenu = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.AddBranchWithTextContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.LoadBranchContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.UpdateBranchContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.EditBranchTextContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.JumpToBranchContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.UndoBranchToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator2 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.RemoveBranchContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); + this.BookmarksBranchesGroupBox.SuspendLayout(); + this.BranchesContextMenu.SuspendLayout(); + this.SuspendLayout(); + // + // BookmarksBranchesGroupBox + // + this.BookmarksBranchesGroupBox.Controls.Add(this.UndoBranchButton); + this.BookmarksBranchesGroupBox.Controls.Add(this.JumpToBranchButton); + this.BookmarksBranchesGroupBox.Controls.Add(this.UpdateBranchButton); + this.BookmarksBranchesGroupBox.Controls.Add(this.AddWithTextBranchButton); + this.BookmarksBranchesGroupBox.Controls.Add(this.AddBranchButton); + this.BookmarksBranchesGroupBox.Controls.Add(this.LoadBranchButton); + this.BookmarksBranchesGroupBox.Controls.Add(this.BranchView); + this.BookmarksBranchesGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.BookmarksBranchesGroupBox.Location = new System.Drawing.Point(0, 0); + this.BookmarksBranchesGroupBox.Name = "BookmarksBranchesGroupBox"; + this.BookmarksBranchesGroupBox.Size = new System.Drawing.Size(198, 278); + this.BookmarksBranchesGroupBox.TabIndex = 0; + this.BookmarksBranchesGroupBox.TabStop = false; + this.BookmarksBranchesGroupBox.Text = "Branches"; + // + // UndoBranchButton + // + this.UndoBranchButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.UndoBranchButton.Enabled = false; + this.UndoBranchButton.Location = new System.Drawing.Point(156, 247); + this.UndoBranchButton.Name = "UndoBranchButton"; + this.UndoBranchButton.Size = new System.Drawing.Size(24, 24); + this.UndoBranchButton.TabIndex = 6; + this.UndoBranchButton.UseVisualStyleBackColor = true; + this.UndoBranchButton.Click += new System.EventHandler(this.UndoBranchToolStripMenuItem_Click); + // + // JumpToBranchButton + // + this.JumpToBranchButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.JumpToBranchButton.Enabled = false; + this.JumpToBranchButton.Location = new System.Drawing.Point(126, 247); + this.JumpToBranchButton.Name = "JumpToBranchButton"; + this.JumpToBranchButton.Size = new System.Drawing.Size(24, 24); + this.JumpToBranchButton.TabIndex = 5; + this.toolTip1.SetToolTip(this.JumpToBranchButton, "Jump To Branch Frame"); + this.JumpToBranchButton.UseVisualStyleBackColor = true; + this.JumpToBranchButton.Click += new System.EventHandler(this.JumpToBranchToolStripMenuItem_Click); + // + // UpdateBranchButton + // + this.UpdateBranchButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.UpdateBranchButton.Enabled = false; + this.UpdateBranchButton.Location = new System.Drawing.Point(96, 247); + this.UpdateBranchButton.Name = "UpdateBranchButton"; + this.UpdateBranchButton.Size = new System.Drawing.Size(24, 24); + this.UpdateBranchButton.TabIndex = 4; + this.toolTip1.SetToolTip(this.UpdateBranchButton, "Update Branch"); + this.UpdateBranchButton.UseVisualStyleBackColor = true; + this.UpdateBranchButton.Click += new System.EventHandler(this.UpdateBranchToolStripMenuItem_Click); + // + // AddWithTextBranchButton + // + this.AddWithTextBranchButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.AddWithTextBranchButton.Location = new System.Drawing.Point(36, 247); + this.AddWithTextBranchButton.Name = "AddWithTextBranchButton"; + this.AddWithTextBranchButton.Size = new System.Drawing.Size(24, 24); + this.AddWithTextBranchButton.TabIndex = 2; + this.toolTip1.SetToolTip(this.AddWithTextBranchButton, "Add Branch with Text"); + this.AddWithTextBranchButton.UseVisualStyleBackColor = true; + this.AddWithTextBranchButton.Click += new System.EventHandler(this.AddBranchWithTexToolStripMenuItem_Click); + // + // AddBranchButton + // + this.AddBranchButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.AddBranchButton.Location = new System.Drawing.Point(6, 247); + this.AddBranchButton.Name = "AddBranchButton"; + this.AddBranchButton.Size = new System.Drawing.Size(24, 24); + this.AddBranchButton.TabIndex = 1; + this.toolTip1.SetToolTip(this.AddBranchButton, "Add Branch"); + this.AddBranchButton.UseVisualStyleBackColor = true; + this.AddBranchButton.Click += new System.EventHandler(this.AddBranchToolStripMenuItem_Click); + // + // LoadBranchButton + // + this.LoadBranchButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.LoadBranchButton.Enabled = false; + this.LoadBranchButton.Location = new System.Drawing.Point(66, 247); + this.LoadBranchButton.Name = "LoadBranchButton"; + this.LoadBranchButton.Size = new System.Drawing.Size(24, 24); + this.LoadBranchButton.TabIndex = 3; + this.toolTip1.SetToolTip(this.LoadBranchButton, "Load Branch"); + this.LoadBranchButton.UseVisualStyleBackColor = true; + this.LoadBranchButton.Click += new System.EventHandler(this.LoadBranchToolStripMenuItem_Click); + // + // BranchView + // + this.BranchView.AllowColumnReorder = false; + this.BranchView.AllowColumnResize = false; + this.BranchView.AlwaysScroll = false; + this.BranchView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.BranchView.CellHeightPadding = 0; + this.BranchView.ChangeSelectionWhenPaging = false; + this.BranchView.ContextMenuStrip = this.BranchesContextMenu; + this.BranchView.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.BranchView.FullRowSelect = true; + this.BranchView.HorizontalOrientation = false; + this.BranchView.LetKeysModifySelection = false; + this.BranchView.Location = new System.Drawing.Point(6, 19); + this.BranchView.Name = "BranchView"; + this.BranchView.RowCount = 0; + this.BranchView.ScrollSpeed = 1; + this.BranchView.Size = new System.Drawing.Size(186, 224); + this.BranchView.TabIndex = 0; + this.BranchView.PointedCellChanged += new BizHawk.Client.EmuHawk.InputRoll.CellChangeEventHandler(this.BranchView_PointedCellChanged); + this.BranchView.SelectedIndexChanged += new System.EventHandler(this.BranchView_SelectedIndexChanged); + this.BranchView.CellDropped += new BizHawk.Client.EmuHawk.InputRoll.CellDroppedEvent(this.BranchView_CellDropped); + this.BranchView.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.BranchView_MouseDoubleClick); + this.BranchView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.BranchView_MouseDown); + this.BranchView.MouseLeave += new System.EventHandler(this.BranchView_MouseLeave); + this.BranchView.MouseMove += new System.Windows.Forms.MouseEventHandler(this.BranchView_MouseMove); + this.BranchView.MouseUp += new System.Windows.Forms.MouseEventHandler(this.BranchView_MouseUp); + // + // BranchesContextMenu + // + this.BranchesContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.AddBranchContextMenu, + this.AddBranchWithTextContextMenuItem, + this.LoadBranchContextMenuItem, + this.UpdateBranchContextMenuItem, + this.EditBranchTextContextMenuItem, + this.JumpToBranchContextMenuItem, + this.UndoBranchToolStripMenuItem, + this.toolStripSeparator2, + this.RemoveBranchContextMenuItem}); + this.BranchesContextMenu.Name = "BranchesContextMenu"; + this.BranchesContextMenu.Size = new System.Drawing.Size(147, 186); + this.BranchesContextMenu.Opening += new System.ComponentModel.CancelEventHandler(this.BranchesContextMenu_Opening); + // + // AddBranchContextMenu + // + this.AddBranchContextMenu.Text = "Add"; + this.AddBranchContextMenu.Click += new System.EventHandler(this.AddBranchToolStripMenuItem_Click); + // + // AddBranchWithTextContextMenuItem + // + this.AddBranchWithTextContextMenuItem.Text = "Add with Text"; + this.AddBranchWithTextContextMenuItem.Click += new System.EventHandler(this.AddBranchWithTexToolStripMenuItem_Click); + // + // LoadBranchContextMenuItem + // + this.LoadBranchContextMenuItem.Text = "Load"; + this.LoadBranchContextMenuItem.Click += new System.EventHandler(this.LoadBranchToolStripMenuItem_Click); + // + // UpdateBranchContextMenuItem + // + this.UpdateBranchContextMenuItem.Text = "&Update"; + this.UpdateBranchContextMenuItem.Click += new System.EventHandler(this.UpdateBranchToolStripMenuItem_Click); + // + // EditBranchTextContextMenuItem + // + this.EditBranchTextContextMenuItem.Text = "Edit Text"; + this.EditBranchTextContextMenuItem.Click += new System.EventHandler(this.EditBranchTextToolStripMenuItem_Click); + // + // JumpToBranchContextMenuItem + // + this.JumpToBranchContextMenuItem.Text = "Jump To"; + this.JumpToBranchContextMenuItem.Click += new System.EventHandler(this.JumpToBranchToolStripMenuItem_Click); + // + // UndoBranchToolStripMenuItem + // + this.UndoBranchToolStripMenuItem.Enabled = false; + this.UndoBranchToolStripMenuItem.Text = "Undo"; + this.UndoBranchToolStripMenuItem.Click += new System.EventHandler(this.UndoBranchToolStripMenuItem_Click); + // + // RemoveBranchContextMenuItem + // + this.RemoveBranchContextMenuItem.Text = "Remove"; + this.RemoveBranchContextMenuItem.Click += new System.EventHandler(this.RemoveBranchToolStripMenuItem_Click); + // + // BookmarksBranchesBox + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit; + this.Controls.Add(this.BookmarksBranchesGroupBox); + this.Name = "BookmarksBranchesBox"; + this.Size = new System.Drawing.Size(198, 278); + this.BookmarksBranchesGroupBox.ResumeLayout(false); + this.BranchesContextMenu.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.GroupBox BookmarksBranchesGroupBox; + private InputRoll BranchView; + private System.Windows.Forms.ContextMenuStrip BranchesContextMenu; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx AddBranchContextMenu; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx RemoveBranchContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx LoadBranchContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx UpdateBranchContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx EditBranchTextContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx AddBranchWithTextContextMenuItem; + private System.Windows.Forms.Button UpdateBranchButton; + private System.Windows.Forms.Button AddWithTextBranchButton; + private System.Windows.Forms.Button AddBranchButton; + private System.Windows.Forms.Button LoadBranchButton; + private System.Windows.Forms.ToolTip toolTip1; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator2; + private System.Windows.Forms.Button JumpToBranchButton; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx JumpToBranchContextMenuItem; + private System.Windows.Forms.Button UndoBranchButton; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx UndoBranchToolStripMenuItem; + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/BookmarksBranchesBoxMPR.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/BookmarksBranchesBoxMPR.cs new file mode 100644 index 00000000000..d2e21f1f401 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/BookmarksBranchesBoxMPR.cs @@ -0,0 +1,699 @@ +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Windows.Forms; + +using BizHawk.Client.Common; +using BizHawk.Client.EmuHawk.Properties; +using BizHawk.Common.CollectionExtensions; +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.EmuHawk +{ + public partial class BookmarksBranchesBoxMPR : UserControl, IDialogParent + { + private const string BranchNumberColumnName = "BranchNumberColumn"; + private const string FrameColumnName = "FrameColumn"; + private const string UserTextColumnName = "TextColumn"; + + private readonly ScreenshotForm _screenshot = new ScreenshotForm(); + + private ITasMovie Movie => TastudioMPR.CurrentTasMovie; + private ITasBranchCollection Branches => Movie.Branches; + + private IMainFormForTools MainForm => TastudioMPR.MainForm; + private TasBranch _backupBranch; + private BranchUndo _branchUndo = BranchUndo.None; + + private enum BranchUndo + { + Load, Update, Text, Remove, None + } + + public Action LoadedCallback { get; set; } + + public Action SavedCallback { get; set; } + + public Action RemovedCallback { get; set; } + + public TAStudioMPR TastudioMPR { get; set; } + + public IDialogController DialogController => TastudioMPR.MainForm; + + public BookmarksBranchesBoxMPR() + { + InitializeComponent(); + UndoBranchButton.Image = Resources.Undo; + JumpToBranchButton.Image = Resources.JumpTo; + UpdateBranchButton.Image = Resources.Reboot; + AddWithTextBranchButton.Image = Resources.AddEdit; + AddBranchButton.Image = Resources.Add; + LoadBranchButton.Image = Resources.Debugger; + AddBranchContextMenu.Image = Resources.Add; + AddBranchWithTextContextMenuItem.Image = Resources.AddEdit; + LoadBranchContextMenuItem.Image = Resources.Debugger; + UpdateBranchContextMenuItem.Image = Resources.Reboot; + EditBranchTextContextMenuItem.Image = Resources.Pencil; + JumpToBranchContextMenuItem.Image = Resources.JumpTo; + UndoBranchToolStripMenuItem.Image = Resources.Undo; + RemoveBranchContextMenuItem.Image = Resources.Delete; + SetupColumns(); + BranchView.QueryItemText += QueryItemText; + BranchView.QueryItemBkColor += QueryItemBkColor; + } + + private void SetupColumns() + { + BranchView.AllColumns.Clear(); + BranchView.AllColumns.Add(new(name: BranchNumberColumnName, widthUnscaled: 30, text: "#")); + BranchView.AllColumns.Add(new(name: FrameColumnName, widthUnscaled: 64, text: "Frame")); + BranchView.AllColumns.Add(new(name: UserTextColumnName, widthUnscaled: 90, text: "UserText")); + } + + private void QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) + { + text = ""; + + // This could happen if the control is told to redraw while Tastudio is rebooting, as we would not have a TasMovie just yet + if (TastudioMPR.CurrentTasMovie == null) + { + return; + } + + text = column.Name switch + { + BranchNumberColumnName => (index + 1).ToString(), + FrameColumnName => Branches[index].Frame.ToString(), + UserTextColumnName => Branches[index].UserText, + _ => text + }; + } + + private void QueryItemBkColor(int index, RollColumn column, ref Color color) + { + // This could happen if the control is told to redraw while Tastudio is rebooting, as we would not have a TasMovie just yet + if (TastudioMPR.CurrentTasMovie == null) + { + return; + } + + var branch = Branches[index]; + if (branch != null) + { + var record = Movie[branch.Frame]; + if (index == Branches.Current) + { + color = TastudioMPR.Palette.CurrentFrame_InputLog; + } + else if (record.Lagged.HasValue) + { + color = record.Lagged.Value + ? TastudioMPR.Palette.LagZone_InputLog + : TastudioMPR.Palette.GreenZone_InputLog; + } + } + + // Highlight the branch cell a little, if hovering over it + if (BranchView.CurrentCell is { RowIndex: int targetRow, Column.Name: BranchNumberColumnName } + && index == targetRow && column.Name is BranchNumberColumnName) + { + color = Color.FromArgb((byte)(color.A - 24), (byte)(color.R - 24), (byte)(color.G - 24), (byte)(color.B - 24)); + } + } + + // used to capture a reserved state immediately on branch creation + // while also not doing a double state + private class BufferedStatable : IStatable + { + private readonly byte[] _bufferedState; + + public BufferedStatable(byte[] state) + => _bufferedState = state; + + public bool AvoidRewind => true; + + public void SaveStateBinary(BinaryWriter writer) + => writer.Write(_bufferedState); + + public void LoadStateBinary(BinaryReader reader) + => throw new NotImplementedException(); + } + + /// + /// Add a new branch. + /// + public void Branch() + { + var branch = CreateBranch(); + Movie.Branches.NewBranchText = ""; // reset every time it's used + Branches.Add(branch); + BranchView.RowCount = Branches.Count; + Branches.Current = Branches.Count - 1; + Movie.TasSession.UpdateValues(TastudioMPR.Emulator.Frame, Branches.Current); + Movie.TasStateManager.Capture(TastudioMPR.Emulator.Frame, new BufferedStatable(branch.CoreData)); + BranchView.ScrollToIndex(Branches.Current); + BranchView.DeselectAll(); + Select(Branches.Current, true); + BranchView.Refresh(); + TastudioMPR.RefreshDialog(); + MainForm.UpdateStatusSlots(); + } + + public TasBranch SelectedBranch + => BranchView.AnyRowsSelected ? Branches[BranchView.FirstSelectedRowIndex] : null; + + private TasBranch CreateBranch() + { + return new() + { + Frame = TastudioMPR.Emulator.Frame, + CoreData = TastudioMPR.Emulator.AsStatable().CloneSavestate(), + InputLog = Movie.GetLogEntries().Clone(), + CoreFrameBuffer = MainForm.MakeScreenshotImage(), + OSDFrameBuffer = MainForm.CaptureOSD(), + ChangeLog = new(Movie), + TimeStamp = DateTime.Now, + Markers = Movie.Markers.DeepClone(), + UserText = Movie.Branches.NewBranchText + }; + } + + private void LoadBranch(TasBranch branch) + { + if (TastudioMPR.Settings.OldControlSchemeForBranches && !TastudioMPR.TasPlaybackBoxMPR.RecordingMode) + { + JumpToBranchToolStripMenuItem_Click(null, null); + return; + } + + Movie.LoadBranch(branch); + TastudioMPR.LoadState(new(branch.Frame, new MemoryStream(branch.CoreData, false))); + // set the controller state to the previous frame for input display purposes + int previousFrame = Movie.Emulator.Frame - 1; + TastudioMPR.MovieSession.MovieController.SetFrom(Movie.GetInputState(previousFrame)); + + Movie.TasStateManager.Capture(TastudioMPR.Emulator.Frame, TastudioMPR.Emulator.AsStatable()); + QuickBmpFile.Copy(new BitmapBufferVideoProvider(branch.CoreFrameBuffer), TastudioMPR.VideoProvider); + + if (TastudioMPR.Settings.OldControlSchemeForBranches && TastudioMPR.TasPlaybackBoxMPR.RecordingMode) + Movie.Truncate(branch.Frame); + + MainForm.PauseOnFrame = null; + TastudioMPR.RefreshDialog(); + } + + private bool LoadSelectedBranch() + { + if (SelectedBranch == null) return false; + Branches.Current = BranchView.FirstSelectedRowIndex; + LoadBranch(SelectedBranch); + BranchView.Refresh(); + TastudioMPR.MainForm.AddOnScreenMessage($"Loaded branch {Branches.Current + 1}"); + return true; + } + + private void BranchesContextMenu_Opening(object sender, CancelEventArgs e) + { + RemoveBranchContextMenuItem.Enabled = SelectedBranch != null; + + UpdateBranchContextMenuItem.Enabled = + LoadBranchContextMenuItem.Enabled = + EditBranchTextContextMenuItem.Enabled = + JumpToBranchContextMenuItem.Enabled = + BranchView.SelectedRows.CountIsExactly(1); + } + + private void AddBranchToolStripMenuItem_Click(object sender, EventArgs e) + { + Branch(); + SavedCallback?.Invoke(Branches.Count - 1); + TastudioMPR.MainForm.AddOnScreenMessage($"Added branch {Branches.Current + 1}"); + } + + private void AddBranchWithTexToolStripMenuItem_Click(object sender, EventArgs e) + { + Branch(); + EditBranchTextPopUp(Branches.Current); + SavedCallback?.Invoke(Branches.Count - 1); + TastudioMPR.MainForm.AddOnScreenMessage($"Added branch {Branches.Current + 1}"); + } + + private bool PrepareHistoryAndLoadSelectedBranch() + { + _backupBranch = CreateBranch(); + + var currentHashes = Branches.Select(b => b.Uuid.GetHashCode()).ToList(); + do + { + _backupBranch.Uuid = Guid.NewGuid(); + } + while (currentHashes.Contains(_backupBranch.Uuid.GetHashCode())); + + UndoBranchToolStripMenuItem.Enabled = UndoBranchButton.Enabled = true; + UndoBranchToolStripMenuItem.Text = "Undo Branch Load"; + toolTip1.SetToolTip(UndoBranchButton, "Undo Branch Load"); + _branchUndo = BranchUndo.Load; + + if (!BranchView.AnyRowsSelected) return false; // why'd we do all that then + + var success = LoadSelectedBranch(); + LoadedCallback?.Invoke(BranchView.FirstSelectedRowIndex); + return success; + } + + private void LoadBranchToolStripMenuItem_Click(object sender, EventArgs e) + => PrepareHistoryAndLoadSelectedBranch(); + + private void UpdateBranchToolStripMenuItem_Click(object sender, EventArgs e) + { + if (SelectedBranch == null) + { + return; + } + + Branches.Current = BranchView.FirstSelectedRowIndex; + + _backupBranch = SelectedBranch.Clone(); + UndoBranchToolStripMenuItem.Enabled = UndoBranchButton.Enabled = true; + UndoBranchToolStripMenuItem.Text = "Undo Branch Update"; + toolTip1.SetToolTip(UndoBranchButton, "Undo Branch Update"); + _branchUndo = BranchUndo.Update; + + BranchView.ScrollToIndex(Branches.Current); + var branch = CreateBranch(); + Branches.Replace(SelectedBranch, branch); + Movie.TasStateManager.Capture(TastudioMPR.Emulator.Frame, new BufferedStatable(branch.CoreData)); + TastudioMPR.RefreshDialog(); + SavedCallback?.Invoke(Branches.Current); + TastudioMPR.MainForm.AddOnScreenMessage($"Saved branch {Branches.Current + 1}"); + } + + private void EditBranchTextToolStripMenuItem_Click(object sender, EventArgs e) + { + if (SelectedBranch == null) + { + return; + } + + var index = BranchView.FirstSelectedRowIndex; + string oldText = SelectedBranch.UserText; + + if (EditBranchTextPopUp(index)) + { + _backupBranch = SelectedBranch.Clone(); + _backupBranch.UserText = oldText; + UndoBranchToolStripMenuItem.Enabled = UndoBranchButton.Enabled = true; + UndoBranchToolStripMenuItem.Text = "Undo Branch Text Edit"; + toolTip1.SetToolTip(UndoBranchButton, "Undo Branch Text Edit"); + _branchUndo = BranchUndo.Text; + + TastudioMPR.MainForm.AddOnScreenMessage($"Edited branch {index + 1}"); + } + } + + private void JumpToBranchToolStripMenuItem_Click(object sender, EventArgs e) + { + if (BranchView.AnyRowsSelected) TastudioMPR.GoToFrame(Branches[BranchView.FirstSelectedRowIndex].Frame); + } + + private void RemoveBranchToolStripMenuItem_Click(object sender, EventArgs e) + { + if (!BranchView.AnyRowsSelected) + { + return; + } + + var indices = BranchView.SelectedRows.ToList(); + var branches = Branches.ToList(); + foreach (var index in indices) + { + _backupBranch = branches[index].Clone(); + Branches.Remove(branches[index]); + RemovedCallback?.Invoke(index); + TastudioMPR.MainForm.AddOnScreenMessage($"Removed branch {index + 1}"); + + if (index == Branches.Current) + { + Branches.Current = -1; + } + else if (index < Branches.Current) + { + Branches.Current--; + } + } + + UndoBranchToolStripMenuItem.Enabled = UndoBranchButton.Enabled = true; + UndoBranchToolStripMenuItem.Text = "Undo Branch Removal"; + toolTip1.SetToolTip(UndoBranchButton, "Undo Branch Removal"); + _branchUndo = BranchUndo.Remove; + + BranchView.RowCount = Branches.Count; + TastudioMPR.RefreshDialog(refreshBranches: false); + MainForm.UpdateStatusSlots(); + } + + private void UndoBranchToolStripMenuItem_Click(object sender, EventArgs e) + { + if (_branchUndo == BranchUndo.Load) + { + LoadBranch(_backupBranch); + LoadedCallback?.Invoke(Branches.IndexOf(_backupBranch)); + TastudioMPR.MainForm.AddOnScreenMessage("Branch Load canceled"); + } + else if (_branchUndo == BranchUndo.Update) + { + var branch = Branches.SingleOrDefault(b => b.Uuid == _backupBranch.Uuid); + if (branch != null) + { + Branches.Replace(branch, _backupBranch); + SavedCallback?.Invoke(Branches.IndexOf(_backupBranch)); + TastudioMPR.MainForm.AddOnScreenMessage("Branch Update canceled"); + } + } + else if (_branchUndo == BranchUndo.Text) + { + var branch = Branches.SingleOrDefault(b => b.Uuid == _backupBranch.Uuid); + if (branch != null) + { + branch.UserText = _backupBranch.UserText; + } + + TastudioMPR.MainForm.AddOnScreenMessage("Branch Text Edit canceled"); + } + else if (_branchUndo == BranchUndo.Remove) + { + Branches.Add(_backupBranch); + BranchView.RowCount = Branches.Count; + SavedCallback?.Invoke(Branches.IndexOf(_backupBranch)); + TastudioMPR.MainForm.AddOnScreenMessage("Branch Removal canceled"); + } + + UndoBranchToolStripMenuItem.Enabled = UndoBranchButton.Enabled = false; + BranchView.Refresh(); + TastudioMPR.RefreshDialog(); + } + + public void AddBranchExternal() + { + AddBranchToolStripMenuItem_Click(null, null); + } + + public bool LoadBranchExternal(int slot = -1) + { + if (TastudioMPR.AxisEditingMode) + { + return false; + } + + if (slot != -1) + { + if (Branches[slot] != null) + { + BranchView.DeselectAll(); + Select(slot, true); + } + else + { + NonExistentBranchMessage(slot); + return false; + } + } + + return PrepareHistoryAndLoadSelectedBranch(); + } + + public void UpdateBranchExternal(int slot = -1) + { + if (TastudioMPR.AxisEditingMode) + { + return; + } + + if (slot != -1) + { + if (Branches[slot] != null) + { + BranchView.DeselectAll(); + Select(slot, true); + } + else + { + //NonExistentBranchMessage(slot); // some people can't get used to creating branches explicitly with unusual hotkeys + AddBranchExternal(); // so just make a new branch, even though the index may be wrong + return; + } + } + + UpdateBranchToolStripMenuItem_Click(null, null); + } + + public void RemoveBranchExternal() + { + RemoveBranchToolStripMenuItem_Click(null, null); + } + + public void SelectBranchExternal(int slot) + { + if (TastudioMPR.AxisEditingMode) + { + return; + } + + if (Branches[slot] != null) + { + Select(slot, true); + BranchView.Refresh(); + } + else + { + NonExistentBranchMessage(slot); + } + } + + public void SelectBranchExternal(bool next) + { + if (SelectedBranch == null) + { + if (Branches.Current != -1) + { + Select(Branches.Current, true); + BranchView.Refresh(); + } + return; + } + + var sel = BranchView.FirstSelectedRowIndex; + if (next) + { + if (Branches[sel + 1] != null) + { + Select(sel, false); + Select(sel + 1, true); + } + } + else // previous + { + if (Branches[sel - 1] != null) + { + Select(sel, false); + Select(sel - 1, true); + } + } + + BranchView.Refresh(); + } + + private void UpdateButtons() + { + UpdateBranchButton.Enabled = + LoadBranchButton.Enabled = + JumpToBranchButton.Enabled = + BranchView.SelectedRows.CountIsExactly(1); + } + + private void Select(int index, bool value) + { + BranchView.SelectRow(index, value); + UpdateButtons(); + } + + public void NonExistentBranchMessage(int slot) + { + TastudioMPR.MainForm.AddOnScreenMessage($"Branch {slot + 1} does not exist"); + TastudioMPR.MainForm.AddOnScreenMessage($"Use {TastudioMPR.Config!.HotkeyBindings["Add Branch"]} to add branches"); + } + + public void UpdateValues() + { + BranchView.RowCount = Branches.Count; + } + + public void Restart() + { + BranchView.RowCount = Branches.Count; + + if (BranchView.RowCount == 0) + { + SetupColumns(); + } + + BranchView.Refresh(); + } + + public void UpdateTextColumnWidth() + { + if (Branches.Count > 0) + { + var longestBranchText = Branches + .OrderBy(b => b.UserText?.Length ?? 0) + .Last() + .UserText; + + BranchView.ExpandColumnToFitText(UserTextColumnName, longestBranchText); + } + } + + public bool EditBranchTextPopUp(int index) + { + var branch = Branches[index]; + if (branch == null) + { + return false; + } + + var i = new InputPrompt + { + Text = $"Text for branch {index + 1}", + TextInputType = InputPrompt.InputType.Text, + Message = "Enter a message", + InitialValue = branch.UserText + }; + + i.FollowMousePointer(); + if (i.ShowDialogOnScreen().IsOk()) + { + branch.UserText = i.PromptText; + UpdateTextColumnWidth(); + UpdateValues(); + return true; + } + + return false; + } + + private void BranchView_MouseDown(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + if (BranchView.CurrentCell is { RowIndex: not null, Column.Name: BranchNumberColumnName }) + { + BranchView.DragCurrentCell(); + } + } + } + + private void BranchView_MouseUp(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + BranchView.ReleaseCurrentCell(); + } + } + + private void BranchView_MouseDoubleClick(object sender, MouseEventArgs e) + { + if (TastudioMPR.Settings.LoadBranchOnDoubleClick) + { + PrepareHistoryAndLoadSelectedBranch(); + } + } + + private void BranchView_MouseMove(object sender, MouseEventArgs e) + { + if (BranchView.CurrentCell?.RowIndex == null || BranchView.CurrentCell.Column == null) + { + _screenshot.FadeOut(); + } + else if (BranchView.CurrentCell.Column.Name == BranchNumberColumnName) + { + BranchView.Refresh(); + } + } + + private void BranchView_MouseLeave(object sender, EventArgs e) + { + _screenshot.FadeOut(); + } + + private void BranchView_CellDropped(object sender, InputRoll.CellEventArgs e) + { + if (e.NewCell.IsDataCell() && e.OldCell.RowIndex < Branches.Count) + { + var guid = Branches.Current > Branches.Count + ? Guid.Empty + : Branches[Branches.Current].Uuid; + + Branches.Swap(e.OldCell.RowIndex.Value, e.NewCell.RowIndex.Value); + int newIndex = Branches.IndexOfHash(guid); + Branches.Current = newIndex; + Select(newIndex, true); + } + } + + private void BranchView_PointedCellChanged(object sender, InputRoll.CellEventArgs e) + { + if (e.NewCell?.RowIndex != null && e.NewCell.Column != null && e.NewCell.RowIndex < Branches.Count) + { + if (BranchView.CurrentCell is { RowIndex: int targetRow, Column.Name: BranchNumberColumnName } + && targetRow < Branches.Count) + { + var branch = Branches[targetRow]; + var bb = branch.OSDFrameBuffer; + var width = bb.Width; + Point location = PointToScreen(Location); + var bottom = location.Y + bb.Height; + location.Offset(-width, 0); + + if (location.X < 0) + { + // show on the right of branch control + location.Offset(width + Width, 0); + } + + location.Y = Math.Max(0, location.Y); + var screen = Screen.AllScreens.First(s => s.WorkingArea.Contains(location)); + var h = screen.WorkingArea.Bottom - bottom; + + if (h < 0) + { + // move up to become fully visible + location.Y += h; + } + + _screenshot.UpdateValues( + bb, + branch.UserText, + location, + width: width, + height: bb.Height, + Graphics.FromHwnd(Handle).MeasureString); + _screenshot.FadeIn(); + } + else + { + _screenshot.FadeOut(); + } + } + else + { + _screenshot.FadeOut(); + } + } + + private void BranchView_SelectedIndexChanged(object sender, EventArgs e) + { + UpdateButtons(); + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/BookmarksBranchesBoxMPR.resx b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/BookmarksBranchesBoxMPR.resx new file mode 100644 index 00000000000..b72db1b6d3f --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/BookmarksBranchesBoxMPR.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 185, 17 + + + 23, 17 + + + 185, 17 + + \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/FramesPromptMPR.Designer.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/FramesPromptMPR.Designer.cs new file mode 100644 index 00000000000..e39c681ec1a --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/FramesPromptMPR.Designer.cs @@ -0,0 +1,110 @@ +namespace BizHawk.Client.EmuHawk +{ + partial class FramesPromptMPR + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.OkBtn = new System.Windows.Forms.Button(); + this.CancelBtn = new System.Windows.Forms.Button(); + this.label1 = new BizHawk.WinForms.Controls.LocLabelEx(); + this.NumFramesBox = new BizHawk.Client.EmuHawk.WatchValueBox(); + this.SuspendLayout(); + // + // OkBtn + // + this.OkBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.OkBtn.Location = new System.Drawing.Point(67, 47); + this.OkBtn.Name = "OkBtn"; + this.OkBtn.Size = new System.Drawing.Size(60, 23); + this.OkBtn.TabIndex = 1; + this.OkBtn.Text = "&OK"; + this.OkBtn.UseVisualStyleBackColor = true; + this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click); + // + // CancelBtn + // + this.CancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.CancelBtn.Location = new System.Drawing.Point(134, 47); + this.CancelBtn.Name = "CancelBtn"; + this.CancelBtn.Size = new System.Drawing.Size(60, 23); + this.CancelBtn.TabIndex = 2; + this.CancelBtn.Text = "&Cancel"; + this.CancelBtn.UseVisualStyleBackColor = true; + this.CancelBtn.Click += new System.EventHandler(this.CancelBtn_Click); + // + // label1 + // + this.label1.Location = new System.Drawing.Point(12, 20); + this.label1.Name = "label1"; + this.label1.Text = "Insert number of frames:"; + // + // NumFramesBox + // + this.NumFramesBox.ByteSize = BizHawk.Client.Common.WatchSize.Word; + this.NumFramesBox.CharacterCasing = System.Windows.Forms.CharacterCasing.Upper; + this.NumFramesBox.Location = new System.Drawing.Point(138, 16); + this.NumFramesBox.MaxLength = 5; + this.NumFramesBox.Name = "NumFramesBox"; + this.NumFramesBox.Nullable = false; + this.NumFramesBox.Size = new System.Drawing.Size(51, 20); + this.NumFramesBox.TabIndex = 3; + this.NumFramesBox.Text = "1"; + this.NumFramesBox.Type = BizHawk.Client.Common.WatchDisplayType.Unsigned; + // + // FramesPrompt + // + this.AcceptButton = this.OkBtn; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.CancelBtn; + this.ClientSize = new System.Drawing.Size(206, 82); + this.Controls.Add(this.label1); + this.Controls.Add(this.NumFramesBox); + this.Controls.Add(this.CancelBtn); + this.Controls.Add(this.OkBtn); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FramesPrompt"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Insert Frames"; + this.Load += new System.EventHandler(this.FramesPrompt_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button OkBtn; + private System.Windows.Forms.Button CancelBtn; + private WatchValueBox NumFramesBox; + private BizHawk.WinForms.Controls.LocLabelEx label1; + } +} \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/FramesPromptMPR.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/FramesPromptMPR.cs new file mode 100644 index 00000000000..5ba86c219f4 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/FramesPromptMPR.cs @@ -0,0 +1,39 @@ +using System.Windows.Forms; + +namespace BizHawk.Client.EmuHawk +{ + public partial class FramesPromptMPR : Form + { + public FramesPromptMPR() + { + InitializeComponent(); + } + + public FramesPromptMPR(string headMessage, string bodyMessage) + { + InitializeComponent(); + + this.Text = headMessage; + this.label1.Text = bodyMessage; + } + + public int Frames => NumFramesBox.ToRawInt() ?? 0; + + private void FramesPrompt_Load(object sender, EventArgs e) + { + NumFramesBox.Select(); + } + + private void OkBtn_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.OK; + Close(); + } + + private void CancelBtn_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + Close(); + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/FramesPromptMPR.resx b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/FramesPromptMPR.resx new file mode 100644 index 00000000000..29dcb1b3a35 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/FramesPromptMPR.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/GreenzoneSettingsMPR.Designer.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/GreenzoneSettingsMPR.Designer.cs new file mode 100644 index 00000000000..bbeb1f0a560 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/GreenzoneSettingsMPR.Designer.cs @@ -0,0 +1,109 @@ +namespace BizHawk.Client.EmuHawk +{ + partial class GreenzoneSettingsMPR + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.OkBtn = new System.Windows.Forms.Button(); + this.CancelBtn = new System.Windows.Forms.Button(); + this.DefaultsButton = new System.Windows.Forms.Button(); + this.SettingsPropertyGrid = new System.Windows.Forms.PropertyGrid(); + this.SuspendLayout(); + // + // OkBtn + // + this.OkBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.OkBtn.Location = new System.Drawing.Point(263, 333); + this.OkBtn.Name = "OkBtn"; + this.OkBtn.Size = new System.Drawing.Size(60, 23); + this.OkBtn.TabIndex = 3; + this.OkBtn.Text = "&OK"; + this.OkBtn.UseVisualStyleBackColor = true; + this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click); + // + // CancelBtn + // + this.CancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.CancelBtn.Location = new System.Drawing.Point(329, 333); + this.CancelBtn.Name = "CancelBtn"; + this.CancelBtn.Size = new System.Drawing.Size(60, 23); + this.CancelBtn.TabIndex = 2; + this.CancelBtn.Text = "&Cancel"; + this.CancelBtn.UseVisualStyleBackColor = true; + this.CancelBtn.Click += new System.EventHandler(this.CancelBtn_Click); + // + // DefaultsButton + // + this.DefaultsButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.DefaultsButton.Location = new System.Drawing.Point(12, 333); + this.DefaultsButton.Name = "DefaultsButton"; + this.DefaultsButton.Size = new System.Drawing.Size(101, 23); + this.DefaultsButton.TabIndex = 4; + this.DefaultsButton.Text = "Restore &Defaults"; + this.DefaultsButton.UseVisualStyleBackColor = true; + this.DefaultsButton.Click += new System.EventHandler(this.DefaultsButton_Click); + // + // SettingsPropertyGrid + // + this.SettingsPropertyGrid.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.SettingsPropertyGrid.Location = new System.Drawing.Point(12, 8); + this.SettingsPropertyGrid.Name = "SettingsPropertyGrid"; + this.SettingsPropertyGrid.PropertySort = System.Windows.Forms.PropertySort.NoSort; + this.SettingsPropertyGrid.Size = new System.Drawing.Size(376, 319); + this.SettingsPropertyGrid.TabIndex = 5; + this.SettingsPropertyGrid.ToolbarVisible = false; + // + // GreenzoneSettings + // + this.AcceptButton = this.OkBtn; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.CancelBtn; + this.ClientSize = new System.Drawing.Size(400, 368); + this.Controls.Add(this.SettingsPropertyGrid); + this.Controls.Add(this.DefaultsButton); + this.Controls.Add(this.OkBtn); + this.Controls.Add(this.CancelBtn); + this.Name = "GreenzoneSettings"; + this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; + this.Text = "Default Savestate History Settings"; + this.Load += new System.EventHandler(this.GreenzoneSettings_Load); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button OkBtn; + private System.Windows.Forms.Button CancelBtn; + private System.Windows.Forms.Button DefaultsButton; + private System.Windows.Forms.PropertyGrid SettingsPropertyGrid; + } +} \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/GreenzoneSettingsMPR.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/GreenzoneSettingsMPR.cs new file mode 100644 index 00000000000..8fef7da0fcf --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/GreenzoneSettingsMPR.cs @@ -0,0 +1,52 @@ +using System.Windows.Forms; + +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public partial class GreenzoneSettingsMPR : Form, IDialogParent + { + private readonly Action _saveSettings; + private ZwinderStateManagerSettings _settings; + private readonly bool _isDefault; + + public IDialogController DialogController { get; } + + public GreenzoneSettingsMPR(IDialogController dialogController, ZwinderStateManagerSettings settings, Action saveSettings, bool isDefault) + { + DialogController = dialogController; + InitializeComponent(); + Icon = Properties.Resources.TAStudioIcon; + + _saveSettings = saveSettings; + _settings = settings; + _isDefault = isDefault; + if (!isDefault) + Text = "Savestate History Settings"; + SettingsPropertyGrid.SelectedObject = _settings; + } + + private void GreenzoneSettings_Load(object sender, EventArgs e) + { + SettingsPropertyGrid.AdjustDescriptionHeightToFit(); + } + + private void OkBtn_Click(object sender, EventArgs e) + { + var keep = !_isDefault && DialogController.ShowMessageBox2("Attempt to keep old states?", "Keep old states?"); + _saveSettings(_settings, keep); + Close(); + } + + private void CancelBtn_Click(object sender, EventArgs e) + { + Close(); + } + + private void DefaultsButton_Click(object sender, EventArgs e) + { + _settings = new ZwinderStateManagerSettings(); + SettingsPropertyGrid.SelectedObject = _settings; + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/GreenzoneSettingsMPR.resx b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/GreenzoneSettingsMPR.resx new file mode 100644 index 00000000000..29dcb1b3a35 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/GreenzoneSettingsMPR.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/HeaderEditorMPR.Designer.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/HeaderEditorMPR.Designer.cs new file mode 100644 index 00000000000..b49db74ba25 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/HeaderEditorMPR.Designer.cs @@ -0,0 +1,233 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace BizHawk.Client.EmuHawk +{ + public partial class MovieHeaderEditorMPR + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.CancelBtn = new System.Windows.Forms.Button(); + this.OkBtn = new System.Windows.Forms.Button(); + this.AuthorTextBox = new System.Windows.Forms.TextBox(); + this.label1 = new BizHawk.WinForms.Controls.LocLabelEx(); + this.DefaultAuthorButton = new System.Windows.Forms.Button(); + this.MakeDefaultCheckbox = new System.Windows.Forms.CheckBox(); + this.label2 = new BizHawk.WinForms.Controls.LocLabelEx(); + this.EmulatorVersionTextBox = new System.Windows.Forms.TextBox(); + this.CoreTextBox = new System.Windows.Forms.TextBox(); + this.label4 = new BizHawk.WinForms.Controls.LocLabelEx(); + this.BoardNameTextBox = new System.Windows.Forms.TextBox(); + this.label5 = new BizHawk.WinForms.Controls.LocLabelEx(); + this.GameNameTextBox = new System.Windows.Forms.TextBox(); + this.label6 = new BizHawk.WinForms.Controls.LocLabelEx(); + this.SuspendLayout(); + // + // CancelBtn + // + this.CancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.CancelBtn.Location = new System.Drawing.Point(249, 238); + this.CancelBtn.Name = "CancelBtn"; + this.CancelBtn.Size = new System.Drawing.Size(60, 23); + this.CancelBtn.TabIndex = 0; + this.CancelBtn.Text = "&Cancel"; + this.CancelBtn.UseVisualStyleBackColor = true; + this.CancelBtn.Click += new System.EventHandler(this.CancelBtn_Click); + // + // OkBtn + // + this.OkBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.OkBtn.Location = new System.Drawing.Point(183, 238); + this.OkBtn.Name = "OkBtn"; + this.OkBtn.Size = new System.Drawing.Size(60, 23); + this.OkBtn.TabIndex = 1; + this.OkBtn.Text = "&OK"; + this.OkBtn.UseVisualStyleBackColor = true; + this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click); + // + // AuthorTextBox + // + this.AuthorTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.AuthorTextBox.Location = new System.Drawing.Point(90, 20); + this.AuthorTextBox.Name = "AuthorTextBox"; + this.AuthorTextBox.Size = new System.Drawing.Size(162, 20); + this.AuthorTextBox.TabIndex = 2; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 20); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(38, 13); + this.label1.TabIndex = 3; + this.label1.Text = "Author"; + // + // DefaultAuthorButton + // + this.DefaultAuthorButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.DefaultAuthorButton.Location = new System.Drawing.Point(258, 19); + this.DefaultAuthorButton.Name = "DefaultAuthorButton"; + this.DefaultAuthorButton.Size = new System.Drawing.Size(51, 23); + this.DefaultAuthorButton.TabIndex = 4; + this.DefaultAuthorButton.Text = "Default"; + this.DefaultAuthorButton.UseVisualStyleBackColor = true; + this.DefaultAuthorButton.Click += new System.EventHandler(this.DefaultAuthorButton_Click); + // + // MakeDefaultCheckbox + // + this.MakeDefaultCheckbox.AutoSize = true; + this.MakeDefaultCheckbox.Location = new System.Drawing.Point(108, 43); + this.MakeDefaultCheckbox.Name = "MakeDefaultCheckbox"; + this.MakeDefaultCheckbox.Size = new System.Drawing.Size(88, 17); + this.MakeDefaultCheckbox.TabIndex = 5; + this.MakeDefaultCheckbox.Text = "Make default"; + this.MakeDefaultCheckbox.UseVisualStyleBackColor = true; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 80); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(66, 13); + this.label2.TabIndex = 6; + this.label2.Text = "Emu Version"; + // + // EmulatorVersionTextBox + // + this.EmulatorVersionTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.EmulatorVersionTextBox.Location = new System.Drawing.Point(90, 76); + this.EmulatorVersionTextBox.Name = "EmulatorVersionTextBox"; + this.EmulatorVersionTextBox.Size = new System.Drawing.Size(162, 20); + this.EmulatorVersionTextBox.TabIndex = 7; + // + // CoreTextBox + // + this.CoreTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.CoreTextBox.Location = new System.Drawing.Point(90, 106); + this.CoreTextBox.Name = "CoreTextBox"; + this.CoreTextBox.Size = new System.Drawing.Size(162, 20); + this.CoreTextBox.TabIndex = 10; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(12, 110); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(29, 13); + this.label4.TabIndex = 11; + this.label4.Text = "Core"; + // + // BoardNameTextBox + // + this.BoardNameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.BoardNameTextBox.Location = new System.Drawing.Point(90, 136); + this.BoardNameTextBox.Name = "BoardNameTextBox"; + this.BoardNameTextBox.Size = new System.Drawing.Size(162, 20); + this.BoardNameTextBox.TabIndex = 12; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(12, 140); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(64, 13); + this.label5.TabIndex = 13; + this.label5.Text = "Board name"; + // + // GameNameTextBox + // + this.GameNameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.GameNameTextBox.Location = new System.Drawing.Point(90, 166); + this.GameNameTextBox.Name = "GameNameTextBox"; + this.GameNameTextBox.Size = new System.Drawing.Size(162, 20); + this.GameNameTextBox.TabIndex = 14; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(12, 170); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(64, 13); + this.label6.TabIndex = 15; + this.label6.Text = "Game name"; + // + // MovieHeaderEditor + // + this.AcceptButton = this.OkBtn; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.CancelBtn; + this.ClientSize = new System.Drawing.Size(321, 273); + this.Controls.Add(this.label6); + this.Controls.Add(this.GameNameTextBox); + this.Controls.Add(this.label5); + this.Controls.Add(this.BoardNameTextBox); + this.Controls.Add(this.label4); + this.Controls.Add(this.CoreTextBox); + this.Controls.Add(this.EmulatorVersionTextBox); + this.Controls.Add(this.label2); + this.Controls.Add(this.MakeDefaultCheckbox); + this.Controls.Add(this.DefaultAuthorButton); + this.Controls.Add(this.label1); + this.Controls.Add(this.AuthorTextBox); + this.Controls.Add(this.OkBtn); + this.Controls.Add(this.CancelBtn); + this.MinimumSize = new System.Drawing.Size(150, 311); + this.Name = "MovieHeaderEditor"; + this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; + this.Text = "Header Info"; + this.Load += new System.EventHandler(this.MovieHeaderEditor_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + private Button CancelBtn; + private Button OkBtn; + private TextBox AuthorTextBox; + private Label label1; + private Button DefaultAuthorButton; + private CheckBox MakeDefaultCheckbox; + private Label label2; + private TextBox EmulatorVersionTextBox; + private TextBox CoreTextBox; + private Label label4; + private TextBox BoardNameTextBox; + private Label label5; + private TextBox GameNameTextBox; + private Label label6; + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/HeaderEditorMPR.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/HeaderEditorMPR.cs new file mode 100644 index 00000000000..df47edfb14e --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/HeaderEditorMPR.cs @@ -0,0 +1,57 @@ +using System.Windows.Forms; + +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public partial class MovieHeaderEditorMPR : Form + { + private readonly IBasicMovieInfo _movie; + private readonly Config _config; + + public MovieHeaderEditorMPR(IBasicMovieInfo movie, Config config) + { + _movie = movie; + _config = config; + InitializeComponent(); + Icon = Properties.Resources.TAStudioIcon; + } + + private void MovieHeaderEditor_Load(object sender, EventArgs e) + { + AuthorTextBox.Text = _movie.Author; + EmulatorVersionTextBox.Text = _movie.EmulatorVersion; + CoreTextBox.Text = _movie.Core; + BoardNameTextBox.Text = _movie.BoardName; + GameNameTextBox.Text = _movie.GameName; + } + + private void OkBtn_Click(object sender, EventArgs e) + { + _movie.Author = AuthorTextBox.Text; + if (MakeDefaultCheckbox.Checked) + { + _config.DefaultAuthor = AuthorTextBox.Text; + } + + _movie.EmulatorVersion = EmulatorVersionTextBox.Text; + _movie.Core = CoreTextBox.Text; + _movie.BoardName = BoardNameTextBox.Text; + _movie.GameName = GameNameTextBox.Text; + + DialogResult = DialogResult.OK; + Close(); + } + + private void CancelBtn_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + Close(); + } + + private void DefaultAuthorButton_Click(object sender, EventArgs e) + { + AuthorTextBox.Text = _config.DefaultAuthor; + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/HeaderEditorMPR.resx b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/HeaderEditorMPR.resx new file mode 100644 index 00000000000..29dcb1b3a35 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/HeaderEditorMPR.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/MarkerControlMPR.Designer.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/MarkerControlMPR.Designer.cs new file mode 100644 index 00000000000..c5a6da6eed2 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/MarkerControlMPR.Designer.cs @@ -0,0 +1,255 @@ +namespace BizHawk.Client.EmuHawk +{ + partial class MarkerControlMPR + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.MarkerContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.JumpToMarkerToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.ScrollToMarkerToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.EditMarkerToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.EditMarkerFrameToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.AddMarkerToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator1 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.RemoveMarkerToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.JumpToMarkerButton = new System.Windows.Forms.Button(); + this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); + this.EditMarkerButton = new System.Windows.Forms.Button(); + this.EditMarkerFrameButton = new System.Windows.Forms.Button(); + this.AddMarkerButton = new System.Windows.Forms.Button(); + this.RemoveMarkerButton = new System.Windows.Forms.Button(); + this.ScrollToMarkerButton = new System.Windows.Forms.Button(); + this.AddMarkerWithTextButton = new System.Windows.Forms.Button(); + this.MarkerView = new BizHawk.Client.EmuHawk.InputRoll(); + this.MarkersGroupBox = new System.Windows.Forms.GroupBox(); + this.MarkerContextMenu.SuspendLayout(); + this.MarkersGroupBox.SuspendLayout(); + this.SuspendLayout(); + // + // MarkerContextMenu + // + this.MarkerContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.JumpToMarkerToolStripMenuItem, + this.ScrollToMarkerToolStripMenuItem, + this.EditMarkerToolStripMenuItem, + this.EditMarkerFrameToolStripMenuItem, + this.AddMarkerToolStripMenuItem, + this.toolStripSeparator1, + this.RemoveMarkerToolStripMenuItem}); + this.MarkerContextMenu.Name = "MarkerContextMenu"; + this.MarkerContextMenu.Size = new System.Drawing.Size(196, 142); + this.MarkerContextMenu.Opening += new System.ComponentModel.CancelEventHandler(this.MarkerContextMenu_Opening); + // + // JumpToMarkerToolStripMenuItem + // + this.JumpToMarkerToolStripMenuItem.Text = "Jump To"; + this.JumpToMarkerToolStripMenuItem.Click += new System.EventHandler(this.JumpToMarkerToolStripMenuItem_Click); + // + // ScrollToMarkerToolStripMenuItem + // + this.ScrollToMarkerToolStripMenuItem.Text = "Scroll To"; + this.ScrollToMarkerToolStripMenuItem.Click += new System.EventHandler(this.ScrollToMarkerToolStripMenuItem_Click); + // + // EditMarkerToolStripMenuItem + // + this.EditMarkerToolStripMenuItem.Text = "Edit Text"; + this.EditMarkerToolStripMenuItem.Click += new System.EventHandler(this.EditMarkerToolStripMenuItem_Click); + // + // EditMarkerFrameToolStripMenuItem + // + this.EditMarkerFrameToolStripMenuItem.Text = "Edit Frame (Alt + Drag)"; + this.EditMarkerFrameToolStripMenuItem.Click += new System.EventHandler(this.EditMarkerFrameToolStripMenuItem_Click); + // + // AddMarkerToolStripMenuItem + // + this.AddMarkerToolStripMenuItem.Text = "Add"; + this.AddMarkerToolStripMenuItem.Click += new System.EventHandler(this.AddMarkerToolStripMenuItem_Click); + // + // RemoveMarkerToolStripMenuItem + // + this.RemoveMarkerToolStripMenuItem.Text = "Remove"; + this.RemoveMarkerToolStripMenuItem.Click += new System.EventHandler(this.RemoveMarkerToolStripMenuItem_Click); + // + // JumpToMarkerButton + // + this.JumpToMarkerButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.JumpToMarkerButton.Enabled = false; + this.JumpToMarkerButton.Location = new System.Drawing.Point(61, 247); + this.JumpToMarkerButton.Name = "JumpToMarkerButton"; + this.JumpToMarkerButton.Size = new System.Drawing.Size(24, 24); + this.JumpToMarkerButton.TabIndex = 3; + this.toolTip1.SetToolTip(this.JumpToMarkerButton, "Jump To Marker Frame"); + this.JumpToMarkerButton.UseVisualStyleBackColor = true; + this.JumpToMarkerButton.Click += new System.EventHandler(this.JumpToMarkerToolStripMenuItem_Click); + // + // EditMarkerButton + // + this.EditMarkerButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.EditMarkerButton.Enabled = false; + this.EditMarkerButton.Location = new System.Drawing.Point(117, 247); + this.EditMarkerButton.Name = "EditMarkerButton"; + this.EditMarkerButton.Size = new System.Drawing.Size(24, 24); + this.EditMarkerButton.TabIndex = 5; + this.toolTip1.SetToolTip(this.EditMarkerButton, "Edit Marker Text"); + this.EditMarkerButton.UseVisualStyleBackColor = true; + this.EditMarkerButton.Click += new System.EventHandler(this.EditMarkerToolStripMenuItem_Click); + // + // EditMarkerFrameButton + // + this.EditMarkerFrameButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.EditMarkerFrameButton.Enabled = false; + this.EditMarkerFrameButton.Location = new System.Drawing.Point(145, 247); + this.EditMarkerFrameButton.Name = "EditMarkerFrameButton"; + this.EditMarkerFrameButton.Size = new System.Drawing.Size(24, 24); + this.EditMarkerFrameButton.TabIndex = 6; + this.toolTip1.SetToolTip(this.EditMarkerFrameButton, "Edit Marker Frame (Alt + Drag)"); + this.EditMarkerFrameButton.UseVisualStyleBackColor = true; + this.EditMarkerFrameButton.Click += new System.EventHandler(this.EditMarkerFrameToolStripMenuItem_Click); + // + // AddMarkerButton + // + this.AddMarkerButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.AddMarkerButton.Location = new System.Drawing.Point(5, 247); + this.AddMarkerButton.Name = "AddMarkerButton"; + this.AddMarkerButton.Size = new System.Drawing.Size(24, 24); + this.AddMarkerButton.TabIndex = 1; + this.toolTip1.SetToolTip(this.AddMarkerButton, "Add Marker to Emulated Frame"); + this.AddMarkerButton.UseVisualStyleBackColor = true; + this.AddMarkerButton.Click += new System.EventHandler(this.AddMarkerToolStripMenuItem_Click); + // + // RemoveMarkerButton + // + this.RemoveMarkerButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.RemoveMarkerButton.Enabled = false; + this.RemoveMarkerButton.Location = new System.Drawing.Point(173, 247); + this.RemoveMarkerButton.Name = "RemoveMarkerButton"; + this.RemoveMarkerButton.Size = new System.Drawing.Size(24, 24); + this.RemoveMarkerButton.TabIndex = 7; + this.toolTip1.SetToolTip(this.RemoveMarkerButton, "Remove Marker"); + this.RemoveMarkerButton.UseVisualStyleBackColor = true; + this.RemoveMarkerButton.Click += new System.EventHandler(this.RemoveMarkerToolStripMenuItem_Click); + // + // ScrollToMarkerButton + // + this.ScrollToMarkerButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.ScrollToMarkerButton.Enabled = false; + this.ScrollToMarkerButton.Location = new System.Drawing.Point(89, 247); + this.ScrollToMarkerButton.Name = "ScrollToMarkerButton"; + this.ScrollToMarkerButton.Size = new System.Drawing.Size(24, 24); + this.ScrollToMarkerButton.TabIndex = 4; + this.toolTip1.SetToolTip(this.ScrollToMarkerButton, "Scroll View To Marker Frame"); + this.ScrollToMarkerButton.UseVisualStyleBackColor = true; + this.ScrollToMarkerButton.Click += new System.EventHandler(this.ScrollToMarkerToolStripMenuItem_Click); + // + // AddMarkerWithTextButton + // + this.AddMarkerWithTextButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.AddMarkerWithTextButton.Location = new System.Drawing.Point(33, 247); + this.AddMarkerWithTextButton.Name = "AddMarkerWithTextButton"; + this.AddMarkerWithTextButton.Size = new System.Drawing.Size(24, 24); + this.AddMarkerWithTextButton.TabIndex = 2; + this.toolTip1.SetToolTip(this.AddMarkerWithTextButton, "Add Marker with Text to Emulated Frame"); + this.AddMarkerWithTextButton.UseVisualStyleBackColor = true; + this.AddMarkerWithTextButton.Click += new System.EventHandler(this.AddMarkerWithTextToolStripMenuItem_Click); + // + // MarkerView + // + this.MarkerView.AllowColumnReorder = false; + this.MarkerView.AllowColumnResize = false; + this.MarkerView.AlwaysScroll = false; + this.MarkerView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.MarkerView.CellHeightPadding = 0; + this.MarkerView.ContextMenuStrip = this.MarkerContextMenu; + this.MarkerView.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.MarkerView.FullRowSelect = true; + this.MarkerView.HorizontalOrientation = false; + this.MarkerView.LetKeysModifySelection = false; + this.MarkerView.Location = new System.Drawing.Point(6, 19); + this.MarkerView.Name = "MarkerView"; + this.MarkerView.RowCount = 0; + this.MarkerView.ScrollSpeed = 1; + this.MarkerView.Size = new System.Drawing.Size(186, 224); + this.MarkerView.TabIndex = 0; + this.MarkerView.TabStop = false; + this.MarkerView.SelectedIndexChanged += new System.EventHandler(this.MarkerView_SelectedIndexChanged); + this.MarkerView.DoubleClick += new System.EventHandler(this.MarkerView_MouseDoubleClick); + // + // MarkersGroupBox + // + this.MarkersGroupBox.Controls.Add(this.MarkerView); + this.MarkersGroupBox.Controls.Add(this.AddMarkerButton); + this.MarkersGroupBox.Controls.Add(this.AddMarkerWithTextButton); + this.MarkersGroupBox.Controls.Add(this.RemoveMarkerButton); + this.MarkersGroupBox.Controls.Add(this.ScrollToMarkerButton); + this.MarkersGroupBox.Controls.Add(this.EditMarkerButton); + this.MarkersGroupBox.Controls.Add(this.EditMarkerFrameButton); + this.MarkersGroupBox.Controls.Add(this.JumpToMarkerButton); + this.MarkersGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.MarkersGroupBox.Location = new System.Drawing.Point(0, 0); + this.MarkersGroupBox.Name = "MarkersGroupBox"; + this.MarkersGroupBox.Size = new System.Drawing.Size(198, 278); + this.MarkersGroupBox.TabIndex = 0; + this.MarkersGroupBox.TabStop = false; + this.MarkersGroupBox.Text = "Markers"; + // + // MarkerControl + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit; + this.Controls.Add(this.MarkersGroupBox); + this.Name = "MarkerControl"; + this.Size = new System.Drawing.Size(198, 278); + this.MarkerContextMenu.ResumeLayout(false); + this.MarkersGroupBox.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private InputRoll MarkerView; + private System.Windows.Forms.Button AddMarkerButton; + private System.Windows.Forms.Button RemoveMarkerButton; + private System.Windows.Forms.Button JumpToMarkerButton; + private System.Windows.Forms.Button EditMarkerButton; + private System.Windows.Forms.Button EditMarkerFrameButton; + private System.Windows.Forms.Button ScrollToMarkerButton; + private System.Windows.Forms.ToolTip toolTip1; + private System.Windows.Forms.ContextMenuStrip MarkerContextMenu; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx ScrollToMarkerToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx EditMarkerToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx EditMarkerFrameToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx AddMarkerToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx RemoveMarkerToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx JumpToMarkerToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator1; + private System.Windows.Forms.Button AddMarkerWithTextButton; + private System.Windows.Forms.GroupBox MarkersGroupBox; + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/MarkerControlMPR.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/MarkerControlMPR.cs new file mode 100644 index 00000000000..0a401fca137 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/MarkerControlMPR.cs @@ -0,0 +1,291 @@ +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +using BizHawk.Client.Common; +using BizHawk.Client.EmuHawk.Properties; + +namespace BizHawk.Client.EmuHawk +{ + public partial class MarkerControlMPR : UserControl, IDialogParent + { + public TAStudioMPR TastudioMPR { get; set; } + public TasMovieMarkerList Markers => TastudioMPR.CurrentTasMovie.Markers; + + public IDialogController DialogController => TastudioMPR.MainForm; + + private TasMovieMarker FirstSelectedMarker + => Markers[MarkerView.FirstSelectedRowIndex]; + + public MarkerControlMPR() + { + InitializeComponent(); + JumpToMarkerToolStripMenuItem.Image = Resources.JumpTo; + ScrollToMarkerToolStripMenuItem.Image = Resources.ScrollTo; + EditMarkerToolStripMenuItem.Image = Resources.Pencil; + EditMarkerFrameToolStripMenuItem.Image = Resources.Clock; + AddMarkerToolStripMenuItem.Image = Resources.Add; + RemoveMarkerToolStripMenuItem.Image = Resources.Delete; + JumpToMarkerButton.Image = Resources.JumpTo; + EditMarkerButton.Image = Resources.Pencil; + EditMarkerFrameButton.Image = Resources.Clock; + AddMarkerButton.Image = Resources.Add; + RemoveMarkerButton.Image = Resources.Delete; + ScrollToMarkerButton.Image = Resources.ScrollTo; + AddMarkerWithTextButton.Image = Resources.AddEdit; + SetupColumns(); + MarkerView.QueryItemBkColor += MarkerView_QueryItemBkColor; + MarkerView.QueryItemText += MarkerView_QueryItemText; + } + + private void SetupColumns() + { + MarkerView.AllColumns.Clear(); + MarkerView.AllColumns.Add(new(name: "FrameColumn", widthUnscaled: 52, text: "Frame")); + MarkerView.AllColumns.Add(new(name: "LabelColumn", widthUnscaled: 125, text: string.Empty)); + } + + public InputRoll MarkerInputRoll => MarkerView; + + private void MarkerView_QueryItemBkColor(int index, RollColumn column, ref Color color) + { + // This could happen if the control is told to redraw while Tastudio is rebooting, as we would not have a TasMovie just yet + if (TastudioMPR.CurrentTasMovie is null) return; + + if (index >= Markers.Count) return; // this should never happen + + var marker = Markers[index]; + var prev = Markers.PreviousOrCurrent(TastudioMPR.Emulator.Frame); + + if (ReferenceEquals(marker, prev)) + { + // feos: taseditor doesn't have it, so we're free to set arbitrary color scheme. and I prefer consistency + color = TastudioMPR.Palette.CurrentFrame_InputLog; + } + else if (TastudioMPR.CurrentTasMovie.LagLog[marker.Frame + 1] is bool lagged) + { + if (lagged) + { + color = column.Name == "FrameColumn" + ? TastudioMPR.Palette.LagZone_FrameCol + : TastudioMPR.Palette.LagZone_InputLog; + } + else + { + color = column.Name == "LabelColumn" + ? TastudioMPR.Palette.GreenZone_FrameCol + : TastudioMPR.Palette.GreenZone_InputLog; + } + } + } + + private void MarkerView_QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) + { + text = ""; + + // This could happen if the control is told to redraw while Tastudio is rebooting, as we would not have a TasMovie just yet + if (TastudioMPR.CurrentTasMovie == null) + { + return; + } + + if (column.Name == "FrameColumn") + { + text = Markers[index].Frame.ToString(); + } + else if (column.Name == "LabelColumn") + { + text = Markers[index].Message; + } + } + + private void MarkerContextMenu_Opening(object sender, CancelEventArgs e) + { + EditMarkerToolStripMenuItem.Enabled = + EditMarkerFrameToolStripMenuItem.Enabled = + RemoveMarkerToolStripMenuItem.Enabled = + MarkerInputRoll.AnyRowsSelected && MarkerView.FirstSelectedRowIndex is not 0; + + JumpToMarkerToolStripMenuItem.Enabled = + ScrollToMarkerToolStripMenuItem.Enabled = + MarkerInputRoll.AnyRowsSelected; + } + + private void ScrollToMarkerToolStripMenuItem_Click(object sender, EventArgs e) + { + if (MarkerView.AnyRowsSelected) + { + TastudioMPR.SetVisibleFrame(FirstSelectedMarker.Frame); + TastudioMPR.RefreshDialog(); + } + } + + private void JumpToMarkerToolStripMenuItem_Click(object sender, EventArgs e) + { + if (MarkerView.AnyRowsSelected) TastudioMPR.GoToFrame(FirstSelectedMarker.Frame); + } + + private void EditMarkerToolStripMenuItem_Click(object sender, EventArgs e) + { + if (MarkerView.AnyRowsSelected) EditMarkerPopUp(FirstSelectedMarker); + } + + private void EditMarkerFrameToolStripMenuItem_Click(object sender, EventArgs e) + { + if (MarkerView.AnyRowsSelected) EditMarkerFramePopUp(FirstSelectedMarker); + } + + private void AddMarkerToolStripMenuItem_Click(object sender, EventArgs e) + { + AddMarker(TastudioMPR.Emulator.Frame); + } + + private void AddMarkerWithTextToolStripMenuItem_Click(object sender, EventArgs e) + { + AddMarker(TastudioMPR.Emulator.Frame, true); + } + + private void RemoveMarkerToolStripMenuItem_Click(object sender, EventArgs e) + { + if (!MarkerView.AnyRowsSelected) return; + foreach (var i in MarkerView.SelectedRows.Select(index => Markers[index]).ToList()) Markers.Remove(i); + MarkerView.RowCount = Markers.Count; + TastudioMPR.RefreshDialog(); + } + + public void UpdateMarkerCount() + { + MarkerView.RowCount = Markers.Count; + } + + public void AddMarker(int frame, bool editText = false) + { + TasMovieMarker marker; + if (editText) + { + var i = new InputPrompt + { + Text = $"Marker for frame {frame}", + TextInputType = InputPrompt.InputType.Text, + Message = "Enter a message", + InitialValue = + Markers.IsMarker(frame) ? + Markers.PreviousOrCurrent(frame).Message : + "" + }; + + i.FollowMousePointer(); + if (!i.ShowDialogOnScreen().IsOk()) return; + + UpdateTextColumnWidth(); + marker = new TasMovieMarker(frame, i.PromptText); + } + else + { + marker = new TasMovieMarker(frame); + } + + UpdateValues(); + Markers.Add(marker); + var index = Markers.IndexOf(marker); + MarkerView.MakeIndexVisible(index); + TastudioMPR.RefreshDialog(); + } + + public void UpdateTextColumnWidth() + { + if (Markers.Count > 0) + { + var longestBranchText = Markers + .OrderBy(b => b.Message?.Length ?? 0) + .Last() + .Message; + + MarkerView.ExpandColumnToFitText("LabelColumn", longestBranchText); + } + } + + public void EditMarkerPopUp(TasMovieMarker marker) + { + var markerFrame = marker.Frame; + var i = new InputPrompt + { + Text = $"Marker for frame {markerFrame}", + TextInputType = InputPrompt.InputType.Text, + Message = "Enter a message", + InitialValue = + Markers.IsMarker(markerFrame) + ? Markers.PreviousOrCurrent(markerFrame).Message + : "" + }; + + i.FollowMousePointer(); + if (!i.ShowDialogOnScreen().IsOk()) return; + + marker.Message = i.PromptText; + UpdateTextColumnWidth(); + UpdateValues(); + } + + public void EditMarkerFramePopUp(TasMovieMarker marker) + { + var markerFrame = marker.Frame; + var i = new InputPrompt + { + Text = $"Marker for frame {markerFrame}", + TextInputType = InputPrompt.InputType.Unsigned, + Message = "Enter a frame number", + InitialValue = Markers.IsMarker(markerFrame) + ? Markers.PreviousOrCurrent(markerFrame).Frame.ToString() + : "0", + }; + + i.FollowMousePointer(); + if (!i.ShowDialogOnScreen().IsOk() + || !int.TryParse(i.PromptText, out var promptValue) + || Markers.IsMarker(promptValue)) // don't move to frame with an existing marker + { + return; + } + Markers.Move(marker.Frame, promptValue); + UpdateTextColumnWidth(); + UpdateValues(); + TastudioMPR.RefreshDialog(); + } + + public void UpdateValues() + { + if (MarkerView != null && TastudioMPR?.CurrentTasMovie != null && Markers != null) + { + MarkerView.RowCount = Markers.Count; + } + } + + public void Restart() + { + SetupColumns(); + MarkerView.RowCount = Markers.Count; + MarkerView.Refresh(); + } + + private void MarkerView_SelectedIndexChanged(object sender, EventArgs e) + { + EditMarkerButton.Enabled = + EditMarkerFrameButton.Enabled = + RemoveMarkerButton.Enabled = + MarkerInputRoll.AnyRowsSelected && MarkerView.FirstSelectedRowIndex is not 0; + + JumpToMarkerButton.Enabled = + ScrollToMarkerButton.Enabled = + MarkerInputRoll.AnyRowsSelected; + } + + // SuuperW: Marker renaming can be done with a right-click. + // A much more useful feature would be to easily jump to it. + private void MarkerView_MouseDoubleClick(object sender, EventArgs e) + { + if (MarkerView.AnyRowsSelected) TastudioMPR.GoToFrame(FirstSelectedMarker.Frame); + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/MarkerControlMPR.resx b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/MarkerControlMPR.resx new file mode 100644 index 00000000000..1e64cf29690 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/MarkerControlMPR.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 168, 17 + + + 168, 17 + + \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PatternsFormMPR.Designer.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PatternsFormMPR.Designer.cs new file mode 100644 index 00000000000..64b3e324946 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PatternsFormMPR.Designer.cs @@ -0,0 +1,202 @@ +namespace BizHawk.Client.EmuHawk +{ + partial class PatternsFormMPR + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.ButtonBox = new System.Windows.Forms.ComboBox(); + this.PatternList = new System.Windows.Forms.ListBox(); + this.InsertButton = new System.Windows.Forms.Button(); + this.DeleteButton = new System.Windows.Forms.Button(); + this.LagBox = new System.Windows.Forms.CheckBox(); + this.label1 = new BizHawk.WinForms.Controls.LocLabelEx(); + this.ValueNum = new System.Windows.Forms.NumericUpDown(); + this.CountNum = new System.Windows.Forms.NumericUpDown(); + this.label2 = new BizHawk.WinForms.Controls.LocLabelEx(); + this.OnOffBox = new System.Windows.Forms.CheckBox(); + ((System.ComponentModel.ISupportInitialize)(this.ValueNum)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.CountNum)).BeginInit(); + this.SuspendLayout(); + // + // ButtonBox + // + this.ButtonBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.ButtonBox.FormattingEnabled = true; + this.ButtonBox.Location = new System.Drawing.Point(12, 12); + this.ButtonBox.Name = "ButtonBox"; + this.ButtonBox.Size = new System.Drawing.Size(169, 21); + this.ButtonBox.TabIndex = 0; + this.ButtonBox.SelectedIndexChanged += new System.EventHandler(this.ButtonBox_SelectedIndexChanged); + // + // PatternList + // + this.PatternList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.PatternList.FormattingEnabled = true; + this.PatternList.Items.AddRange(new object[] { + "0: On\t(x1)", + "1: Off\t(x1)", + "Loop to 0"}); + this.PatternList.Location = new System.Drawing.Point(12, 39); + this.PatternList.Name = "PatternList"; + this.PatternList.Size = new System.Drawing.Size(169, 134); + this.PatternList.TabIndex = 1; + this.PatternList.SelectedIndexChanged += new System.EventHandler(this.PatternList_SelectedIndexChanged); + // + // InsertButton + // + this.InsertButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.InsertButton.Location = new System.Drawing.Point(12, 207); + this.InsertButton.Name = "InsertButton"; + this.InsertButton.Size = new System.Drawing.Size(57, 23); + this.InsertButton.TabIndex = 2; + this.InsertButton.Text = "Insert"; + this.InsertButton.UseVisualStyleBackColor = true; + this.InsertButton.Click += new System.EventHandler(this.InsertButton_Click); + // + // DeleteButton + // + this.DeleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.DeleteButton.Location = new System.Drawing.Point(124, 207); + this.DeleteButton.Name = "DeleteButton"; + this.DeleteButton.Size = new System.Drawing.Size(57, 23); + this.DeleteButton.TabIndex = 2; + this.DeleteButton.Text = "Delete"; + this.DeleteButton.UseVisualStyleBackColor = true; + this.DeleteButton.Click += new System.EventHandler(this.DeleteButton_Click); + // + // LagBox + // + this.LagBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.LagBox.AutoSize = true; + this.LagBox.Checked = true; + this.LagBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.LagBox.Location = new System.Drawing.Point(12, 236); + this.LagBox.Name = "LagBox"; + this.LagBox.Size = new System.Drawing.Size(132, 17); + this.LagBox.TabIndex = 3; + this.LagBox.Text = "Account for lag frames"; + this.LagBox.UseVisualStyleBackColor = true; + this.LagBox.CheckedChanged += new System.EventHandler(this.LagBox_CheckedChanged); + // + // label1 + // + this.label1.Location = new System.Drawing.Point(9, 181); + this.label1.Name = "label1"; + this.label1.Text = "Value:"; + // + // ValueNum + // + this.ValueNum.Location = new System.Drawing.Point(48, 179); + this.ValueNum.Maximum = new decimal(new int[] { + 10000, + 0, + 0, + 0}); + this.ValueNum.Minimum = new decimal(new int[] { + 10000, + 0, + 0, + -2147483648}); + this.ValueNum.Name = "ValueNum"; + this.ValueNum.Size = new System.Drawing.Size(51, 20); + this.ValueNum.TabIndex = 5; + this.ValueNum.Visible = false; + this.ValueNum.ValueChanged += new System.EventHandler(this.ValueNum_ValueChanged); + // + // CountNum + // + this.CountNum.Location = new System.Drawing.Point(143, 179); + this.CountNum.Name = "CountNum"; + this.CountNum.Size = new System.Drawing.Size(38, 20); + this.CountNum.TabIndex = 5; + this.CountNum.Value = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.CountNum.ValueChanged += new System.EventHandler(this.CountNum_ValueChanged); + // + // label2 + // + this.label2.Location = new System.Drawing.Point(103, 181); + this.label2.Name = "label2"; + this.label2.Text = "Count:"; + // + // OnOffBox + // + this.OnOffBox.AutoSize = true; + this.OnOffBox.Location = new System.Drawing.Point(48, 180); + this.OnOffBox.Name = "OnOffBox"; + this.OnOffBox.Size = new System.Drawing.Size(15, 14); + this.OnOffBox.TabIndex = 6; + this.OnOffBox.UseVisualStyleBackColor = true; + this.OnOffBox.CheckedChanged += new System.EventHandler(this.OnOffBox_CheckedChanged); + // + // PatternsForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(193, 258); + this.Controls.Add(this.OnOffBox); + this.Controls.Add(this.CountNum); + this.Controls.Add(this.ValueNum); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.LagBox); + this.Controls.Add(this.DeleteButton); + this.Controls.Add(this.InsertButton); + this.Controls.Add(this.PatternList); + this.Controls.Add(this.ButtonBox); + this.MaximizeBox = false; + this.MaximumSize = new System.Drawing.Size(209, 9999); + this.MinimizeBox = false; + this.MinimumSize = new System.Drawing.Size(209, 39); + this.Name = "PatternsForm"; + this.Text = "Patterns Options"; + this.Load += new System.EventHandler(this.PatternsForm_Load); + ((System.ComponentModel.ISupportInitialize)(this.ValueNum)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.CountNum)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ComboBox ButtonBox; + private System.Windows.Forms.ListBox PatternList; + private System.Windows.Forms.Button InsertButton; + private System.Windows.Forms.Button DeleteButton; + private System.Windows.Forms.CheckBox LagBox; + private BizHawk.WinForms.Controls.LocLabelEx label1; + private System.Windows.Forms.NumericUpDown ValueNum; + private System.Windows.Forms.NumericUpDown CountNum; + private BizHawk.WinForms.Controls.LocLabelEx label2; + private System.Windows.Forms.CheckBox OnOffBox; + } +} \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PatternsFormMPR.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PatternsFormMPR.cs new file mode 100644 index 00000000000..1b6bcf93ed7 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PatternsFormMPR.cs @@ -0,0 +1,310 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Windows.Forms; + +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public partial class PatternsFormMPR : Form + { + private readonly TAStudioMPR _tastudio; + + private readonly List _counts = new List(); + private readonly List _values = new List(); + private int _loopAt; + private bool _updating; + + private string SelectedButton => ButtonBox.Text; + + private bool IsBool => _tastudio.MovieSession.MovieController.Definition.BoolButtons.Contains(SelectedButton); + + public PatternsFormMPR(TAStudioMPR owner) + { + InitializeComponent(); + _tastudio = owner; + + foreach (var button in _tastudio.MovieSession.MovieController.Definition.BoolButtons) + { + ButtonBox.Items.Add(button); + } + + foreach (var button in _tastudio.MovieSession.MovieController.Definition.Axes.Keys) + { + ButtonBox.Items.Add(button); + } + } + + private void PatternsForm_Load(object sender, EventArgs e) + { + ButtonBox.SelectedIndex = 0; + } + + private void ButtonBox_SelectedIndexChanged(object sender, EventArgs e) + { + GetPattern(); + UpdateDisplay(); + + if (IsBool) + { + OnOffBox.Visible = true; + ValueNum.Visible = false; + } + else + { + ValueNum.Visible = true; + OnOffBox.Visible = false; + } + + CountNum.Value = _counts[0]; + } + + private void PatternList_SelectedIndexChanged(object sender, EventArgs e) + { + if (!_updating) + { + UpdateDisplay(); + } + } + + private void InsertButton_Click(object sender, EventArgs e) + { + _counts.Insert(PatternList.SelectedIndex, 1); + string defaultStr = "false"; + if (!IsBool) + { + defaultStr = _tastudio.MovieSession.MovieController.Definition.Axes[SelectedButton].Neutral.ToString(); + } + + _values.Insert(PatternList.SelectedIndex, defaultStr); + + UpdatePattern(); + UpdateDisplay(); + } + + private void DeleteButton_Click(object sender, EventArgs e) + { + if (PatternList.SelectedIndex >= _counts.Count) + { + return; + } + _counts.RemoveAt(PatternList.SelectedIndex); + _values.RemoveAt(PatternList.SelectedIndex); + UpdatePattern(); + UpdateDisplay(); + } + + private void LagBox_CheckedChanged(object sender, EventArgs e) + { + UpdatePattern(); + } + + private void ValueNum_ValueChanged(object sender, EventArgs e) + { + if (_updating || PatternList.SelectedIndex == -1 || PatternList.SelectedIndex >= _counts.Count) + { + return; + } + + _values[PatternList.SelectedIndex] = ((int) ValueNum.Value).ToString(NumberFormatInfo.InvariantInfo); + UpdatePattern(); + UpdateDisplay(); + } + + private void OnOffBox_CheckedChanged(object sender, EventArgs e) + { + if (_updating || PatternList.SelectedIndex == -1 || PatternList.SelectedIndex >= _counts.Count) + { + return; + } + + _values[PatternList.SelectedIndex] = OnOffBox.Checked.ToString(); + UpdatePattern(); + UpdateDisplay(); + } + + private void CountNum_ValueChanged(object sender, EventArgs e) + { + if (_updating || PatternList.SelectedIndex == -1 || PatternList.SelectedIndex > _counts.Count) + { + return; + } + + if (PatternList.SelectedIndex == _counts.Count) + { + _loopAt = (int)CountNum.Value; + } + else + { + // repeating zero times is not allowed + if ((int)CountNum.Value == 0) + { + CountNum.Value = 1; + } + + _counts[PatternList.SelectedIndex] = (int)CountNum.Value; + } + + UpdatePattern(); + UpdateDisplay(); + } + + private void UpdateDisplay() + { + _updating = true; + PatternList.SuspendLayout(); + + int oldIndex = PatternList.SelectedIndex; + if (oldIndex == -1) + { + oldIndex = 0; + } + + PatternList.Items.Clear(); + int index = 0; + for (int i = 0; i < _counts.Count; i++) + { + string str = $"{index}: "; + if (IsBool) + { + str += _values[i][0] == 'T' ? "On" : "Off"; + } + else + { + str += _values[i]; + } + + PatternList.Items.Add($"{str}\t(x{_counts[i]})"); + index += _counts[i]; + } + + PatternList.Items.Add($"Loop to: {_loopAt}"); + + if (oldIndex >= PatternList.Items.Count) + { + oldIndex = PatternList.Items.Count - 1; + } + + PatternList.SelectedIndex = oldIndex; + + if (PatternList.SelectedIndex != -1 && PatternList.SelectedIndex < _values.Count) + { + index = _tastudio.MovieSession.MovieController.Definition.BoolButtons.IndexOf(SelectedButton); + + if (index != -1) + { + LagBox.Checked = _tastudio.BoolPatterns[index].SkipsLag; + OnOffBox.Checked = _values[PatternList.SelectedIndex][0] == 'T'; + CountNum.Value = _counts[PatternList.SelectedIndex]; + } + else + { + index = _tastudio.MovieSession.MovieController.Definition.Axes.IndexOf(SelectedButton); + + LagBox.Checked = _tastudio.AxisPatterns[index].SkipsLag; + ValueNum.Value = int.Parse(_values[PatternList.SelectedIndex]); + CountNum.Value = _counts[PatternList.SelectedIndex]; + } + } + else if (PatternList.SelectedIndex == _values.Count) + { + CountNum.Value = _loopAt; + } + + PatternList.ResumeLayout(); + _updating = false; + } + + private void UpdatePattern() + { + int index = _tastudio.MovieSession.MovieController.Definition.BoolButtons.IndexOf(SelectedButton); + + if (index != -1) + { + var p = new List(); + for (int i = 0; i < _counts.Count; i++) + { + for (int c = 0; c < _counts[i]; c++) + { + p.Add(Convert.ToBoolean(_values[i])); + } + } + + _tastudio.BoolPatterns[index] = new AutoPatternBool(p.ToArray(), LagBox.Checked, 0, _loopAt); + } + else + { + index = _tastudio.MovieSession.MovieController.Definition.Axes.IndexOf(SelectedButton); + + var p = new List(); + for (int i = 0; i < _counts.Count; i++) + { + for (int c = 0; c < _counts[i]; c++) + { + p.Add(int.Parse(_values[i])); + } + } + + _tastudio.AxisPatterns[index] = new AutoPatternAxis(p.ToArray(), LagBox.Checked, 0, _loopAt); + } + + _tastudio.UpdateAutoFire(SelectedButton, null); + } + + private void GetPattern() + { + int index = _tastudio.MovieSession.MovieController.Definition.BoolButtons.IndexOf(SelectedButton); + + if (index != -1) + { + bool[] p = _tastudio.BoolPatterns[index].Pattern; + bool lastValue = p[0]; + _counts.Clear(); + _values.Clear(); + _counts.Add(1); + _values.Add(lastValue.ToString()); + for (int i = 1; i < p.Length; i++) + { + if (p[i] == lastValue) + { + _counts[_counts.Count - 1]++; + } + else + { + _counts.Add(1); + _values.Add(p[i].ToString()); + lastValue = p[i]; + } + } + + _loopAt = _tastudio.BoolPatterns[index].Loop; + } + else + { + index = _tastudio.MovieSession.MovieController.Definition.Axes.IndexOf(SelectedButton); + + var p = _tastudio.AxisPatterns[index].Pattern; + var lastValue = p[0]; + _counts.Clear(); + _values.Clear(); + _counts.Add(1); + _values.Add(lastValue.ToString()); + for (int i = 1; i < p.Length; i++) + { + if (p[i] == lastValue) + { + _counts[_counts.Count - 1]++; + } + else + { + _counts.Add(1); + _values.Add(p[i].ToString()); + lastValue = p[i]; + } + } + + _loopAt = _tastudio.AxisPatterns[index].Loop; + } + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PatternsFormMPR.resx b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PatternsFormMPR.resx new file mode 100644 index 00000000000..29dcb1b3a35 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PatternsFormMPR.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PlaybackBoxMPR.Designer.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PlaybackBoxMPR.Designer.cs new file mode 100644 index 00000000000..e2b16fe7f24 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PlaybackBoxMPR.Designer.cs @@ -0,0 +1,196 @@ +namespace BizHawk.Client.EmuHawk +{ + partial class PlaybackBoxMPR + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.PlaybackGroupBox = new System.Windows.Forms.GroupBox(); + this.RecordingModeCheckbox = new System.Windows.Forms.CheckBox(); + this.AutoRestoreCheckbox = new System.Windows.Forms.CheckBox(); + this.TurboSeekCheckbox = new System.Windows.Forms.CheckBox(); + this.FollowCursorCheckbox = new System.Windows.Forms.CheckBox(); + this.NextMarkerButton = new System.Windows.Forms.Button(); + this.FrameAdvanceButton = new BizHawk.Client.EmuHawk.RepeatButton(); + this.PauseButton = new System.Windows.Forms.Button(); + this.RewindButton = new BizHawk.Client.EmuHawk.RepeatButton(); + this.PreviousMarkerButton = new System.Windows.Forms.Button(); + this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); + this.PlaybackGroupBox.SuspendLayout(); + this.SuspendLayout(); + // + // PlaybackGroupBox + // + this.PlaybackGroupBox.Controls.Add(this.RecordingModeCheckbox); + this.PlaybackGroupBox.Controls.Add(this.AutoRestoreCheckbox); + this.PlaybackGroupBox.Controls.Add(this.TurboSeekCheckbox); + this.PlaybackGroupBox.Controls.Add(this.FollowCursorCheckbox); + this.PlaybackGroupBox.Controls.Add(this.NextMarkerButton); + this.PlaybackGroupBox.Controls.Add(this.FrameAdvanceButton); + this.PlaybackGroupBox.Controls.Add(this.PauseButton); + this.PlaybackGroupBox.Controls.Add(this.RewindButton); + this.PlaybackGroupBox.Controls.Add(this.PreviousMarkerButton); + this.PlaybackGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.PlaybackGroupBox.Location = new System.Drawing.Point(0, 0); + this.PlaybackGroupBox.Name = "PlaybackGroupBox"; + this.PlaybackGroupBox.Size = new System.Drawing.Size(198, 104); + this.PlaybackGroupBox.TabIndex = 0; + this.PlaybackGroupBox.TabStop = false; + this.PlaybackGroupBox.Text = "Playback"; + // + // RecordingModeCheckbox + // + this.RecordingModeCheckbox.AutoSize = true; + this.RecordingModeCheckbox.Location = new System.Drawing.Point(10, 85); + this.RecordingModeCheckbox.Name = "RecordingModeCheckbox"; + this.RecordingModeCheckbox.Size = new System.Drawing.Size(104, 17); + this.RecordingModeCheckbox.TabIndex = 9; + this.RecordingModeCheckbox.Text = "Recording mode"; + this.RecordingModeCheckbox.UseVisualStyleBackColor = true; + this.RecordingModeCheckbox.MouseClick += new System.Windows.Forms.MouseEventHandler(this.RecordingModeCheckbox_MouseClick); + // + // AutoRestoreCheckbox + // + this.AutoRestoreCheckbox.AutoSize = true; + this.AutoRestoreCheckbox.Location = new System.Drawing.Point(10, 64); + this.AutoRestoreCheckbox.Name = "AutoRestoreCheckbox"; + this.AutoRestoreCheckbox.Size = new System.Drawing.Size(141, 17); + this.AutoRestoreCheckbox.TabIndex = 8; + this.AutoRestoreCheckbox.Text = "Auto-restore last position"; + this.AutoRestoreCheckbox.UseVisualStyleBackColor = true; + this.AutoRestoreCheckbox.CheckedChanged += new System.EventHandler(this.AutoRestoreCheckbox_CheckedChanged); + // + // TurboSeekCheckbox + // + this.TurboSeekCheckbox.AutoSize = true; + this.TurboSeekCheckbox.Location = new System.Drawing.Point(117, 43); + this.TurboSeekCheckbox.Name = "TurboSeekCheckbox"; + this.TurboSeekCheckbox.Size = new System.Drawing.Size(80, 17); + this.TurboSeekCheckbox.TabIndex = 6; + this.TurboSeekCheckbox.Text = "Turbo seek"; + this.TurboSeekCheckbox.UseVisualStyleBackColor = true; + this.TurboSeekCheckbox.CheckedChanged += new System.EventHandler(this.TurboSeekCheckbox_CheckedChanged); + // + // FollowCursorCheckbox + // + this.FollowCursorCheckbox.AutoSize = true; + this.FollowCursorCheckbox.Location = new System.Drawing.Point(10, 43); + this.FollowCursorCheckbox.Name = "FollowCursorCheckbox"; + this.FollowCursorCheckbox.Size = new System.Drawing.Size(89, 17); + this.FollowCursorCheckbox.TabIndex = 5; + this.FollowCursorCheckbox.Text = "Follow Cursor"; + this.FollowCursorCheckbox.UseVisualStyleBackColor = true; + this.FollowCursorCheckbox.CheckedChanged += new System.EventHandler(this.FollowCursorCheckbox_CheckedChanged); + // + // NextMarkerButton + // + this.NextMarkerButton.Location = new System.Drawing.Point(154, 17); + this.NextMarkerButton.Name = "NextMarkerButton"; + this.NextMarkerButton.Size = new System.Drawing.Size(38, 23); + this.NextMarkerButton.TabIndex = 4; + this.NextMarkerButton.Text = ">>"; + this.NextMarkerButton.UseVisualStyleBackColor = true; + this.NextMarkerButton.Click += new System.EventHandler(this.NextMarkerButton_Click); + // + // FrameAdvanceButton + // + this.FrameAdvanceButton.InitialDelay = 500; + this.FrameAdvanceButton.Location = new System.Drawing.Point(117, 17); + this.FrameAdvanceButton.Name = "FrameAdvanceButton"; + this.FrameAdvanceButton.RepeatDelay = 50; + this.FrameAdvanceButton.Size = new System.Drawing.Size(38, 23); + this.FrameAdvanceButton.TabIndex = 3; + this.FrameAdvanceButton.Text = ">"; + this.toolTip1.SetToolTip(this.FrameAdvanceButton, "Right Mouse Button + Wheel Down"); + this.FrameAdvanceButton.UseVisualStyleBackColor = true; + this.FrameAdvanceButton.MouseDown += new System.Windows.Forms.MouseEventHandler(this.FrameAdvanceButton_MouseDown); + this.FrameAdvanceButton.MouseLeave += new System.EventHandler(this.FrameAdvanceButton_MouseLeave); + this.FrameAdvanceButton.MouseUp += new System.Windows.Forms.MouseEventHandler(this.FrameAdvanceButton_MouseUp); + // + // PauseButton + // + this.PauseButton.Location = new System.Drawing.Point(80, 17); + this.PauseButton.Name = "PauseButton"; + this.PauseButton.Size = new System.Drawing.Size(38, 23); + this.PauseButton.TabIndex = 2; + this.PauseButton.Text = "> ||"; + this.toolTip1.SetToolTip(this.PauseButton, "Middle Mouse Button"); + this.PauseButton.UseVisualStyleBackColor = true; + this.PauseButton.Click += new System.EventHandler(this.PauseButton_Click); + // + // RewindButton + // + this.RewindButton.InitialDelay = 1000; + this.RewindButton.Location = new System.Drawing.Point(43, 17); + this.RewindButton.Name = "RewindButton"; + this.RewindButton.RepeatDelay = 100; + this.RewindButton.Size = new System.Drawing.Size(38, 23); + this.RewindButton.TabIndex = 1; + this.RewindButton.Text = "<"; + this.toolTip1.SetToolTip(this.RewindButton, "Right Mouse Button + Wheel Up"); + this.RewindButton.UseVisualStyleBackColor = true; + this.RewindButton.MouseDown += new System.Windows.Forms.MouseEventHandler(this.RewindButton_MouseDown); + this.RewindButton.MouseLeave += new System.EventHandler(this.RewindButton_MouseLeave); + this.RewindButton.MouseUp += new System.Windows.Forms.MouseEventHandler(this.RewindButton_MouseUp); + // + // PreviousMarkerButton + // + this.PreviousMarkerButton.Location = new System.Drawing.Point(6, 17); + this.PreviousMarkerButton.Name = "PreviousMarkerButton"; + this.PreviousMarkerButton.Size = new System.Drawing.Size(38, 23); + this.PreviousMarkerButton.TabIndex = 0; + this.PreviousMarkerButton.Text = "<<"; + this.PreviousMarkerButton.UseVisualStyleBackColor = true; + this.PreviousMarkerButton.Click += new System.EventHandler(this.PreviousMarkerButton_Click); + // + // PlaybackBox + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit; + this.Controls.Add(this.PlaybackGroupBox); + this.Name = "PlaybackBox"; + this.Size = new System.Drawing.Size(198, 104); + this.PlaybackGroupBox.ResumeLayout(false); + this.PlaybackGroupBox.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.GroupBox PlaybackGroupBox; + private System.Windows.Forms.Button NextMarkerButton; + private RepeatButton FrameAdvanceButton; + private System.Windows.Forms.Button PauseButton; + private RepeatButton RewindButton; + private System.Windows.Forms.Button PreviousMarkerButton; + private System.Windows.Forms.CheckBox AutoRestoreCheckbox; + private System.Windows.Forms.CheckBox TurboSeekCheckbox; + private System.Windows.Forms.CheckBox FollowCursorCheckbox; + private System.Windows.Forms.CheckBox RecordingModeCheckbox; + private System.Windows.Forms.ToolTip toolTip1; + } +} \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PlaybackBoxMPR.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PlaybackBoxMPR.cs new file mode 100644 index 00000000000..0461f54f5d2 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PlaybackBoxMPR.cs @@ -0,0 +1,155 @@ +using System.ComponentModel; +using System.Windows.Forms; + +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public partial class PlaybackBoxMPR : UserControl + { + private bool _loading = true; + + public TAStudioMPR TastudioMPR { get; set; } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool TurboSeek + { + get => TastudioMPR.Config.TurboSeek; + set => TurboSeekCheckbox.Checked = value; + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool AutoRestore + { + get => TastudioMPR.Settings.AutoRestoreLastPosition; + set => AutoRestoreCheckbox.Checked = value; + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool FollowCursor + { + get => TastudioMPR.Settings.FollowCursor; + set => FollowCursorCheckbox.Checked = value; + } + + [Browsable(true)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool RecordingMode + { + get => TastudioMPR.CurrentTasMovie.IsRecording(); + set + { + RecordingModeCheckbox.Checked = value; + TastudioMPR.MovieSession.ReadOnly = !value; + if (RecordingModeCheckbox.Checked) + { + TastudioMPR.CurrentTasMovie.SwitchToRecord(); + } + else + { + TastudioMPR.CurrentTasMovie.SwitchToPlay(); + } + + TastudioMPR.MainForm.SetMainformMovieInfo(); + } + } + + public PlaybackBoxMPR() + { + InitializeComponent(); + } + + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + if (DesignMode) + { + return; + } + + TurboSeekCheckbox.Checked = TastudioMPR.Config?.TurboSeek ?? false; + AutoRestoreCheckbox.Checked = TastudioMPR.Settings.AutoRestoreLastPosition; + FollowCursorCheckbox.Checked = TastudioMPR.Settings.FollowCursor; + RecordingModeCheckbox.Checked = RecordingMode; + + _loading = false; + } + + private void PreviousMarkerButton_Click(object sender, EventArgs e) + { + TastudioMPR.GoToPreviousMarker(); + } + + private void PauseButton_Click(object sender, EventArgs e) + { + TastudioMPR.TogglePause(); + } + + private void NextMarkerButton_Click(object sender, EventArgs e) + { + TastudioMPR.GoToNextMarker(); + } + + private void TurboSeekCheckbox_CheckedChanged(object sender, EventArgs e) + { + if (!_loading) TastudioMPR.Config.TurboSeek = !TastudioMPR.Config.TurboSeek; + } + + private void AutoRestoreCheckbox_CheckedChanged(object sender, EventArgs e) + { + if (!_loading) TastudioMPR.Settings.AutoRestoreLastPosition = !TastudioMPR.Settings.AutoRestoreLastPosition; + } + + private void FollowCursorCheckbox_CheckedChanged(object sender, EventArgs e) + { + if (!_loading) + { + TastudioMPR.Settings.FollowCursor = !TastudioMPR.Settings.FollowCursor; + if (TastudioMPR.Settings.FollowCursor) + { + TastudioMPR.SetVisibleFrame(); + TastudioMPR.RefreshDialog(); + } + } + } + + private void RecordingModeCheckbox_MouseClick(object sender, MouseEventArgs e) + { + RecordingMode = !RecordingMode; + TastudioMPR.WasRecording = RecordingMode; // hard reset at manual click and hotkey + } + + private void RewindButton_MouseDown(object sender, MouseEventArgs e) + { + TastudioMPR.MainForm.PressRewind = true; + } + + private void RewindButton_MouseUp(object sender, MouseEventArgs e) + { + TastudioMPR.MainForm.PressRewind = false; + } + + private void RewindButton_MouseLeave(object sender, EventArgs e) + { + TastudioMPR.MainForm.PressRewind = false; + } + + private void FrameAdvanceButton_MouseDown(object sender, MouseEventArgs e) + { + TastudioMPR.MainForm.HoldFrameAdvance = true; + } + + private void FrameAdvanceButton_MouseLeave(object sender, EventArgs e) + { + TastudioMPR.MainForm.HoldFrameAdvance = false; + } + + private void FrameAdvanceButton_MouseUp(object sender, MouseEventArgs e) + { + TastudioMPR.MainForm.HoldFrameAdvance = false; + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PlaybackBoxMPR.resx b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PlaybackBoxMPR.resx new file mode 100644 index 00000000000..65a871b69cb --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/PlaybackBoxMPR.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioColorSettingsFormMPR.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioColorSettingsFormMPR.cs new file mode 100644 index 00000000000..f0426c75beb --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioColorSettingsFormMPR.cs @@ -0,0 +1,103 @@ +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +using BizHawk.WinForms.Controls; + +namespace BizHawk.Client.EmuHawk +{ + public sealed class TAStudioColorSettingsFormMPR : Form + { + public TAStudioColorSettingsFormMPR(TAStudioPaletteMPR initPalette, Action save) + { + Dictionary colours = new(); + void Init(TAStudioPaletteMPR fromPalette) + { +// colours["currentFrame_FrameCol"] = fromPalette.CurrentFrame_FrameCol; + colours["currentFrame_InputLog"] = fromPalette.CurrentFrame_InputLog; + colours["greenZone_FrameCol"] = fromPalette.GreenZone_FrameCol; + colours["greenZone_InputLog"] = fromPalette.GreenZone_InputLog; + colours["greenZone_InputLog_Stated"] = fromPalette.GreenZone_InputLog_Stated; + colours["greenZone_InputLog_Invalidated"] = fromPalette.GreenZone_InputLog_Invalidated; + colours["lagZone_FrameCol"] = fromPalette.LagZone_FrameCol; + colours["lagZone_InputLog"] = fromPalette.LagZone_InputLog; + colours["lagZone_InputLog_Stated"] = fromPalette.LagZone_InputLog_Stated; + colours["lagZone_InputLog_Invalidated"] = fromPalette.LagZone_InputLog_Invalidated; + colours["marker_FrameCol"] = fromPalette.Marker_FrameCol; + colours["analogEdit_Col"] = fromPalette.AnalogEdit_Col; + } + Init(initPalette); + + ColorDialog picker = new() { FullOpen = true }; + Size panelSize = new(20, 20); + SingleRowFLP Row(string key, string labelText) // can't use ref here because those aren't captured in closures :( + { + Panel panel = new() { BackColor = colours[key], BorderStyle = BorderStyle.FixedSingle, Size = panelSize, Tag = key }; + panel.Click += (_, _) => + { + picker.Color = colours[key]; + if (picker.ShowDialog().IsOk()) panel.BackColor = colours[key] = picker.Color; + }; + return new() { Controls = { panel, new LabelEx { Text = labelText } } }; + } + SingleColumnFLP flpPanels = new() + { + Controls = + { +// Row("currentFrame_FrameCol", "CurrentFrame: FrameCol"), + Row("currentFrame_InputLog", "Emulated Frame Cursor"), + Row("greenZone_FrameCol", "Frame# Column"), + Row("greenZone_InputLog", "Input Log"), + Row("greenZone_InputLog_Stated", "Savestate"), + Row("greenZone_InputLog_Invalidated", "Invalidated"), + Row("lagZone_FrameCol", "Frame# Column (Lag)"), + Row("lagZone_InputLog", "Input Log (Lag)"), + Row("lagZone_InputLog_Stated", "Savestate (Lag)"), + Row("lagZone_InputLog_Invalidated", "Invalidated (Lag)"), + Row("marker_FrameCol", "Marker"), + Row("analogEdit_Col", "Analog Edit Mode"), + }, + }; + + Size btnSize = new(75, 23); + SzButtonEx btnOK = new() { Size = btnSize, Text = "OK" }; + btnOK.Click += (_, _) => + { + save(new( +// currentFrame_FrameCol: colours["currentFrame_FrameCol"], + currentFrame_InputLog: colours["currentFrame_InputLog"], + greenZone_FrameCol: colours["greenZone_FrameCol"], + greenZone_InputLog: colours["greenZone_InputLog"], + greenZone_InputLog_Stated: colours["greenZone_InputLog_Stated"], + greenZone_InputLog_Invalidated: colours["greenZone_InputLog_Invalidated"], + lagZone_FrameCol: colours["lagZone_FrameCol"], + lagZone_InputLog: colours["lagZone_InputLog"], + lagZone_InputLog_Stated: colours["lagZone_InputLog_Stated"], + lagZone_InputLog_Invalidated: colours["lagZone_InputLog_Invalidated"], + marker_FrameCol: colours["marker_FrameCol"], + analogEdit_Col: colours["analogEdit_Col"])); + Close(); + }; + SzButtonEx btnCancel = new() { Size = btnSize, Text = "Cancel" }; + btnCancel.Click += (_, _) => Close(); + SzButtonEx btnDefaults = new() { Size = btnSize, Text = "Defaults" }; + btnDefaults.Click += (_, _) => + { + Init(TAStudioPaletteMPR.Default); + foreach (var panel in flpPanels.Controls.Cast().Select(flp => (Panel)flp.Controls[0])) + { + panel.BackColor = colours[(string) panel.Tag]; + } + }; + SingleRowFLP flpButtons = new() { Controls = { btnOK, btnCancel, btnDefaults } }; + ((FlowLayoutPanel) flpButtons).FlowDirection = FlowDirection.RightToLeft; // why did I disable this + + SuspendLayout(); + ClientSize = new(240, 320); + Text = "Edit TAStudio Colors"; + Controls.Add(new SingleColumnFLP { Controls = { flpButtons, flpPanels } }); + ResumeLayout(); + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.Callbacks.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.Callbacks.cs new file mode 100644 index 00000000000..26a3dd17558 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.Callbacks.cs @@ -0,0 +1,37 @@ +using System.Drawing; + +namespace BizHawk.Client.EmuHawk +{ + public partial class TAStudioMPR + { + // Everything here is currently for Lua + public Func QueryItemBgColorCallback { get; set; } + public Func QueryItemTextCallback { get; set; } + public Func QueryItemIconCallback { get; set; } + + public Action GreenzoneInvalidatedCallback { get; set; } + public Action BranchLoadedCallback { get; set; } + public Action BranchSavedCallback { get; set; } + public Action BranchRemovedCallback { get; set; } + + private void GreenzoneInvalidated(int index) + { + GreenzoneInvalidatedCallback?.Invoke(index); + } + + private void BranchLoaded(int index) + { + BranchLoadedCallback?.Invoke(index); + } + + private void BranchSaved(int index) + { + BranchSavedCallback?.Invoke(index); + } + + private void BranchRemoved(int index) + { + BranchRemovedCallback?.Invoke(index); + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.Designer.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.Designer.cs new file mode 100644 index 00000000000..da0dc339839 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.Designer.cs @@ -0,0 +1,1383 @@ +using BizHawk.WinForms.Controls; + +namespace BizHawk.Client.EmuHawk +{ + partial class TAStudioMPR + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.TASMenu = new BizHawk.WinForms.Controls.MenuStripEx(); + this.FileSubMenu = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.NewTASMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.NewFromSubMenu = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.NewFromNowMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.NewFromCurrentSaveRamMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.OpenTASMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SaveTASMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SaveAsTASMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SaveBackupMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SaveBk2BackupMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.RecentSubMenu = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator3 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.toolStripSeparator1 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.saveSelectionToMacroToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.placeMacroAtSelectionToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.recentMacrosToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator22 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.toolStripSeparator20 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.ToBk2MenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.EditSubMenu = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.UndoMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.RedoMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.showUndoHistoryToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SelectionUndoMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SelectionRedoMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator5 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.DeselectMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SelectBetweenMarkersMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SelectAllMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.ReselectClipboardMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator7 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.CopyMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.PasteMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.PasteInsertMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.CutMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator8 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.ClearFramesMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.DeleteFramesMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.InsertFrameMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.InsertNumFramesMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.CloneFramesMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.CloneFramesXTimesMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator6 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.TruncateMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.ClearGreenzoneMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.GreenzoneICheckSeparator = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.StateHistoryIntegrityCheckMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.ConfigSubMenu = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SetMaxUndoLevelsMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.CopyIncludesFrameNoMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator26 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.autosaveToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SetAutosaveIntervalMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.AutosaveAsBk2MenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.AutosaveAsBackupFileMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.BackupPerFileSaveMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator9 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.AutoadjustInputMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.applyPatternToPaintedInputToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.onlyOnAutoFireColumnsToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SingleClickAxisEditMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.UseInputKeysItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator4 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.BindMarkersToInputMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.OldControlSchemeForBranchesMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.LoadBranchOnDoubleclickMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.OsdInBranchScreenshotsMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator14 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.AutopauseAtEndOfMovieMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.sepToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.autoHoldFireToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.keepSetPatternsToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.sepToolStripMenuItem1 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.autoHoldToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.autoFireToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.customPatternToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.setpToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.setCustomsToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SetFontMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.disableTasViewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.MetaSubMenu = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.HeaderMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.StateHistorySettingsMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.CommentsMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SubtitlesMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator21 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.DefaultStateSettingsMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SettingsSubMenu = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.RotateMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.HideLagFramesSubMenu = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.HideLagFrames0 = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.HideLagFrames1 = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.HideLagFrames2 = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.HideLagFrames3 = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator12 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.hideWasLagFramesToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.iconsToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.DenoteStatesWithIconsToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.DenoteStatesWithBGColorToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.DenoteMarkersWithIconsToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.DenoteMarkersWithBGColorToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.ColorSettingsMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator23 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.followCursorToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.alwaysScrollToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator24 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.scrollToViewToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.scrollToTopToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.scrollToBottomToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.scrollToCenterToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator25 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.wheelScrollSpeedToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.ColumnsSubMenu = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator19 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.HelpSubMenu = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.TASEditorManualOnlineMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.ForumThreadMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.aboutToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator10 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.EnableTooltipsMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.TasView1 = new BizHawk.Client.EmuHawk.InputRoll(); + this.TasStatusStrip = new BizHawk.WinForms.Controls.StatusStripEx(); + this.MessageStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this.ProgressBar = new System.Windows.Forms.ToolStripProgressBar(); + this.toolStripStatusLabel2 = new System.Windows.Forms.ToolStripStatusLabel(); + this.SplicerStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this.TasPlaybackBoxMPR = new BizHawk.Client.EmuHawk.PlaybackBoxMPR(); + this.MarkerControlMPR = new BizHawk.Client.EmuHawk.MarkerControlMPR(); + this.RightClickMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.SetMarkersContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SetMarkerWithTextContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.RemoveMarkersContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator15 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.DeselectContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.SelectBetweenMarkersContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator16 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.UngreenzoneContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.CancelSeekContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator17 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.copyToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.pasteToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.pasteInsertToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.cutToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.separateToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.ClearContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.DeleteFramesContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.InsertFrameContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.InsertNumFramesContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.CloneContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.CloneXTimesContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.toolStripSeparator18 = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.TruncateContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.BranchContextMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.StartFromNowSeparator = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.StartNewProjectFromNowMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.StartANewProjectFromSaveRamMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.pasteSelectedRowsFromToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.BookMarkControlMPR = new BizHawk.Client.EmuHawk.BookmarksBranchesBoxMPR(); + this.BranchesMarkersSplit = new System.Windows.Forms.SplitContainer(); + this.MainVertialSplit = new System.Windows.Forms.SplitContainer(); + this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); + this.TASMenu.SuspendLayout(); + this.TasStatusStrip.SuspendLayout(); + this.RightClickMenu.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.BranchesMarkersSplit)).BeginInit(); + this.BranchesMarkersSplit.Panel1.SuspendLayout(); + this.BranchesMarkersSplit.Panel2.SuspendLayout(); + this.BranchesMarkersSplit.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.MainVertialSplit)).BeginInit(); + this.MainVertialSplit.Panel1.SuspendLayout(); + this.MainVertialSplit.Panel2.SuspendLayout(); + this.MainVertialSplit.SuspendLayout(); + this.SuspendLayout(); + // + // TASMenu + // + this.TASMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.FileSubMenu, + this.EditSubMenu, + this.ConfigSubMenu, + this.MetaSubMenu, + this.SettingsSubMenu, + this.ColumnsSubMenu, + this.HelpSubMenu}); + this.TASMenu.TabIndex = 0; + this.TASMenu.MenuActivate += new System.EventHandler(this.TASMenu_MenuActivate); + this.TASMenu.MenuDeactivate += new System.EventHandler(this.TASMenu_MenuDeactivate); + // + // FileSubMenu + // + this.FileSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.NewTASMenuItem, + this.NewFromSubMenu, + this.OpenTASMenuItem, + this.SaveTASMenuItem, + this.SaveAsTASMenuItem, + this.SaveBackupMenuItem, + this.SaveBk2BackupMenuItem, + this.RecentSubMenu, + this.toolStripSeparator1, + this.saveSelectionToMacroToolStripMenuItem, + this.placeMacroAtSelectionToolStripMenuItem, + this.recentMacrosToolStripMenuItem, + this.toolStripSeparator20, + this.ToBk2MenuItem}); + this.FileSubMenu.Text = "&File"; + this.FileSubMenu.DropDownOpened += new System.EventHandler(this.FileSubMenu_DropDownOpened); + // + // NewTASMenuItem + // + this.NewTASMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.N))); + this.NewTASMenuItem.Text = "&New"; + this.NewTASMenuItem.Click += new System.EventHandler(this.NewTasMenuItem_Click); + // + // NewFromSubMenu + // + this.NewFromSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.NewFromNowMenuItem, + this.NewFromCurrentSaveRamMenuItem}); + this.NewFromSubMenu.Text = "New From"; + this.NewFromSubMenu.DropDownOpened += new System.EventHandler(this.NewFromSubMenu_DropDownOpened); + // + // NewFromNowMenuItem + // + this.NewFromNowMenuItem.Text = "&Now"; + this.NewFromNowMenuItem.Click += new System.EventHandler(this.StartNewProjectFromNowMenuItem_Click); + // + // NewFromCurrentSaveRamMenuItem + // + this.NewFromCurrentSaveRamMenuItem.Text = "&Current SaveRam"; + this.NewFromCurrentSaveRamMenuItem.Click += new System.EventHandler(this.StartANewProjectFromSaveRamMenuItem_Click); + // + // OpenTASMenuItem + // + this.OpenTASMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O))); + this.OpenTASMenuItem.Text = "&Open"; + this.OpenTASMenuItem.Click += new System.EventHandler(this.OpenTasMenuItem_Click); + // + // SaveTASMenuItem + // + this.SaveTASMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S))); + this.SaveTASMenuItem.Text = "&Save"; + this.SaveTASMenuItem.Click += new System.EventHandler(this.SaveTasMenuItem_Click); + // + // SaveAsTASMenuItem + // + this.SaveAsTASMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) + | System.Windows.Forms.Keys.S))); + this.SaveAsTASMenuItem.Text = "Save As"; + this.SaveAsTASMenuItem.Click += new System.EventHandler(this.SaveAsTasMenuItem_Click); + // + // SaveBackupMenuItem + // + this.SaveBackupMenuItem.Text = "Save Backup"; + this.SaveBackupMenuItem.Click += new System.EventHandler(this.SaveBackupMenuItem_Click); + // + // SaveBk2BackupMenuItem + // + this.SaveBk2BackupMenuItem.Text = "Save Bk2 Backup"; + this.SaveBk2BackupMenuItem.Click += new System.EventHandler(this.SaveBk2BackupMenuItem_Click); + // + // RecentSubMenu + // + this.RecentSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripSeparator3}); + this.RecentSubMenu.Text = "Recent"; + this.RecentSubMenu.DropDownOpened += new System.EventHandler(this.RecentSubMenu_DropDownOpened); + // + // saveSelectionToMacroToolStripMenuItem + // + this.saveSelectionToMacroToolStripMenuItem.Text = "Save Selection to Macro"; + this.saveSelectionToMacroToolStripMenuItem.Click += new System.EventHandler(this.SaveSelectionToMacroMenuItem_Click); + // + // placeMacroAtSelectionToolStripMenuItem + // + this.placeMacroAtSelectionToolStripMenuItem.Text = "Place Macro at Selection"; + this.placeMacroAtSelectionToolStripMenuItem.Click += new System.EventHandler(this.PlaceMacroAtSelectionMenuItem_Click); + // + // recentMacrosToolStripMenuItem + // + this.recentMacrosToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripSeparator22}); + this.recentMacrosToolStripMenuItem.Text = "Recent Macros"; + this.recentMacrosToolStripMenuItem.DropDownOpened += new System.EventHandler(this.RecentMacrosMenuItem_DropDownOpened); + // + // ToBk2MenuItem + // + this.ToBk2MenuItem.Text = "&Export to Bk2"; + this.ToBk2MenuItem.Click += new System.EventHandler(this.ToBk2MenuItem_Click); + // + // EditSubMenu + // + this.EditSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.UndoMenuItem, + this.RedoMenuItem, + this.showUndoHistoryToolStripMenuItem, + this.SelectionUndoMenuItem, + this.SelectionRedoMenuItem, + this.toolStripSeparator5, + this.DeselectMenuItem, + this.SelectBetweenMarkersMenuItem, + this.SelectAllMenuItem, + this.ReselectClipboardMenuItem, + this.toolStripSeparator7, + this.CopyMenuItem, + this.PasteMenuItem, + this.PasteInsertMenuItem, + this.CutMenuItem, + this.toolStripSeparator8, + this.ClearFramesMenuItem, + this.DeleteFramesMenuItem, + this.InsertFrameMenuItem, + this.InsertNumFramesMenuItem, + this.CloneFramesMenuItem, + this.CloneFramesXTimesMenuItem, + this.toolStripSeparator6, + this.TruncateMenuItem, + this.ClearGreenzoneMenuItem, + this.GreenzoneICheckSeparator, + this.StateHistoryIntegrityCheckMenuItem}); + this.EditSubMenu.Text = "&Edit"; + this.EditSubMenu.DropDownOpened += new System.EventHandler(this.EditSubMenu_DropDownOpened); + // + // UndoMenuItem + // + this.UndoMenuItem.Text = "&Undo"; + this.UndoMenuItem.Click += new System.EventHandler(this.UndoMenuItem_Click); + // + // RedoMenuItem + // + this.RedoMenuItem.Enabled = false; + this.RedoMenuItem.Text = "&Redo"; + this.RedoMenuItem.Click += new System.EventHandler(this.RedoMenuItem_Click); + // + // showUndoHistoryToolStripMenuItem + // + this.showUndoHistoryToolStripMenuItem.Text = "Show Undo History"; + this.showUndoHistoryToolStripMenuItem.Click += new System.EventHandler(this.ShowUndoHistoryMenuItem_Click); + // + // SelectionUndoMenuItem + // + this.SelectionUndoMenuItem.Enabled = false; + this.SelectionUndoMenuItem.Text = "Selection Undo"; + // + // SelectionRedoMenuItem + // + this.SelectionRedoMenuItem.Enabled = false; + this.SelectionRedoMenuItem.Text = "Selection Redo"; + // + // DeselectMenuItem + // + this.DeselectMenuItem.Text = "Deselect"; + this.DeselectMenuItem.Click += new System.EventHandler(this.DeselectMenuItem_Click); + // + // SelectBetweenMarkersMenuItem + // + this.SelectBetweenMarkersMenuItem.Text = "Select between Markers"; + this.SelectBetweenMarkersMenuItem.Click += new System.EventHandler(this.SelectBetweenMarkersMenuItem_Click); + // + // SelectAllMenuItem + // + this.SelectAllMenuItem.ShortcutKeyDisplayString = ""; + this.SelectAllMenuItem.Text = "Select &All"; + this.SelectAllMenuItem.Click += new System.EventHandler(this.SelectAllMenuItem_Click); + // + // ReselectClipboardMenuItem + // + this.ReselectClipboardMenuItem.Text = "Reselect Clipboard"; + this.ReselectClipboardMenuItem.Click += new System.EventHandler(this.ReselectClipboardMenuItem_Click); + // + // CopyMenuItem + // + this.CopyMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.C))); + this.CopyMenuItem.Text = "Copy"; + this.CopyMenuItem.Click += new System.EventHandler(this.CopyMenuItem_Click); + // + // PasteMenuItem + // + this.PasteMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.V))); + this.PasteMenuItem.Text = "&Paste"; + this.PasteMenuItem.Click += new System.EventHandler(this.PasteMenuItem_Click); + // + // PasteInsertMenuItem + // + this.PasteInsertMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) + | System.Windows.Forms.Keys.V))); + this.PasteInsertMenuItem.Text = "&Paste Insert"; + this.PasteInsertMenuItem.Click += new System.EventHandler(this.PasteInsertMenuItem_Click); + // + // CutMenuItem + // + this.CutMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.X))); + this.CutMenuItem.Text = "&Cut"; + this.CutMenuItem.Click += new System.EventHandler(this.CutMenuItem_Click); + // + // ClearFramesMenuItem + // + this.ClearFramesMenuItem.ShortcutKeyDisplayString = ""; + this.ClearFramesMenuItem.Text = "Clear"; + this.ClearFramesMenuItem.Click += new System.EventHandler(this.ClearFramesMenuItem_Click); + // + // DeleteFramesMenuItem + // + this.DeleteFramesMenuItem.Text = "&Delete"; + this.DeleteFramesMenuItem.Click += new System.EventHandler(this.DeleteFramesMenuItem_Click); + // + // InsertFrameMenuItem + // + this.InsertFrameMenuItem.Text = "&Insert"; + this.InsertFrameMenuItem.Click += new System.EventHandler(this.InsertFrameMenuItem_Click); + // + // InsertNumFramesMenuItem + // + this.InsertNumFramesMenuItem.ShortcutKeyDisplayString = ""; + this.InsertNumFramesMenuItem.Text = "Insert # of Frames"; + this.InsertNumFramesMenuItem.Click += new System.EventHandler(this.InsertNumFramesMenuItem_Click); + // + // CloneFramesMenuItem + // + this.CloneFramesMenuItem.Text = "&Clone"; + this.CloneFramesMenuItem.Click += new System.EventHandler(this.CloneFramesMenuItem_Click); + // + // CloneFramesXTimesMenuItem + // + this.CloneFramesXTimesMenuItem.Text = "Clone # Times"; + this.CloneFramesXTimesMenuItem.Click += new System.EventHandler(this.CloneFramesXTimesMenuItem_Click); + // + // TruncateMenuItem + // + this.TruncateMenuItem.Text = "&Truncate Movie"; + this.TruncateMenuItem.Click += new System.EventHandler(this.TruncateMenuItem_Click); + // + // ClearGreenzoneMenuItem + // + this.ClearGreenzoneMenuItem.Text = "&Clear Savestate History"; + this.ClearGreenzoneMenuItem.Click += new System.EventHandler(this.ClearGreenzoneMenuItem_Click); + // + // StateHistoryIntegrityCheckMenuItem + // + this.StateHistoryIntegrityCheckMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) + | System.Windows.Forms.Keys.I))); + this.StateHistoryIntegrityCheckMenuItem.Text = "State History Integrity Check"; + this.StateHistoryIntegrityCheckMenuItem.Click += new System.EventHandler(this.StateHistoryIntegrityCheckMenuItem_Click); + // + // ConfigSubMenu + // + this.ConfigSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.SetMaxUndoLevelsMenuItem, + this.CopyIncludesFrameNoMenuItem, + this.toolStripSeparator26, + this.autosaveToolStripMenuItem, + this.BackupPerFileSaveMenuItem, + this.toolStripSeparator9, + this.AutoadjustInputMenuItem, + this.applyPatternToPaintedInputToolStripMenuItem, + this.onlyOnAutoFireColumnsToolStripMenuItem, + this.SingleClickAxisEditMenuItem, + this.UseInputKeysItem, + this.toolStripSeparator4, + this.BindMarkersToInputMenuItem, + this.OldControlSchemeForBranchesMenuItem, + this.LoadBranchOnDoubleclickMenuItem, + this.OsdInBranchScreenshotsMenuItem, + this.toolStripSeparator14, + this.AutopauseAtEndOfMovieMenuItem, + this.sepToolStripMenuItem, + this.autoHoldFireToolStripMenuItem, + this.SetFontMenuItem, + this.disableTasViewToolStripMenuItem}); + this.ConfigSubMenu.Text = "&Config"; + this.ConfigSubMenu.DropDownOpened += new System.EventHandler(this.ConfigSubMenu_DropDownOpened); + // + // SetMaxUndoLevelsMenuItem + // + this.SetMaxUndoLevelsMenuItem.Text = "Set max Undo Levels"; + this.SetMaxUndoLevelsMenuItem.Click += new System.EventHandler(this.SetMaxUndoLevelsMenuItem_Click); + // + // CopyIncludesFrameNoMenuItem + // + this.CopyIncludesFrameNoMenuItem.Text = "Include Frame # When Copying Input"; + this.CopyIncludesFrameNoMenuItem.Click += new System.EventHandler(this.CopyIncludesFrameNoMenuItem_Click); + // + // autosaveToolStripMenuItem + // + this.autosaveToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.SetAutosaveIntervalMenuItem, + this.AutosaveAsBk2MenuItem, + this.AutosaveAsBackupFileMenuItem}); + this.autosaveToolStripMenuItem.Text = "Autosave"; + // + // SetAutosaveIntervalMenuItem + // + this.SetAutosaveIntervalMenuItem.Text = "Set Autosave Interval"; + this.SetAutosaveIntervalMenuItem.Click += new System.EventHandler(this.SetAutosaveIntervalMenuItem_Click); + // + // AutosaveAsBk2MenuItem + // + this.AutosaveAsBk2MenuItem.Text = "Autosave As Bk2"; + this.AutosaveAsBk2MenuItem.Click += new System.EventHandler(this.AutosaveAsBk2MenuItem_Click); + // + // AutosaveAsBackupFileMenuItem + // + this.AutosaveAsBackupFileMenuItem.Text = "Autosave As Backup File"; + this.AutosaveAsBackupFileMenuItem.Click += new System.EventHandler(this.AutosaveAsBackupFileMenuItem_Click); + // + // BackupPerFileSaveMenuItem + // + this.BackupPerFileSaveMenuItem.Text = "Backup Per File Save"; + this.BackupPerFileSaveMenuItem.Click += new System.EventHandler(this.BackupPerFileSaveMenuItem_Click); + // + // AutoadjustInputMenuItem + // + this.AutoadjustInputMenuItem.CheckOnClick = true; + this.AutoadjustInputMenuItem.Text = "Auto-adjust Input according to Lag"; + this.AutoadjustInputMenuItem.Click += new System.EventHandler(this.AutoadjustInputMenuItem_Click); + // + // applyPatternToPaintedInputToolStripMenuItem + // + this.applyPatternToPaintedInputToolStripMenuItem.CheckOnClick = true; + this.applyPatternToPaintedInputToolStripMenuItem.Text = "Apply Pattern to painted input"; + this.applyPatternToPaintedInputToolStripMenuItem.CheckedChanged += new System.EventHandler(this.ApplyPatternToPaintedInputMenuItem_CheckedChanged); + // + // onlyOnAutoFireColumnsToolStripMenuItem + // + this.onlyOnAutoFireColumnsToolStripMenuItem.Checked = true; + this.onlyOnAutoFireColumnsToolStripMenuItem.CheckOnClick = true; + this.onlyOnAutoFireColumnsToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; + this.onlyOnAutoFireColumnsToolStripMenuItem.Enabled = false; + this.onlyOnAutoFireColumnsToolStripMenuItem.Text = "Only on Auto-Fire columns"; + // + // SingleClickAxisEditMenuItem + // + this.SingleClickAxisEditMenuItem.Enabled = false; + this.SingleClickAxisEditMenuItem.Text = "Enter Axis Edit mode by single click"; + this.SingleClickAxisEditMenuItem.Visible = false; + this.SingleClickAxisEditMenuItem.Click += new System.EventHandler(this.SingleClickAxisEditMenuItem_Click); + // + // UseInputKeysItem + // + this.UseInputKeysItem.Enabled = false; + this.UseInputKeysItem.Text = "Use Input keys for Column Set"; + this.UseInputKeysItem.Visible = false; + // + // BindMarkersToInputMenuItem + // + this.BindMarkersToInputMenuItem.Checked = true; + this.BindMarkersToInputMenuItem.CheckOnClick = true; + this.BindMarkersToInputMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; + this.BindMarkersToInputMenuItem.Text = "Bind Markers to Input"; + this.BindMarkersToInputMenuItem.Click += new System.EventHandler(this.BindMarkersToInputMenuItem_Click); + // + // OldControlSchemeForBranchesMenuItem + // + this.OldControlSchemeForBranchesMenuItem.Text = "Old control scheme for Branches"; + this.OldControlSchemeForBranchesMenuItem.Click += new System.EventHandler(this.OldControlSchemeForBranchesMenuItem_Click); + // + // LoadBranchOnDoubleclickMenuItem + // + this.LoadBranchOnDoubleclickMenuItem.Text = "Load Branch on double-click"; + this.LoadBranchOnDoubleclickMenuItem.Click += new System.EventHandler(this.LoadBranchOnDoubleClickMenuItem_Click); + // + // OsdInBranchScreenshotsMenuItem + // + this.OsdInBranchScreenshotsMenuItem.Enabled = false; + this.OsdInBranchScreenshotsMenuItem.Text = "OSD in Branch screenshots"; + this.OsdInBranchScreenshotsMenuItem.Visible = false; + // + // AutopauseAtEndOfMovieMenuItem + // + this.AutopauseAtEndOfMovieMenuItem.Text = "Autopause at end of Movie"; + this.AutopauseAtEndOfMovieMenuItem.Click += new System.EventHandler(this.AutoPauseAtEndMenuItem_Click); + // + // autoHoldFireToolStripMenuItem + // + this.autoHoldFireToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.keepSetPatternsToolStripMenuItem, + this.sepToolStripMenuItem1, + this.autoHoldToolStripMenuItem, + this.autoFireToolStripMenuItem, + this.customPatternToolStripMenuItem, + this.setpToolStripMenuItem, + this.setCustomsToolStripMenuItem}); + this.autoHoldFireToolStripMenuItem.Text = "Auto Hold/Fire"; + // + // keepSetPatternsToolStripMenuItem + // + this.keepSetPatternsToolStripMenuItem.CheckOnClick = true; + this.keepSetPatternsToolStripMenuItem.Text = "Keep set patterns"; + // + // autoHoldToolStripMenuItem + // + this.autoHoldToolStripMenuItem.Checked = true; + this.autoHoldToolStripMenuItem.CheckOnClick = true; + this.autoHoldToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; + this.autoHoldToolStripMenuItem.Text = "Auto-Hold"; + this.autoHoldToolStripMenuItem.CheckedChanged += new System.EventHandler(this.AutoHoldMenuItem_CheckedChanged); + // + // autoFireToolStripMenuItem + // + this.autoFireToolStripMenuItem.CheckOnClick = true; + this.autoFireToolStripMenuItem.Text = "Auto-Fire"; + this.autoFireToolStripMenuItem.CheckedChanged += new System.EventHandler(this.AutoFireMenuItem_CheckedChanged); + // + // customPatternToolStripMenuItem + // + this.customPatternToolStripMenuItem.CheckOnClick = true; + this.customPatternToolStripMenuItem.Text = "Custom Pattern"; + this.customPatternToolStripMenuItem.CheckedChanged += new System.EventHandler(this.CustomPatternMenuItem_CheckedChanged); + // + // setCustomsToolStripMenuItem + // + this.setCustomsToolStripMenuItem.Text = "Set Customs..."; + this.setCustomsToolStripMenuItem.Click += new System.EventHandler(this.SetCustomsMenuItem_Click); + // + // SetFontMenuItem + // + this.SetFontMenuItem.Text = "Set Font"; + this.SetFontMenuItem.Click += new System.EventHandler(this.SetFontMenuItem_Click); + // + // disableTasViewToolStripMenuItem + // + this.disableTasViewToolStripMenuItem.Name = "disableTasViewToolStripMenuItem"; + this.disableTasViewToolStripMenuItem.Size = new System.Drawing.Size(272, 22); + this.disableTasViewToolStripMenuItem.Text = "Toggle Disable TasView1"; + this.disableTasViewToolStripMenuItem.Click += new System.EventHandler(this.disableTasViewToolStripMenuItem_Click); + // + // MetaSubMenu + // + this.MetaSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.HeaderMenuItem, + this.StateHistorySettingsMenuItem, + this.CommentsMenuItem, + this.SubtitlesMenuItem, + this.toolStripSeparator21, + this.DefaultStateSettingsMenuItem}); + this.MetaSubMenu.Text = "&Metadata"; + // + // HeaderMenuItem + // + this.HeaderMenuItem.Text = "&Header..."; + this.HeaderMenuItem.Click += new System.EventHandler(this.HeaderMenuItem_Click); + // + // StateHistorySettingsMenuItem + // + this.StateHistorySettingsMenuItem.Text = "&Savestate History Settings..."; + this.StateHistorySettingsMenuItem.Click += new System.EventHandler(this.StateHistorySettingsMenuItem_Click); + // + // CommentsMenuItem + // + this.CommentsMenuItem.Text = "&Comments..."; + this.CommentsMenuItem.Click += new System.EventHandler(this.CommentsMenuItem_Click); + // + // SubtitlesMenuItem + // + this.SubtitlesMenuItem.Text = "&Subtitles..."; + this.SubtitlesMenuItem.Click += new System.EventHandler(this.SubtitlesMenuItem_Click); + // + // DefaultStateSettingsMenuItem + // + this.DefaultStateSettingsMenuItem.Text = "&Default State History Settings..."; + this.DefaultStateSettingsMenuItem.Click += new System.EventHandler(this.DefaultStateSettingsMenuItem_Click); + // + // SettingsSubMenu + // + this.SettingsSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.RotateMenuItem, + this.HideLagFramesSubMenu, + this.iconsToolStripMenuItem, + this.ColorSettingsMenuItem, + this.toolStripSeparator23, + this.followCursorToolStripMenuItem, + this.toolStripSeparator25, + this.wheelScrollSpeedToolStripMenuItem}); + this.SettingsSubMenu.Text = "&Settings"; + this.SettingsSubMenu.DropDownOpened += new System.EventHandler(this.SettingsSubMenu_DropDownOpened); + // + // RotateMenuItem + // + this.RotateMenuItem.Text = "Rotate"; + this.RotateMenuItem.Click += new System.EventHandler(this.RotateMenuItem_Click); + // + // HideLagFramesSubMenu + // + this.HideLagFramesSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.HideLagFrames0, + this.HideLagFrames1, + this.HideLagFrames2, + this.HideLagFrames3, + this.toolStripSeparator12, + this.hideWasLagFramesToolStripMenuItem}); + this.HideLagFramesSubMenu.Text = "Hide Lag Frames"; + this.HideLagFramesSubMenu.DropDownOpened += new System.EventHandler(this.HideLagFramesSubMenu_DropDownOpened); + // + // HideLagFrames0 + // + this.HideLagFrames0.Checked = true; + this.HideLagFrames0.CheckOnClick = true; + this.HideLagFrames0.CheckState = System.Windows.Forms.CheckState.Checked; + this.HideLagFrames0.Tag = 0; + this.HideLagFrames0.Text = "Don\'t Hide"; + this.HideLagFrames0.Click += new System.EventHandler(this.HideLagFramesX_Click); + // + // HideLagFrames1 + // + this.HideLagFrames1.CheckOnClick = true; + this.HideLagFrames1.Tag = 1; + this.HideLagFrames1.Text = "1 (30 fps)"; + this.HideLagFrames1.Click += new System.EventHandler(this.HideLagFramesX_Click); + // + // HideLagFrames2 + // + this.HideLagFrames2.Tag = 2; + this.HideLagFrames2.Text = "2 (20 fps)"; + this.HideLagFrames2.Click += new System.EventHandler(this.HideLagFramesX_Click); + // + // HideLagFrames3 + // + this.HideLagFrames3.CheckOnClick = true; + this.HideLagFrames3.Tag = 3; + this.HideLagFrames3.Text = "3 (15fps)"; + this.HideLagFrames3.Click += new System.EventHandler(this.HideLagFramesX_Click); + // + // hideWasLagFramesToolStripMenuItem + // + this.hideWasLagFramesToolStripMenuItem.CheckOnClick = true; + this.hideWasLagFramesToolStripMenuItem.Text = "Hide WasLag Frames"; + this.hideWasLagFramesToolStripMenuItem.Click += new System.EventHandler(this.HideWasLagFramesMenuItem_Click); + // + // iconsToolStripMenuItem + // + this.iconsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.DenoteStatesWithIconsToolStripMenuItem, + this.DenoteStatesWithBGColorToolStripMenuItem, + this.DenoteMarkersWithIconsToolStripMenuItem, + this.DenoteMarkersWithBGColorToolStripMenuItem}); + this.iconsToolStripMenuItem.Text = "Icons"; + this.iconsToolStripMenuItem.DropDownOpened += new System.EventHandler(this.IconsMenuItem_DropDownOpened); + // + // DenoteStatesWithIconsToolStripMenuItem + // + this.DenoteStatesWithIconsToolStripMenuItem.CheckOnClick = true; + this.DenoteStatesWithIconsToolStripMenuItem.Text = "Denote States With Icons"; + this.DenoteStatesWithIconsToolStripMenuItem.Click += new System.EventHandler(this.DenoteStatesWithIconsToolStripMenuItem_Click); + // + // DenoteStatesWithBGColorToolStripMenuItem + // + this.DenoteStatesWithBGColorToolStripMenuItem.CheckOnClick = true; + this.DenoteStatesWithBGColorToolStripMenuItem.Text = "Denote States With BG Color"; + this.DenoteStatesWithBGColorToolStripMenuItem.Click += new System.EventHandler(this.DenoteStatesWithBGColorToolStripMenuItem_Click); + // + // DenoteMarkersWithIconsToolStripMenuItem + // + this.DenoteMarkersWithIconsToolStripMenuItem.CheckOnClick = true; + this.DenoteMarkersWithIconsToolStripMenuItem.Text = "Denote Markers With Icons"; + this.DenoteMarkersWithIconsToolStripMenuItem.Click += new System.EventHandler(this.DenoteMarkersWithIconsToolStripMenuItem_Click); + // + // DenoteMarkersWithBGColorToolStripMenuItem + // + this.DenoteMarkersWithBGColorToolStripMenuItem.CheckOnClick = true; + this.DenoteMarkersWithBGColorToolStripMenuItem.Text = "Denote Markers With BG Color"; + this.DenoteMarkersWithBGColorToolStripMenuItem.Click += new System.EventHandler(this.DenoteMarkersWithBGColorToolStripMenuItem_Click); + // + // ColorSettingsMenuItem + // + this.ColorSettingsMenuItem.Text = "Edit TAStudio Colors..."; + this.ColorSettingsMenuItem.Click += new System.EventHandler(this.ColorSettingsMenuItem_Click); + // + // followCursorToolStripMenuItem + // + this.followCursorToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.alwaysScrollToolStripMenuItem, + this.toolStripSeparator24, + this.scrollToViewToolStripMenuItem, + this.scrollToTopToolStripMenuItem, + this.scrollToBottomToolStripMenuItem, + this.scrollToCenterToolStripMenuItem}); + this.followCursorToolStripMenuItem.Text = "Follow Cursor"; + this.followCursorToolStripMenuItem.DropDownOpened += new System.EventHandler(this.FollowCursorMenuItem_DropDownOpened); + // + // alwaysScrollToolStripMenuItem + // + this.alwaysScrollToolStripMenuItem.CheckOnClick = true; + this.alwaysScrollToolStripMenuItem.Text = "Always Scroll"; + this.alwaysScrollToolStripMenuItem.Click += new System.EventHandler(this.AlwaysScrollMenuItem_Click); + // + // scrollToViewToolStripMenuItem + // + this.scrollToViewToolStripMenuItem.Checked = true; + this.scrollToViewToolStripMenuItem.CheckOnClick = true; + this.scrollToViewToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; + this.scrollToViewToolStripMenuItem.Text = "Scroll to View"; + this.scrollToViewToolStripMenuItem.Click += new System.EventHandler(this.ScrollToViewMenuItem_Click); + // + // scrollToTopToolStripMenuItem + // + this.scrollToTopToolStripMenuItem.CheckOnClick = true; + this.scrollToTopToolStripMenuItem.Text = "Scroll to Top"; + this.scrollToTopToolStripMenuItem.Click += new System.EventHandler(this.ScrollToTopMenuItem_Click); + // + // scrollToBottomToolStripMenuItem + // + this.scrollToBottomToolStripMenuItem.CheckOnClick = true; + this.scrollToBottomToolStripMenuItem.Text = "Scroll to Bottom"; + this.scrollToBottomToolStripMenuItem.Click += new System.EventHandler(this.ScrollToBottomMenuItem_Click); + // + // scrollToCenterToolStripMenuItem + // + this.scrollToCenterToolStripMenuItem.CheckOnClick = true; + this.scrollToCenterToolStripMenuItem.Text = "Scroll to Center"; + this.scrollToCenterToolStripMenuItem.Click += new System.EventHandler(this.ScrollToCenterMenuItem_Click); + // + // wheelScrollSpeedToolStripMenuItem + // + this.wheelScrollSpeedToolStripMenuItem.Text = "Wheel Scroll Speed..."; + this.wheelScrollSpeedToolStripMenuItem.Click += new System.EventHandler(this.WheelScrollSpeedMenuItem_Click); + // + // ColumnsSubMenu + // + this.ColumnsSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripSeparator19}); + this.ColumnsSubMenu.Text = "&Columns"; + // + // HelpSubMenu + // + this.HelpSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.TASEditorManualOnlineMenuItem, + this.ForumThreadMenuItem, + this.aboutToolStripMenuItem, + this.toolStripSeparator10, + this.EnableTooltipsMenuItem}); + this.HelpSubMenu.Text = "&Help"; + // + // TASEditorManualOnlineMenuItem + // + this.TASEditorManualOnlineMenuItem.Text = "TAS Editor Manual Online..."; + this.TASEditorManualOnlineMenuItem.Click += new System.EventHandler(this.TASEditorManualOnlineMenuItem_Click); + // + // ForumThreadMenuItem + // + this.ForumThreadMenuItem.Text = "Forum Thread..."; + this.ForumThreadMenuItem.Click += new System.EventHandler(this.ForumThreadMenuItem_Click); + // + // aboutToolStripMenuItem + // + this.aboutToolStripMenuItem.Enabled = false; + this.aboutToolStripMenuItem.Text = "&About"; + // + // EnableTooltipsMenuItem + // + this.EnableTooltipsMenuItem.Enabled = false; + this.EnableTooltipsMenuItem.Text = "&Enable Tooltips"; + // + // TasView1 + // + this.TasView1.AllowColumnReorder = false; + this.TasView1.AllowColumnResize = false; + this.TasView1.AllowMassNavigationShortcuts = false; + this.TasView1.AllowRightClickSelection = false; + this.TasView1.AlwaysScroll = false; + this.TasView1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.TasView1.CellHeightPadding = 0; + this.TasView1.ChangeSelectionWhenPaging = false; + this.TasView1.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.TasView1.FullRowSelect = true; + this.TasView1.HorizontalOrientation = false; + this.TasView1.InputPaintingMode = true; + this.TasView1.LetKeysModifySelection = true; + this.TasView1.Location = new System.Drawing.Point(3, 20); + this.TasView1.Name = "TasView1"; + this.TasView1.Rotatable = true; + this.TasView1.RowCount = 0; + this.TasView1.ScrollSpeed = 1; + this.TasView1.Size = new System.Drawing.Size(250, 550); + this.TasView1.TabIndex = 1; + this.TasView1.ColumnClick += new BizHawk.Client.EmuHawk.InputRoll.ColumnClickEventHandler(this.TasView_ColumnClick); + this.TasView1.ColumnRightClick += new BizHawk.Client.EmuHawk.InputRoll.ColumnClickEventHandler(this.TasView_ColumnRightClick); + this.TasView1.SelectedIndexChanged += new System.EventHandler(this.TasView_SelectedIndexChanged); + this.TasView1.RightMouseScrolled += new BizHawk.Client.EmuHawk.InputRoll.RightMouseScrollEventHandler(this.TasView_MouseWheel); + this.TasView1.ColumnReordered += new BizHawk.Client.EmuHawk.InputRoll.ColumnReorderedEventHandler(this.TasView_ColumnReordered); + this.TasView1.CellDropped += new BizHawk.Client.EmuHawk.InputRoll.CellDroppedEvent(this.TasView_CellDropped); + this.TasView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TasView_KeyDown); + this.TasView1.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.TasView_MouseDoubleClick); + this.TasView1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.TasView_MouseDown); + this.TasView1.MouseEnter += new System.EventHandler(this.TasView_MouseEnter); + this.TasView1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.TasView_MouseMove); + this.TasView1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.TasView_MouseUp); + // + // TasStatusStrip + // + this.TasStatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.MessageStatusLabel, + this.ProgressBar, + this.toolStripStatusLabel2, + this.SplicerStatusLabel}); + this.TasStatusStrip.Location = new System.Drawing.Point(0, 616); + this.TasStatusStrip.Name = "TasStatusStrip"; + this.TasStatusStrip.TabIndex = 4; + // + // MessageStatusLabel + // + this.MessageStatusLabel.Name = "MessageStatusLabel"; + this.MessageStatusLabel.Size = new System.Drawing.Size(103, 17); + this.MessageStatusLabel.Text = "TAStudio engaged"; + // + // ProgressBar + // + this.ProgressBar.Name = "ProgressBar"; + this.ProgressBar.Size = new System.Drawing.Size(100, 16); + // + // toolStripStatusLabel2 + // + this.toolStripStatusLabel2.Name = "toolStripStatusLabel2"; + this.toolStripStatusLabel2.Size = new System.Drawing.Size(821, 17); + this.toolStripStatusLabel2.Spring = true; + // + // SplicerStatusLabel + // + this.SplicerStatusLabel.Name = "SplicerStatusLabel"; + this.SplicerStatusLabel.Padding = new System.Windows.Forms.Padding(20, 0, 0, 0); + this.SplicerStatusLabel.Size = new System.Drawing.Size(20, 17); + // + // TasPlaybackBoxMPR + // + this.TasPlaybackBoxMPR.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.TasPlaybackBoxMPR.Location = new System.Drawing.Point(4, 4); + this.TasPlaybackBoxMPR.Name = "TasPlaybackBoxMPR"; + this.TasPlaybackBoxMPR.Size = new System.Drawing.Size(200, 108); + this.TasPlaybackBoxMPR.TabIndex = 5; + this.TasPlaybackBoxMPR.TastudioMPR = null; + // + // MarkerControlMPR + // + this.MarkerControlMPR.Dock = System.Windows.Forms.DockStyle.Fill; + this.MarkerControlMPR.Location = new System.Drawing.Point(0, 0); + this.MarkerControlMPR.Name = "MarkerControlMPR"; + this.MarkerControlMPR.Size = new System.Drawing.Size(200, 260); + this.MarkerControlMPR.TabIndex = 6; + this.MarkerControlMPR.TastudioMPR = null; + // + // RightClickMenu + // + this.RightClickMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.SetMarkersContextMenuItem, + this.SetMarkerWithTextContextMenuItem, + this.RemoveMarkersContextMenuItem, + this.toolStripSeparator15, + this.DeselectContextMenuItem, + this.SelectBetweenMarkersContextMenuItem, + this.toolStripSeparator16, + this.UngreenzoneContextMenuItem, + this.CancelSeekContextMenuItem, + this.toolStripSeparator17, + this.copyToolStripMenuItem, + this.pasteToolStripMenuItem, + this.pasteInsertToolStripMenuItem, + this.cutToolStripMenuItem, + this.pasteSelectedRowsFromToolStripMenuItem, + this.separateToolStripMenuItem, + this.ClearContextMenuItem, + this.DeleteFramesContextMenuItem, + this.InsertFrameContextMenuItem, + this.InsertNumFramesContextMenuItem, + this.CloneContextMenuItem, + this.CloneXTimesContextMenuItem, + this.toolStripSeparator18, + this.TruncateContextMenuItem, + this.BranchContextMenuItem, + this.StartFromNowSeparator, + this.StartNewProjectFromNowMenuItem, + this.StartANewProjectFromSaveRamMenuItem}); + this.RightClickMenu.Name = "RightClickMenu"; + this.RightClickMenu.Size = new System.Drawing.Size(253, 546); + this.RightClickMenu.Opened += new System.EventHandler(this.RightClickMenu_Opened); + // + // SetMarkersContextMenuItem + // + this.SetMarkersContextMenuItem.Text = "Set Markers"; + this.SetMarkersContextMenuItem.Click += new System.EventHandler(this.SetMarkersMenuItem_Click); + // + // SetMarkerWithTextContextMenuItem + // + this.SetMarkerWithTextContextMenuItem.Text = "Set Marker with Text"; + this.SetMarkerWithTextContextMenuItem.Click += new System.EventHandler(this.SetMarkerWithTextMenuItem_Click); + // + // RemoveMarkersContextMenuItem + // + this.RemoveMarkersContextMenuItem.Text = "Remove Markers"; + this.RemoveMarkersContextMenuItem.Click += new System.EventHandler(this.RemoveMarkersMenuItem_Click); + // + // DeselectContextMenuItem + // + this.DeselectContextMenuItem.Text = "Deselect"; + this.DeselectContextMenuItem.Click += new System.EventHandler(this.DeselectMenuItem_Click); + // + // SelectBetweenMarkersContextMenuItem + // + this.SelectBetweenMarkersContextMenuItem.Text = "Select between Markers"; + this.SelectBetweenMarkersContextMenuItem.Click += new System.EventHandler(this.SelectBetweenMarkersMenuItem_Click); + // + // UngreenzoneContextMenuItem + // + this.UngreenzoneContextMenuItem.Text = "Clear Greenzone"; + this.UngreenzoneContextMenuItem.Click += new System.EventHandler(this.ClearGreenzoneMenuItem_Click); + // + // CancelSeekContextMenuItem + // + this.CancelSeekContextMenuItem.Text = "Cancel Seek"; + this.CancelSeekContextMenuItem.Click += new System.EventHandler(this.CancelSeekContextMenuItem_Click); + // + // copyToolStripMenuItem + // + this.copyToolStripMenuItem.ShortcutKeyDisplayString = "Ctrl+C"; + this.copyToolStripMenuItem.Text = "Copy"; + this.copyToolStripMenuItem.Click += new System.EventHandler(this.CopyMenuItem_Click); + // + // pasteToolStripMenuItem + // + this.pasteToolStripMenuItem.ShortcutKeyDisplayString = "Ctrl+V"; + this.pasteToolStripMenuItem.Text = "Paste"; + this.pasteToolStripMenuItem.Click += new System.EventHandler(this.PasteMenuItem_Click); + // + // pasteInsertToolStripMenuItem + // + this.pasteInsertToolStripMenuItem.ShortcutKeyDisplayString = "Ctrl+Shift+V"; + this.pasteInsertToolStripMenuItem.Text = "Paste Insert"; + this.pasteInsertToolStripMenuItem.Click += new System.EventHandler(this.PasteInsertMenuItem_Click); + // + // cutToolStripMenuItem + // + this.cutToolStripMenuItem.ShortcutKeyDisplayString = "Ctrl+X"; + this.cutToolStripMenuItem.Text = "Cut"; + this.cutToolStripMenuItem.Click += new System.EventHandler(this.CutMenuItem_Click); + // + // ClearContextMenuItem + // + this.ClearContextMenuItem.Text = "Clear"; + this.ClearContextMenuItem.Click += new System.EventHandler(this.ClearFramesMenuItem_Click); + // + // DeleteFramesContextMenuItem + // + this.DeleteFramesContextMenuItem.Text = "Delete"; + this.DeleteFramesContextMenuItem.Click += new System.EventHandler(this.DeleteFramesMenuItem_Click); + // + // InsertFrameContextMenuItem + // + this.InsertFrameContextMenuItem.Text = "Insert"; + this.InsertFrameContextMenuItem.Click += new System.EventHandler(this.InsertFrameMenuItem_Click); + // + // InsertNumFramesContextMenuItem + // + this.InsertNumFramesContextMenuItem.Text = "Insert # of Frames"; + this.InsertNumFramesContextMenuItem.Click += new System.EventHandler(this.InsertNumFramesMenuItem_Click); + // + // CloneContextMenuItem + // + this.CloneContextMenuItem.Text = "Clone"; + this.CloneContextMenuItem.Click += new System.EventHandler(this.CloneFramesMenuItem_Click); + // + // CloneXTimesContextMenuItem + // + this.CloneXTimesContextMenuItem.Text = "Clone # Times"; + this.CloneXTimesContextMenuItem.Click += new System.EventHandler(this.CloneFramesXTimesMenuItem_Click); + // + // TruncateContextMenuItem + // + this.TruncateContextMenuItem.Text = "Truncate Movie"; + this.TruncateContextMenuItem.Click += new System.EventHandler(this.TruncateMenuItem_Click); + // + // BranchContextMenuItem + // + this.BranchContextMenuItem.Text = "&Branch"; + this.BranchContextMenuItem.Click += new System.EventHandler(this.BranchContextMenuItem_Click); + // + // StartNewProjectFromNowMenuItem + // + this.StartNewProjectFromNowMenuItem.Text = "Start a new project from Now"; + this.StartNewProjectFromNowMenuItem.Click += new System.EventHandler(this.StartNewProjectFromNowMenuItem_Click); + // + // StartANewProjectFromSaveRamMenuItem + // + this.StartANewProjectFromSaveRamMenuItem.Text = "Start a new project from SaveRam"; + this.StartANewProjectFromSaveRamMenuItem.Click += new System.EventHandler(this.StartANewProjectFromSaveRamMenuItem_Click); + // + // pasteSelectedRowsFromToolStripMenuItem + // + this.pasteSelectedRowsFromToolStripMenuItem.Name = "pasteSelectedRowsFromToolStripMenuItem"; + this.pasteSelectedRowsFromToolStripMenuItem.Size = new System.Drawing.Size(252, 22); + this.pasteSelectedRowsFromToolStripMenuItem.Text = "Paste Selected Rows From"; + // + // BookMarkControlMPR + // + this.BookMarkControlMPR.Dock = System.Windows.Forms.DockStyle.Fill; + this.BookMarkControlMPR.LoadedCallback = null; + this.BookMarkControlMPR.Location = new System.Drawing.Point(0, 0); + this.BookMarkControlMPR.Name = "BookMarkControlMPR"; + this.BookMarkControlMPR.RemovedCallback = null; + this.BookMarkControlMPR.SavedCallback = null; + this.BookMarkControlMPR.Size = new System.Drawing.Size(200, 210); + this.BookMarkControlMPR.TabIndex = 8; + this.BookMarkControlMPR.TastudioMPR = null; + // + // BranchesMarkersSplit + // + this.BranchesMarkersSplit.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.BranchesMarkersSplit.Location = new System.Drawing.Point(4, 116); + this.BranchesMarkersSplit.Name = "BranchesMarkersSplit"; + this.BranchesMarkersSplit.Orientation = System.Windows.Forms.Orientation.Horizontal; + // + // BranchesMarkersSplit.Panel1 + // + this.BranchesMarkersSplit.Panel1.Controls.Add(this.BookMarkControlMPR); + // + // BranchesMarkersSplit.Panel2 + // + this.BranchesMarkersSplit.Panel2.Controls.Add(this.MarkerControlMPR); + this.BranchesMarkersSplit.Size = new System.Drawing.Size(200, 474); + this.BranchesMarkersSplit.SplitterDistance = 210; + this.BranchesMarkersSplit.TabIndex = 9; + this.BranchesMarkersSplit.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.BranchesMarkersSplit_SplitterMoved); + // + // MainVertialSplit + // + this.MainVertialSplit.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.MainVertialSplit.FixedPanel = System.Windows.Forms.FixedPanel.Panel2; + this.MainVertialSplit.Location = new System.Drawing.Point(2, 23); + this.MainVertialSplit.Name = "MainVertialSplit"; + // + // MainVertialSplit.Panel1 + // + this.MainVertialSplit.Panel1.AutoScroll = true; + this.MainVertialSplit.Panel1.Controls.Add(this.TasView1); + // + // MainVertialSplit.Panel2 + // + this.MainVertialSplit.Panel2.Controls.Add(this.TasPlaybackBoxMPR); + this.MainVertialSplit.Panel2.Controls.Add(this.BranchesMarkersSplit); + this.MainVertialSplit.Size = new System.Drawing.Size(1059, 590); + this.MainVertialSplit.SplitterDistance = 847; + this.MainVertialSplit.TabIndex = 10; + this.MainVertialSplit.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.MainVerticalSplit_SplitterMoved); + // + // TAStudioMPR + // + this.AllowDrop = true; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1061, 638); + this.Controls.Add(this.MainVertialSplit); + this.Controls.Add(this.TasStatusStrip); + this.Controls.Add(this.TASMenu); + this.KeyPreview = true; + this.MainMenuStrip = this.TASMenu; + this.MinimumSize = new System.Drawing.Size(200, 148); + this.Name = "TAStudioMPR"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + 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); + this.DragEnter += new System.Windows.Forms.DragEventHandler(this.DragEnterWrapper); + this.TASMenu.ResumeLayout(false); + this.TASMenu.PerformLayout(); + this.TasStatusStrip.ResumeLayout(false); + this.TasStatusStrip.PerformLayout(); + this.RightClickMenu.ResumeLayout(false); + this.BranchesMarkersSplit.Panel1.ResumeLayout(false); + this.BranchesMarkersSplit.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.BranchesMarkersSplit)).EndInit(); + this.BranchesMarkersSplit.ResumeLayout(false); + this.MainVertialSplit.Panel1.ResumeLayout(false); + this.MainVertialSplit.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.MainVertialSplit)).EndInit(); + this.MainVertialSplit.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private MenuStripEx TASMenu; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx FileSubMenu; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx NewTASMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx OpenTASMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SaveTASMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SaveAsTASMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator1; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx EditSubMenu; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx ConfigSubMenu; + private InputRoll TasView1; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx RecentSubMenu; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator3; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx InsertFrameMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator4; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator7; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx CloneFramesMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx CloneFramesXTimesMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx DeleteFramesMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx ClearFramesMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx InsertNumFramesMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SelectAllMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator8; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx TruncateMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx CopyMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx PasteMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx PasteInsertMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx CutMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx UndoMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx RedoMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SelectionUndoMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SelectionRedoMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator5; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx DeselectMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SelectBetweenMarkersMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx ReselectClipboardMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator6; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator9; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx HelpSubMenu; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx EnableTooltipsMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator10; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx aboutToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SetMaxUndoLevelsMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx AutoadjustInputMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx UseInputKeysItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx BindMarkersToInputMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx OldControlSchemeForBranchesMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx OsdInBranchScreenshotsMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator14; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx AutopauseAtEndOfMovieMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SettingsSubMenu; + private StatusStripEx TasStatusStrip; + private System.Windows.Forms.ToolStripStatusLabel MessageStatusLabel; + public PlaybackBoxMPR TasPlaybackBoxMPR; + private System.Windows.Forms.ToolStripStatusLabel SplicerStatusLabel; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx MetaSubMenu; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx HeaderMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx CommentsMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SubtitlesMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx StateHistorySettingsMenuItem; + private MarkerControlMPR MarkerControlMPR; + private System.Windows.Forms.ContextMenuStrip RightClickMenu; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SetMarkersContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx RemoveMarkersContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator15; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx DeselectContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SelectBetweenMarkersContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator16; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx UngreenzoneContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator17; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx ClearContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx DeleteFramesContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx InsertFrameContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx InsertNumFramesContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx CloneContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx CloneXTimesContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator18; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx TruncateContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx ClearGreenzoneMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx GreenzoneICheckSeparator; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx StateHistoryIntegrityCheckMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx ColumnsSubMenu; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator19; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator21; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx DefaultStateSettingsMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx CancelSeekContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx StartFromNowSeparator; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx StartNewProjectFromNowMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx RotateMenuItem; + private System.Windows.Forms.ToolStripProgressBar ProgressBar; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel2; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx HideLagFramesSubMenu; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx HideLagFrames3; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx HideLagFrames0; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx HideLagFrames1; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx HideLagFrames2; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx copyToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx pasteToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx separateToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx pasteInsertToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx cutToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx showUndoHistoryToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx sepToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx autoHoldFireToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx keepSetPatternsToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx sepToolStripMenuItem1; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx autoHoldToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx autoFireToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx customPatternToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx setpToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx setCustomsToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator12; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx hideWasLagFramesToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx saveSelectionToMacroToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx placeMacroAtSelectionToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator20; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx ToBk2MenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx recentMacrosToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator22; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator23; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx followCursorToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx alwaysScrollToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator24; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx scrollToViewToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx scrollToTopToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx scrollToBottomToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx scrollToCenterToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx applyPatternToPaintedInputToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx onlyOnAutoFireColumnsToolStripMenuItem; + private BookmarksBranchesBoxMPR BookMarkControlMPR; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx BranchContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator25; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx wheelScrollSpeedToolStripMenuItem; + private System.Windows.Forms.SplitContainer BranchesMarkersSplit; + private System.Windows.Forms.SplitContainer MainVertialSplit; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx StartANewProjectFromSaveRamMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx iconsToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx ColorSettingsMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx DenoteStatesWithIconsToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx DenoteStatesWithBGColorToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx DenoteMarkersWithIconsToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx DenoteMarkersWithBGColorToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx NewFromSubMenu; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx NewFromNowMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx NewFromCurrentSaveRamMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SetMarkerWithTextContextMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx toolStripSeparator26; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx TASEditorManualOnlineMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx ForumThreadMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx autosaveToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SetAutosaveIntervalMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx AutosaveAsBk2MenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx AutosaveAsBackupFileMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx BackupPerFileSaveMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SaveBackupMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SaveBk2BackupMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SingleClickAxisEditMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx LoadBranchOnDoubleclickMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx SetFontMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx CopyIncludesFrameNoMenuItem; + private System.Windows.Forms.ToolTip toolTip1; + private System.Windows.Forms.ToolStripMenuItem disableTasViewToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem pasteSelectedRowsFromToolStripMenuItem; + } +} \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.IControlMainForm.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.IControlMainForm.cs new file mode 100644 index 00000000000..0629328296b --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.IControlMainForm.cs @@ -0,0 +1,117 @@ +namespace BizHawk.Client.EmuHawk +{ + public partial class TAStudioMPR : IControlMainform + { + private bool _suppressAskSave; + + public bool NamedStatePending { get; set; } + + public bool WantsToControlSavestates => !NamedStatePending; + + public void SaveState() + { + BookMarkControlMPR.UpdateBranchExternal(); + } + + public bool LoadState() + => BookMarkControlMPR.LoadBranchExternal(); + + public void SaveStateAs() + { + // dummy + } + + public bool LoadStateAs() + => false; + + public void SaveQuickSave(int slot) + => BookMarkControlMPR.UpdateBranchExternal(slot - 1); + + public bool LoadQuickSave(int slot) + => BookMarkControlMPR.LoadBranchExternal(slot - 1); + + public bool SelectSlot(int slot) + { + BookMarkControlMPR.SelectBranchExternal(slot - 1); + return false; + } + + public bool PreviousSlot() + { + BookMarkControlMPR.SelectBranchExternal(false); + return false; + } + + public bool NextSlot() + { + BookMarkControlMPR.SelectBranchExternal(true); + return false; + } + + public bool WantsToControlReadOnly => true; + + public void ToggleReadOnly() + { + TastudioToggleReadOnly(); + } + + public bool WantsToControlStopMovie { get; private set; } + + public void StopMovie(bool suppressSave) + { + if (!MainForm.GameIsClosing) + { + Activate(); + _suppressAskSave = suppressSave; + StartNewTasMovie(); + _suppressAskSave = false; + } + } + + public bool WantsToControlRewind { get; private set; } = true; + + public void CaptureRewind() + { + // Do nothing, Tastudio handles this just fine + } + + public bool Rewind() + { + // copy pasted from TasView_MouseWheel(), just without notch logic + if (MainForm.IsSeeking && !MainForm.EmulatorPaused) + { + MainForm.PauseOnFrame--; + + // that's a weird condition here, but for whatever reason it works best + if (Emulator.Frame >= MainForm.PauseOnFrame) + { + MainForm.PauseEmulator(); + StopSeeking(); + GoToPreviousFrame(); + } + + RefreshDialog(); + } + else + { + StopSeeking(); // late breaking memo: don't know whether this is needed + GoToPreviousFrame(); + } + + return true; + } + + public bool WantsToControlRestartMovie { get; } + + public bool RestartMovie() + { + if (!AskSaveChanges()) return false; + var success = StartNewMovieWrapper(CurrentTasMovie, isNew: false); + RefreshDialog(); + return success; + } + + public bool WantsToControlReboot => false; + public void RebootCore() => throw new NotSupportedException("This should never be called"); + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.IToolForm.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.IToolForm.cs new file mode 100644 index 00000000000..5f9b834427a --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.IToolForm.cs @@ -0,0 +1,145 @@ +using BizHawk.Client.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.EmuHawk +{ + public partial class TAStudioMPR : IToolForm + { + [RequiredService] + public IEmulator Emulator { get; private set; } + + [RequiredService] + public IStatable StatableEmulator { get; private set; } + + [RequiredService] + public IVideoProvider VideoProvider { get; private set; } + + [OptionalService] + public ISaveRam SaveRamEmulator { get; private set; } + + private bool _initializing; // If true, will bypass restart logic, this is necessary since loading projects causes a movie to load which causes a rom to reload causing dialogs to restart + + private int _lastRefresh; + + private void UpdateProgressBar() + { + if (MainForm.PauseOnFrame.HasValue) + { + int diff = Emulator.Frame - _seekStartFrame.Value; + int unit = MainForm.PauseOnFrame.Value - _seekStartFrame.Value; + double progress = 0; + + if (diff != 0 && unit != 0) + { + progress = (double)100d / unit * diff; + } + + if (progress < 0) + { + progress = 0; + } + else if (progress > 100) + { + progress = 100; + } + + ProgressBar.Value = (int)progress; + } + else + { + ProgressBar.Visible = false; + MessageStatusLabel.Text = ""; + } + } + + protected override void GeneralUpdate() + { + RefreshDialog(); + } + + protected override void UpdateAfter() + { + if (!IsHandleCreated || IsDisposed || CurrentTasMovie == null) + { + return; + } + + if (_exiting) + { + return; + } + + var refreshNeeded = false; + if (Settings.AutoadjustInput) + { + refreshNeeded = AutoAdjustInput(); + } + + CurrentTasMovie.TasSession.UpdateValues(Emulator.Frame, CurrentTasMovie.Branches.Current); + MaybeFollowCursor(); + + if (TasView1.IsPartiallyVisible(Emulator.Frame) || TasView1.IsPartiallyVisible(_lastRefresh)) + { + refreshNeeded = true; + } + + RefreshDialog(refreshNeeded, refreshBranches: false); + UpdateProgressBar(); + } + + protected override void FastUpdateAfter() + { + UpdateProgressBar(); + } + + public override void Restart() + { + if (!IsActive) + { + return; + } + + if (_initializing) + { + return; + } + + if (CurrentTasMovie != null) + { + bool loadRecent = Game.Hash == CurrentTasMovie.Hash && CurrentTasMovie.Filename == Settings.RecentTas.MostRecent; + TastudioStopMovie(); + // try to load the most recent movie if it matches the currently loaded movie + if (loadRecent) + { + LoadMostRecentOrStartNew(); + } + else + { + StartNewTasMovie(); + } + } + } + + /// + /// Ask whether changes should be saved. Returns false if cancelled, else true. + /// + public override bool AskSaveChanges() + { + if (_suppressAskSave) + { + return true; + } + + StopSeeking(); + if (CurrentTasMovie?.Changes is not true) return true; + var result = DialogController.DoWithTempMute(() => this.ModalMessageBox3( + caption: "Closing with Unsaved Changes", + icon: EMsgBoxIcon.Question, + text: $"Save {WindowTitleStatic} project?")); + if (result is null) return false; + if (result.Value) SaveTas(); + else CurrentTasMovie.ClearChanges(); + return true; + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.ListView.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.ListView.cs new file mode 100644 index 00000000000..57309a40493 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.ListView.cs @@ -0,0 +1,1469 @@ +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using System.Collections.Generic; +using System.Globalization; +using BizHawk.Emulation.Common; +using BizHawk.Common.NumberExtensions; +using BizHawk.Client.Common; +using BizHawk.Common; +using BizHawk.Common.CollectionExtensions; +using BizHawk.Common.StringExtensions; + +namespace BizHawk.Client.EmuHawk +{ + public partial class TAStudioMPR + { + // Input Painting + private string _startBoolDrawColumn = ""; + private string _startAxisDrawColumn = ""; + private bool _drewAxis; + private bool _boolPaintState; + private int _axisPaintState; + private int _axisBackupState; + private bool _patternPaint; + private bool _startCursorDrag; + private bool _startSelectionDrag; + private bool _selectionDragState; + private bool _suppressContextMenu; + private int _startRow; + private int _paintingMinFrame = -1; + private bool _playbackInterrupted; // Occurs when the emulator is unpaused and the user click and holds mouse down to begin delivering input + + // Editing analog input + private string _axisEditColumn = ""; + private int _axisEditRow = -1; + private string _axisTypedValue; + private int _axisEditYPos = -1; + private int AxisEditRow + { + set + { + _axisEditRow = value; + foreach (InputRoll tasView in TasViews) + { + if (tasView.Focused && tasView.AnyRowsSelected) + { + tasView.SuspendHotkeys = AxisEditingMode; + } + } + } + } + + public bool AxisEditingMode => _axisEditRow != -1; + + private readonly List _extraAxisRows = new List(); + + // Right-click dragging + private string[] _rightClickInput; + private string[] _rightClickOverInput; + private int _rightClickFrame = -1; + private int _rightClickLastFrame = -1; + private bool _rightClickShift, _rightClickControl, _rightClickAlt; + private bool _leftButtonHeld; + + 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 readonly Dictionary _alternateRowColor = new(); + + private ControllerDefinition ControllerType => MovieSession.MovieController.Definition; + + public bool WasRecording { get; set; } + 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) + { + 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; + } + + MainForm.PauseOnFrame = frame.Value; + int? diff = MainForm.PauseOnFrame - _seekStartFrame; + + WasRecording = CurrentTasMovie.IsRecording() || WasRecording; + TastudioPlayMode(); // suspend rec mode until seek ends, to allow mouse editing + MainForm.UnpauseEmulator(); + + if (diff > TasView1.VisibleRows) + { + MessageStatusLabel.Text = "Seeking..."; + ProgressBar.Visible = true; + } + } + + public void StopSeeking(bool skipRecModeCheck = false) + { + if (WasRecording && !skipRecModeCheck) + { + TastudioRecordMode(); + WasRecording = false; + } + + MainForm.PauseOnFrame = null; + if (_unpauseAfterSeeking) + { + MainForm.UnpauseEmulator(); + _unpauseAfterSeeking = false; + } + + if (CurrentTasMovie != null) + { + 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; + private Bitmap ts_h_arrow_blue => Properties.Resources.ts_h_arrow_blue; + private Bitmap ts_v_arrow_green => Properties.Resources.ts_v_arrow_green; + private Bitmap ts_h_arrow_green => Properties.Resources.ts_h_arrow_green; + + private Bitmap icon_marker => Properties.Resources.icon_marker; + private Bitmap icon_anchor_lag => Properties.Resources.icon_anchor_lag; + private Bitmap icon_anchor => Properties.Resources.icon_anchor; + + private void TasView_QueryItemIcon(int index, RollColumn column, ref Bitmap bitmap, ref int offsetX, ref int offsetY) + { + if (!_engaged || _initializing) + { + return; + } + + var overrideIcon = QueryItemIconCallback?.Invoke(index, column.Name); + + if (overrideIcon != null) + { + bitmap = overrideIcon; + return; + } + + var columnName = column.Name; + + if (columnName == CursorColumnName) + { + if (TasView1.HorizontalOrientation) + { + offsetX = -1; + offsetY = 5; + } + + if (index == Emulator.Frame) + { + bitmap = index == MainForm.PauseOnFrame + ? TasView1.HorizontalOrientation ? ts_v_arrow_green_blue : ts_h_arrow_green_blue + : TasView1.HorizontalOrientation ? ts_v_arrow_blue : ts_h_arrow_blue; + } + else if (index == LastPositionFrame) + { + bitmap = TasView1.HorizontalOrientation ? + ts_v_arrow_green : + ts_h_arrow_green; + } + } + else if (columnName == FrameColumnName) + { + offsetX = -3; + offsetY = 1; + + if (Settings.DenoteMarkersWithIcons && CurrentTasMovie.Markers.IsMarker(index)) + { + bitmap = icon_marker; + } + else if (Settings.DenoteStatesWithIcons) + { + var record = CurrentTasMovie[index]; + if (record.HasState) bitmap = record.Lagged is true ? icon_anchor_lag : icon_anchor; + } + } + } + + private void TasView_QueryItemBkColor(int index, RollColumn column, ref Color color) + { + if (!_engaged || _initializing) + { + return; + } + + Color? overrideColor = QueryItemBgColorCallback?.Invoke(index, column.Name); + + if (overrideColor.HasValue) + { + color = overrideColor.Value; + return; + } + + string columnName = column.Name; + + if (columnName == CursorColumnName) + { + color = Color.FromArgb(0xFE, 0xFF, 0xFF); + } + + if (columnName == FrameColumnName) + { + if (Emulator.Frame != index && Settings.DenoteMarkersWithBGColor && CurrentTasMovie.Markers.IsMarker(index)) + { + color = Palette.Marker_FrameCol; + } + else + { + color = Color.FromArgb(0x60, 0xFF, 0xFF, 0xFF); + } + } + else if (AxisEditingMode + && (index == _axisEditRow || _extraAxisRows.Contains(index)) + && columnName == _axisEditColumn) + { + color = Palette.AnalogEdit_Col; + } + + if (_alternateRowColor.GetValueOrPut( + columnName, + columnName1 => + { + var playerNumber = ControllerDefinition.PlayerNumber(columnName1); + return playerNumber % 2 is 0 && playerNumber is not 0; + })) + { + color = Color.FromArgb(0x0D, 0x00, 0x00, 0x00); + } + } + + private void TasView_QueryRowBkColor(int index, ref Color color) + { + if (!_engaged || _initializing) + { + return; + } + + var record = CurrentTasMovie[index]; + + if (MainForm.IsSeeking && MainForm.PauseOnFrame == index) + { + color = Palette.CurrentFrame_InputLog; + } + else if (!MainForm.IsSeeking && Emulator.Frame == index) + { + color = Palette.CurrentFrame_InputLog; + } + else if (record.Lagged.HasValue) + { + if (!record.HasState && Settings.DenoteStatesWithBGColor) + { + color = record.Lagged.Value + ? Palette.LagZone_InputLog + : Palette.GreenZone_InputLog; + } + else + { + color = record.Lagged.Value + ? Palette.LagZone_InputLog_Stated + : Palette.GreenZone_InputLog_Stated; + } + } + else if (record.WasLagged.HasValue) + { + color = record.WasLagged.Value + ? Palette.LagZone_InputLog_Invalidated + : Palette.GreenZone_InputLog_Invalidated; + } + else + { + color = Color.FromArgb(0xFF, 0xFE, 0xEE); + } + } + + private readonly string[] _formatCache = Enumerable.Range(1, 10).Select(i => $"D{i}").ToArray(); + + /// with leading zeroes such that every frame in the movie will be printed with the same number of digits + private string FrameToStringPadded(int index) + => index.ToString(_formatCache[Math.Max( + 4, + NumberExtensions.Log10(Math.Max(CurrentTasMovie.InputLogLength, 1)))]); + + private void TasView_QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) + { + if (!_engaged || _initializing) + { + text = ""; + return; + } + + var overrideText = QueryItemTextCallback?.Invoke(index, column.Name); + if (overrideText != null) + { + text = overrideText; + return; + } + + try + { + text = ""; + var columnName = column.Name; + + if (columnName == CursorColumnName) + { + int branchIndex = CurrentTasMovie.Branches.IndexOfFrame(index); + if (branchIndex != -1) + { + text = (branchIndex + 1).ToString(); + } + } + else if (columnName == FrameColumnName) + { + offsetX = TasView1.HorizontalOrientation ? 2 : 7; + text = FrameToStringPadded(index); + } + else + { + // Display typed float value (string "-" can't be parsed, so CurrentTasMovie.DisplayValue can't return it) + if (index == _axisEditRow && columnName == _axisEditColumn) + { + text = _axisTypedValue; + } + else if (index < CurrentTasMovie.InputLogLength) + { + text = CurrentTasMovie.DisplayValue(index, columnName); + if (column.Type == ColumnType.Axis) + { + // feos: this could be cached, but I don't notice any slowdown this way either + if (text == ((float) ControllerType.Axes[columnName].Neutral).ToString(NumberFormatInfo.InvariantInfo)) + { + text = ""; + } + } + } + } + } + catch (Exception ex) + { + text = ""; + DialogController.ShowMessageBox($"oops\n{ex}"); + } + } + + private bool TasView_QueryFrameLag(int index, bool hideWasLag) + { + var lag = CurrentTasMovie[index]; + return (lag.Lagged.HasValue && lag.Lagged.Value) || (hideWasLag && lag.WasLagged.HasValue && lag.WasLagged.Value); + } + + private void TasView_ColumnClick(object sender, InputRoll.ColumnClickEventArgs e) + { + var tasView = sender as InputRoll; + + if (tasView.AnyRowsSelected) + { + var columnName = e.Column!.Name; + + if (columnName == FrameColumnName) + { + CurrentTasMovie.Markers.Add(tasView.SelectionEndIndex!.Value, ""); + } + else if (columnName != CursorColumnName) + { + var frame = tasView.AnyRowsSelected ? tasView.FirstSelectedRowIndex : 0; + var buttonName = tasView.CurrentCell.Column!.Name; + + if (ControllerType.BoolButtons.Contains(buttonName)) + { + if (ModifierKeys != Keys.Alt) + { + // nifty taseditor logic + bool allPressed = true; + foreach (var index in tasView.SelectedRows) + { + if (index == CurrentTasMovie.FrameCount // last movie frame can't have input, but can be selected + || !CurrentTasMovie.BoolIsPressed(index, buttonName)) + { + allPressed = false; + break; + } + } + CurrentTasMovie.SetBoolStates(frame, tasView.SelectedRows.Count(), buttonName, !allPressed); + } + else + { + BoolPatterns[ControllerType.BoolButtons.IndexOf(buttonName)].Reset(); + foreach (var index in tasView.SelectedRows) + { + CurrentTasMovie.SetBoolState(index, buttonName, BoolPatterns[ControllerType.BoolButtons.IndexOf(buttonName)].GetNextValue()); + } + } + } + else + { + // 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(); + } + } + + private void TasView_ColumnRightClick(object sender, InputRoll.ColumnClickEventArgs e) + { + var tasView = sender as InputRoll; + var col = e.Column!; + if (col.Name is FrameColumnName or CursorColumnName) return; + + col.Emphasis = !col.Emphasis; + UpdateAutoFire(col.Name, col.Emphasis); + tasView.Refresh(); + } + + private void UpdateAutoFire() + { + for (int i = 2; i < TasView1.AllColumns.Count; i++) + { + UpdateAutoFire(TasView1.AllColumns[i].Name, TasView1.AllColumns[i].Emphasis); + } + } + + public void UpdateAutoFire(string button, bool? isOn) + { + // No value means don't change whether it's on or off. + isOn ??= TasView1.AllColumns.Find(c => c.Name == button).Emphasis; + + // use custom pattern if set + bool useCustom = customPatternToolStripMenuItem.Checked; + // else, set autohold or fire based on setting + bool autoHold = autoHoldToolStripMenuItem.Checked; // !autoFireToolStripMenuItem.Checked + + if (ControllerType.BoolButtons.Contains(button)) + { + InputManager.StickyHoldController.SetButtonHold(button, false); + InputManager.StickyAutofireController.SetButtonAutofire(button, false); + if (!isOn.Value) return; + + if (useCustom) + { + InputManager.StickyAutofireController.SetButtonAutofire(button, true, BoolPatterns[ControllerType.BoolButtons.IndexOf(button)]); + } + else if (autoHold) + { + InputManager.StickyHoldController.SetButtonHold(button, true); + } + else + { + InputManager.StickyAutofireController.SetButtonAutofire(button, true); + } + } + else + { + InputManager.StickyHoldController.SetAxisHold(button, null); + InputManager.StickyAutofireController.SetAxisAutofire(button, null); + if (!isOn.Value) return; + + int holdValue = ControllerType.Axes[button].Range.EndInclusive; // it's not clear what value to use for auto-hold, just use max i guess + if (useCustom) + { + InputManager.StickyAutofireController.SetAxisAutofire(button, holdValue, AxisPatterns[ControllerType.Axes.IndexOf(button)]); + } + else if (autoHold) + { + InputManager.StickyHoldController.SetAxisHold(button, holdValue); + } + else + { + InputManager.StickyAutofireController.SetAxisAutofire(button, holdValue); + } + } + } + + private void TasView_ColumnReordered(object sender, InputRoll.ColumnReorderedEventArgs e) + { + CurrentTasMovie.FlagChanges(); + } + + private void TasView_MouseEnter(object sender, EventArgs e) + { + if (ContainsFocus) + { + var tasView = sender as InputRoll; + tasView.Select(); + } + } + + private void TasView_MouseDown(object sender, MouseEventArgs e) + { + var tasView = sender as InputRoll; + + // Clicking with left while right is held or vice versa does weird stuff + if (MouseButtonHeld) + { + return; + } + + // only on mouse button down, check that the pointed to cell is the correct one (can be wrong due to scroll while playing) + tasView._programmaticallyChangingRow = true; + tasView.PointMouseToNewCell(); + + if (e.Button == MouseButtons.Middle) + { + if (MainForm.EmulatorPaused) + { + var record = CurrentTasMovie[LastPositionFrame]; + if (!record.Lagged.HasValue && LastPositionFrame > Emulator.Frame) + { + StartSeeking(LastPositionFrame, true); + return; + } + } + + MainForm.TogglePause(); + return; + } + + if (tasView.CurrentCell is not { RowIndex: int frame, Column: RollColumn targetCol }) return; + + var buttonName = targetCol.Name; + WasRecording = CurrentTasMovie.IsRecording() || WasRecording; + + if (e.Button == MouseButtons.Left) + { + _leftButtonHeld = true; + _paintingMinFrame = frame; + + // SuuperW: Exit axis editing mode, or re-enter mouse editing + if (AxisEditingMode) + { + if (ModifierKeys == Keys.Control || ModifierKeys == Keys.Shift) + { + _extraAxisRows.Clear(); + _extraAxisRows.AddRange(tasView.SelectedRows); + _startSelectionDrag = true; + _selectionDragState = tasView.IsRowSelected(frame); + return; + } + if (_axisEditColumn != buttonName + || !(_axisEditRow == frame || _extraAxisRows.Contains(frame))) + { + _extraAxisRows.Clear(); + AxisEditRow = -1; + SetTasViewRowCount(); + } + else + { + if (_extraAxisRows.Contains(frame)) + { + _extraAxisRows.Clear(); + AxisEditRow = frame; + SetTasViewRowCount(); + } + + _axisEditYPos = e.Y; + _axisPaintState = CurrentTasMovie.GetAxisState(frame, buttonName); + + _triggerAutoRestore = true; + TastudioPlayMode(true); + return; + } + } + + if (targetCol.Name is CursorColumnName) + { + _startCursorDrag = true; + GoToFrame(frame, fromLua: false, fromRewinding: false, OnLeftMouseDown: true); + } + else if (targetCol.Name is FrameColumnName) + { + if (ModifierKeys == Keys.Alt && CurrentTasMovie.Markers.IsMarker(frame)) + { + // TODO + tasView.DragCurrentCell(); + } + else + { + _startSelectionDrag = true; + _selectionDragState = tasView.IsRowSelected(frame); + } + } + else if (targetCol.Type is not ColumnType.Text) // User changed input + { + _playbackInterrupted = !MainForm.EmulatorPaused; + MainForm.PauseEmulator(); + + // Pausing the emulator is insufficient to actually stop frame advancing as the frame advance hotkey can + // still take effect. This can lead to desyncs by simultaneously changing input and frame advancing. + // So we want to block all frame advance operations while the user is changing input in the piano roll + MainForm.BlockFrameAdvance = true; + + if (ControllerType.BoolButtons.Contains(buttonName)) + { + _patternPaint = false; + _startBoolDrawColumn = buttonName; + + var altOrShift4State = ModifierKeys & (Keys.Alt | Keys.Shift); + if (altOrShift4State is Keys.Alt + || (applyPatternToPaintedInputToolStripMenuItem.Checked + && (!onlyOnAutoFireColumnsToolStripMenuItem.Checked || targetCol.Emphasis))) + { + BoolPatterns[ControllerType.BoolButtons.IndexOf(buttonName)].Reset(); + _patternPaint = true; + _startRow = frame; + _boolPaintState = !CurrentTasMovie.BoolIsPressed(frame, buttonName); + } + else if (altOrShift4State is Keys.Shift) + { + if (!tasView.AnyRowsSelected) return; + + var iFirstSelectedRow = tasView.FirstSelectedRowIndex; + var (firstSel, lastSel) = frame <= iFirstSelectedRow + ? (frame, iFirstSelectedRow) + : (iFirstSelectedRow, frame); + + bool allPressed = true; + for (var i = firstSel; i <= lastSel; i++) + { + if (i == CurrentTasMovie.FrameCount // last movie frame can't have input, but can be selected + || !CurrentTasMovie.BoolIsPressed(i, buttonName)) + { + allPressed = false; + break; + } + } + 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) + { + // TODO: Pattern drawing from selection to current cell + } +#endif + else + { + CurrentTasMovie.ChangeLog.BeginNewBatch($"Paint Bool {buttonName} from frame {frame}"); + + CurrentTasMovie.ToggleBoolState(frame, buttonName); + _boolPaintState = CurrentTasMovie.BoolIsPressed(frame, buttonName); + _triggerAutoRestore = true; + TastudioPlayMode(true); + RefreshDialog(); + } + } + else + { + if (frame >= CurrentTasMovie.InputLogLength) + { + CurrentTasMovie.SetAxisState(frame, buttonName, ControllerType.Axes[buttonName].Neutral); + RefreshDialog(); + } + + _axisPaintState = CurrentTasMovie.GetAxisState(frame, buttonName); + if (applyPatternToPaintedInputToolStripMenuItem.Checked && (!onlyOnAutoFireColumnsToolStripMenuItem.Checked + || targetCol.Emphasis)) + { + AxisPatterns[ControllerType.Axes.IndexOf(buttonName)].Reset(); + CurrentTasMovie.SetAxisState(frame, buttonName, AxisPatterns[ControllerType.Axes.IndexOf(buttonName)].GetNextValue()); + _patternPaint = true; + } + else + { + _patternPaint = false; + } + + + if (e.Clicks != 2 && !Settings.SingleClickAxisEdit) + { + CurrentTasMovie.ChangeLog.BeginNewBatch($"Paint Axis {buttonName} from frame {frame}"); + _startAxisDrawColumn = buttonName; + } + else // Double-click enters axis editing mode + { + if (_axisEditColumn == buttonName && _axisEditRow == frame) + { + AxisEditRow = -1; + } + else + { + CurrentTasMovie.ChangeLog.BeginNewBatch($"Axis Edit: {frame}"); + _axisEditColumn = buttonName; + AxisEditRow = frame; + _axisTypedValue = ""; + _axisEditYPos = e.Y; + _axisBackupState = CurrentTasMovie.GetAxisState(_axisEditRow, _axisEditColumn); + } + + RefreshDialog(); + } + } + } + } + else if (e.Button == MouseButtons.Right) + { + if (targetCol.Name is FrameColumnName && frame < CurrentTasMovie.InputLogLength) + { + _rightClickControl = (ModifierKeys | Keys.Control) == ModifierKeys; + _rightClickShift = (ModifierKeys | Keys.Shift) == ModifierKeys; + _rightClickAlt = (ModifierKeys | Keys.Alt) == ModifierKeys; + if (tasView.IsRowSelected(frame)) + { + _rightClickInput = new string[tasView.SelectedRows.Count()]; + _rightClickFrame = tasView.SelectionStartIndex!.Value; + try + { + CurrentTasMovie.GetLogEntries().CopyTo(_rightClickFrame, _rightClickInput, 0, _rightClickInput.Length); + } + catch { } + if (_rightClickControl && _rightClickShift) + { + _rightClickFrame += _rightClickInput.Length; + } + } + else + { + _rightClickInput = new string[1]; + _rightClickInput[0] = CurrentTasMovie.GetInputLogEntry(frame); + _rightClickFrame = frame; + } + + _rightClickLastFrame = -1; + + if (_rightClickAlt || _rightClickControl || _rightClickShift) + { + JumpToGreenzone(); + + // TODO: Turn off ChangeLog.IsRecording and handle the GeneralUndo here. + string undoStepName = "Right-Click Edit:"; + if (_rightClickShift) + { + undoStepName += " Extend Input"; + if (_rightClickControl) + { + undoStepName += ", Insert"; + } + } + else + { + if (_rightClickControl) + { + undoStepName += " Copy"; + } + else // _rightClickAlt + { + undoStepName += " Move"; + } + } + + CurrentTasMovie.ChangeLog.BeginNewBatch(undoStepName); + } + } + } + } + + private void ClearLeftMouseStates() + { + _startCursorDrag = false; + _startSelectionDrag = false; + _startBoolDrawColumn = ""; + _startAxisDrawColumn = ""; + _drewAxis = false; + _paintingMinFrame = -1; + foreach (InputRoll tasView in TasViews) + { + 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) + { + CurrentTasMovie.ChangeLog?.EndBatch(); + } + + MainForm.BlockFrameAdvance = false; + } + + private void TasView_MouseUp(object sender, MouseEventArgs e) + { + var tasView = sender as InputRoll; + + if (e.Button == MouseButtons.Right && !tasView.IsPointingAtColumnHeader + && !_suppressContextMenu && !_leftButtonHeld && tasView.AnyRowsSelected) + { + if (CurrentTasMovie.FrameCount < tasView.SelectionEndIndex) + { + // trying to be smart here + // if a loaded branch log is shorter than selection, keep selection until you attempt to call context menu + // you might need it when you load again the branch where this frame exists + tasView.DeselectAll(); + SetTasViewRowCount(); + } + else + { + var offset = new Point(0); + var topLeft = Cursor.Position; + var bottomRight = new Point( + topLeft.X + RightClickMenu.Width, + topLeft.Y + RightClickMenu.Height); + var screen = Screen.AllScreens.First(s => s.WorkingArea.Contains(topLeft)); + // if we don't fully fit, move to the other side of the pointer + if (bottomRight.X > screen.WorkingArea.Right) + offset.X -= RightClickMenu.Width; + if (bottomRight.Y > screen.WorkingArea.Bottom) + offset.Y -= RightClickMenu.Height; + topLeft.Offset(offset); + // if the screen is insultingly tiny, best we can do is avoid negative pos + RightClickMenu.Show( + Math.Max(0, topLeft.X), + Math.Max(0, topLeft.Y)); + } + } + else if (e.Button == MouseButtons.Left) + { + if (AxisEditingMode && (ModifierKeys == Keys.Control || ModifierKeys == Keys.Shift)) + { + _leftButtonHeld = false; + _startSelectionDrag = false; + } + 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) + { + if (_rightClickFrame != -1) + { + _rightClickInput = null; + _rightClickOverInput = null; + _rightClickFrame = -1; + CurrentTasMovie.ChangeLog.EndBatch(); + } + } + + _suppressContextMenu = false; + } + + private void TasView_MouseWheel(object sender, MouseEventArgs e) + { + + var tasView = sender as InputRoll; + + if (tasView.RightButtonHeld && tasView?.CurrentCell.RowIndex.HasValue == true) + { + _suppressContextMenu = true; + int notch = e.Delta / 120; + if (notch > 1) + { + 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 + { + // needed for AutoAdjustInput() when it removes was-lag frames + MainForm.HoldFrameAdvance = true; + + GoToFrame(Emulator.Frame - notch); + } + } + } + + private void TasView_MouseDoubleClick(object sender, MouseEventArgs e) + { + var tasView = sender as InputRoll; + + if (tasView.CurrentCell?.Column is not { Name: var columnName }) return; + + if (e.Button == MouseButtons.Left) + { + if (!AxisEditingMode && tasView.CurrentCell.RowIndex is not null && columnName is FrameColumnName) + { + var existingMarker = CurrentTasMovie.Markers.FirstOrDefault(m => m.Frame == tasView.CurrentCell.RowIndex.Value); + + if (existingMarker != null) + { + MarkerControlMPR.EditMarkerPopUp(existingMarker); + } + else + { + ClearLeftMouseStates(); + MarkerControlMPR.AddMarker(tasView.CurrentCell.RowIndex.Value); + } + } + } + } + + private void TasView_PointedCellChanged(object sender, InputRoll.CellEventArgs e) + { + var tasView = sender as InputRoll; + + toolTip1.SetToolTip(tasView, null); + + if (e.NewCell.RowIndex is null) + { + return; + } + + if (!MouseButtonHeld) + { + 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; + WasRecording = CurrentTasMovie.IsRecording() || WasRecording; + + int startVal, endVal; + int frame = e.NewCell.RowIndex.Value; + if (e.OldCell.RowIndex < e.NewCell.RowIndex) + { + startVal = e.OldCell.RowIndex.Value; + endVal = e.NewCell.RowIndex.Value; + if (_patternPaint) + { + endVal--; + } + } + else + { + startVal = e.NewCell.RowIndex.Value; + endVal = e.OldCell.RowIndex ?? e.NewCell.RowIndex.Value; + if (_patternPaint) + { + endVal = _startRow; + } + } + + if (_startCursorDrag && !MainForm.IsSeeking) + { + GoToFrame(e.NewCell.RowIndex.Value); + } + else if (_startSelectionDrag) + { + for (var i = startVal; i <= endVal; i++) + { + if (!tasView.IsRowSelected(i)) + tasView.SelectRow(i, _selectionDragState); + if (AxisEditingMode && (ModifierKeys == Keys.Control || ModifierKeys == Keys.Shift)) + { + if (_selectionDragState) + { + _extraAxisRows.Add(i); + } + else + { + _extraAxisRows.Remove(i); + } + } + } + + SetSplicer(); + } + else if (_rightClickFrame != -1) + { + if (frame > CurrentTasMovie.InputLogLength - _rightClickInput.Length) + { + frame = CurrentTasMovie.InputLogLength - _rightClickInput.Length; + } + + if (_rightClickShift) + { + if (_rightClickControl) // Insert + { + // If going backwards, delete! + bool shouldInsert = true; + if (startVal < _rightClickFrame) + { + // Cloning to a previous frame makes no sense. + startVal = _rightClickFrame - 1; + } + + if (startVal < _rightClickLastFrame) + { + shouldInsert = false; + } + + if (shouldInsert) + { + for (int i = startVal + 1; i <= endVal; i++) + { + CurrentTasMovie.InsertInput(i, _rightClickInput[(i - _rightClickFrame).Mod(_rightClickInput.Length)]); + } + } + else + { + CurrentTasMovie.RemoveFrames(startVal + 1, endVal + 1); + } + + _rightClickLastFrame = frame; + } + else // Overwrite + { + for (int i = startVal; i <= endVal; i++) + { + CurrentTasMovie.SetFrame(i, _rightClickInput[(i - _rightClickFrame).Mod(_rightClickInput.Length)]); + } + } + } + else + { + if (_rightClickControl) + { + for (int i = 0; i < _rightClickInput.Length; i++) // Re-set initial range, just to verify it's still there. + { + CurrentTasMovie.SetFrame(_rightClickFrame + i, _rightClickInput[i]); + } + + if (_rightClickOverInput != null) // Restore overwritten input from previous movement + { + for (int i = 0; i < _rightClickOverInput.Length; i++) + { + CurrentTasMovie.SetFrame(_rightClickLastFrame + i, _rightClickOverInput[i]); + } + } + else + { + _rightClickOverInput = new string[_rightClickInput.Length]; + } + + _rightClickLastFrame = frame; // Set new restore log + CurrentTasMovie.GetLogEntries().CopyTo(frame, _rightClickOverInput, 0, _rightClickOverInput.Length); + + for (int i = 0; i < _rightClickInput.Length; i++) // Place copied input + { + CurrentTasMovie.SetFrame(frame + i, _rightClickInput[i]); + } + } + else if (_rightClickAlt) + { + int shiftBy = _rightClickFrame - frame; + string[] shiftInput = new string[Math.Abs(shiftBy)]; + int shiftFrom = frame; + if (shiftBy < 0) + { + shiftFrom = _rightClickFrame + _rightClickInput.Length; + } + + CurrentTasMovie.GetLogEntries().CopyTo(shiftFrom, shiftInput, 0, shiftInput.Length); + int shiftTo = shiftFrom + (_rightClickInput.Length * Math.Sign(shiftBy)); + for (int i = 0; i < shiftInput.Length; i++) + { + CurrentTasMovie.SetFrame(shiftTo + i, shiftInput[i]); + } + + for (int i = 0; i < _rightClickInput.Length; i++) + { + CurrentTasMovie.SetFrame(frame + i, _rightClickInput[i]); + } + + _rightClickFrame = frame; + } + } + + if (_rightClickAlt || _rightClickControl || _rightClickShift) + { + _triggerAutoRestore = true; + TastudioPlayMode(true); + JumpToGreenzone(); + _suppressContextMenu = true; + } + } + + // Left-click + else if (tasView.IsPaintDown && !string.IsNullOrEmpty(_startBoolDrawColumn)) + { + CurrentTasMovie.IsCountingRerecords = false; + + for (int i = startVal; i <= endVal; i++) // Inclusive on both ends (drawing up or down) + { + bool setVal = _boolPaintState; + + if (_patternPaint && _boolPaintState) + { + if (CurrentTasMovie[frame].Lagged.HasValue && CurrentTasMovie[frame].Lagged.Value) + { + setVal = CurrentTasMovie.BoolIsPressed(i - 1, _startBoolDrawColumn); + } + else + { + setVal = BoolPatterns[ControllerType.BoolButtons.IndexOf(_startBoolDrawColumn)].GetNextValue(); + } + } + + 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(); + } + } + } + + else if (tasView.IsPaintDown && !string.IsNullOrEmpty(_startAxisDrawColumn)) + { + CurrentTasMovie.IsCountingRerecords = false; + + for (int i = startVal; i <= endVal; i++) // Inclusive on both ends (drawing up or down) + { + var setVal = _axisPaintState; + if (_patternPaint) + { + if (CurrentTasMovie[frame].Lagged.HasValue && CurrentTasMovie[frame].Lagged.Value) + { + setVal = CurrentTasMovie.GetAxisState(i - 1, _startAxisDrawColumn); + } + else + { + setVal = AxisPatterns[ControllerType.Axes.IndexOf(_startAxisDrawColumn)].GetNextValue(); + } + } + + CurrentTasMovie.SetAxisState(i, _startAxisDrawColumn, setVal); // Notice it uses new row, old column, you can only paint across a single column + } + + _drewAxis = true; + } + + CurrentTasMovie.IsCountingRerecords = wasCountingRerecords; + + if (MouseButtonHeld) + { + tasView.MakeIndexVisible(tasView.CurrentCell.RowIndex.Value); // todo: limit scrolling speed + } + + SetTasViewRowCount(); + } + + private void TasView_MouseMove(object sender, MouseEventArgs e) + { + // For axis editing + if (AxisEditingMode) + { + int increment = (_axisEditYPos - e.Y) / 4; + if (_axisEditYPos == -1) + { + return; + } + + var value = (_axisPaintState + increment).ConstrainWithin(ControllerType.Axes[_axisEditColumn].Range); + CurrentTasMovie.SetAxisState(_axisEditRow, _axisEditColumn, value); + _axisTypedValue = value.ToString(); + RefreshDialog(); + } + } + + private void TasView_SelectedIndexChanged(object sender, EventArgs e) + { + SetSplicer(); + CurrentTasView = sender as InputRoll; + } + + public void AnalogIncrementByOne() + { + if (AxisEditingMode) + { + EditAnalogProgrammatically(new KeyEventArgs(Keys.Up)); + } + } + + public void AnalogDecrementByOne() + { + if (AxisEditingMode) + { + EditAnalogProgrammatically(new KeyEventArgs(Keys.Down)); + } + } + + public void AnalogIncrementByTen() + { + if (AxisEditingMode) + { + EditAnalogProgrammatically(new KeyEventArgs(Keys.Up | Keys.Shift)); + } + } + + public void AnalogDecrementByTen() + { + if (AxisEditingMode) + { + EditAnalogProgrammatically(new KeyEventArgs(Keys.Down | Keys.Shift)); + } + } + + public void AnalogMax() + { + if (AxisEditingMode) + { + EditAnalogProgrammatically(new KeyEventArgs(Keys.Right)); + } + } + + public void AnalogMin() + { + if (AxisEditingMode) + { + EditAnalogProgrammatically(new KeyEventArgs(Keys.Left)); + } + } + + public void EditAnalogProgrammatically(KeyEventArgs e) + { + if (!AxisEditingMode) + { + return; + } + + int value = CurrentTasMovie.GetAxisState(_axisEditRow, _axisEditColumn); + int prev = value; + string prevTyped = _axisTypedValue; + + var range = ControllerType.Axes[_axisEditColumn]; + + // feos: typing past max digits overwrites existing value, not touching the sign + // but doesn't handle situations where the range is like -50 through 100, where minimum is negative and has less digits + // it just uses 3 as maxDigits there too, leaving room for typing impossible values (that are still ignored by the game and then clamped) + int maxDigits = range.MaxDigits; + int curDigits = _axisTypedValue.Length; + string curMinus; + if (_axisTypedValue.StartsWith('-')) + { + curDigits -= 1; + curMinus = "-"; + } + else + { + curMinus = ""; + } + + if (e.KeyCode == Keys.Right) + { + value = range.Max; + _axisTypedValue = value.ToString(NumberFormatInfo.InvariantInfo); + } + else if (e.KeyCode == Keys.Left) + { + value = range.Min; + _axisTypedValue = value.ToString(NumberFormatInfo.InvariantInfo); + } + else if (e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9) + { + if (curDigits >= maxDigits) + { + _axisTypedValue = curMinus; + } + + _axisTypedValue += e.KeyCode - Keys.D0; + } + else if (e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9) + { + if (curDigits >= maxDigits) + { + _axisTypedValue = curMinus; + } + + _axisTypedValue += e.KeyCode - Keys.NumPad0; + } + else if (e.KeyCode == Keys.OemMinus || e.KeyCode == Keys.Subtract) + { + _axisTypedValue = _axisTypedValue.StartsWith('-') + ? _axisTypedValue.Substring(startIndex: 1) + : $"-{_axisTypedValue}"; + } + else if (e.KeyCode == Keys.Back) + { + if (_axisTypedValue.Length is 0) // Very first key press is backspace? + { + _axisTypedValue = value.ToString(NumberFormatInfo.InvariantInfo); + } + + _axisTypedValue = _axisTypedValue.Substring(startIndex: 0, length: _axisTypedValue.Length - 1); // drop last char + if (!int.TryParse(_axisTypedValue, out value)) value = 0; + } + else if (e.KeyCode == Keys.Enter) + { + _axisEditYPos = -1; + AxisEditRow = -1; + } + else if (e.KeyCode == Keys.Escape) + { + _axisEditYPos = -1; + + if (_axisBackupState != _axisPaintState) + { + CurrentTasMovie.SetAxisState(_axisEditRow, _axisEditColumn, _axisBackupState); + _triggerAutoRestore = Emulator.Frame > _axisEditRow; + TastudioPlayMode(true); + JumpToGreenzone(); + DoTriggeredAutoRestoreIfNeeded(); + } + + AxisEditRow = -1; + } + else + { + int changeBy = 0; + if (e.KeyCode == Keys.Up) + { + changeBy = 1; + } + else if (e.KeyCode == Keys.Down) + { + changeBy = -1; + } + + if (ModifierKeys == Keys.Shift) + { + changeBy *= 10; + } + + value += changeBy; + if (changeBy != 0) + { + _axisTypedValue = value.ToString(NumberFormatInfo.InvariantInfo); + } + } + + if (!AxisEditingMode) + { + CurrentTasMovie.ChangeLog.EndBatch(); + } + else + { + if (_axisTypedValue.Length is 0) + { + if (prevTyped != "") + { + value = ControllerType.Axes[_axisEditColumn].Neutral; + CurrentTasMovie.SetAxisState(_axisEditRow, _axisEditColumn, value); + } + } + else + { + if (int.TryParse(_axisTypedValue, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out value)) // String "-" can't be parsed. + { + value = value.ConstrainWithin(range.Range); + + CurrentTasMovie.SetAxisState(_axisEditRow, _axisEditColumn, value); + } + } + + foreach (int row in _extraAxisRows) + { + CurrentTasMovie.SetAxisState(row, _axisEditColumn, value); + } + + if (value != prev) // Auto-restore + { + _triggerAutoRestore = Emulator.Frame > _axisEditRow; + TastudioPlayMode(true); + JumpToGreenzone(); + DoTriggeredAutoRestoreIfNeeded(); + } + } + + RefreshDialog(); + } + + private void TasView_KeyDown(object sender, KeyEventArgs e) + { + // taseditor uses Ctrl for selection and Shift for frame cursor + if (e.IsShift(Keys.PageUp)) + { + GoToPreviousMarker(); + } + else if (e.IsShift(Keys.PageDown)) + { + GoToNextMarker(); + } + else if (e.IsShift(Keys.Home)) + { + GoToFrame(0); + } + else if (e.IsShift(Keys.End)) + { + GoToFrame(CurrentTasMovie.InputLogLength - 1); + } + + if (AxisEditingMode + && e.KeyCode != Keys.Right + && e.KeyCode != Keys.Left + && e.KeyCode != Keys.Up + && e.KeyCode != Keys.Down) + { + EditAnalogProgrammatically(e); + } + + RefreshDialog(); + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.MenuItems.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.MenuItems.cs new file mode 100644 index 00000000000..9db036dffaf --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.MenuItems.cs @@ -0,0 +1,1655 @@ +using System.IO; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using BizHawk.Client.Common; +using BizHawk.Client.EmuHawk.ToolExtensions; +using BizHawk.Common; +using BizHawk.Common.CollectionExtensions; +using BizHawk.Common.StringExtensions; +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.EmuHawk +{ + public partial class TAStudioMPR + { + private static readonly FilesystemFilterSet MoviesFSFilterSet = new( + new FilesystemFilter("All Available Files", MovieService.MovieExtensions.Reverse().ToArray()), + FilesystemFilter.TAStudioProjects, + FilesystemFilter.BizHawkMovies); + + private void FileSubMenu_DropDownOpened(object sender, EventArgs e) + { + SaveBackupMenuItem.Enabled = SaveBk2BackupMenuItem.Enabled = !string.IsNullOrWhiteSpace(CurrentTasMovie.Filename) && CurrentTasMovie.Filename != DefaultTasProjName(); + saveSelectionToMacroToolStripMenuItem.Enabled = + placeMacroAtSelectionToolStripMenuItem.Enabled = + recentMacrosToolStripMenuItem.Enabled = + TasView1.AnyRowsSelected; + } + + private void NewFromSubMenu_DropDownOpened(object sender, EventArgs e) + { + NewFromNowMenuItem.Enabled = + CurrentTasMovie.InputLogLength > 0 + && !CurrentTasMovie.StartsFromSaveRam; + + NewFromCurrentSaveRamMenuItem.Enabled = + CurrentTasMovie.InputLogLength > 0 + && SaveRamEmulator != null; + } + + private void StartNewProjectFromNowMenuItem_Click(object sender, EventArgs e) + { + if (AskSaveChanges()) + { + var newProject = CurrentTasMovie.ConvertToSavestateAnchoredMovie( + Emulator.Frame, StatableEmulator.CloneSavestate()); + + MainForm.PauseEmulator(); + LoadMovie(newProject, true); + } + } + + private void StartANewProjectFromSaveRamMenuItem_Click(object sender, EventArgs e) + { + if (AskSaveChanges()) + { + var saveRam = SaveRamEmulator?.CloneSaveRam() ?? throw new Exception("No SaveRam"); + GoToFrame(TasView1.AnyRowsSelected ? TasView1.FirstSelectedRowIndex : 0); + var newProject = CurrentTasMovie.ConvertToSaveRamAnchoredMovie(saveRam); + MainForm.PauseEmulator(); + LoadMovie(newProject, true); + } + } + + private void RecentSubMenu_DropDownOpened(object sender, EventArgs e) + => RecentSubMenu.ReplaceDropDownItems(Settings.RecentTas.RecentMenu(this, DummyLoadProject, "Project")); + + private void NewTasMenuItem_Click(object sender, EventArgs e) => StartNewTasMovie(); + + private void OpenTasMenuItem_Click(object sender, EventArgs e) + { + if (!AskSaveChanges()) return; + var filename = CurrentTasMovie.Filename; + if (string.IsNullOrWhiteSpace(filename) || filename == DefaultTasProjName()) + { + filename = ""; + } + var result = this.ShowFileOpenDialog( + filter: MoviesFSFilterSet, + initDir: Config!.PathEntries.MovieAbsolutePath(), + initFileName: filename); + if (result is not null) LoadMovieFile(result, askToSave: false); + } + + /// + /// Load the movie with the given filename within TAStudio. + /// + public bool LoadMovieFile(string filename, bool askToSave = true) + { + if (askToSave && !AskSaveChanges()) return false; + if (filename.EndsWithOrdinal(MovieService.TasMovieExtension)) + { + return LoadFileWithFallback(filename); + } + if (filename.EndsWithOrdinal(MovieService.StandardMovieExtension)) + { + if (!DialogController.ShowMessageBox2( + caption: "Convert movie", + icon: EMsgBoxIcon.Question, + text: "This is a regular movie, a new project must be created from it to use in TAStudio\nProceed?", + useOKCancel: true)) + { + return false; + } + + return LoadFileWithFallback(filename); + } + DialogController.ShowMessageBox( + caption: "Movie load error", + icon: EMsgBoxIcon.Error, + text: "This is not a BizHawk movie!"); + return false; + } + + private void SaveTasMenuItem_Click(object sender, EventArgs e) + { + if (string.IsNullOrEmpty(CurrentTasMovie.Filename) || CurrentTasMovie.Filename == DefaultTasProjName()) + { + SaveAsTas(); + } + else + { + SaveTas(); + } + if (Settings.BackupPerFileSave) + { + SaveTas(saveBackup: true); + } + } + + private void SaveAsTasMenuItem_Click(object sender, EventArgs e) + { + SaveAsTas(); + if (Settings.BackupPerFileSave) + { + SaveTas(saveBackup: true); + } + } + + private void SaveBackupMenuItem_Click(object sender, EventArgs e) + { + SaveTas(saveBackup: true); + } + + private void SaveBk2BackupMenuItem_Click(object sender, EventArgs e) + { + SaveTas(saveAsBk2: true, saveBackup: true); + } + + private void SaveSelectionToMacroMenuItem_Click(object sender, EventArgs e) + { + if (!TasView1.Focused && TasView1.AnyRowsSelected) + { + return; + } + + if (TasView1.SelectionEndIndex == CurrentTasMovie.InputLogLength) + { + TasView1.SelectRow(CurrentTasMovie.InputLogLength, false); + } + + var file = SaveFileDialog( + null, + MacroInputTool.SuggestedFolder(Config, Game), + MacroInputTool.MacrosFSFilterSet, + this + ); + + if (file != null) + { + var selectionStart = TasView1.SelectionStartIndex!.Value; + new MovieZone( + Emulator, + Tools, + MovieSession, + start: selectionStart, + length: TasView1.SelectionEndIndex!.Value - selectionStart + 1) + .Save(file.FullName); + + Config.RecentMacros.Add(file.FullName); + } + } + + private void PlaceMacroAtSelectionMenuItem_Click(object sender, EventArgs e) + { + if (!CurrentTasView.Focused && CurrentTasView.AnyRowsSelected) + { + return; + } + + var file = OpenFileDialog( + null, + MacroInputTool.SuggestedFolder(Config, Game), + MacroInputTool.MacrosFSFilterSet + ); + + if (file != null) + { + DummyLoadMacro(file.FullName); + Config.RecentMacros.Add(file.FullName); + } + } + + private void RecentMacrosMenuItem_DropDownOpened(object sender, EventArgs e) + => recentMacrosToolStripMenuItem.ReplaceDropDownItems(Config!.RecentMacros.RecentMenu(this, DummyLoadMacro, "Macro", noAutoload: true)); + + private void ToBk2MenuItem_Click(object sender, EventArgs e) + { + _autosaveTimer.Stop(); + + if (Emulator.HasCycleTiming() && !CurrentTasMovie.IsAtEnd()) + { + DialogController.ShowMessageBox("This core requires emulation to be on the last frame when writing the movie, otherwise movie length will appear incorrect.", "Warning", EMsgBoxIcon.Warning); + } + + string filename = CurrentTasMovie.Filename; + if (string.IsNullOrWhiteSpace(filename) || filename == DefaultTasProjName()) + { + filename = SuggestedTasProjName(); + } + + var fileInfo = new FileInfo(Path.ChangeExtension(filename, Bk2Movie.Extension)); + if (fileInfo.Exists) + { + fileInfo = SaveFileDialog(currentFile: fileInfo.Name, path: Config!.PathEntries.MovieAbsolutePath(), new FilesystemFilterSet(FilesystemFilter.BizHawkMovies), this); + } + + if (fileInfo is not null) + { + MessageStatusLabel.Text = "Exporting to .bk2..."; + MessageStatusLabel.Owner.Update(); + Cursor = Cursors.WaitCursor; + var bk2 = CurrentTasMovie.ToBk2(); + bk2.Filename = fileInfo.FullName; + bk2.Attach(Emulator); // required to be able to save the cycle count for ICycleTiming emulators + bk2.Save(); + MessageStatusLabel.Text = $"{bk2.Name} exported."; + Cursor = Cursors.Default; + } + else + { + MessageStatusLabel.Text = "bk2 export cancelled."; + } + + if (Settings.AutosaveInterval > 0) + { + _autosaveTimer.Start(); + } + } + + private void EditSubMenu_DropDownOpened(object sender, EventArgs e) + { + DeselectMenuItem.Enabled = + SelectBetweenMarkersMenuItem.Enabled = + CopyMenuItem.Enabled = + CutMenuItem.Enabled = + ClearFramesMenuItem.Enabled = + DeleteFramesMenuItem.Enabled = + CloneFramesMenuItem.Enabled = + CloneFramesXTimesMenuItem.Enabled = + TruncateMenuItem.Enabled = + InsertFrameMenuItem.Enabled = + InsertNumFramesMenuItem.Enabled = + TasView1.AnyRowsSelected; + + ReselectClipboardMenuItem.Enabled = + PasteMenuItem.Enabled = + PasteInsertMenuItem.Enabled = TasView1.AnyRowsSelected + && (Clipboard.GetDataObject()?.GetDataPresent(DataFormats.StringFormat) ?? false); + + ClearGreenzoneMenuItem.Enabled = + CurrentTasMovie != null && CurrentTasMovie.TasStateManager.Count > 1; + + GreenzoneICheckSeparator.Visible = + StateHistoryIntegrityCheckMenuItem.Visible = + VersionInfo.DeveloperBuild; + + UndoMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Undo"]; + RedoMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Redo"]; + SelectBetweenMarkersMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Sel. bet. Markers"]; + SelectAllMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Select All"]; + ReselectClipboardMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Reselect Clip."]; + ClearFramesMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Clear Frames"]; + DeleteFramesMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Delete Frames"]; + InsertFrameMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Insert Frame"]; + InsertNumFramesMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Insert # Frames"]; + CloneFramesMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Clone Frames"]; + CloneFramesXTimesMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Clone # Times"]; + } + + 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; + } + + 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; + } + + private void ShowUndoHistoryMenuItem_Click(object sender, EventArgs e) + { + _undoForm = new UndoHistoryFormMPR(this) { Owner = this }; + _undoForm.Show(); + _undoForm.UpdateValues(); + } + + private void DeselectMenuItem_Click(object sender, EventArgs e) + { + CurrentTasView.DeselectAll(); + CurrentTasView.Refresh(); + } + + /// TODO merge w/ Deselect? + private void SelectAllMenuItem_Click(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + tasView.SelectAll(); + tasView.Refresh(); + } + } + + private void SelectBetweenMarkersMenuItem_Click(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + + if (tasView.Focused && tasView.AnyRowsSelected) + { + var selectionEnd = tasView.SelectionEndIndex ?? 0; + var prevMarker = CurrentTasMovie.Markers.PreviousOrCurrent(selectionEnd); + var nextMarker = CurrentTasMovie.Markers.Next(selectionEnd); + + int prev = prevMarker?.Frame ?? 0; + int next = nextMarker?.Frame ?? CurrentTasMovie.InputLogLength; + + tasView.DeselectAll(); + for (int i = prev; i < next; i++) + { + tasView.SelectRow(i, true); + } + + SetSplicer(); + tasView.Refresh(); + } + } + } + private void ReselectClipboardMenuItem_Click(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + if (tasView.Focused && tasView.AnyRowsSelected) + { + tasView.DeselectAll(); + foreach (var item in _tasClipboard) + { + tasView.SelectRow(item.Frame, true); + } + + SetSplicer(); + tasView.Refresh(); + } + } + } + + private void CopyMenuItem_Click(object sender, EventArgs e) + { + int tasViewIndex = TasViews.IndexOf(CurrentTasView); + + if (CurrentTasView.AnyRowsSelected) + { + _tasClipboard.Clear(); + var list = CurrentTasView.SelectedRows.ToArray(); + var sb = new StringBuilder(); + + foreach (var index in list) + { + var input = CurrentTasMovie.GetInputState(index); + if (input == null) + { + break; + } + + _tasClipboard.Add(new TasClipboardEntry(index, input)); + var logEntry = Bk2LogEntryGenerator.GenerateLogEntry(input); + sb.AppendLine(Settings.CopyIncludesFrameNo ? $"{FrameToStringPadded(index)} {logEntry}" : logEntry); + } + + Clipboard.SetDataObject(sb.ToString()); + SetSplicer(); + } + } + + //private void PasteMenuItem_Click(object sender, EventArgs e) + //{ + // int tasViewIndex = TasViews.IndexOf(CurrentTasView); + + // if (CurrentTasView.AnyRowsSelected) + // { + // // TODO: if highlighting 2 rows and pasting 3, only paste 2 of them + // // FCEUX Taseditor doesn't do this, but I think it is the expected behavior in editor programs + + // // TODO: copy paste from PasteInsertMenuItem_Click! + // IDataObject data = Clipboard.GetDataObject(); + // if (data != null && data.GetDataPresent(DataFormats.StringFormat)) + // { + // string input = (string) data.GetData(DataFormats.StringFormat); + // if (!string.IsNullOrWhiteSpace(input)) + // { + // string[] lines = input.Split('\n'); + // if (lines.Length > 0) + // { + // _tasClipboard.Clear(); + // int linesToPaste = lines.Length; + // if (lines[lines.Length - 1].Length is 0) linesToPaste--; + // for (int i = 0; i < linesToPaste; i++) + // { + // var line = ControllerFromMnemonicStr(lines[i]); + // if (line == null) + // { + // return; + // } + + // _tasClipboard.Add(new TasClipboardEntry(i, line)); + // } + + // var rollbackFrame = CurrentTasMovie.CopyOverInput(CurrentTasView.SelectionStartIndex ?? 0, _tasClipboard.Select(static x => x.ControllerState)); + // if (rollbackFrame > 0) + // { + // GoToLastEmulatedFrameIfNecessary(rollbackFrame); + // DoAutoRestore(); + // } + + // FullRefresh(); + // } + // } + // } + // } + //} + private void PasteMenuItem_Click(object sender, EventArgs e) + { + int tasViewIndex = TasViews.IndexOf(CurrentTasView); + + if (CurrentTasView.AnyRowsSelected) + { + // TODO: if highlighting 2 rows and pasting 3, only paste 2 of them + // FCEUX Taseditor doesn't do this, but I think it is the expected behavior in editor programs + + // TODO: copy paste from PasteInsertMenuItem_Click! + IDataObject data = Clipboard.GetDataObject(); + if (data != null && data.GetDataPresent(DataFormats.StringFormat)) + { + string input = (string) data.GetData(DataFormats.StringFormat); + if (!string.IsNullOrWhiteSpace(input)) + { + string[] lines = input.Split('\n'); + if (lines.Length > 0) + { + _tasClipboard.Clear(); + int linesToPaste = lines.Length; + if (lines[lines.Length - 1].Length is 0) linesToPaste--; + for (int i = 0; i < linesToPaste; i++) + { + var line = ControllerFromMnemonicStr(lines[i]); + if (line == null) + { + return; + } + + _tasClipboard.Add(new TasClipboardEntry(i, line)); + } + + int startOffset = 1; //starts with "|" + for (int k = 0; k < tasViewIndex; k++) //add up inputs to get start string offset + { + startOffset += Emulator.ControllerDefinition.ControlsOrdered[k].Count; + startOffset += 1; //add 1 for pipe + } + int currentControlLength = Emulator.ControllerDefinition.ControlsOrdered[tasViewIndex].Count; + + var framesToInsert = CurrentTasView.SelectedRows; + var insertionFrame = Math.Min((CurrentTasView.SelectionEndIndex ?? 0) + 1, CurrentTasMovie.InputLogLength); + var needsToRollback = CurrentTasView.SelectionStartIndex < Emulator.Frame; + + var inputLog = framesToInsert + .Select(frame => CurrentTasMovie.GetInputLogEntry(frame)) + .ToList(); + + var rollbackFrame = 0; + //CurrentTasMovie.InsertInputMPR(insertionFrame, inputLog, startOffset, currentControlLength); + rollbackFrame = CurrentTasMovie.CopyOverInputMPR(CurrentTasView.SelectionStartIndex ?? 0, _tasClipboard.Select(static x => x.ControllerState), startOffset, currentControlLength); + + + if (rollbackFrame > 0) + { + GoToLastEmulatedFrameIfNecessary(rollbackFrame); + DoAutoRestore(); + } + + FullRefresh(); + } + } + } + } + } + + private void PasteToDestMenuItem_Click(object sender, EventArgs e) + { + var tasViewSourceName = sender.ToString(); + InputRoll sourceTasView = TasViews.Find(t => t.Name == tasViewSourceName); + var tasViewSourceIndex = TasViews.IndexOf(sourceTasView); //also used to identify controller controller + + int tasViewDestIndex = TasViews.IndexOf(CurrentTasView); + + if (CurrentTasView.AnyRowsSelected && sourceTasView.AnyRowsSelected) + { + int startOffset = 1; //starts with "|" + for (int k = 0; k < tasViewDestIndex; k++) //add up inputs to get start string offset + { + startOffset += Emulator.ControllerDefinition.ControlsOrdered[k].Count; + startOffset += 1; //add 1 for pipe + } + int currentControlLength = Emulator.ControllerDefinition.ControlsOrdered[tasViewDestIndex].Count; + + var framesToInsert = sourceTasView.SelectedRows; + var insertionFrame = Math.Min((CurrentTasView.SelectionEndIndex ?? 0) + 1, CurrentTasMovie.InputLogLength); + var needsToRollback = CurrentTasView.SelectionStartIndex < Emulator.Frame; + + var inputLog = framesToInsert + .Select(frame => CurrentTasMovie.GetInputLogEntry(frame)) + .ToList(); + + var rollbackFrame = 0; + + int sourceStartOffset = 1; //starts with "|" + for (int k = 0; k < tasViewSourceIndex; k++) //add up inputs to get start string offset + { + sourceStartOffset += Emulator.ControllerDefinition.ControlsOrdered[k].Count; + sourceStartOffset += 1; //add 1 for pipe + } + int sourceCurrentControlLength = Emulator.ControllerDefinition.ControlsOrdered[tasViewDestIndex].Count; + + if (Emulator.ControllerDefinition.ControlsOrdered[tasViewSourceIndex].Count != Emulator.ControllerDefinition.ControlsOrdered[tasViewDestIndex].Count) + { + //("Cannot copy to another TasView where the controller definitions are not equal"); + return; + } + + rollbackFrame = CurrentTasMovie.CopyOverDestInputMPR( + CurrentTasView.SelectionStartIndex ?? 0, + inputLog, + startOffset, + currentControlLength, + sourceStartOffset); + + if (rollbackFrame > 0) + { + GoToLastEmulatedFrameIfNecessary(rollbackFrame); + DoAutoRestore(); + } + + FullRefresh(); + } + } + + private void PasteInsertMenuItem_Click(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + if (tasView.Focused && tasView.AnyRowsSelected) + { + // copy paste from PasteMenuItem_Click! + IDataObject data = Clipboard.GetDataObject(); + if (data != null && data.GetDataPresent(DataFormats.StringFormat)) + { + string input = (string) data.GetData(DataFormats.StringFormat); + if (!string.IsNullOrWhiteSpace(input)) + { + string[] lines = input.Split('\n'); + if (lines.Length > 0) + { + _tasClipboard.Clear(); + int linesToPaste = lines.Length; + if (lines[lines.Length - 1].Length is 0) linesToPaste--; + for (int i = 0; i < linesToPaste; i++) + { + var line = ControllerFromMnemonicStr(lines[i]); + if (line == null) + { + return; + } + + _tasClipboard.Add(new TasClipboardEntry(i, line)); + } + + var selectionStart = TasView1.SelectionStartIndex; + var needsToRollback = selectionStart < Emulator.Frame; + CurrentTasMovie.InsertInput(selectionStart ?? 0, _tasClipboard.Select(static x => x.ControllerState)); + if (needsToRollback) + { + GoToLastEmulatedFrameIfNecessary(selectionStart!.Value); + DoAutoRestore(); + } + + FullRefresh(); + } + } + } + } + } + } + + //private void CutMenuItem_Click(object sender, EventArgs e) + //{ + // foreach (InputRoll tasView in TasViews) + // { + // if (tasView.Focused && tasView.AnyRowsSelected) + // { + // var selectionStart = TasView1.SelectionStartIndex; + // var needsToRollback = selectionStart < Emulator.Frame; + // var rollBackFrame = selectionStart ?? 0; + + // _tasClipboard.Clear(); + // var list = TasView1.SelectedRows.ToArray(); + // var sb = new StringBuilder(); + + // foreach (var index in list) // copy of CopyMenuItem_Click() + // { + // var input = CurrentTasMovie.GetInputState(index); + // if (input == null) + // { + // break; + // } + + // _tasClipboard.Add(new TasClipboardEntry(index, input)); + // sb.AppendLine(Bk2LogEntryGenerator.GenerateLogEntry(input)); + // } + + // Clipboard.SetDataObject(sb.ToString()); + // CurrentTasMovie.RemoveFrames(list); + // SetSplicer(); + + // if (needsToRollback) + // { + // GoToLastEmulatedFrameIfNecessary(rollBackFrame); + // DoAutoRestore(); + // } + + // FullRefresh(); + // } + // } + //} + + private void CutMenuItem_Click(object sender, EventArgs e) + { + int tasViewIndex = TasViews.IndexOf(CurrentTasView); + + if (CurrentTasView.AnyRowsSelected) + { + int startOffset = 1; //starts with "|" + for (int k = 0; k < tasViewIndex; k++) //add up inputs to get start string offset + { + startOffset += Emulator.ControllerDefinition.ControlsOrdered[k].Count; + startOffset += 1; //add 1 for pipe + } + int currentControlLength = Emulator.ControllerDefinition.ControlsOrdered[tasViewIndex].Count; + + var selectionStart = CurrentTasView.SelectionStartIndex; + var needsToRollback = selectionStart < Emulator.Frame; + var rollBackFrame = selectionStart ?? 0; + + _tasClipboard.Clear(); + var list = CurrentTasView.SelectedRows.ToArray(); + var sb = new StringBuilder(); + + foreach (var index in list) // copy of CopyMenuItem_Click() + { + var input = CurrentTasMovie.GetInputState(index); + if (input == null) + { + break; + } + + _tasClipboard.Add(new TasClipboardEntry(index, input)); + sb.AppendLine(Bk2LogEntryGenerator.GenerateLogEntry(input)); + } + + Clipboard.SetDataObject(sb.ToString()); + CurrentTasMovie.RemoveFramesMPR(CurrentTasView.SelectedRows.ToArray(), startOffset, currentControlLength); + + //CurrentTasMovie.RemoveFrames(list); + + SetSplicer(); + + if (needsToRollback) + { + GoToLastEmulatedFrameIfNecessary(rollBackFrame); + DoAutoRestore(); + } + + FullRefresh(); + } + } + + + + private void ClearFramesMenuItem_Click(object sender, EventArgs e) + { + int tasViewIndex = TasViews.IndexOf(CurrentTasView); + + if (CurrentTasView.AnyRowsSelected) + { + int startOffset = 1; //starts with "|" + for (int k = 0; k < tasViewIndex; k++) //add up inputs to get start string offset + { + startOffset += Emulator.ControllerDefinition.ControlsOrdered[k].Count; + startOffset += 1; //add 1 for pipe + } + int currentControlLength = Emulator.ControllerDefinition.ControlsOrdered[tasViewIndex].Count; + + var firstWithInput = FirstNonEmptySelectedFrame; + bool needsToRollback = firstWithInput.HasValue && firstWithInput < Emulator.Frame; + var rollBackFrame = TasViews[tasViewIndex].SelectionStartIndex ?? 0; + + CurrentTasMovie.ChangeLog.BeginNewBatch($"Clear frames {TasViews[tasViewIndex].SelectionStartIndex}-{TasViews[tasViewIndex].SelectionEndIndex}"); + foreach (int frame in TasViews[tasViewIndex].SelectedRows) + { + CurrentTasMovie.ClearFrameMPR(frame, startOffset, currentControlLength); + } + + CurrentTasMovie.ChangeLog.EndBatch(); + + if (needsToRollback) + { + GoToLastEmulatedFrameIfNecessary(rollBackFrame); + DoAutoRestore(); + } + + FullRefresh(); + } + } + + private void DeleteFramesMenuItem_Click(object sender, EventArgs e) + { + int tasViewIndex = TasViews.IndexOf(CurrentTasView); + + if (CurrentTasView.AnyRowsSelected) + { + int startOffset = 1; //starts with "|" + for (int k = 0; k < tasViewIndex; k++) //add up inputs to get start string offset + { + startOffset += Emulator.ControllerDefinition.ControlsOrdered[k].Count; + startOffset += 1; //add 1 for pipe + } + int currentControlLength = Emulator.ControllerDefinition.ControlsOrdered[tasViewIndex].Count; + + var selectionStart = CurrentTasView.SelectionStartIndex; + var needsToRollback = selectionStart < Emulator.Frame; + var rollBackFrame = selectionStart ?? 0; + if (rollBackFrame >= CurrentTasMovie.InputLogLength) + { + // Cannot delete non-existent frames + FullRefresh(); + return; + } + + CurrentTasMovie.RemoveFramesMPR(CurrentTasView.SelectedRows.ToArray(), startOffset, currentControlLength); + SetTasViewRowCount(); + SetSplicer(); + + if (needsToRollback) + { + GoToLastEmulatedFrameIfNecessary(rollBackFrame); + DoAutoRestore(); + } + + FullRefresh(); + } + } + + + private void CloneFramesMenuItem_Click(object sender, EventArgs e) + { + CloneFramesXTimes(1); + } + + private void CloneFramesXTimesMenuItem_Click(object sender, EventArgs e) + { + using var framesPrompt = new FramesPrompt("Clone # Times", "Insert times to clone:"); + if (framesPrompt.ShowDialogOnScreen().IsOk()) + { + CloneFramesXTimes(framesPrompt.Frames); + } + } + + private void CloneFramesXTimes(int timesToClone) + { + int tasViewIndex = TasViews.IndexOf(CurrentTasView); + + if (CurrentTasView.AnyRowsSelected) + { + int startOffset = 1; //starts with "|" + for (int k = 0; k < tasViewIndex; k++) //add up inputs to get start string offset + { + startOffset += Emulator.ControllerDefinition.ControlsOrdered[k].Count; + startOffset += 1; //add 1 for pipe + } + int currentControlLength = Emulator.ControllerDefinition.ControlsOrdered[tasViewIndex].Count; + + for (int j = 0; j < timesToClone; j++) + { + var framesToInsert = CurrentTasView.SelectedRows; + var insertionFrame = Math.Min((CurrentTasView.SelectionEndIndex ?? 0) + 1, CurrentTasMovie.InputLogLength); + var needsToRollback = CurrentTasView.SelectionStartIndex < Emulator.Frame; + + var inputLog = framesToInsert + .Select(frame => CurrentTasMovie.GetInputLogEntry(frame)) + .ToList(); + + //A clone operation will insert the selected stuff for currently selected frames. + //All the other inputs besides the current controls need to stay the same. + //the current controller group need to shift down with the clone. + + CurrentTasMovie.InsertInputMPR(insertionFrame, inputLog, startOffset, currentControlLength); + + if (needsToRollback) + { + GoToLastEmulatedFrameIfNecessary(insertionFrame); + DoAutoRestore(); + } + + FullRefresh(); + } + } + } + + private void InsertFrameMenuItem_Click(object sender, EventArgs e) + { + int tasViewIndex = TasViews.IndexOf(CurrentTasView); + + if (CurrentTasView.AnyRowsSelected) + { + int startOffset = 1; //starts with "|" + for (int k = 0; k < tasViewIndex; k++) //add up inputs to get start string offset + { + startOffset += Emulator.ControllerDefinition.ControlsOrdered[k].Count; + startOffset += 1; //add 1 for pipe + } + int currentControlLength = Emulator.ControllerDefinition.ControlsOrdered[tasViewIndex].Count; + + var selectionStart = CurrentTasView.SelectionStartIndex; + var insertionFrame = selectionStart ?? 0; + var needsToRollback = selectionStart < Emulator.Frame; + + CurrentTasMovie.InsertEmptyFrameMPR(insertionFrame, startOffset, currentControlLength); + + if (needsToRollback) + { + GoToLastEmulatedFrameIfNecessary(insertionFrame); + DoAutoRestore(); + } + + FullRefresh(); + + } + + } + private void InsertNumFramesMenuItem_Click(object sender, EventArgs e) + { + int tasViewIndex = TasViews.IndexOf(CurrentTasView); + + if (CurrentTasView.AnyRowsSelected) + { + int startOffset = 1; //starts with "|" + for (int k = 0; k < tasViewIndex; k++) //add up inputs to get start string offset + { + startOffset += Emulator.ControllerDefinition.ControlsOrdered[k].Count; + startOffset += 1; //add 1 for pipe + } + int currentControlLength = Emulator.ControllerDefinition.ControlsOrdered[tasViewIndex].Count; + + var insertionFrame = CurrentTasView.SelectionStartIndex ?? 0; + using var framesPrompt = new FramesPrompt(); + if (framesPrompt.ShowDialogOnScreen().IsOk()) + { + InsertNumFramesMPR(insertionFrame, framesPrompt.Frames); + } + } + } + + private void TruncateMenuItem_Click(object sender, EventArgs e) + { + int tasViewIndex = TasViews.IndexOf(CurrentTasView); + + if (CurrentTasView.AnyRowsSelected) + { + int startOffset = 1; //starts with "|" + for (int k = 0; k < tasViewIndex; k++) //add up inputs to get start string offset + { + startOffset += Emulator.ControllerDefinition.ControlsOrdered[k].Count; + startOffset += 1; //add 1 for pipe + } + int currentControlLength = Emulator.ControllerDefinition.ControlsOrdered[tasViewIndex].Count; + + var rollbackFrame = CurrentTasView.SelectionEndIndex ?? 0; + var needsToRollback = CurrentTasView.SelectionStartIndex < Emulator.Frame; + + CurrentTasMovie.TruncateFramesMPR(rollbackFrame, startOffset, currentControlLength); + MarkerControlMPR.MarkerInputRoll.TruncateSelection(CurrentTasMovie.Markers.Count - 1); + + if (needsToRollback) + { + GoToFrame(rollbackFrame); + } + + FullRefresh(); + } + } + + private void SetMarkersMenuItem_Click(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + if (tasView.Focused && tasView.AnyRowsSelected) + { + var selectedRows = tasView.SelectedRows.ToList(); + if (selectedRows.Count > 50) + { + var result = DialogController.ShowMessageBox2("Are you sure you want to add more than 50 markers?", "Add markers", EMsgBoxIcon.Question, useOKCancel: true); + if (!result) + { + return; + } + } + + foreach (var index in selectedRows) + { + MarkerControlMPR.AddMarker(index); + } + } + } + } + private void SetMarkerWithTextMenuItem_Click(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + if (tasView.Focused && tasView.AnyRowsSelected) + { + MarkerControlMPR.AddMarker(tasView.AnyRowsSelected ? tasView.FirstSelectedRowIndex : 0, true); + } + } + } + private void RemoveMarkersMenuItem_Click(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + if (tasView.Focused && tasView.AnyRowsSelected) + { + CurrentTasMovie.Markers.RemoveAll(m => tasView.IsRowSelected(m.Frame)); + MarkerControlMPR.UpdateMarkerCount(); + RefreshDialog(); + } + } + } + + private void ClearGreenzoneMenuItem_Click(object sender, EventArgs e) + { + CurrentTasMovie.TasStateManager.Clear(); + RefreshDialog(); + } + + private void StateHistoryIntegrityCheckMenuItem_Click(object sender, EventArgs e) + { + if (!Emulator.DeterministicEmulation) + { + if (!DialogController.ShowMessageBox2("The emulator is not deterministic. It might fail even if the difference isn't enough to cause a desync.\nContinue with check?", "Not Deterministic")) + { + return; + } + } + + GoToFrame(0); + int lastState = 0; + int goToFrame = CurrentTasMovie.TasStateManager.Last; + do + { + MainForm.FrameAdvance(); + + byte[] greenZone = CurrentTasMovie.TasStateManager[Emulator.Frame]; + if (greenZone.Length > 0) + { + byte[] state = StatableEmulator.CloneSavestate(); + + if (!state.SequenceEqual(greenZone)) + { + if (DialogController.ShowMessageBox2($"Bad data between frames {lastState} and {Emulator.Frame}. Save the relevant state (raw data)?", "Integrity Failed!")) + { + var result = this.ShowFileSaveDialog(initDir: Config!.PathEntries.ToolsAbsolutePath(), initFileName: "integrity.fresh"); + if (result is not null) + { + File.WriteAllBytes(result, state); + var path = Path.ChangeExtension(result, ".greenzoned"); + File.WriteAllBytes(path, greenZone); + } + } + + return; + } + + lastState = Emulator.Frame; + } + } + while (Emulator.Frame < goToFrame); + + DialogController.ShowMessageBox("Integrity Check passed"); + } + + private void ConfigSubMenu_DropDownOpened(object sender, EventArgs e) + { + AutopauseAtEndOfMovieMenuItem.Checked = Settings.AutoPause; + AutosaveAsBk2MenuItem.Checked = Settings.AutosaveAsBk2; + AutosaveAsBackupFileMenuItem.Checked = Settings.AutosaveAsBackupFile; + BackupPerFileSaveMenuItem.Checked = Settings.BackupPerFileSave; + SingleClickAxisEditMenuItem.Checked = Settings.SingleClickAxisEdit; + OldControlSchemeForBranchesMenuItem.Checked = Settings.OldControlSchemeForBranches; + LoadBranchOnDoubleclickMenuItem.Checked = Settings.LoadBranchOnDoubleClick; + BindMarkersToInputMenuItem.Checked = CurrentTasMovie.BindMarkersToInput; + CopyIncludesFrameNoMenuItem.Checked = Settings.CopyIncludesFrameNo; + AutoadjustInputMenuItem.Checked = Settings.AutoadjustInput; + } + + private void SetMaxUndoLevelsMenuItem_Click(object sender, EventArgs e) + { + using var prompt = new InputPrompt + { + TextInputType = InputPrompt.InputType.Unsigned, + Message = "Number of Undo Levels to keep", + InitialValue = CurrentTasMovie.ChangeLog.MaxSteps.ToString() + }; + + var result = MainForm.DoWithTempMute(() => prompt.ShowDialogOnScreen()); + if (result.IsOk()) + { + int val = 0; + try + { + val = int.Parse(prompt.PromptText); + } + catch + { + DialogController.ShowMessageBox("Invalid Entry.", "Input Error", EMsgBoxIcon.Error); + } + + if (val > 0) + { + Settings.MaxUndoSteps = CurrentTasMovie.ChangeLog.MaxSteps = val; + } + } + } + + private void CopyIncludesFrameNoMenuItem_Click(object sender, EventArgs e) + => Settings.CopyIncludesFrameNo = !Settings.CopyIncludesFrameNo; + + private void AutoadjustInputMenuItem_Click(object sender, EventArgs e) + => Settings.AutoadjustInput = !Settings.AutoadjustInput; + + private void SetAutosaveIntervalMenuItem_Click(object sender, EventArgs e) + { + using var prompt = new InputPrompt + { + TextInputType = InputPrompt.InputType.Unsigned, + Message = "Autosave Interval in seconds\nSet to 0 to disable", + InitialValue = (Settings.AutosaveInterval / 1000).ToString() + }; + + var result = MainForm.DoWithTempMute(() => prompt.ShowDialogOnScreen()); + if (result.IsOk()) + { + uint val = uint.Parse(prompt.PromptText) * 1000; + Settings.AutosaveInterval = val; + if (val > 0) + { + _autosaveTimer.Interval = (int) val; + _autosaveTimer.Start(); + } + } + } + + private void AutosaveAsBk2MenuItem_Click(object sender, EventArgs e) + => Settings.AutosaveAsBk2 = !Settings.AutosaveAsBk2; + + private void AutosaveAsBackupFileMenuItem_Click(object sender, EventArgs e) + => Settings.AutosaveAsBackupFile = !Settings.AutosaveAsBackupFile; + + private void BackupPerFileSaveMenuItem_Click(object sender, EventArgs e) + => Settings.BackupPerFileSave = !Settings.BackupPerFileSave; + + private void ApplyPatternToPaintedInputMenuItem_CheckedChanged(object sender, EventArgs e) + { + onlyOnAutoFireColumnsToolStripMenuItem.Enabled = applyPatternToPaintedInputToolStripMenuItem.Checked; + } + + private void SingleClickAxisEditMenuItem_Click(object sender, EventArgs e) + => Settings.SingleClickAxisEdit = !Settings.SingleClickAxisEdit; + + private void BindMarkersToInputMenuItem_Click(object sender, EventArgs e) + { + Settings.BindMarkersToInput = CurrentTasMovie.BindMarkersToInput = BindMarkersToInputMenuItem.Checked; + } + + private void AutoPauseAtEndMenuItem_Click(object sender, EventArgs e) + => Settings.AutoPause = !Settings.AutoPause; + + private void AutoHoldMenuItem_CheckedChanged(object sender, EventArgs e) + { + if (autoHoldToolStripMenuItem.Checked) + { + autoFireToolStripMenuItem.Checked = false; + customPatternToolStripMenuItem.Checked = false; + + if (!keepSetPatternsToolStripMenuItem.Checked) + { + UpdateAutoFire(); + } + } + } + + private void AutoFireMenuItem_CheckedChanged(object sender, EventArgs e) + { + if (autoFireToolStripMenuItem.Checked) + { + autoHoldToolStripMenuItem.Checked = false; + customPatternToolStripMenuItem.Checked = false; + + if (!keepSetPatternsToolStripMenuItem.Checked) + { + UpdateAutoFire(); + } + } + } + + private void CustomPatternMenuItem_CheckedChanged(object sender, EventArgs e) + { + if (customPatternToolStripMenuItem.Checked) + { + autoHoldToolStripMenuItem.Checked = false; + autoFireToolStripMenuItem.Checked = false; + + if (!keepSetPatternsToolStripMenuItem.Checked) + { + UpdateAutoFire(); + } + } + } + + private void SetCustomsMenuItem_Click(object sender, EventArgs e) + { + // Exceptions in PatternsForm are not caught by the debugger, I have no idea why. + // Exceptions in UndoForm are caught, which makes it weirder. + var pForm = new PatternsFormMPR(this) { Owner = this }; + pForm.Show(); + } + + private void OldControlSchemeForBranchesMenuItem_Click(object sender, EventArgs e) + => Settings.OldControlSchemeForBranches = !Settings.OldControlSchemeForBranches; + + private void LoadBranchOnDoubleClickMenuItem_Click(object sender, EventArgs e) + => Settings.LoadBranchOnDoubleClick = !Settings.LoadBranchOnDoubleClick; + + private void HeaderMenuItem_Click(object sender, EventArgs e) + { + using MovieHeaderEditor form = new(CurrentTasMovie, Config) + { + Owner = Owner, + Location = this.ChildPointToScreen(TasView1) + }; + form.ShowDialogOnScreen(); + } + + private void StateHistorySettingsMenuItem_Click(object sender, EventArgs e) + { + using GreenzoneSettings form = new( + DialogController, + new ZwinderStateManagerSettings(CurrentTasMovie.TasStateManager.Settings), + (s, k) => { CurrentTasMovie.TasStateManager.UpdateSettings(s, k); }, + false) + { + Owner = Owner, + Location = this.ChildPointToScreen(TasView1) + }; + form.ShowDialogOnScreen(); + } + + private void CommentsMenuItem_Click(object sender, EventArgs e) + { + using EditCommentsForm form = new(CurrentTasMovie, false) + { + Owner = Owner, + StartPosition = FormStartPosition.Manual, + Location = this.ChildPointToScreen(TasView1) + }; + form.ShowDialogOnScreen(); + } + + private void SubtitlesMenuItem_Click(object sender, EventArgs e) + { + using EditSubtitlesForm form = new( + DialogController, + CurrentTasMovie, + Config!.PathEntries, + readOnly: false) + { + Owner = Owner, + StartPosition = FormStartPosition.Manual, + Location = this.ChildPointToScreen(TasView1) + }; + form.ShowDialogOnScreen(); + } + + private void DefaultStateSettingsMenuItem_Click(object sender, EventArgs e) + { + using GreenzoneSettings form = new( + DialogController, + new ZwinderStateManagerSettings(Config.Movies.DefaultTasStateManagerSettings), + (s, k) => { Config.Movies.DefaultTasStateManagerSettings = s; }, + true) + { + Owner = Owner, + Location = this.ChildPointToScreen(TasView1) + }; + form.ShowDialogOnScreen(); + } + + private void SettingsSubMenu_DropDownOpened(object sender, EventArgs e) + { + RotateMenuItem.ShortcutKeyDisplayString = TasView1.RotateHotkeyStr; + } + + private void HideLagFramesSubMenu_DropDownOpened(object sender, EventArgs e) + { + HideLagFrames0.Checked = TasView1.LagFramesToHide == 0; + HideLagFrames1.Checked = TasView1.LagFramesToHide == 1; + HideLagFrames2.Checked = TasView1.LagFramesToHide == 2; + HideLagFrames3.Checked = TasView1.LagFramesToHide == 3; + hideWasLagFramesToolStripMenuItem.Checked = TasView1.HideWasLagFrames; + } + + private void IconsMenuItem_DropDownOpened(object sender, EventArgs e) + { + DenoteStatesWithIconsToolStripMenuItem.Checked = Settings.DenoteStatesWithIcons; + DenoteStatesWithBGColorToolStripMenuItem.Checked = Settings.DenoteStatesWithBGColor; + DenoteMarkersWithIconsToolStripMenuItem.Checked = Settings.DenoteMarkersWithIcons; + DenoteMarkersWithBGColorToolStripMenuItem.Checked = Settings.DenoteMarkersWithBGColor; + } + + private void FollowCursorMenuItem_DropDownOpened(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + alwaysScrollToolStripMenuItem.Checked = Settings.FollowCursorAlwaysScroll; + scrollToViewToolStripMenuItem.Checked = false; + scrollToTopToolStripMenuItem.Checked = false; + scrollToBottomToolStripMenuItem.Checked = false; + scrollToCenterToolStripMenuItem.Checked = false; + if (tasView.ScrollMethod == "near") + { + scrollToViewToolStripMenuItem.Checked = true; + } + else if (tasView.ScrollMethod == "top") + { + scrollToTopToolStripMenuItem.Checked = true; + } + else if (tasView.ScrollMethod == "bottom") + { + scrollToBottomToolStripMenuItem.Checked = true; + } + else + { + scrollToCenterToolStripMenuItem.Checked = true; + } + } + } + + private void RotateMenuItem_Click(object sender, EventArgs e) + { + TasView1.HorizontalOrientation = !TasView1.HorizontalOrientation; + CurrentTasMovie.FlagChanges(); + } + + private void HideLagFramesX_Click(object sender, EventArgs e) + { + TasView1.LagFramesToHide = (int) ((ToolStripMenuItem) sender).Tag; + MaybeFollowCursor(); + RefreshDialog(); + } + + private void HideWasLagFramesMenuItem_Click(object sender, EventArgs e) + => TasView1.HideWasLagFrames = !TasView1.HideWasLagFrames; + + private void AlwaysScrollMenuItem_Click(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + tasView.AlwaysScroll = Settings.FollowCursorAlwaysScroll = alwaysScrollToolStripMenuItem.Checked; + } + } + + private void ScrollToViewMenuItem_Click(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + tasView.ScrollMethod = Settings.FollowCursorScrollMethod = "near"; + } + } + private void ScrollToTopMenuItem_Click(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + tasView.ScrollMethod = Settings.FollowCursorScrollMethod = "top"; + } + } + private void ScrollToBottomMenuItem_Click(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + tasView.ScrollMethod = Settings.FollowCursorScrollMethod = "bottom"; + } + } + private void ScrollToCenterMenuItem_Click(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + tasView.ScrollMethod = Settings.FollowCursorScrollMethod = "center"; + } + } + private void DenoteStatesWithIconsToolStripMenuItem_Click(object sender, EventArgs e) + { + Settings.DenoteStatesWithIcons = DenoteStatesWithIconsToolStripMenuItem.Checked; + RefreshDialog(); + } + + private void DenoteStatesWithBGColorToolStripMenuItem_Click(object sender, EventArgs e) + { + Settings.DenoteStatesWithBGColor = DenoteStatesWithBGColorToolStripMenuItem.Checked; + RefreshDialog(); + } + + private void DenoteMarkersWithIconsToolStripMenuItem_Click(object sender, EventArgs e) + { + Settings.DenoteMarkersWithIcons = DenoteMarkersWithIconsToolStripMenuItem.Checked; + RefreshDialog(); + } + + private void DenoteMarkersWithBGColorToolStripMenuItem_Click(object sender, EventArgs e) + { + Settings.DenoteMarkersWithBGColor = DenoteMarkersWithBGColorToolStripMenuItem.Checked; + RefreshDialog(); + } + + private void ColorSettingsMenuItem_Click(object sender, EventArgs e) + { + using TAStudioColorSettingsFormMPR form = new(Palette, p => Settings.Palette = p) + { + Owner = Owner, + StartPosition = FormStartPosition.Manual, + Location = this.ChildPointToScreen(TasView1) + }; + form.ShowDialogOnScreen(); + } + + private void WheelScrollSpeedMenuItem_Click(object sender, EventArgs e) + { + var inputPrompt = new InputPrompt + { + TextInputType = InputPrompt.InputType.Unsigned, + Message = "Frames per tick:", + InitialValue = TasView1.ScrollSpeed.ToString() + }; + if (!this.ShowDialogWithTempMute(inputPrompt).IsOk()) return; + foreach (InputRoll tasView in TasViews) + { + tasView.ScrollSpeed = int.Parse(inputPrompt.PromptText); + } + Settings.ScrollSpeed = TasView1.ScrollSpeed; + } + + private void SetUpToolStripColumns() + { + ColumnsSubMenu.DropDownItems.Clear(); + + var columns = TasView1.AllColumns + .Where(static c => !string.IsNullOrWhiteSpace(c.Text) && c.Name is not "FrameColumn") + .ToList(); + + int workingHeight = Screen.FromControl(this).WorkingArea.Height; + int rowHeight = ColumnsSubMenu.Height + 4; + int maxRows = workingHeight / rowHeight; + int keyCount = columns.Count(c => c.Name.StartsWithOrdinal("Key ")); + int keysMenusCount = (int) Math.Ceiling((double) keyCount / maxRows); + + var keysMenus = new ToolStripMenuItem[keysMenusCount]; + + for (int i = 0; i < keysMenus.Length; i++) + { + keysMenus[i] = new ToolStripMenuItem(); + } + + var playerMenus = new ToolStripMenuItem[Emulator.ControllerDefinition.PlayerCount + 1]; + playerMenus[0] = ColumnsSubMenu; + + for (int i = 1; i < playerMenus.Length; i++) + { + playerMenus[i] = new ToolStripMenuItem($"Player {i}"); + } + + foreach (var column in columns) + { + var menuItem = new ToolStripMenuItem + { + Text = $"{column.Text} ({column.Name})", + Checked = column.Visible, + CheckOnClick = true, + Tag = column.Name + }; + + menuItem.CheckedChanged += (o, ev) => + { + ToolStripMenuItem sender = (ToolStripMenuItem) o; + TasView1.AllColumns.Find(c => c.Name == (string) sender.Tag).Visible = sender.Checked; + TasView1.AllColumns.ColumnsChanged(); + CurrentTasMovie.FlagChanges(); + TasView1.Refresh(); + ColumnsSubMenu.ShowDropDown(); + ((ToolStripMenuItem) sender.OwnerItem).ShowDropDown(); + }; + + if (column.Name.StartsWithOrdinal("Key ")) + { + keysMenus + .First(m => m.DropDownItems.Count < maxRows) + .DropDownItems + .Add(menuItem); + } + else + { + int player; + + if (column.Name.Length >= 2 && column.Name.StartsWith('P') && char.IsNumber(column.Name, 1)) + { + player = int.Parse(column.Name[1].ToString()); + } + else + { + player = 0; + } + + playerMenus[player].DropDownItems.Add(menuItem); + } + } + + foreach (var menu in keysMenus) + { + string text = $"Keys ({menu.DropDownItems[0].Tag} - {menu.DropDownItems[menu.DropDownItems.Count - 1].Tag})"; + menu.Text = text.Replace("Key ", ""); + ColumnsSubMenu.DropDownItems.Add(menu); + } + + for (int i = 1; i < playerMenus.Length; i++) + { + if (playerMenus[i].HasDropDownItems) + { + ColumnsSubMenu.DropDownItems.Add(playerMenus[i]); + } + } + + for (int i = 1; i < playerMenus.Length; i++) + { + if (playerMenus[i].HasDropDownItems) + { + ColumnsSubMenu.DropDownItems.Add(new ToolStripSeparator()); + break; + } + } + + if (keysMenus.Length > 0) + { + var item = new ToolStripMenuItem("Show Keys") + { + CheckOnClick = true, + Checked = false + }; + + foreach (var menu in keysMenus) + { + var dummyObject1 = menu; + item.CheckedChanged += (o, ev) => + { + foreach (ToolStripMenuItem menuItem in dummyObject1.DropDownItems) + { + menuItem.Checked = !menuItem.Checked; + } + + CurrentTasMovie.FlagChanges(); + TasView1.AllColumns.ColumnsChanged(); + TasView1.Refresh(); + }; + + ColumnsSubMenu.DropDownItems.Add(item); + } + } + + for (int i = 1; i < playerMenus.Length; i++) + { + if (playerMenus[i].HasDropDownItems) + { + var item = new ToolStripMenuItem($"Show Player {i}") + { + CheckOnClick = true, + Checked = playerMenus[i].DropDownItems.OfType().Any(mi => mi.Checked) + }; + + ToolStripMenuItem dummyObject = playerMenus[i]; + item.CheckedChanged += (o, ev) => + { + // TODO: preserve underlying button checked state and make this a master visibility control + foreach (ToolStripMenuItem menuItem in dummyObject.DropDownItems) + { + menuItem.Checked = item.Checked; + } + dummyObject.Visible = item.Checked; + + CurrentTasMovie.FlagChanges(); + TasView1.AllColumns.ColumnsChanged(); + TasView1.Refresh(); + }; + + ColumnsSubMenu.DropDownItems.Add(item); + } + } + } + + // ReSharper disable once UnusedMember.Local + [RestoreDefaults] + private void RestoreDefaults() //changed top three function order. test for bugs + { + SetUpToolStripColumns(); + for (int i = 0; i < TasViews.Count; i++) + { + SetUpColumnsPerControl(i); + TasViews[i].Refresh(); + } + CurrentTasMovie.FlagChanges(); + MainVertialSplit.SplitterDistance = _defaultMainSplitDistance; + BranchesMarkersSplit.SplitterDistance = _defaultBranchMarkerSplitDistance; + } + + private void RightClickMenu_Opened(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + if (tasView.Focused && tasView.AnyRowsSelected) + { + SetMarkersContextMenuItem.Enabled = + SelectBetweenMarkersContextMenuItem.Enabled = + RemoveMarkersContextMenuItem.Enabled = + DeselectContextMenuItem.Enabled = + ClearContextMenuItem.Enabled = + DeleteFramesContextMenuItem.Enabled = + CloneContextMenuItem.Enabled = + CloneXTimesContextMenuItem.Enabled = + InsertFrameContextMenuItem.Enabled = + InsertNumFramesContextMenuItem.Enabled = + TruncateContextMenuItem.Enabled = + tasView.AnyRowsSelected; + + pasteToolStripMenuItem.Enabled = + pasteInsertToolStripMenuItem.Enabled = + (Clipboard.GetDataObject()?.GetDataPresent(DataFormats.StringFormat) ?? false) + && tasView.AnyRowsSelected; + + var selectionIsSingleRow = tasView.SelectedRows.CountIsExactly(1); + StartNewProjectFromNowMenuItem.Visible = + selectionIsSingleRow + && tasView.IsRowSelected(Emulator.Frame) + && !CurrentTasMovie.StartsFromSaveRam; + + StartANewProjectFromSaveRamMenuItem.Visible = + selectionIsSingleRow + && SaveRamEmulator != null + && !CurrentTasMovie.StartsFromSavestate; + + 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; + BranchContextMenuItem.Visible = tasView.CurrentCell?.RowIndex == Emulator.Frame; + + SelectBetweenMarkersContextMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Sel. bet. Markers"]; + ClearContextMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Clear Frames"]; + DeleteFramesContextMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Delete Frames"]; + InsertFrameContextMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Insert Frame"]; + InsertNumFramesContextMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Insert # Frames"]; + CloneContextMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Clone Frames"]; + CloneXTimesContextMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Clone # Times"]; + } + } + } + + private void CancelSeekContextMenuItem_Click(object sender, EventArgs e) + { + MainForm.PauseOnFrame = null; + foreach (InputRoll tasView in TasViews) + { + tasView.Refresh(); + } + } + + private void BranchContextMenuItem_Click(object sender, EventArgs e) + { + BookMarkControlMPR.Branch(); + } + + private void TASEditorManualOnlineMenuItem_Click(object sender, EventArgs e) + { + System.Diagnostics.Process.Start("http://www.fceux.com/web/help/taseditor/"); + } + + private void ForumThreadMenuItem_Click(object sender, EventArgs e) + { + System.Diagnostics.Process.Start("https://tasvideos.org/Forum/Topics/13505"); + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.Navigation.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.Navigation.cs new file mode 100644 index 00000000000..10af4ecc31c --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.Navigation.cs @@ -0,0 +1,119 @@ +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public partial class TAStudioMPR + { + /// + /// 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 + /// + private void GoToLastEmulatedFrameIfNecessary(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 ((MainForm.EmulatorPaused || !MainForm.IsSeeking) + && !CurrentTasMovie.LastPositionStable && !_playbackInterrupted) + { + LastPositionFrame = Emulator.Frame; + CurrentTasMovie.LastPositionStable = true; // until new frame is emulated + } + + GoToFrame(frame, false, false, OnLeftMouseDown); + } + else + { + _triggerAutoRestore = false; + } + } + } + + 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. + WasRecording = CurrentTasMovie.IsRecording() || WasRecording; + + if (frame <= CurrentTasMovie.InputLogLength) + { + // Get as close as we can then emulate there + StartAtNearestFrameAndEmulate(frame, fromLua, fromRewinding); + if (!OnLeftMouseDown) { MaybeFollowCursor(); } + } + else // Emulate to a future frame + { + 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); + } + } + + public void GoToPreviousMarker() + { + if (Emulator.Frame > 0) + { + var prevMarker = CurrentTasMovie.Markers.Previous(Emulator.Frame); + var prev = prevMarker?.Frame ?? 0; + GoToFrame(prev); + } + } + + public void GoToNextMarker() + { + var nextMarker = CurrentTasMovie.Markers.Next(Emulator.Frame); + var next = nextMarker?.Frame ?? CurrentTasMovie.InputLogLength - 1; + GoToFrame(next); + } + + /// + /// Makes the given frame visible. If no frame is given, makes the current frame visible. + /// + public void SetVisibleFrame(int? frame = null) + { + if (TasView1.AlwaysScroll && _leftButtonHeld) + { + return; + } + foreach(InputRoll tasView in TasViews) + { + tasView.ScrollToIndex(frame ?? Emulator.Frame); + } + + } + + private void MaybeFollowCursor() + { + if (TasPlaybackBoxMPR.FollowCursor) + { + SetVisibleFrame(); + } + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.cs new file mode 100644 index 00000000000..8c00a907074 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.cs @@ -0,0 +1,1466 @@ +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Windows.Forms; +using System.ComponentModel; +using BizHawk.Client.Common; +using BizHawk.Client.EmuHawk.ToolExtensions; +using BizHawk.Client.EmuHawk.Properties; +using BizHawk.Common.StringExtensions; +using BizHawk.Emulation.Common; + + +namespace BizHawk.Client.EmuHawk +{ + public partial class TAStudioMPR : ToolFormBase, IToolFormAutoConfig, IControlMainform + { + public static readonly FilesystemFilterSet TAStudioProjectsFSFilterSet = new(FilesystemFilter.TAStudioProjects); + + public static Icon ToolIcon + => Resources.TAStudioIcon; + + public override bool BlocksInputWhenFocused => IsInMenuLoop; + + public new IMainFormForTools MainForm => base.MainForm; + + public new IMovieSession MovieSession => base.MovieSession; + + // TODO: UI flow that conveniently allows to start from savestate + public ITasMovie CurrentTasMovie => MovieSession.Movie as ITasMovie; + + public bool IsInMenuLoop { get; private set; } + + private readonly List _tasClipboard = new List(); + private const string CursorColumnName = "CursorColumn"; + private const string FrameColumnName = "FrameColumn"; + private MovieEndAction _originalEndAction; // The movie end behavior selected by the user (that is overridden by TAStudio) + private UndoHistoryFormMPR _undoForm; + private Timer _autosaveTimer; + + private readonly int _defaultMainSplitDistance; + private readonly int _defaultBranchMarkerSplitDistance; + + private bool _initialized; + private bool _exiting; + private bool _engaged; + + private bool CanAutoload => Settings.RecentTas.AutoLoad && !string.IsNullOrEmpty(Settings.RecentTas.MostRecent); + + /// + /// 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. + /// + public int LastPositionFrame { get; private set; } + + [ConfigPersist] + public TAStudioSettingsMPR Settings { get; set; } = new TAStudioSettingsMPR(); + + public TAStudioPaletteMPR Palette => Settings.Palette; + + [ConfigPersist] + public Font TasViewFont { get; set; } = new Font("Arial", 8.25F, FontStyle.Bold, GraphicsUnit.Point, 0); + + public List TasViews = new List(); + public InputRoll CurrentTasView = new InputRoll(); //For various events. Set in TasView_SelectedIndexChanged + public class TAStudioSettingsMPR + { + public TAStudioSettingsMPR() + { + RecentTas = new RecentFiles(8); + AutoPause = true; + FollowCursor = true; + ScrollSpeed = 6; + FollowCursorAlwaysScroll = false; + FollowCursorScrollMethod = "near"; + AutosaveInterval = 120000; + AutosaveAsBk2 = false; + AutosaveAsBackupFile = false; + BackupPerFileSave = false; + SingleClickAxisEdit = false; + OldControlSchemeForBranches = false; + LoadBranchOnDoubleClick = true; + CopyIncludesFrameNo = false; + AutoadjustInput = false; + + // default to taseditor fashion + DenoteStatesWithIcons = false; + DenoteStatesWithBGColor = true; + DenoteMarkersWithIcons = false; + DenoteMarkersWithBGColor = true; + + Palette = TAStudioPaletteMPR.Default; + } + + public RecentFiles RecentTas { get; set; } + public bool AutoPause { get; set; } + public bool AutoRestoreLastPosition { get; set; } + public bool FollowCursor { get; set; } + public int ScrollSpeed { get; set; } + public bool FollowCursorAlwaysScroll { get; set; } + public string FollowCursorScrollMethod { get; set; } + public uint AutosaveInterval { get; set; } + public bool AutosaveAsBk2 { get; set; } + public bool AutosaveAsBackupFile { get; set; } + public bool BackupPerFileSave { get; set; } + public bool SingleClickAxisEdit { get; set; } + public bool OldControlSchemeForBranches { get; set; } // branch loading will behave differently depending on the recording mode + public bool LoadBranchOnDoubleClick { get; set; } + public bool DenoteStatesWithIcons { get; set; } + public bool DenoteStatesWithBGColor { get; set; } + public bool DenoteMarkersWithIcons { get; set; } + public bool DenoteMarkersWithBGColor { get; set; } + public int MainVerticalSplitDistance { get; set; } + public int BranchMarkerSplitDistance { get; set; } + public bool BindMarkersToInput { get; set; } + public bool CopyIncludesFrameNo { get; set; } + public bool AutoadjustInput { get; set; } + public TAStudioPaletteMPR Palette { get; set; } + public int MaxUndoSteps { get; set; } = 1000; + } + + public TAStudioMPR() + { + InitializeComponent(); + + RecentSubMenu.Image = Resources.Recent; + recentMacrosToolStripMenuItem.Image = Resources.Recent; + TASEditorManualOnlineMenuItem.Image = Resources.Help; + ForumThreadMenuItem.Image = Resources.TAStudio; + Icon = ToolIcon; + + _defaultMainSplitDistance = MainVertialSplit.SplitterDistance; + _defaultBranchMarkerSplitDistance = BranchesMarkersSplit.SplitterDistance; + + // TODO: show this at all times or hide it when saving is done? + ProgressBar.Visible = false; + + WantsToControlStopMovie = true; + WantsToControlRestartMovie = true; + TasPlaybackBoxMPR.TastudioMPR = this; + MarkerControlMPR.TastudioMPR = this; + BookMarkControlMPR.TastudioMPR = this; + + LastPositionFrame = -1; + + BookMarkControlMPR.LoadedCallback = BranchLoaded; + BookMarkControlMPR.SavedCallback = BranchSaved; + BookMarkControlMPR.RemovedCallback = BranchRemoved; + } + + private void Tastudio_Load(object sender, EventArgs e) + { + this.Width = 1050; + TasView1.QueryItemText += TasView_QueryItemText; + TasView1.QueryItemBkColor += TasView_QueryItemBkColor; + TasView1.QueryRowBkColor += TasView_QueryRowBkColor; + TasView1.QueryItemIcon += TasView_QueryItemIcon; + TasView1.QueryFrameLag += TasView_QueryFrameLag; + TasView1.PointedCellChanged += TasView_PointedCellChanged; + TasView1.MouseLeave += TAStudio_MouseLeave; + TasView1.CellHovered += (_, e) => + { + if (e.NewCell.RowIndex is null) + { + toolTip1.Show(e.NewCell.Column!.Name, TasView1, PointToClient(Cursor.Position)); + } + }; + this.pasteSelectedRowsFromToolStripMenuItem.DropDownItems.Add( + new ToolStripMenuItem( + TasView1.Name, + null, + PasteToDestMenuItem_Click) + ); + TasViews.Add(TasView1); + + //get number of controllers MnemonicMapPlayerController + int controllersCount = Emulator.ControllerDefinition.ControlsOrdered.Count; + var startLocation = new System.Drawing.Point(TasView1.Location.X + TasView1.Width + 10, 20); + + //start from "2" since first TasView1 is already defined in designer. + for (int i = 2; i < controllersCount + 1; i++) + { + InputRoll tasView = new InputRoll(); + tasView.Name = "TasView" + i.ToString(); + tasView.Parent = MainVertialSplit.Panel1; + tasView.Height = TasView1.Height; + tasView.Location = startLocation; + startLocation.X += tasView.Width + 10; //for next tasView + + tasView.Anchor = ((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left); + + tasView.CellHeightPadding = 0; + tasView.ChangeSelectionWhenPaging = false; + tasView.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, 0); + tasView.FullRowSelect = true; + tasView.InputPaintingMode = true; + tasView.LetKeysModifySelection = true; + tasView.Rotatable = true; + tasView.ScrollMethod = "near"; + tasView.ScrollSpeed = 1; + + tasView.QueryItemText += TasView_QueryItemText; + tasView.QueryItemBkColor += TasView_QueryItemBkColor; + tasView.QueryRowBkColor += TasView_QueryRowBkColor; + tasView.QueryItemIcon += TasView_QueryItemIcon; + tasView.QueryFrameLag += TasView_QueryFrameLag; + tasView.PointedCellChanged += TasView_PointedCellChanged; + tasView.MouseLeave += TAStudio_MouseLeave; + + tasView.CellDropped += TasView_CellDropped; + tasView.ColumnClick += TasView_ColumnClick; + tasView.ColumnReordered += TasView_ColumnReordered; + tasView.ColumnRightClick += TasView_ColumnRightClick; + tasView.KeyDown += TasView_KeyDown; + tasView.MouseDoubleClick += TasView_MouseDoubleClick; + tasView.MouseDown += TasView_MouseDown; + tasView.MouseEnter += TasView_MouseEnter; + tasView.MouseMove += TasView_MouseMove; + tasView.MouseUp += TasView_MouseUp; + tasView.RightMouseScrolled += TasView_MouseWheel; + tasView.SelectedIndexChanged += TasView_SelectedIndexChanged; + + tasView.CellHovered += (_, e) => + { + if (e.NewCell.RowIndex is null) + { + toolTip1.Show(e.NewCell.Column!.Name, tasView, PointToClient(Cursor.Position)); + } + }; + this.ConfigSubMenu.DropDownItems.Add( + new ToolStripMenuItem( + "Toggle Disable " + tasView.Name, + null, + disableTasViewToolStripMenuItem_Click) + ); + this.pasteSelectedRowsFromToolStripMenuItem.DropDownItems.Add( + new ToolStripMenuItem( + tasView.Name, + null, + PasteToDestMenuItem_Click) + ); + TasViews.Add(tasView); + } + + + if (!Engage()) + { + Close(); + return; + } + + if (TasViews[1].Rotatable) + { + RightClickMenu.Items.AddRange(TasViews[1].GenerateContextMenuItems() + .ToArray()); + + RightClickMenu.Items + .OfType() + .First(t => t.Name == "RotateMenuItem") + .Click += (o, ov) => { CurrentTasMovie.FlagChanges(); }; + } + + for (int i = 0; i < TasViews.Count; i++) + { + TasViews[i].ScrollSpeed = Settings.ScrollSpeed; + TasViews[i].AlwaysScroll = Settings.FollowCursorAlwaysScroll; + TasViews[i].ScrollMethod = Settings.FollowCursorScrollMethod; + + _autosaveTimer = new Timer(components); + _autosaveTimer.Tick += AutosaveTimerEventProcessor; + if (Settings.AutosaveInterval > 0) + { + _autosaveTimer.Interval = (int) Settings.AutosaveInterval; + _autosaveTimer.Start(); + } + + MainVertialSplit.SetDistanceOrDefault( + Settings.MainVerticalSplitDistance, + _defaultMainSplitDistance); + + BranchesMarkersSplit.SetDistanceOrDefault( + Settings.BranchMarkerSplitDistance, + _defaultBranchMarkerSplitDistance); + + TasViews[i].Font = TasViewFont; + RefreshDialog(); + _initialized = true; + } + } + private bool LoadMostRecentOrStartNew() + { + return LoadFileWithFallback(Settings.RecentTas.MostRecent); + } + + private bool Engage(int viewIndex = 0) + { + _engaged = false; + MainForm.PauseOnFrame = null; + MainForm.PauseEmulator(); + bool success = false; + + // Nag if inaccurate core, but not if auto-loading or movie is already loaded + if (!CanAutoload && MovieSession.Movie.NotActive()) + { + // Nag but allow the user to continue anyway, so ignore the return value + MainForm.EnsureCoreIsAccurate(); + } + + // Start Scenario 1: A regular movie is active + if (MovieSession.Movie.IsActive() && MovieSession.Movie is not ITasMovie) + { + var changesString = "Would you like to save the current movie before closing it?"; + if (MovieSession.Movie.Changes) + { + changesString = "The current movie has unsaved changes. Would you like to save before closing it?"; + } + var result = DialogController.ShowMessageBox3( + "TAStudio will create a new project file from the current movie.\n\n" + changesString, + "Convert movie", + EMsgBoxIcon.Question); + if (result == true) + { + MovieSession.Movie.Save(); + } + else if (result == null) + { + return false; + } + + ConvertCurrentMovieToTasproj(); + success = StartNewMovieWrapper(CurrentTasMovie, isNew: false); + } + + // Start Scenario 2: A tasproj is already active + else if (MovieSession.Movie.IsActive() && MovieSession.Movie is ITasMovie) + { + success = LoadMovie(CurrentTasMovie, gotoFrame: Emulator.Frame); + if (!success) + { + success = StartNewTasMovie(); + } + } + + // Start Scenario 3: No movie, but user wants to autoload their last project + else if (CanAutoload) + { + success = LoadMostRecentOrStartNew(); + } + + // Start Scenario 4: No movie, default behavior of engaging tastudio with a new default project + else + { + success = StartNewTasMovie(); + } + + // Attempts to load failed, abort + if (!success) + { + Disengage(); + return false; + } + + MainForm.AddOnScreenMessage("TAStudio engaged"); + _originalEndAction = Config.Movies.MovieEndAction; + MainForm.DisableRewind(); + Config.Movies.MovieEndAction = MovieEndAction.Record; + MainForm.SetMainformMovieInfo(); + MovieSession.ReadOnly = true; + SetSplicer(); + + //Setting the tasview sizes here + var lastTasViewWidth = 0; + var lastTasViewLocation = new System.Drawing.Point(0, 20); + foreach (InputRoll tasView in TasViews) + { + var width = 0; + + foreach (var column in tasView.AllColumns) + { + width += column.Width; + } + tasView.Location = new System.Drawing.Point(lastTasViewLocation.X + lastTasViewWidth + 10, 20); + tasView.Width = width + 18;// padding for scrollbar + lastTasViewWidth = tasView.Width; + lastTasViewLocation = tasView.Location; + } + _engaged = true; + return true; + } + + private void AutosaveTimerEventProcessor(object sender, EventArgs e) + { + if (CurrentTasMovie == null) + { + return; + } + + if (!CurrentTasMovie.Changes || Settings.AutosaveInterval == 0 + || CurrentTasMovie.Filename == DefaultTasProjName()) + { + return; + } + + if (Settings.AutosaveAsBackupFile) + { + if (Settings.AutosaveAsBk2) + { + SaveTas(saveAsBk2: true, saveBackup: true); + } + else + { + SaveTas(saveBackup: true); + } + } + else + { + if (Settings.AutosaveAsBk2) + { + SaveTas(saveAsBk2: true); + } + else + { + SaveTas(); + } + } + } + + private static readonly string[] N64CButtonSuffixes = { " C Up", " C Down", " C Left", " C Right" }; + + private void SetUpColumnsPerControl(int viewIndex) + { + InputRoll tasView = TasViews[viewIndex]; + tasView.AllColumns.Clear(); + tasView.AllColumns.Add(new(name: CursorColumnName, widthUnscaled: 18, type: ColumnType.Boolean, text: string.Empty)); + tasView.AllColumns.Add(new(name: FrameColumnName, widthUnscaled: 60, text: "Frame#") + { + Rotatable = true, + }); + + //viewIndex here is the same as the control group index + foreach ((string name, string mnemonic0, int maxLength) in MnemonicMapPlayerController(viewIndex)) + { + var mnemonic = Emulator.SystemId is VSystemID.Raw.N64 && N64CButtonSuffixes.Any(name.EndsWithOrdinal) + ? $"c{mnemonic0.ToUpperInvariant()}" // prepend 'c' to differentiate from L/R buttons -- this only affects the column headers + : mnemonic0; + + var type = ControllerType.Axes.ContainsKey(name) ? ColumnType.Axis : ColumnType.Boolean; + + tasView.AllColumns.Add(new( + name: name, + widthUnscaled: (maxLength * 6) + 14, // magic numbers reused in EditBranchTextPopUp() --feos // not since eb63fa5a9 (before 2.3.3) --yoshi + type: type, + text: mnemonic)); + } + + var columnsToHide = tasView.AllColumns + .Where(c => + // todo: make a proper user editable list? + c.Name == "Power" + || c.Name == "Reset" + || c.Name == "Light Sensor" + || c.Name == "Disc Select" + || c.Name == "Disk Index" + || c.Name == "Next Drive" + || c.Name == "Next Slot" + || c.Name == "Insert Disk" + || c.Name == "Eject Disk" + || c.Name.StartsWithOrdinal("Tilt") + || c.Name.StartsWithOrdinal("Key ") + || c.Name.StartsWithOrdinal("Open") + || c.Name.StartsWithOrdinal("Close") + || c.Name.EndsWithOrdinal("Tape") + || c.Name.EndsWithOrdinal("Disk") + || c.Name.EndsWithOrdinal("Block") + || c.Name.EndsWithOrdinal("Status")); + + if (Emulator.SystemId is VSystemID.Raw.N64) + { + var fakeAnalogControls = tasView.AllColumns + .Where(c => + c.Name.EndsWithOrdinal("A Up") + || c.Name.EndsWithOrdinal("A Down") + || c.Name.EndsWithOrdinal("A Left") + || c.Name.EndsWithOrdinal("A Right")); + + columnsToHide = columnsToHide.Concat(fakeAnalogControls); + } + + foreach (var column in columnsToHide) + { + column.Visible = false; + } + + foreach (var column in tasView.VisibleColumns) + { + if (InputManager.StickyHoldController.IsSticky(column.Name) || InputManager.StickyAutofireController.IsSticky(column.Name)) + { + column.Emphasis = true; + } + } + + tasView.AllColumns.ColumnsChanged(); + + } + private void SetupCustomPatterns() + { + // custom autofire patterns to allow configuring a unique pattern for each button or axis + BoolPatterns = new AutoPatternBool[ControllerType.BoolButtons.Count]; + AxisPatterns = new AutoPatternAxis[ControllerType.Axes.Count]; + + for (int i = 0; i < BoolPatterns.Length; i++) + { + // standard 1 on 1 off autofire pattern + BoolPatterns[i] = new AutoPatternBool(1, 1); + } + + for (int i = 0; i < AxisPatterns.Length; i++) + { + // autohold pattern with the maximum axis range as hold value (bit arbitrary) + var axisSpec = ControllerType.Axes[ControllerType.Axes[i]]; + AxisPatterns[i] = new AutoPatternAxis([ axisSpec.Range.EndInclusive ]); + } + } + + /// for Lua + public void AddColumn(string name, string text, int widthUnscaled) + => TasView1.AllColumns.Add(new(name: name, widthUnscaled: widthUnscaled, type: ColumnType.Text, text: text)); + + public void LoadBranchByIndex(int index) => BookMarkControlMPR.LoadBranchExternal(index); + public void ClearFramesExternal() => ClearFramesMenuItem_Click(null, null); + public void InsertFrameExternal() => InsertFrameMenuItem_Click(null, null); + public void InsertNumFramesExternal() => InsertNumFramesMenuItem_Click(null, null); + public void DeleteFramesExternal() => DeleteFramesMenuItem_Click(null, null); + public void CloneFramesExternal() => CloneFramesMenuItem_Click(null, null); + public void CloneFramesXTimesExternal() => CloneFramesXTimesMenuItem_Click(null, null); + public void UndoExternal() => UndoMenuItem_Click(null, null); + public void RedoExternal() => RedoMenuItem_Click(null, null); + public void SelectBetweenMarkersExternal() => SelectBetweenMarkersMenuItem_Click(null, null); + public void SelectAllExternal() => SelectAllMenuItem_Click(null, null); + public void ReselectClipboardExternal() => ReselectClipboardMenuItem_Click(null, null); + + public IMovieController GetBranchInput(string branchId, int frame) + { + var branch = CurrentTasMovie.Branches.FirstOrDefault(b => b.Uuid.ToString() == branchId); + if (branch == null || frame >= branch.InputLog.Count) + { + return null; + } + + var controller = MovieSession.GenerateMovieController(); + controller.SetFromMnemonic(branch.InputLog[frame]); + return controller; + } + + private int? FirstNonEmptySelectedFrame + { + get + { + var empty = Bk2LogEntryGenerator.EmptyEntry(MovieSession.MovieController); + foreach (var row in TasView1.SelectedRows) + { + if (CurrentTasMovie[row].LogEntry != empty) + { + return row; + } + } + + return null; + } + } + + private void ConvertCurrentMovieToTasproj() + { + MovieSession.ConvertToTasProj(); + Settings.RecentTas.Add(MovieSession.Movie.Filename); + MainForm.SetMainformMovieInfo(); + } + + private bool LoadMovie(ITasMovie tasMovie, bool startsFromSavestate = false, int gotoFrame = 0) + { + _engaged = false; + + if (!StartNewMovieWrapper(tasMovie, isNew: false)) + { + return false; + } + + _engaged = true; + Settings.RecentTas.Add(CurrentTasMovie.Filename); // only add if it did load + + if (startsFromSavestate) + { + GoToFrame(0); + } + else if (gotoFrame > 0) + { + GoToFrame(gotoFrame); + } + else + { + GoToFrame(CurrentTasMovie.TasSession.CurrentFrame); + } + + // clear all selections + + foreach (InputRoll tasView in TasViews) + { + tasView.DeselectAll(); + } + + BookMarkControlMPR.Restart(); + MarkerControlMPR.Restart(); + + RefreshDialog(); + return true; + } + + private bool StartNewTasMovie(int viewIndex = 0) + { + if (!AskSaveChanges()) + { + return false; + } + + if (Game.IsNullInstance()) throw new InvalidOperationException("how is TAStudio open with no game loaded? please report this including as much detail as possible"); + + var filename = DefaultTasProjName(); // TODO don't do this, take over any mainform actions that can crash without a filename + var tasMovie = (ITasMovie) MovieSession.Get(filename); + tasMovie.Author = Config.DefaultAuthor; + + bool success = StartNewMovieWrapper(tasMovie, isNew: true); //here controllers are set in MovieController + + if (success) + { + // clear all selections + foreach (InputRoll tasView in TasViews) + { + tasView.DeselectAll(); + } + BookMarkControlMPR.Restart(); + MarkerControlMPR.Restart(); + RefreshDialog(); + } + + return success; + } + + private bool StartNewMovieWrapper(ITasMovie movie, bool isNew) + { + _initializing = true; + + movie.InputRollSettingsForSave = () => TasView1.UserSettingsSerialized(); + movie.BindMarkersToInput = Settings.BindMarkersToInput; + movie.GreenzoneInvalidated = GreenzoneInvalidated; + movie.ChangeLog.MaxSteps = Settings.MaxUndoSteps; + movie.PropertyChanged += TasMovie_OnPropertyChanged; + + SuspendLayout(); + WantsToControlStopMovie = false; + bool result = MainForm.StartNewMovie(movie, isNew); + WantsToControlStopMovie = true; + ResumeLayout(); + if (result) + { + BookMarkControlMPR.UpdateTextColumnWidth(); + MarkerControlMPR.UpdateTextColumnWidth(); + TastudioPlayMode(); + UpdateWindowTitle(); + + + if (CurrentTasMovie.InputRollSettings != null) + { + for (int i = 0; i < TasViews.Count; i++) + { + TasViews[i].LoadSettingsSerialized(CurrentTasMovie.InputRollSettings); //not sure if this is necessary with multiple InputRolls + SetUpColumnsPerControl(i); + } + } + else + { + for (int i = 0; i < TasViews.Count; i++) + { + SetUpColumnsPerControl(i); + } + } + SetUpToolStripColumns(); + SetupCustomPatterns(); + UpdateAutoFire(); + } + + _initializing = false; + + return result; + } + + private void DummyLoadProject(string path) + { + if (AskSaveChanges()) + { + LoadFileWithFallback(path); + } + } + + private bool LoadFileWithFallback(string path) + { + bool movieLoadSucceeded = false; + + if (!File.Exists(path)) + { + Settings.RecentTas.HandleLoadError(MainForm, path); + } + else + { + var movie = MovieSession.Get(path, loadMovie: true); + var tasMovie = movie as ITasMovie ?? movie.ToTasMovie(); + movieLoadSucceeded = LoadMovie(tasMovie); + } + + if (!movieLoadSucceeded) + { + movieLoadSucceeded = StartNewTasMovie(); + _engaged = true; + } + + return movieLoadSucceeded; + } + + private void DummyLoadMacro(string path) + { + if (!TasView1.AnyRowsSelected) + { + return; + } + + var loadZone = new MovieZone(path, MainForm, Emulator, MovieSession, Tools) + { + Start = TasView1.SelectionStartIndex!.Value, + }; + loadZone.PlaceZone(CurrentTasMovie, Config); + } + + private void TastudioToggleReadOnly() + { + TasPlaybackBoxMPR.RecordingMode = !TasPlaybackBoxMPR.RecordingMode; + WasRecording = TasPlaybackBoxMPR.RecordingMode; // hard reset at manual click and hotkey + } + + private void TastudioPlayMode(bool resetWasRecording = false) + { + TasPlaybackBoxMPR.RecordingMode = false; + + // once user started editing, rec mode is unsafe + if (resetWasRecording) + { + WasRecording = TasPlaybackBoxMPR.RecordingMode; + } + } + + private void TastudioRecordMode(bool resetWasRecording = false) + { + TasPlaybackBoxMPR.RecordingMode = true; + + if (resetWasRecording) + { + WasRecording = TasPlaybackBoxMPR.RecordingMode; + } + } + + private void TastudioStopMovie() + { + MovieSession.StopMovie(false); + MainForm.SetMainformMovieInfo(); + } + + private void Disengage() + { + _engaged = false; + MainForm.PauseOnFrame = null; + MainForm.AddOnScreenMessage("TAStudio disengaged"); + Config.Movies.MovieEndAction = _originalEndAction; + WantsToControlRewind = false; + MainForm.EnableRewind(true); + MainForm.SetMainformMovieInfo(); + } + + private const string DefaultTasProjectName = "default"; + + // Used when starting a new project + private string DefaultTasProjName() + { + return Path.Combine( + Config.PathEntries.MovieAbsolutePath(), + $"{DefaultTasProjectName}.{MovieService.TasMovieExtension}"); + } + + // Used for things like SaveFile dialogs to suggest a name to the user + private string SuggestedTasProjName() + { + return Path.Combine( + Config.PathEntries.MovieAbsolutePath(), + $"{Game.FilesystemSafeName()}.{MovieService.TasMovieExtension}"); + } + + private void SaveTas(bool saveAsBk2 = false, bool saveBackup = false) + { + if (string.IsNullOrEmpty(CurrentTasMovie.Filename) || CurrentTasMovie.Filename == DefaultTasProjName()) return; + + _autosaveTimer.Stop(); + MessageStatusLabel.Text = saveBackup + ? "Saving backup..." + : "Saving..."; + MessageStatusLabel.Owner.Update(); + Cursor = Cursors.WaitCursor; + + IMovie movieToSave = CurrentTasMovie; + if (saveAsBk2) + { + movieToSave = CurrentTasMovie.ToBk2(); + movieToSave.Attach(Emulator); + } + + if (saveBackup) + movieToSave.SaveBackup(); + else + movieToSave.Save(); + + MessageStatusLabel.Text = saveBackup + ? $"Backup .{(saveAsBk2 ? MovieService.StandardMovieExtension : MovieService.TasMovieExtension)} saved to \"Movie backups\" path." + : "File saved."; + Cursor = Cursors.Default; + if (Settings.AutosaveInterval > 0) + { + _autosaveTimer.Start(); + } + } + + private void SaveAsTas() + { + _autosaveTimer.Stop(); + + var filename = CurrentTasMovie.Filename; + if (string.IsNullOrWhiteSpace(filename) || filename == DefaultTasProjName()) + { + filename = SuggestedTasProjName(); + } + + var fileInfo = SaveFileDialog( + currentFile: filename, + path: Config!.PathEntries.MovieAbsolutePath(), + TAStudioProjectsFSFilterSet, + this); + + if (fileInfo != null) + { + MessageStatusLabel.Text = "Saving..."; + MessageStatusLabel.Owner.Update(); + Cursor = Cursors.WaitCursor; + CurrentTasMovie.Filename = fileInfo.FullName; + CurrentTasMovie.Save(); + Settings.RecentTas.Add(CurrentTasMovie.Filename); + MessageStatusLabel.Text = "File saved."; + Cursor = Cursors.Default; + } + + if (Settings.AutosaveInterval > 0) + { + _autosaveTimer.Start(); + } + + UpdateWindowTitle(); // changing the movie's filename does not flag changes, so we need to ensure the window title is always updated + MainForm.UpdateWindowTitle(); + } + + protected override string WindowTitle + => CurrentTasMovie == null + ? "TAStudio" + : CurrentTasMovie.Changes + ? $"TAStudio - {CurrentTasMovie.Name}*" + : $"TAStudio - {CurrentTasMovie.Name}"; + + protected override string WindowTitleStatic => "TAStudio"; + + public IEnumerable GetSelection() + { + foreach (InputRoll tasView in TasViews) + { + if (tasView.Focused && tasView.AnyRowsSelected) + { + return tasView.SelectedRows; + } + } + return null; //something messed up + } + // Slow but guarantees the entire dialog refreshes + private void FullRefresh() + { + SetTasViewRowCount(); + foreach (InputRoll tasView in TasViews) + { + tasView.Refresh(); // An extra refresh potentially but we need to guarantee + } + + MarkerControlMPR.UpdateValues(); + BookMarkControlMPR.UpdateValues(); + + if (_undoForm != null && !_undoForm.IsDisposed) + { + _undoForm.UpdateValues(); + } + } + + public void RefreshDialog(bool refreshTasView = true, bool refreshBranches = true) + { + if (_exiting) + { + return; + } + + if (refreshTasView) + { + SetTasViewRowCount(); + } + + MarkerControlMPR?.UpdateValues(); + + if (refreshBranches) + { + BookMarkControlMPR?.UpdateValues(); + } + + if (_undoForm != null && !_undoForm.IsDisposed) + { + _undoForm.UpdateValues(); + } + } + + public void RefreshForInputChange(int firstChangedFrame) + { + foreach (InputRoll tasView in TasViews) + { + if (tasView.IsPartiallyVisible(firstChangedFrame) || firstChangedFrame < tasView.FirstVisibleRow) + { + RefreshDialog(); + } + } + } + + private void SetTasViewRowCount() + { + foreach (InputRoll tasView in TasViews) + { + 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; + } + } + + /// + /// 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. + /// + private KeyValuePair GetPriorStateForFramebuffer(int frame) + { + 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 state, bool discardApiHawkSurfaces = false) + { + StatableEmulator.LoadStateBinary(new BinaryReader(state.Value)); + + if (state.Key == 0 && CurrentTasMovie.StartsFromSavestate) + { + Emulator.ResetCounters(); + } + + UpdateTools(); + if (discardApiHawkSurfaces) + { + DisplayManager.DiscardApiHawkSurfaces(); + } + } + + public void AddBranchExternal() => BookMarkControlMPR.AddBranchExternal(); + public void RemoveBranchExternal() => BookMarkControlMPR.RemoveBranchExternal(); + + private void UpdateTools() + { + Tools.UpdateToolsBefore(); + Tools.UpdateToolsAfter(); + } + + public void TogglePause() + { + MainForm.TogglePause(); + } + + private void SetSplicer() + { + + foreach (InputRoll tasView in TasViews) + { + if (tasView.Focused && tasView.AnyRowsSelected) + { + var selectedRowCount = tasView.SelectedRows.Count(); + var temp = $"Selected: {selectedRowCount} {(selectedRowCount == 1 ? "frame" : "frames")}, States: {CurrentTasMovie.TasStateManager.Count}"; + if (_tasClipboard.Count > 0) temp += $", Clipboard: {_tasClipboard.Count} {(_tasClipboard.Count == 1 ? "frame" : "frames")}"; + SplicerStatusLabel.Text = temp; + } + } + // TODO: columns selected? + + } + + private void DoTriggeredAutoRestoreIfNeeded() + { + // Disable the seek that could have been initiated when painting. + // This must done before DoAutoRestore, otherwise it would disable the auto-restore seek. + if (_playbackInterrupted) + { + MainForm.PauseOnFrame = null; + } + + if (_triggerAutoRestore) + { + TastudioPlayMode(true); // once user started editing, rec mode is unsafe + DoAutoRestore(); + + _triggerAutoRestore = false; + _autoRestorePaused = null; + } + + if (_playbackInterrupted) + { + MainForm.UnpauseEmulator(); + _playbackInterrupted = false; + } + } + + public void InsertNumFramesMPR(int insertionFrame, int numberOfFrames) + { + int tasViewIndex = TasViews.IndexOf(CurrentTasView); + + if (CurrentTasView.AnyRowsSelected) + { + int startOffset = 1; //starts with "|" + //for (int k = i; k >= 0; k--) + for (int k = 0; k < tasViewIndex; k++) //add up inputs to get start string offset + { + startOffset += Emulator.ControllerDefinition.ControlsOrdered[k].Count; + startOffset += 1; //add 1 for pipe + } + int currentControlLength = Emulator.ControllerDefinition.ControlsOrdered[tasViewIndex].Count; + + if (insertionFrame <= CurrentTasMovie.InputLogLength) + { + var needsToRollback = CurrentTasView.SelectionStartIndex < Emulator.Frame; + + CurrentTasMovie.InsertEmptyFramesMPR(insertionFrame, startOffset, currentControlLength, numberOfFrames); + + if (needsToRollback) + { + GoToLastEmulatedFrameIfNecessary(insertionFrame); + DoAutoRestore(); + } + else + { + RefreshForInputChange(insertionFrame); + } + } + } + } + public void DeleteFrames(int beginningFrame, int numberOfFrames) + { + if (beginningFrame < CurrentTasMovie.InputLogLength) + { + int[] framesToRemove = Enumerable.Range(beginningFrame, numberOfFrames).ToArray(); + CurrentTasMovie.RemoveFrames(framesToRemove); + SetSplicer(); + + var needsToRollback = beginningFrame < Emulator.Frame; + if (needsToRollback) + { + GoToLastEmulatedFrameIfNecessary(beginningFrame); + DoAutoRestore(); + } + else + { + RefreshForInputChange(beginningFrame); + } + } + } + public void ClearFrames(int beginningFrame, int numberOfFrames) + { + for (int i = 0; i < TasViews.Count; i++) + { + if (TasViews[i].Focused && TasViews[i].AnyRowsSelected) //moving out of for loop to only have the currently focused tasview cloned + { + if (beginningFrame < CurrentTasMovie.InputLogLength) + { + int startOffset = 1; //starts with "|" + for (int k = 0; k < i; k++) //add up inputs to get start string offset + { + startOffset += Emulator.ControllerDefinition.ControlsOrdered[k].Count; + startOffset += 1; //add 1 for pipe + } + int currentControlLength = Emulator.ControllerDefinition.ControlsOrdered[i].Count; + + var needsToRollback = TasViews[i].SelectionStartIndex < Emulator.Frame; + int last = Math.Min(beginningFrame + numberOfFrames, CurrentTasMovie.InputLogLength); + foreach (int frame in TasViews[i].SelectedRows) + { + CurrentTasMovie.ClearFrameMPR(frame, startOffset, currentControlLength); + } + + if (needsToRollback) + { + GoToLastEmulatedFrameIfNecessary(beginningFrame); + DoAutoRestore(); + } + else + { + RefreshForInputChange(beginningFrame); + } + } + } + } + } + private void Tastudio_Closing(object sender, FormClosingEventArgs e) + { + if (!_initialized) + { + return; + } + + _exiting = true; + + if (AskSaveChanges()) + { + WantsToControlStopMovie = false; + TastudioStopMovie(); + Disengage(); + } + else + { + e.Cancel = true; + _exiting = false; + } + + _undoForm?.Close(); + } + + /// + /// This method is called every time the Changes property is toggled on a instance. + /// + private void TasMovie_OnPropertyChanged(object sender, PropertyChangedEventArgs e) + { + UpdateWindowTitle(); + } + + private void TAStudio_DragDrop(object sender, DragEventArgs e) + { + // TODO: Maybe this should call Mainform's DragDrop method, + // since that can file types that are not movies, + // and it can process multiple files sequentially + var filePaths = (string[]) e.Data.GetData(DataFormats.FileDrop); + LoadMovieFile(filePaths[0]); + } + + private void TAStudio_MouseLeave(object sender, EventArgs e) + { + foreach (InputRoll tasView in TasViews) + { + if (tasView.Focused && tasView.AnyRowsSelected) + { + toolTip1.SetToolTip(tasView, null); + DoTriggeredAutoRestoreIfNeeded(); + } + } + } + + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + if (keyData == Keys.Tab + || keyData == (Keys.Shift | Keys.Tab) + || keyData == Keys.Space) + { + return true; + } + + return base.ProcessCmdKey(ref msg, keyData); + } + + private bool AutoAdjustInput() + { + var lagLog = CurrentTasMovie[Emulator.Frame - 1]; // Minus one because get frame is +1; + bool isLag = Emulator.AsInputPollable().IsLagFrame; + + if (lagLog.WasLagged.HasValue) + { + if (lagLog.WasLagged.Value && !isLag) + { + // remove all consecutive was-lag frames in batch like taseditor + // current frame has no lag so they will all have to go anyway + var framesToRemove = new List { Emulator.Frame - 1 }; + for (int frame = Emulator.Frame; CurrentTasMovie[frame].WasLagged.HasValue; frame++) + { + if (CurrentTasMovie[frame].WasLagged.Value) + { + framesToRemove.Add(frame); + } + else + { + break; + } + } + + // Deleting this frame requires rewinding a frame. + CurrentTasMovie.ChangeLog.AddInputBind(Emulator.Frame - 1, true, $"Bind Input; Delete {Emulator.Frame - 1}"); + bool wasRecording = CurrentTasMovie.ChangeLog.IsRecording; + CurrentTasMovie.ChangeLog.IsRecording = false; + CurrentTasMovie.RemoveFrames(framesToRemove); + foreach (int f in framesToRemove) + { + CurrentTasMovie.LagLog.RemoveHistoryAt(f + 1); // Removes from WasLag + } + CurrentTasMovie.ChangeLog.IsRecording = wasRecording; + + CurrentTasMovie.LastPositionStable = true; + GoToLastEmulatedFrameIfNecessary(Emulator.Frame - 1); + if (!MainForm.HoldFrameAdvance) + { + MainForm.PauseOnFrame = LastPositionFrame; + } + return true; + } + + if (!lagLog.WasLagged.Value && isLag) + { + // (it shouldn't need to rewind, since the inserted input wasn't polled) + CurrentTasMovie.ChangeLog.AddInputBind(Emulator.Frame - 1, false, $"Bind Input; Insert {Emulator.Frame - 1}"); + bool wasRecording = CurrentTasMovie.ChangeLog.IsRecording; + CurrentTasMovie.ChangeLog.IsRecording = false; + + CurrentTasMovie.InsertInput(Emulator.Frame - 1, CurrentTasMovie.GetInputLogEntry(Emulator.Frame - 2)); + CurrentTasMovie.LagLog.InsertHistoryAt(Emulator.Frame, true); + + CurrentTasMovie.ChangeLog.IsRecording = wasRecording; + return true; + } + } + + return false; + } + + private void MainVerticalSplit_SplitterMoved(object sender, SplitterEventArgs e) + { + Settings.MainVerticalSplitDistance = MainVertialSplit.SplitterDistance; + } + + private void BranchesMarkersSplit_SplitterMoved(object sender, SplitterEventArgs e) + { + Settings.BranchMarkerSplitDistance = BranchesMarkersSplit.SplitterDistance; + } + + private void TasView_CellDropped(object sender, InputRoll.CellEventArgs e) + { + if (e.NewCell?.RowIndex != null && !CurrentTasMovie.Markers.IsMarker(e.NewCell.RowIndex.Value)) + { + var currentMarker = CurrentTasMovie.Markers.Single(m => m.Frame == e.OldCell.RowIndex.Value); + int newFrame = e.NewCell.RowIndex.Value; + var newMarker = new TasMovieMarker(newFrame, currentMarker.Message); + CurrentTasMovie.Markers.Remove(currentMarker); + CurrentTasMovie.Markers.Add(newMarker); + RefreshDialog(); + } + } + + private void TASMenu_MenuActivate(object sender, EventArgs e) + { + IsInMenuLoop = true; + } + + private void TASMenu_MenuDeactivate(object sender, EventArgs e) + { + IsInMenuLoop = false; + } + + // Stupid designer + protected void DragEnterWrapper(object sender, DragEventArgs e) + { + GenericDragEnter(sender, e); + } + + private void SetFontMenuItem_Click(object sender, EventArgs e) + { + using var fontDialog = new FontDialog + { + ShowColor = false, + Font = TasViews[1].Font + }; + if (fontDialog.ShowDialog() != DialogResult.Cancel) + { + foreach (InputRoll tasView in TasViews) + { + tasView.Font = TasViewFont = fontDialog.Font; + tasView.Refresh(); + } + } + } + private IMovieController ControllerFromMnemonicStr(string inputLogEntry) + { + try + { + var controller = MovieSession.GenerateMovieController(); + controller.SetFromMnemonic(inputLogEntry); + + return controller; + } + catch (Exception) + { + DialogController.ShowMessageBox($"Invalid mnemonic string: {inputLogEntry}", "Paste Input failed!"); + return null; + } + } + + private IEnumerable<(string Name, string Mnemonic, int MaxLength)> MnemonicMap() + { + if (MovieSession.MovieController.Definition.MnemonicsCache is null) + throw new InvalidOperationException("Can't build mnemonic map with empty mnemonics cache"); + + foreach (var playerControls in MovieSession.MovieController.Definition.ControlsOrdered) + { + foreach ((string name, AxisSpec? axisSpec) in playerControls) + { + if (axisSpec.HasValue) + { + string mnemonic = Bk2MnemonicLookup.LookupAxis(name, MovieSession.Movie.SystemID); + yield return (name, mnemonic, Math.Max(mnemonic.Length, axisSpec.Value.MaxDigits)); + } + else + { + yield return (name, MovieSession.MovieController.Definition.MnemonicsCache[name].ToString(), 1); + } + } + } + } + + private IEnumerable<(string Name, string Mnemonic, int MaxLength)> MnemonicMapPlayerController(int viewIndex) + { + if (MovieSession.MovieController.Definition.MnemonicsCache is null) + throw new InvalidOperationException("Can't build mnemonic map with empty mnemonics cache"); + + if (MovieSession.MovieController.Definition.ControlsOrdered.Count != TasViews.Count) + throw new InvalidOperationException("Number of Controllers has changed unexpectedly. Select desired Core, Reboot Core, and try again."); + + var playerControls = MovieSession.MovieController.Definition.ControlsOrdered[viewIndex]; + + //foreach (var playerControls in MovieSession.MovieController.Definition.ControlsOrdered) + //{ + foreach ((string name, AxisSpec? axisSpec) in playerControls) + { + if (axisSpec.HasValue) + { + string mnemonic = Bk2MnemonicLookup.LookupAxis(name, MovieSession.Movie.SystemID); + yield return (name, mnemonic, Math.Max(mnemonic.Length, axisSpec.Value.MaxDigits)); + } + else + { + yield return (name, MovieSession.MovieController.Definition.MnemonicsCache[name].ToString(), 1); + } + } + //} + } + + //experimental feature. See if this makes a difference at all. + private void disableTasViewToolStripMenuItem_Click(object sender, EventArgs e) + { + var tasViewToToggleDisable = sender.ToString().Substring(15); + InputRoll tasView = TasViews.Find(t => t.Name == tasViewToToggleDisable); + tasView.Enabled = !tasView.Enabled; + tasView.Visible = !tasView.Visible; + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.resx b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.resx new file mode 100644 index 00000000000..2de40e63762 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioMPR.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 121, 17 + + + 249, 17 + + + 388, 17 + + \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioPaletteMPR.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioPaletteMPR.cs new file mode 100644 index 00000000000..5442ecc87b2 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/TAStudioPaletteMPR.cs @@ -0,0 +1,86 @@ +using System.Drawing; + +namespace BizHawk.Client.EmuHawk +{ + /// + /// TODO these colours are obviously related in some way, calculate the lighter/darker shades from a base colour + /// (I've already used CurrentFrame_InputLog in the definition of SeekFrame_InputLog, they differed only in alpha) + /// --yoshi + /// + public readonly struct TAStudioPaletteMPR + { + public static readonly TAStudioPaletteMPR Default = new( +// currentFrame_FrameCol: Color.FromArgb(0xCF, 0xED, 0xFC), + currentFrame_InputLog: Color.FromArgb(0xB5, 0xE7, 0xF7), + greenZone_FrameCol: Color.FromArgb(0xDD, 0xFF, 0xDD), + greenZone_InputLog: Color.FromArgb(0xD2, 0xF9, 0xD3), + greenZone_InputLog_Stated: Color.FromArgb(0xC4, 0xF7, 0xC8), + greenZone_InputLog_Invalidated: Color.FromArgb(0xE0, 0xFB, 0xE0), + lagZone_FrameCol: Color.FromArgb(0xFF, 0xDC, 0xDD), + lagZone_InputLog: Color.FromArgb(0xF4, 0xDA, 0xDA), + lagZone_InputLog_Stated: Color.FromArgb(0xF0, 0xD0, 0xD2), + lagZone_InputLog_Invalidated: Color.FromArgb(0xF7, 0xE5, 0xE5), + marker_FrameCol: Color.FromArgb(0xF7, 0xFF, 0xC9), + analogEdit_Col: Color.FromArgb(0x90, 0x90, 0x70)); // SuuperW: When editing an analog value, it will be a gray color. + +// public readonly Color CurrentFrame_FrameCol; + + public readonly Color CurrentFrame_InputLog; + +// public readonly Color SeekFrame_InputLog; + + public readonly Color GreenZone_FrameCol; + + public readonly Color GreenZone_InputLog; + + public readonly Color GreenZone_InputLog_Stated; + + public readonly Color GreenZone_InputLog_Invalidated; + + public readonly Color LagZone_FrameCol; + + public readonly Color LagZone_InputLog; + + public readonly Color LagZone_InputLog_Stated; + + public readonly Color LagZone_InputLog_Invalidated; + + public readonly Color Marker_FrameCol; + + public readonly Color AnalogEdit_Col; + + public TAStudioPaletteMPR( +// Color currentFrame_FrameCol, + Color currentFrame_InputLog, + Color greenZone_FrameCol, + Color greenZone_InputLog, + Color greenZone_InputLog_Stated, + Color greenZone_InputLog_Invalidated, + Color lagZone_FrameCol, + Color lagZone_InputLog, + Color lagZone_InputLog_Stated, + Color lagZone_InputLog_Invalidated, + Color marker_FrameCol, + Color analogEdit_Col) + { +// CurrentFrame_FrameCol = currentFrame_FrameCol; + CurrentFrame_InputLog = currentFrame_InputLog; +// SeekFrame_InputLog = Color.FromArgb(0x70, currentFrame_InputLog); + GreenZone_FrameCol = greenZone_FrameCol; + GreenZone_InputLog = greenZone_InputLog; + GreenZone_InputLog_Stated = greenZone_InputLog_Stated; + GreenZone_InputLog_Invalidated = greenZone_InputLog_Invalidated; + LagZone_FrameCol = lagZone_FrameCol; + LagZone_InputLog = lagZone_InputLog; + LagZone_InputLog_Stated = lagZone_InputLog_Stated; + LagZone_InputLog_Invalidated = lagZone_InputLog_Invalidated; + Marker_FrameCol = marker_FrameCol; + AnalogEdit_Col = analogEdit_Col; + } + + public static implicit operator TAStudioPaletteMPR(TAStudioPalette v) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/UndoHistoryFormMPR.Designer.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/UndoHistoryFormMPR.Designer.cs new file mode 100644 index 00000000000..efe30ebad8c --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/UndoHistoryFormMPR.Designer.cs @@ -0,0 +1,212 @@ +namespace BizHawk.Client.EmuHawk +{ + partial class UndoHistoryFormMPR + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.ClearButton = new System.Windows.Forms.Button(); + this.UndoButton = new System.Windows.Forms.Button(); + this.RedoButton = new System.Windows.Forms.Button(); + this.RightClickMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.undoHereToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.redoHereToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.sepToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripSeparatorEx(); + this.clearHistoryToHereToolStripMenuItem = new BizHawk.WinForms.Controls.ToolStripMenuItemEx(); + this.AutoScrollCheck = new System.Windows.Forms.CheckBox(); + this.MaxStepsNum = new System.Windows.Forms.NumericUpDown(); + this.label1 = new BizHawk.WinForms.Controls.LocLabelEx(); + this.HistoryView = new BizHawk.Client.EmuHawk.InputRoll(); + this.RightClickMenu.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.MaxStepsNum)).BeginInit(); + this.SuspendLayout(); + // + // ClearButton + // + this.ClearButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.ClearButton.Location = new System.Drawing.Point(326, 228); + this.ClearButton.Name = "ClearButton"; + this.ClearButton.Size = new System.Drawing.Size(55, 22); + this.ClearButton.TabIndex = 4; + this.ClearButton.Text = "Clear"; + this.ClearButton.UseVisualStyleBackColor = true; + this.ClearButton.Click += new System.EventHandler(this.ClearButton_Click); + // + // UndoButton + // + this.UndoButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.UndoButton.Location = new System.Drawing.Point(10, 228); + this.UndoButton.Name = "UndoButton"; + this.UndoButton.Size = new System.Drawing.Size(55, 22); + this.UndoButton.TabIndex = 3; + this.UndoButton.Text = "Undo"; + this.UndoButton.UseVisualStyleBackColor = true; + this.UndoButton.Click += new System.EventHandler(this.UndoButton_Click); + // + // RedoButton + // + this.RedoButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.RedoButton.Location = new System.Drawing.Point(71, 228); + this.RedoButton.Name = "RedoButton"; + this.RedoButton.Size = new System.Drawing.Size(55, 22); + this.RedoButton.TabIndex = 3; + this.RedoButton.Text = "Redo"; + this.RedoButton.UseVisualStyleBackColor = true; + this.RedoButton.Click += new System.EventHandler(this.RedoButton_Click); + // + // RightClickMenu + // + this.RightClickMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.undoHereToolStripMenuItem, + this.redoHereToolStripMenuItem, + this.sepToolStripMenuItem, + this.clearHistoryToHereToolStripMenuItem}); + this.RightClickMenu.Name = "RightClickMenu"; + this.RightClickMenu.Size = new System.Drawing.Size(209, 76); + // + // undoHereToolStripMenuItem + // + this.undoHereToolStripMenuItem.Text = "Undo To Selection"; + this.undoHereToolStripMenuItem.Click += new System.EventHandler(this.UndoHereMenuItem_Click); + // + // redoHereToolStripMenuItem + // + this.redoHereToolStripMenuItem.Text = "Redo To Selection"; + this.redoHereToolStripMenuItem.Click += new System.EventHandler(this.RedoHereMenuItem_Click); + // + // clearHistoryToHereToolStripMenuItem + // + this.clearHistoryToHereToolStripMenuItem.Text = "Clear History To Selection"; + this.clearHistoryToHereToolStripMenuItem.Click += new System.EventHandler(this.ClearHistoryToHereMenuItem_Click); + // + // AutoScrollCheck + // + this.AutoScrollCheck.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.AutoScrollCheck.AutoSize = true; + this.AutoScrollCheck.Checked = true; + this.AutoScrollCheck.CheckState = System.Windows.Forms.CheckState.Checked; + this.AutoScrollCheck.Location = new System.Drawing.Point(132, 233); + this.AutoScrollCheck.Name = "AutoScrollCheck"; + this.AutoScrollCheck.Size = new System.Drawing.Size(77, 17); + this.AutoScrollCheck.TabIndex = 5; + this.AutoScrollCheck.Text = "Auto Scroll"; + this.AutoScrollCheck.UseVisualStyleBackColor = true; + // + // MaxStepsNum + // + this.MaxStepsNum.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.MaxStepsNum.Location = new System.Drawing.Point(268, 230); + this.MaxStepsNum.Maximum = new decimal(new int[] { + -1486618625, + 232830643, + 0, + 0}); + this.MaxStepsNum.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.MaxStepsNum.Name = "MaxStepsNum"; + this.MaxStepsNum.Size = new System.Drawing.Size(52, 20); + this.MaxStepsNum.TabIndex = 6; + this.MaxStepsNum.Value = new decimal(new int[] { + 100, + 0, + 0, + 0}); + this.MaxStepsNum.ValueChanged += new System.EventHandler(this.MaxStepsNum_ValueChanged); + // + // label1 + // + this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.label1.Location = new System.Drawing.Point(236, 234); + this.label1.Name = "label1"; + this.label1.Text = "Max:"; + // + // HistoryView + // + this.HistoryView.AllowColumnReorder = false; + this.HistoryView.AllowColumnResize = false; + this.HistoryView.AlwaysScroll = false; + this.HistoryView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.HistoryView.CellHeightPadding = 0; + this.HistoryView.CellWidthPadding = 0; + this.HistoryView.FullRowSelect = true; + this.HistoryView.HorizontalOrientation = false; + this.HistoryView.LetKeysModifySelection = false; + this.HistoryView.Location = new System.Drawing.Point(10, 10); + this.HistoryView.MultiSelect = false; + this.HistoryView.Name = "HistoryView"; + this.HistoryView.RowCount = 0; + this.HistoryView.ScrollSpeed = 0; + this.HistoryView.Size = new System.Drawing.Size(369, 213); + this.HistoryView.TabIndex = 2; + this.HistoryView.DoubleClick += new System.EventHandler(this.HistoryView_DoubleClick); + this.HistoryView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.HistoryView_MouseDown); + this.HistoryView.MouseUp += new System.Windows.Forms.MouseEventHandler(this.HistoryView_MouseUp); + // + // UndoHistoryForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(391, 258); + this.Controls.Add(this.label1); + this.Controls.Add(this.MaxStepsNum); + this.Controls.Add(this.AutoScrollCheck); + this.Controls.Add(this.ClearButton); + this.Controls.Add(this.RedoButton); + this.Controls.Add(this.UndoButton); + this.Controls.Add(this.HistoryView); + this.Name = "UndoHistoryForm"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Undo History"; + this.RightClickMenu.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.MaxStepsNum)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button ClearButton; + private System.Windows.Forms.Button UndoButton; + private InputRoll HistoryView; + private System.Windows.Forms.Button RedoButton; + private System.Windows.Forms.ContextMenuStrip RightClickMenu; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx undoHereToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx redoHereToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripSeparatorEx sepToolStripMenuItem; + private BizHawk.WinForms.Controls.ToolStripMenuItemEx clearHistoryToHereToolStripMenuItem; + private System.Windows.Forms.CheckBox AutoScrollCheck; + private System.Windows.Forms.NumericUpDown MaxStepsNum; + private BizHawk.WinForms.Controls.LocLabelEx label1; + } +} \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/UndoHistoryFormMPR.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/UndoHistoryFormMPR.cs new file mode 100644 index 00000000000..c9fc3f8aa36 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/UndoHistoryFormMPR.cs @@ -0,0 +1,170 @@ +using System.Drawing; +using System.Windows.Forms; +using BizHawk.Client.Common; + +namespace BizHawk.Client.EmuHawk +{ + public partial class UndoHistoryFormMPR : Form + { + private const string IdColumnName = "ID"; + private const string UndoColumnName = "Undo Step"; + + private readonly TAStudioMPR _tastudioMPR; + private string _lastUndoAction; + private IMovieChangeLog Log => _tastudioMPR.CurrentTasMovie.ChangeLog; + + public UndoHistoryFormMPR(TAStudioMPR owner) + { + InitializeComponent(); + _tastudioMPR = owner; + + HistoryView.QueryItemText += HistoryView_QueryItemText; + HistoryView.QueryItemBkColor += HistoryView_QueryItemBkColor; + + HistoryView.AllColumns.Clear(); + HistoryView.AllColumns.Add(new(name: IdColumnName, widthUnscaled: 40, text: IdColumnName)); + HistoryView.AllColumns.Add(new(name: UndoColumnName, widthUnscaled: 280, text: UndoColumnName)); + + MaxStepsNum.Value = Log.MaxSteps; + } + + private void HistoryView_QueryItemText(int index, RollColumn column, out string text, ref int offsetX, ref int offsetY) + { + text = column.Name == UndoColumnName + ? Log.Names[index] + : index.ToString(); + } + + private void HistoryView_QueryItemBkColor(int index, RollColumn column, ref Color color) + { + if (index == Log.UndoIndex) + { + color = _tastudioMPR.Palette.GreenZone_InputLog; + } + else if (index > Log.UndoIndex) + { + color = _tastudioMPR.Palette.LagZone_InputLog; + } + } + + public void UpdateValues() + { + HistoryView.RowCount = Log.Names.Count; + if (AutoScrollCheck.Checked && _lastUndoAction != Log.NextUndoStepName) + { + HistoryView.ScrollToIndex(Log.UndoIndex); + HistoryView.DeselectAll(); + HistoryView.SelectRow(Log.UndoIndex - 1, true); + } + + _lastUndoAction = Log.NextUndoStepName; + + HistoryView.Refresh(); + } + + private void ClearButton_Click(object sender, EventArgs e) + { + Log.Clear(); + UpdateValues(); + } + + private void UndoButton_Click(object sender, EventArgs e) + { + _tastudioMPR.UndoExternal(); + _tastudioMPR.RefreshDialog(); + } + + private void RedoButton_Click(object sender, EventArgs e) + { + _tastudioMPR.RedoExternal(); + _tastudioMPR.RefreshDialog(); + } + + private int SelectedItem + => HistoryView.AnyRowsSelected ? HistoryView.FirstSelectedRowIndex : -1; + + private void UndoToHere(int index) + { + int earliestFrame = int.MaxValue; + while (Log.UndoIndex > index) + { + int frame = Log.Undo(); + if (frame < earliestFrame) + earliestFrame = frame; + } + + UpdateValues(); + + // potentially rewind, then update display for TAStudio + if (_tastudioMPR.Emulator.Frame > earliestFrame) + _tastudioMPR.GoToFrame(earliestFrame); + _tastudioMPR.RefreshDialog(); + } + + private void HistoryView_DoubleClick(object sender, EventArgs e) + { + UndoToHere(SelectedItem); + } + + private void HistoryView_MouseUp(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Right) + { + RightClickMenu.Show(HistoryView, e.X, e.Y); + } + else if (e.Button == MouseButtons.Left) + { + if (SelectedItem == -1) + { + HistoryView.SelectRow(_hackSelect, true); + } + } + } + + // Hacky way to select a row by clicking the names row + private int _hackSelect = -1; + + private void HistoryView_MouseDown(object sender, MouseEventArgs e) + { + _hackSelect = SelectedItem; + } + + private void UndoHereMenuItem_Click(object sender, EventArgs e) + { + UndoToHere(SelectedItem); + } + + private void RedoHereMenuItem_Click(object sender, EventArgs e) + { + int earliestFrame = int.MaxValue; + while (Log.UndoIndex < SelectedItem) + { + int frame = Log.Redo(); + if (earliestFrame < frame) + earliestFrame = frame; + } + + UpdateValues(); + + // potentially rewind, then update display for TAStudio + if (_tastudioMPR.Emulator.Frame > earliestFrame) + _tastudioMPR.GoToFrame(earliestFrame); + _tastudioMPR.RefreshDialog(); + } + + private void ClearHistoryToHereMenuItem_Click(object sender, EventArgs e) + { + if (SelectedItem != -1) + { + Log.Clear(SelectedItem); + } + + UpdateValues(); + } + + private void MaxStepsNum_ValueChanged(object sender, EventArgs e) + { + _tastudioMPR.Settings.MaxUndoSteps = Log.MaxSteps = (int)MaxStepsNum.Value; + } + } +} diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/UndoHistoryFormMPR.resx b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/UndoHistoryFormMPR.resx new file mode 100644 index 00000000000..e9962a344f4 --- /dev/null +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudioMPR/UndoHistoryFormMPR.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/src/BizHawk.Client.EmuHawk/tools/ToolManager.cs index e4c112499d9..5ab787f0ca7 100644 --- a/src/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/src/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -851,6 +851,8 @@ public bool IsAvailable(Type tool) public TAStudio TAStudio => GetTool(); + public TAStudioMPR TAStudioMPR => GetTool(); + public void LoadRamWatch(bool loadDialog) { if (IsLoaded() && !_config.DisplayRamWatch)