#nullable enable using System; using UnityEngine; using UnityEngine.UIElements; namespace UVC.UIToolkit { /// /// 접을 수 있는 섹션 컴포넌트. /// Unity Foldout을 래핑하여 커스텀 스타일을 적용합니다. /// 헤더 클릭으로 내용을 펼치거나 접을 수 있습니다. /// /// /// Foldout(폴드아웃)이란? /// /// Foldout은 헤더를 클릭하여 내용을 펼치거나 접을 수 있는 컨테이너입니다. /// 아코디언(Accordion)이라고도 불리며, 많은 내용을 정리할 때 유용합니다. /// Unity Inspector에서 컴포넌트 섹션을 접는 것과 같은 동작입니다. /// /// /// Foldout vs Panel 차이: /// /// Foldout - 간단한 접기/펼치기, 토글 화살표 표시 /// Panel - 헤더/푸터/액션 등 풍부한 기능, 더 많은 커스터마이징 /// /// /// 주요 속성: /// /// text - 헤더에 표시되는 제목 /// value / IsExpanded - 펼침 상태 (true=펼침, false=접힘) /// /// /// 실제 활용 예시: /// /// 설정 페이지 - 고급 설정 숨기기 /// FAQ - 질문 클릭 시 답변 표시 /// 인스펙터 - 컴포넌트 섹션 접기 /// 필터 패널 - 상세 필터 옵션 숨기기 /// /// /// /// C# 코드에서 사용: /// /// // 기본 폴드아웃 /// 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; /// /// UXML에서 사용: /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// [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 /// 펼침/접힘 상태 변경 이벤트 public event Action? OnValueChanged; #endregion #region Properties /// 펼침 상태 public bool IsExpanded { get => value; set => this.value = value; } #endregion #region Constructor public UTKFoldout() : base() { UTKThemeManager.Instance.ApplyThemeToElement(this); var uss = Resources.Load(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>(OnFoldoutValueChanged); } private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; RegisterCallback(_ => { UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; }); } private void OnThemeChanged(UTKTheme theme) { UTKThemeManager.Instance.ApplyThemeToElement(this); } #endregion #region Event Handlers private void OnFoldoutValueChanged(ChangeEvent evt) { OnValueChanged?.Invoke(evt.newValue); } #endregion #region IDisposable public void Dispose() { if (_disposed) return; _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; OnValueChanged = null; UnregisterCallback>(OnFoldoutValueChanged); } #endregion } }