TAStudio:

-Several buggixes
-Feature: Right-click dragging frames to move/copy/clone. (Combine with Shift and/or Ctrl.)
This commit is contained in:
SuuperW 2015-03-03 18:22:54 +00:00
parent 1d7a8e9b73
commit e4c4910b37
6 changed files with 253 additions and 55 deletions

View File

@ -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<string> inputLog)
{
bool endBatch = ChangeLog.BeginNewBatch(true);
@ -173,7 +227,6 @@ namespace BizHawk.Client.Common
if (endBatch)
ChangeLog.EndBatch();
}
public void InsertInput(int frame, IEnumerable<IController> inputStates)
{
// ChangeLog is done in the InsertInput call.

View File

@ -13,7 +13,11 @@ namespace BizHawk.Client.Common
int UndoIndex = -1;
private bool RecordingBatch = false;
public bool AutoRecord = true;
/// <summary>
/// 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
/// </summary>
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();
}
}
/// <summary>
@ -53,6 +61,9 @@ namespace BizHawk.Client.Common
/// <returns>Returns true if a new batch was started; otherwise false.</returns>
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<IMovieAction>());
UndoIndex++;
return ret;
}
/// <summary>
/// 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.
/// </summary>
public void EndBatch()
{
if (!IsRecording || !RecordingBatch)
return;
RecordingBatch = false;
List<IMovieAction> 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

View File

@ -271,6 +271,7 @@ namespace BizHawk.Client.Common
LagLog.Clear();
StateManager.Clear();
Markers.Clear();
ChangeLog.ClearLog();
}
private static string InputLogToString(List<string> log)

View File

@ -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)

View File

@ -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)

View File

@ -306,7 +306,7 @@ namespace BizHawk.Client.EmuHawk
TasView.RowCount = CurrentTasMovie.InputLogLength + 1;
TasView.Refresh();
CurrentTasMovie.FlushInputCache(TasView.VisibleRows);
CurrentTasMovie.FlushInputCache();
CurrentTasMovie.UseInputCache = false;
}