Skip to content

Commit

Permalink
Generic Choice Option extension and Enum limiting ability
Browse files Browse the repository at this point in the history
  • Loading branch information
MrPurple6411 committed Jan 8, 2023
1 parent b81b22b commit 505359a
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 121 deletions.
7 changes: 5 additions & 2 deletions Example mod/Mod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,11 @@ private void MyGenericValueChangedEvent<T>(ConfigOptionEventArgs<T> e)
case KeybindChangedEventArgs keybindChangedEventArgs:
ExampleMod.LogSource.LogInfo(KeyCodeUtils.KeyCodeToString(keybindChangedEventArgs.Value));
break;
case ChoiceChangedEventArgs choiceChangedEventArgs:
ExampleMod.LogSource.LogInfo($"{choiceChangedEventArgs.Value.Key}: {choiceChangedEventArgs.Value.Value}");
case ChoiceChangedEventArgs<int> choiceChangedEventArgs:
ExampleMod.LogSource.LogInfo($"{choiceChangedEventArgs.Index}: {choiceChangedEventArgs.Value}");
break;
case ChoiceChangedEventArgs<T> choiceChangedEventArgs:
ExampleMod.LogSource.LogInfo($"{choiceChangedEventArgs.Index}: {choiceChangedEventArgs.Value}");
break;
case SliderChangedEventArgs sliderChangedEventArgs:
ExampleMod.LogSource.LogInfo(sliderChangedEventArgs.Value.ToString());
Expand Down
10 changes: 5 additions & 5 deletions SMLHelper/Options/Attributes/ChoiceAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

/// <summary>
/// Attribute used to signify the decorated member should be represented in the mod's options menu as a
/// <see cref="ModChoiceOption"/>. Works for either <see cref="int"/> index-based, <see cref="string"/>-based, or
/// <see cref="ModChoiceOption{T}"/>. Works for either <see cref="int"/> index-based, <see cref="string"/>-based, or
/// <see cref="Enum"/>-based members.
/// </summary>
/// <remarks>
Expand All @@ -30,7 +30,7 @@
/// </code>
/// </example>
/// <seealso cref="MenuAttribute"/>
/// <seealso cref="ModChoiceOption"/>
/// <seealso cref="ModChoiceOption{T}"/>
/// <seealso cref="ConfigFile"/>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public sealed class ChoiceAttribute : ModOptionAttribute
Expand All @@ -42,7 +42,7 @@ public sealed class ChoiceAttribute : ModOptionAttribute

/// <summary>
/// Attribute used to signify the decorated member should be represented in the mod's options menu as a
/// <see cref="ModChoiceOption"/>. Works for either <see cref="int"/> index-based, <see cref="string"/>-based, or
/// <see cref="ModChoiceOption{T}"/>. Works for either <see cref="int"/> index-based, <see cref="string"/>-based, or
/// <see cref="Enum"/>-based members.
/// </summary>
/// <remarks>
Expand All @@ -57,7 +57,7 @@ public ChoiceAttribute(string label = null, params string[] options) : base(labe

/// <summary>
/// Attribute used to signify the decorated member should be represented in the mod's options menu as a
/// <see cref="ModChoiceOption"/>. Works for either <see cref="int"/> index-based, <see cref="string"/>-based, or
/// <see cref="ModChoiceOption{T}"/>. Works for either <see cref="int"/> index-based, <see cref="string"/>-based, or
/// <see cref="Enum"/>-based members.
/// </summary>
/// <remarks>
Expand All @@ -68,7 +68,7 @@ public ChoiceAttribute(string[] options) : this(null, options) { }

/// <summary>
/// Attribute used to signify the decorated member should be represented in the mod's options menu as a
/// <see cref="ModChoiceOption"/>. Works for either <see cref="int"/> index-based, <see cref="string"/>-based, or
/// <see cref="ModChoiceOption{T}"/>. Works for either <see cref="int"/> index-based, <see cref="string"/>-based, or
/// <see cref="Enum"/>-based members.
/// </summary>
public ChoiceAttribute() { }
Expand Down
22 changes: 11 additions & 11 deletions SMLHelper/Options/Attributes/ConfigFileMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,8 @@ public void HandleButtonClick(object sender, ButtonClickedEventArgs e)
/// to invoke any methods specified with an <see cref="OnChangeAttribute"/>.
/// </summary>
/// <param name="sender">The sender of the original choice changed event.</param>
/// <param name="e">The <see cref="ChoiceChangedEventArgs"/> for the choice changed event.</param>
public void HandleChoiceChanged(object sender, ChoiceChangedEventArgs e)
/// <param name="e">The <see cref="ChoiceChangedEventArgs{T}"/> for the choice changed event.</param>
public void HandleChoiceChanged(object sender, ChoiceChangedEventArgs<T> e)
{
if (TryGetMetadata(e.Id, out ModOptionAttributeMetadata<T> modOptionMetadata))
{
Expand All @@ -372,25 +372,25 @@ public void HandleChoiceChanged(object sender, ChoiceChangedEventArgs e)
if (memberInfoMetadata.ValueType.IsEnum && (choiceAttribute.Options == null || !choiceAttribute.Options.Any()))
{
// Enum-based choice where the values are parsed from the enum type
object value = Enum.Parse(memberInfoMetadata.ValueType, e.Value.Value);
object value = Enum.Parse(memberInfoMetadata.ValueType, e.Value.ToString());
memberInfoMetadata.SetValue(Config, value);
}
else if (memberInfoMetadata.ValueType.IsEnum)
{
// Enum-based choice where the values are defined as custom strings
object value = Enum.Parse(memberInfoMetadata.ValueType, Enum.GetNames(memberInfoMetadata.ValueType)[e.Value.Key]);
object value = Enum.Parse(memberInfoMetadata.ValueType, Enum.GetNames(memberInfoMetadata.ValueType)[e.Index]);
memberInfoMetadata.SetValue(Config, value);
}
else if (memberInfoMetadata.ValueType == typeof(string))
{
// string-based choice value
string value = e.Value.Value;
string value = e.Value.ToString();
memberInfoMetadata.SetValue(Config, value);
}
else if (memberInfoMetadata.ValueType == typeof(int))
{
// index-based choice value
int value = e.Value.Key;
int value = e.Index;
memberInfoMetadata.SetValue(Config, value);
}

Expand Down Expand Up @@ -544,8 +544,8 @@ private void InvokeOnChangeEvents(ModOptionAttributeMetadata<T> modOptionMetadat
// Enum-based choice where the values are parsed from the enum type
{
string[] options = Enum.GetNames(memberInfoMetadata.ValueType);
string value = memberInfoMetadata.GetValue(Config).ToString();
ChoiceChangedEventArgs eventArgs = new(id, new KeyValuePair<int, string>(Array.IndexOf(options, value), value));
var value = (T)memberInfoMetadata.GetValue(Config);
ChoiceChangedEventArgs<T> eventArgs = new(id, Array.IndexOf(options, value), value);
InvokeOnChangeEvents(modOptionMetadata, sender, eventArgs);
}
break;
Expand All @@ -554,7 +554,7 @@ private void InvokeOnChangeEvents(ModOptionAttributeMetadata<T> modOptionMetadat
{
string value = memberInfoMetadata.GetValue(Config).ToString();
int index = Math.Max(Array.IndexOf(Enum.GetValues(memberInfoMetadata.ValueType), value), 0);
ChoiceChangedEventArgs eventArgs = new(id, new KeyValuePair<int, string>(index, value));
ChoiceChangedEventArgs<string> eventArgs = new(id, index, value);
InvokeOnChangeEvents(modOptionMetadata, sender, eventArgs);
}
break;
Expand All @@ -563,7 +563,7 @@ private void InvokeOnChangeEvents(ModOptionAttributeMetadata<T> modOptionMetadat
{
string[] options = choiceAttribute.Options;
string value = memberInfoMetadata.GetValue<string>(Config);
ChoiceChangedEventArgs eventArgs = new(id, new KeyValuePair<int, string>(Array.IndexOf(options, value), value));
ChoiceChangedEventArgs<string> eventArgs = new(id, Array.IndexOf(options, value), value);
InvokeOnChangeEvents(modOptionMetadata, sender, eventArgs);
}
break;
Expand All @@ -572,7 +572,7 @@ private void InvokeOnChangeEvents(ModOptionAttributeMetadata<T> modOptionMetadat
{
string[] options = choiceAttribute.Options;
int index = memberInfoMetadata.GetValue<int>(Config);
ChoiceChangedEventArgs eventArgs = new(id, new KeyValuePair<int, string>(index, options[index]));
ChoiceChangedEventArgs<string> eventArgs = new(id, index, options[index]);
InvokeOnChangeEvents(modOptionMetadata, sender, eventArgs);
}
break;
Expand Down
6 changes: 3 additions & 3 deletions SMLHelper/Options/Attributes/OnChangeAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
/// The specified method can take the following parameters in any order:<br/>
/// - <see cref="object"/> sender: The sender of the event<br/>
/// - <see cref="EventArgs"/> eventArgs: The generalized event arguments of the event<br/>
/// - <see cref="ChoiceChangedEventArgs"/> choiceChangedEventArgs: Only when the member corresponds to a
/// <see cref="ModChoiceOption"/><br/>
/// - <see cref="ChoiceChangedEventArgs{T}"/> choiceChangedEventArgs: Only when the member corresponds to a
/// <see cref="ModChoiceOption{T}"/><br/>
/// - <see cref="KeybindChangedEventArgs"/> keybindChangedEventArgs: Only when the member correspends to a
/// <see cref="ModKeybindOption"/><br/>
/// - <see cref="SliderChangedEventArgs"/> sliderChangedEventArgs: Only when the member corresponds to a
Expand Down Expand Up @@ -68,7 +68,7 @@
/// <seealso cref="MenuAttribute"/>
/// <seealso cref="ToggleAttribute"/>
/// <seealso cref="EventArgs"/>
/// <seealso cref="ChoiceChangedEventArgs"/>
/// <seealso cref="ChoiceChangedEventArgs{T}"/>
/// <seealso cref="KeybindChangedEventArgs"/>
/// <seealso cref="SliderChangedEventArgs"/>
/// <seealso cref="ToggleChangedEventArgs"/>
Expand Down
12 changes: 6 additions & 6 deletions SMLHelper/Options/Attributes/OptionsMenuBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ private void RouteEventHandler(object sender, EventArgs e)
case ButtonClickedEventArgs buttonClickedEventArgs:
ConfigFileMetadata.HandleButtonClick(sender, buttonClickedEventArgs);
break;
case ChoiceChangedEventArgs choiceChangedEventArgs:
case ChoiceChangedEventArgs<T> choiceChangedEventArgs:
ConfigFileMetadata.HandleChoiceChanged(sender, choiceChangedEventArgs);
break;
case KeybindChangedEventArgs keybindChangedEventArgs:
Expand Down Expand Up @@ -172,7 +172,7 @@ private void BuildModButtonOption(string id, string label, MemberInfoMetadata<T>
}

/// <summary>
/// Adds a <see cref="ModChoiceOption"/> to the <see cref="ModOptions"/> menu.
/// Adds a <see cref="ModChoiceOption{T}"/> to the <see cref="ModOptions"/> menu.
/// </summary>
/// <param name="id"></param>
/// <param name="label"></param>
Expand All @@ -186,7 +186,7 @@ private void BuildModChoiceOption(string id, string label,
// Enum-based choice where the values are parsed from the enum type
string[] options = Enum.GetNames(memberInfoMetadata.ValueType);
string value = memberInfoMetadata.GetValue(ConfigFileMetadata.Config).ToString();
if(!AddItem(ModChoiceOption.Factory(id, label, options, value)))
if(!AddItem(ModChoiceOption<string>.Factory(id, label, options, value)))
InternalLogger.Warn($"Failed to add ModChoiceOption with id {id} to {Name}");

}
Expand All @@ -196,23 +196,23 @@ private void BuildModChoiceOption(string id, string label,
string[] options = choiceAttribute.Options;
string name = memberInfoMetadata.GetValue(ConfigFileMetadata.Config).ToString();
int index = Math.Max(Array.IndexOf(Enum.GetNames(memberInfoMetadata.ValueType), name), 0);
if(!AddItem(ModChoiceOption.Factory(id, label, options, index)))
if(!AddItem(ModChoiceOption<string>.Factory(id, label, options, index)))
InternalLogger.Warn($"Failed to add ModChoiceOption with id {id} to {Name}");
}
else if (memberInfoMetadata.ValueType == typeof(string))
{
// string-based choice value
string[] options = choiceAttribute.Options;
string value = memberInfoMetadata.GetValue<string>(ConfigFileMetadata.Config);
if(!AddItem(ModChoiceOption.Factory(id, label, options, value)))
if(!AddItem(ModChoiceOption<string>.Factory(id, label, options, value)))
InternalLogger.Warn($"Failed to add ModChoiceOption with id {id} to {Name}");
}
else if (memberInfoMetadata.ValueType == typeof(int))
{
// index-based choice value
string[] options = choiceAttribute.Options;
int index = memberInfoMetadata.GetValue<int>(ConfigFileMetadata.Config);
if(!AddItem(ModChoiceOption.Factory(id, label, options, index)))
if(!AddItem(ModChoiceOption<string>.Factory(id, label, options, index)))
InternalLogger.Warn($"Failed to add ModChoiceOption with id {id} to {Name}");
}
}
Expand Down
54 changes: 30 additions & 24 deletions SMLHelper/Options/ConfigEntryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using BepInEx.Configuration;
using SMLHelper.Utility;
using UnityEngine;

/// <summary>
Expand All @@ -16,7 +15,7 @@ public static class ConfigEntryExtensions
/// Converts a Bepinex ConfigEntry/<int/> into a ModSliderOption that will update the value when the slider changes.
/// </summary>
/// <param name="configEntry">A </param>
/// <returns><see cref="ModChoiceOption"/></returns>
/// <returns><see cref="ModToggleOption"/></returns>
public static ModToggleOption ToModToggleOption(this ConfigEntry<bool> configEntry)
{
ModToggleOption optionItem = ModToggleOption.Factory($"{configEntry.Definition.Section}_{configEntry.Definition.Key}",
Expand Down Expand Up @@ -266,43 +265,50 @@ public static ModKeybindOption ToModKeybindOption(this ConfigEntry<KeyCode> conf
}

/// <summary>
/// Converts a Bepinex ConfigEntry/<Enum/> into a ModChoiceOption that will update the value when the choice changes.
/// Converts an Enum ConfigEntry into a ModChoiceOption that will update the value when the choice changes.
/// </summary>
/// <param name="configEntry">A </param>
/// <param name="options">Array of valid options if not using the whole Enum</param>
/// <returns><see cref="ModKeybindOption"/></returns>
public static ModChoiceOption ToModChoiceOption<T>(this ConfigEntry<T> configEntry) where T : Enum
public static ModChoiceOption<T> ToModChoiceOption<T>(this ConfigEntry<T> configEntry, Array options = null) where T : Enum
{
ModChoiceOption optionItem = ModChoiceOption.Factory($"{configEntry.Definition.Section}_{configEntry.Definition.Key}",
configEntry.Definition.Key, configEntry.Value);
options ??= Enum.GetValues(typeof(T));
ModChoiceOption<T> optionItem = ModChoiceOption<T>.Factory($"{configEntry.Definition.Section}_{configEntry.Definition.Key}",
configEntry.Definition.Key, (T[])options, configEntry.Value);
optionItem.OnChanged += (_, e) =>
{
configEntry.Value = (T)Enum.Parse(typeof(T), e.Value.Value);
configEntry.Value = (T)Enum.Parse(typeof(T), e.Value.ToString());
};

return optionItem;
}

// TODO: Check for AcceptableValueList of *any* type, not sure how exactly to do it
//public static ModChoiceOption ToModChoiceOption<T>(this ConfigEntry<T> configEntry, T[] options = null, object defaultValue = null) where T : IEquatable<T>
//{
// ModChoiceOption optionItem;

// if (configEntry.Description.AcceptableValues is AcceptableValueList<T> valueList)
// options = valueList.AcceptableValues;
/// <summary>
/// Converts a ConfigEntry into a ModChoiceOption that will update the value when the choice changes.
/// </summary>
/// <param name="configEntry">A </param>
/// <param name="options"></param>
/// <returns><see cref="ModKeybindOption"/></returns>
public static ModChoiceOption<T> ToModChoiceOption<T>(this ConfigEntry<T> configEntry, T[] options = null) where T : IEquatable<T>
{
ModChoiceOption<T> optionItem;

// if (options == null)
// throw new ArgumentException("Could not get values from ConfigEntry");
if(configEntry.Description.AcceptableValues is AcceptableValueList<T> valueList)
options = valueList.AcceptableValues;

// optionItem = ModChoiceOption.Factory($"{configEntry.Definition.Section}_{configEntry.Definition.Key}",
// configEntry.Definition.Key, options.Cast<object>().ToArray(), defaultValue ?? options[0]);
if(options == null)
throw new ArgumentException("Could not get values from ConfigEntry");

// optionItem.OnChanged += (_, e) =>
// {
// configEntry.Value = e.Value.Value; // ERROR
// InternalLogger.Error("NOT DONE YET");
// };
optionItem = ModChoiceOption<T>.Factory($"{configEntry.Definition.Section}_{configEntry.Definition.Key}",
configEntry.Definition.Key, options, (T)configEntry.DefaultValue ?? options[0]);

// return optionItem;
//}
optionItem.OnChanged += (_, e) =>
{
configEntry.Value = (T)e.Value;
};

return optionItem;
}
}
}
Loading

0 comments on commit 505359a

Please sign in to comment.