using System; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace BriarQueen.UI.Menus.Components { public class SaveSlotUI : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler { [Header("Clickable Root")] [SerializeField] private Button _slotButton; [Header("Labels")] [SerializeField] private TextMeshProUGUI _saveNameText; [SerializeField] private TextMeshProUGUI _saveDateText; [Header("Delete")] [SerializeField] private Button _deleteButton; [Header("Empty Text")] [SerializeField] private TextMeshProUGUI _emptyImage; [Header("Highlight")] [SerializeField] private SaveSlotHighlight _highlight; private Action _onDeleteClick; private Action _onEmptyClick; private Action _onFilledClick; public SaveFileInfo SaveInfo { get; private set; } public bool IsEmpty { get; private set; } public bool IsSelected { get; private set; } private void Awake() { if (_slotButton != null) { _slotButton.onClick.RemoveAllListeners(); _slotButton.onClick.AddListener(HandleSlotClicked); } if (_deleteButton != null) { _deleteButton.onClick.RemoveAllListeners(); _deleteButton.onClick.AddListener(HandleDeleteClicked); } } private void OnDestroy() { if (_slotButton != null) _slotButton.onClick.RemoveAllListeners(); if (_deleteButton != null) _deleteButton.onClick.RemoveAllListeners(); } // ── Pointer events ──────────────────────────────────────────── public void OnPointerEnter(PointerEventData eventData) { _highlight?.SetHovered(true); } public void OnPointerExit(PointerEventData eventData) { _highlight?.SetHovered(false); } // ── Public API ──────────────────────────────────────────────── public GameObject GetSelectableGameObject() { return _slotButton != null ? _slotButton.gameObject : gameObject; } public void SetSelected(bool selected, bool immediate = false) { IsSelected = selected; if (immediate) _highlight?.SetSelectedImmediate(selected); else _highlight?.SetSelected(selected); } public void SetFilled( SaveFileInfo saveInfo, Action onClickFilled, Action onDelete) { SaveInfo = saveInfo; IsEmpty = false; _onFilledClick = onClickFilled; _onEmptyClick = null; _onDeleteClick = onDelete; if (_emptyImage != null) _emptyImage.gameObject.SetActive(false); if (_saveNameText != null) { _saveNameText.gameObject.SetActive(true); _saveNameText.text = saveInfo.FileName; } if (_saveDateText != null) { _saveDateText.gameObject.SetActive(true); _saveDateText.text = saveInfo.LastModified.ToString("g"); } if (_deleteButton != null) { _deleteButton.gameObject.SetActive(true); _deleteButton.interactable = true; } if (_slotButton != null) _slotButton.interactable = true; } public void SetEmpty(Action onClickEmpty) { SaveInfo = default; IsEmpty = true; _onFilledClick = null; _onEmptyClick = onClickEmpty; _onDeleteClick = null; if (_saveNameText != null) _saveNameText.text = string.Empty; if (_saveDateText != null) _saveDateText.text = string.Empty; if (_emptyImage != null) _emptyImage.gameObject.SetActive(true); if (_deleteButton != null) { _deleteButton.gameObject.SetActive(false); _deleteButton.interactable = false; } if (_slotButton != null) _slotButton.interactable = true; } public void SetInteractable(bool interactable) { if (_slotButton != null) _slotButton.interactable = interactable; if (_deleteButton != null) _deleteButton.interactable = interactable && !IsEmpty; } // ── Internal ────────────────────────────────────────────────── private void HandleSlotClicked() { if (IsEmpty) _onEmptyClick?.Invoke(); else if (!string.IsNullOrWhiteSpace(SaveInfo.FileName)) _onFilledClick?.Invoke(SaveInfo); } private void HandleDeleteClicked() { if (IsEmpty) return; if (!string.IsNullOrWhiteSpace(SaveInfo.FileName)) _onDeleteClick?.Invoke(SaveInfo); } } public struct SaveFileInfo { public readonly string FileName; public readonly DateTime LastModified; public SaveFileInfo(string fileName, DateTime lastModified) { FileName = fileName; LastModified = lastModified; } } }