UTKIntPropertyItemView 수정중

This commit is contained in:
logonkhi
2026-02-05 19:12:16 +09:00
parent c9af0d2d6f
commit acd430c5d7
5 changed files with 218 additions and 14 deletions

View File

@@ -32,7 +32,6 @@
.utk-property-item-view--float.utk-property-item-view--slider .utk-property-item-view__field { .utk-property-item-view--float.utk-property-item-view--slider .utk-property-item-view__field {
flex-grow: 0; flex-grow: 0;
min-width: 60px; min-width: 60px;
max-width: 80px;
} }
/* ReadOnly 상태: Slider 숨김 */ /* ReadOnly 상태: Slider 숨김 */

View File

@@ -12,19 +12,24 @@
flex-grow: 1; flex-grow: 1;
} }
/* 기본 상태: Slider 숨김, Field만 표시 */ /* 기본 상태: Slider, Stepper 숨김, Field만 표시 */
.utk-property-item-view--int .utk-property-item-view__slider { .utk-property-item-view--int .utk-property-item-view__slider {
display: none; display: none;
flex-grow: 1; flex-grow: 1;
margin-right: 8px; 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 { .utk-property-item-view--int .utk-property-item-view__field {
display: flex; display: flex;
flex-grow: 1; 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 { .utk-property-item-view--int.utk-property-item-view--slider .utk-property-item-view__slider {
display: flex; display: flex;
} }
@@ -32,14 +37,48 @@
.utk-property-item-view--int.utk-property-item-view--slider .utk-property-item-view__field { .utk-property-item-view--int.utk-property-item-view--slider .utk-property-item-view__field {
flex-grow: 0; flex-grow: 0;
min-width: 60px; 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 { .utk-property-item-view--int.utk-property-item-view--readonly .utk-property-item-view__slider {
display: none; 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 { .utk-property-item-view--int.utk-property-item-view--readonly .utk-property-item-view__field {
display: flex;
flex-grow: 1; flex-grow: 1;
} }

View File

@@ -114,9 +114,20 @@ namespace UVC.Sample.UIToolkit
entries.Add(new UTKIntPropertyItem("int", "Int", 42, 0, 100, true)); entries.Add(new UTKIntPropertyItem("int", "Int", 42, 0, 100, true));
// Int (읽기 전용) // Int (읽기 전용)
var roInt = new UTKIntPropertyItem("int_ro", "Int (RO)", 99, 0, 100, true); var roInt = new UTKIntPropertyItem("int_ro", "Int (RO)", 99, 0, 100, true, isReadOnly: true);
roInt.IsReadOnly = true;
entries.Add(roInt); 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 (편집 가능) // Float (편집 가능)
entries.Add(new UTKFloatPropertyItem("float", "Float", 3.14f, 0f, 10f, true)); entries.Add(new UTKFloatPropertyItem("float", "Float", 3.14f, 0f, 10f, true));

View File

@@ -1,4 +1,5 @@
#nullable enable #nullable enable
using System;
namespace UVC.UIToolkit namespace UVC.UIToolkit
{ {
@@ -10,8 +11,10 @@ namespace UVC.UIToolkit
{ {
#region Fields #region Fields
private bool _useSlider; private bool _useSlider;
private bool _useStepper;
private int _minValue; private int _minValue;
private int _maxValue = 100; private int _maxValue = 100;
private int _step = 1;
#endregion #endregion
#region Properties #region Properties
@@ -22,7 +25,31 @@ namespace UVC.UIToolkit
public bool UseSlider public bool UseSlider
{ {
get => _useSlider; get => _useSlider;
set => _useSlider = value; set
{
_useSlider = value;
// UseSlider가 true이면 UseStepper는 false로
if (value) _useStepper = false;
}
}
/// <summary>스테퍼(증감 버튼) 사용 여부</summary>
public bool UseStepper
{
get => _useStepper;
set
{
_useStepper = value;
// UseStepper가 true이면 UseSlider는 false로
if (value) _useSlider = false;
}
}
/// <summary>스테퍼 증감 단위 (기본값: 1)</summary>
public int Step
{
get => _step;
set => _step = Math.Max(1, value);
} }
/// <summary>최소값 (슬라이더 모드)</summary> /// <summary>최소값 (슬라이더 모드)</summary>
@@ -62,12 +89,13 @@ 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 = 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) : base(id, name, initialValue)
{ {
_minValue = minValue; _minValue = minValue;
_maxValue = maxValue; _maxValue = maxValue;
_useSlider = useSlider; _useSlider = useSlider;
_useStepper = useStepper;
IsReadOnly = isReadOnly; IsReadOnly = isReadOnly;
} }
#endregion #endregion

View File

@@ -7,7 +7,7 @@ namespace UVC.UIToolkit
{ {
/// <summary> /// <summary>
/// Int 속성 View 클래스입니다. /// Int 속성 View 클래스입니다.
/// UTKIntegerField 또는 UTKSliderInt를 사용하여 int 값을 표시/편집합니다. /// UTKIntegerField, UTKSliderInt, 또는 UTKNumberStepper를 사용하여 int 값을 표시/편집합니다.
/// ///
/// <para><b>사용법 (단독 사용):</b></para> /// <para><b>사용법 (단독 사용):</b></para>
/// <code> /// <code>
@@ -20,8 +20,14 @@ namespace UVC.UIToolkit
/// view.MaxValue = 100; /// view.MaxValue = 100;
/// parent.Add(view); /// parent.Add(view);
/// ///
/// // 스테퍼 모드
/// var stepperView = new UTKIntPropertyItemView();
/// stepperView.UseStepper = true;
/// stepperView.Step = 5;
///
/// // UXML에서 사용 /// // UXML에서 사용
/// &lt;utk:UTKIntPropertyItemView label="수량" value="10" use-slider="true" min-value="0" max-value="100" /&gt; /// &lt;utk:UTKIntPropertyItemView label="수량" value="10" use-slider="true" min-value="0" max-value="100" /&gt;
/// &lt;utk:UTKIntPropertyItemView label="개수" value="1" use-stepper="true" step="1" /&gt;
/// </code> /// </code>
/// </summary> /// </summary>
[UxmlElement] [UxmlElement]
@@ -30,11 +36,14 @@ namespace UVC.UIToolkit
#region Fields #region Fields
private UTKIntegerField? _intField; private UTKIntegerField? _intField;
private UTKSliderInt? _slider; private UTKSliderInt? _slider;
private UTKNumberStepper? _stepper;
private int _value; private int _value;
private int _minValue; private int _minValue;
private int _maxValue = 100; private int _maxValue = 100;
private int _step = 1;
private bool _useSlider; private bool _useSlider;
private bool _useStepper;
private IUTKPropertyItem<int>? _boundData; private IUTKPropertyItem<int>? _boundData;
#endregion #endregion
@@ -103,7 +112,39 @@ namespace UVC.UIToolkit
if (_useSlider != value) if (_useSlider != value)
{ {
_useSlider = value; _useSlider = value;
UpdateSliderClass(); if (value) _useStepper = false;
UpdateModeClass();
}
}
}
/// <summary>스테퍼(증감 버튼) 사용 여부</summary>
[UxmlAttribute("use-stepper")]
public bool UseStepper
{
get => _useStepper;
set
{
if (_useStepper != value)
{
_useStepper = value;
if (value) _useSlider = false;
UpdateModeClass();
}
}
}
/// <summary>스테퍼 증감 단위</summary>
[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(); RegisterEvents();
// 슬라이더 클래스 업데이트 // 슬라이더 클래스 업데이트
UpdateSliderClass(); UpdateModeClass();
UpdateValueUI(); UpdateValueUI();
UpdateReadOnlyState(); UpdateReadOnlyState();
@@ -178,6 +219,7 @@ namespace UVC.UIToolkit
{ {
_slider = this.Q<UTKSliderInt>("slider-field"); _slider = this.Q<UTKSliderInt>("slider-field");
_intField = this.Q<UTKIntegerField>("value-field"); _intField = this.Q<UTKIntegerField>("value-field");
_stepper = this.Q<UTKNumberStepper>("stepper-field");
// Fallback: UXML에서 못 찾으면 생성 // Fallback: UXML에서 못 찾으면 생성
if (_valueContainer != null) if (_valueContainer != null)
@@ -198,6 +240,16 @@ namespace UVC.UIToolkit
_intField.AddToClassList("utk-property-item-view__field"); _intField.AddToClassList("utk-property-item-view__field");
_valueContainer.Add(_intField); _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.SetValueWithoutNotify(_value);
_intField.isReadOnly = IsReadOnly; _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) if (_useSlider)
{ {
AddToClassList("utk-property-item-view--slider"); AddToClassList("utk-property-item-view--slider");
@@ -224,6 +285,16 @@ namespace UVC.UIToolkit
{ {
RemoveFromClassList("utk-property-item-view--slider"); RemoveFromClassList("utk-property-item-view--slider");
} }
// 스테퍼 클래스
if (_useStepper)
{
AddToClassList("utk-property-item-view--stepper");
}
else
{
RemoveFromClassList("utk-property-item-view--stepper");
}
} }
#endregion #endregion
@@ -249,6 +320,11 @@ namespace UVC.UIToolkit
{ {
_slider.IsEnabled = !isReadOnly; _slider.IsEnabled = !isReadOnly;
} }
if (_stepper != null)
{
_stepper.IsReadOnly = isReadOnly;
}
} }
#endregion #endregion
@@ -264,6 +340,11 @@ namespace UVC.UIToolkit
{ {
_slider.OnValueChanged += OnSliderChanged; _slider.OnValueChanged += OnSliderChanged;
} }
if (_stepper != null)
{
_stepper.OnValueChanged += OnStepperChanged;
}
} }
private void UnregisterEvents() private void UnregisterEvents()
@@ -277,6 +358,11 @@ namespace UVC.UIToolkit
{ {
_slider.OnValueChanged -= OnSliderChanged; _slider.OnValueChanged -= OnSliderChanged;
} }
if (_stepper != null)
{
_stepper.OnValueChanged -= OnStepperChanged;
}
} }
private void OnIntFieldChanged(int newValue) 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 #endregion
#region Value Update #region Value Update
@@ -337,6 +437,11 @@ namespace UVC.UIToolkit
{ {
_slider.SetValueWithoutNotify(_value); _slider.SetValueWithoutNotify(_value);
} }
if (_stepper != null && _stepper.Value != _value)
{
_stepper.SetValue(_value, false);
}
} }
#endregion #endregion
@@ -369,11 +474,23 @@ namespace UVC.UIToolkit
{ {
_minValue = intItem.MinValue; _minValue = intItem.MinValue;
_maxValue = intItem.MaxValue; _maxValue = intItem.MaxValue;
_step = intItem.Step;
// 모드 변경 확인
bool modeChanged = false;
if (_useSlider != intItem.UseSlider) if (_useSlider != intItem.UseSlider)
{ {
_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.lowValue = _minValue;
_slider.highValue = _maxValue; _slider.highValue = _maxValue;
} }
// 스테퍼 설정 업데이트
if (_stepper != null)
{
_stepper.MinValue = _minValue;
_stepper.MaxValue = _maxValue;
_stepper.Step = _step;
}
} }
data.OnTypedValueChanged += OnDataValueChanged; data.OnTypedValueChanged += OnDataValueChanged;
@@ -422,6 +547,8 @@ namespace UVC.UIToolkit
OnValueChanged = null; OnValueChanged = null;
_intField = null; _intField = null;
_slider = null; _slider = null;
_stepper?.Dispose();
_stepper = null;
} }
base.Dispose(disposing); base.Dispose(disposing);