using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; using System.Reflection; using System.Windows.Forms; using BizHawk.Client.ApiHawk; using BizHawk.Client.Common; using static BizHawk.Experiment.AutoGenConfig.ConfigEditorUIGenerators; namespace BizHawk.Experiment.AutoGenConfig { [ExternalTool("AutoGenConfig")] public class AutoGenConfigForm : Form, IExternalToolForm { private static readonly IList<(PropertyInfo, IConfigPropEditorUIGen)> CachedControlGenerators; public static ComparisonColors ComparisonColors = new ComparisonColors { Changed = Color.FromArgb(unchecked((int) 0xFF9F3F00)), ChangedInvalid = Color.DarkRed, ChangedUnset = Color.FromArgb(unchecked((int) 0xFF9F1F5F)), Unchanged = Color.FromArgb(unchecked((int) 0xFF00003F)), UnchangedDefault = Color.Black }; public static readonly IDictionary DefaultValues; static AutoGenConfigForm() { CachedControlGenerators = new List<(PropertyInfo, IConfigPropEditorUIGen)>(); DefaultValues = new Dictionary(); foreach (var pi in typeof(Config).GetProperties()) { CachedControlGenerators.Add((pi, FallbackGenerators.TryGetValue(pi.PropertyType, out var gen) ? gen : FinalFallbackGenerator)); DefaultValues[pi.Name] = pi.GetCustomAttributes(typeof(DefaultValueAttribute), false).FirstOrDefault() ?.Let(it => ((DefaultValueAttribute) it).Value) ?? TrueGenericDefault(pi.PropertyType); } } /// value types: default(T); ref types: calls default (no-arg) ctor if it exists, else null private static object? TrueGenericDefault(Type t) { try { return Activator.CreateInstance(t); } catch { return null; } } public readonly IDictionary BaselineValues = new Dictionary(); [RequiredApi] private IEmu? EmuHawkAPI { get; set; } public override string Text => "AutoGenConfig"; public bool UpdateBefore => false; public AutoGenConfigForm() { ClientSize = new Size(640, 720); SuspendLayout(); Controls.Add(new FlowLayoutPanel { Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right, BorderStyle = BorderStyle.FixedSingle, Controls = { new Label { AutoSize = true, Text = "Legend:" }, new Label { AutoSize = true, ForeColor = ComparisonColors.UnchangedDefault, Text = "default, unchanged" }, new Label { AutoSize = true, ForeColor = ComparisonColors.Unchanged, Text = "custom, unchanged" }, new Label { AutoSize = true, ForeColor = ComparisonColors.ChangedUnset, Text = "custom => default" }, new Label { AutoSize = true, ForeColor = ComparisonColors.ChangedInvalid, Text = "invalid" }, new Label { AutoSize = true, ForeColor = ComparisonColors.Changed, Text = "custom A => custom B" } }, Location = new Point(4, 4), Padding = new Padding(0, 4, 0, 0), Size = new Size(ClientSize.Width - 8, 24), WrapContents = false }); FlowLayoutPanel flpMain; Controls.Add(flpMain = new FlowLayoutPanel { Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, AutoScroll = true, FlowDirection = FlowDirection.TopDown, Location = new Point(4, 32), Size = new Size(ClientSize.Width - 8, ClientSize.Height - 64), WrapContents = false }); Controls.Add(new FlowLayoutPanel { Anchor = AnchorStyles.Bottom | AnchorStyles.Right, AutoScroll = true, AutoSize = true, Controls = { new Button { Size = new Size(128, 24), Text = "Discard Changes" }.Also(it => it.Click += (clickEventSender, clickEventArgs) => Close()), new Button { Size = new Size(128, 24), Text = "Review and Save..." }.Also(it => it.Click += (clickEventSender, clickEventArgs) => Close()) }, FlowDirection = FlowDirection.RightToLeft, Location = new Point(ClientSize.Width - 201, ClientSize.Height - 31), WrapContents = false }); Load += (loadEventSender, loadEventArgs) => { var config = (EmuHawkAPI as EmuApi ?? throw new Exception("required API wasn't fulfilled")).ForbiddenConfigReference; flpMain.Controls.AddRange(CachedControlGenerators.Select(it => it.Item2.GenerateControl(it.Item1, config, BaselineValues)).ToArray()); }; ResumeLayout(); } public bool AskSaveChanges() => true; public void FastUpdate() {} public void NewUpdate(ToolFormUpdateType type) {} public void Restart() {} public void UpdateValues() {} } }