From 9e38a01acc45dca23eb031c6fa7baf0c5958dca4 Mon Sep 17 00:00:00 2001
From: nothingTVatYT <34131388+nothingTVatYT@users.noreply.github.com>
Date: Sun, 28 Jan 2024 20:52:25 +0100
Subject: [PATCH] add units support in float, double and Float3 input
---
.../CustomEditors/Editors/DoubleEditor.cs | 5 ++
.../CustomEditors/Editors/FloatEditor.cs | 5 ++
.../CustomEditors/Editors/Vector3Editor.cs | 15 +++++
.../Elements/DoubleValueElement.cs | 10 +++
.../Elements/FloatValueElement.cs | 10 +++
Source/Editor/GUI/Input/DoubleValueBox.cs | 8 ++-
Source/Editor/GUI/Input/FloatValueBox.cs | 8 ++-
Source/Editor/Utilities/ShuntingYardParser.cs | 17 ++++-
Source/Editor/Utilities/Units.cs | 9 +++
Source/Editor/Utilities/Utils.cs | 64 ++++++++++++++++++-
.../Editor/ValueCategoryAttribute.cs | 35 ++++++++++
.../Flax.Build.Tests/Flax.Build.Tests.csproj | 2 +-
Source/Tools/Flax.Build/Flax.Build.csproj | 1 -
13 files changed, 182 insertions(+), 7 deletions(-)
create mode 100644 Source/Editor/Utilities/Units.cs
create mode 100644 Source/Engine/Scripting/Attributes/Editor/ValueCategoryAttribute.cs
diff --git a/Source/Editor/CustomEditors/Editors/DoubleEditor.cs b/Source/Editor/CustomEditors/Editors/DoubleEditor.cs
index c490046b9..0906d22af 100644
--- a/Source/Editor/CustomEditors/Editors/DoubleEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/DoubleEditor.cs
@@ -4,6 +4,7 @@ using System;
using System.Linq;
using FlaxEditor.CustomEditors.Elements;
using FlaxEngine;
+using Utils = FlaxEditor.Utilities.Utils;
namespace FlaxEditor.CustomEditors.Editors
{
@@ -25,6 +26,8 @@ namespace FlaxEditor.CustomEditors.Editors
// Try get limit attribute for value min/max range setting and slider speed
var attributes = Values.GetAttributes();
+ var categoryAttribute = attributes.FirstOrDefault(x => x is ValueCategoryAttribute);
+ var valueCategory = ((ValueCategoryAttribute)categoryAttribute)?.Category ?? Utils.ValueCategory.None;
if (attributes != null)
{
var limit = attributes.FirstOrDefault(x => x is LimitAttribute);
@@ -32,6 +35,7 @@ namespace FlaxEditor.CustomEditors.Editors
{
// Use double value editor with limit
var doubleValue = layout.DoubleValue();
+ doubleValue.SetCategory(valueCategory);
doubleValue.SetLimits((LimitAttribute)limit);
doubleValue.ValueBox.ValueChanged += OnValueChanged;
doubleValue.ValueBox.SlidingEnd += ClearToken;
@@ -43,6 +47,7 @@ namespace FlaxEditor.CustomEditors.Editors
{
// Use double value editor
var doubleValue = layout.DoubleValue();
+ doubleValue.SetCategory(valueCategory);
doubleValue.ValueBox.ValueChanged += OnValueChanged;
doubleValue.ValueBox.SlidingEnd += ClearToken;
_element = doubleValue;
diff --git a/Source/Editor/CustomEditors/Editors/FloatEditor.cs b/Source/Editor/CustomEditors/Editors/FloatEditor.cs
index 07c07030e..525541e99 100644
--- a/Source/Editor/CustomEditors/Editors/FloatEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/FloatEditor.cs
@@ -4,6 +4,7 @@ using System;
using System.Linq;
using FlaxEditor.CustomEditors.Elements;
using FlaxEngine;
+using Utils = FlaxEditor.Utilities.Utils;
namespace FlaxEditor.CustomEditors.Editors
{
@@ -30,6 +31,8 @@ namespace FlaxEditor.CustomEditors.Editors
// Try get limit attribute for value min/max range setting and slider speed
var attributes = Values.GetAttributes();
+ var categoryAttribute = attributes.FirstOrDefault(x => x is ValueCategoryAttribute);
+ var valueCategory = ((ValueCategoryAttribute)categoryAttribute)?.Category ?? Utils.ValueCategory.None;
if (attributes != null)
{
var range = attributes.FirstOrDefault(x => x is RangeAttribute);
@@ -49,6 +52,7 @@ namespace FlaxEditor.CustomEditors.Editors
// Use float value editor with limit
var floatValue = layout.FloatValue();
floatValue.SetLimits((LimitAttribute)limit);
+ floatValue.SetCategory(valueCategory);
floatValue.ValueBox.ValueChanged += OnValueChanged;
floatValue.ValueBox.SlidingEnd += ClearToken;
_element = floatValue;
@@ -59,6 +63,7 @@ namespace FlaxEditor.CustomEditors.Editors
{
// Use float value editor
var floatValue = layout.FloatValue();
+ floatValue.SetCategory(valueCategory);
floatValue.ValueBox.ValueChanged += OnValueChanged;
floatValue.ValueBox.SlidingEnd += ClearToken;
_element = floatValue;
diff --git a/Source/Editor/CustomEditors/Editors/Vector3Editor.cs b/Source/Editor/CustomEditors/Editors/Vector3Editor.cs
index c3edd3913..9826c339f 100644
--- a/Source/Editor/CustomEditors/Editors/Vector3Editor.cs
+++ b/Source/Editor/CustomEditors/Editors/Vector3Editor.cs
@@ -4,6 +4,7 @@ using System.Linq;
using FlaxEditor.CustomEditors.Elements;
using FlaxEngine;
using FlaxEngine.GUI;
+using Utils = FlaxEditor.Utilities.Utils;
namespace FlaxEditor.CustomEditors.Editors
{
@@ -70,23 +71,30 @@ namespace FlaxEditor.CustomEditors.Editors
LimitAttribute limit = null;
var attributes = Values.GetAttributes();
+ var category = Utils.ValueCategory.None;
if (attributes != null)
{
limit = (LimitAttribute)attributes.FirstOrDefault(x => x is LimitAttribute);
+ var categoryAttribute = (ValueCategoryAttribute)attributes.FirstOrDefault(x => x is ValueCategoryAttribute);
+ if (categoryAttribute != null)
+ category = categoryAttribute.Category;
}
XElement = grid.FloatValue();
XElement.SetLimits(limit);
+ XElement.SetCategory(category);
XElement.ValueBox.ValueChanged += OnXValueChanged;
XElement.ValueBox.SlidingEnd += ClearToken;
YElement = grid.FloatValue();
YElement.SetLimits(limit);
+ YElement.SetCategory(category);
YElement.ValueBox.ValueChanged += OnYValueChanged;
YElement.ValueBox.SlidingEnd += ClearToken;
ZElement = grid.FloatValue();
ZElement.SetLimits(limit);
+ ZElement.SetCategory(category);
ZElement.ValueBox.ValueChanged += OnZValueChanged;
ZElement.ValueBox.SlidingEnd += ClearToken;
}
@@ -248,24 +256,31 @@ namespace FlaxEditor.CustomEditors.Editors
gridControl.SlotsVertically = 1;
LimitAttribute limit = null;
+ Utils.ValueCategory category = Utils.ValueCategory.None;
var attributes = Values.GetAttributes();
if (attributes != null)
{
limit = (LimitAttribute)attributes.FirstOrDefault(x => x is LimitAttribute);
+ var categoryAttribute = (ValueCategoryAttribute)attributes.FirstOrDefault(x => x is ValueCategoryAttribute);
+ if (categoryAttribute != null)
+ category = categoryAttribute.Category;
}
XElement = grid.DoubleValue();
XElement.SetLimits(limit);
+ XElement.SetCategory(category);
XElement.ValueBox.ValueChanged += OnValueChanged;
XElement.ValueBox.SlidingEnd += ClearToken;
YElement = grid.DoubleValue();
YElement.SetLimits(limit);
+ YElement.SetCategory(category);
YElement.ValueBox.ValueChanged += OnValueChanged;
YElement.ValueBox.SlidingEnd += ClearToken;
ZElement = grid.DoubleValue();
ZElement.SetLimits(limit);
+ ZElement.SetCategory(category);
ZElement.ValueBox.ValueChanged += OnValueChanged;
ZElement.ValueBox.SlidingEnd += ClearToken;
}
diff --git a/Source/Editor/CustomEditors/Elements/DoubleValueElement.cs b/Source/Editor/CustomEditors/Elements/DoubleValueElement.cs
index 07af5e991..460a344ff 100644
--- a/Source/Editor/CustomEditors/Elements/DoubleValueElement.cs
+++ b/Source/Editor/CustomEditors/Elements/DoubleValueElement.cs
@@ -5,6 +5,7 @@ using System.Reflection;
using FlaxEditor.GUI.Input;
using FlaxEngine;
using FlaxEngine.GUI;
+using Utils = FlaxEditor.Utilities.Utils;
namespace FlaxEditor.CustomEditors.Elements
{
@@ -51,6 +52,15 @@ namespace FlaxEditor.CustomEditors.Elements
}
}
+ ///
+ /// Set the value category of this float element
+ ///
+ ///
+ public void SetCategory(Utils.ValueCategory category)
+ {
+ ValueBox.Category = category;
+ }
+
///
/// Sets the editor limits from member .
///
diff --git a/Source/Editor/CustomEditors/Elements/FloatValueElement.cs b/Source/Editor/CustomEditors/Elements/FloatValueElement.cs
index 789d8966e..413a341c1 100644
--- a/Source/Editor/CustomEditors/Elements/FloatValueElement.cs
+++ b/Source/Editor/CustomEditors/Elements/FloatValueElement.cs
@@ -5,6 +5,7 @@ using System.Reflection;
using FlaxEditor.GUI.Input;
using FlaxEngine;
using FlaxEngine.GUI;
+using Utils = FlaxEditor.Utilities.Utils;
namespace FlaxEditor.CustomEditors.Elements
{
@@ -51,6 +52,15 @@ namespace FlaxEditor.CustomEditors.Elements
}
}
+ ///
+ /// Set the value category of this float element
+ ///
+ ///
+ public void SetCategory(Utils.ValueCategory category)
+ {
+ ValueBox.Category = category;
+ }
+
///
/// Sets the editor limits from member .
///
diff --git a/Source/Editor/GUI/Input/DoubleValueBox.cs b/Source/Editor/GUI/Input/DoubleValueBox.cs
index 0ceb10114..46e6402cb 100644
--- a/Source/Editor/GUI/Input/DoubleValueBox.cs
+++ b/Source/Editor/GUI/Input/DoubleValueBox.cs
@@ -3,6 +3,7 @@
using System;
using FlaxEditor.Utilities;
using FlaxEngine;
+using Utils = FlaxEditor.Utilities.Utils;
namespace FlaxEditor.GUI.Input
{
@@ -129,10 +130,15 @@ namespace FlaxEditor.GUI.Input
Value = Value;
}
+ ///
+ /// Get or set the category of the value. This can either be none for just a number, a distance or an angle.
+ ///
+ public Utils.ValueCategory Category = Utils.ValueCategory.None;
+
///
protected sealed override void UpdateText()
{
- SetText(Utilities.Utils.FormatFloat(_value));
+ SetText(Utilities.Utils.FormatFloat(_value, Category));
}
///
diff --git a/Source/Editor/GUI/Input/FloatValueBox.cs b/Source/Editor/GUI/Input/FloatValueBox.cs
index cdb3b08b1..64ea000fa 100644
--- a/Source/Editor/GUI/Input/FloatValueBox.cs
+++ b/Source/Editor/GUI/Input/FloatValueBox.cs
@@ -4,6 +4,7 @@ using System;
using System.Globalization;
using FlaxEditor.Utilities;
using FlaxEngine;
+using Utils = FlaxEditor.Utilities.Utils;
namespace FlaxEditor.GUI.Input
{
@@ -137,10 +138,15 @@ namespace FlaxEditor.GUI.Input
Value = Value;
}
+ ///
+ /// Get or set the category of the value. This can either be none for just a number, a distance or an angle.
+ ///
+ public Utils.ValueCategory Category = Utils.ValueCategory.None;
+
///
protected sealed override void UpdateText()
{
- SetText(Utilities.Utils.FormatFloat(_value));
+ SetText(Utilities.Utils.FormatFloat(_value, Category));
}
///
diff --git a/Source/Editor/Utilities/ShuntingYardParser.cs b/Source/Editor/Utilities/ShuntingYardParser.cs
index d139b003a..e7c5b5298 100644
--- a/Source/Editor/Utilities/ShuntingYardParser.cs
+++ b/Source/Editor/Utilities/ShuntingYardParser.cs
@@ -121,6 +121,9 @@ namespace FlaxEditor.Utilities
["e"] = Math.E,
["infinity"] = double.MaxValue,
["-infinity"] = -double.MaxValue,
+ ["m"] = Units.Meters2Units,
+ ["cm"] = Units.Meters2Units / 100,
+ ["km"] = Units.Meters2Units * 1000
};
///
@@ -170,7 +173,7 @@ namespace FlaxEditor.Utilities
public static IEnumerable Tokenize(string text)
{
// Prepare text
- text = text.Replace(',', '.');
+ text = text.Replace(',', '.').Replace("°", "");
// Necessary to correctly parse negative numbers
var previous = TokenType.WhiteSpace;
@@ -372,6 +375,18 @@ namespace FlaxEditor.Utilities
}
}
+ // if stack has more than one item we're not finished with evaluating
+ // we assume the remaining values are all factors to be multiplied
+ if (stack.Count > 1)
+ {
+ var stackContent = string.Join(",", stack.ToList());
+ Debug.Log($"parsing numbers, stack is {stackContent}");
+ var v1 = stack.Pop();
+ Debug.Log($"first on stack: {v1}");
+ while (stack.Count > 0)
+ v1 *= stack.Pop();
+ return v1;
+ }
return stack.Pop();
}
diff --git a/Source/Editor/Utilities/Units.cs b/Source/Editor/Utilities/Units.cs
new file mode 100644
index 000000000..00d53a463
--- /dev/null
+++ b/Source/Editor/Utilities/Units.cs
@@ -0,0 +1,9 @@
+namespace FlaxEditor.Utilities;
+
+public class Units
+{
+ ///
+ /// Factor of units per meter.
+ ///
+ public static readonly float Meters2Units = 100f;
+}
diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs
index 3d790ff81..0df4fe573 100644
--- a/Source/Editor/Utilities/Utils.cs
+++ b/Source/Editor/Utilities/Utils.cs
@@ -58,6 +58,16 @@ namespace FlaxEditor.Utilities
///
public static readonly string FlaxEngineAssemblyName = "FlaxEngine.CSharp";
+ ///
+ /// A category of number values used for formatting and input boxes
+ ///
+ public enum ValueCategory
+ {
+ None,
+ Distance,
+ Angle
+ }
+
///
/// Tries to parse number in the name brackets at the end of the value and then increment it to create a new name.
/// Supports numbers at the end without brackets.
@@ -1171,6 +1181,56 @@ namespace FlaxEditor.Utilities
return StringUtils.GetPathWithoutExtension(path);
}
+ ///
+ /// Format a float value either as-is, with a distance unit or with a degree sign
+ ///
+ /// the value to format
+ /// the value type: none means just a number, distance will format in cm/m/km, angle with an appended degree sign
+ /// the formatted string
+ public static string FormatFloat(float value, ValueCategory category)
+ {
+ switch (category)
+ {
+ case ValueCategory.Distance:
+ var absValue = Mathf.Abs(value);
+ // in case a unit != cm this would be (value / Maters2Units * 100)
+ if (absValue < Units.Meters2Units)
+ return value.ToString("g7", CultureInfo.InvariantCulture) + "cm";
+ if (absValue < Units.Meters2Units * 1000)
+ return (value / Units.Meters2Units).ToString("g7", CultureInfo.InvariantCulture) + "m";
+ return (value / 1000 / Units.Meters2Units).ToString("g7", CultureInfo.InvariantCulture) + "km";
+ case ValueCategory.Angle: return value.ToString("g7", CultureInfo.InvariantCulture) + "°";
+ case ValueCategory.None:
+ default:
+ return FormatFloat(value);
+ }
+ }
+
+ ///
+ /// Format a double value either as-is, with a distance unit or with a degree sign
+ ///
+ /// the value to format
+ /// the value type: none means just a number, distance will format in cm/m/km, angle with an appended degree sign
+ /// the formatted string
+ public static string FormatFloat(double value, ValueCategory category)
+ {
+ switch (category)
+ {
+ case ValueCategory.Distance:
+ var absValue = Mathf.Abs(value);
+ // in case a unit != cm this would be (value / Maters2Units * 100)
+ if (absValue < Units.Meters2Units)
+ return value.ToString("g17", CultureInfo.InvariantCulture) + "cm";
+ if (absValue < Units.Meters2Units * 1000)
+ return (value / Units.Meters2Units).ToString("g17", CultureInfo.InvariantCulture) + "m";
+ return (value / 1000 / Units.Meters2Units).ToString("g17", CultureInfo.InvariantCulture) + "km";
+ case ValueCategory.Angle: return value.ToString("g17", CultureInfo.InvariantCulture) + "°";
+ case ValueCategory.None:
+ default:
+ return FormatFloat(value);
+ }
+ }
+
///
/// Formats the floating point value (double precision) into the readable text representation.
///
@@ -1182,7 +1242,7 @@ namespace FlaxEditor.Utilities
return "Infinity";
if (float.IsNegativeInfinity(value) || value == float.MinValue)
return "-Infinity";
- string str = value.ToString("r", CultureInfo.InvariantCulture);
+ string str = value.ToString("g7", CultureInfo.InvariantCulture);
return FormatFloat(str, value < 0);
}
@@ -1197,7 +1257,7 @@ namespace FlaxEditor.Utilities
return "Infinity";
if (double.IsNegativeInfinity(value) || value == double.MinValue)
return "-Infinity";
- string str = value.ToString("r", CultureInfo.InvariantCulture);
+ string str = value.ToString("g17", CultureInfo.InvariantCulture);
return FormatFloat(str, value < 0);
}
diff --git a/Source/Engine/Scripting/Attributes/Editor/ValueCategoryAttribute.cs b/Source/Engine/Scripting/Attributes/Editor/ValueCategoryAttribute.cs
new file mode 100644
index 000000000..3c6da2286
--- /dev/null
+++ b/Source/Engine/Scripting/Attributes/Editor/ValueCategoryAttribute.cs
@@ -0,0 +1,35 @@
+// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
+
+using System;
+
+namespace FlaxEngine
+{
+ ///
+ /// Used to specify the value category of a numeric value as either as-is (a scalar), a distance (formatted as cm/m/km)
+ /// or an angle (formatted with a degree sign).
+ ///
+ ///
+ [Serializable]
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ public sealed class ValueCategoryAttribute : Attribute
+ {
+ ///
+ /// The value category used for formatting.
+ ///
+ public FlaxEditor.Utilities.Utils.ValueCategory Category;
+
+ private ValueCategoryAttribute()
+ {
+ Category = FlaxEditor.Utilities.Utils.ValueCategory.None;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value category.
+ public ValueCategoryAttribute(FlaxEditor.Utilities.Utils.ValueCategory category)
+ {
+ Category = category;
+ }
+ }
+}
diff --git a/Source/Tools/Flax.Build.Tests/Flax.Build.Tests.csproj b/Source/Tools/Flax.Build.Tests/Flax.Build.Tests.csproj
index df3b9851b..78b23ec07 100644
--- a/Source/Tools/Flax.Build.Tests/Flax.Build.Tests.csproj
+++ b/Source/Tools/Flax.Build.Tests/Flax.Build.Tests.csproj
@@ -2,7 +2,7 @@
net7.0
- 11.0
+ 12
disable
annotations
true
diff --git a/Source/Tools/Flax.Build/Flax.Build.csproj b/Source/Tools/Flax.Build/Flax.Build.csproj
index 1837bf0ec..7b189ce56 100644
--- a/Source/Tools/Flax.Build/Flax.Build.csproj
+++ b/Source/Tools/Flax.Build/Flax.Build.csproj
@@ -2,7 +2,6 @@
Exe
net7.0
- 11.0
disable
annotations
false