Ejemplo n.º 1
0
bool
KnobGui::isSecretRecursive() const
{
    // If the Knob is within a group, only show it if the group is unfolded!
    // To test it:
    // try TuttlePinning: fold all groups, then switch from perspective to affine to perspective.
    //  VISIBILITY is different from SECRETNESS. The code considers that both things are equivalent, which is wrong.
    // Of course, this check has to be *recursive* (in case the group is within a folded group)
    KnobPtr knob = getKnob();
    bool isViewerKnob = _imp->container->isInViewerUIKnob();
    bool showit = isViewerKnob ? !knob->getInViewerContextSecret() : !knob->getIsSecret();
    KnobPtr parentKnob = knob->getParentKnob();
    KnobGroup* parentIsGroup = dynamic_cast<KnobGroup*>( parentKnob.get() );

    while (showit && parentKnob && parentIsGroup) {
        KnobGuiGroup* parentGui = dynamic_cast<KnobGuiGroup*>( _imp->container->getKnobGui(parentKnob).get() );
        // check for secretness and visibility of the group
        bool parentSecret = isViewerKnob ? parentKnob->getInViewerContextSecret() : parentKnob->getIsSecret();
        if ( parentSecret || ( parentGui && !parentGui->isChecked() ) ) {
            showit = false; // one of the including groups is folder, so this item is hidden
        }
        // prepare for next loop iteration
        parentKnob = parentKnob->getParentKnob();
        parentIsGroup = dynamic_cast<KnobGroup*>( parentKnob.get() );
    }

    return !showit;
}
Ejemplo n.º 2
0
void
KnobGui::onSetKeyActionTriggered()
{
    QAction* action = qobject_cast<QAction*>( sender() );

    assert(action);
    int dim = action->data().toInt();
    KnobPtr knob = getKnob();

    assert( knob->getHolder()->getApp() );
    //get the current time on the global timeline
    SequenceTime time = knob->getHolder()->getApp()->getTimeLine()->currentFrame();
    AddKeysCommand::KeysToAddList toAdd;
    KnobGuiPtr thisShared = shared_from_this();
    for (int i = 0; i < knob->getDimension(); ++i) {
        if ( (dim == -1) || (i == dim) ) {
            std::list<boost::shared_ptr<CurveGui> > curves = getGui()->getCurveEditor()->findCurve(thisShared, i);
            for (std::list<boost::shared_ptr<CurveGui> >::iterator it = curves.begin(); it != curves.end(); ++it) {
                AddKeysCommand::KeyToAdd keyToAdd;
                KeyFrame kf;
                kf.setTime(time);
                Knob<int>* isInt = dynamic_cast<Knob<int>*>( knob.get() );
                Knob<bool>* isBool = dynamic_cast<Knob<bool>*>( knob.get() );
                AnimatingKnobStringHelper* isString = dynamic_cast<AnimatingKnobStringHelper*>( knob.get() );
                Knob<double>* isDouble = dynamic_cast<Knob<double>*>( knob.get() );

                if (isInt) {
                    kf.setValue( isInt->getValue(i) );
                } else if (isBool) {
                    kf.setValue( isBool->getValue(i) );
                } else if (isDouble) {
                    kf.setValue( isDouble->getValue(i) );
                } else if (isString) {
                    std::string v = isString->getValue(i);
                    double dv;
                    isString->stringToKeyFrameValue(time, ViewIdx(0), v, &dv);
                    kf.setValue(dv);
                }

                keyToAdd.keyframes.push_back(kf);
                keyToAdd.curveUI = *it;
                keyToAdd.knobUI = thisShared;
                keyToAdd.dimension = i;
                toAdd.push_back(keyToAdd);
            }
        }
    }
    pushUndoCommand( new AddKeysCommand(getGui()->getCurveEditor()->getCurveWidget(), toAdd) );
}
Ejemplo n.º 3
0
void
KnobGui::resetDefault(int dimension)
{
    KnobPtr knob = getKnob();
    KnobButton* isBtn = dynamic_cast<KnobButton*>( knob.get() );
    KnobPage* isPage = dynamic_cast<KnobPage*>( knob.get() );
    KnobGroup* isGroup = dynamic_cast<KnobGroup*>( knob.get() );
    KnobSeparator* isSeparator = dynamic_cast<KnobSeparator*>( knob.get() );

    if (!isBtn && !isPage && !isGroup && !isSeparator) {
        std::list<KnobPtr > knobs;
        knobs.push_back(knob);
        pushUndoCommand( new RestoreDefaultsCommand(false, knobs, dimension) );
    }
}
Ejemplo n.º 4
0
void
KnobGui::pasteClipBoard(int targetDimension)
{
    KnobPtr knob = getKnob();

    if (!knob) {
        return;
    }

    //the dimension from which it was copied from
    int cbDim;
    KnobClipBoardType type;
    KnobPtr fromKnob;
    appPTR->getKnobClipBoard(&type, &fromKnob, &cbDim);
    if (!fromKnob) {
        return;
    }

    if ( (targetDimension == 0) && !getAllDimensionsVisible() ) {
        targetDimension = -1;
    }

    if ( !knob->isAnimationEnabled() && (type == eKnobClipBoardTypeCopyAnim) ) {
        Dialogs::errorDialog( tr("Paste").toStdString(), tr("This parameter does not support animation").toStdString() );

        return;
    }

    if ( !KnobI::areTypesCompatibleForSlave( fromKnob.get(), knob.get() ) ) {
        Dialogs::errorDialog( tr("Paste").toStdString(), tr("You can only copy/paste between parameters of the same type. To overcome this, use an expression instead.").toStdString() );

        return;
    }

    if ( (cbDim != -1) && (targetDimension == -1) ) {
        Dialogs::errorDialog( tr("Paste").toStdString(), tr("When copy/pasting on all dimensions, original and target parameters must have the same dimension.").toStdString() );

        return;
    }

    if ( ( (targetDimension == -1) || (cbDim == -1) ) && ( fromKnob->getDimension() != knob->getDimension() ) ) {
        Dialogs::errorDialog( tr("Paste").toStdString(), tr("When copy/pasting on all dimensions, original and target parameters must have the same dimension.").toStdString() );

        return;
    }

    pushUndoCommand( new PasteUndoCommand(shared_from_this(), type, cbDim, targetDimension, fromKnob) );
} // pasteClipBoard
Ejemplo n.º 5
0
void
KnobGui::onLabelChanged()
{
    if (_imp->descriptionLabel) {
        KnobPtr knob = getKnob();
        if (!knob) {
            return;
        }
        const std::string& iconLabel = knob->getIconLabel();
        if (!iconLabel.empty()) {
            return;
        }
        std::string descriptionLabel;
        KnobString* isStringKnob = dynamic_cast<KnobString*>(knob.get());
        bool isLabelKnob = isStringKnob && isStringKnob->isLabel();
        if (isLabelKnob) {
            descriptionLabel = isStringKnob->getValue();
        } else {
            descriptionLabel = knob->getLabel();
        }
        
        _imp->descriptionLabel->setText_overload(QString::fromUtf8(descriptionLabel.c_str()));
        onLabelChangedInternal();
    }
}
Ejemplo n.º 6
0
void
KnobSerialization::restoreTracks(const KnobPtr & knob,
                                 const NodesList & allNodes)
{
    KnobDouble* isDouble = dynamic_cast<KnobDouble*>( knob.get() );

    if ( isDouble && (isDouble->getName() == "center") && (isDouble->getDimension() == 2) ) {
        isDouble->restoreTracks(slavedTracks,allNodes);
    }
}
Ejemplo n.º 7
0
void
KnobGui::onSetValueUsingUndoStack(const Variant & v,
                                  ViewSpec /*view*/,
                                  int dim)
{
    KnobPtr knob = getKnob();

    Knob<int>* isInt = dynamic_cast<Knob<int>*>( knob.get() );
    Knob<bool>* isBool = dynamic_cast<Knob<bool>*>( knob.get() );
    Knob<double>* isDouble = dynamic_cast<Knob<double>*>( knob.get() );
    Knob<std::string>* isString = dynamic_cast<Knob<std::string>*>( knob.get() );

    if (isInt) {
        pushUndoCommand( new KnobUndoCommand<int>(shared_from_this(), isInt->getValue(dim), v.toInt(), dim) );
    } else if (isBool) {
        pushUndoCommand( new KnobUndoCommand<bool>(shared_from_this(), isBool->getValue(dim), v.toBool(), dim) );
    } else if (isDouble) {
        pushUndoCommand( new KnobUndoCommand<double>(shared_from_this(), isDouble->getValue(dim), v.toDouble(), dim) );
    } else if (isString) {
        pushUndoCommand( new KnobUndoCommand<std::string>(shared_from_this(), isString->getValue(dim), v.toString().toStdString(), dim) );
    }
}
void
PythonPanelSerialization::initialize(NATRON_PYTHON_NAMESPACE::PyPanel* tab,
                                     const std::string& func)
{
    name = tab->getLabel();
    pythonFunction = func;
    std::list<NATRON_PYTHON_NAMESPACE::Param*> parameters = tab->getParams();
    for (std::list<NATRON_PYTHON_NAMESPACE::Param*>::iterator it = parameters.begin(); it != parameters.end(); ++it) {
        KnobPtr knob = (*it)->getInternalKnob();
        KnobGroup* isGroup = dynamic_cast<KnobGroup*>( knob.get() );
        KnobPage* isPage = dynamic_cast<KnobPage*>( knob.get() );
        KnobButton* isButton = dynamic_cast<KnobButton*>( knob.get() );
        //KnobChoice* isChoice = dynamic_cast<KnobChoice*>( knob.get() );

        if (!isGroup && !isPage && !isButton) {
            boost::shared_ptr<KnobSerialization> k( new KnobSerialization(knob) );
            knobs.push_back(k);
        }
        delete *it;
    }

    userData = tab->save_serialization_thread().toStdString();
}
Ejemplo n.º 9
0
void
RestoreDefaultsCommand::undo()
{
    assert( _clones.size() == _knobs.size() );

    std::list<SequenceTime> times;
    KnobPtr first = _knobs.front().lock();
    AppInstance* app = first->getHolder()->getApp();
    assert(app);
    std::list<KnobWPtr >::const_iterator itClone = _clones.begin();
    for (std::list<KnobWPtr >::const_iterator it = _knobs.begin(); it != _knobs.end(); ++it, ++itClone) {
        KnobPtr itKnob = it->lock();
        if (!itKnob) {
            continue;
        }
        KnobPtr itCloneKnob = itClone->lock();
        if (!itCloneKnob) {
            continue;
        }
        itKnob->cloneAndUpdateGui( itCloneKnob.get() );

        if ( itKnob->getHolder()->getApp() ) {
            int dim = itKnob->getDimension();
            for (int i = 0; i < dim; ++i) {
                if ( (i == _targetDim) || (_targetDim == -1) ) {
                    boost::shared_ptr<Curve> c = itKnob->getCurve(ViewIdx(0), i);
                    if (c) {
                        KeyFrameSet kfs = c->getKeyFrames_mt_safe();
                        for (KeyFrameSet::iterator it = kfs.begin(); it != kfs.end(); ++it) {
                            times.push_back( std::floor(it->getTime() + 0.5) );
                        }
                    }
                }
            }
        }
    }
    app->addMultipleKeyframeIndicatorsAdded(times, true);

    first->getHolder()->incrHashAndEvaluate(true, true);
    if ( first->getHolder()->getApp() ) {
        first->getHolder()->getApp()->redrawAllViewers();
    }

    setText( tr("Restore default value(s)") );
}
Ejemplo n.º 10
0
///High level test: render 1 frame of dot generator
TEST_F(BaseTest, GenerateDot)
{
    ///create the generator
    NodePtr generator = createNode(_generatorPluginID);

    ///create the writer and set its output filename
    NodePtr writer = createNode(_writeOIIOPluginID);

    ASSERT_TRUE(generator && writer);

    KnobPtr frameRange = generator->getApp()->getProject()->getKnobByName("frameRange");
    ASSERT_TRUE(frameRange);
    KnobInt* knob = dynamic_cast<KnobInt*>( frameRange.get() );
    ASSERT_TRUE(knob);
    knob->setValue(1, ViewSpec::all(), 0);
    knob->setValue(1, ViewSpec::all(), 1);

    Format f(0, 0, 200, 200, "toto", 1.);
    generator->getApp()->getProject()->setOrAddProjectFormat(f);

    const QString& binPath = appPTR->getApplicationBinaryPath();
    QString filePath = binPath + QString::fromUtf8("/test_dot_generator.jpg");
    writer->setOutputFilesForWriter( filePath.toStdString() );

    ///attempt to connect the 2 nodes together
    connectNodes(generator, writer, 0, true);

    ///and start rendering. This call is blocking.
    std::list<AppInstance::RenderWork> works;
    AppInstance::RenderWork w;
    w.writer = dynamic_cast<OutputEffectInstance*>( writer->getEffectInstance().get() );
    assert(w.writer);
    w.firstFrame = INT_MIN;
    w.lastFrame = INT_MAX;
    w.frameStep = INT_MIN;
    w.useRenderStats = false;
    works.push_back(w);
    getApp()->startWritersRendering(false, works);

    EXPECT_TRUE( QFile::exists(filePath) );
    QFile::remove(filePath);
}
Ejemplo n.º 11
0
void
KnobGui::onFrozenChanged(bool frozen)
{
    KnobPtr knob = getKnob();
    KnobButton* isBtn = dynamic_cast<KnobButton*>(knob.get());
    if (isBtn && !isBtn->isRenderButton()) {
        return;
    }
    int dims = knob->getDimension();

    for (int i = 0; i < dims; ++i) {
        ///Do not unset read only if the knob is slaved in this dimension because we are still using it.
        if ( !frozen && knob->isSlave(i) ) {
            continue;
        }
        if (knob->isEnabled(i)) {
            setReadOnly_(frozen, i);
        }
    }
}
Ejemplo n.º 12
0
void
OutputEffectInstance::createWriterPath()
{
    ///Make sure that the file path exists
    KnobPtr fileParam = getKnobByName(kOfxImageEffectFileParamName);

    if (fileParam) {
        Knob<std::string>* isString = dynamic_cast<Knob<std::string>*>( fileParam.get() );
        if (isString) {
            std::string pattern = isString->getValue();
            std::string path = SequenceParsing::removePath(pattern);
            std::map<std::string, std::string> env;
            getApp()->getProject()->getEnvironmentVariables(env);
            Project::expandVariable(env, path);
            if ( !path.empty() ) {
                QDir().mkpath( QString::fromUtf8( path.c_str() ) );
            }
        }
    }
}
Ejemplo n.º 13
0
TEST_F(BaseTest, SetValues)
{
    NodePtr generator = createNode(_generatorPluginID);

    assert(generator);
    KnobPtr knob = generator->getKnobByName("noiseZSlope");
    KnobDouble* radius = dynamic_cast<KnobDouble*>( knob.get() );
    EXPECT_TRUE(radius != 0);
    if (!radius) {
        return;
    }
    radius->setValue(0.5);
    EXPECT_TRUE(radius->getValue() == 0.5);

    //Check that linear interpolation is working as intended
    KeyFrame kf;
    radius->setInterpolationAtTime(eCurveChangeReasonInternal, ViewSpec::all(),  0, 0, eKeyframeTypeLinear, &kf);
    radius->setValueAtTime(0, 0., ViewSpec::all(), 0);
    radius->setValueAtTime(100, 1., ViewSpec::all(), 0);
    for (int i = 0; i <= 100; ++i) {
        double v = radius->getValueAtTime(i);
        EXPECT_TRUE(std::abs(v - i / 100.) < 1e-6);
    }
}
Ejemplo n.º 14
0
void
DockablePanelPrivate::initializeKnobVector(const KnobsVec& knobs,
                                           QWidget* lastRowWidget)
{
    std::list<boost::shared_ptr<KnobPage> > pages;
    KnobsVec regularKnobs;

    //Extract pages first
    for (U32 i = 0; i < knobs.size(); ++i) {
        KnobPage *isPage = dynamic_cast<KnobPage*>( knobs[i].get() );
        if (isPage) {
            pages.push_back( boost::dynamic_pointer_cast<KnobPage>(knobs[i]) );
            continue;
        } else {
            regularKnobs.push_back(knobs[i]);
        }
    }
    for (std::list<boost::shared_ptr<KnobPage> >::iterator it = pages.begin(); it != pages.end(); ++it) {
        //create page
        (void)findKnobGuiOrCreate( *it, true, 0, KnobsVec() );

        KnobsVec children = (*it)->getChildren();
        KnobsVec::iterator prev = children.end();
        for (KnobsVec::iterator it2 = children.begin(); it2 != children.end(); ++it2) {
            bool makeNewLine = true;
            KnobGroup *isGroup = dynamic_cast<KnobGroup*>( it2->get() );

            ////The knob  will have a vector of all other knobs on the same line.
            KnobsVec knobsOnSameLine;


            //If the knob is dynamic (i:e created after the initial creation of knobs)
            //it can be added as part of a group defined earlier hence we have to insert it at the proper index.
            KnobPtr parentKnob = (*it2)->getParentKnob();
            KnobGroup* isParentGroup = dynamic_cast<KnobGroup*>( parentKnob.get() );


            if (!isGroup) {
                if ( ( prev != children.end() ) && !(*prev)->isNewLineActivated() ) {
                    makeNewLine = false;
                }
                if (isParentGroup) {
                    KnobsVec groupsiblings = isParentGroup->getChildren();
                    findKnobsOnSameLine(groupsiblings, *it2, knobsOnSameLine);
                } else {
                    findKnobsOnSameLine(children, *it2, knobsOnSameLine);
                }
            }

            KnobGuiPtr newGui = findKnobGuiOrCreate(*it2, makeNewLine, lastRowWidget, knobsOnSameLine);

            ///childrens cannot be on the same row than their parent
            if (!isGroup && newGui) {
                lastRowWidget = newGui->getFieldContainer();
            }


            std::vector<KnobPtr>::iterator foundRegular = std::find(regularKnobs.begin(), regularKnobs.end(), *it2);
            if ( foundRegular != regularKnobs.end() ) {
                regularKnobs.erase(foundRegular);
            }


            if ( prev == children.end() ) {
                prev = children.begin();
            } else {
                ++prev;
            }
        }
    }

    //For knobs left,  create them
    KnobsVec::iterator prev = regularKnobs.end();
    for (KnobsVec::iterator it = regularKnobs.begin(); it != regularKnobs.end(); ++it) {
        bool makeNewLine = true;
        KnobGroup *isGroup = dynamic_cast<KnobGroup*>( it->get() );

        ////The knob  will have a vector of all other knobs on the same line.
        KnobsVec knobsOnSameLine;


        //If the knob is dynamic (i:e created after the initial creation of knobs)
        //it can be added as part of a group defined earlier hence we have to insert it at the proper index.
        KnobPtr parentKnob = (*it)->getParentKnob();
        KnobGroup* isParentGroup = dynamic_cast<KnobGroup*>( parentKnob.get() );


        if (!isGroup) {
            if ( ( prev != regularKnobs.end() ) && !(*prev)->isNewLineActivated() ) {
                makeNewLine = false;
            }

            KnobPage* isParentPage = dynamic_cast<KnobPage*>( parentKnob.get() );
            if (isParentPage) {
                KnobsVec children = isParentPage->getChildren();
                findKnobsOnSameLine(children, (*it), knobsOnSameLine);
            } else if (isParentGroup) {
                KnobsVec children = isParentGroup->getChildren();
                findKnobsOnSameLine(children, (*it), knobsOnSameLine);
            } else {
                findKnobsOnSameLine(regularKnobs, (*it), knobsOnSameLine);
            }
        }

        KnobGuiPtr newGui = findKnobGuiOrCreate(*it, makeNewLine, lastRowWidget, knobsOnSameLine);

        ///childrens cannot be on the same row than their parent
        if (!isGroup && newGui) {
            lastRowWidget = newGui->getFieldContainer();
        }

        if ( prev == regularKnobs.end() ) {
            prev = regularKnobs.begin();
        } else {
            ++prev;
        }
    }

    _publicInterface->refreshTabWidgetMaxHeight();
} // DockablePanelPrivate::initializeKnobVector
Ejemplo n.º 15
0
KnobGuiPtr
DockablePanelPrivate::findKnobGuiOrCreate(const KnobPtr & knob,
                                          bool makeNewLine,
                                          QWidget* lastRowWidget,
                                          const std::vector< boost::shared_ptr< KnobI > > & knobsOnSameLine)
{
    assert(knob);
    boost::shared_ptr<KnobGroup> isGroup = boost::dynamic_pointer_cast<KnobGroup>(knob);
    boost::shared_ptr<KnobPage> isPage = boost::dynamic_pointer_cast<KnobPage>(knob);
    for (KnobsGuiMapping::const_iterator it = _knobs.begin(); it != _knobs.end(); ++it) {
        if ( (it->first.lock() == knob) && it->second ) {
            if (isPage) {
                return it->second;
            } else if ( isGroup && ( ( !isGroup->isTab() && it->second->hasWidgetBeenCreated() ) || isGroup->isTab() ) ) {
                return it->second;
            } else if ( it->second->hasWidgetBeenCreated() ) {
                return it->second;
            } else {
                break;
            }
        }
    }


    if (isPage) {
        if ( isPage->getChildren().empty() ) {
            return KnobGuiPtr();
        }
        getOrCreatePage(isPage);
        KnobsVec children = isPage->getChildren();
        initializeKnobVector(children, lastRowWidget);

        return KnobGuiPtr();
    }

    KnobGuiPtr ret = createKnobGui(knob);
    if (!ret) {
        return KnobGuiPtr();
    }

    KnobPtr parentKnob = knob->getParentKnob();
    boost::shared_ptr<KnobGroup> parentIsGroup = boost::dynamic_pointer_cast<KnobGroup>(parentKnob);
    KnobGuiGroup* parentGui = 0;
    /// if this knob is within a group, make sure the group is created so far
    if (parentIsGroup) {
        parentGui = dynamic_cast<KnobGuiGroup*>( findKnobGuiOrCreate( parentKnob, true, ret->getFieldContainer() ).get() );
    }

    ///So far the knob could have no parent, in which case we force it to be in the default page.
    if (!parentKnob) {
        boost::shared_ptr<KnobPage> defPage = ensureDefaultPageKnobCreated();
        defPage->addKnob(knob);
        parentKnob = defPage;
    }

    ///if widgets for the KnobGui have already been created, don't do the following
    ///For group only create the gui if it is not  a tab.
    if ( isGroup  && isGroup->isTab() ) {
        boost::shared_ptr<KnobPage> parentIsPage = boost::dynamic_pointer_cast<KnobPage>(parentKnob);
        if (!parentKnob || parentIsPage) {
            PageMap::iterator page = _pages.end();
            if (!parentKnob) {
                page = getDefaultPage(knob);
            } else {
                page = getOrCreatePage(parentIsPage);
            }
            bool existed = true;
            if (!page->second.groupAsTab) {
                existed = false;
                page->second.groupAsTab = new TabGroup(_publicInterface);
            }
            page->second.groupAsTab->addTab( isGroup, QString::fromUtf8( isGroup->getLabel().c_str() ) );

            ///retrieve the form layout
            QGridLayout* layout;
            if (_useScrollAreasForTabs) {
                layout = dynamic_cast<QGridLayout*>( dynamic_cast<QScrollArea*>(page->second.tab)->widget()->layout() );
            } else {
                layout = dynamic_cast<QGridLayout*>( page->second.tab->layout() );
            }
            assert(layout);
            if (!existed) {
                layout->addWidget(page->second.groupAsTab, page->second.currentRow, 0, 1, 2);
            }

            page->second.groupAsTab->refreshTabSecretNess( isGroup.get() );
        } else {
            assert(parentIsGroup);
            assert(parentGui);
            TabGroup* groupAsTab = parentGui->getOrCreateTabWidget();

            groupAsTab->addTab( isGroup, QString::fromUtf8( isGroup->getLabel().c_str() ) );

            if ( parentIsGroup && parentIsGroup->isTab() ) {
                ///insert the tab in the layout of the parent
                ///Find the page in the parentParent group
                KnobPtr parentParent = parentKnob->getParentKnob();
                assert(parentParent);
                boost::shared_ptr<KnobGroup> parentParentIsGroup = boost::dynamic_pointer_cast<KnobGroup>(parentParent);
                boost::shared_ptr<KnobPage> parentParentIsPage = boost::dynamic_pointer_cast<KnobPage>(parentParent);
                assert(parentParentIsGroup || parentParentIsPage);
                TabGroup* parentTabGroup = 0;
                if (parentParentIsPage) {
                    PageMap::iterator page = getOrCreatePage(parentParentIsPage);
                    assert( page != _pages.end() );
                    parentTabGroup = page->second.groupAsTab;
                } else {
                    KnobsGuiMapping::iterator it = findKnobGui(parentParent);
                    assert( it != _knobs.end() );
                    KnobGuiGroup* parentParentGroupGui = dynamic_cast<KnobGuiGroup*>( it->second.get() );
                    assert(parentParentGroupGui);
                    parentTabGroup = parentParentGroupGui->getOrCreateTabWidget();
                }

                QGridLayout* layout = parentTabGroup->addTab( parentIsGroup, QString::fromUtf8( parentIsGroup->getLabel().c_str() ) );
                assert(layout);
                layout->addWidget(groupAsTab, 0, 0, 1, 2);
            } else {
                boost::shared_ptr<KnobPage> topLevelPage = knob->getTopLevelPage();
                PageMap::iterator page = getOrCreatePage(topLevelPage);
                assert( page != _pages.end() );
                ///retrieve the form layout
                QGridLayout* layout;
                if (_useScrollAreasForTabs) {
                    layout = dynamic_cast<QGridLayout*>(
                        dynamic_cast<QScrollArea*>(page->second.tab)->widget()->layout() );
                } else {
                    layout = dynamic_cast<QGridLayout*>( page->second.tab->layout() );
                }
                assert(layout);

                layout->addWidget(groupAsTab, page->second.currentRow, 0, 1, 2);
            }
            groupAsTab->refreshTabSecretNess( isGroup.get() );
        }
    } else if ( !ret->hasWidgetBeenCreated() ) {
        KnobPtr parentKnobTmp = parentKnob;
        while (parentKnobTmp) {
            KnobPtr parent = parentKnobTmp->getParentKnob();
            if (!parent) {
                break;
            } else {
                parentKnobTmp = parent;
            }
        }

        ////find in which page the knob should be
        boost::shared_ptr<KnobPage> isTopLevelParentAPage = boost::dynamic_pointer_cast<KnobPage>(parentKnobTmp);
        assert(isTopLevelParentAPage);

        PageMap::iterator page = getOrCreatePage(isTopLevelParentAPage);
        assert( page != _pages.end() );

        ///retrieve the form layout
        QGridLayout* layout;
        if (_useScrollAreasForTabs) {
            layout = dynamic_cast<QGridLayout*>(
                dynamic_cast<QScrollArea*>(page->second.tab)->widget()->layout() );
        } else {
            layout = dynamic_cast<QGridLayout*>( page->second.tab->layout() );
        }
        assert(layout);


        ///if the knob has specified that it didn't want to trigger a new line, decrement the current row
        /// index of the tab

        if (!makeNewLine) {
            --page->second.currentRow;
        }

        QWidget* fieldContainer = 0;
        QHBoxLayout* fieldLayout = 0;

        if (makeNewLine) {
            ///if new line is not turned off, create a new line
            fieldContainer = new QWidget(page->second.tab);
            fieldLayout = new QHBoxLayout(fieldContainer);
            fieldLayout->setContentsMargins( TO_DPIX(3), 0, 0, TO_DPIY(NATRON_SETTINGS_VERTICAL_SPACING_PIXELS) );
            fieldLayout->setSpacing( TO_DPIY(2) );
            fieldLayout->setAlignment(Qt::AlignLeft);
        } else {
            ///otherwise re-use the last row's widget and layout
            assert(lastRowWidget);
            fieldContainer = lastRowWidget;
            fieldLayout = dynamic_cast<QHBoxLayout*>( fieldContainer->layout() );
        }

        assert(fieldContainer);
        assert(fieldLayout);

        ///Create the label if needed
        KnobClickableLabel* label = 0;
        Label* warningLabel = 0;
        std::string descriptionLabel;
        KnobString* isStringKnob = dynamic_cast<KnobString*>( knob.get() );
        bool isLabelKnob = isStringKnob && isStringKnob->isLabel();
        if (isLabelKnob) {
            descriptionLabel = isStringKnob->getValue();
        } else {
            descriptionLabel = knob->getLabel();
        }
        const std::string& labelIconFilePath = knob->getIconLabel();
        QWidget *labelContainer = 0;
        QHBoxLayout *labelLayout = 0;
        const bool hasLabel = ret->isLabelVisible() || isLabelKnob;
        if (hasLabel) {
            if (makeNewLine) {
                labelContainer = new QWidget(page->second.tab);
                labelLayout = new QHBoxLayout(labelContainer);
                labelLayout->setContentsMargins( TO_DPIX(3), 0, 0, TO_DPIY(NATRON_SETTINGS_VERTICAL_SPACING_PIXELS) );
                labelLayout->setSpacing( TO_DPIY(2) );
            }

            label = new KnobClickableLabel(QString(), ret, page->second.tab);
            warningLabel = new Label(page->second.tab);
            warningLabel->setVisible(false);
            QFontMetrics fm(label->font(), 0);
            int pixSize = fm.height();
            QPixmap stdErrorPix;
            stdErrorPix = getStandardIcon(QMessageBox::Critical, pixSize, label);
            warningLabel->setPixmap(stdErrorPix);

            bool pixmapSet = false;
            if ( !labelIconFilePath.empty() ) {
                QPixmap pix;

                if (labelIconFilePath == "dialog-warning") {
                    pix = getStandardIcon(QMessageBox::Warning, pixSize, label);
                } else if (labelIconFilePath == "dialog-question") {
                    pix = getStandardIcon(QMessageBox::Question, pixSize, label);
                } else if (labelIconFilePath == "dialog-error") {
                    pix = stdErrorPix;
                } else if (labelIconFilePath == "dialog-information") {
                    pix = getStandardIcon(QMessageBox::Information, pixSize, label);
                } else {
                    pix.load( QString::fromUtf8( labelIconFilePath.c_str() ) );
                    if (pix.width() != pixSize) {
                        pix = pix.scaled(pixSize, pixSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
                    }
                }
                if ( !pix.isNull() ) {
                    pixmapSet = true;
                    label->setPixmap(pix);
                }
            }
            if (!pixmapSet) {
                QString labelStr( QString::fromUtf8( descriptionLabel.c_str() ) );
                /*labelStr += ":";*/
                if ( ret->isLabelBold() ) {
                    label->setBold(true);
                }
                label->setText_overload(labelStr );
            }
            QObject::connect( label, SIGNAL(clicked(bool)), ret.get(), SIGNAL(labelClicked(bool)) );


            if (makeNewLine) {
                labelLayout->addWidget(warningLabel);
                labelLayout->addWidget(label);
            }
        }

        /*
         * Find out in which layout the knob should be: either in the layout of the page or in the layout of
         * the nearest parent group tab in the hierarchy
         */
        boost::shared_ptr<KnobGroup> closestParentGroupTab;
        KnobPtr parentTmp = parentKnob;
        assert(parentKnobTmp);
        while (!closestParentGroupTab) {
            boost::shared_ptr<KnobGroup> parentGroup = boost::dynamic_pointer_cast<KnobGroup>(parentTmp);
            if ( parentGroup && parentGroup->isTab() ) {
                closestParentGroupTab = parentGroup;
            }
            parentTmp = parentTmp->getParentKnob();
            if (!parentTmp) {
                break;
            }
        }

        if (closestParentGroupTab) {
            /*
             * At this point we know that the parent group (which is a tab in the TabWidget) will have at least 1 knob
             * so ensure it is added to the TabWidget.
             * There are 2 possibilities, either the parent of the group tab is another group, in which case we have to
             * make sure the TabWidget is visible in the parent TabWidget of the group, otherwise we just add the TabWidget
             * to the on of the page.
             */

            KnobPtr parentParent = closestParentGroupTab->getParentKnob();
            KnobGroup* parentParentIsGroup = dynamic_cast<KnobGroup*>( parentParent.get() );
            boost::shared_ptr<KnobPage> parentParentIsPage = boost::dynamic_pointer_cast<KnobPage>(parentParent);

            assert(parentParentIsGroup || parentParentIsPage);
            if (parentParentIsGroup) {
                KnobGuiGroup* parentParentGroupGui = dynamic_cast<KnobGuiGroup*>( findKnobGuiOrCreate( parentParent, true,
                                                                                                       ret->getFieldContainer() ).get() );
                assert(parentParentGroupGui);
                if (parentParentGroupGui) {
                    TabGroup* groupAsTab = parentParentGroupGui->getOrCreateTabWidget();
                    assert(groupAsTab);
                    layout = groupAsTab->addTab( closestParentGroupTab, QString::fromUtf8( closestParentGroupTab->getLabel().c_str() ) );
                }
            } else if (parentParentIsPage) {
                PageMap::iterator page = getOrCreatePage(parentParentIsPage);
                assert( page != _pages.end() );
                assert(page->second.groupAsTab);
                layout = page->second.groupAsTab->addTab( closestParentGroupTab, QString::fromUtf8( closestParentGroupTab->getLabel().c_str() ) );
            }
            assert(layout);
        }

        ///fill the fieldLayout with the widgets
        ret->createGUI(layout, fieldContainer, labelContainer, label, warningLabel, fieldLayout, makeNewLine, knobsOnSameLine);


        ret->setEnabledSlot();

        ///Must add the row to the layout before calling setSecret()
        if (makeNewLine) {
            int rowIndex;
            if (closestParentGroupTab) {
                rowIndex = layout->rowCount();
            } else if ( parentGui && knob->isDynamicallyCreated() ) {
                const std::list<KnobGuiWPtr>& children = parentGui->getChildren();
                if ( children.empty() ) {
                    rowIndex = parentGui->getActualIndexInLayout();
                } else {
                    rowIndex = children.back().lock()->getActualIndexInLayout();
                }
                ++rowIndex;
            } else {
                rowIndex = page->second.currentRow;
            }


            const bool labelOnSameColumn = ret->isLabelOnSameColumn();


            if (!hasLabel) {
                layout->addWidget(fieldContainer, rowIndex, 0, 1, 2);
            } else {
                if (label) {
                    if (labelOnSameColumn) {
                        labelLayout->addWidget(fieldContainer);
                        layout->addWidget(labelContainer, rowIndex, 0, 1, 2);
                    } else {
                        layout->addWidget(labelContainer, rowIndex, 0, 1, 1, Qt::AlignRight);
                        layout->addWidget(fieldContainer, rowIndex, 1, 1, 1);
                    }
                }
            }


            //if (closestParentGroupTab) {
            ///See http://stackoverflow.com/questions/14033902/qt-qgridlayout-automatically-centers-moves-items-to-the-middle for
            ///a bug of QGridLayout: basically all items are centered, but we would like to add stretch in the bottom of the layout.
            ///To do this we add an empty widget with an expanding vertical size policy.
            /*QWidget* foundSpacer = 0;
               for (int i = 0; i < layout->rowCount(); ++i) {
                QLayoutItem* item = layout->itemAtPosition(i, 0);
                if (!item) {
                    continue;
                }
                QWidget* w = item->widget();
                if (!w) {
                    continue;
                }
                if (w->objectName() == QString::fromUtf8("emptyWidget")) {
                    foundSpacer = w;
                    break;
                }
               }
               if (foundSpacer) {
                layout->removeWidget(foundSpacer);
               } else {
                foundSpacer = new QWidget(layout->parentWidget());
                foundSpacer->setObjectName(QString::fromUtf8("emptyWidget"));
                foundSpacer->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);

               }

               ///And add our stretch
               layout->addWidget(foundSpacer,layout->rowCount(), 0, 1, 2);*/
            // }
        } // makeNewLine

        ret->setSecret();

        if ( knob->isNewLineActivated() && ret->shouldAddStretch() ) {
            fieldLayout->addStretch();
        }


        ///increment the row count
        ++page->second.currentRow;

        if (parentIsGroup && parentGui) {
            parentGui->addKnob(ret);
        }
    } //  if ( !ret->hasWidgetBeenCreated() && ( !isGroup || !isGroup->isTab() ) ) {
Ejemplo n.º 16
0
void
RestoreDefaultsCommand::redo()
{
    std::list<SequenceTime> times;
    KnobPtr first = _knobs.front().lock();
    AppInstance* app = 0;
    KnobHolder* holder = first->getHolder();
    EffectInstance* isEffect = dynamic_cast<EffectInstance*>(holder);

    if (holder) {
        app = holder->getApp();
        holder->beginChanges();
    }


    /*
       First reset all knobs values, this will not call instanceChanged action
     */
    for (std::list<KnobWPtr >::iterator it = _knobs.begin(); it != _knobs.end(); ++it) {
        KnobPtr itKnob = it->lock();
        if (!itKnob) {
            continue;
        }
        if ( itKnob->getHolder() && itKnob->getHolder()->getApp() ) {
            int dim = itKnob->getDimension();
            for (int i = 0; i < dim; ++i) {
                if ( (i == _targetDim) || (_targetDim == -1) ) {
                    boost::shared_ptr<Curve> c = itKnob->getCurve(ViewIdx(0), i);
                    if (c) {
                        KeyFrameSet kfs = c->getKeyFrames_mt_safe();
                        for (KeyFrameSet::iterator it = kfs.begin(); it != kfs.end(); ++it) {
                            times.push_back( std::floor(it->getTime() + 0.5) );
                        }
                    }
                }
            }
        }

        if ( itKnob->getHolder() ) {
            itKnob->getHolder()->beginChanges();
        }
        itKnob->blockValueChanges();

        for (int d = 0; d < itKnob->getDimension(); ++d) {
            itKnob->resetToDefaultValue(d);
        }

        itKnob->unblockValueChanges();

        if ( itKnob->getHolder() ) {
            itKnob->getHolder()->endChanges(true);
        }
    }

    /*
       Block value changes and call instanceChange on all knobs  afterwards to put back the plug-in
       in a correct state
     */
    double time = 0;
    if (app) {
        time = app->getTimeLine()->currentFrame();
    }
    for (std::list<KnobWPtr >::iterator it = _knobs.begin(); it != _knobs.end(); ++it) {
        KnobPtr itKnob = it->lock();
        if (!itKnob) {
            continue;
        }
        if ( itKnob->getHolder() ) {
            itKnob->getHolder()->onKnobValueChanged_public(itKnob.get(), eValueChangedReasonRestoreDefault, time, ViewIdx(0), true);
        }
    }

    if (app) {
        app->removeMultipleKeyframeIndicator(times, true);
    }


    if ( holder && holder->getApp() ) {
        holder->endChanges();
    }

    if (_isNodeReset && isEffect) {
        isEffect->purgeCaches();
    }


    if ( first->getHolder() ) {
        first->getHolder()->incrHashAndEvaluate(true, true);
        if ( first->getHolder()->getApp() ) {
            first->getHolder()->getApp()->redrawAllViewers();
        }
    }
    setText( tr("Restore default value(s)") );
} // RestoreDefaultsCommand::redo
Ejemplo n.º 17
0
void
MultipleKnobEditsUndoCommand::redo()
{
    assert( !knobs.empty() );
    KnobHolder* holder = knobs.begin()->first.lock()->getKnob()->getHolder();
    if (holder) {
        holder->beginChanges();
    }

    ///this is the first redo command, set values
    for (ParamsMap::iterator it = knobs.begin(); it != knobs.end(); ++it) {
        KnobGuiPtr knobUI = it->first.lock();
        if (!knobUI) {
            continue;
        }
        KnobPtr knob = knobUI->getKnob();
        if (!knob) {
            continue;
        }
        knob->beginChanges();
        Knob<int>* isInt = dynamic_cast<Knob<int>*>( knob.get() );
        Knob<bool>* isBool = dynamic_cast<Knob<bool>*>( knob.get() );
        Knob<double>* isDouble = dynamic_cast<Knob<double>*>( knob.get() );
        Knob<std::string>* isString = dynamic_cast<Knob<std::string>*>( knob.get() );

        for (std::list<ValueToSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
            KeyFrame k;

            if (!firstRedoCalled) {
                if (isInt) {
                    it2->oldValue.setValue( isInt->getValueAtTime(it2->time, it2->dimension) );
                } else if (isBool) {
                    it2->oldValue.setValue( isBool->getValueAtTime(it2->time, it2->dimension) );
                } else if (isDouble) {
                    it2->oldValue.setValue( isDouble->getValueAtTime(it2->time, it2->dimension) );
                } else if (isString) {
                    it2->oldValue.setValue( isString->getValueAtTime(it2->time, it2->dimension) );
                }
            }

            if (it2->setKeyFrame) {
                bool keyAdded = false;
                bool refreshGui =  it2->time == knob->getHolder()->getApp()->getTimeLine()->currentFrame();
                if (isInt) {
                    keyAdded = knobUI->setValueAtTime<int>(it2->dimension, it2->newValue.toInt(), it2->time, ViewIdx(0), &k, refreshGui, _reason);
                } else if (isBool) {
                    keyAdded = knobUI->setValueAtTime<bool>(it2->dimension, it2->newValue.toBool(), it2->time, ViewIdx(0), &k, refreshGui, _reason);
                } else if (isDouble) {
                    keyAdded = knobUI->setValueAtTime<double>(it2->dimension, it2->newValue.toDouble(), it2->time, ViewIdx(0), &k, refreshGui, _reason);
                } else if (isString) {
                    keyAdded = knobUI->setValueAtTime<std::string>(it2->dimension, it2->newValue.toString().toStdString(), it2->time,
                                                                   ViewIdx(0), &k, refreshGui, _reason);
                } else {
                    assert(false);
                }
                it2->setValueRetCode = keyAdded ? KnobHelper::eValueChangedReturnCodeKeyframeAdded : KnobHelper::eValueChangedReturnCodeKeyframeModified;
            } else {
                if (isInt) {
                    it2->setValueRetCode = knobUI->setValue<int>(it2->dimension, it2->newValue.toInt(), &k, true, _reason);
                } else if (isBool) {
                    it2->setValueRetCode = knobUI->setValue<bool>(it2->dimension, it2->newValue.toBool(), &k, true, _reason);
                } else if (isDouble) {
                    it2->setValueRetCode = knobUI->setValue<double>(it2->dimension, it2->newValue.toDouble(), &k, true, _reason);
                } else if (isString) {
                    it2->setValueRetCode = knobUI->setValue<std::string>(it2->dimension, it2->newValue.toString().toStdString(),
                                                                         &k, true, _reason);
                } else {
                    assert(false);
                }
                if (!firstRedoCalled && !it2->setKeyFrame) {
                    it2->time = knob->getCurrentTime();
                }
            }
        }
        knob->endChanges();
    }

    if (holder) {
        holder->endChanges();
    }

    firstRedoCalled = true;
} // redo
Ejemplo n.º 18
0
void
MultipleKnobEditsUndoCommand::undo()
{
    assert( !knobs.empty() );
    KnobHolder* holder = knobs.begin()->first.lock()->getKnob()->getHolder();
    if (holder) {
        holder->beginChanges();
    }

    for (ParamsMap::iterator it = knobs.begin(); it != knobs.end(); ++it) {
        KnobGuiPtr knobUI = it->first.lock();
        if (!knobUI) {
            continue;
        }
        KnobPtr knob = knobUI->getKnob();
        if (!knob) {
            continue;
        }
        knob->beginChanges();
        Knob<int>* isInt = dynamic_cast<Knob<int>*>( knob.get() );
        Knob<bool>* isBool = dynamic_cast<Knob<bool>*>( knob.get() );
        Knob<double>* isDouble = dynamic_cast<Knob<double>*>( knob.get() );
        Knob<std::string>* isString = dynamic_cast<Knob<std::string>*>( knob.get() );
        KeyFrame k;
        for (std::list<ValueToSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
            KnobHelper::ValueChangedReturnCodeEnum retCode = (KnobHelper::ValueChangedReturnCodeEnum)it2->setValueRetCode;

            if (retCode == KnobHelper::eValueChangedReturnCodeKeyframeAdded) {
                knobUI->removeKeyFrame( it2->time, it2->dimension, ViewIdx(0) );
            } else {
                if (it2->setKeyFrame) {
                    bool refreshGui =  it2->time == knob->getHolder()->getApp()->getTimeLine()->currentFrame();
                    if (isInt) {
                        knobUI->setValueAtTime<int>(it2->dimension, it2->oldValue.toInt(), it2->time, ViewIdx(0), &k, refreshGui, _reason);
                    } else if (isBool) {
                        knobUI->setValueAtTime<bool>(it2->dimension, it2->oldValue.toBool(), it2->time, ViewIdx(0), &k, refreshGui, _reason);
                    } else if (isDouble) {
                        knobUI->setValueAtTime<double>(it2->dimension, it2->oldValue.toDouble(), it2->time, ViewIdx(0), &k, refreshGui, _reason);
                    } else if (isString) {
                        knobUI->setValueAtTime<std::string>(it2->dimension, it2->oldValue.toString().toStdString(), it2->time, ViewIdx(0), &k, refreshGui, _reason);
                    } else {
                        assert(false);
                    }
                } else {
                    if (isInt) {
                        knobUI->setValue<int>(it2->dimension, it2->oldValue.toInt(), &k, true, _reason);
                    } else if (isBool) {
                        knobUI->setValue<bool>(it2->dimension, it2->oldValue.toBool(), &k, true, _reason);
                    } else if (isDouble) {
                        knobUI->setValue<double>(it2->dimension, it2->oldValue.toDouble(), &k, true, _reason);
                    } else if (isString) {
                        knobUI->setValue<std::string>(it2->dimension, it2->oldValue.toString().toStdString(),
                                                      &k, true, _reason);
                    } else {
                        assert(false);
                    }
                }
            }
        }
        knob->endChanges();
    }


    if (holder) {
        holder->endChanges();
    }
} // MultipleKnobEditsUndoCommand::undo
Ejemplo n.º 19
0
void
PasteUndoCommand::copyFrom(const KnobPtr& serializedKnob,
                           bool isRedo)
{
    KnobPtr internalKnob = _imp->knob.lock()->getKnob();

    switch (_imp->type) {
    case eKnobClipBoardTypeCopyAnim: {
        internalKnob->beginChanges();
        for (int i = 0; i < internalKnob->getDimension(); ++i) {
            if ( ( _imp->targetDimension == -1) || ( i == _imp->targetDimension) ) {
                boost::shared_ptr<Curve> fromCurve;
                if ( ( i == _imp->targetDimension) && ( _imp->fromDimension != -1) ) {
                    fromCurve = serializedKnob->getCurve(ViewIdx(0), _imp->fromDimension);
                } else {
                    fromCurve = serializedKnob->getCurve(ViewIdx(0), i);
                }
                if (!fromCurve) {
                    continue;
                }
                internalKnob->cloneCurve(ViewIdx(0), i, *fromCurve);
            }
        }
        internalKnob->endChanges();
        break;
    }
    case eKnobClipBoardTypeCopyValue: {
        Knob<int>* isInt = dynamic_cast<Knob<int>*>( internalKnob.get() );
        Knob<bool>* isBool = dynamic_cast<Knob<bool>*>( internalKnob.get() );
        Knob<double>* isDouble = dynamic_cast<Knob<double>*>( internalKnob.get() );
        Knob<std::string>* isString = dynamic_cast<Knob<std::string>*>( internalKnob.get() );

        Knob<int>* isFromInt = dynamic_cast<Knob<int>*>( serializedKnob.get() );
        Knob<bool>* isFromBool = dynamic_cast<Knob<bool>*>( serializedKnob.get() );
        Knob<double>* isFromDouble = dynamic_cast<Knob<double>*>( serializedKnob.get() );
        Knob<std::string>* isFromString = dynamic_cast<Knob<std::string>*>( serializedKnob.get() );

        internalKnob->beginChanges();
        for (int i = 0; i < internalKnob->getDimension(); ++i) {
            if ( ( _imp->targetDimension == -1) || ( i == _imp->targetDimension) ) {
                if (isInt && isFromInt) {
                    int f = (i == _imp->targetDimension && _imp->fromDimension != -1) ? isFromInt->getValue(_imp->fromDimension) : isFromInt->getValue(i);
                    isInt->setValue(f, ViewIdx(0), i, eValueChangedReasonNatronInternalEdited, 0);
                } else if (isBool && isFromBool) {
                    bool f = (i == _imp->targetDimension && _imp->fromDimension != -1) ? isFromBool->getValue(_imp->fromDimension) : isFromBool->getValue(i);
                    isBool->setValue(f, ViewIdx(0), i, eValueChangedReasonNatronInternalEdited, 0);
                } else if (isDouble && isFromDouble) {
                    double f = (i == _imp->targetDimension && _imp->fromDimension != -1) ? isFromDouble->getValue(_imp->fromDimension) : isFromDouble->getValue(i);
                    isDouble->setValue(f, ViewIdx(0), i, eValueChangedReasonNatronInternalEdited, 0);
                } else if (isString && isFromString) {
                    std::string f = (i == _imp->targetDimension && _imp->fromDimension != -1) ? isFromString->getValue(_imp->fromDimension) : isFromString->getValue(i);
                    isString->setValue(f, ViewIdx(0), i, eValueChangedReasonNatronInternalEdited, 0);
                }
            }
        }
        internalKnob->endChanges();
        break;
    }
    case eKnobClipBoardTypeCopyLink: {
        //bool useExpression = !KnobI::areTypesCompatibleForSlave(internalKnob.get(), serializedKnob.get());

        internalKnob->beginChanges();
        for (int i = 0; i < internalKnob->getDimension(); ++i) {
            if ( ( _imp->targetDimension == -1) || ( i == _imp->targetDimension) ) {
                if (isRedo) {
                    if (_imp->fromDimension != -1) {
                        internalKnob->slaveTo(i, serializedKnob, _imp->fromDimension);
                    } else {
                        internalKnob->slaveTo(i, serializedKnob, i);
                    }
                } else {
                    internalKnob->unSlave(i, false);
                }
            }
        }
        internalKnob->endChanges();
        break;
    }
    } // switch
} // redo
Ejemplo n.º 20
0
QString
KnobGui::toolTip() const
{
    KnobPtr knob = getKnob();
    KnobChoice* isChoice = dynamic_cast<KnobChoice*>( knob.get() );
    bool isMarkdown = knob.get()->isHintInMarkdown();
    QString tt;
    QString realTt;

    if (isMarkdown) {
        tt = QString::fromUtf8( knob.get()->getName().c_str() );
        tt.append( QString::fromUtf8("\n==========\n\n") );
    } else {
        tt = getScriptNameHtml();
    }

    if (!isChoice) {
        realTt.append( QString::fromUtf8( knob->getHintToolTip().c_str() ) );
    } else {
        realTt.append( QString::fromUtf8( isChoice->getHintToolTipFull().c_str() ) );
    }

    std::vector<std::string> expressions;
    bool exprAllSame = true;
    for (int i = 0; i < knob->getDimension(); ++i) {
        expressions.push_back( knob->getExpression(i) );
        if ( (i > 0) && (expressions[i] != expressions[0]) ) {
            exprAllSame = false;
        }
    }

    QString exprTt;
    if (exprAllSame) {
        if ( !expressions[0].empty() ) {
            if (isMarkdown) {
                exprTt = QString::fromUtf8("ret = **%1**\n\n").arg( QString::fromUtf8( expressions[0].c_str() ) );
            } else {
                exprTt = QString::fromUtf8("ret = <b>%1</b><br />").arg( QString::fromUtf8( expressions[0].c_str() ) );
            }
        }
    } else {
        for (int i = 0; i < knob->getDimension(); ++i) {
            std::string dimName = knob->getDimensionName(i);
            QString toAppend;
            if (isMarkdown) {
                toAppend = QString::fromUtf8("%1 = **%2**\n\n").arg( QString::fromUtf8( dimName.c_str() ) ).arg( QString::fromUtf8( expressions[i].c_str() ) );
            } else {
                toAppend = QString::fromUtf8("%1 = <b>%2</b><br />").arg( QString::fromUtf8( dimName.c_str() ) ).arg( QString::fromUtf8( expressions[i].c_str() ) );
            }
            exprTt.append(toAppend);
        }
    }

    if ( !exprTt.isEmpty() ) {
        tt.append(exprTt);
        if (!isMarkdown) {
            tt += QLatin1String("<br/>");
        }
    }

    if ( !realTt.isEmpty() ) {
        if (!isMarkdown) {
            realTt = GuiUtils::convertFromPlainText(realTt.trimmed(), Qt::WhiteSpaceNormal);
        }
        tt.append(realTt);
    }

    if (isMarkdown) {
        tt = Markdown::convert2html(tt);
        // Shrink H1/H2 (Can't do it in qt stylesheet)
        tt.replace( QString::fromUtf8("<h1>"), QString::fromUtf8("<h1 style=\"font-size:large;\">") );
        tt.replace( QString::fromUtf8("<h2>"), QString::fromUtf8("<h2 style=\"font-size:large;\">") );
    }

    return tt;
} // KnobGui::toolTip
Ejemplo n.º 21
0
void
OutputEffectInstance::renderFullSequence(bool isBlocking,
                                         bool enableRenderStats,
                                         BlockingBackgroundRender* renderController,
                                         int first,
                                         int last,
                                         int frameStep)
{
    int viewsCount = getApp()->getProject()->getProjectViewsCount();
    const ViewIdx mainView(0);
    std::vector<ViewIdx> viewsToRender(viewsCount);

    for (int i = 0; i < viewsCount; ++i) {
        viewsToRender[i] = ViewIdx(i);
    }

    ///The effect is sequential (e.g: WriteFFMPEG), and thus cannot render multiple views, we have to choose one
    ///We pick the user defined main view in the project settings
    SequentialPreferenceEnum sequentiallity = getSequentialPreference();
    bool canOnlyHandleOneView = sequentiallity == eSequentialPreferenceOnlySequential || sequentiallity == eSequentialPreferencePreferSequential;

    if (canOnlyHandleOneView) {
        viewsToRender.clear();
        viewsToRender.push_back(mainView);
    }

    if ( isViewAware() ) {
        //If the Writer is view aware, check if it wants to render all views at once or not
        KnobPtr outputFileNameKnob = getKnobByName(kOfxImageEffectFileParamName);
        if (outputFileNameKnob) {
            KnobOutputFile* outputFileName = dynamic_cast<KnobOutputFile*>( outputFileNameKnob.get() );
            assert(outputFileName);
            if (outputFileName) {
                std::string pattern = outputFileName->getValue();
                std::size_t foundViewPattern = pattern.find_first_of("%v");
                if (foundViewPattern == std::string::npos) {
                    foundViewPattern = pattern.find_first_of("%V");
                }
                if (foundViewPattern == std::string::npos) {
                    ///No view pattern
                    ///all views will be overwritten to the same file
                    ///If this is WriteOIIO, check the parameter "viewsSelector" to determine if the user wants to encode all
                    ///views to a single file or not
                    KnobPtr viewsKnob = getKnobByName(kWriteOIIOParamViewsSelector);
                    bool hasViewChoice = false;
                    if ( viewsKnob && !viewsKnob->getIsSecret() ) {
                        KnobChoice* viewsChoice = dynamic_cast<KnobChoice*>( viewsKnob.get() );
                        if (viewsChoice) {
                            hasViewChoice = true;
                            int viewChoice_i = viewsChoice->getValue();
                            if (viewChoice_i == 0) { // the "All" choice
                                viewsToRender.clear();
                                // note: if the plugin renders all views to a single file, then rendering view 0 will do the job.
                                viewsToRender.push_back( ViewIdx(0) );
                            } else {
                                //The user has specified a view
                                viewsToRender.clear();
                                assert(viewChoice_i >= 1);
                                viewsToRender.push_back( ViewIdx(viewChoice_i - 1) );
                            }
                        }
                    }
                    if (!hasViewChoice) {
                        if (viewsToRender.size() > 1) {
                            std::string mainViewName;
                            const std::vector<std::string>& viewNames = getApp()->getProject()->getProjectViewNames();
                            if ( mainView < (int)viewNames.size() ) {
                                mainViewName = viewNames[mainView];
                            }
                            QString message = tr("%1 does not support multi-view, only the view %2 will be rendered.")
                                              .arg( QString::fromUtf8( getNode()->getLabel_mt_safe().c_str() ) )
                                              .arg( QString::fromUtf8( mainViewName.c_str() ) );
                            if (!renderController) {
                                message.append( QChar::fromLatin1('\n') );
                                message.append( QString::fromUtf8("You can use the %v or %V indicator in the filename to render to separate files.\n"
                                                                  "Would you like to continue?") );
                                StandardButtonEnum rep = Dialogs::questionDialog(tr("Multi-view support").toStdString(), message.toStdString(), false, StandardButtons(eStandardButtonOk | eStandardButtonCancel), eStandardButtonOk);
                                if (rep != eStandardButtonOk) {
                                    return;
                                }
                            } else {
                                Dialogs::warningDialog( tr("Multi-view support").toStdString(), message.toStdString() );
                            }
                        }
                        //Render the main-view only...
                        viewsToRender.clear();
                        viewsToRender.push_back(mainView);
                    }
                } else {
                    ///The user wants to write each view into a separate file
                    ///This will disregard the content of kWriteOIIOParamViewsSelector and the Writer
                    ///should write one view per-file.
                }
            }
        }
    } else { // !isViewAware
        if (viewsToRender.size() > 1) {
            std::string mainViewName;
            const std::vector<std::string>& viewNames = getApp()->getProject()->getProjectViewNames();
            if ( mainView < (int)viewNames.size() ) {
                mainViewName = viewNames[mainView];
            }
            QString message = tr("%1 does not support multi-view, only the view %2 will be rendered.")
                              .arg( QString::fromUtf8( getNode()->getLabel_mt_safe().c_str() ) )
                              .arg( QString::fromUtf8( mainViewName.c_str() ) );
            if (!renderController) {
                message.append( QChar::fromLatin1('\n') );
                message.append( QString::fromUtf8("You can use the %v or %V indicator in the filename to render to separate files.\n"
                                                  "Would you like to continue?") );
                StandardButtonEnum rep = Dialogs::questionDialog(tr("Multi-view support").toStdString(), message.toStdString(), false, StandardButtons(eStandardButtonOk | eStandardButtonCancel), eStandardButtonOk);
                if (rep != eStandardButtonOk) {
                    return;
                }
            } else {
                Dialogs::warningDialog( tr("Multi-view support").toStdString(), message.toStdString() );
            }
        }
    }


    RenderSequenceArgs args;
    {
        QMutexLocker k(&_outputEffectDataLock);
        args.firstFrame = first;
        args.lastFrame = last;
        args.frameStep = frameStep;
        args.renderController = renderController;
        args.useStats = enableRenderStats;
        args.blocking = isBlocking;
        args.viewsToRender = viewsToRender;
        _renderSequenceRequests.push_back(args);
        if (_renderSequenceRequests.size() > 1) {
            //The node is already rendering a sequence, queue it and dequeue it in notifyRenderFinished()
            return;
        }
    }
    launchRenderSequence(args);
} // OutputEffectInstance::renderFullSequence
Ejemplo n.º 22
0
void
OutputEffectInstance::reportStats(int time,
                                  ViewIdx view,
                                  double wallTime,
                                  const std::map<NodePtr, NodeRenderStats > & stats)
{
    std::string filename;
    KnobPtr fileKnob = getKnobByName(kOfxImageEffectFileParamName);

    if (fileKnob) {
        KnobOutputFile* strKnob = dynamic_cast<KnobOutputFile*>( fileKnob.get() );
        if  (strKnob) {
            QString qfileName = QString::fromUtf8( SequenceParsing::generateFileNameFromPattern(strKnob->getValue( 0, ViewIdx(view) ), getApp()->getProject()->getProjectViewNames(), time, view).c_str() );
            QtCompat::removeFileExtension(qfileName);
            qfileName.append( QString::fromUtf8("-stats.txt") );
            filename = qfileName.toStdString();
        }
    }

    //If there's no filename knob, do not write anything
    if ( filename.empty() ) {
        std::cout << tr("Cannot write render statistics file: "
                        "%1 does not seem to have a parameter named \"filename\" "
                        "to determine the location where to write the stats file.")
            .arg( QString::fromUtf8( getScriptName_mt_safe().c_str() ) ).toStdString();

        return;
    }


    FStreamsSupport::ofstream ofile;
    FStreamsSupport::open(&ofile, filename);
    if (!ofile) {
        std::cout << tr("Failure to write render statistics file.").toStdString() << std::endl;

        return;
    }

    ofile << "Time spent to render frame (wall clock time): " << Timer::printAsTime(wallTime, false).toStdString() << std::endl;
    for (std::map<NodePtr, NodeRenderStats >::const_iterator it = stats.begin(); it != stats.end(); ++it) {
        ofile << "------------------------------- " << it->first->getScriptName_mt_safe() << "------------------------------- " << std::endl;
        ofile << "Time spent rendering: " << Timer::printAsTime(it->second.getTotalTimeSpentRendering(), false).toStdString() << std::endl;
        const RectD & rod = it->second.getRoD();
        ofile << "Region of definition: x1 = " << rod.x1  << " y1 = " << rod.y1 << " x2 = " << rod.x2 << " y2 = " << rod.y2 << std::endl;
        ofile << "Is Identity to Effect? ";
        NodePtr identity = it->second.getInputImageIdentity();
        if (identity) {
            ofile << "Yes, to " << identity->getScriptName_mt_safe() << std::endl;
        } else {
            ofile << "No" << std::endl;
        }
        ofile << "Has render-scale support? ";
        if ( it->second.isRenderScaleSupportEnabled() ) {
            ofile << "Yes";
        } else {
            ofile << "No";
        }
        ofile << std::endl;
        ofile << "Has tiles support? ";
        if ( it->second.isTilesSupportEnabled() ) {
            ofile << "Yes";
        } else {
            ofile << "No";
        }
        ofile << std::endl;
        ofile << "Channels processed: ";

        std::bitset<4> processChannels = it->second.getChannelsRendered();
        if (processChannels[0]) {
            ofile << "red ";
        }
        if (processChannels[1]) {
            ofile << "green ";
        }
        if (processChannels[2]) {
            ofile << "blue ";
        }
        if (processChannels[3]) {
            ofile << "alpha";
        }
        ofile << std::endl;

        ofile << "Output alpha premultiplication: ";
        switch ( it->second.getOutputPremult() ) {
        case eImagePremultiplicationOpaque:
            ofile << "opaque";
            break;
        case eImagePremultiplicationPremultiplied:
            ofile << "premultiplied";
            break;
        case eImagePremultiplicationUnPremultiplied:
            ofile << "unpremultiplied";
            break;
        }
        ofile << std::endl;

        ofile << "Mipmap level(s) rendered: ";
        for (std::set<unsigned int>::const_iterator it2 = it->second.getMipMapLevelsRendered().begin(); it2 != it->second.getMipMapLevelsRendered().end(); ++it2) {
            ofile << *it2 << ' ';
        }
        ofile << std::endl;
        int nbCacheMiss, nbCacheHit, nbCacheHitButDownscaled;
        it->second.getCacheAccessInfos(&nbCacheMiss, &nbCacheHit, &nbCacheHitButDownscaled);
        ofile << "Nb cache hit: " << nbCacheMiss << std::endl;
        ofile << "Nb cache miss: " << nbCacheMiss << std::endl;
        ofile << "Nb cache hit requiring mipmap downscaling: " << nbCacheHitButDownscaled << std::endl;

        const std::set<std::string> & planes = it->second.getPlanesRendered();
        ofile << "Plane(s) rendered: ";
        for (std::set<std::string>::const_iterator it2 = planes.begin(); it2 != planes.end(); ++it2) {
            ofile << *it2 << ' ';
        }
        ofile << std::endl;

        std::list<std::pair<RectI, NodePtr > > identityRectangles = it->second.getIdentityRectangles();
        const std::list<RectI> & renderedRectangles = it->second.getRenderedRectangles();

        ofile << "Identity rectangles: " << identityRectangles.size() << std::endl;
        for (std::list<std::pair<RectI, NodePtr > > ::iterator it2 = identityRectangles.begin(); it2 != identityRectangles.end(); ++it2) {
            ofile << "Origin: " << it2->second->getScriptName_mt_safe() << ", rect: x1 = " << it2->first.x1
                  << " y1 = " << it2->first.y1 << " x2 = " << it2->first.x2 << " y2 = " << it2->first.y2 << std::endl;
        }

        ofile << "Rectangles rendered: " << renderedRectangles.size() << std::endl;
        for (std::list<RectI>::const_iterator it2 = renderedRectangles.begin(); it2 != renderedRectangles.end(); ++it2) {
            ofile << "x1 = " << it2->x1 << " y1 = " << it2->y1 << " x2 = " << it2->x2 << " y2 = " << it2->y2 << std::endl;
        }
    }
} // OutputEffectInstance::reportStats