コード例 #1
0
bool
OfxOverlayInteract::onOverlayFocusLost(TimeValue time,
                                       const RenderScale & renderScale,
                                       ViewIdx view)
{

    EffectInstancePtr effect = getEffect();
    EffectInstanceTLSDataPtr tls = effect->getOrCreateTLSObject();
    EffectActionArgsSetter_RAII actionArgsTls(tls, kOfxInteractActionLoseFocus, time, view, renderScale
#ifdef DEBUG
                                              , /*canSetValue*/ true
                                              , /*canBeCalledRecursively*/ true
#endif

                                              );

    ThreadIsActionCaller_RAII actionCaller(toOfxEffectInstance(effect));

    OfxRGBAColourD pickerColor;
    bool hasPicker = hasColorPicker();
    if (hasPicker) {
        pickerColor = colorToOfxColor(getLastColorPickerColor());
    }


    OfxStatus stat;
    stat = loseFocusAction(time, renderScale, view, hasPicker ? &pickerColor : /*colourPicker=*/0);
    if (stat == kOfxStatOK) {
        return true;
    }


    return false;
}
コード例 #2
0
ファイル: DiskCacheNode.cpp プロジェクト: azerupi/Natron
void
DiskCacheNode::getFrameRange(double *first,
                             double *last)
{
    int idx = _imp->frameRange.lock()->getValue();

    switch (idx) {
    case 0: {
        EffectInstancePtr input = getInput(0);
        if (input) {
            input->getFrameRange_public(0, first, last);
        }
        break;
    }
    case 1: {
        getApp()->getFrameRange(first, last);
        break;
    }
    case 2: {
        *first = _imp->firstFrame.lock()->getValue();
        *last = _imp->lastFrame.lock()->getValue();
    };
    default:
        break;
    }
}
コード例 #3
0
void
OfxOverlayInteract::drawOverlay(TimeValue time,
                                const RenderScale & renderScale,
                                ViewIdx view)
{

    EffectInstancePtr effect = getEffect();
    EffectInstanceTLSDataPtr tls = effect->getOrCreateTLSObject();
    EffectActionArgsSetter_RAII actionArgsTls(tls, kOfxInteractActionDraw,  time, view, renderScale
#ifdef DEBUG
                                              , /*canSetValue*/ true
                                              , /*canBeCalledRecursively*/ false
#endif
                                              );

    ThreadIsActionCaller_RAII actionCaller(toOfxEffectInstance(effect));

    OfxRGBAColourD pickerColor;
    bool hasPicker = hasColorPicker();
    if (hasPicker) {
        pickerColor = colorToOfxColor(getLastColorPickerColor());
    }

    drawAction(time, renderScale, view, hasPicker ? &pickerColor : /*colourPicker=*/0);

}
コード例 #4
0
ファイル: KnobGuiChoice.cpp プロジェクト: litlight/Natron
void
KnobGuiChoice::onItemNewSelected()
{
    NewLayerDialog dialog( ImageComponents::getNoneComponents(), getGui() );

    if ( dialog.exec() ) {
        ImageComponents comps = dialog.getComponents();
        if ( comps == ImageComponents::getNoneComponents() ) {
            Dialogs::errorDialog( tr("Layer").toStdString(), tr("A layer must contain at least 1 channel and channel names must be "
                                                                "Python compliant.").toStdString() );

            return;
        }
        KnobHolderPtr holder = _knob.lock()->getHolder();
        assert(holder);
        EffectInstancePtr effect = toEffectInstance(holder);
        assert(effect);
        if (effect) {
            assert( effect->getNode() );
            if ( !effect->getNode()->addUserComponents(comps) ) {
                Dialogs::errorDialog( tr("Layer").toStdString(), tr("A Layer with the same name already exists").toStdString() );
            }
        }
    }
}
コード例 #5
0
bool
OfxOverlayInteract::onOverlayKeyDown(TimeValue time,
                                     const RenderScale & renderScale,
                                     ViewIdx view,
                                     Key key,
                                     KeyboardModifiers /*modifiers*/)
{

    EffectInstancePtr effect = getEffect();
    EffectInstanceTLSDataPtr tls = effect->getOrCreateTLSObject();
    EffectActionArgsSetter_RAII actionArgsTls(tls, kOfxInteractActionKeyDown, time, view, renderScale
#ifdef DEBUG
                                              , /*canSetValue*/ true
                                              , /*canBeCalledRecursively*/ true
#endif
                                              );

    ThreadIsActionCaller_RAII actionCaller(toOfxEffectInstance(effect));

    OfxRGBAColourD pickerColor;
    bool hasPicker = hasColorPicker();
    if (hasPicker) {
        pickerColor = colorToOfxColor(getLastColorPickerColor());
    }

    QByteArray keyStr;
    OfxStatus stat = keyDownAction( time, renderScale, view,hasPicker ? &pickerColor : /*colourPicker=*/0, (int)key, keyStr.data() );

    if (stat == kOfxStatOK) {
        return true;
    }


    return false;
}
コード例 #6
0
ファイル: KnobGuiFile.cpp プロジェクト: MrKepzie/Natron
void
KnobGuiFile::createWidget(QHBoxLayout* layout)
{
    KnobGuiPtr knobUI = getKnobGui();
    if (!knobUI) {
        return;
    }
    Gui* gui = knobUI->getGui();
    if (!gui) {
        return;
    }
    GuiAppInstancePtr app = gui->getApp();
    if (!app) {
        return;
    }
    KnobFilePtr knob = _knob.lock();
    if (!knob) {
        return;
    }
    EffectInstancePtr holderIsEffect = toEffectInstance( knob->getHolder() );


    if ( holderIsEffect && holderIsEffect->isReader() && (knob->getName() == kOfxImageEffectFileParamName) ) {

        TimeLinePtr timeline = app->getTimeLine();
        QObject::connect( timeline.get(), SIGNAL(frameChanged(SequenceTime,int)), this, SLOT(onTimelineFrameChanged(SequenceTime,int)) );
    }
コード例 #7
0
void
DSRightTrimReaderCommand::trimRight(double lastFrame)
{
    DSNodePtr nodeContext = _readerContext.lock();

    if (!nodeContext) {
        return;
    }

    NodePtr node = nodeContext->getInternalNode();

    KnobIntBase *lastFrameKnob = dynamic_cast<KnobIntBase *>( node->getKnobByName(kReaderParamNameLastFrame).get() );
    assert(lastFrameKnob);
    if (!lastFrameKnob) {
        return;
    }
    KnobHolderPtr holder = lastFrameKnob->getHolder();
    EffectInstancePtr effectInstance = toEffectInstance(holder);
    assert(effectInstance);
    if (!effectInstance) {
        return;
    }
    effectInstance->beginChanges();
    KnobHelper::ValueChangedReturnCodeEnum r = lastFrameKnob->setValue(lastFrame, ViewSpec::all(), 0, eValueChangedReasonNatronGuiEdited, 0);
    effectInstance->endChanges();

    Q_UNUSED(r);
}
コード例 #8
0
ファイル: TrackMarker.cpp プロジェクト: Kthulhu/Natron
void
TrackMarker::resetTrack()
{
    Point curCenter;
    KnobDoublePtr knob = getCenterKnob();

    curCenter.x = knob->getValue(0);
    curCenter.y = knob->getValue(1);

    EffectInstancePtr effect = getContext()->getNode()->getEffectInstance();
    effect->beginChanges();

    const KnobsVec& knobs = getKnobs();
    for (KnobsVec::const_iterator it = knobs.begin(); it != knobs.end(); ++it) {
        if (*it != knob) {
            for (int i = 0; i < (*it)->getDimension(); ++i) {
                (*it)->resetToDefaultValue(i);
            }
        } else {
            for (int i = 0; i < (*it)->getDimension(); ++i) {
                (*it)->removeAnimation(ViewSpec::current(), i);
            }
            knob->setValue(curCenter.x, ViewSpec::current(), 0);
            knob->setValue(curCenter.y, ViewSpec::current(), 1);
        }
    }
    effect->endChanges();
    removeAllUserKeyframes();
}
コード例 #9
0
ファイル: PyOverlayInteract.cpp プロジェクト: ebrayton/Natron
 QString viewToString(ViewIdx view) const
 {
     EffectInstancePtr e = effect.lock();
     if (!e) {
         return QString::fromUtf8(kPyParamViewIdxMain);
     }
     return QString::fromUtf8(e->getApp()->getProject()->getViewName(view).c_str());
 }
コード例 #10
0
ファイル: PluginMemory.cpp プロジェクト: Kthulhu/Natron
PluginMemory::~PluginMemory()
{
    EffectInstancePtr e = _imp->effect.lock();

    if (e) {
        e->removePluginMemoryPointer(this);
    }
}
コード例 #11
0
ファイル: PluginMemory.cpp プロジェクト: Kthulhu/Natron
void
PluginMemory::freeMem()
{
    QMutexLocker l(&_imp->mutex);
    EffectInstancePtr e = _imp->effect.lock();

    if (e) {
        e->unregisterPluginMemory( _imp->data.size() );
    }
    _imp->data.clear();
    _imp->locked = 0;
}
コード例 #12
0
ファイル: KnobUndoCommand.cpp プロジェクト: azerupi/Natron
MultipleKnobEditsUndoCommand::MultipleKnobEditsUndoCommand(const KnobIPtr& knob,
                                                           const QString& commandName,
                                                           ValueChangedReasonEnum reason,
                                                           ValueChangedReturnCodeEnum setValueRetCode,
                                                           bool createNew,
                                                           bool setKeyFrame,
                                                           const PerDimViewVariantMap& oldValue,
                                                           const Variant & newValue,
                                                           DimSpec dimension,
                                                           double time,
                                                           ViewSetSpec view)
    : QUndoCommand()
    , knobs()
    , createNew(createNew)
    , firstRedoCalled(false)
{
    assert(knob);
    std::list<ValueToSet>& vlist = knobs[knob];
    vlist.push_back(ValueToSet());

    // Add the new value to set to the list (which may be not empty)
    ValueToSet &v = vlist.back();
    v.newValue = newValue;
    v.dimension = dimension;
    assert(dimension != -1);

    if (!setKeyFrame) {
        // Ensure the time is correct in case auto-keying is on and we add a keyframe
        v.time = knob->getCurrentTime();
    } else {
        v.time = time;
    }
    v.setKeyFrame = setKeyFrame;
    v.view = view;
    v.setValueRetCode = setValueRetCode;
    v.reason = reason;
    v.oldValues = oldValue;

    KnobHolderPtr holder = knob->getHolder();
    EffectInstancePtr effect = toEffectInstance(holder);
    QString holderName;
    if (effect) {
        holderName = QString::fromUtf8( effect->getNode()->getLabel().c_str() );
    }

    // Set the command name in the Edit menu
    if (!commandName.isEmpty()) {
        setText(QString::fromUtf8("%1: ").arg(holderName) + commandName);
    } else {
        // If no command name passed, make up a generic command name
        setText( tr("%1: Multiple Parameters Edits").arg(holderName) );
    }
}
コード例 #13
0
ファイル: TrackMarker.cpp プロジェクト: Kthulhu/Natron
void
TrackMarker::onKnobSlaved(const KnobIPtr& slave,
                          const KnobIPtr& master,
                          int dimension,
                          bool isSlave)
{
    EffectInstancePtr effect = getContext()->getNode()->getEffectInstance();

    if (effect) {
        effect->onKnobSlaved(slave, master, dimension, isSlave);
    }
}
コード例 #14
0
ファイル: AnimationModule.cpp プロジェクト: kcotugno/Natron
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
コード例 #15
0
ファイル: OfxMemory.cpp プロジェクト: MrKepzie/Natron
bool
OfxMemory::freeMem()
{
    // A plug-in is calling freeMem, either this memory is held on the effect itself, in which case
    // calling releasePluginMemory will decrease the reference count and delete it.
    // If not held by an effect delete the memory because it's not held by a plug-in.
    deallocateMemory();
    EffectInstancePtr effect = _effect.lock();
    if (effect) {
        effect->releasePluginMemory(this);
        return false; // the call to releasePluginMemory is in charge of deleting this
    } else {
        return true; // object can be deleted
    }
}
コード例 #16
0
ファイル: TimeLine.cpp プロジェクト: ebrayton/Natron
void
TimeLine::seekFrame(SequenceTime frame,
                    bool updateLastCaller,
                    const EffectInstancePtr& caller,
                    TimelineChangeReasonEnum reason)
{
    if (reason != eTimelineChangeReasonPlaybackSeek) {
        Q_EMIT frameAboutToChange();
    }
    bool changed = false;
    {
        QMutexLocker l(&_lock);
        if (_currentFrame != frame) {
            _currentFrame = frame;
            changed = true;
        }
        _lastSeekReason = reason;
    }

    if (_project && updateLastCaller) {
        _project->getApp()->setLastViewerUsingTimeline( caller ? caller->getNode() : NodePtr() );
    }
    if (changed) {
        Q_EMIT frameChanged(frame, (int)reason);
    }
}
コード例 #17
0
ファイル: FrameViewRequest.cpp プロジェクト: ebrayton/Natron
    FrameViewRequestPrivate(const ImagePlaneDesc& plane,
                            unsigned int mipMapLevel,
                            const RenderScale& proxyScale,
                            const EffectInstancePtr& effect,
                            const TreeRenderPtr& render)
    : lock()
    , renderLock()
    , isDrescribed(false)
    , renderClone(effect)
    , parentRender(render)
    , plane(plane)
    , proxyScale(proxyScale)
    , mipMapLevel(mipMapLevel)
    , renderMappedMipMapLevel(mipMapLevel)
    , cachingPolicy(eCacheAccessModeReadWrite)
    , renderDevice(eRenderBackendTypeCPU)
    , renderDeviceSet(false)
    , fallbackRenderDevice(eRenderBackendTypeCPU)
    , fallbackRenderDeviceEnabled(false)
    , retCode(eActionStatusOK)
    , fullScaleImage()
    , requestedScaleImage()
    , finalRoi()
    , requestData()
    , status(FrameViewRequest::eFrameViewRequestStatusNotRendered)
    , frameViewsNeeded()
    , neededComps()
    , distortion()
    , distortionStack()
    , canonicalRoDs()
    , pixelRoDs()
    , byPassCache(false)
    {
#ifdef TRACE_REQUEST_LIFETIME
        nodeName = effect->getNode()->getScriptName_mt_safe();
        qDebug() << "Create request" << nodeName.c_str();
#endif
        if (effect->getCurrentRender()->isByPassCacheEnabled()) {
            byPassCache = true;
        }

        if (effect->getOpenGLRenderSupport() == ePluginOpenGLRenderSupportNeeded) {
            // The plug-in can only use GPU, so make the device fallback be GPU
            fallbackRenderDevice = eRenderBackendTypeOpenGL;
        }
    }
コード例 #18
0
ファイル: PluginMemory.cpp プロジェクト: Kthulhu/Natron
bool
PluginMemory::alloc(size_t nBytes)
{
    QMutexLocker l(&_imp->mutex);

    if (_imp->locked) {
        return false;
    } else {
        _imp->data.resize(nBytes);
        EffectInstancePtr e = _imp->effect.lock();
        if (e) {
            e->registerPluginMemory( _imp->data.size() );
        }

        return true;
    }
}
コード例 #19
0
RotoShapeRenderNode::RotoShapeRenderNode(const EffectInstancePtr& mainInstance, const FrameViewRenderKey& key)
: EffectInstance(mainInstance, key)
, _imp(new RotoShapeRenderNodePrivate())
{
    RotoShapeRenderNode* other = dynamic_cast<RotoShapeRenderNode*>(mainInstance.get());
    assert(other);
    _imp->osmesaSmearTmpTexture = other->_imp->osmesaSmearTmpTexture;
}
コード例 #20
0
bool
OfxOverlayInteract::onOverlayPenMotion(TimeValue time,
                                      const RenderScale & renderScale,
                                      ViewIdx view,
                                      const QPointF & viewportPos,
                                       const QPointF & pos,
                                       double pressure,
                                       TimeValue /*timestamp*/)
{

    OfxPointD penPos;
    penPos.x = pos.x();
    penPos.y = pos.y();
    OfxPointI penPosViewport;
    penPosViewport.x = viewportPos.x();
    penPosViewport.y = viewportPos.y();
    OfxStatus stat;


    EffectInstancePtr effect = getEffect();
    EffectInstanceTLSDataPtr tls = effect->getOrCreateTLSObject();
    EffectActionArgsSetter_RAII actionArgsTls(tls, kOfxInteractActionPenMotion, time, view, renderScale
#ifdef DEBUG
                                              , /*canSetValue*/ true
                                              , /*canBeCalledRecursively*/ true
#endif
                                              );

    ThreadIsActionCaller_RAII actionCaller(toOfxEffectInstance(effect));

    OfxRGBAColourD pickerColor;
    bool hasPicker = hasColorPicker();
    if (hasPicker) {
        pickerColor = colorToOfxColor(getLastColorPickerColor());
    }

    stat = penMotionAction(time, renderScale, view, hasPicker ? &pickerColor : /*colourPicker=*/0, penPos, penPosViewport, pressure);

    if (stat == kOfxStatOK) {
        return true;
    }


    return false;
}
コード例 #21
0
ファイル: KnobGuiChoice.cpp プロジェクト: MrKepzie/Natron
QString
KnobGuiChoice::getPixmapPathFromFilePath(const KnobHolderPtr& holder, const QString& filePath)
{
    if ( QFile::exists(filePath) ) {
        return filePath;
    }

    QString customFilePath = filePath;

    EffectInstancePtr instance = toEffectInstance(holder);
    if (instance) {
        QString resourcesPath = QString::fromUtf8( instance->getNode()->getPluginResourcesPath().c_str() );
        if ( !resourcesPath.endsWith( QLatin1Char('/') ) ) {
            resourcesPath += QLatin1Char('/');
        }
        customFilePath.prepend(resourcesPath);
    }

    return customFilePath;
}
コード例 #22
0
ファイル: DiskCacheNode.cpp プロジェクト: ebrayton/Natron
ActionRetCodeEnum
DiskCacheNode::getFrameRange(double *first,
                             double *last)
{
    int idx = _imp->frameRange.lock()->getValue();

    switch (idx) {
    case 0: {
        EffectInstancePtr input = getInputRenderEffectAtAnyTimeView(0);
        if (input) {

            GetFrameRangeResultsPtr results;
            ActionRetCodeEnum stat = input->getFrameRange_public(&results);
            if (isFailureRetCode(stat)) {
                return stat;
            }
            RangeD range;
            results->getFrameRangeResults(&range);
            *first = range.min;
            *last = range.max;

        }
        break;
    }
    case 1: {
        TimeValue left, right;
        getApp()->getProject()->getFrameRange(&left, &right);
        *first = left;
        *last = right;
        break;
    }
    case 2: {
        *first = _imp->firstFrame.lock()->getValue();
        *last = _imp->lastFrame.lock()->getValue();
    };
    default:
        break;
    }
    return eActionStatusOK;
}
コード例 #23
0
ファイル: BackdropGui.cpp プロジェクト: kcotugno/Natron
void
BackdropGui::createGui()
{
    NodeGui::createGui();

    _imp->label = new NodeGraphTextItem(getDagGui(), this, false);
    _imp->label->setDefaultTextColor( QColor(0, 0, 0, 255) );
    _imp->label->setZValue(getBaseDepth() + 1);

    EffectInstancePtr effect = getNode()->getEffectInstance();
    assert(effect);
    Backdrop* isBd = dynamic_cast<Backdrop*>( effect.get() );
    assert(isBd);

    QObject::connect( isBd, SIGNAL(labelChanged(QString)), this, SLOT(onLabelChanged(QString)) );

    refreshTextLabelFromKnob();

    // Make the backdrop large enough to contain the selected nodes and position it correctly
    const NodesGuiList& selectedNodes =  getDagGui()->getSelectedNodes();
    QRectF bbox;
    for (NodesGuiList::const_iterator it = selectedNodes.begin(); it != selectedNodes.end(); ++it) {
        QRectF nodeBbox = (*it)->mapToScene( (*it)->boundingRect() ).boundingRect();
        bbox = bbox.united(nodeBbox);
    }

    double border50 = mapToScene( QPoint(50, 0) ).x();
    double border0 = mapToScene( QPoint(0, 0) ).x();
    double border = border50 - border0;
    double headerHeight = getFrameNameHeight();
    QPointF scenePos(bbox.x() - border, bbox.y() - border);

    setPos( mapToParent( mapFromScene(scenePos) ) );
    resize(bbox.width() + 2 * border, bbox.height() + 2 * border - headerHeight);

}
コード例 #24
0
void
DSSlipReaderCommand::slipReader(double dt)
{
    DSNodePtr nodeContext = _readerContext.lock();

    if (!nodeContext) {
        return;
    }

    NodePtr node = nodeContext->getInternalNode();

    KnobIntBase *firstFrameKnob = dynamic_cast<KnobIntBase *>( node->getKnobByName(kReaderParamNameFirstFrame).get() );
    assert(firstFrameKnob);
    KnobIntBase *lastFrameKnob = dynamic_cast<KnobIntBase *>( node->getKnobByName(kReaderParamNameLastFrame).get() );
    assert(lastFrameKnob);
    KnobIntBase *timeOffsetKnob = dynamic_cast<KnobIntBase *>( node->getKnobByName(kReaderParamNameTimeOffset).get() );
    assert(timeOffsetKnob);
    KnobIntBase *startingTimeKnob = dynamic_cast<KnobIntBase *>( node->getKnobByName(kReaderParamNameStartingTime).get() );
    assert(startingTimeKnob);
    if (!firstFrameKnob || !lastFrameKnob || !timeOffsetKnob || !startingTimeKnob) {
        return;
    }


    /*
       Since the lastFrameKnob and startingTimeKnob have their signal connected to the computeNodeRange function in DopeSheetview
       We disconnect them beforehand and reconnect them afterwards, otherwise the dopesheet view is going to get many redraw() calls
       for nothing.
     */
    DopeSheetView* view = _model->getDopesheetView();
    QObject::disconnect( lastFrameKnob->getSignalSlotHandler().get(), SIGNAL(valueChanged(ViewSpec,int,int)),
                         view, SLOT(onRangeNodeChanged(ViewSpec,int,int)) );
    QObject::disconnect( startingTimeKnob->getSignalSlotHandler().get(), SIGNAL(valueChanged(ViewSpec,int,int)),
                         view, SLOT(onRangeNodeChanged(ViewSpec,int,int)) );
    KnobHolderPtr holder = lastFrameKnob->getHolder();
    EffectInstancePtr effectInstance = toEffectInstance(holder);
    assert(effectInstance);
    if (!effectInstance) {
        return;
    }
    effectInstance->beginChanges();
    {
        KnobHelper::ValueChangedReturnCodeEnum r;

        r = firstFrameKnob->setValue(firstFrameKnob->getValue() - dt, ViewSpec::all(), 0, eValueChangedReasonNatronGuiEdited, 0);
        Q_UNUSED(r);
        r = lastFrameKnob->setValue(lastFrameKnob->getValue() - dt, ViewSpec::all(),  0, eValueChangedReasonNatronGuiEdited, 0);
        Q_UNUSED(r);
        r = timeOffsetKnob->setValue(timeOffsetKnob->getValue() + dt, ViewSpec::all(), 0, eValueChangedReasonNatronGuiEdited, 0);
        Q_UNUSED(r);
    }
    effectInstance->endChanges();


    QObject::connect( lastFrameKnob->getSignalSlotHandler().get(), SIGNAL(valueChanged(ViewSpec,int,int)),
                      view, SLOT(onRangeNodeChanged(ViewSpec,int,int)) );
    QObject::connect( startingTimeKnob->getSignalSlotHandler().get(), SIGNAL(valueChanged(ViewSpec,int,int)),
                      view, SLOT(onRangeNodeChanged(ViewSpec,int,int)) );

    view->update();
} // DSSlipReaderCommand::slipReader
コード例 #25
0
ファイル: TrackMarker.cpp プロジェクト: kcotugno/Natron
void
TrackMarkerPM::initializeKnobs()
{
    TrackMarker::initializeKnobs();
    NodePtr thisNode = getModel()->getNode();
    NodePtr node;
    {
        CreateNodeArgsPtr args(CreateNodeArgs::create( PLUGINID_OFX_TRACKERPM, NodeCollectionPtr() ));
        args->setProperty<bool>(kCreateNodeArgsPropVolatile, true);
        args->setProperty<bool>(kCreateNodeArgsPropNoNodeGUI, true);
        args->setProperty<std::string>(kCreateNodeArgsPropNodeInitialName, "TrackerPMNode");

        node = getApp()->createNode(args);
        if (!node) {
            throw std::runtime_error("Couldn't create plug-in " PLUGINID_OFX_TRACKERPM);
        }
        if (thisNode) {
            NodePtr inputNode = thisNode->getInput(0);
            if (inputNode) {
                node->connectInput(inputNode, 0);
            }
        }
        trackerNode = node;
    }

    KnobItemsTablePtr model = getModel();
    EffectInstancePtr effect;
    if (model) {
        effect = model->getNode()->getEffectInstance();
    }

    trackPrevButton = getNodeKnob<KnobButton>(node, kTrackerPMParamTrackingPrevious);
    trackNextButton = getNodeKnob<KnobButton>(node, kTrackerPMParamTrackingNext);
    KnobDoublePtr center = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingCenterPoint);
    centerKnob = center;

    // Slave the center knob and unslave when tracking
    if ( !center->linkTo(getCenterKnob()) ) {
        throw std::runtime_error("Could not link center");
    }

    KnobDoublePtr offset = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingOffset);

    // Slave the offset knob
    if ( !offset->linkTo( getOffsetKnob() ) ) {
        throw std::runtime_error("Could not link offset");
    }

    offsetKnob = offset;

    // Ref frame is set for each
    refFrameKnob = getNodeKnob<KnobInt>(node, kTrackerPMParamTrackingReferenceFrame);

    // Enable reference frame
    KnobBoolPtr enableRefFrameKnob = getNodeKnob<KnobBool>(node, kTrackerPMParamTrackingEnableReferenceFrame);
    enableRefFrameKnob->setValue(true);

    KnobChoicePtr scoreType = getNodeKnob<KnobChoice>(node, kTrackerPMParamScore);
    if (effect) {
#ifdef kTrackerParamPatternMatchingScoreType
        KnobIPtr modelKnob = effect->getKnobByName(kTrackerParamPatternMatchingScoreType);
        if (modelKnob) {
            if ( !scoreType->linkTo(modelKnob) ) {
                throw std::runtime_error("Could not link scoreType");
            }
        }
#endif
    }

    scoreTypeKnob = scoreType;

    KnobDoublePtr correlationScore = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingCorrelationScore);
    correlationScoreKnob = correlationScore;

    KnobDoublePtr patternBtmLeft = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingPatternBoxBtmLeft);
    patternBtmLeftKnob = patternBtmLeft;

    // Slave the search window and pattern of the node to the parameters of the marker
    (void)patternBtmLeft->linkTo(getPatternBtmLeftKnob());

    KnobDoublePtr patternTopRight = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingPatternBoxTopRight);
    patternTopRightKnob = patternTopRight;
    (void)patternTopRight->linkTo(getPatternTopRightKnob());

    KnobDoublePtr searchWindowBtmLeft = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingSearchBoxBtmLeft);
    searchWindowBtmLeftKnob = searchWindowBtmLeft;
    (void)searchWindowBtmLeft->linkTo(getSearchWindowBottomLeftKnob());

    KnobDoublePtr searchWindowTopRight = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingSearchBoxTopRight);
    searchWindowTopRightKnob = searchWindowTopRight;
    (void)searchWindowTopRight->linkTo(getSearchWindowTopRightKnob());

} // TrackMarkerPM::initializeKnobs
コード例 #26
0
ファイル: TrackMarker.cpp プロジェクト: kcotugno/Natron
void
TrackMarker::initializeKnobs()
{
    KnobItemsTablePtr model = getModel();
    EffectInstancePtr effect;
    if (model) {
        effect = model->getNode()->getEffectInstance();
    }
    KnobIntPtr defPatternSizeKnob, defSearchSizeKnob;
    KnobChoicePtr defMotionModelKnob;
    defPatternSizeKnob = toKnobInt(effect->getKnobByName(kTrackerUIParamDefaultMarkerPatternWinSize));
    defSearchSizeKnob = toKnobInt(effect->getKnobByName(kTrackerUIParamDefaultMarkerSearchWinSize));
    defMotionModelKnob = toKnobChoice(effect->getKnobByName(kTrackerUIParamDefaultMotionModel));

    double patternHalfSize = defPatternSizeKnob ? defPatternSizeKnob->getValue() / 2. : 21;
    double searchHalfSize = defSearchSizeKnob ? defSearchSizeKnob->getValue() / 2. : 71;

    int defMotionModel_i = defMotionModelKnob ? defMotionModelKnob->getValue() : 0;

    KnobDoublePtr swbbtmLeft = createKnob<KnobDouble>(kTrackerParamSearchWndBtmLeft, 2);

    swbbtmLeft->setLabel(tr(kTrackerParamSearchWndBtmLeftLabel));
    swbbtmLeft->setDefaultValue(-searchHalfSize, DimIdx(0));
    swbbtmLeft->setDefaultValue(-searchHalfSize, DimIdx(1));
    swbbtmLeft->setHintToolTip( tr(kTrackerParamSearchWndBtmLeftHint) );
    _imp->searchWindowBtmLeft = swbbtmLeft;

    KnobDoublePtr swbtRight = createKnob<KnobDouble>(kTrackerParamSearchWndTopRight, 2);
    swbtRight->setLabel(tr(kTrackerParamSearchWndTopRightLabel));
    swbtRight->setDefaultValue(searchHalfSize, DimIdx(0));
    swbtRight->setDefaultValue(searchHalfSize, DimIdx(1));
    swbtRight->setHintToolTip( tr(kTrackerParamSearchWndTopRightHint) );
    _imp->searchWindowTopRight = swbtRight;


    KnobDoublePtr ptLeft = createKnob<KnobDouble>(kTrackerParamPatternTopLeft, 2);
    ptLeft->setLabel(tr(kTrackerParamPatternTopLeftLabel));
    ptLeft->setDefaultValue(-patternHalfSize, DimIdx(0));
    ptLeft->setDefaultValue(patternHalfSize, DimIdx(1));
    ptLeft->setHintToolTip( tr(kTrackerParamPatternTopLeftHint) );
    _imp->patternTopLeft = ptLeft;

    KnobDoublePtr ptRight = createKnob<KnobDouble>(kTrackerParamPatternTopRight, 2);
    ptRight->setLabel(tr(kTrackerParamPatternTopRightLabel));
    ptRight->setDefaultValue(patternHalfSize, DimIdx(0));
    ptRight->setDefaultValue(patternHalfSize, DimIdx(1));
    ptRight->setHintToolTip( tr(kTrackerParamPatternTopRightHint) );
    _imp->patternTopRight = ptRight;

    KnobDoublePtr pBRight = createKnob<KnobDouble>(kTrackerParamPatternBtmRight, 2);
    pBRight->setLabel(tr(kTrackerParamPatternBtmRightLabel));
    pBRight->setDefaultValue(patternHalfSize, DimIdx(0));
    pBRight->setDefaultValue(-patternHalfSize, DimIdx(1));
    pBRight->setHintToolTip( tr(kTrackerParamPatternBtmRightHint) );
    _imp->patternBtmRight = pBRight;

    KnobDoublePtr pBLeft = createKnob<KnobDouble>(kTrackerParamPatternBtmLeft, 2);
    pBLeft->setLabel(tr(kTrackerParamPatternBtmLeftLabel));
    pBLeft->setDefaultValue(-patternHalfSize, DimIdx(0));
    pBLeft->setDefaultValue(-patternHalfSize, DimIdx(1));
    pBLeft->setHintToolTip( tr(kTrackerParamPatternBtmLeftHint) );
    _imp->patternBtmLeft = pBLeft;

    KnobDoublePtr centerKnob = createKnob<KnobDouble>(kTrackerParamCenter, 2);
    centerKnob->setLabel(tr(kTrackerParamCenterLabel));
    centerKnob->setHintToolTip( tr(kTrackerParamCenterHint) );
    _imp->center = centerKnob;

    KnobDoublePtr offsetKnob = createKnob<KnobDouble>(kTrackerParamOffset, 2);
    offsetKnob->setLabel(tr(kTrackerParamOffsetLabel));
    offsetKnob->setHintToolTip( tr(kTrackerParamOffsetHint) );
    _imp->offset = offsetKnob;

#ifdef NATRON_TRACK_MARKER_USE_WEIGHT
    KnobDoublePtr weightKnob = createKnob<KnobDouble>(kTrackerParamTrackWeight, 1);
    weightKnob->setLabel(tr(kTrackerParamTrackWeightLabel));
    weightKnob->setHintToolTip( tr(kTrackerParamTrackWeightHint) );
    weightKnob->setDefaultValue(1.);
    weightKnob->setAnimationEnabled(false);
    weightKnob->setRange(0., 1.);
    _imp->weight = weightKnob;
#endif

    KnobChoicePtr mmodelKnob = createKnob<KnobChoice>(kTrackerParamMotionModel, 1);
    mmodelKnob->setHintToolTip( tr(kTrackerParamMotionModelHint) );
    mmodelKnob->setLabel(tr(kTrackerParamMotionModelLabel));
    {
        std::vector<ChoiceOption> choices, helps;
        std::map<int, std::string> icons;
        TrackerNodePrivate::getMotionModelsAndHelps(true, &choices, &icons);
        mmodelKnob->populateChoices(choices);
        mmodelKnob->setIcons(icons);
    }

    mmodelKnob->setDefaultValue(defMotionModel_i);
    _imp->motionModel = mmodelKnob;

    KnobDoublePtr errKnob = createKnob<KnobDouble>(kTrackerParamError, 1);
    errKnob->setLabel(tr(kTrackerParamErrorLabel));
    _imp->error = errKnob;

    KnobBoolPtr enableKnob = createKnob<KnobBool>(kTrackerParamEnabled, 1);
    enableKnob->setLabel(tr(kTrackerParamEnabledLabel));
    enableKnob->setHintToolTip( tr(kTrackerParamEnabledHint) );
    enableKnob->setAnimationEnabled(true);
    enableKnob->setDefaultValue(true);
    _imp->enabled = enableKnob;

    addColumn(kKnobTableItemColumnLabel, DimIdx(0));
    addColumn(kTrackerParamEnabled, DimIdx(0));
    addColumn(kTrackerParamMotionModel, DimIdx(0));
    addColumn(kTrackerParamCenter, DimIdx(0));
    addColumn(kTrackerParamCenter, DimIdx(1));
    addColumn(kTrackerParamOffset, DimIdx(0));
    addColumn(kTrackerParamOffset, DimIdx(1));
    addColumn(kTrackerParamError, DimIdx(0));

} // TrackMarker::initializeKnobs
コード例 #27
0
ActionRetCodeEnum
RotoShapeRenderNode::getRegionOfDefinition(TimeValue time, const RenderScale& scale, ViewIdx view, RectD* rod)
{

    RotoDrawableItemPtr item = getAttachedRotoItem();
    assert(item);
    assert((isRenderClone() && item->isRenderClone()) ||
           (!isRenderClone() && !item->isRenderClone()));
    const bool isPainting = isDuringPaintStrokeCreation();
    RectD shapeRoD;
    getRoDFromItem(item, time, view, isPainting, &shapeRoD);

    bool clipToFormat = _imp->clipToFormatKnob.lock()->getValue();

    RotoShapeRenderTypeEnum type = (RotoShapeRenderTypeEnum)_imp->renderType.lock()->getValue();
    switch (type) {
        case eRotoShapeRenderTypeSmear: {
            RectD defaultRod;
            ActionRetCodeEnum stat = EffectInstance::getRegionOfDefinition(time, scale, view, &defaultRod);
            if (isFailureRetCode(stat)) {
                return stat;
            }
            if (!defaultRod.isNull()) {
                *rod = shapeRoD;
                rod->merge(defaultRod);
            }
        }   break;
        case eRotoShapeRenderTypeSolid: {
            RotoPaintOutputRoDTypeEnum rodType = (RotoPaintOutputRoDTypeEnum)_imp->outputRoDTypeKnob.lock()->getValue();
            switch (rodType) {
                case eRotoPaintOutputRoDTypeDefault: {
                    *rod = shapeRoD;
                    // No format is set, use the format from the input
                    if (clipToFormat) {
                        EffectInstancePtr inputEffect = getInputRenderEffectAtAnyTimeView(0);
                        if (inputEffect) {
                            RectI outputFormat = inputEffect->getOutputFormat();
                            RectD outputFormatCanonical;
                            outputFormat.toCanonical_noClipping(scale, inputEffect->getAspectRatio(-1), &outputFormatCanonical);
                            rod->intersect(outputFormatCanonical, rod);
                        }
                    }
                }   break;
                case eRotoPaintOutputRoDTypeFormat: {
                    KnobIntPtr sizeKnob = _imp->outputFormatSizeKnob.lock();
                    int w = sizeKnob->getValue(DimIdx(0));
                    int h = _imp->outputFormatSizeKnob.lock()->getValue(DimIdx(1));
                    double par = _imp->outputFormatParKnob.lock()->getValue();

                    RectI pixelFormat;
                    pixelFormat.x1 = pixelFormat.y1 = 0;
                    pixelFormat.x2 = w;
                    pixelFormat.y2 = h;
                    RenderScale renderScale(1.);
                    pixelFormat.toCanonical_noClipping(renderScale, par, rod);
                    if (!clipToFormat) {
                        rod->merge(shapeRoD);
                    }
                }   break;

                case eRotoPaintOutputRoDTypeProject: {
                    Format f;
                    getApp()->getProject()->getProjectDefaultFormat(&f);
                    f.toCanonical_noClipping(RenderScale(1.), f.getPixelAspectRatio(), rod);
                    if (!clipToFormat) {
                        rod->merge(shapeRoD);
                    }
                }   break;
            }
        }   break;
    }

    return eActionStatusOK;

}
コード例 #28
0
ファイル: KnobGuiButton.cpp プロジェクト: kcotugno/Natron
QPixmap
KnobGuiButton::loadPixmapInternal(bool checked, bool applyColorOverlay, const QColor& overlayColor)
{
    KnobGuiPtr knobUI = getKnobGui();
    KnobButtonPtr knob = _knob.lock();
    EffectInstancePtr isEffect = toEffectInstance( knob->getHolder() );
    KnobTableItemPtr isTableItem = toKnobTableItem(knob->getHolder());
    if (isTableItem) {
        isEffect = isTableItem->getModel()->getNode()->getEffectInstance();
    }

    QString filePath;
    if (knobUI->getLayoutType() == KnobGui::eKnobLayoutTypeViewerUI) {
        filePath = QString::fromUtf8( knob->getInViewerContextIconFilePath(checked).c_str() );
    } else {
        filePath = QString::fromUtf8( knob->getIconLabel(checked).c_str() );
    }
    if ( !filePath.isEmpty() && !QFile::exists(filePath) ) {
        if (isEffect) {
            //Prepend the resources path
            QString resourcesPath = QString::fromUtf8( isEffect->getNode()->getPluginResourcesPath().c_str() );
            if ( !resourcesPath.endsWith( QLatin1Char('/') ) ) {
                resourcesPath += QLatin1Char('/');
            }
            filePath.prepend(resourcesPath);
        }
    }

    if ( !filePath.isEmpty() ) {
#if 0
        QPixmap pix;
        if (pix.load(filePath)) {
            return pix;
        }
#else
        QImage img;
        if ( img.load(filePath) ) {
            if (applyColorOverlay) {

                int depth = img.depth();
                if (depth != 32) {
                    img = img.convertToFormat(QImage::Format_ARGB32);
                }
                depth = img.depth();
                assert(depth == 32);
                for (int y = 0; y < img.height(); ++y) {
                    QRgb* pix = (QRgb*)img.scanLine(y);
                    for (int x = 0; x < img.width(); ++x) {
                        QRgb srcPix = pix[x];
                        double a = qAlpha(srcPix) / 255.f;
                        double r = qRed(srcPix) / 255.f * a;
                        double g = qGreen(srcPix) / 255.f * a;
                        double b = qBlue(srcPix) / 255.f * a;

                        r = Image::clamp(overFunctor(overlayColor.redF(), r, overlayColor.alphaF()), 0., 1.);
                        g = Image::clamp(overFunctor(overlayColor.greenF(), g, overlayColor.alphaF()), 0., 1.);
                        b = Image::clamp(overFunctor(overlayColor.blueF(), b, overlayColor.alphaF()), 0., 1.);
                        a = Image::clamp(overFunctor(overlayColor.alphaF(), a, overlayColor.alphaF()) * a, 0., 1.);

                        QRgb p = qRgba(r * 255, g * 255, b * 255, a * 255);
                        img.setPixel(x, y, p);
                    }
                }
            }
            QPixmap pix = QPixmap::fromImage(img);
            return pix;
        }
#endif
    }
    return QPixmap();
} // loadPixmapInternal
コード例 #29
0
ActionRetCodeEnum
RotoShapeRenderNode::getTimeInvariantMetadata(NodeMetadata& metadata)
{


    assert(_imp->renderType.lock());
    RotoShapeRenderTypeEnum type = (RotoShapeRenderTypeEnum)_imp->renderType.lock()->getValue();
    int nComps;
    if (type == eRotoShapeRenderTypeSolid) {
        // If there's an input to the RotoShapeRender node, pass-through the meta-data number of components so that downstream nodes
        // have a good default color plane.
        // E.g: if we have Constant--> RotoShapeRender --> Merge,  we want the Merge to have the number of components of the Constant
        EffectInstancePtr inputEffect = getInputRenderEffectAtAnyTimeView(0);
        if (inputEffect) {
            ImagePlaneDesc inputPlane, paireInputPlane;
            inputEffect->getMetadataComponents(-1, &inputPlane, &paireInputPlane);
            nComps = inputPlane.getNumComponents();
        } else {
            nComps = 1;
        }
    } else {
        nComps = 4;
    }

    metadata.setColorPlaneNComps(-1, nComps);
    metadata.setColorPlaneNComps(0, nComps);

    // The roto can be sampled at any non integer time
    metadata.setIsContinuous(true);


    RotoPaintOutputRoDTypeEnum rodType = (RotoPaintOutputRoDTypeEnum)_imp->outputRoDTypeKnob.lock()->getValue();
    switch (rodType) {
        case eRotoPaintOutputRoDTypeDefault:
            // No format is set
            break;
        case eRotoPaintOutputRoDTypeFormat: {
            KnobIntPtr sizeKnob = _imp->outputFormatSizeKnob.lock();
            int w = sizeKnob->getValue(DimIdx(0));
            int h = _imp->outputFormatSizeKnob.lock()->getValue(DimIdx(1));
            double par = _imp->outputFormatParKnob.lock()->getValue();

            RectI pixelFormat;
            pixelFormat.x1 = pixelFormat.y1 = 0;
            pixelFormat.x2 = w;
            pixelFormat.y2 = h;

            metadata.setPixelAspectRatio(-1, par);
            metadata.setOutputFormat(pixelFormat);

        }   break;

        case eRotoPaintOutputRoDTypeProject: {
            Format f;
            getApp()->getProject()->getProjectDefaultFormat(&f);
            metadata.setPixelAspectRatio(-1, f.getPixelAspectRatio());
            metadata.setOutputFormat(f);
        }   break;
    }


    return eActionStatusOK;
}
コード例 #30
0
void
moveGroupNode(DopeSheetEditor* model,
              const NodePtr& node,
              double dt)
{
    NodeGroupPtr group = node->isEffectNodeGroup();

    assert(group);
    NodesList nodes;
    group->getNodes_recursive(nodes, true);

    for (NodesList::iterator it = nodes.begin(); it != nodes.end(); ++it) {
        NodeGuiPtr nodeGui = boost::dynamic_pointer_cast<NodeGui>( (*it)->getNodeGui() );
        assert(nodeGui);
        std::string pluginID = (*it)->getPluginID();
        NodeGroupPtr isChildGroup = (*it)->isEffectNodeGroup();

        // Move readers
#ifndef NATRON_ENABLE_IO_META_NODES
        if ( ReadNode::isBundledReader( pluginID, node->getApp()->wasProjectCreatedWithLowerCaseIDs() ) ) {
#else
        if (pluginID == PLUGINID_NATRON_READ) {
#endif
            moveReader(*it, dt);
        } else if (pluginID == PLUGINID_OFX_TIMEOFFSET) {
            moveTimeOffset(*it, dt);
        } else if (pluginID == PLUGINID_OFX_FRAMERANGE) {
            moveFrameRange(*it, dt);
        } else if (isChildGroup) {
            moveGroupNode(model, *it, dt);
        }

        // Move keyframes
        const KnobsVec &knobs = (*it)->getKnobs();

        for (KnobsVec::const_iterator knobIt = knobs.begin(); knobIt != knobs.end(); ++knobIt) {
            const KnobIPtr& knob = *knobIt;
            if ( !knob->hasAnimation() ) {
                continue;
            }

            for (int dim = 0; dim < knob->getDimension(); ++dim) {
                if ( !knob->isAnimated( dim, ViewIdx(0) ) ) {
                    continue;
                }
                KeyFrameSet keyframes = knob->getCurve(ViewIdx(0), dim)->getKeyFrames_mt_safe();

                for (KeyFrameSet::iterator kfIt = keyframes.begin(); kfIt != keyframes.end(); ++kfIt) {
                    KeyFrame kf = (*kfIt);
                    KeyFrame fake;

                    knob->moveValueAtTime(eCurveChangeReasonDopeSheet, kf.getTime(), ViewSpec::all(), dim, dt, 0, &fake);
                }
            }
        }
    }
} // moveGroupNode

NATRON_NAMESPACE_ANONYMOUS_EXIT


////////////////////////// DSMoveKeysCommand //////////////////////////

DSMoveKeysAndNodesCommand::DSMoveKeysAndNodesCommand(const DSKeyPtrList &keys,
                                                     const std::vector<DSNodePtr >& nodes,
                                                     double dt,
                                                     DopeSheetEditor *model,
                                                     QUndoCommand *parent)
    : QUndoCommand(parent),
    _keys(keys),
    _nodes(),
    _dt(dt),
    _model(model)
{
    setText( tr("Move selected keys") );
    std::set<NodePtr > nodesSet;
    for (std::vector<DSNodePtr >::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
        DopeSheetItemType type = (*it)->getItemType();
        if ( (type != eDopeSheetItemTypeReader) &&
             ( type != eDopeSheetItemTypeGroup) &&
             ( type != eDopeSheetItemTypeTimeOffset) &&
             ( type != eDopeSheetItemTypeFrameRange) ) {
            //Note that Retime nodes cannot be moved
            continue;
        }
        _nodes.push_back(*it);
        nodesSet.insert( (*it)->getInternalNode() );
        NodeGroupPtr isGroup = (*it)->getInternalNode()->isEffectNodeGroup();
        if (isGroup) {
            NodesList recurseNodes;
            isGroup->getNodes_recursive(recurseNodes, true);
            for (NodesList::iterator it = recurseNodes.begin(); it != recurseNodes.end(); ++it) {
                nodesSet.insert(*it);
            }
        }
    }

    for (DSKeyPtrList::iterator it = _keys.begin(); it != _keys.end(); ++it) {
        KnobHolderPtr holder = (*it)->getContext()->getInternalKnob()->getHolder();
        assert(holder);
        EffectInstancePtr isEffect = toEffectInstance(holder);
        if (isEffect) {
            nodesSet.insert( isEffect->getNode() );
        }
    }

    for (std::set<NodePtr >::iterator it = nodesSet.begin(); it != nodesSet.end(); ++it) {
        _allDifferentNodes.push_back(*it);
    }
}

void
DSMoveKeysAndNodesCommand::undo()
{
    moveSelection(-_dt);
}