189 lines
6.7 KiB
C#
189 lines
6.7 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using BrewMonster.Scripts.Chat;
|
|
using BrewMonster.Scripts.Chat.EmotionData;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
namespace BrewMonster.Scripts.ChatUI
|
|
{
|
|
/// <summary>
|
|
/// MonoBehaviour gắn trên EmojiPanel — quản lý lưới emoji để người chơi chọn.
|
|
/// MonoBehaviour placed on EmojiPanel — manages the emoji grid for player selection.
|
|
///
|
|
/// Cách dùng trên Inspector:
|
|
/// 1) Kéo component này lên EmojiPanel GameObject trong prefab.
|
|
/// 2) Gán EmotionLibrarySpriteMap SO (đã build từ Emotion Atlas Converter).
|
|
/// 3) Gán GridContent = child "Context" của EmojiPanel.
|
|
/// 4) Tạo prefab EmojiButtonCell → gán vào CellPrefab.
|
|
/// 5) Gán ChatInputHandler và ChatSystemlUI.
|
|
/// </summary>
|
|
public class EmojiPickerUI : MonoBehaviour
|
|
{
|
|
[Header("Emotion Data")]
|
|
[Tooltip("SO chứa Library + TMP Sprite Asset. Tạo qua Perfect World → Chat → Emotion Atlas Converter.")]
|
|
[SerializeField] EmotionLibrarySpriteMap _emotionSpriteMap;
|
|
|
|
[Header("Grid")]
|
|
[Tooltip("RectTransform chứa các ô emoji (child 'Context' của EmojiPanel). GridLayoutGroup được thêm tự động nếu chưa có.")]
|
|
[SerializeField] RectTransform _gridContent;
|
|
|
|
[Tooltip("Prefab một ô emoji (Button + Image + EmojiButtonCell). Cell prefab.")]
|
|
[SerializeField] EmojiButtonCell _cellPrefab;
|
|
|
|
[Tooltip("Kích thước mỗi ô (pixel). Cell size in pixels.")]
|
|
[SerializeField] Vector2 _cellSize = new Vector2(64f, 64f);
|
|
|
|
[Tooltip("Khoảng cách giữa các ô. Spacing between cells.")]
|
|
[SerializeField] Vector2 _cellSpacing = new Vector2(4f, 4f);
|
|
|
|
[Tooltip("Số cột cố định. Fixed column count.")]
|
|
[SerializeField] int _columnCount = 8;
|
|
|
|
[Header("Wiring")]
|
|
[Tooltip("ChatInputHandler để nhét emoji code vào ô nhập liệu.")]
|
|
[SerializeField] ChatInputHandler _chatInput;
|
|
|
|
[Tooltip("ChatSystemlUI để đóng EmojiPanel sau khi chọn.")]
|
|
[SerializeField] ChatSystemlUI _chatSystemUI;
|
|
|
|
private readonly List<EmojiButtonCell> _cells = new();
|
|
private bool _built;
|
|
|
|
private void Awake()
|
|
{
|
|
TryAutoWireIfNeeded();
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
BuildGrid();
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
if (!_built)
|
|
BuildGrid();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Xây dựng lưới emoji từ EmotionLibrarySpriteMap.
|
|
/// Build emoji grid from EmotionLibrarySpriteMap.
|
|
/// </summary>
|
|
public void BuildGrid()
|
|
{
|
|
ClearGrid();
|
|
TryAutoWireIfNeeded();
|
|
|
|
if (_gridContent == null || _cellPrefab == null)
|
|
{
|
|
Debug.LogWarning("[Cuong] GridContent hoặc CellPrefab chưa được gán.", this);
|
|
return;
|
|
}
|
|
|
|
if (_emotionSpriteMap == null || _emotionSpriteMap.Library == null)
|
|
{
|
|
Debug.LogWarning("[Cuong] EmotionLibrarySpriteMap chưa được gán hoặc chưa có Library.", this);
|
|
return;
|
|
}
|
|
|
|
EnsureGridLayout();
|
|
|
|
_gridContent.gameObject.SetActive(true);
|
|
|
|
// Keep UI stable: always render in set index order.
|
|
foreach (var set in _emotionSpriteMap.Library.Sets.OrderBy(x => x?.EmotionSetIndex ?? int.MaxValue))
|
|
{
|
|
if (set == null) continue;
|
|
if (set.Entries == null || set.Entries.Count == 0) continue;
|
|
|
|
for (int i = 0; i < set.Entries.Count; i++)
|
|
{
|
|
var entry = set.Entries[i];
|
|
if (entry == null) continue;
|
|
|
|
Sprite icon = (entry.FrameSprites != null && entry.FrameSprites.Length > 0)
|
|
? entry.FrameSprites[0]
|
|
: null;
|
|
|
|
var cell = Instantiate(_cellPrefab, _gridContent, false);
|
|
cell.Bind(set.EmotionSetIndex, i, icon, entry.Hint);
|
|
cell.OnClicked += HandleEmojiClicked;
|
|
_cells.Add(cell);
|
|
}
|
|
}
|
|
|
|
_built = true;
|
|
}
|
|
|
|
private void ClearGrid()
|
|
{
|
|
foreach (var c in _cells)
|
|
{
|
|
if (c == null) continue;
|
|
c.OnClicked -= HandleEmojiClicked;
|
|
Destroy(c.gameObject);
|
|
}
|
|
_cells.Clear();
|
|
_built = false;
|
|
}
|
|
|
|
private void TryAutoWireIfNeeded()
|
|
{
|
|
_chatInput ??= GetComponentInParent<ChatInputHandler>();
|
|
_chatSystemUI ??= GetComponentInParent<ChatSystemlUI>();
|
|
}
|
|
|
|
private void EnsureGridLayout()
|
|
{
|
|
var layout = _gridContent.GetComponent<GridLayoutGroup>();
|
|
if (layout == null)
|
|
layout = _gridContent.gameObject.AddComponent<GridLayoutGroup>();
|
|
|
|
layout.cellSize = _cellSize;
|
|
layout.spacing = _cellSpacing;
|
|
layout.constraint = GridLayoutGroup.Constraint.FixedColumnCount;
|
|
layout.constraintCount = _columnCount;
|
|
layout.startCorner = GridLayoutGroup.Corner.UpperLeft;
|
|
layout.startAxis = GridLayoutGroup.Axis.Horizontal;
|
|
layout.childAlignment = TextAnchor.UpperLeft;
|
|
|
|
var fitter = _gridContent.GetComponent<ContentSizeFitter>();
|
|
if (fitter == null)
|
|
fitter = _gridContent.gameObject.AddComponent<ContentSizeFitter>();
|
|
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gọi khi người chơi click một ô emoji — Called when player clicks an emoji cell.
|
|
/// Chèn mã emoji vào input field và đóng panel.
|
|
/// Inserts the emotion code into the chat input and closes the panel.
|
|
/// </summary>
|
|
private void HandleEmojiClicked(int emotionSet, int emotionIndex)
|
|
{
|
|
TryAutoWireIfNeeded();
|
|
if (_chatInput != null)
|
|
{
|
|
// Keep wire body as source of truth to avoid TMP tag race/corruption
|
|
// when player taps emoji repeatedly.
|
|
_chatInput.InsertEmoji(emotionSet, emotionIndex);
|
|
Debug.Log("[Cuong] HandleEmojiClicked.");
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("[Cuong] Không tìm thấy ChatInputHandler để insert emoji.", this);
|
|
}
|
|
|
|
/*if (_chatSystemUI != null)
|
|
{
|
|
_chatSystemUI.CloseEmojiPanel();
|
|
}*/
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
ClearGrid();
|
|
}
|
|
}
|
|
}
|