2013-12-01 04:00:02 +00:00
using System ;
using System.Collections.Generic ;
using System.IO ;
2013-12-05 19:18:20 +00:00
using System.Linq ;
2013-12-01 04:00:02 +00:00
using System.Windows.Forms ;
2014-08-23 18:02:02 +00:00
using System.ComponentModel ;
2013-12-01 20:55:52 +00:00
2014-11-30 16:42:58 +00:00
using BizHawk.Emulation.Common ;
2014-12-05 00:52:16 +00:00
using BizHawk.Emulation.Common.IEmulatorExtensions ;
2014-11-30 16:42:58 +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
{
2015-01-01 18:10:07 +00:00
public partial class TAStudio : Form , IToolFormAutoConfig , 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 > ( ) ;
2015-02-24 06:47:32 +00:00
private BackgroundWorker _saveBackgroundWorker ;
2015-01-03 02:29:55 +00:00
2014-07-14 00:35:33 +00:00
private MovieEndAction _originalEndAction ; // The movie end behavior selected by the user (that is overridden by TAStudio)
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-10-17 20:10:21 +00:00
private int? _autoRestoreFrame ; // The frame auto-restore will restore to, if set
2015-01-01 18:24:35 +00:00
[ConfigPersist]
public TAStudioSettings Settings { get ; set ; }
public class TAStudioSettings
{
public TAStudioSettings ( )
{
RecentTas = new RecentFiles ( 8 ) ;
DrawInput = true ;
AutoPause = true ;
FollowCursor = true ;
}
public RecentFiles RecentTas { get ; set ; }
public bool DrawInput { get ; set ; }
public bool AutoPause { get ; set ; }
public bool AutoRestoreLastPosition { get ; set ; }
public bool FollowCursor { get ; set ; }
public bool EmptyMarkers { get ; set ; }
}
2014-10-20 19:04:59 +00:00
public TasMovie CurrentTasMovie
{
get { return Global . MovieSession . Movie as TasMovie ; }
}
2013-12-01 04:00:02 +00:00
public TAStudio ( )
{
InitializeComponent ( ) ;
2015-01-01 20:48:14 +00:00
Settings = new TAStudioSettings ( ) ;
2015-02-24 06:47:32 +00:00
// TODO: show this at all times or hide it when saving is done?
this . SavingProgressBar . Visible = false ;
_saveBackgroundWorker = new BackgroundWorker ( ) ;
_saveBackgroundWorker . WorkerReportsProgress = true ;
_saveBackgroundWorker . DoWork + = ( s , e ) = >
{
this . Invoke ( ( ) = > this . MessageStatusLabel . Text = "Saving " + Path . GetFileName ( CurrentTasMovie . Filename ) + "..." ) ;
this . Invoke ( ( ) = > this . SavingProgressBar . Visible = true ) ;
CurrentTasMovie . Save ( ) ;
} ;
_saveBackgroundWorker . ProgressChanged + = ( s , e ) = >
{
SavingProgressBar . Value = e . ProgressPercentage ;
} ;
_saveBackgroundWorker . RunWorkerCompleted + = ( s , e ) = >
{
this . Invoke ( ( ) = > this . MessageStatusLabel . Text = Path . GetFileName ( CurrentTasMovie . Filename ) + " saved." ) ;
this . Invoke ( ( ) = > this . SavingProgressBar . Visible = false ) ;
// SUPER HACKY, and i'm not even sure it's necessary
Timer t = new Timer ( ) ;
t . Tick + = ( a , b ) = >
{
this . Invoke ( ( ) = > this . MessageStatusLabel . Text = "TAStudio engaged." ) ;
t . Stop ( ) ;
} ;
t . Interval = 5000 ;
t . Start ( ) ;
} ;
2015-01-03 02:29:55 +00:00
2014-08-19 23:56:33 +00:00
WantsToControlStopMovie = true ;
2014-07-17 19:00:28 +00:00
TasPlaybackBox . Tastudio = this ;
2014-07-16 02:20:14 +00:00
MarkerControl . Tastudio = this ;
2014-12-21 18:25:04 +00:00
MarkerControl . Emulator = this . Emulator ;
2014-02-01 15:44:51 +00:00
TasView . QueryItemText + = TasView_QueryItemText ;
TasView . QueryItemBkColor + = TasView_QueryItemBkColor ;
2014-09-03 03:16:16 +00:00
TasView . QueryItemIcon + = TasView_QueryItemIcon ;
2015-02-24 19:00:12 +00:00
TasView . QueryFrameLag + = TasView_QueryFrameLag ;
2015-01-01 18:24:35 +00:00
TasView . InputPaintingMode = Settings . DrawInput ;
2014-02-01 15:44:51 +00:00
TasView . PointedCellChanged + = TasView_PointedCellChanged ;
2014-08-29 18:02:23 +00:00
TasView . MultiSelect = true ;
2014-10-15 22:19:34 +00:00
TasView . MaxCharactersInHorizontal = 1 ;
2014-10-26 16:36:50 +00:00
WantsToControlRestartMovie = true ;
2015-02-24 06:47:32 +00:00
2013-12-01 04:00:02 +00:00
}
2014-10-17 17:40:11 +00:00
private void TastudioToStopMovie ( )
{
Global . MovieSession . StopMovie ( false ) ;
GlobalWin . MainForm . SetMainformMovieInfo ( ) ;
}
2015-01-01 18:24:35 +00:00
private void ConvertCurrentMovieToTasproj ( )
2014-07-08 15:15:35 +00:00
{
Global . MovieSession . Movie . Save ( ) ;
Global . MovieSession . Movie = Global . MovieSession . Movie . ToTasMovie ( ) ;
Global . MovieSession . Movie . Save ( ) ;
2014-08-29 01:14:26 +00:00
Global . MovieSession . Movie . SwitchToRecord ( ) ;
2015-01-01 18:24:35 +00:00
Settings . RecentTas . Add ( Global . MovieSession . Movie . Filename ) ;
2014-07-08 15:15:35 +00:00
}
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-10-14 18:09:30 +00:00
SetTasMovieCallbacks ( ) ;
2014-09-16 23:26:17 +00:00
SetTextProperty ( ) ;
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-14 00:35:33 +00:00
_originalEndAction = Global . Config . MovieEndAction ;
2014-09-27 12:19:50 +00:00
GlobalWin . MainForm . ClearRewindData ( ) ;
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-08-19 19:24:17 +00:00
GlobalWin . MainForm . TakeBackControl ( ) ;
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 ( )
{
2015-01-03 02:29:55 +00:00
Global . MovieSession . Movie = new TasMovie ( false , _saveBackgroundWorker ) ;
2014-10-14 18:09:30 +00:00
SetTasMovieCallbacks ( ) ;
2014-10-20 19:04:59 +00:00
CurrentTasMovie . PropertyChanged + = new PropertyChangedEventHandler ( this . TasMovie_OnPropertyChanged ) ;
CurrentTasMovie . Filename = DefaultTasProjName ( ) ; // TODO don't do this, take over any mainform actions that can crash without a filename
CurrentTasMovie . PopulateWithDefaultHeaderValues ( ) ;
CurrentTasMovie . ClearChanges ( ) ;
2014-10-18 15:31:51 +00:00
TasView . RowCount = 1 ;
2014-07-08 15:15:35 +00:00
}
2014-10-18 15:50:12 +00:00
/// <summary>
/// Used when starting a new project
/// </summary>
2014-07-08 15:15:35 +00:00
private static string DefaultTasProjName ( )
2014-10-18 15:50:12 +00:00
{
return Path . Combine (
PathManager . MakeAbsolutePath ( Global . Config . PathEntries . MoviesPathFragment , null ) ,
TasMovie . DefaultProjectName + "." + TasMovie . Extension ) ;
}
/// <summary>
/// Used for things like SaveFile dialogs to suggest a name to the user
/// </summary>
/// <returns></returns>
private static string SuggestedTasProjName ( )
2014-07-08 15:15:35 +00:00
{
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-10-14 18:09:30 +00:00
private void SetTasMovieCallbacks ( )
{
2014-10-20 19:04:59 +00:00
CurrentTasMovie . ClientSettingsForSave = ClientSettingsForSave ;
CurrentTasMovie . GetClientSettingsOnLoad = GetClientSettingsOnLoad ;
2014-10-14 18:09:30 +00:00
}
2014-07-10 19:51:36 +00:00
private void StartNewTasMovie ( )
2013-12-10 16:37:41 +00:00
{
2014-08-19 19:24:17 +00:00
if ( AskSaveChanges ( ) )
2013-12-10 16:37:41 +00:00
{
2014-07-10 19:51:36 +00:00
NewTasMovie ( ) ;
2014-08-19 23:56:33 +00:00
WantsToControlStopMovie = false ;
2014-10-18 15:27:53 +00:00
StartNewMovieWrapper ( record : true ) ;
2014-10-20 19:04:59 +00:00
CurrentTasMovie . ClearChanges ( ) ;
2014-08-19 23:56:33 +00:00
WantsToControlStopMovie = true ;
2014-09-16 23:26:17 +00:00
SetTextProperty ( ) ;
2014-07-09 22:44:20 +00:00
RefreshDialog ( ) ;
2013-12-10 16:37:41 +00:00
}
}
2014-10-18 15:50:12 +00:00
private void DummyLoadProject ( string path )
{
LoadProject ( path ) ;
}
2014-10-14 18:09:30 +00:00
private string ClientSettingsForSave ( )
{
return TasView . UserSettingsSerialized ( ) ;
}
private void GetClientSettingsOnLoad ( string settingsJson )
{
TasView . LoadSettingsSerialized ( settingsJson ) ;
TasView . Refresh ( ) ;
}
2014-09-16 23:26:17 +00:00
private void SetTextProperty ( )
2014-09-16 23:25:08 +00:00
{
var text = "TAStudio" ;
2014-10-20 19:04:59 +00:00
if ( CurrentTasMovie ! = null )
2014-09-16 23:25:08 +00:00
{
2014-10-20 19:04:59 +00:00
text + = " - " + CurrentTasMovie . Name + ( CurrentTasMovie . Changes ? "*" : "" ) ;
2014-09-16 23:25:08 +00:00
}
2015-01-06 16:35:22 +00:00
if ( this . InvokeRequired )
{
this . Invoke ( ( ) = > Text = text ) ;
}
else
{
Text = text ;
}
2014-09-16 23:25:08 +00:00
}
2014-09-28 01:05:26 +00:00
public bool LoadProject ( string path )
2014-07-08 15:15:35 +00:00
{
2014-08-19 19:24:17 +00:00
if ( AskSaveChanges ( ) )
2014-07-08 15:15:35 +00:00
{
2015-01-03 02:29:55 +00:00
var movie = new TasMovie ( false , _saveBackgroundWorker )
2014-07-09 22:44:20 +00:00
{
2014-10-14 18:09:30 +00:00
Filename = path ,
ClientSettingsForSave = ClientSettingsForSave ,
GetClientSettingsOnLoad = GetClientSettingsOnLoad
2014-07-09 22:44:20 +00:00
} ;
2014-09-25 12:28:58 +00:00
2014-08-23 18:02:02 +00:00
movie . PropertyChanged + = TasMovie_OnPropertyChanged ;
2014-09-25 12:28:58 +00:00
movie . Load ( ) ;
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
{
2015-01-01 18:24:35 +00:00
Settings . RecentTas . HandleLoadError ( path ) ;
2014-07-08 15:15:35 +00:00
}
2014-07-09 22:44:20 +00:00
2014-08-19 23:56:33 +00:00
WantsToControlStopMovie = false ;
2014-09-18 22:11:37 +00:00
2014-10-17 17:58:48 +00:00
var shouldRecord = movie . InputLogLength = = 0 ;
2014-09-18 22:11:37 +00:00
2014-10-18 19:23:14 +00:00
var result = StartNewMovieWrapper ( movie : movie , record : shouldRecord ) ;
2014-09-28 01:05:26 +00:00
if ( ! result )
{
return false ;
}
2014-10-14 18:09:30 +00:00
SetTasMovieCallbacks ( ) ;
WantsToControlStopMovie = true ;
2015-01-01 18:24:35 +00:00
Settings . RecentTas . Add ( path ) ;
2014-10-20 19:04:59 +00:00
Text = "TAStudio - " + CurrentTasMovie . Name ;
2014-10-12 14:12:37 +00:00
2014-07-09 22:44:20 +00:00
RefreshDialog ( ) ;
2014-09-28 01:05:26 +00:00
return true ;
2014-07-08 15:15:35 +00:00
}
2014-09-28 01:05:26 +00:00
return false ;
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-10-20 19:04:59 +00:00
CurrentTasMovie . FlushInputCache ( ) ;
CurrentTasMovie . UseInputCache = true ;
TasView . RowCount = CurrentTasMovie . InputLogLength + 1 ;
2014-08-23 15:19:48 +00:00
TasView . Refresh ( ) ;
2014-08-23 16:00:56 +00:00
2014-10-20 19:04:59 +00:00
CurrentTasMovie . FlushInputCache ( ) ;
CurrentTasMovie . UseInputCache = false ;
2014-08-29 02:58:52 +00:00
2014-07-15 23:43:17 +00:00
if ( MarkerControl ! = null )
{
2014-08-29 00:04:42 +00:00
MarkerControl . UpdateValues ( ) ;
2014-07-15 23:43:17 +00:00
}
2014-07-08 15:15:35 +00:00
}
2014-10-17 20:10:21 +00:00
private void DoAutoRestore ( )
2014-09-27 14:37:02 +00:00
{
2015-01-01 18:24:35 +00:00
if ( Settings . AutoRestoreLastPosition & & _autoRestoreFrame . HasValue )
2014-09-27 14:37:02 +00:00
{
2014-12-14 01:20:19 +00:00
if ( _autoRestoreFrame > Emulator . Frame ) // Don't unpause if we are already on the desired frame, else runaway seek
2014-09-22 23:24:34 +00:00
{
2014-09-27 14:37:02 +00:00
GlobalWin . MainForm . UnpauseEmulator ( ) ;
2014-10-17 20:10:21 +00:00
GlobalWin . MainForm . PauseOnFrame = _autoRestoreFrame ;
2014-07-16 23:04:56 +00:00
}
2014-07-13 15:26:50 +00:00
}
2014-10-17 20:10:21 +00:00
_autoRestoreFrame = null ;
2014-07-13 15:26:50 +00:00
}
2013-12-05 19:18:20 +00:00
private void SetUpColumns ( )
{
2014-10-12 16:37:45 +00:00
TasView . AllColumns . 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
2015-02-24 22:44:47 +00:00
var columnNames = GenerateColumnNames ( ) ;
foreach ( var kvp in columnNames )
2013-12-05 19:18:20 +00:00
{
2015-02-24 22:44:47 +00:00
// N64 hack for now, for fake analog
if ( Emulator . SystemId = = "N64" )
{
if ( kvp . Key . Contains ( "A Up" ) | | kvp . Key . Contains ( "A Down" ) | |
kvp . Key . Contains ( "A Left" ) | | kvp . Key . Contains ( "A Right" ) )
{
continue ;
}
}
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 )
{
2014-10-12 16:37:45 +00:00
if ( TasView . AllColumns [ columnName ] = = null )
2013-12-07 17:29:47 +00:00
{
2014-08-23 23:40:01 +00:00
var column = new InputRoll . RollColumn
2013-12-07 17:29:47 +00:00
{
Name = columnName ,
Text = columnText ,
Width = columnWidth ,
} ;
2014-10-12 16:37:45 +00:00
TasView . AllColumns . Add ( column ) ;
2013-12-05 19:18:20 +00:00
}
2013-12-01 04:00:02 +00:00
}
2014-08-31 16:51:19 +00:00
private void StartAtNearestFrameAndEmulate ( int frame )
{
2014-10-20 19:04:59 +00:00
CurrentTasMovie . SwitchToPlay ( ) ;
2014-10-26 23:26:43 +00:00
KeyValuePair < int , byte [ ] > closestState = CurrentTasMovie . TasStateManager . GetStateClosestToFrame ( frame ) ;
if ( closestState . Value ! = null )
2014-08-31 16:51:19 +00:00
{
2014-10-26 23:37:42 +00:00
LoadState ( closestState ) ;
2014-08-31 16:51:19 +00:00
}
GlobalWin . MainForm . PauseOnFrame = frame ;
GlobalWin . MainForm . UnpauseEmulator ( ) ;
}
2014-10-26 23:37:42 +00:00
private void LoadState ( KeyValuePair < int , byte [ ] > state )
2014-09-27 15:19:07 +00:00
{
2014-12-14 01:20:19 +00:00
StatableEmulator . LoadStateBinary ( new BinaryReader ( new MemoryStream ( state . Value . ToArray ( ) ) ) ) ;
2014-10-26 23:37:42 +00:00
if ( state . Key = = 0 & & CurrentTasMovie . StartsFromSavestate )
{
2014-12-14 01:20:19 +00:00
Emulator . ResetCounters ( ) ;
2014-10-26 23:37:42 +00:00
}
2014-09-27 15:19:07 +00:00
_hackyDontUpdate = true ;
GlobalWin . Tools . UpdateBefore ( ) ;
GlobalWin . Tools . UpdateAfter ( ) ;
_hackyDontUpdate = false ;
}
2014-10-11 17:43:24 +00:00
private void UpdateOtherTools ( ) // a hack probably, surely there is a better way to do this
{
_hackyDontUpdate = true ;
GlobalWin . Tools . UpdateBefore ( ) ;
GlobalWin . Tools . UpdateAfter ( ) ;
_hackyDontUpdate = false ;
2013-12-15 04:45:46 +00:00
}
2014-07-17 19:00:28 +00:00
public void TogglePause ( )
{
2014-07-17 20:35:12 +00:00
GlobalWin . MainForm . TogglePause ( ) ;
2014-07-17 19:00:28 +00:00
}
2013-12-19 03:45:11 +00:00
private void SetSplicer ( )
{
// TODO: columns selected
// TODO: clipboard
2014-08-30 18:42:14 +00:00
var list = TasView . SelectedRows ;
2014-08-23 18:02:02 +00:00
string message = "Selected: " ;
2013-12-19 03:45:11 +00:00
2014-10-13 18:28:29 +00:00
if ( list . Any ( ) )
2013-12-19 03:45:11 +00:00
{
2014-10-13 18:28:29 +00:00
message + = list . Count ( ) + " rows 0 col, Clipboard: " ;
2013-12-19 03:45:11 +00:00
}
else
{
2014-10-13 18:28:29 +00:00
message + = list . Count ( ) + " none, Clipboard: " ;
2013-12-19 03:45:11 +00:00
}
2015-02-24 06:47:32 +00:00
message + = _tasClipboard . Any ( ) ? _tasClipboard . Count + " rows 0 col" : "empty" ;
2013-12-19 03:45:11 +00:00
SplicerStatusLabel . Text = message ;
}
2014-07-16 02:17:19 +00:00
public void CallAddMarkerPopUp ( int? frame = null )
2014-07-15 23:43:17 +00:00
{
2014-12-14 01:20:19 +00:00
var markerFrame = frame ? ? TasView . LastSelectedIndex ? ? 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 ,
2014-08-22 03:59:12 +00:00
Message = "Enter a message" ,
2014-10-20 19:04:59 +00:00
InitialValue = CurrentTasMovie . Markers . IsMarker ( markerFrame ) ? CurrentTasMovie . Markers . PreviousOrCurrent ( markerFrame ) . Message : ""
2014-07-15 23:43:17 +00:00
} ;
var result = i . ShowHawkDialog ( ) ;
if ( result = = DialogResult . OK )
{
2015-03-01 05:47:32 +00:00
AddMarker ( markerFrame , i . PromptText ) ;
2014-08-29 00:04:42 +00:00
MarkerControl . UpdateValues ( ) ;
2014-07-15 23:43:17 +00:00
}
}
2014-10-20 23:03:39 +00:00
public void CallEditMarkerPopUp ( TasMovieMarker marker )
{
var markerFrame = marker . Frame ;
InputPrompt i = new InputPrompt
{
Text = "Marker for frame " + markerFrame ,
TextInputType = InputPrompt . InputType . Text ,
Message = "Enter a message" ,
InitialValue = CurrentTasMovie . Markers . IsMarker ( markerFrame ) ? CurrentTasMovie . Markers . PreviousOrCurrent ( markerFrame ) . Message : ""
} ;
var result = i . ShowHawkDialog ( ) ;
if ( result = = DialogResult . OK )
{
2015-03-01 05:47:32 +00:00
EditMarker ( marker , i . PromptText ) ;
2014-10-20 23:03:39 +00:00
MarkerControl . UpdateValues ( ) ;
}
}
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 )
{
2014-10-20 19:04:59 +00:00
if ( frame < CurrentTasMovie . InputLogLength )
2014-07-25 00:57:06 +00:00
{
2014-10-20 19:04:59 +00:00
CurrentTasMovie . ToggleBoolState ( frame , buttonName ) ;
2014-07-25 00:57:06 +00:00
}
2014-12-14 01:20:19 +00:00
else if ( frame = = Emulator . Frame & & frame = = CurrentTasMovie . InputLogLength )
2014-07-25 00:57:06 +00:00
{
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 )
{
2014-10-20 19:04:59 +00:00
if ( frame < CurrentTasMovie . InputLogLength )
2014-07-25 00:57:06 +00:00
{
2014-10-20 19:04:59 +00:00
CurrentTasMovie . SetBoolState ( frame , buttonName , value ) ;
2014-07-25 00:57:06 +00:00
}
2014-12-14 01:20:19 +00:00
else if ( frame = = Emulator . Frame & & frame = = CurrentTasMovie . InputLogLength )
2014-07-25 00:57:06 +00:00
{
Global . ClickyVirtualPadController . SetBool ( buttonName , value ) ;
}
}
2015-02-27 19:06:02 +00:00
private float GetFloatValue ( int frame , string buttonName )
{
if ( frame < CurrentTasMovie . InputLogLength )
return CurrentTasMovie . GetFloatValue ( frame , buttonName ) ;
else if ( frame = = Emulator . Frame & & frame = = CurrentTasMovie . InputLogLength )
return Global . StickyXORAdapter . GetFloat ( buttonName ) ;
return 0 ; // ? Should I do it differently so it will error instead?
}
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 ) ;
}
2014-09-25 17:52:21 +00:00
private void SetColumnsFromCurrentStickies ( )
{
2014-10-12 16:37:45 +00:00
foreach ( var column in TasView . VisibleColumns )
2014-09-25 17:52:21 +00:00
{
if ( Global . StickyXORAdapter . IsSticky ( column . Name ) )
{
column . Emphasis = true ;
}
}
}
2014-10-17 17:40:11 +00:00
private void NewDefaultProject ( )
{
NewTasMovie ( ) ;
2014-10-18 15:27:53 +00:00
StartNewMovieWrapper ( record : true ) ;
2014-10-20 19:04:59 +00:00
CurrentTasMovie . TasStateManager . Capture ( ) ;
CurrentTasMovie . SwitchToRecord ( ) ;
CurrentTasMovie . ClearChanges ( ) ;
2014-10-17 17:40:11 +00:00
}
2014-10-18 19:12:36 +00:00
private bool StartNewMovieWrapper ( bool record , IMovie movie = null )
2014-10-18 15:27:53 +00:00
{
_initializing = true ;
2014-10-20 19:04:59 +00:00
var result = GlobalWin . MainForm . StartNewMovie ( movie ! = null ? movie : CurrentTasMovie , record ) ;
2014-10-18 15:27:53 +00:00
_initializing = false ;
return result ;
}
2014-10-21 01:31:41 +00:00
private void DoTriggeredAutoRestoreIfNeeded ( )
{
if ( _triggerAutoRestore )
{
GoToLastEmulatedFrameIfNecessary ( _triggerAutoRestoreFromFrame . Value ) ;
2014-10-23 23:14:32 +00:00
if ( GlobalWin . MainForm . PauseOnFrame . HasValue & &
_autoRestoreFrame . HasValue & &
_autoRestoreFrame < GlobalWin . MainForm . PauseOnFrame ) // If we are already seeking to a later frame don't shorten that journey here
{
_autoRestoreFrame = GlobalWin . MainForm . PauseOnFrame ;
}
2014-10-21 01:31:41 +00:00
DoAutoRestore ( ) ;
_triggerAutoRestore = false ;
_triggerAutoRestoreFromFrame = null ;
2015-02-24 06:47:32 +00:00
2014-10-21 01:31:41 +00:00
}
}
2014-10-21 13:12:12 +00:00
private void LoadFile ( FileInfo file )
{
CurrentTasMovie . Filename = file . FullName ;
2014-12-22 22:31:47 +00:00
try
{
CurrentTasMovie . Load ( ) ;
}
catch
{
MessageBox . Show (
2014-12-23 22:13:57 +00:00
"Tastudio could not open the file. Due to the loading process, the emulator/Tastudio may be in a unspecified state depending on the error." ,
2014-12-22 22:31:47 +00:00
"Tastudio" ,
MessageBoxButtons . OK ) ;
2014-12-23 22:13:57 +00:00
return ;
2014-12-22 22:31:47 +00:00
}
2015-01-01 18:24:35 +00:00
Settings . RecentTas . Add ( CurrentTasMovie . Filename ) ;
2014-10-21 13:12:12 +00:00
if ( CurrentTasMovie . InputLogLength > 0 ) // TODO: this is probably reoccuring logic, break off into a function
{
CurrentTasMovie . SwitchToPlay ( ) ;
}
else
{
CurrentTasMovie . SwitchToRecord ( ) ;
}
RefreshDialog ( ) ;
MessageStatusLabel . Text = Path . GetFileName ( CurrentTasMovie . Filename ) + " loaded." ;
}
2014-10-17 17:40:11 +00:00
#region Dialog Events
2014-08-21 22:53:03 +00:00
private void Tastudio_Load ( object sender , EventArgs e )
2014-10-18 15:27:53 +00:00
{
2015-02-24 06:47:32 +00:00
if ( ! InitializeOnLoad ( ) )
2015-01-03 03:30:34 +00:00
{
Close ( ) ;
2015-01-03 14:03:13 +00:00
this . DialogResult = System . Windows . Forms . DialogResult . Cancel ;
2015-01-03 03:30:34 +00:00
return ;
}
2015-01-03 14:03:13 +00:00
2014-10-18 15:27:53 +00:00
SetColumnsFromCurrentStickies ( ) ;
2014-11-19 23:21:08 +00:00
if ( VersionInfo . DeveloperBuild )
{
RightClickMenu . Items . AddRange ( TasView . GenerateContextMenuItems ( ) . ToArray ( ) ) ;
2014-10-19 15:29:03 +00:00
2014-11-22 15:09:01 +00:00
RightClickMenu . Items
2014-10-19 15:29:03 +00:00
. OfType < ToolStripMenuItem > ( )
. First ( t = > t . Name = = "RotateMenuItem" )
. Click + = ( o , ov ) = >
{
2014-10-20 19:04:59 +00:00
CurrentTasMovie . FlagChanges ( ) ;
2014-10-19 15:29:03 +00:00
} ;
2014-11-22 15:09:01 +00:00
}
2014-10-19 15:29:03 +00:00
2014-10-18 15:27:53 +00:00
RefreshDialog ( ) ;
}
2015-01-03 14:03:13 +00:00
private bool InitializeOnLoad ( )
2014-08-21 22:53:03 +00:00
{
// Start Scenario 1: A regular movie is active
if ( Global . MovieSession . Movie . IsActive & & ! ( Global . MovieSession . Movie is TasMovie ) )
{
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 )
{
ConvertCurrentMovieToTasproj ( ) ;
2014-10-26 16:36:50 +00:00
StartNewMovieWrapper ( false ) ;
2014-08-21 22:53:03 +00:00
}
else
{
2015-01-03 14:03:13 +00:00
return false ;
2014-08-21 22:53:03 +00:00
}
}
// Start Scenario 2: A tasproj is already active
else if ( Global . MovieSession . Movie . IsActive & & Global . MovieSession . Movie is TasMovie )
{
// Nothing to do
}
// Start Scenario 3: No movie, but user wants to autload their last project
2015-01-01 18:24:35 +00:00
else if ( Settings . RecentTas . AutoLoad & & ! string . IsNullOrEmpty ( Settings . RecentTas . MostRecent ) )
2014-08-21 22:53:03 +00:00
{
2015-01-01 18:24:35 +00:00
var result = LoadProject ( Settings . RecentTas . MostRecent ) ;
2014-09-28 01:05:26 +00:00
if ( ! result )
{
2014-10-18 01:26:30 +00:00
TasView . AllColumns . Clear ( ) ;
2014-10-17 17:40:11 +00:00
NewDefaultProject ( ) ;
2014-09-28 01:05:26 +00:00
}
2014-08-21 22:53:03 +00:00
}
// Start Scenario 4: No movie, default behavior of engaging tastudio with a new default project
else
{
2014-10-17 17:40:11 +00:00
NewDefaultProject ( ) ;
2014-08-21 22:53:03 +00:00
}
EngageTastudio ( ) ;
2014-10-14 18:42:24 +00:00
if ( ! TasView . AllColumns . Any ( ) ) // If a project with column settings has already been loaded we don't need to do this
{
SetUpColumns ( ) ;
}
2015-01-03 14:03:13 +00:00
return true ;
2014-08-21 22:53:03 +00:00
}
private void Tastudio_Closing ( object sender , FormClosingEventArgs e )
{
2015-01-06 16:35:22 +00:00
_exiting = true ;
2014-08-21 22:53:03 +00:00
if ( AskSaveChanges ( ) )
{
2014-10-18 20:40:20 +00:00
WantsToControlStopMovie = false ;
2014-08-21 22:53:03 +00:00
GlobalWin . MainForm . StopMovie ( saveChanges : false ) ;
DisengageTastudio ( ) ;
}
else
{
e . Cancel = true ;
2015-01-06 16:35:22 +00:00
_exiting = false ;
2014-08-21 22:53:03 +00:00
}
}
2014-08-19 19:24:17 +00:00
2014-10-17 17:40:11 +00:00
/// <summary>
/// This method is called everytime the Changes property is toggled on a TasMovie instance.
/// </summary>
2014-08-23 18:02:02 +00:00
private void TasMovie_OnPropertyChanged ( object sender , PropertyChangedEventArgs e )
{
2014-09-16 23:26:17 +00:00
SetTextProperty ( ) ;
2014-08-23 18:02:02 +00:00
}
2014-10-21 13:12:12 +00:00
private void TAStudio_DragEnter ( object sender , DragEventArgs e )
{
e . Effect = e . Data . GetDataPresent ( DataFormats . FileDrop ) ? DragDropEffects . Copy : DragDropEffects . None ;
}
private void TAStudio_DragDrop ( object sender , DragEventArgs e )
{
var filePaths = ( string [ ] ) e . Data . GetData ( DataFormats . FileDrop ) ;
if ( Path . GetExtension ( filePaths [ 0 ] ) = = "." + TasMovie . Extension )
{
var file = new FileInfo ( filePaths [ 0 ] ) ;
2014-11-22 15:19:32 +00:00
if ( file . Exists )
2014-10-21 13:12:12 +00:00
{
2014-11-22 15:19:32 +00:00
LoadProject ( file . FullName ) ;
2014-10-21 13:12:12 +00:00
}
}
}
2014-10-22 22:43:42 +00:00
private void TAStudio_MouseLeave ( object sender , EventArgs e )
{
DoTriggeredAutoRestoreIfNeeded ( ) ;
}
2014-10-23 00:47:30 +00:00
protected override bool ProcessCmdKey ( ref Message msg , Keys keyData )
{
if ( keyData = = Keys . Tab | |
keyData = = ( Keys . Shift | Keys . Tab ) | |
keyData = = Keys . Space )
{
return true ;
}
2015-02-24 06:47:32 +00:00
2014-10-23 00:47:30 +00:00
return base . ProcessCmdKey ( ref msg , keyData ) ;
}
2014-02-01 15:44:51 +00:00
#endregion
2014-10-25 13:41:23 +00:00
private void MarkerContextMenu_Opening ( object sender , CancelEventArgs e )
{
EditMarkerContextMenuItem . Enabled =
RemoveMarkerContextMenuItem . Enabled =
MarkerControl . MarkerInputRoll . SelectedRows . Any ( ) ;
}
private void EditMarkerContextMenuItem_Click ( object sender , EventArgs e )
{
MarkerControl . EditMarker ( ) ;
}
private void AddMarkerContextMenuItem_Click ( object sender , EventArgs e )
{
MarkerControl . AddMarker ( ) ;
}
private void RemoveMarkerContextMenuItem_Click ( object sender , EventArgs e )
{
MarkerControl . RemoveMarker ( ) ;
}
2015-02-25 21:17:50 +00:00
2015-03-01 05:47:32 +00:00
public void AddMarker ( int markerFrame , string message )
{
TasMovieMarker marker = new TasMovieMarker ( markerFrame , message ) ;
CurrentTasMovie . Markers . Add ( marker ) ;
CurrentTasMovie . ChangeLog . AddMarkerChange ( marker ) ;
}
public void RemoveMarker ( TasMovieMarker marker )
{
CurrentTasMovie . Markers . Remove ( marker ) ;
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 ) ;
}
2013-12-01 04:00:02 +00:00
}
}