Add Array constant node to Visual Script and Anim Graph

This commit is contained in:
Wojciech Figat
2021-11-18 16:35:07 +01:00
parent cdcb2f8f7a
commit 502a67a75a
11 changed files with 408 additions and 134 deletions

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using System; using System;
using FlaxEditor.CustomEditors.Editors;
using FlaxEditor.GUI; using FlaxEditor.GUI;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Surface.Elements; using FlaxEditor.Surface.Elements;
@@ -71,6 +72,134 @@ namespace FlaxEditor.Surface.Archetypes
} }
} }
private class ArrayNode : SurfaceNode
{
private OutputBox _output;
private TypePickerControl _typePicker;
private Button _addButton;
private Button _removeButton;
public ArrayNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
: base(id, context, nodeArch, groupArch)
{
}
public override void OnValuesChanged()
{
base.OnValuesChanged();
UpdateUI();
}
public override void OnLoaded()
{
base.OnLoaded();
_output = (OutputBox)Elements[0];
_typePicker = new TypePickerControl
{
Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderSize, 160, 16),
Parent = this,
};
_typePicker.ValueChanged += () => Set(3);
_removeButton = new Button(0, _typePicker.Y + FlaxEditor.Surface.Constants.LayoutOffsetY, 20, 20)
{
Text = "-",
TooltipText = "Remove the last item (smaller array)",
Parent = this
};
_removeButton.Clicked += () => Set(((Array)Values[0]).Length - 1);
_addButton = new Button(_removeButton.Location, _removeButton.Size)
{
Text = "+",
TooltipText = "Add new item to array (bigger array)",
Parent = this
};
_addButton.Clicked += () => Set(((Array)Values[0]).Length + 1);
UpdateUI();
}
private void Set(int length)
{
SetValue(0, Array.CreateInstance(TypeUtils.GetType(_typePicker.Value), length));
}
public override void OnSurfaceCanEditChanged(bool canEdit)
{
base.OnSurfaceCanEditChanged(canEdit);
_typePicker.Enabled = canEdit;
_addButton.Enabled = canEdit;
_removeButton.Enabled = canEdit;
}
public override void OnDestroy()
{
_output = null;
_typePicker = null;
_addButton = null;
_removeButton = null;
base.OnDestroy();
}
private void UpdateUI()
{
var array = (Array)Values[0];
var arrayType = array.GetType();
var elementType = new ScriptType(arrayType.GetElementType());
_typePicker.Value = elementType;
_output.CurrentType = new ScriptType(arrayType);
var count = array.Length;
var countMin = 0;
var countMax = 32;
for (int i = 0; i < array.Length; i++)
{
var box = (InputBox)AddBox(false, i + 1, i + 1, $"[{i}]", elementType, true);
box.UseCustomValueAccess(GetBoxValue, SetBoxValue);
}
for (int i = count; i <= countMax; i++)
{
var box = GetBox(i + 1);
if (box == null)
break;
RemoveElement(box);
}
var canEdit = Surface.CanEdit;
_typePicker.Enabled = canEdit;
_addButton.Enabled = count < countMax && canEdit;
_removeButton.Enabled = count > countMin && canEdit;
Title = string.Format("{0} Array", Surface.GetTypeName(elementType));
_typePicker.Width = 160.0f;
_addButton.X = 0;
_removeButton.X = 0;
ResizeAuto();
_addButton.X = Width - _addButton.Width - FlaxEditor.Surface.Constants.NodeMarginX;
_removeButton.X = _addButton.X - _removeButton.Width - 4;
_typePicker.Width = Width - 30;
}
private object GetBoxValue(InputBox box)
{
var array = (Array)Values[0];
return array.GetValue(box.ID - 1);
}
private void SetBoxValue(InputBox box, object value)
{
if (_isDuringValuesEditing || !Surface.CanEdit)
return;
var array = (Array)Values[0];
array = (Array)array.Clone();
array.SetValue(value, box.ID - 1);
SetValue(0, array);
}
}
/// <summary> /// <summary>
/// The nodes for that group. /// The nodes for that group.
/// </summary> /// </summary>
@@ -382,6 +511,17 @@ namespace FlaxEditor.Surface.Archetypes
NodeElementArchetype.Factory.UnsignedInteger(0, 0, 0, -1, 0, int.MaxValue) NodeElementArchetype.Factory.UnsignedInteger(0, 0, 0, -1, 0, int.MaxValue)
} }
}, },
new NodeArchetype
{
TypeID = 13,
Title = "Array",
Create = (id, context, arch, groupArch) => new ArrayNode(id, context, arch, groupArch),
Description = "Constant array value.",
Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph,
Size = new Vector2(150, 20),
DefaultValues = new object[] { new int[] { 0, 1, 2 } },
Elements = new[] { NodeElementArchetype.Factory.Output(0, string.Empty, null, 0) }
},
}; };
/// <summary> /// <summary>

View File

@@ -323,7 +323,7 @@ namespace FlaxEditor.Surface.Archetypes
Elements = new[] Elements = new[]
{ {
NodeElementArchetype.Factory.Input(0, string.Empty, false, typeof(void), 0), NodeElementArchetype.Factory.Input(0, string.Empty, false, typeof(void), 0),
NodeElementArchetype.Factory.Input(1, "Array", false, null, 1), NodeElementArchetype.Factory.Input(1, "Array", true, null, 1),
NodeElementArchetype.Factory.Input(2, "Break", false, typeof(void), 2), NodeElementArchetype.Factory.Input(2, "Break", false, typeof(void), 2),
NodeElementArchetype.Factory.Output(0, "Loop", typeof(void), 3, true), NodeElementArchetype.Factory.Output(0, "Loop", typeof(void), 3, true),
NodeElementArchetype.Factory.Output(1, "Item", typeof(object), 4), NodeElementArchetype.Factory.Output(1, "Item", typeof(object), 4),

View File

@@ -111,14 +111,15 @@ namespace FlaxEditor.Surface.Elements
/// </summary> /// </summary>
/// <param name="parentNode">The parent node.</param> /// <param name="parentNode">The parent node.</param>
/// <param name="arch">The node element archetype.</param> /// <param name="arch">The node element archetype.</param>
/// <param name="customValue">The custom value override (optional).</param>
/// <returns>The result value.</returns> /// <returns>The result value.</returns>
public static bool Get(SurfaceNode parentNode, NodeElementArchetype arch) public static bool Get(SurfaceNode parentNode, NodeElementArchetype arch, object customValue = null)
{ {
if (arch.ValueIndex < 0) if (arch.ValueIndex < 0 && customValue == null)
return false; return false;
bool result; bool result;
var value = parentNode.Values[arch.ValueIndex]; var value = customValue ?? parentNode.Values[arch.ValueIndex];
// Note: this value box may edit on component of the vector like Vector3.Y, BoxID from Archetype tells which component pick // Note: this value box may edit on component of the vector like Vector3.Y, BoxID from Archetype tells which component pick

View File

@@ -62,14 +62,15 @@ namespace FlaxEditor.Surface.Elements
/// </summary> /// </summary>
/// <param name="parentNode">The parent node.</param> /// <param name="parentNode">The parent node.</param>
/// <param name="arch">The node element archetype.</param> /// <param name="arch">The node element archetype.</param>
/// <param name="customValue">The custom value override (optional).</param>
/// <returns>The result value.</returns> /// <returns>The result value.</returns>
public static float Get(SurfaceNode parentNode, NodeElementArchetype arch) public static float Get(SurfaceNode parentNode, NodeElementArchetype arch, object customValue = null)
{ {
if (arch.ValueIndex < 0) if (arch.ValueIndex < 0 && customValue == null)
return 0; return 0;
float result; float result;
var value = parentNode.Values[arch.ValueIndex]; var value = customValue ?? parentNode.Values[arch.ValueIndex];
// Note: this value box may edit on component of the vector like Vector3.Y, BoxID from Archetype tells which component pick // Note: this value box may edit on component of the vector like Vector3.Y, BoxID from Archetype tells which component pick

View File

@@ -69,7 +69,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = BoolValue.Get(box.ParentNode, box.Archetype); var value = BoolValue.Get(box.ParentNode, box.Archetype, box.Value);
var control = new CheckBox(bounds.X, bounds.Y, value, bounds.Height) var control = new CheckBox(bounds.X, bounds.Y, value, bounds.Height)
{ {
Parent = box.Parent, Parent = box.Parent,
@@ -87,9 +87,7 @@ namespace FlaxEditor.Surface.Elements
public void UpdateDefaultValue(InputBox box, Control control) public void UpdateDefaultValue(InputBox box, Control control)
{ {
if (control is CheckBox checkBox) if (control is CheckBox checkBox)
{ checkBox.Checked = BoolValue.Get(box.ParentNode, box.Archetype, box.Value);
checkBox.Checked = BoolValue.Get(box.ParentNode, box.Archetype);
}
} }
public void UpdateAttributes(InputBox box, object[] attributes, Control control) public void UpdateAttributes(InputBox box, object[] attributes, Control control)
@@ -99,7 +97,7 @@ namespace FlaxEditor.Surface.Elements
private void OnCheckboxStateChanged(CheckBox control) private void OnCheckboxStateChanged(CheckBox control)
{ {
var box = (InputBox)control.Tag; var box = (InputBox)control.Tag;
box.ParentNode.SetValue(box.Archetype.ValueIndex, control.Checked); box.Value = control.Checked;
} }
} }
@@ -112,7 +110,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = IntegerValue.Get(box.ParentNode, box.Archetype); var value = IntegerValue.Get(box.ParentNode, box.Archetype, box.Value);
var control = new IntValueBox(value, bounds.X, bounds.Y, 40, int.MinValue, int.MaxValue, 0.01f) var control = new IntValueBox(value, bounds.X, bounds.Y, 40, int.MinValue, int.MaxValue, 0.01f)
{ {
Height = bounds.Height, Height = bounds.Height,
@@ -131,9 +129,7 @@ namespace FlaxEditor.Surface.Elements
public void UpdateDefaultValue(InputBox box, Control control) public void UpdateDefaultValue(InputBox box, Control control)
{ {
if (control is IntValueBox intValue) if (control is IntValueBox intValue)
{ intValue.Value = IntegerValue.Get(box.ParentNode, box.Archetype, box.Value);
intValue.Value = IntegerValue.Get(box.ParentNode, box.Archetype);
}
} }
public void UpdateAttributes(InputBox box, object[] attributes, Control control) public void UpdateAttributes(InputBox box, object[] attributes, Control control)
@@ -143,7 +139,10 @@ namespace FlaxEditor.Surface.Elements
private void OnIntValueBoxChanged(ValueBox<int> control) private void OnIntValueBoxChanged(ValueBox<int> control)
{ {
var box = (InputBox)control.Tag; var box = (InputBox)control.Tag;
IntegerValue.Set(box.ParentNode, box.Archetype, control.Value); if (box.HasCustomValueAccess)
box.Value = control.Value;
else
IntegerValue.Set(box.ParentNode, box.Archetype, control.Value);
} }
} }
@@ -156,7 +155,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = UnsignedIntegerValue.Get(box.ParentNode, box.Archetype); var value = UnsignedIntegerValue.Get(box.ParentNode, box.Archetype, box.Value);
var control = new UIntValueBox(value, bounds.X, bounds.Y, 40, uint.MinValue, uint.MaxValue, 0.01f) var control = new UIntValueBox(value, bounds.X, bounds.Y, 40, uint.MinValue, uint.MaxValue, 0.01f)
{ {
Height = bounds.Height, Height = bounds.Height,
@@ -175,9 +174,7 @@ namespace FlaxEditor.Surface.Elements
public void UpdateDefaultValue(InputBox box, Control control) public void UpdateDefaultValue(InputBox box, Control control)
{ {
if (control is UIntValueBox intValue) if (control is UIntValueBox intValue)
{ intValue.Value = UnsignedIntegerValue.Get(box.ParentNode, box.Archetype, box.Value);
intValue.Value = UnsignedIntegerValue.Get(box.ParentNode, box.Archetype);
}
} }
public void UpdateAttributes(InputBox box, object[] attributes, Control control) public void UpdateAttributes(InputBox box, object[] attributes, Control control)
@@ -187,7 +184,10 @@ namespace FlaxEditor.Surface.Elements
private void OnValueBoxChanged(ValueBox<uint> control) private void OnValueBoxChanged(ValueBox<uint> control)
{ {
var box = (InputBox)control.Tag; var box = (InputBox)control.Tag;
UnsignedIntegerValue.Set(box.ParentNode, box.Archetype, control.Value); if (box.HasCustomValueAccess)
box.Value = control.Value;
else
UnsignedIntegerValue.Set(box.ParentNode, box.Archetype, control.Value);
} }
} }
@@ -200,7 +200,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = FloatValue.Get(box.ParentNode, box.Archetype); var value = FloatValue.Get(box.ParentNode, box.Archetype, box.Value);
var control = new FloatValueBox(value, bounds.X, bounds.Y, 40, float.MinValue, float.MaxValue, 0.01f) var control = new FloatValueBox(value, bounds.X, bounds.Y, 40, float.MinValue, float.MaxValue, 0.01f)
{ {
Height = bounds.Height, Height = bounds.Height,
@@ -219,9 +219,7 @@ namespace FlaxEditor.Surface.Elements
public void UpdateDefaultValue(InputBox box, Control control) public void UpdateDefaultValue(InputBox box, Control control)
{ {
if (control is FloatValueBox floatValue) if (control is FloatValueBox floatValue)
{ floatValue.Value = FloatValue.Get(box.ParentNode, box.Archetype, box.Value);
floatValue.Value = FloatValue.Get(box.ParentNode, box.Archetype);
}
} }
public void UpdateAttributes(InputBox box, object[] attributes, Control control) public void UpdateAttributes(InputBox box, object[] attributes, Control control)
@@ -231,7 +229,10 @@ namespace FlaxEditor.Surface.Elements
private void OnFloatValueBoxChanged(ValueBox<float> control) private void OnFloatValueBoxChanged(ValueBox<float> control)
{ {
var box = (InputBox)control.Tag; var box = (InputBox)control.Tag;
FloatValue.Set(box.ParentNode, box.Archetype, control.Value); if (box.HasCustomValueAccess)
box.Value = control.Value;
else
FloatValue.Set(box.ParentNode, box.Archetype, control.Value);
} }
} }
@@ -244,7 +245,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = box.ParentNode.Values[box.Archetype.ValueIndex] as string; var value = box.Value as string;
var control = new TextBox(false, bounds.X, bounds.Y, 40) var control = new TextBox(false, bounds.X, bounds.Y, 40)
{ {
Text = value, Text = value,
@@ -265,7 +266,7 @@ namespace FlaxEditor.Surface.Elements
{ {
if (control is TextBox textBox) if (control is TextBox textBox)
{ {
textBox.Text = box.ParentNode.Values[box.Archetype.ValueIndex] as string; textBox.Text = box.Value as string;
} }
} }
@@ -276,7 +277,7 @@ namespace FlaxEditor.Surface.Elements
private void OnTextBoxTextChanged(TextBoxBase control) private void OnTextBoxTextChanged(TextBoxBase control)
{ {
var box = (InputBox)control.Tag; var box = (InputBox)control.Tag;
box.ParentNode.SetValue(box.Archetype.ValueIndex, control.Text); box.Value = control.Text;
} }
} }
@@ -341,7 +342,7 @@ namespace FlaxEditor.Surface.Elements
private Vector2 GetValue(InputBox box) private Vector2 GetValue(InputBox box)
{ {
var value = Vector2.Zero; var value = Vector2.Zero;
var v = box.ParentNode.Values[box.Archetype.ValueIndex]; var v = box.Value;
if (v is Vector2 vec2) if (v is Vector2 vec2)
value = vec2; value = vec2;
else if (v is Vector3 vec3) else if (v is Vector3 vec3)
@@ -363,7 +364,7 @@ namespace FlaxEditor.Surface.Elements
var box = (InputBox)control.Tag; var box = (InputBox)control.Tag;
var x = ((FloatValueBox)control.Children[0]).Value; var x = ((FloatValueBox)control.Children[0]).Value;
var y = ((FloatValueBox)control.Children[1]).Value; var y = ((FloatValueBox)control.Children[1]).Value;
box.ParentNode.SetValue(box.Archetype.ValueIndex, new Vector2(x, y)); box.Value = new Vector2(x, y);
} }
} }
@@ -436,7 +437,7 @@ namespace FlaxEditor.Surface.Elements
private Vector3 GetValue(InputBox box) private Vector3 GetValue(InputBox box)
{ {
var value = Vector3.Zero; var value = Vector3.Zero;
var v = box.ParentNode.Values[box.Archetype.ValueIndex]; var v = box.Value;
if (v is Vector2 vec2) if (v is Vector2 vec2)
value = new Vector3(vec2, 0.0f); value = new Vector3(vec2, 0.0f);
else if (v is Vector3 vec3) else if (v is Vector3 vec3)
@@ -459,7 +460,7 @@ namespace FlaxEditor.Surface.Elements
var x = ((FloatValueBox)control.Children[0]).Value; var x = ((FloatValueBox)control.Children[0]).Value;
var y = ((FloatValueBox)control.Children[1]).Value; var y = ((FloatValueBox)control.Children[1]).Value;
var z = ((FloatValueBox)control.Children[2]).Value; var z = ((FloatValueBox)control.Children[2]).Value;
box.ParentNode.SetValue(box.Archetype.ValueIndex, new Vector3(x, y, z)); box.Value = new Vector3(x, y, z);
} }
} }
@@ -541,7 +542,7 @@ namespace FlaxEditor.Surface.Elements
private Vector4 GetValue(InputBox box) private Vector4 GetValue(InputBox box)
{ {
var value = Vector4.Zero; var value = Vector4.Zero;
var v = box.ParentNode.Values[box.Archetype.ValueIndex]; var v = box.Value;
if (v is Vector2 vec2) if (v is Vector2 vec2)
value = new Vector4(vec2, 0.0f, 0.0f); value = new Vector4(vec2, 0.0f, 0.0f);
else if (v is Vector3 vec3) else if (v is Vector3 vec3)
@@ -565,7 +566,7 @@ namespace FlaxEditor.Surface.Elements
var y = ((FloatValueBox)control.Children[1]).Value; var y = ((FloatValueBox)control.Children[1]).Value;
var z = ((FloatValueBox)control.Children[2]).Value; var z = ((FloatValueBox)control.Children[2]).Value;
var w = ((FloatValueBox)control.Children[3]).Value; var w = ((FloatValueBox)control.Children[3]).Value;
box.ParentNode.SetValue(box.Archetype.ValueIndex, new Vector4(x, y, z, w)); box.Value = new Vector4(x, y, z, w);
} }
} }
@@ -638,7 +639,7 @@ namespace FlaxEditor.Surface.Elements
private Quaternion GetValue(InputBox box) private Quaternion GetValue(InputBox box)
{ {
var value = Quaternion.Identity; var value = Quaternion.Identity;
var v = box.ParentNode.Values[box.Archetype.ValueIndex]; var v = box.Value;
if (v is Quaternion quat) if (v is Quaternion quat)
value = quat; value = quat;
else if (v is Transform transform) else if (v is Transform transform)
@@ -653,7 +654,7 @@ namespace FlaxEditor.Surface.Elements
var x = ((FloatValueBox)control.Children[0]).Value; var x = ((FloatValueBox)control.Children[0]).Value;
var y = ((FloatValueBox)control.Children[1]).Value; var y = ((FloatValueBox)control.Children[1]).Value;
var z = ((FloatValueBox)control.Children[2]).Value; var z = ((FloatValueBox)control.Children[2]).Value;
box.ParentNode.SetValue(box.Archetype.ValueIndex, Quaternion.Euler(x, y, z)); box.Value = Quaternion.Euler(x, y, z);
} }
} }
@@ -697,7 +698,7 @@ namespace FlaxEditor.Surface.Elements
private Vector4 GetValue(InputBox box) private Vector4 GetValue(InputBox box)
{ {
var value = Color.Black; var value = Color.Black;
var v = box.ParentNode.Values[box.Archetype.ValueIndex]; var v = box.Value;
if (v is Vector2 vec2) if (v is Vector2 vec2)
value = new Color(vec2.X, vec2.Y, 0.0f, 1.0f); value = new Color(vec2.X, vec2.Y, 0.0f, 1.0f);
else if (v is Vector3 vec3) else if (v is Vector3 vec3)
@@ -716,7 +717,7 @@ namespace FlaxEditor.Surface.Elements
private void OnColorValueChanged(ColorValueBox control) private void OnColorValueChanged(ColorValueBox control)
{ {
var box = (InputBox)control.Tag; var box = (InputBox)control.Tag;
box.ParentNode.SetValue(box.Archetype.ValueIndex, control.Value); box.Value = control.Value;
} }
} }
@@ -745,7 +746,7 @@ namespace FlaxEditor.Surface.Elements
private void OnEnumValueChanged(EnumComboBox control) private void OnEnumValueChanged(EnumComboBox control)
{ {
var box = (InputBox)control.Tag; var box = (InputBox)control.Tag;
box.ParentNode.SetValue(box.Archetype.ValueIndex, control.EnumTypeValue); box.Value = control.EnumTypeValue;
} }
public bool IsValid(InputBox box, Control control) public bool IsValid(InputBox box, Control control)
@@ -768,7 +769,7 @@ namespace FlaxEditor.Surface.Elements
private object GetValue(InputBox box) private object GetValue(InputBox box)
{ {
var value = box.CurrentType.CreateInstance(); var value = box.CurrentType.CreateInstance();
var v = box.ParentNode.Values[box.Archetype.ValueIndex]; var v = box.Value;
if (v != null && v.GetType().IsEnum) if (v != null && v.GetType().IsEnum)
value = v; value = v;
return value; return value;
@@ -804,13 +805,13 @@ namespace FlaxEditor.Surface.Elements
private void OnTypeValueChanged(TypePickerControl control) private void OnTypeValueChanged(TypePickerControl control)
{ {
var box = (InputBox)control.Tag; var box = (InputBox)control.Tag;
var v = box.ParentNode.Values[box.Archetype.ValueIndex]; var v = box.Value;
if (v is string) if (v is string)
box.ParentNode.SetValue(box.Archetype.ValueIndex, control.ValueTypeName); box.Value = control.ValueTypeName;
else if (v is Type) else if (v is Type)
box.ParentNode.SetValue(box.Archetype.ValueIndex, TypeUtils.GetType(control.Value)); box.Value = TypeUtils.GetType(control.Value);
else else
box.ParentNode.SetValue(box.Archetype.ValueIndex, control.Value); box.Value = control.Value;
} }
public bool IsValid(InputBox box, Control control) public bool IsValid(InputBox box, Control control)
@@ -830,12 +831,12 @@ namespace FlaxEditor.Surface.Elements
{ {
var typeReference = (TypeReferenceAttribute)attributes.FirstOrDefault(x => x.GetType() == typeof(TypeReferenceAttribute)); var typeReference = (TypeReferenceAttribute)attributes.FirstOrDefault(x => x.GetType() == typeof(TypeReferenceAttribute));
var type = typeReference != null ? TypeUtils.GetType(typeReference.TypeName) : ScriptType.Null; var type = typeReference != null ? TypeUtils.GetType(typeReference.TypeName) : ScriptType.Null;
((TypePickerControl)control).Type = type ? type : new ScriptType(typeof(object)); ((TypePickerControl)control).Type = type ? type : ScriptType.Object;
} }
private string GetValue(InputBox box) private string GetValue(InputBox box)
{ {
var v = box.ParentNode.Values[box.Archetype.ValueIndex]; var v = box.Value;
if (v is Type asType) if (v is Type asType)
return asType.FullName; return asType.FullName;
if (v is ScriptType asScriptType) if (v is ScriptType asScriptType)
@@ -855,6 +856,10 @@ namespace FlaxEditor.Surface.Elements
{ {
private Control _defaultValueEditor; private Control _defaultValueEditor;
private IDefaultValueEditor _editor; private IDefaultValueEditor _editor;
private int _valueIndex;
private Func<InputBox, object> _customValueGetter;
private Action<InputBox, object> _customValueSetter;
private bool _isWatchingForValueChange;
/// <summary> /// <summary>
/// The handlers for the input box default value editing. Used to display the default to the UI. /// The handlers for the input box default value editing. Used to display the default to the UI.
@@ -880,13 +885,40 @@ namespace FlaxEditor.Surface.Elements
/// </summary> /// </summary>
public Control DefaultValueEditor => _defaultValueEditor; public Control DefaultValueEditor => _defaultValueEditor;
/// <summary>
/// Gets or sets the value.
/// </summary>
public object Value
{
get => _customValueGetter != null ? _customValueGetter(this) : ParentNode.Values[_valueIndex];
set
{
if (_customValueSetter != null)
_customValueSetter(this, value);
else
ParentNode.SetValue(_valueIndex, value);
}
}
/// <summary>
/// Returns true if node has custom value access.
/// </summary>
public bool HasCustomValueAccess => _customValueGetter != null;
/// <summary>
/// Returns true if node has value.
/// </summary>
public bool HasValue => _valueIndex != -1 || _customValueGetter != null;
/// <inheritdoc /> /// <inheritdoc />
public InputBox(SurfaceNode parentNode, NodeElementArchetype archetype) public InputBox(SurfaceNode parentNode, NodeElementArchetype archetype)
: base(parentNode, archetype, archetype.Position) : base(parentNode, archetype, archetype.Position)
{ {
// Check if use inlined default value editor // Check if use inlined default value editor
if (Archetype.ValueIndex != -1) _valueIndex = Archetype.ValueIndex;
if (_valueIndex != -1)
{ {
_isWatchingForValueChange = true;
ParentNode.ValuesChanged += UpdateDefaultValue; ParentNode.ValuesChanged += UpdateDefaultValue;
} }
} }
@@ -903,6 +935,24 @@ namespace FlaxEditor.Surface.Elements
} }
} }
/// <summary>
/// Sets the custom accessor callbacks for the box value.
/// </summary>
/// <param name="getter">The function to call to get value for the box.</param>
/// <param name="setter">The function to call to set value for the box.</param>
public void UseCustomValueAccess(Func<InputBox, object> getter, Action<InputBox, object> setter)
{
_customValueGetter = getter;
_customValueSetter = setter;
if (Connections.Count == 0)
CreateDefaultEditor();
if (!_isWatchingForValueChange)
{
_isWatchingForValueChange = true;
ParentNode.ValuesChanged += UpdateDefaultValue;
}
}
/// <inheritdoc /> /// <inheritdoc />
public override bool IsOutput => false; public override bool IsOutput => false;
@@ -952,7 +1002,7 @@ namespace FlaxEditor.Surface.Elements
/// <inheritdoc /> /// <inheritdoc />
public override void OnConnectionsChanged() public override void OnConnectionsChanged()
{ {
bool showEditor = Connections.Count == 0 && Archetype.ValueIndex != -1; bool showEditor = Connections.Count == 0 && HasValue;
if (showEditor) if (showEditor)
{ {
CreateDefaultEditor(); CreateDefaultEditor();
@@ -986,7 +1036,7 @@ namespace FlaxEditor.Surface.Elements
/// <inheritdoc /> /// <inheritdoc />
public override bool OnMouseUp(Vector2 location, MouseButton button) public override bool OnMouseUp(Vector2 location, MouseButton button)
{ {
if (button == MouseButton.Right && Archetype.ValueIndex != -1) if (button == MouseButton.Right && HasValue)
{ {
var menu = new FlaxEditor.GUI.ContextMenu.ContextMenu(); var menu = new FlaxEditor.GUI.ContextMenu.ContextMenu();
menu.AddButton("Copy value", OnCopyValue); menu.AddButton("Copy value", OnCopyValue);
@@ -1041,8 +1091,7 @@ namespace FlaxEditor.Surface.Elements
private void OnCopyValue() private void OnCopyValue()
{ {
var value = ParentNode.Values[Archetype.ValueIndex]; var value = Value;
try try
{ {
string text; string text;
@@ -1087,9 +1136,7 @@ namespace FlaxEditor.Surface.Elements
try try
{ {
if (GetClipboardValue(out var value, true)) if (GetClipboardValue(out var value, true))
{ Value = value;
ParentNode.SetValue(Archetype.ValueIndex, value);
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -1103,7 +1150,7 @@ namespace FlaxEditor.Surface.Elements
/// </summary> /// </summary>
private void CreateDefaultEditor() private void CreateDefaultEditor()
{ {
if (_defaultValueEditor != null || Archetype.ValueIndex == -1) if (_defaultValueEditor != null || !HasValue)
return; return;
for (int i = 0; i < DefaultValueEditors.Count; i++) for (int i = 0; i < DefaultValueEditors.Count; i++)

View File

@@ -65,14 +65,15 @@ namespace FlaxEditor.Surface.Elements
/// </summary> /// </summary>
/// <param name="parentNode">The parent node.</param> /// <param name="parentNode">The parent node.</param>
/// <param name="arch">The node element archetype.</param> /// <param name="arch">The node element archetype.</param>
/// <param name="customValue">The custom value override (optional).</param>
/// <returns>The result value.</returns> /// <returns>The result value.</returns>
public static int Get(SurfaceNode parentNode, NodeElementArchetype arch) public static int Get(SurfaceNode parentNode, NodeElementArchetype arch, object customValue = null)
{ {
if (arch.ValueIndex < 0) if (arch.ValueIndex < 0 && customValue == null)
return 0; return 0;
int result; int result;
var value = parentNode.Values[arch.ValueIndex]; var value = customValue ?? parentNode.Values[arch.ValueIndex];
// Note: this value box may edit on component of the vector like Vector3.Y, BoxID from Archetype tells which component pick // Note: this value box may edit on component of the vector like Vector3.Y, BoxID from Archetype tells which component pick

View File

@@ -57,14 +57,15 @@ namespace FlaxEditor.Surface.Elements
/// </summary> /// </summary>
/// <param name="parentNode">The parent node.</param> /// <param name="parentNode">The parent node.</param>
/// <param name="arch">The node element archetype.</param> /// <param name="arch">The node element archetype.</param>
/// <param name="customValue">The custom value override (optional).</param>
/// <returns>The result value.</returns> /// <returns>The result value.</returns>
public static uint Get(SurfaceNode parentNode, NodeElementArchetype arch) public static uint Get(SurfaceNode parentNode, NodeElementArchetype arch, object customValue = null)
{ {
if (arch.ValueIndex < 0) if (arch.ValueIndex < 0 && customValue == null)
return 0; return 0;
uint result; uint result;
var value = parentNode.Values[arch.ValueIndex]; var value = customValue ?? parentNode.Values[arch.ValueIndex];
// Note: this value box may edit on component of the vector like Vector3.Y, BoxID from Archetype tells which component pick // Note: this value box may edit on component of the vector like Vector3.Y, BoxID from Archetype tells which component pick

View File

@@ -32,7 +32,54 @@
#include <ThirdParty/mono-2.0/mono/metadata/object.h> #include <ThirdParty/mono-2.0/mono/metadata/object.h>
#endif #endif
namespace
{
const char* InBuiltTypesTypeNames[37] =
{
// @formatter:off
"",// Null
"System.Void",// Void
"System.Boolean",// Bool
"System.Int32",// Int
"System.UInt32",// Uint
"System.Int64",// Int64
"System.UInt64",// Uint64
"System.Single",// Float
"System.Double",// Double
"System.IntPtr",// Pointer
"System.String",// String
"System.Object",// Object
"",// Structure
"FlaxEngine.Asset",// Asset
"System.Byte[]",// Blob
"",// Enum
"FlaxEngine.Vector2",// Vector2
"FlaxEngine.Vector3",// Vector3
"FlaxEngine.Vector4",// Vector4
"FlaxEngine.Color",// Color
"System.Guid",// Guid
"FlaxEngine.BoundingBox",// BoundingBox
"FlaxEngine.BoundingSphere",// BoundingSphere
"FlaxEngine.Quaternion",// Quaternion
"FlaxEngine.Transform",// Transform
"FlaxEngine.Rectangle",// Rectangle
"FlaxEngine.Ray",// Ray
"FlaxEngine.Matrix",// Matrix
"System.Object[]",// Array
"Dictionary<System.Object,System.Object>",// Dictionary
"System.Object",// ManagedObject
"System.Type",// Typename
"FlaxEngine.Int2"// Int2
"FlaxEngine.Int3"// Int3
"FlaxEngine.Int4"// Int4
"System.Int16",// Int16
"System.UInt16",// Uint16
// @formatter:on
};
}
static_assert(sizeof(VariantType) <= 16, "Invalid VariantType size!"); static_assert(sizeof(VariantType) <= 16, "Invalid VariantType size!");
static_assert((int32)VariantType::Types::MAX == ARRAY_COUNT(InBuiltTypesTypeNames), "Invalid amount of in-built types infos!");
VariantType::VariantType(Types type, const StringView& typeName) VariantType::VariantType(Types type, const StringView& typeName)
{ {
@@ -54,9 +101,9 @@ VariantType::VariantType(Types type, const StringAnsiView& typeName)
int32 length = typeName.Length(); int32 length = typeName.Length();
if (length) if (length)
{ {
length++; TypeName = static_cast<char*>(Allocator::Allocate(length + 1));
TypeName = static_cast<char*>(Allocator::Allocate(length));
Platform::MemoryCopy(TypeName, typeName.Get(), length); Platform::MemoryCopy(TypeName, typeName.Get(), length);
TypeName[length] = 0;
} }
} }
@@ -69,23 +116,77 @@ VariantType::VariantType(Types type, _MonoClass* klass)
{ {
MString typeName; MString typeName;
MUtils::GetClassFullname(klass, typeName); MUtils::GetClassFullname(klass, typeName);
int32 length = typeName.Length() + 1; const int32 length = typeName.Length();
TypeName = static_cast<char*>(Allocator::Allocate(length)); TypeName = static_cast<char*>(Allocator::Allocate(length + 1));
Platform::MemoryCopy(TypeName, typeName.Get(), length); Platform::MemoryCopy(TypeName, typeName.Get(), length);
TypeName[length] = 0;
} }
#endif #endif
} }
VariantType::VariantType(const StringAnsiView& typeName)
{
// Check case for array
if (typeName.EndsWith(StringAnsiView("[]"), StringSearchCase::CaseSensitive))
{
new(this) VariantType(Array, StringAnsiView(typeName.Get(), typeName.Length() - 2));
return;
}
// Try using in-built type
for (uint32 i = 0; i < ARRAY_COUNT(InBuiltTypesTypeNames); i++)
{
if (typeName == InBuiltTypesTypeNames[i])
{
new(this) VariantType((Types)i);
return;
}
}
// Try using scripting type
const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(typeName);
if (typeHandle)
{
const ScriptingType& type = typeHandle.GetType();
switch (type.Type)
{
case ScriptingTypes::Script:
case ScriptingTypes::Class:
case ScriptingTypes::Interface:
new(this) VariantType(Object, typeName);
return;
case ScriptingTypes::Structure:
new(this) VariantType(Structure, typeName);
return;
case ScriptingTypes::Enum:
new(this) VariantType(Enum, typeName);
return;
}
}
// Try using managed class
#if USE_MONO
if (const auto mclass = Scripting::FindClass(typeName))
{
new(this) VariantType(ManagedObject, typeName);
return;
}
#endif
new(this) VariantType();
LOG(Warning, "Missing scripting type \'{0}\'", ::String(typeName));
}
VariantType::VariantType(const VariantType& other) VariantType::VariantType(const VariantType& other)
{ {
Type = other.Type; Type = other.Type;
TypeName = nullptr; TypeName = nullptr;
int32 length = StringUtils::Length(other.TypeName); const int32 length = StringUtils::Length(other.TypeName);
if (length) if (length)
{ {
length++; TypeName = static_cast<char*>(Allocator::Allocate(length + 1));
TypeName = static_cast<char*>(Allocator::Allocate(length));
Platform::MemoryCopy(TypeName, other.TypeName, length); Platform::MemoryCopy(TypeName, other.TypeName, length);
TypeName[length] = 0;
} }
} }
@@ -119,12 +220,12 @@ VariantType& VariantType::operator=(const VariantType& other)
Type = other.Type; Type = other.Type;
Allocator::Free(TypeName); Allocator::Free(TypeName);
TypeName = nullptr; TypeName = nullptr;
int32 length = StringUtils::Length(other.TypeName); const int32 length = StringUtils::Length(other.TypeName);
if (length) if (length)
{ {
length++; TypeName = static_cast<char*>(Allocator::Allocate(length + 1));
TypeName = static_cast<char*>(Allocator::Allocate(length));
Platform::MemoryCopy(TypeName, other.TypeName, length); Platform::MemoryCopy(TypeName, other.TypeName, length);
TypeName[length] = 0;
} }
return *this; return *this;
} }
@@ -173,67 +274,21 @@ const char* VariantType::GetTypeName() const
{ {
if (TypeName) if (TypeName)
return TypeName; return TypeName;
switch (Type) return InBuiltTypesTypeNames[Type];
}
VariantType VariantType::GetElementType() const
{
if (Type == Array)
{ {
case Void: if (TypeName)
return "System.Void"; {
case Bool: const StringAnsiView elementTypename(TypeName, StringUtils::Length(TypeName) - 2);
return "System.Boolean"; return VariantType(elementTypename);
case Int16: }
return "System.Int16"; return VariantType(Object);
case Uint16:
return "System.UInt16";
case Int:
return "System.Int32";
case Uint:
return "System.UInt32";
case Int64:
return "System.Int64";
case Uint64:
return "System.UInt64";
case Float:
return "System.Single";
case Double:
return "System.Double";
case Pointer:
return "System.IntPtr";
case String:
return "System.String";
case Object:
return "System.Object";
case Asset:
return "FlaxEngine.Asset";
case Vector2:
return "FlaxEngine.Vector2";
case Vector3:
return "FlaxEngine.Vector3";
case Vector4:
return "FlaxEngine.Vector4";
case Color:
return "FlaxEngine.Color";
case Guid:
return "System.Guid";
case BoundingBox:
return "FlaxEngine.BoundingBox";
case BoundingSphere:
return "FlaxEngine.BoundingSphere";
case Quaternion:
return "FlaxEngine.Quaternion";
case Transform:
return "FlaxEngine.Transform";
case Rectangle:
return "FlaxEngine.Rectangle";
case Ray:
return "FlaxEngine.Ray";
case Matrix:
return "FlaxEngine.Matrix";
case Typename:
return "System.Type";
case Array:
return "System.Object[]";
default:
return "";
} }
return VariantType();
} }
::String VariantType::ToString() const ::String VariantType::ToString() const
@@ -3219,7 +3274,7 @@ void Variant::AllocStructure()
{ {
if (typeName.Length() != 0) if (typeName.Length() != 0)
{ {
LOG(Warning, "Missing scripting type \'{0}\'", String(typeName.Get())); LOG(Warning, "Missing scripting type \'{0}\'", String(typeName));
} }
AsBlob.Data = nullptr; AsBlob.Data = nullptr;
AsBlob.Length = 0; AsBlob.Length = 0;

View File

@@ -93,6 +93,7 @@ public:
explicit VariantType(Types type, const StringView& typeName); explicit VariantType(Types type, const StringView& typeName);
explicit VariantType(Types type, const StringAnsiView& typeName); explicit VariantType(Types type, const StringAnsiView& typeName);
explicit VariantType(Types type, struct _MonoClass* klass); explicit VariantType(Types type, struct _MonoClass* klass);
explicit VariantType(const StringAnsiView& typeName);
VariantType(const VariantType& other); VariantType(const VariantType& other);
VariantType(VariantType&& other) noexcept; VariantType(VariantType&& other) noexcept;
@@ -119,6 +120,7 @@ public:
void SetTypeName(const StringView& typeName); void SetTypeName(const StringView& typeName);
void SetTypeName(const StringAnsiView& typeName); void SetTypeName(const StringAnsiView& typeName);
const char* GetTypeName() const; const char* GetTypeName() const;
VariantType GetElementType() const;
::String ToString() const; ::String ToString() const;
}; };

View File

@@ -144,6 +144,16 @@ namespace FlaxEngine.GUI
} }
} }
/// <summary>
/// Initializes a new instance of the <see cref="Button"/> class.
/// </summary>
/// <param name="location">Position</param>
/// <param name="size">Size</param>
public Button(Vector2 location, Vector2 size)
: this(location.X, location.Y, size.X, size.Y)
{
}
/// <summary> /// <summary>
/// Called when mouse clicks the button. /// Called when mouse clicks the button.
/// </summary> /// </summary>
@@ -219,7 +229,7 @@ namespace FlaxEngine.GUI
Render2D.DrawRectangle(clientRect, borderColor); Render2D.DrawRectangle(clientRect, borderColor);
// Draw text // Draw text
Render2D.DrawText(_font.GetFont(), TextMaterial, _text, clientRect, textColor, TextAlignment.Center, TextAlignment.Center); Render2D.DrawText(_font?.GetFont(), TextMaterial, _text, clientRect, textColor, TextAlignment.Center, TextAlignment.Center);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -117,6 +117,22 @@ void VisjectExecutor::ProcessGroupConstants(Box* box, Node* node, Value& value)
case 11: case 11:
value = node->Values[0]; value = node->Values[0];
break; break;
// Array
case 13:
value = node->Values[0];
if (value.Type.Type == VariantType::Array)
{
auto& array = value.AsArray();
const int32 count = Math::Min(array.Count(), node->Boxes.Count() - 1);
const VariantType elementType = value.Type.GetElementType();
for (int32 i = 0; i < count; i++)
{
auto b = &node->Boxes[i + 1];
if (b && b->HasConnection())
array[i] = eatBox(node, b->FirstConnection()).Cast(elementType);
}
}
break;
default: default:
break; break;
} }