Signed-off-by: TRADER_FOER <lhf190@outlook.com>
This commit is contained in:
@@ -3,6 +3,7 @@ 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;
|
||||
@@ -29,26 +30,23 @@ namespace Ichni.Editor
|
||||
rectTransform = this.GetComponent<RectTransform>();
|
||||
}
|
||||
|
||||
public HierarchyTab GenerateTab(GameElement targetElement, GameElement parentElement)
|
||||
public HierarchyTab GenerateTab(GameElement targetElement, GameElement parentElement, bool animate = true)
|
||||
{
|
||||
HierarchyTab tab = Instantiate(hierarchyTabPrefab, tabContainer).GetComponent<HierarchyTab>();
|
||||
tab.SetTab(targetElement, parentElement);
|
||||
if (targetElement.connectedTab != null) return targetElement.connectedTab;
|
||||
|
||||
HierarchyTab tab = LeanPool.Spawn(hierarchyTabPrefab, tabContainer).GetComponent<HierarchyTab>();
|
||||
tab.SetTab(targetElement, parentElement, animate);
|
||||
tabList.Add(tab);
|
||||
return tab;
|
||||
}
|
||||
public async Task<HierarchyTab> GenerateTabAsync(GameElement targetElement, GameElement parentElement)
|
||||
{
|
||||
var request = InstantiateAsync(hierarchyTabPrefab, tabContainer);
|
||||
if (targetElement.connectedTab != null) return targetElement.connectedTab;
|
||||
|
||||
// 等待实例化过程完成
|
||||
while (!request.isDone)
|
||||
{
|
||||
await Task.Yield(); // 异步地等待下一帧
|
||||
}
|
||||
HierarchyTab tab = request.Result[0].GetComponent<HierarchyTab>();
|
||||
HierarchyTab tab = LeanPool.Spawn(hierarchyTabPrefab, tabContainer).GetComponent<HierarchyTab>();
|
||||
tab.SetTab(targetElement, parentElement);
|
||||
tabList.Add(tab);
|
||||
// 返回实例化的游戏对象
|
||||
await Task.Yield();
|
||||
return tab;
|
||||
}
|
||||
public bool isExpand = false;
|
||||
@@ -100,29 +98,20 @@ namespace Ichni.Editor
|
||||
{
|
||||
if (targetElement.connectedTab != null)
|
||||
{
|
||||
// 如果已经有Tab了,直接选中
|
||||
targetElement.connectedTab.SelectGameElement();
|
||||
getTabPos(targetElement.connectedTab);
|
||||
return;
|
||||
}
|
||||
targetElement.ScanAndAddEnableTypes();
|
||||
if (!EditorManager.instance.ExpandWhileClick)
|
||||
{
|
||||
var tab = EditorManager.instance.uiManager.hierarchy.GenerateTab(targetElement, null);
|
||||
tab.SelectGameElement();
|
||||
Destroy(tab.gameObject);
|
||||
EditorManager.instance.uiManager.hierarchy.tabList.Remove(tab);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
StartCoroutine(TryGetTab(targetElement));
|
||||
}
|
||||
|
||||
StartCoroutine(TryGetTab(targetElement));
|
||||
|
||||
}
|
||||
|
||||
public IEnumerator TryGetTab(GameElement targetElement)
|
||||
{
|
||||
// 1. 向上找到最近的有Tab的祖先
|
||||
// 1. 向上收集所有没有Tab的祖先
|
||||
Stack<GameElement> stack = new Stack<GameElement>();
|
||||
GameElement current = targetElement;
|
||||
while (current != null && current.connectedTab == null)
|
||||
@@ -131,47 +120,42 @@ namespace Ichni.Editor
|
||||
current = current.parentElement;
|
||||
}
|
||||
|
||||
// 2. 如果有Tab的祖先存在,依次展开回目标
|
||||
HierarchyTab parentTab = current != null ? current.connectedTab : null;
|
||||
// 2. 从顶层祖先开始,逐层同步展开
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
var elem = stack.Pop();
|
||||
// 只展开父Tab,不直接生成Tab
|
||||
if (elem.parentElement != null && elem.parentElement.connectedTab != null)
|
||||
{
|
||||
if (!elem.parentElement.connectedTab.isExpanded)
|
||||
{
|
||||
elem.parentElement.connectedTab.ExpandOrFold(true);
|
||||
}
|
||||
else if (!elem.parentElement.connectedTab.isExpandDone)
|
||||
{
|
||||
elem.parentElement.connectedTab.ExpandOrFold();
|
||||
elem.parentElement.connectedTab.ExpandOrFold(true);//合上再展开,这思路也是没谁了
|
||||
}
|
||||
else
|
||||
{
|
||||
//他就在展开了,等下就好了
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
// 等待当前elem的Tab生成
|
||||
while (elem.connectedTab == null)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
parentTab = elem.connectedTab;
|
||||
}
|
||||
|
||||
// 3. 等待目标Tab实例化
|
||||
while (targetElement.connectedTab is null)
|
||||
{
|
||||
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;
|
||||
}
|
||||
yield return null; // 等待一帧,确保UI更新
|
||||
|
||||
// 3. 最终确保目标Tab存在
|
||||
if (targetElement.connectedTab == null)
|
||||
{
|
||||
GenerateTab(targetElement, targetElement.parentElement, false);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
yield return null;
|
||||
getTabPos(targetElement.connectedTab);
|
||||
|
||||
|
||||
}
|
||||
void getTabPos(HierarchyTab finalTab)
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using DG.Tweening;
|
||||
using Lean.Pool;
|
||||
using Ichni.RhythmGame;
|
||||
using Michsky.MUIP;
|
||||
using Sirenix.Utilities;
|
||||
@@ -35,10 +36,20 @@ namespace Ichni.Editor
|
||||
public DoubleCheckButton deleteButton;
|
||||
public TMP_Text tabButtonText;
|
||||
|
||||
public void SetTab(GameElement targetElement, GameElement parentElement)
|
||||
private List<GameObject> indentationLines = new List<GameObject>();
|
||||
|
||||
public void SetTab(GameElement targetElement, GameElement parentElement, bool animate = true)
|
||||
{
|
||||
transform.localScale = Vector3.one;
|
||||
transform.DOScale(Vector3.one, 0.2f).SetEase(Ease.OutCirc).From(new Vector3(1, 0, 1));
|
||||
if (animate)
|
||||
{
|
||||
transform.localScale = Vector3.one;
|
||||
transform.DOScale(Vector3.one, 0.2f).SetEase(Ease.OutCirc).From(new Vector3(1, 0, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.DOKill();
|
||||
transform.localScale = Vector3.one;
|
||||
}
|
||||
connectedGameElement = targetElement;
|
||||
tabButtonText.text = targetElement.elementName;
|
||||
targetElement.connectedTab = this;
|
||||
@@ -46,6 +57,14 @@ namespace Ichni.Editor
|
||||
this.isSelected = false;
|
||||
this.childTabList = new List<HierarchyTab>();
|
||||
|
||||
// 清除旧的缩进线
|
||||
for (int i = indentationLines.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (indentationLines[i] != null)
|
||||
Destroy(indentationLines[i]);
|
||||
}
|
||||
indentationLines.Clear();
|
||||
|
||||
if (parentElement == null)
|
||||
{
|
||||
this.tabLayer = 0;
|
||||
@@ -62,7 +81,10 @@ namespace Ichni.Editor
|
||||
if (!this.parentTab.isExpanded)
|
||||
{
|
||||
this.isExpanded = false;
|
||||
var pt = this.parentTab;
|
||||
SetExpansion(false);
|
||||
pt.SetStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 1; i <= this.tabLayer; i++)
|
||||
@@ -70,14 +92,17 @@ namespace Ichni.Editor
|
||||
float lineX = 30 * i - 15;
|
||||
var d = Instantiate(indentationLinePrefab, tabRect);
|
||||
d.GetComponent<RectTransform>().anchoredPosition = new Vector2(lineX, 0);
|
||||
indentationLines.Add(d);
|
||||
}
|
||||
parentTab.SetStatus();
|
||||
parentTab?.SetStatus();
|
||||
}
|
||||
|
||||
|
||||
float posX = (30 * tabLayer);
|
||||
tabMainRect.anchoredPosition = new Vector2(posX, tabMainRect.anchoredPosition.y);
|
||||
tabButton.onClick.RemoveAllListeners();
|
||||
tabButton.onClick.AddListener(SelectGameElement);
|
||||
expandButton.onClick.RemoveAllListeners();
|
||||
expandButton.onClick.AddListener(ExpandOrFold);
|
||||
deleteButton.onConfirm = () => EditorManager.instance.operationManager.CopyPasteDeleteModule.DeleteElement(connectedGameElement);
|
||||
|
||||
@@ -87,6 +112,13 @@ namespace Ichni.Editor
|
||||
private void OnDestroy()
|
||||
{
|
||||
transform.DOKill();
|
||||
// 清除缩进线
|
||||
for (int i = indentationLines.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (indentationLines[i] != null)
|
||||
Destroy(indentationLines[i]);
|
||||
}
|
||||
indentationLines.Clear();
|
||||
}
|
||||
|
||||
public void SetStatus()
|
||||
@@ -293,9 +325,6 @@ namespace Ichni.Editor
|
||||
connectedGameElement.ScanAndAddEnableTypes();
|
||||
List<GameElement> FixedList = !forceAllExPand ? connectedGameElement.GetChildrenByTypes() : connectedGameElement.childElementList;
|
||||
|
||||
// float startTime = Time.realtimeSinceStartup;
|
||||
// connectedGameElement.childElementList.Sort();//TODO: 后续可以让玩家手动快速排序
|
||||
Debug.Log(FixedList.Count);
|
||||
ExpandAsync(FixedList);
|
||||
|
||||
}
|
||||
@@ -313,19 +342,57 @@ namespace Ichni.Editor
|
||||
{
|
||||
if (!expand && isExpanded)
|
||||
{
|
||||
for (int i = childTabList.Count; i > 0; i--)
|
||||
for (int i = childTabList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
childTabList[i - 1].SetExpansion(expand); //false
|
||||
if (childTabList[i] != null)
|
||||
childTabList[i].SetExpansion(expand);
|
||||
}
|
||||
}
|
||||
|
||||
if (!expand)
|
||||
{
|
||||
parentTab.childTabList.Remove(this);
|
||||
Destroy(gameObject);
|
||||
EditorManager.instance.uiManager.hierarchy.tabList.Remove(this);
|
||||
CleanupAndDespawn();
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanupAndDespawn()
|
||||
{
|
||||
if (connectedGameElement != null)
|
||||
{
|
||||
// 如果该元素还在选中列表中,先移除(须在 connectedTab=null 之前执行)
|
||||
if (isSelected)
|
||||
{
|
||||
var sel = EditorManager.instance.operationManager.currentSelectedElements;
|
||||
sel.Remove(connectedGameElement);
|
||||
isSelected = false;
|
||||
}
|
||||
connectedGameElement.connectedTab = null;
|
||||
}
|
||||
|
||||
parentTab?.childTabList.Remove(this);
|
||||
EditorManager.instance.uiManager.hierarchy.tabList.Remove(this);
|
||||
|
||||
transform.DOKill();
|
||||
|
||||
tabButton.onClick.RemoveAllListeners();
|
||||
expandButton.onClick.RemoveAllListeners();
|
||||
|
||||
for (int i = indentationLines.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (indentationLines[i] != null)
|
||||
Destroy(indentationLines[i]);
|
||||
}
|
||||
indentationLines.Clear();
|
||||
|
||||
connectedGameElement = null;
|
||||
parentTab = null;
|
||||
childTabList?.Clear();
|
||||
isExpanded = false;
|
||||
isExpandDone = true;
|
||||
tabLayer = 0;
|
||||
|
||||
LeanPool.Despawn(gameObject);
|
||||
}
|
||||
private void ExpandAnim()
|
||||
{
|
||||
expandButton.transform.DORotate(new Vector3(0, 0, !isExpanded ? 0f : 180f), 0.2f);
|
||||
@@ -341,12 +408,36 @@ namespace Ichni.Editor
|
||||
{
|
||||
var childElement = FixedList[index];
|
||||
EditorManager.instance.uiManager.hierarchy.GenerateTab(childElement, connectedGameElement);
|
||||
Debug.Log($"生成子Tab:{childElement.elementName},索引:{index},总数:{FixedList.Count}");
|
||||
|
||||
// 如果处理时间超过帧时间限制,直接继续执行而不等待
|
||||
// 移除了原来的 yield return null 等待逻辑
|
||||
}
|
||||
}
|
||||
public IEnumerator ExpandSyncBatched()
|
||||
{
|
||||
connectedGameElement.ScanAndAddEnableTypes();
|
||||
isExpanded = true;
|
||||
isExpandDone = false;
|
||||
ExpandAnim();
|
||||
|
||||
var children = connectedGameElement.childElementList;
|
||||
int batchCount = 0;
|
||||
for (int i = 0; i < children.Count; i++)
|
||||
{
|
||||
if (!isExpanded) break;
|
||||
if (children[i].connectedTab == null)
|
||||
{
|
||||
EditorManager.instance.uiManager.hierarchy.GenerateTab(children[i], connectedGameElement, false);
|
||||
batchCount++;
|
||||
if (batchCount >= 15)
|
||||
{
|
||||
batchCount = 0;
|
||||
yield return null;
|
||||
if (!isExpanded) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isExpandDone = true;
|
||||
}
|
||||
|
||||
async void ExpandAsync(List<GameElement> FixedList)
|
||||
{
|
||||
isExpandDone = false;
|
||||
@@ -355,7 +446,6 @@ namespace Ichni.Editor
|
||||
|
||||
var childElement = FixedList[index];
|
||||
await EditorManager.instance.uiManager.hierarchy.GenerateTabAsync(childElement, connectedGameElement);
|
||||
Debug.Log($"生成子Tab:{childElement.elementName},索引:{index},总数:{FixedList.Count}");
|
||||
if (!isExpanded) break;
|
||||
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace Ichni.Editor
|
||||
var item = LeanPool.Spawn(searchResultItemPrefab, searchResultsRoot);
|
||||
var itemText = item.GetComponentInChildren<TMP_Text>();
|
||||
if (itemText != null)
|
||||
itemText.text = element.elementName + " " + element.GetType().ToString();
|
||||
itemText.text = element.elementName + " | " + element.GetType().ToString();
|
||||
|
||||
var button = item.GetComponentInChildren<Button>();
|
||||
if (button != null)
|
||||
|
||||
Reference in New Issue
Block a user