From e4c4910b37e359f0c738d3d2d015cfb8b321f368 Mon Sep 17 00:00:00 2001 From: SuuperW Date: Tue, 3 Mar 2015 18:22:54 +0000 Subject: [PATCH] TAStudio: -Several buggixes -Feature: Right-click dragging frames to move/copy/clone. (Combine with Shift and/or Ctrl.) --- .../movie/tasproj/TasMovie.Editing.cs | 57 ++++++- .../movie/tasproj/TasMovie.History.cs | 100 +++++++------ .../movie/tasproj/TasMovie.IO.cs | 1 + .../movie/tasproj/TasMovie.cs | 9 +- .../tools/TAStudio/TAStudio.ListView.cs | 139 +++++++++++++++++- .../tools/TAStudio/TAStudio.cs | 2 +- 6 files changed, 253 insertions(+), 55 deletions(-) diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs index 146d649bae..654bacb20a 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs @@ -77,6 +77,35 @@ namespace BizHawk.Client.Common ChangeLog.SetGeneralRedo(); } + public void RemoveFrame(int frame) + { + bool endBatch = ChangeLog.BeginNewBatch(true); + ChangeLog.AddGeneralUndo(frame, InputLogLength - 1); + + _log.RemoveAt(frame); + if (BindMarkersToInput) + { + int firstIndex = Markers.FindIndex(m => m.Frame >= frame); + if (firstIndex != -1) + { + for (int i = firstIndex; i < Markers.Count; i++) + { + TasMovieMarker m = Markers.ElementAt(i); + if (m.Frame == frame) + Markers.Remove(m); + else + Markers.Move(m.Frame, m.Frame - 1); + } + } + } + + Changes = true; + InvalidateAfter(frame); + + ChangeLog.SetGeneralRedo(); + if (endBatch) + ChangeLog.EndBatch(); + } public void RemoveFrames(int[] frames) { if (frames.Any()) @@ -112,7 +141,6 @@ namespace BizHawk.Client.Common ChangeLog.SetGeneralRedo(); if (endBatch) ChangeLog.EndBatch(); - } } public void RemoveFrames(int removeStart, int removeUpTo) @@ -147,6 +175,32 @@ namespace BizHawk.Client.Common ChangeLog.EndBatch(); } + public void InsertInput(int frame, string inputState) + { + bool endBatch = ChangeLog.BeginNewBatch(true); + ChangeLog.AddGeneralUndo(frame, InputLogLength); + + _log.Insert(frame, inputState); + Changes = true; + InvalidateAfter(frame); + + if (BindMarkersToInput) + { + int firstIndex = Markers.FindIndex(m => m.Frame >= frame); + if (firstIndex != -1) + { + for (int i = firstIndex; i < Markers.Count; i++) + { + TasMovieMarker m = Markers.ElementAt(i); + Markers.Move(m.Frame, m.Frame + 1); + } + } + } + + ChangeLog.SetGeneralRedo(); + if (endBatch) + ChangeLog.EndBatch(); + } public void InsertInput(int frame, IEnumerable inputLog) { bool endBatch = ChangeLog.BeginNewBatch(true); @@ -173,7 +227,6 @@ namespace BizHawk.Client.Common if (endBatch) ChangeLog.EndBatch(); } - public void InsertInput(int frame, IEnumerable inputStates) { // ChangeLog is done in the InsertInput call. diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.History.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.History.cs index e5860ba786..937da9d810 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.History.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.History.cs @@ -13,7 +13,11 @@ namespace BizHawk.Client.Common int UndoIndex = -1; private bool RecordingBatch = false; - public bool AutoRecord = true; + /// + /// This is not intended to turn off the ChangeLog, but to disable the normal recording process. + /// Use this to manually control the ChangeLog. (Useful for when you are making lots of + /// + public bool IsRecording = true; public TasMovie Movie; public TasMovieChangeLog(TasMovie movie) @@ -37,12 +41,16 @@ namespace BizHawk.Client.Common } private void TruncateLog(int from) { - UndoIndex -= History.Count - from; - if (UndoIndex < -1) - UndoIndex = -1; - History.RemoveRange(from, History.Count - from); - RecordingBatch = false; + + if (UndoIndex < History.Count - 1) + UndoIndex = History.Count - 1; + + if (RecordingBatch) + { + RecordingBatch = false; + BeginNewBatch(); + } } /// @@ -53,6 +61,9 @@ namespace BizHawk.Client.Common /// Returns true if a new batch was started; otherwise false. public bool BeginNewBatch(bool keepOldBatch = false) { + if (!IsRecording) + return false; + bool ret = true; if (RecordingBatch) { @@ -62,22 +73,30 @@ namespace BizHawk.Client.Common EndBatch(); } + if (ret) + { + AddMovieAction(); + } RecordingBatch = true; - History.Add(new List()); - UndoIndex++; return ret; } /// /// Ends the current undo batch. Future changes will be one undo each. - /// If not already recording a batch, does (essentially) nothing. + /// If not already recording a batch, does nothing. /// public void EndBatch() { + if (!IsRecording || !RecordingBatch) + return; + RecordingBatch = false; List last = History.Last(); if (last.Count == 0) // Remove batch if it's empty. + { History.RemoveAt(History.Count - 1); + UndoIndex--; + } else last.Capacity = last.Count; } @@ -125,8 +144,8 @@ namespace BizHawk.Client.Common return PreviousUndoFrame; } - public bool CanUndo { get { return UndoIndex > -1; } } - public bool CanRedo { get { return UndoIndex < History.Count - 1; } } + public bool CanUndo { get { return UndoIndex > -1; } } + public bool CanRedo { get { return UndoIndex < History.Count - 1; } } public int PreviousUndoFrame { @@ -158,9 +177,6 @@ namespace BizHawk.Client.Common #region "Change History" private bool AddMovieAction() { - if (!AutoRecord) - return false; - if (UndoIndex + 1 != History.Count) TruncateLog(UndoIndex + 1); @@ -175,44 +191,44 @@ namespace BizHawk.Client.Common // TODO: These probably aren't the best way to handle undo/redo. private int lastGeneral; - public void AddGeneralUndo(int first, int last) + public void AddGeneralUndo(int first, int last, bool force = false) { - if (AutoRecord) + if (IsRecording || force) { AddMovieAction(); History.Last().Add(new MovieAction(first, last, Movie)); lastGeneral = History.Last().Count - 1; } } - public void SetGeneralRedo() + public void SetGeneralRedo(bool force = false) { - if (AutoRecord) + if (IsRecording || force) { (History.Last()[lastGeneral] as MovieAction).SetRedoLog(Movie); } } - public void AddBoolToggle(int frame, string button, bool oldState) + public void AddBoolToggle(int frame, string button, bool oldState, bool force = false) { - if (AutoRecord) + if (IsRecording || force) { AddMovieAction(); History.Last().Add(new MovieActionFrameEdit(frame, button, oldState, !oldState)); } } - public void AddFloatChange(int frame, string button, float oldState, float newState) + public void AddFloatChange(int frame, string button, float oldState, float newState, bool force = false) { - if (AutoRecord) + if (IsRecording || force) { AddMovieAction(); History.Last().Add(new MovieActionFrameEdit(frame, button, oldState, newState)); } } - public void AddMarkerChange(TasMovieMarker newMarker, int oldPosition = -1, string old_message = "") + public void AddMarkerChange(TasMovieMarker newMarker, int oldPosition = -1, string old_message = "", bool force = false) { - if (AutoRecord) + if (IsRecording || force) { AddMovieAction(); History.Last().Add(new MovieActionMarker(newMarker, oldPosition, old_message)); @@ -265,9 +281,9 @@ namespace BizHawk.Client.Common public void Undo(TasMovie movie) { - bool wasRecording = movie.ChangeLog.AutoRecord; + bool wasRecording = movie.ChangeLog.IsRecording; bool wasBinding = movie.BindMarkersToInput; - movie.ChangeLog.AutoRecord = false; + movie.ChangeLog.IsRecording = false; movie.BindMarkersToInput = bindMarkers; if (redoLength != length) @@ -279,14 +295,14 @@ namespace BizHawk.Client.Common if (undoLength != length) movie.RemoveFrames(FirstFrame + undoLength, movie.InputLogLength); - movie.ChangeLog.AutoRecord = wasRecording; + movie.ChangeLog.IsRecording = wasRecording; movie.BindMarkersToInput = bindMarkers; } public void Redo(TasMovie movie) { - bool wasRecording = movie.ChangeLog.AutoRecord; + bool wasRecording = movie.ChangeLog.IsRecording; bool wasBinding = movie.BindMarkersToInput; - movie.ChangeLog.AutoRecord = false; + movie.ChangeLog.IsRecording = false; movie.BindMarkersToInput = bindMarkers; if (undoLength != length) @@ -298,7 +314,7 @@ namespace BizHawk.Client.Common if (redoLength != length) movie.RemoveFrames(FirstFrame + redoLength, movie.InputLogLength); - movie.ChangeLog.AutoRecord = wasRecording; + movie.ChangeLog.IsRecording = wasRecording; movie.BindMarkersToInput = bindMarkers; } } @@ -382,27 +398,27 @@ namespace BizHawk.Client.Common public void Undo(TasMovie movie) { - bool wasRecording = movie.ChangeLog.AutoRecord; - movie.ChangeLog.AutoRecord = false; + bool wasRecording = movie.ChangeLog.IsRecording; + movie.ChangeLog.IsRecording = false; if (isFloat) movie.SetFloatState(FirstFrame, buttonName, oldState); else movie.SetBoolState(FirstFrame, buttonName, oldState == 1); - movie.ChangeLog.AutoRecord = wasRecording; + movie.ChangeLog.IsRecording = wasRecording; } public void Redo(TasMovie movie) { - bool wasRecording = movie.ChangeLog.AutoRecord; - movie.ChangeLog.AutoRecord = false; + bool wasRecording = movie.ChangeLog.IsRecording; + movie.ChangeLog.IsRecording = false; if (isFloat) movie.SetFloatState(FirstFrame, buttonName, newState); else movie.SetBoolState(FirstFrame, buttonName, newState == 1); - movie.ChangeLog.AutoRecord = wasRecording; + movie.ChangeLog.IsRecording = wasRecording; } } @@ -441,27 +457,27 @@ namespace BizHawk.Client.Common public void Undo(TasMovie movie) { - bool wasRecording = movie.ChangeLog.AutoRecord; - movie.ChangeLog.AutoRecord = false; + bool wasRecording = movie.ChangeLog.IsRecording; + movie.ChangeLog.IsRecording = false; //if (isFloat) // movie.SetFloatStates(FirstFrame, LastFrame - FirstFrame + 1, buttonName, oldState); //else // movie.SetBoolState(FirstFrame, buttonName, oldState == 1); - movie.ChangeLog.AutoRecord = wasRecording; + movie.ChangeLog.IsRecording = wasRecording; } public void Redo(TasMovie movie) { - bool wasRecording = movie.ChangeLog.AutoRecord; - movie.ChangeLog.AutoRecord = false; + bool wasRecording = movie.ChangeLog.IsRecording; + movie.ChangeLog.IsRecording = false; if (isFloat) movie.SetFloatStates(FirstFrame, LastFrame - FirstFrame + 1, buttonName, newState); else movie.SetBoolStates(FirstFrame, LastFrame - FirstFrame + 1, buttonName, newState == 1); - movie.ChangeLog.AutoRecord = wasRecording; + movie.ChangeLog.IsRecording = wasRecording; } } #endregion diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs index 0677f21f49..8d98cdfd54 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs @@ -271,6 +271,7 @@ namespace BizHawk.Client.Common LagLog.Clear(); StateManager.Clear(); Markers.Clear(); + ChangeLog.ClearLog(); } private static string InputLogToString(List log) diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs index 9e24400a08..ab6869a4b5 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs @@ -190,14 +190,9 @@ namespace BizHawk.Client.Common return CreateDisplayValueForButton(adapter, buttonName); } - public void FlushInputCache(int FrameToLeave = 0) + public void FlushInputCache() { - if (InputStateCache.Count <= FrameToLeave) - return; - do - { - InputStateCache.Remove(InputStateCache.Keys.First()); - } while (InputStateCache.Count > FrameToLeave); + InputStateCache.Clear(); } public string CreateDisplayValueForButton(IController adapter, string buttonName) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs index 8eb9bbc027..6a44365ba4 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs @@ -23,6 +23,20 @@ namespace BizHawk.Client.EmuHawk private int _floatEditRow = -1; private string _floatTypedValue; private int _floatEditYPos = -1; + // Right-click dragging + private string[] _rightClickInput = null; + private string[] _rightClickOverInput = null; + private int _rightClickFrame = -1; + private int _rightClickLastFrame = -1; + private bool _rightClickShift, _rightClickControl; + private bool _leftButtonHeld = false; + private bool mouseButtonHeld + { + get + { // Need a left click + return _rightClickFrame != -1 || _leftButtonHeld; + } + } private bool _triggerAutoRestore; // If true, autorestore will be called on mouse up private int? _triggerAutoRestoreFromFrame; // If set and _triggerAutoRestore is true, will call GoToFrameIfNecessary() with this value @@ -248,6 +262,10 @@ namespace BizHawk.Client.EmuHawk private void TasView_MouseDown(object sender, MouseEventArgs e) { + // Clicking with left while right is held or vice versa does weird stuff + if (mouseButtonHeld) + return; + if (e.Button == MouseButtons.Middle) { TogglePause(); @@ -264,6 +282,7 @@ namespace BizHawk.Client.EmuHawk if (e.Button == MouseButtons.Left) { + _leftButtonHeld = true; // SuuperW: Exit float editing mode, or re-enter mouse editing if (_floatEditRow != -1) { @@ -294,12 +313,13 @@ namespace BizHawk.Client.EmuHawk { if (Global.MovieSession.MovieControllerAdapter.Type.BoolButtons.Contains(buttonName)) { + CurrentTasMovie.ChangeLog.BeginNewBatch(); + ToggleBoolState(TasView.CurrentCell.RowIndex.Value, buttonName); _triggerAutoRestore = true; _triggerAutoRestoreFromFrame = TasView.CurrentCell.RowIndex.Value; RefreshDialog(); - CurrentTasMovie.ChangeLog.BeginNewBatch(); _startBoolDrawColumn = buttonName; if (frame < CurrentTasMovie.InputLogLength) @@ -346,6 +366,32 @@ namespace BizHawk.Client.EmuHawk } } } + else if (e.Button == System.Windows.Forms.MouseButtons.Right) + { + if (TasView.CurrentCell.Column.Name == FrameColumnName) + { + _rightClickControl = (Control.ModifierKeys | Keys.Control) == Control.ModifierKeys; + _rightClickShift = (Control.ModifierKeys | Keys.Shift) == Control.ModifierKeys; + if (TasView.SelectedRows.Contains(frame)) + { + _rightClickInput = new string[TasView.SelectedRows.Count()]; + _rightClickFrame = TasView.FirstSelectedIndex.Value; + CurrentTasMovie.GetLogEntries().CopyTo(_rightClickFrame, _rightClickInput, 0, TasView.SelectedRows.Count()); + if (_rightClickControl && _rightClickShift) + _rightClickFrame += _rightClickInput.Length; + } + else + { + _rightClickInput = new string[1]; + _rightClickInput[0] = CurrentTasMovie.GetLogEntries()[frame]; + _rightClickFrame = frame; + } + _rightClickLastFrame = -1; + _supressContextMenu = true; + // TODO: Turn off ChangeLog.IsRecording and handle the GeneralUndo here. + CurrentTasMovie.ChangeLog.BeginNewBatch(); + } + } } private void TasView_MouseUp(object sender, MouseEventArgs e) @@ -358,8 +404,6 @@ namespace BizHawk.Client.EmuHawk { _startMarkerDrag = false; _startFrameDrag = false; - if (_startBoolDrawColumn != string.Empty || _startFloatDrawColumn != string.Empty) - CurrentTasMovie.ChangeLog.EndBatch(); _startBoolDrawColumn = string.Empty; _startFloatDrawColumn = string.Empty; // Exit float editing if value was changed with cursor @@ -370,6 +414,18 @@ namespace BizHawk.Client.EmuHawk } _floatPaintState = 0; _floatEditYPos = -1; + _leftButtonHeld = false; + + CurrentTasMovie.ChangeLog.EndBatch(); + } + else if (e.Button == System.Windows.Forms.MouseButtons.Right) + { + if (_rightClickFrame != -1) + { + _rightClickInput = null; + _rightClickFrame = -1; + CurrentTasMovie.ChangeLog.EndBatch(); + } } _supressContextMenu = false; @@ -427,6 +483,7 @@ namespace BizHawk.Client.EmuHawk } int startVal, endVal; + int frame = e.NewCell.RowIndex.Value; if (e.OldCell.RowIndex.Value < e.NewCell.RowIndex.Value) { startVal = e.OldCell.RowIndex.Value; @@ -457,6 +514,82 @@ namespace BizHawk.Client.EmuHawk RefreshTasView(); } } + 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) % _rightClickInput.Length]); + } + else + { + CurrentTasMovie.RemoveFrames(startVal + 1, endVal + 1); + } + + _rightClickLastFrame = frame; + } + else // Overwrite + { + for (int i = startVal; i <= endVal; i++) + CurrentTasMovie.SetFrame(i, _rightClickInput[(_rightClickFrame - i) % _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 + { + 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; + } + } + RefreshTasView(); + } else if (TasView.IsPaintDown && e.NewCell.RowIndex.HasValue && !string.IsNullOrEmpty(_startBoolDrawColumn)) { if (e.OldCell.RowIndex.HasValue && e.NewCell.RowIndex.HasValue) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index b920a31004..04046fdd47 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -306,7 +306,7 @@ namespace BizHawk.Client.EmuHawk TasView.RowCount = CurrentTasMovie.InputLogLength + 1; TasView.Refresh(); - CurrentTasMovie.FlushInputCache(TasView.VisibleRows); + CurrentTasMovie.FlushInputCache(); CurrentTasMovie.UseInputCache = false; }