Files
XRLib/Assets/Scripts/UVC/UIToolkit/Window/UTKComponentListWindow.cs
2025-12-30 20:38:25 +09:00

290 lines
10 KiB
C#

#nullable enable
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
using UVC.UIToolkit.List;
namespace UVC.UIToolkit.Window
{
/// <summary>
/// UTKComponentList를 래핑하여 윈도우 형태로 제공하는 컴포넌트입니다.
///
/// <para><b>개요:</b></para>
/// <para>
/// UTKComponentListWindow는 UTKComponentList를 내부에 포함하고 헤더(타이틀, 닫기 버튼)를 추가한
/// 윈도우 형태의 컴포넌트입니다. 모든 트리 관련 기능은 내부 UTKComponentList에 위임됩니다.
/// </para>
///
/// <para><b>UXML에서 사용:</b></para>
/// <code>
/// <UVC.UIToolkit.Window.UTKComponentListWindow name="tree-list-window" />
/// </code>
///
/// <para><b>코드에서 사용:</b></para>
/// <code>
/// var window = root.Q<UTKComponentListWindow>();
/// window.OnItemSelected += (items) => Debug.Log($"선택: {items[0].name}");
/// window.SetData(treeItems);
/// </code>
/// </summary>
[UxmlElement]
public partial class UTKComponentListWindow : VisualElement, IDisposable
{
#region IDisposable
private bool _disposed = false;
#endregion
#region (Constants)
/// <summary>메인 UXML 파일 경로 (Resources 폴더 기준)</summary>
private const string UXML_PATH = "UIToolkit/Window/UTKComponentListWindow";
#endregion
#region UI (UI Component References)
/// <summary>내부 UTKComponentList 컴포넌트</summary>
private UTKComponentList? _componentList;
/// <summary>트리 리스트 닫기 버튼</summary>
private Button? _closeButton;
#endregion
#region (Public Properties)
/// <summary>
/// 항목 삭제 기능 활성화 여부입니다.
/// true일 때만 Delete/Backspace 키로 항목 삭제 이벤트가 발생합니다.
/// 기본값은 false입니다.
/// </summary>
public bool EnabledDeleteItem
{
get => _componentList?.EnabledDeleteItem ?? false;
set { if (_componentList != null) _componentList.EnabledDeleteItem = value; }
}
#endregion
#region (Public Events)
/// <summary>
/// 메인/검색 리스트에서 항목이 선택될 때 발생합니다.
/// </summary>
public Action<List<UTKComponentListItemData>>? OnItemSelected
{
get => _componentList?.OnItemSelected;
set { if (_componentList != null) _componentList.OnItemSelected = value; }
}
/// <summary>
/// 메인/검색 리스트에서 항목이 선택 해제될 때 발생합니다.
/// </summary>
public Action<List<UTKComponentListItemData>>? OnItemDeselected
{
get => _componentList?.OnItemDeselected;
set { if (_componentList != null) _componentList.OnItemDeselected = value; }
}
/// <summary>
/// 항목의 가시성(눈 아이콘)이 변경될 때 발생합니다.
/// </summary>
public event Action<UTKComponentListItemData, bool>? OnItemVisibilityChanged
{
add { if (_componentList != null) _componentList.OnItemVisibilityChanged += value; }
remove { if (_componentList != null) _componentList.OnItemVisibilityChanged -= value; }
}
/// <summary>
/// 메인/검색 리스트에서 항목이 삭제될 때 발생합니다 (Delete 키).
/// </summary>
public Action<UTKComponentListItemData>? OnItemDeleted
{
get => _componentList?.OnItemDeleted;
set { if (_componentList != null) _componentList.OnItemDeleted = value; }
}
/// <summary>
/// 메인/검색 리스트에서 항목이 더블클릭될 때 발생합니다.
/// </summary>
public Action<UTKComponentListItemData>? OnItemDoubleClicked
{
get => _componentList?.OnItemDoubleClicked;
set { if (_componentList != null) _componentList.OnItemDoubleClicked = value; }
}
/// <summary>
/// 아이콘을 클릭할 때 발생합니다.
/// </summary>
public Action<string, UTKComponentListItemData>? OnItemIconClicked
{
get => _componentList?.OnItemIconClicked;
set { if (_componentList != null) _componentList.OnItemIconClicked = value; }
}
/// <summary>
/// 트리 리스트가 닫힐 때(숨겨질 때) 발생합니다.
/// 닫기 버튼 클릭 시 트리거됩니다.
/// </summary>
public event Action? OnClosed;
#endregion
#region (Constructor)
/// <summary>
/// UTKComponentListWindow 컴포넌트를 초기화합니다.
/// UXML 템플릿을 로드하고 내부 UTKComponentList를 설정합니다.
/// </summary>
public UTKComponentListWindow()
{
// 1. 메인 UXML 로드 및 복제
var visualTree = Resources.Load<VisualTreeAsset>(UXML_PATH);
if (visualTree == null)
{
Debug.LogError($"[UTKComponentListWindow] UXML not found at: {UXML_PATH}");
return;
}
visualTree.CloneTree(this);
// 2. 내부 UTKComponentList 찾기 (UXML의 ui:Instance로 생성된 컴포넌트)
_componentList = this.Q<UTKComponentList>();
if (_componentList == null)
{
Debug.LogError("[UTKComponentListWindow] UTKComponentList not found in UXML");
return;
}
// 3. 닫기 버튼 찾기 및 이벤트 연결
_closeButton = this.Q<Button>("close-btn");
if (_closeButton != null)
{
_closeButton.clicked += () =>
{
this.style.display = DisplayStyle.None;
OnClosed?.Invoke();
};
}
}
#endregion
#region (Public Methods)
/// <summary>
/// 트리 리스트를 화면에 표시합니다.
/// </summary>
public void Show()
{
this.style.display = DisplayStyle.Flex;
_componentList?.Show();
}
/// <summary>
/// 트리 데이터를 설정합니다.
/// </summary>
/// <param name="roots">루트 항목들의 리스트</param>
public void SetData(List<UTKComponentListItemData> roots)
{
_componentList?.SetData(roots);
}
/// <summary>
/// 지정된 ID의 항목을 프로그래밍 방식으로 선택합니다.
/// </summary>
/// <param name="itemId">선택할 항목의 ID</param>
public void SelectByItemId(int itemId)
{
_componentList?.SelectByItemId(itemId);
}
/// <summary>
/// 지정된 이름 목록에 해당하는 항목만 표시하고 나머지는 숨깁니다.
/// </summary>
/// <param name="items">표시할 항목들의 이름 목록</param>
/// <param name="depth">검색 깊이</param>
public void ShowItems(List<string> items, int depth = 1)
{
_componentList?.ShowItems(items, depth);
}
/// <summary>
/// 루트 레벨에 새 항목을 추가합니다.
/// </summary>
/// <param name="data">추가할 항목 데이터</param>
public void AddItem(UTKComponentListItemData data)
{
_componentList?.AddItem(data);
}
/// <summary>
/// 지정된 부모 항목의 자식으로 새 항목을 추가합니다.
/// </summary>
/// <param name="parent">부모 항목</param>
/// <param name="data">추가할 항목 데이터</param>
public void AddItem(UTKComponentListItemData? parent, UTKComponentListItemData data)
{
_componentList?.AddItem(parent, data);
}
/// <summary>
/// 트리에서 항목을 완전히 삭제합니다.
/// </summary>
/// <param name="data">삭제할 항목 데이터</param>
public void DeleteItem(UTKComponentListItemData data)
{
_componentList?.DeleteItem(data);
}
/// <summary>
/// 항목의 이름을 변경하고 UI를 갱신합니다.
/// </summary>
/// <param name="data">변경할 항목 데이터</param>
/// <param name="newName">새 이름</param>
public void SetItemName(UTKComponentListItemData data, string newName)
{
_componentList?.SetItemName(data, newName);
}
/// <summary>
/// 이름으로 항목을 찾아 선택합니다.
/// </summary>
/// <param name="name">선택할 항목의 이름</param>
/// <param name="notify">선택 이벤트 발송 여부</param>
public void SelectItem(string name, bool notify = true)
{
_componentList?.SelectItem(name, notify);
}
/// <summary>
/// 이름으로 항목을 찾아 선택을 해제합니다.
/// </summary>
/// <param name="name">선택 해제할 항목의 이름</param>
/// <param name="notify">선택 해제 이벤트 발송 여부</param>
public void DeselectItem(string name, bool notify = true)
{
_componentList?.DeselectItem(name, notify);
}
/// <summary>
/// 모든 항목의 선택을 해제합니다.
/// </summary>
public void ClearSelection()
{
_componentList?.ClearSelection();
}
#endregion
#region IDisposable
/// <summary>
/// 리소스를 해제하고 이벤트 핸들러를 정리합니다.
/// </summary>
public void Dispose()
{
if (_disposed) return;
_disposed = true;
// 내부 UTKComponentList 정리
_componentList?.Dispose();
_componentList = null;
// 외부 이벤트 구독자 정리
OnClosed = null;
// UI 참조 정리
_closeButton = null;
}
#endregion
}
}