2013-12-01 04:00:02 +00:00
using System ;
using System.Collections.Generic ;
using System.Drawing ;
using System.IO ;
2013-12-05 19:18:20 +00:00
using System.Linq ;
2014-07-27 15:22:30 +00:00
using System.Text ;
2013-12-01 04:00:02 +00:00
using System.Windows.Forms ;
2013-12-01 20:55:52 +00:00
2013-12-01 04:00:02 +00:00
using BizHawk.Client.Common ;
2014-07-06 21:20:43 +00:00
using BizHawk.Client.Common.MovieConversionExtensions ;
2014-07-27 15:22:30 +00:00
using BizHawk.Client.EmuHawk.WinFormExtensions ;
2014-07-28 01:51:11 +00:00
using BizHawk.Client.EmuHawk.ToolExtensions ;
2013-12-01 04:00:02 +00:00
namespace BizHawk.Client.EmuHawk
{
2014-07-08 16:08:52 +00:00
public partial class TAStudio : Form , IToolForm , IControlMainform
2013-12-01 04:00:02 +00:00
{
2013-12-14 14:40:33 +00:00
// TODO: UI flow that conveniently allows to start from savestate
2013-12-07 17:29:47 +00:00
private const string MarkerColumnName = "MarkerColumn" ;
private const string FrameColumnName = "FrameColumn" ;
2013-12-06 15:47:23 +00:00
2014-02-01 15:44:51 +00:00
private readonly List < TasClipboardEntry > _tasClipboard = new List < TasClipboardEntry > ( ) ;
2013-12-01 04:00:02 +00:00
private int _defaultWidth ;
private int _defaultHeight ;
2013-12-05 19:18:20 +00:00
private TasMovie _tas ;
2014-07-11 17:14:45 +00:00
private bool _originalRewindStatus ; // The client rewind status before TAStudio was engaged (used to restore when disengaged)
2014-07-14 00:35:33 +00:00
private MovieEndAction _originalEndAction ; // The movie end behavior selected by the user (that is overridden by TAStudio)
2013-12-01 04:00:02 +00:00
2014-07-09 21:56:27 +00:00
private Dictionary < string , string > GenerateColumnNames ( )
2014-07-06 22:13:12 +00:00
{
2014-07-09 21:56:27 +00:00
var lg = Global . MovieSession . LogGeneratorInstance ( ) ;
lg . SetSource ( Global . MovieSession . MovieControllerAdapter ) ;
return ( lg as Bk2LogEntryGenerator ) . Map ( ) ;
2014-07-06 22:13:12 +00:00
}
2013-12-01 04:00:02 +00:00
2014-07-11 23:54:18 +00:00
// Indices Helpers
private int FirstSelectedIndex
{
get
{
return TasView . SelectedIndices
. OfType < int > ( )
. OrderBy ( frame = > frame )
. First ( ) ;
}
}
private int LastSelectedIndex
{
get
{
return TasView . SelectedIndices
. OfType < int > ( )
. OrderBy ( frame = > frame )
. Last ( ) ;
}
}
2014-07-12 01:23:38 +00:00
private IEnumerable < int > SelectedIndices
2014-07-11 23:54:18 +00:00
{
get
{
return TasView . SelectedIndices
. OfType < int > ( )
. OrderBy ( frame = > frame ) ;
}
}
2014-07-21 02:23:47 +00:00
public TasMovie CurrentMovie
{
get { return _tas ; }
}
2013-12-01 04:00:02 +00:00
public TAStudio ( )
{
InitializeComponent ( ) ;
2014-07-17 19:00:28 +00:00
TasPlaybackBox . Tastudio = this ;
2014-07-16 02:20:14 +00:00
MarkerControl . Tastudio = this ;
2014-02-01 15:44:51 +00:00
TasView . QueryItemText + = TasView_QueryItemText ;
TasView . QueryItemBkColor + = TasView_QueryItemBkColor ;
2013-12-20 03:28:25 +00:00
TasView . VirtualMode = true ;
2013-12-01 04:00:02 +00:00
Closing + = ( o , e ) = >
{
if ( AskSave ( ) )
{
SaveConfigSettings ( ) ;
2014-07-10 19:51:36 +00:00
GlobalWin . MainForm . StopMovie ( saveChanges : false ) ;
2014-07-08 15:15:35 +00:00
DisengageTastudio ( ) ;
2013-12-01 04:00:02 +00:00
}
else
{
e . Cancel = true ;
}
} ;
2014-02-01 15:44:51 +00:00
TopMost = Global . Config . TAStudioSettings . TopMost ;
2013-12-20 03:28:25 +00:00
TasView . InputPaintingMode = Global . Config . TAStudioDrawInput ;
2014-02-01 15:44:51 +00:00
TasView . PointedCellChanged + = TasView_PointedCellChanged ;
2013-12-01 04:00:02 +00:00
}
2014-02-02 17:49:40 +00:00
private void Tastudio_Load ( object sender , EventArgs e )
2013-12-01 04:00:02 +00:00
{
2014-07-08 13:33:01 +00:00
// Start Scenario 1: A regular movie is active
2014-07-06 21:20:43 +00:00
if ( Global . MovieSession . Movie . IsActive & & ! ( Global . MovieSession . Movie is TasMovie ) )
2013-12-01 22:29:38 +00:00
{
2014-07-06 21:20:43 +00:00
var result = MessageBox . Show ( "In order to use Tastudio, a new project must be created from the current movie\nThe current movie will be saved and closed, and a new project file will be created\nProceed?" , "Convert movie" , MessageBoxButtons . OKCancel , MessageBoxIcon . Question ) ;
if ( result = = DialogResult . OK )
{
2014-07-08 15:15:35 +00:00
ConvertCurrentMovieToTasproj ( ) ;
2014-07-06 21:20:43 +00:00
}
else
2013-12-01 22:29:38 +00:00
{
Close ( ) ;
return ;
}
}
2014-07-08 13:33:01 +00:00
// Start Scenario 2: A tasproj is already active
2014-07-06 21:20:43 +00:00
else if ( Global . MovieSession . Movie . IsActive & & Global . MovieSession . Movie is TasMovie )
{
2014-07-08 15:15:35 +00:00
// Nothing to do
2014-07-06 21:20:43 +00:00
}
2014-07-08 13:33:01 +00:00
// Start Scenario 3: No movie, but user wants to autload their last project
2014-07-13 15:26:50 +00:00
else if ( Global . Config . AutoloadTAStudioProject & & ! string . IsNullOrEmpty ( Global . Config . RecentTas . MostRecent ) )
2013-12-14 19:51:07 +00:00
{
2014-07-08 15:15:35 +00:00
LoadProject ( Global . Config . RecentTas . MostRecent ) ;
2013-12-14 19:51:07 +00:00
}
2014-07-08 13:33:01 +00:00
// Start Scenario 4: No movie, default behavior of engaging tastudio with a new default project
2013-12-14 19:51:07 +00:00
else
{
2014-07-08 15:15:35 +00:00
NewTasMovie ( ) ;
2014-07-10 02:45:56 +00:00
GlobalWin . MainForm . StartNewMovie ( _tas , record : true ) ;
2014-07-17 18:21:12 +00:00
_tas . CaptureCurrentState ( ) ;
2013-12-14 19:51:07 +00:00
}
2014-07-08 15:15:35 +00:00
EngageTastudio ( ) ;
2014-07-06 22:13:12 +00:00
SetUpColumns ( ) ;
2014-07-07 19:48:58 +00:00
LoadConfigSettings ( ) ;
2014-07-09 22:44:20 +00:00
RefreshDialog ( ) ;
2013-12-05 19:18:20 +00:00
}
2014-07-08 15:15:35 +00:00
private void ConvertCurrentMovieToTasproj ( )
{
Global . MovieSession . Movie . Save ( ) ;
Global . MovieSession . Movie = Global . MovieSession . Movie . ToTasMovie ( ) ;
Global . MovieSession . Movie . Save ( ) ;
}
private void EngageTastudio ( )
2013-12-10 16:37:41 +00:00
{
2014-07-27 02:38:21 +00:00
GlobalWin . MainForm . PauseOnFrame = null ;
2013-12-10 16:37:41 +00:00
GlobalWin . OSD . AddMessage ( "TAStudio engaged" ) ;
2014-07-08 15:15:35 +00:00
_tas = Global . MovieSession . Movie as TasMovie ;
2014-07-12 01:32:21 +00:00
GlobalWin . MainForm . PauseEmulator ( ) ;
2014-07-08 16:08:52 +00:00
GlobalWin . MainForm . RelinquishControl ( this ) ;
2014-07-11 17:14:45 +00:00
_originalRewindStatus = Global . Rewinder . RewindActive ;
2014-07-14 00:35:33 +00:00
_originalEndAction = Global . Config . MovieEndAction ;
2014-07-13 14:13:20 +00:00
MarkerControl . Markers = _tas . Markers ;
2014-07-11 17:14:45 +00:00
GlobalWin . MainForm . EnableRewind ( false ) ;
2014-07-14 00:35:33 +00:00
Global . Config . MovieEndAction = MovieEndAction . Record ;
2014-07-19 16:03:12 +00:00
GlobalWin . MainForm . SetMainformMovieInfo ( ) ;
2014-07-08 15:15:35 +00:00
}
2014-07-08 13:46:59 +00:00
2014-07-08 15:15:35 +00:00
private void DisengageTastudio ( )
{
2014-07-27 02:38:21 +00:00
GlobalWin . MainForm . PauseOnFrame = null ;
2014-07-08 15:15:35 +00:00
GlobalWin . OSD . AddMessage ( "TAStudio disengaged" ) ;
Global . MovieSession . Movie = MovieService . DefaultInstance ;
2014-07-08 16:08:52 +00:00
GlobalWin . MainForm . TakeControl ( ) ;
2014-07-11 17:14:45 +00:00
GlobalWin . MainForm . EnableRewind ( _originalRewindStatus ) ;
2014-07-14 00:35:33 +00:00
Global . Config . MovieEndAction = _originalEndAction ;
2014-07-19 16:03:12 +00:00
GlobalWin . MainForm . SetMainformMovieInfo ( ) ;
2014-07-08 15:15:35 +00:00
}
2014-07-08 13:46:59 +00:00
2014-07-08 15:15:35 +00:00
private void NewTasMovie ( )
{
Global . MovieSession . Movie = new TasMovie ( ) ;
2013-12-10 16:37:41 +00:00
_tas = Global . MovieSession . Movie as TasMovie ;
2014-07-08 15:15:35 +00:00
_tas . Filename = DefaultTasProjName ( ) ; // TODO don't do this, take over any mainform actions that can crash without a filename
_tas . PopulateWithDefaultHeaderValues ( ) ;
2014-07-11 18:06:18 +00:00
_tas . ClearChanges ( ) ;
2014-07-08 15:15:35 +00:00
}
private static string DefaultTasProjName ( )
{
return Path . Combine (
PathManager . MakeAbsolutePath ( Global . Config . PathEntries . MoviesPathFragment , null ) ,
PathManager . FilesystemSafeName ( Global . Game ) + "." + TasMovie . Extension ) ;
2013-12-10 16:37:41 +00:00
}
2014-07-10 19:51:36 +00:00
private void StartNewTasMovie ( )
2013-12-10 16:37:41 +00:00
{
if ( AskSave ( ) )
{
2014-07-10 19:51:36 +00:00
NewTasMovie ( ) ;
GlobalWin . MainForm . StartNewMovie ( _tas , record : true ) ;
2014-07-09 22:44:20 +00:00
RefreshDialog ( ) ;
2013-12-10 16:37:41 +00:00
}
}
2014-07-08 15:15:35 +00:00
public void LoadProject ( string path )
{
if ( AskSave ( ) )
{
2014-07-09 22:44:20 +00:00
var movie = new TasMovie
{
Filename = path
} ;
2014-07-08 15:15:35 +00:00
2014-07-09 22:44:20 +00:00
var file = new FileInfo ( path ) ;
if ( ! file . Exists )
2014-07-08 15:15:35 +00:00
{
2014-07-28 01:51:11 +00:00
Global . Config . RecentTas . HandleLoadError ( path ) ;
2014-07-08 15:15:35 +00:00
}
2014-07-09 22:44:20 +00:00
GlobalWin . MainForm . StartNewMovie ( movie , record : false ) ;
_tas = Global . MovieSession . Movie as TasMovie ;
Global . Config . RecentTas . Add ( path ) ;
RefreshDialog ( ) ;
2014-07-08 15:15:35 +00:00
}
}
2014-07-16 02:17:19 +00:00
public void RefreshDialog ( )
2014-07-08 15:15:35 +00:00
{
2014-07-27 15:50:48 +00:00
TasView . BlazingFast = true ;
2014-07-16 23:04:56 +00:00
TasView . ItemCount = _tas . InputLogLength + 1 ;
2014-07-27 15:50:48 +00:00
TasView . BlazingFast = false ;
2014-07-15 23:43:17 +00:00
if ( MarkerControl ! = null )
{
MarkerControl . Refresh ( ) ;
}
2014-07-08 15:15:35 +00:00
}
2014-07-13 15:26:50 +00:00
// TODO: a better name
private void GoToLastEmulatedFrameIfNecessary ( int frame )
{
2014-07-16 23:04:56 +00:00
if ( frame ! = Global . Emulator . Frame ) // Don't go to a frame if you are already on it!
2014-07-13 15:26:50 +00:00
{
2014-07-16 23:04:56 +00:00
if ( frame < = _tas . LastEmulatedFrame )
{
GoToFrame ( frame ) ;
}
2014-07-13 15:26:50 +00:00
}
}
2013-12-05 19:18:20 +00:00
private void SetUpColumns ( )
{
2013-12-20 03:28:25 +00:00
TasView . Columns . Clear ( ) ;
2014-07-06 22:13:12 +00:00
AddColumn ( MarkerColumnName , string . Empty , 18 ) ;
2013-12-07 17:29:47 +00:00
AddColumn ( FrameColumnName , "Frame#" , 68 ) ;
2013-12-05 19:18:20 +00:00
2014-07-09 21:56:27 +00:00
foreach ( var kvp in GenerateColumnNames ( ) )
2013-12-05 19:18:20 +00:00
{
2014-07-07 16:03:22 +00:00
AddColumn ( kvp . Key , kvp . Value , 20 * kvp . Value . Length ) ;
2013-12-07 17:29:47 +00:00
}
}
public void AddColumn ( string columnName , string columnText , int columnWidth )
{
2013-12-20 03:28:25 +00:00
if ( TasView . Columns [ columnName ] = = null )
2013-12-07 17:29:47 +00:00
{
var column = new ColumnHeader
{
Name = columnName ,
Text = columnText ,
Width = columnWidth ,
} ;
2013-12-20 03:28:25 +00:00
TasView . Columns . Add ( column ) ;
2013-12-05 19:18:20 +00:00
}
2013-12-01 04:00:02 +00:00
}
private void LoadConfigSettings ( )
{
_defaultWidth = Size . Width ;
_defaultHeight = Size . Height ;
2014-02-01 15:44:51 +00:00
if ( Global . Config . TAStudioSettings . UseWindowPosition )
2013-12-01 04:00:02 +00:00
{
2014-02-01 15:44:51 +00:00
Location = Global . Config . TAStudioSettings . WindowPosition ;
2013-12-01 04:00:02 +00:00
}
2014-02-01 15:44:51 +00:00
if ( Global . Config . TAStudioSettings . UseWindowSize )
2013-12-01 04:00:02 +00:00
{
2014-02-01 15:44:51 +00:00
Size = Global . Config . TAStudioSettings . WindowSize ;
2013-12-01 04:00:02 +00:00
}
}
private void SaveConfigSettings ( )
{
2014-02-01 15:44:51 +00:00
Global . Config . TAStudioSettings . Wndx = Location . X ;
Global . Config . TAStudioSettings . Wndy = Location . Y ;
Global . Config . TAStudioSettings . Width = Right - Left ;
Global . Config . TAStudioSettings . Height = Bottom - Top ;
2013-12-01 04:00:02 +00:00
}
2014-07-23 23:04:43 +00:00
public void GoToMarker ( TasMovieMarker marker )
{
GoToFrame ( marker . Frame ) ;
}
2013-12-15 04:45:46 +00:00
private void GoToFrame ( int frame )
{
2014-02-01 15:44:51 +00:00
// If past greenzone, emulate and capture states
// If past greenzone AND movie, record input and capture states
// If in greenzone, loadstate
// If near a greenzone item, load and emulate
// Do capturing and recording as needed
2014-07-17 18:21:12 +00:00
2014-07-17 21:43:41 +00:00
if ( frame < _tas . InputLogLength )
2013-12-15 04:45:46 +00:00
{
2014-07-17 21:43:41 +00:00
if ( frame < Global . Emulator . Frame ) // We are rewinding
2014-07-17 18:21:12 +00:00
{
2014-07-17 21:43:41 +00:00
var goToFrame = frame = = 0 ? 0 : frame - 1 ;
if ( _tas [ goToFrame ] . HasState ) // Go back 1 frame and emulate
{
_tas . SwitchToPlay ( ) ;
Global . Emulator . LoadStateBinary ( new BinaryReader ( new MemoryStream ( _tas [ goToFrame ] . State . ToArray ( ) ) ) ) ;
if ( goToFrame > 0 ) // We can't emulate up to frame 0!
{
Global . Emulator . FrameAdvance ( true ) ;
}
GlobalWin . DisplayManager . NeedsToPaint = true ;
TasView . ensureVisible ( frame ) ;
RefreshDialog ( ) ;
}
else
{
_tas . SwitchToPlay ( ) ;
Global . Emulator . LoadStateBinary ( new BinaryReader ( new MemoryStream ( _tas [ _tas . LastEmulatedFrame ] . State . ToArray ( ) ) ) ) ;
GlobalWin . MainForm . UnpauseEmulator ( ) ;
2014-07-26 12:47:09 +00:00
GlobalWin . MainForm . PauseOnFrame = frame ;
2014-07-17 21:43:41 +00:00
}
}
else // We are going foward
{
var goToFrame = frame - 1 ;
if ( _tas [ goToFrame ] . HasState ) // Can we go directly there?
{
_tas . SwitchToPlay ( ) ;
Global . Emulator . LoadStateBinary ( new BinaryReader ( new MemoryStream ( _tas [ goToFrame ] . State . ToArray ( ) ) ) ) ;
Global . Emulator . FrameAdvance ( true ) ;
GlobalWin . DisplayManager . NeedsToPaint = true ;
TasView . ensureVisible ( frame ) ;
RefreshDialog ( ) ;
}
else // TODO: this assume that there are no "gaps", instead of last emulated frame, we should do last frame from X
{
_tas . SwitchToPlay ( ) ;
Global . Emulator . LoadStateBinary ( new BinaryReader ( new MemoryStream ( _tas [ _tas . LastEmulatedFrame ] . State . ToArray ( ) ) ) ) ;
GlobalWin . MainForm . UnpauseEmulator ( ) ;
2014-07-26 12:47:09 +00:00
GlobalWin . MainForm . PauseOnFrame = frame ;
2014-07-17 21:43:41 +00:00
}
2014-07-17 18:21:12 +00:00
}
2013-12-15 04:45:46 +00:00
}
2014-07-17 21:43:41 +00:00
else // Emulate to a future frame
2013-12-15 04:45:46 +00:00
{
2014-07-17 23:38:01 +00:00
// TODO: get the last greenzone frame and go there
_tas . SwitchToPlay ( ) ; // TODO: stop copy/pasting this logic
Global . Emulator . LoadStateBinary ( new BinaryReader ( new MemoryStream ( _tas [ _tas . LastEmulatedFrame ] . State . ToArray ( ) ) ) ) ;
GlobalWin . MainForm . UnpauseEmulator ( ) ;
2014-07-26 12:47:09 +00:00
GlobalWin . MainForm . PauseOnFrame = frame ;
2013-12-15 04:45:46 +00:00
}
2014-07-27 19:07:13 +00:00
RefreshDialog ( ) ;
2013-12-15 04:45:46 +00:00
}
2014-07-17 19:00:28 +00:00
#region Playback Controls
public void GoToPreviousMarker ( )
{
2014-07-17 23:20:10 +00:00
if ( Global . Emulator . Frame > 0 )
{
var prevMarker = _tas . Markers . Previous ( Global . Emulator . Frame ) ;
var prev = prevMarker ! = null ? prevMarker . Frame : 0 ;
GoToFrame ( prev ) ;
}
2014-07-17 19:00:28 +00:00
}
public void GoToPreviousFrame ( )
{
if ( Global . Emulator . Frame > 0 )
{
GoToFrame ( Global . Emulator . Frame - 1 ) ;
}
}
public void TogglePause ( )
{
2014-07-17 20:35:12 +00:00
GlobalWin . MainForm . TogglePause ( ) ;
2014-07-17 19:00:28 +00:00
}
public void GoToNextFrame ( )
{
GoToFrame ( Global . Emulator . Frame + 1 ) ;
}
public void GoToNextMarker ( )
{
var nextMarker = _tas . Markers . Next ( Global . Emulator . Frame ) ;
var next = nextMarker ! = null ? nextMarker . Frame : _tas . InputLogLength - 1 ;
GoToFrame ( next ) ;
}
#endregion
2013-12-19 03:45:11 +00:00
private void SetSplicer ( )
{
// TODO: columns selected
// TODO: clipboard
2014-02-01 15:44:51 +00:00
var list = TasView . SelectedIndices ;
2014-02-02 17:49:40 +00:00
string message ;
2013-12-19 03:45:11 +00:00
if ( list . Count > 0 )
{
2014-02-01 15:44:51 +00:00
message = list . Count + " rows, 0 col, clipboard: " ;
2013-12-19 03:45:11 +00:00
}
else
{
2014-02-01 15:44:51 +00:00
message = list . Count + " selected: none, clipboard: " ;
2013-12-19 03:45:11 +00:00
}
2014-02-01 15:44:51 +00:00
message + = _tasClipboard . Any ( ) ? _tasClipboard . Count . ToString ( ) : "empty" ;
2013-12-19 03:45:11 +00:00
SplicerStatusLabel . Text = message ;
}
2014-02-01 15:44:51 +00:00
private void RefreshFloatingWindowControl ( )
{
Owner = Global . Config . TAStudioSettings . FloatingWindow ? null : GlobalWin . MainForm ;
}
2014-07-16 02:17:19 +00:00
public void CallAddMarkerPopUp ( int? frame = null )
2014-07-15 23:43:17 +00:00
{
2014-07-16 01:37:50 +00:00
var markerFrame = frame ? ? TasView . LastSelectedIndex ? ? Global . Emulator . Frame ;
2014-07-15 23:43:17 +00:00
InputPrompt i = new InputPrompt
{
2014-07-16 01:37:50 +00:00
Text = "Marker for frame " + markerFrame ,
2014-07-28 02:40:30 +00:00
TextInputType = InputPrompt . InputType . Text ,
Message = "Enter a message"
2014-07-15 23:43:17 +00:00
} ;
var result = i . ShowHawkDialog ( ) ;
if ( result = = DialogResult . OK )
{
2014-07-28 02:40:30 +00:00
_tas . Markers . Add ( markerFrame , i . PromptText ) ;
2014-07-15 23:43:17 +00:00
MarkerControl . Refresh ( ) ;
}
MarkerControl . Refresh ( ) ;
}
2014-07-11 02:31:43 +00:00
private void UpdateChangesIndicator ( )
{
// TODO
}
2014-07-25 00:57:06 +00:00
// TODO: move me
// Sets either the pending frame or the tas input log
private void ToggleBoolState ( int frame , string buttonName )
{
if ( frame < _tas . InputLogLength )
{
_tas . ToggleBoolState ( frame , buttonName ) ;
}
else if ( frame = = Global . Emulator . Frame & & frame = = _tas . InputLogLength )
{
Global . ClickyVirtualPadController . Toggle ( 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 < _tas . InputLogLength )
{
_tas . SetBoolState ( frame , buttonName , value ) ;
}
else if ( frame = = Global . Emulator . Frame & & frame = = _tas . InputLogLength )
{
Global . ClickyVirtualPadController . SetBool ( buttonName , value ) ;
}
}
2013-12-01 04:00:02 +00:00
#region Events
#region File Menu
2013-12-10 01:45:45 +00:00
private void FileSubMenu_DropDownOpened ( object sender , EventArgs e )
{
2014-07-10 02:45:56 +00:00
ToBk2MenuItem . Enabled =
2014-07-07 16:14:33 +00:00
SaveTASMenuItem . Enabled =
! string . IsNullOrWhiteSpace ( _tas . Filename ) ;
2013-12-10 01:45:45 +00:00
}
2013-12-10 02:13:50 +00:00
private void RecentSubMenu_DropDownOpened ( object sender , EventArgs e )
{
RecentSubMenu . DropDownItems . Clear ( ) ;
RecentSubMenu . DropDownItems . AddRange (
2014-07-28 01:51:11 +00:00
Global . Config . RecentTas . RecentMenu ( LoadProject ) ) ;
2013-12-10 02:13:50 +00:00
}
2014-02-02 17:49:40 +00:00
private void NewTasMenuItem_Click ( object sender , EventArgs e )
2013-12-10 16:37:41 +00:00
{
2014-07-08 13:33:01 +00:00
GlobalWin . OSD . AddMessage ( "new TAStudio session started" ) ;
2014-07-10 19:51:36 +00:00
StartNewTasMovie ( ) ;
2013-12-10 16:37:41 +00:00
}
2014-02-02 17:49:40 +00:00
private void OpenTasMenuItem_Click ( object sender , EventArgs e )
2013-12-10 02:13:50 +00:00
{
2013-12-14 19:51:07 +00:00
if ( AskSave ( ) )
2013-12-10 02:13:50 +00:00
{
2013-12-14 19:51:07 +00:00
var file = ToolHelpers . GetTasProjFileFromUser ( _tas . Filename ) ;
if ( file ! = null )
{
_tas . Filename = file . FullName ;
_tas . Load ( ) ;
Global . Config . RecentTas . Add ( _tas . Filename ) ;
2014-07-09 22:44:20 +00:00
RefreshDialog ( ) ;
2014-02-02 17:49:40 +00:00
MessageStatusLabel . Text = Path . GetFileName ( _tas . Filename ) + " loaded." ;
2013-12-14 19:51:07 +00:00
}
2013-12-10 02:13:50 +00:00
}
}
2014-02-01 15:44:51 +00:00
private void SaveTasMenuItem_Click ( object sender , EventArgs e )
2013-12-10 01:45:45 +00:00
{
2014-02-01 15:44:51 +00:00
if ( string . IsNullOrEmpty ( _tas . Filename ) )
2013-12-14 14:40:33 +00:00
{
2014-02-01 15:44:51 +00:00
SaveAsTasMenuItem_Click ( sender , e ) ;
2013-12-14 14:40:33 +00:00
}
else
{
_tas . Save ( ) ;
2014-02-02 17:49:40 +00:00
MessageStatusLabel . Text = Path . GetFileName ( _tas . Filename ) + " saved." ;
2014-07-13 15:26:50 +00:00
Global . Config . RecentTas . Add ( _tas . Filename ) ;
2013-12-14 14:40:33 +00:00
}
2013-12-10 01:45:45 +00:00
}
2014-02-01 15:44:51 +00:00
private void SaveAsTasMenuItem_Click ( object sender , EventArgs e )
2013-12-10 01:45:45 +00:00
{
var file = ToolHelpers . GetTasProjSaveFileFromUser ( _tas . Filename ) ;
2013-12-10 16:37:41 +00:00
if ( file ! = null )
2013-12-10 01:45:45 +00:00
{
_tas . Filename = file . FullName ;
_tas . Save ( ) ;
2013-12-10 02:13:50 +00:00
Global . Config . RecentTas . Add ( _tas . Filename ) ;
2014-02-02 17:49:40 +00:00
MessageStatusLabel . Text = Path . GetFileName ( _tas . Filename ) + " saved." ;
2013-12-10 01:45:45 +00:00
}
}
2014-07-07 16:14:33 +00:00
private void ToBk2MenuItem_Click ( object sender , EventArgs e )
{
var bk2 = _tas . ToBk2 ( ) ;
bk2 . Save ( ) ;
MessageStatusLabel . Text = Path . GetFileName ( bk2 . Filename ) + " created." ;
2014-07-10 02:45:56 +00:00
2014-07-07 16:14:33 +00:00
}
2013-12-01 04:00:02 +00:00
private void ExitMenuItem_Click ( object sender , EventArgs e )
{
Close ( ) ;
}
#endregion
2014-07-11 18:36:23 +00:00
#region Edit
2013-12-08 19:30:57 +00:00
2014-07-17 18:38:30 +00:00
private void EditSubMenu_DropDownOpened ( object sender , EventArgs e )
{
2014-07-16 19:23:05 +00:00
DeselectMenuItem . Enabled =
2014-07-17 18:38:30 +00:00
SelectBetweenMarkersMenuItem . Enabled =
2014-07-16 19:23:05 +00:00
CopyMenuItem . Enabled =
CutMenuItem . Enabled =
ClearMenuItem . Enabled =
DeleteFramesMenuItem . Enabled =
CloneMenuItem . Enabled =
TruncateMenuItem . Enabled =
SelectedIndices . Any ( ) ;
ReselectClipboardMenuItem . Enabled =
PasteMenuItem . Enabled =
PasteInsertMenuItem . Enabled =
_tasClipboard . Any ( ) ;
2014-07-17 18:38:30 +00:00
}
2014-07-16 19:23:05 +00:00
2014-07-11 18:36:23 +00:00
private void DeselectMenuItem_Click ( object sender , EventArgs e )
2013-12-08 19:30:57 +00:00
{
2014-07-11 18:36:23 +00:00
TasView . DeselectAll ( ) ;
2013-12-08 19:30:57 +00:00
}
2014-07-11 18:36:23 +00:00
private void SelectAllMenuItem_Click ( object sender , EventArgs e )
2013-12-08 19:30:57 +00:00
{
2014-07-11 18:36:23 +00:00
TasView . SelectAll ( ) ;
2013-12-08 19:30:57 +00:00
}
2014-07-17 18:38:30 +00:00
private void SelectBetweenMarkersMenuItem_Click ( object sender , EventArgs e )
{
if ( SelectedIndices . Any ( ) )
{
2014-07-17 19:00:28 +00:00
var prevMarker = _tas . Markers . PreviousOrCurrent ( LastSelectedIndex ) ;
2014-07-17 18:38:30 +00:00
var nextMarker = _tas . Markers . Next ( LastSelectedIndex ) ;
int prev = prevMarker ! = null ? prevMarker . Frame : 0 ;
int next = nextMarker ! = null ? nextMarker . Frame : _tas . InputLogLength ;
for ( int i = prev ; i < next ; i + + )
{
TasView . SelectItem ( i , true ) ;
}
}
}
2014-07-11 18:52:15 +00:00
private void ReselectClipboardMenuItem_Click ( object sender , EventArgs e )
{
TasView . DeselectAll ( ) ;
foreach ( var item in _tasClipboard )
{
TasView . SelectItem ( item . Frame , true ) ;
}
}
2013-12-19 03:45:11 +00:00
private void CopyMenuItem_Click ( object sender , EventArgs e )
{
2014-07-13 12:44:31 +00:00
if ( SelectedIndices . Any ( ) )
2013-12-19 03:45:11 +00:00
{
2014-07-13 12:44:31 +00:00
_tasClipboard . Clear ( ) ;
var list = TasView . SelectedIndices ;
var sb = new StringBuilder ( ) ;
for ( var i = 0 ; i < list . Count ; i + + )
{
var input = _tas . GetInputState ( list [ i ] ) ;
_tasClipboard . Add ( new TasClipboardEntry ( list [ i ] , input ) ) ;
var lg = _tas . LogGeneratorInstance ( ) ;
lg . SetSource ( input ) ;
sb . AppendLine ( lg . GenerateLogEntry ( ) ) ;
}
2013-12-19 03:45:11 +00:00
2014-07-13 12:44:31 +00:00
Clipboard . SetDataObject ( sb . ToString ( ) ) ;
2014-07-11 18:17:48 +00:00
2014-07-13 12:44:31 +00:00
SetSplicer ( ) ;
}
2013-12-19 03:45:11 +00:00
}
2014-07-11 23:54:18 +00:00
private void PasteMenuItem_Click ( object sender , EventArgs e )
{
// TODO: if highlighting 2 rows and pasting 3, only paste 2 of them
// FCEUX Taseditor does't do this, but I think it is the expected behavior in editor programs
if ( _tasClipboard . Any ( ) )
{
2014-07-17 23:11:28 +00:00
var needsToRollback = ! ( FirstSelectedIndex > Global . Emulator . Frame ) ;
2014-07-11 23:54:18 +00:00
_tas . CopyOverInput ( FirstSelectedIndex , _tasClipboard . Select ( x = > x . ControllerState ) ) ;
2014-07-17 23:11:28 +00:00
if ( needsToRollback )
{
GoToFrame ( FirstSelectedIndex ) ;
}
else
{
RefreshDialog ( ) ;
}
2014-07-11 23:54:18 +00:00
}
}
private void PasteInsertMenuItem_Click ( object sender , EventArgs e )
{
if ( _tasClipboard . Any ( ) )
{
2014-07-17 23:11:28 +00:00
var needsToRollback = ! ( FirstSelectedIndex > Global . Emulator . Frame ) ;
2014-07-11 23:54:18 +00:00
_tas . InsertInput ( FirstSelectedIndex , _tasClipboard . Select ( x = > x . ControllerState ) ) ;
2014-07-17 23:11:28 +00:00
if ( needsToRollback )
{
GoToFrame ( FirstSelectedIndex ) ;
}
else
{
RefreshDialog ( ) ;
}
2014-07-11 23:54:18 +00:00
}
}
2014-07-11 19:11:30 +00:00
private void CutMenuItem_Click ( object sender , EventArgs e )
{
2014-07-13 12:44:31 +00:00
if ( SelectedIndices . Any ( ) )
2014-07-11 19:11:30 +00:00
{
2014-07-17 23:11:28 +00:00
var needsToRollback = ! ( FirstSelectedIndex > Global . Emulator . Frame ) ;
var rollBackFrame = FirstSelectedIndex ;
2014-07-13 12:44:31 +00:00
_tasClipboard . Clear ( ) ;
var list = SelectedIndices . ToArray ( ) ;
var sb = new StringBuilder ( ) ;
for ( var i = 0 ; i < list . Length ; i + + )
{
var input = _tas . GetInputState ( i ) ;
_tasClipboard . Add ( new TasClipboardEntry ( list [ i ] , input ) ) ;
var lg = _tas . LogGeneratorInstance ( ) ;
lg . SetSource ( input ) ;
sb . AppendLine ( lg . GenerateLogEntry ( ) ) ;
}
2014-07-11 19:11:30 +00:00
2014-07-13 12:44:31 +00:00
Clipboard . SetDataObject ( sb . ToString ( ) ) ;
_tas . RemoveFrames ( list ) ;
SetSplicer ( ) ;
TasView . DeselectAll ( ) ;
2014-07-17 23:11:28 +00:00
if ( needsToRollback )
{
GoToFrame ( rollBackFrame ) ;
}
else
{
RefreshDialog ( ) ;
}
2014-07-13 12:44:31 +00:00
}
2014-07-11 19:11:30 +00:00
}
2014-07-11 19:58:24 +00:00
private void ClearMenuItem_Click ( object sender , EventArgs e )
{
2014-07-17 23:11:28 +00:00
if ( SelectedIndices . Any ( ) )
2014-07-11 19:58:24 +00:00
{
2014-07-17 23:11:28 +00:00
var needsToRollback = ! ( FirstSelectedIndex > Global . Emulator . Frame ) ;
var rollBackFrame = FirstSelectedIndex ;
2014-07-11 19:58:24 +00:00
2014-07-17 23:11:28 +00:00
foreach ( var frame in SelectedIndices )
{
_tas . ClearFrame ( frame ) ;
}
if ( needsToRollback )
{
GoToFrame ( rollBackFrame ) ;
}
else
{
RefreshDialog ( ) ;
}
}
2014-07-11 19:58:24 +00:00
}
2014-07-11 20:29:39 +00:00
private void DeleteFramesMenuItem_Click ( object sender , EventArgs e )
{
2014-07-13 12:44:31 +00:00
if ( SelectedIndices . Any ( ) )
{
2014-07-17 23:11:28 +00:00
var needsToRollback = ! ( FirstSelectedIndex > Global . Emulator . Frame ) ;
var rollBackFrame = FirstSelectedIndex ;
2014-07-13 12:44:31 +00:00
_tasClipboard . Clear ( ) ;
_tas . RemoveFrames ( SelectedIndices . ToArray ( ) ) ;
SetSplicer ( ) ;
TasView . DeselectAll ( ) ;
2014-07-17 23:11:28 +00:00
if ( needsToRollback )
{
GoToFrame ( rollBackFrame ) ;
}
else
{
RefreshDialog ( ) ;
}
2014-07-13 12:44:31 +00:00
}
2014-07-11 20:29:39 +00:00
}
2014-07-11 21:05:16 +00:00
private void CloneMenuItem_Click ( object sender , EventArgs e )
{
2014-07-13 12:44:31 +00:00
if ( SelectedIndices . Any ( ) )
2014-07-11 21:05:16 +00:00
{
2014-07-13 12:44:31 +00:00
var framesToInsert = SelectedIndices . ToList ( ) ;
var insertionFrame = LastSelectedIndex + 1 ;
2014-07-17 23:11:28 +00:00
var needsToRollback = ! ( insertionFrame > Global . Emulator . Frame ) ;
2014-07-13 12:44:31 +00:00
var inputLog = new List < string > ( ) ;
foreach ( var frame in framesToInsert )
{
2014-07-13 22:17:31 +00:00
inputLog . Add ( _tas . GetInputLogEntry ( frame ) ) ;
2014-07-13 12:44:31 +00:00
}
2014-07-11 21:05:16 +00:00
2014-07-13 12:44:31 +00:00
_tas . InsertInput ( insertionFrame , inputLog ) ;
2014-07-11 21:05:16 +00:00
2014-07-17 23:11:28 +00:00
if ( needsToRollback )
{
GoToFrame ( insertionFrame ) ;
}
else
{
RefreshDialog ( ) ;
}
2014-07-13 12:44:31 +00:00
}
2014-07-11 21:05:16 +00:00
}
private void InsertFrameMenuItem_Click ( object sender , EventArgs e )
{
2014-07-16 19:23:05 +00:00
var insertionFrame = SelectedIndices . Any ( ) ? LastSelectedIndex + 1 : 0 ;
2014-07-17 23:11:28 +00:00
var needsToRollback = ! ( insertionFrame > Global . Emulator . Frame ) ;
2014-07-16 19:23:05 +00:00
_tas . InsertEmptyFrame ( insertionFrame ) ;
2014-07-17 23:11:28 +00:00
if ( needsToRollback )
{
GoToFrame ( insertionFrame ) ;
}
else
{
RefreshDialog ( ) ;
}
2014-07-13 12:44:31 +00:00
}
private void InsertNumFramesMenuItem_Click ( object sender , EventArgs e )
{
2014-07-16 19:23:05 +00:00
var insertionFrame = SelectedIndices . Any ( ) ? LastSelectedIndex + 1 : 0 ;
2014-07-17 23:11:28 +00:00
var needsToRollback = ! ( insertionFrame > Global . Emulator . Frame ) ;
2014-07-16 19:23:05 +00:00
var framesPrompt = new FramesPrompt ( ) ;
var result = framesPrompt . ShowDialog ( ) ;
if ( result = = DialogResult . OK )
2014-07-13 12:44:31 +00:00
{
2014-07-16 19:23:05 +00:00
_tas . InsertEmptyFrame ( insertionFrame , framesPrompt . Frames ) ;
2014-07-13 12:44:31 +00:00
}
2014-07-17 23:11:28 +00:00
if ( needsToRollback )
{
GoToFrame ( insertionFrame ) ;
}
else
{
RefreshDialog ( ) ;
}
2014-07-12 01:23:38 +00:00
}
2014-07-11 21:05:16 +00:00
2014-07-12 01:23:38 +00:00
private void TruncateMenuItem_Click ( object sender , EventArgs e )
{
2014-07-13 12:44:31 +00:00
if ( SelectedIndices . Any ( ) )
{
2014-07-17 23:11:28 +00:00
var rollbackFrame = LastSelectedIndex + 1 ;
var needsToRollback = ! ( rollbackFrame > Global . Emulator . Frame ) ;
2014-07-13 12:44:31 +00:00
_tas . Truncate ( LastSelectedIndex + 1 ) ;
2014-07-17 23:11:28 +00:00
if ( needsToRollback )
{
GoToFrame ( rollbackFrame ) ;
}
else
{
RefreshDialog ( ) ;
}
2014-07-13 12:44:31 +00:00
}
2014-07-11 21:05:16 +00:00
}
2013-12-08 19:30:57 +00:00
#endregion
2014-07-11 18:36:23 +00:00
#region Config
private void ConfigSubMenu_DropDownOpened ( object sender , EventArgs e )
{
DrawInputByDraggingMenuItem . Checked = Global . Config . TAStudioDrawInput ;
}
private void DrawInputByDraggingMenuItem_Click ( object sender , EventArgs e )
{
TasView . InputPaintingMode = Global . Config . TAStudioDrawInput ^ = true ;
}
#endregion
2014-07-09 22:09:20 +00:00
#region Metadata
2014-07-11 02:31:43 +00:00
private void HeaderMenuItem_Click ( object sender , EventArgs e )
{
new MovieHeaderEditor ( _tas ) . Show ( ) ;
UpdateChangesIndicator ( ) ;
}
2014-07-11 15:43:47 +00:00
private void GreenzoneSettingsMenuItem_Click ( object sender , EventArgs e )
{
new GreenzoneSettings ( _tas . GreenzoneSettings ) . Show ( ) ;
UpdateChangesIndicator ( ) ;
}
2014-07-09 22:09:20 +00:00
private void CommentsMenuItem_Click ( object sender , EventArgs e )
{
var form = new EditCommentsForm ( ) ;
form . GetMovie ( _tas ) ;
form . ShowDialog ( ) ;
}
private void SubtitlesMenuItem_Click ( object sender , EventArgs e )
{
var form = new EditSubtitlesForm { ReadOnly = true } ;
form . GetMovie ( Global . MovieSession . Movie ) ;
form . ShowDialog ( ) ;
}
#endregion
2013-12-01 04:00:02 +00:00
#region Settings Menu
2013-12-08 19:30:57 +00:00
2013-12-01 04:00:02 +00:00
private void SettingsSubMenu_DropDownOpened ( object sender , EventArgs e )
{
2014-02-01 15:44:51 +00:00
SaveWindowPositionMenuItem . Checked = Global . Config . TAStudioSettings . SaveWindowPosition ;
2013-12-01 04:00:02 +00:00
AutoloadMenuItem . Checked = Global . Config . AutoloadTAStudio ;
2013-12-14 19:51:07 +00:00
AutoloadProjectMenuItem . Checked = Global . Config . AutoloadTAStudioProject ;
2014-02-01 15:44:51 +00:00
AlwaysOnTopMenuItem . Checked = Global . Config . TAStudioSettings . TopMost ;
FloatingWindowMenuItem . Checked = Global . Config . TAStudioSettings . FloatingWindow ;
2013-12-01 04:00:02 +00:00
}
private void AutoloadMenuItem_Click ( object sender , EventArgs e )
{
Global . Config . AutoloadTAStudio ^ = true ;
}
2013-12-07 21:37:52 +00:00
2013-12-14 19:51:07 +00:00
private void AutoloadProjectMenuItem_Click ( object sender , EventArgs e )
{
Global . Config . AutoloadTAStudioProject ^ = true ;
}
2013-12-01 04:00:02 +00:00
private void SaveWindowPositionMenuItem_Click ( object sender , EventArgs e )
{
2014-02-01 15:44:51 +00:00
Global . Config . TAStudioSettings . SaveWindowPosition ^ = true ;
2013-12-01 04:00:02 +00:00
}
private void AlwaysOnTopMenuItem_Click ( object sender , EventArgs e )
{
2014-02-01 15:44:51 +00:00
Global . Config . TAStudioSettings . TopMost ^ = true ;
}
private void FloatingWindowMenuItem_Click ( object sender , EventArgs e )
{
Global . Config . TAStudioSettings . FloatingWindow ^ = true ;
RefreshFloatingWindowControl ( ) ;
2013-12-01 04:00:02 +00:00
}
2013-12-14 14:48:05 +00:00
private void RestoreDefaultSettingsMenuItem_Click ( object sender , EventArgs e )
{
Size = new Size ( _defaultWidth , _defaultHeight ) ;
2014-02-01 15:44:51 +00:00
Global . Config . TAStudioSettings . SaveWindowPosition = true ;
Global . Config . TAStudioSettings . TopMost = false ;
Global . Config . TAStudioSettings . FloatingWindow = false ;
RefreshFloatingWindowControl ( ) ;
2013-12-14 14:48:05 +00:00
}
2013-12-01 04:00:02 +00:00
#endregion
2014-02-01 15:44:51 +00:00
#region Dialog Events
protected override void OnShown ( EventArgs e )
{
RefreshFloatingWindowControl ( ) ;
base . OnShown ( e ) ;
}
#endregion
2013-12-19 03:45:11 +00:00
#endregion
2013-12-01 04:00:02 +00:00
}
}