Code/UI/Components/VectorEdit.razor
@using Sandbox.UI
@inherits Panel
@implements IEdit
@implements IGraphStyle
@namespace Nodebox.UI
<root class="@(TypeLibrary.GetType(Type).Name.ToLower())">
<div class="numeric-group" @ref=NumericGroupRef>
@for (int i = 0; i < VectorSize; i++) {
<NumericEdit Type=@BaseVectorType TooltipOverride=@($"{GetTooltipForIndex(i)} in {Tooltip}")/>
}
</div>
@if (Type == typeof(Color)) {
<div class="color-strip" Tooltip=@Tooltip @ref=ColorStripRef/>
}
</root>
@code
{
public Panel NumericGroupRef { get; protected set; }
public Panel ColorStripRef { get; protected set; }
[Change(nameof(OnValueChanged))]
public object Value { get; set; }
public object ValueImmediate => Type switch {
var x when x == typeof(Vector2) =>
new Vector2(GetValueImmediateAt<float>(0), GetValueImmediateAt<float>(1)),
var x when x == typeof(Vector3) =>
new Vector3(GetValueImmediateAt<float>(0), GetValueImmediateAt<float>(1), GetValueImmediateAt<float>(2)),
var x when x == typeof(Vector4) =>
new Vector4(GetValueImmediateAt<float>(0), GetValueImmediateAt<float>(1), GetValueImmediateAt<float>(2), GetValueImmediateAt<float>(3)),
var x when x == typeof(Vector2Int) =>
new Vector2Int(GetValueImmediateAt<int>(0), GetValueImmediateAt<int>(1)),
var x when x == typeof(Vector3Int) =>
new Vector3Int(GetValueImmediateAt<int>(0), GetValueImmediateAt<int>(1), GetValueImmediateAt<int>(2)),
var x when x == typeof(Angles) =>
new Angles(GetValueImmediateAt<float>(0), GetValueImmediateAt<float>(1), GetValueImmediateAt<float>(2)),
var x when x == typeof(Color) =>
new Color(GetValueImmediateAt<float>(0), GetValueImmediateAt<float>(1), GetValueImmediateAt<float>(2), GetValueImmediateAt<float>(3)),
var x when x == typeof(Rotation) =>
new Rotation(GetValueImmediateAt<float>(0), GetValueImmediateAt<float>(1), GetValueImmediateAt<float>(2), GetValueImmediateAt<float>(3)),
_ => throw new NotImplementedException(),
};
public void OnValueChanged(object oldValue, object newValue) {
if (newValue == null) { return; }
Assert.AreEqual(newValue.GetType(), Type, $"{newValue.GetType()} =/= {Type}");
switch (0) {
case var _ when BaseVectorType == typeof(float):
foreach (var pair in PackingExtensions.UnpackAnyFloat(newValue).Enumerate()) {
SetValueAt(pair.Index, pair.Item);
}
break;
case var _ when BaseVectorType == typeof(int):
foreach (var pair in PackingExtensions.UnpackAnyInt(newValue).Enumerate()) {
SetValueAt(pair.Index, pair.Item);
}
break;
}
}
public object GetValueAt(int index) => ((NumericEdit)NumericGroupRef.Children.ElementAt(index)).Value;
public T GetValueAt<T>(int index) => (T)GetValueAt(index);
public void SetValueAt(int index, object value) {
if (!NumericGroupRef.IsValid()) { return; }
((NumericEdit)NumericGroupRef.Children.ElementAt(index)).Value = value;
}
@* public void SetValueAt<T>(int index, T value) => SetValueAt(index, value); *@
public object GetValueImmediateAt(int index) => ((NumericEdit)NumericGroupRef.Children.ElementAt(index)).ValueImmediate;
public T GetValueImmediateAt<T>(int index) => (T)GetValueImmediateAt(index);
public Type Type { get; set; }
public int VectorSize => Type switch {
var x when x == typeof(Vector2) => 2,
var x when x == typeof(Vector3) => 3,
var x when x == typeof(Vector4) => 4,
var x when x == typeof(Vector2Int) => 2,
var x when x == typeof(Vector3Int) => 3,
var x when x == typeof(Angles) => 3,
var x when x == typeof(Color) => 4,
var x when x == typeof(Rotation) => 4,
_ => throw new NotImplementedException(),
};
public Type BaseVectorType => Type switch {
var x when x == typeof(Vector2) => typeof(float),
var x when x == typeof(Vector3) => typeof(float),
var x when x == typeof(Vector4) => typeof(float),
var x when x == typeof(Vector2Int) => typeof(int),
var x when x == typeof(Vector3Int) => typeof(int),
var x when x == typeof(Angles) => typeof(float),
var x when x == typeof(Color) => typeof(float),
var x when x == typeof(Rotation) => typeof(float),
_ => throw new NotImplementedException(),
};
public string GetTooltipForIndex(int index) => index switch {
0 when Type == typeof(Vector2) || Type == typeof(Vector2Int) => "X",
1 when Type == typeof(Vector2) || Type == typeof(Vector2Int) => "Y",
0 when Type == typeof(Vector3) || Type == typeof(Vector3Int) => "X",
1 when Type == typeof(Vector3) || Type == typeof(Vector3Int) => "Y",
2 when Type == typeof(Vector3) || Type == typeof(Vector3Int) => "Z",
0 when Type == typeof(Vector4) || Type == typeof(Rotation) => "X",
1 when Type == typeof(Vector4) || Type == typeof(Rotation) => "Y",
2 when Type == typeof(Vector4) || Type == typeof(Rotation) => "Z",
3 when Type == typeof(Vector4) || Type == typeof(Rotation) => "W",
0 when Type == typeof(Angles) => "Pitch",
1 when Type == typeof(Angles) => "Yaw",
2 when Type == typeof(Angles) => "Roll",
0 when Type == typeof(Color) => "Red",
1 when Type == typeof(Color) => "Green",
2 when Type == typeof(Color) => "Blue",
3 when Type == typeof(Color) => "Alpha",
_ => throw new NotImplementedException(),
};
public static bool IsSupported(Type type) => type switch {
var x when x == typeof(Vector2) => true,
var x when x == typeof(Vector3) => true,
var x when x == typeof(Vector4) => true,
var x when x == typeof(Vector2Int) => true,
var x when x == typeof(Vector3Int) => true,
var x when x == typeof(Angles) => true,
var x when x == typeof(Color) => true,
var x when x == typeof(Rotation) => true,
_ => false,
};
protected override void OnAfterTreeRender(bool firstTime) {
if (firstTime) {
Value ??= TypeLibrary.GetType(Type).CreateDefault();
}
Tooltip = this.ConstructTooltip();
if (!firstTime) { return; }
if (NumericGroupRef.IsValid()) {
OnValueChanged(null, Value);
foreach (var child in NumericGroupRef.Children) {
var numericEdit = (NumericEdit)child;
numericEdit.AddEventListener("onchange", (ev) => {
ev.StopPropagation();
CreateEvent("onchange", ValueImmediate);
});
numericEdit.AddEventListener("onsubmit", (ev) => {
ev.StopPropagation();
Value = Type switch {
var x when x == typeof(Vector2) =>
new Vector2(GetValueAt<float>(0), GetValueAt<float>(1)),
var x when x == typeof(Vector3) =>
new Vector3(GetValueAt<float>(0), GetValueAt<float>(1), GetValueAt<float>(2)),
var x when x == typeof(Vector4) =>
new Vector4(GetValueAt<float>(0), GetValueAt<float>(1), GetValueAt<float>(2), GetValueAt<float>(3)),
var x when x == typeof(Vector2Int) =>
new Vector2Int(GetValueAt<int>(0), GetValueAt<int>(1)),
var x when x == typeof(Vector3Int) =>
new Vector3Int(GetValueAt<int>(0), GetValueAt<int>(1), GetValueAt<int>(2)),
var x when x == typeof(Angles) =>
new Angles(GetValueAt<float>(0), GetValueAt<float>(1), GetValueAt<float>(2)),
var x when x == typeof(Color) =>
new Color(GetValueAt<float>(0), GetValueAt<float>(1), GetValueAt<float>(2), GetValueAt<float>(3)),
var x when x == typeof(Rotation) =>
new Rotation(GetValueAt<float>(0), GetValueAt<float>(1), GetValueAt<float>(2), GetValueAt<float>(3)),
_ => throw new NotImplementedException(),
};
CreateEvent("onsubmit", Value);
});
@* numericEdit.AddEventListener("oncancel", (ev) => {
ev.StopPropagation();
OnValueChanged(null, Value);
CreateEvent("oncancel", Value);
}); *@
}
}
}
[PanelEvent]
protected virtual void OnChangeEvent(PanelEvent ev) {
if (ColorStripRef.IsValid()) {
var color = (Color)ValueImmediate;
ColorStripRef.Style.Set("background-color", color.ToString(true, true));
}
}
protected override int BuildHash() => System.HashCode.Combine( Type );
}