You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
268 lines
8.6 KiB
268 lines
8.6 KiB
using System;
|
|
using System.Linq;
|
|
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
|
|
namespace UnityEditor.VFX.UI
|
|
{
|
|
abstract class NumericPropertyRM<T, U> : SimpleUIPropertyRM<T, U>
|
|
{
|
|
protected NumericPropertyRM(IPropertyRMProvider controller, float labelWidth) : base(controller, labelWidth)
|
|
{
|
|
}
|
|
|
|
public override float GetPreferredControlWidth()
|
|
{
|
|
var range = m_Provider.attributes.FindRange();
|
|
|
|
return HasValidRange(range) ? 120 : 60;
|
|
}
|
|
|
|
protected override void UpdateIndeterminate()
|
|
{
|
|
if (field is IMixedValueSupport mixedValueSupport)
|
|
{
|
|
mixedValueSupport.showMixedValue = indeterminate;
|
|
}
|
|
|
|
if (m_Slider != null)
|
|
{
|
|
m_Slider.isIndeterminate = indeterminate;
|
|
}
|
|
}
|
|
|
|
private bool HasValidRange(Vector2 range)
|
|
{
|
|
return range != Vector2.zero && !float.IsPositiveInfinity(range.y) && range.x < range.y;
|
|
}
|
|
|
|
private VFXBaseSliderField<U> m_Slider;
|
|
private VisualElement m_TextField;
|
|
|
|
protected abstract VisualElement CreateSimpleField(string label);
|
|
protected abstract VFXBaseSliderField<U> CreateSliderField(string label);
|
|
protected abstract T FilterValue(Vector2 range, T value);
|
|
|
|
public override INotifyValueChanged<U> CreateField()
|
|
{
|
|
Vector2 range = m_Provider.attributes.FindRange();
|
|
VisualElement createdField;
|
|
if (!HasValidRange(range))
|
|
{
|
|
createdField = CreateSimpleField(string.IsNullOrEmpty(provider.name) ? " " : ObjectNames.NicifyVariableName(provider.name));
|
|
m_TextField = createdField.Q<TextElement>(null, "unity-text-element__selectable");
|
|
if (m_TextField != null)
|
|
{
|
|
m_TextField.RegisterCallback<KeyDownEvent>(OnKeyDown, TrickleDown.TrickleDown);
|
|
m_TextField.RegisterCallback<BlurEvent>(OnFocusLost, TrickleDown.TrickleDown);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_Slider = CreateSliderField(ObjectNames.NicifyVariableName(m_Provider.name));
|
|
m_Slider.SetOnValueDragStarted(ValueDragStarted);
|
|
m_Slider.SetOnValueDragFinished(ValueDragFinished);
|
|
m_Slider.RegisterCallback<BlurEvent>(OnFocusLost);
|
|
m_Slider.range = range;
|
|
if (IsLogarithmic() && m_Provider.attributes.FindLogarithmicBase() is var logBase and > 0)
|
|
{
|
|
bool snapToPower = m_Provider.attributes.FindSnapToPower();
|
|
if (range.x > 0)
|
|
{
|
|
m_Slider.scale = new LogarithmicSliderScale(range, logBase, snapToPower);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"Property `{this.provider.name}`: logarithmic scale does not support range minimum value <=0\nFallback to linear scale");
|
|
}
|
|
}
|
|
|
|
createdField = m_Slider;
|
|
}
|
|
|
|
if (createdField.Q<Label>() is { } label)
|
|
{
|
|
label.RegisterCallback<PointerCaptureEvent>(x => ValueDragStarted());
|
|
label.RegisterCallback<PointerCaptureOutEvent>(x => ValueDragFinished());
|
|
}
|
|
|
|
return createdField as INotifyValueChanged<U>;
|
|
}
|
|
|
|
bool IsLogarithmic()
|
|
{
|
|
return m_Provider.attributes.Is(VFXPropertyAttributes.Type.Logarithmic);
|
|
}
|
|
|
|
void OnKeyDown(KeyDownEvent e)
|
|
{
|
|
if (e.character == '\n')
|
|
{
|
|
DelayedNotifyValueChange();
|
|
UpdateGUI(true);
|
|
}
|
|
}
|
|
|
|
void OnFocusLost(BlurEvent e)
|
|
{
|
|
DelayedNotifyValueChange();
|
|
UpdateGUI(true);
|
|
}
|
|
|
|
void DelayedNotifyValueChange()
|
|
{
|
|
if (isDelayed && hasChangeDelayed)
|
|
{
|
|
hasChangeDelayed = false;
|
|
NotifyValueChanged();
|
|
}
|
|
}
|
|
|
|
protected override bool HasFocus()
|
|
{
|
|
if (m_Slider != null)
|
|
return m_Slider.HasFocus();
|
|
if (m_TextField != null)
|
|
return m_TextField.HasFocus();
|
|
return false;
|
|
}
|
|
|
|
public override bool IsCompatible(IPropertyRMProvider provider)
|
|
{
|
|
if (!base.IsCompatible(provider)) return false;
|
|
|
|
Vector2 range = m_Provider.attributes.FindRange();
|
|
|
|
return HasValidRange(range) != (m_Slider == null);
|
|
}
|
|
|
|
public override void UpdateGUI(bool force)
|
|
{
|
|
if (m_Slider != null)
|
|
{
|
|
Vector2 range = m_Provider.attributes.FindRange();
|
|
|
|
m_Slider.range = range;
|
|
}
|
|
|
|
base.UpdateGUI(force);
|
|
}
|
|
|
|
public override object FilterValue(object value)
|
|
{
|
|
var range = m_Provider.attributes.FindRange();
|
|
|
|
if (range != Vector2.zero)
|
|
{
|
|
value = FilterValue(range, (T)value);
|
|
}
|
|
return value;
|
|
}
|
|
}
|
|
|
|
class UintPropertyRM : NumericPropertyRM<uint, long>
|
|
{
|
|
private VFXEnumValuePopup m_EnumPopup;
|
|
private VFX32BitField m_BitField;
|
|
|
|
public UintPropertyRM(IPropertyRMProvider controller, float labelWidth) : base(controller, labelWidth)
|
|
{
|
|
}
|
|
|
|
public override float GetPreferredControlWidth()
|
|
{
|
|
return m_Provider.attributes.Is(VFXPropertyAttributes.Type.Enum) ? 120 : base.GetPreferredControlWidth();
|
|
}
|
|
|
|
protected override uint FilterValue(Vector2 range, uint value) => (uint)Math.Clamp(value, range.x, (double)range.y);
|
|
|
|
public override INotifyValueChanged<long> CreateField()
|
|
{
|
|
INotifyValueChanged<long> result;
|
|
if (m_Provider.attributes.Is(VFXPropertyAttributes.Type.Enum))
|
|
{
|
|
result = m_EnumPopup = new VFXEnumValuePopup("Value", m_Provider.attributes.FindEnum().ToList());
|
|
}
|
|
else
|
|
result = base.CreateField();
|
|
return result;
|
|
}
|
|
|
|
public override bool IsCompatible(IPropertyRMProvider provider)
|
|
{
|
|
if (!base.IsCompatible(provider)) return false;
|
|
|
|
|
|
if (m_Provider.attributes.Is(VFXPropertyAttributes.Type.Enum) == (m_EnumPopup == null))
|
|
return false;
|
|
|
|
if (m_Provider.attributes.Is(VFXPropertyAttributes.Type.Enum))
|
|
{
|
|
string[] enumValues = m_Provider.attributes.FindEnum();
|
|
|
|
return enumValues.SequenceEqual(m_EnumPopup.choices);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
protected override VisualElement CreateSimpleField(string label)
|
|
{
|
|
if (m_Provider.attributes.Is(VFXPropertyAttributes.Type.BitField))
|
|
{
|
|
var nameLabel = new Label(label);
|
|
nameLabel.AddToClassList("label");
|
|
Insert(0, nameLabel);
|
|
return new VFX32BitField();
|
|
}
|
|
|
|
return new LongField(label);
|
|
}
|
|
|
|
protected override VFXBaseSliderField<long> CreateSliderField(string label) => new VFXLongSliderField(label);
|
|
|
|
public override uint Convert(object value)
|
|
{
|
|
long longValue = (long)value;
|
|
|
|
if (longValue < 0)
|
|
{
|
|
longValue = 0;
|
|
}
|
|
|
|
return (uint)longValue;
|
|
}
|
|
}
|
|
|
|
class IntPropertyRM : NumericPropertyRM<int, int>
|
|
{
|
|
public IntPropertyRM(IPropertyRMProvider controller, float labelWidth) : base(controller, labelWidth)
|
|
{
|
|
}
|
|
|
|
protected override VisualElement CreateSimpleField(string label)
|
|
{
|
|
return new IntegerField(label);
|
|
}
|
|
|
|
protected override VFXBaseSliderField<int> CreateSliderField(string label) => new VFXIntSliderField(label);
|
|
|
|
protected override int FilterValue(Vector2 range, int value) => (int)Math.Clamp(value, range.x, (double)range.y);
|
|
}
|
|
|
|
class FloatPropertyRM : NumericPropertyRM<float, float>
|
|
{
|
|
public FloatPropertyRM(IPropertyRMProvider controller, float labelWidth) : base(controller, labelWidth)
|
|
{
|
|
}
|
|
|
|
protected override VisualElement CreateSimpleField(string label)
|
|
{
|
|
return new FloatField(label);
|
|
}
|
|
|
|
protected override VFXBaseSliderField<float> CreateSliderField(string label) => new VFXFloatSliderField(label);
|
|
|
|
protected override float FilterValue(Vector2 range, float value) => Math.Max(Math.Min(range.y, value), range.x);
|
|
}
|
|
}
|