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.
 
 
 
 

316 lines
10 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.VFX.UI
{
class VFXUniformOperatorEdit<T, U> : VisualElement, IControlledElement<T> where U : VFXOperatorDynamicOperand, IVFXOperatorUniform where T : VFXUniformOperatorController<U>
{
readonly PopupField<Type> m_PopupField;
public VFXUniformOperatorEdit()
{
this.AddStyleSheetPathWithSkinVariant("VFXControls");
AddToClassList("VFXUniformOperatorEdit");
m_PopupField = new PopupField<Type>();
m_PopupField.formatListItemCallback += x => x.UserFriendlyName();
m_PopupField.formatSelectedValueCallback += x => x.UserFriendlyName();
m_PopupField.RegisterValueChangedCallback(OnChangeType);
m_PopupField.RegisterCallback<MouseDownEvent>(e =>
{
if (e.button == 0)
OnUpdateChoices();
});
Add(m_PopupField);
}
void OnUpdateChoices()
{
m_PopupField.choices = controller.model.validTypes.ToList();
}
void OnChangeType(ChangeEvent<Type> evt)
{
controller.model.SetOperandType(evt.newValue);
}
T m_Controller;
Controller IControlledElement.controller => m_Controller;
public T controller
{
get => m_Controller;
set
{
if (m_Controller != value)
{
if (m_Controller != null)
{
m_Controller.UnregisterHandler(this);
}
m_Controller = value;
if (m_Controller != null)
{
m_Controller.RegisterHandler(this);
}
}
}
}
void IControlledElement.OnControllerChanged(ref ControllerChangedEvent e)
{
if (e.controller == controller)
{
m_PopupField.value = controller.model.GetOperandType();
}
}
}
class VFXMultiOperatorEdit<T, U> : VFXReorderableList, IControlledElement<T> where U : VFXOperatorNumeric, IVFXOperatorNumericUnified where T : VFXUnifiedOperatorControllerBase<U>
{
T m_Controller;
Controller IControlledElement.controller => m_Controller;
public T controller
{
get => m_Controller;
set
{
if (m_Controller != value)
{
if (m_Controller != null)
{
m_Controller.UnregisterHandler(this);
}
m_Controller = value;
if (m_Controller != null)
{
m_Controller.RegisterHandler(this);
}
}
}
}
void OnTypeMenu(PopupField<Type> dropdown, int index)
{
var op = controller.model;
var choices = new List<Type>();
if (op is IVFXOperatorNumericUnifiedConstrained constraintInterface && constraintInterface.slotIndicesThatCanBeScalar.Contains(index))
{
var otherSlotWithConstraint = op.inputSlots.Where((t, i) => constraintInterface.slotIndicesThatMustHaveSameType.Contains(i) && !constraintInterface.slotIndicesThatCanBeScalar.Contains(i)).FirstOrDefault();
foreach (var type in op.validTypes)
{
if (otherSlotWithConstraint == null || otherSlotWithConstraint.property.type == type || VFXUnifiedConstraintOperatorController.GetMatchingScalar(otherSlotWithConstraint.property.type) == type)
choices.Add(type);
}
}
else
{
foreach (var type in op.validTypes)
{
choices.Add(type);
}
}
dropdown.userData = index;
dropdown.choices = choices;
dropdown.value = op.GetOperandType(index);
dropdown.formatListItemCallback += x => x.UserFriendlyName();
dropdown.formatSelectedValueCallback += x => x.UserFriendlyName();
dropdown.RegisterValueChangedCallback(OnChangeType);
}
void OnChangeType(ChangeEvent<Type> evt)
{
var type = evt.newValue;
var currentIndex = (int)((VisualElement)evt.target).userData;
var op = controller.model;
op.SetOperandType(currentIndex, type);
if (op is IVFXOperatorNumericUnifiedConstrained constraintInterface)
{
if (!constraintInterface.slotIndicesThatCanBeScalar.Contains(currentIndex))
{
foreach (var index in constraintInterface.slotIndicesThatMustHaveSameType)
{
if (index != currentIndex && (!constraintInterface.slotIndicesThatCanBeScalar.Contains(index) || VFXUnifiedConstraintOperatorController.GetMatchingScalar(type) != op.GetOperandType(index)))
{
op.SetOperandType(index, type);
}
}
}
}
}
void IControlledElement.OnControllerChanged(ref ControllerChangedEvent e)
{
if (e.controller == controller)
{
SelfChange();
}
}
protected bool m_SelfChanging;
void SelfChange()
{
m_SelfChanging = true;
var op = controller.model;
int count = op.operandCount;
while (itemCount < count)
{
OperandInfoBase item = CreateOperandInfo(itemCount);
item.Set(op);
AddItem(item);
}
while (itemCount > count)
{
RemoveItemAt(itemCount - 1);
}
for (int i = 0; i < count; ++i)
{
OperandInfoBase operand = ItemAt(i) as OperandInfoBase;
operand.index = i; // The operand might have been changed by the drag
operand.Set(op);
}
m_SelfChanging = false;
}
protected virtual OperandInfoBase CreateOperandInfo(int index)
{
return new OperandInfoBase(this, controller.model, index);
}
protected class OperandInfoBase : VisualElement
{
PopupField<Type> type;
public VFXMultiOperatorEdit<T, U> m_Owner;
public int index;
public OperandInfoBase(VFXMultiOperatorEdit<T, U> owner, U op, int index)
{
this.AddStyleSheetPathWithSkinVariant("VFXControls");
m_Owner = owner;
type = new PopupField<Type>();
this.index = index;
m_Owner.OnTypeMenu(type, index);
Add(type);
}
public virtual void Set(U op)
{
}
}
}
class VFXUnifiedOperatorEdit : VFXMultiOperatorEdit<VFXUnifiedOperatorController, VFXOperatorNumericUnified>
{
public VFXUnifiedOperatorEdit()
{
toolbar = false;
reorderable = false;
}
protected override OperandInfoBase CreateOperandInfo(int index)
{
return new OperandInfo(this, controller.model, index);
}
class OperandInfo : OperandInfoBase
{
Label label;
public OperandInfo(VFXUnifiedOperatorEdit owner, VFXOperatorNumericUnified op, int index) : base(owner, op, index)
{
label = new Label();
Insert(0, label);
}
public override void Set(VFXOperatorNumericUnified op)
{
base.Set(op);
label.text = op.GetInputSlot(index).name;
}
}
}
class VFXCascadedOperatorEdit : VFXMultiOperatorEdit<VFXCascadedOperatorController, VFXOperatorNumericCascadedUnified>
{
protected override void ElementMoved(int movedIndex, int targetIndex)
{
base.ElementMoved(movedIndex, targetIndex);
controller.model.OperandMoved(movedIndex, targetIndex);
}
public override void OnAdd()
{
controller.model.AddOperand();
}
public override bool CanRemove()
{
return controller.CanRemove();
}
public override void OnRemove(int index)
{
controller.RemoveOperand(index);
}
void OnChangeLabel(string value, int index)
{
if (!m_SelfChanging)
{
var op = controller.model;
if (value != op.GetOperandName(index)) // test mandatory because TextField might send ChangeEvent anytime
op.SetOperandName(index, value);
}
}
protected override OperandInfoBase CreateOperandInfo(int index)
{
return new OperandInfo(this, controller.model, index);
}
class OperandInfo : OperandInfoBase
{
TextField field;
public OperandInfo(VFXCascadedOperatorEdit owner, VFXOperatorNumericCascadedUnified op, int index) : base(owner, op, index)
{
field = new TextField();
field.Q("unity-text-input").RegisterCallback<BlurEvent>(OnChangeValue, TrickleDown.TrickleDown);
field.Q("unity-text-input").RegisterCallback<KeyDownEvent>(OnKeyDown, TrickleDown.TrickleDown);
Insert(0, field);
}
void OnKeyDown(KeyDownEvent e)
{
if (e.keyCode == KeyCode.KeypadEnter || e.keyCode == KeyCode.Return)
{
OnChangeValue(e);
}
}
void OnChangeValue(EventBase evt)
{
(m_Owner as VFXCascadedOperatorEdit).OnChangeLabel(field.value, index);
}
public override void Set(VFXOperatorNumericCascadedUnified op)
{
base.Set(op);
field.value = op.GetOperandName(index);
}
}
}
}