UTKProperyItem 수정 중

This commit is contained in:
logonkhi
2026-02-10 20:48:49 +09:00
parent 97bbb789ed
commit df6d3e3b5a
112 changed files with 2898 additions and 443 deletions

View File

@@ -37,7 +37,7 @@
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
min-width: 120px; min-width: 100px;
flex-grow: 1; flex-grow: 1;
height: var(--size-input-height); height: var(--size-input-height);
padding-top: 0px; padding-top: 0px;

View File

@@ -0,0 +1,26 @@
<ui:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ui="UnityEngine.UIElements"
xmlns:utk="UVC.UIToolkit"
noNamespaceSchemaLocation="../../../../../UIElementsSchema/UIElements.xsd"
editor-extension-mode="False">
<!--
UTKPropertyGroupHeader.uxml
UTKPropertyList에서 그룹 헤더 항목을 표시하는 템플릿입니다.
펼침/접힘 아이콘, 그룹 이름, 아이템 개수를 표시합니다.
구조:
- group-header: 그룹 헤더 컨테이너
- expand-icon: UTKLabel 펼침/접힘 아이콘
- group-title: UTKLabel 그룹 이름
- group-count: UTKLabel 아이템 개수 - 현재 사용 안 함
관련 스타일:
- Resources/UIToolkit/List/UTKPropertyListUss.uss
-->
<ui:VisualElement name="group-header" class="utk-property-group__header">
<utk:UTKLabel name="expand-icon" class="utk-property-group__expand-icon" />
<utk:UTKLabel name="group-title" class="utk-property-group__title" />
<!-- <utk:UTKLabel name="group-count" class="utk-property-group__count" /> -->
</ui:VisualElement>
</ui:UXML>

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 25fa8d693a22bc249a06e7590195db6b
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}

View File

@@ -0,0 +1,10 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:utk="UVC.UIToolkit" editor-extension-mode="False">
<ui:VisualElement name="container" class="utk-property-item-view-container">
<utk:UTKLabel name="label" text="Label" class="utk-property-item-view__label" />
<ui:VisualElement name="value-container" class="utk-property-item-view__value">
<utk:UTKFloatField name="float-field" class="utk-float-dropdown-view__float-field" />
<utk:UTKFloatStepper name="stepper-field" class="utk-float-dropdown-view__stepper" />
<utk:UTKDropdown name="dropdown-field" class="utk-float-dropdown-view__dropdown" />
</ui:VisualElement>
</ui:VisualElement>
</ui:UXML>

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: d18bd23679149a241aebfeb54061818f
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:utk="UVC.UIToolkit" editor-extension-mode="False">
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:utk="UVC.UIToolkit">
<ui:VisualElement name="container" class="utk-property-item-view-container"> <ui:VisualElement name="container" class="utk-property-item-view-container">
<utk:UTKLabel name="label" text="Label" class="utk-property-item-view__label" /> <utk:UTKLabel name="label" text="Label" class="utk-property-item-view__label" />
<ui:VisualElement name="value-container" class="utk-property-item-view__value"> <ui:VisualElement name="value-container" class="utk-property-item-view__value">
<utk:UTKFloatField name="min-field" class="utk-property-item-view__field" /> <utk:UTKFloatField name="min-field" class="utk-property-item-view__field" />
<utk:UTKFloatStepper name="min-stepper" class="utk-property-item-view__stepper" />
<utk:UTKLabel text="~" class="utk-property-item-view__range-separator" /> <utk:UTKLabel text="~" class="utk-property-item-view__range-separator" />
<utk:UTKFloatField name="max-field" class="utk-property-item-view__field" /> <utk:UTKFloatField name="max-field" class="utk-property-item-view__field" />
<utk:UTKFloatStepper name="max-stepper" class="utk-property-item-view__stepper" />
</ui:VisualElement> </ui:VisualElement>
</ui:VisualElement> </ui:VisualElement>
</ui:UXML> </ui:UXML>

View File

@@ -9,9 +9,18 @@
.utk-property-item-view--float-range .utk-property-item-view__field { .utk-property-item-view--float-range .utk-property-item-view__field {
flex-grow: 1; flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
} }
.utk-property-item-view--float-range .utk-property-item-view__range-separator { .utk-property-item-view--float-range .utk-property-item-view__range-separator {
margin: 0 8px; margin: 0 8px;
-unity-text-align: middle-center; -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;
}

View File

@@ -80,6 +80,12 @@ namespace UVC.Sample.UIToolkit
_propertyWindow.OnPropertyValueChanged += args => _propertyWindow.OnPropertyValueChanged += args =>
{ {
Debug.Log($"Property Changed: {args.PropertyId} {args.PropertyName} ({args.PropertyType}) = {args.NewValue}"); 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 => _propertyWindow.OnPropertyClicked += args =>
@@ -134,14 +140,8 @@ namespace UVC.Sample.UIToolkit
// Bool (편집 가능) // Bool (편집 가능)
entries.Add(new UTKBoolPropertyItem("bool", "Bool", true)); 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 (읽기 전용) // Bool (읽기 전용)
var roBool = new UTKBoolPropertyItem("bool_ro", "Bool (RO)", true); var roBool = new UTKBoolPropertyItem("bool_ro", "Bool (RO)", true, true);
roBool.IsReadOnly = true;
entries.Add(roBool); entries.Add(roBool);
// Int (편집 가능) // Int (편집 가능)
@@ -312,13 +312,52 @@ namespace UVC.Sample.UIToolkit
// FloatRange (편집 가능) // FloatRange (편집 가능)
entries.Add(new UTKFloatRangePropertyItem("floatrange", "FloatRange", 1.5f, 8.5f)); entries.Add(new UTKFloatRangePropertyItem("floatrange", "FloatRange", 1.5f, 8.5f));
// FloatRange (읽기 전용) // FloatRange (읽기 전용)
var roFloatRange = new UTKFloatRangePropertyItem("floatrange_ro", "FloatRange (RO)", 2.5f, 7.5f); var roFloatRange = new UTKFloatRangePropertyItem("floatrange_ro", "FloatRange (RO)", 2.5f, 7.5f);
roFloatRange.IsReadOnly = true; roFloatRange.IsReadOnly = true;
entries.Add(roFloatRange); 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<string> { "mm", "cm", "m", "km" }, "cm"));
// FloatDropdown (Stepper + Dropdown)
entries.Add(new UTKFloatDropdownPropertyItem("floatdropdown2", "FloatDropdown Stepper",
10.0f, new List<string> { "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<string> { "mm", "cm", "m", "km" }, "km", isReadOnly: true));
// ===== Group에 속한 아이템들 ===== // ===== Group에 속한 아이템들 =====
var timeList = new List<string> { "초(sec)", "분(min)", "시간(hour)" };
var gapGroup = new UTKPropertyGroup("gap", "생산 간격 정책");
gapGroup.AddItem(new UTKDropdownPropertyItem("gap_type", "간격 타입",
new List<string> { "상수", "정규 분포", "균등 분포", "지수 분포", "삼각 분포" }, "상수", 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)"); var basicGroup = new UTKPropertyGroup("basic", "Basic Properties (Editable)");
@@ -549,6 +588,30 @@ namespace UVC.Sample.UIToolkit
return entries; return entries;
} }
/// <summary>
/// gap_type 값에 따라 해당 분포 속성의 가시성을 전환합니다.
/// </summary>
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() private void OnDestroy()
{ {
_propertyWindow?.Dispose(); _propertyWindow?.Dispose();

View File

@@ -166,10 +166,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -255,6 +265,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
} }
#endregion #endregion

View File

@@ -120,10 +120,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -167,6 +177,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
UnregisterCallback<ChangeEvent<bool>>(OnRadioValueChanged); UnregisterCallback<ChangeEvent<bool>>(OnRadioValueChanged);
} }

View File

@@ -143,10 +143,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -219,6 +229,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
UnregisterCallback<ChangeEvent<bool>>(OnToggleValueChanged); UnregisterCallback<ChangeEvent<bool>>(OnToggleValueChanged);
UnregisterCallback<MouseDownEvent>(OnMouseDown, TrickleDown.TrickleDown); UnregisterCallback<MouseDownEvent>(OnMouseDown, TrickleDown.TrickleDown);

View File

@@ -104,10 +104,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -156,6 +166,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnSelectionChanged = null; OnSelectionChanged = null;
UnregisterCallback<ChangeEvent<ToggleButtonGroupState>>(OnValueChanged); UnregisterCallback<ChangeEvent<ToggleButtonGroupState>>(OnValueChanged);
} }

View File

@@ -277,10 +277,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -412,6 +422,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnClicked = null; OnClicked = null;
} }
#endregion #endregion

View File

@@ -132,10 +132,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -158,6 +168,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
UnregisterCallback<ChangeEvent<bool>>(OnFoldoutValueChanged); UnregisterCallback<ChangeEvent<bool>>(OnFoldoutValueChanged);
} }

View File

@@ -226,10 +226,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -245,6 +255,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
} }
#endregion #endregion
} }

View File

@@ -230,10 +230,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -484,6 +494,8 @@ namespace UVC.UIToolkit
CleanupExternalTexture(); CleanupExternalTexture();
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnImageLoaded = null; OnImageLoaded = null;
OnImageFailed = null; OnImageFailed = null;
} }

View File

@@ -112,10 +112,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -131,6 +141,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
} }
#endregion #endregion
} }

View File

@@ -293,10 +293,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -568,6 +578,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnSelectionChanged = null; OnSelectionChanged = null;
_inputContainer?.UnregisterCallback<ClickEvent>(OnInputClicked); _inputContainer?.UnregisterCallback<ClickEvent>(OnInputClicked);

View File

@@ -273,10 +273,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -527,6 +537,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
_inputContainer?.UnregisterCallback<ClickEvent>(OnInputClicked); _inputContainer?.UnregisterCallback<ClickEvent>(OnInputClicked);

View File

@@ -287,10 +287,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -596,6 +606,8 @@ namespace UVC.UIToolkit
ClearCheckBoxes(); ClearCheckBoxes();
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnSelectionChanged = null; OnSelectionChanged = null;
_inputContainer?.UnregisterCallback<ClickEvent>(OnInputClicked); _inputContainer?.UnregisterCallback<ClickEvent>(OnInputClicked);

View File

@@ -243,10 +243,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -302,6 +312,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
UnregisterCallback<ChangeEvent<Bounds>>(OnFieldValueChanged); UnregisterCallback<ChangeEvent<Bounds>>(OnFieldValueChanged);
} }

View File

@@ -138,10 +138,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -164,6 +174,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
UnregisterCallback<ChangeEvent<double>>(OnFieldValueChanged); UnregisterCallback<ChangeEvent<double>>(OnFieldValueChanged);
} }

View File

@@ -137,10 +137,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -163,6 +173,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
UnregisterCallback<ChangeEvent<float>>(OnFieldValueChanged); UnregisterCallback<ChangeEvent<float>>(OnFieldValueChanged);
} }

View File

@@ -208,12 +208,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
}
// 패널에서 분리될 때 이벤트 구독 해제 private void OnAttachToPanelForTheme(AttachToPanelEvent evt)
RegisterCallback<DetachFromPanelEvent>(_ => {
{ UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
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) private void OnThemeChanged(UTKTheme theme)
@@ -454,6 +462,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
// 이벤트 콜백 해제 // 이벤트 콜백 해제
_upButton?.UnregisterCallback<ClickEvent>(OnUpButtonClick); _upButton?.UnregisterCallback<ClickEvent>(OnUpButtonClick);

View File

@@ -224,10 +224,21 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -304,6 +315,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
UnregisterCallback<ChangeEvent<string>>(OnTextValueChanged); UnregisterCallback<ChangeEvent<string>>(OnTextValueChanged);
OnValueChanged = null; OnValueChanged = null;
OnFocused = null; OnFocused = null;

View File

@@ -209,12 +209,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
}
// 패널에서 분리될 때 이벤트 구독 해제 private void OnAttachToPanelForTheme(AttachToPanelEvent evt)
RegisterCallback<DetachFromPanelEvent>(_ => {
{ UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
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) private void OnThemeChanged(UTKTheme theme)
@@ -455,6 +463,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
// 이벤트 콜백 해제 // 이벤트 콜백 해제
_upButton?.UnregisterCallback<ClickEvent>(OnUpButtonClick); _upButton?.UnregisterCallback<ClickEvent>(OnUpButtonClick);

View File

@@ -136,10 +136,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -162,6 +172,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
UnregisterCallback<ChangeEvent<int>>(OnFieldValueChanged); UnregisterCallback<ChangeEvent<int>>(OnFieldValueChanged);
} }

View File

@@ -130,10 +130,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -156,6 +166,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
UnregisterCallback<ChangeEvent<long>>(OnFieldValueChanged); UnregisterCallback<ChangeEvent<long>>(OnFieldValueChanged);
} }

View File

@@ -226,10 +226,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -275,6 +285,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
UnregisterCallback<ChangeEvent<Rect>>(OnFieldValueChanged); UnregisterCallback<ChangeEvent<Rect>>(OnFieldValueChanged);
} }

View File

@@ -203,10 +203,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -250,6 +260,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
UnregisterCallback<ChangeEvent<Vector2>>(OnFieldValueChanged); UnregisterCallback<ChangeEvent<Vector2>>(OnFieldValueChanged);
} }

View File

@@ -222,10 +222,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -270,6 +280,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
UnregisterCallback<ChangeEvent<Vector3>>(OnFieldValueChanged); UnregisterCallback<ChangeEvent<Vector3>>(OnFieldValueChanged);
} }

View File

@@ -232,10 +232,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -281,6 +291,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
UnregisterCallback<ChangeEvent<Vector4>>(OnFieldValueChanged); UnregisterCallback<ChangeEvent<Vector4>>(OnFieldValueChanged);
} }

View File

@@ -1666,10 +1666,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -1688,6 +1698,8 @@ namespace UVC.UIToolkit
// 테마 변경 이벤트 해제 // 테마 변경 이벤트 해제
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
// 이미지 로딩 취소 // 이미지 로딩 취소
CancelImageLoading(); CancelImageLoading();

View File

@@ -1675,10 +1675,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -1699,6 +1709,8 @@ namespace UVC.UIToolkit
// 테마 변경 이벤트 해제 // 테마 변경 이벤트 해제
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
// 검색 필드 이벤트 해제 // 검색 필드 이벤트 해제
if (_searchField != null) if (_searchField != null)

View File

@@ -1243,10 +1243,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -1268,6 +1278,8 @@ namespace UVC.UIToolkit
// 테마 변경 이벤트 해제 // 테마 변경 이벤트 해제
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
// 이미지 로딩 취소 // 이미지 로딩 취소
CancelImageLoading(); CancelImageLoading();

View File

@@ -164,10 +164,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -197,6 +207,8 @@ namespace UVC.UIToolkit
selectionChanged -= OnSelectionChanged; selectionChanged -= OnSelectionChanged;
itemsChosen -= OnItemsChosen; itemsChosen -= OnItemsChosen;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnItemSelected = null; OnItemSelected = null;
OnItemDoubleClicked = null; OnItemDoubleClicked = null;
} }

View File

@@ -60,10 +60,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -93,6 +103,8 @@ namespace UVC.UIToolkit
selectionChanged -= OnSelectionChanged; selectionChanged -= OnSelectionChanged;
itemsChosen -= OnItemsChosen; itemsChosen -= OnItemsChosen;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnItemSelected = null; OnItemSelected = null;
OnItemDoubleClicked = null; OnItemDoubleClicked = null;
} }

View File

@@ -60,10 +60,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -93,6 +103,8 @@ namespace UVC.UIToolkit
selectionChanged -= OnSelectionChanged; selectionChanged -= OnSelectionChanged;
itemsChosen -= OnItemsChosen; itemsChosen -= OnItemsChosen;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnItemSelected = null; OnItemSelected = null;
OnItemDoubleClicked = null; OnItemDoubleClicked = null;
} }

View File

@@ -38,6 +38,7 @@ namespace UVC.UIToolkit
#region Constants #region Constants
private const string UXML_PATH = "UIToolkit/List/UTKPropertyList"; private const string UXML_PATH = "UIToolkit/List/UTKPropertyList";
private const string USS_PATH = "UIToolkit/List/UTKPropertyListUss"; private const string USS_PATH = "UIToolkit/List/UTKPropertyListUss";
private const string GROUP_HEADER_UXML_PATH = "UIToolkit/List/UTKPropertyGroupHeader";
#endregion #endregion
#region Fields #region Fields
@@ -53,6 +54,8 @@ namespace UVC.UIToolkit
private int _nextTreeViewId = 1; private int _nextTreeViewId = 1;
private string _searchText = string.Empty; private string _searchText = string.Empty;
private static VisualTreeAsset? _groupHeaderUxmlCache;
#endregion #endregion
#region Events #region Events
@@ -172,10 +175,19 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanel);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanel);
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; }
});
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) private void OnThemeChanged(UTKTheme theme)
@@ -234,12 +246,20 @@ namespace UVC.UIToolkit
#endregion #endregion
#region Public Methods - Group Management #region Public Methods - Group Management
/// <summary>
/// 그룹을 추가하고 TreeView를 갱신합니다.
/// </summary>
/// <param name="group">추가할 속성 그룹.</param>
public void AddGroup(IUTKPropertyGroup group) public void AddGroup(IUTKPropertyGroup group)
{ {
AddGroupInternal(group); AddGroupInternal(group);
RefreshTreeView(); RefreshTreeView();
} }
/// <summary>
/// 지정한 ID의 그룹과 그룹 내 모든 아이템을 제거합니다.
/// </summary>
/// <param name="groupId">제거할 그룹 ID.</param>
public void RemoveGroup(string groupId) public void RemoveGroup(string groupId)
{ {
if (_groupIndex.TryGetValue(groupId, out var group)) if (_groupIndex.TryGetValue(groupId, out var group))
@@ -259,11 +279,21 @@ namespace UVC.UIToolkit
} }
} }
/// <summary>
/// 지정한 ID의 그룹을 반환합니다.
/// </summary>
/// <param name="groupId">조회할 그룹 ID.</param>
/// <returns>그룹 인스턴스 또는 null.</returns>
public IUTKPropertyGroup? GetGroup(string groupId) public IUTKPropertyGroup? GetGroup(string groupId)
{ {
return _groupIndex.TryGetValue(groupId, out var group) ? group : null; return _groupIndex.TryGetValue(groupId, out var group) ? group : null;
} }
/// <summary>
/// 그룹의 펼침/접힘 상태를 설정합니다.
/// </summary>
/// <param name="groupId">대상 그룹 ID.</param>
/// <param name="expanded">true면 펼침, false면 접힘.</param>
public void SetGroupExpanded(string groupId, bool expanded) public void SetGroupExpanded(string groupId, bool expanded)
{ {
if (_groupIndex.TryGetValue(groupId, out var group)) if (_groupIndex.TryGetValue(groupId, out var group))
@@ -280,6 +310,10 @@ namespace UVC.UIToolkit
} }
} }
/// <summary>
/// 그룹의 펼침/접힘 상태를 토글합니다.
/// </summary>
/// <param name="groupId">대상 그룹 ID.</param>
public void ToggleGroupExpanded(string groupId) public void ToggleGroupExpanded(string groupId)
{ {
if (_groupIndex.TryGetValue(groupId, out var group)) if (_groupIndex.TryGetValue(groupId, out var group))
@@ -290,12 +324,21 @@ namespace UVC.UIToolkit
#endregion #endregion
#region Public Methods - Property Management #region Public Methods - Property Management
/// <summary>
/// 최상위 속성 아이템을 추가하고 TreeView를 갱신합니다.
/// </summary>
/// <param name="item">추가할 속성 아이템.</param>
public void AddProperty(IUTKPropertyItem item) public void AddProperty(IUTKPropertyItem item)
{ {
AddPropertyInternal(item); AddPropertyInternal(item);
RefreshTreeView(); RefreshTreeView();
} }
/// <summary>
/// 지정한 그룹에 속성 아이템을 추가하고 TreeView를 갱신합니다.
/// </summary>
/// <param name="groupId">대상 그룹 ID.</param>
/// <param name="item">추가할 속성 아이템.</param>
public void AddPropertyToGroup(string groupId, IUTKPropertyItem item) public void AddPropertyToGroup(string groupId, IUTKPropertyItem item)
{ {
if (_groupIndex.TryGetValue(groupId, out var group)) if (_groupIndex.TryGetValue(groupId, out var group))
@@ -307,6 +350,11 @@ namespace UVC.UIToolkit
} }
} }
/// <summary>
/// 지정한 ID의 속성 아이템을 제거하고 TreeView를 갱신합니다.
/// 그룹에 속한 아이템이면 그룹에서도 제거됩니다.
/// </summary>
/// <param name="itemId">제거할 아이템 ID.</param>
public void RemoveProperty(string itemId) public void RemoveProperty(string itemId)
{ {
if (_itemIndex.TryGetValue(itemId, out var item)) if (_itemIndex.TryGetValue(itemId, out var item))
@@ -328,6 +376,11 @@ namespace UVC.UIToolkit
} }
} }
/// <summary>
/// 지정한 ID의 속성 아이템을 반환합니다.
/// </summary>
/// <param name="itemId">조회할 아이템 ID.</param>
/// <returns>아이템 인스턴스 또는 null.</returns>
public IUTKPropertyItem? GetProperty(string itemId) public IUTKPropertyItem? GetProperty(string itemId)
{ {
return _itemIndex.TryGetValue(itemId, out var item) ? item : null; return _itemIndex.TryGetValue(itemId, out var item) ? item : null;
@@ -335,37 +388,85 @@ namespace UVC.UIToolkit
#endregion #endregion
#region Public Methods - Value Management #region Public Methods - Value Management
public void UpdatePropertyValue(string propertyId, object newValue) /// <summary>
/// 속성 값을 변경합니다. 바인딩된 View에 OnTypedValueChanged 이벤트로 자동 반영됩니다.
/// </summary>
/// <param name="propertyId">대상 속성 ID.</param>
/// <param name="newValue">새 값 (타입 변환 자동 시도).</param>
/// <param name="notify">true면 값 변경 알림 이벤트 발생.</param>
public void UpdatePropertyValue(string propertyId, object newValue, bool notify = false)
{ {
if (_itemIndex.TryGetValue(propertyId, out var item)) if (_itemIndex.TryGetValue(propertyId, out var item))
{ {
item.SetValue(newValue); item.SetValue(newValue, notify);
} }
} }
public void SetPropertyValue(string propertyId, object value) /// <summary>
/// 속성 값을 변경합니다. <see cref="UpdatePropertyValue"/>의 별칭입니다.
/// </summary>
/// <param name="propertyId">대상 속성 ID.</param>
/// <param name="value">새 값.</param>
/// <param name="notify">true면 값 변경 알림 이벤트 발생.</param>
public void SetPropertyValue(string propertyId, object value, bool notify = false)
{ {
UpdatePropertyValue(propertyId, value); UpdatePropertyValue(propertyId, value, notify);
} }
#endregion #endregion
#region Public Methods - Visibility & ReadOnly #region Public Methods - Visibility & ReadOnly
/// <summary>
/// 속성 아이템의 가시성을 변경합니다. TreeView 항목이 추가/제거되므로 Rebuild가 발생합니다.
/// </summary>
/// <param name="propertyId">대상 속성 ID.</param>
/// <param name="visible">true면 표시, false면 숨김.</param>
public void SetPropertyVisibility(string propertyId, bool visible) public void SetPropertyVisibility(string propertyId, bool visible)
{ {
if (_itemIndex.TryGetValue(propertyId, out var item)) if (_itemIndex.TryGetValue(propertyId, out var item))
{ {
if (item.IsVisible == visible) return;
item.IsVisible = visible; item.IsVisible = visible;
RefreshTreeViewLight();
} }
} }
/// <summary>여러 속성의 가시성을 일괄 변경합니다. TreeView는 마지막에 한 번만 갱신됩니다.</summary>
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();
}
/// <summary>
/// 그룹의 가시성을 변경합니다. TreeView 항목이 추가/제거되므로 Rebuild가 발생합니다.
/// </summary>
/// <param name="groupId">대상 그룹 ID.</param>
/// <param name="visible">true면 표시, false면 숨김.</param>
public void SetGroupVisibility(string groupId, bool visible) public void SetGroupVisibility(string groupId, bool visible)
{ {
if (_groupIndex.TryGetValue(groupId, out var group)) if (_groupIndex.TryGetValue(groupId, out var group))
{ {
if (group.IsVisible == visible) return;
group.IsVisible = visible; group.IsVisible = visible;
RefreshTreeViewLight();
} }
} }
/// <summary>
/// 속성 아이템의 읽기 전용 상태를 변경합니다.
/// OnStateChanged 이벤트를 통해 바인딩된 View에 자동 반영됩니다.
/// </summary>
/// <param name="propertyId">대상 속성 ID.</param>
/// <param name="isReadOnly">true면 읽기 전용.</param>
public void SetPropertyReadOnly(string propertyId, bool isReadOnly) public void SetPropertyReadOnly(string propertyId, bool isReadOnly)
{ {
if (_itemIndex.TryGetValue(propertyId, out var item)) if (_itemIndex.TryGetValue(propertyId, out var item))
@@ -374,6 +475,12 @@ namespace UVC.UIToolkit
} }
} }
/// <summary>
/// 그룹 내 모든 아이템의 읽기 전용 상태를 일괄 변경합니다.
/// OnStateChanged 이벤트를 통해 바인딩된 View에 자동 반영됩니다.
/// </summary>
/// <param name="groupId">대상 그룹 ID.</param>
/// <param name="isReadOnly">true면 읽기 전용.</param>
public void SetGroupReadOnly(string groupId, bool isReadOnly) public void SetGroupReadOnly(string groupId, bool isReadOnly)
{ {
if (_groupIndex.TryGetValue(groupId, out var group)) if (_groupIndex.TryGetValue(groupId, out var group))
@@ -381,25 +488,48 @@ namespace UVC.UIToolkit
group.SetAllItemsReadOnly(isReadOnly); group.SetAllItemsReadOnly(isReadOnly);
} }
} }
/// <summary>
/// 속성 아이템의 라벨 표시 여부를 변경합니다.
/// OnStateChanged 이벤트를 통해 바인딩된 View에 자동 반영됩니다.
/// </summary>
/// <param name="propertyId">대상 속성 ID.</param>
/// <param name="showLabel">true면 라벨 표시, false면 값이 전체 너비 사용.</param>
public void SetPropertyShowLabel(string propertyId, bool showLabel)
{
if (_itemIndex.TryGetValue(propertyId, out var item))
{
item.ShowLabel = showLabel;
}
}
#endregion #endregion
#region Public Methods - Utilities #region Public Methods - Utilities
public void Clear() /// <summary>
/// 모든 엔트리(그룹 + 아이템)를 제거하고 TreeView를 초기화합니다.
/// VisualElement.Clear()를 숨깁니다(new).
/// </summary>
public new void Clear()
{ {
ClearInternal(); ClearInternal();
RefreshTreeView(); RefreshTreeView();
} }
/// <summary>
/// 현재 데이터를 기반으로 TreeView를 다시 빌드합니다.
/// </summary>
public void Refresh() public void Refresh()
{ {
RefreshTreeView(); RefreshTreeView();
} }
/// <summary>리스트를 표시합니다.</summary>
public void Show() public void Show()
{ {
style.display = DisplayStyle.Flex; style.display = DisplayStyle.Flex;
} }
/// <summary>리스트를 숨깁니다.</summary>
public void Hide() public void Hide()
{ {
style.display = DisplayStyle.None; style.display = DisplayStyle.None;
@@ -448,7 +578,10 @@ namespace UVC.UIToolkit
private void ClearInternal() private void ClearInternal()
{ {
// 이벤트 구독 해제 // TreeView 내 바인딩된 View의 이벤트 콜백 정리 및 Dispose
CleanupAllTreeViewContainers();
// 데이터 이벤트 구독 해제
foreach (var group in _groupIndex.Values) foreach (var group in _groupIndex.Values)
{ {
UnsubscribeGroup(group); UnsubscribeGroup(group);
@@ -466,6 +599,19 @@ namespace UVC.UIToolkit
_nextTreeViewId = 1; _nextTreeViewId = 1;
} }
/// <summary>TreeView 내 모든 컨테이너의 콜백과 View를 정리합니다.</summary>
private void CleanupAllTreeViewContainers()
{
if (_treeView == null) return;
_treeView.Query<VisualElement>(className: "utk-property-item-container")
.ForEach(container =>
{
CleanupContainerCallbacks(container);
DisposeChildren(container);
});
}
private void RefreshTreeView() private void RefreshTreeView()
{ {
if (_treeView == null) return; if (_treeView == null) return;
@@ -474,7 +620,29 @@ namespace UVC.UIToolkit
_treeView.SetRootItems(treeItems); _treeView.SetRootItems(treeItems);
_treeView.Rebuild(); _treeView.Rebuild();
// 펼침 상태 복원 RestoreExpandedStates();
}
/// <summary>
/// 경량 TreeView 갱신. 아이템 구조(Visibility 변경 등)만 바뀔 때 사용합니다.
/// Rebuild() 대신 RefreshItems()를 사용하여 기존 컨테이너를 재활용합니다.
/// </summary>
private void RefreshTreeViewLight()
{
if (_treeView == null) return;
var treeItems = BuildTreeItems();
_treeView.SetRootItems(treeItems);
_treeView.RefreshItems();
RestoreExpandedStates();
}
/// <summary>그룹 펼침 상태를 복원합니다.</summary>
private void RestoreExpandedStates()
{
if (_treeView == null) return;
foreach (var group in _groupIndex.Values) foreach (var group in _groupIndex.Values)
{ {
if (group.IsExpanded) if (group.IsExpanded)
@@ -545,6 +713,19 @@ namespace UVC.UIToolkit
#endregion #endregion
#region TreeView Callbacks #region TreeView Callbacks
/// <summary>
/// 컨테이너에 등록된 이벤트 콜백 정보를 보관합니다.
/// View 재사용 시 이전 이벤트를 정리하기 위해 사용합니다.
/// </summary>
private sealed class ContainerCallbackInfo
{
public VisualElement? ItemView;
public EventCallback<ClickEvent>? ClickCallback;
public Action<string>? ButtonClickHandler;
public Action<string>? ActionButtonClickHandler;
}
private VisualElement MakeItem() private VisualElement MakeItem()
{ {
var container = new VisualElement(); var container = new VisualElement();
@@ -557,6 +738,15 @@ namespace UVC.UIToolkit
var itemData = _treeView?.GetItemDataForIndex<IUTKPropertyEntry>(index); var itemData = _treeView?.GetItemDataForIndex<IUTKPropertyEntry>(index);
if (itemData == null) return; if (itemData == null) return;
// 기존 자식 View 재사용 시도
if (itemData is IUTKPropertyItem item && TryRebindExistingView(element, item))
{
return;
}
// 재사용 불가 시 기존 View 정리 후 새로 생성
CleanupContainerCallbacks(element);
DisposeChildren(element);
element.Clear(); element.Clear();
switch (itemData) switch (itemData)
@@ -564,55 +754,146 @@ namespace UVC.UIToolkit
case IUTKPropertyGroup group: case IUTKPropertyGroup group:
BindGroupItem(element, group); BindGroupItem(element, group);
break; break;
case IUTKPropertyItem item: case IUTKPropertyItem newItem:
BindPropertyItem(element, item); BindPropertyItem(element, newItem);
break; break;
} }
} }
private void UnbindItem(VisualElement element, int index) private void UnbindItem(VisualElement element, int index)
{ {
// View에서 직접 Unbind 처리 (IUTKPropertyItemView 구현체인 경우) // Unbind만 수행 (View 인스턴스는 유지하여 재사용 가능)
foreach (var child in element.Children()) foreach (var child in element.Children())
{ {
if (child is IUTKPropertyItemView view) if (child is IUTKPropertyItemView view)
{ {
view.Unbind(); view.Unbind();
} }
}
}
// IDisposable 구현체인 경우 Dispose 호출 /// <summary>
/// 기존 자식 View가 동일 PropertyType이면 Unbind → Bind로 재사용합니다.
/// 이전 이벤트 콜백을 정리하고 새 item으로 재등록합니다.
/// </summary>
/// <returns>재사용 성공 시 true</returns>
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;
}
/// <summary>
/// 컨테이너에 저장된 이벤트 콜백을 해제합니다.
/// </summary>
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;
}
/// <summary>자식 View를 Dispose합니다.</summary>
private static void DisposeChildren(VisualElement element)
{
foreach (var child in element.Children())
{
if (child is IUTKPropertyItemView view)
{
view.Unbind();
}
if (child is IDisposable disposable) if (child is IDisposable disposable)
{ {
disposable.Dispose(); disposable.Dispose();
} }
} }
element.Clear();
} }
private void BindGroupItem(VisualElement container, IUTKPropertyGroup group) private void BindGroupItem(VisualElement container, IUTKPropertyGroup group)
{ {
var groupElement = new VisualElement(); // UXML 로드 (캐시)
groupElement.AddToClassList("utk-property-group__header"); if (_groupHeaderUxmlCache == null)
{
_groupHeaderUxmlCache = Resources.Load<VisualTreeAsset>(GROUP_HEADER_UXML_PATH);
}
var expandIcon = new UTKLabel(group.IsExpanded ? UTKMaterialIcons.ExpandMore : UTKMaterialIcons.ChevronRight, 16); VisualElement groupElement;
expandIcon.AddToClassList("utk-property-group__expand-icon"); 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<VisualElement>("group-header");
expandIcon = root.Q<UTKLabel>("expand-icon");
title = root.Q<UTKLabel>("group-title");
// count = root.Q<UTKLabel>("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.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); // 그룹 클릭 이벤트 - ContainerCallbackInfo로 관리
count.Variant = UTKLabel.LabelVariant.Secondary; EventCallback<ClickEvent> clickCallback = _ =>
count.AddToClassList("utk-property-group__count");
groupElement.Add(expandIcon);
groupElement.Add(title);
groupElement.Add(count);
// 그룹 클릭 이벤트 - DetachFromPanelEvent에서 자동 정리됨
EventCallback<ClickEvent> clickCallback = null!;
clickCallback = _ =>
{ {
ToggleGroupExpanded(group.GroupId); ToggleGroupExpanded(group.GroupId);
expandIcon.SetMaterialIcon(group.IsExpanded ? UTKMaterialIcons.ExpandMore : UTKMaterialIcons.ChevronRight, 16); expandIcon.SetMaterialIcon(group.IsExpanded ? UTKMaterialIcons.ExpandMore : UTKMaterialIcons.ChevronRight, 16);
@@ -621,63 +902,51 @@ namespace UVC.UIToolkit
groupElement.RegisterCallback(clickCallback); groupElement.RegisterCallback(clickCallback);
// DetachFromPanelEvent에서 이벤트 해제 // 컨테이너에 콜백 정보 저장 (CleanupContainerCallbacks에서 정리)
groupElement.RegisterCallback<DetachFromPanelEvent>(evt => container.userData = new ContainerCallbackInfo
{ {
groupElement.UnregisterCallback(clickCallback); ItemView = groupElement,
}); ClickCallback = clickCallback
};
container.Add(groupElement);
} }
private void BindPropertyItem(VisualElement container, IUTKPropertyItem item) private void BindPropertyItem(VisualElement container, IUTKPropertyItem item)
{ {
// View Factory를 사용하여 View 생성 및 바인딩 // View Factory를 사용하여 View 생성 및 바인딩
var itemView = UTKPropertyItemViewFactory.CreateView(item); var itemView = UTKPropertyItemViewFactory.CreateView(item);
container.Add(itemView);
// 클릭 이벤트 등록 - DetachFromPanelEvent에서 자동 정리됨 // 이벤트 콜백 등록 및 컨테이너에 저장
EventCallback<ClickEvent> clickCallback = _ => OnPropertyClicked?.Invoke(item); RegisterPropertyCallbacks(container, itemView, item);
itemView.RegisterCallback(clickCallback); }
/// <summary>
/// PropertyItem View에 이벤트 콜백을 등록하고 컨테이너에 정보를 저장합니다.
/// </summary>
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<string>? buttonClickHandler = null;
if (itemView is UTKButtonItemView buttonView) if (itemView is UTKButtonItemView buttonView)
{ {
buttonClickHandler = (actionName) => info.ButtonClickHandler = actionName => OnPropertyButtonClicked?.Invoke(item.Id, actionName);
{ buttonView.OnButtonClicked += info.ButtonClickHandler;
OnPropertyButtonClicked?.Invoke(item.Id, actionName);
};
buttonView.OnButtonClicked += buttonClickHandler;
} }
// String 아이템에 ActionButton이 있는 경우 이벤트 구독 // String 아이템에 ActionButton이 있는 경우 이벤트 구독
Action<string>? actionButtonClickHandler = null;
if (itemView is UTKStringPropertyItemView stringView) if (itemView is UTKStringPropertyItemView stringView)
{ {
actionButtonClickHandler = (actionName) => info.ActionButtonClickHandler = actionName => OnPropertyButtonClicked?.Invoke(item.Id, actionName);
{ stringView.OnActionButtonClicked += info.ActionButtonClickHandler;
OnPropertyButtonClicked?.Invoke(item.Id, actionName);
};
stringView.OnActionButtonClicked += actionButtonClickHandler;
} }
// DetachFromPanelEvent에서 이벤트 해제 // 컨테이너에 콜백 정보 저장 (재사용/정리 시 참조)
itemView.RegisterCallback<DetachFromPanelEvent>(evt => container.userData = info;
{
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);
} }
#endregion #endregion
@@ -751,8 +1020,13 @@ namespace UVC.UIToolkit
// 테마 변경 이벤트 해제 // 테마 변경 이벤트 해제
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanel);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanel);
// TreeView 콜백 정리 // 데이터 이벤트 해제 + TreeView View 콜백/Dispose 정리
ClearInternal();
// TreeView 콜백 해제
if (_treeView != null) if (_treeView != null)
{ {
_treeView.makeItem = null; _treeView.makeItem = null;
@@ -772,9 +1046,6 @@ namespace UVC.UIToolkit
_clearButton.Dispose(); _clearButton.Dispose();
} }
// 이벤트 정리
ClearInternal();
// 이벤트 핸들러 정리 // 이벤트 핸들러 정리
OnPropertyValueChanged = null; OnPropertyValueChanged = null;
OnGroupExpandedChanged = null; OnGroupExpandedChanged = null;

View File

@@ -170,10 +170,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -203,6 +213,8 @@ namespace UVC.UIToolkit
selectionChanged -= OnSelectionChanged; selectionChanged -= OnSelectionChanged;
itemsChosen -= OnItemsChosen; itemsChosen -= OnItemsChosen;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnItemSelected = null; OnItemSelected = null;
OnItemDoubleClicked = null; OnItemDoubleClicked = null;
} }

View File

@@ -503,10 +503,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -641,6 +651,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnClosed = null; OnClosed = null;
OnConfirm = null; OnConfirm = null;
OnCancel = null; OnCancel = null;

View File

@@ -222,12 +222,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
}
// 패널에서 분리될 때 이벤트 구독 해제 private void OnAttachToPanelForTheme(AttachToPanelEvent evt)
RegisterCallback<DetachFromPanelEvent>(_ => {
{ UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
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) private void OnThemeChanged(UTKTheme theme)
@@ -1190,6 +1198,10 @@ namespace UVC.UIToolkit
_hexField?.UnregisterCallback<ChangeEvent<string>>(OnHexFieldChanged); _hexField?.UnregisterCallback<ChangeEvent<string>>(OnHexFieldChanged);
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnColorChanged = null; OnColorChanged = null;
OnColorSelected = null; OnColorSelected = null;
OnClosed = null; OnClosed = null;

View File

@@ -245,12 +245,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
}
// 패널에서 분리될 때 이벤트 구독 해제 private void OnAttachToPanelForTheme(AttachToPanelEvent evt)
RegisterCallback<DetachFromPanelEvent>(_ => {
{ UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
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) private void OnThemeChanged(UTKTheme theme)
@@ -1112,6 +1120,11 @@ namespace UVC.UIToolkit
if (_disposed) return; if (_disposed) return;
_disposed = true; _disposed = true;
// 테마 변경 이벤트 구독 해제
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
// 언어 변경 이벤트 구독 해제 // 언어 변경 이벤트 구독 해제
LocalizationManager.Instance.OnLanguageChanged -= OnLanguageChanged; LocalizationManager.Instance.OnLanguageChanged -= OnLanguageChanged;

View File

@@ -226,10 +226,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -305,6 +315,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnClosed = null; OnClosed = null;
_blocker = null; _blocker = null;
} }

View File

@@ -275,10 +275,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -389,6 +399,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnClosed = null; OnClosed = null;
OnActionClicked = null; OnActionClicked = null;
} }

View File

@@ -305,10 +305,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -436,6 +446,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnCollapsedChanged = null; OnCollapsedChanged = null;
} }
#endregion #endregion

View File

@@ -340,10 +340,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -396,6 +406,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnClosed = null; OnClosed = null;
} }
#endregion #endregion

View File

@@ -40,11 +40,14 @@ namespace UVC.UIToolkit
/// <summary>값 변경 이벤트</summary> /// <summary>값 변경 이벤트</summary>
event Action<IUTKPropertyItem, object?, object?>? OnValueChanged; event Action<IUTKPropertyItem, object?, object?>? OnValueChanged;
/// <summary>상태(ReadOnly 등) 변경 이벤트. View가 구독하여 UI를 갱신합니다.</summary>
event Action<IUTKPropertyItem>? OnStateChanged;
/// <summary>현재 값을 object로 반환</summary> /// <summary>현재 값을 object로 반환</summary>
object? GetValue(); object? GetValue();
/// <summary>값을 설정 (타입 변환 포함)</summary> /// <summary>값을 설정 (타입 변환 포함)</summary>
void SetValue(object? value); void SetValue(object? value, bool notifyChangeEvent = false);
} }
/// <summary> /// <summary>

View File

@@ -62,6 +62,9 @@ namespace UVC.UIToolkit
/// <summary>상태 + 색상 복합 타입</summary> /// <summary>상태 + 색상 복합 타입</summary>
ColorState, ColorState,
/// <summary>실수 + 드롭다운 복합 타입</summary>
FloatDropdown,
/// <summary>버튼 (액션 트리거)</summary> /// <summary>버튼 (액션 트리거)</summary>
Button Button
} }

View File

@@ -0,0 +1,36 @@
#nullable enable
using System;
using UnityEngine;
namespace UVC.UIToolkit
{
/// <summary>
/// Float 값과 Dropdown 선택 문자열을 함께 저장하는 구조체입니다.
/// UTKFloatDropdownPropertyItem의 값 타입으로 사용됩니다.
/// </summary>
public struct UTKFloatDropdownValue : IEquatable<UTKFloatDropdownValue>
{
/// <summary>Float 값</summary>
public float FloatValue { get; set; }
/// <summary>Dropdown 선택 값</summary>
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);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2d41cfdd32cd0484898138be24db75cb

View File

@@ -26,12 +26,12 @@ namespace UVC.UIToolkit
public abstract class UTKPropertyItemBase<T> : IUTKPropertyItem<T>, IDisposable public abstract class UTKPropertyItemBase<T> : IUTKPropertyItem<T>, IDisposable
{ {
#region Fields #region Fields
private T _value; protected T _value;
private bool _isReadOnly; protected bool _isReadOnly;
private bool _isVisible = true; protected bool _isVisible = true;
private bool _showLabel = true; protected bool _showLabel = true;
private string? _description; private string? _description;
private string? _tooltip; protected string? _tooltip;
private string? _groupId; private string? _groupId;
private bool _disposed; private bool _disposed;
#endregion #endregion
@@ -88,7 +88,12 @@ namespace UVC.UIToolkit
public bool IsReadOnly public bool IsReadOnly
{ {
get => _isReadOnly; get => _isReadOnly;
set => _isReadOnly = value; set
{
if (_isReadOnly == value) return;
_isReadOnly = value;
OnStateChanged?.Invoke(this);
}
} }
/// <summary>표시 여부</summary> /// <summary>표시 여부</summary>
@@ -109,7 +114,11 @@ namespace UVC.UIToolkit
public bool ShowLabel public bool ShowLabel
{ {
get => _showLabel; get => _showLabel;
set => _showLabel = value; set{
if (_showLabel == value) return;
_showLabel = value;
OnStateChanged?.Invoke(this);
}
} }
#endregion #endregion
@@ -119,6 +128,9 @@ namespace UVC.UIToolkit
/// <summary>값 변경 이벤트 (제네릭 타입)</summary> /// <summary>값 변경 이벤트 (제네릭 타입)</summary>
public event Action<IUTKPropertyItem<T>, T, T>? OnTypedValueChanged; public event Action<IUTKPropertyItem<T>, T, T>? OnTypedValueChanged;
/// <summary>상태(ReadOnly 등) 변경 이벤트</summary>
public event Action<IUTKPropertyItem>? OnStateChanged;
#endregion #endregion
#region Constructor #region Constructor
@@ -141,24 +153,41 @@ namespace UVC.UIToolkit
public object? GetValue() => _value; public object? GetValue() => _value;
/// <summary>값을 설정합니다 (타입 변환 포함).</summary> /// <summary>값을 설정합니다 (타입 변환 포함).</summary>
public void SetValue(object? value) public void SetValue(object? value, bool notifyChangeEvent = false)
{ {
if (value == null) if (value == null)
{ {
if (default(T) == null) if (default(T) == null)
{ {
Value = default!; if (notifyChangeEvent)
{
Value = default!;
}
else
{
_value = default!;
}
} }
} }
else if (value is T typedValue) else if (value is T typedValue)
{ {
Value = typedValue; if (notifyChangeEvent)
{
Value = typedValue;
}
else
{
_value = typedValue;
}
} }
else else
{ {
try 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) catch (Exception ex)
{ {
@@ -195,6 +224,7 @@ namespace UVC.UIToolkit
{ {
OnValueChanged = null; OnValueChanged = null;
OnTypedValueChanged = null; OnTypedValueChanged = null;
OnStateChanged = null;
} }
} }
#endregion #endregion

View File

@@ -21,10 +21,11 @@ namespace UVC.UIToolkit
/// <param name="name">표시 이름</param> /// <param name="name">표시 이름</param>
/// <param name="initialValue">초기 값</param> /// <param name="initialValue">초기 값</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
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) : base(id, name, initialValue)
{ {
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion
} }

View File

@@ -37,9 +37,6 @@ namespace UVC.UIToolkit
/// <summary>아이콘만 표시 모드</summary> /// <summary>아이콘만 표시 모드</summary>
public bool IconOnly { get; set; } public bool IconOnly { get; set; }
/// <summary>라벨 표시 여부 (false면 버튼이 전체 너비 사용)</summary>
public bool ShowLabel { get; set; }
/// <summary>액션 이름 (버튼 클릭 시 전달되는 고유 이름)</summary> /// <summary>액션 이름 (버튼 클릭 시 전달되는 고유 이름)</summary>
public string ActionName { get; } public string ActionName { get; }
#endregion #endregion
@@ -72,7 +69,7 @@ namespace UVC.UIToolkit
BackgroundColor = null; BackgroundColor = null;
BorderWidth = -1; BorderWidth = -1;
IconOnly = false; IconOnly = false;
ShowLabel = true; // 기본적으로 라벨 표시 _showLabel = true; // 기본적으로 라벨 표시
} }
/// <summary> /// <summary>
@@ -112,7 +109,7 @@ namespace UVC.UIToolkit
BackgroundColor = backgroundColor; BackgroundColor = backgroundColor;
BorderWidth = borderWidth; BorderWidth = borderWidth;
IconOnly = iconOnly; IconOnly = iconOnly;
ShowLabel = showLabel; _showLabel = showLabel;
} }
#endregion #endregion
} }

View File

@@ -34,11 +34,13 @@ namespace UVC.UIToolkit
/// <param name="initialValue">초기 값</param> /// <param name="initialValue">초기 값</param>
/// <param name="useAlpha">알파 채널 사용 여부</param> /// <param name="useAlpha">알파 채널 사용 여부</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKColorPropertyItem(string id, string name, Color initialValue = default, bool useAlpha = false, bool isReadOnly = false) /// <param name="showLabel">레이블 표시 여부</param>
public UTKColorPropertyItem(string id, string name, Color initialValue = default, bool useAlpha = false, bool isReadOnly = false, bool showLabel = true)
: base(id, name, initialValue) : base(id, name, initialValue)
{ {
_useAlpha = useAlpha; _useAlpha = useAlpha;
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion
} }

View File

@@ -22,10 +22,12 @@ namespace UVC.UIToolkit
/// <param name="name">표시 이름</param> /// <param name="name">표시 이름</param>
/// <param name="initialValue">초기 값</param> /// <param name="initialValue">초기 값</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKColorStatePropertyItem(string id, string name, UTKColorState initialValue = default, bool isReadOnly = false) /// <param name="showLabel">라벨 표시 여부</param>
public UTKColorStatePropertyItem(string id, string name, UTKColorState initialValue = default, bool isReadOnly = false, bool showLabel = true)
: base(id, name, initialValue) : base(id, name, initialValue)
{ {
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
/// <summary> /// <summary>
@@ -36,10 +38,12 @@ namespace UVC.UIToolkit
/// <param name="state">상태 텍스트</param> /// <param name="state">상태 텍스트</param>
/// <param name="color">색상</param> /// <param name="color">색상</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKColorStatePropertyItem(string id, string name, string state, Color color, bool isReadOnly = false) /// <param name="showLabel">라벨 표시 여부</param>
public UTKColorStatePropertyItem(string id, string name, string state, Color color, bool isReadOnly = false, bool showLabel = true)
: base(id, name, new UTKColorState(state, color)) : base(id, name, new UTKColorState(state, color))
{ {
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion

View File

@@ -49,12 +49,14 @@ namespace UVC.UIToolkit
/// <param name="name">표시 이름</param> /// <param name="name">표시 이름</param>
/// <param name="initialValue">초기 값 (default이면 오늘 날짜)</param> /// <param name="initialValue">초기 값 (default이면 오늘 날짜)</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKDatePropertyItem(string id, string name, DateTime initialValue = default, bool isReadOnly = false) /// <param name="showLabel">라벨 표시 여부</param>
public UTKDatePropertyItem(string id, string name, DateTime initialValue = default, bool isReadOnly = false, bool showLabel = true)
: base(id, name, initialValue == default ? DateTime.Today : initialValue) : base(id, name, initialValue == default ? DateTime.Today : initialValue)
{ {
_minDay = DateTime.MinValue; _minDay = DateTime.MinValue;
_maxDay = DateTime.MaxValue; _maxDay = DateTime.MaxValue;
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
/// <summary> /// <summary>
@@ -66,12 +68,14 @@ namespace UVC.UIToolkit
/// <param name="minDay">최소 날짜 (null이면 제한 없음)</param> /// <param name="minDay">최소 날짜 (null이면 제한 없음)</param>
/// <param name="maxDay">최대 날짜 (null이면 제한 없음)</param> /// <param name="maxDay">최대 날짜 (null이면 제한 없음)</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKDatePropertyItem(string id, string name, DateTime initialValue, DateTime? minDay, DateTime? maxDay, bool isReadOnly = false) /// <param name="showLabel">라벨 표시 여부</param>
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) : base(id, name, initialValue == default ? DateTime.Today : initialValue)
{ {
_minDay = minDay ?? DateTime.MinValue; _minDay = minDay ?? DateTime.MinValue;
_maxDay = maxDay ?? DateTime.MaxValue; _maxDay = maxDay ?? DateTime.MaxValue;
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion
} }

View File

@@ -33,10 +33,12 @@ namespace UVC.UIToolkit
/// <param name="name">표시 이름</param> /// <param name="name">표시 이름</param>
/// <param name="initialValue">초기 범위 값</param> /// <param name="initialValue">초기 범위 값</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKDateRangePropertyItem(string id, string name, UTKDateRange initialValue = default, bool isReadOnly = false) /// <param name="showLabel">레이블 표시 여부</param>
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) : base(id, name, initialValue.Start == default ? new UTKDateRange(DateTime.Today, DateTime.Today) : initialValue)
{ {
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
/// <summary> /// <summary>
@@ -47,10 +49,11 @@ namespace UVC.UIToolkit
/// <param name="start">시작 날짜</param> /// <param name="start">시작 날짜</param>
/// <param name="end">종료 날짜</param> /// <param name="end">종료 날짜</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
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)) : base(id, name, new UTKDateRange(start, end))
{ {
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion
} }

View File

@@ -33,10 +33,12 @@ namespace UVC.UIToolkit
/// <param name="name">표시 이름</param> /// <param name="name">표시 이름</param>
/// <param name="initialValue">초기 값 (default이면 현재 시간)</param> /// <param name="initialValue">초기 값 (default이면 현재 시간)</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKDateTimePropertyItem(string id, string name, DateTime initialValue = default, bool isReadOnly = false) /// <param name="showLabel">라벨 표시 여부</param>
public UTKDateTimePropertyItem(string id, string name, DateTime initialValue = default, bool isReadOnly = false, bool showLabel = true)
: base(id, name, initialValue == default ? DateTime.Now : initialValue) : base(id, name, initialValue == default ? DateTime.Now : initialValue)
{ {
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion
} }

View File

@@ -33,10 +33,12 @@ namespace UVC.UIToolkit
/// <param name="name">표시 이름</param> /// <param name="name">표시 이름</param>
/// <param name="initialValue">초기 범위 값</param> /// <param name="initialValue">초기 범위 값</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKDateTimeRangePropertyItem(string id, string name, UTKDateTimeRange initialValue = default, bool isReadOnly = false) /// <param name="showLabel">라벨 표시 여부</param>
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) : base(id, name, initialValue.Start == default ? new UTKDateTimeRange(DateTime.Now, DateTime.Now) : initialValue)
{ {
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
/// <summary> /// <summary>
@@ -47,10 +49,11 @@ namespace UVC.UIToolkit
/// <param name="start">시작 날짜시간</param> /// <param name="start">시작 날짜시간</param>
/// <param name="end">종료 날짜시간</param> /// <param name="end">종료 날짜시간</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
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)) : base(id, name, new UTKDateTimeRange(start, end))
{ {
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion
} }

View File

@@ -35,7 +35,8 @@ namespace UVC.UIToolkit
/// <param name="choices">선택 항목 목록</param> /// <param name="choices">선택 항목 목록</param>
/// <param name="initialValue">초기 선택 값</param> /// <param name="initialValue">초기 선택 값</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKDropdownPropertyItem(string id, string name, List<string> choices, string initialValue = "", bool isReadOnly = false) /// <param name="showLabel">라벨 표시 여부</param>
public UTKDropdownPropertyItem(string id, string name, List<string> choices, string initialValue = "", bool isReadOnly = false, bool showLabel = true)
: base(id, name, initialValue) : base(id, name, initialValue)
{ {
_choices = choices ?? new List<string>(); _choices = choices ?? new List<string>();
@@ -43,9 +44,10 @@ namespace UVC.UIToolkit
// initialValue가 choices에 없으면 첫 번째 항목 선택 // initialValue가 choices에 없으면 첫 번째 항목 선택
if (!string.IsNullOrEmpty(initialValue) && !_choices.Contains(initialValue) && _choices.Count > 0) if (!string.IsNullOrEmpty(initialValue) && !_choices.Contains(initialValue) && _choices.Count > 0)
{ {
Value = _choices[0]; _value = _choices[0];
} }
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
/// <summary> /// <summary>
@@ -56,20 +58,22 @@ namespace UVC.UIToolkit
/// <param name="choices">선택 항목 목록</param> /// <param name="choices">선택 항목 목록</param>
/// <param name="selectedIndex">초기 선택 인덱스</param> /// <param name="selectedIndex">초기 선택 인덱스</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKDropdownPropertyItem(string id, string name, IEnumerable<string> choices, int selectedIndex = 0, bool isReadOnly = false) /// <param name="showLabel">라벨 표시 여부</param>
public UTKDropdownPropertyItem(string id, string name, IEnumerable<string> choices, int selectedIndex = 0, bool isReadOnly = false, bool showLabel = true)
: base(id, name, string.Empty) : base(id, name, string.Empty)
{ {
_choices = choices?.ToList() ?? new List<string>(); _choices = choices?.ToList() ?? new List<string>();
if (_choices.Count > 0 && selectedIndex >= 0 && selectedIndex < _choices.Count) if (_choices.Count > 0 && selectedIndex >= 0 && selectedIndex < _choices.Count)
{ {
Value = _choices[selectedIndex]; _value = _choices[selectedIndex];
} }
else if (_choices.Count > 0) else if (_choices.Count > 0)
{ {
Value = _choices[0]; _value = _choices[0];
} }
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion

View File

@@ -29,11 +29,13 @@ namespace UVC.UIToolkit
/// <param name="name">표시 이름</param> /// <param name="name">표시 이름</param>
/// <param name="initialValue">초기 값 (열거형 타입 추론에 사용)</param> /// <param name="initialValue">초기 값 (열거형 타입 추론에 사용)</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKEnumPropertyItem(string id, string name, Enum initialValue, bool isReadOnly = false) /// <param name="showLabel">라벨 표시 여부</param>
public UTKEnumPropertyItem(string id, string name, Enum initialValue, bool isReadOnly = false, bool showLabel = true)
: base(id, name, initialValue ?? throw new ArgumentNullException(nameof(initialValue))) : base(id, name, initialValue ?? throw new ArgumentNullException(nameof(initialValue)))
{ {
_enumType = initialValue.GetType(); _enumType = initialValue.GetType();
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion
} }

View File

@@ -0,0 +1,138 @@
#nullable enable
using System.Collections.Generic;
namespace UVC.UIToolkit
{
/// <summary>
/// Float + Dropdown 복합 속성 데이터 클래스입니다.
/// Float 값(또는 Stepper)과 Dropdown 선택을 하나의 행에 표시합니다.
/// UI는 UTKFloatDropdownPropertyItemView에서 담당합니다.
/// </summary>
public class UTKFloatDropdownPropertyItem : UTKPropertyItemBase<UTKFloatDropdownValue>
{
#region Fields
private List<string> _choices;
private bool _useStepper;
private float _floatMinValue = float.MinValue;
private float _floatMaxValue = float.MaxValue;
private float _stepperStep = 1.0f;
#endregion
#region Properties
/// <summary>속성 타입</summary>
public override UTKPropertyType PropertyType => UTKPropertyType.FloatDropdown;
/// <summary>Dropdown 선택 목록</summary>
public List<string> Choices => _choices;
/// <summary>스테퍼(증감 버튼) 사용 여부. false이면 UTKFloatField 사용</summary>
public bool UseStepper
{
get => _useStepper;
set => _useStepper = value;
}
/// <summary>Float 최소값</summary>
public float FloatMinValue
{
get => _floatMinValue;
set => _floatMinValue = value;
}
/// <summary>Float 최대값</summary>
public float FloatMaxValue
{
get => _floatMaxValue;
set => _floatMaxValue = value;
}
/// <summary>스테퍼 증감 단위 (기본값: 1.0)</summary>
public float StepperStep
{
get => _stepperStep;
set => _stepperStep = value > 0 ? value : 1.0f;
}
#endregion
#region Constructor
/// <summary>
/// Float + Dropdown 복합 속성을 생성합니다.
/// </summary>
/// <param name="id">고유 ID</param>
/// <param name="name">표시 이름</param>
/// <param name="floatValue">초기 float 값</param>
/// <param name="choices">Dropdown 선택 목록</param>
/// <param name="dropdownValue">초기 Dropdown 선택 값</param>
/// <param name="useStepper">스테퍼 사용 여부</param>
/// <param name="isReadOnly">읽기 전용 여부</param>
/// <param name="showLabel">레이블 표시 여부</param>
public UTKFloatDropdownPropertyItem(
string id,
string name,
float floatValue,
List<string> choices,
string dropdownValue = "",
bool useStepper = false,
bool isReadOnly = false,
bool showLabel = true)
: base(id, name, new UTKFloatDropdownValue(floatValue, ValidateDropdownValue(dropdownValue, choices)))
{
_choices = new List<string>(choices);
_useStepper = useStepper;
_isReadOnly = isReadOnly;
_showLabel = showLabel;
}
/// <summary>
/// Float + Dropdown 복합 속성을 생성합니다
/// (최소/최대 float 값 및 스테퍼 단위 포함)
/// </summary>
/// <param name="id">고유 ID</param>
/// <param name="name">표시 이름</param>
/// <param name="floatValue">초기 float 값</param>
/// <param name="choices">Dropdown 선택 목록</param>
/// <param name="dropdownValue">초기 Dropdown 선택 값</param>
/// <param name="floatMinValue">Float 최소값</param>
/// <param name="floatMaxValue">Float 최대값</param>
/// <param name="stepperStep">스테퍼 증감 단위</param
/// <param name="useStepper">스테퍼 사용 여부</param>
/// <param name="isReadOnly">읽기 전용 여부</param>
/// <param name="showLabel">레이블 표시 여부</param>
public UTKFloatDropdownPropertyItem(
string id,
string name,
float floatValue,
List<string> 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<string>(choices);
_floatMinValue = floatMinValue;
_floatMaxValue = floatMaxValue;
_stepperStep = stepperStep;
_useStepper = useStepper;
_isReadOnly = isReadOnly;
_showLabel = showLabel;
}
#endregion
#region Methods
/// <summary>Dropdown 선택 값 검증 (목록에 없으면 첫 번째 값 반환)</summary>
private static string ValidateDropdownValue(string value, List<string> choices)
{
if (choices.Count == 0) return value;
if (string.IsNullOrEmpty(value) || !choices.Contains(value))
{
return choices[0];
}
return value;
}
#endregion
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 86800100e89e3d34fa8b8afa7f290064

View File

@@ -64,10 +64,12 @@ namespace UVC.UIToolkit
/// <param name="name">표시 이름</param> /// <param name="name">표시 이름</param>
/// <param name="initialValue">초기 값</param> /// <param name="initialValue">초기 값</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKFloatPropertyItem(string id, string name, float initialValue = 0f, bool isReadOnly = false) /// <param name="showLabel">라벨 표시 여부</param>
public UTKFloatPropertyItem(string id, string name, float initialValue = 0f, bool isReadOnly = false, bool showLabel = true)
: base(id, name, initialValue) : base(id, name, initialValue)
{ {
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
/// <summary> /// <summary>
@@ -81,14 +83,16 @@ namespace UVC.UIToolkit
/// <param name="useSlider">슬라이더 사용 여부</param> /// <param name="useSlider">슬라이더 사용 여부</param>
/// <param name="useStepper">스테퍼 사용 여부</param> /// <param name="useStepper">스테퍼 사용 여부</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
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) /// <param name="showLabel">라벨 표시 여부</param>
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) : base(id, name, initialValue)
{ {
_minValue = minValue; _minValue = minValue;
_maxValue = maxValue; _maxValue = maxValue;
_useSlider = useSlider; _useSlider = useSlider;
_useStepper = useStepper; _useStepper = useStepper;
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion
} }

View File

@@ -8,23 +8,63 @@ namespace UVC.UIToolkit
/// </summary> /// </summary>
public class UTKFloatRangePropertyItem : UTKPropertyItemBase<UTKFloatRange> public class UTKFloatRangePropertyItem : UTKPropertyItemBase<UTKFloatRange>
{ {
#region Fields
private bool _useStepper;
private float _stepperMinValue = float.MinValue;
private float _stepperMaxValue = float.MaxValue;
private float _stepperStep = 1.0f;
#endregion
#region Properties #region Properties
/// <summary>속성 타입</summary> /// <summary>속성 타입</summary>
public override UTKPropertyType PropertyType => UTKPropertyType.FloatRange; public override UTKPropertyType PropertyType => UTKPropertyType.FloatRange;
/// <summary>스테퍼(증감 버튼) 사용 여부</summary>
public bool UseStepper
{
get => _useStepper;
set
{
_useStepper = value;
}
}
/// <summary>스테퍼 증감 단위 (기본값: 1.0)</summary>
public float StepperStep
{
get => _stepperStep;
set => _stepperStep = value > 0 ? value : 1.0f;
}
/// <summary>스테퍼 최소값</summary>
public float StepperMinValue
{
get => _stepperMinValue;
set => _stepperMinValue = value;
}
/// <summary>스테퍼 최대값</summary>
public float StepperMaxValue
{
get => _stepperMaxValue;
set => _stepperMaxValue = value;
}
#endregion #endregion
#region Constructor #region Constructor
/// <summary> /// <summary>
/// 실수 범위 속성을 생성합니다. /// 실수 범위 속성을 생성합니다 (필드 모드).
/// </summary> /// </summary>
/// <param name="id">고유 ID</param> /// <param name="id">고유 ID</param>
/// <param name="name">표시 이름</param> /// <param name="name">표시 이름</param>
/// <param name="initialValue">초기 범위 값</param> /// <param name="initialValue">초기 범위 값</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKFloatRangePropertyItem(string id, string name, UTKFloatRange initialValue = default, bool isReadOnly = false) /// <param name="showLabel">레이블 표시 여부</param>
public UTKFloatRangePropertyItem(string id, string name, UTKFloatRange initialValue = default, bool isReadOnly = false, bool showLabel = true)
: base(id, name, initialValue) : base(id, name, initialValue)
{ {
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
/// <summary> /// <summary>
@@ -34,11 +74,44 @@ namespace UVC.UIToolkit
/// <param name="name">표시 이름</param> /// <param name="name">표시 이름</param>
/// <param name="min">최소값</param> /// <param name="min">최소값</param>
/// <param name="max">최대값</param> /// <param name="max">최대값</param>
/// <param name="stepperStep">스테퍼 증감 단위</param>
/// <param name="stepperMinValue">스테퍼 최소값</param>
/// <param name="stepperMaxValue">스테퍼 최대값</param>
/// <param name="useStepper">스테퍼 사용 여부</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKFloatRangePropertyItem(string id, string name, float min, float max, bool isReadOnly = false) /// <param name="showLabel">레이블 표시 여부</param>
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)) : base(id, name, new UTKFloatRange(min, max))
{ {
IsReadOnly = isReadOnly; _stepperMinValue = stepperMinValue;
_stepperMaxValue = stepperMaxValue;
_useStepper = useStepper;
_stepperStep = stepperStep;
_isReadOnly = isReadOnly;
_showLabel = showLabel;
}
/// <summary>
/// 실수 범위 속성을 생성합니다 (스테퍼 모드).
/// </summary>
/// <param name="id">고유 ID</param>
/// <param name="name">표시 이름</param>
/// <param name="initialValue">초기 범위 값</param>
/// <param name="stepperStep">스테퍼 증감 단위</param>
/// <param name="stepperMinValue">스테퍼 최소값</param>
/// <param name="stepperMaxValue">스테퍼 최대값</param>
/// <param name="useStepper">스테퍼 사용 여부</param>
/// <param name="isReadOnly">읽기 전용 여부</param>
/// <param name="showLabel">레이블 표시 여부</param>
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 #endregion
} }

View File

@@ -85,14 +85,16 @@ namespace UVC.UIToolkit
/// <param name="maxValue">최대값</param> /// <param name="maxValue">최대값</param>
/// <param name="useSlider">슬라이더 사용 여부</param> /// <param name="useSlider">슬라이더 사용 여부</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKIntPropertyItem(string id, string name, int initialValue, int minValue, int maxValue, bool useSlider = false, bool useStepper = false, bool isReadOnly = false) /// <param name="showLabel">라벨 표시 여부</param>
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) : base(id, name, initialValue)
{ {
_minValue = minValue; _minValue = minValue;
_maxValue = maxValue; _maxValue = maxValue;
_useSlider = useSlider; _useSlider = useSlider;
_useStepper = useStepper; _useStepper = useStepper;
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion
} }

View File

@@ -60,10 +60,12 @@ namespace UVC.UIToolkit
/// <param name="name">표시 이름</param> /// <param name="name">표시 이름</param>
/// <param name="initialValue">초기 범위 값</param> /// <param name="initialValue">초기 범위 값</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKIntRangePropertyItem(string id, string name, UTKIntRange initialValue = default, bool isReadOnly = false) /// <param name="showLabel">라벨 표시 여부</param>
public UTKIntRangePropertyItem(string id, string name, UTKIntRange initialValue = default, bool isReadOnly = false, bool showLabel = true)
: base(id, name, initialValue) : base(id, name, initialValue)
{ {
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
/// <summary> /// <summary>
@@ -78,14 +80,16 @@ namespace UVC.UIToolkit
/// <param name="stepperMaxValue">스테퍼 최대값</param> /// <param name="stepperMaxValue">스테퍼 최대값</param>
/// <param name="useStepper">스테퍼 사용 여부</param> /// <param name="useStepper">스테퍼 사용 여부</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
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) /// <param name="showLabel">라벨 표시 여부</param>
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)) : base(id, name, new UTKIntRange(min, max))
{ {
_stepperMinValue = stepperMinValue; _stepperMinValue = stepperMinValue;
_stepperMaxValue = stepperMaxValue; _stepperMaxValue = stepperMaxValue;
_useStepper = useStepper; _useStepper = useStepper;
_stepperStep = stepperStep; _stepperStep = stepperStep;
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
/// <summary> /// <summary>
@@ -99,14 +103,16 @@ namespace UVC.UIToolkit
/// <param name="stepperMaxValue">스테퍼 최대값</param> /// <param name="stepperMaxValue">스테퍼 최대값</param>
/// <param name="useStepper">스테퍼 사용 여부</param> /// <param name="useStepper">스테퍼 사용 여부</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
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) /// <param name="showLabel">라벨 표시 여부</param>
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) : base(id, name, initialValue)
{ {
_stepperMinValue = stepperMinValue; _stepperMinValue = stepperMinValue;
_stepperMaxValue = stepperMaxValue; _stepperMaxValue = stepperMaxValue;
_useStepper = useStepper; _useStepper = useStepper;
_stepperStep = stepperStep; _stepperStep = stepperStep;
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion
} }

View File

@@ -51,12 +51,14 @@ namespace UVC.UIToolkit
/// <param name="choices">선택 항목 목록</param> /// <param name="choices">선택 항목 목록</param>
/// <param name="initialValues">초기 선택 값 목록</param> /// <param name="initialValues">초기 선택 값 목록</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
/// <param name="showLabel">라벨 표시 여부</param>
public UTKMultiSelectDropdownPropertyItem( public UTKMultiSelectDropdownPropertyItem(
string id, string id,
string name, string name,
List<string> choices, List<string> choices,
List<string>? initialValues = null, List<string>? initialValues = null,
bool isReadOnly = false) bool isReadOnly = false,
bool showLabel = true)
: base(id, name, initialValues ?? new List<string>()) : base(id, name, initialValues ?? new List<string>())
{ {
_choices = choices ?? new List<string>(); _choices = choices ?? new List<string>();
@@ -65,10 +67,11 @@ namespace UVC.UIToolkit
if (initialValues != null && initialValues.Count > 0) if (initialValues != null && initialValues.Count > 0)
{ {
var validValues = initialValues.Where(v => _choices.Contains(v)).ToList(); var validValues = initialValues.Where(v => _choices.Contains(v)).ToList();
Value = validValues; _value = validValues;
} }
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
/// <summary> /// <summary>
@@ -79,12 +82,14 @@ namespace UVC.UIToolkit
/// <param name="choices">선택 항목 목록</param> /// <param name="choices">선택 항목 목록</param>
/// <param name="selectedIndices">초기 선택 인덱스 목록</param> /// <param name="selectedIndices">초기 선택 인덱스 목록</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
/// <param name="showLabel">라벨 표시 여부</param>
public UTKMultiSelectDropdownPropertyItem( public UTKMultiSelectDropdownPropertyItem(
string id, string id,
string name, string name,
IEnumerable<string> choices, IEnumerable<string> choices,
IEnumerable<int>? selectedIndices = null, IEnumerable<int>? selectedIndices = null,
bool isReadOnly = false) bool isReadOnly = false,
bool showLabel = true)
: base(id, name, new List<string>()) : base(id, name, new List<string>())
{ {
_choices = choices?.ToList() ?? new List<string>(); _choices = choices?.ToList() ?? new List<string>();
@@ -95,10 +100,11 @@ namespace UVC.UIToolkit
.Where(i => i >= 0 && i < _choices.Count) .Where(i => i >= 0 && i < _choices.Count)
.Select(i => _choices[i]) .Select(i => _choices[i])
.ToList(); .ToList();
Value = validValues; _value = validValues;
} }
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion

View File

@@ -49,11 +49,13 @@ namespace UVC.UIToolkit
/// <param name="choices">선택 항목 목록</param> /// <param name="choices">선택 항목 목록</param>
/// <param name="selectedIndex">초기 선택 인덱스</param> /// <param name="selectedIndex">초기 선택 인덱스</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKRadioPropertyItem(string id, string name, List<string> choices, int selectedIndex = 0, bool isReadOnly = false) /// <param name="showLabel">라벨 표시 여부</param>
public UTKRadioPropertyItem(string id, string name, List<string> choices, int selectedIndex = 0, bool isReadOnly = false, bool showLabel = true)
: base(id, name, Math.Max(0, Math.Min(selectedIndex, (choices?.Count ?? 1) - 1))) : base(id, name, Math.Max(0, Math.Min(selectedIndex, (choices?.Count ?? 1) - 1)))
{ {
_choices = choices ?? new List<string>(); _choices = choices ?? new List<string>();
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
/// <summary> /// <summary>
@@ -64,8 +66,9 @@ namespace UVC.UIToolkit
/// <param name="choices">선택 항목 목록</param> /// <param name="choices">선택 항목 목록</param>
/// <param name="selectedIndex">초기 선택 인덱스</param> /// <param name="selectedIndex">초기 선택 인덱스</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKRadioPropertyItem(string id, string name, IEnumerable<string> choices, int selectedIndex = 0, bool isReadOnly = false) /// <param name="showLabel">라벨 표시 여부</param>
: this(id, name, choices?.ToList() ?? new List<string>(), selectedIndex, isReadOnly) public UTKRadioPropertyItem(string id, string name, IEnumerable<string> choices, int selectedIndex = 0, bool isReadOnly = false, bool showLabel = true)
: this(id, name, choices?.ToList() ?? new List<string>(), selectedIndex, isReadOnly, showLabel)
{ {
} }
#endregion #endregion

View File

@@ -45,13 +45,15 @@ namespace UVC.UIToolkit
/// <param name="isMultiline">멀티라인 모드</param> /// <param name="isMultiline">멀티라인 모드</param>
/// <param name="maxLength">최대 문자 길이</param> /// <param name="maxLength">최대 문자 길이</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
/// <param name="showLabel">레이블 표시 여부</param>
/// <param name="actionButton">액션 버튼</param> /// <param name="actionButton">액션 버튼</param>
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) : base(id, name, initialValue ?? string.Empty)
{ {
IsReadOnly = isReadOnly;
_isMultiline = isMultiline; _isMultiline = isMultiline;
_maxLength = maxLength; _maxLength = maxLength;
_isReadOnly = isReadOnly;
_showLabel = showLabel;
ActionButton = actionButton; ActionButton = actionButton;
} }
#endregion #endregion

View File

@@ -22,10 +22,12 @@ namespace UVC.UIToolkit
/// <param name="name">표시 이름</param> /// <param name="name">표시 이름</param>
/// <param name="initialValue">초기 값</param> /// <param name="initialValue">초기 값</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKVector2PropertyItem(string id, string name, Vector2 initialValue = default, bool isReadOnly = false) /// <param name="showLabel">레이블 표시 여부</param>
public UTKVector2PropertyItem(string id, string name, Vector2 initialValue = default, bool isReadOnly = false, bool showLabel = true)
: base(id, name, initialValue) : base(id, name, initialValue)
{ {
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion
} }

View File

@@ -22,10 +22,12 @@ namespace UVC.UIToolkit
/// <param name="name">표시 이름</param> /// <param name="name">표시 이름</param>
/// <param name="initialValue">초기 값</param> /// <param name="initialValue">초기 값</param>
/// <param name="isReadOnly">읽기 전용 여부</param> /// <param name="isReadOnly">읽기 전용 여부</param>
public UTKVector3PropertyItem(string id, string name, Vector3 initialValue = default, bool isReadOnly = false) /// <param name="showLabel">레이블 표시 여부</param>
public UTKVector3PropertyItem(string id, string name, Vector3 initialValue = default, bool isReadOnly = false, bool showLabel = true)
: base(id, name, initialValue) : base(id, name, initialValue)
{ {
IsReadOnly = isReadOnly; _isReadOnly = isReadOnly;
_showLabel = showLabel;
} }
#endregion #endregion
} }

View File

@@ -217,17 +217,18 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -235,6 +236,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -137,6 +137,7 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
// 라벨 텍스트 설정 // 라벨 텍스트 설정
if (_labelElement != null) if (_labelElement != null)
@@ -191,6 +192,7 @@ namespace UVC.UIToolkit
{ {
if (_boundData != null) if (_boundData != null)
{ {
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -349,12 +349,13 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
if (data is UTKColorPropertyItem colorItem) if (data is UTKColorPropertyItem colorItem)
{ {
@@ -364,7 +365,7 @@ namespace UVC.UIToolkit
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -372,6 +373,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -283,17 +283,18 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -301,6 +302,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -273,12 +273,13 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
if (data is UTKDatePropertyItem dateItem) if (data is UTKDatePropertyItem dateItem)
{ {
@@ -288,7 +289,7 @@ namespace UVC.UIToolkit
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -296,6 +297,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -376,12 +376,13 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
if (data is UTKDateRangePropertyItem dateRangeItem) if (data is UTKDateRangePropertyItem dateRangeItem)
{ {
@@ -391,7 +392,7 @@ namespace UVC.UIToolkit
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -399,6 +400,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -273,12 +273,13 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
if (data is UTKDateTimePropertyItem dateTimeItem) if (data is UTKDateTimePropertyItem dateTimeItem)
{ {
@@ -288,7 +289,7 @@ namespace UVC.UIToolkit
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -296,6 +297,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -376,12 +376,13 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
if (data is UTKDateTimeRangePropertyItem dateTimeRangeItem) if (data is UTKDateTimeRangePropertyItem dateTimeRangeItem)
{ {
@@ -391,7 +392,7 @@ namespace UVC.UIToolkit
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -399,6 +400,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -325,12 +325,13 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value ?? string.Empty; _value = data.Value ?? string.Empty;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
if (data is UTKDropdownPropertyItem dropdownItem) if (data is UTKDropdownPropertyItem dropdownItem)
{ {
@@ -344,7 +345,7 @@ namespace UVC.UIToolkit
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -352,6 +353,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -277,13 +277,14 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
_enumType = data.Value?.GetType(); _enumType = data.Value?.GetType();
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
if (_enumDropdown != null && _value != null) if (_enumDropdown != null && _value != null)
{ {
@@ -293,7 +294,7 @@ namespace UVC.UIToolkit
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -301,6 +302,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -0,0 +1,505 @@
#nullable enable
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
namespace UVC.UIToolkit
{
/// <summary>
/// Float + Dropdown 복합 속성 View 클래스입니다.
/// UTKFloatField(또는 UTKFloatStepper)와 UTKDropdown을 사용하여
/// float 값과 문자열 선택을 하나의 행에 표시/편집합니다.
///
/// <para><b>사용법 (Data 바인딩):</b></para>
/// <code>
/// var data = new UTKFloatDropdownPropertyItem("id", "Label", 1.5f,
/// new List&lt;string&gt; { "A", "B", "C" }, "A");
/// var view = new UTKFloatDropdownPropertyItemView();
/// view.Bind(data);
/// </code>
/// </summary>
[UxmlElement]
public partial class UTKFloatDropdownPropertyItemView : UTKPropertyItemViewBase, IUTKPropertyItemView<UTKFloatDropdownValue>
{
#region Fields
private UTKFloatField? _floatField;
private UTKFloatStepper? _stepper;
private UTKDropdown? _dropdown;
private UTKInputField? _readOnlyField;
private UTKFloatDropdownValue _value;
private List<string> _choices = new();
private bool _useStepper;
private float _floatMinValue = float.MinValue;
private float _floatMaxValue = float.MaxValue;
private float _stepperStep = 1.0f;
private IUTKPropertyItem<UTKFloatDropdownValue>? _boundData;
#endregion
#region Properties
protected override string ViewTypeName => "UTKFloatDropdownPropertyItemView";
/// <summary>현재 값</summary>
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;
}
}
}
}
/// <summary>Dropdown 선택 목록</summary>
public List<string> Choices
{
get => _choices;
set
{
_choices = value ?? new List<string>();
_dropdown?.SetOptions(_choices);
}
}
/// <summary>스테퍼(증감 버튼) 사용 여부</summary>
public bool UseStepper
{
get => _useStepper;
set
{
if (_useStepper != value)
{
_useStepper = value;
UpdateControlVisibility();
}
}
}
#endregion
#region Events
public event Action<UTKFloatDropdownValue>? OnValueChanged;
#endregion
#region Constructor
public UTKFloatDropdownPropertyItemView() : base()
{
InitializeUI();
}
public UTKFloatDropdownPropertyItemView(string label, List<string> choices) : base()
{
_choices = new List<string>(choices);
Label = label;
InitializeUI();
}
public UTKFloatDropdownPropertyItemView(UTKFloatDropdownPropertyItem data) : base()
{
_value = data.Value;
_choices = new List<string>(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<UTKFloatField>("float-field");
_dropdown = this.Q<UTKDropdown>("dropdown-field");
_stepper = this.Q<UTKFloatStepper>("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;
}
}
/// <summary>컨트롤 가시성을 업데이트합니다.</summary>
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;
}
}
}
/// <summary>ReadOnly 전용 필드를 필요 시 생성합니다.</summary>
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<UTKFloatDropdownValue> typedData)
{
Bind(typedData);
}
else
{
Debug.LogWarning($"[UTKFloatDropdownPropertyItemView] Cannot bind to non-FloatDropdown data: {data.GetType().Name}");
}
}
public void Bind(IUTKPropertyItem<UTKFloatDropdownValue> 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<string>(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<UTKFloatDropdownValue> 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
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6d14075483e28504aa714b26c491a24e

View File

@@ -517,13 +517,14 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
// 데이터에서 속성 동기화 // 데이터에서 속성 동기화
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
// 슬라이더 및 스테퍼 관련 속성 동기화 // 슬라이더 및 스테퍼 관련 속성 동기화
if (data is UTKFloatPropertyItem floatItem) if (data is UTKFloatPropertyItem floatItem)
@@ -570,7 +571,7 @@ namespace UVC.UIToolkit
// UI 갱신 // UI 갱신
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -578,6 +579,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -7,7 +7,7 @@ namespace UVC.UIToolkit
{ {
/// <summary> /// <summary>
/// FloatRange 속성 View 클래스입니다. /// FloatRange 속성 View 클래스입니다.
/// Min, Max 두 개의 UTKFloatField를 사용하여 실수 범위를 표시/편집합니다. /// Min, Max 두 개의 UTKFloatField 또는 UTKFloatStepper를 사용하여 실수 범위를 표시/편집합니다.
/// </summary> /// </summary>
[UxmlElement] [UxmlElement]
public partial class UTKFloatRangePropertyItemView : UTKPropertyItemViewBase, IUTKPropertyItemView<UTKFloatRange> public partial class UTKFloatRangePropertyItemView : UTKPropertyItemViewBase, IUTKPropertyItemView<UTKFloatRange>
@@ -15,14 +15,70 @@ namespace UVC.UIToolkit
#region Fields #region Fields
private UTKFloatField? _minField; private UTKFloatField? _minField;
private UTKFloatField? _maxField; private UTKFloatField? _maxField;
private UTKFloatStepper? _minStepper;
private UTKFloatStepper? _maxStepper;
private UTKFloatRange _value; private UTKFloatRange _value;
private bool _useStepper;
private float _stepperMinValue = float.MinValue;
private float _stepperMaxValue = float.MaxValue;
private float _stepperStep = 1.0f;
private IUTKPropertyItem<UTKFloatRange>? _boundData; private IUTKPropertyItem<UTKFloatRange>? _boundData;
#endregion #endregion
#region Properties #region Properties
protected override string ViewTypeName => "UTKFloatRangePropertyItemView"; protected override string ViewTypeName => "UTKFloatRangePropertyItemView";
/// <summary>스테퍼(증감 버튼) 사용 여부</summary>
public bool UseStepper
{
get => _useStepper;
set
{
if (_useStepper != value)
{
_useStepper = value;
UpdateModeClass();
}
}
}
/// <summary>스테퍼 최소값</summary>
public float StepperMinValue
{
get => _stepperMinValue;
set
{
_stepperMinValue = value;
if (_minStepper != null) _minStepper.MinValue = value;
if (_maxStepper != null) _maxStepper.MinValue = value;
}
}
/// <summary>스테퍼 최대값</summary>
public float StepperMaxValue
{
get => _stepperMaxValue;
set
{
_stepperMaxValue = value;
if (_minStepper != null) _minStepper.MaxValue = value;
if (_maxStepper != null) _maxStepper.MaxValue = value;
}
}
/// <summary>스테퍼 증감 단위</summary>
public float StepperStep
{
get => _stepperStep;
set
{
_stepperStep = value > 0 ? value : 1.0f;
if (_minStepper != null) _minStepper.Step = _stepperStep;
if (_maxStepper != null) _maxStepper.Step = _stepperStep;
}
}
/// <summary>현재 값</summary> /// <summary>현재 값</summary>
public UTKFloatRange Value public UTKFloatRange Value
{ {
@@ -94,31 +150,53 @@ namespace UVC.UIToolkit
{ {
_minField = this.Q<UTKFloatField>("min-field"); _minField = this.Q<UTKFloatField>("min-field");
_maxField = this.Q<UTKFloatField>("max-field"); _maxField = this.Q<UTKFloatField>("max-field");
_minStepper = this.Q<UTKFloatStepper>("min-stepper");
_maxStepper = this.Q<UTKFloatStepper>("max-stepper");
// Fallback: UXML에서 못 찾으면 생성 // Fallback: UXML에서 못 찾으면 생성
if (_valueContainer != null) if (_valueContainer != null)
{ {
_valueContainer.style.flexDirection = FlexDirection.Row; _valueContainer.style.flexDirection = FlexDirection.Row;
// FloatField 생성
if (_minField == null) if (_minField == null)
{ {
_minField = new UTKFloatField { name = "min-field" }; _minField = new UTKFloatField { name = "min-field" };
_minField.style.flexGrow = 1;
_minField.AddToClassList("utk-property-item-view__field"); _minField.AddToClassList("utk-property-item-view__field");
_valueContainer.Add(_minField); _valueContainer.Add(_minField);
var separator = new UTKLabel("~", UTKLabel.LabelSize.Body2);
separator.AddToClassList("utk-property-item-view__range-separator");
_valueContainer.Add(separator);
} }
if (_maxField == null) 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 = new UTKFloatField { name = "max-field" };
_maxField.style.flexGrow = 1;
_maxField.AddToClassList("utk-property-item-view__field"); _maxField.AddToClassList("utk-property-item-view__field");
_valueContainer.Add(_maxField); _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.SetValueWithoutNotify(_value.Max);
_maxField.isReadOnly = IsReadOnly; _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() private void RegisterEvents()
@@ -144,6 +241,14 @@ namespace UVC.UIToolkit
{ {
_maxField.OnValueChanged += OnMaxChanged; _maxField.OnValueChanged += OnMaxChanged;
} }
if (_minStepper != null)
{
_minStepper.OnValueChanged += OnMinStepperChanged;
}
if (_maxStepper != null)
{
_maxStepper.OnValueChanged += OnMaxStepperChanged;
}
} }
private void UnregisterEvents() private void UnregisterEvents()
@@ -156,6 +261,65 @@ namespace UVC.UIToolkit
{ {
_maxField.OnValueChanged -= OnMaxChanged; _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();
}
/// <summary>컨트롤 가시성을 업데이트합니다.</summary>
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 #endregion
@@ -174,6 +338,11 @@ namespace UVC.UIToolkit
{ {
if (_minField != null) _minField.isReadOnly = isReadOnly; if (_minField != null) _minField.isReadOnly = isReadOnly;
if (_maxField != null) _maxField.isReadOnly = isReadOnly; if (_maxField != null) _maxField.isReadOnly = isReadOnly;
if (_minStepper != null) _minStepper.IsReadOnly = isReadOnly;
if (_maxStepper != null) _maxStepper.IsReadOnly = isReadOnly;
// ReadOnly 상태 변경 시 모드 클래스 업데이트
UpdateModeClass();
} }
#endregion #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 #endregion
#region Value Update #region Value Update
@@ -221,6 +420,16 @@ namespace UVC.UIToolkit
{ {
_maxField.SetValueWithoutNotify(_value.Max); _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 #endregion
@@ -242,17 +451,43 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; 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; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -260,6 +495,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }
@@ -287,6 +523,10 @@ namespace UVC.UIToolkit
OnValueChanged = null; OnValueChanged = null;
_minField = null; _minField = null;
_maxField = null; _maxField = null;
_minStepper?.Dispose();
_minStepper = null;
_maxStepper?.Dispose();
_maxStepper = null;
} }
base.Dispose(disposing); base.Dispose(disposing);

View File

@@ -516,12 +516,13 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
if (data is UTKIntPropertyItem intItem) if (data is UTKIntPropertyItem intItem)
{ {
@@ -565,7 +566,7 @@ namespace UVC.UIToolkit
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -573,6 +574,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -162,7 +162,6 @@ namespace UVC.UIToolkit
if (_minField == null) if (_minField == null)
{ {
_minField = new UTKIntegerField { name = "min-field" }; _minField = new UTKIntegerField { name = "min-field" };
_minField.style.flexGrow = 1;
_minField.AddToClassList("utk-property-item-view__field"); _minField.AddToClassList("utk-property-item-view__field");
_valueContainer.Add(_minField); _valueContainer.Add(_minField);
} }
@@ -174,7 +173,6 @@ namespace UVC.UIToolkit
_valueContainer.Add(separator); _valueContainer.Add(separator);
_maxField = new UTKIntegerField { name = "max-field" }; _maxField = new UTKIntegerField { name = "max-field" };
_maxField.style.flexGrow = 1;
_maxField.AddToClassList("utk-property-item-view__field"); _maxField.AddToClassList("utk-property-item-view__field");
_valueContainer.Add(_maxField); _valueContainer.Add(_maxField);
} }
@@ -186,7 +184,6 @@ namespace UVC.UIToolkit
{ {
name = "min-stepper" name = "min-stepper"
}; };
_minStepper.style.flexGrow = 1;
_minStepper.AddToClassList("utk-property-item-view__stepper"); _minStepper.AddToClassList("utk-property-item-view__stepper");
_valueContainer.Add(_minStepper); _valueContainer.Add(_minStepper);
} }
@@ -197,7 +194,6 @@ namespace UVC.UIToolkit
{ {
name = "max-stepper" name = "max-stepper"
}; };
_maxStepper.style.flexGrow = 1;
_maxStepper.AddToClassList("utk-property-item-view__stepper"); _maxStepper.AddToClassList("utk-property-item-view__stepper");
_valueContainer.Add(_maxStepper); _valueContainer.Add(_maxStepper);
} }
@@ -455,12 +451,13 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
// UTKIntRangePropertyItem의 스테퍼 설정 적용 // UTKIntRangePropertyItem의 스테퍼 설정 적용
if (data is UTKIntRangePropertyItem rangeItem) if (data is UTKIntRangePropertyItem rangeItem)
@@ -490,7 +487,7 @@ namespace UVC.UIToolkit
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -498,6 +495,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -385,12 +385,13 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value != null ? new List<string>(data.Value) : new List<string>(); _value = data.Value != null ? new List<string>(data.Value) : new List<string>();
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
if (data is UTKMultiSelectDropdownPropertyItem multiSelectItem) if (data is UTKMultiSelectDropdownPropertyItem multiSelectItem)
{ {
@@ -404,7 +405,7 @@ namespace UVC.UIToolkit
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -412,6 +413,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -54,6 +54,8 @@ namespace UVC.UIToolkit
protected bool _isVisible = true; protected bool _isVisible = true;
protected bool _showLabel = true; protected bool _showLabel = true;
protected string? _tooltipText; protected string? _tooltipText;
private IUTKPropertyItem? _boundItemBase;
#endregion #endregion
#region Properties #region Properties
@@ -285,10 +287,19 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanel);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanel);
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; }
});
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) private void OnThemeChanged(UTKTheme theme)
@@ -390,6 +401,34 @@ namespace UVC.UIToolkit
TooltipText = item.Tooltip; TooltipText = item.Tooltip;
ShowLabel = item.ShowLabel; ShowLabel = item.ShowLabel;
} }
/// <summary>
/// 상태 변경 이벤트를 구독합니다. 하위 View의 Bind에서 호출하세요.
/// </summary>
protected void BindBase(IUTKPropertyItem item)
{
UnbindBase();
_boundItemBase = item;
_boundItemBase.OnStateChanged += OnItemStateChanged;
}
/// <summary>
/// 상태 변경 이벤트 구독을 해제합니다. 하위 View의 Unbind에서 호출하세요.
/// </summary>
protected void UnbindBase()
{
if (_boundItemBase != null)
{
_boundItemBase.OnStateChanged -= OnItemStateChanged;
_boundItemBase = null;
}
}
private void OnItemStateChanged(IUTKPropertyItem item)
{
IsReadOnly = item.IsReadOnly;
ShowLabel = item.ShowLabel;
}
#endregion #endregion
#region IDisposable #region IDisposable
@@ -406,7 +445,10 @@ namespace UVC.UIToolkit
if (disposing) if (disposing)
{ {
UnbindBase();
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanel);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanel);
this.ClearTooltip(); this.ClearTooltip();
_labelElement = null; _labelElement = null;

View File

@@ -83,6 +83,7 @@ namespace UVC.UIToolkit
UTKPropertyType.DateRange => new UTKDateRangePropertyItemView(), UTKPropertyType.DateRange => new UTKDateRangePropertyItemView(),
UTKPropertyType.DateTimeRange => new UTKDateTimeRangePropertyItemView(), UTKPropertyType.DateTimeRange => new UTKDateTimeRangePropertyItemView(),
UTKPropertyType.ColorState => new UTKColorStatePropertyItemView(), UTKPropertyType.ColorState => new UTKColorStatePropertyItemView(),
UTKPropertyType.FloatDropdown => CreateFloatDropdownView(data),
UTKPropertyType.Button => CreateButtonView(data), UTKPropertyType.Button => CreateButtonView(data),
_ => throw new ArgumentException($"Unknown property type: {data.PropertyType}") _ => throw new ArgumentException($"Unknown property type: {data.PropertyType}")
}; };
@@ -121,11 +122,46 @@ namespace UVC.UIToolkit
UTKPropertyType.DateRange => new UTKDateRangePropertyItemView(), UTKPropertyType.DateRange => new UTKDateRangePropertyItemView(),
UTKPropertyType.DateTimeRange => new UTKDateTimeRangePropertyItemView(), UTKPropertyType.DateTimeRange => new UTKDateTimeRangePropertyItemView(),
UTKPropertyType.ColorState => new UTKColorStatePropertyItemView(), UTKPropertyType.ColorState => new UTKColorStatePropertyItemView(),
UTKPropertyType.FloatDropdown => new UTKFloatDropdownPropertyItemView(),
UTKPropertyType.Button => new UTKButtonItemView(), UTKPropertyType.Button => new UTKButtonItemView(),
_ => throw new ArgumentException($"Unknown property type: {propertyType}") _ => throw new ArgumentException($"Unknown property type: {propertyType}")
}; };
} }
/// <summary>
/// PropertyItem 데이터에 해당하는 View의 Type을 반환합니다.
/// View 재사용 시 기존 View와 타입 호환 여부 확인에 사용합니다.
/// </summary>
/// <param name="data">PropertyItem 데이터</param>
/// <returns>View Type</returns>
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)
};
}
/// <summary> /// <summary>
/// 커스텀 View 팩토리를 등록합니다. /// 커스텀 View 팩토리를 등록합니다.
/// </summary> /// </summary>
@@ -225,6 +261,16 @@ namespace UVC.UIToolkit
return new UTKMultiSelectDropdownPropertyItemView(); 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) private static IUTKPropertyItemView CreateButtonView(IUTKPropertyItem data)
{ {
// UTKButtonItem으로 ButtonView 초기화 // UTKButtonItem으로 ButtonView 초기화

View File

@@ -339,12 +339,13 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
if (data is UTKRadioPropertyItem radioItem) if (data is UTKRadioPropertyItem radioItem)
{ {
@@ -355,7 +356,7 @@ namespace UVC.UIToolkit
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateSelection(); UpdateSelection();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -363,6 +364,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -316,12 +316,13 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value ?? string.Empty; _value = data.Value ?? string.Empty;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
if (data is UTKStringPropertyItem stringItem) if (data is UTKStringPropertyItem stringItem)
{ {
@@ -347,7 +348,7 @@ namespace UVC.UIToolkit
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -355,6 +356,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }

View File

@@ -188,17 +188,18 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -206,6 +207,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -188,17 +188,18 @@ namespace UVC.UIToolkit
Unbind(); Unbind();
_boundData = data; _boundData = data;
BindBase(data);
Label = data.Name; Label = data.Name;
_value = data.Value; _value = data.Value;
IsReadOnly = data.IsReadOnly;
IsVisible = data.IsVisible; IsVisible = data.IsVisible;
TooltipText = data.Tooltip; TooltipText = data.Tooltip;
ShowLabel = data.ShowLabel;
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); IsReadOnly = data.IsReadOnly;
} }
public void Unbind() public void Unbind()
@@ -206,6 +207,7 @@ namespace UVC.UIToolkit
if (_boundData != null) if (_boundData != null)
{ {
_boundData.OnTypedValueChanged -= OnDataValueChanged; _boundData.OnTypedValueChanged -= OnDataValueChanged;
UnbindBase();
_boundData = null; _boundData = null;
} }
} }

View File

@@ -168,10 +168,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -194,6 +204,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
OnValueChanged = null; OnValueChanged = null;
UnregisterCallback<ChangeEvent<Vector2>>(OnSliderValueChanged); UnregisterCallback<ChangeEvent<Vector2>>(OnSliderValueChanged);
} }

View File

@@ -252,10 +252,20 @@ namespace UVC.UIToolkit
private void SubscribeToThemeChanges() private void SubscribeToThemeChanges()
{ {
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ => RegisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
{ RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
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) private void OnThemeChanged(UTKTheme theme)
@@ -319,6 +329,8 @@ namespace UVC.UIToolkit
_disposed = true; _disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged; UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback<AttachToPanelEvent>(OnAttachToPanelForTheme);
UnregisterCallback<DetachFromPanelEvent>(OnDetachFromPanelForTheme);
} }
#endregion #endregion
} }

Some files were not shown because too many files have changed in this diff Show More