// MIT License - Copyright (c) 2025 wallstop
// Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE
namespace WallstopStudios.UnityHelpers.Core.Attributes
{
using System;
using System.Collections.Generic;
using UnityEngine;
using WallstopStudios.UnityHelpers.Utils;
///
/// Comparison strategy applied when resolving visibility.
///
public enum WShowIfComparison
{
///
/// Reserved value. Prefer selecting a specific comparison mode.
///
[Obsolete("WShowIfComparison.Unknown is reserved. Choose an explicit comparison mode.")]
Unknown = 0,
///
/// Shows the property when the condition evaluates to true or matches the provided expected values.
///
Equal = 1,
///
/// Shows the property when the condition evaluates to false or does not match the provided expected values.
///
NotEqual = 2,
///
/// Shows the property when the condition is greater than the expected value (numbers and comparable types).
///
GreaterThan = 3,
///
/// Shows the property when the condition is greater than or equal to the expected value (numbers and comparable types).
///
GreaterThanOrEqual = 4,
///
/// Shows the property when the condition is less than the expected value (numbers and comparable types).
///
LessThan = 5,
///
/// Shows the property when the condition is less than or equal to the expected value (numbers and comparable types).
///
LessThanOrEqual = 6,
///
/// Shows the property when the condition resolves to null (supports semantics).
///
IsNull = 7,
///
/// Shows the property when the condition resolves to a non-null value (supports semantics).
///
IsNotNull = 8,
///
/// Shows the property when the condition resolves to a null or empty string, or an empty collection.
///
IsNullOrEmpty = 9,
///
/// Shows the property when the condition resolves to a non-empty string or collection.
///
IsNotNullOrEmpty = 10,
}
///
/// Conditionally hides or shows a serialized field based on the value of another property or field on the same object.
///
///
///
/// works with booleans, numbers, enums, strings, references, and even custom comparable types.
/// You can specify comparison strategies such as or and
/// optionally pass explicit expected values for equality checks.
///
///
/// When multiple conditions are required, stack the attribute instance per rule or combine it with other inspector helpers such as
/// to keep complex editors manageable.
///
///
///
/// Basic boolean toggle:
///
/// public bool advancedMode;
///
/// [WShowIf(nameof(advancedMode))]
/// public float advancedSetting;
///
/// Numerical comparisons:
///
/// public int upgradeLevel;
///
/// [WShowIf(nameof(upgradeLevel), WShowIfComparison.GreaterThanOrEqual, 3)]
/// public Ability ultimateAbility;
///
/// Reference checks and inverse usage:
///
/// public GameObject overridePrefab;
///
/// [WShowIf(nameof(overridePrefab), WShowIfComparison.IsNull)]
/// public GameObject fallbackPrefab;
///
/// [WShowIf(nameof(overridePrefab), inverse: true)]
/// public AbilityOverrides overrideSettings;
///
///
public sealed class WShowIfAttribute : PropertyAttribute
{
///
/// Gets the name of the field or property that determines visibility.
///
public readonly string conditionField;
///
/// Gets a value indicating whether the visibility rule should be inverted.
///
public readonly bool inverse;
///
/// Gets the comparison strategy that should be applied to the condition value.
///
public readonly WShowIfComparison comparison;
///
/// Gets the explicit values that must match the condition field in order for the target to display.
///
public object[] expectedValues;
///
/// Configures a conditional visibility rule for an inspector field.
///
/// Name of the member used for evaluation.
/// Optional explicit values that should evaluate as visible.
public WShowIfAttribute(string conditionField, params object[] expectedValues)
: this(conditionField, false, WShowIfComparison.Equal, expectedValues) { }
///
/// Configures a conditional visibility rule with explicit inversion for an inspector field.
///
/// Name of the member used for evaluation.
/// Set to true to flip the visibility result.
/// Optional explicit values that should evaluate as visible.
public WShowIfAttribute(string conditionField, bool inverse, params object[] expectedValues)
: this(conditionField, inverse, WShowIfComparison.Equal, expectedValues) { }
///
/// Configures a conditional visibility rule with a specific comparison mode.
///
/// Name of the member used for evaluation.
/// Comparison strategy applied to the condition value.
/// Optional explicit values that should evaluate as visible.
public WShowIfAttribute(
string conditionField,
WShowIfComparison comparison,
params object[] expectedValues
)
: this(conditionField, false, comparison, expectedValues) { }
///
/// Configures a conditional visibility rule for an inspector field.
///
/// Name of the member used for evaluation.
/// Set to true to flip the visibility result.
/// Comparison strategy applied to the condition value.
/// Optional explicit values that should evaluate as visible.
public WShowIfAttribute(
string conditionField,
bool inverse,
WShowIfComparison comparison,
params object[] expectedValues
)
{
if (string.IsNullOrEmpty(conditionField))
{
throw new ArgumentException(
"Condition member name cannot be null or empty.",
nameof(conditionField)
);
}
this.conditionField = conditionField;
this.inverse = inverse;
this.comparison = comparison;
if (expectedValues == null || expectedValues.Length == 0)
{
this.expectedValues = Array.Empty