636 lines
30 KiB
C#
636 lines
30 KiB
C#
#nullable enable
|
|
using System.Diagnostics;
|
|
using ImGuiNET;
|
|
using T3.Core.Operator;
|
|
using T3.Editor.Gui.MagGraph.Model;
|
|
using T3.Editor.Gui.MagGraph.States;
|
|
using T3.Editor.Gui.UiHelpers;
|
|
using T3.Editor.UiModel;
|
|
using T3.Editor.UiModel.Commands.Graph;
|
|
using T3.Editor.UiModel.Selection;
|
|
using Vector2 = System.Numerics.Vector2;
|
|
|
|
namespace T3.Editor.Gui.MagGraph.Interaction;
|
|
|
|
/// <summary>
|
|
/// Controls when and how a placeholder is shown and used to create new items / outputs etc.
|
|
/// </summary>
|
|
[HelpUiID("SymbolBrowser")]
|
|
internal sealed class PlaceholderCreation
|
|
{
|
|
internal MagGraphItem? PlaceholderItem;
|
|
|
|
internal void OpenToSplitHoveredConnections(GraphUiContext context)
|
|
{
|
|
if (context.ConnectionHovering.ConnectionHoversWhenClicked.Count == 0)
|
|
{
|
|
Log.Warning("No connections found? ");
|
|
context.StateMachine.SetState(GraphStates.Default, context);
|
|
return;
|
|
}
|
|
|
|
context.TempConnections.Clear();
|
|
|
|
context.StartMacroCommand("Insert operator");
|
|
var posOnCanvas = context.View.InverseTransformPositionFloat(ImGui.GetMousePos());
|
|
|
|
var firstHover = context.ConnectionHovering.ConnectionHoversWhenClicked[0];
|
|
var hoverConnection = firstHover.Connection;
|
|
|
|
// For composition inputs the source slot is the parent's input, not in Outputs - fall back to line 0
|
|
var outputLineIndex = hoverConnection.SourceItem.Variant == MagGraphItem.Variants.Input
|
|
? 0
|
|
: Math.Max(0, hoverConnection.SourceItem.Instance?.Outputs.IndexOf(hoverConnection.SourceOutput) ?? 0);
|
|
|
|
var styleToUse = MagGraphConnection.ConnectionStyles.Unknown;
|
|
if (hoverConnection.Style is MagGraphConnection.ConnectionStyles.BottomToTop or MagGraphConnection.ConnectionStyles.RightToLeft)
|
|
{
|
|
styleToUse = hoverConnection.Style;
|
|
}
|
|
|
|
// Add temp connection into placeholder...
|
|
var tempConnectionIn = new MagGraphConnection
|
|
{
|
|
Style = styleToUse,
|
|
SourcePos = hoverConnection.SourcePos,
|
|
SourceItem = hoverConnection.SourceItem,
|
|
SourceOutput = hoverConnection.SourceOutput,
|
|
TargetPos = default,
|
|
TargetItem = null,
|
|
OutputLineIndex = outputLineIndex,
|
|
VisibleOutputIndex = 0,
|
|
ConnectionHash = 0,
|
|
IsTemporary = true,
|
|
};
|
|
context.TempConnections.Add(tempConnectionIn);
|
|
|
|
PlaceholderItem = new MagGraphItem
|
|
{
|
|
Selectable = _placeHolderSelectable,
|
|
PosOnCanvas = posOnCanvas,
|
|
Id = PlaceHolderId,
|
|
Size = MagGraphItem.GridSize,
|
|
Variant = MagGraphItem.Variants.Placeholder,
|
|
};
|
|
|
|
context.Layout.Items[PlaceHolderId] = PlaceholderItem;
|
|
|
|
PlaceHolderUi.Open(context, PlaceholderItem,
|
|
inputFilter: firstHover.Connection.Type,
|
|
outputFilter: firstHover.Connection.Type);
|
|
|
|
PlaceHolderUi.Filter.UpdateIfNecessary(context.Selector, forceUpdate: true);
|
|
context.StateMachine.SetState(GraphStates.Placeholder, context);
|
|
}
|
|
|
|
internal void OpenOnCanvas(GraphUiContext context, Vector2 posOnCanvas, Type? inputTypeFilter = null, Type? outputTypeFilter = null,
|
|
bool onlyMultiInputs = false)
|
|
{
|
|
// Might continue a macro command started by a preceding connection drag...
|
|
context.StartOrContinueMacroCommand("Insert Operator");
|
|
|
|
PlaceholderItem = new MagGraphItem
|
|
{
|
|
Selectable = _placeHolderSelectable,
|
|
PosOnCanvas = posOnCanvas,
|
|
Id = PlaceHolderId,
|
|
Size = MagGraphItem.GridSize,
|
|
Variant = MagGraphItem.Variants.Placeholder,
|
|
};
|
|
|
|
context.Layout.Items[PlaceHolderId] = PlaceholderItem;
|
|
PlaceHolderUi.Open(context, PlaceholderItem, inputFilter: inputTypeFilter, outputFilter: outputTypeFilter, onlyMultiInputs: onlyMultiInputs);
|
|
}
|
|
|
|
internal void OpenForItemOutput(GraphUiContext context,
|
|
MagGraphItem item,
|
|
MagGraphItem.OutputLine outputLine,
|
|
MagGraphItem.Directions direction = MagGraphItem.Directions.Vertical)
|
|
{
|
|
Debug.Assert(item.OutputLines.Length > 0);
|
|
context.StartMacroCommand("Insert Operator");
|
|
|
|
var focusedItemPosOnCanvas = direction == MagGraphItem.Directions.Vertical
|
|
? item.PosOnCanvas + new Vector2(0, item.Size.Y)
|
|
: item.PosOnCanvas + new Vector2(item.Size.X, MagGraphItem.GridSize.Y * outputLine.VisibleIndex);
|
|
|
|
PlaceholderItem = new MagGraphItem
|
|
{
|
|
Selectable = _placeHolderSelectable,
|
|
PosOnCanvas = focusedItemPosOnCanvas,
|
|
Id = PlaceHolderId,
|
|
Size = MagGraphItem.GridSize,
|
|
Variant = MagGraphItem.Variants.Placeholder,
|
|
};
|
|
|
|
// Make space vertically
|
|
if (direction == MagGraphItem.Directions.Vertical)
|
|
{
|
|
// Keep for after creation because inserted node might exceed unit height and further pushing is required...
|
|
_snappedItems = MagItemMovement.CollectSnappedItems(item);
|
|
|
|
MagItemMovement
|
|
.MoveSnappedItemsVertically(context,
|
|
_snappedItems,
|
|
item.PosOnCanvas.Y + item.Size.Y - MagGraphItem.GridSize.Y / 2,
|
|
MagGraphItem.GridSize.Y);
|
|
}
|
|
else
|
|
{
|
|
// Keep for after creation because inserted node might exceed unit height and further pushing is required...
|
|
_snappedItems = MagItemMovement.CollectSnappedItems(item);
|
|
|
|
MagItemMovement
|
|
.MoveSnappedItemsHorizontally(context,
|
|
_snappedItems,
|
|
item.PosOnCanvas.X + item.Size.X - MagGraphItem.GridSize.X / 2,
|
|
MagGraphItem.GridSize.X);
|
|
}
|
|
|
|
context.Selector.Selection.Clear();
|
|
context.Layout.Items[PlaceHolderId] = PlaceholderItem;
|
|
|
|
var outputValueType = SnappedOutputValueType(outputLine, direction);
|
|
PlaceHolderUi.Open(context,
|
|
PlaceholderItem,
|
|
direction,
|
|
outputLine.Output.ValueType,
|
|
outputValueType);
|
|
|
|
_snappedSourceOutputLine = outputLine;
|
|
_snappedSourceItem = item;
|
|
_connectionOrientation = direction;
|
|
}
|
|
|
|
private static Type? SnappedOutputValueType(MagGraphItem.OutputLine outputLine, MagGraphItem.Directions direction)
|
|
{
|
|
if (outputLine.ConnectionsOut.Count == 0)
|
|
return null;
|
|
|
|
foreach (var c in outputLine.ConnectionsOut)
|
|
{
|
|
if (direction == MagGraphItem.Directions.Vertical)
|
|
{
|
|
if (c.Style == MagGraphConnection.ConnectionStyles.MainOutToMainInSnappedVertical)
|
|
return c.SourceOutput.ValueType;
|
|
}
|
|
else
|
|
{
|
|
if (c.Style == MagGraphConnection.ConnectionStyles.MainOutToInputSnappedHorizontal
|
|
|| c.Style == MagGraphConnection.ConnectionStyles.MainOutToMainInSnappedHorizontal)
|
|
{
|
|
return c.SourceOutput.ValueType;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
internal void OpenForItemInput(GraphUiContext context,
|
|
MagGraphItem targetItem,
|
|
Guid selectedInputId,
|
|
MagGraphItem.Directions direction)
|
|
{
|
|
Debug.Assert(targetItem.Instance != null);
|
|
|
|
var input = targetItem.Instance.Inputs.FirstOrDefault(i => i.Id == selectedInputId);
|
|
if (input == null)
|
|
return;
|
|
|
|
context.StartMacroCommand("Insert Operator");
|
|
|
|
|
|
int insertionLineIndex;
|
|
Vector2 focusedItemPosOnCanvas;
|
|
|
|
var shouldPushDown = false;
|
|
|
|
if (direction == MagGraphItem.Directions.Horizontal)
|
|
{
|
|
// Find insertion index
|
|
var visibleInputLines = targetItem.InputLines;
|
|
var allInputSlots = targetItem.Instance.Inputs;
|
|
|
|
insertionLineIndex = InputPicking.GetInsertionLineIndex(allInputSlots, visibleInputLines, selectedInputId, out shouldPushDown);
|
|
focusedItemPosOnCanvas = targetItem.PosOnCanvas + new Vector2(-targetItem.Size.X, MagGraphItem.GridSize.Y * insertionLineIndex);
|
|
}
|
|
else
|
|
{
|
|
insertionLineIndex = 0;
|
|
focusedItemPosOnCanvas = targetItem.PosOnCanvas + new Vector2(0, -MagGraphItem.GridSize.Y);
|
|
}
|
|
|
|
|
|
PlaceholderItem = new MagGraphItem
|
|
{
|
|
Selectable = _placeHolderSelectable,
|
|
PosOnCanvas = focusedItemPosOnCanvas,
|
|
Id = PlaceHolderId,
|
|
Size = MagGraphItem.GridSize,
|
|
Variant = MagGraphItem.Variants.Placeholder,
|
|
};
|
|
|
|
_snappedTargetItem = targetItem;
|
|
_snappedTargetInputId = selectedInputId;
|
|
|
|
// Keep for after creation because inserted node might exceed unit height and further pushing is required...
|
|
_snappedItems = MagItemMovement.CollectSnappedItems(targetItem, includeRoot: false);
|
|
|
|
if (shouldPushDown)
|
|
{
|
|
MagItemMovement
|
|
.MoveSnappedItemsVertically(context,
|
|
_snappedItems,
|
|
targetItem.PosOnCanvas.Y + (insertionLineIndex - 0.5f) * MagGraphItem.GridSize.Y,
|
|
MagGraphItem.GridSize.Y);
|
|
}
|
|
|
|
context.Selector.Selection.Clear();
|
|
context.Layout.Items[PlaceHolderId] = PlaceholderItem;
|
|
|
|
context.TempConnections.Add(new MagGraphConnection
|
|
{
|
|
Style = direction == MagGraphItem.Directions.Vertical ? MagGraphConnection.ConnectionStyles.MainOutToMainInSnappedVertical : MagGraphConnection.ConnectionStyles.Unknown,
|
|
SourcePos = default,
|
|
SourceOutput = null,
|
|
SourceItem = PlaceholderItem,
|
|
TargetPos = default,
|
|
TargetItem = targetItem,
|
|
InputLineIndex = insertionLineIndex,
|
|
MultiInputIndex = 0,
|
|
OutputLineIndex = 0,
|
|
VisibleOutputIndex = 0,
|
|
ConnectionHash = 0,
|
|
IsTemporary = true,
|
|
});
|
|
|
|
context.DisconnectedInputHashes.Add(MagGraphConnection.GetItemInputHash(targetItem.Id, selectedInputId,
|
|
0)); // keep input visible until state is complete
|
|
context.Layout.FlagStructureAsChanged();
|
|
|
|
PlaceHolderUi.Open(context,
|
|
PlaceholderItem,
|
|
direction,
|
|
null,
|
|
input.ValueType);
|
|
|
|
//_snappedSourceOutputLine = null;//outputLine;
|
|
//_snappedSourceItem = null;
|
|
_connectionOrientation = direction;
|
|
|
|
}
|
|
|
|
internal void Cancel(GraphUiContext context)
|
|
{
|
|
if (context.MacroCommand != null)
|
|
context.CancelMacroCommand();
|
|
|
|
if (_snappedSourceItem != null)
|
|
{
|
|
context.Selector.SetSelection(_snappedSourceItem.Selectable, _snappedSourceItem.Instance);
|
|
}
|
|
|
|
Reset(context);
|
|
}
|
|
|
|
internal void Reset(GraphUiContext context)
|
|
{
|
|
if (context.MacroCommand != null)
|
|
{
|
|
Log.Debug("cancelling placeholder command... " + context.MacroCommand);
|
|
context.CancelMacroCommand();
|
|
}
|
|
|
|
_snappedSourceItem = null;
|
|
_snappedTargetItem = null;
|
|
_snappedTargetInputId = Guid.Empty;
|
|
context.DisconnectedInputHashes.Clear();
|
|
context.Layout.FlagStructureAsChanged();
|
|
context.ConnectionHovering.ConnectionHoversWhenClicked.Clear();
|
|
context.TempConnections.Clear();
|
|
|
|
PlaceHolderUi.Reset();
|
|
|
|
if (PlaceholderItem == null)
|
|
return;
|
|
|
|
context.Layout.Items.Remove(PlaceHolderId);
|
|
PlaceholderItem = null;
|
|
|
|
DrawUtils.RestoreImGuiKeyboardNavigation();
|
|
}
|
|
|
|
internal void Update(GraphUiContext context)
|
|
{
|
|
var uiResult = PlaceHolderUi.Draw(context, out var selectedUi);
|
|
if (uiResult.HasFlag(PlaceHolderUi.UiResults.Create) && selectedUi != null)
|
|
{
|
|
CreateInstance(context, selectedUi.Symbol);
|
|
}
|
|
else if (uiResult.HasFlag(PlaceHolderUi.UiResults.Cancel))
|
|
{
|
|
Cancel(context);
|
|
}
|
|
}
|
|
|
|
private void CreateInstance(GraphUiContext context, Symbol symbol)
|
|
{
|
|
if (context.MacroCommand == null || PlaceholderItem == null)
|
|
{
|
|
Log.Warning("Macro command missing for insertion");
|
|
return;
|
|
}
|
|
|
|
var parentSymbol = context.CompositionInstance.Symbol;
|
|
var parentSymbolUi = parentSymbol.GetSymbolUi();
|
|
|
|
var addSymbolChildCommand = new AddSymbolChildCommand(parentSymbol, symbol.Id) { PosOnCanvas = PlaceholderItem.PosOnCanvas };
|
|
context.MacroCommand.AddAndExecCommand(addSymbolChildCommand);
|
|
|
|
// Get created node
|
|
if (!parentSymbolUi.ChildUis.TryGetValue(addSymbolChildCommand.AddedChildId, out var newChildUi))
|
|
{
|
|
Log.Warning($"Unable to create new operator - failed to retrieve new child ui \"{addSymbolChildCommand.AddedChildId}\" " +
|
|
$"from parent symbol ui {parentSymbolUi.Symbol}");
|
|
return;
|
|
}
|
|
|
|
var newSymbolChild = newChildUi.SymbolChild;
|
|
|
|
Instance newInstance;
|
|
try
|
|
{
|
|
newInstance = context.CompositionInstance.Children[newChildUi.Id];
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
// This can happen if compilation of instance failed (e.g. because there is syntax error in the
|
|
// operator's c# code. Failing gracefully here will reveal these compilation errors in the console log.
|
|
Log.Error($"Failed to access newly created symbol child {newChildUi.Id} {e.Message}");
|
|
return;
|
|
}
|
|
|
|
|
|
//var newInstance = context.CompositionInstance.Children[newChildUi.Id];
|
|
context.Selector.SetSelection(newChildUi, newInstance);
|
|
|
|
// Connect to focus node...
|
|
if (_snappedSourceItem != null)
|
|
{
|
|
if (newInstance.Inputs.Count > 0)
|
|
{
|
|
if (_snappedSourceOutputLine.ConnectionsOut.Count > 0)
|
|
{
|
|
var newItemOutput = newInstance.Outputs[0];
|
|
|
|
// Reroute original connections...
|
|
foreach (var mc in _snappedSourceOutputLine.ConnectionsOut)
|
|
{
|
|
if (newItemOutput.ValueType != mc.Type)
|
|
{
|
|
Log.Warning("Skipping mismatched connection type");
|
|
continue;
|
|
}
|
|
|
|
var splitVertically = _connectionOrientation == MagGraphItem.Directions.Vertical
|
|
&& mc.Style == MagGraphConnection.ConnectionStyles.BottomToTop;
|
|
|
|
var splitHorizontal = _connectionOrientation == MagGraphItem.Directions.Horizontal
|
|
&& mc.Style == MagGraphConnection.ConnectionStyles.RightToLeft;
|
|
|
|
if (!splitVertically && !splitHorizontal)
|
|
continue;
|
|
|
|
context.MacroCommand
|
|
.AddAndExecCommand(new DeleteConnectionCommand(context.CompositionInstance.Symbol,
|
|
mc.AsSymbolConnection(),
|
|
mc.MultiInputIndex));
|
|
|
|
context.MacroCommand
|
|
.AddAndExecCommand(new AddConnectionCommand(context.CompositionInstance.Symbol,
|
|
new Symbol.Connection(newInstance.SymbolChildId,
|
|
newItemOutput.Id,
|
|
mc.TargetParentOrChildId,
|
|
mc.TargetInput.Id
|
|
),
|
|
mc.MultiInputIndex));
|
|
}
|
|
}
|
|
|
|
// Create new Connection
|
|
// Find first input with matching type
|
|
var outputType = _snappedSourceOutputLine.Output.ValueType;
|
|
var matchingInputSlot = newInstance.Inputs.FirstOrDefault(i => i.ValueType == outputType);
|
|
if (matchingInputSlot == null)
|
|
{
|
|
Log.Debug($"Can't find input with type {outputType}");
|
|
}
|
|
else if (matchingInputSlot.ValueType != outputType)
|
|
{
|
|
Log.Warning("Skipping connection with mismatching types");
|
|
}
|
|
else
|
|
{
|
|
var sourceId = _snappedSourceItem.Variant == MagGraphItem.Variants.Input ? Guid.Empty : _snappedSourceItem.Id;
|
|
var sourceOutputId = _snappedSourceItem.Variant == MagGraphItem.Variants.Input ? _snappedSourceItem.Id : _snappedSourceOutputLine.Id;
|
|
context.MacroCommand
|
|
.AddAndExecCommand(new AddConnectionCommand(context.CompositionInstance.Symbol,
|
|
new Symbol.Connection(sourceId,
|
|
sourceOutputId,
|
|
newInstance.SymbolChildId,
|
|
matchingInputSlot.Id
|
|
),
|
|
0));
|
|
}
|
|
}
|
|
|
|
// Push snapped ops further down if new op exceed initial default height
|
|
{
|
|
var newHeight = ComputeNewItemUnitsHeight(context, symbol, newChildUi, newInstance);
|
|
if (newHeight > 1)
|
|
{
|
|
MagItemMovement
|
|
.MoveSnappedItemsVertically(context,
|
|
_snappedItems,
|
|
_snappedSourceItem.PosOnCanvas.Y + _snappedSourceItem.Size.Y - MagGraphItem.GridSize.Y / 2,
|
|
MagGraphItem.GridSize.Y * (newHeight - 1));
|
|
}
|
|
}
|
|
}
|
|
else if (_snappedTargetItem != null)
|
|
{
|
|
var inputLine = _snappedTargetItem.InputLines.FirstOrDefault(i => i.Id == _snappedTargetInputId);
|
|
|
|
var getMatchingOutput = newInstance.Outputs.FirstOrDefault(o2 => o2.ValueType == inputLine.Type);
|
|
if (getMatchingOutput == null)
|
|
{
|
|
Log.Warning("Can't find input?");
|
|
return;
|
|
}
|
|
|
|
//var newItemOutput = newInstance.Outputs[0];
|
|
context.MacroCommand
|
|
.AddAndExecCommand(new AddConnectionCommand(context.CompositionInstance.Symbol,
|
|
new Symbol.Connection(newInstance.SymbolChildId,
|
|
getMatchingOutput.Id,
|
|
_snappedTargetItem.Id,
|
|
_snappedTargetInputId
|
|
),
|
|
0));
|
|
var newHeight = ComputeNewItemUnitsHeight(context, symbol, newChildUi, newInstance);
|
|
if (newHeight > 1)
|
|
{
|
|
MagItemMovement
|
|
.MoveSnappedItemsVertically(context,
|
|
_snappedItems,
|
|
newChildUi.PosOnCanvas.Y + MagGraphItem.GridSize.Y / 2,
|
|
MagGraphItem.GridSize.Y * (newHeight - 1));
|
|
}
|
|
}
|
|
else if (context.TempConnections.Count <= 1 && context.TryGetActiveOutputLine(out _))
|
|
{
|
|
var primaryInput = newInstance.Inputs.FirstOrDefault(i => i.ValueType == context.DraggedPrimaryOutputType);
|
|
if (primaryInput != null)
|
|
{
|
|
var connectionToAdd = new Symbol.Connection(context.ActiveSourceItem!.Id,
|
|
context.ActiveSourceOutputId,
|
|
newInstance.SymbolChildId,
|
|
primaryInput.Id);
|
|
|
|
context.MacroCommand
|
|
.AddAndExecCommand(new AddConnectionCommand(context.CompositionInstance.Symbol,
|
|
connectionToAdd,
|
|
0));
|
|
}
|
|
}
|
|
// Wire connect temp connections
|
|
else if (context.TempConnections.Count > 0 || context.ConnectionHovering.ConnectionHoversWhenClicked.Count > 0)
|
|
{
|
|
foreach (var h in context.ConnectionHovering.ConnectionHoversWhenClicked)
|
|
{
|
|
// Remove current connections
|
|
context.MacroCommand
|
|
.AddAndExecCommand
|
|
(new DeleteConnectionCommand(context.CompositionInstance.Symbol,
|
|
h.Connection.AsSymbolConnection(),
|
|
h.Connection.MultiInputIndex
|
|
));
|
|
|
|
var tempConnectionOut = new MagGraphConnection
|
|
{
|
|
Style = MagGraphConnection.ConnectionStyles.Unknown,
|
|
SourcePos = default,
|
|
SourceOutput = null,
|
|
SourceItem = null,
|
|
TargetPos = default,
|
|
TargetItem = h.Connection.TargetItem,
|
|
InputLineIndex = h.Connection.InputLineIndex,
|
|
MultiInputIndex = h.Connection.MultiInputIndex,
|
|
OutputLineIndex = 0,
|
|
VisibleOutputIndex = 0,
|
|
ConnectionHash = 0,
|
|
IsTemporary = true,
|
|
};
|
|
|
|
context.TempConnections.Add(tempConnectionOut);
|
|
}
|
|
|
|
foreach (var tc in context.TempConnections)
|
|
{
|
|
if (!tc.IsTemporary)
|
|
continue;
|
|
|
|
if (tc.SourceItem != null && tc.TargetItem == null)
|
|
{
|
|
var tcSourceOutput = tc.SourceOutput;
|
|
var matchingInput = newInstance.Inputs.FirstOrDefault(i => i.ValueType == tcSourceOutput.ValueType);
|
|
if (matchingInput != null)
|
|
{
|
|
var connectionToAdd = new Symbol.Connection(tc.SourceParentOrChildId,
|
|
tcSourceOutput.Id,
|
|
newInstance.SymbolChildId,
|
|
matchingInput.Id);
|
|
context.MacroCommand
|
|
.AddAndExecCommand(new AddConnectionCommand(context.CompositionInstance.Symbol,
|
|
connectionToAdd,
|
|
tc.MultiInputIndex));
|
|
}
|
|
}
|
|
else if (tc.SourceItem == null && tc.TargetItem != null)
|
|
{
|
|
var matchingOutput = newInstance.Outputs.FirstOrDefault(o => o.ValueType == tc.Type);
|
|
if (matchingOutput != null)
|
|
{
|
|
var connectionToAdd = new Symbol.Connection(newInstance.SymbolChildId,
|
|
matchingOutput.Id,
|
|
tc.TargetParentOrChildId,
|
|
tc.TargetInput.Id);
|
|
context.MacroCommand
|
|
.AddAndExecCommand(new AddConnectionCommand(context.CompositionInstance.Symbol,
|
|
connectionToAdd,
|
|
tc.MultiInputIndex));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: add preset selection...
|
|
|
|
ParameterPopUp.NodeIdRequestedForParameterWindowActivation = newSymbolChild.Id;
|
|
context.Layout.FlagStructureAsChanged();
|
|
|
|
Complete(context);
|
|
}
|
|
|
|
private static int ComputeNewItemUnitsHeight(GraphUiContext context, Symbol symbol, SymbolUi.Child newChildUi,
|
|
Instance newInstance)
|
|
{
|
|
var newItem = new MagGraphItem
|
|
{
|
|
Variant = MagGraphItem.Variants.Operator,
|
|
Selectable = newChildUi,
|
|
Size = default,
|
|
SymbolUi = symbol.GetSymbolUi(),
|
|
SymbolChild = newChildUi.SymbolChild,
|
|
InstancePath = newInstance.InstancePath,
|
|
|
|
};
|
|
|
|
List<MagGraphItem.InputLine> inputLines = [];
|
|
List<MagGraphItem.OutputLine> outputLines = [];
|
|
MagGraphLayout.CollectVisibleLines(context, newItem, inputLines, outputLines);
|
|
|
|
var newHeight = inputLines.Count + outputLines.Count - 1;
|
|
return newHeight;
|
|
}
|
|
|
|
private void Complete(GraphUiContext context)
|
|
{
|
|
context.CompleteMacroCommand();
|
|
Reset(context);
|
|
}
|
|
|
|
private sealed class PlaceholderSelectable : ISelectableCanvasObject
|
|
{
|
|
public Guid Id => Guid.Empty;
|
|
public Vector2 PosOnCanvas { get; set; }
|
|
public Vector2 Size { get; set; }
|
|
}
|
|
|
|
private static readonly PlaceholderSelectable _placeHolderSelectable = new();
|
|
|
|
internal static Guid PlaceHolderId = Guid.Parse("ffffffff-eeee-47C7-A17F-E297672EE1F3");
|
|
|
|
/** Required For resetting selection and post creation layout changes */
|
|
private MagGraphItem? _snappedSourceItem;
|
|
|
|
/** Used when extracting inputs from parameter window */
|
|
private MagGraphItem? _snappedTargetItem;
|
|
|
|
private Guid _snappedTargetInputId;
|
|
|
|
private static MagGraphItem.Directions _connectionOrientation = MagGraphItem.Directions.Horizontal;
|
|
private MagGraphItem.OutputLine _snappedSourceOutputLine;
|
|
private HashSet<MagGraphItem> _snappedItems = [];
|
|
} |