Files
EnglewoodLAB/Assets/Scripts/UVC/UIToolkit/Button/UTKQuitAppButton.cs

192 lines
5.8 KiB
C#

#nullable enable
using System;
using UnityEngine;
using UnityEngine.UIElements;
using UVC.UI.Commands;
namespace UVC.UIToolkit
{
/// <summary>
/// 앱 종료 버튼 컴포넌트.
/// 클릭 시 <see cref="QuitApplicationCommand"/>를 실행합니다.
/// 고정 크기: width=45, height=32. hover 시 붉은색으로 강조됩니다.
/// </summary>
/// <example>
/// <para><b>C# 코드에서 사용:</b></para>
/// <code>
/// var btn = new UTKQuitAppButton();
/// container.Add(btn);
///
/// // 비활성화
/// btn.IsEnabled = false;
/// </code>
/// <para><b>UXML에서 사용:</b></para>
/// <code>
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
/// <utk:UTKQuitAppButton />
/// <utk:UTKQuitAppButton is-enabled="false" />
/// </ui:UXML>
/// </code>
/// </example>
[UxmlElement]
public partial class UTKQuitAppButton : VisualElement, IDisposable
{
#region Constants
private const string UXML_PATH = "UIToolkit/Button/UTKQuitAppButton";
private const string USS_PATH = "UIToolkit/Button/UTKQuitAppButtonUss";
private const int ICON_SIZE = 18;
#endregion
#region Fields
private bool _disposed;
private bool _isEnabled = true;
private Label? _materialIconLabel;
private readonly QuitApplicationCommand _command = new();
#endregion
#region Properties
/// <summary>활성화 상태. false이면 시각적 비활성화 + 클릭 무시.</summary>
[UxmlAttribute("is-enabled")]
public bool IsEnabled
{
get => _isEnabled;
set
{
_isEnabled = value;
SetEnabled(value);
EnableInClassList("utk-quit-app-btn--disabled", !value);
}
}
#endregion
#region Constructor
public UTKQuitAppButton()
{
UTKThemeManager.Instance.ApplyThemeToElement(this);
var uss = Resources.Load<StyleSheet>(USS_PATH);
if (uss != null)
{
styleSheets.Add(uss);
}
CreateUI();
SetupEvents();
SubscribeToThemeChanges();
}
#endregion
#region Setup
private void CreateUI()
{
AddToClassList("utk-quit-app-btn");
focusable = true;
pickingMode = PickingMode.Position;
var asset = Resources.Load<VisualTreeAsset>(UXML_PATH);
if (asset != null)
{
var root = asset.Instantiate();
_materialIconLabel = root.Q<Label>("material-icon");
Add(root);
}
else
{
CreateUIFallback();
}
ApplyIcon();
}
private void CreateUIFallback()
{
_materialIconLabel = new Label
{
name = "material-icon",
pickingMode = PickingMode.Ignore
};
_materialIconLabel.AddToClassList("utk-quit-app-btn__material-icon");
Add(_materialIconLabel);
}
private void ApplyIcon()
{
if (_materialIconLabel == null) return;
// Material Icon: close (X 아이콘)
string iconChar = UTKMaterialIcons.GetIcon("close");
if (iconChar == string.Empty)
{
iconChar = UTKMaterialIcons.Close;
}
_materialIconLabel.text = iconChar;
UTKMaterialIcons.ApplyIconStyle(_materialIconLabel, ICON_SIZE);
_materialIconLabel.style.display = DisplayStyle.Flex;
}
private void SetupEvents()
{
RegisterCallback<ClickEvent>(OnClick);
RegisterCallback<KeyDownEvent>(OnKeyDown, TrickleDown.TrickleDown);
RegisterCallback<AttachToPanelEvent>(OnAttachToPanel);
RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanel);
}
private void SubscribeToThemeChanges()
{
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
}
private void OnAttachToPanel(AttachToPanelEvent evt)
{
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
UTKThemeManager.Instance.ApplyThemeToElement(this);
}
private void OnDetachFromPanel(DetachFromPanelEvent evt)
{
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
}
private void OnThemeChanged(UTKTheme theme)
{
UTKThemeManager.Instance.ApplyThemeToElement(this);
}
#endregion
#region Event Handlers
private void OnClick(ClickEvent evt)
{
if (!_isEnabled) return;
_command.Execute();
evt.StopPropagation();
}
private void OnKeyDown(KeyDownEvent evt)
{
if (!_isEnabled) return;
if (evt.keyCode == KeyCode.Space || evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.KeypadEnter)
{
_command.Execute();
evt.StopPropagation();
}
}
#endregion
#region IDisposable
/// <summary>이벤트 콜백 및 테마 구독을 해제합니다.</summary>
public void Dispose()
{
if (_disposed) return;
_disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<ClickEvent>(OnClick);
UnregisterCallback<KeyDownEvent>(OnKeyDown, TrickleDown.TrickleDown);
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanel);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanel);
}
#endregion
}
}