185 lines
5.4 KiB
C#
185 lines
5.4 KiB
C#
using TMPro;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.UI;
|
|
using System;
|
|
|
|
namespace BriarQueen.UI.Menus.Components
|
|
{
|
|
[RequireComponent(typeof(Button))]
|
|
public class UnderlineButton : MonoBehaviour,
|
|
IPointerEnterHandler,
|
|
IPointerExitHandler,
|
|
IPointerClickHandler,
|
|
ISelectHandler,
|
|
IDeselectHandler
|
|
{
|
|
[Header("References")]
|
|
[SerializeField] protected TextMeshProUGUI _label;
|
|
|
|
[SerializeField]
|
|
protected TextMeshProUGUI _contextLabel;
|
|
|
|
[SerializeField]
|
|
protected string _contextText;
|
|
|
|
protected Button _button;
|
|
protected UnderlineButtonGroup _group;
|
|
protected bool _isHovered;
|
|
|
|
public event Action<UnderlineButton> SelectionRequested;
|
|
public event Action<UnderlineButton> HoverEntered;
|
|
public event Action<UnderlineButton> HoverExited;
|
|
|
|
public bool IsSelected { get; private set; }
|
|
|
|
// True when this button is registered with a group
|
|
public bool IsGrouped => _group != null;
|
|
|
|
|
|
protected virtual void Awake()
|
|
{
|
|
_button = GetComponent<Button>();
|
|
SetUnderline(false);
|
|
}
|
|
|
|
protected virtual void OnDisable()
|
|
{
|
|
_isHovered = false;
|
|
SetUnderline(false);
|
|
}
|
|
|
|
// ── Group registration ────────────────────────────────────────
|
|
|
|
/// <summary>Called by UnderlineButtonGroup when this button is bound.</summary>
|
|
internal void RegisterGroup(UnderlineButtonGroup group)
|
|
{
|
|
_group = group;
|
|
}
|
|
|
|
/// <summary>Called by UnderlineButtonGroup when this button is unbound.</summary>
|
|
internal void UnregisterGroup()
|
|
{
|
|
_group = null;
|
|
}
|
|
|
|
// ── Pointer / Selection events ────────────────────────────────
|
|
|
|
public void OnPointerEnter(PointerEventData eventData)
|
|
{
|
|
if (_button != null && !_button.interactable) return;
|
|
|
|
_isHovered = true;
|
|
|
|
if (IsGrouped)
|
|
HoverEntered?.Invoke(this);
|
|
else
|
|
RefreshStandaloneState();
|
|
|
|
UpdateContextText();
|
|
}
|
|
|
|
public void OnPointerExit(PointerEventData eventData)
|
|
{
|
|
_isHovered = false;
|
|
|
|
if (IsGrouped)
|
|
HoverExited?.Invoke(this);
|
|
else
|
|
RefreshStandaloneState();
|
|
|
|
UpdateContextText();
|
|
}
|
|
|
|
public void OnPointerClick(PointerEventData eventData)
|
|
{
|
|
Debug.Log($"[UnderlineButton] OnPointerClick {gameObject.name}");
|
|
if (_button != null && !_button.interactable) return;
|
|
SelectionRequested?.Invoke(this);
|
|
}
|
|
|
|
public void OnSelect(BaseEventData eventData)
|
|
{
|
|
if (_button != null && !_button.interactable) return;
|
|
|
|
_isHovered = true;
|
|
|
|
if (IsGrouped)
|
|
{
|
|
HoverEntered?.Invoke(this);
|
|
SelectionRequested?.Invoke(this);
|
|
}
|
|
else
|
|
{
|
|
IsSelected = true;
|
|
RefreshStandaloneState();
|
|
}
|
|
|
|
UpdateContextText();
|
|
}
|
|
|
|
public void OnDeselect(BaseEventData eventData)
|
|
{
|
|
_isHovered = false;
|
|
|
|
if (IsGrouped)
|
|
HoverExited?.Invoke(this);
|
|
else
|
|
{
|
|
IsSelected = false;
|
|
RefreshStandaloneState();
|
|
}
|
|
|
|
UpdateContextText();
|
|
}
|
|
|
|
// ── Public API ────────────────────────────────────────────────
|
|
|
|
/// <summary>Called by the group to update logical selected state.</summary>
|
|
public void SetSelectedState(bool selected)
|
|
{
|
|
IsSelected = selected;
|
|
}
|
|
|
|
/// <summary>Called by the group to drive the underline visual directly.</summary>
|
|
public void SetUnderline(bool underlined)
|
|
{
|
|
if (_label == null) return;
|
|
|
|
if (underlined)
|
|
_label.fontStyle |= FontStyles.Underline;
|
|
else
|
|
_label.fontStyle &= ~FontStyles.Underline;
|
|
}
|
|
|
|
public GameObject GetSelectableGameObject() => gameObject;
|
|
|
|
// ── Standalone logic ──────────────────────────────────────────
|
|
|
|
/// <summary>
|
|
/// Used when not in a group — the button manages its own
|
|
/// underline based on hover and selected state directly.
|
|
/// </summary>
|
|
private void RefreshStandaloneState()
|
|
{
|
|
if (_button != null && !_button.interactable)
|
|
{
|
|
SetUnderline(false);
|
|
return;
|
|
}
|
|
|
|
SetUnderline(IsSelected || _isHovered);
|
|
}
|
|
|
|
private void UpdateContextText()
|
|
{
|
|
if (_contextLabel == null)
|
|
return;
|
|
|
|
if(IsSelected || _isHovered)
|
|
_contextLabel.text = _contextText;
|
|
else
|
|
_contextLabel.text = string.Empty;
|
|
}
|
|
}
|
|
} |