327 lines
12 KiB
C#
327 lines
12 KiB
C#
#nullable enable
|
|
using System.Collections.Generic;
|
|
using Cysharp.Threading.Tasks;
|
|
using UnityEngine;
|
|
using UVC.Core;
|
|
using UVC.Studio.Manager;
|
|
using UVC.UI.List.Tree;
|
|
using UVC.UI.Tab;
|
|
using UVC.UI.Window;
|
|
|
|
namespace UVC.Studio.Tab
|
|
{
|
|
public class StudioSideTabBarHierarchy : MonoBehaviour, ITabContent
|
|
{
|
|
[SerializeField]
|
|
private HierarchyWindow? hierarchyWindow;
|
|
|
|
private bool isInitialized = false;
|
|
|
|
/// <summary>
|
|
/// StageObject ID와 TreeListItemData 간의 매핑
|
|
/// </summary>
|
|
private readonly Dictionary<string, TreeListItemData> _stageObjectToTreeItem = new();
|
|
|
|
/// <summary>
|
|
/// StageObjectManager 참조
|
|
/// </summary>
|
|
private StageObjectManager? _stageObjectManager;
|
|
|
|
/// <summary>
|
|
/// SelectionManager 참조
|
|
/// </summary>
|
|
private SelectionManager? _selectionManager;
|
|
|
|
/// <summary>
|
|
/// 선택 이벤트 처리 중 무한 루프 방지 플래그
|
|
/// </summary>
|
|
private bool _isProcessingSelection = false;
|
|
|
|
protected void Awake()
|
|
{
|
|
if (hierarchyWindow == null)
|
|
{
|
|
hierarchyWindow = GetComponentInChildren<HierarchyWindow>();
|
|
}
|
|
|
|
if (hierarchyWindow == null)
|
|
{
|
|
Debug.LogError("HierarchyWindow component is not assigned or found in Children.");
|
|
return;
|
|
}
|
|
|
|
hierarchyWindow.OnItemSelected += OnItemSelectedHandler;
|
|
hierarchyWindow.OnItemDeselected += OnItemDeselectedHandler;
|
|
hierarchyWindow.OnItemVisibilityChanged += OnItemVisibilityChangedHandler;
|
|
|
|
InjectorAppContext.Instance.Injector.RegisterInstance<StudioSideTabBarHierarchy>(this, ServiceLifetime.Scene);
|
|
}
|
|
|
|
/// <summary>
|
|
/// HierarchyWindow에서 아이템이 선택되었을 때 호출
|
|
/// SelectionManager를 통해 객체를 선택하고 Outlinable을 활성화
|
|
/// </summary>
|
|
private void OnItemSelectedHandler(TreeListItemData item)
|
|
{
|
|
Debug.Log($"[StudioSideTabBarHierarchy] Item selected: {item.Name} (ExternalKey: {item.ExternalKey})");
|
|
|
|
if (_isProcessingSelection) return;
|
|
if (_selectionManager == null || string.IsNullOrEmpty(item.ExternalKey)) return;
|
|
|
|
_isProcessingSelection = true;
|
|
try
|
|
{
|
|
// SelectionManager를 통해 객체 선택 (Outlinable 활성화됨)
|
|
_selectionManager.SelectById(item.ExternalKey);
|
|
}
|
|
finally
|
|
{
|
|
_isProcessingSelection = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// HierarchyWindow에서 아이템 선택이 해제되었을 때 호출
|
|
/// SelectionManager를 통해 객체 선택을 해제하고 Outlinable을 비활성화
|
|
/// </summary>
|
|
private void OnItemDeselectedHandler(TreeListItemData item)
|
|
{
|
|
Debug.Log($"[StudioSideTabBarHierarchy] Item deselected: {item.Name} (ExternalKey: {item.ExternalKey})");
|
|
|
|
if (_isProcessingSelection) return;
|
|
if (_selectionManager == null || string.IsNullOrEmpty(item.ExternalKey)) return;
|
|
|
|
_isProcessingSelection = true;
|
|
try
|
|
{
|
|
// SelectionManager를 통해 객체 선택 해제 (Outlinable 비활성화됨)
|
|
_selectionManager.DeselectById(item.ExternalKey);
|
|
}
|
|
finally
|
|
{
|
|
_isProcessingSelection = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// HierarchyWindow에서 아이템 가시성이 변경되었을 때 호출
|
|
/// 해당 객체의 GameObject.SetActive(true/false) 처리
|
|
/// </summary>
|
|
private void OnItemVisibilityChangedHandler(TreeListItemData item, bool isVisible)
|
|
{
|
|
Debug.Log($"[StudioSideTabBarHierarchy] Item visibility changed: {item.Name} (ExternalKey: {item.ExternalKey}), IsVisible: {isVisible}");
|
|
|
|
if (_selectionManager == null || string.IsNullOrEmpty(item.ExternalKey)) return;
|
|
|
|
// SelectionManager를 통해 객체 가시성 설정
|
|
_selectionManager.SetVisibilityById(item.ExternalKey, isVisible);
|
|
}
|
|
|
|
protected async void Start()
|
|
{
|
|
// InjectorSceneContext 초기화 대기
|
|
await InjectorSceneContext.Instance.WaitForInitializationAsync();
|
|
|
|
// StageObjectManager 가져오기
|
|
_stageObjectManager = InjectorAppContext.Instance.Get<StageObjectManager>();
|
|
if (_stageObjectManager != null)
|
|
{
|
|
// 이벤트 구독
|
|
_stageObjectManager.OnObjectAdded += OnStageObjectAdded;
|
|
_stageObjectManager.OnObjectRemoved += OnStageObjectRemoved;
|
|
|
|
// 이미 등록된 객체들 반영
|
|
foreach (var kvp in _stageObjectManager.Objects)
|
|
{
|
|
AddTreeItem(kvp.Value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("[StudioSideTabBarHierarchy] StageObjectManager not found.");
|
|
}
|
|
|
|
// SelectionManager 가져오기
|
|
_selectionManager = InjectorAppContext.Instance.Get<SelectionManager>();
|
|
if (_selectionManager != null)
|
|
{
|
|
// 선택 변경 이벤트 구독 (화면 클릭으로 선택 시 HierarchyWindow 동기화)
|
|
_selectionManager.OnSelectionChanged += OnSelectionManagerSelectionChanged;
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("[StudioSideTabBarHierarchy] SelectionManager not found.");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// SelectionManager에서 선택이 변경되었을 때 호출 (화면에서 객체 클릭 시)
|
|
/// HierarchyWindow의 선택 상태를 동기화
|
|
/// </summary>
|
|
private void OnSelectionManagerSelectionChanged(StageObjectManager.StageObject stageObject, bool isSelected)
|
|
{
|
|
if (_isProcessingSelection) return;
|
|
if (hierarchyWindow == null || string.IsNullOrEmpty(stageObject.Id)) return;
|
|
|
|
// 매핑에서 TreeListItemData 찾기
|
|
if (!_stageObjectToTreeItem.TryGetValue(stageObject.Id, out var treeItem)) return;
|
|
|
|
_isProcessingSelection = true;
|
|
try
|
|
{
|
|
if (isSelected)
|
|
{
|
|
// HierarchyWindow에서 해당 아이템 선택
|
|
hierarchyWindow.SelectItem(treeItem.Name);
|
|
Debug.Log($"[StudioSideTabBarHierarchy] Synced selection to HierarchyWindow: {treeItem.Name}");
|
|
}
|
|
else
|
|
{
|
|
// HierarchyWindow에서 해당 아이템 선택 해제
|
|
hierarchyWindow.DeselectItem(treeItem.Name);
|
|
Debug.Log($"[StudioSideTabBarHierarchy] Synced deselection to HierarchyWindow: {treeItem.Name}");
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
_isProcessingSelection = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// StageObject가 추가될 때 호출
|
|
/// </summary>
|
|
private void OnStageObjectAdded(StageObjectManager.StageObject stageObject)
|
|
{
|
|
AddTreeItem(stageObject);
|
|
}
|
|
|
|
/// <summary>
|
|
/// StageObject가 제거될 때 호출
|
|
/// </summary>
|
|
private void OnStageObjectRemoved(StageObjectManager.StageObject stageObject)
|
|
{
|
|
RemoveTreeItem(stageObject);
|
|
}
|
|
|
|
/// <summary>
|
|
/// TreeListItemData를 생성하여 HierarchyWindow에 추가
|
|
/// </summary>
|
|
private void AddTreeItem(StageObjectManager.StageObject stageObject)
|
|
{
|
|
if (hierarchyWindow == null) return;
|
|
|
|
// 이미 존재하는지 확인
|
|
if (_stageObjectToTreeItem.ContainsKey(stageObject.Id))
|
|
{
|
|
Debug.LogWarning($"[StudioSideTabBarHierarchy] TreeItem already exists for StageObject: {stageObject.Id}");
|
|
return;
|
|
}
|
|
|
|
// TreeListItemData 생성
|
|
var treeItem = new TreeListItemData(stageObject.GameObject != null ? stageObject.GameObject.name : stageObject.Equipment.model)
|
|
{
|
|
ExternalKey = stageObject.Id
|
|
};
|
|
|
|
// 매핑 저장
|
|
_stageObjectToTreeItem[stageObject.Id] = treeItem;
|
|
|
|
// HierarchyWindow에 추가
|
|
hierarchyWindow.AddItem(treeItem);
|
|
|
|
Debug.Log($"[StudioSideTabBarHierarchy] Added TreeItem: {treeItem.Name}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// TreeListItemData를 HierarchyWindow에서 제거
|
|
/// </summary>
|
|
private void RemoveTreeItem(StageObjectManager.StageObject stageObject)
|
|
{
|
|
if (hierarchyWindow == null) return;
|
|
|
|
// 매핑에서 찾기
|
|
if (_stageObjectToTreeItem.TryGetValue(stageObject.Id, out var treeItem))
|
|
{
|
|
// HierarchyWindow에서 제거
|
|
hierarchyWindow.DeleteItem(treeItem);
|
|
|
|
// 매핑에서 제거
|
|
_stageObjectToTreeItem.Remove(stageObject.Id);
|
|
|
|
Debug.Log($"[StudioSideTabBarHierarchy] Removed TreeItem: {treeItem.Name}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// TreeListItemData로 StageObject ID 찾기
|
|
/// </summary>
|
|
public string? GetStageObjectId(TreeListItemData treeItem)
|
|
{
|
|
return treeItem.ExternalKey;
|
|
}
|
|
|
|
/// <summary>
|
|
/// StageObject ID로 TreeListItemData 찾기
|
|
/// </summary>
|
|
public TreeListItemData? GetTreeItem(string stageObjectId)
|
|
{
|
|
return _stageObjectToTreeItem.TryGetValue(stageObjectId, out var treeItem) ? treeItem : null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 탭 콘텐츠에 데이터를 전달합니다.
|
|
/// </summary>
|
|
/// <param name="data">전달할 데이터 객체</param>
|
|
public void SetContentData(object? data)
|
|
{
|
|
Debug.Log("StudioSideTabBarHierarchy: SetContentData called");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 탭 전환 시 데이터가 있는 경우 전달 되는 데이터. SetContentData 이후 호출 됨
|
|
/// </summary>
|
|
/// <param name="data">전달할 데이터 객체</param>
|
|
public void UpdateContentData(object? data)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// 닫힐 때 실행되는 로직을 처리합니다.
|
|
/// </summary>
|
|
/// <returns>비동기 닫기 작업을 나타내는 <see cref="UniTask"/>입니다.</returns>
|
|
public UniTask OnCloseAsync()
|
|
{
|
|
Debug.Log("StudioSideTabBarHierarchy: OnClose called");
|
|
return UniTask.CompletedTask;
|
|
}
|
|
|
|
protected void OnDestroy()
|
|
{
|
|
if (hierarchyWindow != null)
|
|
{
|
|
hierarchyWindow.OnItemSelected -= OnItemSelectedHandler;
|
|
hierarchyWindow.OnItemDeselected -= OnItemDeselectedHandler;
|
|
hierarchyWindow.OnItemVisibilityChanged -= OnItemVisibilityChangedHandler;
|
|
}
|
|
|
|
// StageObjectManager 이벤트 구독 해제
|
|
if (_stageObjectManager != null)
|
|
{
|
|
_stageObjectManager.OnObjectAdded -= OnStageObjectAdded;
|
|
_stageObjectManager.OnObjectRemoved -= OnStageObjectRemoved;
|
|
_stageObjectManager = null;
|
|
}
|
|
|
|
// SelectionManager 이벤트 구독 해제
|
|
if (_selectionManager != null)
|
|
{
|
|
_selectionManager.OnSelectionChanged -= OnSelectionManagerSelectionChanged;
|
|
_selectionManager = null;
|
|
}
|
|
|
|
// 매핑 정리
|
|
_stageObjectToTreeItem.Clear();
|
|
}
|
|
}
|
|
} |