192 lines
5.8 KiB
C#
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
|
|
}
|
|
}
|