项目文件夹

文件
2026-07-13 13:15:05 +08:00

344 行
11 KiB
C#

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
using ImGuiNET;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using T3.Core.Animation;
using T3.Core.Operator;
using T3.Core.Operator.Slots;
using T3.Editor.Gui.Input;
using T3.Editor.Gui.Styling;
using T3.Editor.UiModel.InputsAndTypes;
using T3.Serialization;
namespace T3.Editor.Gui.InputUi.VectorInputs;
internal abstract class FloatVectorInputValueUi<T> : InputValueUi<T>
{
protected FloatVectorInputValueUi(int componentCount)
{
FloatComponents = new float[componentCount];
}
public override bool IsAnimatable => true;
protected FloatVectorInputValueUi<T> CloneWithType<TT>() where TT : FloatVectorInputValueUi<T>, new()
{
return new TT()
{
Max = Max,
Min = Min,
_scale = _scale,
ClampMin = ClampMin,
ClampMax = ClampMax,
InputDefinition = InputDefinition,
Parent = Parent,
PosOnCanvas = PosOnCanvas,
Relevancy = Relevancy,
Size = Size,
};
}
protected override InputEditStateFlags DrawAnimatedValue(string name, InputSlot<T> inputSlot, Animator animator)
{
var time = Playback.Current.TimeInBars;
if (!animator.TryGetCurvesForInputSlot(inputSlot, out var curves)
|| curves.Length < FloatComponents.Length)
{
ImGui.PushID(inputSlot.Parent.SymbolChildId.GetHashCode() + inputSlot.Id.GetHashCode());
DrawReadOnlyControl(name, ref inputSlot.Value);
ImGui.PopID();
return InputEditStateFlags.Nothing;
}
for (var index = 0; index < FloatComponents.Length; index++)
{
FloatComponents[index] = (float)curves[index].GetSampledValue(time);
}
ImGui.PushID(inputSlot.Parent.SymbolChildId.GetHashCode() + inputSlot.Id.GetHashCode());
var inputEditState = DrawEditControl(name, inputSlot.Input, ref inputSlot.Value, false);
ImGui.PopID();
if ((inputEditState & InputEditStateFlags.Modified) == InputEditStateFlags.Modified)
{
inputSlot.SetTypedInputValue(inputSlot.Value);
}
return inputEditState;
}
protected override void DrawReadOnlyControl(string name, ref T float2Value)
{
ImGui.PushStyleColor(ImGuiCol.Text, UiColors.StatusAutomated.Rgba);
DrawEditControl(name, null!, ref float2Value, true);
ImGui.PopStyleColor();
}
protected override string GetSlotValueAsString(ref T float2Value)
{
return string.Format(T3Ui.FloatNumberFormat, float2Value);
}
public abstract override void ApplyValueToAnimation(IInputSlot inputSlot, InputValue inputValue, Animator animator, double time);
private struct ValueSettingPreset
{
public string Title;
public float Scale;
public float MinValue;
public float MaxValue;
public string CustomFormat;
public bool ClampRangeMin;
public bool ClampRangeMax;
public Vector2InputUi.Vec2Controls Vec2Control;
public float? DefaultComponentValue;
}
private ValueSettingPreset[] _valueSettingPresets =
{
new()
{
Scale = 0,
Title = "Rotation",
MinValue = -180,
MaxValue = 180,
CustomFormat = "{0:0.0}°"
},
new()
{
Scale = 0,
Title = "Translation",
MinValue = -2,
MaxValue = 2,
CustomFormat = null,
Vec2Control = Vector2InputUi.Vec2Controls.Position,
},
new()
{
Scale = 0,
Title = "Color",
MinValue = 0,
MaxValue = 1,
CustomFormat = null,
ClampRangeMin = true,
},
new()
{
Scale = 0,
Title = "Signed Scale × Factor",
MinValue = -5,
MaxValue = 5,
CustomFormat = "{0:0.000} ×",
},
new()
{
Scale = 0,
Title = "Scale × Factor",
MinValue = 0,
MaxValue = 5,
CustomFormat = "{0:0.000} ×",
},
new()
{
Scale = 0,
Title = "Gain & Bias",
MinValue = 0,
MaxValue = 1,
CustomFormat = "{0:0.000}",
ClampRangeMin = true,
ClampRangeMax = true,
Vec2Control = Vector2InputUi.Vec2Controls.GainAndBias,
DefaultComponentValue = 0.5f,
},
};
public override bool DrawSettings()
{
var modified = false;
var keepPosition = ImGui.GetCursorPos();
ImGui.SetCursorPos(new Vector2(ImGui.GetWindowSize().X - ImGui.GetFrameHeight() - ImGui.GetStyle().FramePadding.X,
0));
if (CustomComponents.IconButton(Icon.Settings2, Vector2.One * ImGui.GetFrameHeight()))
{
ImGui.OpenPopup("customFormats");
}
ImGui.SetCursorPos(keepPosition);
if (ImGui.BeginPopup("customFormats"))
{
ImGui.TextUnformatted("Apply formatting presets...");
foreach (var p in _valueSettingPresets)
{
if (!ImGui.Button(p.Title))
continue;
Min = p.MinValue;
Max = p.MaxValue;
_scale = p.Scale;
ClampMin = p.ClampRangeMin;
ClampMax = p.ClampRangeMax;
Format = p.CustomFormat;
if (this is Vector2InputUi vector2InputUi)
{
vector2InputUi.UseVec2Control = p.Vec2Control;
}
if (p.DefaultComponentValue is { } defaultComponentValue)
{
ApplyDefaultComponentValue(defaultComponentValue);
}
Parent?.FlagAsModified();
ImGui.CloseCurrentPopup();
modified = true;
}
ImGui.EndPopup();
}
modified |= base.DrawSettings();
FormInputs.DrawFieldSetHeader("Value Range");
if (FormInputs.DrawValueRangeControl(ref Min, ref Max, ref _scale, ref ClampMin, ref ClampMax, DefaultMin, DefaultMax, DefaultScale))
{
modified = true;
}
FormInputs.DrawFieldSetHeader("Custom Value format");
if (
FormInputs.AddStringInput("##valueFormat",
ref Format,
"Custom format like {0:0.0}",
null,
"Defines custom value format. Here are some examples:\n\n" +
"{0:0.00000} - High precision\n" +
"{0:0}× - With a suffix\n" +
"{0:G5} - scientific notation",
null)
)
{
modified = true;
if (string.IsNullOrWhiteSpace(Format))
{
Format = null;
}
}
return modified;
}
public override void Write(JsonTextWriter writer)
{
base.Write(writer);
// ReSharper disable CompareOfFloatsByEqualityOperator
if (Min != DefaultMin)
writer.WriteValue("Min", Min);
if (Max != DefaultMax)
writer.WriteValue("Max", Max);
if (_scale != DefaultScale)
writer.WriteValue("Scale", _scale);
if (ClampMin)
writer.WriteValue("ClampMin", ClampMin);
if (ClampMax)
writer.WriteValue("ClampMax", ClampMax);
if (!string.IsNullOrEmpty(Format))
writer.WriteObject("Format", Format);
// ReSharper enable CompareOfFloatsByEqualityOperator
}
public void CopyTo(FloatVectorInputValueUi<T> target)
{
target.Min = Min;
target.Max = Max;
target.Scale = Scale;
target.ClampMin = ClampMin;
target.ClampMax = ClampMax;
target.Format = Format;
}
public override void Read(JToken inputToken)
{
base.Read(inputToken);
if (inputToken == null)
return;
Min = inputToken["Min"]?.Value<float>() ?? DefaultMin;
Max = inputToken["Max"]?.Value<float>() ?? DefaultMax;
_scale = inputToken["Scale"]?.Value<float>() ?? DefaultScale;
var legacyClamp = inputToken["Clamp"]?.Value<bool>() ?? false;
ClampMin = (inputToken["ClampMin"]?.Value<bool>() ?? false) | legacyClamp;
ClampMax = (inputToken["ClampMax"]?.Value<bool>() ?? false) | legacyClamp;
Format = inputToken["Format"]?.Value<string>();
}
private void ApplyDefaultComponentValue(float value)
{
switch (InputDefinition.DefaultValue)
{
case InputValue<float> floatValue:
floatValue.Value = value;
break;
case InputValue<Vector2> vector2Value:
vector2Value.Value = new Vector2(value);
break;
case InputValue<Vector3> vector3Value:
vector3Value.Value = new Vector3(value);
break;
case InputValue<Vector4> vector4Value:
vector4Value.Value = new Vector4(value);
break;
default:
return;
}
Parent?.Symbol.InvalidateInputDefaultInInstances(InputDefinition.Id);
}
private static float GetScaleFromRange(float scale, float min, float max)
{
// Automatically set scale from range
if (scale > 0)
return scale;
// A lame hack because we can't set infinity values in parameter properties
if (min < -9999 || max > 9999)
{
return 0.01f;
}
return Math.Abs(min - max) / 100;
}
public float Min = DefaultMin;
public float Max = DefaultMax;
private float _scale = DefaultScale;
public float Scale {
get => FloatInputUi.GetScaleFromRange(_scale, Min, Max);
set => _scale = value;
}
//private bool Clamp;
public bool ClampMin;
public bool ClampMax;
public string Format;
protected readonly float[] FloatComponents;
private const float DefaultScale = 0.0f;
private const float DefaultMin = -9999999f;
private const float DefaultMax = 9999999f;
}