#nullable enable using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UIElements; namespace UVC.UIToolkit { /// /// UTKComponentList와 탭 기능을 결합하여 윈도우 형태로 제공하는 컴포넌트입니다. /// /// 개요: /// /// UTKComponentTabListWindow는 UTKComponentList를 내부에 포함하고 헤더(타이틀, 닫기 버튼)와 /// 탭 버튼들을 추가한 윈도우 형태의 컴포넌트입니다. 탭을 통해 카테고리별 필터링이 가능합니다. /// /// /// UXML 사용 예시: /// /// /// /// /// ]]> /// /// C# 사용 예시: /// ("tab-list-window"); /// /// // 2. 윈도우 제목 및 닫기 버튼 설정 /// tabWindow.Title = "에셋 라이브러리"; /// tabWindow.ShowCloseButton = true; /// /// // 3. 데이터 구성 - 카테고리별로 자동 탭 생성됨 /// var data = new List /// { /// // 첫 번째 카테고리 → "캐릭터" 탭 자동 생성 /// new UTKComponentListCategoryData /// { /// name = "캐릭터", /// isExpanded = true, /// children = new List /// { /// new UTKComponentListItemData { name = "플레이어", ExternalKey = "player" }, /// new UTKComponentListItemData { name = "NPC", ExternalKey = "npc" } /// } /// }, /// // 두 번째 카테고리 → "오브젝트" 탭 자동 생성 /// new UTKComponentListCategoryData /// { /// name = "오브젝트", /// isExpanded = true, /// children = new List /// { /// new UTKComponentListItemData { name = "상자", ExternalKey = "box" }, /// new UTKComponentListItemData { name = "나무", ExternalKey = "tree" } /// } /// } /// }; /// tabWindow.SetData(data); /// // → "All" 탭과 "캐릭터", "오브젝트" 탭이 자동 생성됨 /// /// // 4. 탭 선택 (프로그래밍 방식) /// tabWindow.SelectTab(-1); // -1 = "All" 전체 탭 /// tabWindow.SelectTab(0); // 0 = 첫 번째 카테고리 ("캐릭터") /// tabWindow.SelectTab(1); // 1 = 두 번째 카테고리 ("오브젝트") /// /// // 5. 선택 이벤트 구독 /// tabWindow.OnItemSelected = (selectedItems) => /// { /// foreach (var item in selectedItems) /// { /// Debug.Log($"선택됨: {item.name}"); /// } /// }; /// /// // 6. 선택 해제 이벤트 /// tabWindow.OnItemDeselected = (deselectedItems) => /// { /// foreach (var item in deselectedItems) /// { /// Debug.Log($"선택 해제: {item.name}"); /// } /// }; /// /// // 7. 가시성 변경 이벤트 (눈 아이콘) /// tabWindow.OnItemVisibilityChanged += (item, isVisible) => /// { /// var gameObject = FindGameObjectByKey(item.ExternalKey); /// if (gameObject != null) /// { /// gameObject.SetActive(isVisible); /// } /// }; /// /// // 8. 삭제 이벤트 (Delete/Backspace 키) /// tabWindow.EnabledDeleteItem = true; /// tabWindow.OnItemDeleted = (item) => /// { /// Debug.Log($"삭제 요청: {item.name}"); /// tabWindow.DeleteItem(item); // 탭 목록도 자동 갱신됨 /// }; /// /// // 9. 더블클릭 이벤트 /// tabWindow.OnItemDoubleClicked = (item) => /// { /// FocusCameraOn(item.ExternalKey); /// }; /// /// // 10. 윈도우 닫힘 이벤트 /// tabWindow.OnClosed += () => /// { /// Debug.Log("윈도우가 닫혔습니다."); /// }; /// /// // 11. 프로그래밍 방식 선택 /// tabWindow.SelectItem("플레이어", notify: true); /// tabWindow.DeselectItem("플레이어", notify: false); /// tabWindow.ClearSelection(); /// /// // 12. 아이템 추가/삭제 (탭 자동 갱신) /// var newCategory = new UTKComponentListCategoryData { name = "이펙트" }; /// tabWindow.AddItem(newCategory); // "이펙트" 탭 자동 생성 /// /// var newItem = new UTKComponentListItemData { name = "폭발" }; /// tabWindow.AddItem(newCategory, newItem); // 카테고리에 아이템 추가 /// /// tabWindow.DeleteItem(newItem); // 아이템 삭제 /// /// // 13. 윈도우 표시 /// tabWindow.Show(); /// /// // 14. 리소스 해제 (OnDestroy에서 호출) /// tabWindow.Dispose(); /// ]]> /// /// 탭 동작 설명: /// /// "All" 탭: 모든 카테고리와 아이템을 표시합니다. /// 카테고리 탭: 해당 카테고리의 자식 아이템만 표시합니다 (부모 카테고리 없이). /// 탭별 검색어가 저장되어, 탭 전환 시 해당 탭의 검색어가 복원됩니다. /// /// [UxmlElement] public partial class UTKComponentTabListWindow : VisualElement, IDisposable { #region IDisposable private bool _disposed = false; #endregion #region 상수 (Constants) /// 메인 UXML 파일 경로 (Resources 폴더 기준) private const string UXML_PATH = "UIToolkit/Window/UTKComponentTabListWindow"; /// USS 파일 경로 (Resources 폴더 기준) private const string USS_PATH = "UIToolkit/Window/UTKComponentListWindowUss"; /// "전체" 탭을 나타내는 인덱스 private const int ALL_TAB_INDEX = -1; #endregion #region UI 컴포넌트 참조 (UI Component References) /// 내부 UTKComponentList 컴포넌트 private UTKComponentList? _componentList; /// 탭 버튼 컨테이너 private VisualElement? _tabContainer; /// 트리 리스트 닫기 버튼 (UTKButton) private UTKButton? _closeButton; /// 윈도우 제목 라벨 private Label? _titleLabel; #endregion #region 탭 관련 데이터 (Tab Data) /// 원본 전체 데이터 private List _originalRoots = new(); /// 현재 선택된 탭 인덱스 (-1: 전체) private int _selectedTabIndex = ALL_TAB_INDEX; /// 탭 버튼들 private List