using System; using System.Collections.Generic; using UnityEngine; namespace UnityEngine.UI { public enum UXBindingFallbackMode { KeepCurrent = 0, RestoreCapturedDefault = 1, UseCustomValue = 2 } public enum UXBindingValueKind { Boolean = 0, Float = 1, String = 2, Color = 3, Vector2 = 4, Vector3 = 5, ObjectReference = 6 } public enum UXBindingProperty { GameObjectActive = 0, CanvasGroupAlpha = 1, CanvasGroupInteractable = 2, CanvasGroupBlocksRaycasts = 3, GraphicColor = 4, GraphicMaterial = 5, ImageSprite = 6, TextContent = 7, TextColor = 8, RectTransformAnchoredPosition = 9, TransformLocalScale = 10, TransformLocalEulerAngles = 11 } [Serializable] public sealed class UXBindingValue { [SerializeField] private bool _boolValue; [SerializeField] private float _floatValue; [SerializeField] private string _stringValue = string.Empty; [SerializeField] private Color _colorValue = Color.white; [SerializeField] private Vector2 _vector2Value; [SerializeField] private Vector3 _vector3Value; [SerializeField] private UnityEngine.Object _objectValue; public bool BoolValue { get => _boolValue; set => _boolValue = value; } public float FloatValue { get => _floatValue; set => _floatValue = value; } public string StringValue { get => _stringValue; set => _stringValue = value ?? string.Empty; } public Color ColorValue { get => _colorValue; set => _colorValue = value; } public Vector2 Vector2Value { get => _vector2Value; set => _vector2Value = value; } public Vector3 Vector3Value { get => _vector3Value; set => _vector3Value = value; } public UnityEngine.Object ObjectValue { get => _objectValue; set => _objectValue = value; } public void CopyFrom(UXBindingValue other) { if (other == null) { return; } _boolValue = other._boolValue; _floatValue = other._floatValue; _stringValue = other._stringValue; _colorValue = other._colorValue; _vector2Value = other._vector2Value; _vector3Value = other._vector3Value; _objectValue = other._objectValue; } } [DisallowMultipleComponent] [AddComponentMenu("UX/UX Binding")] public sealed class UXBinding : MonoBehaviour { [Serializable] public sealed class BindingEntry { [SerializeField] private string _controllerId = string.Empty; [SerializeField] private int _controllerIndex; [SerializeField] private UXBindingProperty _property = UXBindingProperty.GameObjectActive; [SerializeField] private UXBindingValue _value = new UXBindingValue(); [SerializeField] private UXBindingFallbackMode _fallbackMode = UXBindingFallbackMode.RestoreCapturedDefault; [SerializeField] private UXBindingValue _fallbackValue = new UXBindingValue(); [HideInInspector] [SerializeField] private UXBindingValue _capturedDefault = new UXBindingValue(); [HideInInspector] [SerializeField] private bool _hasCapturedDefault; [HideInInspector] [SerializeField] private UXBindingProperty _capturedProperty = UXBindingProperty.GameObjectActive; public string ControllerId { get => _controllerId; set => _controllerId = value ?? string.Empty; } public int ControllerIndex { get => Mathf.Max(0, _controllerIndex); set => _controllerIndex = Mathf.Max(0, value); } public UXBindingProperty Property { get => _property; set => _property = value; } public UXBindingValue Value => _value; public UXBindingFallbackMode FallbackMode { get => _fallbackMode; set => _fallbackMode = value; } public UXBindingValue FallbackValue => _fallbackValue; public bool HasCapturedDefault => _hasCapturedDefault; internal void Normalize() { if (_property != UXBindingProperty.GameObjectActive) { return; } if (_fallbackMode == UXBindingFallbackMode.RestoreCapturedDefault) { _fallbackMode = UXBindingFallbackMode.UseCustomValue; _fallbackValue.BoolValue = false; } } internal void CaptureDefault(GameObject target) { if (target == null || !UXBindingPropertyUtility.IsSupported(target, _property)) { return; } UXBindingPropertyUtility.CaptureValue(target, _property, _capturedDefault); _capturedProperty = _property; _hasCapturedDefault = true; } internal void CaptureCurrentAsValue(GameObject target) { if (target == null || !UXBindingPropertyUtility.IsSupported(target, _property)) { return; } UXBindingPropertyUtility.CaptureValue(target, _property, _value); } internal void CaptureCurrentAsFallback(GameObject target) { if (target == null || !UXBindingPropertyUtility.IsSupported(target, _property)) { return; } UXBindingPropertyUtility.CaptureValue(target, _property, _fallbackValue); } internal void ResetToCapturedDefault(GameObject target) { if (target == null) { return; } if (!_hasCapturedDefault || _capturedProperty != _property) { CaptureDefault(target); } UXBindingPropertyUtility.ApplyValue(target, _property, _capturedDefault); } internal void Apply(GameObject target, string controllerId, int selectedIndex) { if (target == null || !string.Equals(_controllerId, controllerId, StringComparison.Ordinal)) { return; } if (!_hasCapturedDefault || _capturedProperty != _property) { CaptureDefault(target); } if (!UXBindingPropertyUtility.IsSupported(target, _property)) { return; } if (selectedIndex == _controllerIndex) { UXBindingPropertyUtility.ApplyValue(target, _property, _value); return; } switch (_fallbackMode) { case UXBindingFallbackMode.KeepCurrent: return; case UXBindingFallbackMode.RestoreCapturedDefault: if (_hasCapturedDefault) { UXBindingPropertyUtility.ApplyValue(target, _property, _capturedDefault); } return; case UXBindingFallbackMode.UseCustomValue: UXBindingPropertyUtility.ApplyValue(target, _property, _fallbackValue); return; } } } [SerializeField] private UXController _controller; [SerializeField] private List _entries = new List(); private bool _initialized; public UXController Controller => _controller; public List Entries => _entries; public void Initialize() { if (_initialized) { return; } _initialized = true; NormalizeEntries(); EnsureControllerReference(); RegisterToController(); CaptureDefaults(); } public void SetController(UXController controller) { if (_controller == controller) { return; } if (_controller != null) { _controller.UnregisterBinding(this); } _controller = controller; RegisterToController(); } public void CaptureDefaults() { for (int i = 0; i < _entries.Count; i++) { if (_entries[i] != null) { _entries[i].CaptureDefault(gameObject); } } } public void ResetToDefaults() { for (int i = 0; i < _entries.Count; i++) { if (_entries[i] != null) { _entries[i].ResetToCapturedDefault(gameObject); } } } public void PreviewEntry(int entryIndex) { if (_controller == null || entryIndex < 0 || entryIndex >= _entries.Count) { return; } BindingEntry entry = _entries[entryIndex]; if (entry == null || string.IsNullOrWhiteSpace(entry.ControllerId)) { return; } _controller.SetControllerIndex(entry.ControllerId, entry.ControllerIndex); } public void CaptureEntryValue(int entryIndex) { if (entryIndex < 0 || entryIndex >= _entries.Count || _entries[entryIndex] == null) { return; } _entries[entryIndex].CaptureCurrentAsValue(gameObject); } public void CaptureEntryFallbackValue(int entryIndex) { if (entryIndex < 0 || entryIndex >= _entries.Count || _entries[entryIndex] == null) { return; } _entries[entryIndex].CaptureCurrentAsFallback(gameObject); } internal void OnControllerChanged(string controllerId, int selectedIndex) { for (int i = 0; i < _entries.Count; i++) { BindingEntry entry = _entries[i]; if (entry != null) { entry.Apply(gameObject, controllerId, selectedIndex); } } } private void Reset() { EnsureControllerReference(); RegisterToController(); } private void Awake() { Initialize(); } private void OnValidate() { NormalizeEntries(); EnsureControllerReference(); RegisterToController(); } private void OnDestroy() { if (_controller != null) { _controller.UnregisterBinding(this); } } private void EnsureControllerReference() { if (_controller == null) { _controller = GetComponentInParent(); } } private void RegisterToController() { if (_controller != null) { _controller.RegisterBinding(this); } } private void NormalizeEntries() { for (int i = 0; i < _entries.Count; i++) { if (_entries[i] != null) { _entries[i].Normalize(); } } } } }