313 lines
9.4 KiB
C#
313 lines
9.4 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
using UnityEditor.UIElements;
|
|
using System;
|
|
|
|
namespace UnityEditor.VFX.UI
|
|
{
|
|
//Copied from mousefield dragger but add notifications needed for delayed fields
|
|
class VFXFieldMouseDragger<T>
|
|
{
|
|
Action m_OnDragFinished;
|
|
Action m_OnDragStarted;
|
|
public VFXFieldMouseDragger(IValueField<T> drivenField, Action onDragFinished = null, Action onDragStarted = null)
|
|
{
|
|
m_DrivenField = drivenField;
|
|
m_DragElement = null;
|
|
m_DragHotZone = new Rect(0, 0, -1, -1);
|
|
m_OnDragFinished = onDragFinished;
|
|
m_OnDragStarted = onDragStarted;
|
|
dragging = false;
|
|
}
|
|
|
|
IValueField<T> m_DrivenField;
|
|
VisualElement m_DragElement;
|
|
Rect m_DragHotZone;
|
|
|
|
public bool dragging;
|
|
public T startValue;
|
|
|
|
public void SetDragZone(VisualElement dragElement)
|
|
{
|
|
SetDragZone(dragElement, new Rect(0, 0, -1, -1));
|
|
}
|
|
|
|
public void SetDragZone(VisualElement dragElement, Rect hotZone)
|
|
{
|
|
if (m_DragElement != null)
|
|
{
|
|
m_DragElement.UnregisterCallback<MouseDownEvent>(UpdateValueOnMouseDown);
|
|
m_DragElement.UnregisterCallback<MouseMoveEvent>(UpdateValueOnMouseMove);
|
|
m_DragElement.UnregisterCallback<MouseUpEvent>(UpdateValueOnMouseUp);
|
|
m_DragElement.UnregisterCallback<KeyDownEvent>(UpdateValueOnKeyDown);
|
|
}
|
|
|
|
m_DragElement = dragElement;
|
|
m_DragHotZone = hotZone;
|
|
|
|
if (m_DragElement != null)
|
|
{
|
|
dragging = false;
|
|
m_DragElement.RegisterCallback<MouseDownEvent>(UpdateValueOnMouseDown);
|
|
m_DragElement.RegisterCallback<MouseMoveEvent>(UpdateValueOnMouseMove);
|
|
m_DragElement.RegisterCallback<MouseUpEvent>(UpdateValueOnMouseUp);
|
|
m_DragElement.RegisterCallback<KeyDownEvent>(UpdateValueOnKeyDown);
|
|
}
|
|
}
|
|
|
|
void UpdateValueOnMouseDown(MouseDownEvent evt)
|
|
{
|
|
if (evt.button == 0 && (m_DragHotZone.width < 0 || m_DragHotZone.height < 0 || m_DragHotZone.Contains(m_DragElement.WorldToLocal(evt.mousePosition))))
|
|
{
|
|
m_DragElement.CaptureMouse();
|
|
|
|
// Make sure no other elements can capture the mouse!
|
|
evt.StopPropagation();
|
|
|
|
dragging = true;
|
|
startValue = m_DrivenField.value;
|
|
if (m_OnDragStarted != null)
|
|
m_OnDragStarted();
|
|
|
|
EditorGUIUtility.SetWantsMouseJumping(1);
|
|
}
|
|
}
|
|
|
|
void UpdateValueOnMouseMove(MouseMoveEvent evt)
|
|
{
|
|
if (dragging)
|
|
{
|
|
DeltaSpeed s = evt.shiftKey ? DeltaSpeed.Fast : (evt.altKey ? DeltaSpeed.Slow : DeltaSpeed.Normal);
|
|
m_DrivenField.ApplyInputDeviceDelta(evt.mouseDelta, s, startValue);
|
|
}
|
|
}
|
|
|
|
void UpdateValueOnMouseUp(MouseUpEvent evt)
|
|
{
|
|
if (dragging)
|
|
{
|
|
dragging = false;
|
|
MouseCaptureController.ReleaseMouse();
|
|
EditorGUIUtility.SetWantsMouseJumping(0);
|
|
if (m_OnDragFinished != null)
|
|
m_OnDragFinished();
|
|
}
|
|
}
|
|
|
|
void UpdateValueOnKeyDown(KeyDownEvent evt)
|
|
{
|
|
if (dragging && evt.keyCode == KeyCode.Escape)
|
|
{
|
|
dragging = false;
|
|
m_DrivenField.value = startValue;
|
|
MouseCaptureController.ReleaseMouse();
|
|
EditorGUIUtility.SetWantsMouseJumping(0);
|
|
}
|
|
}
|
|
}
|
|
class VFXLabeledField<T, U> : VisualElement, INotifyValueChanged<U> where T : VisualElement, INotifyValueChanged<U>, new()
|
|
{
|
|
protected Label m_Label;
|
|
protected T m_Control;
|
|
|
|
public VisualElement m_IndeterminateLabel;
|
|
|
|
public VFXLabeledField(Label existingLabel)
|
|
{
|
|
m_Label = existingLabel;
|
|
|
|
CreateControl();
|
|
SetupLabel();
|
|
}
|
|
|
|
bool m_Indeterminate;
|
|
|
|
public bool indeterminate
|
|
{
|
|
get { return m_Control.parent == null; }
|
|
|
|
set
|
|
{
|
|
if (m_Indeterminate != value)
|
|
{
|
|
m_Indeterminate = value;
|
|
if (value)
|
|
{
|
|
m_Control.RemoveFromHierarchy();
|
|
Add(m_IndeterminateLabel);
|
|
}
|
|
else
|
|
{
|
|
m_IndeterminateLabel.RemoveFromHierarchy();
|
|
Add(m_Control);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public VFXLabeledField(string label)
|
|
{
|
|
if (!string.IsNullOrEmpty(label))
|
|
{
|
|
m_Label = new Label() { text = label };
|
|
m_Label.AddToClassList("label");
|
|
|
|
Add(m_Label);
|
|
}
|
|
style.flexDirection = FlexDirection.Row;
|
|
|
|
CreateControl();
|
|
SetupLabel();
|
|
}
|
|
|
|
void SetupLabel()
|
|
{
|
|
if (typeof(IValueField<U>).IsAssignableFrom(typeof(T)))
|
|
{
|
|
m_Label.styleSheets.Add(VFXView.LoadStyleSheet("VFXLabeledField"));
|
|
if (typeof(U) == typeof(float))
|
|
{
|
|
var dragger = new VFXFieldMouseDragger<float>((IValueField<float>)m_Control, DragValueFinished, DragValueStarted);
|
|
dragger.SetDragZone(m_Label);
|
|
m_Label.AddToClassList("cursor-slide-arrow");
|
|
}
|
|
else if (typeof(U) == typeof(double))
|
|
{
|
|
var dragger = new VFXFieldMouseDragger<double>((IValueField<double>)m_Control, DragValueFinished, DragValueStarted);
|
|
dragger.SetDragZone(m_Label);
|
|
m_Label.AddToClassList("cursor-slide-arrow");
|
|
}
|
|
else if (typeof(U) == typeof(long))
|
|
{
|
|
var dragger = new VFXFieldMouseDragger<long>((IValueField<long>)m_Control, DragValueFinished, DragValueStarted);
|
|
dragger.SetDragZone(m_Label);
|
|
m_Label.AddToClassList("cursor-slide-arrow");
|
|
}
|
|
else if (typeof(U) == typeof(int))
|
|
{
|
|
var dragger = new VFXFieldMouseDragger<int>((IValueField<int>)m_Control, DragValueFinished, DragValueStarted);
|
|
dragger.SetDragZone(m_Label);
|
|
m_Label.AddToClassList("cursor-slide-arrow");
|
|
}
|
|
}
|
|
|
|
m_IndeterminateLabel = new Label()
|
|
{
|
|
name = "indeterminate",
|
|
text = VFXControlConstants.indeterminateText
|
|
};
|
|
m_IndeterminateLabel.SetEnabled(false);
|
|
}
|
|
|
|
void DragValueFinished()
|
|
{
|
|
if (onValueDragFinished != null)
|
|
onValueDragFinished(this);
|
|
}
|
|
|
|
void DragValueStarted()
|
|
{
|
|
if (onValueDragStarted != null)
|
|
onValueDragStarted(this);
|
|
}
|
|
|
|
public Action<VFXLabeledField<T, U>> onValueDragFinished;
|
|
public Action<VFXLabeledField<T, U>> onValueDragStarted;
|
|
|
|
void CreateControl()
|
|
{
|
|
m_Control = new T();
|
|
Add(m_Control);
|
|
|
|
m_Control.RegisterValueChangedCallback(OnControlChange);
|
|
}
|
|
|
|
void OnControlChange(ChangeEvent<U> e)
|
|
{
|
|
e.StopPropagation();
|
|
using (ChangeEvent<U> evt = ChangeEvent<U>.GetPooled(e.previousValue, e.newValue))
|
|
{
|
|
evt.target = this;
|
|
SendEvent(evt);
|
|
}
|
|
}
|
|
|
|
public T control
|
|
{
|
|
get { return m_Control; }
|
|
}
|
|
|
|
public Label label
|
|
{
|
|
get { return m_Label; }
|
|
}
|
|
|
|
public void SetValueAndNotify(U newValue)
|
|
{
|
|
(m_Control as INotifyValueChanged<U>).value = newValue;
|
|
}
|
|
|
|
public void SetValueWithoutNotify(U newValue)
|
|
{
|
|
(m_Control as INotifyValueChanged<U>).SetValueWithoutNotify(newValue);
|
|
}
|
|
|
|
public U value
|
|
{
|
|
get { return m_Control.value; }
|
|
set { m_Control.value = value; }
|
|
}
|
|
}
|
|
|
|
abstract class ValueControl<T> : VisualElement
|
|
{
|
|
protected Label m_Label;
|
|
|
|
protected ValueControl(Label existingLabel)
|
|
{
|
|
m_Label = existingLabel;
|
|
}
|
|
|
|
protected ValueControl(string label)
|
|
{
|
|
if (!string.IsNullOrEmpty(label))
|
|
{
|
|
m_Label = new Label() { text = label };
|
|
m_Label.AddToClassList("label");
|
|
|
|
Add(m_Label);
|
|
}
|
|
style.flexDirection = FlexDirection.Row;
|
|
}
|
|
|
|
public T GetValue()
|
|
{
|
|
return m_Value;
|
|
}
|
|
|
|
public void SetValue(T value)
|
|
{
|
|
m_Value = value;
|
|
ValueToGUI(false);
|
|
}
|
|
|
|
public T value
|
|
{
|
|
get { return GetValue(); }
|
|
set { SetValue(value); }
|
|
}
|
|
|
|
public void SetMultiplier(T multiplier)
|
|
{
|
|
m_Multiplier = multiplier;
|
|
}
|
|
|
|
protected T m_Value;
|
|
protected T m_Multiplier;
|
|
|
|
public System.Action OnValueChanged;
|
|
|
|
protected abstract void ValueToGUI(bool force);
|
|
}
|
|
}
|