#nullable enable using UnityEngine; using UnityEngine.UIElements; namespace UVC.UIToolkit { /// /// 3D 벡터 속성 아이템 /// X, Y, Z 세 개의 FloatField 사용 /// public class UTKVector3PropertyItem : UTKPropertyItemBase { #region Fields private FloatField? _xField; private FloatField? _yField; private FloatField? _zField; #endregion #region Properties public override UTKPropertyType PropertyType => UTKPropertyType.Vector3; #endregion #region Constructor public UTKVector3PropertyItem(string id, string name, Vector3 initialValue = default) : base(id, name, initialValue) { } #endregion #region Override Methods public override VisualElement CreateUI() { var container = CreateContainer(); var label = CreateNameLabel(); container.Add(label); var valueContainer = new VisualElement(); valueContainer.AddToClassList("utk-property-item__value"); // X 필드 var xContainer = new VisualElement(); xContainer.AddToClassList("utk-property-item__vector-field"); xContainer.style.flexDirection = FlexDirection.Row; var xLabel = new Label("X"); xLabel.AddToClassList("utk-property-item__vector-label"); xLabel.AddToClassList("utk-vector-label--x"); _xField = new FloatField(); _xField.name = "x-field"; _xField.value = Value.x; _xField.style.flexGrow = 1; xContainer.Add(xLabel); xContainer.Add(_xField); valueContainer.Add(xContainer); // Y 필드 var yContainer = new VisualElement(); yContainer.AddToClassList("utk-property-item__vector-field"); yContainer.style.flexDirection = FlexDirection.Row; var yLabel = new Label("Y"); yLabel.AddToClassList("utk-property-item__vector-label"); yLabel.AddToClassList("utk-vector-label--y"); _yField = new FloatField(); _yField.name = "y-field"; _yField.value = Value.y; _yField.style.flexGrow = 1; yContainer.Add(yLabel); yContainer.Add(_yField); valueContainer.Add(yContainer); // Z 필드 var zContainer = new VisualElement(); zContainer.AddToClassList("utk-property-item__vector-field"); zContainer.style.flexDirection = FlexDirection.Row; var zLabel = new Label("Z"); zLabel.AddToClassList("utk-property-item__vector-label"); zLabel.AddToClassList("utk-vector-label--z"); _zField = new FloatField(); _zField.name = "z-field"; _zField.value = Value.z; _zField.style.flexGrow = 1; zContainer.Add(zLabel); zContainer.Add(_zField); valueContainer.Add(zContainer); container.Add(valueContainer); return container; } public override void BindUI(VisualElement element) { base.BindUI(element); _xField = element.Q("x-field"); _yField = element.Q("y-field"); _zField = element.Q("z-field"); if (_xField != null) { _xField.value = Value.x; _xField.SetEnabled(!IsReadOnly); _xField.RegisterValueChangedCallback(OnXChanged); } if (_yField != null) { _yField.value = Value.y; _yField.SetEnabled(!IsReadOnly); _yField.RegisterValueChangedCallback(OnYChanged); } if (_zField != null) { _zField.value = Value.z; _zField.SetEnabled(!IsReadOnly); _zField.RegisterValueChangedCallback(OnZChanged); } } public override void UnbindUI(VisualElement element) { if (_xField != null) { _xField.UnregisterValueChangedCallback(OnXChanged); _xField = null; } if (_yField != null) { _yField.UnregisterValueChangedCallback(OnYChanged); _yField = null; } if (_zField != null) { _zField.UnregisterValueChangedCallback(OnZChanged); _zField = null; } base.UnbindUI(element); } public override void RefreshUI() { if (_xField != null && !Mathf.Approximately(_xField.value, Value.x)) { _xField.SetValueWithoutNotify(Value.x); } if (_yField != null && !Mathf.Approximately(_yField.value, Value.y)) { _yField.SetValueWithoutNotify(Value.y); } if (_zField != null && !Mathf.Approximately(_zField.value, Value.z)) { _zField.SetValueWithoutNotify(Value.z); } } protected override void UpdateReadOnlyState() { base.UpdateReadOnlyState(); _xField?.SetEnabled(!IsReadOnly); _yField?.SetEnabled(!IsReadOnly); _zField?.SetEnabled(!IsReadOnly); } #endregion #region Private Methods private void OnXChanged(ChangeEvent evt) { var newValue = new Vector3(evt.newValue, Value.y, Value.z); DebounceValueChange(newValue, 100).Forget(); } private void OnYChanged(ChangeEvent evt) { var newValue = new Vector3(Value.x, evt.newValue, Value.z); DebounceValueChange(newValue, 100).Forget(); } private void OnZChanged(ChangeEvent evt) { var newValue = new Vector3(Value.x, Value.y, evt.newValue); DebounceValueChange(newValue, 100).Forget(); } #endregion } }