Files
XRLib/Assets/Scripts/UVC/UIToolkit/Common/UTKFoldout.cs
2026-02-10 20:48:49 +09:00

179 lines
6.0 KiB
C#

#nullable enable
using System;
using UnityEngine;
using UnityEngine.UIElements;
namespace UVC.UIToolkit
{
/// <summary>
/// 접을 수 있는 섹션 컴포넌트.
/// Unity Foldout을 래핑하여 커스텀 스타일을 적용합니다.
/// 헤더 클릭으로 내용을 펼치거나 접을 수 있습니다.
/// </summary>
/// <remarks>
/// <para><b>Foldout(폴드아웃)이란?</b></para>
/// <para>
/// Foldout은 헤더를 클릭하여 내용을 펼치거나 접을 수 있는 컨테이너입니다.
/// 아코디언(Accordion)이라고도 불리며, 많은 내용을 정리할 때 유용합니다.
/// Unity Inspector에서 컴포넌트 섹션을 접는 것과 같은 동작입니다.
/// </para>
///
/// <para><b>Foldout vs Panel 차이:</b></para>
/// <list type="bullet">
/// <item><description><c>Foldout</c> - 간단한 접기/펼치기, 토글 화살표 표시</description></item>
/// <item><description><c>Panel</c> - 헤더/푸터/액션 등 풍부한 기능, 더 많은 커스터마이징</description></item>
/// </list>
///
/// <para><b>주요 속성:</b></para>
/// <list type="bullet">
/// <item><description><c>text</c> - 헤더에 표시되는 제목</description></item>
/// <item><description><c>value</c> / <c>IsExpanded</c> - 펼침 상태 (true=펼침, false=접힘)</description></item>
/// </list>
///
/// <para><b>실제 활용 예시:</b></para>
/// <list type="bullet">
/// <item><description>설정 페이지 - 고급 설정 숨기기</description></item>
/// <item><description>FAQ - 질문 클릭 시 답변 표시</description></item>
/// <item><description>인스펙터 - 컴포넌트 섹션 접기</description></item>
/// <item><description>필터 패널 - 상세 필터 옵션 숨기기</description></item>
/// </list>
/// </remarks>
/// <example>
/// <para><b>C# 코드에서 사용:</b></para>
/// <code>
/// // 기본 폴드아웃
/// var foldout = new UTKFoldout("고급 설정", expanded: false);
/// foldout.Add(new Label("옵션 1"));
/// foldout.Add(new Label("옵션 2"));
///
/// // 상태 변경 이벤트
/// foldout.OnValueChanged += (isExpanded) => {
/// Debug.Log(isExpanded ? "펼쳐짐" : "접힘");
/// };
///
/// // 프로그래밍 방식으로 상태 제어
/// foldout.IsExpanded = true;
/// </code>
/// <para><b>UXML에서 사용:</b></para>
/// <code>
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
/// <!-- 기본 폴드아웃 -->
/// <utk:UTKFoldout text="설정" value="true">
/// <ui:Label text="내용 1" />
/// <ui:Label text="내용 2" />
/// </utk:UTKFoldout>
///
/// <!-- 접힌 상태 -->
/// <utk:UTKFoldout text="고급 옵션" value="false">
/// <ui:Label text="숨겨진 내용" />
/// </utk:UTKFoldout>
/// </ui:UXML>
/// </code>
/// </example>
[UxmlElement]
public partial class UTKFoldout : Foldout, IDisposable
{
#region Constants
private const string USS_PATH = "UIToolkit/Common/UTKFoldout";
#endregion
#region Fields
private bool _disposed;
#endregion
#region Events
/// <summary>펼침/접힘 상태 변경 이벤트</summary>
public event Action<bool>? OnValueChanged;
#endregion
#region Properties
/// <summary>펼침 상태</summary>
public bool IsExpanded
{
get => value;
set => this.value = value;
}
#endregion
#region Constructor
public UTKFoldout() : base()
{
UTKThemeManager.Instance.ApplyThemeToElement(this);
var uss = Resources.Load<StyleSheet>(USS_PATH);
if (uss != null)
{
styleSheets.Add(uss);
}
SetupStyles();
SetupEvents();
SubscribeToThemeChanges();
}
public UTKFoldout(string title, bool expanded = true) : this()
{
text = title;
value = expanded;
}
#endregion
#region Setup
private void SetupStyles()
{
AddToClassList("utk-foldout");
}
private void SetupEvents()
{
RegisterCallback<ChangeEvent<bool>>(OnFoldoutValueChanged);
}
private void SubscribeToThemeChanges()
{
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
RegisterCallback<DetachFromPanelEvent>(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 OnFoldoutValueChanged(ChangeEvent<bool> evt)
{
OnValueChanged?.Invoke(evt.newValue);
}
#endregion
#region IDisposable
public void Dispose()
{
if (_disposed) return;
_disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null;
UnregisterCallback<ChangeEvent<bool>>(OnFoldoutValueChanged);
}
#endregion
}
}