void ViewerNodePrivate::refreshInputChoiceMenu(int internalIndex, int groupInputIndex) { KnobChoicePtr inputChoiceKnob = internalIndex == 0 ? aInputNodeChoiceKnob.lock() : bInputNodeChoiceKnob.lock(); assert(groupInputIndex >= 0 && groupInputIndex < _publicInterface->getMaxInputCount()); std::string groupInputID; { std::stringstream ss; ss << groupInputIndex; groupInputID = ss.str(); } std::vector<ChoiceOption> entries = inputChoiceKnob->getEntries(); for (std::size_t i = 0; i < entries.size(); ++i) { if (entries[i].id == groupInputID) { inputChoiceKnob->setValue(i); return; } } // Input is no longer connected fallback on first input in the list if any, otherwise on None ("-") inputChoiceKnob->setValue(entries.size() > 1 ? 1 : 0, ViewSetSpec::all(), DimIdx(0), eValueChangedReasonPluginEdited); }
void KnobGuiChoice::onEntryAppended() { KnobChoicePtr knob = _knob.lock(); if (!knob) { return; } std::vector<ChoiceOption> options = knob->getEntries(); for (int i = _comboBox->count(); i < (int)options.size(); ++i) { if ( knob->getNewOptionCallback()) { _comboBox->insertItem(_comboBox->count() - 1, QString::fromUtf8(options[i].label.c_str()), QIcon(), QKeySequence(), QString::fromUtf8(options[i].tooltip.c_str())); } else { _comboBox->addItem(QString::fromUtf8(options[i].label.c_str()), QIcon(), QKeySequence(), QString::fromUtf8(options[i].tooltip.c_str())); } } updateGUI(); }
void ViewerNodePrivate::setAlphaChannelFromLayerIfRGBA() { ImagePlaneDesc selectedLayer, selectedAlphaLayer, selectedDisplayLayer; int alphaChannelIndex; ViewerInstancePtr internalViewer = internalViewerProcessNode[0].lock()->isEffectViewerInstance(); internalViewer->getChannelOptions(_publicInterface->getTimelineCurrentTime(), &selectedLayer, &selectedAlphaLayer, &alphaChannelIndex, &selectedDisplayLayer); // Set the alpha channel to the selected layer's alpha channel if it is not pointing to anything if (selectedLayer.getNumComponents() == 4 && selectedAlphaLayer.getNumComponents() == 0) { ChoiceOption newOption = selectedLayer.getChannelOption(3); KnobChoicePtr alphaChoice = alphaChannelKnob.lock(); std::vector<ChoiceOption> options = alphaChoice->getEntries(); for (std::size_t i = 0; i < options.size(); ++i) { if (options[i].id == newOption.id) { alphaChoice->setValue(i); break; } } } }
NATRON_NAMESPACE_ENTER // those parameters should be ignored (they are always secret in Natron) #define kOCIOParamInputSpace "ocioInputSpace" #define kOCIOParamOutputSpace "ocioOutputSpace" // those parameters should not have their options in the help file if generating markdown, // because the options are dinamlically constructed at run-time from the OCIO config. #define kOCIOParamInputSpaceChoice "ocioInputSpaceIndex" #define kOCIOParamOutputSpaceChoice "ocioOutputSpaceIndex" #define kOCIODisplayPluginIdentifier "fr.inria.openfx.OCIODisplay" #define kOCIODisplayParamDisplay "display" #define kOCIODisplayParamDisplayChoice "displayIndex" #define kOCIODisplayParamView "view" #define kOCIODisplayParamViewChoice "viewIndex" // not yet implemented (see OCIOCDLTransform.cpp) //#define kOCIOCDLTransformPluginIdentifier "fr.inria.openfx.OCIOCDLTransform" //#define kOCIOCDLTransformParamCCCID "cccId" //#define kOCIOCDLTransformParamCCCIDChoice "cccIdIndex" #define kOCIOFileTransformPluginIdentifier "fr.inria.openfx.OCIOFileTransform" #define kOCIOFileTransformParamCCCID "cccId" #define kOCIOFileTransformParamCCCIDChoice "cccIdIndex" // genHTML: true for live HTML output for the internal web-server, false for markdown output QString Node::makeDocumentation(bool genHTML) const { QString ret; QString markdown; QTextStream ts(&ret); QTextStream ms(&markdown); QString pluginID, pluginLabel, pluginDescription, pluginIcon; int majorVersion = getMajorVersion(); int minorVersion = getMinorVersion(); std::vector<std::string> pluginGroup; bool pluginDescriptionIsMarkdown = false; QVector<QStringList> inputs; QVector<QStringList> items; { PluginPtr plugin = getPlugin(); assert(plugin); pluginID = QString::fromUtf8(plugin->getPluginID().c_str()); pluginLabel = QString::fromUtf8( Plugin::makeLabelWithoutSuffix( plugin->getPluginLabel() ).c_str()); pluginDescription = QString::fromUtf8( plugin->getPropertyUnsafe<std::string>(kNatronPluginPropDescription).c_str() ); pluginIcon = QString::fromUtf8(plugin->getPropertyUnsafe<std::string>(kNatronPluginPropIconFilePath).c_str()); pluginGroup = plugin->getPropertyNUnsafe<std::string>(kNatronPluginPropGrouping); pluginDescriptionIsMarkdown = plugin->getPropertyUnsafe<bool>(kNatronPluginPropDescriptionIsMarkdown); for (int i = 0; i < _imp->effect->getNInputs(); ++i) { QStringList input; input << convertFromPlainTextToMarkdown( QString::fromStdString( getInputLabel(i) ), genHTML, true ); input << convertFromPlainTextToMarkdown( QString::fromStdString( getInputHint(i) ), genHTML, true ); input << ( isInputOptional(i) ? tr("Yes") : tr("No") ); inputs.push_back(input); // Don't show more than doc for 4 inputs otherwise it will just clutter the page if (i == 3) { break; } } } // check for plugin icon QString pluginIconUrl; if ( !pluginIcon.isEmpty() ) { QFile iconFile(pluginIcon); if ( iconFile.exists() ) { if (genHTML) { pluginIconUrl.append( QString::fromUtf8("/LOCAL_FILE/") ); pluginIconUrl.append(pluginIcon); pluginIconUrl.replace( QString::fromUtf8("\\"), QString::fromUtf8("/") ); } else { pluginIconUrl.append(pluginID); pluginIconUrl.append(QString::fromUtf8(".png")); } } } // check for extra markdown file QString extraMarkdown; QString pluginMD = pluginIcon; pluginMD.replace( QString::fromUtf8(".png"), QString::fromUtf8(".md") ); QFile pluginMarkdownFile(pluginMD); if ( pluginMarkdownFile.exists() ) { if ( pluginMarkdownFile.open(QIODevice::ReadOnly | QIODevice::Text) ) { extraMarkdown = QString::fromUtf8( pluginMarkdownFile.readAll() ); pluginMarkdownFile.close(); } } // generate knobs info KnobsVec knobs = getEffectInstance()->getKnobs_mt_safe(); for (KnobsVec::const_iterator it = knobs.begin(); it != knobs.end(); ++it) { #pragma message WARN("TODO: restore getDefaultIsSecret from RB-2.2") //if ( (*it)->getDefaultIsSecret() ) { if ( (*it)->getIsSecret() ) { continue; } if ((*it)->getKnobDeclarationType() != KnobI::eKnobDeclarationTypePlugin) { continue; } // do not escape characters in the scriptName, since it will be put between backquotes QString knobScriptName = /*NATRON_NAMESPACE::convertFromPlainTextToMarkdown(*/ QString::fromUtf8( (*it)->getName().c_str() )/*, genHTML, true)*/; QString knobLabel = NATRON_NAMESPACE::convertFromPlainTextToMarkdown( QString::fromUtf8( (*it)->getLabel().c_str() ), genHTML, true); QString knobHint = NATRON_NAMESPACE::convertFromPlainTextToMarkdown( QString::fromUtf8( (*it)->getHintToolTip().c_str() ), genHTML, true); // totally ignore the documentation for these parameters (which are always secret in Natron) if ( knobScriptName.startsWith( QString::fromUtf8("NatronOfxParam") ) || knobScriptName == QString::fromUtf8("exportAsPyPlug") || knobScriptName == QString::fromUtf8(kOCIOParamInputSpace) || knobScriptName == QString::fromUtf8(kOCIOParamOutputSpace) || ( ( pluginID == QString::fromUtf8(kOCIODisplayPluginIdentifier) ) && ( knobScriptName == QString::fromUtf8(kOCIODisplayParamDisplay) ) ) || ( ( pluginID == QString::fromUtf8(kOCIODisplayPluginIdentifier) ) && ( knobScriptName == QString::fromUtf8(kOCIODisplayParamView) ) ) || //( ( pluginID == QString::fromUtf8(kOCIOCDLTransformPluginIdentifier) ) && // ( knobScriptName == QString::fromUtf8(kOCIOCDLTransformParamCCCID) ) ) || ( ( pluginID == QString::fromUtf8(kOCIOFileTransformPluginIdentifier) ) && ( knobScriptName == QString::fromUtf8(kOCIOFileTransformParamCCCID) ) ) || false) { continue; } QString defValuesStr, knobType; std::vector<std::pair<QString, QString> > dimsDefaultValueStr; KnobIntPtr isInt = toKnobInt(*it); KnobChoicePtr isChoice = toKnobChoice(*it); KnobBoolPtr isBool = toKnobBool(*it); KnobDoublePtr isDbl = toKnobDouble(*it); KnobStringPtr isString = toKnobString(*it); bool isLabel = isString && isString->isLabel(); KnobSeparatorPtr isSep = toKnobSeparator(*it); KnobButtonPtr isBtn = toKnobButton(*it); KnobParametricPtr isParametric = toKnobParametric(*it); KnobGroupPtr isGroup = toKnobGroup(*it); KnobPagePtr isPage = toKnobPage(*it); KnobColorPtr isColor = toKnobColor(*it); if (isInt) { knobType = tr("Integer"); } else if (isChoice) { knobType = tr("Choice"); } else if (isBool) { knobType = tr("Boolean"); } else if (isDbl) { knobType = tr("Double"); } else if (isString) { if (isLabel) { knobType = tr("Label"); } else { knobType = tr("String"); } } else if (isSep) { knobType = tr("Separator"); } else if (isBtn) { knobType = tr("Button"); } else if (isParametric) { knobType = tr("Parametric"); } else if (isGroup) { knobType = tr("Group"); } else if (isPage) { knobType = tr("Page"); } else if (isColor) { knobType = tr("Color"); } else { knobType = tr("N/A"); } if (!isGroup && !isPage) { for (int i = 0; i < (*it)->getNDimensions(); ++i) { QString valueStr; if (!isBtn && !isSep && !isParametric) { // If this is a ChoiceParam and we are not generating live HTML doc, // only add the list of entries and their halp if this node should not be // ignored (eg. OCIO colorspace knobs). if ( isChoice && (genHTML || !( knobScriptName == QString::fromUtf8(kOCIOParamInputSpaceChoice) || knobScriptName == QString::fromUtf8(kOCIOParamOutputSpaceChoice) || ( ( pluginID == QString::fromUtf8(kOCIODisplayPluginIdentifier) ) && ( knobScriptName == QString::fromUtf8(kOCIODisplayParamDisplayChoice) ) ) || ( ( pluginID == QString::fromUtf8(kOCIODisplayPluginIdentifier) ) && ( knobScriptName == QString::fromUtf8(kOCIODisplayParamViewChoice) ) ) || //( ( pluginID == QString::fromUtf8(kOCIOCDLTransformPluginIdentifier) ) && // ( knobScriptName == QString::fromUtf8(kOCIOCDLTransformParamCCCIDChoice) ) ) || ( ( pluginID == QString::fromUtf8(kOCIOFileTransformPluginIdentifier) ) && ( knobScriptName == QString::fromUtf8(kOCIOFileTransformParamCCCIDChoice) ) ) || ( ( pluginID == QString::fromUtf8("net.fxarena.openfx.Text") ) && ( knobScriptName == QString::fromUtf8("name") ) ) || // font family from Text plugin ( ( pluginID == QString::fromUtf8("net.fxarena.openfx.Polaroid") ) && ( knobScriptName == QString::fromUtf8("font") ) ) || // font family from Polaroid plugin ( ( pluginID == QString::fromUtf8(PLUGINID_NATRON_PRECOMP) ) && ( knobScriptName == QString::fromUtf8("writeNode") ) ) || ( ( pluginID == QString::fromUtf8(PLUGINID_NATRON_ONEVIEW) ) && ( knobScriptName == QString::fromUtf8("view") ) ) ) ) ) { // see also KnobChoice::getHintToolTipFull() int index = isChoice->getDefaultValue(DimIdx(i)); std::vector<ChoiceOption> entries = isChoice->getEntries(); if ( (index >= 0) && ( index < (int)entries.size() ) ) { valueStr = QString::fromUtf8( entries[index].id.c_str() ); } bool first = true; for (size_t i = 0; i < entries.size(); i++) { QString entryHelp = QString::fromUtf8( entries[i].tooltip.c_str() ); QString entry; if (entries[i].id != entries[i].label) { entry = QString::fromUtf8( "%1 (%2)" ).arg(QString::fromUtf8( entries[i].label.c_str() )).arg(QString::fromUtf8( entries[i].id.c_str() )); } else { entry = QString::fromUtf8( entries[i].label.c_str() ); } if (!entry.isEmpty()) { if (first) { // empty line before the option descriptions if (genHTML) { if ( !knobHint.isEmpty() ) { knobHint.append( QString::fromUtf8("<br />") ); } knobHint.append( tr("Possible values:") + QString::fromUtf8("<br />") ); } else { // we do a hack for multiline elements, because the markdown->rst conversion by pandoc doesn't use the line block syntax. // what we do here is put a supplementary dot at the beginning of each line, which is then converted to a pipe '|' in the // genStaticDocs.sh script by a simple sed command after converting to RsT if ( !knobHint.isEmpty() ) { if (!knobHint.startsWith( QString::fromUtf8(". ") )) { knobHint.prepend( QString::fromUtf8(". ") ); } knobHint.append( QString::fromUtf8("\\\n") ); } knobHint.append( QString::fromUtf8(". ") + tr("Possible values:") + QString::fromUtf8("\\\n") ); } first = false; } if (genHTML) { knobHint.append( QString::fromUtf8("<br />") ); } else { knobHint.append( QString::fromUtf8("\\\n") ); // we do a hack for multiline elements, because the markdown->rst conversion by pandoc doesn't use the line block syntax. // what we do here is put a supplementary dot at the beginning of each line, which is then converted to a pipe '|' in the // genStaticDocs.sh script by a simple sed command after converting to RsT knobHint.append( QString::fromUtf8(". ") ); } if (entryHelp.isEmpty()) { knobHint.append( QString::fromUtf8("**%1**").arg( convertFromPlainTextToMarkdown(entry, genHTML, true) ) ); } else { knobHint.append( QString::fromUtf8("**%1**: %2").arg( convertFromPlainTextToMarkdown(entry, genHTML, true) ).arg( convertFromPlainTextToMarkdown(entryHelp, genHTML, true) ) ); } } } } else if (isInt) { valueStr = QString::number( isInt->getDefaultValue( DimIdx(i) ) ); } else if (isDbl) { valueStr = QString::number( isDbl->getDefaultValue( DimIdx(i) ) ); } else if (isBool) { valueStr = isBool->getDefaultValue( DimIdx(i) ) ? tr("On") : tr("Off"); } else if (isString) { valueStr = QString::fromUtf8( isString->getDefaultValue( DimIdx(i) ).c_str() ); } else if (isColor) { valueStr = QString::number( isColor->getDefaultValue( DimIdx(i) ) ); } } dimsDefaultValueStr.push_back( std::make_pair(convertFromPlainTextToMarkdown( QString::fromUtf8( (*it)->getDimensionName( DimIdx(i) ).c_str() ), genHTML, true ), convertFromPlainTextToMarkdown(valueStr, genHTML, true)) ); } for (std::size_t i = 0; i < dimsDefaultValueStr.size(); ++i) { if ( !dimsDefaultValueStr[i].second.isEmpty() ) { if (dimsDefaultValueStr.size() > 1) { defValuesStr.append(dimsDefaultValueStr[i].first); defValuesStr.append( QString::fromUtf8(": ") ); } defValuesStr.append(dimsDefaultValueStr[i].second); if (i < dimsDefaultValueStr.size() - 1) { defValuesStr.append( QString::fromUtf8(" ") ); } } } if ( defValuesStr.isEmpty() ) { defValuesStr = tr("N/A"); } } if (!isPage && !isSep && !isGroup && !isLabel) { QStringList row; row << knobLabel << knobScriptName << knobType << defValuesStr << knobHint; items.append(row); } } // for (KnobsVec::const_iterator it = knobs.begin(); it!=knobs.end(); ++it) { // generate plugin info ms << tr("%1 node").arg(pluginLabel) << "\n==========\n\n"; // a hack to avoid repeating the documentation for the various merge plugins if ( pluginID.startsWith( QString::fromUtf8("net.sf.openfx.Merge") ) ) { std::string id = pluginID.toStdString(); std::string op; if (id == PLUGINID_OFX_MERGE) { // do nothing } else if (id == "net.sf.openfx.MergeDifference") { op = "difference (a.k.a. absminus)"; } else if (id == "net.sf.openfx.MergeIn") { op = "in"; } else if (id == "net.sf.openfx.MergeMatte") { op = "matte"; } else if (id == "net.sf.openfx.MergeMax") { op = "max"; } else if (id == "net.sf.openfx.MergeMin") { op = "min"; } else if (id == "net.sf.openfx.MergeMultiply") { op = "multiply"; } else if (id == "net.sf.openfx.MergeOut") { op = "out"; } else if (id == "net.sf.openfx.MergePlus") { op = "plus"; } else if (id == "net.sf.openfx.MergeScreen") { op = "screen"; } if ( !op.empty() ) { // we should use the custom link "[Merge node](|http::/plugins/" PLUGINID_OFX_MERGE ".html||rst::net.sf.openfx.MergePlugin|)" // but pandoc borks it ms << tr("The *%1* node is a convenience node identical to the %2, except that the operator is set to *%3* by default.") .arg(pluginLabel) .arg(genHTML ? QString::fromUtf8("<a href=\"" PLUGINID_OFX_MERGE ".html\">Merge node</a>") : QString::fromUtf8(":ref:`" PLUGINID_OFX_MERGE "`") //QString::fromUtf8("[Merge node](http::/plugins/" PLUGINID_OFX_MERGE ".html)") ) .arg( QString::fromUtf8( op.c_str() ) ); goto OUTPUT; } } if (!pluginIconUrl.isEmpty()) { // add a nonbreaking space so that pandoc doesn't use the alt-text as a caption // http://pandoc.org/MANUAL.html#images ms << "![pluginIcon](" << pluginIconUrl << ")"; if (!genHTML) { // specify image width for pandoc-generated printed doc // (for hoedown-generated HTML, this handled by the CSS using the alt=pluginIcon attribute) // see http://pandoc.org/MANUAL.html#images // note that only % units are understood both by pandox and sphinx ms << "{ width=10% }"; } ms << " \n\n"; // required so that there is no legend when converted to rst by pandoc } ms << tr("*This documentation is for version %2.%3 of %1.*").arg(pluginLabel).arg(majorVersion).arg(minorVersion) << "\n\n"; ms << "\n" << tr("Description") << "\n--------------------------------------------------------------------------------\n\n"; if (!pluginDescriptionIsMarkdown) { if (genHTML) { pluginDescription = NATRON_NAMESPACE::convertFromPlainText(pluginDescription, NATRON_NAMESPACE::WhiteSpaceNormal); // replace URLs with links QRegExp re( QString::fromUtf8("((http|ftp|https)://([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])?)") ); pluginDescription.replace( re, QString::fromUtf8("<a href=\"\\1\">\\1</a>") ); } else { pluginDescription = convertFromPlainTextToMarkdown(pluginDescription, genHTML, false); } } ms << pluginDescription << "\n"; // create markdown table ms << "\n" << tr("Inputs") << "\n--------------------------------------------------------------------------------\n\n"; ms << tr("Input") << " | " << tr("Description") << " | " << tr("Optional") << "\n"; ms << "--- | --- | ---\n"; if (inputs.size() > 0) { Q_FOREACH(const QStringList &input, inputs) { QString inputName = input.at(0); QString inputDesc = input.at(1); QString inputOpt = input.at(2); ms << inputName << " | " << inputDesc << " | " << inputOpt << "\n"; }
void KnobGuiChoice::onEntriesPopulated() { KnobChoicePtr knob = _knob.lock(); if (!knob) { return; } _comboBox->clear(); std::vector<ChoiceOption> entries = knob->getEntries(); std::string pluginShortcutGroup; EffectInstancePtr isEffect = toEffectInstance(knob->getHolder()); if (isEffect) { PluginPtr plugin = isEffect->getNode()->getOriginalPlugin(); if (plugin) { pluginShortcutGroup = plugin->getPluginShortcutGroup(); } } const std::map<int, std::string>& shortcutsMap = knob->getShortcuts(); const std::map<int, std::string>& iconsMap = knob->getIcons(); for (U32 i = 0; i < entries.size(); ++i) { std::string shortcutID; std::string iconFilePath; if (!pluginShortcutGroup.empty()) { std::map<int, std::string>::const_iterator foundShortcut = shortcutsMap.find(i); if (foundShortcut != shortcutsMap.end()) { shortcutID = foundShortcut->second; } } std::map<int, std::string>::const_iterator foundIcon = iconsMap.find(i); if (foundIcon != iconsMap.end()) { iconFilePath = foundIcon->second; } QIcon icon; if (!iconFilePath.empty()) { QPixmap pix( getPixmapPathFromFilePath( QString::fromUtf8( iconFilePath.c_str() ) ) ); if (!pix.isNull()) { pix = pix.scaled(TO_DPIX(NATRON_MEDIUM_BUTTON_ICON_SIZE), TO_DPIY(NATRON_MEDIUM_BUTTON_ICON_SIZE)); icon.addPixmap(pix); } } if (!shortcutID.empty() && !pluginShortcutGroup.empty() && !_comboBox->isCascading()) { QAction* action = new ActionWithShortcut(pluginShortcutGroup, shortcutID, entries[i].label, _comboBox); if (!icon.isNull()) { action->setIcon(icon); } _comboBox->addAction(action); } else { _comboBox->addItem( QString::fromUtf8( entries[i].label.c_str() ), icon, QKeySequence(), QString::fromUtf8( entries[i].tooltip.c_str() ) ); } } // for all entries const std::vector<int>& separators = knob->getSeparators(); for (std::size_t i = 0; i < separators.size(); ++i) { _comboBox->insertSeparator(separators[i]); } // the "New" menu is only added to known parameters (e.g. the choice of output channels) if (knob->getNewOptionCallback()) { _comboBox->addItemNew(); } updateGUI(); } // onEntriesPopulated