Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
7192f5216This file is pinned to the selected release. Download the original to open it in your design tool.
using System;
using System.Collections.Generic;
using Godot;
using GodotExt;
using OpenScadGraphEditor.Actions;
using OpenScadGraphEditor.Nodes;
using OpenScadGraphEditor.Refactorings;
namespace OpenScadGraphEditor.Widgets.AddDialog
{
/// <summary>
/// A dialog entry which represents a pair of bound nodes.
/// </summary>
public class BoundPairBasedEntry : IAddDialogEntry
{
private readonly Func<ScadNode> _firstNodeFactory;
private readonly Func<ScadNode> _secondNodeFactory;
private readonly IEditorContext _editorContext;
private readonly ScadNode _firstNodeTemplate;
private readonly ScadNode _secondNodeTemplate;
public string Title { get; }
public string Keywords { get; }
public Action<RequestContext> Action => OnEntrySelected;
public Texture Icon { get; }
public BoundPairBasedEntry(Texture icon, string title, string keywords,
Func<ScadNode> firstNodeFactory, Func<ScadNode> secondNodeFactory,
IEditorContext editorContext)
{
_firstNodeFactory = firstNodeFactory;
_secondNodeFactory = secondNodeFactory;
_editorContext = editorContext;
_firstNodeTemplate = firstNodeFactory();
_secondNodeTemplate = secondNodeFactory();
Icon = icon;
Title = title;
Keywords = keywords;
}
public EntryFittingDecision CanAdd(RequestContext context)
{
if (context.TryGetNodeAndPort(out var graph, out var contextNode, out var contextPort))
{
if (!graph.Description.CanUse(_firstNodeTemplate) || !graph.Description.CanUse(_secondNodeTemplate))
{
// if any of the nodes is not allowed to be used here, we can't use it
return EntryFittingDecision.Veto;
}
// if this came from a node left of us, check if we have a matching input port
if (contextPort.IsOutput)
{
if (ConnectionRules.TryGetPossibleConnection(graph, contextNode, _firstNodeTemplate, contextPort,
out _))
{
return EntryFittingDecision.Fits;
}
}
// if this came from a node right of us, check if we have a matching output port
else
{
if (ConnectionRules.TryGetPossibleConnection(graph, _secondNodeTemplate, contextNode, contextPort,
out _))
{
return EntryFittingDecision.Fits;
}
}
}
// otherwise it doesn't match, but could still be added.
return EntryFittingDecision.DoesNotFit;
}
private void OnEntrySelected(RequestContext context)
{
var hasPosition = context.TryGetPositionInGraph(out var graph, out var position);
GdAssert.That(hasPosition, "BoundPairBasedEntry can only be used in a context with a position.");
// make the new nodes
var firstNode = _firstNodeFactory();
var secondNode = _secondNodeFactory();
// try getting a context node if it is there.
context.TryGetNodeAndPort(out _, out var otherNode, out var otherPort);
// offset the second node from the first node so they don't overlap
firstNode.Offset = position;
secondNode.Offset = position + new Vector2(400, 0);
// interconnect the nodes.
((IAmBoundToOtherNode)firstNode).OtherNodeId = secondNode.Id;
((IAmBoundToOtherNode)secondNode).OtherNodeId = firstNode.Id;
// if we have another node in the context, add a connection context node -> first node
// if the context node is left of us, or add a connection second node -> context node if the
// context node is right of us.
ScadNode incomingNode = null;
ScadNode outgoingNode = null;
if (otherPort.IsInput)
{
incomingNode = otherNode;
}
if (otherPort.IsOutput)
{
outgoingNode = otherNode;
}
// build the list of refactorings
var refactorings = new List<Refactoring>
{
new AddNodeRefactoring(graph, firstNode, incomingNode, otherPort),
new AddNodeRefactoring(graph, secondNode, outgoingNode, otherPort)
};
// and run it.
_editorContext.PerformRefactorings("Add node", refactorings);
}
}
}