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() ); } } } }
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); } }
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) ); } }
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; } }
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; }
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
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); }
void ProjectGuiSerialization::initialize(const ProjectGui* projectGui) { NodesList activeNodes; projectGui->getInternalProject()->getActiveNodesExpandGroups(&activeNodes); _serializedNodes.clear(); for (NodesList::iterator it = activeNodes.begin(); it != activeNodes.end(); ++it) { NodeGuiIPtr nodegui_i = (*it)->getNodeGui(); if (!nodegui_i) { continue; } NodeGuiPtr nodegui = boost::dynamic_pointer_cast<NodeGui>(nodegui_i); if ( nodegui->isVisible() ) { NodeCollectionPtr isInCollection = (*it)->getGroup(); NodeGroupPtr isCollectionAGroup = toNodeGroup( isInCollection ); if (!isCollectionAGroup) { ///Nodes within a group will be serialized recursively in the node group serialization NodeGuiSerialization state; nodegui->serialize(&state); _serializedNodes.push_back(state); } ViewerInstancePtr viewer = (*it)->isEffectViewerInstance(); if (viewer) { ViewerTab* tab = projectGui->getGui()->getViewerTabForInstance(viewer); assert(tab); ViewerData viewerData; double zoompar; tab->getViewer()->getProjection(&viewerData.zoomLeft, &viewerData.zoomBottom, &viewerData.zoomFactor, &zoompar); viewerData.userRoI = tab->getViewer()->getUserRegionOfInterest(); viewerData.userRoIenabled = tab->getViewer()->isUserRegionOfInterestEnabled(); viewerData.isClippedToProject = tab->isClippedToProject(); viewerData.autoContrastEnabled = tab->isAutoContrastEnabled(); viewerData.gain = tab->getGain(); viewerData.gamma = tab->getGamma(); viewerData.colorSpace = tab->getColorSpace(); viewerData.channels = tab->getChannelsString(); viewerData.renderScaleActivated = tab->getRenderScaleActivated(); viewerData.mipMapLevel = tab->getMipMapLevel(); viewerData.zoomOrPanSinceLastFit = tab->getZoomOrPannedSinceLastFit(); viewerData.wipeCompositingOp = (int)tab->getCompositingOperator(); viewerData.leftToolbarVisible = tab->isLeftToolbarVisible(); viewerData.rightToolbarVisible = tab->isRightToolbarVisible(); viewerData.topToolbarVisible = tab->isTopToolbarVisible(); viewerData.infobarVisible = tab->isInfobarVisible(); viewerData.playerVisible = tab->isPlayerVisible(); viewerData.timelineVisible = tab->isTimelineVisible(); viewerData.checkerboardEnabled = tab->isCheckerboardEnabled(); viewerData.isFullFrameProcessEnabled = tab->isFullFrameProcessingEnabled(); viewerData.fps = tab->getDesiredFps(); viewerData.fpsLocked = tab->isFPSLocked(); viewerData.isPauseEnabled[0] = tab->isViewerPaused(0); viewerData.isPauseEnabled[1] = tab->isViewerPaused(1); viewerData.layerName = tab->getCurrentLayerName().toStdString(); viewerData.alphaLayerName = tab->getCurrentAlphaLayerName().toStdString(); tab->getTimelineBounds(&viewerData.leftBound, &viewerData.rightBound); tab->getActiveInputs(&viewerData.aChoice, &viewerData.bChoice); viewerData.version = VIEWER_DATA_SERIALIZATION_VERSION; _viewersData.insert( std::make_pair(viewer->getNode()->getScriptName_mt_safe(), viewerData) ); } } } ///Init windows _layoutSerialization.initialize( projectGui->getGui() ); ///save histograms std::list<Histogram*> histograms = projectGui->getGui()->getHistograms_mt_safe(); for (std::list<Histogram*>::const_iterator it = histograms.begin(); it != histograms.end(); ++it) { _histograms.push_back( (*it)->objectName().toStdString() ); } ///save opened panels by order std::list<DockablePanel*> panels = projectGui->getGui()->getVisiblePanels_mt_safe(); for (std::list<DockablePanel*>::iterator it = panels.begin(); it != panels.end(); ++it) { if ( (*it)->isVisible() ) { KnobHolderPtr holder = (*it)->getHolder(); assert(holder); EffectInstancePtr isEffect = toEffectInstance(holder); ProjectPtr isProj = toProject(holder); if (isProj) { _openedPanelsOrdered.push_back(kNatronProjectSettingsPanelSerializationName); } else if (isEffect) { _openedPanelsOrdered.push_back( isEffect->getNode()->getFullyQualifiedName() ); } } } _scriptEditorInput = projectGui->getGui()->getScriptEditor()->getAutoSavedScript().toStdString(); std::map<NATRON_PYTHON_NAMESPACE::PyPanel*, std::string> pythonPanels = projectGui->getGui()->getPythonPanels(); for (std::map<NATRON_PYTHON_NAMESPACE::PyPanel*, std::string>::iterator it = pythonPanels.begin(); it != pythonPanels.end(); ++it) { boost::shared_ptr<PythonPanelSerialization> s(new PythonPanelSerialization); s->initialize(it->first, it->second); _pythonPanels.push_back(s); } } // initialize
void 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
std::string PasteKnobClipBoardUndoCommand::makeLinkExpression(const std::vector<std::string>& projectViewNames, const KnobIPtr& targetKnob, bool multCurve, const KnobIPtr& fromKnob, DimSpec fromDimension, ViewSetSpec fromView, DimSpec targetDimension, ViewSetSpec targetView) { EffectInstancePtr fromEffect = toEffectInstance( fromKnob->getHolder() ); EffectInstancePtr toEffect = toEffectInstance( targetKnob->getHolder() ); assert(fromEffect && toEffect); if (!fromEffect || !toEffect) { return std::string(); } std::stringstream ss; if (fromEffect == toEffect) { // Same node, use thisNode ss << "thisNode."; } else { // If the container of the effect is a group, prepend thisGroup, otherwise use // the canonical app prefix NodeGroupPtr isEffectContainerGroup; { NodeCollectionPtr effectContainer = fromEffect->getNode()->getGroup(); isEffectContainerGroup = toNodeGroup(effectContainer); } if (isEffectContainerGroup) { ss << "thisGroup."; } else { ss << fromEffect->getApp()->getAppIDString() << "."; } ss << fromEffect->getNode()->getScriptName_mt_safe() << "."; } // Call getValue on the fromKnob ss << fromKnob->getName(); ss << ".getValue("; if (fromKnob->getNDimensions() > 1) { if (fromDimension.isAll()) { ss << "dimension"; } else { ss << fromDimension; } } std::list<ViewIdx> sourceViews = fromKnob->getViewsList(); if (sourceViews.size() > 1) { ss << ", "; if (fromView.isAll()) { ss << "view"; } else { if (fromView >= 0 && fromView < (int)projectViewNames.size()) { ss << projectViewNames[fromView]; } else { ss << "Main"; } } } ss << ")"; // Also check if we need to multiply by the target knob's curve if (multCurve) { ss << " * curve(frame, "; if (targetDimension.isAll()) { ss << "dimension"; } else { ss << targetDimension; } std::list<ViewIdx> targetKnobViews = targetKnob->getViewsList(); if (targetKnobViews.size() > 1) { ss << ", "; if (targetView.isAll()) { ss << "view"; } else { if (targetView >= 0 && targetView < (int)projectViewNames.size()) { ss << projectViewNames[targetView]; } else { ss << "Main"; } } } ss << ")"; } return ss.str(); } // makeLinkExpression