UTKAccodion 완료. UTKComponentList 수정 중
This commit is contained in:
@@ -306,9 +306,10 @@ namespace UVC.UIToolkit
|
||||
if (!string.IsNullOrEmpty(icon))
|
||||
{
|
||||
// 1순위: UTKMaterialIcons에 해당하는지 확인
|
||||
if (UTKMaterialIcons.GetIcon(icon) != null)
|
||||
string iconChar = UTKMaterialIcons.GetIcon(icon);
|
||||
if (iconChar != string.Empty)
|
||||
{
|
||||
SetMaterialIcon(icon, iconSize);
|
||||
SetMaterialIcon(iconChar, iconSize);
|
||||
}
|
||||
// 2순위: UTKImageIcons에 해당하는지 확인
|
||||
else if (!string.IsNullOrEmpty(UTKImageIcons.GetPath(icon)))
|
||||
@@ -536,8 +537,8 @@ namespace UVC.UIToolkit
|
||||
/// <param name="fontSize">아이콘 폰트 크기 (null이면 버튼 크기에 맞춤)</param>
|
||||
public void SetMaterialIconByName(string iconName, int? fontSize = null)
|
||||
{
|
||||
var iconChar = UTKMaterialIcons.GetIcon(iconName);
|
||||
if (!string.IsNullOrEmpty(iconChar))
|
||||
string iconChar = UTKMaterialIcons.GetIcon(iconName);
|
||||
if (iconChar != string.Empty)
|
||||
{
|
||||
SetMaterialIcon(iconChar, fontSize);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
@@ -41,6 +42,9 @@ namespace UVC.UIToolkit
|
||||
/// // 아이콘 존재 여부 확인
|
||||
/// if (UTKMaterialIcons.HasIcon("search")) { }
|
||||
///
|
||||
/// // 존재하는 유니코드 문자인지 확인
|
||||
/// if (UTKMaterialIcons.IsIconChar("□")) { }
|
||||
///
|
||||
/// // 전체 아이콘 이름 순회
|
||||
/// foreach (var name in UTKMaterialIcons.GetAllIconNames()) { }
|
||||
///
|
||||
@@ -152,10 +156,10 @@ namespace UVC.UIToolkit
|
||||
/// </summary>
|
||||
/// <param name="element">스타일을 적용할 요소</param>
|
||||
/// <param name="fontSize">폰트 크기 (기본값: 24)</param>
|
||||
public static void ApplyIconStyle(VisualElement element, int fontSize = 24)
|
||||
public static void ApplyIconStyle(VisualElement element, int? fontSize = 24)
|
||||
{
|
||||
element.style.unityFontDefinition = GetFontDefinition();
|
||||
element.style.fontSize = fontSize;
|
||||
if(fontSize != null) element.style.fontSize = fontSize.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -12501,6 +12505,7 @@ namespace UVC.UIToolkit
|
||||
/// <returns>아이콘 문자, 없으면 빈 문자열</returns>
|
||||
public static string GetIcon(string iconName)
|
||||
{
|
||||
if(IsIconChar(iconName)) return iconName;
|
||||
return _iconsByName.TryGetValue(iconName, out var icon) ? icon : string.Empty;
|
||||
}
|
||||
|
||||
@@ -12509,6 +12514,11 @@ namespace UVC.UIToolkit
|
||||
/// </summary>
|
||||
public static bool HasIcon(string iconName) => _iconsByName.ContainsKey(iconName);
|
||||
|
||||
/// <summary>
|
||||
/// 유니코드 문자로 아이콘이 존재하는지 확인합니다.
|
||||
/// </summary>
|
||||
public static bool IsIconChar(string iconChar) => _iconsByName.Values.Contains(iconChar);
|
||||
|
||||
/// <summary>
|
||||
/// 모든 아이콘 이름 목록을 반환합니다.
|
||||
/// </summary>
|
||||
|
||||
@@ -694,8 +694,8 @@ namespace UVC.UIToolkit
|
||||
/// <param name="fontSize">아이콘 폰트 크기 (null이면 텍스트 크기에 맞춤)</param>
|
||||
public void SetMaterialIconByName(string iconName, int? fontSize = null)
|
||||
{
|
||||
var iconChar = UTKMaterialIcons.GetIcon(iconName);
|
||||
if (!string.IsNullOrEmpty(iconChar))
|
||||
string iconChar = UTKMaterialIcons.GetIcon(iconName);
|
||||
if (iconChar != string.Empty)
|
||||
{
|
||||
SetMaterialIcon(iconChar, fontSize);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,88 @@ namespace UVC.UIToolkit
|
||||
/// <item>비동기 이미지 로딩 및 캐싱</item>
|
||||
/// </list>
|
||||
///
|
||||
/// <para><b>UXML 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// <!-- UXML 파일에서 UTKAccordionList 사용 -->
|
||||
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
|
||||
/// <utk:UTKAccordionList name="accordion-list" />
|
||||
/// </ui:UXML>
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>C# 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// // 1. 아코디언 리스트 참조 획득
|
||||
/// var accordionList = root.Q<UTKAccordionList>("accordion-list");
|
||||
///
|
||||
/// // 2. 데이터 구성 - 섹션(카테고리)과 그리드 아이템
|
||||
/// var data = new List<UTKAccordionItemData>
|
||||
/// {
|
||||
/// // 섹션 생성 (카테고리)
|
||||
/// new UTKAccordionItemData
|
||||
/// {
|
||||
/// nodeType = UTKAccordionNodeType.Section,
|
||||
/// name = "가구",
|
||||
/// isExpanded = true,
|
||||
/// children = new List<UTKAccordionItemData>
|
||||
/// {
|
||||
/// // 그리드 아이템 (이미지 + 캡션)
|
||||
/// new UTKAccordionItemData
|
||||
/// {
|
||||
/// nodeType = UTKAccordionNodeType.GridItem,
|
||||
/// name = "의자",
|
||||
/// caption = "사무용 의자",
|
||||
/// imagePath = "Prefabs/Thumbnails/chair",
|
||||
/// prefabPath = "Prefabs/Furniture/Chair"
|
||||
/// },
|
||||
/// new UTKAccordionItemData
|
||||
/// {
|
||||
/// nodeType = UTKAccordionNodeType.GridItem,
|
||||
/// name = "책상",
|
||||
/// caption = "사무용 책상",
|
||||
/// imagePath = "Prefabs/Thumbnails/desk",
|
||||
/// prefabPath = "Prefabs/Furniture/Desk"
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 3. 데이터 설정
|
||||
/// accordionList.SetData(data);
|
||||
///
|
||||
/// // 4. 이벤트 구독 - 아이템 클릭
|
||||
/// accordionList.OnItemClick += (item) =>
|
||||
/// {
|
||||
/// Debug.Log($"클릭된 아이템: {item.name}");
|
||||
/// };
|
||||
///
|
||||
/// // 5. 드래그 앤 드롭 이벤트
|
||||
/// accordionList.OnItemDrop += (item) =>
|
||||
/// {
|
||||
/// // 드롭된 위치에 프리팹 인스턴스화
|
||||
/// if (!string.IsNullOrEmpty(item.prefabPath))
|
||||
/// {
|
||||
/// var prefab = Resources.Load<GameObject>(item.prefabPath);
|
||||
/// Instantiate(prefab, dropPosition, Quaternion.identity);
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 6. 리스트 영역 밖으로 드래그 시 3D 미리보기 표시
|
||||
/// accordionList.OnDragExitList += (item, screenPos) =>
|
||||
/// {
|
||||
/// Show3DPreview(item.prefabPath, screenPos);
|
||||
/// };
|
||||
///
|
||||
/// // 7. 검색 실행
|
||||
/// accordionList.Search("의자");
|
||||
///
|
||||
/// // 8. 모든 섹션 펼치기/접기
|
||||
/// accordionList.ExpandAll();
|
||||
/// accordionList.CollapseAll();
|
||||
///
|
||||
/// // 9. 리소스 해제 (OnDestroy에서 호출)
|
||||
/// accordionList.Dispose();
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>관련 리소스:</b></para>
|
||||
/// <list type="bullet">
|
||||
/// <item>Resources/UIToolkit/List/UTKAccordionList.uxml - 메인 레이아웃</item>
|
||||
@@ -47,6 +129,7 @@ namespace UVC.UIToolkit
|
||||
#region 상수 (Constants)
|
||||
|
||||
private const string UXML_PATH = "UIToolkit/List/UTKAccordionList";
|
||||
private const string USS_PATH = "UIToolkit/List/UTKAccordionListUss";
|
||||
private const string SECTION_UXML_PATH = "UIToolkit/List/UTKAccordionSection";
|
||||
private const string HORIZONTAL_ITEM_UXML_PATH = "UIToolkit/List/UTKAccordionHorizontalItem";
|
||||
private const string GRID_ITEM_UXML_PATH = "UIToolkit/List/UTKAccordionGridItem";
|
||||
@@ -67,7 +150,7 @@ namespace UVC.UIToolkit
|
||||
#region UI 컴포넌트 참조 (UI Component References)
|
||||
|
||||
private TextField? _searchField;
|
||||
private Button? _clearButton;
|
||||
private UTKButton? _clearButton;
|
||||
private Label? _searchResultLabel;
|
||||
private TreeView? _treeView;
|
||||
|
||||
@@ -179,9 +262,6 @@ namespace UVC.UIToolkit
|
||||
|
||||
public UTKAccordionList()
|
||||
{
|
||||
// 테마 적용
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
|
||||
// 메인 UXML 로드
|
||||
var visualTree = Resources.Load<VisualTreeAsset>(UXML_PATH);
|
||||
if (visualTree == null)
|
||||
@@ -194,10 +274,27 @@ namespace UVC.UIToolkit
|
||||
// 템플릿 로드
|
||||
LoadTemplates();
|
||||
|
||||
// 테마 적용 및 변경 구독
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
SubscribeToThemeChanges();
|
||||
|
||||
// USS 로드 (테마 변수 스타일시트 이후에 로드되어야 변수가 해석됨)
|
||||
var uss = Resources.Load<StyleSheet>(USS_PATH);
|
||||
if (uss != null)
|
||||
{
|
||||
styleSheets.Add(uss);
|
||||
}
|
||||
|
||||
// UI 요소 참조 획득
|
||||
_searchField = this.Q<TextField>("search-field");
|
||||
_clearButton = this.Q<Button>("clear-btn");
|
||||
_clearButton = this.Q<UTKButton>("clear-btn");
|
||||
_searchResultLabel = this.Q<Label>("search-result-label");
|
||||
|
||||
// Clear 버튼 아이콘 설정
|
||||
if (_clearButton != null)
|
||||
{
|
||||
_clearButton.SetMaterialIcon(UTKMaterialIcons.Close, 12);
|
||||
}
|
||||
_treeView = this.Q<TreeView>("accordion-tree-view");
|
||||
|
||||
// 초기화
|
||||
@@ -234,7 +331,7 @@ namespace UVC.UIToolkit
|
||||
// 검색어 지우기 버튼
|
||||
if (_clearButton != null)
|
||||
{
|
||||
_clearButton.clicked += OnClearButtonClicked;
|
||||
_clearButton.OnClicked += OnClearButtonClicked;
|
||||
// 초기에는 숨김
|
||||
_clearButton.style.display = DisplayStyle.None;
|
||||
}
|
||||
@@ -734,7 +831,7 @@ namespace UVC.UIToolkit
|
||||
var tailBtn = CreateTailButton(tailSpec);
|
||||
if (tailBtn != null)
|
||||
{
|
||||
tailBtn.clicked += () =>
|
||||
tailBtn.OnClicked += () =>
|
||||
{
|
||||
// 레거시 이벤트
|
||||
var legacyItem = ConvertToLegacyHorizontalItem(item);
|
||||
@@ -897,21 +994,11 @@ namespace UVC.UIToolkit
|
||||
}, TrickleDown.TrickleDown);
|
||||
}
|
||||
|
||||
private Button CreateTailButton(UTKAccordionContentSpec spec)
|
||||
private UTKButton CreateTailButton(UTKAccordionContentSpec spec)
|
||||
{
|
||||
var btn = new Button();
|
||||
var btn = new UTKButton("", spec.IconName ?? "", UTKButton.ButtonVariant.Text, spec.IconSize ?? 12) { IconOnly = true };
|
||||
btn.AddToClassList("accordion-tail-button");
|
||||
|
||||
var icon = new VisualElement();
|
||||
icon.AddToClassList("accordion-tail-icon");
|
||||
|
||||
if (!string.IsNullOrEmpty(spec.IconName))
|
||||
{
|
||||
LoadIconAsync(icon, spec.IconName).Forget();
|
||||
}
|
||||
|
||||
btn.Add(icon);
|
||||
|
||||
if (!string.IsNullOrEmpty(spec.Tooltip))
|
||||
{
|
||||
btn.tooltip = spec.Tooltip;
|
||||
@@ -924,8 +1011,24 @@ namespace UVC.UIToolkit
|
||||
{
|
||||
if (spec.Kind == UTKAccordionContentKind.Image && !string.IsNullOrEmpty(spec.ImagePath))
|
||||
{
|
||||
BindImageAsync(imageElement, spec.ImagePath).Forget();
|
||||
imageElement.style.unityBackgroundImageTintColor = spec.ImageColor;
|
||||
|
||||
string iconChar = UTKMaterialIcons.GetIcon(spec.ImagePath);
|
||||
Debug.Log($"[UTKAccordionList] Content image path: '{spec.ImagePath} ' → icon char: '{iconChar}'");
|
||||
if (iconChar != string.Empty)
|
||||
{
|
||||
Debug.Log($"[UTKAccordionList] Using material icon '{spec.ImagePath}' for content image.");
|
||||
// 머티리얼 아이콘 사용
|
||||
Label iconLabel = new Label(iconChar);
|
||||
UTKMaterialIcons.ApplyIconStyle(iconLabel, null); //uss에서 설정하기에 null 전달
|
||||
imageElement.Add(iconLabel);
|
||||
if(spec.ImageColor != null) iconLabel.style.color = spec.ImageColor.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 일반 이미지 로드
|
||||
BindImageAsync(imageElement, spec.ImagePath).Forget();
|
||||
if(spec.ImageColor != null) imageElement.style.unityBackgroundImageTintColor = spec.ImageColor.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1586,6 +1689,24 @@ namespace UVC.UIToolkit
|
||||
|
||||
#endregion
|
||||
|
||||
#region 테마 (Theme)
|
||||
|
||||
private void SubscribeToThemeChanges()
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
||||
RegisterCallback<DetachFromPanelEvent>(_ =>
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
});
|
||||
}
|
||||
|
||||
private void OnThemeChanged(UTKTheme theme)
|
||||
{
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
|
||||
public void Dispose()
|
||||
@@ -1593,6 +1714,9 @@ namespace UVC.UIToolkit
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
// 테마 변경 이벤트 해제
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
|
||||
// 이미지 로딩 취소
|
||||
CancelImageLoading();
|
||||
|
||||
@@ -1614,7 +1738,8 @@ namespace UVC.UIToolkit
|
||||
|
||||
if (_clearButton != null)
|
||||
{
|
||||
_clearButton.clicked -= OnClearButtonClicked;
|
||||
_clearButton.OnClicked -= OnClearButtonClicked;
|
||||
_clearButton.Dispose();
|
||||
}
|
||||
|
||||
// TreeView 이벤트 해제
|
||||
|
||||
@@ -47,11 +47,14 @@ namespace UVC.UIToolkit
|
||||
public string? ImagePath { get; set; }
|
||||
|
||||
/// <summary>이미지 색상</summary>
|
||||
public Color ImageColor { get; set; } = Color.white;
|
||||
public Color? ImageColor { get; set; }
|
||||
|
||||
/// <summary>아이콘 이름 또는 경로</summary>
|
||||
public string? IconName { get; set; }
|
||||
|
||||
/// <summary>아이콘 크기 (정사각형 기준, 픽셀 단위)</summary>
|
||||
public int? IconSize { get; set; }
|
||||
|
||||
/// <summary>툴팁 텍스트</summary>
|
||||
public string? Tooltip { get; set; }
|
||||
|
||||
@@ -77,16 +80,17 @@ namespace UVC.UIToolkit
|
||||
{
|
||||
Kind = UTKAccordionContentKind.Image,
|
||||
ImagePath = path,
|
||||
ImageColor = color ?? Color.white,
|
||||
ImageColor = color,
|
||||
Tooltip = tooltip
|
||||
};
|
||||
|
||||
/// <summary>아이콘 버튼 스펙을 생성합니다.</summary>
|
||||
public static UTKAccordionContentSpec FromIconButton(string iconName, string? actionId = null, string? tooltip = null, object? userData = null)
|
||||
public static UTKAccordionContentSpec FromIconButton(string iconName, int iconSize, string? actionId = null, string? tooltip = null, object? userData = null)
|
||||
=> new UTKAccordionContentSpec
|
||||
{
|
||||
Kind = UTKAccordionContentKind.IconButton,
|
||||
IconName = iconName,
|
||||
IconSize = iconSize,
|
||||
ActionId = actionId,
|
||||
Tooltip = tooltip,
|
||||
UserData = userData
|
||||
|
||||
@@ -27,22 +27,123 @@ namespace UVC.UIToolkit
|
||||
/// <item>선택 이벤트 처리</item>
|
||||
/// </list>
|
||||
///
|
||||
/// <para><b>UXML에서 사용:</b></para>
|
||||
/// <code>
|
||||
/// <UVC.UIToolkit.Window.UTKComponentList name="tree-list" />
|
||||
/// </code>
|
||||
/// <para><b>UXML 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// <!-- UXML 파일에서 UTKComponentList 사용 -->
|
||||
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
|
||||
/// <utk:UTKComponentList name="component-list" />
|
||||
/// </ui:UXML>
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>코드에서 사용:</b></para>
|
||||
/// <code>
|
||||
/// var list = root.Q<UTKComponentList>();
|
||||
/// list.OnSelectionChanged += (item) => Debug.Log($"선택: {item.name}");
|
||||
/// list.OnVisibilityChanged += (item) => model.SetActive(item.id, item.IsVisible);
|
||||
/// list.SetData(treeItems);
|
||||
/// </code>
|
||||
/// <para><b>C# 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// // 1. 컴포넌트 리스트 참조 획득
|
||||
/// var componentList = root.Q<UTKComponentList>("component-list");
|
||||
///
|
||||
/// // 2. 데이터 구성 - 카테고리(그룹)와 일반 아이템
|
||||
/// var data = new List<UTKComponentListItemDataBase>
|
||||
/// {
|
||||
/// // 카테고리(그룹) 생성
|
||||
/// new UTKComponentListCategoryData
|
||||
/// {
|
||||
/// name = "모델 그룹 A",
|
||||
/// isExpanded = true,
|
||||
/// children = new List<UTKComponentListItemDataBase>
|
||||
/// {
|
||||
/// // 일반 아이템
|
||||
/// new UTKComponentListItemData
|
||||
/// {
|
||||
/// name = "의자 모델",
|
||||
/// ExternalKey = "chair_001",
|
||||
/// IsVisible = true
|
||||
/// },
|
||||
/// new UTKComponentListItemData
|
||||
/// {
|
||||
/// name = "책상 모델",
|
||||
/// ExternalKey = "desk_001",
|
||||
/// IsVisible = true
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 3. 데이터 설정
|
||||
/// componentList.SetData(data);
|
||||
///
|
||||
/// // 4. 선택 이벤트 구독 - 아이템 선택 시 호출
|
||||
/// componentList.OnItemSelected += (selectedItems) =>
|
||||
/// {
|
||||
/// foreach (var item in selectedItems)
|
||||
/// {
|
||||
/// Debug.Log($"선택됨: {item.name}");
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 5. 선택 해제 이벤트 구독
|
||||
/// componentList.OnItemDeselected += (deselectedItems) =>
|
||||
/// {
|
||||
/// foreach (var item in deselectedItems)
|
||||
/// {
|
||||
/// Debug.Log($"선택 해제: {item.name}");
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 6. 가시성 변경 이벤트 구독 - 눈 아이콘 클릭 시 호출
|
||||
/// componentList.OnItemVisibilityChanged += (item, isVisible) =>
|
||||
/// {
|
||||
/// // 3D 모델의 GameObject 활성화/비활성화
|
||||
/// var gameObject = FindGameObjectByKey(item.ExternalKey);
|
||||
/// if (gameObject != null)
|
||||
/// {
|
||||
/// gameObject.SetActive(isVisible);
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 7. 삭제 이벤트 구독 (Delete/Backspace 키)
|
||||
/// componentList.EnabledDeleteItem = true; // 삭제 기능 활성화 필수
|
||||
/// componentList.OnItemDeleted += (item) =>
|
||||
/// {
|
||||
/// Debug.Log($"삭제 요청: {item.name}");
|
||||
/// componentList.DeleteItem(item); // 리스트에서 제거
|
||||
/// };
|
||||
///
|
||||
/// // 8. 더블클릭 이벤트 구독
|
||||
/// componentList.OnItemDoubleClicked += (item) =>
|
||||
/// {
|
||||
/// Debug.Log($"더블클릭: {item.name}");
|
||||
/// // 카메라 포커스 등의 동작 수행
|
||||
/// };
|
||||
///
|
||||
/// // 9. 아이콘 클릭 이벤트 (setting-btn, search-btn)
|
||||
/// componentList.OnItemIconClicked += (iconName, item) =>
|
||||
/// {
|
||||
/// if (iconName == "setting-btn")
|
||||
/// {
|
||||
/// ShowCategorySettings(item);
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 10. 검색 실행
|
||||
/// componentList.ApplySearch("의자");
|
||||
///
|
||||
/// // 11. 프로그래밍 방식 선택
|
||||
/// componentList.SelectItem("의자 모델", notify: true);
|
||||
/// componentList.DeselectItem("의자 모델", notify: false);
|
||||
/// componentList.ClearSelection();
|
||||
///
|
||||
/// // 12. 아이템 추가/삭제
|
||||
/// var newItem = new UTKComponentListItemData { name = "새 아이템" };
|
||||
/// componentList.AddItem(newItem); // 루트에 추가
|
||||
/// componentList.AddItem(categoryData, newItem); // 특정 카테고리에 추가
|
||||
/// componentList.DeleteItem(newItem); // 삭제
|
||||
///
|
||||
/// // 13. 리소스 해제 (OnDestroy에서 호출)
|
||||
/// componentList.Dispose();
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>관련 리소스:</b></para>
|
||||
/// <list type="bullet">
|
||||
/// <item>Resources/UIToolkit/Window/UTKComponentList.uxml - 메인 레이아웃</item>
|
||||
/// <item>Resources/UIToolkit/List/UTKComponentList.uxml - 메인 레이아웃</item>
|
||||
/// <item>Resources/UIToolkit/List/UTKComponentListItem.uxml - 개별 항목 템플릿</item>
|
||||
/// <item>Resources/UIToolkit/List/UTKComponentListGroupItem.uxml - 그룹 항목 템플릿</item>
|
||||
/// </list>
|
||||
@@ -63,6 +164,8 @@ namespace UVC.UIToolkit
|
||||
/// <summary>메인 UXML 파일 경로 (Resources 폴더 기준)</summary>
|
||||
private const string UXML_PATH = "UIToolkit/List/UTKComponentList";
|
||||
|
||||
private const string USS_PATH = "UIToolkit/List/UTKComponentListUss";
|
||||
|
||||
/// <summary>일반 항목 UXML 파일 경로 (Resources 폴더 기준)</summary>
|
||||
private const string ITEM_UXML_PATH = "UIToolkit/List/UTKComponentListItem";
|
||||
|
||||
@@ -85,8 +188,8 @@ namespace UVC.UIToolkit
|
||||
/// <summary>Unity UI Toolkit의 TreeView 컴포넌트</summary>
|
||||
private TreeView? _treeView;
|
||||
|
||||
/// <summary>검색어 지우기 버튼</summary>
|
||||
private Button? _clearButton;
|
||||
/// <summary>검색어 지우기 버튼 (UTKButton)</summary>
|
||||
private UTKButton? _clearButton;
|
||||
#endregion
|
||||
|
||||
#region 내부 데이터 (Internal Data)
|
||||
@@ -199,6 +302,8 @@ namespace UVC.UIToolkit
|
||||
}
|
||||
visualTree!.CloneTree(this);
|
||||
|
||||
|
||||
|
||||
// 2. 항목 템플릿 로드
|
||||
_itemTemplate = Resources.Load<VisualTreeAsset>(ITEM_UXML_PATH);
|
||||
_groupItemTemplate = Resources.Load<VisualTreeAsset>(GROUP_ITEM_UXML_PATH);
|
||||
@@ -207,13 +312,29 @@ namespace UVC.UIToolkit
|
||||
if (_groupItemTemplate == null)
|
||||
Debug.LogError($"[UTKComponentList] Group Item UXML not found at: {GROUP_ITEM_UXML_PATH}");
|
||||
|
||||
// 테마 적용 및 변경 구독
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
SubscribeToThemeChanges();
|
||||
|
||||
// 2. 자식 요소 참조 획득 (UXML의 name 속성으로 찾음)
|
||||
// USS 로드 (테마 변수 스타일시트 이후에 로드되어야 변수가 해석됨)
|
||||
var uss = Resources.Load<StyleSheet>(USS_PATH);
|
||||
if (uss != null)
|
||||
{
|
||||
styleSheets.Add(uss);
|
||||
}
|
||||
|
||||
// 3. 자식 요소 참조 획득 (UXML의 name 속성으로 찾음)
|
||||
_searchField = this.Q<TextField>("search-field");
|
||||
_treeView = this.Q<TreeView>("main-tree-view");
|
||||
_clearButton = this.Q<Button>("clear-btn");
|
||||
_clearButton = this.Q<UTKButton>("clear-btn");
|
||||
|
||||
// 3. 이벤트 연결 및 로직 초기화
|
||||
// 4. Clear 버튼 아이콘 설정
|
||||
if (_clearButton != null)
|
||||
{
|
||||
_clearButton.SetMaterialIcon(UTKMaterialIcons.Close, 12);
|
||||
}
|
||||
|
||||
// 5. 이벤트 연결 및 로직 초기화
|
||||
InitializeLogic();
|
||||
}
|
||||
#endregion
|
||||
@@ -251,15 +372,7 @@ namespace UVC.UIToolkit
|
||||
if(_clearButton != null)
|
||||
{
|
||||
_clearButton.style.display = DisplayStyle.None; // 초기에는 숨김
|
||||
_clearButton.clicked += () =>
|
||||
{
|
||||
if (_searchField.value.Length > 0)
|
||||
{
|
||||
_searchField.value = string.Empty;
|
||||
OnSearch(string.Empty);
|
||||
}
|
||||
_clearButton.style.display = DisplayStyle.None; // 클리어 후 숨김
|
||||
};
|
||||
_clearButton.OnClicked += OnClearButtonClicked;
|
||||
}
|
||||
|
||||
// 스크롤바 hover/active 색상 설정
|
||||
@@ -1372,6 +1485,22 @@ namespace UVC.UIToolkit
|
||||
OnSearch(_searchField?.value ?? string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear 버튼 클릭 이벤트를 처리합니다.
|
||||
/// </summary>
|
||||
private void OnClearButtonClicked()
|
||||
{
|
||||
if (_searchField != null && _searchField.value.Length > 0)
|
||||
{
|
||||
_searchField.value = string.Empty;
|
||||
OnSearch(string.Empty);
|
||||
}
|
||||
if (_clearButton != null)
|
||||
{
|
||||
_clearButton.style.display = DisplayStyle.None;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 검색어에 따라 트리를 필터링합니다.
|
||||
/// 검색어가 비어있으면 원본 데이터로 복원됩니다.
|
||||
@@ -1562,6 +1691,24 @@ namespace UVC.UIToolkit
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 테마 (Theme)
|
||||
|
||||
private void SubscribeToThemeChanges()
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
||||
RegisterCallback<DetachFromPanelEvent>(_ =>
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
});
|
||||
}
|
||||
|
||||
private void OnThemeChanged(UTKTheme theme)
|
||||
{
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
/// <summary>
|
||||
/// 리소스를 해제하고 이벤트 핸들러를 정리합니다.
|
||||
@@ -1571,6 +1718,9 @@ namespace UVC.UIToolkit
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
// 테마 변경 이벤트 해제
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
|
||||
// 검색 필드 이벤트 해제
|
||||
if (_searchField != null)
|
||||
{
|
||||
@@ -1589,6 +1739,13 @@ namespace UVC.UIToolkit
|
||||
_treeView.makeItem = null;
|
||||
}
|
||||
|
||||
// Clear 버튼 이벤트 해제 및 정리
|
||||
if (_clearButton != null)
|
||||
{
|
||||
_clearButton.OnClicked -= OnClearButtonClicked;
|
||||
_clearButton.Dispose();
|
||||
}
|
||||
|
||||
// 외부 이벤트 구독자 정리
|
||||
OnItemVisibilityChanged = null;
|
||||
OnItemSelected = null;
|
||||
|
||||
@@ -23,22 +23,125 @@ namespace UVC.UIToolkit
|
||||
/// <para><b>주요 기능:</b></para>
|
||||
/// <list type="bullet">
|
||||
/// <item>이미지+텍스트 형태의 아이템을 2열 그리드로 표시</item>
|
||||
/// <item>실시간 검색 필터링 (3글자 이상)</item>
|
||||
/// <item>실시간 검색 필터링 (2글자 이상)</item>
|
||||
/// <item>드래그 앤 드롭 지원</item>
|
||||
/// <item>가상화를 통한 대량 데이터 성능 최적화</item>
|
||||
/// </list>
|
||||
///
|
||||
/// <para><b>UXML에서 사용:</b></para>
|
||||
/// <code>
|
||||
/// <uvc:UTKImageList name="image-list" />
|
||||
/// </code>
|
||||
/// <para><b>UXML 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// <!-- UXML 파일에서 UTKImageList 사용 -->
|
||||
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
|
||||
/// <utk:UTKImageList name="image-list" />
|
||||
/// </ui:UXML>
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>코드에서 사용:</b></para>
|
||||
/// <code>
|
||||
/// var list = root.Q<UTKImageList>();
|
||||
/// list.OnItemClick += (item) => Debug.Log($"클릭: {item.itemName}");
|
||||
/// list.SetData(imageItems);
|
||||
/// </code>
|
||||
/// <para><b>C# 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// // 1. 이미지 리스트 참조 획득
|
||||
/// var imageList = root.Q<UTKImageList>("image-list");
|
||||
///
|
||||
/// // 2. 데이터 구성 - 이미지 경로와 이름을 가진 아이템들
|
||||
/// var data = new List<UTKImageListItemData>
|
||||
/// {
|
||||
/// new UTKImageListItemData
|
||||
/// {
|
||||
/// itemName = "의자",
|
||||
/// imagePath = "Prefabs/Thumbnails/chair",
|
||||
/// prefabPath = "Prefabs/Furniture/Chair"
|
||||
/// },
|
||||
/// new UTKImageListItemData
|
||||
/// {
|
||||
/// itemName = "책상",
|
||||
/// imagePath = "Prefabs/Thumbnails/desk",
|
||||
/// prefabPath = "Prefabs/Furniture/Desk"
|
||||
/// },
|
||||
/// new UTKImageListItemData
|
||||
/// {
|
||||
/// itemName = "소파",
|
||||
/// imagePath = "Prefabs/Thumbnails/sofa",
|
||||
/// prefabPath = "Prefabs/Furniture/Sofa"
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 3. 데이터 설정
|
||||
/// imageList.SetData(data);
|
||||
///
|
||||
/// // 4. 아이템 클릭 이벤트 구독
|
||||
/// imageList.OnItemClick += (item) =>
|
||||
/// {
|
||||
/// Debug.Log($"클릭된 아이템: {item.itemName}");
|
||||
/// };
|
||||
///
|
||||
/// // 5. 드래그 앤 드롭 이벤트 (씬에 프리팹 배치용)
|
||||
/// imageList.OnItemBeginDrag += (item, screenPos) =>
|
||||
/// {
|
||||
/// Debug.Log($"드래그 시작: {item.itemName}");
|
||||
/// };
|
||||
///
|
||||
/// imageList.OnItemDrag += (item, screenPos) =>
|
||||
/// {
|
||||
/// // 드래그 중 - 3D 미리보기 위치 업데이트 등
|
||||
/// };
|
||||
///
|
||||
/// imageList.OnItemEndDrag += (item, screenPos) =>
|
||||
/// {
|
||||
/// Debug.Log($"드래그 종료: {item.itemName}");
|
||||
/// };
|
||||
///
|
||||
/// imageList.OnItemDrop += (item) =>
|
||||
/// {
|
||||
/// // 드롭 완료 - 프리팹 인스턴스화
|
||||
/// if (!string.IsNullOrEmpty(item.prefabPath))
|
||||
/// {
|
||||
/// var prefab = Resources.Load<GameObject>(item.prefabPath);
|
||||
/// Instantiate(prefab, dropPosition, Quaternion.identity);
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 6. 리스트 영역 밖으로 드래그 시 3D 미리보기 표시
|
||||
/// imageList.OnDragExitList += (item, screenPos) =>
|
||||
/// {
|
||||
/// // 리스트 밖 = 3D 씬 영역
|
||||
/// Show3DPreview(item.prefabPath, screenPos);
|
||||
/// };
|
||||
///
|
||||
/// // 7. 리스트 영역 안으로 다시 들어왔을 때 미리보기 숨김
|
||||
/// imageList.OnDragEnterList += (item, screenPos) =>
|
||||
/// {
|
||||
/// Hide3DPreview();
|
||||
/// };
|
||||
///
|
||||
/// // 8. 드래그 영역 설정 (부모 윈도우 영역 기준으로 체크)
|
||||
/// imageList.DragBoundsElement = parentWindow;
|
||||
///
|
||||
/// // 9. 드래그 고스트 이미지 따라다니기 설정
|
||||
/// imageList.DragImageFollowCursor = true;
|
||||
///
|
||||
/// // 10. 검색 실행 (2글자 이상)
|
||||
/// imageList.ApplySearch("의자");
|
||||
///
|
||||
/// // 11. 현재 검색어 확인
|
||||
/// string currentQuery = imageList.SearchQuery;
|
||||
///
|
||||
/// // 12. 아이템 추가/제거
|
||||
/// var newItem = new UTKImageListItemData { itemName = "새 아이템" };
|
||||
/// imageList.AddItem(newItem);
|
||||
/// imageList.RemoveItem(newItem);
|
||||
///
|
||||
/// // 13. 전체 삭제
|
||||
/// imageList.Clear();
|
||||
///
|
||||
/// // 14. 아이템 개수 확인
|
||||
/// int count = imageList.ItemCount;
|
||||
///
|
||||
/// // 15. 리스트 표시/숨김
|
||||
/// imageList.Show();
|
||||
/// imageList.Hide();
|
||||
///
|
||||
/// // 16. 리소스 해제 (OnDestroy에서 호출)
|
||||
/// imageList.Dispose();
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>관련 리소스:</b></para>
|
||||
/// <list type="bullet">
|
||||
@@ -54,6 +157,7 @@ namespace UVC.UIToolkit
|
||||
|
||||
/// <summary>메인 UXML 파일 경로 (Resources 폴더 기준)</summary>
|
||||
private const string UXML_PATH = "UIToolkit/List/UTKImageList";
|
||||
private const string USS_PATH = "UIToolkit/List/UTKImageListUss";
|
||||
|
||||
/// <summary>아이템 UXML 파일 경로 (Resources 폴더 기준)</summary>
|
||||
private const string ITEM_UXML_PATH = "UIToolkit/List/UTKImageListItem";
|
||||
@@ -84,8 +188,8 @@ namespace UVC.UIToolkit
|
||||
/// <summary>Unity UI Toolkit의 ListView 컴포넌트</summary>
|
||||
private ListView? _listView;
|
||||
|
||||
/// <summary>검색어 지우기 버튼</summary>
|
||||
private Button? _clearButton;
|
||||
/// <summary>검색어 지우기 버튼 (UTKButton)</summary>
|
||||
private UTKButton? _clearButton;
|
||||
|
||||
/// <summary>검색 결과 건수 라벨</summary>
|
||||
private Label? _searchResultLabel;
|
||||
@@ -248,13 +352,30 @@ namespace UVC.UIToolkit
|
||||
Debug.LogError($"[UTKImageList] Item UXML not found at: {ITEM_UXML_PATH}");
|
||||
}
|
||||
|
||||
// 3. UI 요소 참조 획득
|
||||
// 3. 테마 적용 및 변경 구독
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
SubscribeToThemeChanges();
|
||||
|
||||
// USS 로드 (테마 변수 스타일시트 이후에 로드되어야 변수가 해석됨)
|
||||
var uss = Resources.Load<StyleSheet>(USS_PATH);
|
||||
if (uss != null)
|
||||
{
|
||||
styleSheets.Add(uss);
|
||||
}
|
||||
|
||||
// 4. UI 요소 참조 획득
|
||||
_searchField = this.Q<TextField>("search-field");
|
||||
_listView = this.Q<ListView>("main-list-view");
|
||||
_clearButton = this.Q<Button>("clear-btn");
|
||||
_clearButton = this.Q<UTKButton>("clear-btn");
|
||||
_searchResultLabel = this.Q<Label>("search-result-label");
|
||||
|
||||
// 4. 이벤트 연결 및 로직 초기화
|
||||
// 5. Clear 버튼 아이콘 설정
|
||||
if (_clearButton != null)
|
||||
{
|
||||
_clearButton.SetMaterialIcon(UTKMaterialIcons.Close, 12);
|
||||
}
|
||||
|
||||
// 6. 이벤트 연결 및 로직 초기화
|
||||
InitializeLogic();
|
||||
}
|
||||
|
||||
@@ -277,7 +398,7 @@ namespace UVC.UIToolkit
|
||||
// 검색어 지우기 버튼 이벤트 등록
|
||||
if (_clearButton != null)
|
||||
{
|
||||
_clearButton.clicked += OnClearButtonClicked;
|
||||
_clearButton.OnClicked += OnClearButtonClicked;
|
||||
_clearButton.style.display = DisplayStyle.None; // 초기에는 숨김
|
||||
}
|
||||
|
||||
@@ -1144,6 +1265,24 @@ namespace UVC.UIToolkit
|
||||
|
||||
#endregion
|
||||
|
||||
#region 테마 (Theme)
|
||||
|
||||
private void SubscribeToThemeChanges()
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
||||
RegisterCallback<DetachFromPanelEvent>(_ =>
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
});
|
||||
}
|
||||
|
||||
private void OnThemeChanged(UTKTheme theme)
|
||||
{
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <summary>
|
||||
@@ -1154,6 +1293,9 @@ namespace UVC.UIToolkit
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
// 테마 변경 이벤트 해제
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
|
||||
// 이미지 로딩 취소
|
||||
CancelImageLoading();
|
||||
|
||||
@@ -1176,7 +1318,8 @@ namespace UVC.UIToolkit
|
||||
|
||||
if (_clearButton != null)
|
||||
{
|
||||
_clearButton.clicked -= OnClearButtonClicked;
|
||||
_clearButton.OnClicked -= OnClearButtonClicked;
|
||||
_clearButton.Dispose();
|
||||
}
|
||||
|
||||
// 드래그 고스트 정리
|
||||
|
||||
@@ -22,6 +22,113 @@ namespace UVC.UIToolkit
|
||||
/// <item>드래그 앤 드롭 이벤트 전달</item>
|
||||
/// </list>
|
||||
///
|
||||
/// <para><b>UXML 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// <!-- UXML 파일에서 UTKAccordionListWindow 사용 -->
|
||||
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
|
||||
/// <utk:UTKAccordionListWindow name="accordion-window" />
|
||||
/// </ui:UXML>
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>C# 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// // 1. 윈도우 참조 획득
|
||||
/// var accordionWindow = root.Q<UTKAccordionListWindow>("accordion-window");
|
||||
///
|
||||
/// // 2. 윈도우 제목 설정
|
||||
/// accordionWindow.Title = "프리팹 라이브러리";
|
||||
///
|
||||
/// // 3. 닫기 버튼 표시 설정
|
||||
/// accordionWindow.ShowCloseButton = true;
|
||||
///
|
||||
/// // 4. 데이터 구성 및 설정
|
||||
/// var data = new List<UTKAccordionItemData>
|
||||
/// {
|
||||
/// new UTKAccordionItemData
|
||||
/// {
|
||||
/// nodeType = UTKAccordionNodeType.Section,
|
||||
/// name = "가구",
|
||||
/// isExpanded = true,
|
||||
/// children = new List<UTKAccordionItemData>
|
||||
/// {
|
||||
/// new UTKAccordionItemData
|
||||
/// {
|
||||
/// nodeType = UTKAccordionNodeType.GridItem,
|
||||
/// name = "의자",
|
||||
/// imagePath = "Prefabs/Thumbnails/chair",
|
||||
/// prefabPath = "Prefabs/Furniture/Chair"
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// };
|
||||
/// accordionWindow.SetData(data);
|
||||
///
|
||||
/// // 5. 아이템 클릭 이벤트 구독 (통합 API)
|
||||
/// accordionWindow.OnItemClick += (item) =>
|
||||
/// {
|
||||
/// Debug.Log($"클릭된 아이템: {item.name}");
|
||||
/// };
|
||||
///
|
||||
/// // 6. 드래그 앤 드롭 이벤트 구독
|
||||
/// accordionWindow.OnItemBeginDrag += (item, screenPos) =>
|
||||
/// {
|
||||
/// Debug.Log($"드래그 시작: {item.name}");
|
||||
/// };
|
||||
///
|
||||
/// accordionWindow.OnItemDrop += (item) =>
|
||||
/// {
|
||||
/// // 프리팹 인스턴스화
|
||||
/// if (!string.IsNullOrEmpty(item.prefabPath))
|
||||
/// {
|
||||
/// var prefab = Resources.Load<GameObject>(item.prefabPath);
|
||||
/// Instantiate(prefab, dropPosition, Quaternion.identity);
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 7. 리스트 영역 밖으로 드래그 시 3D 미리보기 표시
|
||||
/// accordionWindow.OnDragExitList += (gridItem, screenPos) =>
|
||||
/// {
|
||||
/// Show3DPreview(gridItem.PrefabPath, screenPos);
|
||||
/// };
|
||||
///
|
||||
/// // 8. 리스트 영역으로 다시 들어오면 미리보기 숨김
|
||||
/// accordionWindow.OnDragEnterList += (gridItem, screenPos) =>
|
||||
/// {
|
||||
/// Hide3DPreview();
|
||||
/// };
|
||||
///
|
||||
/// // 9. 섹션 펼침/접힘 이벤트
|
||||
/// accordionWindow.OnSectionToggled += (section, isExpanded) =>
|
||||
/// {
|
||||
/// Debug.Log($"섹션 '{section.Title}': {(isExpanded ? "펼침" : "접힘")}");
|
||||
/// };
|
||||
///
|
||||
/// // 10. 윈도우 닫힘 이벤트
|
||||
/// accordionWindow.OnClosed += () =>
|
||||
/// {
|
||||
/// Debug.Log("윈도우가 닫혔습니다.");
|
||||
/// };
|
||||
///
|
||||
/// // 11. 드래그 고스트 이미지 설정
|
||||
/// accordionWindow.ShowDragGhost = true;
|
||||
///
|
||||
/// // 12. 검색 실행
|
||||
/// accordionWindow.Search("의자");
|
||||
/// accordionWindow.ClearSearch();
|
||||
///
|
||||
/// // 13. 섹션 제어
|
||||
/// accordionWindow.ExpandAll();
|
||||
/// accordionWindow.CollapseAll();
|
||||
/// accordionWindow.SetSectionExpanded(sectionId, true);
|
||||
///
|
||||
/// // 14. 윈도우 표시/닫기
|
||||
/// accordionWindow.Show();
|
||||
/// accordionWindow.Close();
|
||||
///
|
||||
/// // 15. 리소스 해제 (OnDestroy에서 호출)
|
||||
/// accordionWindow.Dispose();
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>관련 리소스:</b></para>
|
||||
/// <list type="bullet">
|
||||
/// <item>Resources/UIToolkit/Window/UTKAccordionListWindow.uxml - 윈도우 레이아웃</item>
|
||||
@@ -34,13 +141,14 @@ namespace UVC.UIToolkit
|
||||
#region 상수 (Constants)
|
||||
|
||||
private const string UXML_PATH = "UIToolkit/Window/UTKAccordionListWindow";
|
||||
private const string USS_PATH = "UIToolkit/Window/UTKAccordionListWindowUss";
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI 컴포넌트 참조 (UI Component References)
|
||||
|
||||
private UTKAccordionList? _accordionList;
|
||||
private Button? _closeButton;
|
||||
private UTKButton? _closeButton;
|
||||
private Label? _titleLabel;
|
||||
|
||||
#endregion
|
||||
@@ -226,6 +334,17 @@ namespace UVC.UIToolkit
|
||||
}
|
||||
visualTree.CloneTree(this);
|
||||
|
||||
// 테마 적용 및 변경 구독
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
SubscribeToThemeChanges();
|
||||
|
||||
// USS 로드 (테마 변수 스타일시트 이후에 로드되어야 변수가 해석됨)
|
||||
var uss = Resources.Load<StyleSheet>(USS_PATH);
|
||||
if (uss != null)
|
||||
{
|
||||
styleSheets.Add(uss);
|
||||
}
|
||||
|
||||
// 내부 UTKAccordionList 찾기
|
||||
_accordionList = this.Q<UTKAccordionList>();
|
||||
if (_accordionList == null)
|
||||
@@ -240,12 +359,13 @@ namespace UVC.UIToolkit
|
||||
|
||||
// 헤더 요소 참조
|
||||
_titleLabel = this.Q<Label>("title");
|
||||
_closeButton = this.Q<Button>("close-btn");
|
||||
_closeButton = this.Q<UTKButton>("close-btn");
|
||||
|
||||
// 닫기 버튼 이벤트
|
||||
// 닫기 버튼 설정 및 이벤트 연결
|
||||
if (_closeButton != null)
|
||||
{
|
||||
_closeButton.clicked += OnCloseButtonClicked;
|
||||
_closeButton.SetMaterialIcon(UTKMaterialIcons.Close, 16);
|
||||
_closeButton.OnClicked += OnCloseButtonClicked;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,6 +446,24 @@ namespace UVC.UIToolkit
|
||||
|
||||
#endregion
|
||||
|
||||
#region 테마 (Theme)
|
||||
|
||||
private void SubscribeToThemeChanges()
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
||||
RegisterCallback<DetachFromPanelEvent>(_ =>
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
});
|
||||
}
|
||||
|
||||
private void OnThemeChanged(UTKTheme theme)
|
||||
{
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
|
||||
public void Dispose()
|
||||
@@ -333,14 +471,18 @@ namespace UVC.UIToolkit
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
// 테마 변경 이벤트 해제
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
|
||||
// 내부 UTKAccordionList 정리
|
||||
_accordionList?.Dispose();
|
||||
_accordionList = null;
|
||||
|
||||
// 닫기 버튼 이벤트 해제
|
||||
// 닫기 버튼 이벤트 해제 및 정리
|
||||
if (_closeButton != null)
|
||||
{
|
||||
_closeButton.clicked -= OnCloseButtonClicked;
|
||||
_closeButton.OnClicked -= OnCloseButtonClicked;
|
||||
_closeButton.Dispose();
|
||||
}
|
||||
|
||||
// 외부 이벤트 정리
|
||||
|
||||
@@ -14,17 +14,119 @@ namespace UVC.UIToolkit
|
||||
/// 윈도우 형태의 컴포넌트입니다. 모든 트리 관련 기능은 내부 UTKComponentList에 위임됩니다.
|
||||
/// </para>
|
||||
///
|
||||
/// <para><b>UXML에서 사용:</b></para>
|
||||
/// <code>
|
||||
/// <UVC.UIToolkit.Window.UTKComponentListWindow name="tree-list-window" />
|
||||
/// </code>
|
||||
/// <para><b>UXML 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// <!-- UXML 파일에서 UTKComponentListWindow 사용 -->
|
||||
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
|
||||
/// <utk:UTKComponentListWindow name="component-window" />
|
||||
/// </ui:UXML>
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>코드에서 사용:</b></para>
|
||||
/// <code>
|
||||
/// var window = root.Q<UTKComponentListWindow>();
|
||||
/// window.OnItemSelected += (items) => Debug.Log($"선택: {items[0].name}");
|
||||
/// window.SetData(treeItems);
|
||||
/// </code>
|
||||
/// <para><b>C# 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// // 1. 윈도우 참조 획득
|
||||
/// var componentWindow = root.Q<UTKComponentListWindow>("component-window");
|
||||
///
|
||||
/// // 2. 윈도우 제목 및 닫기 버튼 설정
|
||||
/// componentWindow.Title = "모델 리스트";
|
||||
/// componentWindow.ShowCloseButton = true;
|
||||
///
|
||||
/// // 3. 데이터 구성 - 카테고리와 아이템
|
||||
/// var data = new List<UTKComponentListItemDataBase>
|
||||
/// {
|
||||
/// new UTKComponentListCategoryData
|
||||
/// {
|
||||
/// name = "캐릭터",
|
||||
/// isExpanded = true,
|
||||
/// children = new List<UTKComponentListItemDataBase>
|
||||
/// {
|
||||
/// new UTKComponentListItemData
|
||||
/// {
|
||||
/// name = "플레이어",
|
||||
/// ExternalKey = "player_001",
|
||||
/// IsVisible = true
|
||||
/// },
|
||||
/// new UTKComponentListItemData
|
||||
/// {
|
||||
/// name = "NPC",
|
||||
/// ExternalKey = "npc_001",
|
||||
/// IsVisible = true
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// };
|
||||
/// componentWindow.SetData(data);
|
||||
///
|
||||
/// // 4. 선택 이벤트 구독
|
||||
/// componentWindow.OnItemSelected = (selectedItems) =>
|
||||
/// {
|
||||
/// foreach (var item in selectedItems)
|
||||
/// {
|
||||
/// Debug.Log($"선택됨: {item.name}");
|
||||
/// // 3D 뷰에서 해당 모델 하이라이트
|
||||
/// HighlightModel(item.ExternalKey);
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 5. 선택 해제 이벤트
|
||||
/// componentWindow.OnItemDeselected = (deselectedItems) =>
|
||||
/// {
|
||||
/// foreach (var item in deselectedItems)
|
||||
/// {
|
||||
/// UnhighlightModel(item.ExternalKey);
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 6. 가시성 변경 이벤트 (눈 아이콘)
|
||||
/// componentWindow.OnItemVisibilityChanged += (item, isVisible) =>
|
||||
/// {
|
||||
/// var gameObject = FindGameObjectByKey(item.ExternalKey);
|
||||
/// if (gameObject != null)
|
||||
/// {
|
||||
/// gameObject.SetActive(isVisible);
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 7. 삭제 이벤트 (Delete/Backspace 키)
|
||||
/// componentWindow.EnabledDeleteItem = true;
|
||||
/// componentWindow.OnItemDeleted = (item) =>
|
||||
/// {
|
||||
/// Debug.Log($"삭제 요청: {item.name}");
|
||||
/// componentWindow.DeleteItem(item);
|
||||
/// };
|
||||
///
|
||||
/// // 8. 더블클릭 이벤트
|
||||
/// componentWindow.OnItemDoubleClicked = (item) =>
|
||||
/// {
|
||||
/// // 카메라 포커스
|
||||
/// FocusCameraOn(item.ExternalKey);
|
||||
/// };
|
||||
///
|
||||
/// // 9. 윈도우 닫힘 이벤트
|
||||
/// componentWindow.OnClosed += () =>
|
||||
/// {
|
||||
/// Debug.Log("윈도우가 닫혔습니다.");
|
||||
/// };
|
||||
///
|
||||
/// // 10. 프로그래밍 방식 선택
|
||||
/// componentWindow.SelectItem("플레이어", notify: true);
|
||||
/// componentWindow.DeselectItem("플레이어", notify: false);
|
||||
/// componentWindow.ClearSelection();
|
||||
/// componentWindow.SelectByItemId(itemId);
|
||||
///
|
||||
/// // 11. 아이템 추가/삭제
|
||||
/// var newItem = new UTKComponentListItemData { name = "새 캐릭터" };
|
||||
/// componentWindow.AddItem(newItem);
|
||||
/// componentWindow.AddItem(categoryData, newItem);
|
||||
/// componentWindow.DeleteItem(newItem);
|
||||
/// componentWindow.SetItemName(newItem, "수정된 이름");
|
||||
///
|
||||
/// // 12. 윈도우 표시
|
||||
/// componentWindow.Show();
|
||||
///
|
||||
/// // 13. 리소스 해제 (OnDestroy에서 호출)
|
||||
/// componentWindow.Dispose();
|
||||
/// ]]></code>
|
||||
/// </summary>
|
||||
[UxmlElement]
|
||||
public partial class UTKComponentListWindow : VisualElement, IDisposable
|
||||
@@ -36,14 +138,20 @@ namespace UVC.UIToolkit
|
||||
#region 상수 (Constants)
|
||||
/// <summary>메인 UXML 파일 경로 (Resources 폴더 기준)</summary>
|
||||
private const string UXML_PATH = "UIToolkit/Window/UTKComponentListWindow";
|
||||
|
||||
/// <summary>USS 파일 경로 (Resources 폴더 기준)</summary>
|
||||
private const string USS_PATH = "UIToolkit/Window/UTKComponentListWindowUss";
|
||||
#endregion
|
||||
|
||||
#region UI 컴포넌트 참조 (UI Component References)
|
||||
/// <summary>내부 UTKComponentList 컴포넌트</summary>
|
||||
private UTKComponentList? _componentList;
|
||||
|
||||
/// <summary>트리 리스트 닫기 버튼</summary>
|
||||
private Button? _closeButton;
|
||||
/// <summary>트리 리스트 닫기 버튼 (UTKButton)</summary>
|
||||
private UTKButton? _closeButton;
|
||||
|
||||
/// <summary>윈도우 제목 라벨</summary>
|
||||
private Label? _titleLabel;
|
||||
#endregion
|
||||
|
||||
#region 공개 속성 (Public Properties)
|
||||
@@ -57,6 +165,20 @@ namespace UVC.UIToolkit
|
||||
get => _componentList?.EnabledDeleteItem ?? false;
|
||||
set { if (_componentList != null) _componentList.EnabledDeleteItem = value; }
|
||||
}
|
||||
|
||||
/// <summary>윈도우 제목을 가져오거나 설정합니다.</summary>
|
||||
public string Title
|
||||
{
|
||||
get => _titleLabel?.text ?? string.Empty;
|
||||
set { if (_titleLabel != null) _titleLabel.text = value; }
|
||||
}
|
||||
|
||||
/// <summary>닫기 버튼 표시 여부를 설정합니다.</summary>
|
||||
public bool ShowCloseButton
|
||||
{
|
||||
get => _closeButton?.style.display == DisplayStyle.Flex;
|
||||
set { if (_closeButton != null) _closeButton.style.display = value ? DisplayStyle.Flex : DisplayStyle.None; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 외부 이벤트 (Public Events)
|
||||
@@ -145,17 +267,35 @@ namespace UVC.UIToolkit
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 닫기 버튼 찾기 및 이벤트 연결
|
||||
_closeButton = this.Q<Button>("close-btn");
|
||||
// 3. 테마 적용 및 변경 구독
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
SubscribeToThemeChanges();
|
||||
|
||||
// USS 로드 (테마 변수 스타일시트 이후에 로드되어야 변수가 해석됨)
|
||||
var uss = Resources.Load<StyleSheet>(USS_PATH);
|
||||
if (uss != null)
|
||||
{
|
||||
styleSheets.Add(uss);
|
||||
}
|
||||
|
||||
// 4. 헤더 요소 참조
|
||||
_titleLabel = this.Q<Label>("title");
|
||||
_closeButton = this.Q<UTKButton>("close-btn");
|
||||
|
||||
// 5. 닫기 버튼 설정 및 이벤트 연결
|
||||
if (_closeButton != null)
|
||||
{
|
||||
_closeButton.clicked += () =>
|
||||
{
|
||||
this.style.display = DisplayStyle.None;
|
||||
OnClosed?.Invoke();
|
||||
};
|
||||
_closeButton.SetMaterialIcon(UTKMaterialIcons.Close, 16);
|
||||
_closeButton.OnClicked += OnCloseButtonClicked;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>닫기 버튼 클릭 이벤트 핸들러</summary>
|
||||
private void OnCloseButtonClicked()
|
||||
{
|
||||
this.style.display = DisplayStyle.None;
|
||||
OnClosed?.Invoke();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 공개 메서드 (Public Methods)
|
||||
@@ -263,6 +403,24 @@ namespace UVC.UIToolkit
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 테마 (Theme)
|
||||
|
||||
private void SubscribeToThemeChanges()
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
||||
RegisterCallback<DetachFromPanelEvent>(_ =>
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
});
|
||||
}
|
||||
|
||||
private void OnThemeChanged(UTKTheme theme)
|
||||
{
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
/// <summary>
|
||||
/// 리소스를 해제하고 이벤트 핸들러를 정리합니다.
|
||||
@@ -272,15 +430,26 @@ namespace UVC.UIToolkit
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
// 테마 변경 이벤트 해제
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
|
||||
// 내부 UTKComponentList 정리
|
||||
_componentList?.Dispose();
|
||||
_componentList = null;
|
||||
|
||||
// 닫기 버튼 이벤트 해제 및 정리
|
||||
if (_closeButton != null)
|
||||
{
|
||||
_closeButton.OnClicked -= OnCloseButtonClicked;
|
||||
_closeButton.Dispose();
|
||||
}
|
||||
|
||||
// 외부 이벤트 구독자 정리
|
||||
OnClosed = null;
|
||||
|
||||
// UI 참조 정리
|
||||
_closeButton = null;
|
||||
_titleLabel = null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -15,18 +15,132 @@ namespace UVC.UIToolkit
|
||||
/// 탭 버튼들을 추가한 윈도우 형태의 컴포넌트입니다. 탭을 통해 카테고리별 필터링이 가능합니다.
|
||||
/// </para>
|
||||
///
|
||||
/// <para><b>UXML에서 사용:</b></para>
|
||||
/// <code>
|
||||
/// <UVC.UIToolkit.Window.UTKComponentTabListWindow name="tab-list-window" />
|
||||
/// </code>
|
||||
/// <para><b>UXML 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// <!-- UXML 파일에서 UTKComponentTabListWindow 사용 -->
|
||||
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
|
||||
/// <utk:UTKComponentTabListWindow name="tab-list-window" />
|
||||
/// </ui:UXML>
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>코드에서 사용:</b></para>
|
||||
/// <code>
|
||||
/// var window = root.Q<UTKComponentTabListWindow>();
|
||||
/// window.OnItemSelected += (items) => Debug.Log($"선택: {items[0].name}");
|
||||
/// window.SetData(treeItems);
|
||||
/// window.SelectTab(0); // 첫 번째 카테고리 탭 선택
|
||||
/// </code>
|
||||
/// <para><b>C# 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// // 1. 윈도우 참조 획득
|
||||
/// var tabWindow = root.Q<UTKComponentTabListWindow>("tab-list-window");
|
||||
///
|
||||
/// // 2. 윈도우 제목 및 닫기 버튼 설정
|
||||
/// tabWindow.Title = "에셋 라이브러리";
|
||||
/// tabWindow.ShowCloseButton = true;
|
||||
///
|
||||
/// // 3. 데이터 구성 - 카테고리별로 자동 탭 생성됨
|
||||
/// var data = new List<UTKComponentListItemDataBase>
|
||||
/// {
|
||||
/// // 첫 번째 카테고리 → "캐릭터" 탭 자동 생성
|
||||
/// new UTKComponentListCategoryData
|
||||
/// {
|
||||
/// name = "캐릭터",
|
||||
/// isExpanded = true,
|
||||
/// children = new List<UTKComponentListItemDataBase>
|
||||
/// {
|
||||
/// new UTKComponentListItemData { name = "플레이어", ExternalKey = "player" },
|
||||
/// new UTKComponentListItemData { name = "NPC", ExternalKey = "npc" }
|
||||
/// }
|
||||
/// },
|
||||
/// // 두 번째 카테고리 → "오브젝트" 탭 자동 생성
|
||||
/// new UTKComponentListCategoryData
|
||||
/// {
|
||||
/// name = "오브젝트",
|
||||
/// isExpanded = true,
|
||||
/// children = new List<UTKComponentListItemDataBase>
|
||||
/// {
|
||||
/// 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();
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>탭 동작 설명:</b></para>
|
||||
/// <list type="bullet">
|
||||
/// <item>"All" 탭: 모든 카테고리와 아이템을 표시합니다.</item>
|
||||
/// <item>카테고리 탭: 해당 카테고리의 자식 아이템만 표시합니다 (부모 카테고리 없이).</item>
|
||||
/// <item>탭별 검색어가 저장되어, 탭 전환 시 해당 탭의 검색어가 복원됩니다.</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
[UxmlElement]
|
||||
public partial class UTKComponentTabListWindow : VisualElement, IDisposable
|
||||
@@ -39,6 +153,9 @@ namespace UVC.UIToolkit
|
||||
/// <summary>메인 UXML 파일 경로 (Resources 폴더 기준)</summary>
|
||||
private const string UXML_PATH = "UIToolkit/Window/UTKComponentTabListWindow";
|
||||
|
||||
/// <summary>USS 파일 경로 (Resources 폴더 기준)</summary>
|
||||
private const string USS_PATH = "UIToolkit/Window/UTKComponentListWindowUss";
|
||||
|
||||
/// <summary>"전체" 탭을 나타내는 인덱스</summary>
|
||||
private const int ALL_TAB_INDEX = -1;
|
||||
#endregion
|
||||
@@ -50,8 +167,11 @@ namespace UVC.UIToolkit
|
||||
/// <summary>탭 버튼 컨테이너</summary>
|
||||
private VisualElement? _tabContainer;
|
||||
|
||||
/// <summary>트리 리스트 닫기 버튼</summary>
|
||||
private Button? _closeButton;
|
||||
/// <summary>트리 리스트 닫기 버튼 (UTKButton)</summary>
|
||||
private UTKButton? _closeButton;
|
||||
|
||||
/// <summary>윈도우 제목 라벨</summary>
|
||||
private Label? _titleLabel;
|
||||
#endregion
|
||||
|
||||
#region 탭 관련 데이터 (Tab Data)
|
||||
@@ -79,6 +199,20 @@ namespace UVC.UIToolkit
|
||||
get => _componentList?.EnabledDeleteItem ?? false;
|
||||
set { if (_componentList != null) _componentList.EnabledDeleteItem = value; }
|
||||
}
|
||||
|
||||
/// <summary>윈도우 제목을 가져오거나 설정합니다.</summary>
|
||||
public string Title
|
||||
{
|
||||
get => _titleLabel?.text ?? string.Empty;
|
||||
set { if (_titleLabel != null) _titleLabel.text = value; }
|
||||
}
|
||||
|
||||
/// <summary>닫기 버튼 표시 여부를 설정합니다.</summary>
|
||||
public bool ShowCloseButton
|
||||
{
|
||||
get => _closeButton?.style.display == DisplayStyle.Flex;
|
||||
set { if (_closeButton != null) _closeButton.style.display = value ? DisplayStyle.Flex : DisplayStyle.None; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 외부 이벤트 (Public Events)
|
||||
@@ -167,20 +301,38 @@ namespace UVC.UIToolkit
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 탭 관련 요소 찾기
|
||||
// 3. 테마 적용 및 변경 구독
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
SubscribeToThemeChanges();
|
||||
|
||||
// USS 로드 (테마 변수 스타일시트 이후에 로드되어야 변수가 해석됨)
|
||||
var uss = Resources.Load<StyleSheet>(USS_PATH);
|
||||
if (uss != null)
|
||||
{
|
||||
styleSheets.Add(uss);
|
||||
}
|
||||
|
||||
// 4. 탭 관련 요소 찾기
|
||||
_tabContainer = this.Q<VisualElement>("tab-container");
|
||||
|
||||
// 4. 닫기 버튼 찾기 및 이벤트 연결
|
||||
_closeButton = this.Q<Button>("close-btn");
|
||||
// 5. 헤더 요소 참조
|
||||
_titleLabel = this.Q<Label>("title");
|
||||
_closeButton = this.Q<UTKButton>("close-btn");
|
||||
|
||||
// 6. 닫기 버튼 설정 및 이벤트 연결
|
||||
if (_closeButton != null)
|
||||
{
|
||||
_closeButton.clicked += () =>
|
||||
{
|
||||
this.style.display = DisplayStyle.None;
|
||||
OnClosed?.Invoke();
|
||||
};
|
||||
_closeButton.SetMaterialIcon(UTKMaterialIcons.Close, 16);
|
||||
_closeButton.OnClicked += OnCloseButtonClicked;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>닫기 버튼 클릭 이벤트 핸들러</summary>
|
||||
private void OnCloseButtonClicked()
|
||||
{
|
||||
this.style.display = DisplayStyle.None;
|
||||
OnClosed?.Invoke();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 공개 메서드 (Public Methods)
|
||||
@@ -507,6 +659,24 @@ namespace UVC.UIToolkit
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 테마 (Theme)
|
||||
|
||||
private void SubscribeToThemeChanges()
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
||||
RegisterCallback<DetachFromPanelEvent>(_ =>
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
});
|
||||
}
|
||||
|
||||
private void OnThemeChanged(UTKTheme theme)
|
||||
{
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
/// <summary>
|
||||
/// 리소스를 해제하고 이벤트 핸들러를 정리합니다.
|
||||
@@ -516,6 +686,9 @@ namespace UVC.UIToolkit
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
// 테마 변경 이벤트 해제
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
|
||||
// 내부 UTKComponentList 정리
|
||||
_componentList?.Dispose();
|
||||
_componentList = null;
|
||||
@@ -524,6 +697,13 @@ namespace UVC.UIToolkit
|
||||
_tabButtons.Clear();
|
||||
_tabContainer = null;
|
||||
|
||||
// 닫기 버튼 이벤트 해제 및 정리
|
||||
if (_closeButton != null)
|
||||
{
|
||||
_closeButton.OnClicked -= OnCloseButtonClicked;
|
||||
_closeButton.Dispose();
|
||||
}
|
||||
|
||||
// 외부 이벤트 구독자 정리
|
||||
OnClosed = null;
|
||||
|
||||
@@ -533,6 +713,7 @@ namespace UVC.UIToolkit
|
||||
|
||||
// UI 참조 정리
|
||||
_closeButton = null;
|
||||
_titleLabel = null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -22,17 +22,116 @@ namespace UVC.UIToolkit
|
||||
/// <item>드래그 앤 드롭 이벤트 전달</item>
|
||||
/// </list>
|
||||
///
|
||||
/// <para><b>UXML에서 사용:</b></para>
|
||||
/// <code>
|
||||
/// <uvc:UTKImageListWindow name="library-window" />
|
||||
/// </code>
|
||||
/// <para><b>UXML 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// <!-- UXML 파일에서 UTKImageListWindow 사용 -->
|
||||
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
|
||||
/// <utk:UTKImageListWindow name="library-window" />
|
||||
/// </ui:UXML>
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>코드에서 사용:</b></para>
|
||||
/// <code>
|
||||
/// var window = root.Q<UTKImageListWindow>();
|
||||
/// window.OnItemClick += (item) => Debug.Log($"클릭: {item.itemName}");
|
||||
/// window.SetData(imageItems);
|
||||
/// </code>
|
||||
/// <para><b>C# 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// // 1. 윈도우 참조 획득
|
||||
/// var imageWindow = root.Q<UTKImageListWindow>("library-window");
|
||||
///
|
||||
/// // 2. 윈도우 제목 및 닫기 버튼 설정
|
||||
/// imageWindow.Title = "프리팹 라이브러리";
|
||||
/// imageWindow.ShowCloseButton = true;
|
||||
///
|
||||
/// // 3. 데이터 구성 - 이미지와 이름을 가진 아이템들
|
||||
/// var data = new List<UTKImageListItemData>
|
||||
/// {
|
||||
/// new UTKImageListItemData
|
||||
/// {
|
||||
/// itemName = "의자",
|
||||
/// imagePath = "Prefabs/Thumbnails/chair",
|
||||
/// prefabPath = "Prefabs/Furniture/Chair"
|
||||
/// },
|
||||
/// new UTKImageListItemData
|
||||
/// {
|
||||
/// itemName = "책상",
|
||||
/// imagePath = "Prefabs/Thumbnails/desk",
|
||||
/// prefabPath = "Prefabs/Furniture/Desk"
|
||||
/// }
|
||||
/// };
|
||||
/// imageWindow.SetData(data);
|
||||
///
|
||||
/// // 4. 아이템 클릭 이벤트 구독
|
||||
/// imageWindow.OnItemClick = (item) =>
|
||||
/// {
|
||||
/// Debug.Log($"클릭된 아이템: {item.itemName}");
|
||||
/// };
|
||||
///
|
||||
/// // 5. 드래그 시작 이벤트
|
||||
/// imageWindow.OnItemBeginDrag = (item, screenPos) =>
|
||||
/// {
|
||||
/// Debug.Log($"드래그 시작: {item.itemName}");
|
||||
/// };
|
||||
///
|
||||
/// // 6. 드래그 중 이벤트
|
||||
/// imageWindow.OnItemDrag = (item, screenPos) =>
|
||||
/// {
|
||||
/// // 드래그 중 위치 업데이트
|
||||
/// };
|
||||
///
|
||||
/// // 7. 드래그 종료 이벤트
|
||||
/// imageWindow.OnItemEndDrag = (item, screenPos) =>
|
||||
/// {
|
||||
/// Debug.Log($"드래그 종료: {item.itemName}");
|
||||
/// };
|
||||
///
|
||||
/// // 8. 드롭 이벤트 (프리팹 인스턴스화)
|
||||
/// imageWindow.OnItemDrop = (item) =>
|
||||
/// {
|
||||
/// if (!string.IsNullOrEmpty(item.prefabPath))
|
||||
/// {
|
||||
/// var prefab = Resources.Load<GameObject>(item.prefabPath);
|
||||
/// Instantiate(prefab, dropPosition, Quaternion.identity);
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 9. 리스트 영역 밖으로 드래그 시 3D 미리보기 표시
|
||||
/// imageWindow.OnDragExitList = (item, screenPos) =>
|
||||
/// {
|
||||
/// // 리스트 밖 = 3D 씬 영역
|
||||
/// Show3DPreview(item.prefabPath, screenPos);
|
||||
/// };
|
||||
///
|
||||
/// // 10. 리스트 영역으로 다시 들어오면 미리보기 숨김
|
||||
/// imageWindow.OnDragEnterList = (item, screenPos) =>
|
||||
/// {
|
||||
/// Hide3DPreview();
|
||||
/// };
|
||||
///
|
||||
/// // 11. 윈도우 닫힘 이벤트
|
||||
/// imageWindow.OnClosed += () =>
|
||||
/// {
|
||||
/// Debug.Log("윈도우가 닫혔습니다.");
|
||||
/// };
|
||||
///
|
||||
/// // 12. 드래그 고스트 이미지 설정
|
||||
/// imageWindow.DragImageFollowCursor = true;
|
||||
///
|
||||
/// // 13. 검색 실행
|
||||
/// imageWindow.ApplySearch("의자");
|
||||
///
|
||||
/// // 14. 아이템 추가/제거
|
||||
/// var newItem = new UTKImageListItemData { itemName = "새 아이템" };
|
||||
/// imageWindow.AddItem(newItem);
|
||||
/// imageWindow.RemoveItem(newItem);
|
||||
/// imageWindow.Clear();
|
||||
///
|
||||
/// // 15. 아이템 개수 확인
|
||||
/// int count = imageWindow.ItemCount;
|
||||
///
|
||||
/// // 16. 윈도우 표시/닫기
|
||||
/// imageWindow.Show();
|
||||
/// imageWindow.Close();
|
||||
///
|
||||
/// // 17. 리소스 해제 (OnDestroy에서 호출)
|
||||
/// imageWindow.Dispose();
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>관련 리소스:</b></para>
|
||||
/// <list type="bullet">
|
||||
@@ -48,6 +147,9 @@ namespace UVC.UIToolkit
|
||||
/// <summary>메인 UXML 파일 경로 (Resources 폴더 기준)</summary>
|
||||
private const string UXML_PATH = "UIToolkit/Window/UTKImageListWindow";
|
||||
|
||||
/// <summary>USS 파일 경로 (Resources 폴더 기준)</summary>
|
||||
private const string USS_PATH = "UIToolkit/Window/UTKImageListWindowUss";
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI 컴포넌트 참조 (UI Component References)
|
||||
@@ -55,8 +157,8 @@ namespace UVC.UIToolkit
|
||||
/// <summary>내부 UTKImageList 컴포넌트</summary>
|
||||
private UTKImageList? _imageList;
|
||||
|
||||
/// <summary>윈도우 닫기 버튼</summary>
|
||||
private Button? _closeButton;
|
||||
/// <summary>윈도우 닫기 버튼 (UTKButton)</summary>
|
||||
private UTKButton? _closeButton;
|
||||
|
||||
/// <summary>윈도우 제목 라벨</summary>
|
||||
private Label? _titleLabel;
|
||||
@@ -214,7 +316,18 @@ namespace UVC.UIToolkit
|
||||
}
|
||||
visualTree.CloneTree(this);
|
||||
|
||||
// 2. 내부 UTKImageList 찾기 (UXML에서 생성된 컴포넌트)
|
||||
// 2. 테마 적용 및 변경 구독
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
SubscribeToThemeChanges();
|
||||
|
||||
// USS 로드 (테마 변수 스타일시트 이후에 로드되어야 변수가 해석됨)
|
||||
var uss = Resources.Load<StyleSheet>(USS_PATH);
|
||||
if (uss != null)
|
||||
{
|
||||
styleSheets.Add(uss);
|
||||
}
|
||||
|
||||
// 3. 내부 UTKImageList 찾기 (UXML에서 생성된 컴포넌트)
|
||||
_imageList = this.Q<UTKImageList>();
|
||||
if (_imageList == null)
|
||||
{
|
||||
@@ -226,14 +339,15 @@ namespace UVC.UIToolkit
|
||||
_imageList.DragBoundsElement = this;
|
||||
}
|
||||
|
||||
// 3. 헤더 요소 참조
|
||||
// 4. 헤더 요소 참조
|
||||
_titleLabel = this.Q<Label>("title");
|
||||
_closeButton = this.Q<Button>("close-btn");
|
||||
_closeButton = this.Q<UTKButton>("close-btn");
|
||||
|
||||
// 4. 닫기 버튼 이벤트 연결
|
||||
// 5. 닫기 버튼 설정 및 이벤트 연결
|
||||
if (_closeButton != null)
|
||||
{
|
||||
_closeButton.clicked += OnCloseButtonClicked;
|
||||
_closeButton.SetMaterialIcon(UTKMaterialIcons.Close, 16);
|
||||
_closeButton.OnClicked += OnCloseButtonClicked;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,6 +434,24 @@ namespace UVC.UIToolkit
|
||||
|
||||
#endregion
|
||||
|
||||
#region 테마 (Theme)
|
||||
|
||||
private void SubscribeToThemeChanges()
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
||||
RegisterCallback<DetachFromPanelEvent>(_ =>
|
||||
{
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
});
|
||||
}
|
||||
|
||||
private void OnThemeChanged(UTKTheme theme)
|
||||
{
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <summary>
|
||||
@@ -330,14 +462,18 @@ namespace UVC.UIToolkit
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
// 테마 변경 이벤트 해제
|
||||
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
||||
|
||||
// 내부 UTKImageList 정리
|
||||
_imageList?.Dispose();
|
||||
_imageList = null;
|
||||
|
||||
// 닫기 버튼 이벤트 해제
|
||||
// 닫기 버튼 이벤트 해제 및 정리
|
||||
if (_closeButton != null)
|
||||
{
|
||||
_closeButton.clicked -= OnCloseButtonClicked;
|
||||
_closeButton.OnClicked -= OnCloseButtonClicked;
|
||||
_closeButton.Dispose();
|
||||
}
|
||||
|
||||
// 외부 이벤트 구독자 정리
|
||||
|
||||
@@ -13,9 +13,9 @@ namespace UVC.UIToolkit
|
||||
///
|
||||
/// <para><b>개요:</b></para>
|
||||
/// <para>
|
||||
/// TreeListWindow는 Unity UI Toolkit의 TreeView를 래핑하여 검색, 가시성 토글,
|
||||
/// UTKTreeListWindow는 Unity UI Toolkit의 TreeView를 래핑하여 검색, 가시성 토글,
|
||||
/// 닫기 기능 등을 제공하는 재사용 가능한 컴포넌트입니다.
|
||||
/// UXML 파일(TreeListWindow.uxml, TreeListItem.uxml)과 함께 사용됩니다.
|
||||
/// UXML 파일(UTKTreeListWindow.uxml, UTKTreeListItem.uxml)과 함께 사용됩니다.
|
||||
/// </para>
|
||||
///
|
||||
/// <para><b>주요 기능:</b></para>
|
||||
@@ -23,21 +23,116 @@ namespace UVC.UIToolkit
|
||||
/// <item>계층적 트리 구조 표시 (펼치기/접기 지원)</item>
|
||||
/// <item>실시간 검색 필터링</item>
|
||||
/// <item>항목별 가시성(눈 아이콘) 토글</item>
|
||||
/// <item>선택 이벤트 처리</item>
|
||||
/// <item>다중 선택 지원</item>
|
||||
/// <item>삭제 기능 (Delete/Backspace 키)</item>
|
||||
/// </list>
|
||||
///
|
||||
/// <para><b>UXML에서 사용:</b></para>
|
||||
/// <code>
|
||||
/// <UVC.UIToolkit.Window.UTKTreeListWindow name="tree-list" />
|
||||
/// </code>
|
||||
/// <para><b>UXML 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// <!-- UXML 파일에서 UTKTreeListWindow 사용 -->
|
||||
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
|
||||
/// <utk:UTKTreeListWindow name="tree-list-window" />
|
||||
/// </ui:UXML>
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>코드에서 사용:</b></para>
|
||||
/// <code>
|
||||
/// var treeList = root.Q<UTKTreeListWindow>();
|
||||
/// treeList.OnSelectionChanged += (item) => Debug.Log($"선택: {item.name}");
|
||||
/// treeList.OnVisibilityChanged += (item) => model.SetActive(item.id, item.IsVisible);
|
||||
/// treeList.SetData(treeItems);
|
||||
/// </code>
|
||||
/// <para><b>C# 사용 예시:</b></para>
|
||||
/// <code><![CDATA[
|
||||
/// // 1. 윈도우 참조 획득
|
||||
/// var treeWindow = root.Q<UTKTreeListWindow>("tree-list-window");
|
||||
///
|
||||
/// // 2. 윈도우 제목 및 닫기 버튼 설정
|
||||
/// treeWindow.Title = "씬 계층구조";
|
||||
/// treeWindow.ShowCloseButton = true;
|
||||
///
|
||||
/// // 3. 데이터 구성 - 계층적 트리 구조
|
||||
/// var data = new List<UTKTreeListItemData>
|
||||
/// {
|
||||
/// new UTKTreeListItemData
|
||||
/// {
|
||||
/// name = "루트 오브젝트",
|
||||
/// isExpanded = true,
|
||||
/// IsVisible = true,
|
||||
/// children = new List<UTKTreeListItemData>
|
||||
/// {
|
||||
/// new UTKTreeListItemData
|
||||
/// {
|
||||
/// name = "자식 오브젝트 1",
|
||||
/// IsVisible = true
|
||||
/// },
|
||||
/// new UTKTreeListItemData
|
||||
/// {
|
||||
/// name = "자식 오브젝트 2",
|
||||
/// IsVisible = false,
|
||||
/// children = new List<UTKTreeListItemData>
|
||||
/// {
|
||||
/// new UTKTreeListItemData { name = "손자 오브젝트" }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// };
|
||||
/// treeWindow.SetData(data);
|
||||
///
|
||||
/// // 4. 선택 변경 이벤트 구독 (선택 및 해제 모두)
|
||||
/// treeWindow.OnSelectionChanged += (selectedItems) =>
|
||||
/// {
|
||||
/// Debug.Log($"선택된 아이템 수: {selectedItems.Count}");
|
||||
/// foreach (var item in selectedItems)
|
||||
/// {
|
||||
/// Debug.Log($"선택: {item.name}");
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 5. 가시성 변경 이벤트 (눈 아이콘 클릭)
|
||||
/// treeWindow.OnVisibilityChanged += (item) =>
|
||||
/// {
|
||||
/// Debug.Log($"{item.name} 가시성: {item.IsVisible}");
|
||||
/// // 3D 씬에서 해당 오브젝트 활성화/비활성화
|
||||
/// var gameObject = FindGameObjectByName(item.name);
|
||||
/// if (gameObject != null)
|
||||
/// {
|
||||
/// gameObject.SetActive(item.IsVisible);
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // 6. 삭제 이벤트 (Delete/Backspace 키)
|
||||
/// treeWindow.EnabledDeleteItem = true;
|
||||
/// treeWindow.OnItemDeleted += (item) =>
|
||||
/// {
|
||||
/// Debug.Log($"삭제 요청: {item.name}");
|
||||
/// // 데이터에서 제거 후 UI 갱신
|
||||
/// RemoveFromData(item);
|
||||
/// treeWindow.Rebuild();
|
||||
/// };
|
||||
///
|
||||
/// // 7. 윈도우 닫힘 이벤트
|
||||
/// treeWindow.OnClosed += () =>
|
||||
/// {
|
||||
/// Debug.Log("윈도우가 닫혔습니다.");
|
||||
/// };
|
||||
///
|
||||
/// // 8. 검색 실행
|
||||
/// treeWindow.ApplySearch("자식");
|
||||
/// // 검색어는 SearchQuery 속성으로 확인 가능
|
||||
/// string currentQuery = treeWindow.SearchQuery;
|
||||
///
|
||||
/// // 9. 프로그래밍 방식 선택
|
||||
/// treeWindow.SelectByItemId(itemId);
|
||||
///
|
||||
/// // 10. 전체 펼치기/접기
|
||||
/// treeWindow.ExpandAll();
|
||||
/// treeWindow.CollapseAll();
|
||||
///
|
||||
/// // 11. TreeView 갱신 (데이터 변경 후)
|
||||
/// treeWindow.Rebuild();
|
||||
///
|
||||
/// // 12. 윈도우 표시/숨김
|
||||
/// treeWindow.Show();
|
||||
/// treeWindow.Hide();
|
||||
///
|
||||
/// // 13. 리소스 해제 (OnDestroy에서 호출)
|
||||
/// treeWindow.Dispose();
|
||||
/// ]]></code>
|
||||
///
|
||||
/// <para><b>관련 리소스:</b></para>
|
||||
/// <list type="bullet">
|
||||
@@ -60,7 +155,9 @@ namespace UVC.UIToolkit
|
||||
#region 상수 (Constants)
|
||||
/// <summary>메인 UXML 파일 경로 (Resources 폴더 기준)</summary>
|
||||
private const string UXML_PATH = "UIToolkit/Window/UTKTreeListWindow";
|
||||
|
||||
|
||||
/// <summary>USS 파일 경로 (Resources 폴더 기준)</summary>
|
||||
private const string USS_PATH = "UIToolkit/Window/UTKTreeListWindowUss";
|
||||
#endregion
|
||||
|
||||
#region UI 컴포넌트 참조 (UI Component References)
|
||||
@@ -70,11 +167,14 @@ namespace UVC.UIToolkit
|
||||
/// <summary>Unity UI Toolkit의 TreeView 컴포넌트</summary>
|
||||
private TreeView? _treeView;
|
||||
|
||||
/// <summary>트리 리스트 닫기 버튼</summary>
|
||||
private Button? _closeButton;
|
||||
/// <summary>트리 리스트 닫기 버튼 (UTKButton)</summary>
|
||||
private UTKButton? _closeButton;
|
||||
|
||||
/// <summary>검색어 지우기 버튼</summary>
|
||||
private Button? _clearButton;
|
||||
/// <summary>검색어 지우기 버튼 (UTKButton)</summary>
|
||||
private UTKButton? _clearButton;
|
||||
|
||||
/// <summary>윈도우 제목 라벨</summary>
|
||||
private Label? _titleLabel;
|
||||
#endregion
|
||||
|
||||
#region 내부 데이터 (Internal Data)
|
||||
@@ -124,6 +224,20 @@ namespace UVC.UIToolkit
|
||||
/// 기본값은 true입니다.
|
||||
/// </summary>
|
||||
public bool EnabledDeleteItem { get; set; } = true;
|
||||
|
||||
/// <summary>윈도우 제목</summary>
|
||||
public string Title
|
||||
{
|
||||
get => _titleLabel?.text ?? string.Empty;
|
||||
set { if (_titleLabel != null) _titleLabel.text = value; }
|
||||
}
|
||||
|
||||
/// <summary>닫기 버튼 표시 여부</summary>
|
||||
public bool ShowCloseButton
|
||||
{
|
||||
get => _closeButton?.style.display == DisplayStyle.Flex;
|
||||
set { if (_closeButton != null) _closeButton.style.display = value ? DisplayStyle.Flex : DisplayStyle.None; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 외부 이벤트 (Public Events)
|
||||
@@ -177,14 +291,36 @@ namespace UVC.UIToolkit
|
||||
}
|
||||
visualTree!.CloneTree(this);
|
||||
|
||||
// 2. 테마 적용
|
||||
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
||||
|
||||
// 2. 자식 요소 참조 획득 (UXML의 name 속성으로 찾음)
|
||||
// USS 로드 (테마 변수 스타일시트 이후에 로드되어야 변수가 해석됨)
|
||||
var uss = Resources.Load<StyleSheet>(USS_PATH);
|
||||
if (uss != null)
|
||||
{
|
||||
styleSheets.Add(uss);
|
||||
}
|
||||
|
||||
// 3. 자식 요소 참조 획득 (UXML의 name 속성으로 찾음)
|
||||
_searchField = this.Q<TextField>("search-field");
|
||||
_treeView = this.Q<TreeView>("main-tree-view");
|
||||
_closeButton = this.Q<Button>("close-btn");
|
||||
_clearButton = this.Q<Button>("clear-btn");
|
||||
_titleLabel = this.Q<Label>("title");
|
||||
_closeButton = this.Q<UTKButton>("close-btn");
|
||||
_clearButton = this.Q<UTKButton>("clear-btn");
|
||||
|
||||
// 3. 이벤트 연결 및 로직 초기화
|
||||
// 4. 닫기 버튼 아이콘 설정
|
||||
if (_closeButton != null)
|
||||
{
|
||||
_closeButton.SetMaterialIcon(UTKMaterialIcons.Close, 16);
|
||||
}
|
||||
|
||||
// 5. Clear 버튼 아이콘 설정
|
||||
if (_clearButton != null)
|
||||
{
|
||||
_clearButton.SetMaterialIcon(UTKMaterialIcons.Close, 12);
|
||||
}
|
||||
|
||||
// 6. 이벤트 연결 및 로직 초기화
|
||||
InitializeLogic();
|
||||
}
|
||||
#endregion
|
||||
@@ -218,26 +354,14 @@ namespace UVC.UIToolkit
|
||||
// 닫기 버튼: 트리 리스트를 숨기고 이벤트 발생
|
||||
if (_closeButton != null)
|
||||
{
|
||||
_closeButton.clicked += () =>
|
||||
{
|
||||
this.style.display = DisplayStyle.None;
|
||||
OnClosed?.Invoke();
|
||||
};
|
||||
_closeButton.OnClicked += OnCloseButtonClicked;
|
||||
}
|
||||
|
||||
// 검색어 지우기 버튼
|
||||
if(_clearButton != null)
|
||||
{
|
||||
_clearButton.style.display = DisplayStyle.None; // 초기에는 숨김
|
||||
_clearButton.clicked += () =>
|
||||
{
|
||||
if (_searchField.value.Length > 0)
|
||||
{
|
||||
_searchField.value = string.Empty;
|
||||
OnSearch(string.Empty);
|
||||
}
|
||||
_clearButton.style.display = DisplayStyle.None; // 클리어 후 숨김
|
||||
};
|
||||
_clearButton.OnClicked += OnClearButtonClicked;
|
||||
}
|
||||
|
||||
// 스크롤바 hover/active 색상 설정
|
||||
@@ -1095,6 +1219,33 @@ namespace UVC.UIToolkit
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 버튼 이벤트 핸들러 (Button Event Handlers)
|
||||
/// <summary>
|
||||
/// 닫기 버튼 클릭 이벤트를 처리합니다.
|
||||
/// </summary>
|
||||
private void OnCloseButtonClicked()
|
||||
{
|
||||
this.style.display = DisplayStyle.None;
|
||||
OnClosed?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear 버튼 클릭 이벤트를 처리합니다.
|
||||
/// </summary>
|
||||
private void OnClearButtonClicked()
|
||||
{
|
||||
if (_searchField != null && _searchField.value.Length > 0)
|
||||
{
|
||||
_searchField.value = string.Empty;
|
||||
OnSearch(string.Empty);
|
||||
}
|
||||
if (_clearButton != null)
|
||||
{
|
||||
_clearButton.style.display = DisplayStyle.None;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 검색 기능 (Search Functionality)
|
||||
/// <summary>
|
||||
/// 검색 필드에서 Enter 키를 눌렀을 때 검색을 실행합니다.
|
||||
@@ -1270,6 +1421,20 @@ namespace UVC.UIToolkit
|
||||
_treeView.makeItem = null;
|
||||
}
|
||||
|
||||
// 닫기 버튼 이벤트 해제 및 정리
|
||||
if (_closeButton != null)
|
||||
{
|
||||
_closeButton.OnClicked -= OnCloseButtonClicked;
|
||||
_closeButton.Dispose();
|
||||
}
|
||||
|
||||
// Clear 버튼 이벤트 해제 및 정리
|
||||
if (_clearButton != null)
|
||||
{
|
||||
_clearButton.OnClicked -= OnClearButtonClicked;
|
||||
_clearButton.Dispose();
|
||||
}
|
||||
|
||||
// 외부 이벤트 구독자 정리
|
||||
OnItemVisibilityChanged = null;
|
||||
OnClosed = null;
|
||||
@@ -1290,6 +1455,7 @@ namespace UVC.UIToolkit
|
||||
// UI 참조 정리
|
||||
_searchField = null;
|
||||
_treeView = null;
|
||||
_titleLabel = null;
|
||||
_closeButton = null;
|
||||
_clearButton = null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user