#nullable enable
using System;
using UnityEngine;
using UnityEngine.UIElements;
using UVC.Locale;
namespace UVC.UIToolkit
{
///
/// UIToolkit 기반 메뉴 아이템의 추상 베이스 클래스입니다.
/// 공통 로직을 제공하고, UI 생성은 하위 클래스에서 구현합니다.
///
[UxmlElement]
public abstract partial class UTKMenuItemBase : VisualElement, IDisposable
{
#region Fields
protected bool _disposed;
protected Button? _button;
protected VisualElement? _arrow;
protected UTKMenuItemData? _data;
protected LocalizationManager? _locManager;
protected EventCallback? _onClickCallback;
protected string _ussPath = "";
#endregion
#region UXML Attributes
/// 메뉴 아이템 ID
[UxmlAttribute("item-id")]
public string ItemId { get; set; } = "";
/// 표시 이름 (다국어 키 또는 이미지 경로)
[UxmlAttribute("display-name")]
public string DisplayName { get; set; } = "";
/// 활성화 상태
[UxmlAttribute("is-enabled")]
public bool IsEnabled
{
get => _button?.enabledSelf ?? true;
set
{
if (_button != null)
_button.SetEnabled(value);
}
}
/// 단축키
[UxmlAttribute("shortcut")]
public string Shortcut { get; set; } = "";
#endregion
#region Events
/// 메뉴 아이템 클릭 이벤트
public event Action? OnClicked;
#endregion
#region Constructor
///
/// UTKMenuItemBase의 새 인스턴스를 초기화합니다.
///
protected UTKMenuItemBase()
{
// 1. 테마 적용
UTKThemeManager.Instance.ApplyThemeToElement(this);
// 2. USS 로드 (하위 클래스에서 _ussPath 설정 필요)
LoadStyleSheet();
// 3. UI 생성 (추상 메서드, 하위 클래스 구현)
CreateUI();
// 4. 테마 변경 구독
SubscribeToThemeChanges();
// 5. LocalizationManager 가져오기
_locManager = LocalizationManager.Instance;
}
#endregion
#region Setup
///
/// USS 스타일시트를 로드합니다.
///
protected virtual void LoadStyleSheet()
{
if (string.IsNullOrEmpty(_ussPath)) return;
var uss = Resources.Load(_ussPath);
if (uss != null)
{
styleSheets.Add(uss);
}
}
///
/// UI를 생성합니다. 하위 클래스에서 구현해야 합니다.
///
protected abstract void CreateUI();
///
/// 테마 변경 이벤트를 구독합니다.
///
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 Public Methods
///
/// 메뉴 아이템 데이터를 설정합니다.
///
/// 메뉴 아이템 데이터
/// data가 null인 경우
public virtual void SetData(UTKMenuItemData data)
{
if (data == null)
throw new ArgumentNullException(nameof(data), "메뉴 아이템 데이터가 null입니다.");
_data = data;
ItemId = data.ItemId;
DisplayName = data.DisplayName;
IsEnabled = data.IsEnabled;
Shortcut = data.Shortcut ?? "";
UpdateUI();
}
///
/// 활성화 상태를 업데이트합니다.
///
/// 활성화 여부
public void UpdateEnabled(bool enabled)
{
IsEnabled = enabled;
if (_data != null)
_data.IsEnabled = enabled;
UpdateOpacity();
}
///
/// 단축키를 업데이트합니다.
///
/// 단축키 문자열
public void UpdateShortcut(string shortcut)
{
Shortcut = shortcut ?? "";
if (_data != null)
_data.Shortcut = shortcut;
}
///
/// 하위 메뉴 화살표를 표시합니다.
///
/// 하위 메뉴 존재 여부
public void ShowArrow(bool hasSubMenu)
{
if (_arrow != null)
{
_arrow.style.display = hasSubMenu ? DisplayStyle.Flex : DisplayStyle.None;
}
}
#endregion
#region Protected Methods
///
/// UI를 업데이트합니다. 하위 클래스에서 오버라이드하여 구현합니다.
///
protected abstract void UpdateUI();
///
/// 활성화 상태에 따라 투명도를 업데이트합니다. 하위 클래스에서 오버라이드 가능합니다.
///
protected virtual void UpdateOpacity()
{
// 하위 클래스에서 구현
}
///
/// 버튼 클릭 시 호출됩니다.
///
/// 클릭 이벤트
protected virtual void OnButtonClicked(ClickEvent evt)
{
if (_data != null && IsEnabled)
{
OnClicked?.Invoke(_data);
}
}
#endregion
#region IDisposable
///
/// 리소스를 정리합니다.
///
public virtual void Dispose()
{
if (_disposed) return;
_disposed = true;
// 이벤트 구독 해제
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback(OnAttachToPanelForTheme);
UnregisterCallback(OnDetachFromPanelForTheme);
// 버튼 이벤트 해제
if (_button != null && _onClickCallback != null)
{
_button.UnregisterCallback(_onClickCallback);
}
// 참조 정리
OnClicked = null;
_button = null;
_arrow = null;
_data = null;
_onClickCallback = null;
}
#endregion
}
}