diff --git a/Data/DoubleLimit.cs b/Data/DoubleLimit.cs
deleted file mode 100644
index dd45b3d..0000000
--- a/Data/DoubleLimit.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-namespace ADOFAIRenderer.Data;
-
-///
-/// Base class for double input validation limits.
-/// Multiple limits can be composed on a single input field — all are checked in order.
-///
-internal abstract class DoubleLimit
-{
- ///
- /// Validates the given double value against this limit.
- ///
- /// The parsed double value to validate.
- ///
- /// When validation fails, set to a human-readable error message.
- /// When validation succeeds, set to null.
- ///
- /// true if the value satisfies this limit; false otherwise.
- public abstract bool Validate(double value, out string errorMessage);
-}
-
-///
-/// Requires the double value to be strictly positive (> 0).
-///
-internal class PositiveOnlyDoubleLimit : DoubleLimit
-{
- public override bool Validate(double value, out string errorMessage)
- {
- if (value > 0)
- {
- errorMessage = null!;
- return true;
- }
-
- errorMessage = "Value must be a positive number greater than 0.";
- return false;
- }
-}
-
-///
-/// Requires the double value to be within an inclusive [Min, Max] range.
-/// Either bound can be null to represent an unbounded side.
-///
-internal class RangeDoubleLimit : DoubleLimit
-{
- // ReSharper disable MemberCanBePrivate.Global
- public double? Min { get; }
- public double? Max { get; }
- // ReSharper restore MemberCanBePrivate.Global
-
- /// Inclusive lower bound, or null for no lower bound.
- /// Inclusive upper bound, or null for no upper bound.
- public RangeDoubleLimit(double? min, double? max)
- {
- Min = min;
- Max = max;
- }
-
- public override bool Validate(double value, out string errorMessage)
- {
- if (value < Min)
- {
- errorMessage = Max.HasValue
- ? $"Value must be a number between {Min.Value} and {Max.Value}."
- : $"Value must be a number greater than or equal to {Min.Value}.";
- return false;
- }
-
- if (value > Max)
- {
- errorMessage = Min.HasValue
- ? $"Value must be a number between {Min.Value} and {Max.Value}."
- : $"Value must be a number less than or equal to {Max.Value}.";
- return false;
- }
-
- errorMessage = null!;
- return true;
- }
-}
\ No newline at end of file
diff --git a/Data/Input/DoubleInputValidator.cs b/Data/Input/DoubleInputValidator.cs
deleted file mode 100644
index f5bb42f..0000000
--- a/Data/Input/DoubleInputValidator.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using MelonLoader;
-using UnityEngine.UIElements;
-
-namespace ADOFAIRenderer.Data.Input;
-
-internal class DoubleInputValidator
-{
- private struct FieldEntry
- {
- public List Limits;
- }
-
- private readonly VisualElement _rootVisualElement;
- private readonly Dictionary _fields = new();
-
- public DoubleInputValidator(VisualElement rootVisualElement)
- {
- _rootVisualElement = rootVisualElement;
- }
-
- ///
- /// Registers one or more s for the field with the given name.
- /// Multiple limits can be added to the same field — they are all checked in order.
- ///
- /// The name of the DoubleField in the UXML.
- /// The limits to apply.
- public DoubleInputValidator AddLimits(string fieldName, params DoubleLimit[] limits)
- {
- if (!_fields.TryGetValue(fieldName, out var entry))
- {
- entry = new FieldEntry
- {
- Limits = new List()
- };
- }
-
- entry.Limits.AddRange(limits);
- _fields[fieldName] = entry;
- return this;
- }
-
- ///
- /// Queries all registered fields from the root VisualElement and
- /// registers value-changed callbacks that rollback invalid values.
- ///
- public void SetupValidation()
- {
- foreach (var (fieldName, entry) in _fields)
- {
- var field = _rootVisualElement.Q(fieldName);
- if (field == null)
- {
- Melon.Logger.Warning(
- $"DoubleField '{fieldName}' not found. Skipping validation.");
- continue;
- }
-
- var limits = entry.Limits;
-
- field.RegisterValueChangedCallback(evt =>
- {
- if (string.IsNullOrEmpty(field.text))
- {
- return;
- }
-
- if (limits.Any(limit => !limit.Validate(evt.newValue, out _)))
- {
- field.SetValueWithoutNotify(evt.previousValue);
- }
- });
- }
- }
-}
\ No newline at end of file
diff --git a/Data/Input/EnumDropdownBinder.cs b/Data/Input/EnumDropdownBinder.cs
deleted file mode 100644
index 6e4d3cc..0000000
--- a/Data/Input/EnumDropdownBinder.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using MelonLoader;
-using UnityEngine.UIElements;
-
-namespace ADOFAIRenderer.Data.Input;
-
-///
-/// Binds a UI Toolkit to an enum type.
-/// Populates choices from enum names and provides typed access to the selected value.
-///
-/// The enum type to bind.
-[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
-internal class EnumDropdownBinder where T : struct, Enum
-{
- private readonly DropdownField? _dropdown;
- private readonly List _values;
- private Action? _onValueChanged;
-
- ///
- /// The currently selected enum value.
- ///
- public T Value => _dropdown is { index: >= 0 } && _dropdown.index < _values.Count
- ? _values[_dropdown.index]
- : default;
-
- ///
- /// Queries a by name from the root VisualElement,
- /// populates it with enum names, and selects the default value.
- ///
- /// The root VisualElement loaded from the UXML bundle.
- /// The name of the DropdownField in the UXML.
- /// The initial selected value. Defaults to the first enum member.
- public EnumDropdownBinder(VisualElement rootVisualElement, string fieldName, T? defaultValue = null)
- {
- _values = Enum.GetValues(typeof(T)).Cast().ToList();
-
- _dropdown = rootVisualElement.Q(fieldName);
- if (_dropdown == null)
- {
- Melon.Logger.Error(
- $"DropdownField '{fieldName}' not found.");
- return;
- }
-
- _dropdown.choices = _values.Select(v => v.ToString()).ToList();
-
- // Register the callback BEFORE setting index so the initial selection fires it too
- _dropdown.RegisterValueChangedCallback(_ =>
- {
- _onValueChanged?.Invoke(Value);
- });
-
- var initial = defaultValue ?? _values[0];
- _dropdown.index = _values.IndexOf(initial);
- }
-
- ///
- /// Registers a callback that fires when the selection changes, providing the new enum value.
- ///
- public void OnValueChanged(Action callback)
- {
- _onValueChanged = callback;
-
- // Fire immediately with current value so the caller gets the initial state
- if (_dropdown != null)
- {
- callback(Value);
- }
- }
-
- ///
- /// Sets the selected enum value and updates the dropdown index.
- ///
- /// The enum value to set.
- public void SetValue(T value)
- {
- if (_dropdown == null) return;
- int idx = _values.IndexOf(value);
- if (idx >= 0)
- {
- _dropdown.index = idx;
- }
- }
-}
\ No newline at end of file
diff --git a/Data/Input/IntegerInputValidator.cs b/Data/Input/IntegerInputValidator.cs
deleted file mode 100644
index e59df8b..0000000
--- a/Data/Input/IntegerInputValidator.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using MelonLoader;
-using UnityEngine.UIElements;
-
-namespace ADOFAIRenderer.Data.Input;
-
-internal class IntegerInputValidator
-{
- private struct FieldEntry
- {
- public List Limits;
- }
-
- private readonly VisualElement _rootVisualElement;
- private readonly Dictionary _fields = new();
-
- public IntegerInputValidator(VisualElement rootVisualElement)
- {
- _rootVisualElement = rootVisualElement;
- }
-
- ///
- /// Registers one or more s for the field with the given name.
- /// Multiple limits can be added to the same field — they are all checked in order.
- ///
- /// The name of the IntegerField in the UXML.
- /// The limits to apply.
- public IntegerInputValidator AddLimits(string fieldName, params IntegerLimit[] limits)
- {
- if (!_fields.TryGetValue(fieldName, out var entry))
- {
- entry = new FieldEntry
- {
- Limits = new List()
- };
- }
-
- entry.Limits.AddRange(limits);
- _fields[fieldName] = entry;
- return this;
- }
-
- ///
- /// Queries all registered fields from the root VisualElement and
- /// registers value-changed callbacks that rollback invalid values.
- ///
- public void SetupValidation()
- {
- foreach (var (fieldName, entry) in _fields)
- {
- var field = _rootVisualElement.Q(fieldName);
- if (field == null)
- {
- Melon.Logger.Warning(
- $"IntegerField '{fieldName}' not found. Skipping validation.");
- continue;
- }
-
- var limits = entry.Limits;
-
- field.RegisterValueChangedCallback(evt =>
- {
- if (string.IsNullOrEmpty(field.text))
- {
- return;
- }
-
- if (limits.Any(limit => !limit.Validate(evt.newValue, out _)))
- {
- field.SetValueWithoutNotify(evt.previousValue);
- }
- });
- }
- }
-}
\ No newline at end of file
diff --git a/Data/IntegerLimit.cs b/Data/IntegerLimit.cs
deleted file mode 100644
index f118b91..0000000
--- a/Data/IntegerLimit.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-namespace ADOFAIRenderer.Data;
-
-///
-/// Base class for integer input validation limits.
-/// Multiple limits can be composed on a single input field — all are checked in order.
-///
-internal abstract class IntegerLimit
-{
- ///
- /// Validates the given integer value against this limit.
- ///
- /// The parsed integer value to validate.
- ///
- /// When validation fails, set to a human-readable error message.
- /// When validation succeeds, set to null.
- ///
- /// true if the value satisfies this limit; false otherwise.
- public abstract bool Validate(int value, out string errorMessage);
-}
-
-///
-/// Requires the integer value to be strictly positive (> 0).
-///
-internal class PositiveOnlyIntegerLimit : IntegerLimit
-{
- public override bool Validate(int value, out string errorMessage)
- {
- if (value > 0)
- {
- errorMessage = null!;
- return true;
- }
-
- errorMessage = "Value must be a positive integer greater than 0.";
- return false;
- }
-}
-
-///
-/// Requires the integer value to be within an inclusive [Min, Max] range.
-/// Either bound can be null to represent an unbounded side.
-///
-internal class RangeIntegerLimit : IntegerLimit
-{
- // ReSharper disable MemberCanBePrivate.Global
- public int? Min { get; }
- public int? Max { get; }
- // ReSharper restore MemberCanBePrivate.Global
-
- /// Inclusive lower bound, or null for no lower bound.
- /// Inclusive upper bound, or null for no upper bound.
- public RangeIntegerLimit(int? min, int? max)
- {
- Min = min;
- Max = max;
- }
-
- public override bool Validate(int value, out string errorMessage)
- {
- if (value < Min)
- {
- errorMessage = Max.HasValue
- ? $"Value must be an integer between {Min.Value} and {Max.Value}."
- : $"Value must be an integer greater than or equal to {Min.Value}.";
- return false;
- }
-
- if (value > Max)
- {
- errorMessage = Min.HasValue
- ? $"Value must be an integer between {Min.Value} and {Max.Value}."
- : $"Value must be an integer less than or equal to {Max.Value}.";
- return false;
- }
-
- errorMessage = null!;
- return true;
- }
-}
\ No newline at end of file
diff --git a/Data/PresetManager.cs b/Data/PresetManager.cs
index dfb41c5..f0b2bde 100644
--- a/Data/PresetManager.cs
+++ b/Data/PresetManager.cs
@@ -177,9 +177,9 @@ internal static class PresetManager
public static void DeletePreset(string name)
{
- string dir = GetPresetsDirectory();
- string safeName = GetSafeFileName(name);
- string filePath = Path.Combine(dir, safeName + ".json");
+ var dir = GetPresetsDirectory();
+ var safeName = GetSafeFileName(name);
+ var filePath = Path.Combine(dir, safeName + ".json");
if (File.Exists(filePath))
{
diff --git a/UI/Window/RenderConfigWindow.cs b/UI/Window/RenderConfigWindow.cs
index 9226b0e..5401402 100644
--- a/UI/Window/RenderConfigWindow.cs
+++ b/UI/Window/RenderConfigWindow.cs
@@ -83,7 +83,7 @@ internal static class RenderConfigWindow
private static void BuildUI(RectTransform content)
{
var ctx = RendererUIManager.Context;
- var (viewport, scrollContent, scroller) =
+ var (_, scrollContent, _) =
O5Factory.ScrollView(ctx, content, spacing: 10f, padding: 8f);
// ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract