diff --git a/Assets/Resources/UIToolkit/Menu.meta b/Assets/Resources/UIToolkit/Menu.meta
new file mode 100644
index 00000000..6390afc7
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7f1d048442c47cc48ad2cb26f6cd97f4
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Resources/UIToolkit/Menu/UTKMenuImageItem.uxml b/Assets/Resources/UIToolkit/Menu/UTKMenuImageItem.uxml
new file mode 100644
index 00000000..67592e23
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKMenuImageItem.uxml
@@ -0,0 +1,6 @@
+
+
+
diff --git a/Assets/Resources/UIToolkit/Menu/UTKMenuImageItem.uxml.meta b/Assets/Resources/UIToolkit/Menu/UTKMenuImageItem.uxml.meta
new file mode 100644
index 00000000..01641602
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKMenuImageItem.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 6ffed7426014c8a4bb119007e0bbdae2
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/Assets/Resources/UIToolkit/Menu/UTKMenuImageItemUss.uss b/Assets/Resources/UIToolkit/Menu/UTKMenuImageItemUss.uss
new file mode 100644
index 00000000..1b18f213
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKMenuImageItemUss.uss
@@ -0,0 +1,53 @@
+.menu-item {
+ padding-left: 0;
+ padding-right: 0;
+ width: 40px;
+ height: 40px;
+ border-width: 0;
+ background-color: transparent;
+ transition-property: background-color;
+ transition-duration: 0.2s;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ margin: 0;
+}
+
+.menu-item:hover {
+ background-color: var(--color-bg-hover);
+}
+
+.menu-item:active {
+ background-color: var(--color-bg-active);
+}
+
+.menu-item:disabled {
+ opacity: 0.5;
+}
+
+.menu-item__icon {
+ -unity-font-style: normal;
+ font-size: 20px;
+ color: var(--color-text-primary);
+ -unity-text-align: middle-center;
+ flex-shrink: 0;
+}
+
+.menu-item__image {
+ width: 20px;
+ height: 20px;
+}
+
+.menu-item__arrow {
+ width: 0;
+ height: 0;
+ margin-left: 4px;
+ border-left-width: 4px;
+ border-right-width: 4px;
+ border-top-width: 4px;
+ border-bottom-width: 4px;
+ border-left-color: transparent;
+ border-right-color: transparent;
+ border-top-color: var(--color-text-primary);
+ border-bottom-color: transparent;
+}
diff --git a/Assets/Resources/UIToolkit/Menu/UTKMenuImageItemUss.uss.meta b/Assets/Resources/UIToolkit/Menu/UTKMenuImageItemUss.uss.meta
new file mode 100644
index 00000000..172d3c45
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKMenuImageItemUss.uss.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 62cac8dfd8f41d14b8bf1195de5e2cc8
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
+ disableValidation: 0
diff --git a/Assets/Resources/UIToolkit/Menu/UTKMenuItem.uxml b/Assets/Resources/UIToolkit/Menu/UTKMenuItem.uxml
new file mode 100644
index 00000000..1ba90cc0
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKMenuItem.uxml
@@ -0,0 +1,7 @@
+
+
+
diff --git a/Assets/Resources/UIToolkit/Menu/UTKMenuItem.uxml.meta b/Assets/Resources/UIToolkit/Menu/UTKMenuItem.uxml.meta
new file mode 100644
index 00000000..82603fb9
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKMenuItem.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 18625630452b37a468a7deb385187c05
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/Assets/Resources/UIToolkit/Menu/UTKMenuItemUss.uss b/Assets/Resources/UIToolkit/Menu/UTKMenuItemUss.uss
new file mode 100644
index 00000000..4e0d3371
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKMenuItemUss.uss
@@ -0,0 +1,46 @@
+.menu-item {
+ padding-left: 12px;
+ padding-right: 12px;
+ height: 40px;
+ border-width: 0;
+ background-color: transparent;
+ transition-property: background-color;
+ transition-duration: 0.2s;
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-start;
+ margin: 0;
+}
+
+.menu-item:hover {
+ background-color: var(--color-bg-hover);
+}
+
+.menu-item:active {
+ background-color: var(--color-bg-active);
+}
+
+.menu-item:disabled {
+ opacity: 0.5;
+}
+
+.menu-item__label {
+ -unity-font-style: normal;
+ font-size: 14px;
+ color: var(--color-text-primary);
+ -unity-text-align: middle-left;
+}
+
+.menu-item__arrow {
+ width: 0;
+ height: 0;
+ margin-left: 4px;
+ border-left-width: 4px;
+ border-right-width: 4px;
+ border-top-width: 4px;
+ border-bottom-width: 4px;
+ border-left-color: transparent;
+ border-right-color: transparent;
+ border-top-color: var(--color-text-primary);
+ border-bottom-color: transparent;
+}
diff --git a/Assets/Resources/UIToolkit/Menu/UTKMenuItemUss.uss.meta b/Assets/Resources/UIToolkit/Menu/UTKMenuItemUss.uss.meta
new file mode 100644
index 00000000..1a35988c
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKMenuItemUss.uss.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6871fdccc61fab047bc39781b65546ac
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
+ disableValidation: 0
diff --git a/Assets/Resources/UIToolkit/Menu/UTKSubMenuItem.uxml b/Assets/Resources/UIToolkit/Menu/UTKSubMenuItem.uxml
new file mode 100644
index 00000000..6b584606
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKSubMenuItem.uxml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/Assets/Resources/UIToolkit/Menu/UTKSubMenuItem.uxml.meta b/Assets/Resources/UIToolkit/Menu/UTKSubMenuItem.uxml.meta
new file mode 100644
index 00000000..033d1273
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKSubMenuItem.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: fd7d2115694c74b4ea118c851352ecb4
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/Assets/Resources/UIToolkit/Menu/UTKSubMenuItemUss.uss b/Assets/Resources/UIToolkit/Menu/UTKSubMenuItemUss.uss
new file mode 100644
index 00000000..0d866ce8
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKSubMenuItemUss.uss
@@ -0,0 +1,68 @@
+.submenu-item {
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ padding-left: 16px;
+ padding-right: 16px;
+ padding-top: 8px;
+ padding-bottom: 8px;
+ min-width: 200px;
+ height: 32px;
+ border-width: 0;
+ background-color: var(--color-bg-primary);
+ margin: 0;
+}
+
+.submenu-item:hover {
+ background-color: var(--color-bg-hover);
+}
+
+.submenu-item:active {
+ background-color: var(--color-bg-active);
+}
+
+.submenu-item:disabled {
+ opacity: 0.5;
+}
+
+.submenu-item__label {
+ font-size: 14px;
+ color: var(--color-text-primary);
+ -unity-text-align: middle-left;
+ flex-shrink: 0;
+}
+
+.submenu-item__spacer {
+ flex-grow: 1;
+ min-width: 24px;
+}
+
+.submenu-item__shortcut {
+ font-size: 12px;
+ color: var(--color-text-secondary);
+ -unity-text-align: middle-right;
+ flex-shrink: 0;
+}
+
+.submenu-item__arrow {
+ width: 0;
+ height: 0;
+ margin-left: 8px;
+ border-left-width: 5px;
+ border-right-width: 5px;
+ border-top-width: 5px;
+ border-bottom-width: 5px;
+ border-left-color: var(--color-text-primary);
+ border-right-color: transparent;
+ border-top-color: transparent;
+ border-bottom-color: transparent;
+ flex-shrink: 0;
+}
+
+/* 구분선 스타일 */
+.submenu-separator {
+ height: 1px;
+ background-color: var(--color-border);
+ margin-top: 4px;
+ margin-bottom: 4px;
+}
diff --git a/Assets/Resources/UIToolkit/Menu/UTKSubMenuItemUss.uss.meta b/Assets/Resources/UIToolkit/Menu/UTKSubMenuItemUss.uss.meta
new file mode 100644
index 00000000..e227c601
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKSubMenuItemUss.uss.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bf6082681da1aa34a84eb0ee95c92062
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
+ disableValidation: 0
diff --git a/Assets/Resources/UIToolkit/Menu/UTKTopMenu.uxml b/Assets/Resources/UIToolkit/Menu/UTKTopMenu.uxml
new file mode 100644
index 00000000..5115ee81
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKTopMenu.uxml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/Assets/Resources/UIToolkit/Menu/UTKTopMenu.uxml.meta b/Assets/Resources/UIToolkit/Menu/UTKTopMenu.uxml.meta
new file mode 100644
index 00000000..1be112fc
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKTopMenu.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 22005f651aee4e2449797387a6890b5a
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/Assets/Resources/UIToolkit/Menu/UTKTopMenuUss.uss b/Assets/Resources/UIToolkit/Menu/UTKTopMenuUss.uss
new file mode 100644
index 00000000..fe7b6884
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKTopMenuUss.uss
@@ -0,0 +1,25 @@
+.top-menu {
+ position: relative;
+ flex-direction: column;
+ width: 100%;
+ height: 100%;
+ background-color: transparent;
+}
+
+.top-menu__items {
+ flex-direction: row;
+ height: 40px;
+ background-color: var(--color-bg-primary);
+ border-bottom-width: 1px;
+ border-bottom-color: var(--color-border);
+}
+
+/* 하위 메뉴 컨테이너 스타일 */
+.submenu-container {
+ position: absolute;
+ background-color: var(--color-bg-primary);
+ border-width: 1px;
+ border-color: var(--color-border);
+ min-width: 200px;
+ padding: 4px 0;
+}
diff --git a/Assets/Resources/UIToolkit/Menu/UTKTopMenuUss.uss.meta b/Assets/Resources/UIToolkit/Menu/UTKTopMenuUss.uss.meta
new file mode 100644
index 00000000..9ec205e5
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Menu/UTKTopMenuUss.uss.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 61573ee2ffda4e840b52e48e36d21206
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
+ disableValidation: 0
diff --git a/Assets/Resources/UIToolkit/Style/UTKThemeDark.uss b/Assets/Resources/UIToolkit/Style/UTKThemeDark.uss
index ff4be6ae..436e0a72 100644
--- a/Assets/Resources/UIToolkit/Style/UTKThemeDark.uss
+++ b/Assets/Resources/UIToolkit/Style/UTKThemeDark.uss
@@ -128,6 +128,7 @@
Semantic Colors - Background (color-bg-*)
=================================== */
--color-bg-base: var(--color-base-20);
+ --color-bg-primary: var(--color-base-20);
--color-bg-secondary: var(--color-base-19);
--color-bg-tertiary: var(--color-base-13);
--color-bg-elevated: var(--color-base-18);
diff --git a/Assets/Resources/UIToolkit/Style/UTKThemeLight.uss b/Assets/Resources/UIToolkit/Style/UTKThemeLight.uss
index 7c0ba94c..cf5b6f0f 100644
--- a/Assets/Resources/UIToolkit/Style/UTKThemeLight.uss
+++ b/Assets/Resources/UIToolkit/Style/UTKThemeLight.uss
@@ -139,6 +139,7 @@
라이트 테마에서는 밝은 배경 사용
=================================== */
--color-bg-base: var(--color-base-01);
+ --color-bg-primary: var(--color-base-01);
--color-bg-secondary: var(--color-base-03);
--color-bg-tertiary: var(--color-base-06);
--color-bg-elevated: var(--color-base-02);
diff --git a/Assets/Sample/CursorManagerSample.unity b/Assets/Sample/CursorManagerSample.unity
index 3f61b76a..b5605904 100644
--- a/Assets/Sample/CursorManagerSample.unity
+++ b/Assets/Sample/CursorManagerSample.unity
@@ -290,6 +290,21 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 1bbeb3b46a029fe4896da3350401b214, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::CursorManagerSample
+ _buttonWidth: 150
+ _buttonHeight: 30
+ _padding: 10
+ _cursorManager: {fileID: 1239580076}
+--- !u!114 &1239580076 stripped
+MonoBehaviour:
+ m_CorrespondingSourceObject: {fileID: 4705914027077067912, guid: 42ed16ae6a9f96d4f9cd6c292a9edd85, type: 3}
+ m_PrefabInstance: {fileID: 1339613670}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 39e7217342f0a104a985deeef6a5dc4a, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
--- !u!1001 &1339613670
PrefabInstance:
m_ObjectHideFlags: 0
diff --git a/Assets/Sample/UIToolkit/UTKMenu.unity b/Assets/Sample/UIToolkit/UTKMenu.unity
new file mode 100644
index 00000000..c97d8d30
--- /dev/null
+++ b/Assets/Sample/UIToolkit/UTKMenu.unity
@@ -0,0 +1,497 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_OcclusionBakeSettings:
+ smallestOccluder: 5
+ smallestHole: 0.25
+ backfaceThreshold: 100
+ m_SceneGUID: 00000000000000000000000000000000
+ m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 10
+ m_Fog: 0
+ m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+ m_FogMode: 3
+ m_FogDensity: 0.01
+ m_LinearFogStart: 0
+ m_LinearFogEnd: 300
+ m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+ m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+ m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+ m_AmbientIntensity: 1
+ m_AmbientMode: 0
+ m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+ m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+ m_HaloStrength: 0.5
+ m_FlareStrength: 1
+ m_FlareFadeSpeed: 3
+ m_HaloTexture: {fileID: 0}
+ m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+ m_DefaultReflectionMode: 0
+ m_DefaultReflectionResolution: 128
+ m_ReflectionBounces: 1
+ m_ReflectionIntensity: 1
+ m_CustomReflection: {fileID: 0}
+ m_Sun: {fileID: 0}
+ m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 13
+ m_BakeOnSceneLoad: 0
+ m_GISettings:
+ serializedVersion: 2
+ m_BounceScale: 1
+ m_IndirectOutputScale: 1
+ m_AlbedoBoost: 1
+ m_EnvironmentLightingMode: 0
+ m_EnableBakedLightmaps: 1
+ m_EnableRealtimeLightmaps: 0
+ m_LightmapEditorSettings:
+ serializedVersion: 12
+ m_Resolution: 2
+ m_BakeResolution: 40
+ m_AtlasSize: 1024
+ m_AO: 0
+ m_AOMaxDistance: 1
+ m_CompAOExponent: 1
+ m_CompAOExponentDirect: 0
+ m_ExtractAmbientOcclusion: 0
+ m_Padding: 2
+ m_LightmapParameters: {fileID: 0}
+ m_LightmapsBakeMode: 1
+ m_TextureCompression: 1
+ m_ReflectionCompression: 2
+ m_MixedBakeMode: 2
+ m_BakeBackend: 1
+ m_PVRSampling: 1
+ m_PVRDirectSampleCount: 32
+ m_PVRSampleCount: 512
+ m_PVRBounces: 2
+ m_PVREnvironmentSampleCount: 256
+ m_PVREnvironmentReferencePointCount: 2048
+ m_PVRFilteringMode: 1
+ m_PVRDenoiserTypeDirect: 1
+ m_PVRDenoiserTypeIndirect: 1
+ m_PVRDenoiserTypeAO: 1
+ m_PVRFilterTypeDirect: 0
+ m_PVRFilterTypeIndirect: 0
+ m_PVRFilterTypeAO: 0
+ m_PVREnvironmentMIS: 1
+ m_PVRCulling: 1
+ m_PVRFilteringGaussRadiusDirect: 1
+ m_PVRFilteringGaussRadiusIndirect: 1
+ m_PVRFilteringGaussRadiusAO: 1
+ m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+ m_PVRFilteringAtrousPositionSigmaIndirect: 2
+ m_PVRFilteringAtrousPositionSigmaAO: 1
+ m_ExportTrainingData: 0
+ m_TrainingDataDestination: TrainingData
+ m_LightProbeSampleCountMultiplier: 4
+ m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0}
+ m_LightingSettings: {fileID: 0}
+--- !u!196 &4
+NavMeshSettings:
+ serializedVersion: 2
+ m_ObjectHideFlags: 0
+ m_BuildSettings:
+ serializedVersion: 3
+ agentTypeID: 0
+ agentRadius: 0.5
+ agentHeight: 2
+ agentSlope: 45
+ agentClimb: 0.4
+ ledgeDropHeight: 0
+ maxJumpAcrossDistance: 0
+ minRegionArea: 2
+ manualCellSize: 0
+ cellSize: 0.16666667
+ manualTileSize: 0
+ tileSize: 256
+ buildHeightMesh: 0
+ maxJobWorkers: 0
+ preserveTilesOutsideBounds: 0
+ debug:
+ m_Flags: 0
+ m_NavMeshData: {fileID: 0}
+--- !u!1 &1097328750
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1097328752}
+ - component: {fileID: 1097328754}
+ - component: {fileID: 1097328755}
+ m_Layer: 0
+ m_Name: Sample
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &1097328752
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1097328750}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1097328754
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1097328750}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
+ m_Name:
+ m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
+ m_PanelSettings: {fileID: 11400000, guid: 5ad7007b08a97b54d927c352279a18b6, type: 2}
+ m_ParentUI: {fileID: 0}
+ sourceAsset: {fileID: 9197481963319205126, guid: ea6c8ab095077eb4889ac1b615a0b324, type: 3}
+ m_SortingOrder: 1
+ m_Position: 0
+ m_WorldSpaceSizeMode: 1
+ m_WorldSpaceWidth: 1920
+ m_WorldSpaceHeight: 1080
+ m_PivotReferenceSize: 0
+ m_Pivot: 0
+ m_WorldSpaceCollider: {fileID: 0}
+--- !u!114 &1097328755
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1097328750}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: c2be721e7a021bf49b462c82e1f4892c, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: Assembly-CSharp::UVC.Sample.UIToolkit.UTKMenuSample
+ _uiDocument: {fileID: 1097328754}
+ initialTheme: 0
+--- !u!1 &1331954412
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1331954415}
+ - component: {fileID: 1331954414}
+ - component: {fileID: 1331954413}
+ m_Layer: 0
+ m_Name: EventSystem
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!114 &1331954413
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1331954412}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 01614664b831546d2ae94a42149d80ac, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_SendPointerHoverToParent: 1
+ m_MoveRepeatDelay: 0.5
+ m_MoveRepeatRate: 0.1
+ m_XRTrackingOrigin: {fileID: 0}
+ m_ActionsAsset: {fileID: -944628639613478452, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+ m_PointAction: {fileID: -1654692200621890270, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+ m_MoveAction: {fileID: -8784545083839296357, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+ m_SubmitAction: {fileID: 392368643174621059, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+ m_CancelAction: {fileID: 7727032971491509709, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+ m_LeftClickAction: {fileID: 3001919216989983466, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+ m_MiddleClickAction: {fileID: -2185481485913320682, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+ m_RightClickAction: {fileID: -4090225696740746782, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+ m_ScrollWheelAction: {fileID: 6240969308177333660, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+ m_TrackedDevicePositionAction: {fileID: 6564999863303420839, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+ m_TrackedDeviceOrientationAction: {fileID: 7970375526676320489, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+ m_DeselectOnBackgroundClick: 0
+ m_PointerBehavior: 0
+ m_CursorLockBehavior: 0
+ m_ScrollDeltaPerTick: 6
+--- !u!114 &1331954414
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1331954412}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_FirstSelected: {fileID: 0}
+ m_sendNavigationEvents: 1
+ m_DragThreshold: 10
+--- !u!4 &1331954415
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1331954412}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &1414861612
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1414861614}
+ - component: {fileID: 1414861613}
+ - component: {fileID: 1414861615}
+ m_Layer: 0
+ m_Name: Directional Light
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!108 &1414861613
+Light:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1414861612}
+ m_Enabled: 1
+ serializedVersion: 11
+ m_Type: 1
+ m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
+ m_Intensity: 1
+ m_Range: 10
+ m_SpotAngle: 30
+ m_InnerSpotAngle: 21.80208
+ m_CookieSize: 10
+ m_Shadows:
+ m_Type: 2
+ m_Resolution: -1
+ m_CustomResolution: -1
+ m_Strength: 1
+ m_Bias: 0.05
+ m_NormalBias: 0.4
+ m_NearPlane: 0.2
+ m_CullingMatrixOverride:
+ e00: 1
+ e01: 0
+ e02: 0
+ e03: 0
+ e10: 0
+ e11: 1
+ e12: 0
+ e13: 0
+ e20: 0
+ e21: 0
+ e22: 1
+ e23: 0
+ e30: 0
+ e31: 0
+ e32: 0
+ e33: 1
+ m_UseCullingMatrixOverride: 0
+ m_Cookie: {fileID: 0}
+ m_DrawHalo: 0
+ m_Flare: {fileID: 0}
+ m_RenderMode: 0
+ m_CullingMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_RenderingLayerMask: 1
+ m_Lightmapping: 4
+ m_LightShadowCasterMode: 0
+ m_AreaSize: {x: 1, y: 1}
+ m_BounceIntensity: 1
+ m_ColorTemperature: 6570
+ m_UseColorTemperature: 0
+ m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
+ m_UseBoundingSphereOverride: 0
+ m_UseViewFrustumForShadowCasterCull: 1
+ m_ForceVisible: 0
+ m_ShadowRadius: 0
+ m_ShadowAngle: 0
+ m_LightUnit: 1
+ m_LuxAtDistance: 1
+ m_EnableSpotReflector: 1
+--- !u!4 &1414861614
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1414861612}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
+ m_LocalPosition: {x: 0, y: 3, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
+--- !u!114 &1414861615
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1414861612}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_UsePipelineSettings: 1
+ m_AdditionalLightsShadowResolutionTier: 2
+ m_CustomShadowLayers: 0
+ m_LightCookieSize: {x: 1, y: 1}
+ m_LightCookieOffset: {x: 0, y: 0}
+ m_SoftShadowQuality: 0
+ m_RenderingLayersMask:
+ serializedVersion: 0
+ m_Bits: 1
+ m_ShadowRenderingLayersMask:
+ serializedVersion: 0
+ m_Bits: 1
+ m_Version: 4
+ m_LightLayerMask: 1
+ m_ShadowLayerMask: 1
+ m_RenderingLayers: 1
+ m_ShadowRenderingLayers: 1
+--- !u!1 &2136621999
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 2136622002}
+ - component: {fileID: 2136622001}
+ - component: {fileID: 2136622000}
+ m_Layer: 0
+ m_Name: Main Camera
+ m_TagString: MainCamera
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!81 &2136622000
+AudioListener:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2136621999}
+ m_Enabled: 1
+--- !u!20 &2136622001
+Camera:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2136621999}
+ m_Enabled: 1
+ serializedVersion: 2
+ m_ClearFlags: 1
+ m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
+ m_projectionMatrixMode: 1
+ m_GateFitMode: 2
+ m_FOVAxisMode: 0
+ m_Iso: 200
+ m_ShutterSpeed: 0.005
+ m_Aperture: 16
+ m_FocusDistance: 10
+ m_FocalLength: 50
+ m_BladeCount: 5
+ m_Curvature: {x: 2, y: 11}
+ m_BarrelClipping: 0.25
+ m_Anamorphism: 0
+ m_SensorSize: {x: 36, y: 24}
+ m_LensShift: {x: 0, y: 0}
+ m_NormalizedViewPortRect:
+ serializedVersion: 2
+ x: 0
+ y: 0
+ width: 1
+ height: 1
+ near clip plane: 0.3
+ far clip plane: 1000
+ field of view: 60
+ orthographic: 0
+ orthographic size: 5
+ m_Depth: -1
+ m_CullingMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_RenderingPath: -1
+ m_TargetTexture: {fileID: 0}
+ m_TargetDisplay: 0
+ m_TargetEye: 3
+ m_HDR: 1
+ m_AllowMSAA: 1
+ m_AllowDynamicResolution: 0
+ m_ForceIntoRT: 0
+ m_OcclusionCulling: 1
+ m_StereoConvergence: 10
+ m_StereoSeparation: 0.022
+--- !u!4 &2136622002
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 2136621999}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 1, z: -10}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1660057539 &9223372036854775807
+SceneRoots:
+ m_ObjectHideFlags: 0
+ m_Roots:
+ - {fileID: 2136622002}
+ - {fileID: 1414861614}
+ - {fileID: 1331954415}
+ - {fileID: 1097328752}
diff --git a/Assets/Sample/UIToolkit/UTKMenu.unity.meta b/Assets/Sample/UIToolkit/UTKMenu.unity.meta
new file mode 100644
index 00000000..57ac2313
--- /dev/null
+++ b/Assets/Sample/UIToolkit/UTKMenu.unity.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 78506514708184a4893eba450c0b865a
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Sample/UIToolkit/UTKMenuSample.cs b/Assets/Sample/UIToolkit/UTKMenuSample.cs
new file mode 100644
index 00000000..57a226c4
--- /dev/null
+++ b/Assets/Sample/UIToolkit/UTKMenuSample.cs
@@ -0,0 +1,548 @@
+#nullable enable
+using System;
+using Cysharp.Threading.Tasks;
+using UnityEngine;
+using UnityEngine.UIElements;
+using UVC.UIToolkit;
+using UVC.UIToolkit.Menu;
+using UVC.UI.Commands;
+using UVC.Log;
+
+namespace UVC.Sample.UIToolkit
+{
+ ///
+ /// UTKMenu 샘플 코드
+ /// UIToolkit 기반 TopMenu 시스템을 테스트합니다.
+ ///
+ public class UTKMenuSample : MonoBehaviour
+ {
+ [SerializeField] private UIDocument? _uiDocument;
+
+ [SerializeField]
+ [Tooltip("시작 시 적용할 테마")]
+ private UTKTheme initialTheme = UTKTheme.Dark;
+
+ private UTKToggle? _themeToggle;
+ private VisualElement? _root;
+ private UTKTopMenuView? _menuView;
+ private UTKTopMenuModel? _menuModel;
+
+ private UTKTopMenuView? _menuView2;
+ private UTKTopMenuModel? _menuModel2;
+
+ // 상태 관리용
+ private bool _canUndo = false;
+ private bool _canRedo = false;
+ private bool _isFileOpen = false;
+
+
+ private void Start()
+ {
+ // UIDocument 참조 확인
+ var doc = GetComponent();
+ if (doc == null)
+ {
+ Debug.LogError("UIDocument가 할당되지 않았습니다.");
+ return;
+ }
+ _uiDocument = doc;
+
+ var toggle = _uiDocument.rootVisualElement.Q("toggle");
+ if (toggle == null)
+ {
+ Debug.LogError("UXML에서 UTKToggle을 찾을 수 없습니다.");
+ return;
+ }
+ _themeToggle = toggle;
+
+ UTKThemeManager.Instance.RegisterRoot(_uiDocument.rootVisualElement);
+ UTKThemeManager.Instance.SetTheme(initialTheme);
+
+ _themeToggle.OnValueChanged += (isOn) =>
+ {
+ UTKThemeManager.Instance.SetTheme(!isOn ? UTKTheme.Dark : UTKTheme.Light);
+ };
+
+ _root = _uiDocument.rootVisualElement;
+ CreateSampleUI();
+ }
+
+ private void CreateSampleUI()
+ {
+ if (_root == null) return;
+
+ // 1. UTKTopMenuView 생성
+ _menuView = new UTKTopMenuView();
+ _menuView.style.position = Position.Absolute;
+ _menuView.style.top = 0;
+ _menuView.style.left = 50;
+
+ _menuView2 = new UTKTopMenuView();
+ _menuView2.style.position = Position.Absolute;
+ _menuView2.style.top = 0;
+ _menuView2.style.left = 0;
+ _menuView2.SubMenuOffsetX = 30;
+ _root.Add(_menuView2);
+ _root.Add(_menuView);
+
+ // 2. UTKTopMenuModel 생성 및 메뉴 아이템 추가
+ _menuModel = new UTKTopMenuModel();
+ _menuModel2 = new UTKTopMenuModel();
+
+ CreateMenuItems();
+
+ // 3. View에 메뉴 생성
+ if (_menuView.MenuContainer != null)
+ {
+ _menuView.CreateMenuItems(_menuModel.MenuItems, _menuView.MenuContainer);
+ }
+
+ if (_menuView2.MenuContainer != null)
+ {
+ _menuView2.CreateMenuItems(_menuModel2.MenuItems, _menuView2.MenuContainer);
+ }
+
+ // 4. 이벤트 구독
+ _menuView.OnMenuItemClicked += HandleMenuItemClicked;
+ _menuView2.OnMenuItemClicked += HandleMenuItemClicked2;
+
+ // 5. 상태 테스트 버튼 생성
+ CreateTestButtons();
+
+ ULog.Debug("UTKTopMenu 샘플 UI 생성 완료");
+ }
+
+ ///
+ /// 메뉴 아이템들을 생성합니다.
+ ///
+ private void CreateMenuItems()
+ {
+ if (_menuModel == null || _menuModel2 == null) return;
+
+ // 파일 메뉴
+ var fileMenu = new UTKMenuItemData("file", "파일");
+ fileMenu.AddSubMenuItem(new UTKMenuItemData(
+ "file_new",
+ "새 파일",
+ new DebugLogCommand("새 파일 생성"),
+ shortcut: "Ctrl+N"
+ ));
+ fileMenu.AddSubMenuItem(new UTKMenuItemData(
+ "file_open",
+ "열기",
+ new DebugLogCommand("파일 열기"),
+ shortcut: "Ctrl+O"
+ ));
+ fileMenu.AddSubMenuItem(UTKMenuItemData.CreateSeparator());
+ fileMenu.AddSubMenuItem(new UTKMenuItemData(
+ "file_save",
+ "저장",
+ new DebugLogCommand("파일 저장"),
+ isEnabled: false, // 초기에는 비활성화
+ shortcut: "Ctrl+S"
+ ));
+ fileMenu.AddSubMenuItem(new UTKMenuItemData(
+ "file_save_as",
+ "다른 이름으로 저장",
+ new DebugLogCommand("다른 이름으로 저장"),
+ isEnabled: false,
+ shortcut: "Ctrl+Shift+S"
+ ));
+ fileMenu.AddSubMenuItem(UTKMenuItemData.CreateSeparator());
+ fileMenu.AddSubMenuItem(new UTKMenuItemData(
+ "file_exit",
+ "종료",
+ new DebugLogCommand("애플리케이션 종료"),
+ shortcut: "Alt+F4"
+ ));
+ _menuModel.AddMenuItem(fileMenu);
+
+ // 편집 메뉴
+ var editMenu = new UTKMenuItemData("edit", "편집");
+ editMenu.AddSubMenuItem(new UTKMenuItemData(
+ "edit_undo",
+ "실행 취소",
+ new DebugLogCommand("실행 취소"),
+ isEnabled: false,
+ shortcut: "Ctrl+Z"
+ ));
+ editMenu.AddSubMenuItem(new UTKMenuItemData(
+ "edit_redo",
+ "다시 실행",
+ new DebugLogCommand("다시 실행"),
+ isEnabled: false,
+ shortcut: "Ctrl+Y"
+ ));
+ editMenu.AddSubMenuItem(UTKMenuItemData.CreateSeparator());
+ editMenu.AddSubMenuItem(new UTKMenuItemData(
+ "edit_cut",
+ "잘라내기",
+ new DebugLogCommand("잘라내기"),
+ shortcut: "Ctrl+X"
+ ));
+ editMenu.AddSubMenuItem(new UTKMenuItemData(
+ "edit_copy",
+ "복사",
+ new DebugLogCommand("복사"),
+ shortcut: "Ctrl+C"
+ ));
+ editMenu.AddSubMenuItem(new UTKMenuItemData(
+ "edit_paste",
+ "붙여넣기",
+ new DebugLogCommand("붙여넣기"),
+ shortcut: "Ctrl+V"
+ ));
+ _menuModel.AddMenuItem(editMenu);
+
+ // 보기 메뉴 (하위 메뉴 테스트)
+ var viewMenu = new UTKMenuItemData("view", "보기");
+
+ var layoutMenu = new UTKMenuItemData("view_layout", "레이아웃");
+ layoutMenu.AddSubMenuItem(new UTKMenuItemData("view_layout_default", "기본", new DebugLogCommand("기본 레이아웃")));
+ layoutMenu.AddSubMenuItem(new UTKMenuItemData("view_layout_wide", "와이드", new DebugLogCommand("와이드 레이아웃")));
+ layoutMenu.AddSubMenuItem(new UTKMenuItemData("view_layout_compact", "컴팩트", new DebugLogCommand("컴팩트 레이아웃")));
+
+ viewMenu.AddSubMenuItem(layoutMenu);
+ viewMenu.AddSubMenuItem(UTKMenuItemData.CreateSeparator());
+ viewMenu.AddSubMenuItem(new UTKMenuItemData("view_fullscreen", "전체 화면", new DebugLogCommand("전체 화면 전환"), shortcut: "F11"));
+ _menuModel.AddMenuItem(viewMenu);
+
+ // 도구 메뉴
+ var toolsMenu = new UTKMenuItemData("tools", "도구");
+ toolsMenu.AddSubMenuItem(new UTKMenuItemData("tools_options", "옵션", new DebugLogCommand("옵션 열기")));
+ toolsMenu.AddSubMenuItem(new UTKMenuItemData("tools_settings", "설정", new DebugLogCommand("설정 열기")));
+ _menuModel.AddMenuItem(toolsMenu);
+
+ // 도움말 메뉴
+ var helpMenu = new UTKMenuItemData("help", "도움말");
+ helpMenu.AddSubMenuItem(new UTKMenuItemData("help_documentation", "문서", new DebugLogCommand("문서 열기"), shortcut: "F1"));
+ helpMenu.AddSubMenuItem(UTKMenuItemData.CreateSeparator());
+ helpMenu.AddSubMenuItem(new UTKMenuItemData("help_about", "정보", new DebugLogCommand("정보 표시")));
+ _menuModel.AddMenuItem(helpMenu);
+
+ // 이미지 메뉴 (4 depth 테스트)
+ var imageMenu = new UTKMenuImageItemData(
+ "image_menu",
+ UTKMaterialIcons.Settings, // Material Icon 사용
+ useMaterialIcon: true,
+ imageSize: 24f
+ );
+
+ // Depth 1 아이템
+ var depth1Item = new UTKMenuItemData("depth1", "레벨 1 메뉴");
+ var depth1Item1 = new UTKMenuItemData("depth11", "레벨 1 1메뉴");
+ var depth1Item2 = new UTKMenuItemData("depth12", "레벨 1 2메뉴");
+ var depth1Item3 = new UTKMenuItemData("depth13", "레벨 1 3메뉴");
+
+ // Depth 2 아이템
+ var depth2Item = new UTKMenuItemData("depth2", "레벨 2 메뉴");
+ var depth2Item1 = new UTKMenuItemData("depth21", "레벨 2 1 메뉴");
+ var depth2Item2 = new UTKMenuItemData("depth22", "레벨 2 2 메뉴");
+ var depth2Item3 = new UTKMenuItemData("depth23", "레벨 2 3 메뉴");
+
+ // Depth 3 아이템
+ var depth3Item = new UTKMenuItemData("depth3", "레벨 3 메뉴");
+
+ // Depth 4 아이템들 (실제 액션)
+ var depth4Action1 = new UTKMenuItemData("depth4_action1", "액션 1", new DebugLogCommand("4 Depth 액션 1 실행"));
+ var depth4Action2 = new UTKMenuItemData("depth4_action2", "액션 2", new DebugLogCommand("4 Depth 액션 2 실행"));
+ var depth4Action3 = new UTKMenuItemData("depth4_action3", "액션 3", new DebugLogCommand("4 Depth 액션 3 실행"));
+
+ // 계층 구조 구성 (역순으로)
+ depth3Item.AddSubMenuItem(depth4Action1);
+ depth3Item.AddSubMenuItem(depth4Action2);
+ depth3Item.AddSubMenuItem(depth4Action3);
+ depth2Item.AddSubMenuItem(depth3Item);
+ depth1Item.AddSubMenuItem(depth2Item);
+ depth1Item.AddSubMenuItem(depth2Item1);
+ depth1Item.AddSubMenuItem(depth2Item2);
+ depth1Item.AddSubMenuItem(depth2Item3);
+ imageMenu.AddSubMenuItem(depth1Item1);
+ imageMenu.AddSubMenuItem(depth1Item2);
+ imageMenu.AddSubMenuItem(depth1Item3);
+ imageMenu.AddSubMenuItem(depth1Item);
+
+ _menuModel2.AddMenuItem(imageMenu);
+
+ ULog.Debug($"메뉴 아이템 생성 완료: {_menuModel.MenuItems.Count}개 최상위 메뉴");
+ }
+
+ ///
+ /// 테스트 버튼들을 생성합니다.
+ ///
+ private void CreateTestButtons()
+ {
+ if (_root == null) return;
+
+ // 테스트 버튼 컨테이너
+ var buttonContainer = new VisualElement();
+ buttonContainer.style.position = Position.Absolute;
+ buttonContainer.style.top = 60;
+ buttonContainer.style.left = 10;
+ buttonContainer.style.flexDirection = FlexDirection.Column;
+ buttonContainer.style.width = 250;
+ _root.Insert(0, buttonContainer);
+
+ // 타이틀
+ var title = new Label("메뉴 상태 테스트");
+ title.style.fontSize = 16;
+ title.style.unityFontStyleAndWeight = FontStyle.Bold;
+ title.style.marginBottom = 10;
+ buttonContainer.Add(title);
+
+ // 파일 열기/닫기 버튼
+ var fileToggleBtn = new Button(() => ToggleFileOpen())
+ {
+ text = "파일 열기 (Save 활성화)"
+ };
+ fileToggleBtn.style.marginBottom = 5;
+ buttonContainer.Add(fileToggleBtn);
+
+ // Undo/Redo 토글 버튼
+ var undoToggleBtn = new Button(() => ToggleUndoRedo())
+ {
+ text = "Undo/Redo 활성화"
+ };
+ undoToggleBtn.style.marginBottom = 5;
+ buttonContainer.Add(undoToggleBtn);
+
+ // 모든 하위 메뉴 닫기
+ var closeAllBtn = new Button(() => _menuView?.CloseAllOpenSubMenus())
+ {
+ text = "모든 하위 메뉴 닫기"
+ };
+ closeAllBtn.style.marginBottom = 5;
+ buttonContainer.Add(closeAllBtn);
+
+ // 메뉴 아이템 추가
+ var addMenuBtn = new Button(() => AddDynamicMenu())
+ {
+ text = "동적 메뉴 추가"
+ };
+ addMenuBtn.style.marginBottom = 5;
+ buttonContainer.Add(addMenuBtn);
+
+ // 메뉴 아이템 제거
+ var removeMenuBtn = new Button(() => RemoveDynamicMenu())
+ {
+ text = "동적 메뉴 제거"
+ };
+ removeMenuBtn.style.marginBottom = 5;
+ buttonContainer.Add(removeMenuBtn);
+
+ // 단축키 변경
+ var changeShortcutBtn = new Button(() => ChangeShortcut())
+ {
+ text = "Save 단축키 변경"
+ };
+ buttonContainer.Add(changeShortcutBtn);
+
+ // 상태 표시 레이블
+ var statusLabel = new Label();
+ statusLabel.style.marginTop = 20;
+ statusLabel.style.fontSize = 12;
+ statusLabel.style.color = new Color(0.7f, 0.7f, 0.7f);
+ buttonContainer.Add(statusLabel);
+
+ UpdateStatusLabel(statusLabel);
+ }
+
+ ///
+ /// 파일 열기/닫기 상태를 토글합니다.
+ ///
+ private void ToggleFileOpen()
+ {
+ _isFileOpen = !_isFileOpen;
+
+ var saveItem = _menuModel?.FindMenuItem("file_save");
+ var saveAsItem = _menuModel?.FindMenuItem("file_save_as");
+
+ if (saveItem != null)
+ {
+ saveItem.IsEnabled = _isFileOpen;
+ if (_menuView != null && _menuView.TryGetMenuItemElement("file_save", out var element))
+ {
+ var button = element.Q