From cfd7573ffec9ea4a2786628c06dbdf9a38b01cb1 Mon Sep 17 00:00:00 2001 From: logonkhi Date: Tue, 16 Dec 2025 20:31:27 +0900 Subject: [PATCH] =?UTF-8?q?Studio=20Setting=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Setting/SettingShortcutTabContent.prefab | 9 ++- .../Gizmos/Skins/DefaultGizmosSkin.asset | 2 +- Assets/Scenes/Studio.unity | 2 +- .../Settings/SettingDatabaseTabContent.cs | 44 ++++++++++- .../Settings/SettingGeneralTabContent.cs | 74 +++++++++++++++++- .../Studio/Modal/Settings/SettingModal.cs | 4 +- .../Settings/SettingShortcutTabContent.cs | 78 ++++++++++++++++++- Assets/Scripts/Studio/StudioSceneMain.cs | 1 + Assets/StreamingAssets/Settings.json | 2 +- 9 files changed, 200 insertions(+), 16 deletions(-) diff --git a/Assets/Resources/Studio/Prefabs/Modal/Setting/SettingShortcutTabContent.prefab b/Assets/Resources/Studio/Prefabs/Modal/Setting/SettingShortcutTabContent.prefab index c9fa3167..d059f82f 100644 --- a/Assets/Resources/Studio/Prefabs/Modal/Setting/SettingShortcutTabContent.prefab +++ b/Assets/Resources/Studio/Prefabs/Modal/Setting/SettingShortcutTabContent.prefab @@ -71,7 +71,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 5, y: 0} + m_AnchoredPosition: {x: 1, y: -2} m_SizeDelta: {x: 280, y: 0} m_Pivot: {x: 0, y: 1} --- !u!114 &1439525333927440954 @@ -173,6 +173,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd2a999fb90a1842bc1b34fc30f49c4, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::UVC.Studio.Modal.Settings.SettingShortcutTabContent + scrollRect: {fileID: 1767596478105099482} labelGroup: {fileID: 1439525333927440954} valueGroup: {fileID: 4763940519200166932} firstLabelTxt: {fileID: 6899382311698274704} @@ -303,7 +304,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 285, y: 0} + m_AnchoredPosition: {x: 281, y: -2} m_SizeDelta: {x: 300, y: 0} m_Pivot: {x: 0, y: 1} --- !u!114 &4763940519200166932 @@ -1307,9 +1308,9 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.HorizontalLayoutGroup m_Padding: - m_Left: 5 + m_Left: 1 m_Right: 0 - m_Top: 0 + m_Top: 2 m_Bottom: 0 m_ChildAlignment: 0 m_Spacing: 0 diff --git a/Assets/Runtime Transform Gizmos (Lite)/Lite/Resources/Gizmos/Skins/DefaultGizmosSkin.asset b/Assets/Runtime Transform Gizmos (Lite)/Lite/Resources/Gizmos/Skins/DefaultGizmosSkin.asset index f2bb6768..5dcd9844 100644 --- a/Assets/Runtime Transform Gizmos (Lite)/Lite/Resources/Gizmos/Skins/DefaultGizmosSkin.asset +++ b/Assets/Runtime Transform Gizmos (Lite)/Lite/Resources/Gizmos/Skins/DefaultGizmosSkin.asset @@ -12,7 +12,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 6eec73d24eb5fde4695987a5dceedb12, type: 3} m_Name: DefaultGizmosSkin m_EditorClassIdentifier: - mGizmoType: 1 + mGizmoType: 0 mInitialized: 1 mGlobalGizmoStyle: mVisible: 1 diff --git a/Assets/Scenes/Studio.unity b/Assets/Scenes/Studio.unity index a74d21a1..6de54e62 100644 --- a/Assets/Scenes/Studio.unity +++ b/Assets/Scenes/Studio.unity @@ -649,7 +649,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 23e3c568776ffe042b2f38278a66f548, type: 3} m_Name: m_EditorClassIdentifier: - mSkin: {fileID: 0} + mSkin: {fileID: 11400000, guid: 5a1d6f55a1eee8943831d025fbb2a974, type: 2} mSortGizmos: 1 --- !u!1 &177094387 GameObject: diff --git a/Assets/Scripts/Studio/Modal/Settings/SettingDatabaseTabContent.cs b/Assets/Scripts/Studio/Modal/Settings/SettingDatabaseTabContent.cs index fa6bee11..850a9d19 100644 --- a/Assets/Scripts/Studio/Modal/Settings/SettingDatabaseTabContent.cs +++ b/Assets/Scripts/Studio/Modal/Settings/SettingDatabaseTabContent.cs @@ -30,22 +30,22 @@ namespace UVC.Studio.Modal.Settings private bool changedValue = false; + // Tab 키 포커스 이동을 위한 InputField 배열 + private TMP_InputField?[] inputFields = null!; + /// /// 탭 콘텐츠에 데이터를 전달합니다. /// /// 전달할 데이터 객체 public async void SetContentData(object? data) { - Debug.Log($"SettingDatabaseTabContent SetContentData: {data} {setting == null}"); - if (setting == null) { + // Start 전에 호출 되서 Injection 완료 대기 후 Setting 인스턴스 획득 await InjectorAppContext.Instance.WaitForInitializationAsync(); setting = InjectorAppContext.Instance.Get(); } - Debug.Log($"SettingDatabaseTabContent SetContentData: {data} {setting == null}"); - if (setting != null) { changedValue = false; @@ -91,9 +91,45 @@ namespace UVC.Studio.Modal.Settings }); } + // Tab 키 포커스 이동을 위한 배열 초기화 + inputFields = new TMP_InputField?[] { ipTxt, portTxt, idTxt, pwTxt }; } } + private void Update() + { + // Tab 키 입력 처리 + if (Input.GetKeyDown(KeyCode.Tab) && inputFields != null) + { + int currentIndex = GetCurrentFocusedIndex(); + if (currentIndex >= 0) + { + int nextIndex = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift) + ? (currentIndex - 1 + inputFields.Length) % inputFields.Length // Shift+Tab: 이전 + : (currentIndex + 1) % inputFields.Length; // Tab: 다음 + + if (inputFields[nextIndex] != null) + { + inputFields[nextIndex]!.Select(); + } + } + } + } + + private int GetCurrentFocusedIndex() + { + if (inputFields == null) return -1; + + for (int i = 0; i < inputFields.Length; i++) + { + if (inputFields[i] != null && inputFields[i]!.isFocused) + { + return i; + } + } + return -1; + } + /// /// 탭 전환 시 데이터가 있는 경우 전달 되는 데이터. SetContentData 이후 호출 됨 /// diff --git a/Assets/Scripts/Studio/Modal/Settings/SettingGeneralTabContent.cs b/Assets/Scripts/Studio/Modal/Settings/SettingGeneralTabContent.cs index b15e5845..c543d020 100644 --- a/Assets/Scripts/Studio/Modal/Settings/SettingGeneralTabContent.cs +++ b/Assets/Scripts/Studio/Modal/Settings/SettingGeneralTabContent.cs @@ -1,5 +1,6 @@ #nullable enable using Cysharp.Threading.Tasks; +using RTGLite; using TMPro; using UnityEngine; using UVC.Core; @@ -31,16 +32,25 @@ namespace UVC.Studio.Modal.Settings private bool changedValue = false; + // Tab 키 포커스 이동을 위한 InputField 배열 + private TMP_InputField?[] inputFields = null!; + + private int autoSaveInterval = -1; + private float gridSize = -1f; + private float snapPosition = -1f; + private float snapRotation = -1f; + private float snapScale = -1f; + /// /// 탭 콘텐츠에 데이터를 전달합니다. /// /// 전달할 데이터 객체 public async void SetContentData(object? data) { - Debug.Log($"SettingGeneralTabContent SetContentData: {data}"); if (setting == null) { + // Start 전에 호출 되서 Injection 완료 대기 후 Setting 인스턴스 획득 await InjectorAppContext.Instance.WaitForInitializationAsync(); setting = InjectorAppContext.Instance.Get(); } @@ -50,6 +60,12 @@ namespace UVC.Studio.Modal.Settings changedValue = false; GeneralSetting general = setting.Data.general; + autoSaveInterval = general.autoSaveInterval; + gridSize = general.gridSize; + snapPosition = general.snapPosition; + snapRotation = general.snapRotation; + snapScale = general.snapScale; + if (autoSaveValueTxt != null) { autoSaveValueTxt.text = general.autoSaveInterval.ToString(); @@ -75,9 +91,55 @@ namespace UVC.Studio.Modal.Settings ScaleSnapValueTxt.text = general.snapScale.ToString(); ScaleSnapValueTxt.onEndEdit.AddListener(onChagedTextScaleSnap); } + + // Tab 키 포커스 이동을 위한 배열 초기화 + inputFields = new TMP_InputField?[] { + autoSaveValueTxt, + gridValueTxt, + positionSnapValueTxt, + RotationSnapValueTxt, + ScaleSnapValueTxt + }; } } + private void Update() + { + // Tab 키 입력 처리 + if (Input.GetKeyDown(KeyCode.Tab) && inputFields != null) + { + int currentIndex = GetCurrentFocusedIndex(); + if (currentIndex >= 0) + { + int nextIndex = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift) + ? (currentIndex - 1 + inputFields.Length) % inputFields.Length // Shift+Tab: 이전 + : (currentIndex + 1) % inputFields.Length; // Tab: 다음 + + if (inputFields[nextIndex] != null) + { + inputFields[nextIndex]!.Select(); + } + } + } + } + + /// + /// 현재 포커스된 InputField의 인덱스를 반환합니다. + /// + private int GetCurrentFocusedIndex() + { + if (inputFields == null) return -1; + + for (int i = 0; i < inputFields.Length; i++) + { + if (inputFields[i] != null && inputFields[i]!.isFocused) + { + return i; + } + } + return -1; + } + private void onChagedTextAutoSave(string value) { if (setting != null && int.TryParse(value, out int intValue)) @@ -93,6 +155,11 @@ namespace UVC.Studio.Modal.Settings { setting.Data.general.gridSize = floatValue; changedValue = true; + + if (setting.Data.general.gridSize != gridSize) + { + RTGrid.get.settings.cellSize = new Vector3(setting.Data.general.gridSize, setting.Data.general.gridSize, setting.Data.general.gridSize); + } } } @@ -149,6 +216,11 @@ namespace UVC.Studio.Modal.Settings Debug.Log($"SettingGeneralTabContent OnCloseAsync: changedValue={changedValue} setting == null:{setting == null}"); + if (setting != null && setting.Data.general.gridSize != gridSize) + { + RTGrid.get.settings.cellSize = new Vector3(setting.Data.general.gridSize, setting.Data.general.gridSize, setting.Data.general.gridSize); + } + if(changedValue && setting != null) { await setting.SaveAsync(); diff --git a/Assets/Scripts/Studio/Modal/Settings/SettingModal.cs b/Assets/Scripts/Studio/Modal/Settings/SettingModal.cs index 7ab3fc9f..3f0a4563 100644 --- a/Assets/Scripts/Studio/Modal/Settings/SettingModal.cs +++ b/Assets/Scripts/Studio/Modal/Settings/SettingModal.cs @@ -65,11 +65,11 @@ namespace UVC.Studio.Modal.Settings if (parts.Length > 0) { //시간차를 계산해 0.5초 후에 탭을 활성화 - UniTask.Delay(500).ContinueWith(() => { + //UniTask.Delay(500).ContinueWith(() => { Debug.Log($"ActivateTab: {parts[0]}"); string tabKey = parts; tabController.ActivateTab(tabKey, content.Message); - }); + //}); } } } diff --git a/Assets/Scripts/Studio/Modal/Settings/SettingShortcutTabContent.cs b/Assets/Scripts/Studio/Modal/Settings/SettingShortcutTabContent.cs index 3c24bc3c..fc68692c 100644 --- a/Assets/Scripts/Studio/Modal/Settings/SettingShortcutTabContent.cs +++ b/Assets/Scripts/Studio/Modal/Settings/SettingShortcutTabContent.cs @@ -12,6 +12,8 @@ namespace UVC.Studio.Modal.Settings { public class SettingShortcutTabContent : MonoBehaviour, ITabContent { + [SerializeField] + private ScrollRect? scrollRect; [SerializeField] private LayoutGroup? labelGroup; @@ -40,10 +42,10 @@ namespace UVC.Studio.Modal.Settings /// 전달할 데이터 객체 public async void SetContentData(object? data) { - Debug.Log($"SettingShortcutTabContent SetContentData: {data}"); if (setting == null) { + // Start 전에 호출 되서 Injection 완료 대기 후 Setting 인스턴스 획득 await InjectorAppContext.Instance.WaitForInitializationAsync(); setting = InjectorAppContext.Instance.Get(); } @@ -71,7 +73,7 @@ namespace UVC.Studio.Modal.Settings { var shortcut = (ShortcutItem?)field.GetValue(group); if (shortcut == null) continue; - if (i == 0) + if (i == 0 && group == shortcuts.menu) { firstLabelTxt!.text = shortcut.label; firstValueTxt!.text = shortcut.key; @@ -128,6 +130,78 @@ namespace UVC.Studio.Modal.Settings } } + private void Update() + { + // Tab 키 입력 처리 + if (Input.GetKeyDown(KeyCode.Tab) && valueTxts.Count > 0) + { + int currentIndex = GetCurrentFocusedIndex(); + if (currentIndex >= 0) + { + int nextIndex = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift) + ? (currentIndex - 1 + valueTxts.Count) % valueTxts.Count // Shift+Tab: 이전 + : (currentIndex + 1) % valueTxts.Count; // Tab: 다음 + + valueTxts[nextIndex].Select(); + ScrollToItem(nextIndex); + } + } + } + + private int GetCurrentFocusedIndex() + { + for (int i = 0; i < valueTxts.Count; i++) + { + if (valueTxts[i] != null && valueTxts[i].isFocused) + { + return i; + } + } + return -1; + } + + /// + /// 해당 인덱스의 항목이 보이도록 스크롤합니다. + /// + private void ScrollToItem(int index) + { + if (scrollRect == null || scrollRect.content == null || index < 0 || index >= valueTxts.Count) + return; + + RectTransform targetRect = valueTxts[index].GetComponent(); + RectTransform contentRect = scrollRect.content; + RectTransform viewportRect = scrollRect.viewport != null ? scrollRect.viewport : scrollRect.GetComponent(); + + // 타겟 항목의 위치 계산 + float contentHeight = contentRect.rect.height; + float viewportHeight = viewportRect.rect.height; + + if (contentHeight <= viewportHeight) return; // 스크롤 필요 없음 + + // 타겟의 로컬 위치 (content 기준) + float targetY = -targetRect.anchoredPosition.y; + float itemHeight = targetRect.rect.height; + + // 현재 스크롤 위치에서 보이는 영역 + float scrollY = contentRect.anchoredPosition.y; + float visibleTop = scrollY; + float visibleBottom = scrollY + viewportHeight; + + // 항목이 보이지 않으면 스크롤 + if (targetY < visibleTop) + { + // 위로 스크롤 + float normalizedPos = targetY / (contentHeight - viewportHeight); + scrollRect.verticalNormalizedPosition = 1f - Mathf.Clamp01(normalizedPos); + } + else if (targetY + itemHeight > visibleBottom) + { + // 아래로 스크롤 + float normalizedPos = (targetY + itemHeight - viewportHeight) / (contentHeight - viewportHeight); + scrollRect.verticalNormalizedPosition = 1f - Mathf.Clamp01(normalizedPos); + } + } + /// /// 탭 전환 시 데이터가 있는 경우 전달 되는 데이터. SetContentData 이후 호출 됨 /// diff --git a/Assets/Scripts/Studio/StudioSceneMain.cs b/Assets/Scripts/Studio/StudioSceneMain.cs index c98acdc7..133ed569 100644 --- a/Assets/Scripts/Studio/StudioSceneMain.cs +++ b/Assets/Scripts/Studio/StudioSceneMain.cs @@ -57,6 +57,7 @@ namespace UVC.Studio var sceneCtx = FindAnyObjectByType(); if (sceneCtx != null) { + // Injection이 완료될 때까지 대기 await sceneCtx.WaitForInitializationAsync(); Initialize(); } diff --git a/Assets/StreamingAssets/Settings.json b/Assets/StreamingAssets/Settings.json index fc872682..0e050b34 100644 --- a/Assets/StreamingAssets/Settings.json +++ b/Assets/StreamingAssets/Settings.json @@ -7,7 +7,7 @@ }, "general": { "autoSaveInterval": 5, - "gridSize": 5.0, + "gridSize": 1.0, "snapPosition": 0.5, "snapRotation": 10.0, "snapScale": 0.5