-Feature: Changing input past the movie now extends the movie.

-Implemented max undo levels feature.
-Started making TAStudio UI for undo history.
This commit is contained in:
SuuperW 2015-03-03 21:10:48 +00:00
parent e4c4910b37
commit 1e0ce3b7c1
8 changed files with 267 additions and 136 deletions

View File

@ -210,6 +210,7 @@ namespace BizHawk.Client.Common
Changes = true;
InvalidateAfter(frame);
if (BindMarkersToInput)
{
int firstIndex = Markers.FindIndex(m => m.Frame >= frame);
@ -226,7 +227,7 @@ namespace BizHawk.Client.Common
ChangeLog.SetGeneralRedo();
if (endBatch)
ChangeLog.EndBatch();
}
}
public void InsertInput(int frame, IEnumerable<IController> inputStates)
{
// ChangeLog is done in the InsertInput call.
@ -270,9 +271,7 @@ namespace BizHawk.Client.Common
lg.SetSource(Global.MovieSession.MovieControllerInstance());
for (int i = 0; i < count; i++)
{
_log.Insert(frame, lg.EmptyEntry);
}
if (BindMarkersToInput)
{
@ -294,132 +293,128 @@ namespace BizHawk.Client.Common
ChangeLog.SetGeneralRedo();
if (endBatch)
ChangeLog.EndBatch();
if (Global.Emulator.Frame < _log.Count) // Don't stay in recording mode? Fixes TAStudio recording after paint inserting.
this.SwitchToPlay();
}
public void ToggleBoolState(int frame, string buttonName)
{
if (frame < _log.Count)
{
var adapter = GetInputState(frame) as Bk2ControllerAdapter;
adapter[buttonName] = !adapter.IsPressed(buttonName);
if (frame >= _log.Count) // Insert blank frames up to this point
InsertEmptyFrame(_log.Count, frame - _log.Count + 1);
var lg = LogGeneratorInstance();
lg.SetSource(adapter);
_log[frame] = lg.GenerateLogEntry();
Changes = true;
InvalidateAfter(frame);
var adapter = GetInputState(frame) as Bk2ControllerAdapter;
adapter[buttonName] = !adapter.IsPressed(buttonName);
ChangeLog.AddBoolToggle(frame, buttonName, !adapter[buttonName]);
}
var lg = LogGeneratorInstance();
lg.SetSource(adapter);
_log[frame] = lg.GenerateLogEntry();
Changes = true;
InvalidateAfter(frame);
ChangeLog.AddBoolToggle(frame, buttonName, !adapter[buttonName]);
}
public void SetBoolState(int frame, string buttonName, bool val)
{
if (frame < _log.Count)
if (frame >= _log.Count) // Insert blank frames up to this point
InsertEmptyFrame(_log.Count, frame - _log.Count + 1);
var adapter = GetInputState(frame) as Bk2ControllerAdapter;
var old = adapter[buttonName];
adapter[buttonName] = val;
var lg = LogGeneratorInstance();
lg.SetSource(adapter);
_log[frame] = lg.GenerateLogEntry();
if (old != val)
{
var adapter = GetInputState(frame) as Bk2ControllerAdapter;
var old = adapter[buttonName];
adapter[buttonName] = val;
var lg = LogGeneratorInstance();
lg.SetSource(adapter);
_log[frame] = lg.GenerateLogEntry();
if (old != val)
{
InvalidateAfter(frame);
Changes = true;
ChangeLog.AddBoolToggle(frame, buttonName, old);
}
InvalidateAfter(frame);
Changes = true;
ChangeLog.AddBoolToggle(frame, buttonName, old);
}
}
public void SetBoolStates(int frame, int count, string buttonName, bool val)
{
if (frame < _log.Count)
if (frame + count >= _log.Count) // Insert blank frames up to this point
InsertEmptyFrame(_log.Count, frame + count - _log.Count + 1);
ChangeLog.AddGeneralUndo(frame, frame + count - 1);
int changed = -1;
for (int i = 0; i < count; i++)
{
if (frame + count >= _log.Count)
count = _log.Count - frame - 1;
var adapter = GetInputState(frame + i) as Bk2ControllerAdapter;
bool old = adapter[buttonName];
adapter[buttonName] = val;
ChangeLog.AddGeneralUndo(frame, frame + count - 1);
var lg = LogGeneratorInstance();
lg.SetSource(adapter);
_log[frame + i] = lg.GenerateLogEntry();
int changed = -1;
for (int i = 0; i < count; i++)
{
var adapter = GetInputState(frame + i) as Bk2ControllerAdapter;
bool old = adapter[buttonName];
adapter[buttonName] = val;
var lg = LogGeneratorInstance();
lg.SetSource(adapter);
_log[frame + i] = lg.GenerateLogEntry();
if (changed == -1 && old != val)
changed = frame + i;
}
if (changed != -1)
{
InvalidateAfter(changed);
Changes = true;
}
ChangeLog.SetGeneralRedo();
if (changed == -1 && old != val)
changed = frame + i;
}
if (changed != -1)
{
InvalidateAfter(changed);
Changes = true;
}
ChangeLog.SetGeneralRedo();
}
public void SetFloatState(int frame, string buttonName, float val)
{
if (frame < _log.Count)
if (frame >= _log.Count) // Insert blank frames up to this point
InsertEmptyFrame(_log.Count, frame - _log.Count + 1);
var adapter = GetInputState(frame) as Bk2ControllerAdapter;
var old = adapter.GetFloat(buttonName);
adapter.SetFloat(buttonName, val);
var lg = LogGeneratorInstance();
lg.SetSource(adapter);
_log[frame] = lg.GenerateLogEntry();
if (old != val)
{
var adapter = GetInputState(frame) as Bk2ControllerAdapter;
var old = adapter.GetFloat(buttonName);
adapter.SetFloat(buttonName, val);
var lg = LogGeneratorInstance();
lg.SetSource(adapter);
_log[frame] = lg.GenerateLogEntry();
if (old != val)
{
InvalidateAfter(frame);
Changes = true;
ChangeLog.AddFloatChange(frame, buttonName, old, val);
}
InvalidateAfter(frame);
Changes = true;
ChangeLog.AddFloatChange(frame, buttonName, old, val);
}
}
public void SetFloatStates(int frame, int count, string buttonName, float val)
{
if (frame < _log.Count)
if (frame + count >= _log.Count) // Insert blank frames up to this point
InsertEmptyFrame(_log.Count, frame + count - _log.Count + 1);
ChangeLog.AddGeneralUndo(frame, frame + count - 1);
int changed = -1;
for (int i = 0; i < count; i++)
{
if (frame + count >= _log.Count)
count = _log.Count - frame - 1;
var adapter = GetInputState(frame + i) as Bk2ControllerAdapter;
float old = adapter.GetFloat(buttonName);
adapter.SetFloat(buttonName, val);
ChangeLog.AddGeneralUndo(frame, frame + count - 1);
var lg = LogGeneratorInstance();
lg.SetSource(adapter);
_log[frame + i] = lg.GenerateLogEntry();
int changed = -1;
for (int i = 0; i < count; i++)
{
var adapter = GetInputState(frame + i) as Bk2ControllerAdapter;
float old = adapter.GetFloat(buttonName);
adapter.SetFloat(buttonName, val);
var lg = LogGeneratorInstance();
lg.SetSource(adapter);
_log[frame + i] = lg.GenerateLogEntry();
if (changed == -1 && old != val)
changed = frame + i;
}
if (changed != -1)
{
InvalidateAfter(changed);
Changes = true;
}
ChangeLog.SetGeneralRedo();
if (changed == -1 && old != val)
changed = frame + i;
}
}
if (changed != -1)
{
InvalidateAfter(changed);
Changes = true;
}
ChangeLog.SetGeneralRedo();
}
}
}

View File

@ -10,7 +10,24 @@ namespace BizHawk.Client.Common
public class TasMovieChangeLog
{
List<List<IMovieAction>> History;
public List<string> Names;
int UndoIndex = -1;
int _maxSteps = 100;
public int MaxSteps
{
get { return _maxSteps; }
set
{
_maxSteps = value;
if (History.Count > value)
{
if (History.Count <= value)
ClearLog();
else
ClearLog(History.Count - value);
}
}
}
private bool RecordingBatch = false;
/// <summary>
@ -23,6 +40,7 @@ namespace BizHawk.Client.Common
public TasMovieChangeLog(TasMovie movie)
{
History = new List<List<IMovieAction>>();
Names = new List<string>();
Movie = movie;
}
@ -32,6 +50,7 @@ namespace BizHawk.Client.Common
upTo = History.Count;
History.RemoveRange(0, upTo);
Names.RemoveRange(0, upTo);
UndoIndex -= upTo;
if (UndoIndex < -1)
UndoIndex = -1;
@ -42,6 +61,7 @@ namespace BizHawk.Client.Common
private void TruncateLog(int from)
{
History.RemoveRange(from, History.Count - from);
Names.RemoveRange(from, Names.Count - from);
if (UndoIndex < History.Count - 1)
UndoIndex = History.Count - 1;
@ -75,7 +95,7 @@ namespace BizHawk.Client.Common
if (ret)
{
AddMovieAction();
ret = AddMovieAction();
}
RecordingBatch = true;
@ -183,11 +203,23 @@ namespace BizHawk.Client.Common
if (!RecordingBatch)
{
History.Add(new List<IMovieAction>(1));
UndoIndex += 1;
Names.Add("");
if (History.Count < MaxSteps)
UndoIndex += 1;
else
{
History.RemoveAt(0);
Names.RemoveAt(0);
}
}
return true;
}
public void SetName(string name)
{
Names[Names.Count - 1] = name;
}
// TODO: These probably aren't the best way to handle undo/redo.
private int lastGeneral;

View File

@ -1,4 +1,4 @@
namespace BizHawk.Client.EmuHawk.tools.TAStudio
namespace BizHawk.Client.EmuHawk
{
partial class HistoryBox
{
@ -28,22 +28,69 @@
/// </summary>
private void InitializeComponent()
{
this.HistoryGroupBox = new System.Windows.Forms.GroupBox();
this.HistoryView = new BizHawk.Client.EmuHawk.VirtualListView();
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.UndoButton = new System.Windows.Forms.Button();
this.ClearButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// HistoryGroupBox
// HistoryView
//
this.HistoryGroupBox.Location = new System.Drawing.Point(3, 3);
this.HistoryGroupBox.Name = "HistoryGroupBox";
this.HistoryGroupBox.Size = new System.Drawing.Size(198, 334);
this.HistoryGroupBox.TabIndex = 0;
this.HistoryGroupBox.TabStop = false;
this.HistoryGroupBox.Text = "History";
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.BlazingFast = false;
this.HistoryView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeader1,
this.columnHeader2});
this.HistoryView.ItemCount = 0;
this.HistoryView.Location = new System.Drawing.Point(0, 0);
this.HistoryView.Name = "HistoryView";
this.HistoryView.SelectAllInProgress = false;
this.HistoryView.selectedItem = -1;
this.HistoryView.Size = new System.Drawing.Size(204, 318);
this.HistoryView.TabIndex = 0;
this.HistoryView.UseCompatibleStateImageBehavior = false;
this.HistoryView.UseCustomBackground = true;
this.HistoryView.View = System.Windows.Forms.View.Details;
//
// columnHeader1
//
this.columnHeader1.Text = "ID";
this.columnHeader1.Width = 40;
//
// columnHeader2
//
this.columnHeader2.Text = "Undo Step";
this.columnHeader2.Width = 160;
//
// 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(3, 324);
this.UndoButton.Name = "UndoButton";
this.UndoButton.Size = new System.Drawing.Size(55, 23);
this.UndoButton.TabIndex = 1;
this.UndoButton.Text = "Undo";
this.UndoButton.UseVisualStyleBackColor = true;
//
// 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(146, 324);
this.ClearButton.Name = "ClearButton";
this.ClearButton.Size = new System.Drawing.Size(55, 23);
this.ClearButton.TabIndex = 1;
this.ClearButton.Text = "Clear";
this.ClearButton.UseVisualStyleBackColor = true;
//
// HistoryBox
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.Controls.Add(this.HistoryGroupBox);
this.Controls.Add(this.ClearButton);
this.Controls.Add(this.UndoButton);
this.Controls.Add(this.HistoryView);
this.Name = "HistoryBox";
this.Size = new System.Drawing.Size(204, 350);
this.ResumeLayout(false);
@ -52,6 +99,12 @@
#endregion
private System.Windows.Forms.GroupBox HistoryGroupBox;
private VirtualListView HistoryView;
private System.Windows.Forms.ColumnHeader columnHeader1;
private System.Windows.Forms.ColumnHeader columnHeader2;
private System.Windows.Forms.Button UndoButton;
private System.Windows.Forms.Button ClearButton;
}
}

View File

@ -7,13 +7,23 @@ using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace BizHawk.Client.EmuHawk.tools.TAStudio
//using BizHawk.Client.Common;
//using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk
{
public partial class HistoryBox : UserControl
{
public TAStudio Tastudio { get; set; }
public HistoryBox()
{
InitializeComponent();
}
public void UpdateValues()
{
}
}
}

View File

@ -54,6 +54,8 @@ namespace BizHawk.Client.EmuHawk
NormalFont = new Font("Courier New", 8); // Only support fixed width
// PrepDrawString doesn't actually set the font, so this is rather useless.
// I'm leaving this stuff as-is so it will be a bit easier to fix up with another rendering method.
RotatedFont = GDIRenderer.CreateRotatedHFont(Font, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);

View File

@ -143,11 +143,15 @@ namespace BizHawk.Client.EmuHawk
this.StartFromNowSeparator = new System.Windows.Forms.ToolStripSeparator();
this.StartNewProjectFromNowMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.historyBox1 = new BizHawk.Client.EmuHawk.HistoryBox();
this.btnShowUndoHistory = new System.Windows.Forms.Button();
this.TASMenu.SuspendLayout();
this.TasStatusStrip.SuspendLayout();
this.MarkerContextMenu.SuspendLayout();
this.RightClickMenu.SuspendLayout();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.SuspendLayout();
//
// TASMenu
@ -505,10 +509,10 @@ namespace BizHawk.Client.EmuHawk
//
// SetMaxUndoLevelsMenuItem
//
this.SetMaxUndoLevelsMenuItem.Enabled = false;
this.SetMaxUndoLevelsMenuItem.Name = "SetMaxUndoLevelsMenuItem";
this.SetMaxUndoLevelsMenuItem.Size = new System.Drawing.Size(288, 22);
this.SetMaxUndoLevelsMenuItem.Text = "Set max Undo Levels";
this.SetMaxUndoLevelsMenuItem.Click += new System.EventHandler(this.SetMaxUndoLevelsMenuItem_Click);
//
// toolStripSeparator9
//
@ -850,7 +854,7 @@ namespace BizHawk.Client.EmuHawk
this.MarkerControl.Emulator = null;
this.MarkerControl.Location = new System.Drawing.Point(2, 16);
this.MarkerControl.Name = "MarkerControl";
this.MarkerControl.Size = new System.Drawing.Size(198, 343);
this.MarkerControl.Size = new System.Drawing.Size(198, 258);
this.MarkerControl.TabIndex = 6;
this.MarkerControl.Tastudio = null;
//
@ -1083,17 +1087,47 @@ namespace BizHawk.Client.EmuHawk
this.groupBox1.Controls.Add(this.MarkerControl);
this.groupBox1.Location = new System.Drawing.Point(302, 129);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(201, 365);
this.groupBox1.Size = new System.Drawing.Size(201, 280);
this.groupBox1.TabIndex = 7;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Markers";
//
// groupBox2
//
this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.groupBox2.Controls.Add(this.historyBox1);
this.groupBox2.Controls.Add(this.btnShowUndoHistory);
this.groupBox2.Location = new System.Drawing.Point(302, 409);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(200, 85);
this.groupBox2.TabIndex = 8;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Undo History";
//
// historyBox1
//
this.historyBox1.Location = new System.Drawing.Point(5, 19);
this.historyBox1.Name = "historyBox1";
this.historyBox1.Size = new System.Drawing.Size(192, 63);
this.historyBox1.TabIndex = 1;
this.historyBox1.Tastudio = null;
//
// btnShowUndoHistory
//
this.btnShowUndoHistory.Location = new System.Drawing.Point(174, -1);
this.btnShowUndoHistory.Name = "btnShowUndoHistory";
this.btnShowUndoHistory.Size = new System.Drawing.Size(20, 21);
this.btnShowUndoHistory.TabIndex = 0;
this.btnShowUndoHistory.Text = "v";
this.btnShowUndoHistory.UseVisualStyleBackColor = true;
//
// TAStudio
//
this.AllowDrop = true;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(506, 519);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.TasPlaybackBox);
this.Controls.Add(this.TasStatusStrip);
@ -1117,6 +1151,7 @@ namespace BizHawk.Client.EmuHawk
this.MarkerContextMenu.ResumeLayout(false);
this.RightClickMenu.ResumeLayout(false);
this.groupBox1.ResumeLayout(false);
this.groupBox2.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
@ -1235,5 +1270,8 @@ namespace BizHawk.Client.EmuHawk
private System.Windows.Forms.ToolStripSeparator separateToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem pasteInsertToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem cutToolStripMenuItem;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.Button btnShowUndoHistory;
private HistoryBox historyBox1;
}
}

View File

@ -575,6 +575,25 @@ namespace BizHawk.Client.EmuHawk
#region Config
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()
})
{
DialogResult result = prompt.ShowDialog();
if (result == DialogResult.OK)
{
int val = int.Parse(prompt.PromptText);
if (val > 0)
CurrentTasMovie.ChangeLog.MaxSteps = val;
}
}
}
private void ConfigSubMenu_DropDownOpened(object sender, EventArgs e)
{
DrawInputByDraggingMenuItem.Checked = Settings.DrawInput;

View File

@ -295,9 +295,8 @@ namespace BizHawk.Client.EmuHawk
RefreshTasView();
if (MarkerControl != null)
{
MarkerControl.UpdateValues();
}
}
private void RefreshTasView()
@ -474,28 +473,14 @@ namespace BizHawk.Client.EmuHawk
// Sets either the pending frame or the tas input log
private void ToggleBoolState(int frame, string buttonName)
{
if (frame < CurrentTasMovie.InputLogLength)
{
CurrentTasMovie.ToggleBoolState(frame, buttonName);
}
else if (frame == Emulator.Frame && frame == CurrentTasMovie.InputLogLength)
{
Global.ClickyVirtualPadController.Toggle(buttonName);
}
CurrentTasMovie.ToggleBoolState(frame, buttonName);
}
// TODO: move me
// Sets either the pending frame or the tas input log
private void SetBoolState(int frame, string buttonName, bool value)
{
if (frame < CurrentTasMovie.InputLogLength)
{
CurrentTasMovie.SetBoolState(frame, buttonName, value);
}
else if (frame == Emulator.Frame && frame == CurrentTasMovie.InputLogLength)
{
Global.ClickyVirtualPadController.SetBool(buttonName, value);
}
CurrentTasMovie.SetBoolState(frame, buttonName, value);
}
private float GetFloatValue(int frame, string buttonName)
@ -508,10 +493,7 @@ namespace BizHawk.Client.EmuHawk
}
private void SetFloatValue(int frame, string buttonName, float value)
{
if (frame < CurrentTasMovie.InputLogLength)
CurrentTasMovie.SetFloatState(frame, buttonName, value);
else if (frame == Emulator.Frame && frame == CurrentTasMovie.InputLogLength)
Global.StickyXORAdapter.SetFloat(buttonName, value);
CurrentTasMovie.SetFloatState(frame, buttonName, value);
}
private void SetColumnsFromCurrentStickies()