Files
XRLib/Assets/Sample/UIToolkit/UTKStyleGuideSample.cs
2026-02-19 18:40:37 +09:00

599 lines
22 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;
/// <summary>
/// UTK 컴포넌트들의 테마 전환 테스트를 위한 샘플입니다.
/// 왼쪽에 컨트롤 목록, 오른쪽에 선택된 컨트롤 미리보기를 표시합니다.
/// UXML 파일을 로드하여 각 컴포넌트 샘플을 표시합니다.
/// </summary>
public partial class UTKStyleGuideSample : MonoBehaviour
{
[SerializeField]
public UIDocument? uiDocument;
[SerializeField]
[Tooltip("시작 시 적용할 테마")]
private UTKTheme initialTheme = UTKTheme.Dark;
#region Constants
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";
}
/// <summary>
/// 컨트롤 이름과 UXML 경로 매핑
/// </summary>
private static readonly Dictionary<string, string> ControlUxmlPaths = new()
{
// Icon
["UTKMaterialIcons"] = "UIToolkit/Sample/Icon/UTKMaterialIconsSample",
["UTKImageIcons"] = "UIToolkit/Sample/Icon/UTKImageIconsSample",
["UTKImage"] = "UIToolkit/Sample/Icon/UTKImageSample",
// Button
["UTKButton"] = "UIToolkit/Sample/Button/UTKButtonSample",
["UTKCheckBox"] = "UIToolkit/Sample/Button/UTKCheckBoxSample",
["UTKToggle"] = "UIToolkit/Sample/Button/UTKToggleSample",
["UTKRadioButton"] = "UIToolkit/Sample/Button/UTKRadioButtonSample",
["UTKToggleButtonGroup"] = "UIToolkit/Sample/Button/UTKToggleButtonGroupSample",
// Input
["UTKInputField"] = "UIToolkit/Sample/Input/UTKInputFieldSample",
["UTKIntegerField"] = "UIToolkit/Sample/Input/UTKIntegerFieldSample",
["UTKLongField"] = "UIToolkit/Sample/Input/UTKLongFieldSample",
["UTKFloatField"] = "UIToolkit/Sample/Input/UTKFloatFieldSample",
["UTKDoubleField"] = "UIToolkit/Sample/Input/UTKDoubleFieldSample",
["UTKVector2Field"] = "UIToolkit/Sample/Input/UTKVector2FieldSample",
["UTKVector3Field"] = "UIToolkit/Sample/Input/UTKVector3FieldSample",
["UTKVector4Field"] = "UIToolkit/Sample/Input/UTKVector4FieldSample",
["UTKRectField"] = "UIToolkit/Sample/Input/UTKRectFieldSample",
["UTKBoundsField"] = "UIToolkit/Sample/Input/UTKBoundsFieldSample",
["UTKIntStepper"] = "UIToolkit/Sample/Input/UTKIntStepperSample",
["UTKFloatStepper"] = "UIToolkit/Sample/Input/UTKFloatStepperSample",
// Slider
["UTKSlider"] = "UIToolkit/Sample/Slider/UTKSliderSample",
["UTKSliderInt"] = "UIToolkit/Sample/Slider/UTKSliderIntSample",
["UTKMinMaxSlider"] = "UIToolkit/Sample/Slider/UTKMinMaxSliderSample",
["UTKProgressBar"] = "UIToolkit/Sample/Slider/UTKProgressBarSample",
// Dropdown
["UTKDropdown"] = "UIToolkit/Sample/Dropdown/UTKDropdownSample",
["UTKEnumDropDown"] = "UIToolkit/Sample/Dropdown/UTKEnumDropDownSample",
["UTKMultiSelectDropdown"] = "UIToolkit/Sample/Dropdown/UTKMultiSelectDropdownSample",
// Label
["UTKLabel"] = "UIToolkit/Sample/Label/UTKLabelSample",
["UTKHelpBox"] = "UIToolkit/Sample/Label/UTKHelpBoxSample",
// List
["UTKListView"] = "UIToolkit/Sample/List/UTKListViewSample",
["UTKTreeView"] = "UIToolkit/Sample/List/UTKTreeViewSample",
["UTKMultiColumnListView"] = "UIToolkit/Sample/List/UTKMultiColumnListViewSample",
["UTKMultiColumnTreeView"] = "UIToolkit/Sample/List/UTKMultiColumnTreeViewSample",
["UTKFoldout"] = "UIToolkit/Sample/List/UTKFoldoutSample",
["UTKScrollView"] = "UIToolkit/Sample/List/UTKScrollViewSample",
// Card
["UTKCard"] = "UIToolkit/Sample/Card/UTKCardSample",
["UTKPanel"] = "UIToolkit/Sample/Card/UTKPanelSample",
// Tab
["UTKTabView"] = "UIToolkit/Sample/Tab/UTKTabViewSample",
// Modal
["UTKAlert"] = "UIToolkit/Sample/Modal/UTKAlertSample",
["UTKToast"] = "UIToolkit/Sample/Modal/UTKToastSample",
["UTKTooltip"] = "UIToolkit/Sample/Modal/UTKTooltipSample",
// Picker
["UTKColorPicker"] = "UIToolkit/Sample/Picker/UTKColorPickerSample",
["UTKDatePicker"] = "UIToolkit/Sample/Picker/UTKDatePickerSample",
// Menu
["UTKTopMenu"] = "UIToolkit/Sample/Menu/UTKTopMenuSample",
// ToolBar
["UTKToolBar"] = "UIToolkit/Sample/ToolBar/UTKToolBarSample",
// Window
["UTKAccordionListWindow"] = "UIToolkit/Sample/Window/UTKAccordionListWindowSample",
["UTKComponentListWindow"] = "UIToolkit/Sample/Window/UTKComponentListWindowSample",
["UTKComponentTabListWindow"] = "UIToolkit/Sample/Window/UTKComponentTabListWindowSample",
["UTKImageListWindow"] = "UIToolkit/Sample/Window/UTKImageListWindowSample",
["UTKTreeListWindow"] = "UIToolkit/Sample/Window/UTKTreeListWindowSample",
["UTKPropertyListWindow"] = "UIToolkit/Sample/Window/UTKPropertyListWindowSample",
};
private static readonly Dictionary<string, string[]> ControlCategories = new()
{
["Icon"] = new[] { "UTKMaterialIcons", "UTKImageIcons", "UTKImage" },
["Button"] = new[] { "UTKButton", "UTKCheckBox", "UTKToggle", "UTKRadioButton", "UTKToggleButtonGroup" },
["Input"] = new[] { "UTKInputField", "UTKIntegerField", "UTKLongField", "UTKFloatField", "UTKDoubleField", "UTKVector2Field", "UTKVector3Field", "UTKVector4Field", "UTKRectField", "UTKBoundsField", "UTKIntStepper", "UTKFloatStepper" },
["Slider"] = new[] { "UTKSlider", "UTKSliderInt", "UTKMinMaxSlider", "UTKProgressBar" },
["Dropdown"] = new[] { "UTKDropdown", "UTKEnumDropDown", "UTKMultiSelectDropdown" },
["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" },
["Menu"] = new[] { "UTKTopMenu" },
["ToolBar"] = new[] { "UTKToolBar" },
["Window"] = new[] { "UTKAccordionListWindow", "UTKComponentListWindow", "UTKComponentTabListWindow", "UTKImageListWindow", "UTKTreeListWindow", "UTKPropertyListWindow" },
};
/// <summary>
/// 컴포넌트별 코드 샘플 (C#, UXML, Icon)
/// Initialize 메서드에서 SetCodeSamples를 호출하여 UXML의 UTKCodeBlock에 코드를 설정합니다.
/// </summary>
private static readonly Dictionary<string, (string? CSharp, string? Uxml, string? Icon)> CodeSamples = new()
{
// 코드 샘플들은 각 컴포넌트의 Initialize 메서드에서 직접 정의됩니다.
// 이 Dictionary는 더 이상 사용되지 않으며, 각 Initialize 메서드에서 직접 SetCodeSamples를 호출합니다.
};
#endregion
#region Fields
private VisualElement? _root;
private VisualElement? _previewContent;
private Label? _previewTitle;
private Label? _themeLabel;
private string _selectedControl = "";
private VisualElement? _selectedItem;
// UXML 캐시
private readonly Dictionary<string, VisualTreeAsset> _uxmlCache = new();
// Picker 상태
private Color _selectedColor = Color.white;
private VisualElement? _colorPreviewBox;
private Label? _colorHexLabel;
private DateTime _selectedDate = DateTime.Today;
private DateTime _rangeStartDate = DateTime.Today;
private DateTime _rangeEndDate = DateTime.Today.AddDays(7);
private Label? _dateLabel;
private Label? _rangeDateLabel;
// Icon ListView
private List<string>? _iconNameList;
private List<string>? _filteredIconNameList;
private ListView? _iconListView;
private Label? _iconCountLabel;
private List<string>? _imageIconNameList;
private List<string>? _filteredImageIconNameList;
private ListView? _imageIconListView;
private Label? _imageIconCountLabel;
private UTKCodeBlock? _materialIconCodeBlock;
private UTKCodeBlock? _imageIconCodeBlock;
private const int IconItemWidth = 80;
private const int IconItemHeight = 80;
private const int IconItemMargin = 4;
private const int IconsPerRow = 10;
private const int ImageIconItemWidth = 100;
private const int ImageIconItemHeight = 100;
private const int ImageIconItemMargin = 8;
private const int ImageIconsPerRow = 8;
#endregion
#region Unity Lifecycle
void Start()
{
uiDocument ??= GetComponent<UIDocument>();
_root = uiDocument.rootVisualElement;
UTKToast.SetRoot(_root);
UTKThemeManager.Instance.RegisterRoot(_root);
var sampleStyle = Resources.Load<StyleSheet>("UIToolkit/Sample/UTKStyleGuideSample");
if (sampleStyle != null)
{
_root.styleSheets.Add(sampleStyle);
}
UTKThemeManager.Instance.SetTheme(initialTheme);
UTKTooltipManager.Instance.Initialize(_root);
CreateUI();
}
#endregion
#region UI Creation
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);
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);
}
#endregion
#region Control Selection
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();
LoadControlPreview(controlName, _previewContent);
}
/// <summary>
/// UXML 파일을 로드하고 필요한 초기화를 수행합니다.
/// </summary>
private void LoadControlPreview(string controlName, VisualElement container)
{
if (!ControlUxmlPaths.TryGetValue(controlName, out var uxmlPath))
{
container.Add(new Label($"UXML not found for {controlName}"));
return;
}
// UXML 로드 (캐싱)
if (!_uxmlCache.TryGetValue(uxmlPath, out var uxml))
{
uxml = Resources.Load<VisualTreeAsset>(uxmlPath);
if (uxml != null)
{
_uxmlCache[uxmlPath] = uxml;
}
}
if (uxml == null)
{
container.Add(new Label($"Failed to load UXML: {uxmlPath}"));
return;
}
// UXML 인스턴스화
var instance = uxml.Instantiate();
container.Add(instance);
// 컴포넌트별 초기화
InitializeControl(controlName, instance);
// 코드 샘플 추가
AddCodeSample(controlName, container);
}
/// <summary>
/// 컴포넌트별 코드 샘플을 추가합니다.
/// </summary>
private void AddCodeSample(string controlName, VisualElement container)
{
if (!CodeSamples.TryGetValue(controlName, out var samples))
return;
var codeSampleContainer = UTKCodeBlock.CreateCodeSampleContainer(samples.CSharp, samples.Uxml);
container.Add(codeSampleContainer);
}
/// <summary>
/// UXML에서 로드된 UTKCodeBlock에 코드 샘플을 설정합니다.
/// </summary>
private void SetCodeSamples(VisualElement root, string? csharpCode = null, string? uxmlCode = null, string? iconCode = null)
{
if (csharpCode != null)
{
var codeCSharp = root.Q<UTKCodeBlock>("code-csharp");
if (codeCSharp != null)
{
codeCSharp.Code = csharpCode;
}
}
if (uxmlCode != null)
{
var codeUxml = root.Q<UTKCodeBlock>("code-uxml");
if (codeUxml != null)
{
codeUxml.Code = uxmlCode;
}
}
if (iconCode != null)
{
var codeIcon = root.Q<UTKCodeBlock>("code-icon");
if (codeIcon != null)
{
codeIcon.Code = iconCode;
}
}
}
/// <summary>
/// UXML 로드 후 컴포넌트별 추가 초기화를 수행합니다.
/// </summary>
private void InitializeControl(string controlName, VisualElement root)
{
switch (controlName)
{
// Button
case "UTKButton":
InitializeButtonSample(root);
break;
case "UTKCheckBox":
InitializeCheckBoxSample(root);
break;
case "UTKToggle":
InitializeToggleSample(root);
break;
case "UTKRadioButton":
InitializeRadioButtonSample(root);
break;
case "UTKToggleButtonGroup":
InitializeToggleButtonGroupSample(root);
break;
// Input
case "UTKInputField":
InitializeInputFieldSample(root);
break;
case "UTKIntegerField":
InitializeIntegerFieldSample(root);
break;
case "UTKLongField":
InitializeLongFieldSample(root);
break;
case "UTKFloatField":
InitializeFloatFieldSample(root);
break;
case "UTKDoubleField":
InitializeDoubleFieldSample(root);
break;
case "UTKIntStepper":
InitializeNumberStepperSample(root);
break;
case "UTKFloatStepper":
InitializeFloatStepperSample(root);
break;
case "UTKVector2Field":
InitializeVector2FieldSample(root);
break;
case "UTKVector3Field":
InitializeVector3FieldSample(root);
break;
case "UTKVector4Field":
InitializeVector4FieldSample(root);
break;
case "UTKRectField":
InitializeRectFieldSample(root);
break;
case "UTKBoundsField":
InitializeBoundsFieldSample(root);
break;
// Slider
case "UTKSlider":
InitializeSliderSample(root);
break;
case "UTKSliderInt":
InitializeSliderIntSample(root);
break;
case "UTKMinMaxSlider":
InitializeMinMaxSliderSample(root);
break;
case "UTKProgressBar":
InitializeProgressBarSample(root);
break;
// Dropdown
case "UTKDropdown":
InitializeDropdownSample(root);
break;
case "UTKEnumDropDown":
InitializeEnumDropDownSample(root);
break;
case "UTKMultiSelectDropdown":
InitializeMultiSelectDropdownSample(root);
break;
// Label
case "UTKLabel":
InitializeLabelSample(root);
break;
case "UTKHelpBox":
InitializeHelpBoxSample(root);
break;
// List
case "UTKListView":
InitializeListViewSample(root);
break;
case "UTKTreeView":
InitializeTreeViewSample(root);
break;
case "UTKMultiColumnListView":
InitializeMultiColumnListViewSample(root);
break;
case "UTKMultiColumnTreeView":
InitializeMultiColumnTreeViewSample(root);
break;
case "UTKFoldout":
InitializeFoldoutSample(root);
break;
case "UTKScrollView":
InitializeScrollViewSample(root);
break;
// Card
case "UTKCard":
InitializeCardSample(root);
break;
case "UTKPanel":
InitializePanelSample(root);
break;
// Tab
case "UTKTabView":
InitializeTabViewSample(root);
break;
// Modal
case "UTKAlert":
InitializeAlertSample(root);
break;
case "UTKToast":
InitializeToastSample(root);
break;
case "UTKTooltip":
InitializeTooltipSample(root);
break;
// Picker
case "UTKColorPicker":
InitializeColorPickerSample(root);
break;
case "UTKDatePicker":
InitializeDatePickerSample(root);
break;
// Icon
case "UTKMaterialIcons":
InitializeUTKMaterialIconsSample(root);
break;
case "UTKImageIcons":
InitializeImageIconsSample(root);
break;
case "UTKImage":
InitializeUTKImageSample(root);
break;
// Menu
case "UTKTopMenu":
InitializeTopMenuSample(root);
break;
// ToolBar
case "UTKToolBar":
InitializeToolBarSample(root);
break;
// Window
case "UTKAccordionListWindow":
InitializeAccordionListWindowSample(root);
break;
case "UTKComponentListWindow":
InitializeComponentListWindowSample(root);
break;
case "UTKComponentTabListWindow":
InitializeComponentTabListWindowSample(root);
break;
case "UTKImageListWindow":
InitializeImageListWindowSample(root);
break;
case "UTKTreeListWindow":
InitializeTreeListWindowSample(root);
break;
case "UTKPropertyListWindow":
InitializePropertyListWindowSample(root);
break;
}
}
#endregion
}