using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace BrewMonster.Scripts.Task.UI { public class TaskTreeView : MonoBehaviour, IRefreshLayout { [SerializeField] private TaskTreeViewHolder m_pTreeViewHolder; [Header("DEBUG")] [SerializeField] private TaskTreeViewHolder _currentSelectedItem = null; [SerializeField] private TaskTreeViewHolder[] m_aTreeViewItems; private RectTransform _rectTransform; private void Awake() { _rectTransform = GetComponent(); } private void Start() { EventBus.Subscribe(evt => { SetSelectedItem(evt.Data); }); } public void SetItemData(TaskTreeViewHolder item, uint taskType) { item.SetItemData(taskType); } public uint GetItemData(TaskTreeViewHolder item) { if (item == null) return 0; return item.GetItemData(); } public TaskTreeViewHolder GetNextSiblingItem(TaskTreeViewHolder item) { if (m_aTreeViewItems == null) { m_aTreeViewItems = GetComponentsInChildren(true); } for (int i = 0; i < m_aTreeViewItems.Length - 1; i++) { if (m_aTreeViewItems[i] == item) { return m_aTreeViewItems[i + 1]; } } return null; } public TaskTreeViewHolder InsertItem(string text, TaskTreeViewHolder pParent, TaskTreeViewHolder pAfter) { //caculate treelevel first int treeLevel = pParent != null ? pParent.GetTreeLevel() + 1 : 0; // Create a new item GameObject and component TaskTreeViewHolder pItem = Instantiate(m_pTreeViewHolder); if(pParent != null) { pParent.SetLastItem(false); } pItem.SetLastItem(true); GameObject go = pItem.gameObject; // go.name = $"Task_{}"; if (pItem == null) return null; // Parent: root (this) if null; otherwise under given parent item var parentTransform = (pParent != null ? pParent.transform : this.transform); go.transform.SetParent(parentTransform, false); // Set sibling position: after specific item if provided; otherwise append to end if (pAfter != null && pAfter.transform.parent == parentTransform) { int afterIndex = pAfter.transform.GetSiblingIndex(); go.transform.SetSiblingIndex(afterIndex + 1); } else { go.transform.SetAsLastSibling(); } // Optionally set label text if a TMP_Text is attached under the item (not required here) // var label = go.GetComponentInChildren(true); // if (label != null) label.text = text ?? string.Empty; pItem.SetItemText(text); pItem.SetTreeLevel(treeLevel); // Refresh local cache of items m_aTreeViewItems = GetComponentsInChildren(true); // pParent.RefreshLayout(); if(pParent) pParent.OnExpand(false); // Collapse parent to show new item only when expanded return pItem; } public void DeleteAllItems() { List childrenCopy = new(); foreach (Transform child in transform) { // Destroy(child.GetComponent()); childrenCopy.Add(child); } foreach (var child in childrenCopy) { child.SetParent(null); Destroy(child.gameObject); } m_aTreeViewItems = null; // m_aTreeViewItems = GetComponentsInChildren(true); _currentSelectedItem = null; } public TaskTreeViewHolder GetItemByData(uint taskType) { if (m_aTreeViewItems == null) { m_aTreeViewItems = new TaskTreeViewHolder[this.transform.childCount]; m_aTreeViewItems = GetComponentsInChildren(true); } foreach (var item in m_aTreeViewItems) { if (item.GetItemData() == taskType) { return item; } } return null; } public TaskTreeViewHolder GetFirstChild() { return transform.childCount == 0 ? null : transform.GetChild(0).GetComponent(); } public TaskTreeViewHolder GetSelectedItem() { return _currentSelectedItem; } void SetSelectedItem(uint idItem) { _currentSelectedItem = GetItemByData(idItem); } public void RefreshLayout() { var parent = _rectTransform; foreach(var child in GetComponentsInChildren(true)) { child.RefreshSelf(); } // Force Unity to rebuild layout immediately parent.ForceUpdateRectTransforms(); LayoutRebuilder.ForceRebuildLayoutImmediate(parent); } /// /// Resolve all prefabs after quest loading is complete /// This should be called after all items are added and SetLastItem() calls are done /// 在任务加载完成后解析所有预制体 /// 这应该在所有项目添加完成且SetLastItem()调用完成后调用 /// public void ResolveAllPrefabs() { // Refresh cache to get all items m_aTreeViewItems = GetComponentsInChildren(true); if (m_aTreeViewItems == null) return; // Resolve prefab for each item foreach (var item in m_aTreeViewItems) { if (item != null) { item.ResolvePrefab(); item.RefreshSelf(); } } } } }