From e40b10a0b61b40f4c539f8166bd1266faacfae2f Mon Sep 17 00:00:00 2001 From: SuuperW Date: Tue, 3 Mar 2015 08:32:39 +0000 Subject: [PATCH] -marker undo code moved to proper place -undo history fixes -feature: binding markers to input -bugfix: TasView wasn't always refreshing when inserting/deleting frames --- .../movie/tasproj/TasMovie.Editing.cs | 85 +++++++++++++++++-- .../movie/tasproj/TasMovie.History.cs | 33 ++++++- .../movie/tasproj/TasMovie.cs | 5 ++ .../movie/tasproj/TasMovieMarker.cs | 33 ++++++- .../tools/TAStudio/TAStudio.Designer.cs | 6 +- .../tools/TAStudio/TAStudio.MenuItems.cs | 21 +++-- .../tools/TAStudio/TAStudio.cs | 7 +- 7 files changed, 163 insertions(+), 27 deletions(-) diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs index 05b0996011..146d649bae 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs @@ -29,6 +29,7 @@ namespace BizHawk.Client.Common public override void Truncate(int frame) { + bool endBatch = ChangeLog.BeginNewBatch(true); ChangeLog.AddGeneralUndo(frame, InputLogLength - 1); if (frame < _log.Count - 1) @@ -43,12 +44,14 @@ namespace BizHawk.Client.Common Markers.TruncateAt(frame); ChangeLog.SetGeneralRedo(); + if (endBatch) + ChangeLog.EndBatch(); } public override void PokeFrame(int frame, IController source) { ChangeLog.AddGeneralUndo(frame, frame); - + base.PokeFrame(frame, source); InvalidateAfter(frame); @@ -80,47 +83,100 @@ namespace BizHawk.Client.Common { var invalidateAfter = frames.Min(); + bool endBatch = ChangeLog.BeginNewBatch(true); ChangeLog.AddGeneralUndo(invalidateAfter, InputLogLength - 1); foreach (var frame in frames.OrderByDescending(x => x)) // Removin them in reverse order allows us to remove by index; { _log.RemoveAt(frame); + if (BindMarkersToInput) // TODO: This is slow, is there a better way to do it? + { + 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(invalidateAfter); ChangeLog.SetGeneralRedo(); + if (endBatch) + ChangeLog.EndBatch(); + } } public void RemoveFrames(int removeStart, int removeUpTo) { + bool endBatch = ChangeLog.BeginNewBatch(true); ChangeLog.AddGeneralUndo(removeStart, InputLogLength - 1); for (int i = removeUpTo - 1; i >= removeStart; i--) _log.RemoveAt(i); + if (BindMarkersToInput) + { + int firstIndex = Markers.FindIndex(m => m.Frame >= removeStart); + if (firstIndex != -1) + { + for (int i = firstIndex; i < Markers.Count; i++) + { + TasMovieMarker m = Markers.ElementAt(i); + if (m.Frame < removeUpTo) + Markers.Remove(m); + else + Markers.Move(m.Frame, m.Frame - (removeUpTo - removeStart)); + } + } + } + Changes = true; InvalidateAfter(removeStart); ChangeLog.SetGeneralRedo(); + if (endBatch) + ChangeLog.EndBatch(); } public void InsertInput(int frame, IEnumerable inputLog) { + bool endBatch = ChangeLog.BeginNewBatch(true); ChangeLog.AddGeneralUndo(frame, InputLogLength + inputLog.Count() - 1); _log.InsertRange(frame, inputLog); 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 + inputLog.Count()); + } + } + } + ChangeLog.SetGeneralRedo(); + if (endBatch) + ChangeLog.EndBatch(); } public void InsertInput(int frame, IEnumerable inputStates) { - ChangeLog.AddGeneralUndo(frame, InputLogLength + inputStates.Count() - 1); - + // ChangeLog is done in the InsertInput call. var lg = LogGeneratorInstance(); var inputLog = new List(); @@ -131,9 +187,7 @@ namespace BizHawk.Client.Common inputLog.Add(lg.GenerateLogEntry()); } - InsertInput(frame, inputLog); - - ChangeLog.SetGeneralRedo(); + InsertInput(frame, inputLog); // Sets the ChangeLog } public void CopyOverInput(int frame, IEnumerable inputStates) @@ -156,6 +210,7 @@ namespace BizHawk.Client.Common public void InsertEmptyFrame(int frame, int count = 1) { + bool endBatch = ChangeLog.BeginNewBatch(true); ChangeLog.AddGeneralUndo(frame, InputLogLength + count - 1); var lg = LogGeneratorInstance(); @@ -166,10 +221,26 @@ namespace BizHawk.Client.Common _log.Insert(frame, lg.EmptyEntry); } + 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 + count); + } + } + } + + Changes = true; InvalidateAfter(frame - 1); ChangeLog.SetGeneralRedo(); + if (endBatch) + ChangeLog.EndBatch(); } public void ToggleBoolState(int frame, string buttonName) @@ -186,7 +257,7 @@ namespace BizHawk.Client.Common InvalidateAfter(frame); ChangeLog.AddBoolToggle(frame, buttonName, !adapter[buttonName]); - } + } } public void SetBoolState(int frame, string buttonName, bool val) diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.History.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.History.cs index 9bd153d5dd..e5860ba786 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.History.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.History.cs @@ -49,13 +49,24 @@ namespace BizHawk.Client.Common /// All changes made between calling Begin and End will be one Undo. /// If already recording in a batch, calls EndBatch. /// - public void BeginNewBatch() + /// If set and a batch is in progress, a new batch will not be created. + /// Returns true if a new batch was started; otherwise false. + public bool BeginNewBatch(bool keepOldBatch = false) { + bool ret = true; if (RecordingBatch) - EndBatch(); + { + if (keepOldBatch) + ret = false; + else + EndBatch(); + } RecordingBatch = true; History.Add(new List()); + UndoIndex++; + + return ret; } /// /// Ends the current undo batch. Future changes will be one undo each. @@ -65,7 +76,10 @@ namespace BizHawk.Client.Common { RecordingBatch = false; List last = History.Last(); - last.Capacity = last.Count; + if (last.Count == 0) // Remove batch if it's empty. + History.RemoveAt(History.Count - 1); + else + last.Capacity = last.Count; } /// @@ -160,19 +174,21 @@ 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) { if (AutoRecord) { AddMovieAction(); History.Last().Add(new MovieAction(first, last, Movie)); + lastGeneral = History.Last().Count - 1; } } public void SetGeneralRedo() { if (AutoRecord) { - (History.Last().Last() as MovieAction).SetRedoLog(Movie); + (History.Last()[lastGeneral] as MovieAction).SetRedoLog(Movie); } } @@ -225,6 +241,7 @@ namespace BizHawk.Client.Common { get { return LastFrame - FirstFrame + 1; } } private List oldLog; private List newLog; + private bool bindMarkers; public MovieAction(int firstFrame, int lastFrame, TasMovie movie) { @@ -235,6 +252,8 @@ namespace BizHawk.Client.Common undoLength = Math.Min(lastFrame + 1, movie.InputLogLength) - firstFrame; for (int i = 0; i < undoLength; i++) oldLog.Add(movie.GetLogEntries()[FirstFrame + i]); + + bindMarkers = movie.BindMarkersToInput; } public void SetRedoLog(TasMovie movie) { @@ -247,7 +266,9 @@ namespace BizHawk.Client.Common public void Undo(TasMovie movie) { bool wasRecording = movie.ChangeLog.AutoRecord; + bool wasBinding = movie.BindMarkersToInput; movie.ChangeLog.AutoRecord = false; + movie.BindMarkersToInput = bindMarkers; if (redoLength != length) movie.InsertEmptyFrame(movie.InputLogLength, length - redoLength); @@ -259,11 +280,14 @@ namespace BizHawk.Client.Common movie.RemoveFrames(FirstFrame + undoLength, movie.InputLogLength); movie.ChangeLog.AutoRecord = wasRecording; + movie.BindMarkersToInput = bindMarkers; } public void Redo(TasMovie movie) { bool wasRecording = movie.ChangeLog.AutoRecord; + bool wasBinding = movie.BindMarkersToInput; movie.ChangeLog.AutoRecord = false; + movie.BindMarkersToInput = bindMarkers; if (undoLength != length) movie.InsertEmptyFrame(movie.InputLogLength, length - undoLength); @@ -275,6 +299,7 @@ namespace BizHawk.Client.Common movie.RemoveFrames(FirstFrame + redoLength, movie.InputLogLength); movie.ChangeLog.AutoRecord = wasRecording; + movie.BindMarkersToInput = bindMarkers; } } diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs index af0ca787e8..9e24400a08 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs @@ -45,6 +45,8 @@ namespace BizHawk.Client.Common Markers = new TasMovieMarkerList(this); Markers.CollectionChanged += Markers_CollectionChanged; Markers.Add(0, startsFromSavestate ? "Savestate" : "Power on"); + + BindMarkersToInput = true; } public TasMovie(bool startsFromSavestate = false, BackgroundWorker progressReportWorker = null) @@ -63,9 +65,12 @@ namespace BizHawk.Client.Common Markers = new TasMovieMarkerList(this); Markers.CollectionChanged += Markers_CollectionChanged; Markers.Add(0, startsFromSavestate ? "Savestate" : "Power on"); + + BindMarkersToInput = true; } public TasMovieMarkerList Markers { get; set; } + public bool BindMarkersToInput { get; set; } public bool UseInputCache { get; set; } public override string PreferredExtension diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovieMarker.cs b/BizHawk.Client.Common/movie/tasproj/TasMovieMarker.cs index f2a671bb26..8e5f13600c 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovieMarker.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovieMarker.cs @@ -107,12 +107,14 @@ namespace BizHawk.Client.Common { if (existingItem.Message != item.Message) { + _movie.ChangeLog.AddMarkerChange(item, item.Frame, existingItem.Message); existingItem.Message = item.Message; OnListChanged(NotifyCollectionChangedAction.Replace); } } else { + _movie.ChangeLog.AddMarkerChange(item); base.Add(item); this.Sort((m1, m2) => m1.Frame.CompareTo(m2.Frame)); OnListChanged(NotifyCollectionChangedAction.Add); @@ -126,13 +128,18 @@ namespace BizHawk.Client.Common public new void AddRange(IEnumerable collection) { - foreach(TasMovieMarker m in collection){ + bool endBatch = _movie.ChangeLog.BeginNewBatch(true); + foreach (TasMovieMarker m in collection) + { Add(m); } + if (endBatch) + _movie.ChangeLog.EndBatch(); } public new void Insert(int index, TasMovieMarker item) { + _movie.ChangeLog.AddMarkerChange(item); base.Insert(index, item); this.Sort((m1, m2) => m1.Frame.CompareTo(m2.Frame)); OnListChanged(NotifyCollectionChangedAction.Add); @@ -140,6 +147,12 @@ namespace BizHawk.Client.Common public new void InsertRange(int index, IEnumerable collection) { + bool endBatch = _movie.ChangeLog.BeginNewBatch(true); + foreach (TasMovieMarker m in collection) + _movie.ChangeLog.AddMarkerChange(m); + if (endBatch) + _movie.ChangeLog.EndBatch(); + base.InsertRange(index, collection); this.Sort((m1, m2) => m1.Frame.CompareTo(m2.Frame)); OnListChanged(NotifyCollectionChangedAction.Add); @@ -147,12 +160,22 @@ namespace BizHawk.Client.Common public new void Remove(TasMovieMarker item) { + _movie.ChangeLog.AddMarkerChange(null, item.Frame, item.Message); base.Remove(item); OnListChanged(NotifyCollectionChangedAction.Remove); } public new int RemoveAll(Predicate match) { + bool endBatch = _movie.ChangeLog.BeginNewBatch(true); + foreach (TasMovieMarker m in this) + { + if (match.Invoke(m)) + _movie.ChangeLog.AddMarkerChange(null, m.Frame, m.Message); + } + if (endBatch) + _movie.ChangeLog.EndBatch(); + int removeCount = base.RemoveAll(match); if (removeCount > 0) { @@ -164,6 +187,7 @@ namespace BizHawk.Client.Common public void Move(int fromFrame, int toFrame) { TasMovieMarker m = Get(fromFrame); + _movie.ChangeLog.AddMarkerChange(m, m.Frame); Insert(0, new TasMovieMarker(toFrame, m.Message)); Remove(m); } @@ -176,13 +200,18 @@ namespace BizHawk.Client.Common public int TruncateAt(int startFrame) { int deletedCount = 0; + bool endBatch = _movie.ChangeLog.BeginNewBatch(true); for (int i = Count - 1; i > -1; i--) { - if(this[i].Frame >= startFrame){ + if (this[i].Frame >= startFrame) + { + _movie.ChangeLog.AddMarkerChange(null, this[i].Frame, this[i].Message); RemoveAt(i); deletedCount++; } } + if (endBatch) + _movie.ChangeLog.EndBatch(); if (deletedCount > 0) { OnListChanged(NotifyCollectionChangedAction.Remove); diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs index 2af0dbd41f..f4b69c5aec 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Designer.cs @@ -555,10 +555,13 @@ namespace BizHawk.Client.EmuHawk // // BindMarkersToInputMenuItem // - this.BindMarkersToInputMenuItem.Enabled = false; + this.BindMarkersToInputMenuItem.Checked = true; + this.BindMarkersToInputMenuItem.CheckOnClick = true; + this.BindMarkersToInputMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; this.BindMarkersToInputMenuItem.Name = "BindMarkersToInputMenuItem"; this.BindMarkersToInputMenuItem.Size = new System.Drawing.Size(288, 22); this.BindMarkersToInputMenuItem.Text = "Bind Markers to Input"; + this.BindMarkersToInputMenuItem.Click += new System.EventHandler(this.BindMarkersToInputMenuItem_Click); // // EmptyNewMarkerNotesMenuItem // @@ -771,7 +774,6 @@ namespace BizHawk.Client.EmuHawk this.TasView.FullRowSelect = true; this.TasView.HorizontalOrientation = false; this.TasView.LagFramesToHide = 0; - this.TasView.LastVisibleRow = 28; this.TasView.Location = new System.Drawing.Point(8, 27); this.TasView.MaxCharactersInHorizontal = 1; this.TasView.MultiSelect = false; diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index 69cf882b86..5ad18f6753 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -251,7 +251,7 @@ namespace BizHawk.Client.EmuHawk if (_tasClipboard.Any()) { - var needsToRollback = !(TasView.FirstSelectedIndex > Emulator.Frame); + var needsToRollback = TasView.FirstSelectedIndex < Emulator.Frame; CurrentTasMovie.CopyOverInput(TasView.FirstSelectedIndex.Value, _tasClipboard.Select(x => x.ControllerState)); @@ -280,7 +280,7 @@ namespace BizHawk.Client.EmuHawk if (_tasClipboard.Any()) { - var needsToRollback = !(TasView.FirstSelectedIndex > Emulator.Frame); + var needsToRollback = TasView.FirstSelectedIndex < Emulator.Frame; CurrentTasMovie.InsertInput(TasView.FirstSelectedIndex.Value, _tasClipboard.Select(x => x.ControllerState)); @@ -308,7 +308,7 @@ namespace BizHawk.Client.EmuHawk if (TasView.SelectedRows.Any()) { var wasPaused = GlobalWin.MainForm.EmulatorPaused; - var needsToRollback = !(TasView.FirstSelectedIndex.Value > Emulator.Frame); + var needsToRollback = TasView.FirstSelectedIndex < Emulator.Frame; var rollBackFrame = TasView.FirstSelectedIndex.Value; _tasClipboard.Clear(); @@ -384,7 +384,7 @@ namespace BizHawk.Client.EmuHawk if (TasView.SelectedRows.Any()) { var wasPaused = GlobalWin.MainForm.EmulatorPaused; - var needsToRollback = TasView.FirstSelectedIndex <= Emulator.Frame; + var needsToRollback = TasView.FirstSelectedIndex < Emulator.Frame; var rollBackFrame = TasView.FirstSelectedIndex.Value; if (rollBackFrame >= CurrentTasMovie.InputLogLength) { // Cannot delete non-existant frames @@ -421,7 +421,7 @@ namespace BizHawk.Client.EmuHawk var wasPaused = GlobalWin.MainForm.EmulatorPaused; var framesToInsert = TasView.SelectedRows.ToList(); var insertionFrame = Math.Min(TasView.LastSelectedIndex.Value + 1, CurrentTasMovie.InputLogLength); - var needsToRollback = insertionFrame <= Emulator.Frame; + var needsToRollback = TasView.FirstSelectedIndex < Emulator.Frame; var inputLog = framesToInsert .Select(frame => CurrentTasMovie.GetInputLogEntry(frame)) @@ -452,7 +452,7 @@ namespace BizHawk.Client.EmuHawk { var wasPaused = GlobalWin.MainForm.EmulatorPaused; var insertionFrame = TasView.SelectedRows.Any() ? TasView.FirstSelectedIndex.Value : 0; - var needsToRollback = insertionFrame <= Emulator.Frame; + var needsToRollback = TasView.FirstSelectedIndex < Emulator.Frame; CurrentTasMovie.InsertEmptyFrame(insertionFrame); @@ -478,7 +478,7 @@ namespace BizHawk.Client.EmuHawk { var wasPaused = GlobalWin.MainForm.EmulatorPaused; var insertionFrame = TasView.SelectedRows.Any() ? TasView.FirstSelectedIndex.Value : 0; - var needsToRollback = insertionFrame <= Emulator.Frame; + var needsToRollback = TasView.FirstSelectedIndex < Emulator.Frame; var framesPrompt = new FramesPrompt(); var result = framesPrompt.ShowDialog(); @@ -510,7 +510,7 @@ namespace BizHawk.Client.EmuHawk if (TasView.SelectedRows.Any()) { var rollbackFrame = TasView.LastSelectedIndex.Value; - var needsToRollback = !(rollbackFrame > Emulator.Frame); + var needsToRollback = TasView.FirstSelectedIndex < Emulator.Frame; CurrentTasMovie.Truncate(rollbackFrame); MarkerControl.MarkerInputRoll.TruncateSelection(CurrentTasMovie.Markers.Count - 1); @@ -587,6 +587,11 @@ namespace BizHawk.Client.EmuHawk TasView.InputPaintingMode = Settings.DrawInput ^= true; } + private void BindMarkersToInputMenuItem_Click(object sender, EventArgs e) + { + CurrentTasMovie.BindMarkersToInput = BindMarkersToInputMenuItem.Checked; + } + private void EmptyNewMarkerNotesMenuItem_Click(object sender, EventArgs e) { Settings.EmptyMarkers ^= true; diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index 158457de61..b920a31004 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -760,19 +760,18 @@ namespace BizHawk.Client.EmuHawk { TasMovieMarker marker = new TasMovieMarker(markerFrame, message); CurrentTasMovie.Markers.Add(marker); - CurrentTasMovie.ChangeLog.AddMarkerChange(marker); + //CurrentTasMovie.ChangeLog.AddMarkerChange(marker); } public void RemoveMarker(TasMovieMarker marker) { CurrentTasMovie.Markers.Remove(marker); - CurrentTasMovie.ChangeLog.AddMarkerChange(null, marker.Frame, marker.Message); + //CurrentTasMovie.ChangeLog.AddMarkerChange(null, marker.Frame, marker.Message); } public void EditMarker(TasMovieMarker marker, string message) { string old = marker.Message; marker.Message = message; - CurrentTasMovie.ChangeLog.AddMarkerChange(marker, marker.Frame, old); + //CurrentTasMovie.ChangeLog.AddMarkerChange(marker, marker.Frame, old); } - } }