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

277 lines
12 KiB
C#

#nullable enable
using ImGuiNET;
using T3.Core.DataTypes.Vector;
using T3.Core.Operator;
using T3.Core.Utils;
using T3.Editor.Gui.Input;
using T3.Editor.Gui.OpUis;
using T3.Editor.Gui.Styling;
using T3.Editor.Gui.UiHelpers;
using T3.Editor.Gui.Windows;
using T3.Editor.Gui.Windows.Layouts;
using T3.Editor.Gui.Windows.Variations;
using T3.Editor.UiModel;
using T3.Editor.UiModel.Commands;
using T3.Editor.UiModel.Commands.Graph;
using T3.Editor.UiModel.ProjectHandling;
namespace T3.Editor.Gui;
[HelpUiID("ParameterPopup")]
internal static class ParameterPopUp
{
public static void HandleOpenParameterPopUp(SymbolUi.Child childUi, Instance instance, OpUi.CustomUiResult customUiResult, ImRect nodeScreenRect)
{
var activatedWithLeftMouse = ImGui.IsItemHovered()
&& ImGui.IsMouseReleased(ImGuiMouseButton.Left)
&& ImGui.GetMouseDragDelta(ImGuiMouseButton.Left, 0).Length() < UserSettings.Config.ClickThreshold
&& !ParameterWindow.IsAnyInstanceVisible()
&& !ImGui.GetIO().KeyShift; // allow double click to open
var activatedWithMiddleMouse = ImGui.IsItemHovered()
&& ImGui.IsMouseReleased(ImGuiMouseButton.Middle)
&& ImGui.GetMouseDragDelta(ImGuiMouseButton.Middle, 0).Length() < UserSettings.Config.ClickThreshold;
var activationRequested = NodeIdRequestedForParameterWindowActivation == instance.SymbolChildId
&& !ParameterWindow.IsAnyInstanceVisible();
if ((activatedWithLeftMouse || activatedWithMiddleMouse || activationRequested)
&& (customUiResult & OpUi.CustomUiResult.PreventOpenParameterPopUp) == 0
)
{
Open(instance);
}
}
public static void Open(Instance instance)
{
_selectedInstance = instance;
NodeIdRequestedForParameterWindowActivation = Guid.Empty;
_isOpen = true;
_lastRequiredHeight = 0;
_focusDelayCount = 3;
}
private static Vector2 DefaultWindowSize => new Vector2(310, 250) * T3Ui.UiScaleFactor;
private static void Close()
{
_isOpen = false;
}
public static void DrawParameterPopUp(ProjectView graphWindow)
{
if (!_isOpen || _selectedInstance == null || graphWindow.CompositionInstance == null)
return;
var symbolUi = _selectedInstance.GetSymbolUi();
var compositionSymbolUi = graphWindow.CompositionInstance.GetSymbolUi();
if (!compositionSymbolUi.ChildUis.TryGetValue(_selectedInstance.SymbolChildId, out var symbolChildUi))
{
Close();
return;
}
if (!graphWindow.NodeSelection.IsAnythingSelected())
{
Close();
return;
}
var nodeScreenRect = graphWindow.GraphView.Canvas.TransformRect(ImRect.RectWithSize(symbolChildUi.PosOnCanvas, symbolChildUi.Size));
var horizontalOffset = 25 * graphWindow.GraphView.Canvas.Scale.X;
var screenPos = new Vector2(nodeScreenRect.Min.X + horizontalOffset, nodeScreenRect.Max.Y + 5);
var height = _lastRequiredHeight.Clamp(MinHeight, DefaultWindowSize.Y);
ImGui.SetNextWindowPos(screenPos);
var preventTabbingIntoUnfocusedStringInputs = ImGui.IsAnyItemActive() ? ImGuiWindowFlags.None : ImGuiWindowFlags.NoNavInputs;
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.One * 2);
ImGui.PushStyleVar(ImGuiStyleVar.ChildBorderSize, 2);
ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, 4);
if (ImGui.BeginChild("Popup",
new Vector2(DefaultWindowSize.X, height),
ImGuiChildFlags.Borders,
preventTabbingIntoUnfocusedStringInputs
| ImGuiWindowFlags.NoScrollWithMouse
| ImGuiWindowFlags.NoScrollbar))
{
if (ImGui.IsKeyDown(ImGuiKey.Escape))
{
Close();
}
FrameStats.Current.OpenedPopUpName = ParameterPopUpName;
ImGui.GetWindowDrawList().AddRectFilled(ImGui.GetWindowPos(),
ImGui.GetWindowPos() + ImGui.GetWindowSize(),
UiColors.BackgroundFull);
FormInputs.SetIndent(20);
if (_focusDelayCount >= 0)
{
ImGui.SetWindowFocus();
_focusDelayCount--;
}
else if (!ImGui.IsWindowFocused(ImGuiFocusedFlags.ChildWindows))
{
Close();
}
FrameStats.Current.OpenedPopupHovered = ImGui.IsItemHovered();
// Toolbar
{
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(2,4) * T3Ui.UiScaleFactor);
ImGui.PushStyleColor(ImGuiCol.Button, Color.Transparent.Rgba);
ImGui.SetCursorPos( new Vector2(5,5));
CustomComponents.AddSegmentedIconButton(ref _viewMode, _modeIcons);
ImGui.SameLine();
var spaceBetweenViewIconsAndActions = ImGui.GetContentRegionAvail().X
- 3 * (ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.X);
// Bypass
{
if (symbolChildUi.SymbolChild.IsBypassable())
{
ImGui.SameLine(0, spaceBetweenViewIconsAndActions);
var isBypassed = symbolChildUi.SymbolChild.IsBypassed;
if (CustomComponents.ToggleTwoIconsButton(ref isBypassed,
Icon.OperatorBypassOff,
Icon.OperatorBypassOn,
CustomComponents.ButtonStates.NeedsAttention,
CustomComponents.ButtonStates.Default))
{
UndoRedoStack.AddAndExecute(isBypassed
? new ChangeInstanceBypassedCommand(symbolChildUi.SymbolChild, true)
: new ChangeInstanceBypassedCommand(symbolChildUi.SymbolChild, false));
}
ImGui.SameLine();
}
}
// Disable
{
ImGui.SameLine();
var isDisabled = symbolChildUi.SymbolChild.IsDisabled;
if (CustomComponents.ToggleIconButton(ref isDisabled,
Icon.OperatorDisabled,
Vector2.Zero,
CustomComponents.ButtonStates.NeedsAttention))
{
UndoRedoStack.AddAndExecute(isDisabled
? new ChangeInstanceIsDisabledCommand(symbolChildUi, true)
: new ChangeInstanceIsDisabledCommand(symbolChildUi, false));
}
}
// Pin to background
{
ImGui.SameLine();
var isPinned = _selectedInstance == graphWindow.GraphImageBackground.OutputInstance;
if (CustomComponents.ToggleIconButton(ref isPinned, Icon.PlayOutput, Vector2.Zero))
{
if (isPinned)
graphWindow.SetBackgroundOutput(_selectedInstance);
}
}
ImGui.PopStyleVar();
ImGui.PopStyleColor();
}
// Content
switch (_viewMode)
{
case ViewModes.Parameters:
ImGui.BeginChild("Scrolling", new Vector2(DefaultWindowSize.X, height - 20 ), ImGuiChildFlags.None);
CustomComponents.HandleDragScrolling(_parameterPopUpReference);
ImGui.PushFont(Fonts.FontSmall);
ParameterWindow.DrawParameters(_selectedInstance, symbolUi, symbolChildUi, compositionSymbolUi, hideNonEssentials: true);
FormInputs.AddVerticalSpace();
ImGui.PopFont();
_lastRequiredHeight = ImGui.GetCursorPosY() + ImGui.GetFrameHeight() + 0;
ImGui.Dummy(new Vector2(10,10));
ImGui.EndChild();
break;
case ViewModes.Presets:
var allWindows = WindowManager.GetAllWindows();
foreach (var w in allWindows)
{
if (w is not VariationsWindow variationsWindow)
continue;
ImGui.BeginChild("Scrolling", DefaultWindowSize, ImGuiChildFlags.None,
ImGuiWindowFlags.NoScrollWithMouse|
ImGuiWindowFlags.NoScrollbar |
ImGuiWindowFlags.NoBackground);
variationsWindow.DrawWindowContent(hideHeader: true);
_lastRequiredHeight = DefaultWindowSize.Y;
ImGui.GetWindowDrawList().AddRect(ImGui.GetWindowPos()+ Vector2.One, ImGui.GetWindowPos() + ImGui.GetWindowSize() - new Vector2(2,27), UiColors.WindowBackground);
ImGui.EndChild();
break;
}
break;
case ViewModes.Help:
ImGui.BeginChild("Scrolling",
new Vector2(DefaultWindowSize.X,
height),
ImGuiChildFlags.None,
ImGuiWindowFlags.NoBackground
);
FormInputs.AddVerticalSpace();
OperatorHelp.DrawHelp(symbolUi);
FormInputs.AddVerticalSpace();
_lastRequiredHeight = ImGui.GetCursorPosY() + ImGui.GetFrameHeight();
// Draw a small border to separate from graph
ImGui.GetWindowDrawList().AddRect(ImGui.GetWindowPos()+ Vector2.One, ImGui.GetWindowPos() + ImGui.GetWindowSize() - new Vector2(2,2), UiColors.WindowBackground);
ImGui.EndChild();
break;
default:
throw new ArgumentOutOfRangeException();
}
//
}
ImGui.EndChild();
ImGui.PopStyleVar(3);
}
private enum ViewModes
{
Parameters,
Presets,
Help,
}
private static readonly List<Icon> _modeIcons = new()
{
Icon.ViewList,
Icon.Presets,
Icon.HelpOutline
};
private static float _lastRequiredHeight;
private const float MaxHeight = 280;
private const float MinHeight = 50;
private static bool _isOpen;
private static int _focusDelayCount;
private static object _parameterPopUpReference = new();
private static ViewModes _viewMode = ViewModes.Parameters;
private static Instance? _selectedInstance;
private const string ParameterPopUpName = "parameterContextPopup";
public static Guid NodeIdRequestedForParameterWindowActivation;
}