MultipleKnobEditsUndoCommand::MultipleKnobEditsUndoCommand(const KnobGuiPtr& knob, ValueChangedReasonEnum reason, bool createNew, bool setKeyFrame, const Variant & value, int dimension, double time) : QUndoCommand() , knobs() , createNew(createNew) , firstRedoCalled(false) , _reason(reason) { assert(knob); std::list<ValueToSet>& vlist = knobs[knob]; ValueToSet v; v.newValue = value; v.dimension = dimension; assert(dimension != -1); v.time = time; v.setKeyFrame = setKeyFrame; v.setValueRetCode = -1; vlist.push_back(v); KnobHolder* holder = knob->getKnob()->getHolder(); EffectInstance* effect = dynamic_cast<EffectInstance*>(holder); QString holderName; if (effect) { holderName = QString::fromUtf8( effect->getNode()->getLabel().c_str() ); } setText( tr("Multiple edits for %1").arg(holderName) ); }
LinkToKnobDialog::LinkToKnobDialog(const KnobGuiPtr& from, QWidget* parent) : QDialog(parent) , _imp( new LinkToKnobDialogPrivate(from) ) { _imp->mainLayout = new QVBoxLayout(this); _imp->firstLine = new QWidget(this); _imp->firstLineLayout = new QHBoxLayout(_imp->firstLine); _imp->mainLayout->addWidget(_imp->firstLine); _imp->buttons = new QDialogButtonBox(QDialogButtonBox::StandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel), Qt::Horizontal, this); QObject::connect( _imp->buttons, SIGNAL(accepted()), this, SLOT(accept()) ); QObject::connect( _imp->buttons, SIGNAL(rejected()), this, SLOT(reject()) ); _imp->mainLayout->addWidget(_imp->buttons); _imp->selectNodeLabel = new Label(tr("Parent:"), _imp->firstLine); _imp->firstLineLayout->addWidget(_imp->selectNodeLabel); EffectInstance* isEffect = dynamic_cast<EffectInstance*>( from->getKnob()->getHolder() ); assert(isEffect); if (!isEffect) { throw std::logic_error(""); } boost::shared_ptr<NodeCollection> group = isEffect->getNode()->getGroup(); group->getActiveNodes(&_imp->allNodes); NodeGroup* isGroup = dynamic_cast<NodeGroup*>( group.get() ); if (isGroup) { _imp->allNodes.push_back( isGroup->getNode() ); } QStringList nodeNames; for (NodesList::iterator it = _imp->allNodes.begin(); it != _imp->allNodes.end(); ++it) { QString name = QString::fromUtf8( (*it)->getLabel().c_str() ); nodeNames.push_back(name); //_imp->nodeSelectionCombo->addItem(name); } nodeNames.sort(); _imp->nodeSelectionCombo = new CompleterLineEdit(nodeNames, nodeNames, false, this); _imp->nodeSelectionCombo->setToolTip( GuiUtils::convertFromPlainText(tr("Input the name of a node in the current project."), Qt::WhiteSpaceNormal) ); _imp->firstLineLayout->addWidget(_imp->nodeSelectionCombo); _imp->nodeSelectionCombo->setFocus(Qt::PopupFocusReason); QTimer::singleShot( 25, _imp->nodeSelectionCombo, SLOT(showCompleter()) ); _imp->knobSelectionCombo = new ComboBox(_imp->firstLine); _imp->firstLineLayout->addWidget(_imp->knobSelectionCombo); QObject::connect( _imp->nodeSelectionCombo, SIGNAL(itemCompletionChosen()), this, SLOT(onNodeComboEditingFinished()) ); _imp->firstLineLayout->addStretch(); }
void KnobFile::reloadFile() { assert( getHolder() ); EffectInstance* effect = dynamic_cast<EffectInstance*>( getHolder() ); if (effect) { effect->purgeCaches(); effect->clearPersistentMessage(false); } evaluateValueChange(0, getCurrentTime(), ViewIdx(0), eValueChangedReasonNatronInternalEdited); }
void NodeGraph::removeNode(const NodeGuiPtr & node) { NodeGroup* isGrp = node->getNode()->isEffectGroup(); const KnobsVec & knobs = node->getNode()->getKnobs(); for (U32 i = 0; i < knobs.size(); ++i) { KnobI::ListenerDimsMap listeners; knobs[i]->getListeners(listeners); ///For all listeners make sure they belong to a node bool foundEffect = false; for (KnobI::ListenerDimsMap::iterator it2 = listeners.begin(); it2 != listeners.end(); ++it2) { KnobPtr listener = it2->first.lock(); if (!listener) { continue; } EffectInstance* isEffect = dynamic_cast<EffectInstance*>(listener->getHolder()); if (!isEffect) { continue; } if (isGrp && isEffect->getNode()->getGroup().get() == isGrp) { continue; } if ( isEffect && ( isEffect != node->getNode()->getEffectInstance().get() ) ) { foundEffect = true; break; } } if (foundEffect) { StandardButtonEnum reply = Dialogs::questionDialog( tr("Delete").toStdString(), tr("This node has one or several " "parameters from which other parameters " "of the project rely on through expressions " "or links. Deleting this node will " "remove these expressions " "and undoing the action will not recover " "them. Do you wish to continue ?") .toStdString(), false ); if (reply == eStandardButtonNo) { return; } break; } } node->setUserSelected(false); NodesGuiList nodesToRemove; nodesToRemove.push_back(node); pushUndoCommand( new RemoveMultipleNodesCommand(this,nodesToRemove) ); }
quint32* EffectUser::applyFilters( const Workflow::Frame* frame, qint64 currentFrame, double time ) { QReadLocker lock( m_effectsLock ); if ( m_filters.size() == 0 ) return NULL; EffectsEngine::EffectList::const_iterator it = m_filters.constBegin(); EffectsEngine::EffectList::const_iterator ite = m_filters.constEnd(); quint32 *buff1 = NULL; quint32 *buff2 = NULL; const quint32 *input = frame->buffer(); bool firstBuff = true; while ( it != ite ) { if ( (*it)->begin() < currentFrame && ( (*it)->end() < 0 || (*it)->end() > currentFrame ) ) { quint32 **buff; if ( firstBuff == true ) buff = &buff1; else buff = &buff2; if ( *buff == NULL ) *buff = new quint32[frame->nbPixels()]; EffectInstance *effect = (*it)->effectInstance(); effect->process( time, input, *buff ); input = *buff; firstBuff = !firstBuff; } ++it; } if ( buff1 != NULL || buff2 != NULL ) { if ( firstBuff == true ) { delete[] buff1; return buff2; } else { delete[] buff2; return buff1; } } return NULL; }
void KnobGui::onCreateAliasOnGroupActionTriggered() { KnobHolder* holder = getKnob()->getHolder(); EffectInstance* isEffect = dynamic_cast<EffectInstance*>(holder); assert(isEffect); if (!isEffect) { throw std::logic_error(""); } boost::shared_ptr<NodeCollection> collec = isEffect->getNode()->getGroup(); NodeGroup* isCollecGroup = dynamic_cast<NodeGroup*>( collec.get() ); assert(isCollecGroup); if (isCollecGroup) { createDuplicateOnNode(isCollecGroup, true, boost::shared_ptr<KnobPage>(), boost::shared_ptr<KnobGroup>(), -1); } }
void QtWriter::getFrameRange(double *first, double *last) { int index = _frameRangeChoosal->getValue(); if (index == 0) { EffectInstance* inp = getInput(0); if (inp) { inp->getFrameRange_public(inp->getRenderHash(), first, last); } else { *first = 0; *last = 0; } } else if (index == 1) { getApp()->getFrameRange(first, last); } else { *first = _firstFrameKnob->getValue(); *last = _lastFrameKnob->getValue(); } }
void QtWriter::getFrameRange(SequenceTime *first, SequenceTime *last) { int index = _frameRangeChoosal->getValue(); if (index == 0) { EffectInstance* inp = getInput(0); if (inp) { inp->getFrameRange_public(inp->getRenderHash(),first, last); } else { *first = 0; *last = 0; } } else if (index == 1) { *first = getApp()->getTimeLine()->leftBound(); *last = getApp()->getTimeLine()->rightBound(); } else { *first = _firstFrameKnob->getValue(); *last = _lastFrameKnob->getValue(); } }
void KnobGui::linkTo(int dimension) { KnobPtr thisKnob = getKnob(); assert(thisKnob); EffectInstance* isEffect = dynamic_cast<EffectInstance*>( thisKnob->getHolder() ); if (!isEffect) { return; } for (int i = 0; i < thisKnob->getDimension(); ++i) { if ( (i == dimension) || (dimension == -1) ) { std::string expr = thisKnob->getExpression(dimension); if ( !expr.empty() ) { Dialogs::errorDialog( tr("Param Link").toStdString(), tr("This parameter already has an expression set, edit or clear it.").toStdString() ); return; } } } LinkToKnobDialog dialog( shared_from_this(), _imp->copyRightClickMenu->parentWidget() ); if ( dialog.exec() ) { KnobPtr otherKnob = dialog.getSelectedKnobs(); if (otherKnob) { if ( !thisKnob->isTypeCompatible(otherKnob) ) { Dialogs::errorDialog( tr("Param Link").toStdString(), tr("Types are incompatible!").toStdString() ); return; } for (int i = 0; i < thisKnob->getDimension(); ++i) { std::pair<int, KnobPtr > existingLink = thisKnob->getMaster(i); if (existingLink.second) { Dialogs::errorDialog( tr("Param Link").toStdString(), tr("Cannot link %1 because the knob is already linked to %2.") .arg( QString::fromUtf8( thisKnob->getLabel().c_str() ) ) .arg( QString::fromUtf8( existingLink.second->getLabel().c_str() ) ) .toStdString() ); return; } } EffectInstance* otherEffect = dynamic_cast<EffectInstance*>( otherKnob->getHolder() ); if (!otherEffect) { return; } std::stringstream expr; boost::shared_ptr<NodeCollection> thisCollection = isEffect->getNode()->getGroup(); NodeGroup* otherIsGroup = dynamic_cast<NodeGroup*>(otherEffect); if ( otherIsGroup == thisCollection.get() ) { expr << "thisGroup"; // make expression generic if possible } else { expr << otherEffect->getNode()->getFullyQualifiedName(); } expr << "." << otherKnob->getName() << ".get()"; if (otherKnob->getDimension() > 1) { expr << "[dimension]"; } thisKnob->beginChanges(); for (int i = 0; i < thisKnob->getDimension(); ++i) { if ( (i == dimension) || (dimension == -1) ) { thisKnob->setExpression(i, expr.str(), false, false); } } thisKnob->endChanges(); thisKnob->getHolder()->getApp()->triggerAutoSave(); } } } // KnobGui::linkTo
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
void ProjectGuiSerialization::initialize(const ProjectGui* projectGui) { NodesList activeNodes; projectGui->getInternalProject()->getActiveNodesExpandGroups(&activeNodes); _serializedNodes.clear(); for (NodesList::iterator it = activeNodes.begin(); it != activeNodes.end(); ++it) { boost::shared_ptr<NodeGuiI> nodegui_i = (*it)->getNodeGui(); if (!nodegui_i) { continue; } NodeGuiPtr nodegui = boost::dynamic_pointer_cast<NodeGui>(nodegui_i); if ( nodegui->isVisible() ) { boost::shared_ptr<NodeCollection> isInCollection = (*it)->getGroup(); NodeGroup* isCollectionAGroup = dynamic_cast<NodeGroup*>( isInCollection.get() ); if (!isCollectionAGroup) { ///Nodes within a group will be serialized recursively in the node group serialization NodeGuiSerialization state; nodegui->serialize(&state); _serializedNodes.push_back(state); } ViewerInstance* viewer = (*it)->isEffectViewer(); 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.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() ) { KnobHolder* holder = (*it)->getHolder(); assert(holder); EffectInstance* isEffect = dynamic_cast<EffectInstance*>(holder); Project* isProject = dynamic_cast<Project*>(holder); if (isProject) { _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 KnobGuiButton::createWidget(QHBoxLayout* layout) { boost::shared_ptr<KnobButton> knob = _knob.lock(); QString label = QString::fromUtf8( knob->getLabel().c_str() ); QString onIconFilePath = QString::fromUtf8( knob->getIconLabel(true).c_str() ); QString offIconFilePath = QString::fromUtf8( knob->getIconLabel(false).c_str() ); if ( !onIconFilePath.isEmpty() && !QFile::exists(onIconFilePath) ) { EffectInstance* isEffect = dynamic_cast<EffectInstance*>( knob->getHolder() ); if (isEffect) { //Prepend the resources path QString resourcesPath = QString::fromUtf8( isEffect->getNode()->getPluginResourcesPath().c_str() ); if ( !resourcesPath.endsWith( QLatin1Char('/') ) ) { resourcesPath += QLatin1Char('/'); } onIconFilePath.prepend(resourcesPath); } } if ( !offIconFilePath.isEmpty() && !QFile::exists(offIconFilePath) ) { EffectInstance* isEffect = dynamic_cast<EffectInstance*>( knob->getHolder() ); if (isEffect) { //Prepend the resources path QString resourcesPath = QString::fromUtf8( isEffect->getNode()->getPluginResourcesPath().c_str() ); if ( !resourcesPath.endsWith( QLatin1Char('/') ) ) { resourcesPath += QLatin1Char('/'); } offIconFilePath.prepend(resourcesPath); } } bool checkable = knob->getIsCheckable(); QIcon icon; QPixmap pixChecked, pixUnchecked; if ( !offIconFilePath.isEmpty() ) { if ( pixUnchecked.load(offIconFilePath) ) { icon.addPixmap(pixUnchecked, QIcon::Normal, QIcon::Off); } } if ( !onIconFilePath.isEmpty() ) { if ( pixChecked.load(onIconFilePath) ) { icon.addPixmap(pixChecked, QIcon::Normal, QIcon::On); } } if ( !icon.isNull() ) { _button = new Button( icon, QString(), layout->parentWidget() ); _button->setFixedSize(NATRON_MEDIUM_BUTTON_SIZE, NATRON_MEDIUM_BUTTON_SIZE); _button->setIconSize( QSize(NATRON_MEDIUM_BUTTON_ICON_SIZE, NATRON_MEDIUM_BUTTON_ICON_SIZE) ); } else { _button = new Button( label, layout->parentWidget() ); } if (checkable) { _button->setCheckable(true); bool checked = knob->getValue(); _button->setChecked(checked); _button->setDown(checked); } QObject::connect( _button, SIGNAL(clicked(bool)), this, SLOT(emitValueChanged(bool)) ); if ( hasToolTip() ) { _button->setToolTip( toolTip() ); } layout->addWidget(_button); } // KnobGuiButton::createWidget
void NodeGraph::deleteSelection() { if ( !_imp->_selection.empty()) { NodesGuiList nodesToRemove = _imp->_selection; ///For all backdrops also move all the nodes contained within it for (NodesGuiList::iterator it = nodesToRemove.begin(); it != nodesToRemove.end(); ++it) { NodesGuiList nodesWithinBD = getNodesWithinBackdrop(*it); for (NodesGuiList::iterator it2 = nodesWithinBD.begin(); it2 != nodesWithinBD.end(); ++it2) { NodesGuiList::iterator found = std::find(nodesToRemove.begin(),nodesToRemove.end(),*it2); if ( found == nodesToRemove.end()) { nodesToRemove.push_back(*it2); } } } for (NodesGuiList::iterator it = nodesToRemove.begin(); it != nodesToRemove.end(); ++it) { const KnobsVec & knobs = (*it)->getNode()->getKnobs(); bool mustBreak = false; NodeGroup* isGrp = (*it)->getNode()->isEffectGroup(); for (U32 i = 0; i < knobs.size(); ++i) { KnobI::ListenerDimsMap listeners; knobs[i]->getListeners(listeners); ///For all listeners make sure they belong to a node bool foundEffect = false; for (KnobI::ListenerDimsMap::iterator it2 = listeners.begin(); it2 != listeners.end(); ++it2) { KnobPtr listener = it2->first.lock(); if (!listener) { continue; } EffectInstance* isEffect = dynamic_cast<EffectInstance*>(listener->getHolder() ); if (!isEffect) { continue; } if (isGrp && isEffect->getNode()->getGroup().get() == isGrp) { continue; } if (!isEffect->getNode()->getGroup()) { continue; } if ( isEffect && ( isEffect != (*it)->getNode()->getEffectInstance().get() ) ) { foundEffect = true; break; } } if (foundEffect) { StandardButtonEnum reply = Dialogs::questionDialog( tr("Delete").toStdString(), tr("This node has one or several " "parameters from which other parameters " "of the project rely on through expressions " "or links. Deleting this node will " "may break these expressions." "\nContinue anyway ?") .toStdString(), false ); if (reply == eStandardButtonNo) { return; } mustBreak = true; break; } } if (mustBreak) { break; } } for (NodesGuiList::iterator it = nodesToRemove.begin(); it != nodesToRemove.end(); ++it) { (*it)->setUserSelected(false); } pushUndoCommand( new RemoveMultipleNodesCommand(this,nodesToRemove) ); _imp->_selection.clear(); } } // deleteSelection