using UnityEngine; using UnityEngine.UIElements; using UnityEditor.UIElements; using System.Collections.Generic; using System.Linq; using Action = System.Action; namespace UnityEditor.VFX.UI { abstract class VFXBaseSliderField : VisualElement, INotifyValueChanged { protected Slider m_Slider; protected INotifyValueChanged m_Field; class StartFinishSliderManipulator : Manipulator { VFXBaseSliderField m_Slider; bool m_InDrag; protected override void RegisterCallbacksOnTarget() { m_Slider = target.GetFirstOfType>(); target.RegisterCallback(OnMouseDown, TrickleDown.TrickleDown); target.RegisterCallback(OnMouseUp, TrickleDown.TrickleDown); } protected override void UnregisterCallbacksFromTarget() { target.UnregisterCallback(OnMouseDown, TrickleDown.TrickleDown); target.UnregisterCallback(OnMouseUp, TrickleDown.TrickleDown); } void OnMouseDown(MouseDownEvent e) { target.RegisterCallback(OnMouseMove, TrickleDown.TrickleDown); } void OnMouseMove(MouseMoveEvent e) { if (!m_InDrag) { m_InDrag = true; m_Slider.ValueDragStarted(); target.UnregisterCallback(OnMouseMove, TrickleDown.TrickleDown); //we care only about the first drag event } } void OnMouseUp(MouseUpEvent e) { if (m_InDrag) m_Slider.ValueDragFinished(); else target.UnregisterCallback(OnMouseMove, TrickleDown.TrickleDown); m_InDrag = false; } } protected void ValueDragFinished() { if (onValueDragFinished != null) onValueDragFinished(); } protected void ValueDragStarted() { if (onValueDragStarted != null) onValueDragStarted(); } public Action onValueDragFinished; public Action onValueDragStarted; public VFXBaseSliderField() { AddToClassList("sliderField"); } protected void RegisterCallBack() { (m_Field as VisualElement).RegisterCallback(OnFocusLost); m_Slider.Children().First().AddManipulator(new StartFinishSliderManipulator()); } void OnFocusLost(BlurEvent e) { //forward the focus lost event using (BlurEvent newE = BlurEvent.GetPooled(this, e.relatedTarget, e.direction, panel.focusController)) { SendEvent(newE); } e.StopPropagation(); } public T m_Value; public T value { get { return m_Value; } set { SetValueAndNotify(value); } } protected abstract float ValueToFloat(T value); private Vector2 m_Range; public Vector2 range { get { return m_Range; } set { m_Range = value; m_IgnoreNotification = true; if (m_Slider.lowValue != m_Range.x || m_Slider.highValue != m_Range.y) { m_Slider.lowValue = m_Range.x; m_Slider.highValue = m_Range.y; m_Slider.value = m_Range.x; m_Slider.value = m_Range.y; m_Slider.value = ValueToFloat(this.value); } m_IgnoreNotification = false; } } protected bool m_IgnoreNotification; public abstract bool hasFocus { get; } public void OnValueChanged(EventCallback> callback) { RegisterCallback(callback); } public void RemoveOnValueChanged(EventCallback> callback) { UnregisterCallback(callback); } public void SetValueAndNotify(T newValue) { if (!EqualityComparer.Default.Equals(value, newValue)) { using (ChangeEvent evt = ChangeEvent.GetPooled(value, newValue)) { evt.target = this; SetValueWithoutNotify(newValue); SendEvent(evt); } } } public void SetValueWithoutNotify(T newValue) { m_IgnoreNotification = true; m_Value = newValue; tooltip = newValue.ToString(); if (!hasFocus) m_Field.value = newValue; m_Slider.value = ValueToFloat(value); m_IgnoreNotification = false; } protected void ValueChanged(ChangeEvent e) { e.StopPropagation(); if (!m_IgnoreNotification) SetValueAndNotify(e.newValue); } } class VFXFloatSliderField : VFXBaseSliderField { public VFXFloatSliderField() { m_Slider = new Slider(0, 1, SliderDirection.Horizontal); m_Slider.AddToClassList("textfield"); m_Slider.RegisterValueChangedCallback(evt => ValueChanged(evt.newValue)); m_FloatField = new FloatField(); m_FloatField.RegisterValueChangedCallback(ValueChanged); m_FloatField.name = "Field"; m_Field = m_FloatField; m_IndeterminateLabel = new Label() { name = "indeterminate", text = VFXControlConstants.indeterminateText }; m_IndeterminateLabel.SetEnabled(false); Add(m_Slider); Add(m_FloatField); RegisterCallBack(); } VisualElement m_IndeterminateLabel; FloatField m_FloatField; public override bool hasFocus { get { return ((FloatField)m_Field).HasFocus() || (panel != null && panel.focusController.focusedElement == m_Field as VisualElement); } } protected override float ValueToFloat(float value) { return value; } void ValueChanged(float newValue) { if (!m_IgnoreNotification) SetValueAndNotify(newValue); } public bool indeterminate { get { return m_FloatField.parent == null; } set { if (indeterminate != value) { if (value) { m_FloatField.RemoveFromHierarchy(); Add(m_IndeterminateLabel); } else { m_IndeterminateLabel.RemoveFromHierarchy(); Add(m_FloatField); } m_Slider.SetEnabled(!value); } } } } class VFXIntSliderField : VFXBaseSliderField { public VFXIntSliderField() { m_Slider = new Slider(0, 1, SliderDirection.Horizontal); m_Slider.AddToClassList("textfield"); m_Slider.RegisterValueChangedCallback(evt => ValueChanged(evt.newValue)); var integerField = new IntegerField(); integerField.RegisterValueChangedCallback(ValueChanged); integerField.name = "Field"; m_Field = integerField; Add(m_Slider); Add(integerField); RegisterCallBack(); } public override bool hasFocus { get { return ((IntegerField)m_Field).HasFocus() || (panel != null && panel.focusController.focusedElement == m_Field as VisualElement); } } protected override float ValueToFloat(int value) { return (float)value; } void ValueChanged(float newValue) { SetValueAndNotify((int)newValue); } } class VFXLongSliderField : VFXBaseSliderField { public VFXLongSliderField() { m_Slider = new Slider(0, 1, SliderDirection.Horizontal); m_Slider.AddToClassList("textfield"); m_Slider.RegisterValueChangedCallback(evt => ValueChanged(evt.newValue)); var integerField = new LongField(); integerField.RegisterValueChangedCallback(ValueChanged); integerField.name = "Field"; m_Field = integerField; Add(m_Slider); Add(integerField); RegisterCallBack(); } public override bool hasFocus { get { return ((LongField)m_Field).HasFocus() || (panel != null && panel.focusController.focusedElement == m_Field as VisualElement); } } protected override float ValueToFloat(long value) { return (float)value; } void ValueChanged(float newValue) { SetValueAndNotify((long)newValue); } } }