static LinkedNodesDependency CreateDependencyFromEdge(IEdgeModel model, out INodeModel parent)
        {
            LinkedNodesDependency dependency;

            if (model.InputPortModel.NodeModel is IStackModel && model.InputPortModel.PortType != PortType.Instance)
            {
                dependency = new LinkedNodesDependency
                {
                    DependentPort = model.InputPortModel,
                    ParentPort    = model.OutputPortModel,
                    count         = 1,
                };
                parent = model.OutputPortModel.NodeModel;
            }
            else
            {
                dependency = new LinkedNodesDependency
                {
                    DependentPort = model.OutputPortModel,
                    ParentPort    = model.InputPortModel,
                };
                parent = model.InputPortModel.NodeModel;
            }

            return(dependency);
        }
        public void AlignNodes(VseGraphView vseGraphView, bool follow, List <ISelectable> selection)
        {
            HashSet <INodeModel> topMostModels = new HashSet <INodeModel>();

            topMostModels.Clear();

            var selectedNodeModels          = selection.OfType <Node>().Select(e => e.model);
            var nodeModelsFromSelectedEdges = selection.OfType <Edge>().SelectMany(e => e.model.GetPortModels().Select(p => p.NodeModel));
            var affectedNodeModels          = selectedNodeModels.Concat(nodeModelsFromSelectedEdges);

            foreach (INodeModel stackedNode in affectedNodeModels.Where(n => n.IsStacked))
            {
                InitModelPositionFromUI(stackedNode);
            }

            bool anyEdge = false;

            foreach (Edge edge in selection.OfType <Edge>())
            {
                anyEdge = true;

                LinkedNodesDependency dependency = CreateDependencyFromEdge(edge.model, out INodeModel parent);
                GraphElement          element    = vseGraphView.UIController.ModelsToNodeMapping[dependency.DependentNode];
                AlignDependency(element, dependency, Vector2.zero, parent);
                topMostModels.Add(dependency.DependentNode);
            }

            if (anyEdge && !follow)
            {
                return;
            }

            if (!topMostModels.Any())
            {
                foreach (GraphElement element in selection.OfType <GraphElement>())
                {
                    if (element is IHasGraphElementModel hasModel &&
                        hasModel.GraphElementModel is INodeModel nodeModel)
                    {
                        topMostModels.Add(nodeModel);
                    }
                }
            }

            if (!anyEdge && !follow)
            {
                // Align each top-most node then move dependencies by the same delta
                foreach (INodeModel model in topMostModels)
                {
                    if (!m_DependenciesByNode.TryGetValue(model.Guid, out Dictionary <GUID, IDependency> dependencies))
                    {
                        continue;
                    }
                    foreach (KeyValuePair <GUID, IDependency> dependency in dependencies)
                    {
                        INodeModel   dependentNode = dependency.Value.DependentNode;
                        GraphElement element       = vseGraphView.UIController.ModelsToNodeMapping[dependentNode];
                        Vector2      startPos      = dependentNode.Position;
                        AlignDependency(element, dependency.Value, Vector2.zero, model);
                        Vector2 endPos = dependentNode.Position;
                        Vector2 delta  = endPos - startPos;

                        OffsetNodeDependencies(dependentNode, delta);
                    }
                }
            }
            else
            {
                // Align recursively
                m_ModelsToMove.AddRange(topMostModels);
                ProcessMovedNodes(Vector2.zero, AlignDependency);
            }

            m_ModelsToMove.Clear();
            m_TempMovedModels.Clear();
        }