2014-07-09 23:04:22 +00:00
using System ;
using System.Drawing ;
2014-07-28 16:43:47 +00:00
using System.Linq ;
2014-07-09 23:04:22 +00:00
using System.Windows.Forms ;
using BizHawk.Client.Common ;
namespace BizHawk.Client.EmuHawk
{
public partial class TAStudio
{
2014-07-11 16:08:47 +00:00
// Input Painting
2014-07-11 16:26:19 +00:00
private string _startBoolDrawColumn = string . Empty ;
private string _startFloatDrawColumn = string . Empty ;
2014-07-11 16:08:47 +00:00
private bool _boolPaintState ;
2014-07-11 16:26:19 +00:00
private float _floatPaintState ;
2014-07-11 16:08:47 +00:00
private bool _startMarkerDrag ;
private bool _startFrameDrag ;
2014-10-17 18:14:21 +00:00
private bool _supressContextMenu ;
2014-07-11 16:08:47 +00:00
2014-07-21 02:23:47 +00:00
public static Color CurrentFrame_FrameCol = Color . FromArgb ( 0xCFEDFC ) ;
public static Color CurrentFrame_InputLog = Color . FromArgb ( 0xB5E7F7 ) ;
2014-07-16 00:10:37 +00:00
2014-07-21 02:23:47 +00:00
public static Color GreenZone_FrameCol = Color . FromArgb ( 0xDDFFDD ) ;
2014-08-22 16:05:06 +00:00
public static Color GreenZone_Invalidated_FrameCol = Color . FromArgb ( 0xFFFFFF ) ;
2014-07-21 02:23:47 +00:00
public static Color GreenZone_InputLog = Color . FromArgb ( 0xC4F7C8 ) ;
2014-08-22 16:05:06 +00:00
public static Color GreenZone_Invalidated_InputLog = Color . FromArgb ( 0xE0FBE0 ) ;
2014-07-16 00:10:37 +00:00
2014-07-21 02:23:47 +00:00
public static Color LagZone_FrameCol = Color . FromArgb ( 0xFFDCDD ) ;
2014-08-22 16:05:06 +00:00
public static Color LagZone_Invalidated_FrameCol = Color . FromArgb ( 0xFFE9E9 ) ;
2014-07-21 02:23:47 +00:00
public static Color LagZone_InputLog = Color . FromArgb ( 0xF0D0D2 ) ;
2014-08-22 16:05:06 +00:00
public static Color LagZone_Invalidated_InputLog = Color . FromArgb ( 0xF7E5E5 ) ;
2014-07-16 00:10:37 +00:00
2014-07-21 02:23:47 +00:00
public static Color Marker_FrameCol = Color . FromArgb ( 0xF7FFC9 ) ;
2014-07-16 00:10:37 +00:00
2014-07-09 23:04:22 +00:00
#region Query callbacks
2014-10-13 19:30:59 +00:00
private void TasView_QueryItemIcon ( int index , InputRoll . RollColumn column , ref Bitmap bitmap )
2014-09-03 03:16:16 +00:00
{
2014-10-13 19:30:59 +00:00
var columnName = column . Name ;
2014-09-03 03:16:16 +00:00
if ( columnName = = MarkerColumnName )
{
2014-09-16 19:20:19 +00:00
if ( index = = Global . Emulator . Frame & & index = = GlobalWin . MainForm . PauseOnFrame )
{
2014-10-17 18:14:21 +00:00
bitmap = TasView . HorizontalOrientation ?
Properties . Resources . ts_v_arrow_green_blue :
Properties . Resources . ts_h_arrow_green_blue ;
2014-09-16 19:20:19 +00:00
}
else if ( index = = Global . Emulator . Frame )
2014-09-03 03:16:16 +00:00
{
2014-10-17 18:14:21 +00:00
bitmap = TasView . HorizontalOrientation ?
Properties . Resources . ts_v_arrow_blue :
Properties . Resources . ts_h_arrow_blue ;
2014-09-03 03:16:16 +00:00
}
2014-09-16 19:20:19 +00:00
else if ( index = = GlobalWin . MainForm . PauseOnFrame )
{
2014-10-17 18:14:21 +00:00
bitmap = TasView . HorizontalOrientation ?
Properties . Resources . ts_v_arrow_green :
Properties . Resources . ts_h_arrow_green ;
2014-09-16 19:20:19 +00:00
}
2014-09-03 03:16:16 +00:00
}
}
2014-10-13 19:30:59 +00:00
private void TasView_QueryItemBkColor ( int index , InputRoll . RollColumn column , ref Color color )
2014-07-09 23:04:22 +00:00
{
2014-10-13 19:30:59 +00:00
var columnName = column . Name ;
2014-09-22 21:47:07 +00:00
var record = _currentTasMovie [ index ] ;
2014-07-16 00:10:37 +00:00
if ( columnName = = MarkerColumnName )
2014-07-09 23:04:22 +00:00
{
2014-09-22 21:47:07 +00:00
if ( VersionInfo . DeveloperBuild ) // For debugging purposes, let's visually show the state frames
2014-07-16 23:04:56 +00:00
{
2014-09-22 21:47:07 +00:00
color = ( record . HasState ? color = Color . FromArgb ( 0xEEEEEE ) : Color . White ) ;
2014-07-16 23:04:56 +00:00
}
2014-09-22 21:47:07 +00:00
2014-07-16 23:04:56 +00:00
return ;
2014-07-09 23:04:22 +00:00
}
2014-07-16 23:04:56 +00:00
if ( columnName = = FrameColumnName )
2014-07-09 23:04:22 +00:00
{
2014-07-16 00:10:37 +00:00
if ( Global . Emulator . Frame = = index )
{
color = CurrentFrame_FrameCol ;
}
2014-08-19 19:24:17 +00:00
else if ( _currentTasMovie . Markers . IsMarker ( index ) )
2014-07-16 00:10:37 +00:00
{
color = Marker_FrameCol ;
}
else if ( record . Lagged . HasValue )
2014-07-10 19:24:21 +00:00
{
2014-10-17 18:14:21 +00:00
color = record . Lagged . Value ?
LagZone_FrameCol :
GreenZone_FrameCol ;
2014-07-10 19:24:21 +00:00
}
else
{
2014-07-16 00:10:37 +00:00
color = Color . White ;
}
}
else
{
if ( Global . Emulator . Frame = = index )
{
color = CurrentFrame_InputLog ;
}
else
{
if ( record . Lagged . HasValue )
{
2014-10-17 18:14:21 +00:00
color = record . Lagged . Value ?
LagZone_InputLog :
GreenZone_InputLog ;
2014-07-16 00:10:37 +00:00
}
else
{
2014-10-15 19:06:33 +00:00
color = Color . FromArgb ( 0xFFFEEE ) ;
2014-07-16 00:10:37 +00:00
}
2014-07-10 19:24:21 +00:00
}
2014-07-09 23:04:22 +00:00
}
}
2014-10-13 19:10:11 +00:00
private void TasView_QueryItemText ( int index , InputRoll . RollColumn column , out string text )
2014-07-09 23:04:22 +00:00
{
try
{
2014-07-16 23:04:56 +00:00
text = string . Empty ;
2014-10-13 19:10:11 +00:00
var columnName = column . Name ;
2014-07-09 23:04:22 +00:00
if ( columnName = = MarkerColumnName )
{
2014-09-18 00:51:16 +00:00
// Do nothing
2014-07-09 23:04:22 +00:00
}
else if ( columnName = = FrameColumnName )
{
2014-09-18 00:51:16 +00:00
text = ( index ) . ToString ( ) . PadLeft ( _currentTasMovie . InputLogLength . ToString ( ) . Length , '0' ) ;
2014-07-09 23:04:22 +00:00
}
else
{
2014-08-19 19:24:17 +00:00
if ( index < _currentTasMovie . InputLogLength )
2014-07-16 23:04:56 +00:00
{
2014-08-19 19:24:17 +00:00
text = _currentTasMovie . DisplayValue ( index , columnName ) ;
2014-07-16 23:04:56 +00:00
}
2014-08-19 19:24:17 +00:00
else if ( Global . Emulator . Frame = = _currentTasMovie . InputLogLength ) // In this situation we have a "pending" frame for the user to click
2014-07-16 23:04:56 +00:00
{
2014-08-29 01:59:08 +00:00
text = _currentTasMovie . CreateDisplayValueForButton (
2014-07-16 23:04:56 +00:00
Global . ClickyVirtualPadController ,
columnName ) ;
}
2014-07-09 23:04:22 +00:00
}
}
catch ( Exception ex )
{
text = string . Empty ;
MessageBox . Show ( "oops\n" + ex ) ;
}
}
#endregion
#region Events
2014-10-14 00:31:59 +00:00
private void TasView_ColumnClick ( object sender , InputRoll . ColumnClickEventArgs e )
2014-07-28 16:43:47 +00:00
{
2014-08-30 18:42:14 +00:00
if ( TasView . SelectedRows . Any ( ) )
2014-07-28 16:43:47 +00:00
{
2014-10-14 00:31:59 +00:00
var columnName = e . Column . Name ;
2014-07-28 16:43:47 +00:00
if ( columnName = = FrameColumnName )
{
2014-09-19 01:15:14 +00:00
_currentTasMovie . Markers . Add ( TasView . LastSelectedIndex . Value , "" ) ;
RefreshDialog ( ) ;
2014-07-28 16:43:47 +00:00
}
else if ( columnName ! = MarkerColumnName ) // TODO: what about float?
{
2014-08-30 18:42:14 +00:00
foreach ( var index in TasView . SelectedRows )
2014-07-28 16:43:47 +00:00
{
ToggleBoolState ( index , columnName ) ;
2014-10-15 14:36:08 +00:00
GoToLastEmulatedFrameIfNecessary ( TasView . SelectedRows . Min ( ) ) ;
2014-07-28 16:43:47 +00:00
}
RefreshDialog ( ) ;
}
}
}
2014-10-14 00:31:59 +00:00
private void TasView_ColumnRightClick ( object sender , InputRoll . ColumnClickEventArgs e )
2014-09-25 17:52:21 +00:00
{
2014-10-14 00:31:59 +00:00
e . Column . Emphasis ^ = true ;
2014-09-25 17:52:21 +00:00
2014-10-14 00:31:59 +00:00
Global . StickyXORAdapter . SetSticky ( e . Column . Name , e . Column . Emphasis ) ;
2014-09-25 18:12:18 +00:00
TasView . Refresh ( ) ;
2014-09-25 17:52:21 +00:00
}
2014-10-17 17:40:11 +00:00
private void TasView_MouseEnter ( object sender , EventArgs e )
{
TasView . Focus ( ) ;
}
2014-07-09 23:04:22 +00:00
private void TasView_MouseDown ( object sender , MouseEventArgs e )
{
2014-07-17 20:35:12 +00:00
if ( e . Button = = MouseButtons . Middle )
{
TogglePause ( ) ;
return ;
}
2014-08-31 17:15:21 +00:00
if ( TasView . CurrentCell ! = null & & TasView . CurrentCell . RowIndex . HasValue & & TasView . CurrentCell . Column ! = null )
2014-07-09 23:04:22 +00:00
{
2014-07-14 01:49:37 +00:00
if ( e . Button = = MouseButtons . Left )
2014-07-09 23:04:22 +00:00
{
2014-08-23 15:19:48 +00:00
if ( TasView . CurrentCell . Column . Name = = MarkerColumnName )
2014-07-10 20:40:50 +00:00
{
2014-07-14 01:49:37 +00:00
_startMarkerDrag = true ;
2014-08-23 13:14:25 +00:00
GoToFrame ( TasView . CurrentCell . RowIndex . Value ) ;
2014-07-14 01:49:37 +00:00
}
2014-08-23 15:19:48 +00:00
else if ( TasView . CurrentCell . Column . Name = = FrameColumnName )
2014-07-14 01:49:37 +00:00
{
_startFrameDrag = true ;
2014-07-10 20:40:50 +00:00
}
2014-09-22 22:52:34 +00:00
else // User changed input
2014-07-11 16:26:19 +00:00
{
2014-08-23 13:14:25 +00:00
var frame = TasView . CurrentCell . RowIndex . Value ;
2014-08-23 15:19:48 +00:00
var buttonName = TasView . CurrentCell . Column . Name ;
2014-07-14 01:49:37 +00:00
if ( Global . MovieSession . MovieControllerAdapter . Type . BoolButtons . Contains ( buttonName ) )
{
2014-08-23 15:19:48 +00:00
ToggleBoolState ( TasView . CurrentCell . RowIndex . Value , buttonName ) ;
2014-08-23 13:14:25 +00:00
GoToLastEmulatedFrameIfNecessary ( TasView . CurrentCell . RowIndex . Value ) ;
2014-09-25 01:26:39 +00:00
RefreshDialog ( ) ;
2014-07-14 01:49:37 +00:00
2014-08-23 15:19:48 +00:00
_startBoolDrawColumn = buttonName ;
2014-09-18 21:56:13 +00:00
if ( frame < _currentTasMovie . InputLogLength )
{
_boolPaintState = _currentTasMovie . BoolIsPressed ( frame , buttonName ) ;
}
else
{
Global . ClickyVirtualPadController . IsPressed ( buttonName ) ;
}
2014-07-14 01:49:37 +00:00
}
else
{
2014-08-23 15:19:48 +00:00
_startFloatDrawColumn = buttonName ;
2014-08-19 19:24:17 +00:00
_floatPaintState = _currentTasMovie . GetFloatValue ( frame , buttonName ) ;
2014-07-14 01:49:37 +00:00
}
2014-07-11 16:26:19 +00:00
}
2014-07-09 23:04:22 +00:00
}
}
}
private void TasView_MouseUp ( object sender , MouseEventArgs e )
{
2014-10-15 22:52:23 +00:00
if ( e . Button = = MouseButtons . Right & & ! _supressContextMenu )
{
RightClickMenu . Show ( TasView , e . X , e . Y ) ;
}
else if ( e . Button = = MouseButtons . Left )
{
_startMarkerDrag = false ;
_startFrameDrag = false ;
_startBoolDrawColumn = string . Empty ;
_startFloatDrawColumn = string . Empty ;
_floatPaintState = 0 ;
}
_supressContextMenu = false ;
2014-07-09 23:04:22 +00:00
}
2014-07-16 01:37:50 +00:00
private void TasView_MouseWheel ( object sender , MouseEventArgs e )
{
2014-08-23 13:14:25 +00:00
if ( TasView . RightButtonHeld & & TasView . CurrentCell . RowIndex . HasValue )
2014-07-16 01:37:50 +00:00
{
2014-10-15 22:52:23 +00:00
_supressContextMenu = true ;
2014-07-16 01:37:50 +00:00
if ( e . Delta < 0 )
{
2014-07-17 23:55:10 +00:00
GoToFrame ( Global . Emulator . Frame + 1 ) ;
2014-07-16 01:37:50 +00:00
}
else
{
2014-08-31 16:07:11 +00:00
if ( Global . Emulator . Frame > 0 )
{
GoToFrame ( Global . Emulator . Frame - 1 ) ;
}
2014-07-16 01:37:50 +00:00
}
}
}
private void TasView_MouseDoubleClick ( object sender , MouseEventArgs e )
{
2014-08-23 13:14:25 +00:00
if ( TasView . CurrentCell . RowIndex . HasValue & &
2014-08-23 15:19:48 +00:00
TasView . CurrentCell ! = null & &
2014-08-31 18:06:31 +00:00
TasView . CurrentCell . Column . Name = = FrameColumnName & &
e . Button = = MouseButtons . Left )
2014-07-16 01:37:50 +00:00
{
2014-10-15 16:09:14 +00:00
if ( Global . Config . TAStudioEmptyMarkers )
{
_currentTasMovie . Markers . Add ( TasView . CurrentCell . RowIndex . Value , string . Empty ) ;
RefreshDialog ( ) ;
}
else
{
CallAddMarkerPopUp ( TasView . CurrentCell . RowIndex . Value ) ;
}
2014-07-16 01:37:50 +00:00
}
}
2014-08-23 15:19:48 +00:00
private void TasView_PointedCellChanged ( object sender , InputRoll . CellEventArgs e )
2014-07-09 23:04:22 +00:00
{
2014-08-23 15:19:48 +00:00
// TODO: think about nullability
// For now return if a null because this happens OnEnter which doesn't have any of the below behaviors yet?
// Most of these are stupid but I got annoyed at null crashes
if ( e . OldCell = = null | | e . OldCell . Column = = null | | e . OldCell . RowIndex = = null | |
e . NewCell = = null | | e . NewCell . RowIndex = = null | | e . NewCell . Column = = null )
{
return ;
}
2014-07-11 16:08:47 +00:00
int startVal , endVal ;
2014-08-23 13:14:25 +00:00
if ( e . OldCell . RowIndex . Value < e . NewCell . RowIndex . Value )
2014-07-11 16:08:47 +00:00
{
2014-08-23 13:14:25 +00:00
startVal = e . OldCell . RowIndex . Value ;
endVal = e . NewCell . RowIndex . Value ;
2014-07-11 16:08:47 +00:00
}
else
{
2014-08-23 13:14:25 +00:00
startVal = e . NewCell . RowIndex . Value ;
endVal = e . OldCell . RowIndex . Value ;
2014-07-11 16:08:47 +00:00
}
2014-07-09 23:04:22 +00:00
if ( _startMarkerDrag )
{
2014-08-23 13:14:25 +00:00
if ( e . NewCell . RowIndex . HasValue )
2014-07-09 23:04:22 +00:00
{
2014-08-23 13:14:25 +00:00
GoToFrame ( e . NewCell . RowIndex . Value ) ;
2014-07-09 23:04:22 +00:00
}
}
else if ( _startFrameDrag )
{
2014-08-23 13:14:25 +00:00
if ( e . OldCell . RowIndex . HasValue & & e . NewCell . RowIndex . HasValue )
2014-07-09 23:04:22 +00:00
{
2014-08-29 18:02:23 +00:00
for ( var i = startVal ; i < endVal ; i + + )
2014-07-09 23:04:22 +00:00
{
2014-08-31 15:40:02 +00:00
TasView . SelectRow ( i , true ) ;
2014-08-29 18:02:23 +00:00
TasView . Refresh ( ) ;
2014-07-09 23:04:22 +00:00
}
}
}
2014-08-23 13:14:25 +00:00
else if ( TasView . IsPaintDown & & e . NewCell . RowIndex . HasValue & & ! string . IsNullOrEmpty ( _startBoolDrawColumn ) )
2014-07-11 16:26:19 +00:00
{
2014-08-23 13:14:25 +00:00
if ( e . OldCell . RowIndex . HasValue & & e . NewCell . RowIndex . HasValue )
2014-07-11 16:26:19 +00:00
{
for ( var i = startVal ; i < endVal ; i + + )
{
2014-07-16 23:04:56 +00:00
SetBoolState ( i , _startBoolDrawColumn , _boolPaintState ) ; // Notice it uses new row, old column, you can only paint across a single column
2014-08-23 13:14:25 +00:00
GoToLastEmulatedFrameIfNecessary ( TasView . CurrentCell . RowIndex . Value ) ;
2014-07-11 16:26:19 +00:00
}
TasView . Refresh ( ) ;
}
}
2014-08-23 13:14:25 +00:00
else if ( TasView . IsPaintDown & & e . NewCell . RowIndex . HasValue & & ! string . IsNullOrEmpty ( _startFloatDrawColumn ) )
2014-07-09 23:04:22 +00:00
{
2014-08-23 13:14:25 +00:00
if ( e . OldCell . RowIndex . HasValue & & e . NewCell . RowIndex . HasValue )
2014-07-11 16:08:47 +00:00
{
for ( var i = startVal ; i < endVal ; i + + )
{
2014-08-19 19:24:17 +00:00
if ( i < _currentTasMovie . InputLogLength ) // TODO: how do we really want to handle the user setting the float state of the pending frame?
2014-07-16 23:04:56 +00:00
{
2014-08-19 19:24:17 +00:00
_currentTasMovie . SetFloatState ( i , _startFloatDrawColumn , _floatPaintState ) ; // Notice it uses new row, old column, you can only paint across a single column
2014-08-23 13:14:25 +00:00
GoToLastEmulatedFrameIfNecessary ( TasView . CurrentCell . RowIndex . Value ) ;
2014-07-16 23:04:56 +00:00
}
2014-07-11 16:08:47 +00:00
}
2014-07-11 16:26:19 +00:00
2014-07-11 16:08:47 +00:00
TasView . Refresh ( ) ;
}
2014-07-09 23:04:22 +00:00
}
}
private void TasView_SelectedIndexChanged ( object sender , EventArgs e )
{
SetSplicer ( ) ;
}
2014-07-17 19:57:44 +00:00
private void TasView_KeyDown ( object sender , KeyEventArgs e )
{
if ( e . Control & & ! e . Shift & & ! e . Alt & & e . KeyCode = = Keys . Left ) // Ctrl + Left
{
GoToPreviousMarker ( ) ;
}
else if ( e . Control & & ! e . Shift & & ! e . Alt & & e . KeyCode = = Keys . Right ) // Ctrl + Left
{
GoToNextMarker ( ) ;
}
2014-07-25 01:02:24 +00:00
else if ( e . Control & & ! e . Shift & & ! e . Alt & & e . KeyCode = = Keys . Up ) // Ctrl + Up
{
GoToPreviousFrame ( ) ;
}
else if ( e . Control & & ! e . Shift & & ! e . Alt & & e . KeyCode = = Keys . Down ) // Ctrl + Down
{
GoToNextFrame ( ) ;
2014-09-01 15:35:48 +00:00
} else if ( e . Control & & ! e . Alt & & e . Shift & & e . KeyCode = = Keys . R ) // Ctrl + Shift + R
{
TasView . HorizontalOrientation ^ = true ;
2014-07-25 01:02:24 +00:00
}
2014-07-17 19:57:44 +00:00
}
2014-07-09 23:04:22 +00:00
#endregion
}
}