861 lines
30 KiB
C#
861 lines
30 KiB
C#
#nullable enable
|
|
using System;
|
|
using System.Threading;
|
|
using Cysharp.Threading.Tasks;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
using UVC.Extention;
|
|
|
|
namespace UVC.UIToolkit
|
|
{
|
|
/// <summary>
|
|
/// 텍스트 라벨 컴포넌트.
|
|
/// 다양한 스타일과 크기의 텍스트를 표시합니다.
|
|
/// Material Icon 또는 Image Icon을 텍스트와 함께 또는 단독으로 표시할 수 있습니다.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para><b>라벨(Label)이란?</b></para>
|
|
/// <para>
|
|
/// 라벨은 화면에 텍스트를 표시하는 가장 기본적인 UI 컴포넌트입니다.
|
|
/// 제목, 본문, 설명, 상태 메시지 등 다양한 용도로 사용됩니다.
|
|
/// UTKLabel은 Unity의 기본 Label에 스타일 시스템과 아이콘 기능을 추가한 확장 버전입니다.
|
|
/// </para>
|
|
///
|
|
/// <para><b>텍스트 크기 (LabelSize):</b></para>
|
|
/// <list type="bullet">
|
|
/// <item><description><c>H1</c> - 가장 큰 제목 (28px)</description></item>
|
|
/// <item><description><c>H2</c> - 중간 제목 (24px)</description></item>
|
|
/// <item><description><c>H3</c> - 작은 제목 (20px)</description></item>
|
|
/// <item><description><c>Body1</c> - 기본 본문 (16px, 기본값)</description></item>
|
|
/// <item><description><c>Body2</c> - 작은 본문 (14px)</description></item>
|
|
/// <item><description><c>Label1</c> - 필드 라벨 (14px)</description></item>
|
|
/// <item><description><c>Label2</c>, <c>Label3</c> - 작은 라벨 (12px)</description></item>
|
|
/// <item><description><c>Caption</c> - 캡션, 힌트 텍스트 (12px)</description></item>
|
|
/// </list>
|
|
///
|
|
/// <para><b>텍스트 색상 (LabelVariant):</b></para>
|
|
/// <list type="bullet">
|
|
/// <item><description><c>Primary</c> - 기본 색상 (가장 진한 텍스트)</description></item>
|
|
/// <item><description><c>Secondary</c> - 보조 색상 (흐린 텍스트)</description></item>
|
|
/// <item><description><c>Disabled</c> - 비활성화 색상</description></item>
|
|
/// <item><description><c>Success</c> - 성공 (녹색)</description></item>
|
|
/// <item><description><c>Warning</c> - 경고 (주황색)</description></item>
|
|
/// <item><description><c>Error</c> - 오류 (빨간색)</description></item>
|
|
/// <item><description><c>Info</c> - 정보 (파란색)</description></item>
|
|
/// </list>
|
|
///
|
|
/// <para><b>아이콘 사용 방법:</b></para>
|
|
/// <list type="number">
|
|
/// <item><description>Material Icon: 폰트 기반 벡터 아이콘 (권장, <c>UTKMaterialIcons</c> 클래스 사용)</description></item>
|
|
/// <item><description>Image Icon: 이미지 기반 아이콘 (<c>UTKImageIcons</c> 클래스 사용)</description></item>
|
|
/// </list>
|
|
///
|
|
/// <para><b>실제 활용 예시:</b></para>
|
|
/// <list type="bullet">
|
|
/// <item><description>페이지 제목, 섹션 헤더</description></item>
|
|
/// <item><description>버튼/입력 필드의 라벨</description></item>
|
|
/// <item><description>상태 메시지, 오류 메시지</description></item>
|
|
/// <item><description>네비게이션 메뉴 항목 (아이콘 + 텍스트)</description></item>
|
|
/// <item><description>아이콘 버튼 (아이콘만)</description></item>
|
|
/// </list>
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <para><b>C# 코드에서 사용:</b></para>
|
|
/// <code>
|
|
/// // 기본 라벨
|
|
/// var label = new UTKLabel();
|
|
/// label.Text = "안녕하세요";
|
|
/// label.Size = UTKLabel.LabelSize.Body1;
|
|
/// label.Variant = UTKLabel.LabelVariant.Primary;
|
|
///
|
|
/// // 제목 스타일
|
|
/// var title = new UTKLabel();
|
|
/// title.Text = "제목";
|
|
/// title.Size = UTKLabel.LabelSize.Heading1;
|
|
/// title.IsBold = true;
|
|
///
|
|
/// // 스타일 적용
|
|
/// label.IsItalic = true;
|
|
/// label.TextAlignment = UTKLabel.TextAlign.Center;
|
|
///
|
|
/// // Material Icon과 텍스트 함께 사용
|
|
/// var iconLabel = new UTKLabel("설정", UTKMaterialIcons.Settings);
|
|
///
|
|
/// // Image Icon과 텍스트 함께 사용
|
|
/// var imgLabel = new UTKLabel("닫기", UTKImageIcons.BtnClose16, isImageIcon: true);
|
|
///
|
|
/// // Material Icon만 사용 (iconSize 파라미터)
|
|
/// var iconOnly = new UTKLabel(UTKMaterialIcons.Home, 12);
|
|
///
|
|
/// // Image Icon만 사용
|
|
/// var imgOnly = new UTKLabel(UTKImageIcons.IconSetting22, isImageIcon: true, iconSize: 0);
|
|
///
|
|
/// // 메서드로 아이콘 설정
|
|
/// label.SetMaterialIcon(UTKMaterialIcons.Search);
|
|
/// label.SetImageIcon(UTKImageIcons.IconSetting22);
|
|
/// </code>
|
|
/// <para><b>UXML에서 사용:</b></para>
|
|
/// <code>
|
|
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
|
|
/// <!-- 기본 라벨 -->
|
|
/// <utk:UTKLabel text="일반 텍스트" />
|
|
///
|
|
/// <!-- 제목 -->
|
|
/// <utk:UTKLabel text="제목" size="H1" is-bold="true" />
|
|
///
|
|
/// <!-- 보조 텍스트 -->
|
|
/// <utk:UTKLabel text="설명" size="Caption" variant="Secondary" />
|
|
///
|
|
/// <!-- Material Icon과 텍스트 -->
|
|
/// <utk:UTKLabel text="설정" material-icon="settings" />
|
|
///
|
|
/// <!-- Image Icon과 텍스트 -->
|
|
/// <utk:UTKLabel text="닫기" image-icon="btn_close_16" />
|
|
///
|
|
/// <!-- 아이콘만 (Material) -->
|
|
/// <utk:UTKLabel material-icon="home" icon-size="24" />
|
|
///
|
|
/// <!-- 아이콘만 (Image) -->
|
|
/// <utk:UTKLabel image-icon="icon_setting_22" icon-size="22" />
|
|
///
|
|
/// <!-- 아이콘 오른쪽 배치 -->
|
|
/// <utk:UTKLabel text="다음" material-icon="arrow_forward" icon-placement="right" />
|
|
/// </ui:UXML>
|
|
/// </code>
|
|
/// </example>
|
|
[UxmlElement]
|
|
public partial class UTKLabel : VisualElement, IDisposable
|
|
{
|
|
#region Constants
|
|
private const string USS_PATH = "UIToolkit/Label/UTKLabel";
|
|
#endregion
|
|
|
|
#region Fields
|
|
private bool _disposed;
|
|
private Label? _label;
|
|
private Label? _iconLabel;
|
|
private VisualElement? _imageIcon;
|
|
|
|
private string _text = "";
|
|
private LabelSize _size = LabelSize.Body1;
|
|
private LabelVariant _variant = LabelVariant.Primary;
|
|
private bool _isBold;
|
|
private bool _isItalic;
|
|
private TextAlign _textAlign = TextAlign.Left;
|
|
private bool _isSelectable;
|
|
private IconPosition _iconPosition = IconPosition.Left;
|
|
private int _iconSize;
|
|
private int _gap = 4;
|
|
private string _materialIconName = "";
|
|
private string _imageIconName = "";
|
|
#endregion
|
|
|
|
#region Properties
|
|
/// <summary>텍스트</summary>
|
|
[UxmlAttribute("text")]
|
|
public string Text
|
|
{
|
|
get => _text;
|
|
set
|
|
{
|
|
_text = value;
|
|
if (_label != null) _label.text = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>텍스트 크기</summary>
|
|
[UxmlAttribute("size")]
|
|
public LabelSize Size
|
|
{
|
|
get => _size;
|
|
set
|
|
{
|
|
_size = value;
|
|
UpdateSize();
|
|
}
|
|
}
|
|
|
|
/// <summary>텍스트 변형</summary>
|
|
[UxmlAttribute("variant")]
|
|
public LabelVariant Variant
|
|
{
|
|
get => _variant;
|
|
set
|
|
{
|
|
_variant = value;
|
|
UpdateVariant();
|
|
}
|
|
}
|
|
|
|
/// <summary>굵은 글꼴</summary>
|
|
[UxmlAttribute("is-bold")]
|
|
public bool IsBold
|
|
{
|
|
get => _isBold;
|
|
set
|
|
{
|
|
_isBold = value;
|
|
EnableInClassList("utk-label--bold", value);
|
|
}
|
|
}
|
|
|
|
/// <summary>기울임 글꼴</summary>
|
|
[UxmlAttribute("is-italic")]
|
|
public bool IsItalic
|
|
{
|
|
get => _isItalic;
|
|
set
|
|
{
|
|
_isItalic = value;
|
|
EnableInClassList("utk-label--italic", value);
|
|
}
|
|
}
|
|
|
|
/// <summary>텍스트 정렬</summary>
|
|
[UxmlAttribute("text-alignment")]
|
|
public TextAlign TextAlignment
|
|
{
|
|
get => _textAlign;
|
|
set
|
|
{
|
|
_textAlign = value;
|
|
UpdateTextAlign();
|
|
}
|
|
}
|
|
|
|
/// <summary>텍스트 선택 가능 여부</summary>
|
|
[UxmlAttribute("is-selectable")]
|
|
public bool IsSelectable
|
|
{
|
|
get => _isSelectable;
|
|
set
|
|
{
|
|
_isSelectable = value;
|
|
if (_label != null)
|
|
{
|
|
_label.selection.isSelectable = value;
|
|
_label.pickingMode = value ? PickingMode.Position : PickingMode.Ignore;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>아이콘 위치 (텍스트 기준 왼쪽/오른쪽)</summary>
|
|
[UxmlAttribute("icon-placement")]
|
|
public IconPosition IconPlacement
|
|
{
|
|
get => _iconPosition;
|
|
set
|
|
{
|
|
_iconPosition = value;
|
|
UpdateIconPosition();
|
|
}
|
|
}
|
|
|
|
/// <summary>아이콘 크기 (0이면 텍스트 크기에 맞춤)</summary>
|
|
[UxmlAttribute("icon-size")]
|
|
public int IconSize
|
|
{
|
|
get => _iconSize;
|
|
set
|
|
{
|
|
_iconSize = value;
|
|
UpdateIconSize();
|
|
}
|
|
}
|
|
|
|
/// <summary>아이콘과 텍스트 사이 간격 (px)</summary>
|
|
[UxmlAttribute("gap")]
|
|
public int Gap
|
|
{
|
|
get => _gap;
|
|
set
|
|
{
|
|
_gap = value;
|
|
UpdateGap();
|
|
}
|
|
}
|
|
|
|
/// <summary>Material Icon 이름 (예: "settings", "home")</summary>
|
|
[UxmlAttribute("material-icon")]
|
|
public string MaterialIcon
|
|
{
|
|
get => _materialIconName;
|
|
set
|
|
{
|
|
_materialIconName = value;
|
|
if (!string.IsNullOrEmpty(value))
|
|
{
|
|
SetMaterialIconByName(value);
|
|
}
|
|
else
|
|
{
|
|
ClearIcon();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Image Icon 이름 (예: "icon_setting_22", "btn_close_16")</summary>
|
|
[UxmlAttribute("image-icon")]
|
|
public string ImageIcon
|
|
{
|
|
get => _imageIconName;
|
|
set
|
|
{
|
|
_imageIconName = value;
|
|
if (!string.IsNullOrEmpty(value))
|
|
{
|
|
SetImageIconByName(value);
|
|
}
|
|
else
|
|
{
|
|
ClearIcon();
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Enums
|
|
public enum LabelSize
|
|
{
|
|
H1,
|
|
H2,
|
|
H3,
|
|
Body1,
|
|
Body2,
|
|
Label1,
|
|
Label2,
|
|
Label3,
|
|
Label4,
|
|
Caption
|
|
}
|
|
|
|
public enum LabelVariant
|
|
{
|
|
Primary,
|
|
Secondary,
|
|
Disabled,
|
|
Success,
|
|
Warning,
|
|
Error,
|
|
Info
|
|
}
|
|
|
|
public enum TextAlign
|
|
{
|
|
Left,
|
|
Center,
|
|
Right
|
|
}
|
|
|
|
public enum IconPosition
|
|
{
|
|
Left,
|
|
Right
|
|
}
|
|
#endregion
|
|
|
|
#region Constructor
|
|
public UTKLabel()
|
|
{
|
|
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
|
|
|
var uss = Resources.Load<StyleSheet>(USS_PATH);
|
|
if (uss != null)
|
|
{
|
|
styleSheets.Add(uss);
|
|
}
|
|
|
|
CreateUI();
|
|
SubscribeToThemeChanges();
|
|
|
|
// UXML에서 로드될 때 속성이 설정된 후 UI 갱신
|
|
// Unity 6의 소스 생성기는 Deserialize에서 필드에 직접 값을 할당하므로
|
|
// AttachToPanelEvent를 사용하여 패널에 연결된 후 UI를 갱신
|
|
RegisterCallback<AttachToPanelEvent>(OnAttachToPanel);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 텍스트와 크기를 지정하여 라벨을 생성합니다.
|
|
/// </summary>
|
|
/// <param name="text">표시할 텍스트</param>
|
|
/// <param name="size">텍스트 크기</param>
|
|
public UTKLabel(string text, LabelSize size = LabelSize.Body1) : this()
|
|
{
|
|
Text = text;
|
|
Size = size;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Material Icon과 텍스트를 함께 표시하는 라벨을 생성합니다.
|
|
/// </summary>
|
|
/// <param name="text">표시할 텍스트</param>
|
|
/// <param name="materialIcon">Material Icon 유니코드 문자 (예: UTKMaterialIcons.Settings)</param>
|
|
/// <param name="iconPosition">아이콘 위치 (기본: 왼쪽)</param>
|
|
/// <param name="size">텍스트 크기</param>
|
|
public UTKLabel(string text, string materialIcon, IconPosition iconPosition = IconPosition.Left, LabelSize size = LabelSize.Body1) : this()
|
|
{
|
|
Text = text;
|
|
Size = size;
|
|
IconPlacement = iconPosition;
|
|
SetMaterialIcon(materialIcon);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Image Icon과 텍스트를 함께 표시하는 라벨을 생성합니다.
|
|
/// </summary>
|
|
/// <param name="text">표시할 텍스트</param>
|
|
/// <param name="imageIconPath">Image Icon 리소스 경로 (예: UTKImageIcons.IconSetting22)</param>
|
|
/// <param name="isImageIcon">true로 설정해야 합니다 (Image Icon 생성자 구분용)</param>
|
|
/// <param name="iconPosition">아이콘 위치 (기본: 왼쪽)</param>
|
|
/// <param name="size">텍스트 크기</param>
|
|
public UTKLabel(string text, string imageIconPath, bool isImageIcon, IconPosition iconPosition = IconPosition.Left, LabelSize size = LabelSize.Body1) : this()
|
|
{
|
|
Text = text;
|
|
Size = size;
|
|
IconPlacement = iconPosition;
|
|
if (isImageIcon)
|
|
{
|
|
SetImageIcon(imageIconPath);
|
|
}
|
|
else
|
|
{
|
|
SetMaterialIcon(imageIconPath);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Material Icon만 표시하는 라벨을 생성합니다.
|
|
/// </summary>
|
|
/// <param name="materialIcon">Material Icon 유니코드 문자 (예: UTKMaterialIcons.Home)</param>
|
|
/// <param name="iconSize">아이콘 크기 (0이면 기본 크기)</param>
|
|
public UTKLabel(string materialIcon, int iconSize = 0) : this()
|
|
{
|
|
IconSize = iconSize;
|
|
SetMaterialIcon(materialIcon);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Image Icon만 표시하는 라벨을 생성합니다.
|
|
/// </summary>
|
|
/// <param name="imageIconPath">Image Icon 리소스 경로 (예: UTKImageIcons.IconSetting22)</param>
|
|
/// <param name="isImageIcon">true로 설정해야 합니다 (Image Icon 생성자 구분용)</param>
|
|
/// <param name="iconSize">아이콘 크기 (0이면 기본 크기)</param>
|
|
public UTKLabel(string imageIconPath, bool isImageIcon, int iconSize = 0) : this()
|
|
{
|
|
IconSize = iconSize;
|
|
if (isImageIcon)
|
|
{
|
|
SetImageIcon(imageIconPath);
|
|
}
|
|
else
|
|
{
|
|
SetMaterialIcon(imageIconPath);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region UI Creation
|
|
private void CreateUI()
|
|
{
|
|
AddToClassList("utk-label");
|
|
|
|
_label = new Label { name = "label", pickingMode = PickingMode.Ignore };
|
|
_label.AddToClassList("utk-label__text");
|
|
Add(_label);
|
|
|
|
UpdateSize();
|
|
UpdateVariant();
|
|
UpdateTextAlign();
|
|
}
|
|
|
|
private void SubscribeToThemeChanges()
|
|
{
|
|
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
|
RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanel);
|
|
RegisterCallback<AttachToPanelEvent>(OnReattachToPanel);
|
|
}
|
|
|
|
private void OnDetachFromPanel(DetachFromPanelEvent evt)
|
|
{
|
|
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
|
}
|
|
|
|
private void OnReattachToPanel(AttachToPanelEvent evt)
|
|
{
|
|
// TreeView 가상화로 인해 재연결 시 테마 재적용
|
|
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; // 중복 방지
|
|
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
|
|
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
|
}
|
|
|
|
private void OnThemeChanged(UTKTheme theme)
|
|
{
|
|
UTKThemeManager.Instance.ApplyThemeToElement(this);
|
|
}
|
|
|
|
private void OnAttachToPanel(AttachToPanelEvent evt)
|
|
{
|
|
// UXML 속성이 설정된 후 한 번만 UI 갱신
|
|
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanel);
|
|
if (_label != null) _label.text = _text;
|
|
UpdateSize();
|
|
UpdateVariant();
|
|
UpdateTextAlign();
|
|
EnableInClassList("utk-label--bold", _isBold);
|
|
EnableInClassList("utk-label--italic", _isItalic);
|
|
|
|
// 아이콘 속성이 설정된 경우 적용
|
|
if (!string.IsNullOrEmpty(_materialIconName))
|
|
{
|
|
SetMaterialIconByName(_materialIconName);
|
|
}
|
|
else if (!string.IsNullOrEmpty(_imageIconName))
|
|
{
|
|
SetImageIconByName(_imageIconName);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Update Methods
|
|
private void UpdateSize()
|
|
{
|
|
RemoveFromClassList("utk-label--h1");
|
|
RemoveFromClassList("utk-label--h2");
|
|
RemoveFromClassList("utk-label--h3");
|
|
RemoveFromClassList("utk-label--body1");
|
|
RemoveFromClassList("utk-label--body2");
|
|
RemoveFromClassList("utk-label--label1");
|
|
RemoveFromClassList("utk-label--label2");
|
|
RemoveFromClassList("utk-label--label3");
|
|
RemoveFromClassList("utk-label--label4");
|
|
RemoveFromClassList("utk-label--caption");
|
|
|
|
var sizeClass = _size switch
|
|
{
|
|
LabelSize.H1 => "utk-label--h1",
|
|
LabelSize.H2 => "utk-label--h2",
|
|
LabelSize.H3 => "utk-label--h3",
|
|
LabelSize.Body2 => "utk-label--body2",
|
|
LabelSize.Label1 => "utk-label--label1",
|
|
LabelSize.Label2 => "utk-label--label2",
|
|
LabelSize.Label3 => "utk-label--label3",
|
|
LabelSize.Label4 => "utk-label--label4",
|
|
LabelSize.Caption => "utk-label--caption",
|
|
_ => "utk-label--body1"
|
|
};
|
|
AddToClassList(sizeClass);
|
|
}
|
|
|
|
private void UpdateVariant()
|
|
{
|
|
RemoveFromClassList("utk-label--primary");
|
|
RemoveFromClassList("utk-label--secondary");
|
|
RemoveFromClassList("utk-label--disabled");
|
|
RemoveFromClassList("utk-label--success");
|
|
RemoveFromClassList("utk-label--warning");
|
|
RemoveFromClassList("utk-label--error");
|
|
RemoveFromClassList("utk-label--info");
|
|
|
|
var variantClass = _variant switch
|
|
{
|
|
LabelVariant.Secondary => "utk-label--secondary",
|
|
LabelVariant.Disabled => "utk-label--disabled",
|
|
LabelVariant.Success => "utk-label--success",
|
|
LabelVariant.Warning => "utk-label--warning",
|
|
LabelVariant.Error => "utk-label--error",
|
|
LabelVariant.Info => "utk-label--info",
|
|
_ => "utk-label--primary"
|
|
};
|
|
AddToClassList(variantClass);
|
|
}
|
|
|
|
private void UpdateTextAlign()
|
|
{
|
|
RemoveFromClassList("utk-label--left");
|
|
RemoveFromClassList("utk-label--center");
|
|
RemoveFromClassList("utk-label--right");
|
|
|
|
var alignClass = _textAlign switch
|
|
{
|
|
TextAlign.Center => "utk-label--center",
|
|
TextAlign.Right => "utk-label--right",
|
|
_ => "utk-label--left"
|
|
};
|
|
AddToClassList(alignClass);
|
|
}
|
|
|
|
private void UpdateIconPosition()
|
|
{
|
|
if (_iconLabel != null)
|
|
{
|
|
_iconLabel.SendToBack();
|
|
if (_iconPosition == IconPosition.Right)
|
|
{
|
|
_iconLabel.BringToFront();
|
|
}
|
|
}
|
|
|
|
if (_imageIcon != null)
|
|
{
|
|
_imageIcon.SendToBack();
|
|
if (_iconPosition == IconPosition.Right)
|
|
{
|
|
_imageIcon.BringToFront();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdateIconSize()
|
|
{
|
|
var size = GetEffectiveIconSize();
|
|
|
|
if (_iconLabel != null && _iconLabel.style.display == DisplayStyle.Flex)
|
|
{
|
|
_iconLabel.style.fontSize = size;
|
|
}
|
|
|
|
if (_imageIcon != null && _imageIcon.style.display == DisplayStyle.Flex)
|
|
{
|
|
_imageIcon.style.width = size;
|
|
_imageIcon.style.height = size;
|
|
}
|
|
}
|
|
|
|
private void UpdateGap()
|
|
{
|
|
// 아이콘과 텍스트 사이의 간격을 적용
|
|
if (_iconLabel != null)
|
|
{
|
|
_iconLabel.style.marginRight = _iconPosition == IconPosition.Left ? (_text.IsNullOrEmpty() ? 0 : _gap) : 0;
|
|
_iconLabel.style.marginLeft = _iconPosition == IconPosition.Right ? (_text.IsNullOrEmpty() ? 0 : _gap) : 0;
|
|
}
|
|
|
|
if (_imageIcon != null)
|
|
{
|
|
_imageIcon.style.marginRight = _iconPosition == IconPosition.Left ? (_text.IsNullOrEmpty() ? 0 : _gap) : 0;
|
|
_imageIcon.style.marginLeft = _iconPosition == IconPosition.Right ? (_text.IsNullOrEmpty() ? 0 : _gap) : 0;
|
|
}
|
|
}
|
|
|
|
private int GetEffectiveIconSize()
|
|
{
|
|
if (_iconSize > 0) return _iconSize;
|
|
|
|
return _size switch
|
|
{
|
|
LabelSize.H1 => 28,
|
|
LabelSize.H2 => 24,
|
|
LabelSize.H3 => 20,
|
|
LabelSize.Body1 => 16,
|
|
LabelSize.Body2 => 14,
|
|
LabelSize.Label1 => 14,
|
|
LabelSize.Label2 => 12,
|
|
LabelSize.Label3 => 12,
|
|
LabelSize.Caption => 12,
|
|
_ => 16
|
|
};
|
|
}
|
|
#endregion
|
|
|
|
#region Icon Methods
|
|
/// <summary>
|
|
/// Material Icon을 설정합니다.
|
|
/// </summary>
|
|
/// <param name="icon">Material Icon 유니코드 문자 (예: UTKMaterialIcons.Settings)</param>
|
|
/// <param name="fontSize">아이콘 폰트 크기 (null이면 텍스트 크기에 맞춤)</param>
|
|
public void SetMaterialIcon(string icon, int? fontSize = null)
|
|
{
|
|
ClearImageIcon();
|
|
EnsureIconLabel();
|
|
|
|
if (_iconLabel != null)
|
|
{
|
|
_iconLabel.text = icon;
|
|
_iconLabel.style.display = DisplayStyle.Flex;
|
|
UTKMaterialIcons.ApplyIconStyle(_iconLabel, fontSize ?? GetEffectiveIconSize());
|
|
}
|
|
if(_text.IsNullOrEmpty()) TextAlignment = TextAlign.Center; // 텍스트가 없는 경우 아이콘 중앙 정렬
|
|
EnableInClassList("utk-label--has-icon", true);
|
|
UpdateIconPosition();
|
|
UpdateGap();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Material Icon을 비동기로 설정합니다.
|
|
/// </summary>
|
|
/// <param name="icon">Material Icon 유니코드 문자 (예: UTKMaterialIcons.Settings)</param>
|
|
/// <param name="ct">취소 토큰</param>
|
|
/// <param name="fontSize">아이콘 폰트 크기 (null이면 텍스트 크기에 맞춤)</param>
|
|
public async UniTask SetMaterialIconAsync(string icon, CancellationToken ct = default, int? fontSize = null)
|
|
{
|
|
ClearImageIcon();
|
|
EnsureIconLabel();
|
|
|
|
if (_iconLabel != null)
|
|
{
|
|
_iconLabel.text = icon;
|
|
_iconLabel.style.display = DisplayStyle.Flex;
|
|
await UTKMaterialIcons.ApplyIconStyleAsync(_iconLabel, ct, fontSize ?? GetEffectiveIconSize());
|
|
}
|
|
|
|
if(_text.IsNullOrEmpty()) TextAlignment = TextAlign.Center; // 텍스트가 없는 경우 아이콘 중앙 정렬
|
|
EnableInClassList("utk-label--has-icon", true);
|
|
UpdateIconPosition();
|
|
UpdateGap();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 아이콘 이름으로 Material Icon을 설정합니다.
|
|
/// </summary>
|
|
/// <param name="iconName">아이콘 이름 (예: "settings", "home")</param>
|
|
/// <param name="fontSize">아이콘 폰트 크기 (null이면 텍스트 크기에 맞춤)</param>
|
|
public void SetMaterialIconByName(string iconName, int? fontSize = null)
|
|
{
|
|
string iconChar = UTKMaterialIcons.GetIcon(iconName);
|
|
if (iconChar != string.Empty)
|
|
{
|
|
SetMaterialIcon(iconChar, fontSize);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"[UTKLabel] Material icon '{iconName}'을(를) 찾을 수 없습니다.");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Image Icon을 설정합니다.
|
|
/// </summary>
|
|
/// <param name="resourcePath">이미지 리소스 경로 (예: UTKImageIcons.IconSetting22)</param>
|
|
/// <param name="iconSize">아이콘 크기 (null이면 텍스트 크기에 맞춤)</param>
|
|
public void SetImageIcon(string resourcePath, int? iconSize = null)
|
|
{
|
|
var texture = UTKImageIcons.LoadTexture(resourcePath);
|
|
if (texture != null)
|
|
{
|
|
ApplyImageIcon(texture, iconSize);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"[UTKLabel] Image icon '{resourcePath}'을(를) 로드할 수 없습니다.");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Image Icon을 비동기로 설정합니다.
|
|
/// </summary>
|
|
/// <param name="resourcePath">이미지 리소스 경로 (예: UTKImageIcons.IconSetting22)</param>
|
|
/// <param name="ct">취소 토큰</param>
|
|
/// <param name="iconSize">아이콘 크기 (null이면 텍스트 크기에 맞춤)</param>
|
|
public async UniTask SetImageIconAsync(string resourcePath, CancellationToken ct = default, int? iconSize = null)
|
|
{
|
|
var texture = await UTKImageIcons.LoadTextureAsync(resourcePath, ct);
|
|
if (texture != null)
|
|
{
|
|
ApplyImageIcon(texture, iconSize);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"[UTKLabel] Image icon '{resourcePath}'을(를) 로드할 수 없습니다.");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 아이콘 이름으로 Image Icon을 설정합니다.
|
|
/// </summary>
|
|
/// <param name="iconName">아이콘 이름 (예: "icon_setting_22", "btn_close_16")</param>
|
|
/// <param name="iconSize">아이콘 크기 (null이면 텍스트 크기에 맞춤)</param>
|
|
public void SetImageIconByName(string iconName, int? iconSize = null)
|
|
{
|
|
var texture = UTKImageIcons.LoadTextureByName(iconName);
|
|
if (texture != null)
|
|
{
|
|
ApplyImageIcon(texture, iconSize);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"[UTKLabel] Image icon '{iconName}'을(를) 찾을 수 없습니다.");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 모든 아이콘을 제거합니다.
|
|
/// </summary>
|
|
public void ClearIcon()
|
|
{
|
|
ClearMaterialIcon();
|
|
ClearImageIcon();
|
|
EnableInClassList("utk-label--has-icon", false);
|
|
}
|
|
|
|
private void EnsureIconLabel()
|
|
{
|
|
if (_iconLabel != null) return;
|
|
|
|
_iconLabel = new Label
|
|
{
|
|
name = "icon",
|
|
pickingMode = PickingMode.Ignore
|
|
};
|
|
_iconLabel.AddToClassList("utk-label__icon");
|
|
_iconLabel.style.display = DisplayStyle.None;
|
|
Insert(0, _iconLabel);
|
|
}
|
|
|
|
private void ApplyImageIcon(Texture2D texture, int? iconSize)
|
|
{
|
|
ClearMaterialIcon();
|
|
|
|
if (_imageIcon == null)
|
|
{
|
|
_imageIcon = new VisualElement
|
|
{
|
|
name = "image-icon",
|
|
pickingMode = PickingMode.Ignore
|
|
};
|
|
_imageIcon.AddToClassList("utk-label__image-icon");
|
|
Insert(0, _imageIcon);
|
|
}
|
|
|
|
var size = iconSize ?? GetEffectiveIconSize();
|
|
_imageIcon.style.width = size;
|
|
_imageIcon.style.height = size;
|
|
_imageIcon.style.backgroundImage = new StyleBackground(texture);
|
|
_imageIcon.style.display = DisplayStyle.Flex;
|
|
|
|
if(_text.IsNullOrEmpty()) TextAlignment = TextAlign.Center; // 텍스트가 없는 경우 아이콘 중앙 정렬
|
|
EnableInClassList("utk-label--has-icon", true);
|
|
UpdateIconPosition();
|
|
UpdateGap();
|
|
}
|
|
|
|
private void ClearMaterialIcon()
|
|
{
|
|
if (_iconLabel != null)
|
|
{
|
|
_iconLabel.text = "";
|
|
_iconLabel.style.display = DisplayStyle.None;
|
|
}
|
|
}
|
|
|
|
private void ClearImageIcon()
|
|
{
|
|
if (_imageIcon != null)
|
|
{
|
|
_imageIcon.style.backgroundImage = StyleKeyword.None;
|
|
_imageIcon.style.display = DisplayStyle.None;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region IDisposable
|
|
public void Dispose()
|
|
{
|
|
if (_disposed) return;
|
|
_disposed = true;
|
|
|
|
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
|
|
}
|
|
#endregion
|
|
}
|
|
}
|