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