Beispiel #1
0
ViewerTab::~ViewerTab()
{
    Gui* gui = getGui();
    if (gui) {
        NodeGraph* graph = 0;
        ViewerNodePtr internalNode = getInternalNode();

        ViewerInstancePtr viewerNode = internalNode ? internalNode->getInternalViewerNode() : ViewerInstancePtr();
        if (viewerNode) {
            NodeCollectionPtr collection = viewerNode->getNode()->getGroup();
            if (collection) {
                NodeGroupPtr isGrp = toNodeGroup(collection);
                if (isGrp) {
                    NodeGraphI* graph_i = isGrp->getNodeGraph();
                    if (graph_i) {
                        graph = dynamic_cast<NodeGraph*>(graph_i);
                        assert(graph);
                    }
                } else {
                    graph = gui->getNodeGraph();
                }
            }
            internalNode->invalidateUiContext();
        } else {
            graph = gui->getNodeGraph();
        }
        assert(graph);
        GuiAppInstancePtr app = gui->getApp();
        if ( app && !app->isClosing() && graph && (graph->getLastSelectedViewer() == this) ) {
            graph->setLastSelectedViewer(0);
        }
    }
    _imp->nodesContext.clear();
}
Beispiel #2
0
void
NodeAnimPrivate::refreshParentContainerRange()
{
    NodeGuiPtr nodeUI = nodeGui.lock();
    NodePtr node = nodeUI->getNode();
    if (!node) {
        return;
    }
    AnimationModulePtr isAnimModule = toAnimationModule(model.lock());
    assert(isAnimModule);

    // If inside a group, refresh the group
    {
        NodeGroupPtr parentGroup = toNodeGroup( node->getGroup() );
        NodeAnimPtr parentGroupNodeAnim;

        if (parentGroup) {
            parentGroupNodeAnim = isAnimModule->findNodeAnim( parentGroup->getNode() );
        }
        if (parentGroupNodeAnim) {
            parentGroupNodeAnim->refreshFrameRange();
        }
    }
    // if modified by a time node, refresh its frame range as well
    {
        NodeAnimPtr isConnectedToTimeNode = isAnimModule->getNearestTimeNodeFromOutputsInternal(node);
        if (isConnectedToTimeNode) {
            isConnectedToTimeNode->refreshFrameRange();
        }
    }
} // refreshParentContainerRange
Beispiel #3
0
void
AnimationModule::addNode(const NodeGuiPtr& nodeGui)
{
    // Check if it already exists
    for (std::list<NodeAnimPtr>::const_iterator it = _imp->nodes.begin(); it != _imp->nodes.end(); ++it) {
        if ((*it)->getNodeGui() == nodeGui) {
            (*it)->refreshVisibility();
            return;
        }
    }
    
    // Determinate the node type
    // It will be useful to identify and sort tree items
    AnimatedItemTypeEnum nodeType = eAnimatedItemTypeCommon;

    NodePtr node = nodeGui->getNode();

    assert(node && node->getGroup());
    if ( !node || !node->getGroup() ) {
        return;
    }

    EffectInstancePtr effectInstance = node->getEffectInstance();

    // Don't add an item for this node if it doesn't have any knob that may animate
    //if ( !getNodeCanAnimate(node) ) {
    //    return;
    //}

    std::string pluginID = node->getPluginID();
    NodeGroupPtr isGroup = toNodeGroup(effectInstance);

    if (effectInstance->isReader()) {
        nodeType = eAnimatedItemTypeReader;
    } else if (isGroup) {
        nodeType = eAnimatedItemTypeGroup;
    } else if (pluginID == PLUGINID_OFX_RETIME) {
        nodeType = eAnimatedItemTypeRetime;
    } else if (pluginID == PLUGINID_OFX_TIMEOFFSET) {
        nodeType = eAnimatedItemTypeTimeOffset;
    } else if (pluginID == PLUGINID_OFX_FRAMERANGE) {
        nodeType = eAnimatedItemTypeFrameRange;
    }

    // The NodeAnim should not be created if there's no settings panel.
    assert(nodeGui->getSettingPanel());

    NodeAnimPtr anim(NodeAnim::create(toAnimationModule(shared_from_this()), nodeType, nodeGui) );
    _imp->nodes.push_back(anim);

    Q_EMIT nodeAdded(anim);
} // AnimationModule::addNode
Beispiel #4
0
void
Gui::createGroupGui(const NodePtr & group,
                    const CreateNodeArgs& args)
{
    NodeGroupPtr isGrp = toNodeGroup( group->getEffectInstance()->shared_from_this() );

    assert(isGrp);
    NodeCollectionPtr collection = boost::dynamic_pointer_cast<NodeCollection>(isGrp);
    assert(collection);

    TabWidget* where = 0;
    if (_imp->_lastFocusedGraph) {
        TabWidget* isTab = dynamic_cast<TabWidget*>( _imp->_lastFocusedGraph->parentWidget() );
        if (isTab) {
            where = isTab;
        } else {
            std::list<TabWidgetI*> panes = getApp()->getTabWidgetsSerialization();
            assert( !panes.empty() );
            where = dynamic_cast<TabWidget*>(panes.front());
        }
    }

    QGraphicsScene* scene = new QGraphicsScene(this);
    scene->setItemIndexMethod(QGraphicsScene::NoIndex);

    
    std::string newName = isGrp->getNode()->getFullyQualifiedName();
    for (std::size_t i = 0; i < newName.size(); ++i) {
        if (newName[i] == '.') {
            newName[i] = '_';
        }
    }
    newName += "_NodeGraph";
    std::string label = tr(" Node Graph").toStdString();
    NodeGraph::makeFullyQualifiedLabel(group, &label);


    NodeGraph* nodeGraph = new NodeGraph(this, collection, newName, scene, this);
    nodeGraph->setLabel(label);
    nodeGraph->setObjectName( QString::fromUtf8( group->getLabel().c_str() ) );
    _imp->_groups.push_back(nodeGraph);
    
    SERIALIZATION_NAMESPACE::NodeSerializationPtr serialization = args.getPropertyUnsafe<SERIALIZATION_NAMESPACE::NodeSerializationPtr>(kCreateNodeArgsPropNodeSerialization);
    bool showSubGraph = args.getPropertyUnsafe<bool>(kCreateNodeArgsPropSubGraphOpened);
    if ( showSubGraph && where && !serialization ) {
        where->appendTab(nodeGraph, nodeGraph);
        QTimer::singleShot( 25, nodeGraph, SLOT(centerOnAllNodes()) );
    } else {
        nodeGraph->setVisible(false);
    }
}
Beispiel #5
0
NodeAnimPtr AnimationModule::getGroupNodeAnim(const NodeAnimPtr& node) const
{
    NodePtr internalNode = node->getInternalNode();
    if (!internalNode) {
        return NodeAnimPtr();
    }
    NodeGroupPtr parentGroup = toNodeGroup( internalNode->getGroup() );
    NodeAnimPtr parentGroupNodeAnim;

    if (parentGroup) {
        parentGroupNodeAnim = findNodeAnim( parentGroup->getNode() );
    }

    return parentGroupNodeAnim;
}
void
NodePrivate::runOnNodeDeleteCB()
{

    if (_publicInterface->getScriptName_mt_safe().empty()) {
        return;
    }
    std::string cb = _publicInterface->getApp()->getProject()->getOnNodeDeleteCB();
    NodeCollectionPtr group = _publicInterface->getGroup();

    if (!group) {
        return;
    }

    std::string callbackFunction;
    if (figureOutCallbackName(cb, &callbackFunction)) {
        runOnNodeDeleteCBInternal(callbackFunction);
    }




    // If this is a group, run the node deleted callback on itself
    {
        cb = effect->getBeforeNodeRemovalCallback();
        if (!cb.empty()) {
            if (figureOutCallbackName(cb, &callbackFunction)) {
                runOnNodeDeleteCBInternal(callbackFunction);
            }

        }
    }

    // if there's a parent group, run the node deletec callback on the parent
    NodeGroupPtr isParentGroup = toNodeGroup(group);
    if (isParentGroup) {
        NodePtr grpNode = isParentGroup->getNode();
        if (grpNode) {
            cb = isParentGroup->getBeforeNodeRemovalCallback();
            if (figureOutCallbackName(cb, &callbackFunction)) {
                runOnNodeDeleteCBInternal(callbackFunction);
            }
        }
    }
}
Beispiel #7
0
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);
       }*/
}
Beispiel #8
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);
        }
    }
}
void
NodePrivate::runOnNodeCreatedCB(bool userEdited)
{

    std::string cb = _publicInterface->getApp()->getProject()->getOnNodeCreatedCB();
    NodeCollectionPtr group = _publicInterface->getGroup();

    if (!group) {
        return;
    }
    std::string callbackFunction;
    if (figureOutCallbackName(cb, &callbackFunction)) {
        runOnNodeCreatedCBInternal(callbackFunction, userEdited);
    }

    // If this is a group, run the node created callback on itself
    cb = effect->getAfterNodeCreatedCallback();
    if (!cb.empty()) {
        if (figureOutCallbackName(cb, &callbackFunction)) {
            runOnNodeCreatedCBInternal(callbackFunction, userEdited);
        }

    }

    // if there's a parent group, run the node created callback on the parent
    NodeGroupPtr isParentGroup = toNodeGroup(group);
    if (isParentGroup) {
        NodePtr grpNode = isParentGroup->getNode();
        if (grpNode) {
            cb = isParentGroup->getAfterNodeCreatedCallback();
            if (figureOutCallbackName(cb, &callbackFunction)) {
                runOnNodeCreatedCBInternal(callbackFunction, userEdited);
            }
        }
    }

}
Beispiel #10
0
std::string
PasteKnobClipBoardUndoCommand::makeLinkExpression(const std::vector<std::string>& projectViewNames,
                                                  const KnobIPtr& targetKnob,
                                                  bool multCurve,
                                                  const KnobIPtr& fromKnob,
                                                  DimSpec fromDimension,
                                                  ViewSetSpec fromView,
                                                  DimSpec targetDimension,
                                                  ViewSetSpec targetView)
{
    EffectInstancePtr fromEffect = toEffectInstance( fromKnob->getHolder() );
    EffectInstancePtr toEffect = toEffectInstance( targetKnob->getHolder() );
    assert(fromEffect && toEffect);
    if (!fromEffect || !toEffect) {
        return std::string();
    }

    std::stringstream ss;
    if (fromEffect == toEffect) {
        // Same node, use thisNode
        ss << "thisNode.";
    } else {
        // If the container of the effect is a group, prepend thisGroup, otherwise use
        // the canonical app prefix
        NodeGroupPtr isEffectContainerGroup;
        {
            NodeCollectionPtr effectContainer = fromEffect->getNode()->getGroup();
            isEffectContainerGroup = toNodeGroup(effectContainer);
        }
        if (isEffectContainerGroup) {
            ss << "thisGroup.";
        } else {
            ss << fromEffect->getApp()->getAppIDString() << ".";
        }
        ss << fromEffect->getNode()->getScriptName_mt_safe() << ".";
    }

    // Call getValue on the fromKnob
    ss << fromKnob->getName();
    ss << ".getValue(";
    if (fromKnob->getNDimensions() > 1) {
        if (fromDimension.isAll()) {
            ss << "dimension";
        } else {
            ss << fromDimension;
        }
    }
    std::list<ViewIdx> sourceViews = fromKnob->getViewsList();
    if (sourceViews.size() > 1) {
        ss << ", ";
        if (fromView.isAll()) {
            ss << "view";
        } else {
            if (fromView >= 0 && fromView < (int)projectViewNames.size()) {
                ss << projectViewNames[fromView];
            } else {
                ss << "Main";
            }
        }
    }
    ss << ")";

    // Also check if we need to multiply by the target knob's curve
    if (multCurve) {
        ss << " * curve(frame, ";
        if (targetDimension.isAll()) {
            ss << "dimension";
        } else {
            ss << targetDimension;
        }

        std::list<ViewIdx> targetKnobViews = targetKnob->getViewsList();
        if (targetKnobViews.size() > 1) {
            ss << ", ";
            if (targetView.isAll()) {
                ss << "view";
            } else {

                if (targetView >= 0 && targetView < (int)projectViewNames.size()) {
                    ss << projectViewNames[targetView];
                } else {
                    ss << "Main";
                }
            }
        }

        ss << ")";
    }
    return ss.str();
} // makeLinkExpression
void
ProjectGuiSerialization::initialize(const ProjectGui* projectGui)
{
    NodesList activeNodes;

    projectGui->getInternalProject()->getActiveNodesExpandGroups(&activeNodes);

    _serializedNodes.clear();
    for (NodesList::iterator it = activeNodes.begin(); it != activeNodes.end(); ++it) {
        NodeGuiIPtr nodegui_i = (*it)->getNodeGui();
        if (!nodegui_i) {
            continue;
        }
        NodeGuiPtr nodegui = boost::dynamic_pointer_cast<NodeGui>(nodegui_i);

        if ( nodegui->isVisible() ) {
            NodeCollectionPtr isInCollection = (*it)->getGroup();
            NodeGroupPtr isCollectionAGroup = toNodeGroup( isInCollection );
            if (!isCollectionAGroup) {
                ///Nodes within a group will be serialized recursively in the node group serialization
                NodeGuiSerialization state;
                nodegui->serialize(&state);
                _serializedNodes.push_back(state);
            }
            ViewerInstancePtr viewer = (*it)->isEffectViewerInstance();
            if (viewer) {
                ViewerTab* tab = projectGui->getGui()->getViewerTabForInstance(viewer);
                assert(tab);
                ViewerData viewerData;
                double zoompar;
                tab->getViewer()->getProjection(&viewerData.zoomLeft, &viewerData.zoomBottom, &viewerData.zoomFactor, &zoompar);
                viewerData.userRoI = tab->getViewer()->getUserRegionOfInterest();
                viewerData.userRoIenabled = tab->getViewer()->isUserRegionOfInterestEnabled();
                viewerData.isClippedToProject = tab->isClippedToProject();
                viewerData.autoContrastEnabled = tab->isAutoContrastEnabled();
                viewerData.gain = tab->getGain();
                viewerData.gamma = tab->getGamma();
                viewerData.colorSpace = tab->getColorSpace();
                viewerData.channels = tab->getChannelsString();
                viewerData.renderScaleActivated = tab->getRenderScaleActivated();
                viewerData.mipMapLevel = tab->getMipMapLevel();
                viewerData.zoomOrPanSinceLastFit = tab->getZoomOrPannedSinceLastFit();
                viewerData.wipeCompositingOp = (int)tab->getCompositingOperator();
                viewerData.leftToolbarVisible = tab->isLeftToolbarVisible();
                viewerData.rightToolbarVisible = tab->isRightToolbarVisible();
                viewerData.topToolbarVisible = tab->isTopToolbarVisible();
                viewerData.infobarVisible = tab->isInfobarVisible();
                viewerData.playerVisible = tab->isPlayerVisible();
                viewerData.timelineVisible = tab->isTimelineVisible();
                viewerData.checkerboardEnabled = tab->isCheckerboardEnabled();
                viewerData.isFullFrameProcessEnabled = tab->isFullFrameProcessingEnabled();
                viewerData.fps = tab->getDesiredFps();
                viewerData.fpsLocked = tab->isFPSLocked();
                viewerData.isPauseEnabled[0] = tab->isViewerPaused(0);
                viewerData.isPauseEnabled[1] = tab->isViewerPaused(1);
                viewerData.layerName = tab->getCurrentLayerName().toStdString();
                viewerData.alphaLayerName = tab->getCurrentAlphaLayerName().toStdString();
                tab->getTimelineBounds(&viewerData.leftBound, &viewerData.rightBound);
                tab->getActiveInputs(&viewerData.aChoice, &viewerData.bChoice);
                viewerData.version = VIEWER_DATA_SERIALIZATION_VERSION;
                _viewersData.insert( std::make_pair(viewer->getNode()->getScriptName_mt_safe(), viewerData) );
            }
        }
    }

    ///Init windows
    _layoutSerialization.initialize( projectGui->getGui() );

    ///save histograms
    std::list<Histogram*> histograms = projectGui->getGui()->getHistograms_mt_safe();
    for (std::list<Histogram*>::const_iterator it = histograms.begin(); it != histograms.end(); ++it) {
        _histograms.push_back( (*it)->objectName().toStdString() );
    }

    ///save opened panels by order

    std::list<DockablePanel*> panels = projectGui->getGui()->getVisiblePanels_mt_safe();
    for (std::list<DockablePanel*>::iterator it = panels.begin(); it != panels.end(); ++it) {
        if ( (*it)->isVisible() ) {
            KnobHolderPtr holder = (*it)->getHolder();
            assert(holder);

            EffectInstancePtr isEffect = toEffectInstance(holder);
            ProjectPtr isProj = toProject(holder);

            if (isProj) {
                _openedPanelsOrdered.push_back(kNatronProjectSettingsPanelSerializationName);
            } else if (isEffect) {
                _openedPanelsOrdered.push_back( isEffect->getNode()->getFullyQualifiedName() );
            }
        }
    }

    _scriptEditorInput = projectGui->getGui()->getScriptEditor()->getAutoSavedScript().toStdString();

    std::map<NATRON_PYTHON_NAMESPACE::PyPanel*, std::string> pythonPanels = projectGui->getGui()->getPythonPanels();
    for (std::map<NATRON_PYTHON_NAMESPACE::PyPanel*, std::string>::iterator it = pythonPanels.begin(); it != pythonPanels.end(); ++it) {
        boost::shared_ptr<PythonPanelSerialization> s(new PythonPanelSerialization);
        s->initialize(it->first, it->second);
        _pythonPanels.push_back(s);
    }
} // initialize
void
NodePrivate::runChangedParamCallback(const std::string& cb, const KnobIPtr& k, bool userEdited)
{
    std::vector<std::string> args;
    std::string error;

    if ( !k || (k->getName() == "onParamChanged") ) {
        return;
    }

    std::string callbackFunction;
    if (!figureOutCallbackName(cb, &callbackFunction)) {
        return;
    }

    try {
        NATRON_PYTHON_NAMESPACE::getFunctionArguments(callbackFunction, &error, &args);
    } catch (const std::exception& e) {
        _publicInterface->getApp()->appendToScriptEditor( tr("Failed to run onParamChanged callback: %1").arg( QString::fromUtf8( e.what() ) ).toStdString() );

        return;
    }

    if ( !error.empty() ) {
        _publicInterface->getApp()->appendToScriptEditor( tr("Failed to run onParamChanged callback: %1").arg( QString::fromUtf8( error.c_str() ) ).toStdString() );

        return;
    }

    std::string signatureError;
    signatureError.append( tr("The param changed callback supports the following signature(s):").toStdString() );
    signatureError.append("\n- callback(thisParam,thisNode,thisGroup,app,userEdited)");
    if (args.size() != 5) {
        _publicInterface->getApp()->appendToScriptEditor( tr("Failed to run onParamChanged callback: %1").arg( QString::fromUtf8( signatureError.c_str() ) ).toStdString() );

        return;
    }

    if ( ( (args[0] != "thisParam") || (args[1] != "thisNode") || (args[2] != "thisGroup") || (args[3] != "app") || (args[4] != "userEdited") ) ) {
        _publicInterface->getApp()->appendToScriptEditor( tr("Failed to run onParamChanged callback: %1").arg( QString::fromUtf8( signatureError.c_str() ) ).toStdString() );

        return;
    }

    std::string appID = _publicInterface->getApp()->getAppIDString();

    assert(k);
    std::string thisNodeVar = appID + ".";
    thisNodeVar.append( _publicInterface->getFullyQualifiedName() );

    NodeCollectionPtr collection = _publicInterface->getGroup();
    assert(collection);
    if (!collection) {
        return;
    }

    std::string thisGroupVar;
    NodeGroupPtr isParentGrp = toNodeGroup(collection);
    if (isParentGrp) {
        std::string nodeName = isParentGrp->getNode()->getFullyQualifiedName();
        std::string nodeFullName = appID + "." + nodeName;
        thisGroupVar = nodeFullName;
    } else {
        thisGroupVar = appID;
    }

    bool alreadyDefined = false;
    PyObject* nodeObj = NATRON_PYTHON_NAMESPACE::getAttrRecursive(thisNodeVar, NATRON_PYTHON_NAMESPACE::getMainModule(), &alreadyDefined);
    if (!nodeObj || !alreadyDefined) {
        return;
    }

    if (!PyObject_HasAttrString( nodeObj, k->getName().c_str() ) ) {
        return;
    }

    std::stringstream ss;
    ss << callbackFunction << "(" << thisNodeVar << "." << k->getName() << "," << thisNodeVar << "," << thisGroupVar << "," << appID
    << ",";
    if (userEdited) {
        ss << "True";
    } else {
        ss << "False";
    }
    ss << ")\n";

    std::string script = ss.str();
    std::string err;
    std::string output;
    if ( !NATRON_PYTHON_NAMESPACE::interpretPythonScript(script, &err, &output) ) {
        _publicInterface->getApp()->appendToScriptEditor( tr("Failed to execute onParamChanged callback: %1").arg( QString::fromUtf8( err.c_str() ) ).toStdString() );
    } else {
        if ( !output.empty() ) {
            _publicInterface->getApp()->appendToScriptEditor(output);
        }
    }

} // runChangedParamCallback
void
NodePrivate::runInputChangedCallback(int index,
                                     const std::string& cb)
{
    std::vector<std::string> args;
    std::string error;

    std::string callbackFunction;
    if (!figureOutCallbackName(cb, &callbackFunction)) {
        return;
    }

    try {
        NATRON_PYTHON_NAMESPACE::getFunctionArguments(callbackFunction, &error, &args);
    } catch (const std::exception& e) {
        _publicInterface->getApp()->appendToScriptEditor( std::string("Failed to run onInputChanged callback: ")
                                                         + e.what() );

        return;
    }

    if ( !error.empty() ) {
        _publicInterface->getApp()->appendToScriptEditor("Failed to run onInputChanged callback: " + error);

        return;
    }

    std::string signatureError;
    signatureError.append("The on input changed callback supports the following signature(s):\n");
    signatureError.append("- callback(inputIndex,thisNode,thisGroup,app)");
    if (args.size() != 4) {
        _publicInterface->getApp()->appendToScriptEditor("Failed to run onInputChanged callback: " + signatureError);

        return;
    }

    if ( (args[0] != "inputIndex") || (args[1] != "thisNode") || (args[2] != "thisGroup") || (args[3] != "app") ) {
        _publicInterface->getApp()->appendToScriptEditor("Failed to run onInputChanged callback: " + signatureError);

        return;
    }

    std::string appID = _publicInterface->getApp()->getAppIDString();
    NodeCollectionPtr collection = _publicInterface->getGroup();
    assert(collection);
    if (!collection) {
        return;
    }

    std::string thisGroupVar;
    NodeGroupPtr isParentGrp = toNodeGroup(collection);
    if (isParentGrp) {
        std::string nodeName = isParentGrp->getNode()->getFullyQualifiedName();
        std::string nodeFullName = appID + "." + nodeName;
        thisGroupVar = nodeFullName;
    } else {
        thisGroupVar = appID;
    }

    std::stringstream ss;
    ss << callbackFunction << "(" << index << "," << appID << "." << _publicInterface->getFullyQualifiedName() << "," << thisGroupVar << "," << appID << ")\n";

    std::string script = ss.str();
    std::string output;
    if ( !NATRON_PYTHON_NAMESPACE::interpretPythonScript(script, &error, &output) ) {
        _publicInterface->getApp()->appendToScriptEditor( tr("Failed to execute callback: %1").arg( QString::fromUtf8( error.c_str() ) ).toStdString() );
    } else {
        if ( !output.empty() ) {
            _publicInterface->getApp()->appendToScriptEditor(output);
        }
    }
} //runInputChangedCallback
Beispiel #14
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
Beispiel #15
0
void
NodeGraph::mouseMoveEvent(QMouseEvent* e)
{
    QPointF newPos = mapToScene( e->pos() );
    QPointF lastMousePosScene = mapToScene( _imp->_lastMousePos.x(), _imp->_lastMousePos.y() );
    double dx, dy;
    {
        QPointF newPosRoot = _imp->_root->mapFromScene(newPos);
        QPointF lastMousePosRoot = _imp->_root->mapFromScene(lastMousePosScene);
        dx = newPosRoot.x() - lastMousePosRoot.x();
        dy = newPosRoot.y() - lastMousePosRoot.y();
    }

    _imp->_hasMovedOnce = true;

    bool mustUpdate = true;
    NodeCollectionPtr collection = getGroup();
    NodeGroupPtr isGroup = toNodeGroup(collection);
    bool isGroupEditable = true;
    bool groupEdited = true;
    if (isGroup) {
        isGroupEditable = isGroup->isSubGraphEditable();
        groupEdited = isGroup->isSubGraphEditedByUser();
    }
    if (!groupEdited && isGroupEditable) {
        ///check if user is nearby unlock
        // see NodeGraph::paintEvent()
        QPoint pixPos = _imp->getPyPlugUnlockPos();
        int pixW = _imp->unlockIcon.width();
        int pixH = _imp->unlockIcon.height();
        QRect pixRect(pixPos.x(), pixPos.y(), pixW, pixH);
        pixRect.adjust(-2, -2, 2, 2);
        QRect selRect = pixRect;
        selRect.adjust(-3, -3, 3, 3);
        if ( selRect.contains( e->pos() ) ) {
            assert(isGroup);
            QPoint pos = mapToGlobal( e->pos() );
            // Unfortunately, the timeout delay for the tooltip is hardcoded in Qt 4, and the last parameter to showText doesn't seem to influence anything
            // Can not fix https://github.com/MrKepzie/Natron/issues/1151 (at least in Qt4)
            QToolTip::showText( pos, NATRON_NAMESPACE::convertFromPlainText(QCoreApplication::translate("NodeGraph", "Clicking the unlock button will convert the PyPlug to a regular group saved in the project and dettach it from the script.\n"
                                                                                                "Any modification will not be written to the Python script. Subsequent loading of the project will no longer load this group from the python script."), NATRON_NAMESPACE::WhiteSpaceNormal),
                               this, selRect);
            e->accept();
            return;
        }
    }

    QRectF sceneR = visibleSceneRect();

    bool mustUpdateNavigator = false;
    ///Apply actions
    switch (_imp->_evtState) {
    case eEventStateDraggingArrow: {
        QPointF np = _imp->_arrowSelected->mapFromScene(newPos);
        if ( _imp->_arrowSelected->isOutputEdge() ) {
            _imp->_arrowSelected->dragDest(np);
        } else {
            _imp->_arrowSelected->dragSource(np);
        }
        checkAndStartAutoScrollTimer(newPos);
        mustUpdate = true;
        if (_imp->cursorSet) {
            _imp->cursorSet = false;
            unsetCursor();
        }
        break;
    }
    case eEventStateDraggingNode: {
        mustUpdate = true;
        mustUpdateNavigator = true;
        bool controlDown = modifierHasControl(e);
        bool shiftdown = modifierHasShift(e);
        moveSelectedNodesBy(shiftdown, controlDown, lastMousePosScene, newPos, sceneR, true);
        _imp->cursorSet = true;
        setCursor( QCursor(Qt::ClosedHandCursor) );
        break;
    }
    case eEventStateMovingArea: {
        mustUpdateNavigator = true;
        moveRootInternal(dx, dy);
        mustUpdate = true;
        _imp->cursorSet = true;
        setCursor( QCursor(Qt::SizeAllCursor) );
        break;
    }
    case eEventStateResizingBackdrop: {
        mustUpdateNavigator = true;
        assert(_imp->_backdropResized.lock());
        QPointF p = _imp->_backdropResized.lock()->scenePos();
        int w = newPos.x() - p.x();
        int h = newPos.y() - p.y();
        checkAndStartAutoScrollTimer(newPos);
        mustUpdate = true;
        pushUndoCommand( new ResizeBackdropCommand(_imp->_backdropResized.lock(), w, h) );
        _imp->cursorSet = true;
        setCursor( QCursor(Qt::SizeFDiagCursor) );
        break;
    }
    case eEventStateSelectionRect: {
        QPointF startDrag = _imp->_lastSelectionStartPointScene;
        QPointF cur = newPos;
        double xmin = std::min( cur.x(), startDrag.x() );
        double xmax = std::max( cur.x(), startDrag.x() );
        double ymin = std::min( cur.y(), startDrag.y() );
        double ymax = std::max( cur.y(), startDrag.y() );
        checkAndStartAutoScrollTimer(newPos);
        QRectF selRect(xmin, ymin, xmax - xmin, ymax - ymin);
        _imp->_selectionRect = selRect;
        mustUpdate = true;
        _imp->cursorSet = true;
        setCursor( QCursor(Qt::CrossCursor) );
        break;
    }
    case eEventStateDraggingNavigator: {
        _imp->cursorSet = true;
        setCursor( QCursor(Qt::ClosedHandCursor) );
        QPointF mousePosSceneCoordinates;
        bool insideNavigator = isNearbyNavigator(e->pos(), mousePosSceneCoordinates);
        if (insideNavigator) {
            _imp->_refreshOverlays = true;
            centerOn(mousePosSceneCoordinates);
            _imp->_lastMousePos = e->pos();
            update();

            return;
        }
        break;
    }
    case eEventStateZoomingArea: {
        int delta = 2 * ( ( e->x() - _imp->_lastMousePos.x() ) - ( e->y() - _imp->_lastMousePos.y() ) );
        setTransformationAnchor(QGraphicsView::AnchorViewCenter);
        wheelEventInternal(modCASIsControl(e), delta);
        setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
        mustUpdate = true;
        _imp->cursorSet = true;
        setCursor( QCursor(Qt::SizeAllCursor) );
        break;
    }
    case eEventStateNone:
    default: {
        mustUpdate = false;
        // Test if mouse is inside the navigator
        QPointF mousePosSceneCoordinates;
        bool insideNavigator = isNearbyNavigator(e->pos(), mousePosSceneCoordinates);
        if (insideNavigator) {
            _imp->cursorSet = true;
            setCursor( QCursor(Qt::OpenHandCursor) );
        } else if (!groupEdited) {
            if (_imp->cursorSet) {
                _imp->cursorSet = false;
                unsetCursor();
            }
        } else {
            // Set cursor
            // The cursor should clearly indicate when will happen if mouse is pressed
            NodeGuiPtr nearbyNode;
            Edge* nearbyEdge = NULL;
            NearbyItemEnum nearbyItemCode = hasItemNearbyMouse(e->pos(), &nearbyNode, &nearbyEdge);

            switch (nearbyItemCode) {
            case eNearbyItemNode:
            case eNearbyItemBackdropFrame:
            case eNearbyItemEdgeBendPoint: {
                _imp->cursorSet = true;
                setCursor( QCursor(Qt::OpenHandCursor) );
                break;
            }
            case eNearbyItemBackdropResizeHandle: {
                _imp->cursorSet = true;
                setCursor( QCursor(Qt::SizeFDiagCursor) );
                break;
            }
            case eNearbyItemNone: {
                _imp->cursorSet = true;
                setCursor( QCursor(Qt::CrossCursor) );
                break;
            }
            case eNearbyItemNodeEdge:
            default: {
                if (_imp->cursorSet) {
                    _imp->cursorSet = false;
                    unsetCursor();
                }
                break;
            }
            }
        }
        break;
    }
    } // switch


    _imp->_lastMousePos = e->pos();


    if (mustUpdateNavigator) {
        _imp->_refreshOverlays = true;
        mustUpdate = true;
    }

    if (mustUpdate) {
        update();
    }

    TabWidget* tab = getParentPane() ;
    if (tab && _imp->_evtState == eEventStateNone) {
        // If the Viewer is in a tab, send the tab widget the event directly
        qApp->sendEvent(tab, e);
    }
    QGraphicsView::mouseMoveEvent(e);
} // mouseMoveEvent
Beispiel #16
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
Beispiel #17
0
void
NodeGraph::mouseMoveEvent(QMouseEvent* e)
{
    QPointF newPos = mapToScene( e->pos() );
    QPointF lastMousePosScene = mapToScene( _imp->_lastMousePos.x(), _imp->_lastMousePos.y() );
    double dx, dy;
    {
        QPointF newPosRoot = _imp->_root->mapFromScene(newPos);
        QPointF lastMousePosRoot = _imp->_root->mapFromScene(lastMousePosScene);
        dx = newPosRoot.x() - lastMousePosRoot.x();
        dy = newPosRoot.y() - lastMousePosRoot.y();
    }

    _imp->_hasMovedOnce = true;

    bool mustUpdate = true;
    NodeCollectionPtr collection = getGroup();
    NodeGroupPtr isGroup = toNodeGroup(collection);
    bool isGroupEditable = true;
    bool groupEdited = true;
    if (isGroup) {
        isGroupEditable = isGroup->isSubGraphEditable();
        groupEdited = isGroup->getNode()->hasPyPlugBeenEdited();
    }
    if (!groupEdited && isGroupEditable) {
        ///check if user is nearby unlock
        int iw = _imp->unlockIcon.width();
        int ih = _imp->unlockIcon.height();
        int w = width();
        if ( ( e->x() >= (w - iw - 10 - 15) ) && ( e->x() <= (w - 10 + 15) ) &&
             ( e->y() >= (10 - 15) ) && ( e->y() <= (10 + ih + 15) ) ) {
            assert(isGroup);
            QPoint pos = mapToGlobal( e->pos() );
            QToolTip::showText( pos, GuiUtils::convertFromPlainText(QCoreApplication::translate("NodeGraph", "Clicking the unlock button will convert the PyPlug to a regular group saved in the project and dettach it from the script.\n"
                                                                                                "Any modification will not be written to the Python script. Subsequent loading of the project will no longer load this group from the python script."), Qt::WhiteSpaceNormal) );
        }
    }

    QRectF sceneR = visibleSceneRect();
    if ( groupEdited && (_imp->_evtState != eEventStateSelectionRect) && (_imp->_evtState != eEventStateDraggingArrow) ) {
        // Set cursor

        std::set<NodeGuiPtr> visibleNodes;
        getNodesWithinViewportRect(visibleWidgetRect(), &visibleNodes);

        NodeGuiPtr selected;
        Edge* selectedEdge = 0;
        bool optionalInputsAutoHidden = areOptionalInputsAutoHidden();

        for (std::set<NodeGuiPtr>::iterator it = visibleNodes.begin(); it != visibleNodes.end(); ++it) {
            QPointF evpt = (*it)->mapFromScene(newPos);
            QRectF bbox = (*it)->mapToScene( (*it)->boundingRect() ).boundingRect();
            if ( (*it)->isActive() && bbox.intersects(sceneR) ) {
                if ( (*it)->contains(evpt) ) {
                    selected = (*it)->shared_from_this();
                    if (optionalInputsAutoHidden) {
                        (*it)->refreshEdgesVisility(true);
                    } else {
                        break;
                    }
                } else {
                    Edge* edge = (*it)->hasEdgeNearbyPoint(newPos);
                    if (edge) {
                        selectedEdge = edge;
                        if (!optionalInputsAutoHidden) {
                            break;
                        }
                    } else if ( optionalInputsAutoHidden && !(*it)->getIsSelected() ) {
                        (*it)->refreshEdgesVisility(false);
                    }
                }
            }
        }
        if (selected) {
            _imp->cursorSet = true;
            setCursor( QCursor(Qt::OpenHandCursor) );
        } else if (selectedEdge) {
        } else if (!selectedEdge && !selected) {
            if (_imp->cursorSet) {
                _imp->cursorSet = false;
                unsetCursor();
            }
        }
    }

    bool mustUpdateNavigator = false;
    ///Apply actions
    switch (_imp->_evtState) {
    case eEventStateDraggingArrow: {
        QPointF np = _imp->_arrowSelected->mapFromScene(newPos);
        if ( _imp->_arrowSelected->isOutputEdge() ) {
            _imp->_arrowSelected->dragDest(np);
        } else {
            _imp->_arrowSelected->dragSource(np);
        }
        checkAndStartAutoScrollTimer(newPos);
        mustUpdate = true;
        break;
    }
    case eEventStateDraggingNode: {
        mustUpdate = true;
        mustUpdateNavigator = true;
        bool controlDown = modifierHasControl(e);
        bool shiftdown = modifierHasShift(e);
        moveSelectedNodesBy(shiftdown, controlDown, lastMousePosScene, newPos, sceneR, true);
        break;
    }
    case eEventStateMovingArea: {
        mustUpdateNavigator = true;
        moveRootInternal(dx, dy);
        _imp->cursorSet = true;
        setCursor( QCursor(Qt::SizeAllCursor) );
        mustUpdate = true;
        break;
    }
    case eEventStateResizingBackdrop: {
        mustUpdateNavigator = true;
        assert(_imp->_backdropResized);
        QPointF p = _imp->_backdropResized->scenePos();
        int w = newPos.x() - p.x();
        int h = newPos.y() - p.y();
        checkAndStartAutoScrollTimer(newPos);
        mustUpdate = true;
        pushUndoCommand( new ResizeBackdropCommand(_imp->_backdropResized, w, h) );
        break;
    }
    case eEventStateSelectionRect: {
        QPointF startDrag = _imp->_lastSelectionStartPointScene;
        QPointF cur = newPos;
        double xmin = std::min( cur.x(), startDrag.x() );
        double xmax = std::max( cur.x(), startDrag.x() );
        double ymin = std::min( cur.y(), startDrag.y() );
        double ymax = std::max( cur.y(), startDrag.y() );
        checkAndStartAutoScrollTimer(newPos);
        QRectF selRect(xmin, ymin, xmax - xmin, ymax - ymin);
        _imp->_selectionRect = selRect;
        mustUpdate = true;
        break;
    }
    case eEventStateDraggingNavigator: {
        QPointF mousePosSceneCoordinates;
        bool insideNavigator = isNearbyNavigator(e->pos(), mousePosSceneCoordinates);
        if (insideNavigator) {
            _imp->_refreshOverlays = true;
            centerOn(mousePosSceneCoordinates);
            _imp->_lastMousePos = e->pos();
            update();

            return;
        }
        break;
    }
    case eEventStateZoomingArea: {
        int delta = 2 * ( ( e->x() - _imp->_lastMousePos.x() ) - ( e->y() - _imp->_lastMousePos.y() ) );
        setTransformationAnchor(QGraphicsView::AnchorViewCenter);
        wheelEventInternal(modCASIsControl(e), delta);
        setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
        mustUpdate = true;
        break;
    }
    default:
        mustUpdate = false;
        break;
    } // switch


    _imp->_lastMousePos = e->pos();


    if (mustUpdateNavigator) {
        _imp->_refreshOverlays = true;
        mustUpdate = true;
    }

    if (mustUpdate) {
        update();
    }
    QGraphicsView::mouseMoveEvent(e);
} // mouseMoveEvent
Beispiel #18
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()) );
}