/* * Copyright 2022 Peter Han * Permission is hereby granted, free of charge, to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ using System; using System.Collections.Generic; using System.Reflection; using PeterHan.PLib.UI; using UnityEngine; namespace PeterHan.PLib.Options { /// /// An options entry which represents Enum and displays a spinner with text options. /// public class SelectOneOptionsEntry : OptionsEntry { /// /// Obtains the title and tool tip for an enumeration value. /// /// The value in the enumeration. /// The type of the Enum field. /// The matching Option private static EnumOption GetAttribute(object enumValue, Type fieldType) { if (enumValue == null) throw new ArgumentNullException(nameof(enumValue)); string valueName = enumValue.ToString(), title = valueName, tooltip = ""; foreach (var enumField in fieldType.GetMember(valueName, BindingFlags.Public | BindingFlags.Static)) if (enumField.DeclaringType == fieldType) { // Search for OptionsAttribute foreach (var attrib in enumField.GetCustomAttributes(false)) if (attrib is IOptionSpec spec) { if (string.IsNullOrEmpty(spec.Title)) spec = HandleDefaults(spec, enumField); title = LookInStrings(spec.Title); tooltip = LookInStrings(spec.Tooltip); break; } break; } return new EnumOption(title, tooltip, enumValue); } public override object Value { get { return chosen?.Value; } set { // Find a matching value, if possible string valueStr = value?.ToString() ?? ""; foreach (var option in options) if (valueStr == option.Value.ToString()) { chosen = option; Update(); break; } } } /// /// The chosen item in the array. /// protected EnumOption chosen; /// /// The realized item label. /// private GameObject comboBox; /// /// The available options to cycle through. /// protected readonly IList options; public SelectOneOptionsEntry(string field, IOptionSpec spec, Type fieldType) : base(field, spec) { var eval = Enum.GetValues(fieldType); if (eval == null) throw new ArgumentException("No values, or invalid values, for enum"); int n = eval.Length; if (n == 0) throw new ArgumentException("Enum has no declared members"); chosen = null; comboBox = null; options = new List(n); for (int i = 0; i < n; i++) options.Add(GetAttribute(eval.GetValue(i), fieldType)); } public override GameObject GetUIComponent() { // Find largest option to size the label appropriately, using em width this time! EnumOption firstOption = null; int maxLen = 0; foreach (var option in options) { int len = option.Title?.Trim()?.Length ?? 0; // Kerning each string is slow, so estimate based on em width instead if (firstOption == null && len > 0) firstOption = option; if (len > maxLen) maxLen = len; } comboBox = new PComboBox("Select") { BackColor = PUITuning.Colors.ButtonPinkStyle, InitialItem = firstOption, Content = options, EntryColor = PUITuning.Colors.ButtonBlueStyle, TextStyle = PUITuning.Fonts.TextLightStyle, OnOptionSelected = UpdateValue, }.SetMinWidthInCharacters(maxLen).Build(); Update(); return comboBox; } /// /// Updates the displayed text to match the current item. /// private void Update() { if (comboBox != null && chosen != null) PComboBox.SetSelectedItem(comboBox, chosen, false); } /// /// Triggered when the value chosen from the combo box has been changed. /// /// The value selected by the user. private void UpdateValue(GameObject _, EnumOption selected) { if (selected != null) chosen = selected; } /// /// Represents a selectable option. /// protected sealed class EnumOption : ITooltipListableOption { /// /// The option title. /// public string Title { get; } /// /// The option tool tip. /// public string ToolTip { get; } /// /// The value to assign if this option is chosen. /// public object Value { get; } public EnumOption(string title, string toolTip, object value) { Title = title ?? throw new ArgumentNullException(nameof(title)); ToolTip = toolTip; Value = value; } public string GetProperName() { return Title; } public string GetToolTipText() { return ToolTip; } public override string ToString() { return string.Format("Option[Title={0},Value={1}]", Title, Value); } } } }