add local setting buttons

This commit is contained in:
xChipseq committed 2025-09-01 23:34:17 +02:00
1 parent 6b37b9c09c
commit 1f6962efe9
7 files changed
+182 -12

No files matched your search

+10 -2
View File
@@ -2,6 +2,7 @@
using MiraAPI.LocalSettings;
using MiraAPI.LocalSettings.Attributes;
using MiraAPI.Utilities;
using Reactor.Utilities;
using UnityEngine;
namespace MiraAPI.Example;
@@ -13,11 +14,13 @@ public class ExampleLocalSettings(ConfigFile config) : LocalSettingsTab(config)
public override LocalSettingTabAppearance TabAppearance => new()
{
TabColor = Color.cyan,
ToggleActiveColor = Color.blue,
ToggleInactiveColor = Color.red,
};
[LocalSettingsButton]
public LocalSettingsButton ExampleButton { get; private set; } = new("Example Button", OnExampleButtonClick);
[LocalToggleSetting]
public ConfigEntry<bool> ExampleToggle { get; private set; } = config.Bind("General", "Example Bool", true);
@@ -32,6 +35,11 @@ public class ExampleLocalSettings(ConfigFile config) : LocalSettingsTab(config)
[LocalEnumSetting]
public ConfigEntry<ExampleEnumSetting> ExampleEnum { get; private set; } = config.Bind("General", "Example Enum", ExampleEnumSetting.Fries);
private static void OnExampleButtonClick(LocalSettingsTab instance)
{
Logger<ExamplePlugin>.Warning("Button clicked");
}
}
public enum ExampleEnumSetting
@@ -40,4 +48,4 @@ public enum ExampleEnumSetting
Sandwich,
Fries,
ChickenNuggets,
}
}
@@ -0,0 +1,12 @@
using System;
using BepInEx.Configuration;
namespace MiraAPI.LocalSettings.Attributes;
/// <summary>
/// Attribute for local setting buttons.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class LocalSettingsButtonAttribute : Attribute
{
}
@@ -0,0 +1,80 @@
using System;
using MiraAPI.Utilities;
using Reactor.Localization.Utilities;
using Reactor.Utilities.Extensions;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using Object = UnityEngine.Object;
namespace MiraAPI.LocalSettings;
/// <summary>
/// Represents a local settings button.
/// </summary>
public class LocalSettingsButton(string text, Action<LocalSettingsTab> onClick)
{
/// <summary>
/// Gets or sets the button text.
/// </summary>
public string Text { get; set; } = text;
/// <summary>
/// Gets or sets the button on-click action.
/// </summary>
public Action<LocalSettingsTab> OnClick { get; set; } = onClick;
/// <summary>
/// Gets the tab instance this button belongs to.
/// </summary>
public LocalSettingsTab Tab { get; internal set; }
internal GameObject CreateButton(ToggleButtonBehaviour toggle, Transform parent, ref float offset, ref int order, bool last)
{
var button = Object.Instantiate(toggle, parent).GetComponent<PassiveButton>();
var tmp = button.transform.FindChild("Text_TMP").GetComponent<TextMeshPro>();
var rollover = button.GetComponent<ButtonRolloverHandler>();
tmp.GetComponent<TextTranslatorTMP>().Destroy();
button.gameObject.SetActive(true);
var toggleComp = button.GetComponent<ToggleButtonBehaviour>();
var background = toggleComp.Background;
button.transform.FindChild("ButtonHighlight")?.gameObject.DestroyImmediate();
toggleComp.Destroy();
if (last && order == 1)
{
// Button in the middle
button.transform.localPosition = new Vector3(0, 1.85f - offset, -7);
}
else
{
button.transform.localPosition = new Vector3(order == 1 ? -1.185f : 1.185f, 1.85f - offset, -7);
}
tmp.text = Text;
button.name = Text;
button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
rollover.OutColor = Tab!.TabAppearance.ButtonColor;
rollover.OverColor = Tab!.TabAppearance.ButtonHoverColor;
rollover.Target = background;
background.color = Tab!.TabAppearance.ButtonColor;
var tab = Tab;
var click = OnClick;
button.OnClick.AddListener((UnityAction)(() => click(tab)));
Helpers.DivideSize(button.gameObject, 1.1f);
order++;
if (order > 2 && !last)
{
offset += 0.5f;
order = 1;
}
if (last)
offset += 0.6f;
return button.gameObject;
}
}
+55 -5
View File
@@ -42,11 +42,32 @@ public abstract class LocalSettingsTab(ConfigFile config)
/// </summary>
public ConfigFile Config { get; } = config ?? throw new ArgumentNullException(nameof(config));
internal TabGroup? TabButton { get; set; }
internal List<ILocalSetting> Settings { get; } = [];
/// <summary>
/// Gets the tab button instance.
/// </summary>
public TabGroup? TabButton { get; internal set; }
/// <summary>
/// Gets the list of settings.
/// </summary>
public List<ILocalSetting> Settings { get; } = [];
/// <summary>
/// Gets the list of buttons.
/// </summary>
public List<LocalSettingsButton> Buttons { get; } = [];
private Scroller? Scroller { get; set; }
internal GameObject CreateTab(OptionsMenuBehaviour instance)
/// <summary>
/// Invoked when an option value is changed.
/// </summary>
/// <param name="configEntry">The config entry which was changed.</param>
public virtual void OnOptionChanged(ConfigEntryBase configEntry)
{
}
public virtual GameObject CreateTab(OptionsMenuBehaviour instance)
{
var tab = Object.Instantiate(instance.transform.FindChild("GeneralTab").gameObject, instance.transform);
tab.name = $"{TabName}Tab";
@@ -120,11 +141,40 @@ public abstract class LocalSettingsTab(ConfigFile config)
contentOrder = 1;
}
Scroller.SetBounds(new FloatRange(0, Settings.Count * 0.5f - 5f), new FloatRange(0, 0));
contentIndex = 0;
contentOrder = 1;
foreach (var button in Buttons)
{
var obj = button.CreateButton(
toggle,
Scroller.Inner,
ref contentOffset,
ref contentOrder,
contentIndex == Buttons.Count);
obj!.GetComponentsInChildren<SpriteRenderer>(true).Do(x =>
{
x.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
x.sortingOrder = 150;
x.sortingLayerName = "Default";
});
obj.GetComponentsInChildren<MeshRenderer>(true).Do(x =>
{
x.sortingOrder = 151;
x.sortingLayerName = "Default";
});
obj.GetComponentsInChildren<PassiveButton>().Do(x => { x.ClickMask = OptionsMenuPatches.MaskCollider; });
contentIndex++;
}
Scroller.SetBounds(new FloatRange(0, (Settings.Count + Buttons.Count) * 0.5f - 5f), new FloatRange(0, 0));
return tab;
}
internal GameObject CreateTabButton(OptionsMenuBehaviour instance, ref int tabIdx, ref float offset)
public virtual GameObject CreateTabButton(OptionsMenuBehaviour instance, ref int tabIdx, ref float offset)
{
var tabButtonObject = Object.Instantiate(instance.Tabs[0], instance.transform);
tabButtonObject.name = $"{TabName} Button";
@@ -78,4 +78,14 @@ public record struct LocalSettingTabAppearance()
/// Gets or sets hover color of enum buttons.
/// </summary>
public Color EnumHoverColor { get; set; } = Palette.AcceptedGreen;
/// <summary>
/// Gets or sets color of buttons.
/// </summary>
public Color ButtonColor { get; set; } = Color.white;
/// <summary>
/// Gets or sets hover color of buttons.
/// </summary>
public Color ButtonHoverColor { get; set; } = Palette.AcceptedGreen;
}
@@ -68,5 +68,6 @@ public abstract class LocalSettingBase<T> : ILocalSetting
public void SetValue(T value)
{
ConfigEntry.BoxedValue = value;
Tab?.OnOptionChanged(ConfigEntry);
}
}
+14 -5
View File
@@ -344,6 +344,20 @@ public sealed class MiraPluginManager
foreach (var property in type.GetProperties())
{
if (LocalSettingsManager.TypeToTab[type] is not { } tabInstance)
{
continue;
}
if (property.GetCustomAttribute<LocalSettingsButtonAttribute>() != null &&
property.PropertyType.IsAssignableTo(typeof(LocalSettingsButton)))
{
var button = property.GetValue(tabInstance) as LocalSettingsButton;
button!.Tab = tabInstance;
tabInstance.Buttons.Add(button);
continue;
}
if (!typeof(ConfigEntryBase).IsAssignableFrom(property.PropertyType))
{
continue;
@@ -355,11 +369,6 @@ public sealed class MiraPluginManager
continue;
}
if (LocalSettingsManager.TypeToTab[type] is not { } tabInstance)
{
continue;
}
if (property.GetValue(tabInstance) is not ConfigEntryBase configEntry)
{
Logger<MiraApiPlugin>.Error($"Option property {property.Name} in {type.Name} has to be a config entry.");