diff --git a/Assets/Resources/UIToolkit/Property/Views/UTKFloatPropertyItemViewUss.uss b/Assets/Resources/UIToolkit/Property/Views/UTKFloatPropertyItemViewUss.uss
index 1d77ebf7..572821a4 100644
--- a/Assets/Resources/UIToolkit/Property/Views/UTKFloatPropertyItemViewUss.uss
+++ b/Assets/Resources/UIToolkit/Property/Views/UTKFloatPropertyItemViewUss.uss
@@ -32,7 +32,6 @@
.utk-property-item-view--float.utk-property-item-view--slider .utk-property-item-view__field {
flex-grow: 0;
min-width: 60px;
- max-width: 80px;
}
/* ReadOnly 상태: Slider 숨김 */
diff --git a/Assets/Resources/UIToolkit/Property/Views/UTKIntPropertyItemViewUss.uss b/Assets/Resources/UIToolkit/Property/Views/UTKIntPropertyItemViewUss.uss
index fbec2430..b8e23d43 100644
--- a/Assets/Resources/UIToolkit/Property/Views/UTKIntPropertyItemViewUss.uss
+++ b/Assets/Resources/UIToolkit/Property/Views/UTKIntPropertyItemViewUss.uss
@@ -12,19 +12,24 @@
flex-grow: 1;
}
-/* 기본 상태: Slider 숨김, Field만 표시 */
+/* 기본 상태: Slider, Stepper 숨김, Field만 표시 */
.utk-property-item-view--int .utk-property-item-view__slider {
display: none;
flex-grow: 1;
margin-right: 8px;
}
+.utk-property-item-view--int .utk-property-item-view__stepper {
+ display: none;
+ flex-grow: 1;
+}
+
.utk-property-item-view--int .utk-property-item-view__field {
display: flex;
flex-grow: 1;
}
-/* UseSlider 상태: Slider + Field 모두 표시 */
+/* UseSlider 상태: Slider + Field 모두 표시, Stepper 숨김 */
.utk-property-item-view--int.utk-property-item-view--slider .utk-property-item-view__slider {
display: flex;
}
@@ -32,14 +37,48 @@
.utk-property-item-view--int.utk-property-item-view--slider .utk-property-item-view__field {
flex-grow: 0;
min-width: 60px;
- max-width: 80px;
}
-/* ReadOnly 상태: Slider 숨김 */
+.utk-property-item-view--int.utk-property-item-view--slider .utk-property-item-view__stepper {
+ display: none;
+}
+
+/* UseStepper 상태: Stepper만 표시, Field/Slider 숨김 */
+.utk-property-item-view--int.utk-property-item-view--stepper .utk-property-item-view__stepper {
+ display: flex;
+}
+
+.utk-property-item-view--int.utk-property-item-view--stepper .utk-property-item-view__field {
+ display: none;
+}
+
+.utk-property-item-view--int.utk-property-item-view--stepper .utk-property-item-view__slider {
+ display: none;
+}
+
+/* UseSlider + UseStepper 상태: Slider + Stepper 모두 표시, Field 숨김 */
+.utk-property-item-view--int.utk-property-item-view--slider.utk-property-item-view--stepper .utk-property-item-view__slider {
+ display: flex;
+}
+
+.utk-property-item-view--int.utk-property-item-view--slider.utk-property-item-view--stepper .utk-property-item-view__stepper {
+ display: flex;
+}
+
+.utk-property-item-view--int.utk-property-item-view--slider.utk-property-item-view--stepper .utk-property-item-view__field {
+ display: none;
+}
+
+/* ReadOnly 상태: Slider/Stepper 숨김, Field만 표시 (flex-grow: 1) */
.utk-property-item-view--int.utk-property-item-view--readonly .utk-property-item-view__slider {
display: none;
}
+.utk-property-item-view--int.utk-property-item-view--readonly .utk-property-item-view__stepper {
+ display: none;
+}
+
.utk-property-item-view--int.utk-property-item-view--readonly .utk-property-item-view__field {
+ display: flex;
flex-grow: 1;
}
diff --git a/Assets/Sample/UIToolkit/UTKPropertyListWindowSample.cs b/Assets/Sample/UIToolkit/UTKPropertyListWindowSample.cs
index bc12bb94..1293ea7e 100644
--- a/Assets/Sample/UIToolkit/UTKPropertyListWindowSample.cs
+++ b/Assets/Sample/UIToolkit/UTKPropertyListWindowSample.cs
@@ -114,9 +114,20 @@ namespace UVC.Sample.UIToolkit
entries.Add(new UTKIntPropertyItem("int", "Int", 42, 0, 100, true));
// Int (읽기 전용)
- var roInt = new UTKIntPropertyItem("int_ro", "Int (RO)", 99, 0, 100, true);
- roInt.IsReadOnly = true;
+ var roInt = new UTKIntPropertyItem("int_ro", "Int (RO)", 99, 0, 100, true, isReadOnly: true);
entries.Add(roInt);
+
+ // Int stepper (편집 가능)
+ entries.Add(new UTKIntPropertyItem("int2", "Int2", 42, 0, 100, false, true));
+
+ // Int stepper (읽기 전용)
+ entries.Add(new UTKIntPropertyItem("int2_ro", "Int2 (RO)", 99, 0, 100, false, true, isReadOnly: true));
+
+ // Int stepper (편집 가능)
+ entries.Add(new UTKIntPropertyItem("int3", "Int3", 42, 0, 100, true, true));
+
+ // Int stepper (읽기 전용)
+ entries.Add(new UTKIntPropertyItem("int3_ro", "Int3 (RO)", 99, 0, 100, true, true, isReadOnly: true));
// Float (편집 가능)
entries.Add(new UTKFloatPropertyItem("float", "Float", 3.14f, 0f, 10f, true));
diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntPropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntPropertyItem.cs
index 097753eb..33916779 100644
--- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntPropertyItem.cs
+++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntPropertyItem.cs
@@ -1,4 +1,5 @@
#nullable enable
+using System;
namespace UVC.UIToolkit
{
@@ -10,8 +11,10 @@ namespace UVC.UIToolkit
{
#region Fields
private bool _useSlider;
+ private bool _useStepper;
private int _minValue;
private int _maxValue = 100;
+ private int _step = 1;
#endregion
#region Properties
@@ -22,7 +25,31 @@ namespace UVC.UIToolkit
public bool UseSlider
{
get => _useSlider;
- set => _useSlider = value;
+ set
+ {
+ _useSlider = value;
+ // UseSlider가 true이면 UseStepper는 false로
+ if (value) _useStepper = false;
+ }
+ }
+
+ /// 스테퍼(증감 버튼) 사용 여부
+ public bool UseStepper
+ {
+ get => _useStepper;
+ set
+ {
+ _useStepper = value;
+ // UseStepper가 true이면 UseSlider는 false로
+ if (value) _useSlider = false;
+ }
+ }
+
+ /// 스테퍼 증감 단위 (기본값: 1)
+ public int Step
+ {
+ get => _step;
+ set => _step = Math.Max(1, value);
}
/// 최소값 (슬라이더 모드)
@@ -62,12 +89,13 @@ namespace UVC.UIToolkit
/// 최대값
/// 슬라이더 사용 여부
/// 읽기 전용 여부
- public UTKIntPropertyItem(string id, string name, int initialValue, int minValue, int maxValue, bool useSlider = true, bool isReadOnly = false)
+ public UTKIntPropertyItem(string id, string name, int initialValue, int minValue, int maxValue, bool useSlider = false, bool useStepper = false, bool isReadOnly = false)
: base(id, name, initialValue)
{
_minValue = minValue;
_maxValue = maxValue;
_useSlider = useSlider;
+ _useStepper = useStepper;
IsReadOnly = isReadOnly;
}
#endregion
diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntPropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntPropertyItemView.cs
index b1a5a170..fa0bff3e 100644
--- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntPropertyItemView.cs
+++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntPropertyItemView.cs
@@ -7,7 +7,7 @@ namespace UVC.UIToolkit
{
///
/// Int 속성 View 클래스입니다.
- /// UTKIntegerField 또는 UTKSliderInt를 사용하여 int 값을 표시/편집합니다.
+ /// UTKIntegerField, UTKSliderInt, 또는 UTKNumberStepper를 사용하여 int 값을 표시/편집합니다.
///
/// 사용법 (단독 사용):
///
@@ -20,8 +20,14 @@ namespace UVC.UIToolkit
/// view.MaxValue = 100;
/// parent.Add(view);
///
+ /// // 스테퍼 모드
+ /// var stepperView = new UTKIntPropertyItemView();
+ /// stepperView.UseStepper = true;
+ /// stepperView.Step = 5;
+ ///
/// // UXML에서 사용
/// <utk:UTKIntPropertyItemView label="수량" value="10" use-slider="true" min-value="0" max-value="100" />
+ /// <utk:UTKIntPropertyItemView label="개수" value="1" use-stepper="true" step="1" />
///
///
[UxmlElement]
@@ -30,11 +36,14 @@ namespace UVC.UIToolkit
#region Fields
private UTKIntegerField? _intField;
private UTKSliderInt? _slider;
+ private UTKNumberStepper? _stepper;
private int _value;
private int _minValue;
private int _maxValue = 100;
+ private int _step = 1;
private bool _useSlider;
+ private bool _useStepper;
private IUTKPropertyItem? _boundData;
#endregion
@@ -103,7 +112,39 @@ namespace UVC.UIToolkit
if (_useSlider != value)
{
_useSlider = value;
- UpdateSliderClass();
+ if (value) _useStepper = false;
+ UpdateModeClass();
+ }
+ }
+ }
+
+ /// 스테퍼(증감 버튼) 사용 여부
+ [UxmlAttribute("use-stepper")]
+ public bool UseStepper
+ {
+ get => _useStepper;
+ set
+ {
+ if (_useStepper != value)
+ {
+ _useStepper = value;
+ if (value) _useSlider = false;
+ UpdateModeClass();
+ }
+ }
+ }
+
+ /// 스테퍼 증감 단위
+ [UxmlAttribute("step")]
+ public int Step
+ {
+ get => _step;
+ set
+ {
+ _step = Math.Max(1, value);
+ if (_stepper != null)
+ {
+ _stepper.Step = _step;
}
}
}
@@ -168,7 +209,7 @@ namespace UVC.UIToolkit
RegisterEvents();
// 슬라이더 클래스 업데이트
- UpdateSliderClass();
+ UpdateModeClass();
UpdateValueUI();
UpdateReadOnlyState();
@@ -178,6 +219,7 @@ namespace UVC.UIToolkit
{
_slider = this.Q("slider-field");
_intField = this.Q("value-field");
+ _stepper = this.Q("stepper-field");
// Fallback: UXML에서 못 찾으면 생성
if (_valueContainer != null)
@@ -198,6 +240,16 @@ namespace UVC.UIToolkit
_intField.AddToClassList("utk-property-item-view__field");
_valueContainer.Add(_intField);
}
+
+ if (_stepper == null)
+ {
+ _stepper = new UTKNumberStepper(_minValue, _maxValue, _value, _step, IsReadOnly)
+ {
+ name = "stepper-field"
+ };
+ _stepper.AddToClassList("utk-property-item-view__stepper");
+ _valueContainer.Add(_stepper);
+ }
}
// 초기 값 설정
@@ -212,10 +264,19 @@ namespace UVC.UIToolkit
_intField.SetValueWithoutNotify(_value);
_intField.isReadOnly = IsReadOnly;
}
+ if (_stepper != null)
+ {
+ _stepper.MinValue = _minValue;
+ _stepper.MaxValue = _maxValue;
+ _stepper.Step = _step;
+ _stepper.SetValue(_value, false);
+ _stepper.IsReadOnly = IsReadOnly;
+ }
}
- private void UpdateSliderClass()
+ private void UpdateModeClass()
{
+ // 슬라이더 클래스
if (_useSlider)
{
AddToClassList("utk-property-item-view--slider");
@@ -224,6 +285,16 @@ namespace UVC.UIToolkit
{
RemoveFromClassList("utk-property-item-view--slider");
}
+
+ // 스테퍼 클래스
+ if (_useStepper)
+ {
+ AddToClassList("utk-property-item-view--stepper");
+ }
+ else
+ {
+ RemoveFromClassList("utk-property-item-view--stepper");
+ }
}
#endregion
@@ -249,6 +320,11 @@ namespace UVC.UIToolkit
{
_slider.IsEnabled = !isReadOnly;
}
+
+ if (_stepper != null)
+ {
+ _stepper.IsReadOnly = isReadOnly;
+ }
}
#endregion
@@ -264,6 +340,11 @@ namespace UVC.UIToolkit
{
_slider.OnValueChanged += OnSliderChanged;
}
+
+ if (_stepper != null)
+ {
+ _stepper.OnValueChanged += OnStepperChanged;
+ }
}
private void UnregisterEvents()
@@ -277,6 +358,11 @@ namespace UVC.UIToolkit
{
_slider.OnValueChanged -= OnSliderChanged;
}
+
+ if (_stepper != null)
+ {
+ _stepper.OnValueChanged -= OnStepperChanged;
+ }
}
private void OnIntFieldChanged(int newValue)
@@ -323,6 +409,20 @@ namespace UVC.UIToolkit
}
}
}
+
+ private void OnStepperChanged(int newValue)
+ {
+ if (_value != newValue)
+ {
+ _value = newValue;
+ OnValueChanged?.Invoke(newValue);
+
+ if (_boundData != null && _boundData.Value != newValue)
+ {
+ _boundData.Value = newValue;
+ }
+ }
+ }
#endregion
#region Value Update
@@ -337,6 +437,11 @@ namespace UVC.UIToolkit
{
_slider.SetValueWithoutNotify(_value);
}
+
+ if (_stepper != null && _stepper.Value != _value)
+ {
+ _stepper.SetValue(_value, false);
+ }
}
#endregion
@@ -369,11 +474,23 @@ namespace UVC.UIToolkit
{
_minValue = intItem.MinValue;
_maxValue = intItem.MaxValue;
+ _step = intItem.Step;
+ // 모드 변경 확인
+ bool modeChanged = false;
if (_useSlider != intItem.UseSlider)
{
_useSlider = intItem.UseSlider;
- UpdateSliderClass();
+ modeChanged = true;
+ }
+ if (_useStepper != intItem.UseStepper)
+ {
+ _useStepper = intItem.UseStepper;
+ modeChanged = true;
+ }
+ if (modeChanged)
+ {
+ UpdateModeClass();
}
// 슬라이더 범위 업데이트
@@ -382,6 +499,14 @@ namespace UVC.UIToolkit
_slider.lowValue = _minValue;
_slider.highValue = _maxValue;
}
+
+ // 스테퍼 설정 업데이트
+ if (_stepper != null)
+ {
+ _stepper.MinValue = _minValue;
+ _stepper.MaxValue = _maxValue;
+ _stepper.Step = _step;
+ }
}
data.OnTypedValueChanged += OnDataValueChanged;
@@ -422,6 +547,8 @@ namespace UVC.UIToolkit
OnValueChanged = null;
_intField = null;
_slider = null;
+ _stepper?.Dispose();
+ _stepper = null;
}
base.Dispose(disposing);