BizHawk/BizHawk.Client.EmuHawk/tools/Cheats/CheatEdit.cs

420 lines
9.2 KiB
C#

using System;
using System.Linq;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
using Emu = BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk
{
public partial class CheatEdit : UserControl
{
public Emu.IMemoryDomains MemoryDomains { get; set; }
public CheatEdit()
{
InitializeComponent();
AddressBox.Nullable = false;
ValueBox.Nullable = false;
}
#region Privates
private const string HexInd = "0x";
private Cheat _cheat;
private bool _loading;
private bool _editmode;
private Action _addCallback;
private Action _editCallback;
private void CheatEdit_Load(object sender, EventArgs e)
{
Restart();
}
public void Restart()
{
if (MemoryDomains != null) // the designer needs this check
{
DomainDropDown.Items.Clear();
DomainDropDown.Items.AddRange(MemoryDomains
.Where(d => d.CanPoke())
.Select(d => d.ToString())
.ToArray());
DomainDropDown.SelectedItem = MemoryDomains.HasSystemBus
? MemoryDomains.SystemBus.ToString()
: MemoryDomains.MainMemory.ToString();
}
SetFormToDefault();
}
private void SetFormToCheat()
{
_loading = true;
SetSizeSelected(_cheat.Size);
PopulateTypeDropdown();
SetTypeSelected(_cheat.Type);
SetDomainSelected(_cheat.Domain);
AddressBox.SetHexProperties(_cheat.Domain.Size);
ValueBox.ByteSize =
CompareBox.ByteSize =
_cheat.Size;
ValueBox.Type =
CompareBox.Type =
_cheat.Type;
ValueHexIndLabel.Text =
CompareHexIndLabel.Text =
_cheat.Type == DisplayType.Hex ? HexInd : "";
BigEndianCheckBox.Checked = _cheat.BigEndian ?? false;
NameBox.Text = _cheat.Name;
AddressBox.Text = _cheat.AddressStr;
ValueBox.Text = _cheat.ValueStr;
CompareBox.Text = _cheat.Compare.HasValue ? _cheat.CompareStr : "";
if (_cheat.ComparisonType.Equals(Cheat.CompareType.None))
{
CompareTypeDropDown.SelectedIndex = 0;
}
else
{
CompareTypeDropDown.SelectedIndex = (int)_cheat.ComparisonType - 1;
}
CheckFormState();
if (!_cheat.Compare.HasValue)
{
CompareBox.Text = ""; // Necessary hack until WatchValueBox.ToRawInt() becomes nullable
}
_loading = false;
}
private void SetFormToDefault()
{
_loading = true;
SetSizeSelected(WatchSize.Byte);
PopulateTypeDropdown();
NameBox.Text = "";
if (MemoryDomains != null)
{
AddressBox.SetHexProperties(MemoryDomains.SystemBus.Size);
}
ValueBox.ByteSize =
CompareBox.ByteSize =
WatchSize.Byte;
ValueBox.Type =
CompareBox.Type =
DisplayType.Hex;
ValueBox.ResetText();
CompareBox.ResetText();
ValueHexIndLabel.Text =
CompareHexIndLabel.Text =
HexInd;
BigEndianCheckBox.Checked = false;
SetTypeSelected(DisplayType.Hex);
CheckFormState();
CompareBox.Text = ""; // TODO: A needed hack until WatchValueBox.ToRawInt() becomes nullable
_loading = false;
}
private void SetSizeSelected(WatchSize size)
{
switch (size)
{
default:
case WatchSize.Byte:
SizeDropDown.SelectedIndex = 0;
break;
case WatchSize.Word:
SizeDropDown.SelectedIndex = 1;
break;
case WatchSize.DWord:
SizeDropDown.SelectedIndex = 2;
break;
}
}
private void SetTypeSelected(Common.DisplayType type)
{
foreach (var item in DisplayTypeDropDown.Items)
{
if (item.ToString() == Watch.DisplayTypeToString(type))
{
DisplayTypeDropDown.SelectedItem = item;
return;
}
}
}
private void SetDomainSelected(Emu.MemoryDomain domain)
{
foreach (var item in DomainDropDown.Items)
{
if (item.ToString() == domain.Name)
{
DomainDropDown.SelectedItem = item;
return;
}
}
}
private void PopulateTypeDropdown()
{
DisplayTypeDropDown.Items.Clear();
switch (SizeDropDown.SelectedIndex)
{
default:
case 0:
foreach (DisplayType t in ByteWatch.ValidTypes)
{
DisplayTypeDropDown.Items.Add(Watch.DisplayTypeToString(t));
}
break;
case 1:
foreach (DisplayType t in WordWatch.ValidTypes)
{
DisplayTypeDropDown.Items.Add(Watch.DisplayTypeToString(t));
}
break;
case 2:
foreach (DisplayType t in DWordWatch.ValidTypes)
{
DisplayTypeDropDown.Items.Add(Watch.DisplayTypeToString(t));
}
break;
}
DisplayTypeDropDown.SelectedItem = DisplayTypeDropDown.Items[0];
}
private void CheckFormState()
{
var valid = !string.IsNullOrWhiteSpace(AddressBox.Text) && !string.IsNullOrWhiteSpace(ValueBox.Text);
AddButton.Enabled = valid;
EditButton.Enabled = _editmode && valid;
}
private void SizeDropDown_SelectedIndexChanged(object sender, EventArgs e)
{
if (!_loading)
{
PopulateTypeDropdown();
ValueBox.ByteSize =
CompareBox.ByteSize =
GetCurrentSize();
}
}
private void DomainDropDown_SelectedIndexChanged(object sender, EventArgs e)
{
if (!_loading)
{
var domain = MemoryDomains[DomainDropDown.SelectedItem.ToString()];
AddressBox.SetHexProperties(domain.Size);
}
}
private WatchSize GetCurrentSize()
{
switch (SizeDropDown.SelectedIndex)
{
default:
case 0:
return WatchSize.Byte;
case 1:
return WatchSize.Word;
case 2:
return WatchSize.DWord;
}
}
private void DisplayTypeDropDown_SelectedIndexChanged(object sender, EventArgs e)
{
ValueBox.Type =
CompareBox.Type =
Watch.StringToDisplayType(DisplayTypeDropDown.SelectedItem.ToString());
}
private void AddButton_Click(object sender, EventArgs e)
{
_addCallback?.Invoke();
}
private void EditButton_Click(object sender, EventArgs e)
{
_editCallback?.Invoke();
}
#endregion
#region API
public void SetCheat(Cheat cheat)
{
_editmode = true;
_cheat = cheat;
if (cheat.IsSeparator)
{
SetFormToDefault();
}
else
{
SetFormToCheat();
}
}
public void ClearForm()
{
_cheat = Cheat.Separator;
_editmode = false;
SetFormToDefault();
}
public Cheat OriginalCheat => _cheat;
public Cheat GetCheat()
{
var domain = MemoryDomains[DomainDropDown.SelectedItem.ToString()];
var address = AddressBox.ToRawInt().Value;
if (address < domain.Size)
{
var watch = Watch.GenerateWatch(
MemoryDomains[DomainDropDown.SelectedItem.ToString()],
AddressBox.ToRawInt().Value,
GetCurrentSize(),
Watch.StringToDisplayType(DisplayTypeDropDown.SelectedItem.ToString()),
BigEndianCheckBox.Checked,
NameBox.Text);
Cheat.CompareType comparisonType;
switch (CompareTypeDropDown.SelectedItem.ToString())
{
case "":
comparisonType = Cheat.CompareType.None;
break;
case "=":
comparisonType = Cheat.CompareType.Equal;
break;
case ">":
comparisonType = Cheat.CompareType.GreaterThan;
break;
case ">=":
comparisonType = Cheat.CompareType.GreaterThanOrEqual;
break;
case "<":
comparisonType = Cheat.CompareType.LessThan;
break;
case "<=":
comparisonType = Cheat.CompareType.LessThanOrEqual;
break;
case "!=":
comparisonType = Cheat.CompareType.NotEqual;
break;
default:
comparisonType = Cheat.CompareType.None;
break;
}
return new Cheat(
watch,
ValueBox.ToRawInt().Value,
CompareBox.ToRawInt() == null ? null : (int?)CompareBox.ToRawInt().Value,
true,
comparisonType);
}
else
{
MessageBox.Show(address + " is not a valid address for the domain " + domain.Name, "Index out of range", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return Cheat.Separator;
}
}
public void SetAddEvent(Action addCallback)
{
_addCallback = addCallback;
}
public void SetEditEvent(Action editCallback)
{
_editCallback = editCallback;
}
#endregion
private void CompareBox_TextChanged(object sender, EventArgs e)
{
WatchValueBox compareBox = (WatchValueBox)sender;
PopulateComparisonTypeBox(string.IsNullOrWhiteSpace(compareBox.Text));
}
/// <summary>
/// Populates the comparison type drop down
/// </summary>
/// <param name="empty">True if drop down should be left empty</param>
private void PopulateComparisonTypeBox(bool empty = false)
{
// Don't need to do anything in this case
if (empty && CompareTypeDropDown.Items.Count == 1)
{
return;
}
// Don't need to do anything in this case
if (!empty && CompareTypeDropDown.Items.Count == 6)
{
return;
}
CompareTypeDropDown.Items.Clear();
if (empty)
{
CompareTypeDropDown.Items.AddRange(new object[]
{
""
});
}
else
{
CompareTypeDropDown.Items.AddRange(new object[]
{
"=",
">",
">=",
"<",
"<=",
"!="
});
}
CompareTypeDropDown.SelectedIndex = 0;
}
}
}