2014-06-22 13:58:12 +00:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
2014-06-24 00:26:35 +00:00
using System.Reflection ;
2014-06-22 13:58:12 +00:00
using System.Windows.Forms ;
2015-01-01 19:15:32 +00:00
using BizHawk.Emulation.Common ;
2014-06-22 13:58:12 +00:00
using BizHawk.Client.Common ;
namespace BizHawk.Client.EmuHawk
{
2015-01-01 18:42:08 +00:00
public partial class VirtualpadTool : Form , IToolFormAutoConfig
2014-06-22 13:58:12 +00:00
{
2015-01-01 19:15:32 +00:00
[RequiredService]
private IEmulator Emulator { get ; set ; }
[ConfigPersist]
public bool StickyPads { get ; set ; }
[ConfigPersist]
public bool ClearAlsoClearsAnalog { get ; set ; }
2014-06-29 03:14:40 +00:00
private bool _readOnly ;
2014-06-22 13:58:12 +00:00
2019-10-29 14:27:56 +00:00
private List < VirtualPad > Pads = >
ControllerPanel . Controls
. OfType < VirtualPad > ( )
. ToList ( ) ;
2014-06-22 13:58:12 +00:00
2014-06-27 01:45:30 +00:00
public bool Readonly
2014-06-26 20:36:33 +00:00
{
2019-12-21 22:34:29 +00:00
get = > _readOnly ;
2014-06-27 01:45:30 +00:00
set
{
_readOnly = value ;
Pads . ForEach ( p = > p . ReadOnly = value ) ;
2014-06-26 20:36:33 +00:00
}
}
2014-06-22 13:58:12 +00:00
public VirtualpadTool ( )
{
2015-01-01 18:42:08 +00:00
StickyPads = true ;
2014-06-22 13:58:12 +00:00
InitializeComponent ( ) ;
}
private void VirtualpadTool_Load ( object sender , EventArgs e )
{
CreatePads ( ) ;
}
public void ClearVirtualPadHolds ( )
{
2015-01-01 18:42:08 +00:00
if ( ClearAlsoClearsAnalog )
2014-07-27 12:39:56 +00:00
{
Pads . ForEach ( pad = > pad . Clear ( ) ) ;
}
else
{
Pads . ForEach ( pad = > pad . ClearBoolean ( ) ) ;
}
2014-06-22 13:58:12 +00:00
}
2014-06-29 23:43:31 +00:00
public void BumpAnalogValue ( int? x , int? y ) // TODO: multi-player
2014-06-22 13:58:12 +00:00
{
2014-06-29 23:43:31 +00:00
Pads . ForEach ( pad = > pad . BumpAnalog ( x , y ) ) ;
2014-06-22 13:58:12 +00:00
}
private void CreatePads ( )
{
2014-12-19 03:24:48 +00:00
ControllerPanel . Controls . Clear ( ) ;
2014-06-22 13:58:12 +00:00
2014-06-24 00:26:35 +00:00
var schemaType = Assembly
. GetExecutingAssembly ( )
. GetTypes ( )
. Where ( t = > typeof ( IVirtualPadSchema )
. IsAssignableFrom ( t ) & & t . GetCustomAttributes ( false )
2017-07-12 19:40:10 +00:00
. OfType < SchemaAttribute > ( )
2014-06-24 00:26:35 +00:00
. Any ( ) )
. FirstOrDefault ( t = > t . GetCustomAttributes ( false )
2017-07-12 19:40:10 +00:00
. OfType < SchemaAttribute > ( )
2015-01-01 19:15:32 +00:00
. First ( ) . SystemId = = Emulator . SystemId ) ;
2020-03-21 19:52:09 +00:00
2020-03-31 11:40:36 +00:00
if ( schemaType = = null ) return ;
2020-03-21 19:52:09 +00:00
2020-03-31 11:40:36 +00:00
var padSchemata = ( ( IVirtualPadSchema ) Activator . CreateInstance ( schemaType ) )
. GetPadSchemas ( Emulator )
. ToList ( ) ;
2014-06-27 17:02:46 +00:00
2020-03-31 11:40:36 +00:00
if ( VersionInfo . DeveloperBuild )
{
var buttonControls = Emulator . ControllerDefinition . BoolButtons ;
var axisControls = Emulator . ControllerDefinition . AxisControls ;
foreach ( var schema in padSchemata ) foreach ( var controlSchema in schema . Buttons )
2014-06-26 21:09:14 +00:00
{
2020-03-31 11:40:36 +00:00
Predicate < string > searchSetContains = controlSchema switch
{
ButtonSchema _ = > buttonControls . Contains ,
DiscManagerSchema _ = > s = > buttonControls . Contains ( s ) | | axisControls . Contains ( s ) ,
_ = > axisControls . Contains
} ;
if ( ! searchSetContains ( controlSchema . Name ) )
{
MessageBox . Show ( this ,
$"Schema warning: Schema entry '{schema.DisplayName}':'{controlSchema.Name}' will not correspond to any control in definition '{Emulator.ControllerDefinition.Name}'" ,
"Dev Warning" ) ;
}
2014-06-26 21:09:14 +00:00
}
2014-06-22 13:58:12 +00:00
}
2020-03-31 11:40:36 +00:00
ControllerPanel . Controls . AddRange ( padSchemata . Select ( s = > ( Control ) new VirtualPad ( s ) ) . Reverse ( ) . ToArray ( ) ) ;
2014-06-22 13:58:12 +00:00
}
2014-12-19 03:24:48 +00:00
public void ScrollToPadSchema ( string padSchemaName )
{
foreach ( var control in ControllerPanel . Controls )
{
2020-03-21 19:52:09 +00:00
var vp = control as VirtualPad ;
if ( vp = = null )
{
continue ;
}
2014-12-19 03:24:48 +00:00
if ( vp . PadSchemaDisplayName = = padSchemaName )
2020-03-21 19:52:09 +00:00
{
2014-12-19 03:24:48 +00:00
ControllerPanel . ScrollControlIntoView ( vp ) ;
2020-03-21 19:52:09 +00:00
}
2014-12-19 03:24:48 +00:00
}
}
2014-06-22 13:58:12 +00:00
#region IToolForm Implementation
2019-12-21 22:34:29 +00:00
public bool AskSaveChanges ( ) = > true ;
public bool UpdateBefore = > false ;
2014-06-22 13:58:12 +00:00
public void Restart ( )
{
if ( ! IsHandleCreated | | IsDisposed )
{
return ;
}
CreatePads ( ) ;
}
2016-08-13 20:31:04 +00:00
public void NewUpdate ( ToolFormUpdateType type ) { }
2014-06-22 13:58:12 +00:00
public void UpdateValues ( )
{
if ( ! IsHandleCreated | | IsDisposed )
{
return ;
}
2014-06-29 14:42:20 +00:00
Pads . ForEach ( p = > p . SetPrevious ( null ) ) ; // Not the cleanest way to clear this every frame
2019-12-21 22:34:29 +00:00
if ( Global . MovieSession . Movie . Mode = = MovieMode . Play )
2014-06-22 13:58:12 +00:00
{
2014-06-27 01:45:30 +00:00
Readonly = true ;
2018-10-19 02:05:14 +00:00
if ( Global . MovieSession . CurrentInput ! = null )
{
Pads . ForEach ( p = > p . Set ( Global . MovieSession . CurrentInput ) ) ;
}
2014-06-22 13:58:12 +00:00
}
2014-06-26 20:07:07 +00:00
else
{
2019-12-21 22:34:29 +00:00
if ( Global . MovieSession . Movie . IsRecording ( ) )
2014-06-29 14:42:20 +00:00
{
Pads . ForEach ( p = > p . SetPrevious ( Global . MovieSession . PreviousFrame ) ) ;
}
2014-06-27 01:45:30 +00:00
Readonly = false ;
2014-06-26 20:07:07 +00:00
}
2014-06-24 16:36:19 +00:00
2020-03-21 19:52:09 +00:00
if ( ! Readonly & & ! StickyPads & & ! MouseButtons . HasFlag ( MouseButtons . Left ) )
2014-06-26 20:36:33 +00:00
{
Pads . ForEach ( pad = > pad . Clear ( ) ) ;
}
2014-07-04 15:15:08 +00:00
2014-07-26 17:11:47 +00:00
Pads . ForEach ( pad = > pad . UpdateValues ( ) ) ;
2014-06-22 13:58:12 +00:00
}
2014-07-25 01:55:21 +00:00
public void FastUpdate ( )
{
// TODO: SetPrevious logic should go here too or that will get out of whack
2015-01-01 18:42:08 +00:00
if ( ! Readonly & & ! StickyPads )
2014-07-25 01:55:21 +00:00
{
Pads . ForEach ( pad = > pad . Clear ( ) ) ;
}
}
2014-06-22 13:58:12 +00:00
#endregion
#region Menu
2015-01-01 18:42:08 +00:00
private void PadsSubMenu_DropDownOpened ( object sender , EventArgs e )
2014-06-22 13:58:12 +00:00
{
2015-01-01 18:42:08 +00:00
StickyMenuItem . Checked = StickyPads ;
2014-06-22 13:58:12 +00:00
}
2015-01-01 18:42:08 +00:00
private void ClearAllMenuItem_Click ( object sender , EventArgs e )
2014-06-22 13:58:12 +00:00
{
2015-01-01 18:42:08 +00:00
ClearVirtualPadHolds ( ) ;
2014-06-22 13:58:12 +00:00
}
2015-01-01 18:42:08 +00:00
private void StickyMenuItem_Click ( object sender , EventArgs e )
2014-06-22 13:58:12 +00:00
{
2015-01-01 18:42:08 +00:00
StickyPads ^ = true ;
2014-06-22 13:58:12 +00:00
}
2015-01-01 18:42:08 +00:00
private void PadBoxContextMenu_Opening ( object sender , System . ComponentModel . CancelEventArgs e )
2014-06-22 13:58:12 +00:00
{
2015-01-01 18:42:08 +00:00
StickyContextMenuItem . Checked = StickyPads ;
2014-06-22 13:58:12 +00:00
}
private void ExitMenuItem_Click ( object sender , EventArgs e )
{
Close ( ) ;
}
2015-01-01 18:42:08 +00:00
private void OptionsSubMenu_DropDownOpened ( object sender , EventArgs e )
2014-06-22 15:05:37 +00:00
{
2015-01-01 18:42:08 +00:00
ClearClearsAnalogInputMenuItem . Checked = ClearAlsoClearsAnalog ;
2014-06-22 15:05:37 +00:00
}
2015-01-01 18:42:08 +00:00
private void ClearClearsAnalogInputMenuItem_Click ( object sender , EventArgs e )
2014-06-29 21:16:33 +00:00
{
2015-01-01 18:42:08 +00:00
ClearAlsoClearsAnalog ^ = true ;
2014-06-29 21:16:33 +00:00
}
2014-06-22 13:58:12 +00:00
#endregion
}
}