스타일 가이드 수정 중

This commit is contained in:
logonkhi
2026-01-23 19:04:12 +09:00
parent 59d473c87b
commit 99f9c3b26d
86 changed files with 3013 additions and 1795 deletions

View File

@@ -9,105 +9,209 @@ namespace UVC.UIToolkit
{
/// <summary>
/// 커스텀 버튼 컴포넌트.
/// 텍스트와 아이콘을 동시에 표시하거나, 아이콘만 표시할 수 있습니다.
/// 배경 색상, 외곽선 굵기 등을 설정할 수 있습니다.
/// 다양한 스타일 변형(Filled, Outline, Ghost, Text 등)과 아이콘을 지원합니다.
/// Material Icons와 이미지 아이콘을 모두 사용할 수 있으며, 클릭 이벤트와 비동기 액션을 지원합니다.
/// </summary>
/// <example>
/// <para><b>C# 코드에서 사용:</b></para>
/// <para><b>1. Filled Buttons (배경이 채워진 버튼)</b></para>
/// <code>
/// // 기본 버튼 생성
/// var btn = new UTKButton("확인");
/// btn.OnClicked += () => Debug.Log("클릭됨!");
/// // C# 코드
/// var primaryBtn = new UTKButton("Primary", variant: ButtonVariant.Primary);
/// var normalBtn = new UTKButton("Normal", variant: ButtonVariant.Normal);
/// var dangerBtn = new UTKButton("Danger", variant: ButtonVariant.Danger);
///
/// // 텍스트와 Material Icon이 있는 버튼
/// var saveBtn = new UTKButton("저장", UTKMaterialIcons.Save, UTKButton.ButtonVariant.Primary);
/// primaryBtn.OnClicked += () => Debug.Log("Primary 클릭!");
///
/// // 텍스트와 아이콘 (크기 지정)
/// var largeIconBtn = new UTKButton("설정", UTKMaterialIcons.Settings, UTKButton.ButtonVariant.Primary, 28);
/// var smallImageBtn = new UTKButton("닫기", UTKImageIcons.BtnClose22, UTKButton.ButtonVariant.Danger, 20);
/// // UXML 태그
/// // <utk:UTKButton text="Primary" variant="Primary" />
/// // <utk:UTKButton text="Normal" variant="Normal" />
/// // <utk:UTKButton text="Danger" variant="Danger" />
/// </code>
///
/// <para><b>2. Outline Buttons (외곽선 버튼)</b></para>
/// <code>
/// // C# 코드
/// var outlinePrimary = new UTKButton("Outline Primary", variant: ButtonVariant.OutlinePrimary);
/// var outlineNormal = new UTKButton("Outline Normal", variant: ButtonVariant.OutlineNormal);
/// var outlineDanger = new UTKButton("Outline Danger", variant: ButtonVariant.OutlineDanger);
///
/// // UXML 태그
/// // <utk:UTKButton text="Outline Primary" variant="OutlinePrimary" />
/// // <utk:UTKButton text="Outline Normal" variant="OutlineNormal" />
/// // <utk:UTKButton text="Outline Danger" variant="OutlineDanger" />
/// </code>
///
/// <para><b>3. Icon Only (아이콘만 표시)</b></para>
/// <code>
/// // C# 코드
/// var plusOneBtn = new UTKButton("", UTKMaterialIcons.PlusOne, ButtonVariant.Primary) { IconOnly = true };
/// var editBtn = new UTKButton("", UTKMaterialIcons.Edit, ButtonVariant.Normal) { IconOnly = true };
/// var closeBtn = new UTKButton("", UTKMaterialIcons.Close, ButtonVariant.Danger) { IconOnly = true };
/// var settingsBtn = new UTKButton("", UTKMaterialIcons.Settings, ButtonVariant.OutlinePrimary) { IconOnly = true };
/// var cancelBtn = new UTKButton("", UTKMaterialIcons.Cancel, ButtonVariant.OutlineNormal) { IconOnly = true };
///
/// // UXML 태그
/// // <utk:UTKButton icon="UTKMaterialIcons.Close" icon-only="true" variant="Primary" />
/// // <utk:UTKButton icon="UTKMaterialIcons.Check" icon-only="true" variant="Normal" />
/// // <utk:UTKButton icon="UTKMaterialIcons.Settings" icon-only="true" variant="Danger" />
/// // <utk:UTKButton icon="UTKMaterialIcons.Edit" icon-only="true" variant="OutlinePrimary" />
/// // <utk:UTKButton icon="UTKMaterialIcons.Search" icon-only="true" variant="OutlineNormal" />
/// </code>
///
/// <para><b>4. Ghost (반투명 배경)</b></para>
/// <code>
/// // C# 코드
/// var ghostBtn = new UTKButton("Ghost", variant: ButtonVariant.Ghost);
/// var ghostIconBtn = new UTKButton("", UTKMaterialIcons.Settings, ButtonVariant.Ghost) { IconOnly = true };
///
/// // UXML 태그
/// // <utk:UTKButton text="Ghost" variant="Ghost" />
/// // <utk:UTKButton icon="UTKMaterialIcons.Close" icon-only="true" variant="Ghost" />
/// </code>
///
/// <para><b>5. Text (Label/Icon Only - 배경 없음)</b></para>
/// <code>
/// // C# 코드
/// var textOnlyBtn = new UTKButton("Text Only", variant: ButtonVariant.Text);
/// var linkStyleBtn = new UTKButton("Link Style", variant: ButtonVariant.Text);
/// var withIconBtn = new UTKButton("With Icon", UTKMaterialIcons.Bolt, ButtonVariant.Text);
///
/// // UXML 태그
/// // <utk:UTKButton text="Text Only" variant="Text" />
/// // <utk:UTKButton text="Link Style" variant="Text" />
/// // <utk:UTKButton text="With Icon" icon="close" variant="Text" />
/// </code>
///
/// <para><b>6. Text Icon Only (Circle - 원형 배경의 아이콘 버튼)</b></para>
/// <code>
/// // C# 코드
/// var circleBtn1 = new UTKButton("", UTKMaterialIcons.Home, ButtonVariant.Text, 12) { IconOnly = true };
///
/// var circleBtn2 = new UTKButton("", UTKMaterialIcons.Home, ButtonVariant.Text, 12) { IconOnly = true };
/// var circleBtn3 = new UTKButton("", UTKMaterialIcons.Close, ButtonVariant.Text, 12) { IconOnly = true };
/// var circleBtn4 = new UTKButton("", UTKMaterialIcons.Check, ButtonVariant.Text, 12) { IconOnly = true };
/// var circleBtn5 = new UTKButton("", UTKMaterialIcons.Search, ButtonVariant.Text, 12) { IconOnly = true };
/// var circleBtn6 = new UTKButton("", UTKMaterialIcons.Edit, ButtonVariant.Text, 12) { IconOnly = true };
///
/// // UXML 태그
/// // <utk:UTKButton icon="home;" icon-only="true" icon-size="12" variant="Text" />
/// // <utk:UTKButton icon="close;" icon-only="true" icon-size="12" variant="Text" />
/// // <utk:UTKButton icon="check;" icon-only="true" icon-size="12" variant="Text" />
/// // <utk:UTKButton icon="search;" icon-only="true" icon-size="12" variant="Text" />
/// // <utk:UTKButton icon="edit;" icon-only="true" icon-size="12" variant="Text" />
/// </code>
///
/// <para><b>7. Disabled (비활성화)</b></para>
/// <code>
/// // C# 코드
/// var disabledBtn1 = new UTKButton("Disabled", variant: ButtonVariant.Primary);
/// disabledBtn1.SetEnabled(false);
///
/// var disabledBtn2 = new UTKButton("Disabled", variant: ButtonVariant.Normal);
/// disabledBtn2.SetEnabled(false);
///
/// var disabledBtn3 = new UTKButton("Disabled", variant: ButtonVariant.Danger);
/// disabledBtn3.SetEnabled(false);
///
/// // UXML 태그
/// // <utk:UTKButton text="Disabled" variant="Primary" is-enabled="false" />
/// // <utk:UTKButton text="Disabled" variant="Normal" is-enabled="false" />
/// // <utk:UTKButton text="Disabled" variant="Danger" is-enabled="false" />
/// </code>
///
/// <para><b>8. UTKButton Action 사용 (비동기 작업 지원)</b></para>
/// <code>
/// // Action 사용 - 일반 동기 작업
/// var saveBtn = new UTKButton("저장", UTKMaterialIcons.Save, ButtonVariant.Primary);
/// saveBtn.OnClicked += () => {
/// Debug.Log("저장 중...");
/// SaveData();
/// };
///
/// // Action 사용 - UniTask 비동기 작업
/// var loadBtn = new UTKButton("로드", UTKMaterialIcons.Download, ButtonVariant.Primary);
/// loadBtn.OnClicked += async () => {
/// Debug.Log("로딩 시작...");
/// await LoadDataAsync();
/// Debug.Log("로딩 완료!");
/// };
///
/// // CancellationToken을 사용한 비동기 작업
/// var cts = new CancellationTokenSource();
/// var processBtn = new UTKButton("처리", ButtonVariant.Primary);
/// processBtn.OnClicked += async () => {
/// try {
/// processBtn.SetEnabled(false); // 처리 중 비활성화
/// await ProcessDataAsync(cts.Token);
/// } catch (OperationCanceledException) {
/// Debug.Log("작업이 취소되었습니다.");
/// } finally {
/// processBtn.SetEnabled(true);
/// }
/// };
///
/// // UXML에서 로드 후 Action 할당
/// var root = GetComponent<UIDocument>().rootVisualElement;
/// var confirmBtn = root.Q<UTKButton>("confirm-button");
/// confirmBtn.OnClicked += () => OnConfirm();
///
/// // 여러 Action 구독
/// var multiBtn = new UTKButton("Multi Action", ButtonVariant.Primary);
/// multiBtn.OnClicked += Action1;
/// multiBtn.OnClicked += Action2;
/// multiBtn.OnClicked += Action3;
///
/// // Action 해제
/// multiBtn.OnClicked -= Action2;
/// </code>
///
/// <para><b>9. 아이콘 설정 방법</b></para>
/// <code>
/// // Material Icon 설정
/// // 텍스트와 아이콘 (크기 지정)
/// var largeIconBtn = new UTKButton("설정", UTKMaterialIcons.Settings, UTKButton.ButtonVariant.Primary, 28);
/// var smallImageBtn = new UTKButton("닫기", UTKImageIcons.BtnClose22, UTKButton.ButtonVariant.Danger, 20);
/// var btn = new UTKButton("설정");
/// btn.SetMaterialIcon(UTKMaterialIcons.Settings);
///
/// // Text 버튼 스타일에서 아이콘 크기 지
/// var textSmallIcon = new UTKButton("Small", UTKMaterialIcons.Settings, UTKButton.ButtonVariant.Text, 16);
/// var textMediumIcon = new UTKButton("Medium", UTKMaterialIcons.Settings, UTKButton.ButtonVariant.Text, 24);
/// var textLargeIcon = new UTKButton("Large", UTKMaterialIcons.Settings, UTKButton.ButtonVariant.Text, 32);
///
/// // Material Icon 설정
/// var imgBtn = new UTKButton("닫기");
/// imgBtn.SetImageIcon(UTKImageIcons.BtnClose22);
/// imgBtn.SetImageIconByName("icon_setting_22");
/// // 이미지 아이콘
/// btn.SetImageIcon(UTKImageIcons.BtnClose22);
/// btn.SetImageIconByName("icon_setting_22");
///
/// // 비동기 아이콘 설정
/// await btn.SetMaterialIconAsync(UTKMaterialIcons.Search);
/// await btn.SetImageIconAsync(UTKImageIcons.IconSetting22);
///
/// // 아이콘만 표시하는 버튼
/// var iconOnlyBtn = new UTKButton { IconOnly = true };
/// iconOnlyBtn.SetMaterialIcon(UTKMaterialIcons.Close);
/// // 아이콘 크기 지정
/// var largeIconBtn = new UTKButton("Large Icon", UTKMaterialIcons.Settings, ButtonVariant.Primary, 28);
/// btn.IconSize = 24;
///
/// // 버튼 스타일 변형
/// btn.Variant = UTKButton.ButtonVariant.Primary;
/// btn.Variant = UTKButton.ButtonVariant.Danger;
/// btn.Variant = UTKButton.ButtonVariant.Ghost;
///
/// // 버튼 크기
/// btn.Size = UTKButton.ButtonSize.Small;
/// btn.Size = UTKButton.ButtonSize.Large;
/// // 아이콘 제거
/// btn.ClearIcon();
///
/// // 주의: 생성자에서 icon 파라미터로 아이콘을 전달하면 다음 순서로 타입이 감지됩니다.
/// // 1. UTKMaterialIcons에서 먼저 검사 (Material Symbols Outlined 아이콘)
/// // 2. UTKImageIcons에서 검사 (이미지 기반 아이콘)
/// // 3. 둘 다 아니면 텍스트로 처리됨
///
/// // 아이콘 제거
/// btn.ClearIcon();
/// </code>
/// <para><b>UXML에서 사용:</b></para>
/// <code>
/// <!-- 네임스페이스 선언 -->
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
///
/// <!-- 기본 버튼 -->
/// <utk:UTKButton Text="확인" />
///
/// <!-- Material Icon 버튼 (유니코드 직접 입력) -->
/// <utk:UTKButton Text="설정" Icon="&#xe8b8;" />
///
/// <!-- 버튼 변형 -->
/// <utk:UTKButton Text="저장" Variant="Primary" />
/// <utk:UTKButton Text="삭제" Variant="Danger" />
/// <utk:UTKButton Text="취소" Variant="Ghost" />
/// <utk:UTKButton Text="링크" Variant="Text" />
///
/// <!-- 외곽선 변형 -->
/// <utk:UTKButton Text="확인" Variant="OutlinePrimary" />
/// <utk:UTKButton Text="삭제" Variant="OutlineDanger" />
///
/// <!-- 크기 변형 -->
/// <utk:UTKButton Text="작은 버튼" Size="Small" />
/// <utk:UTKButton Text="큰 버튼" Size="Large" />
///
/// <!-- 아이콘만 표시 -->
/// <utk:UTKButton Icon="&#xe5cd;" IconOnly="true" />
/// <utk:UTKButton Text="" Icon="Close" Variant="Text" IconSize="12" />
///
/// <!-- 비활성화 -->
/// <utk:UTKButton Text="비활성화" IsEnabled="false" />
///
/// <!-- 외곽선 굵기 -->
/// <utk:UTKButton Text="두꺼운 외곽선" BorderWidth="2" />
///
/// </ui:UXML>
/// </code>
/// <para><b>UXML에서 로드 후 C#에서 아이콘 설정:</b></para>
/// <para><b>10. 기타 속성 설정</b></para>
/// <code>
/// var root = GetComponent<UIDocument>().rootVisualElement;
/// var btn = root.Q<UTKButton>("my-button");
/// btn.SetMaterialIcon(UTKMaterialIcons.Settings);
/// // 버튼 크기
/// btn.Size = ButtonSize.Small;
/// btn.Size = ButtonSize.Medium;
/// btn.Size = ButtonSize.Large;
///
/// // 커스텀 배경색
/// btn.BackgroundColor = new Color(0.2f, 0.4f, 0.8f);
///
/// // 외곽선 굵기
/// btn.BorderWidth = 2;
///
/// // 텍스트 동적 변경
/// btn.Text = "새로운 텍스트";
///
/// // UXML에서 사용 시 네임스페이스 선언
/// // <ui:UXML xmlns:utk="UVC.UIToolkit">
/// // <utk:UTKButton text="버튼" />
/// // </ui:UXML>
/// </code>
/// </example>
[UxmlElement]
@@ -130,6 +234,7 @@ namespace UVC.UIToolkit
private ButtonSize sizeValue = ButtonSize.Medium;
private Color? _backgroundColor;
private int borderWidthValue = -1;
private int? iconSizeValue = null;
private bool iconOnlyValue;
private bool isEnabledValue = true;
#endregion
@@ -160,7 +265,7 @@ namespace UVC.UIToolkit
set
{
iconValue = value;
UpdateContent();
UpdateContent();
}
}
@@ -188,6 +293,29 @@ namespace UVC.UIToolkit
}
}
/// <summary>아이콘 크기</summary>
[UxmlAttribute("icon-size")]
public int IconSize
{
get => iconSizeValue ?? 12;
set
{
//if(iconSizeValue == value) return;
iconSizeValue = value;
string iconChar = UTKMaterialIcons.GetIcon(iconValue);
Debug.Log($"[UTKButton] Update Icon Size: {iconSizeValue} {iconValue} -> {iconChar}");
if (iconChar != string.Empty)
{
UpdateMaterialIconSize(iconSizeValue);
}
// 2순위: UTKImageIcons에 해당하는지 확인
else if (!string.IsNullOrEmpty(UTKImageIcons.GetPath(iconValue)))
{
UpdateImageIconSize(iconSizeValue);
}
}
}
/// <summary>커스텀 배경 색상 (null이면 기본 스타일 사용)</summary>
public Color? BackgroundColor
{
@@ -220,6 +348,7 @@ namespace UVC.UIToolkit
{
iconOnlyValue = value;
UpdateContent();
UpdateIcon(iconValue);
}
}
@@ -301,23 +430,9 @@ namespace UVC.UIToolkit
variantValue = variant;
UpdateContent();
UpdateVariant();
iconSizeValue = iconSize;
UpdateIcon(icon);
// 아이콘 타입 자동 감지 및 적용
if (!string.IsNullOrEmpty(icon))
{
// 1순위: UTKMaterialIcons에 해당하는지 확인
string iconChar = UTKMaterialIcons.GetIcon(icon);
if (iconChar != string.Empty)
{
SetMaterialIcon(iconChar, iconSize);
}
// 2순위: UTKImageIcons에 해당하는지 확인
else if (!string.IsNullOrEmpty(UTKImageIcons.GetPath(icon)))
{
SetImageIcon(icon, iconSize);
}
// 3순위: 둘 다 아니면 현재 로직 유지 (UpdateContent에서 이미 처리됨)
}
}
#endregion
@@ -493,6 +608,26 @@ namespace UVC.UIToolkit
style.borderRightWidth = StyleKeyword.Null;
}
}
private void UpdateIcon(string icon)
{
// 아이콘 타입 자동 감지 및 적용
if (!string.IsNullOrEmpty(icon))
{
// 1순위: UTKMaterialIcons에 해당하는지 확인
string iconChar = UTKMaterialIcons.GetIcon(icon);
if (iconChar != string.Empty)
{
SetMaterialIcon(iconChar, iconSizeValue);
}
// 2순위: UTKImageIcons에 해당하는지 확인
else if (!string.IsNullOrEmpty(UTKImageIcons.GetPath(icon)))
{
SetImageIcon(icon, iconSizeValue);
}
// 3순위: 둘 다 아니면 현재 로직 유지 (UpdateContent에서 이미 처리됨)
}
}
#endregion
#region Icon Methods
@@ -513,6 +648,14 @@ namespace UVC.UIToolkit
}
}
private void UpdateMaterialIconSize(int? fontSize)
{
if (_iconLabel != null)
{
UTKMaterialIcons.ApplyIconStyle(_iconLabel, fontSize ?? GetDefaultIconSize());
}
}
/// <summary>
/// Material Icon을 비동기로 설정합니다.
/// </summary>
@@ -637,16 +780,23 @@ namespace UVC.UIToolkit
_imageIcon.AddToClassList("utk-button__image-icon");
Insert(0, _imageIcon);
}
var size = iconSize ?? GetDefaultIconSize();
_imageIcon.style.width = size;
_imageIcon.style.height = size;
UpdateImageIconSize(iconSize);
_imageIcon.style.backgroundImage = new StyleBackground(texture);
_imageIcon.style.display = DisplayStyle.Flex;
EnableInClassList("utk-button--has-image-icon", true);
}
private void UpdateImageIconSize(int? iconSize)
{
if (_imageIcon != null)
{
var size = iconSize ?? GetDefaultIconSize();
_imageIcon.style.width = size;
_imageIcon.style.height = size;
}
}
private void ClearImageIcon()
{
if (_imageIcon != null)

View File

@@ -25,13 +25,13 @@ namespace UVC.UIToolkit
/// <code>
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
/// <!-- 기본 체크박스 -->
/// <utk:UTKCheckBox Text="이메일 수신 동의" />
/// <utk:UTKCheckBox text="이메일 수신 동의" />
///
/// <!-- 기본값 체크됨 -->
/// <utk:UTKCheckBox Text="자동 로그인" IsChecked="true" />
/// <utk:UTKCheckBox text="자동 로그인" is-checked="true" />
///
/// <!-- 비활성화 -->
/// <utk:UTKCheckBox Text="필수 동의" IsEnabled="false" IsChecked="true" />
/// <utk:UTKCheckBox text="필수 동의" is-enabled="false" is-checked="true" />
/// </ui:UXML>
/// </code>
/// </example>

View File

@@ -28,7 +28,7 @@ namespace UVC.UIToolkit
/// <utk:UTKToggle label="자동 저장" value="true" />
///
/// <!-- 비활성화 -->
/// <utk:UTKToggle label="프리미엄 기능" IsEnabled="false" />
/// <utk:UTKToggle label="프리미엄 기능" is-enabled="false" />
/// </ui:UXML>
/// </code>
/// </example>

View File

@@ -60,7 +60,7 @@ namespace UVC.UIToolkit
#region Properties
/// <summary>활성화 상태</summary>
[UxmlAttribute]
[UxmlAttribute("is-enabled")]
public bool IsEnabled
{
get => _isEnabled;

View File

@@ -229,6 +229,20 @@ namespace UVC.UIToolkit
/// </summary>
public static bool HasIcon(string iconName) => _pathsByName.ContainsKey(iconName);
/// <summary>
/// 리소스 경로로 아이콘 이름을 조회합니다.
/// </summary>
/// <param name="resourcePath">리소스 경로 (예: Icons/Home)</param>
/// <returns>아이콘 이름, 없으면 빈 문자열</returns>
public static string GetIconName(string resourcePath)
{
foreach (var kvp in _pathsByName)
{
if (kvp.Value == resourcePath) return kvp.Key;
}
return string.Empty;
}
/// <summary>
/// 모든 아이콘 이름 목록을 반환합니다.
/// </summary>

View File

@@ -12499,14 +12499,28 @@ namespace UVC.UIToolkit
};
/// <summary>
/// 아이콘 이름으로 유니코드 문자를 조회합니다.
/// 아이콘 이름(settings) 또는 유니코드(\uE8B8)로 유니코드 문자를 조회합니다. "□" 식의 유니코드 지원 않함
/// </summary>
/// <param name="iconName">아이콘 이름 (예: "home", "settings")</param>
/// <returns>아이콘 문자, 없으면 빈 문자열</returns>
public static string GetIcon(string iconName)
{
// 실제 유니코드 문자가 아니라 이스케이프 문자열인 경우 변환
if (iconName.StartsWith("\\u") && iconName.Length == 6)
{
try
{
var code = Convert.ToInt32(iconName.Substring(2), 16);
iconName = char.ConvertFromUtf32(code);
}
catch
{
Debug.LogWarning($"Failed to convert escape sequence: {iconName}");
}
}
if(IsIconChar(iconName)) return iconName;
return _iconsByName.TryGetValue(iconName, out var icon) ? icon : string.Empty;
return _iconsByName.TryGetValue(iconName.ToLower(), out var icon) ? icon : string.Empty;
}
/// <summary>
@@ -12517,7 +12531,21 @@ namespace UVC.UIToolkit
/// <summary>
/// 유니코드 문자로 아이콘이 존재하는지 확인합니다.
/// </summary>
public static bool IsIconChar(string iconChar) => _iconsByName.Values.Contains(iconChar);
public static bool IsIconChar(string iconChar) => _iconsByName.Values.Any(v => string.Equals(v, iconChar, StringComparison.OrdinalIgnoreCase));
/// <summary>
/// 유니코드 문자로 아이콘 이름을 조회합니다.
/// </summary>
/// <param name="iconChar"></param>
/// <returns></returns>
public static string GetIconNameByChar(string iconChar)
{
foreach (var kvp in _iconsByName)
{
if (string.Equals(kvp.Value, iconChar, StringComparison.OrdinalIgnoreCase)) return kvp.Key;
}
return string.Empty;
}
/// <summary>
/// 모든 아이콘 이름 목록을 반환합니다.

View File

@@ -83,7 +83,7 @@ namespace UVC.UIToolkit
/// index="0" />
///
/// <!-- 비활성화 상태 -->
/// <utk:UTKDropdown label="선택" IsEnabled="false"
/// <utk:UTKDropdown label="선택" is-enabled="false"
/// choices="옵션1,옵션2,옵션3" />
/// </code>
/// </example>

View File

@@ -102,7 +102,7 @@ namespace UVC.UIToolkit
#region Properties
/// <summary>활성화 상태</summary>
[UxmlAttribute]
[UxmlAttribute("is-enabled")]
public bool IsEnabled
{
get => _isEnabled;
@@ -122,7 +122,7 @@ namespace UVC.UIToolkit
}
/// <summary>Center 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("center-label")]
public string CenterLabel
{
get => _centerLabel;
@@ -134,7 +134,7 @@ namespace UVC.UIToolkit
}
/// <summary>Extents 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("extents-label")]
public string ExtentsLabel
{
get => _extentsLabel;
@@ -146,7 +146,7 @@ namespace UVC.UIToolkit
}
/// <summary>X축 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("x-label")]
public string XLabel
{
get => _xLabel;
@@ -158,7 +158,7 @@ namespace UVC.UIToolkit
}
/// <summary>Y축 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("y-label")]
public string YLabel
{
get => _yLabel;
@@ -170,7 +170,7 @@ namespace UVC.UIToolkit
}
/// <summary>Z축 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("z-label")]
public string ZLabel
{
get => _zLabel;

View File

@@ -37,7 +37,7 @@ namespace UVC.UIToolkit
/// <utk:UTKInputField label="이름" />
///
/// <!-- 플레이스홀더 -->
/// <utk:UTKInputField label="이메일" Placeholder="example@email.com" />
/// <utk:UTKInputField label="이메일" placeholder="example@email.com" />
///
/// <!-- 비밀번호 필드 -->
/// <utk:UTKInputField label="비밀번호" is-password-field="true" />
@@ -46,7 +46,7 @@ namespace UVC.UIToolkit
/// <utk:UTKInputField label="설명" multiline="true" />
///
/// <!-- 비활성화 -->
/// <utk:UTKInputField label="읽기전용" IsEnabled="false" value="수정 불가" />
/// <utk:UTKInputField label="읽기전용" is-enabled="false" value="수정 불가" />
/// </ui:UXML>
/// </code>
/// </example>

View File

@@ -49,11 +49,11 @@ namespace UVC.UIToolkit
///
/// <!-- 커스텀 라벨 -->
/// <utk:UTKRectField label="스프라이트 영역"
/// XLabel="Left" YLabel="Top"
/// WLabel="W" HLabel="H" />
/// x-label="Left" y-label="Top"
/// w-label="W" h-label="H" />
///
/// <!-- 비활성화 상태 -->
/// <utk:UTKRectField label="읽기 전용" IsEnabled="false" />
/// <utk:UTKRectField label="읽기 전용" is-enabled="false" />
/// ]]></code>
/// <para><b>실제 활용 예시 (스프라이트 영역 편집):</b></para>
/// <code>
@@ -89,7 +89,7 @@ namespace UVC.UIToolkit
#region Properties
/// <summary>활성화 상태</summary>
[UxmlAttribute]
[UxmlAttribute("is-enabled")]
public bool IsEnabled
{
get => _isEnabled;
@@ -109,7 +109,7 @@ namespace UVC.UIToolkit
}
/// <summary>X 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("x-label")]
public string XLabel
{
get => _xLabel;
@@ -121,7 +121,7 @@ namespace UVC.UIToolkit
}
/// <summary>Y 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("y-label")]
public string YLabel
{
get => _yLabel;
@@ -133,7 +133,7 @@ namespace UVC.UIToolkit
}
/// <summary>W 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("w-label")]
public string WLabel
{
get => _wLabel;
@@ -145,7 +145,7 @@ namespace UVC.UIToolkit
}
/// <summary>H 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("h-label")]
public string HLabel
{
get => _hLabel;

View File

@@ -97,7 +97,7 @@ namespace UVC.UIToolkit
}
/// <summary>활성화 상태</summary>
[UxmlAttribute]
[UxmlAttribute("is-enabled")]
public bool IsEnabled
{
get => _isEnabled;
@@ -110,7 +110,7 @@ namespace UVC.UIToolkit
}
/// <summary>X축 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("x-label")]
public string XLabel
{
get => _xLabel;
@@ -122,7 +122,7 @@ namespace UVC.UIToolkit
}
/// <summary>Y축 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("y-label")]
public string YLabel
{
get => _yLabel;

View File

@@ -54,10 +54,10 @@ namespace UVC.UIToolkit
///
/// <!-- 커스텀 축 라벨 -->
/// <utk:UTKVector3Field label="크기"
/// XLabel="Width" YLabel="Height" ZLabel="Depth" />
/// x-label="Width" y-label="Height" z-label="Depth" />
///
/// <!-- 비활성화 상태 -->
/// <utk:UTKVector3Field label="읽기 전용" IsEnabled="false" />
/// <utk:UTKVector3Field label="읽기 전용" is-enabled="false" />
/// ]]></code>
/// <para><b>실제 활용 예시 (Transform 편집기):</b></para>
/// <code>
@@ -104,7 +104,7 @@ namespace UVC.UIToolkit
}
/// <summary>활성화 상태</summary>
[UxmlAttribute]
[UxmlAttribute("is-enabled")]
public bool IsEnabled
{
get => _isEnabled;
@@ -117,7 +117,7 @@ namespace UVC.UIToolkit
}
/// <summary>X축 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("x-label")]
public string XLabel
{
get => _xLabel;
@@ -129,7 +129,7 @@ namespace UVC.UIToolkit
}
/// <summary>Y축 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("y-label")]
public string YLabel
{
get => _yLabel;
@@ -141,7 +141,7 @@ namespace UVC.UIToolkit
}
/// <summary>Z축 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("z-label")]
public string ZLabel
{
get => _zLabel;

View File

@@ -95,7 +95,7 @@ namespace UVC.UIToolkit
#region Properties
/// <summary>활성화 상태</summary>
[UxmlAttribute]
[UxmlAttribute("is-enabled")]
public bool IsEnabled
{
get => _isEnabled;
@@ -115,7 +115,7 @@ namespace UVC.UIToolkit
}
/// <summary>X축 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("x-label")]
public string XLabel
{
get => _xLabel;
@@ -127,7 +127,7 @@ namespace UVC.UIToolkit
}
/// <summary>Y축 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("y-label")]
public string YLabel
{
get => _yLabel;
@@ -139,7 +139,7 @@ namespace UVC.UIToolkit
}
/// <summary>Z축 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("z-label")]
public string ZLabel
{
get => _zLabel;
@@ -151,7 +151,7 @@ namespace UVC.UIToolkit
}
/// <summary>W축 라벨</summary>
[UxmlAttribute]
[UxmlAttribute("w-label")]
public string WLabel
{
get => _wLabel;

View File

@@ -84,7 +84,7 @@ namespace UVC.UIToolkit
/// var imgLabel = new UTKLabel("닫기", UTKImageIcons.BtnClose16, isImageIcon: true);
///
/// // Material Icon만 사용
/// var iconOnly = new UTKLabel(UTKMaterialIcons.Home);
/// var iconOnly = new UTKLabel(UTKMaterialIcons.Home, 12);
///
/// // Image Icon만 사용
/// var imgOnly = new UTKLabel(UTKImageIcons.IconSetting22, isImageIcon: true);
@@ -100,25 +100,25 @@ namespace UVC.UIToolkit
/// <utk:UTKLabel text="일반 텍스트" />
///
/// <!-- 제목 -->
/// <utk:UTKLabel text="제목" size="H1" isBold="true" />
/// <utk:UTKLabel text="제목" size="H1" is-bold="true" />
///
/// <!-- 보조 텍스트 -->
/// <utk:UTKLabel text="설명" size="Caption" variant="Secondary" />
///
/// <!-- Material Icon과 텍스트 -->
/// <utk:UTKLabel text="설정" materialIcon="settings" />
/// <utk:UTKLabel text="설정" material-icon="settings" />
///
/// <!-- Image Icon과 텍스트 -->
/// <utk:UTKLabel text="닫기" imageIcon="btn_close_16" />
/// <utk:UTKLabel text="닫기" image-icon="btn_close_16" />
///
/// <!-- 아이콘만 (Material) -->
/// <utk:UTKLabel materialIcon="home" iconSize="24" />
/// <utk:UTKLabel material-icon="home" icon-size="24" />
///
/// <!-- 아이콘만 (Image) -->
/// <utk:UTKLabel imageIcon="icon_setting_22" iconSize="22" />
/// <utk:UTKLabel image-icon="icon_setting_22" icon-size="22" />
///
/// <!-- 아이콘 오른쪽 배치 -->
/// <utk:UTKLabel text="다음" materialIcon="arrow_forward" iconPlacement="Right" />
/// <utk:UTKLabel text="다음" material-icon="arrow_forward" icon-placement="right" />
/// </ui:UXML>
/// </code>
/// </example>

View File

@@ -1350,7 +1350,7 @@ namespace UVC.UIToolkit
}
// setting-btn 클릭 이벤트 연결
var settingBtn = element.Q<Button>("setting-btn");
var settingBtn = element.Q<UTKButton>("setting-btn");
if (settingBtn != null)
{
// 검색 결과 그룹인 경우 setting-btn 숨기기
@@ -1365,41 +1365,41 @@ namespace UVC.UIToolkit
settingBtn.SetEnabled(true);
// 기존 이벤트 제거 후 재등록 (메모리 누수 방지)
if (settingBtn.userData is Action oldSettingAction) settingBtn.clicked -= oldSettingAction;
if (settingBtn.userData is Action oldSettingAction) settingBtn.OnClicked -= oldSettingAction;
Action settingClickAction = () =>
{
OnItemIconClicked?.Invoke("setting-btn", item);
};
settingBtn.userData = settingClickAction;
settingBtn.clicked += settingClickAction;
settingBtn.OnClicked += settingClickAction;
}
}
}
else
{
// 일반 항목의 search-btn 클릭 이벤트 연결
var searchBtn = element.Q<Button>("search-btn");
var searchBtn = element.Q<UTKButton>("search-btn");
if (searchBtn != null)
{
// 기존 이벤트 제거 후 재등록 (메모리 누수 방지)
if (searchBtn.userData is Action oldSearchAction) searchBtn.clicked -= oldSearchAction;
if (searchBtn.userData is Action oldSearchAction) searchBtn.OnClicked -= oldSearchAction;
Action searchClickAction = () =>
{
OnItemIconClicked?.Invoke("search-btn", item);
};
searchBtn.userData = searchClickAction;
searchBtn.clicked += searchClickAction;
searchBtn.OnClicked += searchClickAction;
}
// 4. 가시성 아이콘 버튼 설정 (일반 항목만)
var toggleBtn = element.Q<Button>("visibility-btn");
var toggleBtn = element.Q<UTKButton>("visibility-btn");
if (toggleBtn != null)
{
UpdateVisibilityIcon(toggleBtn, item.IsVisible);
// 가시성 버튼 클릭 이벤트 연결
// 주의: bindItem은 스크롤 시 재호출되므로 기존 이벤트 제거 후 재등록
if (toggleBtn.userData is Action oldAction) toggleBtn.clicked -= oldAction;
if (toggleBtn.userData is Action oldAction) toggleBtn.OnClicked -= oldAction;
Action clickAction = () =>
{
// 가시성 상태 토글
@@ -1416,7 +1416,7 @@ namespace UVC.UIToolkit
OnItemVisibilityChanged?.Invoke(item, item.IsVisible);
};
toggleBtn.userData = clickAction;
toggleBtn.clicked += clickAction;
toggleBtn.OnClicked += clickAction;
}
}
}
@@ -1447,17 +1447,15 @@ namespace UVC.UIToolkit
/// </summary>
/// <param name="btn">가시성 토글 버튼</param>
/// <param name="isVisible">현재 가시성 상태</param>
private void UpdateVisibilityIcon(Button btn, bool isVisible)
private void UpdateVisibilityIcon(UTKButton btn, bool isVisible)
{
if (isVisible)
{
btn.RemoveFromClassList("visibility-off");
btn.AddToClassList("visibility-on");
btn.SetMaterialIcon("visibility");
}
else
{
btn.RemoveFromClassList("visibility-on");
btn.AddToClassList("visibility-off");
btn.SetMaterialIcon("visibility_off");
}
}
#endregion

View File

@@ -77,7 +77,7 @@ namespace UVC.UIToolkit
/// <code>
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
/// <!-- Alert는 주로 C# 코드로 동적 생성합니다 -->
/// <utk:UTKAlert Title="알림" Message="메시지" AlertType="Info" />
/// <utk:UTKAlert title="알림" message="메시지" alert-type="Info" />
/// </ui:UXML>
/// </code>
/// </example>
@@ -118,7 +118,7 @@ namespace UVC.UIToolkit
#region Properties
/// <summary>제목</summary>
[UxmlAttribute]
[UxmlAttribute("title")]
public string Title
{
get => _title;
@@ -134,7 +134,7 @@ namespace UVC.UIToolkit
}
/// <summary>메시지</summary>
[UxmlAttribute]
[UxmlAttribute("message")]
public string Message
{
get => _message;
@@ -146,7 +146,7 @@ namespace UVC.UIToolkit
}
/// <summary>알림 유형</summary>
[UxmlAttribute]
[UxmlAttribute("type")]
public AlertType Type
{
get => _alertType;

View File

@@ -156,7 +156,7 @@ namespace UVC.UIToolkit
/// <summary>
/// 알파(투명도) 값을 다룰지 여부 (기본값: true)
/// </summary>
[UxmlAttribute]
[UxmlAttribute("use-alpha")]
public bool UseAlpha
{
get => _useAlpha;

View File

@@ -32,7 +32,7 @@ namespace UVC.UIToolkit
/// <para><b>UXML에서 사용:</b></para>
/// <code>
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
/// <utk:UTKModal Title="설정" Size="Medium" ShowCloseButton="true">
/// <utk:UTKModal title="설정" size="Medium" show-close-button="true">
/// <ui:Label text="모달 내용을 여기에 추가하세요" />
/// </utk:UTKModal>
/// </ui:UXML>
@@ -67,7 +67,7 @@ namespace UVC.UIToolkit
#region Properties
/// <summary>모달 제목</summary>
[UxmlAttribute]
[UxmlAttribute("title")]
public string Title
{
get => _title;
@@ -79,7 +79,7 @@ namespace UVC.UIToolkit
}
/// <summary>닫기 버튼 표시 여부</summary>
[UxmlAttribute]
[UxmlAttribute("show-close-button")]
public bool ShowCloseButton
{
get => _showCloseButton;
@@ -94,7 +94,7 @@ namespace UVC.UIToolkit
}
/// <summary>배경 클릭 시 닫기 여부</summary>
[UxmlAttribute]
[UxmlAttribute("close-on-backdrop-click")]
public bool CloseOnBackdropClick
{
get => _closeOnBackdropClick;
@@ -102,7 +102,7 @@ namespace UVC.UIToolkit
}
/// <summary>모달 크기</summary>
[UxmlAttribute]
[UxmlAttribute("size")]
public ModalSize Size
{
get => _size;

View File

@@ -37,7 +37,7 @@ namespace UVC.UIToolkit
/// <code>
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
/// <!-- Notification은 주로 C# 코드로 동적 생성합니다 -->
/// <utk:UTKNotification Title="알림" Message="메시지" Type="Info" />
/// <utk:UTKNotification title="알림" message="메시지" type="Info" />
/// </ui:UXML>
/// </code>
/// </example>
@@ -74,7 +74,7 @@ namespace UVC.UIToolkit
#region Properties
/// <summary>제목</summary>
[UxmlAttribute]
[UxmlAttribute("title")]
public string Title
{
get => _title;
@@ -86,7 +86,7 @@ namespace UVC.UIToolkit
}
/// <summary>메시지</summary>
[UxmlAttribute]
[UxmlAttribute("message")]
public string Message
{
get => _message;
@@ -98,7 +98,7 @@ namespace UVC.UIToolkit
}
/// <summary>알림 유형</summary>
[UxmlAttribute]
[UxmlAttribute("type")]
public NotificationType Type
{
get => _type;
@@ -110,7 +110,7 @@ namespace UVC.UIToolkit
}
/// <summary>표시 시간 (밀리초, 0이면 수동 닫기)</summary>
[UxmlAttribute]
[UxmlAttribute("duration")]
public int Duration
{
get => _duration;
@@ -118,7 +118,7 @@ namespace UVC.UIToolkit
}
/// <summary>표시 위치</summary>
[UxmlAttribute]
[UxmlAttribute("position")]
public NotificationPosition Position
{
get => _position;

View File

@@ -110,7 +110,7 @@ namespace UVC.UIToolkit
#region Properties
/// <summary>메시지</summary>
[UxmlAttribute]
[UxmlAttribute("message")]
public string Message
{
get => _message;
@@ -122,7 +122,7 @@ namespace UVC.UIToolkit
}
/// <summary>토스트 유형</summary>
[UxmlAttribute]
[UxmlAttribute("type")]
public ToastType Type
{
get => _type;
@@ -134,7 +134,7 @@ namespace UVC.UIToolkit
}
/// <summary>표시 시간 (밀리초)</summary>
[UxmlAttribute]
[UxmlAttribute("duration")]
public int Duration
{
get => _duration;
@@ -142,7 +142,7 @@ namespace UVC.UIToolkit
}
/// <summary>닫기 버튼 표시 여부</summary>
[UxmlAttribute]
[UxmlAttribute("show-close-button")]
public bool ShowCloseButton
{
get => _showCloseButton;