StyleGuide Sample 완료
This commit is contained in:
@@ -124,6 +124,61 @@ namespace UVC.Sample.UIToolkit
|
||||
openPickerAsyncBtn.style.marginBottom = 10;
|
||||
container.Add(openPickerAsyncBtn);
|
||||
|
||||
// Alpha 프리셋 버튼들
|
||||
var alphaPresetLabel = new Label("Alpha Presets:");
|
||||
alphaPresetLabel.style.color = Color.white;
|
||||
alphaPresetLabel.style.marginTop = 10;
|
||||
alphaPresetLabel.style.marginBottom = 5;
|
||||
container.Add(alphaPresetLabel);
|
||||
|
||||
var alphaPresetRow = new VisualElement();
|
||||
alphaPresetRow.style.flexDirection = FlexDirection.Row;
|
||||
alphaPresetRow.style.marginBottom = 10;
|
||||
|
||||
// Alpha 값이 다른 프리셋 버튼들
|
||||
float[] alphaValues = { 1.0f, 0.75f, 0.5f, 0.25f };
|
||||
foreach (var alpha in alphaValues)
|
||||
{
|
||||
var alphaBtn = new Button(() => SetColorWithAlpha(alpha));
|
||||
alphaBtn.style.width = 50;
|
||||
alphaBtn.style.height = 28;
|
||||
alphaBtn.style.marginRight = 5;
|
||||
alphaBtn.style.backgroundColor = new Color(0.3f, 0.3f, 0.3f);
|
||||
alphaBtn.style.borderTopLeftRadius = 4;
|
||||
alphaBtn.style.borderTopRightRadius = 4;
|
||||
alphaBtn.style.borderBottomLeftRadius = 4;
|
||||
alphaBtn.style.borderBottomRightRadius = 4;
|
||||
alphaBtn.text = $"{(int)(alpha * 100)}%";
|
||||
alphaBtn.style.fontSize = 11;
|
||||
alphaPresetRow.Add(alphaBtn);
|
||||
}
|
||||
|
||||
container.Add(alphaPresetRow);
|
||||
|
||||
// Alpha 활성화/비활성화 직접 호출 버튼들
|
||||
var alphaControlLabel = new Label("Alpha Control Examples:");
|
||||
alphaControlLabel.style.color = Color.white;
|
||||
alphaControlLabel.style.marginTop = 5;
|
||||
alphaControlLabel.style.marginBottom = 5;
|
||||
container.Add(alphaControlLabel);
|
||||
|
||||
var alphaControlRow = new VisualElement();
|
||||
alphaControlRow.style.flexDirection = FlexDirection.Row;
|
||||
alphaControlRow.style.marginBottom = 10;
|
||||
|
||||
var withAlphaBtn = new Button(OpenColorPickerWithAlpha) { text = "With Alpha" };
|
||||
withAlphaBtn.style.height = 28;
|
||||
withAlphaBtn.style.flexGrow = 1;
|
||||
withAlphaBtn.style.marginRight = 5;
|
||||
alphaControlRow.Add(withAlphaBtn);
|
||||
|
||||
var withoutAlphaBtn = new Button(OpenColorPickerWithoutAlpha) { text = "Without Alpha" };
|
||||
withoutAlphaBtn.style.height = 28;
|
||||
withoutAlphaBtn.style.flexGrow = 1;
|
||||
alphaControlRow.Add(withoutAlphaBtn);
|
||||
|
||||
container.Add(alphaControlRow);
|
||||
|
||||
// 프리셋 색상 버튼들
|
||||
var presetLabel = new Label("Preset Colors:");
|
||||
presetLabel.style.color = Color.white;
|
||||
@@ -169,6 +224,58 @@ namespace UVC.Sample.UIToolkit
|
||||
_currentPicker.OnColorSelected += OnColorSelected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Alpha 채널 활성화 상태로 컬러 피커 열기
|
||||
/// </summary>
|
||||
private void OpenColorPickerWithAlpha()
|
||||
{
|
||||
if (_root == null || _currentPicker != null) return;
|
||||
|
||||
// useAlpha = true로 명시적 호출
|
||||
_currentPicker = UTKColorPicker.Show(_root, _currentColor, "Select Color (Alpha ON)", useAlpha: true);
|
||||
|
||||
_currentPicker.OnColorChanged += OnColorChanged;
|
||||
_currentPicker.OnColorSelected += OnColorSelected;
|
||||
|
||||
Debug.Log("[Sample] ColorPicker opened with Alpha channel enabled");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Alpha 채널 비활성화 상태로 컬러 피커 열기
|
||||
/// </summary>
|
||||
private void OpenColorPickerWithoutAlpha()
|
||||
{
|
||||
if (_root == null || _currentPicker != null) return;
|
||||
|
||||
// useAlpha = false로 명시적 호출
|
||||
_currentPicker = UTKColorPicker.Show(_root, _currentColor, "Select Color (Alpha OFF)", useAlpha: false);
|
||||
|
||||
_currentPicker.OnColorChanged += OnColorChanged;
|
||||
_currentPicker.OnColorSelected += OnColorSelected;
|
||||
|
||||
Debug.Log("[Sample] ColorPicker opened without Alpha channel");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 현재 색상의 Alpha 값을 변경
|
||||
/// </summary>
|
||||
private void SetColorWithAlpha(float alpha)
|
||||
{
|
||||
_currentColor = new Color(_currentColor.r, _currentColor.g, _currentColor.b, alpha);
|
||||
|
||||
if (_colorPreview != null)
|
||||
{
|
||||
_colorPreview.style.backgroundColor = _currentColor;
|
||||
}
|
||||
|
||||
if (_colorLabel != null)
|
||||
{
|
||||
_colorLabel.text = ColorToHex(_currentColor);
|
||||
}
|
||||
|
||||
Debug.Log($"[Sample] Alpha set to {(int)(alpha * 100)}% - Color: {ColorToHex(_currentColor)}");
|
||||
}
|
||||
|
||||
private async UniTaskVoid OpenColorPickerAsync()
|
||||
{
|
||||
if (_root == null) return;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
@@ -48,6 +49,7 @@ public class UTKStyleGuideSample : MonoBehaviour
|
||||
// 카테고리별 컨트롤 정의
|
||||
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" },
|
||||
@@ -57,7 +59,7 @@ public class UTKStyleGuideSample : MonoBehaviour
|
||||
["Card"] = new[] { "UTKCard", "UTKPanel" },
|
||||
["Tab"] = new[] { "UTKTabView" },
|
||||
["Modal"] = new[] { "UTKAlert", "UTKToast", "UTKTooltip" },
|
||||
["Picker"] = new[] { "UTKColorPicker", "UTKDatePicker" }
|
||||
["Picker"] = new[] { "UTKColorPicker", "UTKDatePicker" },
|
||||
};
|
||||
|
||||
// UI 요소들
|
||||
@@ -73,6 +75,8 @@ public class UTKStyleGuideSample : MonoBehaviour
|
||||
uiDocument ??= GetComponent<UIDocument>();
|
||||
_root = uiDocument.rootVisualElement;
|
||||
|
||||
UTKToast.SetRoot(_root);
|
||||
|
||||
// 테마 매니저에 루트 등록
|
||||
UTKThemeManager.Instance.RegisterRoot(_root);
|
||||
|
||||
@@ -344,6 +348,12 @@ public class UTKStyleGuideSample : MonoBehaviour
|
||||
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;
|
||||
@@ -370,15 +380,33 @@ public class UTKStyleGuideSample : MonoBehaviour
|
||||
|
||||
// Icon Only
|
||||
var row3 = CreateRow(container, "Icon Only");
|
||||
row3.Add(new UTKButton("", "✚", UTKButton.ButtonVariant.Primary) { IconOnly = true });
|
||||
row3.Add(new UTKButton("", "✎", UTKButton.ButtonVariant.Normal) { IconOnly = true });
|
||||
row3.Add(new UTKButton("", "✖", UTKButton.ButtonVariant.Danger) { IconOnly = true });
|
||||
row3.Add(new UTKButton("", "⚙", UTKButton.ButtonVariant.OutlinePrimary) { IconOnly = true });
|
||||
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 row4 = CreateRow(container, "Disabled");
|
||||
row4.Add(new UTKButton("Disabled", "", UTKButton.ButtonVariant.Primary) { IsEnabled = false });
|
||||
row4.Add(new UTKButton("Disabled", "", UTKButton.ButtonVariant.Normal) { IsEnabled = false });
|
||||
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)
|
||||
@@ -718,14 +746,68 @@ public class UTKStyleGuideSample : MonoBehaviour
|
||||
|
||||
private void CreateLabelPreview(VisualElement container)
|
||||
{
|
||||
AddDescription(container, "다양한 크기의 라벨 컴포넌트");
|
||||
AddDescription(container, "다양한 크기와 아이콘을 지원하는 라벨 컴포넌트");
|
||||
|
||||
container.Add(new UTKLabel("H1 Heading", UTKLabel.LabelSize.H1));
|
||||
container.Add(new UTKLabel("H2 Heading", UTKLabel.LabelSize.H2));
|
||||
container.Add(new UTKLabel("H3 Heading", UTKLabel.LabelSize.H3));
|
||||
container.Add(new UTKLabel("Body1 Text", UTKLabel.LabelSize.Body1));
|
||||
container.Add(new UTKLabel("Body2 Text", UTKLabel.LabelSize.Body2));
|
||||
container.Add(new UTKLabel("Caption Text", UTKLabel.LabelSize.Caption));
|
||||
// 텍스트 크기
|
||||
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)
|
||||
@@ -1172,8 +1254,6 @@ public class UTKStyleGuideSample : MonoBehaviour
|
||||
|
||||
var row = CreateRow(container, "Toasts");
|
||||
|
||||
UTKToast.SetRoot(_root);
|
||||
|
||||
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);
|
||||
@@ -1315,6 +1395,8 @@ public class UTKStyleGuideSample : MonoBehaviour
|
||||
|
||||
AddDescription(container, "날짜 선택 컴포넌트 (버튼 클릭으로 모달 표시)");
|
||||
|
||||
UTKDatePicker.SetDayNames(new[] { "일", "월", "화", "수", "목", "금", "토" });
|
||||
|
||||
// 현재 선택된 날짜 표시
|
||||
var previewRow = CreateRow(container, "Current Date");
|
||||
_dateLabel = new Label($"Selected: {_selectedDate:yyyy-MM-dd}");
|
||||
@@ -1435,6 +1517,472 @@ public class UTKStyleGuideSample : MonoBehaviour
|
||||
|
||||
#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)
|
||||
|
||||
Reference in New Issue
Block a user