示例#1
0
        private void PasteDatas(ref SerializableGraph serializableGraph)
        {
            for (int i = 0; i < newContexts.Count; ++i)
            {
                VFXNodeController nodeController = null;
                newControllers.TryGetValue(ContextFlag | (uint)i, out nodeController);
                var contextController = nodeController as VFXContextController;

                if (contextController != null)
                {
                    if ((contextController.flowInputAnchors.Count() == 0 ||
                         contextController.flowInputAnchors.First().connections.Count() == 0 ||
                         contextController.flowInputAnchors.First().connections.First().output.context.model.GetData() == null) &&
                        serializableGraph.contexts[i].dataIndex >= 0)
                    {
                        var     data       = serializableGraph.datas[serializableGraph.contexts[i].dataIndex];
                        VFXData targetData = contextController.model.GetData();
                        if (targetData != null)
                        {
                            PasteModelSettings(targetData, data.settings, targetData.GetType());
                            targetData.Invalidate(VFXModel.InvalidationCause.kSettingChanged);
                        }
                    }
                }
            }
        }
示例#2
0
        void PasteDataEdges(ref SerializableGraph serializableGraph)
        {
            if (serializableGraph.dataEdges != null)
            {
                foreach (var dataEdge in serializableGraph.dataEdges)
                {
                    if (dataEdge.input.targetIndex == InvalidID || dataEdge.output.targetIndex == InvalidID)
                    {
                        continue;
                    }

                    VFXModel inputModel = newControllers.ContainsKey(dataEdge.input.targetIndex) ? newControllers[dataEdge.input.targetIndex].model : null;

                    VFXNodeController outputController = newControllers.ContainsKey(dataEdge.output.targetIndex) ? newControllers[dataEdge.output.targetIndex] : null;
                    VFXModel          outputModel      = outputController != null ? outputController.model : null;
                    if (inputModel != null && outputModel != null)
                    {
                        VFXSlot outputSlot = FetchSlot(outputModel as IVFXSlotContainer, dataEdge.output.slotPath, false);
                        VFXSlot inputSlot  = FetchSlot(inputModel as IVFXSlotContainer, dataEdge.input.slotPath, true);

                        inputSlot.Link(outputSlot);

                        if (outputController is VFXParameterNodeController)
                        {
                            var parameterNodeController = outputController as VFXParameterNodeController;

                            parameterNodeController.infos.linkedSlots.Add(new VFXParameter.NodeLinkedSlot {
                                inputSlot = inputSlot, outputSlot = outputSlot
                            });
                        }
                    }
                }
            }
        }
        public bool CanLinkToNode(VFXNodeController nodeController, CanLinkCache cache)
        {
            if (nodeController == sourceNode)
            {
                return(false);
            }

            if (cache == null)
            {
                cache = new CanLinkCache();
            }

            cache.localChildrenOperator.Clear();
            cache.localParentOperator.Clear();

            bool result;

            if (direction != Direction.Input)
            {
                VFXViewController.CollectAncestorOperator(sourceNode.slotContainer, cache.localParentOperator);
                result = !cache.localParentOperator.Contains(nodeController.slotContainer);
            }
            else
            {
                VFXViewController.CollectDescendantOperator(sourceNode.slotContainer, cache.localChildrenOperator);
                result = !cache.localChildrenOperator.Contains(nodeController.slotContainer);
            }

            return(result);
        }
            public void ConvertToSubgraphBlock(VFXView sourceView, IEnumerable <Controller> controllers, Rect rect)
            {
                this.m_Rect = rect;
                Init(sourceView, controllers);
                CreateUniqueSubgraph("SubgraphBlock", VisualEffectSubgraphBlock.Extension, VisualEffectAssetEditorUtility.CreateNew <VisualEffectSubgraphBlock>);

                m_SourceControllers.RemoveAll(t => t is VFXContextController); // Don't copy contexts
                CopyPasteNodes();

                m_SourceBlockControllers = m_SourceControllers.OfType <VFXBlockController>().OrderBy(t => t.index).ToList();

                VFXContextController sourceContextController = m_SourceBlockControllers.First().contextController;

                object copyData = VFXCopy.CopyBlocks(m_SourceBlockControllers);

                var targetContext = m_TargetController.graph.children.OfType <VFXBlockSubgraphContext>().FirstOrDefault();

                if (targetContext == null)
                {
                    targetContext = ScriptableObject.CreateInstance <VFXBlockSubgraphContext>();
                    m_TargetController.graph.AddChild(targetContext);
                }
                m_TargetController.LightApplyChanges();
                targetContext.position = sourceContextController.position;
                targetContext.SetSettingValue("m_SuitableContexts", (VFXBlockSubgraphContext.ContextType)m_SourceBlockControllers.Select(t => t.model.compatibleContexts).Aggregate((t, s) => t & s));
                m_TargetBlocks = new List <VFXBlockController>();

                VFXPaste.PasteBlocks(m_TargetController, copyData, targetContext, 0, m_TargetBlocks);

                var otherSourceControllers = m_SourceControllers.OfType <VFXNodeController>().Where(t => !(t is VFXBlockController)).ToList();

                //Create lost links between nodes and blocks
                foreach (var edge in m_SourceController.dataEdges.Where(t => otherSourceControllers.Contains(t.output.sourceNode) && m_SourceBlockControllers.Contains(t.input.sourceNode)))
                {
                    var outputNode = m_TargetControllers[m_SourceControllers.IndexOf(edge.output.sourceNode)];
                    var output     = outputNode.outputPorts.First(t => t.path == edge.output.path);

                    var inputBlock = m_TargetBlocks[m_SourceBlockControllers.IndexOf(edge.input.sourceNode as VFXBlockController)];
                    var input      = inputBlock.inputPorts.First(t => t.path == edge.input.path);

                    m_TargetController.CreateLink(input, output);
                }

                var sourceBlock = ScriptableObject.CreateInstance <VFXSubgraphBlock>();

                m_SourceNode = sourceBlock;
                sourceContextController.model.AddChild(m_SourceNode, m_SourceBlockControllers.Select(t => t.index).Min());
                sourceContextController.ApplyChanges();
                m_SourceNodeController = sourceContextController.blockControllers.First(t => t.model == m_SourceNode);
                PostSetup();
                m_SourceNodeController.ApplyChanges();

                var targetContextController = m_TargetController.GetRootNodeController(targetContext, 0) as VFXContextController;

                m_SourceControllersWithBlocks = m_SourceControllers.Concat(m_SourceBlockControllers);
                TransferEdges();
                UninitSmart();
            }
示例#5
0
        void AlignNodeToLinkedPort(VFXView view, VFXDataAnchorController port, VFXNodeController nodeController)
        {
            var portNode         = view.GetDataAnchorByController(port);
            var connectorElement = portNode.Q <VisualElement>("connector");
            var newNode          = view.GetNodeByController(nodeController);
            var offset           = newNode.worldBound.position - connectorElement.worldBound.position + portPositionOffset;

            nodeController.model.position += offset / view.scale;
        }
 void PostSetupNode()
 {
     PostSetup();
     m_SourceNode.position = m_Rect.center;
     m_SourceController.graph.AddChild(m_SourceNode);
     m_SourceController.LightApplyChanges();
     m_SourceNodeController = m_SourceController.GetRootNodeController(m_SourceNode, 0);
     m_SourceNodeController.ApplyChanges();
 }
 public bool ContainsNode(VFXNodeController controller)
 {
     if (m_Index == -1) return false;
     if (m_UI.groupInfos[m_Index].contents != null)
     {
         return m_UI.groupInfos[m_Index].contents.Contains(new VFXNodeID(controller.model, controller.id));
     }
     return false;
 }
        public void AddNode(VFXNodeController controller)
        {
            if (m_Index < 0)
                return;

            AddNodeID(new VFXNodeID(controller.model, controller.id));

            Modified();
        }
示例#9
0
 void PostSetupNode()
 {
     PostSetup();
     m_SourceNode.position = m_Rect.center;
     m_SourceController.graph.AddChild(m_SourceNode);
     m_SourceNode.SetSettingValue("m_Subgraph", m_TargetSubgraph);
     m_SourceController.LightApplyChanges();
     m_SourceNodeController = m_SourceController.GetRootNodeController(m_SourceNode, 0);
     m_SourceNodeController.ApplyChanges();
 }
示例#10
0
        public bool CanLinkToNode(VFXNodeController nodeController, CanLinkCache cache)
        {
            if (nodeController == sourceNode)
            {
                return(false);
            }

            if (cache == null)
            {
                cache = new CanLinkCache();
            }

            cache.localChildrenOperator.Clear();
            cache.localParentOperator.Clear();

            bool result;

            if (direction != Direction.Input)
            {
                VFXViewController.CollectAncestorOperator(sourceNode.slotContainer, cache.localParentOperator);
#if _RESTRICT_ATTRIBUTE_ACCESS
                if (cache.localParentOperator.Any(o => DependOnAttribute(o)))
                {
                    if (cache.ancestorOfSpawners == null)
                    {
                        cache.ancestorOfSpawners = CollectAnscestorOfSpawner(viewController.AllSlotContainerControllers);
                    }
                    var additionnalExcludeOperator = cache.ancestorOfSpawners;
                    cache.localChildrenOperator.UnionWith(additionnalExcludeOperator);
                }
#endif
                result = !cache.localParentOperator.Contains(nodeController.slotContainer);
            }
            else
            {
                VFXViewController.CollectDescendantOperator(sourceNode.slotContainer, cache.localChildrenOperator);
#if _RESTRICT_ATTRIBUTE_ACCESS
                var contextTypeInChildren = cache.localChildrenOperator.OfType <VFXBlock>().Select(o => o.GetParent().contextType);
                if (contextTypeInChildren.Any(o => o == VFXContextType.Spawner))
                {
                    if (cache.descendantOfAttribute == null)
                    {
                        cache.descendantOfAttribute = CollectDescendantOfAttribute(viewController.AllSlotContainerControllers);
                    }

                    var additionnalExcludeOperator = cache.descendantOfAttribute;
                    return(!cache.localParentOperator.Contains(sourceNode.slotContainer) && !additionnalExcludeOperator.Contains(nodeController.slotContainer));
                }
#endif
                result = !cache.localChildrenOperator.Contains(nodeController.slotContainer);
            }

            return(result);
        }
        public void RemoveNode(VFXNodeController nodeController)
        {
            if (m_Index < 0)
                return;

            if (m_UI.groupInfos[m_Index].contents == null)
                return;

            int id = nodeController.id;
            var model = nodeController.model;
            if (!m_UI.groupInfos[m_Index].contents.Any(t => t.model == model && t.id == id))
                return;
            m_UI.groupInfos[m_Index].contents = m_UI.groupInfos[m_Index].contents.Where(t => t.model != model || t.id != id).ToArray();

            Modified();
        }
示例#12
0
        public VFXDataAnchorController(VFXSlot model, VFXNodeController sourceNode, bool hidden) : base(sourceNode.viewController, model)
        {
            m_SourceNode = sourceNode;
            m_Hidden     = hidden;
            m_Expanded   = expandedSelf;

            if (model != null)
            {
                portType = model.property.type;

                if (model.GetMasterSlot() != null && model.GetMasterSlot() != model)
                {
                    m_MasterSlot = model.GetMasterSlot();

                    viewController.RegisterNotification(m_MasterSlot, MasterSlotChanged);
                }
                ModelChanged(model);
            }
        }
示例#13
0
        void IEdgeConnectorListener.OnDropOutsidePort(Edge edge, Vector2 position)
        {
            VFXSlot startSlot = controller.model;

            VFXView           view           = this.GetFirstAncestorOfType <VFXView>();
            VFXViewController viewController = view.controller;


            VFXNodeUI endNode = null;

            foreach (var node in view.GetAllNodes())
            {
                if (node.worldBound.Contains(position))
                {
                    endNode = node;
                }
            }

            VFXDataEdge dataEdge = edge as VFXDataEdge;
            bool        exists   = false;

            if (dataEdge.controller != null)
            {
                exists = true;
                view.controller.RemoveElement(dataEdge.controller);
            }

            if (endNode != null)
            {
                VFXNodeController nodeController = endNode.controller;

                if (nodeController != null)
                {
                    IVFXSlotContainer slotContainer = nodeController.slotContainer;
                    if (controller.direction == Direction.Input)
                    {
                        foreach (var output in nodeController.outputPorts.Where(t => t.model == null || t.model.IsMasterSlot()))
                        {
                            if (viewController.CreateLink(controller, output))
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        foreach (var input in nodeController.inputPorts.Where(t => t.model == null || t.model.IsMasterSlot()))
                        {
                            if (viewController.CreateLink(input, controller))
                            {
                                break;
                            }
                        }
                    }
                }
            }
            else if (controller.direction == Direction.Input && Event.current.modifiers == EventModifiers.Alt)
            {
                VFXModelDescriptorParameters parameterDesc = VFXLibrary.GetParameters().FirstOrDefault(t => t.name == controller.portType.UserFriendlyName());
                if (parameterDesc != null)
                {
                    VFXParameter parameter = viewController.AddVFXParameter(view.contentViewContainer.GlobalToBound(position) - new Vector2(140, 20), parameterDesc);
                    parameter.SetSettingValue("m_Exposed", true);
                    startSlot.Link(parameter.outputSlots[0]);

                    CopyValueToParameter(parameter);
                }
            }
            else if (!exists)
            {
                VFXFilterWindow.Show(VFXViewWindow.currentWindow, Event.current.mousePosition, view.ViewToScreenPosition(Event.current.mousePosition), new VFXNodeProvider(viewController, AddLinkedNode, ProviderFilter, new Type[] { typeof(VFXOperator), typeof(VFXParameter), typeof(VFXContext) }));
            }
        }
 public VFXContextDataAnchorController(VFXSlot model, VFXNodeController sourceNode, bool hidden) : base(model, sourceNode, hidden)
 {
 }
示例#15
0
 public VFXUpcommingDataAnchorController(VFXNodeController sourceNode, bool hidden) : base(null, sourceNode, hidden)
 {
 }
 public VFXOutputOperatorAnchorController(VFXSlot model, VFXNodeController sourceNode, bool hidden) : base(model, sourceNode, hidden)
 {
 }
示例#17
0
        private void PasteGroupNodes(ref SerializableGraph serializableGraph, VFXUI ui)
        {
            if (serializableGraph.groupNodes != null && serializableGraph.groupNodes.Length > 0)
            {
                if (ui.groupInfos == null)
                {
                    ui.groupInfos = new VFXUI.GroupInfo[0];
                }
                firstCopiedGroup = ui.groupInfos.Length;

                List <VFXUI.GroupInfo> newGroupInfos = new List <VFXUI.GroupInfo>();
                foreach (var groupInfos in serializableGraph.groupNodes)
                {
                    var newGroupInfo = new VFXUI.GroupInfo();
                    newGroupInfo.position = new Rect(groupInfos.infos.position.position + pasteOffset, groupInfos.infos.position.size);
                    newGroupInfo.title    = groupInfos.infos.title;
                    newGroupInfos.Add(newGroupInfo);
                    newGroupInfo.contents = groupInfos.contents.Take(groupInfos.contents.Length - groupInfos.stickNodeCount).Select(t => { VFXNodeController node = null; newControllers.TryGetValue(t, out node); return(node); }).Where(t => t != null).Select(node => new VFXNodeID(node.model, node.id))
                                            .Concat(groupInfos.contents.Skip(groupInfos.contents.Length - groupInfos.stickNodeCount).Select(t => new VFXNodeID((int)t + firstCopiedStickyNote)))
                                            .ToArray();
                }
                ui.groupInfos = ui.groupInfos.Concat(newGroupInfos).ToArray();
            }
        }
示例#18
0
            void TransfertDataEdges()
            {
                m_SourceControllersWithBlocks = m_SourceControllers.Concat(m_SourceControllers.OfType <VFXContextController>().SelectMany(t => t.blockControllers));

                // Search for links between with inputs in the selected part and the output in other parts of the graph.
                Dictionary <VFXDataAnchorController, List <VFXDataAnchorController> > traversingInEdges = new Dictionary <VFXDataAnchorController, List <VFXDataAnchorController> >();

                foreach (var edge in m_SourceController.dataEdges.Where(
                             t =>
                {
                    if (parameterNodeControllers.Contains(t.output.sourceNode))
                    {
                        return(false);
                    }
                    var inputInControllers = m_SourceControllersWithBlocks.Contains(t.input.sourceNode);
                    var outputInControllers = m_SourceControllersWithBlocks.Contains(t.output.sourceNode);

                    return(inputInControllers && !outputInControllers);
                }
                             ))
                {
                    List <VFXDataAnchorController> outputs = null;
                    if (!traversingInEdges.TryGetValue(edge.input, out outputs))
                    {
                        outputs = new List <VFXDataAnchorController>();
                        traversingInEdges[edge.input] = outputs;
                    }

                    outputs.Add(edge.output);
                }

                var newSourceInputs = traversingInEdges.Keys.ToArray();

                for (int i = 0; i < newSourceInputs.Length; ++i)
                {
                    VFXParameter newTargetParameter = m_TargetController.AddVFXParameter(Vector2.zero, VFXLibrary.GetParameters().First(t => t.model.type == newSourceInputs[i].portType));

                    m_TargetController.LightApplyChanges();

                    VFXParameterController newTargetParamController = m_TargetController.GetParameterController(newTargetParameter);
                    newTargetParamController.exposed = true;

                    var outputs = traversingInEdges[newSourceInputs[i]];

                    var linkedParameter = outputs.FirstOrDefault(t => t.sourceNode is VFXParameterNodeController);
                    if (linkedParameter != null)
                    {
                        newTargetParamController.exposedName = (linkedParameter.sourceNode as VFXParameterNodeController).parentController.exposedName;
                    }
                    else
                    {
                        newTargetParamController.exposedName = newSourceInputs[i].name;
                    }

                    //first the equivalent of sourceInput in the target

                    VFXNodeController targetNode = null;
                    Vector2           position;

                    if (newSourceInputs[i].sourceNode is VFXBlockController)
                    {
                        var blockController = newSourceInputs[i].sourceNode as VFXBlockController;
                        if (m_TargetBlocks != null)
                        {
                            targetNode = m_TargetBlocks[m_SourceBlockControllers.IndexOf(blockController)];
                            position   = blockController.contextController.position;
                        }
                        else
                        {
                            var targetContext = m_TargetControllers[m_SourceControllers.IndexOf(blockController.contextController)] as VFXContextController;

                            targetNode = targetContext.blockControllers[blockController.index];
                            position   = blockController.contextController.position;
                        }
                    }
                    else
                    {
                        targetNode = m_TargetControllers[m_SourceControllers.IndexOf(newSourceInputs[i].sourceNode)];
                        position   = targetNode.position;
                    }

                    VFXDataAnchorController targetAnchor = targetNode.inputPorts.First(t => t.path == newSourceInputs[i].path);


                    position.y += targetAnchor.model.owner.inputSlots.IndexOf(targetAnchor.model) * 32;

                    VFXNodeController parameterNode = m_TargetController.AddVFXParameter(position - new Vector2(200, 0), newTargetParamController, null);

                    // Link the parameternode and the input in the target
                    m_TargetController.CreateLink(targetAnchor, parameterNode.outputPorts[0]);

                    if (m_SourceSlotContainer is VFXOperator)
                    {
                        (m_SourceSlotContainer as VFXOperator).ResyncSlots(true);
                    }
                    else if (m_SourceSlotContainer is VFXSubgraphBlock)
                    {
                        VFXSubgraphBlock blk = (m_SourceSlotContainer as VFXSubgraphBlock);
                        blk.RecreateCopy();
                        blk.ResyncSlots(true);
                    }
                    else if (m_SourceSlotContainer is VFXSubgraphContext)
                    {
                        VFXSubgraphContext ctx = (m_SourceSlotContainer as VFXSubgraphContext);
                        ctx.RecreateCopy();
                        ctx.ResyncSlots(true);
                    }

                    m_SourceNodeController.ApplyChanges();
                    //Link all the outputs to the matching input of the subgraph
                    foreach (var output in outputs)
                    {
                        m_SourceController.CreateLink(m_SourceNodeController.inputPorts.First(t => t.model == m_SourceSlotContainer.inputSlots.Last()), output);
                    }
                }
            }
示例#19
0
            void TransfertOperatorOutputEdges()
            {
                var traversingOutEdges = new Dictionary <VFXDataAnchorController, List <VFXDataAnchorController> >();

                foreach (var edge in m_SourceController.dataEdges.Where(
                             t =>
                {
                    if (t.output.sourceNode is VFXParameterNodeController)
                    {
                        return(false);
                    }
                    var inputInControllers = m_SourceControllersWithBlocks.Contains(t.input.sourceNode);
                    var outputInControllers = m_SourceControllersWithBlocks.Contains(t.output.sourceNode);

                    return(!inputInControllers && outputInControllers);
                }
                             ))
                {
                    List <VFXDataAnchorController> inputs = null;
                    if (!traversingOutEdges.TryGetValue(edge.output, out inputs))
                    {
                        inputs = new List <VFXDataAnchorController>();
                        traversingOutEdges[edge.output] = inputs;
                    }

                    inputs.Add(edge.input);
                }

                var newSourceOutputs = traversingOutEdges.Keys.ToArray();

                for (int i = 0; i < newSourceOutputs.Length; ++i)
                {
                    VFXParameter newTargetParameter = m_TargetController.AddVFXParameter(Vector2.zero, VFXLibrary.GetParameters().First(t => t.model.type == newSourceOutputs[i].portType));

                    m_TargetController.LightApplyChanges();

                    VFXParameterController newTargetParamController = m_TargetController.GetParameterController(newTargetParameter);
                    newTargetParamController.isOutput = true;

                    var inputs = traversingOutEdges[newSourceOutputs[i]];

                    var linkedParameter = inputs.FirstOrDefault(t => t.sourceNode is VFXParameterNodeController);
                    if (linkedParameter != null)
                    {
                        newTargetParamController.exposedName = (linkedParameter.sourceNode as VFXParameterNodeController).parentController.exposedName;
                    }
                    else
                    {
                        newTargetParamController.exposedName = newSourceOutputs[i].name;
                    }

                    //first the equivalent of sourceInput in the target

                    VFXNodeController targetNode = null;

                    if (newSourceOutputs[i].sourceNode is VFXBlockController)
                    {
                        var blockController = newSourceOutputs[i].sourceNode as VFXBlockController;
                        if (m_TargetBlocks != null)
                        {
                            targetNode = m_TargetBlocks[m_SourceBlockControllers.IndexOf(blockController)];
                        }
                        else
                        {
                            var targetContext = m_TargetControllers[m_SourceControllers.IndexOf(blockController.contextController)] as VFXContextController;

                            targetNode = targetContext.blockControllers[blockController.index];
                        }
                    }
                    else
                    {
                        targetNode = m_TargetControllers[m_SourceControllers.IndexOf(newSourceOutputs[i].sourceNode)];
                    }

                    VFXDataAnchorController targetAnchor = targetNode.outputPorts.FirstOrDefault(t => t.path == newSourceOutputs[i].path);

                    if (targetAnchor != null)
                    {
                        VFXNodeController parameterNode = m_TargetController.AddVFXParameter(targetNode.position + new Vector2(400, 0), newTargetParamController, null);

                        // Link the parameternode and the input in the target
                        m_TargetController.CreateLink(parameterNode.inputPorts[0], targetAnchor);

                        if (m_SourceSlotContainer is VFXOperator)
                        {
                            (m_SourceSlotContainer as VFXOperator).ResyncSlots(true);
                        }
                        m_SourceNodeController.ApplyChanges();
                    }
                    //Link all the outputs to the matching input of the subgraph
                    foreach (var input in inputs)
                    {
                        var port = m_SourceNodeController.outputPorts.FirstOrDefault(t => t.model == m_SourceSlotContainer.outputSlots.Last());
                        if (port != null)
                        {
                            m_SourceController.CreateLink(input, port);
                        }
                    }
                }
            }
示例#20
0
        void IEdgeConnectorListener.OnDropOutsidePort(Edge edge, Vector2 position)
        {
            VFXSlot startSlot = controller.model;

            VFXView           view           = this.GetFirstAncestorOfType <VFXView>();
            VFXViewController viewController = view.controller;


            List <VisualElement> picked = new List <VisualElement>();

            panel.PickAll(position, picked);
            VFXNodeUI endNode = null;

            foreach (var element in picked)
            {
                if (element is VFXNodeUI node)
                {
                    endNode = node;
                    break;
                }
            }


            VFXDataEdge dataEdge = edge as VFXDataEdge;
            bool        exists   = false;

            if (dataEdge.controller != null)
            {
                exists = true;
                view.controller.RemoveElement(dataEdge.controller);
            }

            if (endNode != null)
            {
                VFXNodeController nodeController = endNode.controller;

                if (nodeController != null)
                {
                    IVFXSlotContainer slotContainer = nodeController.slotContainer;
                    if (controller.direction == Direction.Input)
                    {
                        foreach (var output in nodeController.outputPorts.Where(t => t.model == null || t.model.IsMasterSlot()))
                        {
                            if (viewController.CreateLink(controller, output))
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        foreach (var input in nodeController.inputPorts.Where(t => t.model == null || t.model.IsMasterSlot() && !t.model.HasLink(true)))
                        {
                            if (viewController.CreateLink(input, controller))
                            {
                                break;
                            }
                        }
                    }
                }
            }
            else if (controller.direction == Direction.Input && Event.current.modifiers == EventModifiers.Alt)
            {
                var targetType = controller.portType;

                var attribute = VFXLibrary.GetAttributeFromSlotType(controller.portType);
                VFXModelDescriptorParameters parameterDesc;
                if (attribute != null && attribute.usages.HasFlag(VFXTypeAttribute.Usage.ExcludeFromProperty))
                {
                    parameterDesc = VFXLibrary.GetParameters().FirstOrDefault(t =>
                    {
                        if (!t.model.outputSlots[0].CanLink(controller.model))
                        {
                            return(false);
                        }
                        var attributeCandidate = VFXLibrary.GetAttributeFromSlotType(t.model.type);
                        return(attributeCandidate == null || !attributeCandidate.usages.HasFlag(VFXTypeAttribute.Usage.ExcludeFromProperty));
                    });
                }
                else
                {
                    parameterDesc = VFXLibrary.GetParameters().FirstOrDefault(t =>
                    {
                        return(t.model.type == targetType);
                    });
                }

                if (parameterDesc != null)
                {
                    Vector2 pos = view.contentViewContainer.GlobalToBound(position) - new Vector2(140, 20);
                    view.UpdateSelectionWithNewNode();
                    VFXParameter parameter = viewController.AddVFXParameter(pos, parameterDesc, false);
                    parameter.SetSettingValue("m_Exposed", true);
                    startSlot.Link(parameter.outputSlots[0]);

                    CopyValueToParameter(parameter);

                    viewController.AddVFXModel(pos, parameter);
                }
            }
            else if (!exists)
            {
                var window = VFXViewWindow.GetWindow(view);

                if (direction == Direction.Input || viewController.model.visualEffectObject is VisualEffectSubgraphOperator || viewController.model.visualEffectObject is VisualEffectSubgraphBlock) // no context for subgraph operators.
                {
                    VFXFilterWindow.Show(window, Event.current.mousePosition, view.ViewToScreenPosition(Event.current.mousePosition), new VFXNodeProvider(viewController, AddLinkedNode, ProviderFilter, new Type[] { typeof(VFXOperator), typeof(VFXParameter) }));
                }
                else
                {
                    VFXFilterWindow.Show(window, Event.current.mousePosition, view.ViewToScreenPosition(Event.current.mousePosition), new VFXNodeProvider(viewController, AddLinkedNode, ProviderFilter, new Type[] { typeof(VFXOperator), typeof(VFXParameter), typeof(VFXContext) }));
                }
            }
        }