UIToolkit 기본 UI 개발 중

This commit is contained in:
logonkhi
2026-01-08 20:15:57 +09:00
parent ef4e86820c
commit 71831dd4c3
319 changed files with 28283 additions and 761 deletions

View File

@@ -0,0 +1,353 @@
#nullable enable
using System;
using UnityEngine;
using UnityEngine.UIElements;
namespace UVC.UIToolkit
{
/// <summary>
/// 커스텀 버튼 컴포넌트.
/// 텍스트와 아이콘을 동시에 표시하거나, 아이콘만 표시할 수 있습니다.
/// 배경 색상, 외곽선 굵기 등을 설정할 수 있습니다.
/// </summary>
[UxmlElement]
public partial class UTKButton : VisualElement, IDisposable
{
#region Constants
private const string USS_PATH = "UIToolkit/Button/UTKButton";
#endregion
#region Fields
private bool _disposed;
private Label? _iconLabel;
private Label? _textLabel;
private string _text = "";
private string _icon = "";
private ButtonVariant _variant = ButtonVariant.Normal;
private ButtonSize _size = ButtonSize.Medium;
private Color? _backgroundColor;
private int _borderWidth = -1;
private bool _iconOnly;
private bool _isEnabled = true;
#endregion
#region Events
/// <summary>버튼 클릭 이벤트</summary>
public event Action? OnClicked;
#endregion
#region Properties
/// <summary>버튼 텍스트</summary>
[UxmlAttribute]
public string Text
{
get => _text;
set
{
_text = value;
UpdateContent();
}
}
/// <summary>아이콘 (유니코드 문자 또는 텍스트)</summary>
[UxmlAttribute]
public string Icon
{
get => _icon;
set
{
_icon = value;
UpdateContent();
}
}
/// <summary>버튼 스타일 변형</summary>
[UxmlAttribute]
public ButtonVariant Variant
{
get => _variant;
set
{
_variant = value;
UpdateVariant();
}
}
/// <summary>버튼 크기</summary>
[UxmlAttribute]
public ButtonSize Size
{
get => _size;
set
{
_size = value;
UpdateSize();
}
}
/// <summary>커스텀 배경 색상 (null이면 기본 스타일 사용)</summary>
public Color? BackgroundColor
{
get => _backgroundColor;
set
{
_backgroundColor = value;
UpdateCustomStyles();
}
}
/// <summary>외곽선 굵기 (-1이면 기본값 사용)</summary>
[UxmlAttribute]
public int BorderWidth
{
get => _borderWidth;
set
{
_borderWidth = value;
UpdateCustomStyles();
}
}
/// <summary>아이콘만 표시 모드</summary>
[UxmlAttribute]
public bool IconOnly
{
get => _iconOnly;
set
{
_iconOnly = value;
UpdateContent();
}
}
/// <summary>버튼 활성화 상태</summary>
[UxmlAttribute]
public bool IsEnabled
{
get => _isEnabled;
set
{
_isEnabled = value;
SetEnabled(value);
EnableInClassList("utk-button--disabled", !value);
}
}
#endregion
#region Enums
public enum ButtonVariant
{
Normal,
Primary,
Secondary,
Ghost,
Danger,
OutlineNormal,
OutlinePrimary,
OutlineDanger
}
public enum ButtonSize
{
Small,
Medium,
Large
}
#endregion
#region Constructor
public UTKButton()
{
UTKThemeManager.Instance.ApplyThemeToElement(this);
var uss = Resources.Load<StyleSheet>(USS_PATH);
if (uss != null)
{
styleSheets.Add(uss);
}
CreateUI();
SetupEvents();
SubscribeToThemeChanges();
}
public UTKButton(string text, string icon = "", ButtonVariant variant = ButtonVariant.Normal) : this()
{
_text = text;
_icon = icon;
_variant = variant;
UpdateContent();
UpdateVariant();
}
#endregion
#region UI Creation
private void CreateUI()
{
AddToClassList("utk-button");
focusable = true;
_iconLabel = new Label
{
name = "icon",
pickingMode = PickingMode.Ignore
};
_iconLabel.AddToClassList("utk-button__icon");
Add(_iconLabel);
_textLabel = new Label
{
name = "text",
pickingMode = PickingMode.Ignore
};
_textLabel.AddToClassList("utk-button__text");
Add(_textLabel);
UpdateContent();
UpdateVariant();
UpdateSize();
}
private void SetupEvents()
{
RegisterCallback<ClickEvent>(OnClick);
RegisterCallback<KeyDownEvent>(OnKeyDown);
}
private void SubscribeToThemeChanges()
{
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ =>
{
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;
OnClicked?.Invoke();
evt.StopPropagation();
}
private void OnKeyDown(KeyDownEvent evt)
{
if (!_isEnabled) return;
if (evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.Space)
{
OnClicked?.Invoke();
evt.StopPropagation();
}
}
#endregion
#region Update Methods
private void UpdateContent()
{
bool hasIcon = !string.IsNullOrEmpty(_icon);
bool hasText = !string.IsNullOrEmpty(_text);
if (_iconLabel != null)
{
_iconLabel.text = _icon;
_iconLabel.style.display = hasIcon ? DisplayStyle.Flex : DisplayStyle.None;
}
if (_textLabel != null)
{
_textLabel.text = _text;
_textLabel.style.display = (_iconOnly || !hasText) ? DisplayStyle.None : DisplayStyle.Flex;
}
EnableInClassList("utk-button--icon-only", _iconOnly || (hasIcon && !hasText));
EnableInClassList("utk-button--has-icon", hasIcon && hasText && !_iconOnly);
}
private void UpdateVariant()
{
RemoveFromClassList("utk-button--normal");
RemoveFromClassList("utk-button--primary");
RemoveFromClassList("utk-button--secondary");
RemoveFromClassList("utk-button--ghost");
RemoveFromClassList("utk-button--danger");
RemoveFromClassList("utk-button--outline-normal");
RemoveFromClassList("utk-button--outline-primary");
RemoveFromClassList("utk-button--outline-danger");
var variantClass = _variant switch
{
ButtonVariant.Primary => "utk-button--primary",
ButtonVariant.Secondary => "utk-button--secondary",
ButtonVariant.Ghost => "utk-button--ghost",
ButtonVariant.Danger => "utk-button--danger",
ButtonVariant.OutlineNormal => "utk-button--outline-normal",
ButtonVariant.OutlinePrimary => "utk-button--outline-primary",
ButtonVariant.OutlineDanger => "utk-button--outline-danger",
_ => "utk-button--normal"
};
AddToClassList(variantClass);
}
private void UpdateSize()
{
RemoveFromClassList("utk-button--small");
RemoveFromClassList("utk-button--medium");
RemoveFromClassList("utk-button--large");
var sizeClass = _size switch
{
ButtonSize.Small => "utk-button--small",
ButtonSize.Large => "utk-button--large",
_ => "utk-button--medium"
};
AddToClassList(sizeClass);
}
private void UpdateCustomStyles()
{
if (_backgroundColor.HasValue)
{
style.backgroundColor = _backgroundColor.Value;
}
else
{
style.backgroundColor = StyleKeyword.Null;
}
if (_borderWidth >= 0)
{
style.borderTopWidth = _borderWidth;
style.borderBottomWidth = _borderWidth;
style.borderLeftWidth = _borderWidth;
style.borderRightWidth = _borderWidth;
}
else
{
style.borderTopWidth = StyleKeyword.Null;
style.borderBottomWidth = StyleKeyword.Null;
style.borderLeftWidth = StyleKeyword.Null;
style.borderRightWidth = StyleKeyword.Null;
}
}
#endregion
#region IDisposable
public void Dispose()
{
if (_disposed) return;
_disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
OnClicked = null;
}
#endregion
}
}