diff --git a/Source/Editor/Surface/Archetypes/Constants.cs b/Source/Editor/Surface/Archetypes/Constants.cs
index 0a5083c89..e6a9849b3 100644
--- a/Source/Editor/Surface/Archetypes/Constants.cs
+++ b/Source/Editor/Surface/Archetypes/Constants.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using System;
+using FlaxEditor.CustomEditors.Editors;
using FlaxEditor.GUI;
using FlaxEditor.Scripting;
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);
+ }
+ }
+
///
/// The nodes for that group.
///
@@ -382,6 +511,17 @@ namespace FlaxEditor.Surface.Archetypes
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) }
+ },
};
///
diff --git a/Source/Editor/Surface/Archetypes/Flow.cs b/Source/Editor/Surface/Archetypes/Flow.cs
index 3e79bfe23..5de3d03b6 100644
--- a/Source/Editor/Surface/Archetypes/Flow.cs
+++ b/Source/Editor/Surface/Archetypes/Flow.cs
@@ -323,7 +323,7 @@ namespace FlaxEditor.Surface.Archetypes
Elements = new[]
{
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.Output(0, "Loop", typeof(void), 3, true),
NodeElementArchetype.Factory.Output(1, "Item", typeof(object), 4),
diff --git a/Source/Editor/Surface/Elements/BoolValue.cs b/Source/Editor/Surface/Elements/BoolValue.cs
index 8fa6dc7e0..badcb3474 100644
--- a/Source/Editor/Surface/Elements/BoolValue.cs
+++ b/Source/Editor/Surface/Elements/BoolValue.cs
@@ -111,14 +111,15 @@ namespace FlaxEditor.Surface.Elements
///
/// The parent node.
/// The node element archetype.
+ /// The custom value override (optional).
/// The result value.
- 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;
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
diff --git a/Source/Editor/Surface/Elements/FloatValue.cs b/Source/Editor/Surface/Elements/FloatValue.cs
index 54c5d7bf6..f51441142 100644
--- a/Source/Editor/Surface/Elements/FloatValue.cs
+++ b/Source/Editor/Surface/Elements/FloatValue.cs
@@ -62,14 +62,15 @@ namespace FlaxEditor.Surface.Elements
///
/// The parent node.
/// The node element archetype.
+ /// The custom value override (optional).
/// The result value.
- 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;
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
diff --git a/Source/Editor/Surface/Elements/InputBox.cs b/Source/Editor/Surface/Elements/InputBox.cs
index c830cf499..bbceee101 100644
--- a/Source/Editor/Surface/Elements/InputBox.cs
+++ b/Source/Editor/Surface/Elements/InputBox.cs
@@ -69,7 +69,7 @@ namespace FlaxEditor.Surface.Elements
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)
{
Parent = box.Parent,
@@ -87,9 +87,7 @@ namespace FlaxEditor.Surface.Elements
public void UpdateDefaultValue(InputBox box, Control control)
{
if (control is CheckBox checkBox)
- {
- checkBox.Checked = BoolValue.Get(box.ParentNode, box.Archetype);
- }
+ checkBox.Checked = BoolValue.Get(box.ParentNode, box.Archetype, box.Value);
}
public void UpdateAttributes(InputBox box, object[] attributes, Control control)
@@ -99,7 +97,7 @@ namespace FlaxEditor.Surface.Elements
private void OnCheckboxStateChanged(CheckBox control)
{
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)
{
- 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)
{
Height = bounds.Height,
@@ -131,9 +129,7 @@ namespace FlaxEditor.Surface.Elements
public void UpdateDefaultValue(InputBox box, Control control)
{
if (control is IntValueBox intValue)
- {
- intValue.Value = IntegerValue.Get(box.ParentNode, box.Archetype);
- }
+ intValue.Value = IntegerValue.Get(box.ParentNode, box.Archetype, box.Value);
}
public void UpdateAttributes(InputBox box, object[] attributes, Control control)
@@ -143,7 +139,10 @@ namespace FlaxEditor.Surface.Elements
private void OnIntValueBoxChanged(ValueBox control)
{
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)
{
- 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)
{
Height = bounds.Height,
@@ -175,9 +174,7 @@ namespace FlaxEditor.Surface.Elements
public void UpdateDefaultValue(InputBox box, Control control)
{
if (control is UIntValueBox intValue)
- {
- intValue.Value = UnsignedIntegerValue.Get(box.ParentNode, box.Archetype);
- }
+ intValue.Value = UnsignedIntegerValue.Get(box.ParentNode, box.Archetype, box.Value);
}
public void UpdateAttributes(InputBox box, object[] attributes, Control control)
@@ -187,7 +184,10 @@ namespace FlaxEditor.Surface.Elements
private void OnValueBoxChanged(ValueBox control)
{
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)
{
- 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)
{
Height = bounds.Height,
@@ -219,9 +219,7 @@ namespace FlaxEditor.Surface.Elements
public void UpdateDefaultValue(InputBox box, Control control)
{
if (control is FloatValueBox floatValue)
- {
- floatValue.Value = FloatValue.Get(box.ParentNode, box.Archetype);
- }
+ floatValue.Value = FloatValue.Get(box.ParentNode, box.Archetype, box.Value);
}
public void UpdateAttributes(InputBox box, object[] attributes, Control control)
@@ -231,7 +229,10 @@ namespace FlaxEditor.Surface.Elements
private void OnFloatValueBoxChanged(ValueBox control)
{
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)
{
- 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)
{
Text = value,
@@ -265,7 +266,7 @@ namespace FlaxEditor.Surface.Elements
{
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)
{
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)
{
var value = Vector2.Zero;
- var v = box.ParentNode.Values[box.Archetype.ValueIndex];
+ var v = box.Value;
if (v is Vector2 vec2)
value = vec2;
else if (v is Vector3 vec3)
@@ -363,7 +364,7 @@ namespace FlaxEditor.Surface.Elements
var box = (InputBox)control.Tag;
var x = ((FloatValueBox)control.Children[0]).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)
{
var value = Vector3.Zero;
- var v = box.ParentNode.Values[box.Archetype.ValueIndex];
+ var v = box.Value;
if (v is Vector2 vec2)
value = new Vector3(vec2, 0.0f);
else if (v is Vector3 vec3)
@@ -459,7 +460,7 @@ namespace FlaxEditor.Surface.Elements
var x = ((FloatValueBox)control.Children[0]).Value;
var y = ((FloatValueBox)control.Children[1]).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)
{
var value = Vector4.Zero;
- var v = box.ParentNode.Values[box.Archetype.ValueIndex];
+ var v = box.Value;
if (v is Vector2 vec2)
value = new Vector4(vec2, 0.0f, 0.0f);
else if (v is Vector3 vec3)
@@ -565,7 +566,7 @@ namespace FlaxEditor.Surface.Elements
var y = ((FloatValueBox)control.Children[1]).Value;
var z = ((FloatValueBox)control.Children[2]).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)
{
var value = Quaternion.Identity;
- var v = box.ParentNode.Values[box.Archetype.ValueIndex];
+ var v = box.Value;
if (v is Quaternion quat)
value = quat;
else if (v is Transform transform)
@@ -653,7 +654,7 @@ namespace FlaxEditor.Surface.Elements
var x = ((FloatValueBox)control.Children[0]).Value;
var y = ((FloatValueBox)control.Children[1]).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)
{
var value = Color.Black;
- var v = box.ParentNode.Values[box.Archetype.ValueIndex];
+ var v = box.Value;
if (v is Vector2 vec2)
value = new Color(vec2.X, vec2.Y, 0.0f, 1.0f);
else if (v is Vector3 vec3)
@@ -716,7 +717,7 @@ namespace FlaxEditor.Surface.Elements
private void OnColorValueChanged(ColorValueBox control)
{
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)
{
var box = (InputBox)control.Tag;
- box.ParentNode.SetValue(box.Archetype.ValueIndex, control.EnumTypeValue);
+ box.Value = control.EnumTypeValue;
}
public bool IsValid(InputBox box, Control control)
@@ -768,7 +769,7 @@ namespace FlaxEditor.Surface.Elements
private object GetValue(InputBox box)
{
var value = box.CurrentType.CreateInstance();
- var v = box.ParentNode.Values[box.Archetype.ValueIndex];
+ var v = box.Value;
if (v != null && v.GetType().IsEnum)
value = v;
return value;
@@ -804,13 +805,13 @@ namespace FlaxEditor.Surface.Elements
private void OnTypeValueChanged(TypePickerControl control)
{
var box = (InputBox)control.Tag;
- var v = box.ParentNode.Values[box.Archetype.ValueIndex];
+ var v = box.Value;
if (v is string)
- box.ParentNode.SetValue(box.Archetype.ValueIndex, control.ValueTypeName);
+ box.Value = control.ValueTypeName;
else if (v is Type)
- box.ParentNode.SetValue(box.Archetype.ValueIndex, TypeUtils.GetType(control.Value));
+ box.Value = TypeUtils.GetType(control.Value);
else
- box.ParentNode.SetValue(box.Archetype.ValueIndex, control.Value);
+ box.Value = control.Value;
}
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 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)
{
- var v = box.ParentNode.Values[box.Archetype.ValueIndex];
+ var v = box.Value;
if (v is Type asType)
return asType.FullName;
if (v is ScriptType asScriptType)
@@ -855,6 +856,10 @@ namespace FlaxEditor.Surface.Elements
{
private Control _defaultValueEditor;
private IDefaultValueEditor _editor;
+ private int _valueIndex;
+ private Func _customValueGetter;
+ private Action _customValueSetter;
+ private bool _isWatchingForValueChange;
///
/// 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
///
public Control DefaultValueEditor => _defaultValueEditor;
+ ///
+ /// Gets or sets the value.
+ ///
+ public object Value
+ {
+ get => _customValueGetter != null ? _customValueGetter(this) : ParentNode.Values[_valueIndex];
+ set
+ {
+ if (_customValueSetter != null)
+ _customValueSetter(this, value);
+ else
+ ParentNode.SetValue(_valueIndex, value);
+ }
+ }
+
+ ///
+ /// Returns true if node has custom value access.
+ ///
+ public bool HasCustomValueAccess => _customValueGetter != null;
+
+ ///
+ /// Returns true if node has value.
+ ///
+ public bool HasValue => _valueIndex != -1 || _customValueGetter != null;
+
///
public InputBox(SurfaceNode parentNode, NodeElementArchetype archetype)
: base(parentNode, archetype, archetype.Position)
{
// Check if use inlined default value editor
- if (Archetype.ValueIndex != -1)
+ _valueIndex = Archetype.ValueIndex;
+ if (_valueIndex != -1)
{
+ _isWatchingForValueChange = true;
ParentNode.ValuesChanged += UpdateDefaultValue;
}
}
@@ -903,6 +935,24 @@ namespace FlaxEditor.Surface.Elements
}
}
+ ///
+ /// Sets the custom accessor callbacks for the box value.
+ ///
+ /// The function to call to get value for the box.
+ /// The function to call to set value for the box.
+ public void UseCustomValueAccess(Func getter, Action setter)
+ {
+ _customValueGetter = getter;
+ _customValueSetter = setter;
+ if (Connections.Count == 0)
+ CreateDefaultEditor();
+ if (!_isWatchingForValueChange)
+ {
+ _isWatchingForValueChange = true;
+ ParentNode.ValuesChanged += UpdateDefaultValue;
+ }
+ }
+
///
public override bool IsOutput => false;
@@ -952,7 +1002,7 @@ namespace FlaxEditor.Surface.Elements
///
public override void OnConnectionsChanged()
{
- bool showEditor = Connections.Count == 0 && Archetype.ValueIndex != -1;
+ bool showEditor = Connections.Count == 0 && HasValue;
if (showEditor)
{
CreateDefaultEditor();
@@ -986,7 +1036,7 @@ namespace FlaxEditor.Surface.Elements
///
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();
menu.AddButton("Copy value", OnCopyValue);
@@ -1041,8 +1091,7 @@ namespace FlaxEditor.Surface.Elements
private void OnCopyValue()
{
- var value = ParentNode.Values[Archetype.ValueIndex];
-
+ var value = Value;
try
{
string text;
@@ -1087,9 +1136,7 @@ namespace FlaxEditor.Surface.Elements
try
{
if (GetClipboardValue(out var value, true))
- {
- ParentNode.SetValue(Archetype.ValueIndex, value);
- }
+ Value = value;
}
catch (Exception ex)
{
@@ -1103,7 +1150,7 @@ namespace FlaxEditor.Surface.Elements
///
private void CreateDefaultEditor()
{
- if (_defaultValueEditor != null || Archetype.ValueIndex == -1)
+ if (_defaultValueEditor != null || !HasValue)
return;
for (int i = 0; i < DefaultValueEditors.Count; i++)
diff --git a/Source/Editor/Surface/Elements/IntegerValue.cs b/Source/Editor/Surface/Elements/IntegerValue.cs
index f04578b75..4d31a9ed6 100644
--- a/Source/Editor/Surface/Elements/IntegerValue.cs
+++ b/Source/Editor/Surface/Elements/IntegerValue.cs
@@ -65,14 +65,15 @@ namespace FlaxEditor.Surface.Elements
///
/// The parent node.
/// The node element archetype.
+ /// The custom value override (optional).
/// The result value.
- 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;
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
diff --git a/Source/Editor/Surface/Elements/UnsignedIntegerValue.cs b/Source/Editor/Surface/Elements/UnsignedIntegerValue.cs
index a1822a268..fe0582669 100644
--- a/Source/Editor/Surface/Elements/UnsignedIntegerValue.cs
+++ b/Source/Editor/Surface/Elements/UnsignedIntegerValue.cs
@@ -57,14 +57,15 @@ namespace FlaxEditor.Surface.Elements
///
/// The parent node.
/// The node element archetype.
+ /// The custom value override (optional).
/// The result value.
- 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;
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
diff --git a/Source/Engine/Core/Types/Variant.cpp b/Source/Engine/Core/Types/Variant.cpp
index a2fee9f70..2246a7158 100644
--- a/Source/Engine/Core/Types/Variant.cpp
+++ b/Source/Engine/Core/Types/Variant.cpp
@@ -32,7 +32,54 @@
#include
#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",// 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((int32)VariantType::Types::MAX == ARRAY_COUNT(InBuiltTypesTypeNames), "Invalid amount of in-built types infos!");
VariantType::VariantType(Types type, const StringView& typeName)
{
@@ -54,9 +101,9 @@ VariantType::VariantType(Types type, const StringAnsiView& typeName)
int32 length = typeName.Length();
if (length)
{
- length++;
- TypeName = static_cast(Allocator::Allocate(length));
+ TypeName = static_cast(Allocator::Allocate(length + 1));
Platform::MemoryCopy(TypeName, typeName.Get(), length);
+ TypeName[length] = 0;
}
}
@@ -69,23 +116,77 @@ VariantType::VariantType(Types type, _MonoClass* klass)
{
MString typeName;
MUtils::GetClassFullname(klass, typeName);
- int32 length = typeName.Length() + 1;
- TypeName = static_cast(Allocator::Allocate(length));
+ const int32 length = typeName.Length();
+ TypeName = static_cast(Allocator::Allocate(length + 1));
Platform::MemoryCopy(TypeName, typeName.Get(), length);
+ TypeName[length] = 0;
}
#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)
{
Type = other.Type;
TypeName = nullptr;
- int32 length = StringUtils::Length(other.TypeName);
+ const int32 length = StringUtils::Length(other.TypeName);
if (length)
{
- length++;
- TypeName = static_cast(Allocator::Allocate(length));
+ TypeName = static_cast(Allocator::Allocate(length + 1));
Platform::MemoryCopy(TypeName, other.TypeName, length);
+ TypeName[length] = 0;
}
}
@@ -119,12 +220,12 @@ VariantType& VariantType::operator=(const VariantType& other)
Type = other.Type;
Allocator::Free(TypeName);
TypeName = nullptr;
- int32 length = StringUtils::Length(other.TypeName);
+ const int32 length = StringUtils::Length(other.TypeName);
if (length)
{
- length++;
- TypeName = static_cast(Allocator::Allocate(length));
+ TypeName = static_cast(Allocator::Allocate(length + 1));
Platform::MemoryCopy(TypeName, other.TypeName, length);
+ TypeName[length] = 0;
}
return *this;
}
@@ -173,67 +274,21 @@ const char* VariantType::GetTypeName() const
{
if (TypeName)
return TypeName;
- switch (Type)
+ return InBuiltTypesTypeNames[Type];
+}
+
+VariantType VariantType::GetElementType() const
+{
+ if (Type == Array)
{
- case Void:
- return "System.Void";
- case Bool:
- return "System.Boolean";
- case Int16:
- return "System.Int16";
- 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 "";
+ if (TypeName)
+ {
+ const StringAnsiView elementTypename(TypeName, StringUtils::Length(TypeName) - 2);
+ return VariantType(elementTypename);
+ }
+ return VariantType(Object);
}
+ return VariantType();
}
::String VariantType::ToString() const
@@ -3219,7 +3274,7 @@ void Variant::AllocStructure()
{
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.Length = 0;
diff --git a/Source/Engine/Core/Types/Variant.h b/Source/Engine/Core/Types/Variant.h
index a7700df9d..a9544899f 100644
--- a/Source/Engine/Core/Types/Variant.h
+++ b/Source/Engine/Core/Types/Variant.h
@@ -93,6 +93,7 @@ public:
explicit VariantType(Types type, const StringView& typeName);
explicit VariantType(Types type, const StringAnsiView& typeName);
explicit VariantType(Types type, struct _MonoClass* klass);
+ explicit VariantType(const StringAnsiView& typeName);
VariantType(const VariantType& other);
VariantType(VariantType&& other) noexcept;
@@ -119,6 +120,7 @@ public:
void SetTypeName(const StringView& typeName);
void SetTypeName(const StringAnsiView& typeName);
const char* GetTypeName() const;
+ VariantType GetElementType() const;
::String ToString() const;
};
diff --git a/Source/Engine/UI/GUI/Common/Button.cs b/Source/Engine/UI/GUI/Common/Button.cs
index fa2b89d7e..d08d03dec 100644
--- a/Source/Engine/UI/GUI/Common/Button.cs
+++ b/Source/Engine/UI/GUI/Common/Button.cs
@@ -144,6 +144,16 @@ namespace FlaxEngine.GUI
}
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Position
+ /// Size
+ public Button(Vector2 location, Vector2 size)
+ : this(location.X, location.Y, size.X, size.Y)
+ {
+ }
+
///
/// Called when mouse clicks the button.
///
@@ -219,7 +229,7 @@ namespace FlaxEngine.GUI
Render2D.DrawRectangle(clientRect, borderColor);
// 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);
}
///
diff --git a/Source/Engine/Visject/VisjectGraph.cpp b/Source/Engine/Visject/VisjectGraph.cpp
index b0093fc7a..9e98fa5f5 100644
--- a/Source/Engine/Visject/VisjectGraph.cpp
+++ b/Source/Engine/Visject/VisjectGraph.cpp
@@ -117,6 +117,22 @@ void VisjectExecutor::ProcessGroupConstants(Box* box, Node* node, Value& value)
case 11:
value = node->Values[0];
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:
break;
}