void AlignDependency(IDependency dependency, INodeModel prev, GraphViewStateComponent.StateUpdater graphUpdater)
        {
            // Warning: Don't try to use the VisualElement.layout Rect as it is not up to date yet.
            // Use Node.GetPosition() when possible

            var parentUI = prev.GetUI <Node>(m_GraphView);
            var depUI    = dependency.DependentNode.GetUI <Node>(m_GraphView);

            if (parentUI == null || depUI == null)
            {
                return;
            }

            switch (dependency)
            {
            case LinkedNodesDependency linked:

                Vector2 position;

                var input  = linked.ParentPort.GetUI <Port>(m_GraphView);
                var output = linked.DependentPort.GetUI <Port>(m_GraphView);

                if (input?.Model != null && output?.Model != null &&
                    ((IPortModel)input.Model).Orientation == ((IPortModel)output.Model).Orientation)
                {
                    Vector2 inputPortPos  = input.parent.ChangeCoordinatesTo(parentUI, input.layout.center);
                    Vector2 inputPos      = prev.Position;
                    Vector2 outputPortPos = output.parent.ChangeCoordinatesTo(depUI, output.layout.center);

                    if (((IPortModel)input.Model).Orientation == PortOrientation.Horizontal)
                    {
                        position = new Vector2(
                            prev.Position.x + (linked.ParentPort.Direction == PortDirection.Output
                                    ? parentUI.layout.width + k_AlignHorizontalOffset
                                    : -k_AlignHorizontalOffset - depUI.layout.width),
                            inputPos.y + inputPortPos.y - outputPortPos.y
                            );
                    }
                    else
                    {
                        position = new Vector2(
                            inputPos.x + inputPortPos.x - outputPortPos.x,
                            prev.Position.y + (linked.ParentPort.Direction == PortDirection.Output
                                    ? parentUI.layout.height + k_AlignVerticalOffset
                                    : -k_AlignVerticalOffset - depUI.layout.height)
                            );
                    }

                    linked.DependentNode.Position = position;
                    graphUpdater.MarkChanged(linked.DependentNode);
                }
                break;
            }
        }
        public IEnumerator DeletableElementCanBeDeleted()
        {
            yield return(null);

            var node1 = m_NodeModel1.GetUI <Node>(graphView);
            var node2 = m_NodeModel2.GetUI <Node>(graphView);

            Assert.IsNotNull(node1);
            Assert.IsNotNull(node2);

            Assert.True(m_NodeModel1.IsDeletable());
            Assert.False(m_NodeModel2.IsDeletable());

            // We need to get the graphView in focus for the commands to be properly sent.
            graphView.Focus();

            Assert.AreEqual(2, graphView.GraphElements.ToList().Count);

            CommandDispatcher.Dispatch(new SelectElementsCommand(SelectElementsCommand.SelectionMode.Replace, m_NodeModel1));
            yield return(null);

            helpers.ExecuteCommand("Delete");
            yield return(null);

            Assert.AreEqual(1, graphView.GraphElements.ToList().Count);

            // Node 2 is not deletable.
            // Selecting it and sending the Delete command should leave the node count unchanged.
            CommandDispatcher.Dispatch(new SelectElementsCommand(SelectElementsCommand.SelectionMode.Replace, m_NodeModel2));
            yield return(null);

            helpers.ExecuteCommand("Delete");
            yield return(null);

            Assert.AreEqual(1, graphView.GraphElements.ToList().Count);
            yield return(null);
        }
        void GetNodesAndSetViewDataKey(out Node node1, out Node node2, out Node node3)
        {
            node1 = node1Model.GetUI <Node>(graphView);
            if (node1 != null)
            {
                node1.viewDataKey = key1;
            }

            node2 = node2Model.GetUI <Node>(graphView);
            if (node2 != null)
            {
                node2.viewDataKey = key2;
            }

            node3 = node3Model.GetUI <Node>(graphView);
            if (node3 != null)
            {
                node3.viewDataKey = key3;
            }
        }
        IEnumerator TestMove(TestingMode mode, Vector2 mouseDelta, INodeModel[] movedNodes,
                             INodeModel[] expectedMovedDependencies,
                             INodeModel[] expectedUnmovedDependencies = null)
        {
            const float epsilon = 0.00001f;

            Vector2        startMousePos        = new Vector2(42, 13);
            List <Vector2> initPositions        = expectedMovedDependencies.Select(x => x.Position).ToList();
            List <Vector2> initUnmovedPositions = expectedUnmovedDependencies != null?expectedUnmovedDependencies.Select(x => x.Position).ToList() : new List <Vector2>();

            yield return(TestPrereqCommandPostreq(mode,
                                                  () =>
            {
                for (int i = 0; i < expectedMovedDependencies.Length; i++)
                {
                    GraphModel.TryGetModelFromGuid(expectedMovedDependencies[i].Guid, out var elementModel);
                    var model = elementModel as INodeModel;
                    GraphElement element = model.GetUI <GraphElement>(GraphView);

                    Assert.IsNotNull(element);
                    Assert.That(model.Position.x, Is.EqualTo(initPositions[i].x).Within(epsilon));
                    Assert.That(model.Position.y, Is.EqualTo(initPositions[i].y).Within(epsilon));
                    Assert.That(element.GetPosition().position.x, Is.EqualTo(initPositions[i].x).Within(epsilon));
                    Assert.That(element.GetPosition().position.y, Is.EqualTo(initPositions[i].y).Within(epsilon));
                }
            },
                                                  frame =>
            {
                switch (frame)
                {
                case 0:
                    CommandDispatcher.State.PushUndo(null);

                    var selectables = movedNodes.Cast <IGraphElementModel>().ToList();
                    GraphView.PositionDependenciesManager.StartNotifyMove(selectables, startMousePos);
                    GraphView.PositionDependenciesManager.ProcessMovedNodes(startMousePos + mouseDelta);
                    for (int i = 0; i < expectedMovedDependencies.Length; i++)
                    {
                        INodeModel model = expectedMovedDependencies[i];
                        GraphElement element = model.GetUI <GraphElement>(GraphView);
                        Assert.That(model.Position.x, Is.EqualTo(initPositions[i].x).Within(epsilon));
                        Assert.That(model.Position.y, Is.EqualTo(initPositions[i].y).Within(epsilon));
                        Assert.That(element.GetPosition().position.x, Is.EqualTo(initPositions[i].x).Within(epsilon));
                        Assert.That(element.GetPosition().position.y, Is.EqualTo(initPositions[i].y).Within(epsilon));
                    }
                    return TestPhase.WaitForNextFrame;

                default:
                    GraphView.PositionDependenciesManager.StopNotifyMove();
                    return TestPhase.Done;
                }
            },
                                                  () =>
            {
                for (int i = 0; i < expectedMovedDependencies.Length; i++)
                {
                    GraphModel.TryGetModelFromGuid(expectedMovedDependencies[i].Guid, out var elementModel);
                    var model = elementModel as INodeModel;
                    GraphElement element = model.GetUI <GraphElement>(GraphView);
                    Assert.IsNotNull(element);
                    Assert.That(model.Position.x, Is.EqualTo(initPositions[i].x + mouseDelta.x).Within(epsilon), () => $"Model {model} was expected to have moved");
                    Assert.That(model.Position.y, Is.EqualTo(initPositions[i].y + mouseDelta.y).Within(epsilon), () => $"Model {model} was expected to have moved");
                    Assert.That(element.GetPosition().position.x, Is.EqualTo(initPositions[i].x + mouseDelta.x).Within(epsilon));
                    Assert.That(element.GetPosition().position.y, Is.EqualTo(initPositions[i].y + mouseDelta.y).Within(epsilon));
                }

                if (expectedUnmovedDependencies != null)
                {
                    for (int i = 0; i < expectedUnmovedDependencies.Length; i++)
                    {
                        GraphModel.TryGetModelFromGuid(expectedUnmovedDependencies[i].Guid, out var elementModel);
                        var model = elementModel as INodeModel;
                        GraphElement element = model.GetUI <GraphElement>(GraphView);
                        Assert.IsNotNull(element);
                        Assert.That(model.Position.x, Is.EqualTo(initUnmovedPositions[i].x).Within(epsilon));
                        Assert.That(model.Position.y, Is.EqualTo(initUnmovedPositions[i].y).Within(epsilon));
                        Assert.That(element.GetPosition().position.x, Is.EqualTo(initUnmovedPositions[i].x).Within(epsilon));
                        Assert.That(element.GetPosition().position.y, Is.EqualTo(initUnmovedPositions[i].y).Within(epsilon));
                    }
                }
            }
                                                  ));
        }