207 lines
6.0 KiB
C#
207 lines
6.0 KiB
C#
#nullable enable
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
|
|
namespace UVC.UIToolkit
|
|
{
|
|
/// <summary>
|
|
/// 실수 속성 아이템
|
|
/// FloatField 또는 Slider 사용
|
|
/// </summary>
|
|
public class UTKFloatPropertyItem : UTKPropertyItemBase<float>
|
|
{
|
|
#region Fields
|
|
private FloatField? _floatField;
|
|
private Slider? _slider;
|
|
private bool _useSlider;
|
|
private float _minValue;
|
|
private float _maxValue = 1f;
|
|
#endregion
|
|
|
|
#region Properties
|
|
public override UTKPropertyType PropertyType => UTKPropertyType.Float;
|
|
|
|
/// <summary>슬라이더 사용 여부</summary>
|
|
public bool UseSlider
|
|
{
|
|
get => _useSlider;
|
|
set => _useSlider = value;
|
|
}
|
|
|
|
/// <summary>최소값 (슬라이더 모드)</summary>
|
|
public float MinValue
|
|
{
|
|
get => _minValue;
|
|
set
|
|
{
|
|
_minValue = value;
|
|
if (_slider != null)
|
|
{
|
|
_slider.lowValue = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>최대값 (슬라이더 모드)</summary>
|
|
public float MaxValue
|
|
{
|
|
get => _maxValue;
|
|
set
|
|
{
|
|
_maxValue = value;
|
|
if (_slider != null)
|
|
{
|
|
_slider.highValue = value;
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Constructor
|
|
public UTKFloatPropertyItem(string id, string name, float initialValue = 0f)
|
|
: base(id, name, initialValue)
|
|
{
|
|
}
|
|
|
|
public UTKFloatPropertyItem(string id, string name, float initialValue, float minValue, float maxValue, bool useSlider = true)
|
|
: base(id, name, initialValue)
|
|
{
|
|
_minValue = minValue;
|
|
_maxValue = maxValue;
|
|
_useSlider = useSlider;
|
|
}
|
|
#endregion
|
|
|
|
#region Override Methods
|
|
public override VisualElement CreateUI()
|
|
{
|
|
var container = CreateContainer();
|
|
|
|
if (_useSlider)
|
|
{
|
|
container.AddToClassList("utk-property-item--slider");
|
|
}
|
|
|
|
var label = CreateNameLabel();
|
|
container.Add(label);
|
|
|
|
var valueContainer = new VisualElement();
|
|
valueContainer.AddToClassList("utk-property-item__value");
|
|
|
|
if (_useSlider)
|
|
{
|
|
_slider = new Slider(_minValue, _maxValue);
|
|
_slider.name = "slider-field";
|
|
_slider.value = Value;
|
|
_slider.AddToClassList("utk-property-item__slider");
|
|
valueContainer.Add(_slider);
|
|
|
|
_floatField = new FloatField();
|
|
_floatField.name = "value-field";
|
|
_floatField.value = Value;
|
|
_floatField.AddToClassList("utk-property-item__number-field");
|
|
valueContainer.Add(_floatField);
|
|
}
|
|
else
|
|
{
|
|
_floatField = new FloatField();
|
|
_floatField.name = "value-field";
|
|
_floatField.value = Value;
|
|
valueContainer.Add(_floatField);
|
|
}
|
|
|
|
container.Add(valueContainer);
|
|
|
|
return container;
|
|
}
|
|
|
|
public override void BindUI(VisualElement element)
|
|
{
|
|
base.BindUI(element);
|
|
|
|
_floatField = element.Q<FloatField>("value-field");
|
|
_slider = element.Q<Slider>("slider-field");
|
|
|
|
if (_floatField != null)
|
|
{
|
|
_floatField.value = Value;
|
|
_floatField.SetEnabled(!IsReadOnly);
|
|
_floatField.RegisterValueChangedCallback(OnFloatFieldChanged);
|
|
}
|
|
|
|
if (_slider != null)
|
|
{
|
|
_slider.lowValue = _minValue;
|
|
_slider.highValue = _maxValue;
|
|
_slider.value = Value;
|
|
_slider.SetEnabled(!IsReadOnly);
|
|
_slider.RegisterValueChangedCallback(OnSliderChanged);
|
|
}
|
|
}
|
|
|
|
public override void UnbindUI(VisualElement element)
|
|
{
|
|
if (_floatField != null)
|
|
{
|
|
_floatField.UnregisterValueChangedCallback(OnFloatFieldChanged);
|
|
_floatField = null;
|
|
}
|
|
|
|
if (_slider != null)
|
|
{
|
|
_slider.UnregisterValueChangedCallback(OnSliderChanged);
|
|
_slider = null;
|
|
}
|
|
|
|
base.UnbindUI(element);
|
|
}
|
|
|
|
public override void RefreshUI()
|
|
{
|
|
if (_floatField != null && !Mathf.Approximately(_floatField.value, Value))
|
|
{
|
|
_floatField.SetValueWithoutNotify(Value);
|
|
}
|
|
|
|
if (_slider != null && !Mathf.Approximately(_slider.value, Value))
|
|
{
|
|
_slider.SetValueWithoutNotify(Value);
|
|
}
|
|
}
|
|
|
|
protected override void UpdateReadOnlyState()
|
|
{
|
|
base.UpdateReadOnlyState();
|
|
|
|
_floatField?.SetEnabled(!IsReadOnly);
|
|
_slider?.SetEnabled(!IsReadOnly);
|
|
}
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
private void OnFloatFieldChanged(ChangeEvent<float> evt)
|
|
{
|
|
float clampedValue = _useSlider ? Mathf.Clamp(evt.newValue, _minValue, _maxValue) : evt.newValue;
|
|
|
|
if (_slider != null && !Mathf.Approximately(_slider.value, clampedValue))
|
|
{
|
|
_slider.SetValueWithoutNotify(clampedValue);
|
|
}
|
|
|
|
DebounceValueChange(clampedValue, 100).Forget();
|
|
}
|
|
|
|
private void OnSliderChanged(ChangeEvent<float> evt)
|
|
{
|
|
if (_floatField != null && !Mathf.Approximately(_floatField.value, evt.newValue))
|
|
{
|
|
_floatField.SetValueWithoutNotify(evt.newValue);
|
|
}
|
|
|
|
// 슬라이더는 빠른 반응이 필요하므로 짧은 디바운스
|
|
DebounceValueChange(evt.newValue, 50).Forget();
|
|
}
|
|
#endregion
|
|
}
|
|
}
|