#nullable enable
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
namespace UVC.UIToolkit
{
///
/// 리스트 뷰 컴포넌트.
/// Unity ListView를 래핑하여 커스텀 스타일을 적용합니다.
/// 가상화(Virtualization)를 지원하여 대량의 데이터도 효율적으로 표시합니다.
///
///
/// ListView(리스트 뷰)란?
///
/// ListView는 여러 항목을 세로로 나열하여 표시하는 UI 컴포넌트입니다.
/// 파일 목록, 연락처, 설정 항목 등 반복되는 데이터를 표시할 때 사용합니다.
///
///
/// 가상화(Virtualization)란?
///
/// 수천 개의 항목이 있어도 화면에 보이는 항목만 실제로 렌더링하는 기술입니다.
/// 스크롤 시 보이지 않는 항목은 메모리에서 재활용되어 성능이 유지됩니다.
/// 이를 위해 makeItem(요소 생성)과 bindItem(데이터 바인딩)을 분리합니다.
///
///
/// 필수 설정:
///
/// - itemsSource - 표시할 데이터 컬렉션 (IList)
/// - makeItem - 항목 VisualElement 생성 함수
/// - bindItem - 데이터를 요소에 바인딩하는 함수
///
///
/// 주요 속성:
///
/// - fixedItemHeight - 항목 높이 (고정 시 성능 향상)
/// - selectionType - 선택 모드 (None, Single, Multiple)
/// - selectedIndex - 현재 선택된 인덱스
/// - showBorder - 테두리 표시 여부
///
///
/// 주요 이벤트:
///
/// - OnItemSelected - 항목 선택 시 (인덱스 전달)
/// - OnItemDoubleClicked - 항목 더블클릭 시 (인덱스 전달)
///
///
/// 실제 활용 예시:
///
/// - 파일 탐색기 - 파일/폴더 목록
/// - 설정 화면 - 설정 항목 목록
/// - 채팅 앱 - 대화 목록
/// - 게임 인벤토리 - 아이템 목록
/// - 데이터 테이블 - 행 단위 데이터
///
///
///
/// C# 코드에서 사용:
///
/// // 리스트 뷰 생성
/// var listView = new UTKListView();
/// listView.fixedItemHeight = 30; // 항목 높이 고정 (성능 향상)
///
/// // 데이터 소스 설정
/// var items = new List { "항목 1", "항목 2", "항목 3" };
/// listView.itemsSource = items;
///
/// // 항목 생성 함수 (가상화를 위해 재사용됨)
/// listView.makeItem = () => new Label();
///
/// // 데이터 바인딩 함수 (스크롤 시 호출됨)
/// listView.bindItem = (element, index) => {
/// (element as Label).text = items[index];
/// };
///
/// // 선택 이벤트
/// listView.OnItemSelected += (index) => {
/// Debug.Log($"선택: {items[index]}");
/// };
///
/// // 더블클릭 이벤트 (파일 열기 등)
/// listView.OnItemDoubleClicked += (index) => {
/// OpenFile(items[index]);
/// };
///
/// // 복잡한 항목 구조
/// listView.makeItem = () => {
/// var container = new VisualElement();
/// container.Add(new Label { name = "title" });
/// container.Add(new Label { name = "subtitle" });
/// return container;
/// };
///
/// listView.bindItem = (element, index) => {
/// var data = myDataList[index];
/// element.Q
/// UXML에서 사용:
///
///
///
///
///
///
///
///
///
///
///
[UxmlElement]
public partial class UTKListView : ListView, IDisposable
{
#region Constants
private const string USS_PATH = "UIToolkit/List/UTKListView";
#endregion
#region Fields
private bool _disposed;
#endregion
#region Events
/// 아이템 선택 이벤트
public event Action? OnItemSelected;
/// 아이템 더블클릭 이벤트
public event Action? OnItemDoubleClicked;
#endregion
#region Constructor
public UTKListView() : base()
{
UTKThemeManager.Instance.ApplyThemeToElement(this);
var uss = Resources.Load(USS_PATH);
if (uss != null)
{
styleSheets.Add(uss);
}
else
{
Debug.LogWarning($"[UTKListView] Failed to load USS: {USS_PATH}");
}
SetupStyles();
SetupEvents();
SubscribeToThemeChanges();
}
#endregion
#region Setup
private void SetupStyles()
{
AddToClassList("utk-listview");
}
private void SetupEvents()
{
selectionChanged += OnSelectionChanged;
itemsChosen += OnItemsChosen;
}
private void SubscribeToThemeChanges()
{
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback(OnAttachToPanelForTheme);
RegisterCallback(OnDetachFromPanelForTheme);
}
private void OnAttachToPanelForTheme(AttachToPanelEvent evt)
{
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
UTKThemeManager.Instance.ApplyThemeToElement(this);
}
private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt)
{
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
}
private void OnThemeChanged(UTKTheme theme)
{
UTKThemeManager.Instance.ApplyThemeToElement(this);
}
#endregion
#region Event Handlers
private void OnSelectionChanged(IEnumerable