diff --git a/Source/Editor/GUI/Input/UIntValueBox.cs b/Source/Editor/GUI/Input/UIntValueBox.cs
new file mode 100644
index 000000000..a7ad984d7
--- /dev/null
+++ b/Source/Editor/GUI/Input/UIntValueBox.cs
@@ -0,0 +1,161 @@
+// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
+
+using System;
+using FlaxEditor.Utilities;
+using FlaxEngine;
+
+namespace FlaxEditor.GUI.Input
+{
+ ///
+ /// Unsigned Integer value editor.
+ ///
+ ///
+ [HideInEditor]
+ public class UIntValueBox : ValueBox
+ {
+ ///
+ public override uint Value
+ {
+ get => _value;
+ set
+ {
+ value = Mathf.Clamp(value, _min, _max);
+ if (_value != value)
+ {
+ // Set value
+ _value = value;
+
+ // Update
+ UpdateText();
+ OnValueChanged();
+ }
+ }
+ }
+
+ ///
+ public override uint MinValue
+ {
+ get => _min;
+ set
+ {
+ if (_min != value)
+ {
+ if (value > _max)
+ throw new ArgumentException();
+
+ _min = value;
+ Value = Value;
+ }
+ }
+ }
+
+ ///
+ public override uint MaxValue
+ {
+ get => _max;
+ set
+ {
+ if (_max != value)
+ {
+ if (value < _min)
+ throw new ArgumentException();
+
+ _max = value;
+ Value = Value;
+ }
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value.
+ /// The x location.
+ /// The y location.
+ /// The width.
+ /// The minimum value.
+ /// The maximum value.
+ /// The slide speed.
+ public UIntValueBox(uint value, float x = 0, float y = 0, float width = 120, uint min = uint.MinValue, uint max = uint.MaxValue, float slideSpeed = 1)
+ : base(Mathf.Clamp(value, min, max), x, y, width, min, max, slideSpeed)
+ {
+ UpdateText();
+ }
+
+ ///
+ /// Sets the value limits.
+ ///
+ /// The minimum value (bottom range).
+ /// The maximum value (upper range).
+ public void SetLimits(uint min, uint max)
+ {
+ _min = min;
+ _max = Mathf.Max(_min, max);
+ Value = Value;
+ }
+
+ ///
+ /// Sets the limits from the attribute.
+ ///
+ /// The limits.
+ public void SetLimits(RangeAttribute limits)
+ {
+ _min = limits.Min <= 0 ? uint.MinValue : (uint)limits.Min;
+ _max = Math.Max(_min, limits.Max == float.MaxValue ? uint.MaxValue : (uint)limits.Max);
+ Value = Value;
+ }
+
+ ///
+ /// Sets the limits from the attribute.
+ ///
+ /// The limits.
+ public void SetLimits(LimitAttribute limits)
+ {
+ _min = limits.Min <= 0 ? uint.MinValue : (uint)limits.Min;
+ _max = Math.Max(_min, limits.Max == float.MaxValue ? uint.MaxValue : (uint)limits.Max);
+ _slideSpeed = limits.SliderSpeed;
+ Value = Value;
+ }
+
+ ///
+ /// Sets the limits from the other .
+ ///
+ /// The other.
+ public void SetLimits(UIntValueBox other)
+ {
+ _min = other._min;
+ _max = other._max;
+ _slideSpeed = other._slideSpeed;
+ Value = Value;
+ }
+
+ ///
+ protected sealed override void UpdateText()
+ {
+ var text = _value.ToString();
+
+ SetText(text);
+ }
+
+ ///
+ protected override void TryGetValue()
+ {
+ try
+ {
+ var value = ShuntingYard.Parse(Text);
+ Value = (uint)value;
+ }
+ catch (Exception ex)
+ {
+ // Fall back to previous value
+ Editor.LogWarning(ex);
+ }
+ }
+
+ ///
+ protected override void ApplySliding(float delta)
+ {
+ Value = _startSlideValue + (uint)delta;
+ }
+ }
+}
diff --git a/Source/Editor/Surface/Elements/InputBox.cs b/Source/Editor/Surface/Elements/InputBox.cs
index 434cf7a5c..99fd681e9 100644
--- a/Source/Editor/Surface/Elements/InputBox.cs
+++ b/Source/Editor/Surface/Elements/InputBox.cs
@@ -105,13 +105,13 @@ namespace FlaxEditor.Surface.Elements
{
public bool CanUse(InputBox box, ref ScriptType type)
{
- return type.Type == typeof(int) || type.Type == typeof(uint);
+ return type.Type == typeof(int);
}
public Control Create(InputBox box, ref Rectangle bounds)
{
var value = IntegerValue.Get(box.ParentNode, box.Archetype);
- var control = new IntValueBox(value, bounds.X, bounds.Y, 40, box.CurrentType.Type == typeof(uint) ? 0 : 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,
Parent = box.Parent,
@@ -145,6 +145,50 @@ namespace FlaxEditor.Surface.Elements
}
}
+ class UnsignedIntegerDefaultValueEditor : IDefaultValueEditor
+ {
+ public bool CanUse(InputBox box, ref ScriptType type)
+ {
+ return type.Type == typeof(uint);
+ }
+
+ public Control Create(InputBox box, ref Rectangle bounds)
+ {
+ var value = UnsignedIntegerValue.Get(box.ParentNode, box.Archetype);
+ var control = new UIntValueBox(value, bounds.X, bounds.Y, 40, uint.MinValue, uint.MaxValue, 0.01f)
+ {
+ Height = bounds.Height,
+ Parent = box.Parent,
+ Tag = box,
+ };
+ control.BoxValueChanged += OnValueBoxChanged;
+ return control;
+ }
+
+ public bool IsValid(InputBox box, Control control)
+ {
+ return control is UIntValueBox;
+ }
+
+ public void UpdateDefaultValue(InputBox box, Control control)
+ {
+ if (control is UIntValueBox intValue)
+ {
+ intValue.Value = UnsignedIntegerValue.Get(box.ParentNode, box.Archetype);
+ }
+ }
+
+ public void UpdateAttributes(InputBox box, object[] attributes, Control control)
+ {
+ }
+
+ private void OnValueBoxChanged(ValueBox control)
+ {
+ var box = (InputBox)control.Tag;
+ UnsignedIntegerValue.Set(box.ParentNode, box.Archetype, control.Value);
+ }
+ }
+
class FloatingDefaultValueEditor : IDefaultValueEditor
{
public bool CanUse(InputBox box, ref ScriptType type)
@@ -817,6 +861,7 @@ namespace FlaxEditor.Surface.Elements
{
new BooleanDefaultValueEditor(),
new IntegerDefaultValueEditor(),
+ new UnsignedIntegerDefaultValueEditor(),
new FloatingDefaultValueEditor(),
new StringDefaultValueEditor(),
new Vector2DefaultValueEditor(),
diff --git a/Source/Editor/Surface/Elements/UnsignedIntegerValue.cs b/Source/Editor/Surface/Elements/UnsignedIntegerValue.cs
new file mode 100644
index 000000000..2ccd97b5c
--- /dev/null
+++ b/Source/Editor/Surface/Elements/UnsignedIntegerValue.cs
@@ -0,0 +1,153 @@
+// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
+
+using FlaxEditor.GUI.Input;
+using FlaxEngine;
+using FlaxEngine.GUI;
+
+namespace FlaxEditor.Surface.Elements
+{
+ ///
+ /// Unsigned Integer value editing element.
+ ///
+ ///
+ ///
+ [HideInEditor]
+ public sealed class UnsignedIntegerValue : UIntValueBox, ISurfaceNodeElement
+ {
+ ///
+ public SurfaceNode ParentNode { get; }
+
+ ///
+ public NodeElementArchetype Archetype { get; }
+
+ ///
+ public UnsignedIntegerValue(SurfaceNode parentNode, NodeElementArchetype archetype)
+ : base(Get(parentNode, archetype), archetype.Position.X, archetype.Position.Y, 50, (uint)archetype.ValueMin, (uint)archetype.ValueMax, 0.05f)
+ {
+ ParentNode = parentNode;
+ Archetype = archetype;
+
+ ParentNode.ValuesChanged += OnNodeValuesChanged;
+ }
+
+ private void OnNodeValuesChanged()
+ {
+ Value = Get(ParentNode, Archetype);
+ }
+
+ ///
+ public override void Draw()
+ {
+ base.Draw();
+
+ // Draw border
+ if (!IsFocused)
+ Render2D.DrawRectangle(new Rectangle(Vector2.Zero, Size), Style.Current.BorderNormal);
+ }
+
+ ///
+ protected override void OnValueChanged()
+ {
+ base.OnValueChanged();
+ Set(ParentNode, Archetype, Value);
+ }
+
+ ///
+ /// Gets the unsigned integer value from the specified parent node. Handles type casting and components gather.
+ ///
+ /// The parent node.
+ /// The node element archetype.
+ /// The result value.
+ public static uint Get(SurfaceNode parentNode, NodeElementArchetype arch)
+ {
+ if (arch.ValueIndex < 0)
+ return 0;
+
+ uint result;
+ var value = 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
+
+ if (value is int valueInt)
+ result = (uint)valueInt;
+ else if (value is uint valueUint)
+ result = valueUint;
+ else if (value is long valueLong)
+ result = (uint)valueLong;
+ else if (value is ulong valueUlong)
+ result = (uint)valueUlong;
+ else if (value is float valueFloat)
+ result = (uint)valueFloat;
+ else if (value is Vector2 valueVec2)
+ result = (uint)(arch.BoxID == 0 ? valueVec2.X : valueVec2.Y);
+ else if (value is Vector3 valueVec3)
+ result = (uint)(arch.BoxID == 0 ? valueVec3.X : arch.BoxID == 1 ? valueVec3.Y : valueVec3.Z);
+ else if (value is Vector4 valueVec4)
+ result = (uint)(arch.BoxID == 0 ? valueVec4.X : arch.BoxID == 1 ? valueVec4.Y : arch.BoxID == 2 ? valueVec4.Z : valueVec4.W);
+ else
+ result = 0;
+
+ return result;
+ }
+
+ ///
+ /// Sets the unsigned integer value of the specified parent node. Handles type casting and components assignment.
+ ///
+ /// The parent node.
+ /// The node element archetype.
+ /// The value to set.
+ public static void Set(SurfaceNode parentNode, NodeElementArchetype arch, uint toSet)
+ {
+ if (arch.ValueIndex < 0)
+ return;
+
+ var value = parentNode.Values[arch.ValueIndex];
+ float toSetF = (float)toSet;
+
+ if (value is int)
+ value = (int)toSet;
+ else if (value is uint)
+ value = toSet;
+ else if (value is long)
+ value = (long)toSet;
+ else if (value is ulong)
+ value = (ulong)toSet;
+ else if (value is float)
+ value = toSetF;
+ else if (value is Vector2 valueVec2)
+ {
+ if (arch.BoxID == 0)
+ valueVec2.X = toSetF;
+ else
+ valueVec2.Y = toSetF;
+ value = valueVec2;
+ }
+ else if (value is Vector3 valueVec3)
+ {
+ if (arch.BoxID == 0)
+ valueVec3.X = toSetF;
+ else if (arch.BoxID == 1)
+ valueVec3.Y = toSetF;
+ else
+ valueVec3.Z = toSetF;
+ value = valueVec3;
+ }
+ else if (value is Vector4 valueVec4)
+ {
+ if (arch.BoxID == 0)
+ valueVec4.X = toSetF;
+ else if (arch.BoxID == 1)
+ valueVec4.Y = toSetF;
+ else if (arch.BoxID == 2)
+ valueVec4.Z = toSetF;
+ else
+ valueVec4.W = toSetF;
+ value = valueVec4;
+ }
+ else
+ value = 0;
+
+ parentNode.SetValue(arch.ValueIndex, value);
+ }
+ }
+}
diff --git a/Source/Engine/Core/Math/Mathf.cs b/Source/Engine/Core/Math/Mathf.cs
index d311799f2..4d4bd89c7 100644
--- a/Source/Engine/Core/Math/Mathf.cs
+++ b/Source/Engine/Core/Math/Mathf.cs
@@ -316,6 +316,16 @@ namespace FlaxEngine
return a <= b ? b : a;
}
+ ///
+ /// Returns the largest of two or more values.
+ ///
+ ///
+ ///
+ public static uint Max(uint a, uint b)
+ {
+ return a <= b ? b : a;
+ }
+
///
/// Returns the largest of two or more values.
///
@@ -401,6 +411,16 @@ namespace FlaxEngine
return a >= b ? b : a;
}
+ ///
+ /// Returns the smallest of two or more values.
+ ///
+ ///
+ ///
+ public static uint Min(uint a, uint b)
+ {
+ return a >= b ? b : a;
+ }
+
///
/// Returns the smallest of two or more values.
///
@@ -1173,6 +1193,18 @@ namespace FlaxEngine
return value < min ? min : value > max ? max : value;
}
+ ///
+ /// Clamps the specified value.
+ ///
+ /// The value.
+ /// The min.
+ /// The max.
+ /// The result of clamping a value between min and max
+ public static uint Clamp(uint value, uint min, uint max)
+ {
+ return value < min ? min : value > max ? max : value;
+ }
+
///
/// Interpolates between two values using a linear function by a given amount.
///