using System; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using UnityEngine.EventSystems; using UnityEngine.InputSystem; namespace DDD { public enum ButtonState { Normal, Highlighted, Pressed, Selected, Disabled } public enum ButtonType { Normal = 0, Toggle } [RequireComponent(typeof(Button))] public class CommonButton : MonoBehaviour, IInteractableUi, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler, ISelectHandler, IDeselectHandler, ISubmitHandler { [SerializeField] private Button _button; [SerializeField] private Animator _animator; [SerializeField] private bool _isEnabled = true; [SerializeField] private bool _synchronizeStates = true; [SerializeField] private ButtonType _buttonType; private bool _isPressed; private bool _isHighlighted; private bool _isSelected; private bool _isToggled; private readonly int _normalHash = Animator.StringToHash("Normal"); private readonly int _highlightedHash = Animator.StringToHash("Highlighted"); private readonly int _pressedHash = Animator.StringToHash("Pressed"); private readonly int _selectedHash = Animator.StringToHash("Selected"); private readonly int _toggleHash = Animator.StringToHash("Toggled"); private readonly int _disabledHash = Animator.StringToHash("Disabled"); private readonly int _isEnabledHash = Animator.StringToHash("Enabled"); private void OnEnable() { _isPressed = false; _isHighlighted = false; _isSelected = false; _isToggled = false; UpdateVisualState(); } private void OnDestroy() { if (_button) { _button.onClick.RemoveAllListeners(); } } private void UpdateVisualState() { if (gameObject.activeInHierarchy == false || _synchronizeStates == false) return; var currentState = GetCurrentState(); ApplyVisualState(currentState); } private ButtonState GetCurrentState() { if (_buttonType == ButtonType.Normal) { if (_button.interactable == false) { return ButtonState.Disabled; } if (_isPressed) { return ButtonState.Pressed; } if (_isSelected) { return ButtonState.Selected; } return ButtonState.Normal; } if (_buttonType == ButtonType.Toggle) { if (_isToggled) { return ButtonState.Selected; } if (_isPressed) { return ButtonState.Pressed; } if (_isSelected || _isHighlighted) { return ButtonState.Highlighted; } if (_button.interactable == false) { return ButtonState.Disabled; } } return ButtonState.Normal; } private void ApplyVisualState(ButtonState state) { if (_animator && _animator.runtimeAnimatorController) { ApplyAnimatorState(state); } } private void ApplyAnimatorState(ButtonState state) { _animator.SetBool(_isEnabledHash, _isEnabled); _animator.SetBool(_highlightedHash, _isHighlighted); _animator.SetBool(_pressedHash, _isPressed); _animator.SetBool(_selectedHash, _isSelected); _animator.SetBool(_toggleHash, _isToggled); _animator.SetBool(_disabledHash, !_button.interactable); } public void OnInteract() { _button.onClick.Invoke(); } public void OnPointerClick(PointerEventData eventData) { UpdateVisualState(); } public void OnPointerEnter(PointerEventData eventData) { if (_button.interactable == false) return; if (_buttonType == ButtonType.Normal) { _isSelected = true; EventSystem.current.SetSelectedGameObject(gameObject); } else if (_buttonType == ButtonType.Toggle) { _isHighlighted = true; } UpdateVisualState(); } public void OnPointerExit(PointerEventData eventData) { if (_button.interactable == false) return; if (_buttonType == ButtonType.Normal) { _isSelected = false; } else if (_buttonType == ButtonType.Toggle) { _isHighlighted = false; } UpdateVisualState(); } public void OnPointerDown(PointerEventData eventData) { if (_button.interactable == false) return; if (eventData.button == PointerEventData.InputButton.Left) { _isPressed = true; UpdateVisualState(); } } public void OnPointerUp(PointerEventData eventData) { if (_button.interactable == false) return; if (eventData.button == PointerEventData.InputButton.Left) { _isPressed = false; if (_buttonType == ButtonType.Normal) { _isSelected = false; } else if (_buttonType == ButtonType.Toggle) { _isHighlighted = false; _isToggled = true; } UpdateVisualState(); } } public void OnSelect(BaseEventData eventData) { if (_button.interactable == false) return; if (_buttonType == ButtonType.Normal) { _isSelected = true; } else if (_buttonType == ButtonType.Toggle) { _isHighlighted = true; } UpdateVisualState(); } public void OnDeselect(BaseEventData eventData) { if (_button.interactable == false) return; if (_buttonType == ButtonType.Normal) { _isSelected = false; } else if (_buttonType == ButtonType.Toggle) { _isHighlighted = false; } UpdateVisualState(); } public void OnSubmit(BaseEventData eventData) { _button.onClick.Invoke(); } public void AddListener(UnityAction action) => _button.onClick.AddListener(action); public void RemoveListener(UnityAction action) => _button?.onClick.RemoveListener(action); public void RemoveAllListeners() => _button.onClick.RemoveAllListeners(); public bool IsEnabled => _isEnabled; public bool IsInteractable => _button.interactable; public void SetInteractable(bool interactable) { _button.interactable = interactable; UpdateVisualState(); } public void SetToggle(bool isSelected) { if (_buttonType == ButtonType.Toggle) { _isToggled = isSelected; _isHighlighted = false; _button.interactable = !isSelected; } UpdateVisualState(); } public void ForceUpdateState() { UpdateVisualState(); } public bool UseToggle { get => _buttonType == ButtonType.Toggle; set => _buttonType = value ? ButtonType.Toggle : ButtonType.Normal; } public bool IsToggled => _isToggled; public void SetToggleState(bool toggled) { if (_buttonType != ButtonType.Toggle) return; _isToggled = toggled; _isPressed = false; if (!toggled) { _isSelected = false; } UpdateVisualState(); } } }