diff --git a/.claude/settings.local.json b/.claude/settings.local.json
index 08fe7b39..5195bc45 100644
--- a/.claude/settings.local.json
+++ b/.claude/settings.local.json
@@ -35,7 +35,8 @@
"Bash(/bin/mkdir -p:*)",
"Bash(/bin/rm:*)",
"WebFetch(domain:docs.unity3d.com)",
- "Bash(ls:*)"
+ "Bash(ls:*)",
+ "WebFetch(domain:discussions.unity.com)"
],
"deny": [],
"ask": []
diff --git a/Assets/Resources/Studio/UIToolkit.meta b/Assets/Resources/Studio/UIToolkit.meta
new file mode 100644
index 00000000..04b1cc7a
--- /dev/null
+++ b/Assets/Resources/Studio/UIToolkit.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 036922f6ebd1fc246b7f9dcbed76951d
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Resources/Studio/UIToolkit/Modal.meta b/Assets/Resources/Studio/UIToolkit/Modal.meta
new file mode 100644
index 00000000..3359da6d
--- /dev/null
+++ b/Assets/Resources/Studio/UIToolkit/Modal.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 523651d33563a6e4eb5a39945fe0017f
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentDBUXML.uxml b/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentDBUXML.uxml
new file mode 100644
index 00000000..d0afa7c9
--- /dev/null
+++ b/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentDBUXML.uxml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentDBUXML.uxml.meta b/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentDBUXML.uxml.meta
new file mode 100644
index 00000000..61356b36
--- /dev/null
+++ b/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentDBUXML.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: d27b20f78aec0354b8b97b9af0765701
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentGeneralUXML.uxml b/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentGeneralUXML.uxml
new file mode 100644
index 00000000..c3cd0cfc
--- /dev/null
+++ b/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentGeneralUXML.uxml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentGeneralUXML.uxml.meta b/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentGeneralUXML.uxml.meta
new file mode 100644
index 00000000..670af551
--- /dev/null
+++ b/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentGeneralUXML.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 0a709a335acffbd4c9d4358c153fad81
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentShortcutUXML.uxml b/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentShortcutUXML.uxml
new file mode 100644
index 00000000..96d9145f
--- /dev/null
+++ b/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentShortcutUXML.uxml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentShortcutUXML.uxml.meta b/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentShortcutUXML.uxml.meta
new file mode 100644
index 00000000..37338f45
--- /dev/null
+++ b/Assets/Resources/Studio/UIToolkit/Modal/UTKSettingModalContentShortcutUXML.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: dcdd51dd452d3e94ca374da0307608a4
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/Assets/Resources/UIToolkit/Input/UTKInputField.uss b/Assets/Resources/UIToolkit/Input/UTKInputField.uss
index 0a5c8fa0..1800f2d8 100644
--- a/Assets/Resources/UIToolkit/Input/UTKInputField.uss
+++ b/Assets/Resources/UIToolkit/Input/UTKInputField.uss
@@ -35,7 +35,7 @@
.utk-input > .unity-base-text-field__input {
flex-grow: 1;
height: var(--size-input-height);
- min-width: 120px;
+ min-width: 60px;
padding-left: var(--space-m);
padding-right: var(--space-m);
background-color: var(--color-bg-input);
diff --git a/Assets/Resources/UIToolkit/List/UTKShortcutList.uxml b/Assets/Resources/UIToolkit/List/UTKShortcutList.uxml
new file mode 100644
index 00000000..3fb58dbf
--- /dev/null
+++ b/Assets/Resources/UIToolkit/List/UTKShortcutList.uxml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Assets/Resources/UIToolkit/List/UTKShortcutList.uxml.meta b/Assets/Resources/UIToolkit/List/UTKShortcutList.uxml.meta
new file mode 100644
index 00000000..0c38a658
--- /dev/null
+++ b/Assets/Resources/UIToolkit/List/UTKShortcutList.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 009b695fb58d74b43a48be6fb5a00895
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/Assets/Resources/UIToolkit/List/UTKShortcutListItem.uxml b/Assets/Resources/UIToolkit/List/UTKShortcutListItem.uxml
new file mode 100644
index 00000000..1011d7ce
--- /dev/null
+++ b/Assets/Resources/UIToolkit/List/UTKShortcutListItem.uxml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Assets/Resources/UIToolkit/List/UTKShortcutListItem.uxml.meta b/Assets/Resources/UIToolkit/List/UTKShortcutListItem.uxml.meta
new file mode 100644
index 00000000..5cf4441b
--- /dev/null
+++ b/Assets/Resources/UIToolkit/List/UTKShortcutListItem.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 0d18cdf18ee19874aaf8decc2b8805ff
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/Assets/Resources/UIToolkit/List/UTKShortcutListUss.uss b/Assets/Resources/UIToolkit/List/UTKShortcutListUss.uss
new file mode 100644
index 00000000..93d4b59c
--- /dev/null
+++ b/Assets/Resources/UIToolkit/List/UTKShortcutListUss.uss
@@ -0,0 +1,262 @@
+/*
+ * ===================================
+ * UTKShortcutListUss.uss
+ * 단축키 설정 리스트 컴포넌트 전용 스타일
+ * ===================================
+ *
+ * 이 파일은 UTKThemeManager 의 CSS 변수를 참조합니다.
+ * - 색상 : var(--color-*)
+ * - 간격 : var(--space-*)
+ * - 반지름: var(--radius-*)
+ * - 폰트 : var(--font-size-*)
+ *
+ * 컬럼 너비 (컨테이너 · 헤더 · 아이템 공통으로 맞춤):
+ * command flex-grow:1 명령 이름 (나머지 공간 전부)
+ * modifier 52px Ctrl / Shift / Alt 체크박스 셀
+ * key 76px 주요 키 입력 셀
+ *
+ * 관련 파일:
+ * UTKShortcutList.uxml – 메인 레이아웃
+ * UTKShortcutListItem.uxml – 아이템 행 레이아웃
+ * UTKShortcutList.cs – 컴포넌트 로직
+ */
+
+/* =============================================
+ 루트 컨테이너
+ ============================================= */
+
+.utk-shortcut-list {
+ flex-grow: 1;
+ flex-direction: column;
+ background-color: var(--color-bg-panel);
+}
+
+.utk-shortcut-list-container {
+ flex-grow: 1;
+ flex-direction: column;
+}
+
+/* =============================================
+ 검색 영역 (검색 필드 + Clear 버튼)
+ ============================================= */
+
+.utk-shortcut-list__search-container {
+ position: relative;
+ margin: var(--space-m) var(--space-m) 0 var(--space-m);
+ justify-content: center;
+}
+
+.utk-shortcut-list__search {
+ flex-grow: 1;
+}
+
+/* 검색어 있을 때 텍스트가 버튼 뒤로 가리지 않도록 오른쪽 패딩 확보 */
+.utk-shortcut-list__search .unity-text-field__input {
+ padding-right: 28px;
+}
+
+.utk-shortcut-list__clear-btn {
+ width: 16px;
+ height: 16px;
+ min-width: 16px;
+ min-height: 16px;
+ border-width: 0;
+ margin: 0;
+ padding: 0;
+ align-self: center;
+ position: absolute;
+ right: 4px;
+}
+
+.utk-shortcut-list__search .unity-text-field__input {
+ background-color: var(--color-bg-input);
+ border-width: var(--border-width);
+ border-color: var(--color-border);
+ border-radius: var(--radius-s);
+ padding: var(--space-xs) var(--space-m);
+ font-size: var(--font-size-body2);
+ min-height: 28px;
+}
+
+.utk-shortcut-list__search:focus .unity-text-field__input {
+ border-color: var(--color-border-focus);
+}
+
+/* UTKInputField 내부 label 숨김 (placeholder 모드에서 label 없이 사용) */
+.utk-shortcut-list__search .unity-label {
+ display: none;
+ min-width: 0;
+ width: 0;
+ padding: 0;
+}
+
+/* =============================================
+ 컬럼 헤더 행
+ ============================================= */
+
+.utk-shortcut-list__header {
+ flex-direction: row;
+ align-items: center;
+ padding: var(--space-s) var(--space-m);
+ margin-top: var(--space-s);
+ border-bottom-width: 1px;
+ border-color: var(--color-border);
+}
+
+.utk-shortcut-list__header-command {
+ flex-grow: 1;
+ font-size: var(--font-size-body2);
+ color: var(--color-text-secondary);
+ -unity-font-style: bold;
+ overflow: hidden;
+ min-width: 0;
+}
+
+.utk-shortcut-list__header-modifier {
+ width: 52px;
+ flex-shrink: 0;
+ font-size: var(--font-size-body2);
+ color: var(--color-text-secondary);
+ -unity-text-align: middle-center;
+ -unity-font-style: bold;
+}
+
+.utk-shortcut-list__header-key {
+ width: 90px;
+ flex-shrink: 0;
+ font-size: var(--font-size-body2);
+ color: var(--color-text-secondary);
+ -unity-text-align: middle-center;
+ -unity-font-style: bold;
+}
+
+/* =============================================
+ UTKListView 컨테이너
+ ============================================= */
+
+.utk-shortcut-list__listview {
+ flex-grow: 1;
+ background-color: transparent;
+}
+
+/* ListView 자체의 테두리·배경 제거 (디자인 가이드: 패널 배경 사용) */
+.utk-shortcut-list__listview.utk-listview {
+ border-width: 0;
+ border-radius: 0;
+ background-color: transparent;
+}
+
+/* =============================================
+ 아이템 행 컨테이너
+ ============================================= */
+
+.utk-shortcut-list-item {
+ flex-direction: row;
+ align-items: center;
+ padding: 0 var(--space-m);
+ min-height: 36px;
+ flex-grow: 1;
+ border-bottom-width: 1px;
+ border-color: var(--color-border);
+ transition-duration: var(--anim-fast);
+ transition-property: background-color;
+}
+
+.utk-shortcut-list-item:hover {
+ background-color: var(--color-btn-hover);
+}
+
+/* =============================================
+ 아이템 – 명령 이름 레이블
+ ============================================= */
+
+.utk-shortcut-list-item__command {
+ flex-grow: 1;
+ min-width: 0;
+ overflow: hidden;
+}
+
+/* UTKLabel 내부 Label 텍스트 스타일 */
+.utk-shortcut-list-item__command .unity-label {
+ font-size: var(--font-size-body2);
+ color: var(--color-text-primary);
+ -unity-text-align: middle-left;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+/* =============================================
+ 아이템 – 수정자 키 체크박스 (Ctrl / Shift / Alt)
+ ============================================= */
+
+.utk-shortcut-list-item__modifier {
+ width: 52px;
+ flex-shrink: 0;
+ justify-content: center;
+ align-items: center;
+ margin: 0;
+ padding: 0;
+}
+
+/* UTKCheckBox 내부 컨테이너를 중앙 정렬 */
+.utk-shortcut-list-item__modifier .utk-checkbox {
+ justify-content: center;
+ margin: 0;
+}
+
+/* 체크박스 레이블(텍스트) 숨김 – 헤더가 컬럼 레이블 역할을 담당 */
+.utk-shortcut-list-item__modifier .utk-checkbox__label {
+ display: none;
+}
+
+/* =============================================
+ 아이템 – 주요 키 입력 필드
+ ============================================= */
+
+.utk-shortcut-list-item__key {
+ width: 90px;
+ flex-shrink: 0;
+ margin: 0;
+ padding: 0;
+}
+
+/* UTKInputField label 숨김 */
+.utk-shortcut-list-item__key .unity-label {
+ display: none;
+ min-width: 0;
+ width: 0;
+ padding: 0;
+}
+
+/* 텍스트 입력 영역: 키 뱃지 스타일 */
+.utk-shortcut-list-item__key .unity-text-field__input {
+ background-color: var(--color-bg-secondary);
+ border-width: var(--border-width);
+ border-color: var(--color-border);
+ border-radius: var(--radius-s);
+ -unity-text-align: middle-center;
+ font-size: var(--font-size-body2);
+ color: var(--color-text-primary);
+ padding: 0 var(--space-s);
+ min-height: 24px;
+ cursor: link;
+ transition-duration: var(--anim-fast);
+ transition-property: border-color, background-color;
+}
+
+.utk-shortcut-list-item__key .unity-text-field__input:hover {
+ border-color: var(--color-border-focus);
+}
+
+/* 캡처 모드: 키 입력 대기 중 */
+.utk-shortcut-list-item__key--capturing .unity-text-field__input {
+ border-color: var(--color-border-focus);
+ background-color: var(--color-bg-input);
+ color: var(--color-text-secondary);
+}
+
+/* 텍스트 커서(caret) 숨김 – 읽기전용이므로 커서 불필요 */
+.utk-shortcut-list-item__key .unity-text-field__input > TextElement {
+ cursor: link;
+}
diff --git a/Assets/Resources/UIToolkit/List/UTKShortcutListUss.uss.meta b/Assets/Resources/UIToolkit/List/UTKShortcutListUss.uss.meta
new file mode 100644
index 00000000..c71c8d73
--- /dev/null
+++ b/Assets/Resources/UIToolkit/List/UTKShortcutListUss.uss.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a9fafe6cd359d2c4899d36f1fb6ad99a
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
+ disableValidation: 0
diff --git a/Assets/Resources/UIToolkit/Modal/UTKAlert.uss b/Assets/Resources/UIToolkit/Modal/UTKAlert.uss
index 1c63b144..00af26cd 100644
--- a/Assets/Resources/UIToolkit/Modal/UTKAlert.uss
+++ b/Assets/Resources/UIToolkit/Modal/UTKAlert.uss
@@ -69,10 +69,12 @@
justify-content: flex-end;
}
+.utk-alert__buttons .last-child {
+ margin-left: var(--space-s);
+}
+
.utk-alert__btn {
min-width: 80px;
- margin-left: var(--space-s);
- margin-right: var(--space-s);
}
/* ===================================
diff --git a/Assets/Resources/UIToolkit/Modal/UTKModal.uss b/Assets/Resources/UIToolkit/Modal/UTKModal.uss
index d5282c65..64e832fd 100644
--- a/Assets/Resources/UIToolkit/Modal/UTKModal.uss
+++ b/Assets/Resources/UIToolkit/Modal/UTKModal.uss
@@ -33,7 +33,8 @@
}
.utk-modal--large {
- width: 640px;
+ width: 800px;
+ height: 600px;
max-height: 800px;
}
@@ -112,6 +113,14 @@
justify-content: flex-end;
align-items: center;
padding: var(--space-m) var(--space-l);
- border-top-width: var(--border-width);
+ border-top-width: 0;
border-top-color: var(--color-border);
}
+
+.utk-modal__footer--has-children {
+ border-top-width: var(--border-width);
+}
+
+.utk-modal__footer .last-child {
+ margin-left: var(--space-s);
+}
\ No newline at end of file
diff --git a/Assets/Resources/UIToolkit/Modal/UTKNotification.uss b/Assets/Resources/UIToolkit/Modal/UTKNotification.uss
index 5c773a35..3a846328 100644
--- a/Assets/Resources/UIToolkit/Modal/UTKNotification.uss
+++ b/Assets/Resources/UIToolkit/Modal/UTKNotification.uss
@@ -131,3 +131,7 @@
justify-content: flex-end;
margin-top: var(--space-s);
}
+
+.utk-notification__actions .last-child {
+ margin-left: var(--space-s);
+}
\ No newline at end of file
diff --git a/Assets/Resources/UIToolkit/Sample/List/UTKListSample.uss b/Assets/Resources/UIToolkit/Sample/List/UTKListSample.uss
index 79fd825b..476076fc 100644
--- a/Assets/Resources/UIToolkit/Sample/List/UTKListSample.uss
+++ b/Assets/Resources/UIToolkit/Sample/List/UTKListSample.uss
@@ -29,3 +29,8 @@
height: 150px;
width: 200px;
}
+
+.utk-sample-shortcut-list {
+ height: 320px;
+ width: 620px;
+}
diff --git a/Assets/Resources/UIToolkit/Sample/List/UTKShortcutListSample.uxml b/Assets/Resources/UIToolkit/Sample/List/UTKShortcutListSample.uxml
new file mode 100644
index 00000000..ca0ebcc8
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Sample/List/UTKShortcutListSample.uxml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Assets/Resources/UIToolkit/Sample/List/UTKShortcutListSample.uxml.meta b/Assets/Resources/UIToolkit/Sample/List/UTKShortcutListSample.uxml.meta
new file mode 100644
index 00000000..0e3d008f
--- /dev/null
+++ b/Assets/Resources/UIToolkit/Sample/List/UTKShortcutListSample.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: db17838bfbe1351449a155173abfc075
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/Assets/Resources/UIToolkit/Tab/UTKTabView.uss b/Assets/Resources/UIToolkit/Tab/UTKTabView.uss
index e64e7ba6..ac048ded 100644
--- a/Assets/Resources/UIToolkit/Tab/UTKTabView.uss
+++ b/Assets/Resources/UIToolkit/Tab/UTKTabView.uss
@@ -61,6 +61,7 @@
margin-right: var(--space-s);
transition-duration: var(--anim-fast);
transition-property: background-color;
+ align-self: stretch;
}
.utk-tabview .unity-tab__header:hover {
@@ -150,11 +151,13 @@
border-bottom-width: 0;
border-top-width: 0;
border-left-width: 0;
+ flex-grow: 1;
}
.utk-tabview.utk-tabview--align-left .unity-tab__header {
margin-right: 0;
margin-bottom: var(--space-s);
+ position: relative;
}
.utk-tabview.utk-tabview--align-left .unity-tab__header-underline {
@@ -183,6 +186,7 @@
.utk-tabview.utk-tabview--align-right .unity-tab__header {
margin-right: 0;
margin-bottom: var(--space-s);
+ position: relative;
}
.utk-tabview.utk-tabview--align-right .unity-tab__header-underline {
diff --git a/Assets/Sample/UIToolkit/UTKSettingModal.unity b/Assets/Sample/UIToolkit/UTKSettingModal.unity
index e368c5a5..b98575bd 100644
--- a/Assets/Sample/UIToolkit/UTKSettingModal.unity
+++ b/Assets/Sample/UIToolkit/UTKSettingModal.unity
@@ -166,7 +166,7 @@ MonoBehaviour:
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
m_PanelSettings: {fileID: 11400000, guid: 5ad7007b08a97b54d927c352279a18b6, type: 2}
m_ParentUI: {fileID: 0}
- sourceAsset: {fileID: 9197481963319205126, guid: 54e4f33c8b08cb54f97dbdb5edd79e1e, type: 3}
+ sourceAsset: {fileID: 9197481963319205126, guid: 6c8eae7ee21b96245b325f08111b214b, type: 3}
m_SortingOrder: 1
m_Position: 0
m_WorldSpaceSizeMode: 1
@@ -184,9 +184,9 @@ MonoBehaviour:
m_GameObject: {fileID: 1097328750}
m_Enabled: 1
m_EditorHideFlags: 0
- m_Script: {fileID: 11500000, guid: 39265a781c40bdb4a90aa56b0fbf44a6, type: 3}
+ m_Script: {fileID: 11500000, guid: e88ad13f58976fb4a837242a7e1c8282, type: 3}
m_Name:
- m_EditorClassIdentifier: Assembly-CSharp::UVC.Sample.UIToolkit.UTKToolBarSample
+ m_EditorClassIdentifier: Assembly-CSharp::UVC.Sample.UIToolkit.UTKSettingModalSample
_uiDocument: {fileID: 1097328754}
initialTheme: 0
--- !u!1 &1331954412
diff --git a/Assets/Sample/UIToolkit/UTKSettingModalSample.cs b/Assets/Sample/UIToolkit/UTKSettingModalSample.cs
index 6584227b..c56aab5f 100644
--- a/Assets/Sample/UIToolkit/UTKSettingModalSample.cs
+++ b/Assets/Sample/UIToolkit/UTKSettingModalSample.cs
@@ -5,6 +5,7 @@ using UnityEngine.UIElements;
using UVC.UIToolkit;
using UVC.UI.Commands;
using UVC.Log;
+using UVC.Studio.UIToolkit.Modal;
namespace UVC.Sample.UIToolkit
{
@@ -21,6 +22,10 @@ namespace UVC.Sample.UIToolkit
private UTKToggle? _themeToggle;
private VisualElement? _root;
+
+ private UTKButton? _openButton0;
+ private UTKButton? _openButton1;
+ private UTKButton? _openButton2;
private void Start()
{
@@ -33,7 +38,7 @@ namespace UVC.Sample.UIToolkit
}
_uiDocument = doc;
_root = _uiDocument.rootVisualElement;
-
+ UTKModal.SetRoot(_root);
UTKThemeManager.Instance.RegisterRoot(_root);
UTKThemeManager.Instance.SetTheme(initialTheme);
@@ -47,6 +52,39 @@ namespace UVC.Sample.UIToolkit
};
}
+ _openButton0 = _root.Q("openButton0");
+ if (_openButton0 != null) {
+ _openButton0.OnClicked += async () =>
+ {
+ var modal = UTKModal.Create("Settings", UTKModal.ModalSize.Large);
+ var content = new UTKSettingModalContent(0); // 초기 탭 인덱스 설정
+ modal.Add(content);
+ await modal.ShowAsync();
+ };
+ }
+
+ _openButton1 = _root.Q("openButton1");
+ if (_openButton1 != null) {
+ _openButton1.OnClicked += async () =>
+ {
+ var modal = UTKModal.Create("Settings", UTKModal.ModalSize.Large);
+ var content = new UTKSettingModalContent(1); // 초기 탭 인덱스 설정
+ modal.Add(content);
+ await modal.ShowAsync();
+ };
+ }
+
+ _openButton2 = _root.Q("openButton2");
+ if (_openButton2 != null) {
+ _openButton2.OnClicked += async () =>
+ {
+ var modal = UTKModal.Create("Settings", UTKModal.ModalSize.Large);
+ var content = new UTKSettingModalContent(2); // 초기 탭 인덱스 설정
+ modal.Add(content);
+ await modal.ShowAsync();
+ };
+ }
+
}
private void OnDestroy()
diff --git a/Assets/Sample/UIToolkit/UTKSettingModalUXML.uxml b/Assets/Sample/UIToolkit/UTKSettingModalUXML.uxml
index d4b81360..17809125 100644
--- a/Assets/Sample/UIToolkit/UTKSettingModalUXML.uxml
+++ b/Assets/Sample/UIToolkit/UTKSettingModalUXML.uxml
@@ -1,6 +1,8 @@
-
+
+
+
diff --git a/Assets/Sample/UIToolkit/UTKShortcutList.unity b/Assets/Sample/UIToolkit/UTKShortcutList.unity
new file mode 100644
index 00000000..838bfa32
--- /dev/null
+++ b/Assets/Sample/UIToolkit/UTKShortcutList.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: 274352955998a6e478eb57d04c49969b, type: 3}
+ m_SortingOrder: 0
+ 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: 85433d2caa763104f86b4b44ded2fc2d, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: Assembly-CSharp::UTKShortcutListSample
+ 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/UTKShortcutList.unity.meta b/Assets/Sample/UIToolkit/UTKShortcutList.unity.meta
new file mode 100644
index 00000000..e2861b41
--- /dev/null
+++ b/Assets/Sample/UIToolkit/UTKShortcutList.unity.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: f46f8f4e748fbd34ab6be590a5584d89
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Sample/UIToolkit/UTKShortcutListSample.cs b/Assets/Sample/UIToolkit/UTKShortcutListSample.cs
new file mode 100644
index 00000000..c85cf9ab
--- /dev/null
+++ b/Assets/Sample/UIToolkit/UTKShortcutListSample.cs
@@ -0,0 +1,213 @@
+#nullable enable
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UIElements;
+using UVC.UIToolkit;
+
+///
+/// UTKShortcutList의 기능을 테스트하기 위한 샘플 MonoBehaviour입니다.
+///
+/// - Studio 단축키 목록 SetData
+/// - OnDataChanged 이벤트 핸들링
+/// - GetData / 리셋 / 항목 추가 버튼
+/// - 라이트/다크 테마 토글
+///
+///
+public class UTKShortcutListSample : MonoBehaviour
+{
+ [SerializeField]
+ public UIDocument uiDocument;
+
+ [SerializeField]
+ [Tooltip("시작 시 적용할 테마")]
+ private UTKTheme initialTheme = UTKTheme.Dark;
+
+ private UTKToggle? _themeToggle;
+ private UTKShortcutList? _shortcutList;
+
+ // ── 샘플 데이터 원본 (리셋용) ──────────────────────────────────────────
+ private static readonly List DefaultShortcuts = new()
+ {
+ new() { Id = "file.new_project", CommandName = "File > New Project", UseCtrl = true, UseShift = false, UseAlt = false, Key = "N" },
+ new() { Id = "file.open_project", CommandName = "File > Open Project", UseCtrl = true, UseShift = true, UseAlt = false, Key = "O" },
+ new() { Id = "file.save_project", CommandName = "File > Save Project", UseCtrl = true, UseShift = false, UseAlt = true, Key = "S" },
+ new() { Id = "file.save_as", CommandName = "File > Save As...", UseCtrl = true, UseShift = true, UseAlt = true, Key = "S" },
+ new() { Id = "file.insert_database", CommandName = "File > Insert Database", UseCtrl = true, UseShift = true, UseAlt = false, Key = "I" },
+ new() { Id = "file.export_layout", CommandName = "File > Export > Layout", UseCtrl = true, UseShift = true, UseAlt = false, Key = "L" },
+ new() { Id = "file.export_metadata", CommandName = "File > Export > Metadata",UseCtrl = true, UseShift = true, UseAlt = false, Key = "M" },
+ new() { Id = "file.export_gltf", CommandName = "File > Export > glTF", UseCtrl = true, UseShift = true, UseAlt = false, Key = "G" },
+ new() { Id = "edit.undo", CommandName = "Edit > Undo", UseCtrl = true, UseShift = true, UseAlt = false, Key = "Z" },
+ new() { Id = "edit.redo", CommandName = "Edit > Redo", UseCtrl = true, UseShift = true, UseAlt = false, Key = "Y" },
+ new() { Id = "edit.duplicate", CommandName = "Edit > Duplicate", UseCtrl = true, UseShift = true, UseAlt = false, Key = "D" },
+ new() { Id = "edit.delete", CommandName = "Edit > Delete", UseCtrl = false, UseShift = true, UseAlt = false, Key = "Delete" },
+ new() { Id = "create.plane", CommandName = "Create > Plane", UseCtrl = true, UseShift = true, UseAlt = false, Key = "V" },
+ new() { Id = "tool.select", CommandName = "Select Tool", UseCtrl = false, UseShift = false, UseAlt = false, Key = "1" },
+ new() { Id = "tool.move", CommandName = "Move Tool", UseCtrl = false, UseShift = false, UseAlt = false, Key = "2" },
+ new() { Id = "tool.rotate", CommandName = "Rotate Tool", UseCtrl = false, UseShift = false, UseAlt = false, Key = "3" },
+ new() { Id = "tool.scale", CommandName = "Scale Tool", UseCtrl = false, UseShift = false, UseAlt = false, Key = "4" },
+ new() { Id = "view.focus", CommandName = "View > Focus Selected", UseCtrl = false, UseShift = false, UseAlt = false, Key = "F" },
+ new() { Id = "view.toggle_grid", CommandName = "View > Toggle Grid", UseCtrl = false, UseShift = false, UseAlt = false, Key = "G" },
+ new() { Id = "view.toggle_wireframe", CommandName = "View > Toggle Wireframe", UseCtrl = false, UseShift = false, UseAlt = false, Key = "W" },
+ };
+
+ // ─────────────────────────────────────────────────────────────────────────
+
+ private void Start()
+ {
+ // UIDocument 참조
+ var doc = GetComponent();
+ if (doc == null)
+ {
+ Debug.LogError("[UTKShortcutListSample] UIDocument 컴포넌트가 없습니다.");
+ return;
+ }
+ uiDocument = doc;
+
+ var root = uiDocument.rootVisualElement;
+
+ // 테마 토글
+ _themeToggle = root.Q("toggle");
+ if (_themeToggle == null)
+ Debug.LogWarning("[UTKShortcutListSample] UXML에서 UTKToggle(name='toggle')을 찾을 수 없습니다.");
+
+ // ShortcutList
+ _shortcutList = root.Q("shortcut-list");
+ if (_shortcutList == null)
+ {
+ // 이름을 못 찾으면 타입으로 검색
+ _shortcutList = root.Q();
+ }
+ if (_shortcutList == null)
+ {
+ Debug.LogError("[UTKShortcutListSample] UXML에서 UTKShortcutList를 찾을 수 없습니다.");
+ return;
+ }
+
+ // 테마 초기화
+ UTKThemeManager.Instance.RegisterRoot(root);
+ UTKThemeManager.Instance.SetTheme(initialTheme);
+
+ _themeToggle!.OnValueChanged += (isOn) =>
+ {
+ UTKThemeManager.Instance.SetTheme(isOn ? UTKTheme.Light : UTKTheme.Dark);
+ };
+
+ // 이벤트 핸들러
+ _shortcutList.OnDataChanged += OnShortcutDataChanged;
+
+ // 기본 데이터 로드 (DeepCopy 로 원본 보존)
+ LoadDefaultData();
+
+ // 테스트 버튼 생성
+ CreateButtons(root);
+ }
+
+ // ── 이벤트 핸들러 ─────────────────────────────────────────────────────────
+
+ /// 단축키 데이터가 변경될 때 호출됩니다.
+ private void OnShortcutDataChanged(UTKShortcutItemData item)
+ {
+ Debug.Log($"[UTKShortcutListSample] 변경 → id={item.Id} " +
+ $"Ctrl={item.UseCtrl} Shift={item.UseShift} Alt={item.UseAlt} Key={item.Key}");
+ }
+
+ // ── 데이터 관리 ───────────────────────────────────────────────────────────
+
+ /// DefaultShortcuts 의 복사본을 리스트에 로드합니다.
+ private void LoadDefaultData()
+ {
+ var copy = new List(DefaultShortcuts.Count);
+ foreach (var src in DefaultShortcuts)
+ {
+ copy.Add(new UTKShortcutItemData
+ {
+ Id = src.Id,
+ CommandName = src.CommandName,
+ UseCtrl = src.UseCtrl,
+ UseShift = src.UseShift,
+ UseAlt = src.UseAlt,
+ Key = src.Key,
+ });
+ }
+ _shortcutList?.SetData(copy);
+ Debug.Log($"[UTKShortcutListSample] {copy.Count}개 단축키 로드 완료");
+ }
+
+ // ── 테스트 버튼 ───────────────────────────────────────────────────────────
+
+ private void CreateButtons(VisualElement root)
+ {
+ var bar = new VisualElement();
+ bar.style.flexDirection = FlexDirection.Row;
+ bar.style.justifyContent = Justify.Center;
+ bar.style.paddingTop = 8;
+ bar.style.paddingBottom = 8;
+ bar.style.flexWrap = Wrap.Wrap;
+
+ // GetData 버튼: 현재 데이터를 콘솔에 출력
+ var getDataBtn = new UTKButton("GetData", variant: UTKButton.ButtonVariant.Primary);
+ getDataBtn.OnClicked += OnGetDataClicked;
+ getDataBtn.style.marginRight = 4;
+ bar.Add(getDataBtn);
+
+ // 리셋 버튼: 기본값으로 복원
+ var resetBtn = new UTKButton("리셋", variant: UTKButton.ButtonVariant.Normal);
+ resetBtn.OnClicked += LoadDefaultData;
+ resetBtn.style.marginRight = 4;
+ bar.Add(resetBtn);
+
+ // 항목 추가 버튼: 빈 항목 하나 추가
+ var addBtn = new UTKButton("항목 추가", variant: UTKButton.ButtonVariant.OutlinePrimary);
+ addBtn.OnClicked += OnAddItemClicked;
+ bar.Add(addBtn);
+
+ root.Add(bar);
+ }
+
+ /// 현재 최종 데이터를 콘솔에 출력합니다.
+ private void OnGetDataClicked()
+ {
+ if (_shortcutList == null) return;
+
+ var data = _shortcutList.GetData();
+ Debug.Log($"[UTKShortcutListSample] ── GetData ({data.Count}개) ──");
+ foreach (var item in data)
+ {
+ var mods = $"{(item.UseCtrl ? "Ctrl+" : "")}" +
+ $"{(item.UseShift ? "Shift+" : "")}" +
+ $"{(item.UseAlt ? "Alt+" : "")}";
+ Debug.Log($" [{item.Id}] {item.CommandName} → {mods}{item.Key}");
+ }
+ }
+
+ /// 빈 항목을 목록 끝에 추가하고 리스트를 갱신합니다.
+ private void OnAddItemClicked()
+ {
+ if (_shortcutList == null) return;
+
+ var current = _shortcutList.GetData();
+ var newItem = new UTKShortcutItemData
+ {
+ Id = $"custom.{current.Count + 1}",
+ CommandName = $"Custom Command {current.Count + 1}",
+ UseCtrl = false,
+ UseShift = false,
+ UseAlt = false,
+ Key = "",
+ };
+ current.Add(newItem);
+ _shortcutList.SetData(current);
+ Debug.Log($"[UTKShortcutListSample] 항목 추가: {newItem.CommandName}");
+ }
+
+ // ─────────────────────────────────────────────────────────────────────────
+
+ private void OnDestroy()
+ {
+ if (_shortcutList != null)
+ {
+ _shortcutList.OnDataChanged -= OnShortcutDataChanged;
+ _shortcutList.Dispose();
+ }
+ }
+}
diff --git a/Assets/Sample/UIToolkit/UTKShortcutListSample.cs.meta b/Assets/Sample/UIToolkit/UTKShortcutListSample.cs.meta
new file mode 100644
index 00000000..a73e6c9e
--- /dev/null
+++ b/Assets/Sample/UIToolkit/UTKShortcutListSample.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 85433d2caa763104f86b4b44ded2fc2d
diff --git a/Assets/Sample/UIToolkit/UTKShortcutListUXML.uxml b/Assets/Sample/UIToolkit/UTKShortcutListUXML.uxml
new file mode 100644
index 00000000..41754908
--- /dev/null
+++ b/Assets/Sample/UIToolkit/UTKShortcutListUXML.uxml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Assets/Sample/UIToolkit/UTKShortcutListUXML.uxml.meta b/Assets/Sample/UIToolkit/UTKShortcutListUXML.uxml.meta
new file mode 100644
index 00000000..4752d41d
--- /dev/null
+++ b/Assets/Sample/UIToolkit/UTKShortcutListUXML.uxml.meta
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 274352955998a6e478eb57d04c49969b
+ScriptedImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 2
+ userData:
+ assetBundleName:
+ assetBundleVariant:
+ script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
diff --git a/Assets/Sample/UIToolkit/UTKStyleGuideSample.Input.cs b/Assets/Sample/UIToolkit/UTKStyleGuideSample.Input.cs
index 2e8d4dd3..15723163 100644
--- a/Assets/Sample/UIToolkit/UTKStyleGuideSample.Input.cs
+++ b/Assets/Sample/UIToolkit/UTKStyleGuideSample.Input.cs
@@ -102,7 +102,11 @@ input.ErrorMessage = """"; // 오류 제거
// 비활성화 / 읽기 전용
input.IsEnabled = false;
input.isReadOnly = true;
-input.multiline = true;",
+input.multiline = true;
+
+// ── Label Min-Width ──────────────────────────
+// label이 있을 때 .unity-label의 min-width를 설정
+input.LabelMinWidth = 120f; // 120px (-1이면 미설정)",
uxmlCode: @"
@@ -124,6 +128,9 @@ input.multiline = true;",
+
+
+
");
}
@@ -200,7 +207,10 @@ ageField.ClearError();
// 5) 에러 메시지 직접 설정 (Validation 없이, 서버 오류 등)
intField.ErrorMessage = ""서버 오류가 발생했습니다."";
-intField.ErrorMessage = """"; // 오류 제거",
+intField.ErrorMessage = """"; // 오류 제거
+
+// ── Label Min-Width ──────────────────────────
+intField.LabelMinWidth = 120f; // label의 min-width 설정",
uxmlCode: @"
@@ -213,6 +223,9 @@ intField.ErrorMessage = """"; // 오류 제거",
+
+
+
");
}
@@ -276,7 +289,10 @@ sizeField.Validation = () => sizeField.Value >= 0 && sizeField.Value <= 1000000;
bool isValid = sizeField.Validate();
// 3) 에러 수동 해제
-sizeField.ClearError();",
+sizeField.ClearError();
+
+// ── Label Min-Width ──────────────────────────
+longField.LabelMinWidth = 120f; // label의 min-width 설정",
uxmlCode: @"
@@ -289,6 +305,9 @@ sizeField.ClearError();",
+
+
+
");
}
@@ -353,7 +372,10 @@ speedField.Validation = () => speedField.Value >= 0f && speedField.Value <= 100f
bool isValid = speedField.Validate();
// 3) 에러 수동 해제
-speedField.ClearError();",
+speedField.ClearError();
+
+// ── Label Min-Width ──────────────────────────
+floatField.LabelMinWidth = 120f; // label의 min-width 설정",
uxmlCode: @"
@@ -366,6 +388,9 @@ speedField.ClearError();",
+
+
+
");
}
@@ -430,7 +455,10 @@ percentField.Validation = () => percentField.Value >= 0.0 && percentField.Value
bool isValid = percentField.Validate();
// 3) 에러 수동 해제
-percentField.ClearError();",
+percentField.ClearError();
+
+// ── Label Min-Width ──────────────────────────
+doubleField.LabelMinWidth = 120f; // label의 min-width 설정",
uxmlCode: @"
@@ -443,6 +471,9 @@ percentField.ClearError();",
+
+
+
");
}
@@ -695,7 +726,11 @@ dirField.ErrorMessage = ""방향 벡터는 (0,0)이 될 수 없습니다."";
dirField.Validation = () => dirField.Value != Vector2.zero;
bool isValid = dirField.Validate();
-dirField.ClearError();",
+dirField.ClearError();
+
+// ── Label Min-Width ──────────────────────────
+// label이 있을 때 .unity-label의 min-width를 설정
+positionField.LabelMinWidth = 120f; // 120px (-1이면 미설정)",
uxmlCode: @"
@@ -708,6 +743,9 @@ dirField.ClearError();",
+
+
+
");
}
@@ -767,7 +805,11 @@ scaleField.ErrorMessage = ""스케일 벡터는 (0,0,0)이 될 수 없습니다.
scaleField.Validation = () => scaleField.Value != Vector3.zero;
bool isValid = scaleField.Validate();
-scaleField.ClearError();",
+scaleField.ClearError();
+
+// ── Label Min-Width ──────────────────────────
+// label이 있을 때 .unity-label의 min-width를 설정
+positionField.LabelMinWidth = 120f; // 120px (-1이면 미설정)",
uxmlCode: @"
@@ -780,6 +822,9 @@ scaleField.ClearError();",
+
+
+
");
}
@@ -853,7 +898,11 @@ rgbaField.Validation = () =>
};
bool isValid = rgbaField.Validate();
-rgbaField.ClearError();",
+rgbaField.ClearError();
+
+// ── Label Min-Width ──────────────────────────
+// label이 있을 때 .unity-label의 min-width를 설정
+colorField.LabelMinWidth = 120f; // 120px (-1이면 미설정)",
uxmlCode: @"
@@ -866,6 +915,9 @@ rgbaField.ClearError();",
+
+
+
");
}
@@ -927,7 +979,11 @@ viewportField.Validation = () =>
viewportField.Value.width > 0 && viewportField.Value.height > 0;
bool isValid = viewportField.Validate();
-viewportField.ClearError();",
+viewportField.ClearError();
+
+// ── Label Min-Width ──────────────────────────
+// label이 있을 때 .unity-label의 min-width를 설정
+areaField.LabelMinWidth = 120f; // 120px (-1이면 미설정)",
uxmlCode: @"
@@ -940,6 +996,9 @@ viewportField.ClearError();",
+
+
+
");
}
@@ -1009,7 +1068,11 @@ colliderField.Validation = () =>
};
bool isValid = colliderField.Validate();
-colliderField.ClearError();",
+colliderField.ClearError();
+
+// ── Label Min-Width ──────────────────────────
+// label이 있을 때 .unity-label의 min-width를 설정
+boundsField.LabelMinWidth = 120f; // 120px (-1이면 미설정)",
uxmlCode: @"
@@ -1022,6 +1085,9 @@ colliderField.ClearError();",
+
+
+
");
}
diff --git a/Assets/Sample/UIToolkit/UTKStyleGuideSample.List.cs b/Assets/Sample/UIToolkit/UTKStyleGuideSample.List.cs
index da78a3e3..d9811ba3 100644
--- a/Assets/Sample/UIToolkit/UTKStyleGuideSample.List.cs
+++ b/Assets/Sample/UIToolkit/UTKStyleGuideSample.List.cs
@@ -456,6 +456,72 @@ treeView.OnItemSelected += (index) => Debug.Log($""선택된 항목: {index}"");
");
}
+ private void InitializeShortcutListSample(VisualElement root)
+ {
+ var shortcutList = root.Q("shortcut-list-sample");
+ if (shortcutList != null)
+ {
+ shortcutList.SetData(new System.Collections.Generic.List
+ {
+ new() { Id = "file.new_project", CommandName = "File > New Project", UseCtrl = true, UseShift = false, UseAlt = false, Key = "N" },
+ new() { Id = "file.open_project", CommandName = "File > Open Project", UseCtrl = true, UseShift = true, UseAlt = false, Key = "O" },
+ new() { Id = "file.save_project", CommandName = "File > Save Project", UseCtrl = true, UseShift = false, UseAlt = true, Key = "S" },
+ new() { Id = "file.save_as", CommandName = "File > Save As...", UseCtrl = true, UseShift = true, UseAlt = true, Key = "S" },
+ new() { Id = "file.export_layout", CommandName = "File > Export > Layout", UseCtrl = true, UseShift = true, UseAlt = false, Key = "L" },
+ new() { Id = "file.export_gltf", CommandName = "File > Export > glTF", UseCtrl = true, UseShift = true, UseAlt = false, Key = "G" },
+ new() { Id = "edit.undo", CommandName = "Edit > Undo", UseCtrl = true, UseShift = true, UseAlt = false, Key = "Z" },
+ new() { Id = "edit.redo", CommandName = "Edit > Redo", UseCtrl = true, UseShift = true, UseAlt = false, Key = "Y" },
+ new() { Id = "edit.duplicate", CommandName = "Edit > Duplicate", UseCtrl = true, UseShift = true, UseAlt = false, Key = "D" },
+ new() { Id = "edit.delete", CommandName = "Edit > Delete", UseCtrl = false, UseShift = true, UseAlt = false, Key = "Delete" },
+ new() { Id = "create.plane", CommandName = "Create > Plane", UseCtrl = true, UseShift = true, UseAlt = false, Key = "V" },
+ new() { Id = "tool.select", CommandName = "Select Tool", UseCtrl = false, UseShift = false, UseAlt = false, Key = "1" },
+ });
+
+ shortcutList.OnDataChanged += item =>
+ Debug.Log($"[StyleGuide] 단축키 변경: {item.CommandName} → {(item.UseCtrl ? "Ctrl+" : "")}{(item.UseShift ? "Shift+" : "")}{(item.UseAlt ? "Alt+" : "")}{item.Key}");
+ }
+
+ SetCodeSamples(root,
+ csharpCode:
+@"// 데이터 생성
+var data = new List
+{
+ new() { Id = ""file.new"", CommandName = ""File > New Project"", UseCtrl = true, UseShift = false, UseAlt = false, Key = ""N"" },
+ new() { Id = ""edit.undo"", CommandName = ""Edit > Undo"", UseCtrl = true, UseShift = true, UseAlt = false, Key = ""Z"" },
+ new() { Id = ""edit.delete"", CommandName = ""Edit > Delete"", UseCtrl = false, UseShift = true, UseAlt = false, Key = ""Delete"" },
+};
+
+// 리스트 생성 & 데이터 설정
+var list = new UTKShortcutList();
+list.SetData(data);
+
+// 변경 이벤트 (Ctrl/Shift/Alt 체크 또는 Key 캡처 시 발생)
+list.OnDataChanged += item =>
+{
+ Debug.Log($""{item.CommandName}: Ctrl={item.UseCtrl} Key={item.Key}"");
+};
+
+// Key 캡처 방법:
+// 1. Key 필드 클릭 → ""···"" 표시
+// 2. 원하는 키 입력 → 자동 저장
+// 3. Escape → 취소 (이전 값 복원)
+
+// 현재 데이터 가져오기
+var current = list.GetData();
+
+// 업데이트된 데이터 다시 적용
+current[0].Key = ""F1"";
+list.SetData(current);",
+ uxmlCode:
+@"
+
+
+
+
+
+");
+ }
+
private void InitializeScrollViewSample(VisualElement root)
{
// Horizontal scroll
diff --git a/Assets/Sample/UIToolkit/UTKStyleGuideSample.Modal.cs b/Assets/Sample/UIToolkit/UTKStyleGuideSample.Modal.cs
index 5c157189..79f63fdf 100644
--- a/Assets/Sample/UIToolkit/UTKStyleGuideSample.Modal.cs
+++ b/Assets/Sample/UIToolkit/UTKStyleGuideSample.Modal.cs
@@ -430,7 +430,7 @@ for (int i = 0; i < buttons.Length; i++)
var btnFooter = root.Q("btn-modal-footer");
btnFooter?.RegisterCallback(_ =>
{
- var modal = UTKModal.Show("푸터 버튼 모달", UTKModal.ModalSize.Medium);
+ var modal = UTKModal.Create("푸터 버튼 모달", UTKModal.ModalSize.Medium);
modal.Add(new Label("확인 또는 취소를 선택하세요."));
var confirmBtn = new UTKButton("확인") { Variant = UTKButton.ButtonVariant.Primary };
@@ -449,29 +449,33 @@ for (int i = 0; i < buttons.Length; i++)
modal.AddToFooter(cancelBtn);
modal.AddToFooter(confirmBtn);
+ modal.Show();
});
var btnNoClose = root.Q("btn-modal-no-close");
btnNoClose?.RegisterCallback(_ =>
{
- var modal = UTKModal.Show("닫기 버튼 없음", UTKModal.ModalSize.Small);
+ var modal = UTKModal.Create("닫기 버튼 없음", UTKModal.ModalSize.Small);
modal.ShowCloseButton = false;
+ modal.CloseOnBackdropClick = true;
modal.Add(new Label("닫기 버튼이 없습니다.\n배경을 클릭하면 닫힙니다."));
+ modal.Show();
});
var btnNoBackdrop = root.Q("btn-modal-no-backdrop");
btnNoBackdrop?.RegisterCallback(_ =>
{
- var modal = UTKModal.Show("배경 클릭 비활성화", UTKModal.ModalSize.Small);
+ var modal = UTKModal.Create("배경 클릭 비활성화", UTKModal.ModalSize.Small);
modal.CloseOnBackdropClick = false;
modal.Add(new Label("배경을 클릭해도 닫히지 않습니다.\nX 버튼으로만 닫을 수 있습니다."));
+ modal.Show();
});
// Custom Content - Form Modal
var btnForm = root.Q("btn-modal-form");
btnForm?.RegisterCallback(_ =>
{
- var modal = UTKModal.Show("사용자 정보 입력", UTKModal.ModalSize.Medium);
+ var modal = UTKModal.Create("사용자 정보 입력", UTKModal.ModalSize.Medium);
var nameField = new UTKInputField("이름");
var emailField = new UTKInputField("이메일");
@@ -490,6 +494,7 @@ for (int i = 0; i < buttons.Length; i++)
modal.AddToFooter(cancelBtn);
modal.AddToFooter(submitBtn);
+ modal.Show();
});
SetCodeSamples(root,
@@ -500,33 +505,40 @@ UTKModal.SetRoot(rootVisualElement);
// 1. 기본 모달 표시
// ========================================
-var modal = UTKModal.Show(""제목"", UTKModal.ModalSize.Medium);
+var modal = UTKModal.Create(""제목"", UTKModal.ModalSize.Medium);
modal.Add(new Label(""모달 내용""));
// 닫힘 이벤트
modal.OnClosed += () => Debug.Log(""모달 닫힘"");
+// 화면에 표시
+modal.Show();
+
// ========================================
// 2. 모달 크기
// ========================================
// Small
-UTKModal.Show(""Small"", UTKModal.ModalSize.Small);
+var small = UTKModal.Create(""Small"", UTKModal.ModalSize.Small);
+small.Show();
// Medium (기본)
-UTKModal.Show(""Medium"", UTKModal.ModalSize.Medium);
+var medium = UTKModal.Create(""Medium"", UTKModal.ModalSize.Medium);
+medium.Show();
// Large
-UTKModal.Show(""Large"", UTKModal.ModalSize.Large);
+var large = UTKModal.Create(""Large"", UTKModal.ModalSize.Large);
+large.Show();
// FullScreen
-UTKModal.Show(""FullScreen"", UTKModal.ModalSize.FullScreen);
+var full = UTKModal.Create(""FullScreen"", UTKModal.ModalSize.FullScreen);
+full.Show();
// ========================================
// 3. 옵션 설정
// ========================================
-var modal = UTKModal.Show(""설정"");
+var modal = UTKModal.Create(""설정"");
// 닫기 버튼 숨기기
modal.ShowCloseButton = false;
@@ -537,11 +549,14 @@ modal.CloseOnBackdropClick = false;
// 푸터 숨기기
modal.SetFooterVisible(false);
+// 옵션 설정 후 표시
+modal.Show();
+
// ========================================
// 4. 푸터 버튼 추가
// ========================================
-var modal = UTKModal.Show(""확인 모달"");
+var modal = UTKModal.Create(""확인 모달"");
modal.Add(new Label(""정말 삭제하시겠습니까?""));
var confirmBtn = new UTKButton(""삭제"") { Variant = UTKButton.ButtonVariant.Danger };
@@ -556,12 +571,13 @@ cancelBtn.RegisterCallback(_ => modal.Close());
modal.AddToFooter(cancelBtn);
modal.AddToFooter(confirmBtn);
+modal.Show();
// ========================================
// 5. 폼 모달
// ========================================
-var modal = UTKModal.Show(""사용자 정보"");
+var modal = UTKModal.Create(""사용자 정보"");
var nameField = new UTKInputField(""이름"");
var emailField = new UTKInputField(""이메일"");
@@ -575,18 +591,83 @@ submitBtn.RegisterCallback(_ =>
modal.Close();
});
modal.AddToFooter(submitBtn);
+modal.Show();
// ========================================
// 6. 프로그래밍 방식 닫기
// ========================================
-var modal = UTKModal.Show(""타이머 모달"");
+var modal = UTKModal.Create(""타이머 모달"");
modal.Add(new Label(""3초 후 자동으로 닫힙니다.""));
modal.ShowCloseButton = false;
modal.CloseOnBackdropClick = false;
+modal.Show();
// 3초 후 닫기
-modal.schedule.Execute(() => modal.Close()).StartingIn(3000);",
+modal.schedule.Execute(() => modal.Close()).StartingIn(3000);
+
+// ========================================
+// 7. Async/Await 방식 (닫힐 때까지 대기)
+// ========================================
+
+var modal = UTKModal.Create(""설정"");
+modal.Add(new Label(""모달 내용""));
+
+var closeBtn = new UTKButton(""닫기"") { Variant = UTKButton.ButtonVariant.Primary };
+closeBtn.OnClicked += () => modal.Close();
+modal.AddToFooter(closeBtn);
+
+// 모달이 닫힐 때까지 대기
+await modal.ShowAsync();
+Debug.Log(""모달이 닫혔습니다."");
+
+// Async 폼 예시
+var formModal = UTKModal.Create(""사용자 정보"");
+var nameField = new UTKInputField(""이름"");
+formModal.Add(nameField);
+
+var submitBtn = new UTKButton(""제출"") { Variant = UTKButton.ButtonVariant.Primary };
+submitBtn.OnClicked += () => formModal.Close();
+formModal.AddToFooter(submitBtn);
+
+await formModal.ShowAsync();
+Debug.Log($""입력된 이름: {nameField.value}"");
+
+// ========================================
+// 8. IUTKModalContent 결과 반환
+// ========================================
+
+// IUTKModalContent를 구현한 콘텐츠 클래스 정의
+// public class UserFormContent : VisualElement, IUTKModalContent
+// {
+// private UTKInputField _nameField = new(""이름"");
+// private UTKInputField _emailField = new(""이메일"");
+//
+// public UserFormContent()
+// {
+// Add(_nameField);
+// Add(_emailField);
+// }
+//
+// public UserData? GetResult()
+// {
+// return new UserData(_nameField.value, _emailField.value);
+// }
+// }
+
+// 사용
+var modal = UTKModal.Create(""사용자 정보"");
+var form = new UserFormContent();
+modal.Add(form);
+
+var submitBtn = new UTKButton(""제출"") { Variant = UTKButton.ButtonVariant.Primary };
+submitBtn.OnClicked += () => modal.Close();
+modal.AddToFooter(submitBtn);
+
+// Close() 시 자동으로 form.GetResult() 호출
+UserData? result = await modal.ShowAsync();
+if (result != null)
+ Debug.Log($""이름: {result.Name}, 이메일: {result.Email}"");",
uxmlCode: @"
@@ -612,9 +693,10 @@ modal.schedule.Execute(() => modal.Close()).StartingIn(3000);",
{
if (_root == null) return;
- var modal = UTKModal.Show($"{size} Modal", size);
+ var modal = UTKModal.Create($"{size} Modal", size);
modal.Add(new Label($"이것은 {size} 크기의 모달입니다."));
modal.OnClosed += () => Debug.Log($"{size} modal closed");
+ modal.Show();
}
#endregion
diff --git a/Assets/Sample/UIToolkit/UTKStyleGuideSample.cs b/Assets/Sample/UIToolkit/UTKStyleGuideSample.cs
index 3e7affd2..8653b5a3 100644
--- a/Assets/Sample/UIToolkit/UTKStyleGuideSample.cs
+++ b/Assets/Sample/UIToolkit/UTKStyleGuideSample.cs
@@ -88,6 +88,7 @@ public partial class UTKStyleGuideSample : MonoBehaviour
["UTKMultiColumnTreeView"] = "UIToolkit/Sample/List/UTKMultiColumnTreeViewSample",
["UTKFoldout"] = "UIToolkit/Sample/List/UTKFoldoutSample",
["UTKScrollView"] = "UIToolkit/Sample/List/UTKScrollViewSample",
+ ["UTKShortcutList"] = "UIToolkit/Sample/List/UTKShortcutListSample",
// Card
["UTKCard"] = "UIToolkit/Sample/Card/UTKCardSample",
["UTKPanel"] = "UIToolkit/Sample/Card/UTKPanelSample",
@@ -123,7 +124,7 @@ public partial class UTKStyleGuideSample : MonoBehaviour
["Slider"] = new[] { "UTKSlider", "UTKSliderInt", "UTKMinMaxSlider", "UTKProgressBar" },
["Dropdown"] = new[] { "UTKDropdown", "UTKEnumDropDown", "UTKMultiSelectDropdown" },
["Label"] = new[] { "UTKLabel", "UTKHelpBox" },
- ["List"] = new[] { "UTKListView", "UTKTreeView", "UTKMultiColumnListView", "UTKMultiColumnTreeView", "UTKFoldout", "UTKScrollView" },
+ ["List"] = new[] { "UTKListView", "UTKTreeView", "UTKMultiColumnListView", "UTKMultiColumnTreeView", "UTKFoldout", "UTKScrollView", "UTKShortcutList" },
["Card"] = new[] { "UTKCard", "UTKPanel" },
["Tab"] = new[] { "UTKTabView" },
["Modal"] = new[] { "UTKAlert", "UTKToast", "UTKTooltip", "UTKNotification", "UTKModal" },
@@ -527,6 +528,9 @@ public partial class UTKStyleGuideSample : MonoBehaviour
case "UTKScrollView":
InitializeScrollViewSample(root);
break;
+ case "UTKShortcutList":
+ InitializeShortcutListSample(root);
+ break;
// Card
case "UTKCard":
InitializeCardSample(root);
diff --git a/Assets/Scripts/Factory/UIToolkit.meta b/Assets/Scripts/Factory/UIToolkit.meta
new file mode 100644
index 00000000..599a6c22
--- /dev/null
+++ b/Assets/Scripts/Factory/UIToolkit.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: a61045a867dc1e942a2cd33b53f96d50
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/Factory/UIToolkit/Modal.meta b/Assets/Scripts/Factory/UIToolkit/Modal.meta
new file mode 100644
index 00000000..873fdb42
--- /dev/null
+++ b/Assets/Scripts/Factory/UIToolkit/Modal.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7fcce7ee7cafeaf439e7e492d93cc565
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/Studio/UIToolkit.meta b/Assets/Scripts/Studio/UIToolkit.meta
new file mode 100644
index 00000000..e660b99a
--- /dev/null
+++ b/Assets/Scripts/Studio/UIToolkit.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 64f4ac483a97a0f4b84735c007f9fabb
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/Studio/UIToolkit/Modal.meta b/Assets/Scripts/Studio/UIToolkit/Modal.meta
new file mode 100644
index 00000000..6cbc2813
--- /dev/null
+++ b/Assets/Scripts/Studio/UIToolkit/Modal.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 83909bf9f7c75a148b50d4efc03855b4
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/Studio/UIToolkit/Modal/UTKSettingModalContent.cs b/Assets/Scripts/Studio/UIToolkit/Modal/UTKSettingModalContent.cs
new file mode 100644
index 00000000..4244b3c6
--- /dev/null
+++ b/Assets/Scripts/Studio/UIToolkit/Modal/UTKSettingModalContent.cs
@@ -0,0 +1,75 @@
+#nullable enable
+using System;
+using UnityEngine;
+using UnityEngine.UIElements;
+using UVC.UIToolkit;
+
+namespace UVC.Studio.UIToolkit.Modal
+{
+
+ [UxmlElement]
+ public partial class UTKSettingModalContent : VisualElement, IDisposable, IUTKModalContent
/// ]]>
+ /// Label Min-Width 설정:
+ ///
+ /// // label이 있을 때 .unity-label의 min-width를 설정
+ /// var input = new UTKInputField("이름");
+ /// input.LabelMinWidth = 120f; // 120px
+ /// // -1이면 미설정 (기본값)
+ ///
///
[UxmlElement]
public partial class UTKInputField : TextField, IDisposable
@@ -94,6 +104,7 @@ namespace UVC.UIToolkit
private bool _disposed;
private bool _isEnabled = true;
private string _errorMessage = "";
+ private float _labelMinWidth = -1f;
private InputFieldVariant _variant = InputFieldVariant.Default;
private Func? _validation;
private Label? _errorLabel;
@@ -160,6 +171,18 @@ namespace UVC.UIToolkit
}
}
+ /// label이 있을 때 .unity-label의 min-width (px). -1이면 미설정
+ [UxmlAttribute("label-min-width")]
+ public float LabelMinWidth
+ {
+ get => _labelMinWidth;
+ set
+ {
+ _labelMinWidth = value;
+ ApplyLabelMinWidth();
+ }
+ }
+
/// 읽기 전용
public new bool isReadOnly
{
@@ -237,6 +260,9 @@ namespace UVC.UIToolkit
{
AddToClassList("utk-input");
UpdateVariant();
+
+ // label 설정 후 LabelMinWidth 적용
+ schedule.Execute(() => ApplyLabelMinWidth());
}
private void SetupEvents()
@@ -271,6 +297,22 @@ namespace UVC.UIToolkit
{
UTKThemeManager.Instance.ApplyThemeToElement(this);
}
+
+ private void ApplyLabelMinWidth()
+ {
+ if (string.IsNullOrEmpty(label)) return;
+ var labelElement = this.Q