using System; using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; using DG.Tweening; using Lean.Pool; using Ichni.RhythmGame; using Unity.VisualScripting; using UnityEngine; using UnityEngine.UI; namespace Ichni.Editor { public class Hierarchy : StaticWindow { public GameObject hierarchyTabPrefab; public RectTransform tabContainer; public Button addFolderButton; public List tabList; public Button expandButtom; public bool NeedExecute = false; private void Awake() { tabList = new List(); addFolderButton.onClick.AddListener(() => { ElementFolder.GenerateElement("New Folder", Guid.NewGuid(), new List(), true, null); }); expandButtom.onClick.AddListener(Expand); rectTransform = this.GetComponent(); } public HierarchyTab GenerateTab(GameElement targetElement, GameElement parentElement, bool animate = true) { if (targetElement.connectedTab != null) return targetElement.connectedTab; HierarchyTab tab = LeanPool.Spawn(hierarchyTabPrefab, tabContainer).GetComponent(); tab.SetTab(targetElement, parentElement, animate); tabList.Add(tab); return tab; } public async Task GenerateTabAsync(GameElement targetElement, GameElement parentElement) { if (targetElement.connectedTab != null) return targetElement.connectedTab; HierarchyTab tab = LeanPool.Spawn(hierarchyTabPrefab, tabContainer).GetComponent(); tab.SetTab(targetElement, parentElement); tabList.Add(tab); await Task.Yield(); return tab; } public bool isExpand = false; private RectTransform rectTransform; public void Expand() { float originX = 225f; isExpand = !isExpand; // 用DOTween动画赋值 if (isExpand) { rectTransform.DOSizeDelta( new Vector2(rectTransform.sizeDelta.x * 2, rectTransform.sizeDelta.y), 0.5f); rectTransform.DOAnchorPos( new Vector2(originX * 2, rectTransform.anchoredPosition.y), 0.5f); enableButtonGroup.disableButton.GetComponent().DOAnchorPos( new Vector2( enableButtonGroup.disableButton.GetComponent().anchoredPosition.x * 3, enableButtonGroup.disableButton.GetComponent().anchoredPosition.y ), 0.5f); expandButtom.GetComponent().DOAnchorPos( new Vector2( expandButtom.GetComponent().anchoredPosition.x * 2, expandButtom.GetComponent().anchoredPosition.y ), 0.5f); } else { rectTransform.DOSizeDelta( new Vector2(rectTransform.sizeDelta.x / 2, rectTransform.sizeDelta.y), 0.5f); rectTransform.DOAnchorPos( new Vector2(originX, rectTransform.anchoredPosition.y), 0.5f); enableButtonGroup.disableButton.GetComponent().DOAnchorPos( new Vector2( enableButtonGroup.disableButton.GetComponent().anchoredPosition.x / 3, enableButtonGroup.disableButton.GetComponent().anchoredPosition.y ), 0.5f); expandButtom.GetComponent().DOAnchorPos( new Vector2( expandButtom.GetComponent().anchoredPosition.x / 2, expandButtom.GetComponent().anchoredPosition.y ), 0.5f); } } public ScrollRect scrollRect; public Vector2 vector2; public void FindTab(GameElement targetElement) { if (targetElement.connectedTab != null) { targetElement.connectedTab.SelectGameElement(); getTabPos(targetElement.connectedTab); return; } targetElement.ScanAndAddEnableTypes(); StartCoroutine(TryGetTab(targetElement)); } public IEnumerator TryGetTab(GameElement targetElement) { // 1. 向上收集所有没有Tab的祖先 Stack stack = new Stack(); GameElement current = targetElement; while (current != null && current.connectedTab == null) { stack.Push(current); current = current.parentElement; } // 2. 从顶层祖先开始,逐层同步展开 while (stack.Count > 0) { var elem = stack.Pop(); var parentTab = elem.parentElement?.connectedTab; if (parentTab != null) { if (!parentTab.isExpanded) { StartCoroutine(parentTab.ExpandSyncBatched()); yield return new WaitUntil(() => parentTab.isExpandDone); } else if (elem.connectedTab == null) { // 父节点已展开但当前元素缺失Tab(刚添加或曾被折叠),直接补生成 GenerateTab(elem, elem.parentElement, false); } } else { if (elem.connectedTab == null) GenerateTab(elem, null, false); } yield return null; } // 3. 最终确保目标Tab存在 if (targetElement.connectedTab == null) { GenerateTab(targetElement, targetElement.parentElement, false); yield return null; } yield return null; getTabPos(targetElement.connectedTab); } void getTabPos(HierarchyTab finalTab) { // 修正定位算法 RectTransform tabRect = finalTab.GetComponent(); RectTransform containerRect = tabContainer; RectTransform viewportRect = scrollRect.viewport != null ? scrollRect.viewport : scrollRect.GetComponent(); // Tab相对于内容顶部的距离(正值为下,负值为上) float tabTop = -tabRect.anchoredPosition.y; float tabHeight = tabRect.rect.height; float contentHeight = containerRect.rect.height; float viewportHeight = viewportRect.rect.height; // 目标:让Tab居中(或尽量居中) float targetCenter = tabTop + tabHeight / 2f; float viewportCenter = viewportHeight / 2f; float scrollOffset = targetCenter - viewportCenter; // normalizedPosition = 1 - (scrollOffset / (contentHeight - viewportHeight)) float denominator = Mathf.Max(1f, contentHeight - viewportHeight); float normalized = 1f - Mathf.Clamp01(scrollOffset / denominator); scrollRect.verticalNormalizedPosition = normalized; finalTab.SelectGameElement(); } public GameElement upLoadElement = null; public IEnumerator TryGetElement() { NeedExecute = true; // 等待直到upLoadElement被赋值 if (upLoadElement == null) { yield return new WaitUntil(() => upLoadElement != null); } NeedExecute = false; upLoadElement = null; } } }