Add support for Vector3, Float3, Double3, and Quaternion mutliselect value changing.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using FlaxEditor.CustomEditors.GUI;
|
||||
@@ -269,10 +270,18 @@ namespace FlaxEditor.CustomEditors
|
||||
object val = _valueToSet;
|
||||
_hasValueDirty = false;
|
||||
_valueToSet = null;
|
||||
|
||||
|
||||
// Assign value
|
||||
for (int i = 0; i < _values.Count; i++)
|
||||
_values[i] = val;
|
||||
if (val is IList l && l.Count == _values.Count)
|
||||
{
|
||||
for (int i = 0; i < _values.Count; i++)
|
||||
_values[i] = l[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < _values.Count; i++)
|
||||
_values[i] = val;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -33,6 +33,15 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DisplayStyle Style => DisplayStyle.Inline;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use the average for sliding different values.
|
||||
/// </summary>
|
||||
public virtual bool AllowSlidingForDifferentValues => true;
|
||||
|
||||
private ValueChanged _valueChanged;
|
||||
private float _defaultSlidingSpeed;
|
||||
private bool _slidingEnded = false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
@@ -46,18 +55,30 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
XElement = grid.FloatValue();
|
||||
XElement.ValueBox.Category = Utils.ValueCategory.Angle;
|
||||
XElement.ValueBox.ValueChanged += OnValueChanged;
|
||||
XElement.ValueBox.SlidingEnd += ClearToken;
|
||||
XElement.ValueBox.ValueChanged += OnXValueChanged;
|
||||
XElement.ValueBox.SlidingEnd += () =>
|
||||
{
|
||||
_slidingEnded = true;
|
||||
ClearToken();
|
||||
};
|
||||
|
||||
YElement = grid.FloatValue();
|
||||
YElement.ValueBox.Category = Utils.ValueCategory.Angle;
|
||||
YElement.ValueBox.ValueChanged += OnValueChanged;
|
||||
YElement.ValueBox.SlidingEnd += ClearToken;
|
||||
YElement.ValueBox.ValueChanged += OnYValueChanged;
|
||||
YElement.ValueBox.SlidingEnd += () =>
|
||||
{
|
||||
_slidingEnded = true;
|
||||
ClearToken();
|
||||
};
|
||||
|
||||
ZElement = grid.FloatValue();
|
||||
ZElement.ValueBox.Category = Utils.ValueCategory.Angle;
|
||||
ZElement.ValueBox.ValueChanged += OnValueChanged;
|
||||
ZElement.ValueBox.SlidingEnd += ClearToken;
|
||||
ZElement.ValueBox.ValueChanged += OnZValueChanged;
|
||||
ZElement.ValueBox.SlidingEnd += () =>
|
||||
{
|
||||
_slidingEnded = true;
|
||||
ClearToken();
|
||||
};
|
||||
|
||||
if (LinkedLabel != null)
|
||||
{
|
||||
@@ -69,33 +90,162 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void OnValueChanged()
|
||||
|
||||
private void OnXValueChanged()
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
_valueChanged = ValueChanged.X;
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
private void OnYValueChanged()
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
_valueChanged = ValueChanged.Y;
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
private void OnZValueChanged()
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
_valueChanged = ValueChanged.Z;
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
private void OnValueChanged()
|
||||
{
|
||||
var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding;
|
||||
var token = isSliding ? this : null;
|
||||
var useCachedAngles = isSliding && token == _cachedToken;
|
||||
|
||||
float x = (useCachedAngles && !XElement.IsSliding) ? _cachedAngles.X : XElement.ValueBox.Value;
|
||||
float y = (useCachedAngles && !YElement.IsSliding) ? _cachedAngles.Y : YElement.ValueBox.Value;
|
||||
float z = (useCachedAngles && !ZElement.IsSliding) ? _cachedAngles.Z : ZElement.ValueBox.Value;
|
||||
|
||||
x = Mathf.UnwindDegrees(x);
|
||||
y = Mathf.UnwindDegrees(y);
|
||||
z = Mathf.UnwindDegrees(z);
|
||||
|
||||
if (!useCachedAngles)
|
||||
|
||||
if (HasDifferentValues && Values.Count > 1)
|
||||
{
|
||||
_cachedAngles = new Float3(x, y, z);
|
||||
var xValue = XElement.ValueBox.Value;
|
||||
var yValue = YElement.ValueBox.Value;
|
||||
var zValue = ZElement.ValueBox.Value;
|
||||
|
||||
xValue = Mathf.UnwindDegrees(xValue);
|
||||
yValue = Mathf.UnwindDegrees(yValue);
|
||||
zValue = Mathf.UnwindDegrees(zValue);
|
||||
|
||||
var value = new Float3(xValue, yValue, zValue);
|
||||
|
||||
_cachedToken = token;
|
||||
|
||||
var newObjects = new object[Values.Count];
|
||||
// Handle Sliding
|
||||
if (AllowSlidingForDifferentValues && (isSliding || _slidingEnded))
|
||||
{
|
||||
Float3 average = Float3.Zero;
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
var v = (Quaternion)Values[0];
|
||||
var euler = v.EulerAngles;
|
||||
|
||||
average += euler;
|
||||
}
|
||||
|
||||
average /= Values.Count;
|
||||
|
||||
var newValue = value - average;
|
||||
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
var v = Values[i];
|
||||
switch (_valueChanged)
|
||||
{
|
||||
case ValueChanged.X:
|
||||
{
|
||||
var val = (Quaternion)v;
|
||||
Quaternion.Euler(newValue.X, 0, 0, out Quaternion qVal);
|
||||
v = val * qVal;
|
||||
break;
|
||||
}
|
||||
case ValueChanged.Y:
|
||||
{
|
||||
var val = (Quaternion)v;
|
||||
Quaternion.Euler(0, newValue.Y, 0, out Quaternion qVal);
|
||||
v = val * qVal;
|
||||
break;
|
||||
}
|
||||
case ValueChanged.Z:
|
||||
{
|
||||
var val = (Quaternion)v;
|
||||
Quaternion.Euler(0, 0, newValue.Z, out Quaternion qVal);
|
||||
v = val * qVal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
newObjects[i] = v;
|
||||
}
|
||||
|
||||
// Capture last sliding value
|
||||
if (_slidingEnded)
|
||||
_slidingEnded = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
object v = Values[i];
|
||||
switch (_valueChanged)
|
||||
{
|
||||
case ValueChanged.X:
|
||||
{
|
||||
var val = (Quaternion)v;
|
||||
var euler = val.EulerAngles;
|
||||
Quaternion.Euler(xValue, euler.Y, euler.Z, out Quaternion qVal);
|
||||
v = qVal;
|
||||
break;
|
||||
}
|
||||
case ValueChanged.Y:
|
||||
{
|
||||
var val = (Quaternion)v;
|
||||
var euler = val.EulerAngles;
|
||||
Quaternion.Euler(euler.X, yValue, euler.Z, out Quaternion qVal);
|
||||
v = qVal;
|
||||
break;
|
||||
}
|
||||
case ValueChanged.Z:
|
||||
{
|
||||
var val = (Quaternion)v;
|
||||
var euler = val.EulerAngles;
|
||||
Quaternion.Euler(euler.X, euler.Y, zValue, out Quaternion qVal);
|
||||
v = qVal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
newObjects[i] = v;
|
||||
}
|
||||
}
|
||||
|
||||
SetValue(newObjects, token);
|
||||
}
|
||||
else
|
||||
{
|
||||
float x = (useCachedAngles && !XElement.IsSliding) ? _cachedAngles.X : XElement.ValueBox.Value;
|
||||
float y = (useCachedAngles && !YElement.IsSliding) ? _cachedAngles.Y : YElement.ValueBox.Value;
|
||||
float z = (useCachedAngles && !ZElement.IsSliding) ? _cachedAngles.Z : ZElement.ValueBox.Value;
|
||||
|
||||
_cachedToken = token;
|
||||
x = Mathf.UnwindDegrees(x);
|
||||
y = Mathf.UnwindDegrees(y);
|
||||
z = Mathf.UnwindDegrees(z);
|
||||
|
||||
Quaternion.Euler(x, y, z, out Quaternion value);
|
||||
SetValue(value, token);
|
||||
if (!useCachedAngles)
|
||||
{
|
||||
_cachedAngles = new Float3(x, y, z);
|
||||
}
|
||||
|
||||
_cachedToken = token;
|
||||
|
||||
Quaternion.Euler(x, y, z, out Quaternion value);
|
||||
SetValue(value, token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -112,7 +262,73 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
if (HasDifferentValues)
|
||||
{
|
||||
// TODO: support different values for ValueBox<T>
|
||||
// Get which values are different
|
||||
bool xDifferent = false;
|
||||
bool yDifferent = false;
|
||||
bool zDifferent = false;
|
||||
Float3 cachedFirstValue = Float3.Zero;
|
||||
Float3 average = Float3.Zero;
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
var value = (Quaternion)Values[0];
|
||||
var euler = value.EulerAngles;
|
||||
|
||||
average += euler;
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
cachedFirstValue = euler;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Mathf.NearEqual(cachedFirstValue.X, value.X))
|
||||
xDifferent = true;
|
||||
if (!Mathf.NearEqual(cachedFirstValue.Y, value.Y))
|
||||
yDifferent = true;
|
||||
if (!Mathf.NearEqual(cachedFirstValue.Z, value.Z))
|
||||
zDifferent = true;
|
||||
}
|
||||
|
||||
average /= Values.Count;
|
||||
|
||||
if (!xDifferent)
|
||||
{
|
||||
XElement.ValueBox.Value = cachedFirstValue.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AllowSlidingForDifferentValues)
|
||||
XElement.ValueBox.Value = average.X;
|
||||
else
|
||||
XElement.ValueBox.SlideSpeed = 0;
|
||||
XElement.ValueBox.Text = "---";
|
||||
}
|
||||
|
||||
if (!yDifferent)
|
||||
{
|
||||
YElement.ValueBox.Value = cachedFirstValue.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AllowSlidingForDifferentValues)
|
||||
YElement.ValueBox.Value = average.Y;
|
||||
else
|
||||
YElement.ValueBox.SlideSpeed = 0;
|
||||
YElement.ValueBox.Text = "---";
|
||||
}
|
||||
|
||||
if (!zDifferent)
|
||||
{
|
||||
ZElement.ValueBox.Value = cachedFirstValue.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AllowSlidingForDifferentValues)
|
||||
ZElement.ValueBox.Value = average.Z;
|
||||
else
|
||||
ZElement.ValueBox.SlideSpeed = 0;
|
||||
ZElement.ValueBox.Text = "---";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -7,6 +7,27 @@ using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
/// <summary>
|
||||
/// The value changed by custom Vector3 editors.
|
||||
/// </summary>
|
||||
public enum ValueChanged
|
||||
{
|
||||
/// <summary>
|
||||
/// X value changed.
|
||||
/// </summary>
|
||||
X = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Y value changed.
|
||||
/// </summary>
|
||||
Y = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Z value changed.
|
||||
/// </summary>
|
||||
Z = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default implementation of the inspector used to edit Vector3 value type properties.
|
||||
/// </summary>
|
||||
@@ -49,14 +70,14 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// </summary>
|
||||
public bool LinkValues = false;
|
||||
|
||||
private enum ValueChanged
|
||||
{
|
||||
X = 0,
|
||||
Y = 1,
|
||||
Z = 2
|
||||
}
|
||||
/// <summary>
|
||||
/// Whether to use the average for sliding different values.
|
||||
/// </summary>
|
||||
public virtual bool AllowSlidingForDifferentValues => true;
|
||||
|
||||
private ValueChanged _valueChanged;
|
||||
private float _defaultSlidingSpeed;
|
||||
private bool _slidingEnded = false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
@@ -83,19 +104,32 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
XElement.SetLimits(limit);
|
||||
XElement.SetCategory(category);
|
||||
XElement.ValueBox.ValueChanged += OnXValueChanged;
|
||||
XElement.ValueBox.SlidingEnd += ClearToken;
|
||||
XElement.ValueBox.SlidingEnd += () =>
|
||||
{
|
||||
_slidingEnded = true;
|
||||
ClearToken();
|
||||
};
|
||||
_defaultSlidingSpeed = XElement.ValueBox.SlideSpeed;
|
||||
|
||||
YElement = grid.FloatValue();
|
||||
YElement.SetLimits(limit);
|
||||
YElement.SetCategory(category);
|
||||
YElement.ValueBox.ValueChanged += OnYValueChanged;
|
||||
YElement.ValueBox.SlidingEnd += ClearToken;
|
||||
YElement.ValueBox.SlidingEnd += () =>
|
||||
{
|
||||
_slidingEnded = true;
|
||||
ClearToken();
|
||||
};
|
||||
|
||||
ZElement = grid.FloatValue();
|
||||
ZElement.SetLimits(limit);
|
||||
ZElement.SetCategory(category);
|
||||
ZElement.ValueBox.ValueChanged += OnZValueChanged;
|
||||
ZElement.ValueBox.SlidingEnd += ClearToken;
|
||||
ZElement.ValueBox.SlidingEnd += () =>
|
||||
{
|
||||
_slidingEnded = true;
|
||||
ClearToken();
|
||||
};
|
||||
|
||||
if (LinkedLabel != null)
|
||||
{
|
||||
@@ -118,8 +152,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
if (LinkValues)
|
||||
_valueChanged = ValueChanged.X;
|
||||
_valueChanged = ValueChanged.X;
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
@@ -127,8 +160,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
if (LinkValues)
|
||||
_valueChanged = ValueChanged.Y;
|
||||
_valueChanged = ValueChanged.Y;
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
@@ -136,8 +168,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
if (LinkValues)
|
||||
_valueChanged = ValueChanged.Z;
|
||||
_valueChanged = ValueChanged.Z;
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
@@ -191,14 +222,121 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding;
|
||||
var token = isSliding ? this : null;
|
||||
var value = new Float3(xValue, yValue, zValue);
|
||||
object v = Values[0];
|
||||
if (v is Vector3)
|
||||
v = (Vector3)value;
|
||||
else if (v is Float3)
|
||||
v = (Float3)value;
|
||||
else if (v is Double3)
|
||||
v = (Double3)value;
|
||||
SetValue(v, token);
|
||||
if (HasDifferentValues && Values.Count > 1)
|
||||
{
|
||||
var newObjects = new object[Values.Count];
|
||||
// Handle Sliding
|
||||
if (AllowSlidingForDifferentValues && (isSliding || _slidingEnded))
|
||||
{
|
||||
// TODO: handle linked values
|
||||
Float3 average = Float3.Zero;
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
var v = Values[i];
|
||||
var castedValue = Float3.Zero;
|
||||
if (v is Vector3 asVector3)
|
||||
castedValue = asVector3;
|
||||
else if (v is Float3 asFloat3)
|
||||
castedValue = asFloat3;
|
||||
else if (v is Double3 asDouble3)
|
||||
castedValue = asDouble3;
|
||||
|
||||
average += castedValue;
|
||||
}
|
||||
|
||||
average /= Values.Count;
|
||||
|
||||
var newValue = value - average;
|
||||
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
var v = Values[i];
|
||||
switch (_valueChanged)
|
||||
{
|
||||
case ValueChanged.X:
|
||||
if (v is Vector3 asVector3)
|
||||
v = asVector3 + new Vector3(newValue.X, 0, 0);
|
||||
else if (v is Float3 asFloat3)
|
||||
v = asFloat3 + new Float3(newValue.X, 0, 0);
|
||||
else if (v is Double3 asDouble3)
|
||||
v = asDouble3 + new Double3(newValue.X, 0, 0);
|
||||
break;
|
||||
case ValueChanged.Y:
|
||||
if (v is Vector3 asVector3y)
|
||||
v = asVector3y + new Vector3(0, newValue.Y, 0);
|
||||
else if (v is Float3 asFloat3y)
|
||||
v = asFloat3y + new Float3(0, newValue.Y, 0);
|
||||
else if (v is Double3 asDouble3y)
|
||||
v = asDouble3y + new Double3(0, newValue.Y, 0);
|
||||
break;
|
||||
case ValueChanged.Z:
|
||||
if (v is Vector3 asVector3z)
|
||||
v = asVector3z + new Vector3(0, 0, newValue.Z);
|
||||
else if (v is Float3 asFloat3z)
|
||||
v = asFloat3z + new Float3(0, 0, newValue.Z);
|
||||
else if (v is Double3 asDouble3z)
|
||||
v = asDouble3z + new Double3(0, 0, newValue.Z);
|
||||
break;
|
||||
}
|
||||
|
||||
newObjects[i] = v;
|
||||
}
|
||||
|
||||
// Capture last sliding value
|
||||
if (_slidingEnded)
|
||||
_slidingEnded = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: handle linked values
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
object v = Values[i];
|
||||
switch (_valueChanged)
|
||||
{
|
||||
case ValueChanged.X:
|
||||
if (v is Vector3 vx3)
|
||||
v = new Vector3(xValue, vx3.Y, vx3.Z);
|
||||
else if (v is Float3 fx3)
|
||||
v = new Float3(xValue, fx3.Y, fx3.Z);
|
||||
else if (v is Double3 dx3)
|
||||
v = new Double3(xValue, dx3.Y, dx3.Z);
|
||||
break;
|
||||
case ValueChanged.Y:
|
||||
if (v is Vector3 vy3)
|
||||
v = new Vector3(vy3.X, yValue, vy3.Z);
|
||||
else if (v is Float3 fy3)
|
||||
v = new Float3(fy3.X, yValue, fy3.Z);
|
||||
else if (v is Double3 dy3)
|
||||
v = new Double3(dy3.X, yValue, dy3.Z);
|
||||
break;
|
||||
case ValueChanged.Z:
|
||||
if (v is Vector3 vz3)
|
||||
v = new Vector3(vz3.X, vz3.Y, zValue);
|
||||
else if (v is Float3 fz3)
|
||||
v = new Float3(fz3.X, fz3.Y, zValue);
|
||||
else if (v is Double3 dz3)
|
||||
v = new Double3(dz3.X, dz3.Y, zValue);
|
||||
break;
|
||||
}
|
||||
|
||||
newObjects[i] = v;
|
||||
}
|
||||
}
|
||||
|
||||
SetValue(newObjects, token);
|
||||
}
|
||||
else
|
||||
{
|
||||
object v = Values[0];
|
||||
if (v is Vector3)
|
||||
v = (Vector3)value;
|
||||
else if (v is Float3)
|
||||
v = (Float3)value;
|
||||
else if (v is Double3)
|
||||
v = (Double3)value;
|
||||
SetValue(v, token);
|
||||
}
|
||||
}
|
||||
|
||||
private float GetRatio(float value, float initialValue)
|
||||
@@ -218,7 +356,79 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
if (HasDifferentValues)
|
||||
{
|
||||
// TODO: support different values for ValueBox<T>
|
||||
// Get which values are different
|
||||
bool xDifferent = false;
|
||||
bool yDifferent = false;
|
||||
bool zDifferent = false;
|
||||
Float3 cachedFirstValue = Float3.Zero;
|
||||
Float3 average = Float3.Zero;
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
var v = Values[i];
|
||||
var value = Float3.Zero;
|
||||
if (v is Vector3 asVector3)
|
||||
value = asVector3;
|
||||
else if (v is Float3 asFloat3)
|
||||
value = asFloat3;
|
||||
else if (v is Double3 asDouble3)
|
||||
value = asDouble3;
|
||||
|
||||
average += value;
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
cachedFirstValue = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Mathf.NearEqual(cachedFirstValue.X, value.X))
|
||||
xDifferent = true;
|
||||
if (!Mathf.NearEqual(cachedFirstValue.Y, value.Y))
|
||||
yDifferent = true;
|
||||
if (!Mathf.NearEqual(cachedFirstValue.Z, value.Z))
|
||||
zDifferent = true;
|
||||
}
|
||||
|
||||
average /= Values.Count;
|
||||
|
||||
if (!xDifferent)
|
||||
{
|
||||
XElement.ValueBox.Value = cachedFirstValue.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AllowSlidingForDifferentValues)
|
||||
XElement.ValueBox.Value = average.X;
|
||||
else
|
||||
XElement.ValueBox.SlideSpeed = 0;
|
||||
XElement.ValueBox.Text = "---";
|
||||
}
|
||||
|
||||
if (!yDifferent)
|
||||
{
|
||||
YElement.ValueBox.Value = cachedFirstValue.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AllowSlidingForDifferentValues)
|
||||
YElement.ValueBox.Value = average.Y;
|
||||
else
|
||||
YElement.ValueBox.SlideSpeed = 0;
|
||||
YElement.ValueBox.Text = "---";
|
||||
}
|
||||
|
||||
if (!zDifferent)
|
||||
{
|
||||
ZElement.ValueBox.Value = cachedFirstValue.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AllowSlidingForDifferentValues)
|
||||
ZElement.ValueBox.Value = average.Z;
|
||||
else
|
||||
ZElement.ValueBox.SlideSpeed = 0;
|
||||
ZElement.ValueBox.Text = "---";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -232,6 +442,19 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
XElement.ValueBox.Value = value.X;
|
||||
YElement.ValueBox.Value = value.Y;
|
||||
ZElement.ValueBox.Value = value.Z;
|
||||
|
||||
if (!Mathf.NearEqual(XElement.ValueBox.SlideSpeed, _defaultSlidingSpeed))
|
||||
{
|
||||
XElement.ValueBox.SlideSpeed = _defaultSlidingSpeed;
|
||||
}
|
||||
if (!Mathf.NearEqual(YElement.ValueBox.SlideSpeed, _defaultSlidingSpeed))
|
||||
{
|
||||
YElement.ValueBox.SlideSpeed = _defaultSlidingSpeed;
|
||||
}
|
||||
if (!Mathf.NearEqual(ZElement.ValueBox.SlideSpeed, _defaultSlidingSpeed))
|
||||
{
|
||||
ZElement.ValueBox.SlideSpeed = _defaultSlidingSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,6 +482,15 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DisplayStyle Style => DisplayStyle.Inline;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use the average for sliding different values.
|
||||
/// </summary>
|
||||
public virtual bool AllowSlidingForDifferentValues => true;
|
||||
|
||||
private ValueChanged _valueChanged;
|
||||
private float _defaultSlidingSpeed;
|
||||
private bool _slidingEnded = false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
@@ -284,20 +516,33 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
XElement = grid.DoubleValue();
|
||||
XElement.SetLimits(limit);
|
||||
XElement.SetCategory(category);
|
||||
XElement.ValueBox.ValueChanged += OnValueChanged;
|
||||
XElement.ValueBox.SlidingEnd += ClearToken;
|
||||
XElement.ValueBox.ValueChanged += OnXValueChanged;
|
||||
XElement.ValueBox.SlidingEnd += () =>
|
||||
{
|
||||
_slidingEnded = true;
|
||||
ClearToken();
|
||||
};
|
||||
_defaultSlidingSpeed = XElement.ValueBox.SlideSpeed;
|
||||
|
||||
YElement = grid.DoubleValue();
|
||||
YElement.SetLimits(limit);
|
||||
YElement.SetCategory(category);
|
||||
YElement.ValueBox.ValueChanged += OnValueChanged;
|
||||
YElement.ValueBox.SlidingEnd += ClearToken;
|
||||
YElement.ValueBox.ValueChanged += OnYValueChanged;
|
||||
YElement.ValueBox.SlidingEnd += () =>
|
||||
{
|
||||
_slidingEnded = true;
|
||||
ClearToken();
|
||||
};
|
||||
|
||||
ZElement = grid.DoubleValue();
|
||||
ZElement.SetLimits(limit);
|
||||
ZElement.SetCategory(category);
|
||||
ZElement.ValueBox.ValueChanged += OnValueChanged;
|
||||
ZElement.ValueBox.SlidingEnd += ClearToken;
|
||||
ZElement.ValueBox.ValueChanged += OnZValueChanged;
|
||||
ZElement.ValueBox.SlidingEnd += () =>
|
||||
{
|
||||
_slidingEnded = true;
|
||||
ClearToken();
|
||||
};
|
||||
|
||||
if (LinkedLabel != null)
|
||||
{
|
||||
@@ -316,32 +561,239 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
}
|
||||
|
||||
private void OnXValueChanged()
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
_valueChanged = ValueChanged.X;
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
private void OnYValueChanged()
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
_valueChanged = ValueChanged.Y;
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
private void OnZValueChanged()
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
_valueChanged = ValueChanged.Z;
|
||||
OnValueChanged();
|
||||
}
|
||||
|
||||
private void OnValueChanged()
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
|
||||
var xValue = XElement.ValueBox.Value;
|
||||
var yValue = YElement.ValueBox.Value;
|
||||
var zValue = ZElement.ValueBox.Value;
|
||||
|
||||
var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding;
|
||||
var token = isSliding ? this : null;
|
||||
var value = new Double3(XElement.ValueBox.Value, YElement.ValueBox.Value, ZElement.ValueBox.Value);
|
||||
object v = Values[0];
|
||||
if (v is Vector3)
|
||||
v = (Vector3)value;
|
||||
else if (v is Float3)
|
||||
v = (Float3)value;
|
||||
else if (v is Double3)
|
||||
v = (Double3)value;
|
||||
SetValue(v, token);
|
||||
var value = new Double3(xValue, yValue, zValue);
|
||||
if (HasDifferentValues && Values.Count > 1)
|
||||
{
|
||||
var newObjects = new object[Values.Count];
|
||||
// Handle Sliding
|
||||
if (AllowSlidingForDifferentValues && (isSliding || _slidingEnded))
|
||||
{
|
||||
// TODO: handle linked values
|
||||
Double3 average = Double3.Zero;
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
var v = Values[i];
|
||||
var castedValue = Double3.Zero;
|
||||
if (v is Vector3 asVector3)
|
||||
castedValue = asVector3;
|
||||
else if (v is Float3 asFloat3)
|
||||
castedValue = asFloat3;
|
||||
else if (v is Double3 asDouble3)
|
||||
castedValue = asDouble3;
|
||||
|
||||
average += castedValue;
|
||||
}
|
||||
|
||||
average /= Values.Count;
|
||||
|
||||
var newValue = value - average;
|
||||
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
var v = Values[i];
|
||||
switch (_valueChanged)
|
||||
{
|
||||
case ValueChanged.X:
|
||||
if (v is Vector3 asVector3)
|
||||
v = asVector3 + new Vector3(newValue.X, 0, 0);
|
||||
else if (v is Float3 asFloat3)
|
||||
v = asFloat3 + new Float3((float)newValue.X, 0, 0);
|
||||
else if (v is Double3 asDouble3)
|
||||
v = asDouble3 + new Double3(newValue.X, 0, 0);
|
||||
break;
|
||||
case ValueChanged.Y:
|
||||
if (v is Vector3 asVector3y)
|
||||
v = asVector3y + new Vector3(0, newValue.Y, 0);
|
||||
else if (v is Float3 asFloat3y)
|
||||
v = asFloat3y + new Float3(0, (float)newValue.Y, 0);
|
||||
else if (v is Double3 asDouble3y)
|
||||
v = asDouble3y + new Double3(0, newValue.Y, 0);
|
||||
break;
|
||||
case ValueChanged.Z:
|
||||
if (v is Vector3 asVector3z)
|
||||
v = asVector3z + new Vector3(0, 0, newValue.Z);
|
||||
else if (v is Float3 asFloat3z)
|
||||
v = asFloat3z + new Float3(0, 0, (float)newValue.Z);
|
||||
else if (v is Double3 asDouble3z)
|
||||
v = asDouble3z + new Double3(0, 0, newValue.Z);
|
||||
break;
|
||||
}
|
||||
|
||||
newObjects[i] = v;
|
||||
}
|
||||
|
||||
// Capture last sliding value
|
||||
if (_slidingEnded)
|
||||
_slidingEnded = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: handle linked values
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
object v = Values[i];
|
||||
switch (_valueChanged)
|
||||
{
|
||||
case ValueChanged.X:
|
||||
if (v is Vector3 vx3)
|
||||
v = new Vector3(xValue, vx3.Y, vx3.Z);
|
||||
else if (v is Float3 fx3)
|
||||
v = new Float3((float)xValue, fx3.Y, fx3.Z);
|
||||
else if (v is Double3 dx3)
|
||||
v = new Double3(xValue, dx3.Y, dx3.Z);
|
||||
break;
|
||||
case ValueChanged.Y:
|
||||
if (v is Vector3 vy3)
|
||||
v = new Vector3(vy3.X, yValue, vy3.Z);
|
||||
else if (v is Float3 fy3)
|
||||
v = new Float3(fy3.X, (float)yValue, fy3.Z);
|
||||
else if (v is Double3 dy3)
|
||||
v = new Double3(dy3.X, yValue, dy3.Z);
|
||||
break;
|
||||
case ValueChanged.Z:
|
||||
if (v is Vector3 vz3)
|
||||
v = new Vector3(vz3.X, vz3.Y, zValue);
|
||||
else if (v is Float3 fz3)
|
||||
v = new Float3(fz3.X, fz3.Y, (float)zValue);
|
||||
else if (v is Double3 dz3)
|
||||
v = new Double3(dz3.X, dz3.Y, zValue);
|
||||
break;
|
||||
}
|
||||
|
||||
newObjects[i] = v;
|
||||
}
|
||||
}
|
||||
|
||||
SetValue(newObjects, token);
|
||||
}
|
||||
else
|
||||
{
|
||||
object v = Values[0];
|
||||
if (v is Vector3)
|
||||
v = (Vector3)value;
|
||||
else if (v is Float3)
|
||||
v = (Float3)value;
|
||||
else if (v is Double3)
|
||||
v = (Double3)value;
|
||||
SetValue(v, token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
if (HasDifferentValues)
|
||||
{
|
||||
// TODO: support different values for ValueBox<T>
|
||||
// Get which values are different
|
||||
bool xDifferent = false;
|
||||
bool yDifferent = false;
|
||||
bool zDifferent = false;
|
||||
Double3 cachedFirstValue = Double3.Zero;
|
||||
Double3 average = Double3.Zero;
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
var v = Values[i];
|
||||
var value = Double3.Zero;
|
||||
if (v is Vector3 asVector3)
|
||||
value = asVector3;
|
||||
else if (v is Float3 asFloat3)
|
||||
value = asFloat3;
|
||||
else if (v is Double3 asDouble3)
|
||||
value = asDouble3;
|
||||
|
||||
average += value;
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
cachedFirstValue = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Mathd.NearEqual(cachedFirstValue.X, value.X))
|
||||
xDifferent = true;
|
||||
if (!Mathd.NearEqual(cachedFirstValue.Y, value.Y))
|
||||
yDifferent = true;
|
||||
if (!Mathd.NearEqual(cachedFirstValue.Z, value.Z))
|
||||
zDifferent = true;
|
||||
}
|
||||
|
||||
average /= Values.Count;
|
||||
|
||||
if (!xDifferent)
|
||||
{
|
||||
XElement.ValueBox.Value = cachedFirstValue.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AllowSlidingForDifferentValues)
|
||||
XElement.ValueBox.Value = average.X;
|
||||
else
|
||||
XElement.ValueBox.SlideSpeed = 0;
|
||||
XElement.ValueBox.Text = "---";
|
||||
}
|
||||
|
||||
if (!yDifferent)
|
||||
{
|
||||
YElement.ValueBox.Value = cachedFirstValue.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AllowSlidingForDifferentValues)
|
||||
YElement.ValueBox.Value = average.Y;
|
||||
else
|
||||
YElement.ValueBox.SlideSpeed = 0;
|
||||
YElement.ValueBox.Text = "---";
|
||||
}
|
||||
|
||||
if (!zDifferent)
|
||||
{
|
||||
ZElement.ValueBox.Value = cachedFirstValue.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AllowSlidingForDifferentValues)
|
||||
ZElement.ValueBox.Value = average.Z;
|
||||
else
|
||||
ZElement.ValueBox.SlideSpeed = 0;
|
||||
ZElement.ValueBox.Text = "---";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -355,6 +807,19 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
XElement.ValueBox.Value = value.X;
|
||||
YElement.ValueBox.Value = value.Y;
|
||||
ZElement.ValueBox.Value = value.Z;
|
||||
|
||||
if (!Mathf.NearEqual(XElement.ValueBox.SlideSpeed, _defaultSlidingSpeed))
|
||||
{
|
||||
XElement.ValueBox.SlideSpeed = _defaultSlidingSpeed;
|
||||
}
|
||||
if (!Mathf.NearEqual(YElement.ValueBox.SlideSpeed, _defaultSlidingSpeed))
|
||||
{
|
||||
YElement.ValueBox.SlideSpeed = _defaultSlidingSpeed;
|
||||
}
|
||||
if (!Mathf.NearEqual(ZElement.ValueBox.SlideSpeed, _defaultSlidingSpeed))
|
||||
{
|
||||
ZElement.ValueBox.SlideSpeed = _defaultSlidingSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
@@ -379,10 +380,21 @@ namespace FlaxEditor.CustomEditors
|
||||
if (instanceValues.Count != Count)
|
||||
throw new ArgumentException();
|
||||
|
||||
for (int i = 0; i < Count; i++)
|
||||
if (value is IList l && l.Count == Count)
|
||||
{
|
||||
Info.SetValue(instanceValues[i], value);
|
||||
this[i] = Info.GetValue(instanceValues[i]);
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
Info.SetValue(instanceValues[i], l[i]);
|
||||
this[i] = Info.GetValue(instanceValues[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
Info.SetValue(instanceValues[i], value);
|
||||
this[i] = Info.GetValue(instanceValues[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user