2014 lines
76 KiB
C#
2014 lines
76 KiB
C#
#nullable enable
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Cysharp.Threading.Tasks;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
using UVC.UIToolkit;
|
|
using UVC.UIToolkit.Common;
|
|
using UVC.UIToolkit.Input;
|
|
using UVC.UIToolkit.Modal;
|
|
|
|
/// <summary>
|
|
/// UTK 컴포넌트들의 테마 전환 테스트를 위한 샘플입니다.
|
|
/// 왼쪽에 컨트롤 목록, 오른쪽에 선택된 컨트롤 미리보기를 표시합니다.
|
|
/// </summary>
|
|
public class UTKStyleGuideSample : MonoBehaviour
|
|
{
|
|
[SerializeField]
|
|
public UIDocument? uiDocument;
|
|
|
|
[SerializeField]
|
|
[Tooltip("시작 시 적용할 테마")]
|
|
private UTKTheme initialTheme = UTKTheme.Dark;
|
|
|
|
// USS 클래스명 상수
|
|
private static class UssClasses
|
|
{
|
|
public const string Main = "utk-sample-main";
|
|
public const string Header = "utk-sample-header";
|
|
public const string Title = "utk-sample-title";
|
|
public const string ThemeArea = "utk-sample-theme-area";
|
|
public const string ThemeLabel = "utk-sample-theme-label";
|
|
public const string Content = "utk-sample-content";
|
|
public const string Sidebar = "utk-sample-sidebar";
|
|
public const string SidebarScroll = "utk-sample-sidebar-scroll";
|
|
public const string Preview = "utk-sample-preview";
|
|
public const string PreviewScroll = "utk-sample-preview-scroll";
|
|
public const string PreviewTitle = "utk-sample-preview-title";
|
|
public const string PreviewContent = "utk-sample-preview-content";
|
|
public const string ControlItem = "utk-sample-control-item";
|
|
public const string ControlItemSelected = "utk-sample-control-item--selected";
|
|
public const string Section = "utk-sample-section";
|
|
public const string SectionTitle = "utk-sample-section__title";
|
|
public const string SectionDesc = "utk-sample-section__desc";
|
|
public const string Row = "utk-sample-row";
|
|
}
|
|
|
|
// 카테고리별 컨트롤 정의
|
|
private static readonly Dictionary<string, string[]> ControlCategories = new()
|
|
{
|
|
["Icon"] = new[] { "MaterialSymbolsOutlined", "UTKImageIcons" },
|
|
["Button"] = new[] { "UTKButton", "UTKCheckBox", "UTKToggle", "UTKRadioButton", "UTKToggleButtonGroup" },
|
|
["Input"] = new[] { "UTKInputField", "UTKIntegerField", "UTKLongField", "UTKFloatField", "UTKDoubleField", "UTKVector2Field", "UTKVector3Field", "UTKVector4Field", "UTKRectField", "UTKBoundsField", "UTKNumberStepper" },
|
|
["Slider"] = new[] { "UTKSlider", "UTKMinMaxSlider", "UTKProgressBar" },
|
|
["Dropdown"] = new[] { "UTKDropdown", "UTKEnumDropDown" },
|
|
["Label"] = new[] { "UTKLabel", "UTKHelpBox" },
|
|
["List"] = new[] { "UTKListView", "UTKTreeView", "UTKMultiColumnListView", "UTKMultiColumnTreeView", "UTKFoldout", "UTKScrollView" },
|
|
["Card"] = new[] { "UTKCard", "UTKPanel" },
|
|
["Tab"] = new[] { "UTKTabView" },
|
|
["Modal"] = new[] { "UTKAlert", "UTKToast", "UTKTooltip" },
|
|
["Picker"] = new[] { "UTKColorPicker", "UTKDatePicker" },
|
|
};
|
|
|
|
// UI 요소들
|
|
private VisualElement? _root;
|
|
private VisualElement? _previewContent;
|
|
private Label? _previewTitle;
|
|
private Label? _themeLabel;
|
|
private string _selectedControl = "";
|
|
private VisualElement? _selectedItem;
|
|
|
|
void Start()
|
|
{
|
|
uiDocument ??= GetComponent<UIDocument>();
|
|
_root = uiDocument.rootVisualElement;
|
|
|
|
UTKToast.SetRoot(_root);
|
|
|
|
// 테마 매니저에 루트 등록
|
|
UTKThemeManager.Instance.RegisterRoot(_root);
|
|
|
|
// 샘플 전용 USS 로드
|
|
var sampleStyle = Resources.Load<StyleSheet>("UIToolkit/Sample/UTKStyleGuideSample");
|
|
if (sampleStyle != null)
|
|
{
|
|
_root.styleSheets.Add(sampleStyle);
|
|
}
|
|
|
|
// 초기 테마 설정
|
|
UTKThemeManager.Instance.SetTheme(initialTheme);
|
|
|
|
// 툴팁 매니저 초기화
|
|
UTKTooltipManager.Instance.Initialize(_root);
|
|
|
|
// UI 생성
|
|
CreateUI();
|
|
}
|
|
|
|
private void CreateUI()
|
|
{
|
|
if (_root == null) return;
|
|
|
|
// 메인 컨테이너
|
|
var mainContainer = new VisualElement { name = "main-container" };
|
|
mainContainer.AddToClassList(UssClasses.Main);
|
|
_root.Add(mainContainer);
|
|
|
|
// 헤더 영역
|
|
CreateHeader(mainContainer);
|
|
|
|
// 콘텐츠 영역 (사이드바 + 미리보기)
|
|
var content = new VisualElement { name = "content" };
|
|
content.AddToClassList(UssClasses.Content);
|
|
mainContainer.Add(content);
|
|
|
|
// 사이드바 (왼쪽)
|
|
CreateSidebar(content);
|
|
|
|
// 미리보기 영역 (오른쪽)
|
|
CreatePreviewArea(content);
|
|
|
|
// 첫 번째 컨트롤 선택
|
|
SelectControl("UTKButton");
|
|
}
|
|
|
|
private void CreateHeader(VisualElement parent)
|
|
{
|
|
var header = new VisualElement { name = "header" };
|
|
header.AddToClassList(UssClasses.Header);
|
|
parent.Add(header);
|
|
|
|
// 타이틀
|
|
var title = new Label("UTK Style Guide");
|
|
title.AddToClassList(UssClasses.Title);
|
|
header.Add(title);
|
|
|
|
// 테마 전환 영역
|
|
var themeArea = new VisualElement();
|
|
themeArea.AddToClassList(UssClasses.ThemeArea);
|
|
header.Add(themeArea);
|
|
|
|
// 현재 테마 라벨
|
|
_themeLabel = new Label($"Theme: {initialTheme}");
|
|
_themeLabel.AddToClassList(UssClasses.ThemeLabel);
|
|
themeArea.Add(_themeLabel);
|
|
|
|
// 테마 토글
|
|
var themeToggle = new UTKToggle("Dark Mode");
|
|
themeToggle.IsOn = initialTheme == UTKTheme.Dark;
|
|
themeToggle.OnValueChanged += (isOn) =>
|
|
{
|
|
var theme = isOn ? UTKTheme.Dark : UTKTheme.Light;
|
|
UTKThemeManager.Instance.SetTheme(theme);
|
|
if (_themeLabel != null)
|
|
_themeLabel.text = $"Theme: {theme}";
|
|
};
|
|
themeArea.Add(themeToggle);
|
|
}
|
|
|
|
private void CreateSidebar(VisualElement parent)
|
|
{
|
|
var sidebar = new VisualElement { name = "sidebar" };
|
|
sidebar.AddToClassList(UssClasses.Sidebar);
|
|
parent.Add(sidebar);
|
|
|
|
var sidebarScroll = new ScrollView(ScrollViewMode.Vertical);
|
|
sidebarScroll.AddToClassList(UssClasses.SidebarScroll);
|
|
sidebar.Add(sidebarScroll);
|
|
|
|
// 카테고리별 Foldout 생성
|
|
foreach (var category in ControlCategories)
|
|
{
|
|
var foldout = new UTKFoldout(category.Key, true);
|
|
sidebarScroll.Add(foldout);
|
|
|
|
foreach (var controlName in category.Value)
|
|
{
|
|
var item = new VisualElement { name = $"item-{controlName}" };
|
|
item.AddToClassList(UssClasses.ControlItem);
|
|
|
|
var label = new Label(controlName);
|
|
item.Add(label);
|
|
|
|
// 클릭 이벤트
|
|
var control = controlName; // 캡처용
|
|
item.RegisterCallback<ClickEvent>(_ => SelectControl(control));
|
|
|
|
foldout.Add(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CreatePreviewArea(VisualElement parent)
|
|
{
|
|
var preview = new VisualElement { name = "preview" };
|
|
preview.AddToClassList(UssClasses.Preview);
|
|
parent.Add(preview);
|
|
|
|
// 미리보기 타이틀
|
|
_previewTitle = new Label("Select a control");
|
|
_previewTitle.AddToClassList(UssClasses.PreviewTitle);
|
|
preview.Add(_previewTitle);
|
|
|
|
// 미리보기 스크롤
|
|
var previewScroll = new ScrollView(ScrollViewMode.Vertical);
|
|
previewScroll.AddToClassList(UssClasses.PreviewScroll);
|
|
preview.Add(previewScroll);
|
|
|
|
// 미리보기 컨텐츠
|
|
_previewContent = new VisualElement { name = "preview-content" };
|
|
_previewContent.AddToClassList(UssClasses.PreviewContent);
|
|
previewScroll.Add(_previewContent);
|
|
}
|
|
|
|
private void SelectControl(string controlName)
|
|
{
|
|
if (_root == null || _previewContent == null || _previewTitle == null) return;
|
|
|
|
// 이전 선택 해제
|
|
_selectedItem?.RemoveFromClassList(UssClasses.ControlItemSelected);
|
|
|
|
// 새 선택
|
|
_selectedControl = controlName;
|
|
_selectedItem = _root.Q<VisualElement>($"item-{controlName}");
|
|
_selectedItem?.AddToClassList(UssClasses.ControlItemSelected);
|
|
|
|
// 타이틀 업데이트
|
|
_previewTitle.text = controlName;
|
|
|
|
// 미리보기 컨텐츠 클리어 및 생성
|
|
_previewContent.Clear();
|
|
CreateControlPreview(controlName, _previewContent);
|
|
}
|
|
|
|
private void CreateControlPreview(string controlName, VisualElement container)
|
|
{
|
|
switch (controlName)
|
|
{
|
|
case "UTKButton":
|
|
CreateButtonPreview(container);
|
|
break;
|
|
case "UTKCheckBox":
|
|
CreateCheckBoxPreview(container);
|
|
break;
|
|
case "UTKToggle":
|
|
CreateTogglePreview(container);
|
|
break;
|
|
case "UTKRadioButton":
|
|
CreateRadioButtonPreview(container);
|
|
break;
|
|
case "UTKToggleButtonGroup":
|
|
CreateToggleButtonGroupPreview(container);
|
|
break;
|
|
case "UTKInputField":
|
|
CreateInputFieldPreview(container);
|
|
break;
|
|
case "UTKIntegerField":
|
|
CreateIntegerFieldPreview(container);
|
|
break;
|
|
case "UTKFloatField":
|
|
CreateFloatFieldPreview(container);
|
|
break;
|
|
case "UTKLongField":
|
|
CreateLongFieldPreview(container);
|
|
break;
|
|
case "UTKDoubleField":
|
|
CreateDoubleFieldPreview(container);
|
|
break;
|
|
case "UTKVector2Field":
|
|
CreateVector2FieldPreview(container);
|
|
break;
|
|
case "UTKVector3Field":
|
|
CreateVector3FieldPreview(container);
|
|
break;
|
|
case "UTKVector4Field":
|
|
CreateVector4FieldPreview(container);
|
|
break;
|
|
case "UTKRectField":
|
|
CreateRectFieldPreview(container);
|
|
break;
|
|
case "UTKBoundsField":
|
|
CreateBoundsFieldPreview(container);
|
|
break;
|
|
case "UTKNumberStepper":
|
|
CreateNumberStepperPreview(container);
|
|
break;
|
|
case "UTKSlider":
|
|
CreateSliderPreview(container);
|
|
break;
|
|
case "UTKMinMaxSlider":
|
|
CreateMinMaxSliderPreview(container);
|
|
break;
|
|
case "UTKProgressBar":
|
|
CreateProgressBarPreview(container);
|
|
break;
|
|
case "UTKDropdown":
|
|
CreateDropdownPreview(container);
|
|
break;
|
|
case "UTKEnumDropDown":
|
|
CreateEnumDropDownPreview(container);
|
|
break;
|
|
case "UTKLabel":
|
|
CreateLabelPreview(container);
|
|
break;
|
|
case "UTKHelpBox":
|
|
CreateHelpBoxPreview(container);
|
|
break;
|
|
case "UTKListView":
|
|
CreateListViewPreview(container);
|
|
break;
|
|
case "UTKTreeView":
|
|
CreateTreeViewPreview(container);
|
|
break;
|
|
case "UTKMultiColumnListView":
|
|
CreateMultiColumnListViewPreview(container);
|
|
break;
|
|
case "UTKMultiColumnTreeView":
|
|
CreateMultiColumnTreeViewPreview(container);
|
|
break;
|
|
case "UTKFoldout":
|
|
CreateFoldoutPreview(container);
|
|
break;
|
|
case "UTKScrollView":
|
|
CreateScrollViewPreview(container);
|
|
break;
|
|
case "UTKCard":
|
|
CreateCardPreview(container);
|
|
break;
|
|
case "UTKPanel":
|
|
CreatePanelPreview(container);
|
|
break;
|
|
case "UTKTabView":
|
|
CreateTabViewPreview(container);
|
|
break;
|
|
case "UTKAlert":
|
|
CreateAlertPreview(container);
|
|
break;
|
|
case "UTKToast":
|
|
CreateToastPreview(container);
|
|
break;
|
|
case "UTKTooltip":
|
|
CreateTooltipPreview(container);
|
|
break;
|
|
case "UTKColorPicker":
|
|
CreateColorPickerPreview(container);
|
|
break;
|
|
case "UTKDatePicker":
|
|
CreateDatePickerPreview(container);
|
|
break;
|
|
case "MaterialSymbolsOutlined":
|
|
CreateIconPreview(container);
|
|
break;
|
|
case "UTKImageIcons":
|
|
CreateImageIconPreview(container);
|
|
break;
|
|
default:
|
|
container.Add(new Label($"Preview for {controlName} not implemented"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
#region Button Previews
|
|
|
|
private void CreateButtonPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "다양한 스타일의 버튼 컴포넌트");
|
|
|
|
// Primary / Normal / Danger
|
|
var row1 = CreateRow(container, "Filled Buttons");
|
|
row1.Add(new UTKButton("Primary", "", UTKButton.ButtonVariant.Primary));
|
|
row1.Add(new UTKButton("Normal", "", UTKButton.ButtonVariant.Normal));
|
|
row1.Add(new UTKButton("Danger", "", UTKButton.ButtonVariant.Danger));
|
|
|
|
// Outline
|
|
var row2 = CreateRow(container, "Outline Buttons");
|
|
row2.Add(new UTKButton("Outline Primary", "", UTKButton.ButtonVariant.OutlinePrimary));
|
|
row2.Add(new UTKButton("Outline Normal", "", UTKButton.ButtonVariant.OutlineNormal));
|
|
row2.Add(new UTKButton("Outline Danger", "", UTKButton.ButtonVariant.OutlineDanger));
|
|
|
|
// Icon Only
|
|
var row3 = CreateRow(container, "Icon Only");
|
|
row3.Add(new UTKButton("", UTKMaterialIcons.PlusOne, UTKButton.ButtonVariant.Primary) { IconOnly = true });
|
|
row3.Add(new UTKButton("", UTKMaterialIcons.Edit, UTKButton.ButtonVariant.Normal) { IconOnly = true });
|
|
row3.Add(new UTKButton("", UTKMaterialIcons.Close, UTKButton.ButtonVariant.Danger) { IconOnly = true });
|
|
row3.Add(new UTKButton("", UTKMaterialIcons.Settings, UTKButton.ButtonVariant.OutlinePrimary) { IconOnly = true });
|
|
row3.Add(new UTKButton("", UTKMaterialIcons.Cancel, UTKButton.ButtonVariant.Normal) { IconOnly = true });
|
|
// Ghost
|
|
var row4 = CreateRow(container, "Ghost");
|
|
row4.Add(new UTKButton("Ghost", "", UTKButton.ButtonVariant.Ghost));
|
|
row4.Add(new UTKButton("", UTKMaterialIcons.Settings, UTKButton.ButtonVariant.Ghost) { IconOnly = true });
|
|
// Text (배경/외곽선 없이 텍스트/아이콘만)
|
|
var row5 = CreateRow(container, "Text (Label/Icon Only)");
|
|
row5.Add(new UTKButton("Text Only", "", UTKButton.ButtonVariant.Text));
|
|
row5.Add(new UTKButton("With Icon", UTKMaterialIcons.FlashOn, UTKButton.ButtonVariant.Text));
|
|
row5.Add(new UTKButton("Link Style", "", UTKButton.ButtonVariant.Text));
|
|
|
|
// Text Icon Only (원형 아이콘 버튼 - UTKColorPicker 닫기 버튼 스타일)
|
|
var row6 = CreateRow(container, "Text Icon Only (Circle)");
|
|
row6.Add(new UTKButton("", UTKMaterialIcons.Close, UTKButton.ButtonVariant.Text, 12) { IconOnly = true });
|
|
row6.Add(new UTKButton("", UTKMaterialIcons.Check, UTKButton.ButtonVariant.Text, 12) { IconOnly = true });
|
|
row6.Add(new UTKButton("", UTKMaterialIcons.Settings, UTKButton.ButtonVariant.Text, 12) { IconOnly = true });
|
|
row6.Add(new UTKButton("", UTKMaterialIcons.Edit, UTKButton.ButtonVariant.Text, 12) { IconOnly = true });
|
|
row6.Add(new UTKButton("", UTKMaterialIcons.Search, UTKButton.ButtonVariant.Text, 12) { IconOnly = true });
|
|
// Disabled
|
|
var row7 = CreateRow(container, "Disabled");
|
|
row7.Add(new UTKButton("Disabled", "", UTKButton.ButtonVariant.Primary) { IsEnabled = false });
|
|
row7.Add(new UTKButton("Disabled", "", UTKButton.ButtonVariant.Normal) { IsEnabled = false });
|
|
row7.Add(new UTKButton("Disabled", "", UTKButton.ButtonVariant.Text) { IsEnabled = false });
|
|
}
|
|
|
|
private void CreateCheckBoxPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "체크박스 컴포넌트");
|
|
|
|
var row = CreateRow(container, "States");
|
|
row.Add(new UTKCheckBox("Unchecked"));
|
|
row.Add(new UTKCheckBox("Checked") { IsChecked = true });
|
|
row.Add(new UTKCheckBox("Indeterminate") { IsIndeterminate = true });
|
|
row.Add(new UTKCheckBox("Disabled") { IsEnabled = false });
|
|
}
|
|
|
|
private void CreateTogglePreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "토글 스위치 컴포넌트");
|
|
|
|
var row = CreateRow(container, "States");
|
|
row.Add(new UTKToggle("Off"));
|
|
row.Add(new UTKToggle("On") { IsOn = true });
|
|
row.Add(new UTKToggle("Disabled Off") { IsEnabled = false });
|
|
row.Add(new UTKToggle("Disabled On") { IsOn = true, IsEnabled = false });
|
|
}
|
|
|
|
private void CreateRadioButtonPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "라디오 버튼 컴포넌트");
|
|
|
|
var row = CreateRow(container, "Options");
|
|
row.Add(new UTKRadioButton("Option A") { IsChecked = true });
|
|
row.Add(new UTKRadioButton("Option B"));
|
|
row.Add(new UTKRadioButton("Option C"));
|
|
row.Add(new UTKRadioButton("Disabled") { IsEnabled = false });
|
|
}
|
|
|
|
private void CreateToggleButtonGroupPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "토글 버튼 그룹 컴포넌트");
|
|
|
|
var row = CreateRow(container, "Single Select");
|
|
var group1 = new UTKToggleButtonGroup();
|
|
group1.AddButton("Option 1");
|
|
group1.AddButton("Option 2");
|
|
group1.AddButton("Option 3");
|
|
row.Add(group1);
|
|
|
|
var row2 = CreateRow(container, "Multi Select");
|
|
var group2 = new UTKToggleButtonGroup { isMultipleSelection = true };
|
|
group2.AddButton("A");
|
|
group2.AddButton("B");
|
|
group2.AddButton("C");
|
|
group2.AddButton("D");
|
|
row2.Add(group2);
|
|
|
|
var row3 = CreateRow(container, "Disabled");
|
|
var group3 = new UTKToggleButtonGroup { IsEnabled = false };
|
|
group3.AddButton("Option 1");
|
|
group3.AddButton("Option 2");
|
|
group3.AddButton("Option 3");
|
|
row3.Add(group3);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Input Previews
|
|
|
|
private void CreateInputFieldPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "텍스트 입력 필드");
|
|
|
|
var row1 = CreateRow(container, "With Label");
|
|
var input1 = new UTKInputField("Username", "Enter your name...");
|
|
input1.style.width = 250;
|
|
row1.Add(input1);
|
|
|
|
var row2 = CreateRow(container, "No Label");
|
|
var input2 = new UTKInputField("", "Search...");
|
|
input2.style.width = 200;
|
|
row2.Add(input2);
|
|
|
|
var row3 = CreateRow(container, "Disabled");
|
|
var input3 = new UTKInputField("Disabled", "Cannot edit...");
|
|
input3.style.width = 250;
|
|
input3.IsEnabled = false;
|
|
row3.Add(input3);
|
|
|
|
var row4 = CreateRow(container, "No Label Disabled");
|
|
var input4 = new UTKInputField("", "Cannot edit...");
|
|
input4.style.width = 200;
|
|
input4.IsEnabled = false;
|
|
row4.Add(input4);
|
|
}
|
|
|
|
private void CreateIntegerFieldPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "정수 입력 필드");
|
|
|
|
var row1 = CreateRow(container, "Normal");
|
|
var field1 = new UTKIntegerField("Count");
|
|
field1.Value = 42;
|
|
field1.style.width = 200;
|
|
row1.Add(field1);
|
|
|
|
var row2 = CreateRow(container, "Disabled");
|
|
var field2 = new UTKIntegerField("Disabled") { IsEnabled = false };
|
|
field2.Value = 100;
|
|
field2.style.width = 200;
|
|
row2.Add(field2);
|
|
}
|
|
|
|
private void CreateFloatFieldPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "실수 입력 필드");
|
|
|
|
var row1 = CreateRow(container, "Normal");
|
|
var field1 = new UTKFloatField("Value");
|
|
field1.Value = 3.14f;
|
|
field1.style.width = 200;
|
|
row1.Add(field1);
|
|
|
|
var row2 = CreateRow(container, "Disabled");
|
|
var field2 = new UTKFloatField("Disabled") { IsEnabled = false };
|
|
field2.Value = 2.718f;
|
|
field2.style.width = 200;
|
|
row2.Add(field2);
|
|
}
|
|
|
|
private void CreateLongFieldPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "Long 정수 입력 필드");
|
|
|
|
var row1 = CreateRow(container, "Normal");
|
|
var field1 = new UTKLongField("Value");
|
|
field1.Value = 1234567890L;
|
|
field1.style.width = 200;
|
|
row1.Add(field1);
|
|
|
|
var row2 = CreateRow(container, "Disabled");
|
|
var field2 = new UTKLongField("Disabled") { IsEnabled = false };
|
|
field2.Value = 9876543210L;
|
|
field2.style.width = 200;
|
|
row2.Add(field2);
|
|
}
|
|
|
|
private void CreateDoubleFieldPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "Double 실수 입력 필드");
|
|
|
|
var row1 = CreateRow(container, "Normal");
|
|
var field1 = new UTKDoubleField("Value");
|
|
field1.Value = 3.141592653589793;
|
|
field1.style.width = 200;
|
|
row1.Add(field1);
|
|
|
|
var row2 = CreateRow(container, "Disabled");
|
|
var field2 = new UTKDoubleField("Disabled") { IsEnabled = false };
|
|
field2.Value = 2.718281828459045;
|
|
field2.style.width = 200;
|
|
row2.Add(field2);
|
|
}
|
|
|
|
private void CreateVector2FieldPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "2D 벡터 입력 필드");
|
|
|
|
var row = CreateRow(container, "Position");
|
|
var field = new UTKVector2Field("Position");
|
|
field.Value = new Vector2(100, 200);
|
|
field.style.width = 250;
|
|
row.Add(field);
|
|
}
|
|
|
|
private void CreateVector3FieldPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "3D 벡터 입력 필드");
|
|
|
|
var row = CreateRow(container, "Position");
|
|
var field = new UTKVector3Field("Position");
|
|
field.Value = new Vector3(10, 20, 30);
|
|
field.style.width = 300;
|
|
row.Add(field);
|
|
}
|
|
|
|
private void CreateVector4FieldPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "4D 벡터 입력 필드");
|
|
|
|
var row = CreateRow(container, "Value");
|
|
var field = new UTKVector4Field("Color");
|
|
field.Value = new Vector4(1, 0.5f, 0.25f, 1);
|
|
field.style.width = 350;
|
|
row.Add(field);
|
|
}
|
|
|
|
private void CreateRectFieldPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "Rect 입력 필드 (x, y, width, height)");
|
|
|
|
var row = CreateRow(container, "Bounds");
|
|
var field = new UTKRectField("Area");
|
|
field.Value = new Rect(10, 20, 100, 50);
|
|
field.style.width = 300;
|
|
row.Add(field);
|
|
}
|
|
|
|
private void CreateBoundsFieldPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "Bounds 입력 필드 (center, extents)");
|
|
|
|
var row = CreateRow(container, "Collision");
|
|
var field = new UTKBoundsField("Bounds");
|
|
field.Value = new Bounds(new Vector3(0, 1, 0), new Vector3(2, 2, 2));
|
|
field.style.width = 350;
|
|
row.Add(field);
|
|
}
|
|
|
|
private void CreateNumberStepperPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "숫자 스테퍼 컴포넌트 (증감 버튼 포함)");
|
|
|
|
var row1 = CreateRow(container, "Step 1");
|
|
var stepper1 = new UTKNumberStepper(0, 100, 50, 1);
|
|
stepper1.style.width = 150;
|
|
row1.Add(stepper1);
|
|
|
|
var row2 = CreateRow(container, "Step 5");
|
|
var stepper2 = new UTKNumberStepper(0, 100, 25, 5);
|
|
stepper2.style.width = 150;
|
|
row2.Add(stepper2);
|
|
|
|
var row3 = CreateRow(container, "Wrap Around");
|
|
var stepper3 = new UTKNumberStepper(0, 100, 0, 10) { WrapAround = true };
|
|
stepper3.style.width = 150;
|
|
row3.Add(stepper3);
|
|
|
|
var row4 = CreateRow(container, "Disabled");
|
|
var stepper4 = new UTKNumberStepper(0, 100, 30, 1);
|
|
stepper4.style.width = 150;
|
|
stepper4.SetEnabled(false);
|
|
row4.Add(stepper4);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Slider Previews
|
|
|
|
private void CreateSliderPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "슬라이더 컴포넌트");
|
|
|
|
var row1 = CreateRow(container, "Normal");
|
|
var slider1 = new UTKSlider("Volume", 0f, 100f, 50f);
|
|
slider1.style.width = 250;
|
|
row1.Add(slider1);
|
|
|
|
var row2 = CreateRow(container, "Disabled");
|
|
var slider2 = new UTKSlider("Disabled", 0f, 100f, 30f) { IsEnabled = false };
|
|
slider2.style.width = 250;
|
|
row2.Add(slider2);
|
|
}
|
|
|
|
private void CreateMinMaxSliderPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "최소/최대 범위 슬라이더");
|
|
|
|
var row = CreateRow(container, "Range");
|
|
var slider = new UTKMinMaxSlider("Range", 0f, 100f, 25f, 75f);
|
|
slider.style.width = 250;
|
|
row.Add(slider);
|
|
}
|
|
|
|
private void CreateProgressBarPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "프로그레스 바 컴포넌트");
|
|
|
|
var row1 = CreateRow(container, "25%");
|
|
var progress1 = new UTKProgressBar();
|
|
progress1.Value = 25f;
|
|
progress1.style.width = 250;
|
|
row1.Add(progress1);
|
|
|
|
var row2 = CreateRow(container, "50%");
|
|
var progress2 = new UTKProgressBar();
|
|
progress2.Value = 50f;
|
|
progress2.style.width = 250;
|
|
row2.Add(progress2);
|
|
|
|
var row3 = CreateRow(container, "75%");
|
|
var progress3 = new UTKProgressBar();
|
|
progress3.Value = 75f;
|
|
progress3.style.width = 250;
|
|
row3.Add(progress3);
|
|
|
|
var row4 = CreateRow(container, "100%");
|
|
var progress4 = new UTKProgressBar();
|
|
progress4.Value = 100f;
|
|
progress4.style.width = 250;
|
|
row4.Add(progress4);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Dropdown Previews
|
|
|
|
private void CreateDropdownPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "드롭다운 선택 컴포넌트");
|
|
|
|
var row1 = CreateRow(container, "Normal");
|
|
var dropdown1 = new UTKDropdown("Select Option");
|
|
dropdown1.SetOptions(new List<string> { "Option 1", "Option 2", "Option 3", "Option 4" });
|
|
dropdown1.SelectedIndex = 0;
|
|
row1.Add(dropdown1);
|
|
|
|
var row2 = CreateRow(container, "Disabled");
|
|
var dropdown2 = new UTKDropdown("Disabled");
|
|
dropdown2.SetOptions(new List<string> { "Option 1", "Option 2" });
|
|
dropdown2.SelectedIndex = 0;
|
|
dropdown2.IsEnabled = false;
|
|
row2.Add(dropdown2);
|
|
}
|
|
|
|
private enum SampleEnum { Option1, Option2, Option3 }
|
|
|
|
private void CreateEnumDropDownPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "Enum 선택 드롭다운");
|
|
|
|
var row = CreateRow(container, "Enum");
|
|
var field = new UTKEnumDropDown("Choice", SampleEnum.Option1);
|
|
row.Add(field);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Label Previews
|
|
|
|
private void CreateLabelPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "다양한 크기와 아이콘을 지원하는 라벨 컴포넌트");
|
|
|
|
// 텍스트 크기
|
|
var row1 = CreateRow(container, "Text Sizes");
|
|
row1.style.flexDirection = FlexDirection.Column;
|
|
row1.style.alignItems = Align.FlexStart;
|
|
row1.Add(new UTKLabel("H1 Heading", UTKLabel.LabelSize.H1));
|
|
row1.Add(new UTKLabel("H2 Heading", UTKLabel.LabelSize.H2));
|
|
row1.Add(new UTKLabel("H3 Heading", UTKLabel.LabelSize.H3));
|
|
row1.Add(new UTKLabel("Body1 Text", UTKLabel.LabelSize.Body1));
|
|
row1.Add(new UTKLabel("Body2 Text", UTKLabel.LabelSize.Body2));
|
|
row1.Add(new UTKLabel("Caption Text", UTKLabel.LabelSize.Caption));
|
|
|
|
// Material Icon + 텍스트
|
|
var row2 = CreateRow(container, "Material Icon + Text");
|
|
row2.Add(new UTKLabel("Settings", UTKMaterialIcons.Settings));
|
|
row2.Add(new UTKLabel("Home", UTKMaterialIcons.Home));
|
|
row2.Add(new UTKLabel("Search", UTKMaterialIcons.Search));
|
|
row2.Add(new UTKLabel("Edit", UTKMaterialIcons.Edit));
|
|
|
|
// Material Icon 오른쪽 배치
|
|
var row3 = CreateRow(container, "Icon Right");
|
|
row3.Add(new UTKLabel("Next", UTKMaterialIcons.ArrowForward, UTKLabel.IconPosition.Right));
|
|
row3.Add(new UTKLabel("Download", UTKMaterialIcons.Download, UTKLabel.IconPosition.Right));
|
|
row3.Add(new UTKLabel("External", UTKMaterialIcons.OpenInNew, UTKLabel.IconPosition.Right));
|
|
|
|
// Image Icon + 텍스트
|
|
var row4 = CreateRow(container, "Image Icon + Text");
|
|
row4.Add(new UTKLabel("Close", UTKImageIcons.BtnClose16, isImageIcon: true));
|
|
row4.Add(new UTKLabel("Settings", UTKImageIcons.IconSetting22, isImageIcon: true));
|
|
|
|
// Material Icon만
|
|
var row5 = CreateRow(container, "Material Icon Only");
|
|
row5.Add(new UTKLabel(UTKMaterialIcons.Home, 24));
|
|
row5.Add(new UTKLabel(UTKMaterialIcons.Settings, 24));
|
|
row5.Add(new UTKLabel(UTKMaterialIcons.Search, 24));
|
|
row5.Add(new UTKLabel(UTKMaterialIcons.Edit, 24));
|
|
row5.Add(new UTKLabel(UTKMaterialIcons.Delete, 24));
|
|
|
|
// Image Icon만
|
|
var row6 = CreateRow(container, "Image Icon Only");
|
|
row6.Add(new UTKLabel(UTKImageIcons.BtnClose22, isImageIcon: true, iconSize: 22));
|
|
row6.Add(new UTKLabel(UTKImageIcons.IconSetting22, isImageIcon: true, iconSize: 22));
|
|
|
|
// 메서드로 아이콘 설정
|
|
var row7 = CreateRow(container, "Set Icon via Method");
|
|
var label1 = new UTKLabel("Dynamic Icon", UTKLabel.LabelSize.Body1);
|
|
label1.SetMaterialIcon(UTKMaterialIcons.Star);
|
|
row7.Add(label1);
|
|
|
|
var label2 = new UTKLabel("Image Icon", UTKLabel.LabelSize.Body1);
|
|
label2.SetImageIconByName("icon_setting_22");
|
|
row7.Add(label2);
|
|
|
|
// 텍스트 변형
|
|
var row8 = CreateRow(container, "Variants");
|
|
row8.Add(new UTKLabel("Primary", UTKLabel.LabelSize.Body1) { Variant = UTKLabel.LabelVariant.Primary });
|
|
row8.Add(new UTKLabel("Secondary", UTKLabel.LabelSize.Body1) { Variant = UTKLabel.LabelVariant.Secondary });
|
|
row8.Add(new UTKLabel("Success", UTKLabel.LabelSize.Body1) { Variant = UTKLabel.LabelVariant.Success });
|
|
row8.Add(new UTKLabel("Warning", UTKLabel.LabelSize.Body1) { Variant = UTKLabel.LabelVariant.Warning });
|
|
row8.Add(new UTKLabel("Error", UTKLabel.LabelSize.Body1) { Variant = UTKLabel.LabelVariant.Error });
|
|
row8.Add(new UTKLabel("Disabled", UTKLabel.LabelSize.Body1) { Variant = UTKLabel.LabelVariant.Disabled });
|
|
}
|
|
|
|
private void CreateHelpBoxPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "도움말 박스 컴포넌트");
|
|
|
|
container.Add(new UTKHelpBox("This is an info message.", HelpBoxMessageType.Info));
|
|
container.Add(new UTKHelpBox("This is a warning message.", HelpBoxMessageType.Warning));
|
|
container.Add(new UTKHelpBox("This is an error message.", HelpBoxMessageType.Error));
|
|
container.Add(new UTKHelpBox("This is a plain message.", HelpBoxMessageType.None));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region List Previews
|
|
|
|
private void CreateListViewPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "가상화된 리스트 뷰 컴포넌트");
|
|
|
|
var listView = new UTKListView();
|
|
listView.style.height = 200;
|
|
listView.style.width = 300;
|
|
|
|
var items = new List<string>();
|
|
for (int i = 1; i <= 20; i++)
|
|
items.Add($"Item {i}");
|
|
|
|
listView.makeItem = () => new Label();
|
|
listView.bindItem = (element, index) => ((Label)element).text = items[index];
|
|
listView.itemsSource = items;
|
|
listView.fixedItemHeight = 24;
|
|
|
|
container.Add(listView);
|
|
}
|
|
|
|
private void CreateTreeViewPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "트리 뷰 컴포넌트");
|
|
|
|
var treeView = new UTKTreeView();
|
|
treeView.style.height = 200;
|
|
treeView.style.width = 300;
|
|
|
|
// TreeView 데이터 생성
|
|
var treeItems = new List<TreeViewItemData<string>>
|
|
{
|
|
new TreeViewItemData<string>(1, "Parent 1", new List<TreeViewItemData<string>>
|
|
{
|
|
new TreeViewItemData<string>(2, "Child 1-1"),
|
|
new TreeViewItemData<string>(3, "Child 1-2"),
|
|
}),
|
|
new TreeViewItemData<string>(4, "Parent 2", new List<TreeViewItemData<string>>
|
|
{
|
|
new TreeViewItemData<string>(5, "Child 2-1"),
|
|
new TreeViewItemData<string>(6, "Child 2-2", new List<TreeViewItemData<string>>
|
|
{
|
|
new TreeViewItemData<string>(7, "Grandchild 2-2-1"),
|
|
new TreeViewItemData<string>(8, "Grandchild 2-2-2"),
|
|
}),
|
|
}),
|
|
new TreeViewItemData<string>(9, "Parent 3"),
|
|
new TreeViewItemData<string>(10, "Parent 4", new List<TreeViewItemData<string>>
|
|
{
|
|
new TreeViewItemData<string>(11, "Child 4-1"),
|
|
new TreeViewItemData<string>(12, "Child 4-2"),
|
|
}),
|
|
new TreeViewItemData<string>(13, "Parent 5", new List<TreeViewItemData<string>>
|
|
{
|
|
new TreeViewItemData<string>(14, "Child 5-1"),
|
|
new TreeViewItemData<string>(15, "Child 5-2", new List<TreeViewItemData<string>>
|
|
{
|
|
new TreeViewItemData<string>(16, "Grandchild 5-2-1"),
|
|
new TreeViewItemData<string>(17, "Grandchild 5-2-2"),
|
|
}),
|
|
}),
|
|
new TreeViewItemData<string>(18, "Parent 6"),
|
|
};
|
|
|
|
treeView.SetRootItems(treeItems);
|
|
treeView.Rebuild();
|
|
container.Add(treeView);
|
|
}
|
|
|
|
/// <summary>
|
|
/// MultiColumnListView 샘플 데이터 클래스
|
|
/// </summary>
|
|
private class SampleListItem
|
|
{
|
|
public int Id { get; set; }
|
|
public string Name { get; set; } = "";
|
|
public string Status { get; set; } = "";
|
|
public int Progress { get; set; }
|
|
}
|
|
|
|
private void CreateMultiColumnListViewPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "멀티 컬럼 리스트 뷰 (정렬 가능한 테이블)");
|
|
|
|
var listView = new UTKMultiColumnListView();
|
|
listView.style.height = 200;
|
|
listView.style.width = 450;
|
|
|
|
// 컬럼 정의
|
|
listView.columns.Add(new Column { name = "id", title = "ID", width = 50 });
|
|
listView.columns.Add(new Column { name = "name", title = "Name", width = 150, stretchable = true });
|
|
listView.columns.Add(new Column { name = "status", title = "Status", width = 100 });
|
|
listView.columns.Add(new Column { name = "progress", title = "Progress", width = 80 });
|
|
|
|
// 샘플 데이터
|
|
var items = new List<SampleListItem>
|
|
{
|
|
new() { Id = 1, Name = "Task Alpha", Status = "Active", Progress = 75 },
|
|
new() { Id = 2, Name = "Task Beta", Status = "Pending", Progress = 30 },
|
|
new() { Id = 3, Name = "Task Gamma", Status = "Completed", Progress = 100 },
|
|
new() { Id = 4, Name = "Task Delta", Status = "Active", Progress = 50 },
|
|
new() { Id = 5, Name = "Task Epsilon", Status = "Cancelled", Progress = 0 },
|
|
new() { Id = 6, Name = "Task Zeta", Status = "Active", Progress = 90 },
|
|
new() { Id = 7, Name = "Task Eta", Status = "Pending", Progress = 15 },
|
|
new() { Id = 8, Name = "Task Theta", Status = "Completed", Progress = 100 },
|
|
};
|
|
|
|
listView.itemsSource = items;
|
|
listView.fixedItemHeight = 24;
|
|
|
|
// 셀 생성 및 바인딩
|
|
listView.columns["id"].makeCell = () => new Label();
|
|
listView.columns["id"].bindCell = (e, i) => ((Label)e).text = items[i].Id.ToString();
|
|
|
|
listView.columns["name"].makeCell = () => new Label();
|
|
listView.columns["name"].bindCell = (e, i) => ((Label)e).text = items[i].Name;
|
|
|
|
listView.columns["status"].makeCell = () => new Label();
|
|
listView.columns["status"].bindCell = (e, i) => ((Label)e).text = items[i].Status;
|
|
|
|
listView.columns["progress"].makeCell = () => new Label();
|
|
listView.columns["progress"].bindCell = (e, i) => ((Label)e).text = $"{items[i].Progress}%";
|
|
|
|
container.Add(listView);
|
|
}
|
|
|
|
/// <summary>
|
|
/// MultiColumnTreeView 샘플 데이터 클래스
|
|
/// </summary>
|
|
private class SampleTreeItem
|
|
{
|
|
public int Id { get; set; }
|
|
public string Name { get; set; } = "";
|
|
public string Type { get; set; } = "";
|
|
public string Size { get; set; } = "";
|
|
}
|
|
|
|
private void CreateMultiColumnTreeViewPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "멀티 컬럼 트리 뷰 (계층적 테이블)");
|
|
|
|
var treeView = new UTKMultiColumnTreeView();
|
|
treeView.style.height = 220;
|
|
treeView.style.width = 450;
|
|
|
|
// 컬럼 정의
|
|
treeView.columns.Add(new Column { name = "name", title = "Name", width = 200, stretchable = true });
|
|
treeView.columns.Add(new Column { name = "type", title = "Type", width = 100 });
|
|
treeView.columns.Add(new Column { name = "size", title = "Size", width = 80 });
|
|
|
|
// 샘플 데이터 (계층 구조)
|
|
var rootItems = new List<TreeViewItemData<SampleTreeItem>>
|
|
{
|
|
new(1, new SampleTreeItem { Id = 1, Name = "Documents", Type = "Folder", Size = "2.5 GB" },
|
|
new List<TreeViewItemData<SampleTreeItem>>
|
|
{
|
|
new(11, new SampleTreeItem { Id = 11, Name = "Reports", Type = "Folder", Size = "500 MB" },
|
|
new List<TreeViewItemData<SampleTreeItem>>
|
|
{
|
|
new(111, new SampleTreeItem { Id = 111, Name = "Q1_Report.pdf", Type = "PDF", Size = "2.3 MB" }),
|
|
new(112, new SampleTreeItem { Id = 112, Name = "Q2_Report.pdf", Type = "PDF", Size = "1.8 MB" }),
|
|
}),
|
|
new(12, new SampleTreeItem { Id = 12, Name = "Images", Type = "Folder", Size = "1.2 GB" }),
|
|
}),
|
|
new(2, new SampleTreeItem { Id = 2, Name = "Projects", Type = "Folder", Size = "5.0 GB" },
|
|
new List<TreeViewItemData<SampleTreeItem>>
|
|
{
|
|
new(21, new SampleTreeItem { Id = 21, Name = "ProjectA", Type = "Folder", Size = "2.0 GB" }),
|
|
new(22, new SampleTreeItem { Id = 22, Name = "ProjectB", Type = "Folder", Size = "3.0 GB" }),
|
|
}),
|
|
new(3, new SampleTreeItem { Id = 3, Name = "Config.json", Type = "JSON", Size = "4 KB" }),
|
|
};
|
|
|
|
treeView.SetRootItems(rootItems);
|
|
treeView.fixedItemHeight = 22;
|
|
|
|
// 셀 생성 및 바인딩
|
|
treeView.columns["name"].makeCell = () => new Label();
|
|
treeView.columns["name"].bindCell = (e, i) =>
|
|
{
|
|
var item = treeView.GetItemDataForIndex<SampleTreeItem>(i);
|
|
((Label)e).text = item.Name;
|
|
};
|
|
|
|
treeView.columns["type"].makeCell = () => new Label();
|
|
treeView.columns["type"].bindCell = (e, i) =>
|
|
{
|
|
var item = treeView.GetItemDataForIndex<SampleTreeItem>(i);
|
|
((Label)e).text = item.Type;
|
|
};
|
|
|
|
treeView.columns["size"].makeCell = () => new Label();
|
|
treeView.columns["size"].bindCell = (e, i) =>
|
|
{
|
|
var item = treeView.GetItemDataForIndex<SampleTreeItem>(i);
|
|
((Label)e).text = item.Size;
|
|
};
|
|
|
|
// 기본 확장
|
|
treeView.ExpandAll();
|
|
|
|
container.Add(treeView);
|
|
}
|
|
|
|
private void CreateFoldoutPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "접을 수 있는 섹션 컴포넌트");
|
|
|
|
var foldout1 = new UTKFoldout("Expanded Section", true);
|
|
foldout1.Add(new Label("Content inside the foldout"));
|
|
foldout1.Add(new Label("More content here"));
|
|
container.Add(foldout1);
|
|
|
|
var foldout2 = new UTKFoldout("Collapsed Section", false);
|
|
foldout2.Add(new Label("Hidden content"));
|
|
container.Add(foldout2);
|
|
}
|
|
|
|
private void CreateScrollViewPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "스크롤 뷰 컴포넌트");
|
|
|
|
var row = CreateRow(container, "ScrollViews");
|
|
|
|
// 세로 스크롤
|
|
var verticalScroll = new UTKScrollView();
|
|
verticalScroll.style.height = 150;
|
|
verticalScroll.style.width = 200;
|
|
|
|
for (int i = 1; i <= 15; i++)
|
|
{
|
|
verticalScroll.Add(new Label($"Vertical Item {i}"));
|
|
}
|
|
row.Add(verticalScroll);
|
|
|
|
// 가로 스크롤
|
|
var horizontalScroll = new UTKScrollView();
|
|
horizontalScroll.mode = ScrollViewMode.Horizontal;
|
|
horizontalScroll.style.height = 150;
|
|
horizontalScroll.style.width = 200;
|
|
|
|
var horizontalContent = new VisualElement();
|
|
horizontalContent.style.flexDirection = FlexDirection.Row;
|
|
for (int i = 1; i <= 15; i++)
|
|
{
|
|
var item = new Label($"H-Item {i}");
|
|
item.style.minWidth = 80;
|
|
item.style.marginRight = 8;
|
|
horizontalContent.Add(item);
|
|
}
|
|
horizontalScroll.Add(horizontalContent);
|
|
row.Add(horizontalScroll);
|
|
|
|
// 양방향 스크롤
|
|
var bothScroll = new UTKScrollView();
|
|
bothScroll.mode = ScrollViewMode.VerticalAndHorizontal;
|
|
bothScroll.style.height = 150;
|
|
bothScroll.style.width = 200;
|
|
|
|
for (int i = 1; i <= 10; i++)
|
|
{
|
|
var item = new Label($"This is a very long scrollable item number {i} that requires horizontal scrolling");
|
|
item.style.whiteSpace = WhiteSpace.NoWrap;
|
|
bothScroll.Add(item);
|
|
}
|
|
row.Add(bothScroll);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Card Previews
|
|
|
|
private void CreateCardPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "카드 컴포넌트");
|
|
|
|
var row = CreateRow(container, "Cards");
|
|
|
|
var card1 = new UTKCard("Card Title", "This is the card content.");
|
|
card1.style.width = 200;
|
|
row.Add(card1);
|
|
|
|
var card2 = new UTKCard("Another Card", "Different content here.");
|
|
card2.style.width = 200;
|
|
row.Add(card2);
|
|
}
|
|
|
|
private void CreatePanelPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "패널 컴포넌트");
|
|
|
|
var panel = new UTKPanel("Panel Title");
|
|
panel.style.width = 300;
|
|
panel.Add(new Label("Panel content goes here"));
|
|
panel.Add(new Label("More panel content"));
|
|
container.Add(panel);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Tab Previews
|
|
|
|
private void CreateTabViewPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "탭 뷰 컴포넌트");
|
|
|
|
var tabView = new UTKTabView();
|
|
tabView.style.width = 400;
|
|
tabView.style.height = 200;
|
|
|
|
tabView.AddUTKTab("Tab 1", new Label("Content for Tab 1"));
|
|
tabView.AddUTKTab("Tab 2", new Label("Content for Tab 2"));
|
|
tabView.AddUTKTab("Tab 3", new Label("Content for Tab 3"));
|
|
|
|
container.Add(tabView);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Modal Previews
|
|
|
|
private void CreateAlertPreview(VisualElement container)
|
|
{
|
|
if (_root == null) return;
|
|
|
|
AddDescription(container, "알림 다이얼로그 (async/await 지원)");
|
|
|
|
// Alert Types (Async)
|
|
var row1 = CreateRow(container, "Alert Types (Async)");
|
|
|
|
UTKAlert.SetRoot(_root);
|
|
|
|
var infoBtn = new UTKButton("Info", "", UTKButton.ButtonVariant.Primary);
|
|
infoBtn.OnClicked += () => ShowInfoAlertAsync().Forget();
|
|
row1.Add(infoBtn);
|
|
|
|
var successBtn = new UTKButton("Success", "", UTKButton.ButtonVariant.Normal);
|
|
successBtn.OnClicked += () => ShowSuccessAlertAsync().Forget();
|
|
row1.Add(successBtn);
|
|
|
|
var warnBtn = new UTKButton("Warning", "", UTKButton.ButtonVariant.Normal);
|
|
warnBtn.OnClicked += () => ShowWarningAlertAsync().Forget();
|
|
row1.Add(warnBtn);
|
|
|
|
var errorBtn = new UTKButton("Error", "", UTKButton.ButtonVariant.Danger);
|
|
errorBtn.OnClicked += () => ShowErrorAlertAsync().Forget();
|
|
row1.Add(errorBtn);
|
|
|
|
// Confirm Dialog (Async)
|
|
var row2 = CreateRow(container, "Confirm Dialog (Async)");
|
|
|
|
var confirmBtn = new UTKButton("Confirm", "", UTKButton.ButtonVariant.Normal);
|
|
confirmBtn.OnClicked += () => ShowConfirmAlertAsync().Forget();
|
|
row2.Add(confirmBtn);
|
|
|
|
var confirmCustomBtn = new UTKButton("Custom Labels", "", UTKButton.ButtonVariant.Normal);
|
|
confirmCustomBtn.OnClicked += () => ShowConfirmCustomLabelsAsync().Forget();
|
|
row2.Add(confirmCustomBtn);
|
|
|
|
// Callback Style (Non-Async)
|
|
var row3 = CreateRow(container, "Callback Style");
|
|
|
|
var callbackBtn = new UTKButton("With Callback", "", UTKButton.ButtonVariant.OutlineNormal);
|
|
callbackBtn.OnClicked += () =>
|
|
{
|
|
UTKAlert.ShowInfo(_root, "Callback Style", "This uses callback instead of async.",
|
|
onClose: () => Debug.Log("Alert closed via callback"));
|
|
};
|
|
row3.Add(callbackBtn);
|
|
|
|
var confirmCallbackBtn = new UTKButton("Confirm Callback", "", UTKButton.ButtonVariant.OutlineNormal);
|
|
confirmCallbackBtn.OnClicked += () =>
|
|
{
|
|
UTKAlert.ShowConfirm(_root, "Confirm", "Do you want to proceed?",
|
|
onConfirm: () => Debug.Log("Confirmed via callback!"),
|
|
onCancel: () => Debug.Log("Cancelled via callback!"));
|
|
};
|
|
row3.Add(confirmCallbackBtn);
|
|
}
|
|
|
|
private async UniTaskVoid ShowInfoAlertAsync()
|
|
{
|
|
if (_root == null) return;
|
|
await UTKAlert.ShowInfoAsync("Information", "This is an info message.");
|
|
Debug.Log("Info alert closed");
|
|
}
|
|
|
|
private async UniTaskVoid ShowSuccessAlertAsync()
|
|
{
|
|
if (_root == null) return;
|
|
await UTKAlert.ShowSuccessAsync("Success", "Operation completed successfully!", closeOnBlockerClick: true);
|
|
Debug.Log("Success alert closed");
|
|
}
|
|
|
|
private async UniTaskVoid ShowWarningAlertAsync()
|
|
{
|
|
if (_root == null) return;
|
|
await UTKAlert.ShowWarningAsync("Warning", "This is a warning message.");
|
|
Debug.Log("Warning alert closed");
|
|
}
|
|
|
|
private async UniTaskVoid ShowErrorAlertAsync()
|
|
{
|
|
if (_root == null) return;
|
|
await UTKAlert.ShowErrorAsync("Error", "An error has occurred!");
|
|
Debug.Log("Error alert closed");
|
|
}
|
|
|
|
private async UniTaskVoid ShowConfirmAlertAsync()
|
|
{
|
|
if (_root == null) return;
|
|
bool result = await UTKAlert.ShowConfirmAsync("Confirm", "Are you sure?");
|
|
Debug.Log(result ? "Confirmed!" : "Cancelled!");
|
|
}
|
|
|
|
private async UniTaskVoid ShowConfirmCustomLabelsAsync()
|
|
{
|
|
if (_root == null) return;
|
|
bool result = await UTKAlert.ShowConfirmAsync("Delete Item", "Are you sure you want to delete this item?",
|
|
confirmLabel: "Delete", cancelLabel: "Keep");
|
|
Debug.Log(result ? "Item deleted!" : "Item kept!");
|
|
}
|
|
|
|
private void CreateToastPreview(VisualElement container)
|
|
{
|
|
if (_root == null) return;
|
|
|
|
AddDescription(container, "토스트 알림");
|
|
|
|
var row = CreateRow(container, "Toasts");
|
|
|
|
var infoBtn = new UTKButton("Info Toast", "", UTKButton.ButtonVariant.Primary);
|
|
infoBtn.OnClicked += () => UTKToast.Show("This is an info toast!This is an info toast!This is an info toast!This is an info toast!This is an info toast!");
|
|
row.Add(infoBtn);
|
|
|
|
var successBtn = new UTKButton("Success Toast", "", UTKButton.ButtonVariant.Normal);
|
|
successBtn.OnClicked += () => UTKToast.ShowSuccess("Operation successful!");
|
|
row.Add(successBtn);
|
|
|
|
var warningBtn = new UTKButton("Warning Toast", "", UTKButton.ButtonVariant.Normal);
|
|
warningBtn.OnClicked += () => UTKToast.ShowWarning("Warning: Check your input!");
|
|
row.Add(warningBtn);
|
|
|
|
var errorBtn = new UTKButton("Error Toast", "", UTKButton.ButtonVariant.Danger);
|
|
errorBtn.OnClicked += () => UTKToast.ShowError("An error occurred!");
|
|
row.Add(errorBtn);
|
|
}
|
|
|
|
private void CreateTooltipPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, "툴팁 컴포넌트 (마우스 오버 시 표시)");
|
|
|
|
var row = CreateRow(container, "Hover over buttons");
|
|
|
|
var btn1 = new UTKButton("Short Tooltip", "", UTKButton.ButtonVariant.Normal);
|
|
UTKTooltipManager.Instance.AttachTooltip(btn1, "This is a short tooltip.");
|
|
row.Add(btn1);
|
|
|
|
var btn2 = new UTKButton("Long Tooltip", "", UTKButton.ButtonVariant.Normal);
|
|
UTKTooltipManager.Instance.AttachTooltip(btn2, "This is a longer tooltip message that demonstrates how the tooltip handles multiple lines of text content.");
|
|
row.Add(btn2);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Picker Previews
|
|
|
|
private Color _selectedColor = Color.white;
|
|
private VisualElement? _colorPreviewBox;
|
|
private Label? _colorHexLabel;
|
|
|
|
private void CreateColorPickerPreview(VisualElement container)
|
|
{
|
|
if (_root == null) return;
|
|
|
|
AddDescription(container, "색상 선택 컴포넌트 (버튼 클릭으로 모달 표시)");
|
|
|
|
// 현재 색상 미리보기
|
|
var previewRow = CreateRow(container, "Current Color");
|
|
|
|
_colorPreviewBox = new VisualElement();
|
|
_colorPreviewBox.style.width = 60;
|
|
_colorPreviewBox.style.height = 30;
|
|
_colorPreviewBox.style.backgroundColor = _selectedColor;
|
|
_colorPreviewBox.style.borderTopLeftRadius = 4;
|
|
_colorPreviewBox.style.borderTopRightRadius = 4;
|
|
_colorPreviewBox.style.borderBottomLeftRadius = 4;
|
|
_colorPreviewBox.style.borderBottomRightRadius = 4;
|
|
_colorPreviewBox.style.borderTopWidth = 1;
|
|
_colorPreviewBox.style.borderBottomWidth = 1;
|
|
_colorPreviewBox.style.borderLeftWidth = 1;
|
|
_colorPreviewBox.style.borderRightWidth = 1;
|
|
_colorPreviewBox.style.borderTopColor = new Color(0.4f, 0.4f, 0.4f);
|
|
_colorPreviewBox.style.borderBottomColor = new Color(0.4f, 0.4f, 0.4f);
|
|
_colorPreviewBox.style.borderLeftColor = new Color(0.4f, 0.4f, 0.4f);
|
|
_colorPreviewBox.style.borderRightColor = new Color(0.4f, 0.4f, 0.4f);
|
|
previewRow.Add(_colorPreviewBox);
|
|
|
|
_colorHexLabel = new Label($"#{ColorUtility.ToHtmlStringRGBA(_selectedColor)}");
|
|
_colorHexLabel.style.marginLeft = 10;
|
|
previewRow.Add(_colorHexLabel);
|
|
|
|
// 버튼들
|
|
var row1 = CreateRow(container, "With Alpha");
|
|
var withAlphaBtn = new UTKButton("Open Color Picker (Alpha)", "", UTKButton.ButtonVariant.Primary);
|
|
withAlphaBtn.OnClicked += () => OpenColorPicker(true);
|
|
row1.Add(withAlphaBtn);
|
|
|
|
var row2 = CreateRow(container, "Without Alpha");
|
|
var withoutAlphaBtn = new UTKButton("Open Color Picker (No Alpha)", "", UTKButton.ButtonVariant.Normal);
|
|
withoutAlphaBtn.OnClicked += () => OpenColorPicker(false);
|
|
row2.Add(withoutAlphaBtn);
|
|
|
|
// Async 버튼
|
|
var row3 = CreateRow(container, "Async/Await");
|
|
var asyncBtn = new UTKButton("Open Color Picker (Async)", "", UTKButton.ButtonVariant.Normal);
|
|
asyncBtn.OnClicked += () => OpenColorPickerAsync().Forget();
|
|
row3.Add(asyncBtn);
|
|
}
|
|
|
|
private void OpenColorPicker(bool useAlpha)
|
|
{
|
|
if (_root == null) return;
|
|
|
|
var picker = UTKColorPicker.Show(_root, _selectedColor, "Select Color", useAlpha);
|
|
picker.OnColorChanged += (color) =>
|
|
{
|
|
// 실시간 미리보기 업데이트
|
|
if (_colorPreviewBox != null)
|
|
_colorPreviewBox.style.backgroundColor = color;
|
|
if (_colorHexLabel != null)
|
|
_colorHexLabel.text = useAlpha
|
|
? $"#{ColorUtility.ToHtmlStringRGBA(color)}"
|
|
: $"#{ColorUtility.ToHtmlStringRGB(color)}";
|
|
};
|
|
picker.OnColorSelected += (color) =>
|
|
{
|
|
_selectedColor = color;
|
|
Debug.Log($"Color Selected: #{(useAlpha ? ColorUtility.ToHtmlStringRGBA(color) : ColorUtility.ToHtmlStringRGB(color))}");
|
|
};
|
|
}
|
|
|
|
private async UniTaskVoid OpenColorPickerAsync()
|
|
{
|
|
if (_root == null) return;
|
|
|
|
// ShowAsync를 사용하여 색상 선택 대기
|
|
// OK 클릭 시 선택된 색상 반환, 취소/닫기 시 _selectedColor 반환
|
|
Color result = await UTKColorPicker.ShowAsync(_root, _selectedColor, "Select Color (Async)", useAlpha: true);
|
|
|
|
// 결과 처리
|
|
_selectedColor = result;
|
|
if (_colorPreviewBox != null)
|
|
_colorPreviewBox.style.backgroundColor = result;
|
|
if (_colorHexLabel != null)
|
|
_colorHexLabel.text = $"#{ColorUtility.ToHtmlStringRGBA(result)}";
|
|
|
|
Debug.Log($"[Async] Color Result: #{ColorUtility.ToHtmlStringRGBA(result)}");
|
|
}
|
|
|
|
private DateTime _selectedDate = DateTime.Today;
|
|
private DateTime _rangeStartDate = DateTime.Today;
|
|
private DateTime _rangeEndDate = DateTime.Today.AddDays(7);
|
|
private Label? _dateLabel;
|
|
private Label? _rangeDateLabel;
|
|
|
|
private void CreateDatePickerPreview(VisualElement container)
|
|
{
|
|
if (_root == null) return;
|
|
|
|
AddDescription(container, "날짜 선택 컴포넌트 (버튼 클릭으로 모달 표시)");
|
|
|
|
UTKDatePicker.SetDayNames(new[] { "일", "월", "화", "수", "목", "금", "토" });
|
|
|
|
// 현재 선택된 날짜 표시
|
|
var previewRow = CreateRow(container, "Current Date");
|
|
_dateLabel = new Label($"Selected: {_selectedDate:yyyy-MM-dd}");
|
|
previewRow.Add(_dateLabel);
|
|
|
|
// 날짜만 선택 버튼
|
|
var row1 = CreateRow(container, "Date Only");
|
|
var dateOnlyBtn = new UTKButton("Open Date Picker", "", UTKButton.ButtonVariant.Primary);
|
|
dateOnlyBtn.OnClicked += () => OpenDatePicker(UTKDatePicker.PickerMode.DateOnly);
|
|
row1.Add(dateOnlyBtn);
|
|
|
|
// 날짜 + 시간 선택 버튼
|
|
var row2 = CreateRow(container, "Date & Time");
|
|
var dateTimeBtn = new UTKButton("Open DateTime Picker", "", UTKButton.ButtonVariant.Normal);
|
|
dateTimeBtn.OnClicked += () => OpenDatePicker(UTKDatePicker.PickerMode.DateAndTime);
|
|
row2.Add(dateTimeBtn);
|
|
|
|
// Async 버튼
|
|
var row3 = CreateRow(container, "Async/Await");
|
|
var asyncBtn = new UTKButton("Open Date Picker (Async)", "", UTKButton.ButtonVariant.Normal);
|
|
asyncBtn.OnClicked += () => OpenDatePickerAsync().Forget();
|
|
row3.Add(asyncBtn);
|
|
|
|
// 날짜 범위 표시
|
|
var rangePreviewRow = CreateRow(container, "Date Range");
|
|
_rangeDateLabel = new Label($"Range: {_rangeStartDate:yyyy-MM-dd} ~ {_rangeEndDate:yyyy-MM-dd}");
|
|
rangePreviewRow.Add(_rangeDateLabel);
|
|
|
|
// 날짜 범위 선택 버튼
|
|
var row4 = CreateRow(container, "Date Range");
|
|
var rangeBtn = new UTKButton("Open Range Picker", "", UTKButton.ButtonVariant.Normal);
|
|
rangeBtn.OnClicked += OpenDateRangePicker;
|
|
row4.Add(rangeBtn);
|
|
|
|
// 날짜 범위 Async 버튼
|
|
var row5 = CreateRow(container, "Range Async");
|
|
var rangeAsyncBtn = new UTKButton("Open Range Picker (Async)", "", UTKButton.ButtonVariant.Normal);
|
|
rangeAsyncBtn.OnClicked += () => OpenDateRangePickerAsync().Forget();
|
|
row5.Add(rangeAsyncBtn);
|
|
}
|
|
|
|
private void OpenDatePicker(UTKDatePicker.PickerMode mode)
|
|
{
|
|
if (_root == null) return;
|
|
|
|
string title = mode == UTKDatePicker.PickerMode.DateOnly ? "Select Date" : "Select Date & Time";
|
|
var picker = UTKDatePicker.Show(_root, _selectedDate, mode, title);
|
|
picker.OnDateSelected += (date) =>
|
|
{
|
|
_selectedDate = date;
|
|
if (_dateLabel != null)
|
|
{
|
|
_dateLabel.text = mode == UTKDatePicker.PickerMode.DateOnly
|
|
? $"Selected: {date:yyyy-MM-dd}"
|
|
: $"Selected: {date:yyyy-MM-dd HH:mm}";
|
|
}
|
|
Debug.Log($"Date Selected: {date:yyyy-MM-dd HH:mm}");
|
|
};
|
|
}
|
|
|
|
private async UniTaskVoid OpenDatePickerAsync()
|
|
{
|
|
if (_root == null) return;
|
|
|
|
// ShowAsync를 사용하여 날짜 선택 대기
|
|
// OK 클릭 시 선택된 날짜 반환, 취소/닫기 시 null 반환
|
|
DateTime? result = await UTKDatePicker.ShowAsync(_root, _selectedDate, UTKDatePicker.PickerMode.DateOnly, "Select Date (Async)");
|
|
|
|
if (result.HasValue)
|
|
{
|
|
_selectedDate = result.Value;
|
|
if (_dateLabel != null)
|
|
_dateLabel.text = $"Selected: {result.Value:yyyy-MM-dd}";
|
|
Debug.Log($"[Async] Date Result: {result.Value:yyyy-MM-dd}");
|
|
}
|
|
else
|
|
{
|
|
Debug.Log("[Async] Date selection cancelled");
|
|
}
|
|
}
|
|
|
|
private void OpenDateRangePicker()
|
|
{
|
|
if (_root == null) return;
|
|
|
|
var picker = UTKDatePicker.ShowRange(_root, _rangeStartDate, _rangeEndDate, false, "Select Date Range");
|
|
picker.OnDateRangeSelected += (start, end) =>
|
|
{
|
|
_rangeStartDate = start;
|
|
_rangeEndDate = end;
|
|
if (_rangeDateLabel != null)
|
|
_rangeDateLabel.text = $"Range: {start:yyyy-MM-dd} ~ {end:yyyy-MM-dd}";
|
|
Debug.Log($"Date Range Selected: {start:yyyy-MM-dd} ~ {end:yyyy-MM-dd}");
|
|
};
|
|
}
|
|
|
|
private async UniTaskVoid OpenDateRangePickerAsync()
|
|
{
|
|
if (_root == null) return;
|
|
|
|
// ShowRangeAsync를 사용하여 날짜 범위 선택 대기
|
|
// OK 클릭 시 선택된 범위 반환, 취소/닫기 시 null 반환
|
|
var result = await UTKDatePicker.ShowRangeAsync(_root, _rangeStartDate, _rangeEndDate, false, "Select Date Range (Async)");
|
|
|
|
if (result.HasValue)
|
|
{
|
|
_rangeStartDate = result.Value.Start;
|
|
_rangeEndDate = result.Value.End;
|
|
if (_rangeDateLabel != null)
|
|
_rangeDateLabel.text = $"Range: {result.Value.Start:yyyy-MM-dd} ~ {result.Value.End:yyyy-MM-dd}";
|
|
Debug.Log($"[Async] Range Result: {result.Value.Start:yyyy-MM-dd} ~ {result.Value.End:yyyy-MM-dd}");
|
|
}
|
|
else
|
|
{
|
|
Debug.Log("[Async] Date range selection cancelled");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Icon Previews
|
|
|
|
private List<string>? _iconNameList;
|
|
private List<string>? _filteredIconNameList;
|
|
private ListView? _iconListView;
|
|
private Label? _iconCountLabel;
|
|
|
|
// 그리드 레이아웃 상수
|
|
private const int IconItemWidth = 80;
|
|
private const int IconItemHeight = 80;
|
|
private const int IconItemMargin = 4;
|
|
private const int IconsPerRow = 10; // 한 행에 표시할 아이콘 수
|
|
|
|
private void CreateIconPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, $"Material Symbols Outlined 아이콘 폰트 (UTKMaterialIcons 사용, ListView 가상화 적용)");
|
|
|
|
// UTKMaterialIcons에서 폰트 로드
|
|
var font = UTKMaterialIcons.LoadFont();
|
|
if (font == null)
|
|
{
|
|
container.Add(new Label("Error: UTKMaterialIcons 폰트를 로드할 수 없습니다."));
|
|
return;
|
|
}
|
|
|
|
// UTKMaterialIcons에서 모든 아이콘 이름 가져오기
|
|
_iconNameList = UTKMaterialIcons.GetAllIconNames().ToList();
|
|
_filteredIconNameList = _iconNameList;
|
|
|
|
// 아이콘 개수 표시
|
|
_iconCountLabel = new Label($"총 {UTKMaterialIcons.Count}개의 아이콘 (가상화 적용)");
|
|
_iconCountLabel.style.marginBottom = 10;
|
|
_iconCountLabel.style.color = new Color(0.6f, 0.6f, 0.6f);
|
|
container.Add(_iconCountLabel);
|
|
|
|
// 검색 필드
|
|
var searchRow = CreateRow(container, "Search");
|
|
var searchField = new UTKInputField("", "Search icons...");
|
|
searchField.style.width = 300;
|
|
searchRow.Add(searchField);
|
|
|
|
// 행 데이터 생성 (아이콘 이름을 행 단위로 그룹화)
|
|
var rowData = CreateIconRowData(_filteredIconNameList);
|
|
|
|
// ListView 생성 (가상화 적용)
|
|
_iconListView = new ListView();
|
|
_iconListView.style.flexGrow = 1;
|
|
_iconListView.style.maxHeight = 500;
|
|
_iconListView.fixedItemHeight = IconItemHeight + IconItemMargin;
|
|
_iconListView.itemsSource = rowData;
|
|
_iconListView.makeItem = MakeIconRow;
|
|
_iconListView.bindItem = BindIconRow;
|
|
_iconListView.selectionType = SelectionType.None;
|
|
_iconListView.virtualizationMethod = CollectionVirtualizationMethod.FixedHeight;
|
|
_iconListView.AddToClassList("utk-icon-listview");
|
|
container.Add(_iconListView);
|
|
|
|
// 검색 기능 (Enter 키 또는 포커스 해제 시 검색)
|
|
void PerformSearch(string searchValue)
|
|
{
|
|
if (_iconNameList == null || _iconListView == null || _iconCountLabel == null) return;
|
|
|
|
_filteredIconNameList = string.IsNullOrEmpty(searchValue)
|
|
? _iconNameList
|
|
: _iconNameList.FindAll(name => name.Contains(searchValue, StringComparison.OrdinalIgnoreCase));
|
|
|
|
var newRowData = CreateIconRowData(_filteredIconNameList);
|
|
_iconListView.itemsSource = newRowData;
|
|
_iconListView.Rebuild();
|
|
|
|
// 필터링 결과 개수 업데이트
|
|
_iconCountLabel.text = string.IsNullOrEmpty(searchValue)
|
|
? $"총 {UTKMaterialIcons.Count}개의 아이콘 (가상화 적용)"
|
|
: $"{_filteredIconNameList.Count}개 / {UTKMaterialIcons.Count}개 아이콘 (가상화 적용)";
|
|
}
|
|
|
|
// Enter 키로 검색
|
|
searchField.OnSubmit += PerformSearch;
|
|
|
|
// 포커스 해제 시 검색
|
|
searchField.OnBlurred += () => PerformSearch(searchField.Value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 아이콘 이름 목록을 행 단위로 그룹화합니다.
|
|
/// </summary>
|
|
private List<List<string>> CreateIconRowData(List<string> iconNames)
|
|
{
|
|
var rows = new List<List<string>>();
|
|
for (int i = 0; i < iconNames.Count; i += IconsPerRow)
|
|
{
|
|
var row = new List<string>();
|
|
for (int j = 0; j < IconsPerRow && i + j < iconNames.Count; j++)
|
|
{
|
|
row.Add(iconNames[i + j]);
|
|
}
|
|
rows.Add(row);
|
|
}
|
|
return rows;
|
|
}
|
|
|
|
/// <summary>
|
|
/// ListView 행 아이템을 생성합니다.
|
|
/// </summary>
|
|
private VisualElement MakeIconRow()
|
|
{
|
|
var row = new VisualElement();
|
|
row.style.flexDirection = FlexDirection.Row;
|
|
row.style.height = IconItemHeight;
|
|
|
|
// 행에 아이콘 슬롯 미리 생성
|
|
for (int i = 0; i < IconsPerRow; i++)
|
|
{
|
|
var iconSlot = CreateIconSlot();
|
|
row.Add(iconSlot);
|
|
}
|
|
|
|
return row;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 아이콘 슬롯 (재사용 가능한 컨테이너)을 생성합니다.
|
|
/// </summary>
|
|
private VisualElement CreateIconSlot()
|
|
{
|
|
var item = new VisualElement();
|
|
item.name = "icon-slot";
|
|
item.style.width = IconItemWidth;
|
|
item.style.height = IconItemHeight;
|
|
item.style.marginRight = IconItemMargin;
|
|
item.style.alignItems = Align.Center;
|
|
item.style.justifyContent = Justify.Center;
|
|
item.style.backgroundColor = new Color(0.15f, 0.15f, 0.15f, 0.5f);
|
|
item.style.borderTopLeftRadius = 4;
|
|
item.style.borderTopRightRadius = 4;
|
|
item.style.borderBottomLeftRadius = 4;
|
|
item.style.borderBottomRightRadius = 4;
|
|
|
|
// 호버 효과
|
|
item.RegisterCallback<MouseEnterEvent>(_ =>
|
|
{
|
|
if (item.style.display != DisplayStyle.None)
|
|
item.style.backgroundColor = new Color(0.25f, 0.25f, 0.25f, 0.8f);
|
|
});
|
|
item.RegisterCallback<MouseLeaveEvent>(_ =>
|
|
{
|
|
if (item.style.display != DisplayStyle.None)
|
|
item.style.backgroundColor = new Color(0.15f, 0.15f, 0.15f, 0.5f);
|
|
});
|
|
|
|
// 아이콘 라벨 (UTKMaterialIcons.ApplyIconStyle 사용)
|
|
var iconLabel = new Label();
|
|
iconLabel.name = "icon-label";
|
|
UTKMaterialIcons.ApplyIconStyle(iconLabel, 28);
|
|
iconLabel.style.color = Color.white;
|
|
iconLabel.style.marginBottom = 4;
|
|
item.Add(iconLabel);
|
|
|
|
// 아이콘 이름
|
|
var nameLabel = new Label();
|
|
nameLabel.name = "name-label";
|
|
nameLabel.style.fontSize = 8;
|
|
nameLabel.style.color = new Color(0.7f, 0.7f, 0.7f);
|
|
nameLabel.style.whiteSpace = WhiteSpace.NoWrap;
|
|
nameLabel.style.overflow = Overflow.Hidden;
|
|
nameLabel.style.textOverflow = TextOverflow.Ellipsis;
|
|
nameLabel.style.maxWidth = IconItemWidth - 4;
|
|
nameLabel.style.unityTextAlign = TextAnchor.MiddleCenter;
|
|
item.Add(nameLabel);
|
|
|
|
return item;
|
|
}
|
|
|
|
/// <summary>
|
|
/// ListView 행에 데이터를 바인딩합니다.
|
|
/// </summary>
|
|
private void BindIconRow(VisualElement row, int index)
|
|
{
|
|
if (_iconListView?.itemsSource is not List<List<string>> rowData) return;
|
|
if (index < 0 || index >= rowData.Count) return;
|
|
|
|
var iconNames = rowData[index];
|
|
var slots = row.Query<VisualElement>("icon-slot").ToList();
|
|
|
|
for (int i = 0; i < slots.Count; i++)
|
|
{
|
|
var slot = slots[i];
|
|
if (i < iconNames.Count)
|
|
{
|
|
var iconName = iconNames[i];
|
|
var iconChar = UTKMaterialIcons.GetIcon(iconName);
|
|
|
|
slot.style.display = DisplayStyle.Flex;
|
|
|
|
// 아이콘 라벨 업데이트
|
|
var iconLabel = slot.Q<Label>("icon-label");
|
|
if (iconLabel != null)
|
|
iconLabel.text = iconChar;
|
|
|
|
// 이름 라벨 업데이트
|
|
var nameLabel = slot.Q<Label>("name-label");
|
|
if (nameLabel != null)
|
|
nameLabel.text = iconName;
|
|
|
|
// 툴팁 갱신
|
|
slot.tooltip = iconName;
|
|
|
|
// 클릭 이벤트 재등록 (userData로 아이콘 이름 저장)
|
|
slot.userData = iconName;
|
|
slot.UnregisterCallback<ClickEvent>(OnIconSlotClicked);
|
|
slot.RegisterCallback<ClickEvent>(OnIconSlotClicked);
|
|
}
|
|
else
|
|
{
|
|
// 빈 슬롯 숨기기
|
|
slot.style.display = DisplayStyle.None;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 아이콘 슬롯 클릭 이벤트 핸들러
|
|
/// </summary>
|
|
private void OnIconSlotClicked(ClickEvent evt)
|
|
{
|
|
if (evt.currentTarget is VisualElement slot && slot.userData is string iconName)
|
|
{
|
|
var iconChar = UTKMaterialIcons.GetIcon(iconName);
|
|
GUIUtility.systemCopyBuffer = iconChar;
|
|
UTKToast.Show($"'{iconName}' 아이콘이 클립보드에 복사되었습니다.");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Image Icon Previews
|
|
|
|
private List<string>? _imageIconNameList;
|
|
private List<string>? _filteredImageIconNameList;
|
|
private ListView? _imageIconListView;
|
|
private Label? _imageIconCountLabel;
|
|
|
|
// 이미지 아이콘 그리드 레이아웃 상수
|
|
private const int ImageIconItemWidth = 100;
|
|
private const int ImageIconItemHeight = 100;
|
|
private const int ImageIconItemMargin = 8;
|
|
private const int ImageIconsPerRow = 8;
|
|
|
|
private void CreateImageIconPreview(VisualElement container)
|
|
{
|
|
AddDescription(container, $"이미지 기반 아이콘 (UTKImageIcons 사용, ListView 가상화 적용)");
|
|
|
|
// UTKImageIcons에서 모든 아이콘 이름 가져오기
|
|
_imageIconNameList = UTKImageIcons.GetAllIconNames().ToList();
|
|
_filteredImageIconNameList = _imageIconNameList;
|
|
|
|
// 아이콘 개수 표시
|
|
_imageIconCountLabel = new Label($"총 {UTKImageIcons.Count}개의 이미지 아이콘 (가상화 적용)");
|
|
_imageIconCountLabel.style.marginBottom = 10;
|
|
_imageIconCountLabel.style.color = new Color(0.6f, 0.6f, 0.6f);
|
|
container.Add(_imageIconCountLabel);
|
|
|
|
// 검색 필드
|
|
var searchRow = CreateRow(container, "Search");
|
|
var searchField = new UTKInputField("", "Search image icons...");
|
|
searchField.style.width = 300;
|
|
searchRow.Add(searchField);
|
|
|
|
// 행 데이터 생성 (아이콘 이름을 행 단위로 그룹화)
|
|
var rowData = CreateImageIconRowData(_filteredImageIconNameList);
|
|
|
|
// ListView 생성 (가상화 적용)
|
|
_imageIconListView = new ListView();
|
|
_imageIconListView.style.flexGrow = 1;
|
|
_imageIconListView.style.maxHeight = 500;
|
|
_imageIconListView.fixedItemHeight = ImageIconItemHeight + ImageIconItemMargin;
|
|
_imageIconListView.itemsSource = rowData;
|
|
_imageIconListView.makeItem = MakeImageIconRow;
|
|
_imageIconListView.bindItem = BindImageIconRow;
|
|
_imageIconListView.selectionType = SelectionType.None;
|
|
_imageIconListView.virtualizationMethod = CollectionVirtualizationMethod.FixedHeight;
|
|
_imageIconListView.AddToClassList("utk-image-icon-listview");
|
|
container.Add(_imageIconListView);
|
|
|
|
// 검색 기능
|
|
void PerformSearch(string searchValue)
|
|
{
|
|
if (_imageIconNameList == null || _imageIconListView == null || _imageIconCountLabel == null) return;
|
|
|
|
_filteredImageIconNameList = string.IsNullOrEmpty(searchValue)
|
|
? _imageIconNameList
|
|
: _imageIconNameList.FindAll(name => name.Contains(searchValue, StringComparison.OrdinalIgnoreCase));
|
|
|
|
var newRowData = CreateImageIconRowData(_filteredImageIconNameList);
|
|
_imageIconListView.itemsSource = newRowData;
|
|
_imageIconListView.Rebuild();
|
|
|
|
_imageIconCountLabel.text = string.IsNullOrEmpty(searchValue)
|
|
? $"총 {UTKImageIcons.Count}개의 이미지 아이콘 (가상화 적용)"
|
|
: $"{_filteredImageIconNameList.Count}개 / {UTKImageIcons.Count}개 이미지 아이콘 (가상화 적용)";
|
|
}
|
|
|
|
searchField.OnSubmit += PerformSearch;
|
|
searchField.OnBlurred += () => PerformSearch(searchField.Value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 이미지 아이콘 이름 목록을 행 단위로 그룹화합니다.
|
|
/// </summary>
|
|
private List<List<string>> CreateImageIconRowData(List<string> iconNames)
|
|
{
|
|
var rows = new List<List<string>>();
|
|
for (int i = 0; i < iconNames.Count; i += ImageIconsPerRow)
|
|
{
|
|
var row = new List<string>();
|
|
for (int j = 0; j < ImageIconsPerRow && i + j < iconNames.Count; j++)
|
|
{
|
|
row.Add(iconNames[i + j]);
|
|
}
|
|
rows.Add(row);
|
|
}
|
|
return rows;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 이미지 아이콘 ListView 행 아이템을 생성합니다.
|
|
/// </summary>
|
|
private VisualElement MakeImageIconRow()
|
|
{
|
|
var row = new VisualElement();
|
|
row.style.flexDirection = FlexDirection.Row;
|
|
row.style.height = ImageIconItemHeight;
|
|
|
|
for (int i = 0; i < ImageIconsPerRow; i++)
|
|
{
|
|
var iconSlot = CreateImageIconSlot();
|
|
row.Add(iconSlot);
|
|
}
|
|
|
|
return row;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 이미지 아이콘 슬롯을 생성합니다.
|
|
/// </summary>
|
|
private VisualElement CreateImageIconSlot()
|
|
{
|
|
var item = new VisualElement();
|
|
item.name = "image-icon-slot";
|
|
item.style.width = ImageIconItemWidth;
|
|
item.style.height = ImageIconItemHeight;
|
|
item.style.marginRight = ImageIconItemMargin;
|
|
item.style.alignItems = Align.Center;
|
|
item.style.justifyContent = Justify.Center;
|
|
item.style.backgroundColor = new Color(0.15f, 0.15f, 0.15f, 0.5f);
|
|
item.style.borderTopLeftRadius = 4;
|
|
item.style.borderTopRightRadius = 4;
|
|
item.style.borderBottomLeftRadius = 4;
|
|
item.style.borderBottomRightRadius = 4;
|
|
|
|
// 호버 효과
|
|
item.RegisterCallback<MouseEnterEvent>(_ =>
|
|
{
|
|
if (item.style.display != DisplayStyle.None)
|
|
item.style.backgroundColor = new Color(0.25f, 0.25f, 0.25f, 0.8f);
|
|
});
|
|
item.RegisterCallback<MouseLeaveEvent>(_ =>
|
|
{
|
|
if (item.style.display != DisplayStyle.None)
|
|
item.style.backgroundColor = new Color(0.15f, 0.15f, 0.15f, 0.5f);
|
|
});
|
|
|
|
// 이미지 아이콘
|
|
var iconImage = new VisualElement();
|
|
iconImage.name = "icon-image";
|
|
iconImage.style.width = 32;
|
|
iconImage.style.height = 32;
|
|
iconImage.style.marginBottom = 4;
|
|
item.Add(iconImage);
|
|
|
|
// 아이콘 이름
|
|
var nameLabel = new Label();
|
|
nameLabel.name = "name-label";
|
|
nameLabel.style.fontSize = 8;
|
|
nameLabel.style.color = new Color(0.7f, 0.7f, 0.7f);
|
|
nameLabel.style.whiteSpace = WhiteSpace.NoWrap;
|
|
nameLabel.style.overflow = Overflow.Hidden;
|
|
nameLabel.style.textOverflow = TextOverflow.Ellipsis;
|
|
nameLabel.style.maxWidth = ImageIconItemWidth - 4;
|
|
nameLabel.style.unityTextAlign = TextAnchor.MiddleCenter;
|
|
item.Add(nameLabel);
|
|
|
|
return item;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 이미지 아이콘 ListView 행에 데이터를 바인딩합니다.
|
|
/// </summary>
|
|
private void BindImageIconRow(VisualElement row, int index)
|
|
{
|
|
if (_imageIconListView?.itemsSource is not List<List<string>> rowData) return;
|
|
if (index < 0 || index >= rowData.Count) return;
|
|
|
|
var iconNames = rowData[index];
|
|
var slots = row.Query<VisualElement>("image-icon-slot").ToList();
|
|
|
|
for (int i = 0; i < slots.Count; i++)
|
|
{
|
|
var slot = slots[i];
|
|
if (i < iconNames.Count)
|
|
{
|
|
var iconName = iconNames[i];
|
|
var iconPath = UTKImageIcons.GetPath(iconName);
|
|
|
|
slot.style.display = DisplayStyle.Flex;
|
|
|
|
// 이미지 아이콘 로드 및 표시
|
|
var iconImage = slot.Q<VisualElement>("icon-image");
|
|
if (iconImage != null)
|
|
{
|
|
var texture = UTKImageIcons.LoadTextureByName(iconName);
|
|
if (texture != null)
|
|
{
|
|
iconImage.style.backgroundImage = new StyleBackground(texture);
|
|
}
|
|
else
|
|
{
|
|
iconImage.style.backgroundImage = StyleKeyword.None;
|
|
}
|
|
}
|
|
|
|
// 이름 라벨 업데이트
|
|
var nameLabel = slot.Q<Label>("name-label");
|
|
if (nameLabel != null)
|
|
nameLabel.text = iconName;
|
|
|
|
// 툴팁 갱신
|
|
slot.tooltip = $"{iconName}\n{iconPath}";
|
|
|
|
// 클릭 이벤트 재등록
|
|
slot.userData = iconName;
|
|
slot.UnregisterCallback<ClickEvent>(OnImageIconSlotClicked);
|
|
slot.RegisterCallback<ClickEvent>(OnImageIconSlotClicked);
|
|
}
|
|
else
|
|
{
|
|
slot.style.display = DisplayStyle.None;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 이미지 아이콘 슬롯 클릭 이벤트 핸들러
|
|
/// </summary>
|
|
private void OnImageIconSlotClicked(ClickEvent evt)
|
|
{
|
|
if (evt.currentTarget is VisualElement slot && slot.userData is string iconName)
|
|
{
|
|
var iconCode = $"UTKImageIcons.LoadSpriteByName(\"{iconName}\")";
|
|
GUIUtility.systemCopyBuffer = iconCode;
|
|
UTKToast.Show($"'{iconName}' 코드가 클립보드에 복사되었습니다.\n{iconCode}");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Helper Methods
|
|
|
|
private void AddDescription(VisualElement container, string text)
|
|
{
|
|
var desc = new Label(text);
|
|
desc.AddToClassList(UssClasses.SectionDesc);
|
|
container.Add(desc);
|
|
}
|
|
|
|
private VisualElement CreateRow(VisualElement container, string label)
|
|
{
|
|
var section = new VisualElement();
|
|
section.AddToClassList(UssClasses.Section);
|
|
container.Add(section);
|
|
|
|
var titleLabel = new Label(label);
|
|
titleLabel.AddToClassList(UssClasses.SectionTitle);
|
|
section.Add(titleLabel);
|
|
|
|
var row = new VisualElement();
|
|
row.AddToClassList(UssClasses.Row);
|
|
section.Add(row);
|
|
|
|
return row;
|
|
}
|
|
|
|
#endregion
|
|
}
|