using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using BizHawk.Client.Common; using Emu = BizHawk.Emulation.Common; namespace BizHawk.Client.EmuHawk { public partial class WatchEditor : Form { public enum Mode { New, Duplicate, Edit } public Emu.IMemoryDomains MemoryDomains { get; set; } private Mode _mode = Mode.New; private bool _loading = true; private bool _changedSize; private bool _changedDisplayType; public List Watches { get; } = new List(); public Point InitialLocation { get; set; } = new Point(0, 0); public WatchEditor() { _changedDisplayType = false; InitializeComponent(); } private void RamWatchNewWatch_Load(object sender, EventArgs e) { if (InitialLocation.X > 0 || InitialLocation.Y > 0) { Location = InitialLocation; } _loading = false; SetAddressBoxProperties(); switch (_mode) { default: case Mode.New: switch (MemoryDomains.First().WordSize) { default: case 1: SizeDropDown.SelectedItem = SizeDropDown.Items[0]; break; case 2: SizeDropDown.SelectedItem = SizeDropDown.Items[1]; break; case 4: SizeDropDown.SelectedItem = SizeDropDown.Items[2]; break; } break; case Mode.Duplicate: case Mode.Edit: switch (Watches[0].Size) { case WatchSize.Byte: SizeDropDown.SelectedItem = SizeDropDown.Items[0]; break; case WatchSize.Word: SizeDropDown.SelectedItem = SizeDropDown.Items[1]; break; case WatchSize.DWord: SizeDropDown.SelectedItem = SizeDropDown.Items[2]; break; } var index = DisplayTypeDropDown.Items.IndexOf(Watch.DisplayTypeToString(Watches[0].Type)); DisplayTypeDropDown.SelectedItem = DisplayTypeDropDown.Items[index]; if (Watches.Count > 1) { NotesBox.Enabled = false; NotesBox.Text = ""; AddressBox.Enabled = false; AddressBox.Text = Watches.Select(a => a.AddressString).Aggregate((addrStr, nextStr) => $"{addrStr},{nextStr}"); BigEndianCheckBox.ThreeState = true; if (Watches.Select(s => s.Size).Distinct().Count() > 1) { DisplayTypeDropDown.Enabled = false; } } else { NotesBox.Text = Watches[0].Notes; AddressBox.SetFromLong(Watches[0].Address); } SetBigEndianCheckBox(); DomainDropDown.Enabled = false; break; } } public void SetWatch(Emu.MemoryDomain domain, IEnumerable watches = null, Mode mode = Mode.New) { if (watches != null) { Watches.AddRange(watches); } _mode = mode; DomainDropDown.Items.Clear(); DomainDropDown.Items.AddRange(MemoryDomains .Select(d => d.ToString()) .Cast() .ToArray()); DomainDropDown.SelectedItem = domain.ToString(); SetTitle(); } private void SetTitle() { switch (_mode) { default: case Mode.New: Text = "New Watch"; break; case Mode.Edit: Text = $"Edit {(Watches.Count == 1 ? "Watch" : "Watches")}"; break; case Mode.Duplicate: Text = "Duplicate Watch"; break; } } private void SetAddressBoxProperties() { if (!_loading) { var domain = MemoryDomains.FirstOrDefault(d => d.Name == DomainDropDown.SelectedItem.ToString()); if (domain != null) { AddressBox.SetHexProperties(domain.Size); } } } private void SetDisplayTypes() { string oldType = DisplayTypeDropDown.Text; 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.Contains(oldType) ? oldType : DisplayTypeDropDown.Items[0]; } private void SetBigEndianCheckBox() { if (Watches.Count > 1) { // Aggregate state var hasBig = Watches.Any(x => x.BigEndian); var hasLittle = Watches.Any(x => x.BigEndian == false); if (hasBig && hasLittle) { BigEndianCheckBox.Checked = true; BigEndianCheckBox.CheckState = CheckState.Indeterminate; } else if (hasBig) { BigEndianCheckBox.Checked = true; } else { BigEndianCheckBox.Checked = false; } } else if (Watches.Count == 1) { BigEndianCheckBox.Checked = Watches[0].BigEndian; return; } var domain = MemoryDomains.FirstOrDefault(d => d.Name == DomainDropDown.SelectedItem.ToString()) ?? MemoryDomains.MainMemory; BigEndianCheckBox.Checked = domain.EndianType == Emu.MemoryDomain.Endian.Big; } #region Events private void Cancel_Click(object sender, EventArgs e) { DialogResult = DialogResult.Cancel; Close(); } private void Ok_Click(object sender, EventArgs e) { DialogResult = DialogResult.OK; switch (_mode) { default: case Mode.New: var domain = MemoryDomains.FirstOrDefault(d => d.Name == DomainDropDown.SelectedItem.ToString()); var address = AddressBox.ToLong() ?? 0; var notes = NotesBox.Text; var type = Watch.StringToDisplayType(DisplayTypeDropDown.SelectedItem.ToString()); var bigEndian = BigEndianCheckBox.Checked; switch (SizeDropDown.SelectedIndex) { case 0: Watches.Add(Watch.GenerateWatch(domain, address, WatchSize.Byte, type, bigEndian, notes)); break; case 1: Watches.Add(Watch.GenerateWatch(domain, address, WatchSize.Word, type, bigEndian, notes)); break; case 2: Watches.Add(Watch.GenerateWatch(domain, address, WatchSize.DWord, type, bigEndian, notes)); break; } break; case Mode.Edit: DoEdit(); break; case Mode.Duplicate: var tempWatchList = new List(); tempWatchList.AddRange(Watches); Watches.Clear(); foreach (var watch in tempWatchList) { Watches.Add(Watch.GenerateWatch( watch.Domain, watch.Address, watch.Size, watch.Type, watch.BigEndian, watch.Notes)); } DoEdit(); break; } Close(); } private void DoEdit() { if (Watches.Count == 1) { Watches[0].Notes = NotesBox.Text; } if (_changedSize) { for (var i = 0; i < Watches.Count; i++) { var size = WatchSize.Byte; switch (SizeDropDown.SelectedIndex) { case 0: size = WatchSize.Byte; break; case 1: size = WatchSize.Word; break; case 2: size = WatchSize.DWord; break; } Watches[i] = Watch.GenerateWatch( Watches[i].Domain, Watches.Count == 1 ? AddressBox.ToRawInt() ?? 0 : Watches[i].Address, size, Watches[i].Type, Watches[i].BigEndian, Watches[i].Notes); } } if (_changedDisplayType) { Watches.ForEach(x => x.Type = Watch.StringToDisplayType(DisplayTypeDropDown.SelectedItem.ToString())); } if (BigEndianCheckBox.CheckState != CheckState.Indeterminate) { Watches.ForEach(x => x.BigEndian = BigEndianCheckBox.Checked); } } private void DomainComboBox_SelectedIndexChanged(object sender, EventArgs e) { SetAddressBoxProperties(); SetBigEndianCheckBox(); _changedSize = true; _changedDisplayType = true; } private void SizeDropDown_SelectedIndexChanged(object sender, EventArgs e) { SetDisplayTypes(); _changedSize = true; if (!DisplayTypeDropDown.Enabled) { DisplayTypeDropDown.Enabled = true; _changedDisplayType = true; } } private void DisplayTypeDropDown_SelectedIndexChanged(object sender, EventArgs e) { _changedDisplayType = true; } #endregion } }