using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using PKHeX.Core; namespace PKHeX.WinForms { public partial class TrashEditor : Form { private readonly SaveFile SAV; public TrashEditor(TextBoxBase TB_NN, byte[] raw, SaveFile sav) { SAV = sav; InitializeComponent(); bigendian = new[] { GameVersion.COLO, GameVersion.XD, GameVersion.BATREV, }.Contains(SAV.Version); WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage); FinalString = TB_NN.Text; Raw = FinalBytes = raw; editing = true; if (raw != null) AddTrashEditing(raw.Length); AddCharEditing(); TB_Text.MaxLength = TB_NN.MaxLength; TB_Text.Text = TB_NN.Text; TB_Text.Font = pkxFont; if (FLP_Characters.Controls.Count == 0) { FLP_Characters.Visible = false; FLP_Hex.Height *= 2; } else if (FLP_Hex.Controls.Count == 0) { FLP_Characters.Location = FLP_Hex.Location; FLP_Characters.Height *= 2; } editing = false; CenterToParent(); } private readonly List Bytes = new List(); private readonly Font pkxFont = FontUtil.GetPKXFont(12F); public string FinalString; public byte[] FinalBytes { get; private set; } private readonly byte[] Raw; private bool editing; private readonly bool bigendian; private void B_Cancel_Click(object sender, EventArgs e) => Close(); private void B_Save_Click(object sender, EventArgs e) { FinalString = TB_Text.Text; if (FinalBytes != null) FinalBytes = Raw; Close(); } private void AddCharEditing() { ushort[] chars = GetChars(SAV.Generation); if (chars.Length == 0) return; FLP_Characters.Visible = true; foreach (ushort c in chars) { var l = GetLabel((char)c+""); l.Font = pkxFont; l.AutoSize = false; l.Size = new Size(20, 20); l.Click += (s, e) => { if (TB_Text.Text.Length < TB_Text.MaxLength) TB_Text.AppendText(l.Text); }; FLP_Characters.Controls.Add(l); } } private void AddTrashEditing(int count) { FLP_Hex.Visible = true; GB_Trash.Visible = true; NUD_Generation.Value = SAV.Generation; Font courier = new Font("Courier New", 8); for (int i = 0; i < count; i++) { var l = GetLabel($"${i:X2}"); l.Font = courier; var n = GetNUD(hex: true, min: 0, max: 255); n.Click += (s, e) => { switch (ModifierKeys) { case Keys.Shift: n.Value = n.Maximum; break; case Keys.Alt: n.Value = n.Minimum; break; } }; n.Value = Raw[i]; n.ValueChanged += UpdateNUD; FLP_Hex.Controls.Add(l); FLP_Hex.Controls.Add(n); Bytes.Add(n); } TB_Text.TextChanged += UpdateString; CB_Species.DisplayMember = "Text"; CB_Species.ValueMember = "Value"; CB_Species.DataSource = new BindingSource(GameInfo.SpeciesDataSource, null); CB_Language.DisplayMember = "Text"; CB_Language.ValueMember = "Value"; var languages = Util.GetUnsortedCBList("languages"); if (SAV.Generation < 7) languages = languages.Where(l => l.Value <= 8).ToList(); // Korean CB_Language.DataSource = languages; } private void UpdateNUD(object sender, EventArgs e) { if (editing) return; editing = true; // build bytes var nud = sender as NumericUpDown; int index = Bytes.IndexOf(nud); Raw[index] = (byte)nud.Value; string str = StringConverter.GetString(Raw, SAV.Generation, SAV.Japanese, bigendian, Raw.Length); TB_Text.Text = str; editing = false; } private void UpdateString(object sender, EventArgs e) { if (editing) return; editing = true; // build bytes byte[] data = StringConverter.SetString(TB_Text.Text, SAV.Generation, SAV.Japanese, bigendian, Raw.Length, SAV.Language); Array.Copy(data, Raw, Math.Min(data.Length, Raw.Length)); for (int i = 0; i < Raw.Length; i++) Bytes[i].Value = Raw[i]; editing = false; } private void B_ApplyTrash_Click(object sender, EventArgs e) { string species = PKX.GetSpeciesNameGeneration(WinFormsUtil.GetIndex(CB_Species), WinFormsUtil.GetIndex(CB_Language), (int) NUD_Generation.Value); if (species == "") // no result species = CB_Species.Text; byte[] current = StringConverter.SetString(TB_Text.Text, SAV.Generation, SAV.Japanese, bigendian, Raw.Length, SAV.Language); byte[] data = StringConverter.SetString(species, SAV.Generation, SAV.Japanese, bigendian, Raw.Length, SAV.Language); if (data.Length <= current.Length) { WinFormsUtil.Alert("Trash byte layer is hidden by current text.", $"Current Bytes: {current.Length}" + Environment.NewLine + $"Layer Bytes: {data.Length}"); return; } if (data.Length > Bytes.Count) { WinFormsUtil.Alert("Trash byte layer is too long to apply."); return; } for (int i = current.Length; i < data.Length; i++) Bytes[i].Value = data[i]; } private void B_ClearTrash_Click(object sender, EventArgs e) { byte[] current = StringConverter.SetString(TB_Text.Text, SAV.Generation, SAV.Japanese, bigendian, Raw.Length, SAV.Language); for (int i = current.Length; i < Bytes.Count; i++) Bytes[i].Value = 0; } // Helpers private static Label GetLabel(string str) => new Label {Text = str, AutoSize = true}; private static NumericUpDown GetNUD(int min, int max, bool hex) => new NumericUpDown { Maximum = max, Minimum = min, Hexadecimal = hex, Width = 36, Padding = new Padding(0), Margin = new Padding(0), }; private static ushort[] GetChars(int generation) { switch (generation) { case 6: case 7: return chars67; default: return new ushort[0]; } } private static readonly ushort[] chars67 = { 0xE081, 0xE082, 0xE083, 0xE084, 0xE085, 0xE086, 0xE087, 0xE08D, 0xE08E, 0xE08F, 0xE090, 0xE091, 0xE092, 0xE093, 0xE094, 0xE095, 0xE096, 0xE097, 0xE098, 0xE099, 0xE09A, 0xE09B, 0xE09C, 0xE09D, 0xE09E, 0xE09F, 0xE0A0, 0xE0A1, 0xE0A2, 0xE0A3, 0xE0A4, 0xE0A5, }; } }