Files
2026-07-13 13:13:17 +08:00

239 lines
8.9 KiB
C#

#nullable enable
using ImGuiNET;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using T3.Core.DataTypes;
using T3.Core.DataTypes.Vector;
using T3.Core.Operator;
using T3.Core.Operator.Slots;
using T3.Editor.Gui.Interaction;
using T3.Core.Utils;
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 sealed class Vector2InputUi : FloatVectorInputValueUi<Vector2>
{
public Vector2InputUi() : base(2)
{
}
public override IInputUi Clone()
{
return CloneWithType<Vector2InputUi>();
}
protected override InputEditStateFlags DrawEditControl(string name, Symbol.Child.Input input, ref Vector2 float2Value, bool readOnly)
{
float2Value.CopyTo(FloatComponents);
var controlRatio = MathUtils.RemapAndClamp(ImGui.GetWindowWidth(), 280, 350, 1, 16f / 9);
var showControl = (controlRatio > 1f && UseVec2Control != Vec2Controls.None);
var rightPadding = showControl ? ImGui.GetFrameHeight() * controlRatio : 0;
var inputEditState = VectorValueEdit.Draw(FloatComponents, Min, Max, Scale, ClampMin, ClampMax, rightPadding , Format);
var shouldClamp = false;
if (showControl)
{
ImGui.SameLine();
ImGui.InvisibleButton("## dragging", new Vector2(rightPadding, ImGui.GetFrameHeight()));
var min = ImGui.GetItemRectMin();
var max = ImGui.GetItemRectMax();
var drawList = ImGui.GetWindowDrawList();
Color backgroundColor = ImGui.IsItemActive()
? UiColors.BackgroundActive.Fade(0.4f)
: (UiColors.BackgroundButton.Fade(ImGui.IsItemHovered() ? 1 : 0.5f));
drawList.AddRectFilled(min, max, backgroundColor);
var normalizedVec = ((float2Value - new Vector2(Min)) / (Max - Min) - new Vector2(0.5f)) * new Vector2(controlRatio,1) + new Vector2(0.5f);
var color = input == null ? UiColors.StatusAutomated
: input.IsDefault ? UiColors.TextMuted
: UiColors.ForegroundFull;
var exceedsDragCanvas = normalizedVec.X < 0 || normalizedVec.X > 1 || normalizedVec.Y < 0 || normalizedVec.Y > 1;
if (exceedsDragCanvas)
{
color = color.Fade(0.3f);
normalizedVec = new Vector2(normalizedVec.X.Clamp(0, 1), normalizedVec.Y.Clamp(0, 1));
}
var controlPointScreenPos = new Vector2(
MathUtils.Lerp(min.X, max.X, normalizedVec.X),
MathUtils.Lerp(max.Y, min.Y, normalizedVec.Y)
);
if (UseVec2Control == Vec2Controls.Position)
{
drawList.AddCircleFilled(controlPointScreenPos, 2, color);
// Center lines...
var center = (min + max) / 2;
drawList.AddLine(new Vector2(center.X, min.Y), new Vector2(center.X, max.Y), UiColors.ForegroundFull.Fade(0.06f), 1);
drawList.AddLine(new Vector2(min.X, center.Y), new Vector2(max.X, center.Y), UiColors.ForegroundFull.Fade(0.06f), 1);
}
else if (UseVec2Control == Vec2Controls.GainAndBias)
{
shouldClamp = true;
drawList.AddCircleFilled(controlPointScreenPos, 2, color);
const int steps = 15;
var points = new Vector2[steps];
// Distribution...
for(var i=0; i < steps ; i ++)
{
var t = (float)i / (steps-1);
var f = t.ApplyGainAndBias(float2Value.X, float2Value.Y);
var x = MathUtils.Lerp(min.X, max.X, f);
var y = MathUtils.Lerp(max.Y, min.Y, f);
// drawList.AddLine(new Vector2(x, min.Y), new Vector2(x, max.Y),
// UiColors.ForegroundFull.Fade(0.1f), 1);
drawList.AddLine(new Vector2(min.X, y), new
Vector2(max.X, y),
UiColors.ForegroundFull.Fade(0.1f), 1);
points[i] = new Vector2(MathUtils.Lerp(min.X, max.X, t),
MathUtils.Lerp(min.Y, max.Y, 1-f));
}
drawList.AddPolyline(ref points[0], steps, UiColors.TextMuted, ImDrawFlags.None, 1);
}
if (ImGui.IsItemActivated())
{
_valueInDragStart = float2Value;
}
if (ImGui.IsItemActive())
{
inputEditState = InputEditStateFlags.Modified;
var mouseDragDelta = ImGui.GetMouseDragDelta();
var speedFactor = 1f;
if (ImGui.GetIO().KeyShift)
{
speedFactor *= 0.1f;
}
if (ImGui.GetIO().KeyAlt)
{
speedFactor *= 10f;
}
var dx = mouseDragDelta.X * 0.005f * speedFactor;
var dy = mouseDragDelta.Y * 0.005f * speedFactor;
if (UseVec2Control != Vec2Controls.Range)
{
FloatComponents[0] = _valueInDragStart.X + dx;
FloatComponents[1] = _valueInDragStart.Y - dy;
}
else
{
var zoom = MathF.Pow(4,-dy);
var center = (_valueInDragStart.X + _valueInDragStart.Y) / 2 + dx*zoom * 0.1f;
var width = (_valueInDragStart.Y - _valueInDragStart.X) * zoom;
FloatComponents[0] = center - width/2;
FloatComponents[1] = center + width/2;
}
if (shouldClamp)
{
FloatComponents[0] = FloatComponents[0].Clamp(Min, Max);
FloatComponents[1] = FloatComponents[1].Clamp(Min, Max);
}
}
if (ImGui.IsItemActivated())
{
inputEditState |= InputEditStateFlags.Started;
}
if (ImGui.IsItemDeactivated())
{
inputEditState = InputEditStateFlags.Finished;
}
}
if (readOnly)
return InputEditStateFlags.Nothing;
float2Value = new Vector2(FloatComponents[0], FloatComponents[1]);
return inputEditState;
}
public override void ApplyValueToAnimation(IInputSlot inputSlot, InputValue inputValue, Animator animator, double time)
{
if (inputValue is not InputValue<Vector2> typedInputValue)
return;
if (!animator.TryGetCurvesForInputSlot(inputSlot, out var curves))
{
Log.Warning("Can't find Vec2 animation curves?");
return;
}
typedInputValue.Value.CopyTo(FloatComponents);
Curve.UpdateCurveValues(curves, time, FloatComponents);
}
public override bool DrawSettings()
{
var modified = base.DrawSettings();
FormInputs.DrawFieldSetHeader("Show 2D Control");
var tmpForRef = UseVec2Control;
if (FormInputs.AddEnumDropdown(ref tmpForRef, null))
{
modified = true;
UseVec2Control = tmpForRef;
}
return modified;
}
public override void Write(JsonTextWriter writer)
{
base.Write(writer);
if (UseVec2Control != Vec2Controls.None)
writer.WriteObject(nameof(UseVec2Control), UseVec2Control.ToString());
}
public override void Read(JToken? inputToken)
{
base.Read(inputToken);
// Back-compat: older files use the legacy spelling "BiasAndGain"
var controlName = inputToken?[nameof(UseVec2Control)]?.Value<string>();
UseVec2Control = controlName switch
{
"BiasAndGain" => Vec2Controls.GainAndBias,
_ when Enum.TryParse(controlName, out Vec2Controls value) => value,
_ => Vec2Controls.None,
};
}
public Vec2Controls UseVec2Control;
private static Vector2 _valueInDragStart;
public enum Vec2Controls
{
None,
Position,
GainAndBias,
Range,
}
}