// 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; /// /// Exposes a parameterless method as a clickable inspector button for rapid authoring tools, debug hooks, or content workflows. /// /// /// /// Apply to any method on a derived type to surface it in the inspector. /// You can override the label, group related buttons, and control the ordering so that the editor layout remains predictable. /// /// /// The attribute never runs in player builds—methods execute only inside the Unity Editor when the button is pressed—making it safe for destructive /// utilities such as spawning test content, clearing caches, or invoking validation passes. /// /// /// Group Priority and Placement: Use to control the render order of button groups within a placement section /// (lower values render first). Use to override where a group renders (top or bottom) independent of the global setting. /// When multiple buttons in the same group specify different values for these properties, the first declared button's values are used and a warning /// is displayed in the inspector. /// /// /// /// Simple editor utility buttons: /// /// public sealed class EnemySpawner : MonoBehaviour /// { /// [WButton("Rebuild Spawn Points")] /// private void Rebuild() /// { /// // expensive setup logic omitted /// } /// /// [WButton(drawOrder: 1, groupName: "Debug")] /// private void PrintSpawnCount() /// { /// Debug.Log(spawnPoints.Count); /// } /// } /// /// Grouped buttons with priority and placement overrides: /// /// public sealed class QuestAuthoringTool : ScriptableObject /// { /// // This group renders at the top regardless of global settings, with priority 0 (renders first) /// [WButton("Generate IDs", groupName: "Authoring", groupPriority: 0, groupPlacement: WButtonGroupPlacement.Top)] /// private void GenerateIds() { } /// /// // This group renders at the bottom, with priority 10 (renders after priority 0 groups in bottom section) /// [WButton("Submit", groupName: "Debug", groupPriority: 10, groupPlacement: WButtonGroupPlacement.Bottom)] /// private void SubmitToServer() { } /// } /// /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public sealed class WButtonAttribute : Attribute { public const int UseGlobalHistory = -1; /// /// Sentinel value indicating no explicit group priority was set. /// Groups without explicit priority sort after groups with explicit priorities. /// public const int NoGroupPriority = int.MaxValue; public WButtonAttribute( string displayName = null, int drawOrder = 0, int historyCapacity = UseGlobalHistory, string colorKey = null, string groupName = null, int groupPriority = NoGroupPriority, WButtonGroupPlacement groupPlacement = WButtonGroupPlacement.UseGlobalSetting ) { DisplayName = string.IsNullOrWhiteSpace(displayName) ? null : displayName.Trim(); DrawOrder = drawOrder; HistoryCapacity = historyCapacity < 0 ? UseGlobalHistory : historyCapacity; ColorKey = string.IsNullOrWhiteSpace(colorKey) ? null : colorKey.Trim(); GroupName = string.IsNullOrWhiteSpace(groupName) ? null : groupName.Trim(); GroupPriority = groupPriority; GroupPlacement = groupPlacement; } /// /// Explicit label override for the button. Falls back to the method name when null. /// public string DisplayName { get; } /// /// Controls sorting within a group. Lower values render first within the group. /// Buttons with the same draw order but different group names render as separate groups. /// public int DrawOrder { get; } /// /// Optional override for the number of results retained. Negative values defer to the global setting. /// public int HistoryCapacity { get; } /// /// Optional custom color key used to resolve palette-based styling. /// public string ColorKey { get; } /// /// Optional group name for organizing buttons. Buttons with the same group name /// are rendered together. Groups render in the order determined by /// and then by declaration order. /// public string GroupName { get; } /// /// Controls the render order of this button's group within its placement section. /// Lower values render first. The first declared button in a group sets the canonical /// priority for the entire group; conflicting values from other buttons in the same group /// are ignored with a warning displayed in the inspector. /// Default is , which sorts after groups with explicit priorities. /// Only applies to buttons with a ; ungrouped buttons ignore this value. /// public int GroupPriority { get; } /// /// Controls whether this button's group renders at the top or bottom of the inspector, /// overriding the global Unity Helpers setting. The first declared button in a group sets /// the canonical placement for the entire group; conflicting values from other buttons in /// the same group are ignored with a warning displayed in the inspector. /// Default is . /// Only applies to buttons with a ; ungrouped buttons ignore this value. /// public WButtonGroupPlacement GroupPlacement { get; } /// /// Legacy alias for to maintain backwards compatibility. /// [Obsolete("Use ColorKey instead.")] public string Priority => ColorKey; } }