BizHawk/BizHawk.Client.EmuHawk/tools/VirtualPads/VirtualpadsTool.cs

255 lines
5.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using BizHawk.Emulation.Common;
using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk
{
public partial class VirtualpadTool : Form, IToolFormAutoConfig
{
[RequiredService]
private IEmulator Emulator { get; set; }
[ConfigPersist]
public bool StickyPads { get; set; }
[ConfigPersist]
public bool ClearAlsoClearsAnalog { get; set; }
private bool _readOnly;
private List<VirtualPad> Pads
{
get
{
return ControllerPanel.Controls
.OfType<VirtualPad>()
.ToList();
}
}
public bool Readonly
{
get
{
return _readOnly;
}
set
{
_readOnly = value;
Pads.ForEach(p => p.ReadOnly = value);
}
}
public VirtualpadTool()
{
StickyPads = true;
InitializeComponent();
}
private void VirtualpadTool_Load(object sender, EventArgs e)
{
CreatePads();
}
public void ClearVirtualPadHolds()
{
if (ClearAlsoClearsAnalog)
{
Pads.ForEach(pad => pad.Clear());
}
else
{
Pads.ForEach(pad => pad.ClearBoolean());
}
}
public void BumpAnalogValue(int? x, int? y) // TODO: multi-player
{
Pads.ForEach(pad => pad.BumpAnalog(x, y));
}
private void CreatePads()
{
ControllerPanel.Controls.Clear();
var schemaType = Assembly
.GetExecutingAssembly()
.GetTypes()
.Where(t => typeof(IVirtualPadSchema)
.IsAssignableFrom(t) && t.GetCustomAttributes(false)
.OfType<SchemaAttributes>()
.Any())
.FirstOrDefault(t => t.GetCustomAttributes(false)
.OfType<SchemaAttributes>()
.First().SystemId == Emulator.SystemId);
if (schemaType != null)
{
var padschemas = (Activator.CreateInstance(schemaType) as IVirtualPadSchema).GetPadSchemas();
if (VersionInfo.DeveloperBuild)
{
CheckPads(padschemas, Emulator.ControllerDefinition);
}
var pads = padschemas.Select(s => new VirtualPad(s));
if (pads.Any())
{
ControllerPanel.Controls.AddRange(pads.Reverse().ToArray());
}
}
}
public void ScrollToPadSchema(string padSchemaName)
{
foreach (var control in ControllerPanel.Controls)
{
VirtualPad vp = control as VirtualPad;
if (vp == null) continue;
if (vp.PadSchemaDisplayName == padSchemaName)
ControllerPanel.ScrollControlIntoView(vp);
}
}
private void CheckPads(IEnumerable<PadSchema> schemas, BizHawk.Emulation.Common.ControllerDefinition def)
{
HashSet<string> analogs = new HashSet<string>(def.FloatControls);
HashSet<string> bools = new HashSet<string>(def.BoolButtons);
foreach (var schema in schemas)
{
foreach (var button in schema.Buttons)
{
HashSet<string> searchset = null;
switch (button.Type)
{
case PadSchema.PadInputType.AnalogStick:
case PadSchema.PadInputType.FloatSingle:
case PadSchema.PadInputType.TargetedPair:
// analog
searchset = analogs;
break;
case PadSchema.PadInputType.Boolean:
searchset = bools;
break;
case PadSchema.PadInputType.DiscManager:
searchset = bools;
searchset.UnionWith(analogs);
break;
}
if (!searchset.Contains(button.Name))
{
MessageBox.Show(this,
string.Format("Schema warning: Schema entry '{0}':'{1}' will not correspond to any control in definition '{2}'", schema.DisplayName, button.Name, def.Name),
"Dev Warning");
}
}
}
}
#region IToolForm Implementation
public bool AskSaveChanges() { return true; }
public bool UpdateBefore { get { return false; } }
public void Restart()
{
if (!IsHandleCreated || IsDisposed)
{
return;
}
CreatePads();
}
public void UpdateValues()
{
if (!IsHandleCreated || IsDisposed)
{
return;
}
Pads.ForEach(p => p.SetPrevious(null)); // Not the cleanest way to clear this every frame
if (Global.MovieSession.Movie.IsPlaying && !Global.MovieSession.Movie.IsFinished)
{
Readonly = true;
Pads.ForEach(p => p.Set(Global.MovieSession.CurrentInput));
}
else
{
if (Global.MovieSession.Movie.IsRecording)
{
Pads.ForEach(p => p.SetPrevious(Global.MovieSession.PreviousFrame));
}
Readonly = false;
}
if (!Readonly && !StickyPads && !Control.MouseButtons.HasFlag(MouseButtons.Left))
{
Pads.ForEach(pad => pad.Clear());
}
Pads.ForEach(pad => pad.UpdateValues());
}
public void FastUpdate()
{
// TODO: SetPrevious logic should go here too or that will get out of whack
if (!Readonly && !StickyPads)
{
Pads.ForEach(pad => pad.Clear());
}
}
#endregion
#region Menu
private void PadsSubMenu_DropDownOpened(object sender, EventArgs e)
{
StickyMenuItem.Checked = StickyPads;
}
private void ClearAllMenuItem_Click(object sender, EventArgs e)
{
ClearVirtualPadHolds();
}
private void StickyMenuItem_Click(object sender, EventArgs e)
{
StickyPads ^= true;
}
private void PadBoxContextMenu_Opening(object sender, System.ComponentModel.CancelEventArgs e)
{
StickyContextMenuItem.Checked = StickyPads;
}
private void ExitMenuItem_Click(object sender, EventArgs e)
{
Close();
}
private void OptionsSubMenu_DropDownOpened(object sender, EventArgs e)
{
ClearClearsAnalogInputMenuItem.Checked = ClearAlsoClearsAnalog;
}
private void ClearClearsAnalogInputMenuItem_Click(object sender, EventArgs e)
{
ClearAlsoClearsAnalog ^= true;
}
#endregion
}
}