void NodeGraph::setNodeToDefaultPosition(const NodeGuiPtr& node, const NodesGuiList& selectedNodes, const CreateNodeArgs& args) { NodePtr internalNode = node->getNode(); // Serializatino, don't do anything SERIALIZATION_NAMESPACE::NodeSerializationPtr serialization = args.getPropertyUnsafe<SERIALIZATION_NAMESPACE::NodeSerializationPtr >(kCreateNodeArgsPropNodeSerialization); if (serialization) { return; } bool hasPositionnedNode = false; // Try to autoconnect if there is a selection bool autoConnect = args.getPropertyUnsafe<bool>(kCreateNodeArgsPropAutoConnect); if ( selectedNodes.empty() || serialization) { autoConnect = false; } if (autoConnect) { BackdropGuiPtr isBd = toBackdropGui(node); if (!isBd) { NodeGuiPtr selectedNode; if ( !serialization && (selectedNodes.size() == 1) ) { selectedNode = selectedNodes.front(); BackdropGuiPtr isBdGui = toBackdropGui(selectedNode); if (isBdGui) { selectedNode.reset(); } } if (selectedNode && node->getNode()->autoConnect(selectedNode->getNode())) { hasPositionnedNode = true; } } } if (!hasPositionnedNode) { // If there's a position hint, use it to position the node double xPosHint = args.getPropertyUnsafe<double>(kCreateNodeArgsPropNodeInitialPosition, 0); double yPosHint = args.getPropertyUnsafe<double>(kCreateNodeArgsPropNodeInitialPosition, 1); if ((xPosHint != INT_MIN) && (yPosHint != INT_MIN)) { QPointF pos = node->mapToParent( node->mapFromScene( QPointF(xPosHint, yPosHint) ) ); node->refreshPosition( pos.x(), pos.y(), true ); hasPositionnedNode = true; } } // Ok fallback with the node in the middle of the node graph if (!hasPositionnedNode) { moveNodeToCenterOfVisiblePortion(node); } }
void GuiAppInstance::onGroupCreationFinished(const NodePtr& node, const NodeSerializationPtr& serialization, bool autoConnect) { NodeGuiIPtr node_gui_i = node->getNodeGui(); if (autoConnect && !serialization && node_gui_i) { NodeGraph* graph = 0; NodeCollectionPtr collection = node->getGroup(); assert(collection); NodeGroupPtr isGrp = toNodeGroup(collection); if (isGrp) { NodeGraphI* graph_i = isGrp->getNodeGraph(); assert(graph_i); graph = dynamic_cast<NodeGraph*>(graph_i); } else { graph = _imp->_gui->getNodeGraph(); } assert(graph); if (!graph) { throw std::logic_error(""); } NodesGuiList selectedNodes = graph->getSelectedNodes(); NodeGuiPtr selectedNode; if ( !selectedNodes.empty() ) { selectedNode = selectedNodes.front(); if (toBackdropGui(selectedNode) ) { selectedNode.reset(); } } NodeGuiPtr nodeGui = boost::dynamic_pointer_cast<NodeGui>(node_gui_i); graph->moveNodesForIdealPosition(nodeGui, selectedNode, true); } AppInstance::onGroupCreationFinished(node, serialization, autoConnect); /*std::list<ViewerInstancePtr> viewers; node->hasViewersConnected(&viewers); for (std::list<ViewerInstancePtr>::iterator it2 = viewers.begin(); it2 != viewers.end(); ++it2) { (*it2)->renderCurrentFrame(false); }*/ }
void NodeGraph::decloneSelectedNodes() { if ( _imp->_selection.empty() ) { Dialogs::warningDialog( tr("Declone").toStdString(), tr("You must select at least a node to declone first.").toStdString() ); return; } std::map<NodeGuiPtr, NodePtr> nodesToDeclone; for (NodesGuiList::iterator it = _imp->_selection.begin(); it != _imp->_selection.end(); ++it) { BackdropGuiPtr isBd = toBackdropGui(*it); if (isBd) { // Also clone all nodes within the backdrop NodesGuiList nodesWithinBD = getNodesWithinBackdrop(*it); for (NodesGuiList::iterator it2 = nodesWithinBD.begin(); it2 != nodesWithinBD.end(); ++it2) { std::map<NodeGuiPtr, NodePtr>::iterator found = nodesToDeclone.find(*it2); if ( found == nodesToDeclone.end() ) { std::list<NodePtr> linkedNodes; (*it2)->getNode()->getCloneLinkedNodes(&linkedNodes); if (!linkedNodes.empty()) { nodesToDeclone[*it2] = linkedNodes.front(); } } } } std::list<NodePtr> linkedNodes; (*it)->getNode()->getCloneLinkedNodes(&linkedNodes); if (!linkedNodes.empty()) { nodesToDeclone[*it] = linkedNodes.front(); } } pushUndoCommand( new DecloneMultipleNodesCommand(this, nodesToDeclone) ); }
void NodeGraph::moveNodesForIdealPosition(const NodeGuiPtr &node, const NodeGuiPtr &selected, bool autoConnect) { BackdropGuiPtr isBd = toBackdropGui(node); if (isBd) { return; } QRectF viewPos = visibleSceneRect(); ///3 possible values: /// 0 = default , i.e: we pop the node in the middle of the graph's current view /// 1 = pop the node above the selected node and move the inputs of the selected node a little /// 2 = pop the node below the selected node and move the outputs of the selected node a little int behavior = 0; if (!selected || !autoConnect) { behavior = 0; } else { ///this function is redundant with Project::autoConnect, depending on the node selected ///and this node we make some assumptions on to where we could put the node. // 1) selected is output // a) created is output --> fail // b) created is input --> connect input // c) created is regular --> connect input // 2) selected is input // a) created is output --> connect output // b) created is input --> fail // c) created is regular --> connect output // 3) selected is regular // a) created is output--> connect output // b) created is input --> connect input // c) created is regular --> connect output ///1) if ( selected->getNode()->isOutputNode() ) { ///case 1-a) just do default we don't know what else to do if ( node->getNode()->isOutputNode() ) { behavior = 0; } else { ///for either cases 1-b) or 1-c) we just connect the created node as input of the selected node. behavior = 1; } } ///2) and 3) are similar except for case b) else { ///case 2 or 3- a): connect the created node as output of the selected node. if ( node->getNode()->isOutputNode() ) { behavior = 2; } ///case b) else if ( node->getNode()->isInputNode() ) { if ( selected->getNode()->getEffectInstance()->isReader() ) { ///case 2-b) just do default we don't know what else to do behavior = 0; } else { ///case 3-b): connect the created node as input of the selected node behavior = 1; } } ///case c) connect created as output of the selected node else { behavior = 2; } } } NodePtr createdNodeInternal = node->getNode(); NodePtr selectedNodeInternal; if (selected) { selectedNodeInternal = selected->getNode(); } ///if behaviour is 1 , just check that we can effectively connect the node to avoid moving them for nothing ///otherwise fallback on behaviour 0 if (behavior == 1) { const std::vector<NodeWPtr > & inputs = selected->getNode()->getGuiInputs(); bool oneInputEmpty = false; for (std::size_t i = 0; i < inputs.size(); ++i) { if ( !inputs[i].lock() ) { oneInputEmpty = true; break; } } if (!oneInputEmpty) { behavior = 0; } } ProjectPtr proj = getGui()->getApp()->getProject(); ///default QPointF position; if (behavior == 0) { position.setX( ( viewPos.bottomRight().x() + viewPos.topLeft().x() ) / 2. ); position.setY( ( viewPos.topLeft().y() + viewPos.bottomRight().y() ) / 2. ); } else if (behavior == 1) { ///pop it above the selected node ///If this is the first connected input, insert it in a "linear" way so the tree remains vertical int nbConnectedInput = 0; const std::vector<Edge*> & selectedNodeInputs = selected->getInputsArrows(); for (std::vector<Edge*>::const_iterator it = selectedNodeInputs.begin(); it != selectedNodeInputs.end(); ++it) { NodeGuiPtr input; if (*it) { input = (*it)->getSource(); } if (input) { ++nbConnectedInput; } } ///connect it to the first input QSize selectedNodeSize = selected->getSize(); QSize createdNodeSize = node->getSize(); if (nbConnectedInput == 0) { QPointF selectedNodeMiddlePos = selected->scenePos() + QPointF(selectedNodeSize.width() / 2, selectedNodeSize.height() / 2); position.setX(selectedNodeMiddlePos.x() - createdNodeSize.width() / 2); position.setY( selectedNodeMiddlePos.y() - selectedNodeSize.height() / 2 - NodeGui::DEFAULT_OFFSET_BETWEEN_NODES - createdNodeSize.height() ); QRectF createdNodeRect( position.x(), position.y(), createdNodeSize.width(), createdNodeSize.height() ); ///now that we have the position of the node, move the inputs of the selected node to make some space for this node for (std::vector<Edge*>::const_iterator it = selectedNodeInputs.begin(); it != selectedNodeInputs.end(); ++it) { if ( (*it)->hasSource() ) { (*it)->getSource()->moveAbovePositionRecursively(createdNodeRect); } } int selectedInput = selectedNodeInternal->getPreferredInputForConnection(); if (selectedInput != -1) { bool ok = proj->connectNodes(selectedInput, createdNodeInternal, selectedNodeInternal, true); Q_UNUSED(ok); } } else { //ViewerInstancePtr isSelectedViewer = selectedNodeInternal->isEffectViewerInstance(); //Don't pop a dot, it will most likely annoy the user, just fallback on behavior 0 /* position.setX( ( viewPos.bottomRight().x() + viewPos.topLeft().x() ) / 2. ); position.setY( ( viewPos.topLeft().y() + viewPos.bottomRight().y() ) / 2. ); } else { */ QRectF selectedBbox = selected->mapToScene( selected->boundingRect() ).boundingRect(); QPointF selectedCenter = selectedBbox.center(); double y = selectedCenter.y() - selectedNodeSize.height() / 2. - NodeGui::DEFAULT_OFFSET_BETWEEN_NODES - createdNodeSize.height(); double x = selectedCenter.x() + nbConnectedInput * 150; position.setX(x - createdNodeSize.width() / 2.); position.setY(y); int index = selectedNodeInternal->getPreferredInputForConnection(); if (index != -1) { bool ok = proj->connectNodes(index, createdNodeInternal, selectedNodeInternal, true); Q_UNUSED(ok); } //} // if (isSelectedViewer) {*/ } // if (nbConnectedInput == 0) { } else { ///pop it below the selected node const NodesWList& outputs = selectedNodeInternal->getGuiOutputs(); if ( !createdNodeInternal->isOutputNode() || outputs.empty() ) { QSize selectedNodeSize = selected->getSize(); QSize createdNodeSize = node->getSize(); QPointF selectedNodeMiddlePos = selected->scenePos() + QPointF(selectedNodeSize.width() / 2, selectedNodeSize.height() / 2); ///actually move the created node where the selected node is position.setX(selectedNodeMiddlePos.x() - createdNodeSize.width() / 2); position.setY(selectedNodeMiddlePos.y() + (selectedNodeSize.height() / 2) + NodeGui::DEFAULT_OFFSET_BETWEEN_NODES); QRectF createdNodeRect( position.x(), position.y(), createdNodeSize.width(), createdNodeSize.height() ); ///and move the selected node below recusively for (NodesWList::const_iterator it = outputs.begin(); it != outputs.end(); ++it) { NodePtr output = it->lock(); if (!output) { continue; } NodeGuiIPtr output_i = output->getNodeGui(); if (!output_i) { continue; } NodeGuiPtr outputGui = toNodeGui( output_i ); assert(outputGui); if (outputGui) { outputGui->moveBelowPositionRecursively(createdNodeRect); } } ///Connect the created node to the selected node ///finally we connect the created node to the selected node int createdInput = createdNodeInternal->getPreferredInputForConnection(); if (createdInput != -1) { ignore_result( createdNodeInternal->connectInput(selectedNodeInternal, createdInput) ); } if ( !createdNodeInternal->isOutputNode() ) { ///we find all the nodes that were previously connected to the selected node, ///and connect them to the created node instead. std::map<NodePtr, int> outputsConnectedToSelectedNode; selectedNodeInternal->getOutputsConnectedToThisNode(&outputsConnectedToSelectedNode); for (std::map<NodePtr, int>::iterator it = outputsConnectedToSelectedNode.begin(); it != outputsConnectedToSelectedNode.end(); ++it) { if ( it->first->getParentMultiInstanceName().empty() && (it->first != createdNodeInternal) ) { /* Internal rotopaint nodes are connecting to the Rotopaint itself... make sure not to connect internal nodes of the tree */ RotoDrawableItemPtr stroke = it->first->getAttachedRotoItem(); if ( stroke && (stroke->getContext()->getNode() == selectedNodeInternal) ) { continue; } ignore_result( it->first->replaceInput(createdNodeInternal, it->second) ); // bool ok = proj->disconnectNodes(selectedNodeInternal.get(), it->first); // if (ok) { // ignore_result(proj->connectNodes(it->second, createdNodeInternal, it->first)); // } //assert(ok); Might not be ok if the disconnectNodes() action above was queued } } } } else { ///the created node is an output node and the selected node already has several outputs, create it aside QSize createdNodeSize = node->getSize(); QRectF selectedBbox = selected->mapToScene( selected->boundingRect() ).boundingRect(); QPointF selectedCenter = selectedBbox.center(); double y = selectedCenter.y() + selectedBbox.height() / 2. + NodeGui::DEFAULT_OFFSET_BETWEEN_NODES; double x = selectedCenter.x() + (int)outputs.size() * 150; position.setX(x - createdNodeSize.width() / 2.); position.setY(y); //Don't pop a dot, it will most likely annoy the user, just fallback on behavior 0 int index = createdNodeInternal->getPreferredInputForConnection(); bool ok = proj->connectNodes(index, selectedNodeInternal, createdNodeInternal, true); Q_UNUSED(ok); } } position = node->mapFromScene(position); position = node->mapToParent(position); node->setPosition( position.x(), position.y() ); } // moveNodesForIdealPosition
void GuiAppInstance::createNodeGui(const NodePtr &node, const NodePtr& parentMultiInstance, const CreateNodeArgs& args) { NodeCollectionPtr group = node->getGroup(); NodeGraph* graph; if (group) { NodeGraphI* graph_i = group->getNodeGraph(); assert(graph_i); graph = dynamic_cast<NodeGraph*>(graph_i); assert(graph); } else { graph = _imp->_gui->getNodeGraph(); } if (!graph) { throw std::logic_error(""); } NodesGuiList selectedNodes = graph->getSelectedNodes(); NodeGuiPtr nodegui = _imp->_gui->createNodeGUI(node, args); assert(nodegui); if (parentMultiInstance && nodegui) { nodegui->hideGui(); NodeGuiIPtr parentNodeGui_i = parentMultiInstance->getNodeGui(); assert(parentNodeGui_i); nodegui->setParentMultiInstance( boost::dynamic_pointer_cast<NodeGui>(parentNodeGui_i) ); } bool isViewer = node->isEffectViewerInstance() != 0; if (isViewer) { _imp->_gui->createViewerGui(node); } // Must be done after the viewer gui has been created _imp->_gui->createNodeViewerInterface(nodegui); NodeGroupPtr isGroup = node->isEffectNodeGroup(); if ( isGroup && isGroup->isSubGraphUserVisible() ) { _imp->_gui->createGroupGui(node, args); } ///Don't initialize inputs if it is a multi-instance child since it is not part of the graph if (!parentMultiInstance) { nodegui->initializeInputs(); } NodeSerializationPtr serialization = args.getProperty<NodeSerializationPtr >(kCreateNodeArgsPropNodeSerialization); if ( !serialization && !isViewer ) { ///we make sure we can have a clean preview. node->computePreviewImage( getTimeLine()->currentFrame() ); triggerAutoSave(); } ///only move main instances if ( node->getParentMultiInstanceName().empty() && !serialization) { bool autoConnect = args.getProperty<bool>(kCreateNodeArgsPropAutoConnect); if ( selectedNodes.empty() || serialization) { autoConnect = false; } double xPosHint = serialization ? INT_MIN : args.getProperty<double>(kCreateNodeArgsPropNodeInitialPosition, 0); double yPosHint = serialization ? INT_MIN : args.getProperty<double>(kCreateNodeArgsPropNodeInitialPosition, 1); if ( (xPosHint != INT_MIN) && (yPosHint != INT_MIN) && (!autoConnect) ) { QPointF pos = nodegui->mapToParent( nodegui->mapFromScene( QPointF(xPosHint, yPosHint) ) ); nodegui->refreshPosition( pos.x(), pos.y(), true ); } else { BackdropGuiPtr isBd = toBackdropGui(nodegui); if (!isBd) { NodeGuiPtr selectedNode; if ( !serialization && (selectedNodes.size() == 1) ) { selectedNode = selectedNodes.front(); BackdropGuiPtr isBdGui = toBackdropGui(selectedNode); if (isBdGui) { selectedNode.reset(); } } nodegui->getDagGui()->moveNodesForIdealPosition(nodegui, selectedNode, autoConnect); } } } } // createNodeGui
void NodeGraph::checkForHints(bool shiftdown, bool controlDown, const NodeGuiPtr& selectedNode, const QRectF& visibleSceneR) { NodePtr internalNode = selectedNode->getNode(); bool doMergeHints = shiftdown && controlDown; bool doConnectionHints = appPTR->getCurrentSettings()->isConnectionHintEnabled(); //Ignore hints for backdrops BackdropGuiPtr isBd = toBackdropGui( selectedNode ); if (isBd) { return; } if (!doMergeHints) { ///for nodes already connected don't show hint if ( ( internalNode->getMaxInputCount() == 0) && internalNode->hasOutputConnected() ) { doConnectionHints = false; } else if ( ( internalNode->getMaxInputCount() > 0) && internalNode->hasAllInputsConnected() && internalNode->hasOutputConnected() ) { doConnectionHints = false; } } if (!doConnectionHints) { return; } QRectF selectedNodeBbox = selectedNode->boundingRectWithEdges(); //selectedNode->mapToParent( selectedNode->boundingRect() ).boundingRect(); double tolerance = 10; selectedNodeBbox.adjust(-tolerance, -tolerance, tolerance, tolerance); NodeGuiPtr nodeToShowMergeRect; NodePtr selectedNodeInternalNode = selectedNode->getNode(); bool selectedNodeIsReader = selectedNodeInternalNode->getEffectInstance()->isReader() || selectedNodeInternalNode->getMaxInputCount() == 0; Edge* edge = 0; std::set<NodeGuiPtr> nodesWithinRect; getNodesWithinViewportRect(visibleWidgetRect(), &nodesWithinRect); { for (std::set<NodeGuiPtr>::iterator it = nodesWithinRect.begin(); it != nodesWithinRect.end(); ++it) { bool isAlreadyAnOutput = false; const NodesWList& outputs = internalNode->getGuiOutputs(); for (NodesWList::const_iterator it2 = outputs.begin(); it2 != outputs.end(); ++it2) { NodePtr node = it2->lock(); if (!node) { continue; } if ( node == (*it)->getNode() ) { isAlreadyAnOutput = true; break; } } if (isAlreadyAnOutput) { continue; } QRectF nodeBbox = (*it)->boundingRectWithEdges(); if ( ( (*it) != selectedNode ) && (*it)->isVisible() && nodeBbox.intersects(visibleSceneR) ) { if (doMergeHints) { //QRectF nodeRect = (*it)->mapToParent((*it)->boundingRect()).boundingRect(); NodePtr internalNode = (*it)->getNode(); if ( !internalNode->isOutputNode() && nodeBbox.intersects(selectedNodeBbox) ) { bool nHasInput = internalNode->hasInputConnected(); int nMaxInput = internalNode->getMaxInputCount(); bool selectedHasInput = selectedNodeInternalNode->hasInputConnected(); int selectedMaxInput = selectedNodeInternalNode->getMaxInputCount(); double nPAR = internalNode->getEffectInstance()->getAspectRatio(-1); double selectedPAR = selectedNodeInternalNode->getEffectInstance()->getAspectRatio(-1); double nFPS = internalNode->getEffectInstance()->getFrameRate(); double selectedFPS = selectedNodeInternalNode->getEffectInstance()->getFrameRate(); bool isValid = true; if ( (selectedPAR != nPAR) || (std::abs(nFPS - selectedFPS) > 0.01) ) { if (nHasInput || selectedHasInput) { isValid = false; } else if ( !nHasInput && (nMaxInput == 0) && !selectedHasInput && (selectedMaxInput == 0) ) { isValid = false; } } if (isValid) { nodeToShowMergeRect = (*it)->shared_from_this(); } } else { (*it)->setMergeHintActive(false); } } else { //!doMergeHints edge = (*it)->hasEdgeNearbyRect(selectedNodeBbox); ///if the edge input is the selected node don't continue if ( edge && ( edge->getSource() == selectedNode) ) { edge = 0; } if ( edge && edge->isOutputEdge() ) { if (selectedNodeIsReader) { continue; } int prefInput = selectedNodeInternalNode->getPreferredInputForConnection(); if (prefInput == -1) { edge = 0; } else { Node::CanConnectInputReturnValue ret = selectedNodeInternalNode->canConnectInput(edge->getSource()->getNode(), prefInput); if (ret != Node::eCanConnectInput_ok) { edge = 0; } } } if ( edge && !edge->isOutputEdge() ) { if ( (*it)->getNode()->getEffectInstance()->isReader() || ( (*it)->getNode()->getMaxInputCount() == 0 ) ) { edge = 0; continue; } //Check that the edge can connect to the selected node { Node::CanConnectInputReturnValue ret = edge->getDest()->getNode()->canConnectInput( selectedNodeInternalNode, edge->getInputNumber() ); if ( (ret == Node::eCanConnectInput_inputAlreadyConnected) && !selectedNodeIsReader ) { ret = Node::eCanConnectInput_ok; } if (ret != Node::eCanConnectInput_ok) { edge = 0; } } //Check that the selected node can connect to the input of the edge if (edge) { NodeGuiPtr edgeHasSource = edge->getSource(); if (edgeHasSource) { int prefInput = selectedNodeInternalNode->getPreferredInputForConnection(); if (prefInput != -1) { Node::CanConnectInputReturnValue ret = selectedNodeInternalNode->canConnectInput(edgeHasSource->getNode(), prefInput); if ( (ret == Node::eCanConnectInput_inputAlreadyConnected) && !selectedNodeIsReader ) { ret = Node::eCanConnectInput_ok; } if (ret != Node::eCanConnectInput_ok) { edge = 0; } } } } } if (edge) { edge->setUseHighlight(true); break; } } // doMergeHints } } } // QMutexLocker l(&_imp->_nodesMutex); if ( _imp->_highLightedEdge && ( _imp->_highLightedEdge != edge) ) { _imp->_highLightedEdge->setUseHighlight(false); _imp->_hintInputEdge->hide(); _imp->_hintOutputEdge->hide(); } _imp->_highLightedEdge = edge; if ( edge && edge->getSource() && edge->getDest() ) { ///setup the hints edge ///find out if the node is already connected to what the edge is connected bool alreadyConnected = false; const std::vector<NodeWPtr > & inpNodes = selectedNode->getNode()->getGuiInputs(); for (std::size_t i = 0; i < inpNodes.size(); ++i) { if ( inpNodes[i].lock() == edge->getSource()->getNode() ) { alreadyConnected = true; break; } } if ( !_imp->_hintInputEdge->isVisible() ) { if (!alreadyConnected) { int prefInput = selectedNode->getNode()->getPreferredInputForConnection(); _imp->_hintInputEdge->setInputNumber(prefInput != -1 ? prefInput : 0); _imp->_hintInputEdge->setSourceAndDestination(edge->getSource(), selectedNode); _imp->_hintInputEdge->setVisible(true); } _imp->_hintOutputEdge->setInputNumber( edge->getInputNumber() ); _imp->_hintOutputEdge->setSourceAndDestination( selectedNode, edge->getDest() ); _imp->_hintOutputEdge->setVisible(true); } else { if (!alreadyConnected) { _imp->_hintInputEdge->initLine(); } _imp->_hintOutputEdge->initLine(); } } else if (edge) { ///setup only 1 of the hints edge if ( _imp->_highLightedEdge && !_imp->_hintInputEdge->isVisible() ) { if ( edge->isOutputEdge() ) { int prefInput = selectedNode->getNode()->getPreferredInputForConnection(); if (prefInput != -1) { _imp->_hintInputEdge->setInputNumber(prefInput); _imp->_hintInputEdge->setSourceAndDestination(edge->getSource(), selectedNode); _imp->_hintInputEdge->setVisible(true); } } else { _imp->_hintInputEdge->setInputNumber( edge->getInputNumber() ); _imp->_hintInputEdge->setSourceAndDestination( selectedNode, edge->getDest() ); _imp->_hintInputEdge->setVisible(true); } } else if ( _imp->_highLightedEdge && _imp->_hintInputEdge->isVisible() ) { _imp->_hintInputEdge->initLine(); } } else if (nodeToShowMergeRect) { nodeToShowMergeRect->setMergeHintActive(true); selectedNode->setMergeHintActive(true); _imp->_mergeHintNode = nodeToShowMergeRect; } else { selectedNode->setMergeHintActive(false); _imp->_mergeHintNode.reset(); } } // NodeGraph::checkForHints