From 5879cc8a18951e2d5557dae33879b9b0614ea096 Mon Sep 17 00:00:00 2001 From: Kurt Date: Wed, 29 May 2019 21:35:52 -0700 Subject: [PATCH] Extract some pkm gui logic probably won't stay this way if things are eventually rewritten; too much business logic in the pkmeditor.cs, would need a ton of abstraction --- PKHeX.Core/Editing/PKM/EditPKMUtil.cs | 30 ++++++ PKHeX.Core/Editing/PKM/LegalMoveSource.cs | 48 +++++++++ .../Controls/PKM Editor/PKMEditor.cs | 102 ++++++------------ 3 files changed, 112 insertions(+), 68 deletions(-) create mode 100644 PKHeX.Core/Editing/PKM/EditPKMUtil.cs create mode 100644 PKHeX.Core/Editing/PKM/LegalMoveSource.cs diff --git a/PKHeX.Core/Editing/PKM/EditPKMUtil.cs b/PKHeX.Core/Editing/PKM/EditPKMUtil.cs new file mode 100644 index 000000000..d4eeffed0 --- /dev/null +++ b/PKHeX.Core/Editing/PKM/EditPKMUtil.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Linq; +using static PKHeX.Core.MessageStrings; + +namespace PKHeX.Core +{ + public static class EditPKMUtil + { + public static List GetSuggestionMessage(PKM pkm, int level, int location, int minlvl) + { + var suggestion = new List { MsgPKMSuggestionStart }; + if (pkm.Format >= 3) + { + var met_list = GameInfo.GetLocationList((GameVersion)pkm.Version, pkm.Format, egg: false); + var locstr = met_list.First(loc => loc.Value == location).Text; + suggestion.Add($"{MsgPKMSuggestionMetLocation} {locstr}"); + suggestion.Add($"{MsgPKMSuggestionMetLevel} {level}"); + } + if (pkm.CurrentLevel < minlvl) + suggestion.Add($"{MsgPKMSuggestionLevel} {minlvl}"); + return suggestion; + } + + public static IReadOnlyList GetAbilityList(PKM pkm) + { + var abils = pkm.PersonalInfo.Abilities; + return GameInfo.GetAbilityList(abils, pkm.Format); + } + } +} diff --git a/PKHeX.Core/Editing/PKM/LegalMoveSource.cs b/PKHeX.Core/Editing/PKM/LegalMoveSource.cs new file mode 100644 index 000000000..e542fca3e --- /dev/null +++ b/PKHeX.Core/Editing/PKM/LegalMoveSource.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace PKHeX.Core +{ + public class LegalMoveSource + { + public readonly IList IsMoveBoxOrdered = new bool[4]; + public IReadOnlyList DataSource => (ComboItem[])MoveDataAllowed.Clone(); + public bool CanLearn(int move) => AllowedMoves.Contains(move); + + private readonly HashSet AllowedMoves = new HashSet(); + private ComboItem[] MoveDataAllowed = Array.Empty(); + + public void ReloadMoves(IReadOnlyList moves) + { + // check prior movepool to not needlessly refresh the dataset + if (AllowedMoves.Count == moves.Count && AllowedMoves.SetEquals(moves)) + return; + + AllowedMoves.Clear(); + foreach (var m in moves) + AllowedMoves.Add(m); + Array.Sort(MoveDataAllowed, Compare); + // MoveDataAllowed = MoveDataAllowed.OrderByDescending(m => AllowedMoves.Contains(m.Value)).ToArray(); + + // defer repop until dropdown is opened; handled by dropdown event + for (int i = 0; i < IsMoveBoxOrdered.Count; i++) + IsMoveBoxOrdered[i] = false; + } + + private int Compare(ComboItem i1, ComboItem i2) + { + // split into 2 groups: Allowed & Not, and sort each sublist + var c1 = AllowedMoves.Contains(i1.Value); + var c2 = AllowedMoves.Contains(i2.Value); + if (c1) + return c2 ? string.CompareOrdinal(i1.Text, i2.Text) : -1; + return c2 ? 1 : string.CompareOrdinal(i1.Text, i2.Text); + } + + public void ReloadMoves(IReadOnlyList moves) + { + MoveDataAllowed = moves.ToArray(); + } + } +} diff --git a/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs b/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs index cba502e30..7b458a5b4 100644 --- a/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs +++ b/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs @@ -109,7 +109,7 @@ public bool HideSecretValues private LegalityAnalysis Legality; private IReadOnlyList gendersymbols = GameInfo.GenderSymbolUnicode; private readonly Image mixedHighlight = ImageUtil.ChangeOpacity(Resources.slotSet, 0.5); - private HashSet AllowedMoves = new HashSet(); + private readonly LegalMoveSource LegalMoveSource = new LegalMoveSource(); public event EventHandler LegalityChanged; public event EventHandler UpdatePreviewSprite; @@ -290,34 +290,11 @@ public void UpdateLegality(LegalityAnalysis la = null, bool skipMoveRepop = fals return; // Resort moves FieldsLoaded = false; - ReloadMoves(Legality.AllSuggestedMovesAndRelearn); + LegalMoveSource.ReloadMoves(Legality.AllSuggestedMovesAndRelearn); FieldsLoaded = true; LegalityChanged?.Invoke(Legality.Valid, EventArgs.Empty); } - private IReadOnlyList MoveDataAllowed = new List(); - - private void ReloadMoves(IReadOnlyCollection moves) - { - // check prior movepool to not needlessly refresh the dataset - if (AllowedMoves.Count <= moves.Count && moves.All(AllowedMoves.Contains)) - return; - - AllowedMoves = new HashSet(moves); - MoveDataAllowed = GameInfo.Strings.MoveDataSource.OrderByDescending(m => AllowedMoves.Contains(m.Value)).ToList(); - - // defer repop until dropdown is opened; handled by dropdown event - for (int i = 0; i < IsMoveBoxOrdered.Count; i++) - IsMoveBoxOrdered[i] = false; - } - - private void SetMoveDataSource(ComboBox c) - { - var index = WinFormsUtil.GetIndex(c); - c.DataSource = new BindingSource(MoveDataAllowed, null); - c.SelectedValue = index; - } - public void UpdateUnicode(IReadOnlyList symbols) { gendersymbols = symbols; @@ -428,7 +405,7 @@ private void SetAbilityList() bool tmp = FieldsLoaded; FieldsLoaded = false; - CB_Ability.DataSource = GetAbilityList(pkm); + CB_Ability.DataSource = EditPKMUtil.GetAbilityList(pkm); CB_Ability.SelectedIndex = GetSafeIndex(CB_Ability, abil); // restore original index if available FieldsLoaded = tmp; } @@ -517,11 +494,8 @@ private void ClickLevel(object sender, EventArgs e) private void ClickGender(object sender, EventArgs e) { - // Get Gender Threshold - int gt = pkm.PersonalInfo.Gender; - - if (gt == 255 || gt == 0 || gt == 254) // Single gender/genderless - return; + if (!pkm.PersonalInfo.IsDualGender) + return; // can't toggle int newGender = (PKX.GetGenderFromString(Label_Gender.Text) & 1) ^ 1; if (pkm.Format <= 2) @@ -539,11 +513,11 @@ private void ClickGender(object sender, EventArgs e) TB_PID.Text = pkm.PID.ToString("X8"); } pkm.Gender = newGender; - Label_Gender.Text = gendersymbols[pkm.Gender]; - Label_Gender.ForeColor = Draw.GetGenderColor(pkm.Gender); + Label_Gender.Text = gendersymbols[newGender]; + Label_Gender.ForeColor = Draw.GetGenderColor(newGender); if (PKX.GetGenderFromString(CB_Form.Text) < 2) // Gendered Forms - CB_Form.SelectedIndex = PKX.GetGenderFromString(Label_Gender.Text); + CB_Form.SelectedIndex = Math.Min(newGender, CB_Form.Items.Count - 1); UpdatePreviewSprite(Label_Gender, EventArgs.Empty); } @@ -742,7 +716,7 @@ private bool SetSuggestedMetLocation(bool silent = false) if (!silent) { - var suggestions = GetSuggestionMessage(pkm, level, location, minlvl); + var suggestions = EditPKMUtil.GetSuggestionMessage(pkm, level, location, minlvl); if (suggestions.Count <= 1) // no suggestion return false; @@ -772,7 +746,7 @@ public void UpdateIVsGB(bool skipForm) return; Label_Gender.Text = gendersymbols[pkm.Gender]; Label_Gender.ForeColor = Draw.GetGenderColor(pkm.Gender); - if (pkm.Species == 201 && !skipForm) // Unown + if (pkm.Species == (int)Species.Unown && !skipForm) CB_Form.SelectedIndex = pkm.AltForm; UpdateIsShiny(); @@ -893,7 +867,7 @@ private void UpdateForm(object sender, EventArgs e) SetAbilityList(); // Gender Forms - if (WinFormsUtil.GetIndex(CB_Species) == 201 && FieldsLoaded) + if (WinFormsUtil.GetIndex(CB_Species) == (int)Species.Unown && FieldsLoaded) { if (pkm.Format == 3) { @@ -1530,30 +1504,42 @@ private void ValidateMovePaint(object sender, DrawItemEventArgs e) if (e.Index < 0) return; - var i = (ComboItem)((ComboBox)sender).Items[e.Index]; - var valid = AllowedMoves.Contains(i.Value) && !HaX; - var current = (e.State & DrawItemState.Selected) == DrawItemState.Selected; + var item = (ComboItem)((ComboBox)sender).Items[e.Index]; + var valid = LegalMoveSource.CanLearn(item.Value) && !HaX; - var rec = new Rectangle(e.Bounds.X - 1, e.Bounds.Y, e.Bounds.Width + 1, e.Bounds.Height + 0); // 1px left + var current = (e.State & DrawItemState.Selected) == DrawItemState.Selected; var brush = Draw.Brushes.GetBackground(valid, current); + var textColor = Draw.GetText(current); + + DrawMoveRectangle(e, brush, item.Text, textColor); + } + + private static void DrawMoveRectangle(DrawItemEventArgs e, Brush brush, string text, Color textColor) + { + var rec = new Rectangle(e.Bounds.X - 1, e.Bounds.Y, e.Bounds.Width + 1, e.Bounds.Height + 0); // 1px left e.Graphics.FillRectangle(brush, rec); const TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.EndEllipsis | TextFormatFlags.ExpandTabs | TextFormatFlags.SingleLine; - TextRenderer.DrawText(e.Graphics, i.Text, e.Font, rec, Draw.GetText(current), flags); + TextRenderer.DrawText(e.Graphics, text, e.Font, rec, textColor, flags); } private void MeasureDropDownHeight(object sender, MeasureItemEventArgs e) => e.ItemHeight = CB_RelearnMove1.ItemHeight; - private readonly IList IsMoveBoxOrdered = new bool[4]; - private void ValidateMoveDropDown(object sender, EventArgs e) { var s = (ComboBox) sender; var index = Array.IndexOf(Moves, s); - if (IsMoveBoxOrdered[index]) + if (LegalMoveSource.IsMoveBoxOrdered[index]) return; SetMoveDataSource(s); - IsMoveBoxOrdered[index] = true; + LegalMoveSource.IsMoveBoxOrdered[index] = true; + } + + private void SetMoveDataSource(ComboBox c) + { + var index = WinFormsUtil.GetIndex(c); + c.DataSource = new BindingSource(LegalMoveSource.DataSource, null); + c.SelectedValue = index; } private void ValidateLocation(object sender, EventArgs e) @@ -1786,32 +1772,12 @@ private void PopulateFilteredDataSources(SaveFile sav) CB_GameOrigin.DataSource = new BindingSource(GameInfo.VersionDataSource.Where(g => gamelist.Contains((GameVersion)g.Value)).ToList(), null); // Set the Move ComboBoxes too.. - MoveDataAllowed = GameInfo.Strings.MoveDataSource = (HaX ? GameInfo.HaXMoveDataSource : GameInfo.LegalMoveDataSource).Where(m => m.Value <= sav.MaxMoveID).ToList(); // Filter Z-Moves if appropriate + GameInfo.Strings.MoveDataSource = (HaX ? GameInfo.HaXMoveDataSource : GameInfo.LegalMoveDataSource).Where(m => m.Value <= sav.MaxMoveID).ToList(); // Filter Z-Moves if appropriate + LegalMoveSource.ReloadMoves(GameInfo.Strings.MoveDataSource); foreach (var cb in Moves.Concat(Relearn)) { cb.DataSource = new BindingSource(GameInfo.MoveDataSource, null); } } - - private static List GetSuggestionMessage(PKM pkm, int level, int location, int minlvl) - { - var suggestion = new List { MsgPKMSuggestionStart }; - if (pkm.Format >= 3) - { - var met_list = GameInfo.GetLocationList((GameVersion)pkm.Version, pkm.Format, egg: false); - var locstr = met_list.First(loc => loc.Value == location).Text; - suggestion.Add($"{MsgPKMSuggestionMetLocation} {locstr}"); - suggestion.Add($"{MsgPKMSuggestionMetLevel} {level}"); - } - if (pkm.CurrentLevel < minlvl) - suggestion.Add($"{MsgPKMSuggestionLevel} {minlvl}"); - return suggestion; - } - - private static IReadOnlyList GetAbilityList(PKM pkm) - { - var abils = pkm.PersonalInfo.Abilities; - return GameInfo.GetAbilityList(abils, pkm.Format); - } } }