diff --git a/Assets/Resources/UIToolkit/Property/Views/UTKIntRangePropertyItemView.uxml b/Assets/Resources/UIToolkit/Property/Views/UTKIntRangePropertyItemView.uxml
index 5800a9ce..1c1482ed 100644
--- a/Assets/Resources/UIToolkit/Property/Views/UTKIntRangePropertyItemView.uxml
+++ b/Assets/Resources/UIToolkit/Property/Views/UTKIntRangePropertyItemView.uxml
@@ -4,8 +4,10 @@
+
+
diff --git a/Assets/Resources/UIToolkit/Property/Views/UTKIntRangePropertyItemViewUss.uss b/Assets/Resources/UIToolkit/Property/Views/UTKIntRangePropertyItemViewUss.uss
index a78b3f95..802f6205 100644
--- a/Assets/Resources/UIToolkit/Property/Views/UTKIntRangePropertyItemViewUss.uss
+++ b/Assets/Resources/UIToolkit/Property/Views/UTKIntRangePropertyItemViewUss.uss
@@ -9,6 +9,14 @@
.utk-property-item-view--int-range .utk-property-item-view__field {
flex-grow: 1;
+ flex-shrink: 1;
+ flex-basis: 0;
+}
+
+.utk-property-item-view--int-range .utk-property-item-view__stepper {
+ flex-grow: 1;
+ flex-shrink: 1;
+ flex-basis: 0;
}
.utk-property-item-view--int-range .utk-property-item-view__range-separator {
diff --git a/Assets/Sample/UIToolkit/UTKPropertyListWindowSample.cs b/Assets/Sample/UIToolkit/UTKPropertyListWindowSample.cs
index ee1b519e..0b7ef0b0 100644
--- a/Assets/Sample/UIToolkit/UTKPropertyListWindowSample.cs
+++ b/Assets/Sample/UIToolkit/UTKPropertyListWindowSample.cs
@@ -180,17 +180,13 @@ namespace UVC.Sample.UIToolkit
entries.Add(new UTKDatePropertyItem("date", "Date", DateTime.Today));
// Date (읽기 전용)
- var roDate = new UTKDatePropertyItem("date_ro", "Date (RO)", DateTime.Today.AddDays(7));
- roDate.IsReadOnly = true;
- entries.Add(roDate);
+ entries.Add(new UTKDatePropertyItem("date_ro", "Date (RO)", DateTime.Today.AddDays(7), true));
// DateTime (편집 가능)
entries.Add(new UTKDateTimePropertyItem("datetime", "DateTime", DateTime.Now));
// DateTime (읽기 전용)
- var roDateTime = new UTKDateTimePropertyItem("datetime_ro", "DateTime (RO)", DateTime.Now.AddHours(1));
- roDateTime.IsReadOnly = true;
- entries.Add(roDateTime);
+ entries.Add(new UTKDateTimePropertyItem("datetime_ro", "DateTime (RO)", DateTime.Now.AddHours(1), true));
// DateRange (편집 가능)
entries.Add(new UTKDateRangePropertyItem("daterange", "DateRange",
@@ -244,9 +240,13 @@ namespace UVC.Sample.UIToolkit
entries.Add(new UTKIntRangePropertyItem("intrange", "IntRange", 10, 90));
// IntRange (읽기 전용)
- var roIntRange = new UTKIntRangePropertyItem("intrange_ro", "IntRange (RO)", 20, 80);
- roIntRange.IsReadOnly = true;
- entries.Add(roIntRange);
+ entries.Add(new UTKIntRangePropertyItem("intrange_ro", "IntRange (RO)", 20, 80, isReadOnly: true));
+
+ // IntRange (편집 가능)
+ entries.Add(new UTKIntRangePropertyItem("intrange2", "IntRange2", 10, 90, useStepper: true));
+
+ // IntRange (읽기 전용)
+ entries.Add(new UTKIntRangePropertyItem("intrange2_ro", "IntRange2 (RO)", 20, 80, useStepper: true, isReadOnly: true));
// FloatRange (편집 가능)
entries.Add(new UTKFloatRangePropertyItem("floatrange", "FloatRange", 1.5f, 8.5f));
diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDatePropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDatePropertyItem.cs
index 5a3f01d1..f4efd824 100644
--- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDatePropertyItem.cs
+++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKDatePropertyItem.cs
@@ -11,6 +11,8 @@ namespace UVC.UIToolkit
{
#region Fields
private string _dateFormat = "yyyy-MM-dd";
+ private DateTime _minDay = DateTime.MinValue;
+ private DateTime _maxDay = DateTime.MaxValue;
#endregion
#region Properties
@@ -23,6 +25,20 @@ namespace UVC.UIToolkit
get => _dateFormat;
set => _dateFormat = value ?? "yyyy-MM-dd";
}
+
+ /// 최소 날짜
+ public DateTime MinDay
+ {
+ get => _minDay;
+ set => _minDay = value;
+ }
+
+ /// 최대 날짜
+ public DateTime MaxDay
+ {
+ get => _maxDay;
+ set => _maxDay = value;
+ }
#endregion
#region Constructor
@@ -36,6 +52,25 @@ namespace UVC.UIToolkit
public UTKDatePropertyItem(string id, string name, DateTime initialValue = default, bool isReadOnly = false)
: base(id, name, initialValue == default ? DateTime.Today : initialValue)
{
+ _minDay = DateTime.MinValue;
+ _maxDay = DateTime.MaxValue;
+ IsReadOnly = isReadOnly;
+ }
+
+ ///
+ /// 날짜 속성을 생성합니다 (날짜 제한 포함).
+ ///
+ /// 고유 ID
+ /// 표시 이름
+ /// 초기 값
+ /// 최소 날짜 (null이면 제한 없음)
+ /// 최대 날짜 (null이면 제한 없음)
+ /// 읽기 전용 여부
+ public UTKDatePropertyItem(string id, string name, DateTime initialValue, DateTime? minDay, DateTime? maxDay, bool isReadOnly = false)
+ : base(id, name, initialValue == default ? DateTime.Today : initialValue)
+ {
+ _minDay = minDay ?? DateTime.MinValue;
+ _maxDay = maxDay ?? DateTime.MaxValue;
IsReadOnly = isReadOnly;
}
#endregion
diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatPropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatPropertyItem.cs
index 913694c5..5078ac15 100644
--- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatPropertyItem.cs
+++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKFloatPropertyItem.cs
@@ -64,7 +64,7 @@ namespace UVC.UIToolkit
/// 최대값
/// 슬라이더 사용 여부
/// 읽기 전용 여부
- public UTKFloatPropertyItem(string id, string name, float initialValue, float minValue, float maxValue, bool useSlider = true, bool isReadOnly = false)
+ public UTKFloatPropertyItem(string id, string name, float initialValue, float minValue = float.MinValue, float maxValue = float.MaxValue, bool useSlider = true, bool isReadOnly = false)
: base(id, name, initialValue)
{
_minValue = minValue;
diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntPropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntPropertyItem.cs
index 33916779..500d2c55 100644
--- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntPropertyItem.cs
+++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntPropertyItem.cs
@@ -12,8 +12,8 @@ namespace UVC.UIToolkit
#region Fields
private bool _useSlider;
private bool _useStepper;
- private int _minValue;
- private int _maxValue = 100;
+ private int _minValue = int.MinValue;
+ private int _maxValue = int.MaxValue;
private int _step = 1;
#endregion
@@ -28,8 +28,6 @@ namespace UVC.UIToolkit
set
{
_useSlider = value;
- // UseSlider가 true이면 UseStepper는 false로
- if (value) _useStepper = false;
}
}
@@ -40,8 +38,6 @@ namespace UVC.UIToolkit
set
{
_useStepper = value;
- // UseStepper가 true이면 UseSlider는 false로
- if (value) _useSlider = false;
}
}
diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntRangePropertyItem.cs b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntRangePropertyItem.cs
index 8b3ce8c0..233c5bc5 100644
--- a/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntRangePropertyItem.cs
+++ b/Assets/Scripts/UVC/UIToolkit/Property/Items/UTKIntRangePropertyItem.cs
@@ -1,4 +1,5 @@
#nullable enable
+using System;
namespace UVC.UIToolkit
{
@@ -8,14 +9,52 @@ namespace UVC.UIToolkit
///
public class UTKIntRangePropertyItem : UTKPropertyItemBase
{
+ #region Fields
+ private bool _useStepper;
+ private int _stepperMinValue = int.MinValue;
+ private int _stepperMaxValue = int.MaxValue;
+ private int _stepperStep = 1;
+ #endregion
+
#region Properties
/// 속성 타입
public override UTKPropertyType PropertyType => UTKPropertyType.IntRange;
+
+ /// 스테퍼(증감 버튼) 사용 여부
+ public bool UseStepper
+ {
+ get => _useStepper;
+ set
+ {
+ _useStepper = value;
+ }
+ }
+
+ /// 스테퍼 증감 단위 (기본값: 1)
+ public int StepperStep
+ {
+ get => _stepperStep;
+ set => _stepperStep = Math.Max(1, value);
+ }
+
+ /// 스테퍼 최소값
+ public int StepperMinValue
+ {
+ get => _stepperMinValue;
+ set => _stepperMinValue = value;
+ }
+
+ /// 스테퍼 최대값
+ public int StepperMaxValue
+ {
+ get => _stepperMaxValue;
+ set => _stepperMaxValue = value;
+ }
#endregion
#region Constructor
///
- /// 정수 범위 속성을 생성합니다.
+ /// 정수 범위 속성을 생성합니다 (필드 모드).
///
/// 고유 ID
/// 표시 이름
@@ -34,10 +73,39 @@ namespace UVC.UIToolkit
/// 표시 이름
/// 최소값
/// 최대값
+ /// 스테퍼 증감 단위
+ /// 스테퍼 최소값
+ /// 스테퍼 최대값
+ /// 스테퍼 사용 여부
/// 읽기 전용 여부
- public UTKIntRangePropertyItem(string id, string name, int min, int max, bool isReadOnly = false)
+ public UTKIntRangePropertyItem(string id, string name, int min, int max, int stepperStep = 1, int stepperMinValue = int.MinValue, int stepperMaxValue = int.MaxValue, bool useStepper = false, bool isReadOnly = false)
: base(id, name, new UTKIntRange(min, max))
{
+ _stepperMinValue = stepperMinValue;
+ _stepperMaxValue = stepperMaxValue;
+ _useStepper = useStepper;
+ _stepperStep = stepperStep;
+ IsReadOnly = isReadOnly;
+ }
+
+ ///
+ /// 정수 범위 속성을 생성합니다 (슬라이더/스테퍼 모드).
+ ///
+ /// 고유 ID
+ /// 표시 이름
+ /// 초기 범위 값
+ /// 스테퍼 증감 단위
+ /// 스테퍼 최소값
+ /// 스테퍼 최대값
+ /// 스테퍼 사용 여부
+ /// 읽기 전용 여부
+ 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)
+ : base(id, name, initialValue)
+ {
+ _stepperMinValue = stepperMinValue;
+ _stepperMaxValue = stepperMaxValue;
+ _useStepper = useStepper;
+ _stepperStep = stepperStep;
IsReadOnly = isReadOnly;
}
#endregion
diff --git a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntRangePropertyItemView.cs b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntRangePropertyItemView.cs
index ae09065b..df7bb79b 100644
--- a/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntRangePropertyItemView.cs
+++ b/Assets/Scripts/UVC/UIToolkit/Property/Views/UTKIntRangePropertyItemView.cs
@@ -15,14 +15,70 @@ namespace UVC.UIToolkit
#region Fields
private UTKIntegerField? _minField;
private UTKIntegerField? _maxField;
+ private UTKNumberStepper? _minStepper;
+ private UTKNumberStepper? _maxStepper;
private UTKIntRange _value;
+ private bool _useStepper;
+ private int _stepperMinValue = int.MinValue;
+ private int _stepperMaxValue = int.MaxValue;
+ private int _stepperStep = 1;
private IUTKPropertyItem? _boundData;
#endregion
#region Properties
protected override string ViewTypeName => "UTKIntRangePropertyItemView";
+ /// 스테퍼(증감 버튼) 사용 여부
+ public bool UseStepper
+ {
+ get => _useStepper;
+ set
+ {
+ if (_useStepper != value)
+ {
+ _useStepper = value;
+ UpdateModeClass();
+ }
+ }
+ }
+
+ /// 스테퍼 최소값
+ public int StepperMinValue
+ {
+ get => _stepperMinValue;
+ set
+ {
+ _stepperMinValue = value;
+ if (_minStepper != null) _minStepper.MinValue = value;
+ if (_maxStepper != null) _maxStepper.MinValue = value;
+ }
+ }
+
+ /// 스테퍼 최대값
+ public int StepperMaxValue
+ {
+ get => _stepperMaxValue;
+ set
+ {
+ _stepperMaxValue = value;
+ if (_minStepper != null) _minStepper.MaxValue = value;
+ if (_maxStepper != null) _maxStepper.MaxValue = value;
+ }
+ }
+
+ /// 스테퍼 증감 단위
+ public int StepperStep
+ {
+ get => _stepperStep;
+ set
+ {
+ _stepperStep = Math.Max(1, value);
+ if (_minStepper != null) _minStepper.Step = _stepperStep;
+ if (_maxStepper != null) _maxStepper.Step = _stepperStep;
+ }
+ }
+
/// 현재 값
public UTKIntRange Value
{
@@ -94,31 +150,57 @@ namespace UVC.UIToolkit
{
_minField = this.Q("min-field");
_maxField = this.Q("max-field");
+ _minStepper = this.Q("min-stepper");
+ _maxStepper = this.Q("max-stepper");
// Fallback: UXML에서 못 찾으면 생성
if (_valueContainer != null)
{
_valueContainer.style.flexDirection = FlexDirection.Row;
+ // IntegerField 생성
if (_minField == null)
{
_minField = new UTKIntegerField { name = "min-field" };
_minField.style.flexGrow = 1;
_minField.AddToClassList("utk-property-item-view__field");
_valueContainer.Add(_minField);
-
- var separator = new UTKLabel("~", UTKLabel.LabelSize.Body2);
- separator.AddToClassList("utk-property-item-view__range-separator");
- _valueContainer.Add(separator);
}
if (_maxField == null)
{
+ var separator = new UTKLabel("~", UTKLabel.LabelSize.Body2);
+ separator.AddToClassList("utk-property-item-view__range-separator");
+ _valueContainer.Add(separator);
+
_maxField = new UTKIntegerField { name = "max-field" };
_maxField.style.flexGrow = 1;
_maxField.AddToClassList("utk-property-item-view__field");
_valueContainer.Add(_maxField);
}
+
+ // NumberStepper 생성
+ if (_minStepper == null)
+ {
+ _minStepper = new UTKNumberStepper(_stepperMinValue, _stepperMaxValue, _value.Min, _stepperStep, IsReadOnly)
+ {
+ name = "min-stepper"
+ };
+ _minStepper.style.flexGrow = 1;
+ _minStepper.AddToClassList("utk-property-item-view__stepper");
+ _valueContainer.Add(_minStepper);
+ }
+
+ if (_maxStepper == null)
+ {
+ _maxStepper = new UTKNumberStepper(_stepperMinValue, _stepperMaxValue, _value.Max, _stepperStep, IsReadOnly)
+ {
+ name = "max-stepper"
+ };
+ _maxStepper.style.flexGrow = 1;
+ _maxStepper.AddToClassList("utk-property-item-view__stepper");
+ _valueContainer.Add(_maxStepper);
+ }
}
// 초기 값 설정
@@ -132,6 +214,25 @@ namespace UVC.UIToolkit
_maxField.SetValueWithoutNotify(_value.Max);
_maxField.isReadOnly = IsReadOnly;
}
+ if (_minStepper != null)
+ {
+ _minStepper.MinValue = _stepperMinValue;
+ _minStepper.MaxValue = _stepperMaxValue;
+ _minStepper.Step = _stepperStep;
+ _minStepper.SetValue(_value.Min, false);
+ _minStepper.IsReadOnly = IsReadOnly;
+ }
+ if (_maxStepper != null)
+ {
+ _maxStepper.MinValue = _stepperMinValue;
+ _maxStepper.MaxValue = _stepperMaxValue;
+ _maxStepper.Step = _stepperStep;
+ _maxStepper.SetValue(_value.Max, false);
+ _maxStepper.IsReadOnly = IsReadOnly;
+ }
+
+ // 컨트롤 가시성 업데이트
+ UpdateControlVisibility();
}
private void RegisterEvents()
@@ -144,6 +245,14 @@ namespace UVC.UIToolkit
{
_maxField.OnValueChanged += OnMaxChanged;
}
+ if (_minStepper != null)
+ {
+ _minStepper.OnValueChanged += OnMinStepperChanged;
+ }
+ if (_maxStepper != null)
+ {
+ _maxStepper.OnValueChanged += OnMaxStepperChanged;
+ }
}
private void UnregisterEvents()
@@ -156,6 +265,65 @@ namespace UVC.UIToolkit
{
_maxField.OnValueChanged -= OnMaxChanged;
}
+ if (_minStepper != null)
+ {
+ _minStepper.OnValueChanged -= OnMinStepperChanged;
+ }
+ if (_maxStepper != null)
+ {
+ _maxStepper.OnValueChanged -= OnMaxStepperChanged;
+ }
+ }
+
+ private void UpdateModeClass()
+ {
+ // ReadOnly 상태에서는 무조건 IntegerField만 표시
+ if (IsReadOnly)
+ {
+ RemoveFromClassList("utk-property-item-view--stepper");
+ UpdateControlVisibility();
+ return;
+ }
+
+ // 스테퍼 클래스
+ if (_useStepper)
+ {
+ AddToClassList("utk-property-item-view--stepper");
+ }
+ else
+ {
+ RemoveFromClassList("utk-property-item-view--stepper");
+ }
+
+ UpdateControlVisibility();
+ }
+
+ /// 컨트롤 가시성을 업데이트합니다.
+ private void UpdateControlVisibility()
+ {
+ bool isReadOnlyMode = IsReadOnly;
+ bool showStepper = !isReadOnlyMode && _useStepper;
+ bool showIntField = isReadOnlyMode || !_useStepper;
+
+ if (_minField != null)
+ {
+ _minField.style.display = showIntField ? DisplayStyle.Flex : DisplayStyle.None;
+ }
+
+ if (_maxField != null)
+ {
+ _maxField.style.display = showIntField ? DisplayStyle.Flex : DisplayStyle.None;
+ }
+
+ if (_minStepper != null)
+ {
+ _minStepper.style.display = showStepper ? DisplayStyle.Flex : DisplayStyle.None;
+ }
+
+ if (_maxStepper != null)
+ {
+ _maxStepper.style.display = showStepper ? DisplayStyle.Flex : DisplayStyle.None;
+ }
}
#endregion
@@ -174,6 +342,11 @@ namespace UVC.UIToolkit
{
if (_minField != null) _minField.isReadOnly = isReadOnly;
if (_maxField != null) _maxField.isReadOnly = isReadOnly;
+ if (_minStepper != null) _minStepper.IsReadOnly = isReadOnly;
+ if (_maxStepper != null) _maxStepper.IsReadOnly = isReadOnly;
+
+ // ReadOnly 상태 변경 시 모드 클래스 업데이트
+ UpdateModeClass();
}
#endregion
@@ -207,6 +380,36 @@ namespace UVC.UIToolkit
}
}
}
+
+ private void OnMinStepperChanged(int newMin)
+ {
+ var newValue = new UTKIntRange(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(int newMax)
+ {
+ var newValue = new UTKIntRange(_value.Min, newMax);
+ if (!_value.Equals(newValue))
+ {
+ _value = newValue;
+ OnValueChanged?.Invoke(newValue);
+
+ if (_boundData != null && !_boundData.Value.Equals(newValue))
+ {
+ _boundData.Value = newValue;
+ }
+ }
+ }
#endregion
#region Value Update
@@ -221,6 +424,16 @@ namespace UVC.UIToolkit
{
_maxField.SetValueWithoutNotify(_value.Max);
}
+
+ if (_minStepper != null && _minStepper.Value != _value.Min)
+ {
+ _minStepper.SetValue(_value.Min, false);
+ }
+
+ if (_maxStepper != null && _maxStepper.Value != _value.Max)
+ {
+ _maxStepper.SetValue(_value.Max, false);
+ }
}
#endregion
@@ -249,6 +462,31 @@ namespace UVC.UIToolkit
IsVisible = data.IsVisible;
TooltipText = data.Tooltip;
+ // UTKIntRangePropertyItem의 스테퍼 설정 적용
+ if (data is UTKIntRangePropertyItem rangeItem)
+ {
+ _useStepper = rangeItem.UseStepper;
+ _stepperMinValue = rangeItem.StepperMinValue;
+ _stepperMaxValue = rangeItem.StepperMaxValue;
+ _stepperStep = rangeItem.StepperStep;
+
+ // 스테퍼에 값 적용
+ if (_minStepper != null)
+ {
+ _minStepper.MinValue = _stepperMinValue;
+ _minStepper.MaxValue = _stepperMaxValue;
+ _minStepper.Step = _stepperStep;
+ }
+ if (_maxStepper != null)
+ {
+ _maxStepper.MinValue = _stepperMinValue;
+ _maxStepper.MaxValue = _stepperMaxValue;
+ _maxStepper.Step = _stepperStep;
+ }
+
+ UpdateModeClass();
+ }
+
data.OnTypedValueChanged += OnDataValueChanged;
UpdateValueUI();
@@ -287,6 +525,8 @@ namespace UVC.UIToolkit
OnValueChanged = null;
_minField = null;
_maxField = null;
+ _minStepper = null;
+ _maxStepper = null;
}
base.Dispose(disposing);