Example #1
0
void
ViewerNodePrivate::getAllViewerNodes(bool inGroupOnly, std::list<ViewerNodePtr>& viewerNodes) const
{
    NodeCollectionPtr collection;
    if (inGroupOnly) {
        collection = _publicInterface->getNode()->getGroup();
    } else {
        collection = _publicInterface->getApp()->getProject();
    }
    NodesList nodes;
    if (inGroupOnly) {
        nodes = collection->getNodes();
    } else {
        collection->getNodes_recursive(nodes, false);
    }
    for (NodesList::iterator it = nodes.begin(); it != nodes.end(); ++it) {
        if (!(*it)->isActivated()) {
            continue;
        }
        ViewerNodePtr isViewer = (*it)->isEffectViewerNode();
        if (isViewer) {
            viewerNodes.push_back(isViewer);
        }
    }
}
Example #2
0
static void
restoreLinksRecursive(const NodeCollectionPtr& group,
                      const SERIALIZATION_NAMESPACE::NodeSerializationList& nodes,
                      const std::list<std::pair<NodePtr, SERIALIZATION_NAMESPACE::NodeSerializationPtr > >* allCreatedNodes)
{
    for (SERIALIZATION_NAMESPACE::NodeSerializationList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {

        // The nodes created from the serialization may have changed name if another node with the same script-name already existed.
        // By chance since we created all nodes within the same Group at the same time, we have a list of the old node serialization
        // and the corresponding created node (with its new script-name).
        // If we find a match, make sure we use the new node script-name to restore the input.
        NodePtr foundNode;
        if (allCreatedNodes) {
            foundNode = Project::findNodeWithScriptName((*it)->_nodeScriptName, *allCreatedNodes);
        }
        if (!foundNode) {
            // We did not find the node in the serialized nodes list, the last resort is to look into already created nodes
            // and find an exact match, hoping the script-name of the node did not change.
            foundNode = group->getNodeByName((*it)->_nodeScriptName);
        }
        if (!foundNode) {
            continue;
        }

        // The allCreatedNodes list is useful if the nodes that we created had their script-name changed from what was inside the node serialization object.
        // It may have changed if a node would already exist in the group with the same script-name.
        // This kind of conflict may only occur in the top-level graph that we are restoring: sub-graphs are created entirely so script-names should remain
        // the same between the serilization object and the created node.
        foundNode->restoreKnobsLinks(**it, allCreatedNodes ? *allCreatedNodes : std::list<std::pair<NodePtr, SERIALIZATION_NAMESPACE::NodeSerializationPtr > >());

        NodeGroupPtr isGroup = toNodeGroup(foundNode->getEffectInstance());
        if (isGroup) {

            // For sub-groupe, we don't have the list of created nodes, and their serialization list, but we should not need it:
            // It's only the top-level group that we create that may have conflicts with script-names, sub-groups are conflict free since
            // we just created them.
            restoreLinksRecursive(isGroup, (*it)->_children, 0);
        }
    }
}
Example #3
0
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
Example #4
0
bool
Project::restoreGroupFromSerialization(const SERIALIZATION_NAMESPACE::NodeSerializationList & serializedNodes,
                                       const NodeCollectionPtr& group,
                                       std::list<std::pair<NodePtr, SERIALIZATION_NAMESPACE::NodeSerializationPtr > >* createdNodesOut)
{
    bool mustShowErrorsLog = false;

    NodeGroupPtr isGrp = toNodeGroup(group);

    QString groupName;
    if (isGrp) {
        groupName = QString::fromUtf8( isGrp->getNode()->getLabel().c_str() );
    } else {
        groupName = tr("top-level");
    }
    group->getApplication()->updateProjectLoadStatus( tr("Creating nodes in group: %1").arg(groupName) );


    std::list<std::pair<NodePtr, SERIALIZATION_NAMESPACE::NodeSerializationPtr > > createdNodes;



    // Loop over all node serialization and create them first
    for (SERIALIZATION_NAMESPACE::NodeSerializationList::const_iterator it = serializedNodes.begin(); it != serializedNodes.end(); ++it) {

        NodePtr node = appPTR->createNodeForProjectLoading(*it, group);
        if (!node) {
            QString text( tr("ERROR: The node %1 version %2.%3"
                             " was found in the script but does not"
                             " exist in the loaded plug-ins.")
                         .arg( QString::fromUtf8( (*it)->_pluginID.c_str() ) )
                         .arg((*it)->_pluginMajorVersion).arg((*it)->_pluginMinorVersion) );
            appPTR->writeToErrorLog_mt_safe(tr("Project"), QDateTime::currentDateTime(), text);
            mustShowErrorsLog = true;
            continue;
        } else {
            if (node->getPluginID() == PLUGINID_NATRON_STUB) {
                // If the node could not be created and we made a stub instead, warn the user
                QString text( tr("WARNING: The node %1 (%2 version %3.%4) "
                                 "was found in the script but the plug-in could not be found. It has been replaced by a pass-through node instead.")
                             .arg( QString::fromUtf8( (*it)->_nodeScriptName.c_str() ) )
                             .arg( QString::fromUtf8( (*it)->_pluginID.c_str() ) )
                             .arg((*it)->_pluginMajorVersion)
                             .arg((*it)->_pluginMinorVersion));
                appPTR->writeToErrorLog_mt_safe(tr("Project"), QDateTime::currentDateTime(), text);
                mustShowErrorsLog = true;
            } else if ( (*it)->_pluginMajorVersion != -1 && (node->getMajorVersion() != (int)(*it)->_pluginMajorVersion) ) {
                // If the node has a IOContainer don't do this check: when loading older projects that had a
                // ReadOIIO node for example in version 2, we would now create a new Read meta-node with version 1 instead
                QString text( tr("WARNING: The node %1 (%2 version %3.%4) "
                                 "was found in the script but was loaded "
                                 "with version %5.%6 instead.")
                             .arg( QString::fromUtf8( (*it)->_nodeScriptName.c_str() ) )
                             .arg( QString::fromUtf8( (*it)->_pluginID.c_str() ) )
                             .arg((*it)->_pluginMajorVersion)
                             .arg((*it)->_pluginMinorVersion)
                             .arg( node->getPlugin()->getPropertyUnsafe<unsigned int>(kNatronPluginPropVersion, 0) )
                             .arg( node->getPlugin()->getPropertyUnsafe<unsigned int>(kNatronPluginPropVersion, 1) ) );
                appPTR->writeToErrorLog_mt_safe(tr("Project"), QDateTime::currentDateTime(), text);
            }
        }

        assert(node);

        createdNodes.push_back(std::make_pair(node, *it));

    } // for all node serialization


    group->getApplication()->updateProjectLoadStatus( tr("Restoring graph links in group: %1").arg(groupName) );


    // Connect the nodes together
    for (std::list<std::pair<NodePtr, SERIALIZATION_NAMESPACE::NodeSerializationPtr > >::const_iterator it = createdNodes.begin(); it != createdNodes.end(); ++it) {


        // Loop over the inputs map
        // This is a map <input label, input node name>
        //
        // When loading projects before Natron 2.2, the inputs contain both masks and inputs.
        //

        restoreInputs(it->first, it->second->_inputs, createdNodes, false /*isMasks*/);

        // After Natron 2.2, masks are saved separatly
        restoreInputs(it->first, it->second->_masks, createdNodes, true /*isMasks*/);

    } // for (std::list< NodeSerializationPtr >::const_iterator it = serializedNodes.begin(); it != serializedNodes.end(); ++it) {


    if (createdNodesOut) {
        *createdNodesOut = createdNodes;
    }
    // If we created all sub-groups recursively, then we are in the top-level group. We may now restore all links
    if (!group->getApplication()->isCreatingNode()) {

        // Now that we created all nodes. There may be cross-graph link(s) and they can only be truely restored now.
        restoreLinksRecursive(group, serializedNodes, createdNodesOut);
    }


    return !mustShowErrorsLog;
} // ProjectPrivate::restoreGroupFromSerialization
Example #5
0
PickKnobDialog::PickKnobDialog(DockablePanel* panel,
                               QWidget* parent)
    : QDialog(parent)
    , _imp( new PickKnobDialogPrivate(panel) )
{
    NodeSettingsPanel* nodePanel = dynamic_cast<NodeSettingsPanel*>(panel);

    assert(nodePanel);
    if (!nodePanel) {
        throw std::logic_error("PickKnobDialog::PickKnobDialog()");
    }
    NodeGuiPtr nodeGui = nodePanel->getNodeGui();
    NodePtr node = nodeGui->getNode();
    NodeGroupPtr isGroup = node->isEffectNodeGroup();
    NodeCollectionPtr collec = node->getGroup();
    NodeGroupPtr isCollecGroup = toNodeGroup(collec);
    NodesList collectNodes = collec->getNodes();
    for (NodesList::iterator it = collectNodes.begin(); it != collectNodes.end(); ++it) {
        if ((*it)->isActivated() && (*it)->getNodeGui() && ( (*it)->getKnobs().size() > 0 ) ) {
            _imp->allNodes.push_back(*it);
        }
    }
    if (isCollecGroup) {
        _imp->allNodes.push_back( isCollecGroup->getNode() );
    }
    if (isGroup) {
        NodesList groupnodes = isGroup->getNodes();
        for (NodesList::iterator it = groupnodes.begin(); it != groupnodes.end(); ++it) {
            if ( (*it)->getNodeGui() &&
                (*it)->isActivated() &&
                ( (*it)->getKnobs().size() > 0 ) ) {
                _imp->allNodes.push_back(*it);
            }
        }
    }
    QStringList nodeNames;
    for (NodesList::iterator it = _imp->allNodes.begin(); it != _imp->allNodes.end(); ++it) {
        QString name = QString::fromUtf8( (*it)->getLabel().c_str() );
        nodeNames.push_back(name);
    }
    nodeNames.sort();

    _imp->mainLayout = new QGridLayout(this);
    _imp->selectNodeLabel = new Label( tr("Node:") );
    _imp->nodeSelectionCombo = new CompleterLineEdit(nodeNames, nodeNames, false, this);
    _imp->nodeSelectionCombo->setToolTip( NATRON_NAMESPACE::convertFromPlainText(tr("Input the name of a node in the current project."), NATRON_NAMESPACE::WhiteSpaceNormal) );
    _imp->nodeSelectionCombo->setFocus(Qt::PopupFocusReason);

    _imp->knobSelectionCombo = new ComboBox(this);
    QObject::connect( _imp->knobSelectionCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onKnobComboIndexChanged(int)) );
    QString useAliasTt = NATRON_NAMESPACE::convertFromPlainText(tr("If checked, an alias of the selected parameter will be created, coyping entirely its state. "
                                                           "Only the script-name, label and tooltip will be editable.\n"
                                                           "For choice parameters this will also "
                                                           "dynamically refresh the menu entries when the original parameter's menu is changed.\n"
                                                           "When unchecked, a simple expression will be set linking the two parameters, but things such as dynamic menus "
                                                           "will be disabled."), NATRON_NAMESPACE::WhiteSpaceNormal);
    _imp->useAliasLabel = new Label(tr("Make Alias:"), this);
    _imp->useAliasLabel->setToolTip(useAliasTt);
    _imp->useAliasCheckBox = new QCheckBox(this);
    _imp->useAliasCheckBox->setToolTip(useAliasTt);
    _imp->useAliasCheckBox->setChecked(true);

    QObject::connect( _imp->nodeSelectionCombo, SIGNAL(itemCompletionChosen()), this, SLOT(onNodeComboEditingFinished()) );

    _imp->destPageLabel = new Label(tr("Page:"), this);
    QString pagett = NATRON_NAMESPACE::convertFromPlainText(tr("Select the page into which the parameter will be created."), NATRON_NAMESPACE::WhiteSpaceNormal);
    _imp->destPageLabel->setToolTip(pagett);
    _imp->destPageCombo = new ComboBox(this);
    _imp->destPageCombo->setToolTip(pagett);
    QObject::connect( _imp->destPageCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onPageComboIndexChanged(int)) );
    const KnobsVec& knobs = node->getKnobs();
    for (std::size_t i = 0; i < knobs.size(); ++i) {
        if ( knobs[i]->isUserKnob() ) {
            KnobPagePtr isPage = toKnobPage(knobs[i]);
            if (isPage) {
                _imp->pages.push_back(isPage);
                _imp->destPageCombo->addItem( QString::fromUtf8( isPage->getName().c_str() ) );
            } else {
                KnobGroupPtr isGrp = toKnobGroup(knobs[i]);
                if (isGrp) {
                    _imp->groups.push_back(isGrp);
                }
            }
        }
    }
    if (_imp->destPageCombo->count() == 0) {
        _imp->destPageLabel->hide();
        _imp->destPageCombo->hide();
    }


    _imp->groupLabel = new Label(tr("Group:"), this);
    QString grouptt = NATRON_NAMESPACE::convertFromPlainText(tr("Select the group into which the parameter will be created."), NATRON_NAMESPACE::WhiteSpaceNormal);
    _imp->groupCombo = new ComboBox(this);
    _imp->groupLabel->setToolTip(grouptt);
    _imp->groupCombo->setToolTip(grouptt);
    onPageComboIndexChanged(0);

    _imp->buttons = new DialogButtonBox(QDialogButtonBox::StandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel),
                                         Qt::Horizontal, this);
    QObject::connect( _imp->buttons, SIGNAL(accepted()), this, SLOT(accept()) );
    QObject::connect( _imp->buttons, SIGNAL(rejected()), this, SLOT(reject()) );

    _imp->mainLayout->addWidget(_imp->selectNodeLabel, 0, 0, 1, 1);
    _imp->mainLayout->addWidget(_imp->nodeSelectionCombo, 0, 1, 1, 1);
    _imp->mainLayout->addWidget(_imp->knobSelectionCombo, 0, 2, 1, 1);
    _imp->mainLayout->addWidget(_imp->useAliasLabel, 1, 0, 1, 1);
    _imp->mainLayout->addWidget(_imp->useAliasCheckBox, 1, 1, 1, 1);
    _imp->mainLayout->addWidget(_imp->destPageLabel, 2, 0, 1, 1);
    _imp->mainLayout->addWidget(_imp->destPageCombo, 2, 1, 1, 1);
    _imp->mainLayout->addWidget(_imp->groupLabel, 2, 2, 1, 1);
    _imp->mainLayout->addWidget(_imp->groupCombo, 2, 3, 1, 1);
    _imp->mainLayout->addWidget(_imp->buttons, 3, 0, 1, 3);

    QTimer::singleShot( 25, _imp->nodeSelectionCombo, SLOT(showCompleter()) );
}
Example #6
0
void
Gui::removeViewerTab(ViewerTab* tab,
                     bool initiatedFromNode,
                     bool deleteData)
{
    assert(tab);
    unregisterTab(tab);

    if (tab == _imp->_activeViewer) {
        _imp->_activeViewer = 0;
    }
    NodeGraph* graph = 0;
    NodeGroupPtr isGrp;
    NodeCollectionPtr collection;
    if ( tab->getInternalNode() && tab->getInternalNode()->getNode() ) {
        NodeCollectionPtr collection = tab->getInternalNode()->getNode()->getGroup();
        isGrp = toNodeGroup(collection);
    }


    if (isGrp) {
        NodeGraphI* graph_i = isGrp->getNodeGraph();
        assert(graph_i);
        graph = dynamic_cast<NodeGraph*>(graph_i);
    } else {
        graph = getNodeGraph();
    }
    assert(graph);
    if (!graph) {
        throw std::logic_error("");
    }

    ViewerTab* lastSelectedViewer = graph->getLastSelectedViewer();

    if (lastSelectedViewer == tab) {
        bool foundOne = false;
        NodesList nodes;
        if (collection) {
            nodes = collection->getNodes();
        }
        for (NodesList::iterator it = nodes.begin(); it != nodes.end(); ++it) {
            ViewerNodePtr isViewer = (*it)->isEffectViewerNode();
            if ( !isViewer || ( isViewer == tab->getInternalNode() ) || !(*it)->isActivated() ) {
                continue;
            }
            OpenGLViewerI* viewerI = isViewer->getUiContext();
            assert(viewerI);
            ViewerGL* glViewer = dynamic_cast<ViewerGL*>(viewerI);
            assert(glViewer);
            if (glViewer) {
                graph->setLastSelectedViewer( glViewer->getViewerTab() );
            }
            foundOne = true;
            break;
        }
        if (!foundOne) {
            graph->setLastSelectedViewer(0);
        }
    }

    ViewerNodePtr viewerNode = tab->getInternalNode();
    ViewerInstancePtr internalViewer;
    if (viewerNode) {
        internalViewer = viewerNode->getInternalViewerNode();
    }
    if (internalViewer) {
        internalViewer->abortAnyEvaluation();
        if (getApp()->getLastViewerUsingTimeline() == internalViewer) {
            getApp()->discardLastViewerUsingTimeline();
        }
    }

    if (!initiatedFromNode) {
        assert(_imp->_nodeGraphArea);
        ///call the deleteNode which will call this function again when the node will be deactivated.
        NodePtr internalNode = tab->getInternalNode()->getNode();
        NodeGuiIPtr guiI = internalNode->getNodeGui();
        NodeGuiPtr gui = boost::dynamic_pointer_cast<NodeGui>(guiI);
        assert(gui);
        NodeGraphI* graph_i = internalNode->getGroup()->getNodeGraph();
        assert(graph_i);
        NodeGraph* graph = dynamic_cast<NodeGraph*>(graph_i);
        assert(graph);
        if (graph) {
            graph->removeNode(gui);
        }
    } else {
        tab->hide();


        TabWidget* container = dynamic_cast<TabWidget*>( tab->parentWidget() );
        if (container) {
            container->removeTab(tab, false);
        }

        if (deleteData) {
            QMutexLocker l(&_imp->_viewerTabsMutex);
            std::list<ViewerTab*>::iterator it = std::find(_imp->_viewerTabs.begin(), _imp->_viewerTabs.end(), tab);
            if ( it != _imp->_viewerTabs.end() ) {
                _imp->_viewerTabs.erase(it);
            }
            tab->notifyGuiClosingPublic();
            tab->deleteLater();
        }
    }
    Q_EMIT viewersChanged();
} // Gui::removeViewerTab
Example #7
0
ViewerTab*
Gui::addNewViewerTab(const NodeGuiPtr& node,
                     TabWidget* where)
{
    if (!node) {
        return 0;
    }

    ViewerNodePtr viewer = node->getNode()->isEffectViewerNode();

    NodesGuiList activeNodeViewerUi, nodeViewerUi;

    //Don't create tracker & roto interface for file dialog preview viewer
    NodeCollectionPtr group = viewer->getNode()->getGroup();
    if (group) {
        if ( !_imp->_viewerTabs.empty() ) {
            ( *_imp->_viewerTabs.begin() )->getNodesViewerInterface(&nodeViewerUi, &activeNodeViewerUi);
        } else {
            NodeGraph* graph = dynamic_cast<NodeGraph*>( group->getNodeGraph() );
            if (!graph) {
                graph = _imp->_nodeGraphArea;
            }

            if (graph) {
                const NodesGuiList & allNodes = graph->getAllActiveNodes();
                std::set<std::string> activeNodesPluginID;

                for (NodesGuiList::const_iterator it = allNodes.begin(); it != allNodes.end(); ++it) {
                    nodeViewerUi.push_back( *it );
                    std::string pluginID = (*it)->getNode()->getPluginID();
                    std::set<std::string>::iterator found = activeNodesPluginID.find(pluginID);
                    if ( found == activeNodesPluginID.end() ) {
                        activeNodesPluginID.insert(pluginID);
                        activeNodeViewerUi.push_back(*it);
                    }
                }
            }
        }
    }

    std::string nodeName =  node->getNode()->getFullyQualifiedName();
    for (std::size_t i = 0; i < nodeName.size(); ++i) {
        if (nodeName[i] == '.') {
            nodeName[i] = '_';
        }
    }
    std::string label;
    NodeGraph::makeFullyQualifiedLabel(node->getNode(), &label);

    ViewerTab* tab = new ViewerTab(nodeName, nodeViewerUi, activeNodeViewerUi, this, node, where);
    tab->setLabel(label);

    QObject::connect( tab->getViewer(), SIGNAL(imageChanged(int,bool)), this, SLOT(onViewerImageChanged(int,bool)) );
    {
        QMutexLocker l(&_imp->_viewerTabsMutex);
        _imp->_viewerTabs.push_back(tab);
        if (!_imp->_activeViewer) {
            _imp->_activeViewer = tab;
        }
    }
    where->appendTab(tab, tab);
    Q_EMIT viewersChanged();

    return tab;
} // Gui::addNewViewerTab