using System.Collections.Generic; using TMPro; using UnityEditor; using UnityEngine; using UnityEngine.UI; [InitializeOnLoad] public static class UIDebugTheme { private static readonly Color BackgroundColor = new Color(0.11f, 0.15f, 0.25f, 0.90f); private static readonly Color PanelColor = new Color(0.17f, 0.24f, 0.31f, 0.85f); private static readonly Color ButtonColor = new Color(0.16f, 0.50f, 0.73f, 1.00f); private static readonly Color ToggleOnColor = new Color(0.53f, 0.81f, 0.98f, 1.00f); // light blue private static readonly Color ToggleOffColor = new Color(0.10f, 0.22f, 0.40f, 1.00f); // dark blue private static readonly Color RadioOnColor = new Color(0.15f, 0.85f, 0.55f, 1.00f); // bright green — distinct from all blues private static readonly Color LeafColor = new Color(0.36f, 0.43f, 0.49f, 1.00f); private static readonly Dictionary _originals = new Dictionary(); private static readonly Dictionary _lastToggleStates = new Dictionary(); private static readonly List _addedLabels = new List(); private static readonly Dictionary _originalBlocks = new Dictionary(); private static readonly Dictionary _originalTransitions = new Dictionary(); private static readonly Dictionary _originalMaterials = new Dictionary(); private static double _nextRescanTime = 0; // ColorBlock for regular interactables (buttons etc.). normalColor=white leaves // image.color unmodified in normal state; >1 values lighten on hover/select, // <1 darkens on press. private static readonly ColorBlock ThemedBlock = new ColorBlock { normalColor = Color.white, highlightedColor = new Color(1.20f, 1.20f, 1.20f, 1.0f), pressedColor = new Color(0.65f, 0.65f, 0.65f, 1.0f), selectedColor = new Color(1.15f, 1.15f, 1.15f, 1.0f), disabledColor = new Color(0.50f, 0.50f, 0.50f, 0.5f), colorMultiplier = 1f, fadeDuration = 0.1f, }; // ColorBlock for input fields. normalColor is light gray so the background is // visible and differs from pure-white text, and selectedColor shows a blue tint // when the field has focus so the user can tell it is active. private static readonly ColorBlock InputFieldBlock = new ColorBlock { normalColor = new Color(0.82f, 0.82f, 0.82f, 1.00f), highlightedColor = new Color(0.90f, 0.90f, 0.90f, 1.00f), pressedColor = new Color(0.60f, 0.60f, 0.60f, 1.00f), selectedColor = new Color(0.65f, 0.83f, 0.98f, 1.00f), // light blue when focused disabledColor = new Color(0.50f, 0.50f, 0.50f, 0.50f), colorMultiplier = 1f, fadeDuration = 0.1f, }; static UIDebugTheme() { EditorApplication.playModeStateChanged += OnPlayModeStateChanged; } static void OnPlayModeStateChanged(PlayModeStateChange state) { switch (state) { case PlayModeStateChange.EnteredPlayMode: ApplyTheme(); EditorApplication.update += PollToggleStates; break; case PlayModeStateChange.ExitingPlayMode: EditorApplication.update -= PollToggleStates; CleanupToggleTracking(); _originals.Clear(); _originalBlocks.Clear(); _originalTransitions.Clear(); _originalMaterials.Clear(); break; } } static void ApplyTheme() { _originals.Clear(); var images = Object.FindObjectsOfType(true); int count = 0; foreach (var image in images) { if (!PassesSpriteFilter(image)) { continue; } int id = image.GetInstanceID(); _originals[id] = image.color; image.color = ClassifyColor(image); count++; } SetupToggleTracking(); AddIconButtonLabels(); AddMissingAssetLabels(); ApplySelectableColors(); Debug.Log($"[UIDebugTheme] Applied debug colours to {count} Image component{(count == 1 ? "" : "s")} with missing sprites."); } // Returns true for Images that should receive debug theme colours: // sprite must be null AND color must be near-white (or have a direct text child // whose sprite was providing the label background). static bool PassesSpriteFilter(Image image) { if (image.sprite != null) { return false; } // Never theme images that live inside a CardImage hierarchy — those are // card art / key-card visuals and must keep their original colours. for (Transform t = image.transform; t != null; t = t.parent) { if (t.name == "CardImage" || t.name == "DetailCard") { return false; } } var c = image.color; bool isBlankWhite = c.a >= 0.5f && c.r >= 0.9f && c.g >= 0.9f && c.b >= 0.9f; if (isBlankWhite) { return true; } // Non-white but has a direct text child — the sprite was providing the label // background and must be replaced so text remains readable. for (int i = 0; i < image.transform.childCount; i++) { var child = image.transform.GetChild(i); if (child.GetComponent() != null || child.GetComponent() != null) return true; } return false; } static Color ClassifyColor(Image image) { var go = image.gameObject; if (go.GetComponent