From df6d3e3b5aa52c87917f34df247e0b4cee83b5f1 Mon Sep 17 00:00:00 2001 From: logonkhi Date: Tue, 10 Feb 2026 20:48:49 +0900 Subject: [PATCH] =?UTF-8?q?UTKProperyItem=20=EC=88=98=EC=A0=95=20=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UIToolkit/Dropdown/UTKDropdownUss.uss | 2 +- .../List/UTKPropertyGroupHeader.uxml | 26 + .../List/UTKPropertyGroupHeader.uxml.meta | 10 + .../UTKFloatDropdownPropertyItemView.uxml | 10 + ...UTKFloatDropdownPropertyItemView.uxml.meta | 10 + .../UTKFloatDropdownPropertyItemViewUss.uss | 56 ++ ...KFloatDropdownPropertyItemViewUss.uss.meta | 11 + .../Views/UTKFloatRangePropertyItemView.uxml | 5 +- .../UTKFloatRangePropertyItemViewUss.uss | 9 + .../UIToolkit/UTKPropertyListWindowSample.cs | 79 ++- .../UVC/UIToolkit/Button/UTKCheckBox.cs | 20 +- .../UVC/UIToolkit/Button/UTKRadioButton.cs | 20 +- .../Scripts/UVC/UIToolkit/Button/UTKToggle.cs | 20 +- .../UIToolkit/Button/UTKToggleButtonGroup.cs | 20 +- Assets/Scripts/UVC/UIToolkit/Card/UTKCard.cs | 20 +- .../UVC/UIToolkit/Common/UTKFoldout.cs | 20 +- .../UVC/UIToolkit/Common/UTKHelpBox.cs | 20 +- .../Scripts/UVC/UIToolkit/Common/UTKImage.cs | 20 +- .../UVC/UIToolkit/Common/UTKScrollView.cs | 20 +- .../UVC/UIToolkit/Dropdown/UTKDropdown.cs | 20 +- .../UVC/UIToolkit/Dropdown/UTKEnumDropDown.cs | 20 +- .../Dropdown/UTKMultiSelectDropdown.cs | 20 +- .../UVC/UIToolkit/Input/UTKBoundsField.cs | 20 +- .../UVC/UIToolkit/Input/UTKDoubleField.cs | 20 +- .../UVC/UIToolkit/Input/UTKFloatField.cs | 20 +- .../UVC/UIToolkit/Input/UTKFloatStepper.cs | 20 +- .../UVC/UIToolkit/Input/UTKInputField.cs | 21 +- .../UVC/UIToolkit/Input/UTKIntStepper.cs | 20 +- .../UVC/UIToolkit/Input/UTKIntegerField.cs | 20 +- .../UVC/UIToolkit/Input/UTKLongField.cs | 20 +- .../UVC/UIToolkit/Input/UTKRectField.cs | 20 +- .../UVC/UIToolkit/Input/UTKVector2Field.cs | 20 +- .../UVC/UIToolkit/Input/UTKVector3Field.cs | 20 +- .../UVC/UIToolkit/Input/UTKVector4Field.cs | 20 +- .../UVC/UIToolkit/List/UTKAccordionList.cs | 20 +- .../UVC/UIToolkit/List/UTKComponentList.cs | 20 +- .../UVC/UIToolkit/List/UTKImageList.cs | 20 +- .../Scripts/UVC/UIToolkit/List/UTKListView.cs | 20 +- .../UIToolkit/List/UTKMultiColumnListView.cs | 20 +- .../UIToolkit/List/UTKMultiColumnTreeView.cs | 20 +- .../UVC/UIToolkit/List/UTKPropertyList.cs | 423 ++++++++++++--- .../Scripts/UVC/UIToolkit/List/UTKTreeView.cs | 20 +- .../Scripts/UVC/UIToolkit/Modal/UTKAlert.cs | 20 +- .../UVC/UIToolkit/Modal/UTKColorPicker.cs | 22 +- .../UVC/UIToolkit/Modal/UTKDatePicker.cs | 23 +- .../Scripts/UVC/UIToolkit/Modal/UTKModal.cs | 20 +- .../UVC/UIToolkit/Modal/UTKNotification.cs | 20 +- .../Scripts/UVC/UIToolkit/Modal/UTKPanel.cs | 20 +- .../Scripts/UVC/UIToolkit/Modal/UTKToast.cs | 20 +- .../Property/Core/IUTKPropertyItem.cs | 5 +- .../Property/Core/UTKPropertyType.cs | 3 + .../Property/Data/UTKFloatDropdownValue.cs | 36 ++ .../Data/UTKFloatDropdownValue.cs.meta | 2 + .../Items/Base/UTKPropertyItemBase.cs | 52 +- .../Property/Items/UTKBoolPropertyItem.cs | 5 +- .../UIToolkit/Property/Items/UTKButtonItem.cs | 7 +- .../Property/Items/UTKColorPropertyItem.cs | 6 +- .../Items/UTKColorStatePropertyItem.cs | 12 +- .../Property/Items/UTKDatePropertyItem.cs | 12 +- .../Items/UTKDateRangePropertyItem.cs | 11 +- .../Property/Items/UTKDateTimePropertyItem.cs | 6 +- .../Items/UTKDateTimeRangePropertyItem.cs | 11 +- .../Property/Items/UTKDropdownPropertyItem.cs | 18 +- .../Property/Items/UTKEnumPropertyItem.cs | 6 +- .../Items/UTKFloatDropdownPropertyItem.cs | 138 +++++ .../UTKFloatDropdownPropertyItem.cs.meta | 2 + .../Property/Items/UTKFloatPropertyItem.cs | 12 +- .../Items/UTKFloatRangePropertyItem.cs | 83 ++- .../Property/Items/UTKIntPropertyItem.cs | 6 +- .../Property/Items/UTKIntRangePropertyItem.cs | 18 +- .../UTKMultiSelectDropdownPropertyItem.cs | 18 +- .../Property/Items/UTKRadioPropertyItem.cs | 11 +- .../Property/Items/UTKStringPropertyItem.cs | 6 +- .../Property/Items/UTKVector2PropertyItem.cs | 6 +- .../Property/Items/UTKVector3PropertyItem.cs | 6 +- .../Property/Views/UTKBoolPropertyItemView.cs | 6 +- .../Property/Views/UTKButtonItemView.cs | 2 + .../Views/UTKColorPropertyItemView.cs | 6 +- .../Views/UTKColorStatePropertyItemView.cs | 6 +- .../Property/Views/UTKDatePropertyItemView.cs | 6 +- .../Views/UTKDateRangePropertyItemView.cs | 6 +- .../Views/UTKDateTimePropertyItemView.cs | 6 +- .../Views/UTKDateTimeRangePropertyItemView.cs | 6 +- .../Views/UTKDropdownPropertyItemView.cs | 6 +- .../Property/Views/UTKEnumPropertyItemView.cs | 6 +- .../Views/UTKFloatDropdownPropertyItemView.cs | 505 ++++++++++++++++++ .../UTKFloatDropdownPropertyItemView.cs.meta | 2 + .../Views/UTKFloatPropertyItemView.cs | 6 +- .../Views/UTKFloatRangePropertyItemView.cs | 258 ++++++++- .../Property/Views/UTKIntPropertyItemView.cs | 6 +- .../Views/UTKIntRangePropertyItemView.cs | 10 +- .../UTKMultiSelectDropdownPropertyItemView.cs | 6 +- .../Property/Views/UTKPropertyItemViewBase.cs | 50 +- .../Views/UTKPropertyItemViewFactory.cs | 46 ++ .../Views/UTKRadioPropertyItemView.cs | 6 +- .../Views/UTKStringPropertyItemView.cs | 6 +- .../Views/UTKVector2PropertyItemView.cs | 6 +- .../Views/UTKVector3PropertyItemView.cs | 6 +- .../UVC/UIToolkit/Slider/UTKMinMaxSlider.cs | 20 +- .../UVC/UIToolkit/Slider/UTKProgressBar.cs | 20 +- .../Scripts/UVC/UIToolkit/Slider/UTKSlider.cs | 20 +- .../UVC/UIToolkit/Slider/UTKSliderInt.cs | 20 +- Assets/Scripts/UVC/UIToolkit/Tab/UTKTab.cs | 20 +- .../Scripts/UVC/UIToolkit/Tab/UTKTabView.cs | 20 +- .../Scripts/UVC/UIToolkit/UTKThemeManager.cs | 40 +- .../Window/UTKAccordionListWindow.cs | 20 +- .../Window/UTKComponentListWindow.cs | 20 +- .../Window/UTKComponentTabListWindow.cs | 20 +- .../UIToolkit/Window/UTKImageListWindow.cs | 20 +- .../UIToolkit/Window/UTKPropertyListWindow.cs | 187 ++++++- .../UVC/UIToolkit/Window/UTKTreeListWindow.cs | 20 +- CLAUDE.md | 20 +- 112 files changed, 2898 insertions(+), 443 deletions(-) create mode 100644 Assets/Resources/UIToolkit/List/UTKPropertyGroupHeader.uxml create mode 100644 Assets/Resources/UIToolkit/List/UTKPropertyGroupHeader.uxml.meta create mode 100644 Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.uxml create mode 100644 Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.uxml.meta create mode 100644 Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemViewUss.uss create mode 100644 Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemViewUss.uss.meta create mode 100644 Assets/Scripts/UVC/UIToolkit/Property/Data/UTKFloatDropdownValue.cs create mode 100644 Assets/Scripts/UVC/UIToolkit/Property/Data/UTKFloatDropdownValue.cs.meta create mode 100644 Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatDropdownPropertyItem.cs create mode 100644 Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatDropdownPropertyItem.cs.meta create mode 100644 Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.cs create mode 100644 Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.cs.meta diff --git a/Assets/Resources/UIToolkit/Dropdown/UTKDropdownUss.uss b/Assets/Resources/UIToolkit/Dropdown/UTKDropdownUss.uss index f9e16a08..8320730d 100644 --- a/Assets/Resources/UIToolkit/Dropdown/UTKDropdownUss.uss +++ b/Assets/Resources/UIToolkit/Dropdown/UTKDropdownUss.uss @@ -37,7 +37,7 @@ flex-direction: row; align-items: center; justify-content: space-between; - min-width: 120px; + min-width: 100px; flex-grow: 1; height: var(--size-input-height); padding-top: 0px; diff --git a/Assets/Resources/UIToolkit/List/UTKPropertyGroupHeader.uxml b/Assets/Resources/UIToolkit/List/UTKPropertyGroupHeader.uxml new file mode 100644 index 00000000..194b3525 --- /dev/null +++ b/Assets/Resources/UIToolkit/List/UTKPropertyGroupHeader.uxml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/Assets/Resources/UIToolkit/List/UTKPropertyGroupHeader.uxml.meta b/Assets/Resources/UIToolkit/List/UTKPropertyGroupHeader.uxml.meta new file mode 100644 index 00000000..8dd99aa6 --- /dev/null +++ b/Assets/Resources/UIToolkit/List/UTKPropertyGroupHeader.uxml.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 25fa8d693a22bc249a06e7590195db6b +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} diff --git a/Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.uxml b/Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.uxml new file mode 100644 index 00000000..d69277ae --- /dev/null +++ b/Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.uxml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.uxml.meta b/Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.uxml.meta new file mode 100644 index 00000000..818fd9c6 --- /dev/null +++ b/Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.uxml.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: d18bd23679149a241aebfeb54061818f +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} diff --git a/Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemViewUss.uss b/Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemViewUss.uss new file mode 100644 index 00000000..d1e6a62c --- /dev/null +++ b/Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemViewUss.uss @@ -0,0 +1,56 @@ +/* + * =================================== + * UTKFloatDropdownPropertyItemView.uss + * Float + Dropdown Composite View + * =================================== + */ + +/* =================================== + Root + =================================== */ + +.utk-property-item-view--float-dropdown .utk-property-item-view__value { + flex-direction: row; + align-items: stretch; +} + +/* =================================== + Float Field + =================================== */ + +.utk-float-dropdown-view__float-field { + flex-grow: 1; + flex-basis: 0; + margin-right: var(--space-xs); +} + +/* =================================== + Float Stepper + =================================== */ + +.utk-float-dropdown-view__stepper { + flex-grow: 1; + flex-basis: 0; + margin-right: var(--space-xs); +} + +/* =================================== + Dropdown + =================================== */ + +.utk-float-dropdown-view__dropdown { + flex-grow: 1; + flex-basis: 0; + margin-left: 4px; + margin-right: 0; +} + +/* =================================== + ReadOnly Field + =================================== */ + +.utk-float-dropdown-view__readonly-field { + flex-grow: 1; + margin-left: 0; + margin-right: 0; +} diff --git a/Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemViewUss.uss.meta b/Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemViewUss.uss.meta new file mode 100644 index 00000000..5dc27770 --- /dev/null +++ b/Assets/Resources/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemViewUss.uss.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cdc7ac16146263844be31b4bb9ef85b4 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 diff --git a/Assets/Resources/UIToolkit/Property/Views/UTKFloatRangePropertyItemView.uxml b/Assets/Resources/UIToolkit/Property/Views/UTKFloatRangePropertyItemView.uxml index 55cb335f..51ce5bbd 100644 --- a/Assets/Resources/UIToolkit/Property/Views/UTKFloatRangePropertyItemView.uxml +++ b/Assets/Resources/UIToolkit/Property/Views/UTKFloatRangePropertyItemView.uxml @@ -1,11 +1,12 @@ - - + + + diff --git a/Assets/Resources/UIToolkit/Property/Views/UTKFloatRangePropertyItemViewUss.uss b/Assets/Resources/UIToolkit/Property/Views/UTKFloatRangePropertyItemViewUss.uss index 087a0079..f4f96407 100644 --- a/Assets/Resources/UIToolkit/Property/Views/UTKFloatRangePropertyItemViewUss.uss +++ b/Assets/Resources/UIToolkit/Property/Views/UTKFloatRangePropertyItemViewUss.uss @@ -9,9 +9,18 @@ .utk-property-item-view--float-range .utk-property-item-view__field { flex-grow: 1; + flex-shrink: 1; + flex-basis: 0; } .utk-property-item-view--float-range .utk-property-item-view__range-separator { margin: 0 8px; -unity-text-align: middle-center; } + +.utk-property-item-view--float-range .utk-property-item-view__stepper { + flex-grow: 1; + flex-shrink: 1; + flex-basis: 0; + margin-left: 0; +} \ No newline at end of file diff --git a/Assets/Sample/UIToolkit/UTKPropertyListWindowSample.cs b/Assets/Sample/UIToolkit/UTKPropertyListWindowSample.cs index 14938f7d..58c43407 100644 --- a/Assets/Sample/UIToolkit/UTKPropertyListWindowSample.cs +++ b/Assets/Sample/UIToolkit/UTKPropertyListWindowSample.cs @@ -80,6 +80,12 @@ namespace UVC.Sample.UIToolkit _propertyWindow.OnPropertyValueChanged += args => { Debug.Log($"Property Changed: {args.PropertyId} {args.PropertyName} ({args.PropertyType}) = {args.NewValue}"); + + // gap_type 변경 시 해당 분포 속성만 표시 + if (args.PropertyId == "gap_type" && args.NewValue is string gapType) + { + UpdateGapVisibility(gapType); + } }; _propertyWindow.OnPropertyClicked += args => @@ -134,14 +140,8 @@ namespace UVC.Sample.UIToolkit // Bool (편집 가능) entries.Add(new UTKBoolPropertyItem("bool", "Bool", true)); - // Bool (ShowLabel = false) - var boolNoLabel = new UTKBoolPropertyItem("bool_no_label", "No Label Bool", false); - boolNoLabel.ShowLabel = false; - entries.Add(boolNoLabel); - // Bool (읽기 전용) - var roBool = new UTKBoolPropertyItem("bool_ro", "Bool (RO)", true); - roBool.IsReadOnly = true; + var roBool = new UTKBoolPropertyItem("bool_ro", "Bool (RO)", true, true); entries.Add(roBool); // Int (편집 가능) @@ -312,13 +312,52 @@ namespace UVC.Sample.UIToolkit // FloatRange (편집 가능) entries.Add(new UTKFloatRangePropertyItem("floatrange", "FloatRange", 1.5f, 8.5f)); - + // FloatRange (읽기 전용) var roFloatRange = new UTKFloatRangePropertyItem("floatrange_ro", "FloatRange (RO)", 2.5f, 7.5f); roFloatRange.IsReadOnly = true; entries.Add(roFloatRange); + // FloatRange Stepper (편집 가능) + entries.Add(new UTKFloatRangePropertyItem("floatrange2", "FloatRange Stepper", 1.5f, 8.5f, stepperStep: 0.5f, stepperMinValue: 0f, stepperMaxValue: 100f, useStepper: true)); + + // FloatRange Stepper (읽기 전용) + entries.Add(new UTKFloatRangePropertyItem("floatrange2_ro", "FloatRange Stepper (RO)", 2.5f, 7.5f, stepperStep: 0.5f, stepperMinValue: 0f, stepperMaxValue: 100f, useStepper: true, isReadOnly: true)); + + // FloatDropdown (FloatField + Dropdown) + entries.Add(new UTKFloatDropdownPropertyItem("floatdropdown1", "FloatDropdown", + 1.5f, new List { "mm", "cm", "m", "km" }, "cm")); + + // FloatDropdown (Stepper + Dropdown) + entries.Add(new UTKFloatDropdownPropertyItem("floatdropdown2", "FloatDropdown Stepper", + 10.0f, new List { "mm", "cm", "m", "km" }, "m", + floatMinValue: 0f, floatMaxValue: 1000f, stepperStep: 0.5f, useStepper: true)); + + // FloatDropdown (읽기 전용) + entries.Add(new UTKFloatDropdownPropertyItem("floatdropdown_ro", "FloatDropdown (RO)", + 5.0f, new List { "mm", "cm", "m", "km" }, "km", isReadOnly: true)); + // ===== Group에 속한 아이템들 ===== + var timeList = new List { "초(sec)", "분(min)", "시간(hour)" }; + var gapGroup = new UTKPropertyGroup("gap", "생산 간격 정책"); + gapGroup.AddItem(new UTKDropdownPropertyItem("gap_type", "간격 타입", + new List { "상수", "정규 분포", "균등 분포", "지수 분포", "삼각 분포" }, "상수", showLabel: false)); + //상수 + gapGroup.AddItem(new UTKFloatDropdownPropertyItem("gap_value", "상수", 1.0f, timeList, "초(sec)")); + //정규 분포 + gapGroup.AddItem(new UTKFloatDropdownPropertyItem("gap_normal_mean", "정규 분포 평균치", 1.0f, timeList, "초(sec)"){ IsVisible = false }); + gapGroup.AddItem(new UTKFloatDropdownPropertyItem("gap_normal_stddev", "정규 분포 표준 편차", 1.0f, timeList, "초(sec)"){ IsVisible = false }); + //균등 분포 + gapGroup.AddItem(new UTKFloatDropdownPropertyItem("gap_uniform_min", "균등 분포 최소값", 1.0f, timeList, "초(sec)"){ IsVisible = false }); + gapGroup.AddItem(new UTKFloatDropdownPropertyItem("gap_uniform_max", "균등 분포 최대값", 1.0f, timeList, "초(sec)"){ IsVisible = false }); + //지수 분포 + gapGroup.AddItem(new UTKFloatDropdownPropertyItem("gap_exponential", "지수 분포 평균치", 1.0f, timeList, "초(sec)"){ IsVisible = false }); + //삼각 분포 + gapGroup.AddItem(new UTKFloatDropdownPropertyItem("gap_triangular_min", "삼각 분포 최소값", 1.0f, timeList, "초(sec)"){ IsVisible = false }); + gapGroup.AddItem(new UTKFloatDropdownPropertyItem("gap_triangular_mode", "삼각 분포 최빈값", 1.0f, timeList, "초(sec)"){ IsVisible = false }); + gapGroup.AddItem(new UTKFloatDropdownPropertyItem("gap_triangular_max", "삼각 분포 최대값", 1.0f, timeList, "초(sec)"){ IsVisible = false }); + entries.Add(gapGroup); + // 기본 속성 그룹 (편집 가능) var basicGroup = new UTKPropertyGroup("basic", "Basic Properties (Editable)"); @@ -549,6 +588,30 @@ namespace UVC.Sample.UIToolkit return entries; } + /// + /// gap_type 값에 따라 해당 분포 속성의 가시성을 전환합니다. + /// + private void UpdateGapVisibility(string gapType) + { + _propertyWindow.SetPropertyVisibilityBatch(new (string, bool)[] + { + // 상수 + ("gap_value", gapType == "상수"), + // 정규 분포 + ("gap_normal_mean", gapType == "정규 분포"), + ("gap_normal_stddev", gapType == "정규 분포"), + // 균등 분포 + ("gap_uniform_min", gapType == "균등 분포"), + ("gap_uniform_max", gapType == "균등 분포"), + // 지수 분포 + ("gap_exponential", gapType == "지수 분포"), + // 삼각 분포 + ("gap_triangular_min", gapType == "삼각 분포"), + ("gap_triangular_mode", gapType == "삼각 분포"), + ("gap_triangular_max", gapType == "삼각 분포"), + }); + } + private void OnDestroy() { _propertyWindow?.Dispose(); diff --git a/Assets/Scripts/UVC/UIToolkit/Button/UTKCheckBox.cs b/Assets/Scripts/UVC/UIToolkit/Button/UTKCheckBox.cs index 0fc98e31..01b3fb56 100644 --- a/Assets/Scripts/UVC/UIToolkit/Button/UTKCheckBox.cs +++ b/Assets/Scripts/UVC/UIToolkit/Button/UTKCheckBox.cs @@ -166,10 +166,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -255,6 +265,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; } #endregion diff --git a/Assets/Scripts/UVC/UIToolkit/Button/UTKRadioButton.cs b/Assets/Scripts/UVC/UIToolkit/Button/UTKRadioButton.cs index 6574a6ae..3dfec2fa 100644 --- a/Assets/Scripts/UVC/UIToolkit/Button/UTKRadioButton.cs +++ b/Assets/Scripts/UVC/UIToolkit/Button/UTKRadioButton.cs @@ -120,10 +120,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -167,6 +177,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnRadioValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/Button/UTKToggle.cs b/Assets/Scripts/UVC/UIToolkit/Button/UTKToggle.cs index 055ad00a..1de5e380 100644 --- a/Assets/Scripts/UVC/UIToolkit/Button/UTKToggle.cs +++ b/Assets/Scripts/UVC/UIToolkit/Button/UTKToggle.cs @@ -143,10 +143,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -219,6 +229,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnToggleValueChanged); UnregisterCallback(OnMouseDown, TrickleDown.TrickleDown); diff --git a/Assets/Scripts/UVC/UIToolkit/Button/UTKToggleButtonGroup.cs b/Assets/Scripts/UVC/UIToolkit/Button/UTKToggleButtonGroup.cs index 1a805d9e..06caba6b 100644 --- a/Assets/Scripts/UVC/UIToolkit/Button/UTKToggleButtonGroup.cs +++ b/Assets/Scripts/UVC/UIToolkit/Button/UTKToggleButtonGroup.cs @@ -104,10 +104,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -156,6 +166,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnSelectionChanged = null; UnregisterCallback>(OnValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/Card/UTKCard.cs b/Assets/Scripts/UVC/UIToolkit/Card/UTKCard.cs index 86f3ec53..334ab43a 100644 --- a/Assets/Scripts/UVC/UIToolkit/Card/UTKCard.cs +++ b/Assets/Scripts/UVC/UIToolkit/Card/UTKCard.cs @@ -277,10 +277,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -412,6 +422,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnClicked = null; } #endregion diff --git a/Assets/Scripts/UVC/UIToolkit/Common/UTKFoldout.cs b/Assets/Scripts/UVC/UIToolkit/Common/UTKFoldout.cs index 73bee5b7..e11a37c4 100644 --- a/Assets/Scripts/UVC/UIToolkit/Common/UTKFoldout.cs +++ b/Assets/Scripts/UVC/UIToolkit/Common/UTKFoldout.cs @@ -132,10 +132,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -158,6 +168,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnFoldoutValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/Common/UTKHelpBox.cs b/Assets/Scripts/UVC/UIToolkit/Common/UTKHelpBox.cs index 5b460052..8c9f65e9 100644 --- a/Assets/Scripts/UVC/UIToolkit/Common/UTKHelpBox.cs +++ b/Assets/Scripts/UVC/UIToolkit/Common/UTKHelpBox.cs @@ -226,10 +226,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -245,6 +255,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Common/UTKImage.cs b/Assets/Scripts/UVC/UIToolkit/Common/UTKImage.cs index 281a90e4..210e94b0 100644 --- a/Assets/Scripts/UVC/UIToolkit/Common/UTKImage.cs +++ b/Assets/Scripts/UVC/UIToolkit/Common/UTKImage.cs @@ -230,10 +230,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -484,6 +494,8 @@ namespace UVC.UIToolkit CleanupExternalTexture(); UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnImageLoaded = null; OnImageFailed = null; } diff --git a/Assets/Scripts/UVC/UIToolkit/Common/UTKScrollView.cs b/Assets/Scripts/UVC/UIToolkit/Common/UTKScrollView.cs index f7c760a2..5b18ec84 100644 --- a/Assets/Scripts/UVC/UIToolkit/Common/UTKScrollView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Common/UTKScrollView.cs @@ -112,10 +112,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -131,6 +141,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Dropdown/UTKDropdown.cs b/Assets/Scripts/UVC/UIToolkit/Dropdown/UTKDropdown.cs index 243dc38a..4705bd84 100644 --- a/Assets/Scripts/UVC/UIToolkit/Dropdown/UTKDropdown.cs +++ b/Assets/Scripts/UVC/UIToolkit/Dropdown/UTKDropdown.cs @@ -293,10 +293,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -568,6 +578,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnSelectionChanged = null; _inputContainer?.UnregisterCallback(OnInputClicked); diff --git a/Assets/Scripts/UVC/UIToolkit/Dropdown/UTKEnumDropDown.cs b/Assets/Scripts/UVC/UIToolkit/Dropdown/UTKEnumDropDown.cs index d75b598a..9ffc1f03 100644 --- a/Assets/Scripts/UVC/UIToolkit/Dropdown/UTKEnumDropDown.cs +++ b/Assets/Scripts/UVC/UIToolkit/Dropdown/UTKEnumDropDown.cs @@ -273,10 +273,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -527,6 +537,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; _inputContainer?.UnregisterCallback(OnInputClicked); diff --git a/Assets/Scripts/UVC/UIToolkit/Dropdown/UTKMultiSelectDropdown.cs b/Assets/Scripts/UVC/UIToolkit/Dropdown/UTKMultiSelectDropdown.cs index b3c61018..461eebe0 100644 --- a/Assets/Scripts/UVC/UIToolkit/Dropdown/UTKMultiSelectDropdown.cs +++ b/Assets/Scripts/UVC/UIToolkit/Dropdown/UTKMultiSelectDropdown.cs @@ -287,10 +287,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -596,6 +606,8 @@ namespace UVC.UIToolkit ClearCheckBoxes(); UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnSelectionChanged = null; _inputContainer?.UnregisterCallback(OnInputClicked); diff --git a/Assets/Scripts/UVC/UIToolkit/Input/UTKBoundsField.cs b/Assets/Scripts/UVC/UIToolkit/Input/UTKBoundsField.cs index 2c07e8b1..9141c05f 100644 --- a/Assets/Scripts/UVC/UIToolkit/Input/UTKBoundsField.cs +++ b/Assets/Scripts/UVC/UIToolkit/Input/UTKBoundsField.cs @@ -243,10 +243,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -302,6 +312,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnFieldValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/Input/UTKDoubleField.cs b/Assets/Scripts/UVC/UIToolkit/Input/UTKDoubleField.cs index 809a1784..00b82d70 100644 --- a/Assets/Scripts/UVC/UIToolkit/Input/UTKDoubleField.cs +++ b/Assets/Scripts/UVC/UIToolkit/Input/UTKDoubleField.cs @@ -138,10 +138,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -164,6 +174,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnFieldValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/Input/UTKFloatField.cs b/Assets/Scripts/UVC/UIToolkit/Input/UTKFloatField.cs index 992b9892..31d9860f 100644 --- a/Assets/Scripts/UVC/UIToolkit/Input/UTKFloatField.cs +++ b/Assets/Scripts/UVC/UIToolkit/Input/UTKFloatField.cs @@ -137,10 +137,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -163,6 +173,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnFieldValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/Input/UTKFloatStepper.cs b/Assets/Scripts/UVC/UIToolkit/Input/UTKFloatStepper.cs index 3a4e4adb..31404332 100644 --- a/Assets/Scripts/UVC/UIToolkit/Input/UTKFloatStepper.cs +++ b/Assets/Scripts/UVC/UIToolkit/Input/UTKFloatStepper.cs @@ -208,12 +208,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } - // 패널에서 분리될 때 이벤트 구독 해제 - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -454,6 +462,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); // 이벤트 콜백 해제 _upButton?.UnregisterCallback(OnUpButtonClick); diff --git a/Assets/Scripts/UVC/UIToolkit/Input/UTKInputField.cs b/Assets/Scripts/UVC/UIToolkit/Input/UTKInputField.cs index f70279bf..e650a9cd 100644 --- a/Assets/Scripts/UVC/UIToolkit/Input/UTKInputField.cs +++ b/Assets/Scripts/UVC/UIToolkit/Input/UTKInputField.cs @@ -224,10 +224,21 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + // 패널에 다시 붙을 때 현재 테마 재적용 + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -304,6 +315,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); UnregisterCallback>(OnTextValueChanged); OnValueChanged = null; OnFocused = null; diff --git a/Assets/Scripts/UVC/UIToolkit/Input/UTKIntStepper.cs b/Assets/Scripts/UVC/UIToolkit/Input/UTKIntStepper.cs index 67806e9d..a4336555 100644 --- a/Assets/Scripts/UVC/UIToolkit/Input/UTKIntStepper.cs +++ b/Assets/Scripts/UVC/UIToolkit/Input/UTKIntStepper.cs @@ -209,12 +209,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } - // 패널에서 분리될 때 이벤트 구독 해제 - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -455,6 +463,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); // 이벤트 콜백 해제 _upButton?.UnregisterCallback(OnUpButtonClick); diff --git a/Assets/Scripts/UVC/UIToolkit/Input/UTKIntegerField.cs b/Assets/Scripts/UVC/UIToolkit/Input/UTKIntegerField.cs index 9f06cc63..aa75396e 100644 --- a/Assets/Scripts/UVC/UIToolkit/Input/UTKIntegerField.cs +++ b/Assets/Scripts/UVC/UIToolkit/Input/UTKIntegerField.cs @@ -136,10 +136,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -162,6 +172,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnFieldValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/Input/UTKLongField.cs b/Assets/Scripts/UVC/UIToolkit/Input/UTKLongField.cs index 283d6c3d..9d1d1562 100644 --- a/Assets/Scripts/UVC/UIToolkit/Input/UTKLongField.cs +++ b/Assets/Scripts/UVC/UIToolkit/Input/UTKLongField.cs @@ -130,10 +130,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -156,6 +166,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnFieldValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/Input/UTKRectField.cs b/Assets/Scripts/UVC/UIToolkit/Input/UTKRectField.cs index f4b065e2..cc9b8f62 100644 --- a/Assets/Scripts/UVC/UIToolkit/Input/UTKRectField.cs +++ b/Assets/Scripts/UVC/UIToolkit/Input/UTKRectField.cs @@ -226,10 +226,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -275,6 +285,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnFieldValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/Input/UTKVector2Field.cs b/Assets/Scripts/UVC/UIToolkit/Input/UTKVector2Field.cs index 9f7aa934..a4433278 100644 --- a/Assets/Scripts/UVC/UIToolkit/Input/UTKVector2Field.cs +++ b/Assets/Scripts/UVC/UIToolkit/Input/UTKVector2Field.cs @@ -203,10 +203,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -250,6 +260,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnFieldValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/Input/UTKVector3Field.cs b/Assets/Scripts/UVC/UIToolkit/Input/UTKVector3Field.cs index a27f83d0..30289fd3 100644 --- a/Assets/Scripts/UVC/UIToolkit/Input/UTKVector3Field.cs +++ b/Assets/Scripts/UVC/UIToolkit/Input/UTKVector3Field.cs @@ -222,10 +222,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -270,6 +280,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnFieldValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/Input/UTKVector4Field.cs b/Assets/Scripts/UVC/UIToolkit/Input/UTKVector4Field.cs index 087ec424..418cf03c 100644 --- a/Assets/Scripts/UVC/UIToolkit/Input/UTKVector4Field.cs +++ b/Assets/Scripts/UVC/UIToolkit/Input/UTKVector4Field.cs @@ -232,10 +232,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -281,6 +291,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnFieldValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/List/UTKAccordionList.cs b/Assets/Scripts/UVC/UIToolkit/List/UTKAccordionList.cs index 45eb8a6e..7280ce7d 100644 --- a/Assets/Scripts/UVC/UIToolkit/List/UTKAccordionList.cs +++ b/Assets/Scripts/UVC/UIToolkit/List/UTKAccordionList.cs @@ -1666,10 +1666,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -1688,6 +1698,8 @@ namespace UVC.UIToolkit // 테마 변경 이벤트 해제 UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); // 이미지 로딩 취소 CancelImageLoading(); diff --git a/Assets/Scripts/UVC/UIToolkit/List/UTKComponentList.cs b/Assets/Scripts/UVC/UIToolkit/List/UTKComponentList.cs index 1ab75553..1da528bd 100644 --- a/Assets/Scripts/UVC/UIToolkit/List/UTKComponentList.cs +++ b/Assets/Scripts/UVC/UIToolkit/List/UTKComponentList.cs @@ -1675,10 +1675,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -1699,6 +1709,8 @@ namespace UVC.UIToolkit // 테마 변경 이벤트 해제 UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); // 검색 필드 이벤트 해제 if (_searchField != null) diff --git a/Assets/Scripts/UVC/UIToolkit/List/UTKImageList.cs b/Assets/Scripts/UVC/UIToolkit/List/UTKImageList.cs index 2d662107..93dd316e 100644 --- a/Assets/Scripts/UVC/UIToolkit/List/UTKImageList.cs +++ b/Assets/Scripts/UVC/UIToolkit/List/UTKImageList.cs @@ -1243,10 +1243,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -1268,6 +1278,8 @@ namespace UVC.UIToolkit // 테마 변경 이벤트 해제 UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); // 이미지 로딩 취소 CancelImageLoading(); diff --git a/Assets/Scripts/UVC/UIToolkit/List/UTKListView.cs b/Assets/Scripts/UVC/UIToolkit/List/UTKListView.cs index 92502219..4b814357 100644 --- a/Assets/Scripts/UVC/UIToolkit/List/UTKListView.cs +++ b/Assets/Scripts/UVC/UIToolkit/List/UTKListView.cs @@ -164,10 +164,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -197,6 +207,8 @@ namespace UVC.UIToolkit selectionChanged -= OnSelectionChanged; itemsChosen -= OnItemsChosen; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnItemSelected = null; OnItemDoubleClicked = null; } diff --git a/Assets/Scripts/UVC/UIToolkit/List/UTKMultiColumnListView.cs b/Assets/Scripts/UVC/UIToolkit/List/UTKMultiColumnListView.cs index 7133ed3a..992f4726 100644 --- a/Assets/Scripts/UVC/UIToolkit/List/UTKMultiColumnListView.cs +++ b/Assets/Scripts/UVC/UIToolkit/List/UTKMultiColumnListView.cs @@ -60,10 +60,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -93,6 +103,8 @@ namespace UVC.UIToolkit selectionChanged -= OnSelectionChanged; itemsChosen -= OnItemsChosen; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnItemSelected = null; OnItemDoubleClicked = null; } diff --git a/Assets/Scripts/UVC/UIToolkit/List/UTKMultiColumnTreeView.cs b/Assets/Scripts/UVC/UIToolkit/List/UTKMultiColumnTreeView.cs index 093962b7..be1ff98e 100644 --- a/Assets/Scripts/UVC/UIToolkit/List/UTKMultiColumnTreeView.cs +++ b/Assets/Scripts/UVC/UIToolkit/List/UTKMultiColumnTreeView.cs @@ -60,10 +60,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -93,6 +103,8 @@ namespace UVC.UIToolkit selectionChanged -= OnSelectionChanged; itemsChosen -= OnItemsChosen; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnItemSelected = null; OnItemDoubleClicked = null; } diff --git a/Assets/Scripts/UVC/UIToolkit/List/UTKPropertyList.cs b/Assets/Scripts/UVC/UIToolkit/List/UTKPropertyList.cs index 85cdf7bf..8618c2f1 100644 --- a/Assets/Scripts/UVC/UIToolkit/List/UTKPropertyList.cs +++ b/Assets/Scripts/UVC/UIToolkit/List/UTKPropertyList.cs @@ -38,6 +38,7 @@ namespace UVC.UIToolkit #region Constants private const string UXML_PATH = "UIToolkit/List/UTKPropertyList"; private const string USS_PATH = "UIToolkit/List/UTKPropertyListUss"; + private const string GROUP_HEADER_UXML_PATH = "UIToolkit/List/UTKPropertyGroupHeader"; #endregion #region Fields @@ -53,6 +54,8 @@ namespace UVC.UIToolkit private int _nextTreeViewId = 1; private string _searchText = string.Empty; + + private static VisualTreeAsset? _groupHeaderUxmlCache; #endregion #region Events @@ -172,10 +175,19 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanel); + RegisterCallback(OnDetachFromPanel); + } + + private void OnAttachToPanel(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + } + + private void OnDetachFromPanel(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -234,12 +246,20 @@ namespace UVC.UIToolkit #endregion #region Public Methods - Group Management + /// + /// 그룹을 추가하고 TreeView를 갱신합니다. + /// + /// 추가할 속성 그룹. public void AddGroup(IUTKPropertyGroup group) { AddGroupInternal(group); RefreshTreeView(); } + /// + /// 지정한 ID의 그룹과 그룹 내 모든 아이템을 제거합니다. + /// + /// 제거할 그룹 ID. public void RemoveGroup(string groupId) { if (_groupIndex.TryGetValue(groupId, out var group)) @@ -259,11 +279,21 @@ namespace UVC.UIToolkit } } + /// + /// 지정한 ID의 그룹을 반환합니다. + /// + /// 조회할 그룹 ID. + /// 그룹 인스턴스 또는 null. public IUTKPropertyGroup? GetGroup(string groupId) { return _groupIndex.TryGetValue(groupId, out var group) ? group : null; } + /// + /// 그룹의 펼침/접힘 상태를 설정합니다. + /// + /// 대상 그룹 ID. + /// true면 펼침, false면 접힘. public void SetGroupExpanded(string groupId, bool expanded) { if (_groupIndex.TryGetValue(groupId, out var group)) @@ -280,6 +310,10 @@ namespace UVC.UIToolkit } } + /// + /// 그룹의 펼침/접힘 상태를 토글합니다. + /// + /// 대상 그룹 ID. public void ToggleGroupExpanded(string groupId) { if (_groupIndex.TryGetValue(groupId, out var group)) @@ -290,12 +324,21 @@ namespace UVC.UIToolkit #endregion #region Public Methods - Property Management + /// + /// 최상위 속성 아이템을 추가하고 TreeView를 갱신합니다. + /// + /// 추가할 속성 아이템. public void AddProperty(IUTKPropertyItem item) { AddPropertyInternal(item); RefreshTreeView(); } + /// + /// 지정한 그룹에 속성 아이템을 추가하고 TreeView를 갱신합니다. + /// + /// 대상 그룹 ID. + /// 추가할 속성 아이템. public void AddPropertyToGroup(string groupId, IUTKPropertyItem item) { if (_groupIndex.TryGetValue(groupId, out var group)) @@ -307,6 +350,11 @@ namespace UVC.UIToolkit } } + /// + /// 지정한 ID의 속성 아이템을 제거하고 TreeView를 갱신합니다. + /// 그룹에 속한 아이템이면 그룹에서도 제거됩니다. + /// + /// 제거할 아이템 ID. public void RemoveProperty(string itemId) { if (_itemIndex.TryGetValue(itemId, out var item)) @@ -328,6 +376,11 @@ namespace UVC.UIToolkit } } + /// + /// 지정한 ID의 속성 아이템을 반환합니다. + /// + /// 조회할 아이템 ID. + /// 아이템 인스턴스 또는 null. public IUTKPropertyItem? GetProperty(string itemId) { return _itemIndex.TryGetValue(itemId, out var item) ? item : null; @@ -335,37 +388,85 @@ namespace UVC.UIToolkit #endregion #region Public Methods - Value Management - public void UpdatePropertyValue(string propertyId, object newValue) + /// + /// 속성 값을 변경합니다. 바인딩된 View에 OnTypedValueChanged 이벤트로 자동 반영됩니다. + /// + /// 대상 속성 ID. + /// 새 값 (타입 변환 자동 시도). + /// true면 값 변경 알림 이벤트 발생. + public void UpdatePropertyValue(string propertyId, object newValue, bool notify = false) { if (_itemIndex.TryGetValue(propertyId, out var item)) { - item.SetValue(newValue); + item.SetValue(newValue, notify); } } - public void SetPropertyValue(string propertyId, object value) + /// + /// 속성 값을 변경합니다. 의 별칭입니다. + /// + /// 대상 속성 ID. + /// 새 값. + /// true면 값 변경 알림 이벤트 발생. + public void SetPropertyValue(string propertyId, object value, bool notify = false) { - UpdatePropertyValue(propertyId, value); + UpdatePropertyValue(propertyId, value, notify); } #endregion #region Public Methods - Visibility & ReadOnly + /// + /// 속성 아이템의 가시성을 변경합니다. TreeView 항목이 추가/제거되므로 Rebuild가 발생합니다. + /// + /// 대상 속성 ID. + /// true면 표시, false면 숨김. public void SetPropertyVisibility(string propertyId, bool visible) { if (_itemIndex.TryGetValue(propertyId, out var item)) { + if (item.IsVisible == visible) return; item.IsVisible = visible; + RefreshTreeViewLight(); } } + /// 여러 속성의 가시성을 일괄 변경합니다. TreeView는 마지막에 한 번만 갱신됩니다. + public void SetPropertyVisibilityBatch(IEnumerable<(string propertyId, bool visible)> changes) + { + bool changed = false; + foreach (var (propertyId, visible) in changes) + { + if (_itemIndex.TryGetValue(propertyId, out var item) && item.IsVisible != visible) + { + item.IsVisible = visible; + changed = true; + } + } + + if (changed) RefreshTreeViewLight(); + } + + /// + /// 그룹의 가시성을 변경합니다. TreeView 항목이 추가/제거되므로 Rebuild가 발생합니다. + /// + /// 대상 그룹 ID. + /// true면 표시, false면 숨김. public void SetGroupVisibility(string groupId, bool visible) { if (_groupIndex.TryGetValue(groupId, out var group)) { + if (group.IsVisible == visible) return; group.IsVisible = visible; + RefreshTreeViewLight(); } } + /// + /// 속성 아이템의 읽기 전용 상태를 변경합니다. + /// OnStateChanged 이벤트를 통해 바인딩된 View에 자동 반영됩니다. + /// + /// 대상 속성 ID. + /// true면 읽기 전용. public void SetPropertyReadOnly(string propertyId, bool isReadOnly) { if (_itemIndex.TryGetValue(propertyId, out var item)) @@ -374,6 +475,12 @@ namespace UVC.UIToolkit } } + /// + /// 그룹 내 모든 아이템의 읽기 전용 상태를 일괄 변경합니다. + /// OnStateChanged 이벤트를 통해 바인딩된 View에 자동 반영됩니다. + /// + /// 대상 그룹 ID. + /// true면 읽기 전용. public void SetGroupReadOnly(string groupId, bool isReadOnly) { if (_groupIndex.TryGetValue(groupId, out var group)) @@ -381,25 +488,48 @@ namespace UVC.UIToolkit group.SetAllItemsReadOnly(isReadOnly); } } + + /// + /// 속성 아이템의 라벨 표시 여부를 변경합니다. + /// OnStateChanged 이벤트를 통해 바인딩된 View에 자동 반영됩니다. + /// + /// 대상 속성 ID. + /// true면 라벨 표시, false면 값이 전체 너비 사용. + public void SetPropertyShowLabel(string propertyId, bool showLabel) + { + if (_itemIndex.TryGetValue(propertyId, out var item)) + { + item.ShowLabel = showLabel; + } + } #endregion #region Public Methods - Utilities - public void Clear() + /// + /// 모든 엔트리(그룹 + 아이템)를 제거하고 TreeView를 초기화합니다. + /// VisualElement.Clear()를 숨깁니다(new). + /// + public new void Clear() { ClearInternal(); RefreshTreeView(); } + /// + /// 현재 데이터를 기반으로 TreeView를 다시 빌드합니다. + /// public void Refresh() { RefreshTreeView(); } + /// 리스트를 표시합니다. public void Show() { style.display = DisplayStyle.Flex; } + /// 리스트를 숨깁니다. public void Hide() { style.display = DisplayStyle.None; @@ -448,7 +578,10 @@ namespace UVC.UIToolkit private void ClearInternal() { - // 이벤트 구독 해제 + // TreeView 내 바인딩된 View의 이벤트 콜백 정리 및 Dispose + CleanupAllTreeViewContainers(); + + // 데이터 이벤트 구독 해제 foreach (var group in _groupIndex.Values) { UnsubscribeGroup(group); @@ -466,6 +599,19 @@ namespace UVC.UIToolkit _nextTreeViewId = 1; } + /// TreeView 내 모든 컨테이너의 콜백과 View를 정리합니다. + private void CleanupAllTreeViewContainers() + { + if (_treeView == null) return; + + _treeView.Query(className: "utk-property-item-container") + .ForEach(container => + { + CleanupContainerCallbacks(container); + DisposeChildren(container); + }); + } + private void RefreshTreeView() { if (_treeView == null) return; @@ -474,7 +620,29 @@ namespace UVC.UIToolkit _treeView.SetRootItems(treeItems); _treeView.Rebuild(); - // 펼침 상태 복원 + RestoreExpandedStates(); + } + + /// + /// 경량 TreeView 갱신. 아이템 구조(Visibility 변경 등)만 바뀔 때 사용합니다. + /// Rebuild() 대신 RefreshItems()를 사용하여 기존 컨테이너를 재활용합니다. + /// + private void RefreshTreeViewLight() + { + if (_treeView == null) return; + + var treeItems = BuildTreeItems(); + _treeView.SetRootItems(treeItems); + _treeView.RefreshItems(); + + RestoreExpandedStates(); + } + + /// 그룹 펼침 상태를 복원합니다. + private void RestoreExpandedStates() + { + if (_treeView == null) return; + foreach (var group in _groupIndex.Values) { if (group.IsExpanded) @@ -545,6 +713,19 @@ namespace UVC.UIToolkit #endregion #region TreeView Callbacks + + /// + /// 컨테이너에 등록된 이벤트 콜백 정보를 보관합니다. + /// View 재사용 시 이전 이벤트를 정리하기 위해 사용합니다. + /// + private sealed class ContainerCallbackInfo + { + public VisualElement? ItemView; + public EventCallback? ClickCallback; + public Action? ButtonClickHandler; + public Action? ActionButtonClickHandler; + } + private VisualElement MakeItem() { var container = new VisualElement(); @@ -557,6 +738,15 @@ namespace UVC.UIToolkit var itemData = _treeView?.GetItemDataForIndex(index); if (itemData == null) return; + // 기존 자식 View 재사용 시도 + if (itemData is IUTKPropertyItem item && TryRebindExistingView(element, item)) + { + return; + } + + // 재사용 불가 시 기존 View 정리 후 새로 생성 + CleanupContainerCallbacks(element); + DisposeChildren(element); element.Clear(); switch (itemData) @@ -564,55 +754,146 @@ namespace UVC.UIToolkit case IUTKPropertyGroup group: BindGroupItem(element, group); break; - case IUTKPropertyItem item: - BindPropertyItem(element, item); + case IUTKPropertyItem newItem: + BindPropertyItem(element, newItem); break; } } private void UnbindItem(VisualElement element, int index) { - // View에서 직접 Unbind 처리 (IUTKPropertyItemView 구현체인 경우) + // Unbind만 수행 (View 인스턴스는 유지하여 재사용 가능) foreach (var child in element.Children()) { if (child is IUTKPropertyItemView view) { view.Unbind(); } + } + } - // IDisposable 구현체인 경우 Dispose 호출 + /// + /// 기존 자식 View가 동일 PropertyType이면 Unbind → Bind로 재사용합니다. + /// 이전 이벤트 콜백을 정리하고 새 item으로 재등록합니다. + /// + /// 재사용 성공 시 true + private bool TryRebindExistingView(VisualElement container, IUTKPropertyItem item) + { + if (container.childCount != 1) return false; + + var existingChild = container[0]; + if (existingChild is not IUTKPropertyItemView existingView) return false; + + // 같은 PropertyType인지 확인 + var expectedViewType = UTKPropertyItemViewFactory.GetViewType(item); + if (existingChild.GetType() != expectedViewType) return false; + + // 이전 이벤트 콜백 정리 + CleanupContainerCallbacks(container); + + // Unbind → Bind (View 인스턴스 재사용) + existingView.Unbind(); + existingView.Bind(item); + + // 새 item에 대한 이벤트 콜백 재등록 + RegisterPropertyCallbacks(container, existingChild, item); + return true; + } + + /// + /// 컨테이너에 저장된 이벤트 콜백을 해제합니다. + /// + private static void CleanupContainerCallbacks(VisualElement container) + { + if (container.userData is not ContainerCallbackInfo info) return; + + if (info.ItemView != null && info.ClickCallback != null) + { + info.ItemView.UnregisterCallback(info.ClickCallback); + } + + if (info.ButtonClickHandler != null && info.ItemView is UTKButtonItemView btnView) + { + btnView.OnButtonClicked -= info.ButtonClickHandler; + } + + if (info.ActionButtonClickHandler != null && info.ItemView is UTKStringPropertyItemView strView) + { + strView.OnActionButtonClicked -= info.ActionButtonClickHandler; + } + + container.userData = null; + } + + /// 자식 View를 Dispose합니다. + private static void DisposeChildren(VisualElement element) + { + foreach (var child in element.Children()) + { + if (child is IUTKPropertyItemView view) + { + view.Unbind(); + } if (child is IDisposable disposable) { disposable.Dispose(); } } - - element.Clear(); } private void BindGroupItem(VisualElement container, IUTKPropertyGroup group) { - var groupElement = new VisualElement(); - groupElement.AddToClassList("utk-property-group__header"); + // UXML 로드 (캐시) + if (_groupHeaderUxmlCache == null) + { + _groupHeaderUxmlCache = Resources.Load(GROUP_HEADER_UXML_PATH); + } - var expandIcon = new UTKLabel(group.IsExpanded ? UTKMaterialIcons.ExpandMore : UTKMaterialIcons.ChevronRight, 16); - expandIcon.AddToClassList("utk-property-group__expand-icon"); + VisualElement groupElement; + UTKLabel expandIcon; + UTKLabel title; + // UTKLabel count; - var title = new UTKLabel(group.GroupName, UTKLabel.LabelSize.Label1); + if (_groupHeaderUxmlCache != null) + { + var root = _groupHeaderUxmlCache.Instantiate(); + groupElement = root.Q("group-header"); + expandIcon = root.Q("expand-icon"); + title = root.Q("group-title"); + // count = root.Q("group-count"); + container.Add(root); + } + else + { + // Fallback: UXML 로드 실패 시 코드로 생성 + groupElement = new VisualElement(); + groupElement.AddToClassList("utk-property-group__header"); + + expandIcon = new UTKLabel(); + expandIcon.AddToClassList("utk-property-group__expand-icon"); + + title = new UTKLabel(); + title.AddToClassList("utk-property-group__title"); + + // count = new UTKLabel(); + // count.AddToClassList("utk-property-group__count"); + + groupElement.Add(expandIcon); + groupElement.Add(title); + // groupElement.Add(count); + container.Add(groupElement); + } + + // 데이터 바인딩 + expandIcon.SetMaterialIcon(group.IsExpanded ? UTKMaterialIcons.ExpandMore : UTKMaterialIcons.ChevronRight, 16); + title.Text = group.GroupName; + title.Size = UTKLabel.LabelSize.Label1; title.IsBold = true; - title.AddToClassList("utk-property-group__title"); + // count.Text = $"({group.ItemCount})"; + // count.Variant = UTKLabel.LabelVariant.Secondary; - var count = new UTKLabel($"({group.ItemCount})", UTKLabel.LabelSize.Caption); - count.Variant = UTKLabel.LabelVariant.Secondary; - count.AddToClassList("utk-property-group__count"); - - groupElement.Add(expandIcon); - groupElement.Add(title); - groupElement.Add(count); - - // 그룹 클릭 이벤트 - DetachFromPanelEvent에서 자동 정리됨 - EventCallback clickCallback = null!; - clickCallback = _ => + // 그룹 클릭 이벤트 - ContainerCallbackInfo로 관리 + EventCallback clickCallback = _ => { ToggleGroupExpanded(group.GroupId); expandIcon.SetMaterialIcon(group.IsExpanded ? UTKMaterialIcons.ExpandMore : UTKMaterialIcons.ChevronRight, 16); @@ -621,63 +902,51 @@ namespace UVC.UIToolkit groupElement.RegisterCallback(clickCallback); - // DetachFromPanelEvent에서 이벤트 해제 - groupElement.RegisterCallback(evt => + // 컨테이너에 콜백 정보 저장 (CleanupContainerCallbacks에서 정리) + container.userData = new ContainerCallbackInfo { - groupElement.UnregisterCallback(clickCallback); - }); - - container.Add(groupElement); + ItemView = groupElement, + ClickCallback = clickCallback + }; } private void BindPropertyItem(VisualElement container, IUTKPropertyItem item) { // View Factory를 사용하여 View 생성 및 바인딩 var itemView = UTKPropertyItemViewFactory.CreateView(item); + container.Add(itemView); - // 클릭 이벤트 등록 - DetachFromPanelEvent에서 자동 정리됨 - EventCallback clickCallback = _ => OnPropertyClicked?.Invoke(item); - itemView.RegisterCallback(clickCallback); + // 이벤트 콜백 등록 및 컨테이너에 저장 + RegisterPropertyCallbacks(container, itemView, item); + } + + /// + /// PropertyItem View에 이벤트 콜백을 등록하고 컨테이너에 정보를 저장합니다. + /// + private void RegisterPropertyCallbacks(VisualElement container, VisualElement itemView, IUTKPropertyItem item) + { + var info = new ContainerCallbackInfo { ItemView = itemView }; + + // 클릭 이벤트 등록 + info.ClickCallback = _ => OnPropertyClicked?.Invoke(item); + itemView.RegisterCallback(info.ClickCallback); // 버튼 아이템인 경우 버튼 클릭 이벤트 구독 - Action? buttonClickHandler = null; if (itemView is UTKButtonItemView buttonView) { - buttonClickHandler = (actionName) => - { - OnPropertyButtonClicked?.Invoke(item.Id, actionName); - }; - buttonView.OnButtonClicked += buttonClickHandler; + info.ButtonClickHandler = actionName => OnPropertyButtonClicked?.Invoke(item.Id, actionName); + buttonView.OnButtonClicked += info.ButtonClickHandler; } // String 아이템에 ActionButton이 있는 경우 이벤트 구독 - Action? actionButtonClickHandler = null; if (itemView is UTKStringPropertyItemView stringView) { - actionButtonClickHandler = (actionName) => - { - OnPropertyButtonClicked?.Invoke(item.Id, actionName); - }; - stringView.OnActionButtonClicked += actionButtonClickHandler; + info.ActionButtonClickHandler = actionName => OnPropertyButtonClicked?.Invoke(item.Id, actionName); + stringView.OnActionButtonClicked += info.ActionButtonClickHandler; } - // DetachFromPanelEvent에서 이벤트 해제 - itemView.RegisterCallback(evt => - { - itemView.UnregisterCallback(clickCallback); - - if (itemView is UTKButtonItemView btnView && buttonClickHandler != null) - { - btnView.OnButtonClicked -= buttonClickHandler; - } - - if (itemView is UTKStringPropertyItemView strView && actionButtonClickHandler != null) - { - strView.OnActionButtonClicked -= actionButtonClickHandler; - } - }); - - container.Add(itemView); + // 컨테이너에 콜백 정보 저장 (재사용/정리 시 참조) + container.userData = info; } #endregion @@ -751,8 +1020,13 @@ namespace UVC.UIToolkit // 테마 변경 이벤트 해제 UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanel); + UnregisterCallback(OnDetachFromPanel); - // TreeView 콜백 정리 + // 데이터 이벤트 해제 + TreeView View 콜백/Dispose 정리 + ClearInternal(); + + // TreeView 콜백 해제 if (_treeView != null) { _treeView.makeItem = null; @@ -772,9 +1046,6 @@ namespace UVC.UIToolkit _clearButton.Dispose(); } - // 이벤트 정리 - ClearInternal(); - // 이벤트 핸들러 정리 OnPropertyValueChanged = null; OnGroupExpandedChanged = null; diff --git a/Assets/Scripts/UVC/UIToolkit/List/UTKTreeView.cs b/Assets/Scripts/UVC/UIToolkit/List/UTKTreeView.cs index 11034862..f31797c3 100644 --- a/Assets/Scripts/UVC/UIToolkit/List/UTKTreeView.cs +++ b/Assets/Scripts/UVC/UIToolkit/List/UTKTreeView.cs @@ -170,10 +170,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -203,6 +213,8 @@ namespace UVC.UIToolkit selectionChanged -= OnSelectionChanged; itemsChosen -= OnItemsChosen; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnItemSelected = null; OnItemDoubleClicked = null; } diff --git a/Assets/Scripts/UVC/UIToolkit/Modal/UTKAlert.cs b/Assets/Scripts/UVC/UIToolkit/Modal/UTKAlert.cs index e11917da..0a3d1286 100644 --- a/Assets/Scripts/UVC/UIToolkit/Modal/UTKAlert.cs +++ b/Assets/Scripts/UVC/UIToolkit/Modal/UTKAlert.cs @@ -503,10 +503,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -641,6 +651,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnClosed = null; OnConfirm = null; OnCancel = null; diff --git a/Assets/Scripts/UVC/UIToolkit/Modal/UTKColorPicker.cs b/Assets/Scripts/UVC/UIToolkit/Modal/UTKColorPicker.cs index 31c88b4d..76614cc0 100644 --- a/Assets/Scripts/UVC/UIToolkit/Modal/UTKColorPicker.cs +++ b/Assets/Scripts/UVC/UIToolkit/Modal/UTKColorPicker.cs @@ -222,12 +222,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } - // 패널에서 분리될 때 이벤트 구독 해제 - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -1190,6 +1198,10 @@ namespace UVC.UIToolkit _hexField?.UnregisterCallback>(OnHexFieldChanged); + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); + OnColorChanged = null; OnColorSelected = null; OnClosed = null; diff --git a/Assets/Scripts/UVC/UIToolkit/Modal/UTKDatePicker.cs b/Assets/Scripts/UVC/UIToolkit/Modal/UTKDatePicker.cs index adb58e01..1f5283ec 100644 --- a/Assets/Scripts/UVC/UIToolkit/Modal/UTKDatePicker.cs +++ b/Assets/Scripts/UVC/UIToolkit/Modal/UTKDatePicker.cs @@ -245,12 +245,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } - // 패널에서 분리될 때 이벤트 구독 해제 - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -1112,6 +1120,11 @@ namespace UVC.UIToolkit if (_disposed) return; _disposed = true; + // 테마 변경 이벤트 구독 해제 + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); + // 언어 변경 이벤트 구독 해제 LocalizationManager.Instance.OnLanguageChanged -= OnLanguageChanged; diff --git a/Assets/Scripts/UVC/UIToolkit/Modal/UTKModal.cs b/Assets/Scripts/UVC/UIToolkit/Modal/UTKModal.cs index 3995ad9b..4aec0c33 100644 --- a/Assets/Scripts/UVC/UIToolkit/Modal/UTKModal.cs +++ b/Assets/Scripts/UVC/UIToolkit/Modal/UTKModal.cs @@ -226,10 +226,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -305,6 +315,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnClosed = null; _blocker = null; } diff --git a/Assets/Scripts/UVC/UIToolkit/Modal/UTKNotification.cs b/Assets/Scripts/UVC/UIToolkit/Modal/UTKNotification.cs index 15651e4a..55a4d18d 100644 --- a/Assets/Scripts/UVC/UIToolkit/Modal/UTKNotification.cs +++ b/Assets/Scripts/UVC/UIToolkit/Modal/UTKNotification.cs @@ -275,10 +275,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -389,6 +399,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnClosed = null; OnActionClicked = null; } diff --git a/Assets/Scripts/UVC/UIToolkit/Modal/UTKPanel.cs b/Assets/Scripts/UVC/UIToolkit/Modal/UTKPanel.cs index 91c0cb16..ad6a16c6 100644 --- a/Assets/Scripts/UVC/UIToolkit/Modal/UTKPanel.cs +++ b/Assets/Scripts/UVC/UIToolkit/Modal/UTKPanel.cs @@ -305,10 +305,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -436,6 +446,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnCollapsedChanged = null; } #endregion diff --git a/Assets/Scripts/UVC/UIToolkit/Modal/UTKToast.cs b/Assets/Scripts/UVC/UIToolkit/Modal/UTKToast.cs index d93f63b7..ad5ab48d 100644 --- a/Assets/Scripts/UVC/UIToolkit/Modal/UTKToast.cs +++ b/Assets/Scripts/UVC/UIToolkit/Modal/UTKToast.cs @@ -340,10 +340,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -396,6 +406,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnClosed = null; } #endregion diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Core/IUTKPropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Core/IUTKPropertyItem.cs index a9353d99..1302eff0 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Core/IUTKPropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Core/IUTKPropertyItem.cs @@ -40,11 +40,14 @@ namespace UVC.UIToolkit /// 값 변경 이벤트 event Action? OnValueChanged; + /// 상태(ReadOnly 등) 변경 이벤트. View가 구독하여 UI를 갱신합니다. + event Action? OnStateChanged; + /// 현재 값을 object로 반환 object? GetValue(); /// 값을 설정 (타입 변환 포함) - void SetValue(object? value); + void SetValue(object? value, bool notifyChangeEvent = false); } /// diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Core/UTKPropertyType.cs b/Assets/Scripts/UVC/UIToolkit/Property/Core/UTKPropertyType.cs index 4526a4cb..54133d57 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Core/UTKPropertyType.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Core/UTKPropertyType.cs @@ -62,6 +62,9 @@ namespace UVC.UIToolkit /// 상태 + 색상 복합 타입 ColorState, + /// 실수 + 드롭다운 복합 타입 + FloatDropdown, + /// 버튼 (액션 트리거) Button } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Data/UTKFloatDropdownValue.cs b/Assets/Scripts/UVC/UIToolkit/Property/Data/UTKFloatDropdownValue.cs new file mode 100644 index 00000000..f70365cf --- /dev/null +++ b/Assets/Scripts/UVC/UIToolkit/Property/Data/UTKFloatDropdownValue.cs @@ -0,0 +1,36 @@ +#nullable enable +using System; +using UnityEngine; + +namespace UVC.UIToolkit +{ + /// + /// Float 값과 Dropdown 선택 문자열을 함께 저장하는 구조체입니다. + /// UTKFloatDropdownPropertyItem의 값 타입으로 사용됩니다. + /// + public struct UTKFloatDropdownValue : IEquatable + { + /// Float 값 + public float FloatValue { get; set; } + + /// Dropdown 선택 값 + public string DropdownValue { get; set; } + + public UTKFloatDropdownValue(float floatValue, string dropdownValue) + { + FloatValue = floatValue; + DropdownValue = dropdownValue ?? ""; + } + + public bool Equals(UTKFloatDropdownValue other) => + Mathf.Approximately(FloatValue, other.FloatValue) && + string.Equals(DropdownValue, other.DropdownValue, StringComparison.Ordinal); + + public override bool Equals(object? obj) => obj is UTKFloatDropdownValue other && Equals(other); + public override int GetHashCode() => HashCode.Combine(FloatValue, DropdownValue); + public override string ToString() => $"{FloatValue}{DropdownValue}";//$"{FloatValue:F2}{DropdownValue}"; + + public static bool operator ==(UTKFloatDropdownValue left, UTKFloatDropdownValue right) => left.Equals(right); + public static bool operator !=(UTKFloatDropdownValue left, UTKFloatDropdownValue right) => !left.Equals(right); + } +} diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Data/UTKFloatDropdownValue.cs.meta b/Assets/Scripts/UVC/UIToolkit/Property/Data/UTKFloatDropdownValue.cs.meta new file mode 100644 index 00000000..b76a6310 --- /dev/null +++ b/Assets/Scripts/UVC/UIToolkit/Property/Data/UTKFloatDropdownValue.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2d41cfdd32cd0484898138be24db75cb \ No newline at end of file diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/Base/UTKPropertyItemBase.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/Base/UTKPropertyItemBase.cs index 6efc55c7..c846bd8f 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/Base/UTKPropertyItemBase.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/Base/UTKPropertyItemBase.cs @@ -26,12 +26,12 @@ namespace UVC.UIToolkit public abstract class UTKPropertyItemBase : IUTKPropertyItem, IDisposable { #region Fields - private T _value; - private bool _isReadOnly; - private bool _isVisible = true; - private bool _showLabel = true; + protected T _value; + protected bool _isReadOnly; + protected bool _isVisible = true; + protected bool _showLabel = true; private string? _description; - private string? _tooltip; + protected string? _tooltip; private string? _groupId; private bool _disposed; #endregion @@ -88,7 +88,12 @@ namespace UVC.UIToolkit public bool IsReadOnly { get => _isReadOnly; - set => _isReadOnly = value; + set + { + if (_isReadOnly == value) return; + _isReadOnly = value; + OnStateChanged?.Invoke(this); + } } /// 표시 여부 @@ -109,7 +114,11 @@ namespace UVC.UIToolkit public bool ShowLabel { get => _showLabel; - set => _showLabel = value; + set{ + if (_showLabel == value) return; + _showLabel = value; + OnStateChanged?.Invoke(this); + } } #endregion @@ -119,6 +128,9 @@ namespace UVC.UIToolkit /// 값 변경 이벤트 (제네릭 타입) public event Action, T, T>? OnTypedValueChanged; + + /// 상태(ReadOnly 등) 변경 이벤트 + public event Action? OnStateChanged; #endregion #region Constructor @@ -141,24 +153,41 @@ namespace UVC.UIToolkit public object? GetValue() => _value; /// 값을 설정합니다 (타입 변환 포함). - public void SetValue(object? value) + public void SetValue(object? value, bool notifyChangeEvent = false) { if (value == null) { if (default(T) == null) { - Value = default!; + if (notifyChangeEvent) + { + Value = default!; + } + else + { + _value = default!; + } } } else if (value is T typedValue) { - Value = typedValue; + if (notifyChangeEvent) + { + Value = typedValue; + } + else + { + _value = typedValue; + } } else { try { - Value = (T)Convert.ChangeType(value, typeof(T)); + if (notifyChangeEvent) + Value = (T)Convert.ChangeType(value, typeof(T)); + else + _value = (T)Convert.ChangeType(value, typeof(T)); } catch (Exception ex) { @@ -195,6 +224,7 @@ namespace UVC.UIToolkit { OnValueChanged = null; OnTypedValueChanged = null; + OnStateChanged = null; } } #endregion diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKBoolPropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKBoolPropertyItem.cs index 407a1045..0cb3ed95 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKBoolPropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKBoolPropertyItem.cs @@ -21,10 +21,11 @@ namespace UVC.UIToolkit /// 표시 이름 /// 초기 값 /// 읽기 전용 여부 - public UTKBoolPropertyItem(string id, string name, bool initialValue = false, bool isReadOnly = false) + public UTKBoolPropertyItem(string id, string name, bool initialValue = false, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue) { - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKButtonItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKButtonItem.cs index e9e2989e..f37ee9c3 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKButtonItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKButtonItem.cs @@ -37,9 +37,6 @@ namespace UVC.UIToolkit /// 아이콘만 표시 모드 public bool IconOnly { get; set; } - /// 라벨 표시 여부 (false면 버튼이 전체 너비 사용) - public bool ShowLabel { get; set; } - /// 액션 이름 (버튼 클릭 시 전달되는 고유 이름) public string ActionName { get; } #endregion @@ -72,7 +69,7 @@ namespace UVC.UIToolkit BackgroundColor = null; BorderWidth = -1; IconOnly = false; - ShowLabel = true; // 기본적으로 라벨 표시 + _showLabel = true; // 기본적으로 라벨 표시 } /// @@ -112,7 +109,7 @@ namespace UVC.UIToolkit BackgroundColor = backgroundColor; BorderWidth = borderWidth; IconOnly = iconOnly; - ShowLabel = showLabel; + _showLabel = showLabel; } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKColorPropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKColorPropertyItem.cs index 9b484aad..12d38af3 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKColorPropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKColorPropertyItem.cs @@ -34,11 +34,13 @@ namespace UVC.UIToolkit /// 초기 값 /// 알파 채널 사용 여부 /// 읽기 전용 여부 - public UTKColorPropertyItem(string id, string name, Color initialValue = default, bool useAlpha = false, bool isReadOnly = false) + /// 레이블 표시 여부 + public UTKColorPropertyItem(string id, string name, Color initialValue = default, bool useAlpha = false, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue) { _useAlpha = useAlpha; - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKColorStatePropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKColorStatePropertyItem.cs index 08951ff4..1fed55af 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKColorStatePropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKColorStatePropertyItem.cs @@ -22,10 +22,12 @@ namespace UVC.UIToolkit /// 표시 이름 /// 초기 값 /// 읽기 전용 여부 - public UTKColorStatePropertyItem(string id, string name, UTKColorState initialValue = default, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKColorStatePropertyItem(string id, string name, UTKColorState initialValue = default, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue) { - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } /// @@ -36,10 +38,12 @@ namespace UVC.UIToolkit /// 상태 텍스트 /// 색상 /// 읽기 전용 여부 - public UTKColorStatePropertyItem(string id, string name, string state, Color color, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKColorStatePropertyItem(string id, string name, string state, Color color, bool isReadOnly = false, bool showLabel = true) : base(id, name, new UTKColorState(state, color)) { - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDatePropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDatePropertyItem.cs index f4efd824..5c9536a0 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDatePropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDatePropertyItem.cs @@ -49,12 +49,14 @@ namespace UVC.UIToolkit /// 표시 이름 /// 초기 값 (default이면 오늘 날짜) /// 읽기 전용 여부 - public UTKDatePropertyItem(string id, string name, DateTime initialValue = default, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKDatePropertyItem(string id, string name, DateTime initialValue = default, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue == default ? DateTime.Today : initialValue) { _minDay = DateTime.MinValue; _maxDay = DateTime.MaxValue; - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } /// @@ -66,12 +68,14 @@ namespace UVC.UIToolkit /// 최소 날짜 (null이면 제한 없음) /// 최대 날짜 (null이면 제한 없음) /// 읽기 전용 여부 - public UTKDatePropertyItem(string id, string name, DateTime initialValue, DateTime? minDay, DateTime? maxDay, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKDatePropertyItem(string id, string name, DateTime initialValue, DateTime? minDay, DateTime? maxDay, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue == default ? DateTime.Today : initialValue) { _minDay = minDay ?? DateTime.MinValue; _maxDay = maxDay ?? DateTime.MaxValue; - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDateRangePropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDateRangePropertyItem.cs index 060ac75b..324b3c0f 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDateRangePropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDateRangePropertyItem.cs @@ -33,10 +33,12 @@ namespace UVC.UIToolkit /// 표시 이름 /// 초기 범위 값 /// 읽기 전용 여부 - public UTKDateRangePropertyItem(string id, string name, UTKDateRange initialValue = default, bool isReadOnly = false) + /// 레이블 표시 여부 + public UTKDateRangePropertyItem(string id, string name, UTKDateRange initialValue = default, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue.Start == default ? new UTKDateRange(DateTime.Today, DateTime.Today) : initialValue) { - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } /// @@ -47,10 +49,11 @@ namespace UVC.UIToolkit /// 시작 날짜 /// 종료 날짜 /// 읽기 전용 여부 - public UTKDateRangePropertyItem(string id, string name, DateTime start, DateTime end, bool isReadOnly = false) + public UTKDateRangePropertyItem(string id, string name, DateTime start, DateTime end, bool isReadOnly = false, bool showLabel = true) : base(id, name, new UTKDateRange(start, end)) { - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDateTimePropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDateTimePropertyItem.cs index cffca168..9d5255ce 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDateTimePropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDateTimePropertyItem.cs @@ -33,10 +33,12 @@ namespace UVC.UIToolkit /// 표시 이름 /// 초기 값 (default이면 현재 시간) /// 읽기 전용 여부 - public UTKDateTimePropertyItem(string id, string name, DateTime initialValue = default, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKDateTimePropertyItem(string id, string name, DateTime initialValue = default, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue == default ? DateTime.Now : initialValue) { - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDateTimeRangePropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDateTimeRangePropertyItem.cs index 8b42997f..ff0652b7 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDateTimeRangePropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDateTimeRangePropertyItem.cs @@ -33,10 +33,12 @@ namespace UVC.UIToolkit /// 표시 이름 /// 초기 범위 값 /// 읽기 전용 여부 - public UTKDateTimeRangePropertyItem(string id, string name, UTKDateTimeRange initialValue = default, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKDateTimeRangePropertyItem(string id, string name, UTKDateTimeRange initialValue = default, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue.Start == default ? new UTKDateTimeRange(DateTime.Now, DateTime.Now) : initialValue) { - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } /// @@ -47,10 +49,11 @@ namespace UVC.UIToolkit /// 시작 날짜시간 /// 종료 날짜시간 /// 읽기 전용 여부 - public UTKDateTimeRangePropertyItem(string id, string name, DateTime start, DateTime end, bool isReadOnly = false) + public UTKDateTimeRangePropertyItem(string id, string name, DateTime start, DateTime end, bool isReadOnly = false, bool showLabel = true) : base(id, name, new UTKDateTimeRange(start, end)) { - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDropdownPropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDropdownPropertyItem.cs index 586108b3..8eaa1370 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDropdownPropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDropdownPropertyItem.cs @@ -35,7 +35,8 @@ namespace UVC.UIToolkit /// 선택 항목 목록 /// 초기 선택 값 /// 읽기 전용 여부 - public UTKDropdownPropertyItem(string id, string name, List choices, string initialValue = "", bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKDropdownPropertyItem(string id, string name, List choices, string initialValue = "", bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue) { _choices = choices ?? new List(); @@ -43,9 +44,10 @@ namespace UVC.UIToolkit // initialValue가 choices에 없으면 첫 번째 항목 선택 if (!string.IsNullOrEmpty(initialValue) && !_choices.Contains(initialValue) && _choices.Count > 0) { - Value = _choices[0]; + _value = _choices[0]; } - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } /// @@ -56,20 +58,22 @@ namespace UVC.UIToolkit /// 선택 항목 목록 /// 초기 선택 인덱스 /// 읽기 전용 여부 - public UTKDropdownPropertyItem(string id, string name, IEnumerable choices, int selectedIndex = 0, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKDropdownPropertyItem(string id, string name, IEnumerable choices, int selectedIndex = 0, bool isReadOnly = false, bool showLabel = true) : base(id, name, string.Empty) { _choices = choices?.ToList() ?? new List(); if (_choices.Count > 0 && selectedIndex >= 0 && selectedIndex < _choices.Count) { - Value = _choices[selectedIndex]; + _value = _choices[selectedIndex]; } else if (_choices.Count > 0) { - Value = _choices[0]; + _value = _choices[0]; } - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKEnumPropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKEnumPropertyItem.cs index 4d390ebc..0f79b0df 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKEnumPropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKEnumPropertyItem.cs @@ -29,11 +29,13 @@ namespace UVC.UIToolkit /// 표시 이름 /// 초기 값 (열거형 타입 추론에 사용) /// 읽기 전용 여부 - public UTKEnumPropertyItem(string id, string name, Enum initialValue, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKEnumPropertyItem(string id, string name, Enum initialValue, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue ?? throw new ArgumentNullException(nameof(initialValue))) { _enumType = initialValue.GetType(); - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatDropdownPropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatDropdownPropertyItem.cs new file mode 100644 index 00000000..ae3a7d43 --- /dev/null +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatDropdownPropertyItem.cs @@ -0,0 +1,138 @@ +#nullable enable +using System.Collections.Generic; + +namespace UVC.UIToolkit +{ + /// + /// Float + Dropdown 복합 속성 데이터 클래스입니다. + /// Float 값(또는 Stepper)과 Dropdown 선택을 하나의 행에 표시합니다. + /// UI는 UTKFloatDropdownPropertyItemView에서 담당합니다. + /// + public class UTKFloatDropdownPropertyItem : UTKPropertyItemBase + { + #region Fields + private List _choices; + private bool _useStepper; + private float _floatMinValue = float.MinValue; + private float _floatMaxValue = float.MaxValue; + private float _stepperStep = 1.0f; + #endregion + + #region Properties + /// 속성 타입 + public override UTKPropertyType PropertyType => UTKPropertyType.FloatDropdown; + + /// Dropdown 선택 목록 + public List Choices => _choices; + + /// 스테퍼(증감 버튼) 사용 여부. false이면 UTKFloatField 사용 + public bool UseStepper + { + get => _useStepper; + set => _useStepper = value; + } + + /// Float 최소값 + public float FloatMinValue + { + get => _floatMinValue; + set => _floatMinValue = value; + } + + /// Float 최대값 + public float FloatMaxValue + { + get => _floatMaxValue; + set => _floatMaxValue = value; + } + + /// 스테퍼 증감 단위 (기본값: 1.0) + public float StepperStep + { + get => _stepperStep; + set => _stepperStep = value > 0 ? value : 1.0f; + } + #endregion + + #region Constructor + /// + /// Float + Dropdown 복합 속성을 생성합니다. + /// + /// 고유 ID + /// 표시 이름 + /// 초기 float 값 + /// Dropdown 선택 목록 + /// 초기 Dropdown 선택 값 + /// 스테퍼 사용 여부 + /// 읽기 전용 여부 + /// 레이블 표시 여부 + public UTKFloatDropdownPropertyItem( + string id, + string name, + float floatValue, + List choices, + string dropdownValue = "", + bool useStepper = false, + bool isReadOnly = false, + bool showLabel = true) + : base(id, name, new UTKFloatDropdownValue(floatValue, ValidateDropdownValue(dropdownValue, choices))) + { + _choices = new List(choices); + _useStepper = useStepper; + _isReadOnly = isReadOnly; + _showLabel = showLabel; + } + + /// + /// Float + Dropdown 복합 속성을 생성합니다 + /// (최소/최대 float 값 및 스테퍼 단위 포함) + /// + /// 고유 ID + /// 표시 이름 + /// 초기 float 값 + /// Dropdown 선택 목록 + /// 초기 Dropdown 선택 값 + /// Float 최소값 + /// Float 최대값 + /// 스테퍼 증감 단위스테퍼 사용 여부 + /// 읽기 전용 여부 + /// 레이블 표시 여부 + public UTKFloatDropdownPropertyItem( + string id, + string name, + float floatValue, + List choices, + string dropdownValue, + float floatMinValue, + float floatMaxValue, + float stepperStep = 1.0f, + bool useStepper = false, + bool isReadOnly = false, + bool showLabel = true) + : base(id, name, new UTKFloatDropdownValue(floatValue, ValidateDropdownValue(dropdownValue, choices))) + { + _choices = new List(choices); + _floatMinValue = floatMinValue; + _floatMaxValue = floatMaxValue; + _stepperStep = stepperStep; + _useStepper = useStepper; + _isReadOnly = isReadOnly; + _showLabel = showLabel; + } + #endregion + + #region Methods + /// Dropdown 선택 값 검증 (목록에 없으면 첫 번째 값 반환) + private static string ValidateDropdownValue(string value, List choices) + { + if (choices.Count == 0) return value; + if (string.IsNullOrEmpty(value) || !choices.Contains(value)) + { + return choices[0]; + } + return value; + } + #endregion + } +} diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatDropdownPropertyItem.cs.meta b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatDropdownPropertyItem.cs.meta new file mode 100644 index 00000000..7d7e0a1a --- /dev/null +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatDropdownPropertyItem.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 86800100e89e3d34fa8b8afa7f290064 \ No newline at end of file diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatPropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatPropertyItem.cs index 721acf61..1a39124d 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatPropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatPropertyItem.cs @@ -64,10 +64,12 @@ namespace UVC.UIToolkit /// 표시 이름 /// 초기 값 /// 읽기 전용 여부 - public UTKFloatPropertyItem(string id, string name, float initialValue = 0f, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKFloatPropertyItem(string id, string name, float initialValue = 0f, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue) { - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } /// @@ -81,14 +83,16 @@ namespace UVC.UIToolkit /// 슬라이더 사용 여부 /// 스테퍼 사용 여부 /// 읽기 전용 여부 - public UTKFloatPropertyItem(string id, string name, float initialValue, float minValue = float.MinValue, float maxValue = float.MaxValue, bool useSlider = true, bool useStepper = false, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKFloatPropertyItem(string id, string name, float initialValue, float minValue = float.MinValue, float maxValue = float.MaxValue, bool useSlider = true, bool useStepper = false, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue) { _minValue = minValue; _maxValue = maxValue; _useSlider = useSlider; _useStepper = useStepper; - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatRangePropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatRangePropertyItem.cs index 28df30dd..33b2876a 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatRangePropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatRangePropertyItem.cs @@ -8,23 +8,63 @@ namespace UVC.UIToolkit /// public class UTKFloatRangePropertyItem : UTKPropertyItemBase { + #region Fields + private bool _useStepper; + private float _stepperMinValue = float.MinValue; + private float _stepperMaxValue = float.MaxValue; + private float _stepperStep = 1.0f; + #endregion + #region Properties /// 속성 타입 public override UTKPropertyType PropertyType => UTKPropertyType.FloatRange; + + /// 스테퍼(증감 버튼) 사용 여부 + public bool UseStepper + { + get => _useStepper; + set + { + _useStepper = value; + } + } + + /// 스테퍼 증감 단위 (기본값: 1.0) + public float StepperStep + { + get => _stepperStep; + set => _stepperStep = value > 0 ? value : 1.0f; + } + + /// 스테퍼 최소값 + public float StepperMinValue + { + get => _stepperMinValue; + set => _stepperMinValue = value; + } + + /// 스테퍼 최대값 + public float StepperMaxValue + { + get => _stepperMaxValue; + set => _stepperMaxValue = value; + } #endregion #region Constructor /// - /// 실수 범위 속성을 생성합니다. + /// 실수 범위 속성을 생성합니다 (필드 모드). /// /// 고유 ID /// 표시 이름 /// 초기 범위 값 /// 읽기 전용 여부 - public UTKFloatRangePropertyItem(string id, string name, UTKFloatRange initialValue = default, bool isReadOnly = false) + /// 레이블 표시 여부 + public UTKFloatRangePropertyItem(string id, string name, UTKFloatRange initialValue = default, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue) { - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } /// @@ -34,11 +74,44 @@ namespace UVC.UIToolkit /// 표시 이름 /// 최소값 /// 최대값 + /// 스테퍼 증감 단위 + /// 스테퍼 최소값 + /// 스테퍼 최대값 + /// 스테퍼 사용 여부 /// 읽기 전용 여부 - public UTKFloatRangePropertyItem(string id, string name, float min, float max, bool isReadOnly = false) + /// 레이블 표시 여부 + public UTKFloatRangePropertyItem(string id, string name, float min, float max, float stepperStep = 1.0f, float stepperMinValue = float.MinValue, float stepperMaxValue = float.MaxValue, bool useStepper = false, bool isReadOnly = false, bool showLabel = true) : base(id, name, new UTKFloatRange(min, max)) { - IsReadOnly = isReadOnly; + _stepperMinValue = stepperMinValue; + _stepperMaxValue = stepperMaxValue; + _useStepper = useStepper; + _stepperStep = stepperStep; + _isReadOnly = isReadOnly; + _showLabel = showLabel; + } + + /// + /// 실수 범위 속성을 생성합니다 (스테퍼 모드). + /// + /// 고유 ID + /// 표시 이름 + /// 초기 범위 값 + /// 스테퍼 증감 단위 + /// 스테퍼 최소값 + /// 스테퍼 최대값 + /// 스테퍼 사용 여부 + /// 읽기 전용 여부 + /// 레이블 표시 여부 + public UTKFloatRangePropertyItem(string id, string name, UTKFloatRange initialValue, float stepperStep = 1.0f, float stepperMinValue = float.MinValue, float stepperMaxValue = float.MaxValue, bool useStepper = false, bool isReadOnly = false, bool showLabel = true) + : base(id, name, initialValue) + { + _stepperMinValue = stepperMinValue; + _stepperMaxValue = stepperMaxValue; + _useStepper = useStepper; + _stepperStep = stepperStep; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntPropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntPropertyItem.cs index 500d2c55..abfef525 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntPropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntPropertyItem.cs @@ -85,14 +85,16 @@ namespace UVC.UIToolkit /// 최대값 /// 슬라이더 사용 여부 /// 읽기 전용 여부 - public UTKIntPropertyItem(string id, string name, int initialValue, int minValue, int maxValue, bool useSlider = false, bool useStepper = false, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKIntPropertyItem(string id, string name, int initialValue, int minValue, int maxValue, bool useSlider = false, bool useStepper = false, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue) { _minValue = minValue; _maxValue = maxValue; _useSlider = useSlider; _useStepper = useStepper; - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntRangePropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntRangePropertyItem.cs index 233c5bc5..ce621a04 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntRangePropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntRangePropertyItem.cs @@ -60,10 +60,12 @@ namespace UVC.UIToolkit /// 표시 이름 /// 초기 범위 값 /// 읽기 전용 여부 - public UTKIntRangePropertyItem(string id, string name, UTKIntRange initialValue = default, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKIntRangePropertyItem(string id, string name, UTKIntRange initialValue = default, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue) { - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } /// @@ -78,14 +80,16 @@ namespace UVC.UIToolkit /// 스테퍼 최대값 /// 스테퍼 사용 여부 /// 읽기 전용 여부 - public UTKIntRangePropertyItem(string id, string name, int min, int max, int stepperStep = 1, int stepperMinValue = int.MinValue, int stepperMaxValue = int.MaxValue, bool useStepper = false, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKIntRangePropertyItem(string id, string name, int min, int max, int stepperStep = 1, int stepperMinValue = int.MinValue, int stepperMaxValue = int.MaxValue, bool useStepper = false, bool isReadOnly = false, bool showLabel = true) : base(id, name, new UTKIntRange(min, max)) { _stepperMinValue = stepperMinValue; _stepperMaxValue = stepperMaxValue; _useStepper = useStepper; _stepperStep = stepperStep; - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } /// @@ -99,14 +103,16 @@ namespace UVC.UIToolkit /// 스테퍼 최대값 /// 스테퍼 사용 여부 /// 읽기 전용 여부 - public UTKIntRangePropertyItem(string id, string name, UTKIntRange initialValue, int stepperStep = 1, int stepperMinValue = int.MinValue, int stepperMaxValue = int.MaxValue, bool useStepper = false, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKIntRangePropertyItem(string id, string name, UTKIntRange initialValue, int stepperStep = 1, int stepperMinValue = int.MinValue, int stepperMaxValue = int.MaxValue, bool useStepper = false, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue) { _stepperMinValue = stepperMinValue; _stepperMaxValue = stepperMaxValue; _useStepper = useStepper; _stepperStep = stepperStep; - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKMultiSelectDropdownPropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKMultiSelectDropdownPropertyItem.cs index 9c0656ab..d1af7e80 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKMultiSelectDropdownPropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKMultiSelectDropdownPropertyItem.cs @@ -51,12 +51,14 @@ namespace UVC.UIToolkit /// 선택 항목 목록 /// 초기 선택 값 목록 /// 읽기 전용 여부 + /// 라벨 표시 여부 public UTKMultiSelectDropdownPropertyItem( string id, string name, List choices, List? initialValues = null, - bool isReadOnly = false) + bool isReadOnly = false, + bool showLabel = true) : base(id, name, initialValues ?? new List()) { _choices = choices ?? new List(); @@ -65,10 +67,11 @@ namespace UVC.UIToolkit if (initialValues != null && initialValues.Count > 0) { var validValues = initialValues.Where(v => _choices.Contains(v)).ToList(); - Value = validValues; + _value = validValues; } - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } /// @@ -79,12 +82,14 @@ namespace UVC.UIToolkit /// 선택 항목 목록 /// 초기 선택 인덱스 목록 /// 읽기 전용 여부 + /// 라벨 표시 여부 public UTKMultiSelectDropdownPropertyItem( string id, string name, IEnumerable choices, IEnumerable? selectedIndices = null, - bool isReadOnly = false) + bool isReadOnly = false, + bool showLabel = true) : base(id, name, new List()) { _choices = choices?.ToList() ?? new List(); @@ -95,10 +100,11 @@ namespace UVC.UIToolkit .Where(i => i >= 0 && i < _choices.Count) .Select(i => _choices[i]) .ToList(); - Value = validValues; + _value = validValues; } - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKRadioPropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKRadioPropertyItem.cs index 649f0ae9..b109baad 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKRadioPropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKRadioPropertyItem.cs @@ -49,11 +49,13 @@ namespace UVC.UIToolkit /// 선택 항목 목록 /// 초기 선택 인덱스 /// 읽기 전용 여부 - public UTKRadioPropertyItem(string id, string name, List choices, int selectedIndex = 0, bool isReadOnly = false) + /// 라벨 표시 여부 + public UTKRadioPropertyItem(string id, string name, List choices, int selectedIndex = 0, bool isReadOnly = false, bool showLabel = true) : base(id, name, Math.Max(0, Math.Min(selectedIndex, (choices?.Count ?? 1) - 1))) { _choices = choices ?? new List(); - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } /// @@ -64,8 +66,9 @@ namespace UVC.UIToolkit /// 선택 항목 목록 /// 초기 선택 인덱스 /// 읽기 전용 여부 - public UTKRadioPropertyItem(string id, string name, IEnumerable choices, int selectedIndex = 0, bool isReadOnly = false) - : this(id, name, choices?.ToList() ?? new List(), selectedIndex, isReadOnly) + /// 라벨 표시 여부 + public UTKRadioPropertyItem(string id, string name, IEnumerable choices, int selectedIndex = 0, bool isReadOnly = false, bool showLabel = true) + : this(id, name, choices?.ToList() ?? new List(), selectedIndex, isReadOnly, showLabel) { } #endregion diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKStringPropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKStringPropertyItem.cs index d8802aa0..adb08399 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKStringPropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKStringPropertyItem.cs @@ -45,13 +45,15 @@ namespace UVC.UIToolkit /// 멀티라인 모드 /// 최대 문자 길이 /// 읽기 전용 여부 + /// 레이블 표시 여부 /// 액션 버튼 - public UTKStringPropertyItem(string id, string name, string initialValue = "", bool isMultiline = false, int maxLength = -1, bool isReadOnly = false, UTKButtonItem? actionButton = null) + public UTKStringPropertyItem(string id, string name, string initialValue = "", bool isMultiline = false, int maxLength = -1, bool isReadOnly = false, bool showLabel = true, UTKButtonItem? actionButton = null) : base(id, name, initialValue ?? string.Empty) { - IsReadOnly = isReadOnly; _isMultiline = isMultiline; _maxLength = maxLength; + _isReadOnly = isReadOnly; + _showLabel = showLabel; ActionButton = actionButton; } #endregion diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKVector2PropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKVector2PropertyItem.cs index eab98473..4b971118 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKVector2PropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKVector2PropertyItem.cs @@ -22,10 +22,12 @@ namespace UVC.UIToolkit /// 표시 이름 /// 초기 값 /// 읽기 전용 여부 - public UTKVector2PropertyItem(string id, string name, Vector2 initialValue = default, bool isReadOnly = false) + /// 레이블 표시 여부 + public UTKVector2PropertyItem(string id, string name, Vector2 initialValue = default, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue) { - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKVector3PropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKVector3PropertyItem.cs index a80b22ac..47cce06e 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKVector3PropertyItem.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKVector3PropertyItem.cs @@ -22,10 +22,12 @@ namespace UVC.UIToolkit /// 표시 이름 /// 초기 값 /// 읽기 전용 여부 - public UTKVector3PropertyItem(string id, string name, Vector3 initialValue = default, bool isReadOnly = false) + /// 레이블 표시 여부 + public UTKVector3PropertyItem(string id, string name, Vector3 initialValue = default, bool isReadOnly = false, bool showLabel = true) : base(id, name, initialValue) { - IsReadOnly = isReadOnly; + _isReadOnly = isReadOnly; + _showLabel = showLabel; } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKBoolPropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKBoolPropertyItemView.cs index db5e063c..9a332518 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKBoolPropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKBoolPropertyItemView.cs @@ -217,17 +217,18 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -235,6 +236,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKButtonItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKButtonItemView.cs index 3e73b834..db908e43 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKButtonItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKButtonItemView.cs @@ -137,6 +137,7 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); // 라벨 텍스트 설정 if (_labelElement != null) @@ -191,6 +192,7 @@ namespace UVC.UIToolkit { if (_boundData != null) { + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKColorPropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKColorPropertyItemView.cs index 8d3f5b60..f0a3df33 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKColorPropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKColorPropertyItemView.cs @@ -349,12 +349,13 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; if (data is UTKColorPropertyItem colorItem) { @@ -364,7 +365,7 @@ namespace UVC.UIToolkit data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -372,6 +373,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKColorStatePropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKColorStatePropertyItemView.cs index 4854e9d1..54f0ed9c 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKColorStatePropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKColorStatePropertyItemView.cs @@ -283,17 +283,18 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -301,6 +302,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDatePropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDatePropertyItemView.cs index b78e3812..cfbeaf22 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDatePropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDatePropertyItemView.cs @@ -273,12 +273,13 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; if (data is UTKDatePropertyItem dateItem) { @@ -288,7 +289,7 @@ namespace UVC.UIToolkit data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -296,6 +297,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDateRangePropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDateRangePropertyItemView.cs index 47cbe235..ccc194a4 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDateRangePropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDateRangePropertyItemView.cs @@ -376,12 +376,13 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; if (data is UTKDateRangePropertyItem dateRangeItem) { @@ -391,7 +392,7 @@ namespace UVC.UIToolkit data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -399,6 +400,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDateTimePropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDateTimePropertyItemView.cs index a42d97dd..fd91f77e 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDateTimePropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDateTimePropertyItemView.cs @@ -273,12 +273,13 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; if (data is UTKDateTimePropertyItem dateTimeItem) { @@ -288,7 +289,7 @@ namespace UVC.UIToolkit data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -296,6 +297,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDateTimeRangePropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDateTimeRangePropertyItemView.cs index 2e4985a1..de2c8f36 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDateTimeRangePropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDateTimeRangePropertyItemView.cs @@ -376,12 +376,13 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; if (data is UTKDateTimeRangePropertyItem dateTimeRangeItem) { @@ -391,7 +392,7 @@ namespace UVC.UIToolkit data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -399,6 +400,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDropdownPropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDropdownPropertyItemView.cs index a08028f3..30ceec68 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDropdownPropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKDropdownPropertyItemView.cs @@ -325,12 +325,13 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value ?? string.Empty; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; if (data is UTKDropdownPropertyItem dropdownItem) { @@ -344,7 +345,7 @@ namespace UVC.UIToolkit data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -352,6 +353,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKEnumPropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKEnumPropertyItemView.cs index 37d6a975..a7a3ad34 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKEnumPropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKEnumPropertyItemView.cs @@ -277,13 +277,14 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value; _enumType = data.Value?.GetType(); - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; if (_enumDropdown != null && _value != null) { @@ -293,7 +294,7 @@ namespace UVC.UIToolkit data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -301,6 +302,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.cs new file mode 100644 index 00000000..6dfb7721 --- /dev/null +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.cs @@ -0,0 +1,505 @@ +#nullable enable +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UIElements; + +namespace UVC.UIToolkit +{ + /// + /// Float + Dropdown 복합 속성 View 클래스입니다. + /// UTKFloatField(또는 UTKFloatStepper)와 UTKDropdown을 사용하여 + /// float 값과 문자열 선택을 하나의 행에 표시/편집합니다. + /// + /// 사용법 (Data 바인딩): + /// + /// var data = new UTKFloatDropdownPropertyItem("id", "Label", 1.5f, + /// new List<string> { "A", "B", "C" }, "A"); + /// var view = new UTKFloatDropdownPropertyItemView(); + /// view.Bind(data); + /// + /// + [UxmlElement] + public partial class UTKFloatDropdownPropertyItemView : UTKPropertyItemViewBase, IUTKPropertyItemView + { + #region Fields + private UTKFloatField? _floatField; + private UTKFloatStepper? _stepper; + private UTKDropdown? _dropdown; + private UTKInputField? _readOnlyField; + + private UTKFloatDropdownValue _value; + private List _choices = new(); + private bool _useStepper; + private float _floatMinValue = float.MinValue; + private float _floatMaxValue = float.MaxValue; + private float _stepperStep = 1.0f; + + private IUTKPropertyItem? _boundData; + #endregion + + #region Properties + protected override string ViewTypeName => "UTKFloatDropdownPropertyItemView"; + + /// 현재 값 + public UTKFloatDropdownValue Value + { + get => _value; + set + { + if (!_value.Equals(value)) + { + _value = value; + UpdateValueUI(); + OnValueChanged?.Invoke(value); + + if (_boundData != null && !_boundData.Value.Equals(value)) + { + _boundData.Value = value; + } + } + } + } + + /// Dropdown 선택 목록 + public List Choices + { + get => _choices; + set + { + _choices = value ?? new List(); + _dropdown?.SetOptions(_choices); + } + } + + /// 스테퍼(증감 버튼) 사용 여부 + public bool UseStepper + { + get => _useStepper; + set + { + if (_useStepper != value) + { + _useStepper = value; + UpdateControlVisibility(); + } + } + } + #endregion + + #region Events + public event Action? OnValueChanged; + #endregion + + #region Constructor + public UTKFloatDropdownPropertyItemView() : base() + { + InitializeUI(); + } + + public UTKFloatDropdownPropertyItemView(string label, List choices) : base() + { + _choices = new List(choices); + Label = label; + InitializeUI(); + } + + public UTKFloatDropdownPropertyItemView(UTKFloatDropdownPropertyItem data) : base() + { + _value = data.Value; + _choices = new List(data.Choices); + _useStepper = data.UseStepper; + _floatMinValue = data.FloatMinValue; + _floatMaxValue = data.FloatMaxValue; + _stepperStep = data.StepperStep; + Label = data.Name; + _isReadOnly = data.IsReadOnly; + InitializeUI(); + Bind(data); + } + #endregion + + #region Initialization + private void InitializeUI() + { + AddToClassList("utk-property-item-view"); + AddToClassList("utk-property-item-view--float-dropdown"); + + if (!CreateUIFromUxml()) + { + CreateUIFallback(); + } + + QueryUIElements(); + RegisterEvents(); + UpdateControlVisibility(); + UpdateValueUI(); + UpdateReadOnlyState(); + } + + private void QueryUIElements() + { + _floatField = this.Q("float-field"); + _dropdown = this.Q("dropdown-field"); + _stepper = this.Q("stepper-field"); + + if (_valueContainer != null) + { + _valueContainer.style.flexDirection = FlexDirection.Row; + + // FloatField 생성 + if (_floatField == null) + { + _floatField = new UTKFloatField { name = "float-field" }; + _floatField.AddToClassList("utk-float-dropdown-view__float-field"); + _valueContainer.Add(_floatField); + } + + // FloatStepper 생성 + if (_stepper == null) + { + _stepper = new UTKFloatStepper(_floatMinValue, _floatMaxValue, _value.FloatValue, _stepperStep, IsReadOnly) + { + name = "stepper-field" + }; + _stepper.AddToClassList("utk-float-dropdown-view__stepper"); + _valueContainer.Add(_stepper); + } + + // Dropdown 생성 + if (_dropdown == null) + { + _dropdown = new UTKDropdown { name = "dropdown-field" }; + _dropdown.AddToClassList("utk-float-dropdown-view__dropdown"); + _valueContainer.Add(_dropdown); + } + } + + // 초기 값 설정 + if (_floatField != null) + { + _floatField.SetValueWithoutNotify(_value.FloatValue); + _floatField.isReadOnly = IsReadOnly; + } + if (_stepper != null) + { + _stepper.MinValue = _floatMinValue; + _stepper.MaxValue = _floatMaxValue; + _stepper.Step = _stepperStep; + _stepper.SetValue(_value.FloatValue, false); + _stepper.IsReadOnly = IsReadOnly; + } + if (_dropdown != null) + { + _dropdown.SetOptions(_choices); + _dropdown.SetSelectedValue(_value.DropdownValue, notify: false); + _dropdown.IsEnabled = !IsReadOnly; + } + } + + private void RegisterEvents() + { + if (_floatField != null) + { + _floatField.OnValueChanged += OnFloatFieldChanged; + } + if (_stepper != null) + { + _stepper.OnValueChanged += OnStepperChanged; + } + if (_dropdown != null) + { + _dropdown.OnSelectionChanged += OnDropdownChanged; + } + } + + private void UnregisterEvents() + { + if (_floatField != null) + { + _floatField.OnValueChanged -= OnFloatFieldChanged; + } + if (_stepper != null) + { + _stepper.OnValueChanged -= OnStepperChanged; + } + if (_dropdown != null) + { + _dropdown.OnSelectionChanged -= OnDropdownChanged; + } + } + + /// 컨트롤 가시성을 업데이트합니다. + private void UpdateControlVisibility() + { + bool isReadOnlyMode = IsReadOnly; + bool showStepper = !isReadOnlyMode && _useStepper; + bool showFloatField = !isReadOnlyMode && !_useStepper; + bool showDropdown = !isReadOnlyMode; + + if (_floatField != null) + { + _floatField.style.display = showFloatField ? DisplayStyle.Flex : DisplayStyle.None; + } + + if (_stepper != null) + { + _stepper.style.display = showStepper ? DisplayStyle.Flex : DisplayStyle.None; + } + + if (_dropdown != null) + { + _dropdown.style.display = showDropdown ? DisplayStyle.Flex : DisplayStyle.None; + } + + // ReadOnly 모드: 단일 텍스트 필드로 표시 + if (isReadOnlyMode) + { + EnsureReadOnlyField(); + if (_readOnlyField != null) + { + _readOnlyField.style.display = DisplayStyle.Flex; + _readOnlyField.Value = _value.ToString(); + } + } + else + { + if (_readOnlyField != null) + { + _readOnlyField.style.display = DisplayStyle.None; + } + } + } + + /// ReadOnly 전용 필드를 필요 시 생성합니다. + private void EnsureReadOnlyField() + { + if (_readOnlyField != null || _valueContainer == null) return; + + _readOnlyField = new UTKInputField { name = "readonly-field" }; + _readOnlyField.AddToClassList("utk-float-dropdown-view__readonly-field"); + _readOnlyField.isReadOnly = true; + _readOnlyField.Value = _value.ToString(); + _valueContainer.Add(_readOnlyField); + } + #endregion + + #region Override Methods + protected override void CreateValueUI(VisualElement container) + { + // UXML/QueryUIElements 기반으로 생성하므로 여기서는 생성하지 않음 + } + + public override void RefreshUI() + { + UpdateValueUI(); + } + + protected override void OnReadOnlyStateChanged(bool isReadOnly) + { + if (_floatField != null) + { + _floatField.isReadOnly = isReadOnly; + } + if (_stepper != null) + { + _stepper.IsReadOnly = isReadOnly; + } + if (_dropdown != null) + { + _dropdown.IsEnabled = !isReadOnly; + } + + UpdateControlVisibility(); + } + #endregion + + #region Event Handling + private void OnFloatFieldChanged(float newFloat) + { + var newValue = new UTKFloatDropdownValue(newFloat, _value.DropdownValue); + if (!_value.Equals(newValue)) + { + _value = newValue; + + // 스테퍼가 있으면 동기화 + if (_stepper != null && !Mathf.Approximately(_stepper.Value, newFloat)) + { + _stepper.SetValue(newFloat, false); + } + + OnValueChanged?.Invoke(newValue); + + if (_boundData != null && !_boundData.Value.Equals(newValue)) + { + _boundData.Value = newValue; + } + } + } + + private void OnStepperChanged(float newFloat) + { + var newValue = new UTKFloatDropdownValue(newFloat, _value.DropdownValue); + if (!_value.Equals(newValue)) + { + _value = newValue; + + // FloatField가 있으면 동기화 + if (_floatField != null && !Mathf.Approximately(_floatField.Value, newFloat)) + { + _floatField.SetValueWithoutNotify(newFloat); + } + + OnValueChanged?.Invoke(newValue); + + if (_boundData != null && !_boundData.Value.Equals(newValue)) + { + _boundData.Value = newValue; + } + } + } + + private void OnDropdownChanged(int index, string newDropdownValue) + { + var newValue = new UTKFloatDropdownValue(_value.FloatValue, newDropdownValue); + if (!_value.Equals(newValue)) + { + _value = newValue; + OnValueChanged?.Invoke(newValue); + + if (_boundData != null && !_boundData.Value.Equals(newValue)) + { + _boundData.Value = newValue; + } + } + } + #endregion + + #region Value Update + private void UpdateValueUI() + { + if (_floatField != null && !Mathf.Approximately(_floatField.Value, _value.FloatValue)) + { + _floatField.SetValueWithoutNotify(_value.FloatValue); + } + + if (_stepper != null && !Mathf.Approximately(_stepper.Value, _value.FloatValue)) + { + _stepper.SetValue(_value.FloatValue, false); + } + + if (_dropdown != null) + { + string? selectedValue = _dropdown.SelectedValue; + if (selectedValue != _value.DropdownValue) + { + _dropdown.SetSelectedValue(_value.DropdownValue, notify: false); + } + } + + if (_readOnlyField != null && IsReadOnly) + { + _readOnlyField.Value = _value.ToString(); + } + } + #endregion + + #region Data Binding + public void Bind(IUTKPropertyItem data) + { + if (data is IUTKPropertyItem typedData) + { + Bind(typedData); + } + else + { + Debug.LogWarning($"[UTKFloatDropdownPropertyItemView] Cannot bind to non-FloatDropdown data: {data.GetType().Name}"); + } + } + + public void Bind(IUTKPropertyItem data) + { + Unbind(); + + _boundData = data; + BindBase(data); + + Label = data.Name; + _value = data.Value; + IsVisible = data.IsVisible; + TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; + + // UTKFloatDropdownPropertyItem의 설정 적용 + if (data is UTKFloatDropdownPropertyItem floatDropdownItem) + { + _choices = new List(floatDropdownItem.Choices); + _useStepper = floatDropdownItem.UseStepper; + _floatMinValue = floatDropdownItem.FloatMinValue; + _floatMaxValue = floatDropdownItem.FloatMaxValue; + _stepperStep = floatDropdownItem.StepperStep; + + // Dropdown 옵션 업데이트 + _dropdown?.SetOptions(_choices); + + // 스테퍼 설정 업데이트 + if (_stepper != null) + { + _stepper.MinValue = _floatMinValue; + _stepper.MaxValue = _floatMaxValue; + _stepper.Step = _stepperStep; + } + + UpdateControlVisibility(); + } + + data.OnTypedValueChanged += OnDataValueChanged; + + UpdateValueUI(); + IsReadOnly = data.IsReadOnly; + } + + public void Unbind() + { + if (_boundData != null) + { + _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); + _boundData = null; + } + } + + private void OnDataValueChanged(IUTKPropertyItem item, UTKFloatDropdownValue oldValue, UTKFloatDropdownValue newValue) + { + if (!_value.Equals(newValue)) + { + _value = newValue; + UpdateValueUI(); + } + } + #endregion + + #region Dispose + protected override void Dispose(bool disposing) + { + if (_disposed) return; + + if (disposing) + { + UnregisterEvents(); + Unbind(); + + OnValueChanged = null; + _floatField = null; + _stepper?.Dispose(); + _stepper = null; + _dropdown?.Dispose(); + _dropdown = null; + _readOnlyField = null; + } + + base.Dispose(disposing); + } + #endregion + } +} diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.cs.meta b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.cs.meta new file mode 100644 index 00000000..0831a607 --- /dev/null +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatDropdownPropertyItemView.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6d14075483e28504aa714b26c491a24e \ No newline at end of file diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatPropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatPropertyItemView.cs index 28dfaa8a..9ada4384 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatPropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatPropertyItemView.cs @@ -517,13 +517,14 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); // 데이터에서 속성 동기화 Label = data.Name; _value = data.Value; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; // 슬라이더 및 스테퍼 관련 속성 동기화 if (data is UTKFloatPropertyItem floatItem) @@ -570,7 +571,7 @@ namespace UVC.UIToolkit // UI 갱신 UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -578,6 +579,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatRangePropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatRangePropertyItemView.cs index 6d51f791..811e9d5c 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatRangePropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKFloatRangePropertyItemView.cs @@ -7,7 +7,7 @@ namespace UVC.UIToolkit { /// /// FloatRange 속성 View 클래스입니다. - /// Min, Max 두 개의 UTKFloatField를 사용하여 실수 범위를 표시/편집합니다. + /// Min, Max 두 개의 UTKFloatField 또는 UTKFloatStepper를 사용하여 실수 범위를 표시/편집합니다. /// [UxmlElement] public partial class UTKFloatRangePropertyItemView : UTKPropertyItemViewBase, IUTKPropertyItemView @@ -15,14 +15,70 @@ namespace UVC.UIToolkit #region Fields private UTKFloatField? _minField; private UTKFloatField? _maxField; + private UTKFloatStepper? _minStepper; + private UTKFloatStepper? _maxStepper; private UTKFloatRange _value; + private bool _useStepper; + private float _stepperMinValue = float.MinValue; + private float _stepperMaxValue = float.MaxValue; + private float _stepperStep = 1.0f; private IUTKPropertyItem? _boundData; #endregion #region Properties protected override string ViewTypeName => "UTKFloatRangePropertyItemView"; + /// 스테퍼(증감 버튼) 사용 여부 + public bool UseStepper + { + get => _useStepper; + set + { + if (_useStepper != value) + { + _useStepper = value; + UpdateModeClass(); + } + } + } + + /// 스테퍼 최소값 + public float StepperMinValue + { + get => _stepperMinValue; + set + { + _stepperMinValue = value; + if (_minStepper != null) _minStepper.MinValue = value; + if (_maxStepper != null) _maxStepper.MinValue = value; + } + } + + /// 스테퍼 최대값 + public float StepperMaxValue + { + get => _stepperMaxValue; + set + { + _stepperMaxValue = value; + if (_minStepper != null) _minStepper.MaxValue = value; + if (_maxStepper != null) _maxStepper.MaxValue = value; + } + } + + /// 스테퍼 증감 단위 + public float StepperStep + { + get => _stepperStep; + set + { + _stepperStep = value > 0 ? value : 1.0f; + if (_minStepper != null) _minStepper.Step = _stepperStep; + if (_maxStepper != null) _maxStepper.Step = _stepperStep; + } + } + /// 현재 값 public UTKFloatRange Value { @@ -94,31 +150,53 @@ namespace UVC.UIToolkit { _minField = this.Q("min-field"); _maxField = this.Q("max-field"); + _minStepper = this.Q("min-stepper"); + _maxStepper = this.Q("max-stepper"); // Fallback: UXML에서 못 찾으면 생성 if (_valueContainer != null) { _valueContainer.style.flexDirection = FlexDirection.Row; + // FloatField 생성 if (_minField == null) { _minField = new UTKFloatField { name = "min-field" }; - _minField.style.flexGrow = 1; _minField.AddToClassList("utk-property-item-view__field"); _valueContainer.Add(_minField); - - var separator = new UTKLabel("~", UTKLabel.LabelSize.Body2); - separator.AddToClassList("utk-property-item-view__range-separator"); - _valueContainer.Add(separator); } if (_maxField == null) { + var separator = new UTKLabel("~", UTKLabel.LabelSize.Body2); + separator.AddToClassList("utk-property-item-view__range-separator"); + _valueContainer.Add(separator); + _maxField = new UTKFloatField { name = "max-field" }; - _maxField.style.flexGrow = 1; _maxField.AddToClassList("utk-property-item-view__field"); _valueContainer.Add(_maxField); } + + // FloatStepper 생성 + if (_minStepper == null) + { + _minStepper = new UTKFloatStepper(_stepperMinValue, _stepperMaxValue, _value.Min, _stepperStep, IsReadOnly) + { + name = "min-stepper" + }; + _minStepper.AddToClassList("utk-property-item-view__stepper"); + _valueContainer.Add(_minStepper); + } + + if (_maxStepper == null) + { + _maxStepper = new UTKFloatStepper(_stepperMinValue, _stepperMaxValue, _value.Max, _stepperStep, IsReadOnly) + { + name = "max-stepper" + }; + _maxStepper.AddToClassList("utk-property-item-view__stepper"); + _valueContainer.Add(_maxStepper); + } } // 초기 값 설정 @@ -132,6 +210,25 @@ namespace UVC.UIToolkit _maxField.SetValueWithoutNotify(_value.Max); _maxField.isReadOnly = IsReadOnly; } + if (_minStepper != null) + { + _minStepper.MinValue = _stepperMinValue; + _minStepper.MaxValue = _stepperMaxValue; + _minStepper.Step = _stepperStep; + _minStepper.SetValue(_value.Min, false); + _minStepper.IsReadOnly = IsReadOnly; + } + if (_maxStepper != null) + { + _maxStepper.MinValue = _stepperMinValue; + _maxStepper.MaxValue = _stepperMaxValue; + _maxStepper.Step = _stepperStep; + _maxStepper.SetValue(_value.Max, false); + _maxStepper.IsReadOnly = IsReadOnly; + } + + // 컨트롤 가시성 업데이트 + UpdateControlVisibility(); } private void RegisterEvents() @@ -144,6 +241,14 @@ namespace UVC.UIToolkit { _maxField.OnValueChanged += OnMaxChanged; } + if (_minStepper != null) + { + _minStepper.OnValueChanged += OnMinStepperChanged; + } + if (_maxStepper != null) + { + _maxStepper.OnValueChanged += OnMaxStepperChanged; + } } private void UnregisterEvents() @@ -156,6 +261,65 @@ namespace UVC.UIToolkit { _maxField.OnValueChanged -= OnMaxChanged; } + if (_minStepper != null) + { + _minStepper.OnValueChanged -= OnMinStepperChanged; + } + if (_maxStepper != null) + { + _maxStepper.OnValueChanged -= OnMaxStepperChanged; + } + } + + private void UpdateModeClass() + { + // ReadOnly 상태에서는 무조건 FloatField만 표시 + if (IsReadOnly) + { + RemoveFromClassList("utk-property-item-view--stepper"); + UpdateControlVisibility(); + return; + } + + // 스테퍼 클래스 + if (_useStepper) + { + AddToClassList("utk-property-item-view--stepper"); + } + else + { + RemoveFromClassList("utk-property-item-view--stepper"); + } + + UpdateControlVisibility(); + } + + /// 컨트롤 가시성을 업데이트합니다. + private void UpdateControlVisibility() + { + bool isReadOnlyMode = IsReadOnly; + bool showStepper = !isReadOnlyMode && _useStepper; + bool showFloatField = isReadOnlyMode || !_useStepper; + + if (_minField != null) + { + _minField.style.display = showFloatField ? DisplayStyle.Flex : DisplayStyle.None; + } + + if (_maxField != null) + { + _maxField.style.display = showFloatField ? DisplayStyle.Flex : DisplayStyle.None; + } + + if (_minStepper != null) + { + _minStepper.style.display = showStepper ? DisplayStyle.Flex : DisplayStyle.None; + } + + if (_maxStepper != null) + { + _maxStepper.style.display = showStepper ? DisplayStyle.Flex : DisplayStyle.None; + } } #endregion @@ -174,6 +338,11 @@ namespace UVC.UIToolkit { if (_minField != null) _minField.isReadOnly = isReadOnly; if (_maxField != null) _maxField.isReadOnly = isReadOnly; + if (_minStepper != null) _minStepper.IsReadOnly = isReadOnly; + if (_maxStepper != null) _maxStepper.IsReadOnly = isReadOnly; + + // ReadOnly 상태 변경 시 모드 클래스 업데이트 + UpdateModeClass(); } #endregion @@ -207,6 +376,36 @@ namespace UVC.UIToolkit } } } + + private void OnMinStepperChanged(float newMin) + { + var newValue = new UTKFloatRange(newMin, _value.Max); + if (!_value.Equals(newValue)) + { + _value = newValue; + OnValueChanged?.Invoke(newValue); + + if (_boundData != null && !_boundData.Value.Equals(newValue)) + { + _boundData.Value = newValue; + } + } + } + + private void OnMaxStepperChanged(float newMax) + { + var newValue = new UTKFloatRange(_value.Min, newMax); + if (!_value.Equals(newValue)) + { + _value = newValue; + OnValueChanged?.Invoke(newValue); + + if (_boundData != null && !_boundData.Value.Equals(newValue)) + { + _boundData.Value = newValue; + } + } + } #endregion #region Value Update @@ -221,6 +420,16 @@ namespace UVC.UIToolkit { _maxField.SetValueWithoutNotify(_value.Max); } + + if (_minStepper != null && !Mathf.Approximately(_minStepper.Value, _value.Min)) + { + _minStepper.SetValue(_value.Min, false); + } + + if (_maxStepper != null && !Mathf.Approximately(_maxStepper.Value, _value.Max)) + { + _maxStepper.SetValue(_value.Max, false); + } } #endregion @@ -242,17 +451,43 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; + + // UTKFloatRangePropertyItem의 스테퍼 설정 적용 + if (data is UTKFloatRangePropertyItem rangeItem) + { + _useStepper = rangeItem.UseStepper; + _stepperMinValue = rangeItem.StepperMinValue; + _stepperMaxValue = rangeItem.StepperMaxValue; + _stepperStep = rangeItem.StepperStep; + + // 스테퍼에 값 적용 + if (_minStepper != null) + { + _minStepper.MinValue = _stepperMinValue; + _minStepper.MaxValue = _stepperMaxValue; + _minStepper.Step = _stepperStep; + } + if (_maxStepper != null) + { + _maxStepper.MinValue = _stepperMinValue; + _maxStepper.MaxValue = _stepperMaxValue; + _maxStepper.Step = _stepperStep; + } + + UpdateModeClass(); + } data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -260,6 +495,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } @@ -287,6 +523,10 @@ namespace UVC.UIToolkit OnValueChanged = null; _minField = null; _maxField = null; + _minStepper?.Dispose(); + _minStepper = null; + _maxStepper?.Dispose(); + _maxStepper = null; } base.Dispose(disposing); diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntPropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntPropertyItemView.cs index c47fca6f..2b2b47ab 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntPropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntPropertyItemView.cs @@ -516,12 +516,13 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; if (data is UTKIntPropertyItem intItem) { @@ -565,7 +566,7 @@ namespace UVC.UIToolkit data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -573,6 +574,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntRangePropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntRangePropertyItemView.cs index f8333058..3788a8c7 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntRangePropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntRangePropertyItemView.cs @@ -162,7 +162,6 @@ namespace UVC.UIToolkit if (_minField == null) { _minField = new UTKIntegerField { name = "min-field" }; - _minField.style.flexGrow = 1; _minField.AddToClassList("utk-property-item-view__field"); _valueContainer.Add(_minField); } @@ -174,7 +173,6 @@ namespace UVC.UIToolkit _valueContainer.Add(separator); _maxField = new UTKIntegerField { name = "max-field" }; - _maxField.style.flexGrow = 1; _maxField.AddToClassList("utk-property-item-view__field"); _valueContainer.Add(_maxField); } @@ -186,7 +184,6 @@ namespace UVC.UIToolkit { name = "min-stepper" }; - _minStepper.style.flexGrow = 1; _minStepper.AddToClassList("utk-property-item-view__stepper"); _valueContainer.Add(_minStepper); } @@ -197,7 +194,6 @@ namespace UVC.UIToolkit { name = "max-stepper" }; - _maxStepper.style.flexGrow = 1; _maxStepper.AddToClassList("utk-property-item-view__stepper"); _valueContainer.Add(_maxStepper); } @@ -455,12 +451,13 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; // UTKIntRangePropertyItem의 스테퍼 설정 적용 if (data is UTKIntRangePropertyItem rangeItem) @@ -490,7 +487,7 @@ namespace UVC.UIToolkit data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -498,6 +495,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKMultiSelectDropdownPropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKMultiSelectDropdownPropertyItemView.cs index 3f436e2e..67b84b76 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKMultiSelectDropdownPropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKMultiSelectDropdownPropertyItemView.cs @@ -385,12 +385,13 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value != null ? new List(data.Value) : new List(); - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; if (data is UTKMultiSelectDropdownPropertyItem multiSelectItem) { @@ -404,7 +405,7 @@ namespace UVC.UIToolkit data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -412,6 +413,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKPropertyItemViewBase.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKPropertyItemViewBase.cs index acfd03c8..e33ded7d 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKPropertyItemViewBase.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKPropertyItemViewBase.cs @@ -54,6 +54,8 @@ namespace UVC.UIToolkit protected bool _isVisible = true; protected bool _showLabel = true; protected string? _tooltipText; + + private IUTKPropertyItem? _boundItemBase; #endregion #region Properties @@ -285,10 +287,19 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanel); + RegisterCallback(OnDetachFromPanel); + } + + private void OnAttachToPanel(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + } + + private void OnDetachFromPanel(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -390,6 +401,34 @@ namespace UVC.UIToolkit TooltipText = item.Tooltip; ShowLabel = item.ShowLabel; } + + /// + /// 상태 변경 이벤트를 구독합니다. 하위 View의 Bind에서 호출하세요. + /// + protected void BindBase(IUTKPropertyItem item) + { + UnbindBase(); + _boundItemBase = item; + _boundItemBase.OnStateChanged += OnItemStateChanged; + } + + /// + /// 상태 변경 이벤트 구독을 해제합니다. 하위 View의 Unbind에서 호출하세요. + /// + protected void UnbindBase() + { + if (_boundItemBase != null) + { + _boundItemBase.OnStateChanged -= OnItemStateChanged; + _boundItemBase = null; + } + } + + private void OnItemStateChanged(IUTKPropertyItem item) + { + IsReadOnly = item.IsReadOnly; + ShowLabel = item.ShowLabel; + } #endregion #region IDisposable @@ -406,7 +445,10 @@ namespace UVC.UIToolkit if (disposing) { + UnbindBase(); UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanel); + UnregisterCallback(OnDetachFromPanel); this.ClearTooltip(); _labelElement = null; diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKPropertyItemViewFactory.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKPropertyItemViewFactory.cs index 9849f30a..c9118253 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKPropertyItemViewFactory.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKPropertyItemViewFactory.cs @@ -83,6 +83,7 @@ namespace UVC.UIToolkit UTKPropertyType.DateRange => new UTKDateRangePropertyItemView(), UTKPropertyType.DateTimeRange => new UTKDateTimeRangePropertyItemView(), UTKPropertyType.ColorState => new UTKColorStatePropertyItemView(), + UTKPropertyType.FloatDropdown => CreateFloatDropdownView(data), UTKPropertyType.Button => CreateButtonView(data), _ => throw new ArgumentException($"Unknown property type: {data.PropertyType}") }; @@ -121,11 +122,46 @@ namespace UVC.UIToolkit UTKPropertyType.DateRange => new UTKDateRangePropertyItemView(), UTKPropertyType.DateTimeRange => new UTKDateTimeRangePropertyItemView(), UTKPropertyType.ColorState => new UTKColorStatePropertyItemView(), + UTKPropertyType.FloatDropdown => new UTKFloatDropdownPropertyItemView(), UTKPropertyType.Button => new UTKButtonItemView(), _ => throw new ArgumentException($"Unknown property type: {propertyType}") }; } + /// + /// PropertyItem 데이터에 해당하는 View의 Type을 반환합니다. + /// View 재사용 시 기존 View와 타입 호환 여부 확인에 사용합니다. + /// + /// PropertyItem 데이터 + /// View Type + public static Type GetViewType(IUTKPropertyItem data) + { + return data.PropertyType switch + { + UTKPropertyType.String => typeof(UTKStringPropertyItemView), + UTKPropertyType.Int => typeof(UTKIntPropertyItemView), + UTKPropertyType.Float => typeof(UTKFloatPropertyItemView), + UTKPropertyType.Bool => typeof(UTKBoolPropertyItemView), + UTKPropertyType.Vector2 => typeof(UTKVector2PropertyItemView), + UTKPropertyType.Vector3 => typeof(UTKVector3PropertyItemView), + UTKPropertyType.Color => typeof(UTKColorPropertyItemView), + UTKPropertyType.Date => typeof(UTKDatePropertyItemView), + UTKPropertyType.DateTime => typeof(UTKDateTimePropertyItemView), + UTKPropertyType.Enum => typeof(UTKEnumPropertyItemView), + UTKPropertyType.DropdownList => typeof(UTKDropdownPropertyItemView), + UTKPropertyType.MultiSelectDropdownList => typeof(UTKMultiSelectDropdownPropertyItemView), + UTKPropertyType.RadioGroup => typeof(UTKRadioPropertyItemView), + UTKPropertyType.IntRange => typeof(UTKIntRangePropertyItemView), + UTKPropertyType.FloatRange => typeof(UTKFloatRangePropertyItemView), + UTKPropertyType.DateRange => typeof(UTKDateRangePropertyItemView), + UTKPropertyType.DateTimeRange => typeof(UTKDateTimeRangePropertyItemView), + UTKPropertyType.ColorState => typeof(UTKColorStatePropertyItemView), + UTKPropertyType.FloatDropdown => typeof(UTKFloatDropdownPropertyItemView), + UTKPropertyType.Button => typeof(UTKButtonItemView), + _ => typeof(VisualElement) + }; + } + /// /// 커스텀 View 팩토리를 등록합니다. /// @@ -225,6 +261,16 @@ namespace UVC.UIToolkit return new UTKMultiSelectDropdownPropertyItemView(); } + private static IUTKPropertyItemView CreateFloatDropdownView(IUTKPropertyItem data) + { + // UTKFloatDropdownPropertyItem의 Choices로 View 초기화 + if (data is UTKFloatDropdownPropertyItem floatDropdownItem) + { + return new UTKFloatDropdownPropertyItemView(floatDropdownItem); + } + return new UTKFloatDropdownPropertyItemView(); + } + private static IUTKPropertyItemView CreateButtonView(IUTKPropertyItem data) { // UTKButtonItem으로 ButtonView 초기화 diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKRadioPropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKRadioPropertyItemView.cs index 802a3f4d..13abbf16 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKRadioPropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKRadioPropertyItemView.cs @@ -339,12 +339,13 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; if (data is UTKRadioPropertyItem radioItem) { @@ -355,7 +356,7 @@ namespace UVC.UIToolkit data.OnTypedValueChanged += OnDataValueChanged; UpdateSelection(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -363,6 +364,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKStringPropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKStringPropertyItemView.cs index 33094997..246ab979 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKStringPropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKStringPropertyItemView.cs @@ -316,12 +316,13 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value ?? string.Empty; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; if (data is UTKStringPropertyItem stringItem) { @@ -347,7 +348,7 @@ namespace UVC.UIToolkit data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -355,6 +356,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKVector2PropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKVector2PropertyItemView.cs index fe2c532f..f629d01d 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKVector2PropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKVector2PropertyItemView.cs @@ -188,17 +188,18 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -206,6 +207,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKVector3PropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKVector3PropertyItemView.cs index c0b75a47..4f5f74ef 100644 --- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKVector3PropertyItemView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKVector3PropertyItemView.cs @@ -188,17 +188,18 @@ namespace UVC.UIToolkit Unbind(); _boundData = data; + BindBase(data); Label = data.Name; _value = data.Value; - IsReadOnly = data.IsReadOnly; IsVisible = data.IsVisible; TooltipText = data.Tooltip; + ShowLabel = data.ShowLabel; data.OnTypedValueChanged += OnDataValueChanged; UpdateValueUI(); - UpdateReadOnlyState(); + IsReadOnly = data.IsReadOnly; } public void Unbind() @@ -206,6 +207,7 @@ namespace UVC.UIToolkit if (_boundData != null) { _boundData.OnTypedValueChanged -= OnDataValueChanged; + UnbindBase(); _boundData = null; } } diff --git a/Assets/Scripts/UVC/UIToolkit/Slider/UTKMinMaxSlider.cs b/Assets/Scripts/UVC/UIToolkit/Slider/UTKMinMaxSlider.cs index 8be429c9..a1436211 100644 --- a/Assets/Scripts/UVC/UIToolkit/Slider/UTKMinMaxSlider.cs +++ b/Assets/Scripts/UVC/UIToolkit/Slider/UTKMinMaxSlider.cs @@ -168,10 +168,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -194,6 +204,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnSliderValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/Slider/UTKProgressBar.cs b/Assets/Scripts/UVC/UIToolkit/Slider/UTKProgressBar.cs index 9299e5fb..d8624b3d 100644 --- a/Assets/Scripts/UVC/UIToolkit/Slider/UTKProgressBar.cs +++ b/Assets/Scripts/UVC/UIToolkit/Slider/UTKProgressBar.cs @@ -252,10 +252,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -319,6 +329,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Slider/UTKSlider.cs b/Assets/Scripts/UVC/UIToolkit/Slider/UTKSlider.cs index fa09d4fa..f63b7b9f 100644 --- a/Assets/Scripts/UVC/UIToolkit/Slider/UTKSlider.cs +++ b/Assets/Scripts/UVC/UIToolkit/Slider/UTKSlider.cs @@ -150,10 +150,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -176,6 +186,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnSliderValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/Slider/UTKSliderInt.cs b/Assets/Scripts/UVC/UIToolkit/Slider/UTKSliderInt.cs index d8978c5a..85267102 100644 --- a/Assets/Scripts/UVC/UIToolkit/Slider/UTKSliderInt.cs +++ b/Assets/Scripts/UVC/UIToolkit/Slider/UTKSliderInt.cs @@ -151,10 +151,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -185,6 +195,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); OnValueChanged = null; UnregisterCallback>(OnSliderValueChanged); } diff --git a/Assets/Scripts/UVC/UIToolkit/Tab/UTKTab.cs b/Assets/Scripts/UVC/UIToolkit/Tab/UTKTab.cs index 9cc693b7..98101c85 100644 --- a/Assets/Scripts/UVC/UIToolkit/Tab/UTKTab.cs +++ b/Assets/Scripts/UVC/UIToolkit/Tab/UTKTab.cs @@ -99,10 +99,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -118,6 +128,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); } #endregion } diff --git a/Assets/Scripts/UVC/UIToolkit/Tab/UTKTabView.cs b/Assets/Scripts/UVC/UIToolkit/Tab/UTKTabView.cs index fdd1d3c3..28e856e0 100644 --- a/Assets/Scripts/UVC/UIToolkit/Tab/UTKTabView.cs +++ b/Assets/Scripts/UVC/UIToolkit/Tab/UTKTabView.cs @@ -190,10 +190,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -310,6 +320,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); foreach (var tab in _utkTabs) { diff --git a/Assets/Scripts/UVC/UIToolkit/UTKThemeManager.cs b/Assets/Scripts/UVC/UIToolkit/UTKThemeManager.cs index 59cb2990..693126c4 100644 --- a/Assets/Scripts/UVC/UIToolkit/UTKThemeManager.cs +++ b/Assets/Scripts/UVC/UIToolkit/UTKThemeManager.cs @@ -112,27 +112,51 @@ namespace UVC.UIToolkit /// UTK 컴포넌트에서 사용 (내부 구현): /// /// [UxmlElement] - /// public partial class MyCustomComponent : VisualElement + /// public partial class MyCustomComponent : VisualElement, IDisposable /// { + /// private bool _disposed; + /// /// public MyCustomComponent() /// { /// // 컴포넌트에 테마 스타일 적용 /// UTKThemeManager.Instance.ApplyThemeToElement(this); /// - /// // 테마 변경 구독 - /// UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + /// // 테마 변경 구독 (Attach/Detach 쌍으로 관리) + /// SubscribeToThemeChanges(); + /// } /// - /// // 패널에서 분리될 때 구독 해제 - /// RegisterCallback(_ => - /// { - /// UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - /// }); + /// private void SubscribeToThemeChanges() + /// { + /// UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + /// RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme); + /// RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme); + /// } + /// + /// private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + /// { + /// UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + /// UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + /// UTKThemeManager.Instance.ApplyThemeToElement(this); + /// } + /// + /// private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + /// { + /// UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; /// } /// /// private void OnThemeChanged(UTKTheme theme) /// { /// UTKThemeManager.Instance.ApplyThemeToElement(this); /// } + /// + /// public void Dispose() + /// { + /// if (_disposed) return; + /// _disposed = true; + /// UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + /// UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme); + /// UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme); + /// } /// } /// /// diff --git a/Assets/Scripts/UVC/UIToolkit/Window/UTKAccordionListWindow.cs b/Assets/Scripts/UVC/UIToolkit/Window/UTKAccordionListWindow.cs index 9bda7f0a..16549738 100644 --- a/Assets/Scripts/UVC/UIToolkit/Window/UTKAccordionListWindow.cs +++ b/Assets/Scripts/UVC/UIToolkit/Window/UTKAccordionListWindow.cs @@ -451,10 +451,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -473,6 +483,8 @@ namespace UVC.UIToolkit // 테마 변경 이벤트 해제 UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); // 내부 UTKAccordionList 정리 _accordionList?.Dispose(); diff --git a/Assets/Scripts/UVC/UIToolkit/Window/UTKComponentListWindow.cs b/Assets/Scripts/UVC/UIToolkit/Window/UTKComponentListWindow.cs index a7d33584..a2e94679 100644 --- a/Assets/Scripts/UVC/UIToolkit/Window/UTKComponentListWindow.cs +++ b/Assets/Scripts/UVC/UIToolkit/Window/UTKComponentListWindow.cs @@ -408,10 +408,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -432,6 +442,8 @@ namespace UVC.UIToolkit // 테마 변경 이벤트 해제 UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); // 내부 UTKComponentList 정리 _componentList?.Dispose(); diff --git a/Assets/Scripts/UVC/UIToolkit/Window/UTKComponentTabListWindow.cs b/Assets/Scripts/UVC/UIToolkit/Window/UTKComponentTabListWindow.cs index 70699cce..e4b01055 100644 --- a/Assets/Scripts/UVC/UIToolkit/Window/UTKComponentTabListWindow.cs +++ b/Assets/Scripts/UVC/UIToolkit/Window/UTKComponentTabListWindow.cs @@ -664,10 +664,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -688,6 +698,8 @@ namespace UVC.UIToolkit // 테마 변경 이벤트 해제 UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); // 내부 UTKComponentList 정리 _componentList?.Dispose(); diff --git a/Assets/Scripts/UVC/UIToolkit/Window/UTKImageListWindow.cs b/Assets/Scripts/UVC/UIToolkit/Window/UTKImageListWindow.cs index b3ac2b1f..0e226a11 100644 --- a/Assets/Scripts/UVC/UIToolkit/Window/UTKImageListWindow.cs +++ b/Assets/Scripts/UVC/UIToolkit/Window/UTKImageListWindow.cs @@ -439,10 +439,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -464,6 +474,8 @@ namespace UVC.UIToolkit // 테마 변경 이벤트 해제 UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); // 내부 UTKImageList 정리 _imageList?.Dispose(); diff --git a/Assets/Scripts/UVC/UIToolkit/Window/UTKPropertyListWindow.cs b/Assets/Scripts/UVC/UIToolkit/Window/UTKPropertyListWindow.cs index 07edd6f5..78cf4b84 100644 --- a/Assets/Scripts/UVC/UIToolkit/Window/UTKPropertyListWindow.cs +++ b/Assets/Scripts/UVC/UIToolkit/Window/UTKPropertyListWindow.cs @@ -8,8 +8,65 @@ using UnityEngine.UIElements; namespace UVC.UIToolkit { /// - /// UTKPropertyList를 감싸는 윈도우 래퍼 - /// 헤더, 타이틀, 닫기 버튼 등 윈도우 프레임 제공 + /// UTKPropertyList를 감싸는 윈도우 래퍼입니다. + /// 헤더(타이틀 + 닫기 버튼), 드래그 이동, 그리고 내부 UTKPropertyList를 통한 + /// 속성 목록 관리 기능을 제공합니다. + /// + /// 주요 기능: + /// + /// 윈도우 프레임 (헤더, 타이틀, 닫기 버튼) + /// 헤더 드래그로 위치 이동 + /// UTKPropertyList 위임 메서드 (데이터 로드, 속성 관리, 값 변경 등) + /// 속성 값 변경 / 클릭 / 버튼 클릭 이벤트 + /// + /// + /// 관련 리소스: + /// + /// Resources/UIToolkit/Window/UTKPropertyListWindow.uxml + /// Resources/UIToolkit/Window/UTKPropertyListWindowUss.uss + /// + /// + /// 사용 예: + /// + /// // 1. 윈도우 생성 및 설정 + /// var window = new UTKPropertyListWindow("속성 편집기"); + /// window.ShowCloseButton = true; + /// window.SetSize(300, 600); + /// + /// // 2. 이벤트 구독 + /// window.OnCloseClicked += () => window.Hide(); + /// window.OnPropertyValueChanged += args => + /// { + /// Debug.Log($"{args.PropertyId} = {args.NewValue}"); + /// + /// // 조건부 가시성 제어 예시 + /// if (args.PropertyId == "type" && args.NewValue is string type) + /// { + /// window.SetPropertyVisibilityBatch(new (string, bool)[] + /// { + /// ("option_a", type == "A"), + /// ("option_b", type == "B"), + /// }); + /// } + /// }; + /// + /// // 3. 데이터 로드 (그룹 + 개별 아이템 혼합) + /// var entries = new List<IUTKPropertyEntry>(); + /// entries.Add(new UTKStringPropertyItem("name", "이름", "기본값")); + /// + /// var group = new UTKPropertyGroup("transform", "Transform"); + /// group.AddItem(new UTKVector3PropertyItem("pos", "Position", Vector3.zero)); + /// entries.Add(group); + /// + /// window.LoadMixedProperties(entries); + /// + /// // 4. 런타임 속성 제어 + /// window.SetPropertyReadOnly("name", true); // 읽기 전용 전환 + /// window.SetPropertyVisibility("pos", false); // 숨김 + /// window.UpdatePropertyValue("name", "새 이름"); // 값 변경 + /// + /// root.Add(window); + /// /// [UxmlElement] public partial class UTKPropertyListWindow : VisualElement, IDisposable @@ -222,57 +279,151 @@ namespace UVC.UIToolkit } #endregion - #region Public Methods - PropertyList 위임 + #region Public Methods - Data Loading (PropertyList 위임) + /// 평면 속성 목록을 로드합니다 (그룹 없이). + /// 로드할 속성 아이템 목록. public void LoadProperties(List items) => PropertyList.LoadProperties(items); + + /// 그룹화된 속성 목록을 로드합니다. + /// 로드할 속성 그룹 목록. public void LoadGroupedProperties(List groups) => PropertyList.LoadGroupedProperties(groups); + + /// 그룹과 개별 아이템이 혼합된 엔트리 목록을 로드합니다. + /// 로드할 엔트리 목록 (IUTKPropertyGroup 또는 IUTKPropertyItem). public void LoadMixedProperties(List entries) => PropertyList.LoadMixedProperties(entries); + #endregion + #region Public Methods - Group Management (PropertyList 위임) + /// 그룹을 추가합니다. + /// 추가할 속성 그룹. public void AddGroup(IUTKPropertyGroup group) => PropertyList.AddGroup(group); + + /// 지정한 ID의 그룹과 내부 아이템을 모두 제거합니다. + /// 제거할 그룹 ID. public void RemoveGroup(string groupId) => PropertyList.RemoveGroup(groupId); + + /// 지정한 ID의 그룹을 반환합니다. + /// 조회할 그룹 ID. + /// 그룹 인스턴스 또는 null. public IUTKPropertyGroup? GetGroup(string groupId) => PropertyList.GetGroup(groupId); + + /// 그룹의 펼침/접힘 상태를 설정합니다. + /// 대상 그룹 ID. + /// true면 펼침, false면 접힘. public void SetGroupExpanded(string groupId, bool expanded) => PropertyList.SetGroupExpanded(groupId, expanded); + + /// 그룹의 펼침/접힘 상태를 토글합니다. + /// 대상 그룹 ID. public void ToggleGroupExpanded(string groupId) => PropertyList.ToggleGroupExpanded(groupId); + #endregion + #region Public Methods - Property Management (PropertyList 위임) + /// 최상위 속성 아이템을 추가합니다. + /// 추가할 속성 아이템. public void AddProperty(IUTKPropertyItem item) => PropertyList.AddProperty(item); + + /// 지정한 그룹에 속성 아이템을 추가합니다. + /// 대상 그룹 ID. + /// 추가할 속성 아이템. public void AddPropertyToGroup(string groupId, IUTKPropertyItem item) => PropertyList.AddPropertyToGroup(groupId, item); + + /// 지정한 ID의 속성 아이템을 제거합니다. + /// 제거할 아이템 ID. public void RemoveProperty(string itemId) => PropertyList.RemoveProperty(itemId); + + /// 지정한 ID의 속성 아이템을 반환합니다. + /// 조회할 아이템 ID. + /// 아이템 인스턴스 또는 null. public IUTKPropertyItem? GetProperty(string itemId) => PropertyList.GetProperty(itemId); + #endregion - public void UpdatePropertyValue(string propertyId, object newValue) => PropertyList.UpdatePropertyValue(propertyId, newValue); - public void SetPropertyValue(string propertyId, object value) => PropertyList.SetPropertyValue(propertyId, value); + #region Public Methods - Value Management (PropertyList 위임) + /// 속성 값을 변경합니다. 바인딩된 View에 자동 반영됩니다. + /// 대상 속성 ID. + /// 새 값 (타입 변환 자동 시도). + /// true면 값 변경 알림 이벤트 발생. + public void UpdatePropertyValue(string propertyId, object newValue, bool notify = false) => PropertyList.UpdatePropertyValue(propertyId, newValue, notify); + /// 속성 값을 변경합니다. 의 별칭입니다. + /// 대상 속성 ID. + /// 새 값. + /// true면 값 변경 알림 이벤트 발생. + public void SetPropertyValue(string propertyId, object value, bool notify = false) => PropertyList.SetPropertyValue(propertyId, value, notify); + #endregion + + #region Public Methods - Visibility & ReadOnly (PropertyList 위임) + /// 속성 아이템의 가시성을 변경합니다. TreeView Rebuild가 발생합니다. + /// 대상 속성 ID. + /// true면 표시, false면 숨김. public void SetPropertyVisibility(string propertyId, bool visible) => PropertyList.SetPropertyVisibility(propertyId, visible); - public void SetGroupVisibility(string groupId, bool visible) => PropertyList.SetGroupVisibility(groupId, visible); - public void SetPropertyReadOnly(string propertyId, bool isReadOnly) => PropertyList.SetPropertyReadOnly(propertyId, isReadOnly); - public void SetGroupReadOnly(string groupId, bool isReadOnly) => PropertyList.SetGroupReadOnly(groupId, isReadOnly); + /// 여러 속성의 가시성을 일괄 변경합니다. TreeView는 마지막에 한 번만 갱신됩니다. + /// 변경할 (속성 ID, 가시성) 튜플 목록. + public void SetPropertyVisibilityBatch(IEnumerable<(string propertyId, bool visible)> changes) => PropertyList.SetPropertyVisibilityBatch(changes); + + /// 그룹의 가시성을 변경합니다. TreeView Rebuild가 발생합니다. + /// 대상 그룹 ID. + /// true면 표시, false면 숨김. + public void SetGroupVisibility(string groupId, bool visible) => PropertyList.SetGroupVisibility(groupId, visible); + + /// 속성 아이템의 읽기 전용 상태를 변경합니다. OnStateChanged로 View에 자동 반영됩니다. + /// 대상 속성 ID. + /// true면 읽기 전용. + public void SetPropertyReadOnly(string propertyId, bool isReadOnly) => PropertyList.SetPropertyReadOnly(propertyId, isReadOnly); + + /// 그룹 내 모든 아이템의 읽기 전용 상태를 일괄 변경합니다. + /// 대상 그룹 ID. + /// true면 읽기 전용. + public void SetGroupReadOnly(string groupId, bool isReadOnly) => PropertyList.SetGroupReadOnly(groupId, isReadOnly); + #endregion + + #region Public Methods - Utilities (PropertyList 위임) + /// 모든 엔트리(그룹 + 아이템)를 제거하고 초기화합니다. public void Clear() => PropertyList.Clear(); + + /// 현재 데이터를 기반으로 TreeView를 다시 빌드합니다. public void Refresh() => PropertyList.Refresh(); #endregion #region Public Methods - Window + /// 윈도우를 표시합니다. public void Show() { style.display = DisplayStyle.Flex; } + /// 윈도우를 숨깁니다. public void Hide() { style.display = DisplayStyle.None; } + /// + /// 윈도우의 위치를 설정합니다 (absolute 포지셔닝). + /// + /// 왼쪽 오프셋 (px). + /// 상단 오프셋 (px). public void SetPosition(float x, float y) { style.left = x; style.top = y; } + /// + /// 윈도우의 크기를 설정합니다. + /// + /// 너비 (px). + /// 높이 (px). public void SetSize(float width, float height) { style.width = width; style.height = height; } + /// + /// 부모 요소 기준으로 윈도우를 중앙에 배치합니다. + /// schedule.Execute로 다음 프레임에 실행됩니다. + /// public void CenterOnScreen() { schedule.Execute(() => @@ -325,10 +476,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -346,6 +507,8 @@ namespace UVC.UIToolkit // 테마 변경 이벤트 해제 UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); // 드래그 이벤트 해제 if (_header != null) diff --git a/Assets/Scripts/UVC/UIToolkit/Window/UTKTreeListWindow.cs b/Assets/Scripts/UVC/UIToolkit/Window/UTKTreeListWindow.cs index 7ebce755..c4f3a062 100644 --- a/Assets/Scripts/UVC/UIToolkit/Window/UTKTreeListWindow.cs +++ b/Assets/Scripts/UVC/UIToolkit/Window/UTKTreeListWindow.cs @@ -1378,10 +1378,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -1402,6 +1412,8 @@ namespace UVC.UIToolkit // 테마 변경 이벤트 해제 UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); // 검색 필드 이벤트 해제 if (_searchField != null) diff --git a/CLAUDE.md b/CLAUDE.md index f18c3ce2..89068f85 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -498,10 +498,20 @@ namespace UVC.UIToolkit private void SubscribeToThemeChanges() { UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; - RegisterCallback(_ => - { - UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; - }); + RegisterCallback(OnAttachToPanelForTheme); + RegisterCallback(OnDetachFromPanelForTheme); + } + + private void OnAttachToPanelForTheme(AttachToPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; + UTKThemeManager.Instance.ApplyThemeToElement(this); + } + + private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt) + { + UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; } private void OnThemeChanged(UTKTheme theme) @@ -517,6 +527,8 @@ namespace UVC.UIToolkit _disposed = true; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; + UnregisterCallback(OnAttachToPanelForTheme); + UnregisterCallback(OnDetachFromPanelForTheme); } #endregion }