bool GuiAppInstance::checkAllReadersModificationDate(bool errorAndWarn) { NodesList allNodes; SequenceTime time = getProject()->getCurrentTime(); getProject()->getNodes_recursive(allNodes, true); bool changed = false; for (NodesList::iterator it = allNodes.begin(); it != allNodes.end(); ++it) { if ( (*it)->getEffectInstance()->isReader() ) { KnobIPtr fileKnobI = (*it)->getKnobByName(kOfxImageEffectFileParamName); if (!fileKnobI) { continue; } KnobGuiIPtr knobUi_i = fileKnobI->getKnobGuiPointer(); KnobGuiFile* isFileKnob = dynamic_cast<KnobGuiFile*>( knobUi_i.get() ); if (!isFileKnob) { continue; } changed |= isFileKnob->checkFileModificationAndWarn(time, errorAndWarn); } } return changed; }
static void getOldExprForDimView(const KnobIPtr& knob, DimIdx dim, ViewIdx view, SetExpressionCommand::PerDimViewExprMap* ret) { DimensionViewPair key = {dim, view}; SetExpressionCommand::Expr& e = (*ret)[key]; e.expression = knob->getExpression(dim, view); e.hasRetVar = knob->isExpressionUsingRetVariable(view, dim); }
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) ); } }
void DSTransformKeysCommand::transformKey(const DSKeyPtr& key) { DSKnobPtr knobContext = key->context.lock(); if (!knobContext) { return; } KnobIPtr knob = knobContext->getKnobGui()->getKnob(); knob->transformValueAtTime(eCurveChangeReasonDopeSheet, key->key.getTime(), ViewSpec::all(), knobContext->getDimension(), _transform, &key->key); }
void EditExpressionDialog::setTitle() { KnobIPtr k = _knob->getKnob(); QString title( tr("Set expression on ") ); title.append( QString::fromUtf8( k->getName().c_str() ) ); if ( !_dimension.isAll() && (k->getNDimensions() > 1) ) { title.append( QLatin1Char('.') ); title.append( QString::fromUtf8( k->getDimensionName(DimIdx(_dimension)).c_str() ) ); } setWindowTitle(title); }
static void deleteKnobAnimation(const std::set<double>& userKeyframes, const KnobIPtr& knob, DeleteKnobAnimationEnum type, double currentTime) { for (int i = 0; i < knob->getNDimensions(); ++i) { CurvePtr curve = knob->getAnimationCurve(ViewIdx(0), DimIdx(i)); assert(curve); KeyFrameSet keys = curve->getKeyFrames_mt_safe(); std::list<double> toRemove; switch (type) { case eDeleteKnobAnimationAll: { for (KeyFrameSet::iterator it = keys.begin(); it != keys.end(); ++it) { std::set<double>::iterator found = userKeyframes.find( it->getTime() ); if ( found == userKeyframes.end() ) { toRemove.push_back( it->getTime() ); } } break; } case eDeleteKnobAnimationBeforeTime: { for (KeyFrameSet::iterator it = keys.begin(); it != keys.end(); ++it) { if (it->getTime() >= currentTime) { break; } std::set<double>::iterator found = userKeyframes.find( it->getTime() ); if ( found == userKeyframes.end() ) { toRemove.push_back( it->getTime() ); } } break; } case eDeleteKnobAnimationAfterTime: { for (KeyFrameSet::reverse_iterator it = keys.rbegin(); it != keys.rend(); ++it) { if (it->getTime() <= currentTime) { break; } std::set<double>::iterator found = userKeyframes.find( it->getTime() ); if ( found == userKeyframes.end() ) { toRemove.push_back( it->getTime() ); } } break; } } knob->deleteValuesAtTime(toRemove, ViewSetSpec::all(), DimIdx(i), eValueChangedReasonUserEdited); } }
std::string KnobGuiWidgets::getDescriptionLabel() const { std::string ret; KnobGuiPtr knob = getKnobGui(); if (!knob) { return ret; } KnobIPtr internalKnob = knob->getKnob(); if (!internalKnob) { return ret; } ret = internalKnob->getLabel(); return ret; }
void SetExpressionCommand::redo() { KnobIPtr knob = _knob.lock(); if (!knob) { return; } try { // Don't fail if exception is invalid, it should have been tested prior to creating an undo/redo command, otherwise user is going // to hit CTRL-Z and nothing will happen knob->setExpression(_dimension, _view, _newExpr, _hasRetVar, /*failIfInvalid*/ false); } catch (...) { Dialogs::errorDialog( tr("Expression").toStdString(), tr("The expression is invalid.").toStdString() ); } }
static void setOldExprForDimView(const KnobIPtr& knob, DimIdx dim, ViewIdx view, const SetExpressionCommand::PerDimViewExprMap& ret) { DimensionViewPair key = {dim, view}; SetExpressionCommand::PerDimViewExprMap::const_iterator foundDimView = ret.find(key); if (foundDimView == ret.end()) { return; } knob->setExpression(dim, view, foundDimView->second.expression, foundDimView->second.hasRetVar, false /*failIfInvalid*/); }
KnobGuiColor::KnobGuiColor(KnobIPtr knob, KnobGuiContainerI *container) : KnobGuiValue(knob, container) , _knob( toKnobColor(knob) ) , _colorLabel(0) , _colorDialogButton(0) , _lastColor( knob->getDimension() ) , _useSimplifiedUI( isViewerUIKnob() || _knob.lock()->isSimplified() ) { }
SetExpressionCommand::SetExpressionCommand(const KnobIPtr & knob, bool hasRetVar, DimSpec dimension, ViewSetSpec view, const std::string& expr, QUndoCommand *parent) : QUndoCommand(parent) , _knob(knob) , _oldExprs() , _newExpr(expr) , _hasRetVar(hasRetVar) , _dimension(dimension) , _view(view) { int nDims = knob->getNDimensions(); std::list<ViewIdx> allViews = knob->getViewsList(); if (dimension.isAll()) { for (int i = 0; i < nDims; ++i) { if (view.isAll()) { for (std::list<ViewIdx>::const_iterator it = allViews.begin(); it!=allViews.end(); ++it) { getOldExprForDimView(knob, DimIdx(i), *it, &_oldExprs); } } else { getOldExprForDimView(knob, DimIdx(i), ViewIdx(view), &_oldExprs); } } } else { if (view.isAll()) { for (std::list<ViewIdx>::const_iterator it = allViews.begin(); it!=allViews.end(); ++it) { getOldExprForDimView(knob, DimIdx(dimension), *it, &_oldExprs); } } else { getOldExprForDimView(knob, DimIdx(dimension), ViewIdx(view), &_oldExprs); } } setText( tr("Set Expression") ); }
PasteKnobClipBoardUndoCommand::PasteKnobClipBoardUndoCommand(const KnobIPtr& knob, KnobClipBoardType type, DimSpec fromDimension, DimSpec targetDimensionIn, ViewSetSpec fromView, ViewSetSpec targetViewIn, const KnobIPtr& fromKnob) : QUndoCommand(0) , _imp( new PasteKnobClipBoardUndoCommandPrivate() ) { assert(knob && fromKnob); // If target view is all but target is not multi-view, convert back to main view // Also, if all dimensions are folded, convert to all dimensions knob->convertDimViewArgAccordingToKnobState(targetDimensionIn, targetViewIn, &_imp->targetDimension, &_imp->targetView); _imp->fromKnob = fromKnob; _imp->knob = knob; _imp->type = type; _imp->fromDimension = fromDimension; _imp->fromView = fromView; _imp->toKnobSerialization.reset(new SERIALIZATION_NAMESPACE::KnobSerialization); knob->toSerialization(_imp->toKnobSerialization.get()); _imp->fromKnobSerialization.reset(new SERIALIZATION_NAMESPACE::KnobSerialization); fromKnob->toSerialization(_imp->fromKnobSerialization.get()); QString text; switch (type) { case eKnobClipBoardTypeCopyAnim: text = tr("Paste Animation on %1").arg( QString::fromUtf8( knob->getLabel().c_str() ) ); break; case eKnobClipBoardTypeCopyValue: text = tr("Paste Value on %1").arg( QString::fromUtf8( knob->getLabel().c_str() ) ); break; case eKnobClipBoardTypeCopyLink: text = tr("Link %1 to %2").arg( QString::fromUtf8( fromKnob->getLabel().c_str() ) ).arg( QString::fromUtf8( knob->getLabel().c_str() ) ); break; case eKnobClipBoardTypeCopyExpressionLink: text = tr("Link with Expression %1 to %2").arg( QString::fromUtf8( fromKnob->getLabel().c_str() ) ).arg( QString::fromUtf8( knob->getLabel().c_str() ) ); break; case eKnobClipBoardTypeCopyExpressionMultCurveLink: text = tr("Set curve(frame)*%1 on %2").arg( QString::fromUtf8( fromKnob->getLabel().c_str() ) ).arg( QString::fromUtf8( knob->getLabel().c_str() ) ); break; } setText(text); }
void SetExpressionCommand::undo() { KnobIPtr knob = _knob.lock(); if (!knob) { return; } knob->beginChanges(); try { int nDims = knob->getNDimensions(); std::list<ViewIdx> allViews = knob->getViewsList(); if (_dimension.isAll()) { for (int i = 0; i < nDims; ++i) { if (_view.isAll()) { for (std::list<ViewIdx>::const_iterator it = allViews.begin(); it!=allViews.end(); ++it) { setOldExprForDimView(knob, DimIdx(i), *it, _oldExprs); } } else { setOldExprForDimView(knob, DimIdx(i), ViewIdx(_view), _oldExprs); } } } else { if (_view.isAll()) { for (std::list<ViewIdx>::const_iterator it = allViews.begin(); it!=allViews.end(); ++it) { setOldExprForDimView(knob, DimIdx(_dimension), *it, _oldExprs); } } else { setOldExprForDimView(knob, DimIdx(_dimension), ViewIdx(_view), _oldExprs); } } } catch (...) { Dialogs::errorDialog( tr("Expression").toStdString(), tr("The expression is invalid.").toStdString() ); } knob->endChanges(); }
bool AnimationModule::getNodeCanAnimate(const NodePtr &node) { // A node with an items table such as Tracker or RotoPaint always animates if (node->getEffectInstance()->getItemsTable()) { return true; } // Check that it has at least one knob that can animate const KnobsVec &knobs = node->getKnobs(); for (KnobsVec::const_iterator it = knobs.begin(); it != knobs.end(); ++it) { KnobIPtr knob = *it; if ( knob->isAnimationEnabled() ) { return true; } } return false; }
void KnobSpinBox::focusInEvent(QFocusEvent* e) { _dnd->focusIn(); SpinBox::focusInEvent(e); //Set the expression so the user can edit it easily KnobGuiPtr k = knob.lock(); if (!k) { return; } KnobIPtr knob = k->getKnob(); if (!knob) { return; } std::string expr = knob->getExpression(dimension, view); if ( expr.empty() ) { return; } else { QLineEdit::setText( QString::fromUtf8( expr.c_str() ) ); setCursorPosition(expr.size() - 1); } }
void DSPasteKeysCommand::addOrRemoveKeyframe(bool add) { for (std::list<boost::weak_ptr<DSKnob> >::const_iterator it = _dstKnobs.begin(); it != _dstKnobs.end(); ++it) { DSKnobPtr knobContext = it->lock(); if (!knobContext) { continue; } for (std::size_t i = 0; i < _keys.size(); ++i) { int dim = knobContext->getDimension(); KnobIPtr knob = knobContext->getInternalKnob(); knob->beginChanges(); double keyTime = _keys[i].key.getTime(); double setTime = _pasteRelativeToRefTime ? keyTime - _keys[_refKeyindex].key.getTime() + _refTime : keyTime; if (add) { for (int j = 0; j < knob->getDimension(); ++j) { if ( (dim == -1) || (j == dim) ) { KeyFrame k = _keys[i].key; k.setTime(setTime); knob->setKeyFrame(k, ViewSpec::all(), j, eValueChangedReasonNatronGuiEdited); } } } else { for (int j = 0; j < knob->getDimension(); ++j) { if ( (dim == -1) || (j == dim) ) { knob->deleteValueAtTime(eCurveChangeReasonDopeSheet, setTime, ViewSpec::all(), j, i == 0); } } } knob->endChanges(); } } _model->refreshSelectionBboxAndRedrawView(); } // DSPasteKeysCommand::addOrRemoveKeyframe
void RestoreDefaultsCommand::undo() { assert( _serializations.size() == _knobs.size() ); KnobIPtr first = _knobs.front().lock(); AppInstancePtr app = first->getHolder()->getApp(); assert(app); SERIALIZATION_NAMESPACE::KnobSerializationList::const_iterator itClone = _serializations.begin(); for (std::list<KnobIWPtr >::const_iterator it = _knobs.begin(); it != _knobs.end(); ++it, ++itClone) { KnobIPtr itKnob = it->lock(); if (!itKnob) { continue; } itKnob->fromSerialization(**itClone); } if ( first->getHolder()->getApp() ) { first->getHolder()->getApp()->redrawAllViewers(); } }
void NodePrivate::runChangedParamCallback(const std::string& cb, const KnobIPtr& k, bool userEdited) { std::vector<std::string> args; std::string error; if ( !k || (k->getName() == "onParamChanged") ) { return; } std::string callbackFunction; if (!figureOutCallbackName(cb, &callbackFunction)) { return; } try { NATRON_PYTHON_NAMESPACE::getFunctionArguments(callbackFunction, &error, &args); } catch (const std::exception& e) { _publicInterface->getApp()->appendToScriptEditor( tr("Failed to run onParamChanged callback: %1").arg( QString::fromUtf8( e.what() ) ).toStdString() ); return; } if ( !error.empty() ) { _publicInterface->getApp()->appendToScriptEditor( tr("Failed to run onParamChanged callback: %1").arg( QString::fromUtf8( error.c_str() ) ).toStdString() ); return; } std::string signatureError; signatureError.append( tr("The param changed callback supports the following signature(s):").toStdString() ); signatureError.append("\n- callback(thisParam,thisNode,thisGroup,app,userEdited)"); if (args.size() != 5) { _publicInterface->getApp()->appendToScriptEditor( tr("Failed to run onParamChanged callback: %1").arg( QString::fromUtf8( signatureError.c_str() ) ).toStdString() ); return; } if ( ( (args[0] != "thisParam") || (args[1] != "thisNode") || (args[2] != "thisGroup") || (args[3] != "app") || (args[4] != "userEdited") ) ) { _publicInterface->getApp()->appendToScriptEditor( tr("Failed to run onParamChanged callback: %1").arg( QString::fromUtf8( signatureError.c_str() ) ).toStdString() ); return; } std::string appID = _publicInterface->getApp()->getAppIDString(); assert(k); std::string thisNodeVar = appID + "."; thisNodeVar.append( _publicInterface->getFullyQualifiedName() ); NodeCollectionPtr collection = _publicInterface->getGroup(); assert(collection); if (!collection) { return; } std::string thisGroupVar; NodeGroupPtr isParentGrp = toNodeGroup(collection); if (isParentGrp) { std::string nodeName = isParentGrp->getNode()->getFullyQualifiedName(); std::string nodeFullName = appID + "." + nodeName; thisGroupVar = nodeFullName; } else { thisGroupVar = appID; } bool alreadyDefined = false; PyObject* nodeObj = NATRON_PYTHON_NAMESPACE::getAttrRecursive(thisNodeVar, NATRON_PYTHON_NAMESPACE::getMainModule(), &alreadyDefined); if (!nodeObj || !alreadyDefined) { return; } if (!PyObject_HasAttrString( nodeObj, k->getName().c_str() ) ) { return; } std::stringstream ss; ss << callbackFunction << "(" << thisNodeVar << "." << k->getName() << "," << thisNodeVar << "," << thisGroupVar << "," << appID << ","; if (userEdited) { ss << "True"; } else { ss << "False"; } ss << ")\n"; std::string script = ss.str(); std::string err; std::string output; if ( !NATRON_PYTHON_NAMESPACE::interpretPythonScript(script, &err, &output) ) { _publicInterface->getApp()->appendToScriptEditor( tr("Failed to execute onParamChanged callback: %1").arg( QString::fromUtf8( err.c_str() ) ).toStdString() ); } else { if ( !output.empty() ) { _publicInterface->getApp()->appendToScriptEditor(output); } } } // runChangedParamCallback
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
void ViewerNode::createViewerProcessNode() { NodePtr internalViewerNode[2]; for (int i = 0; i < 2; ++ i) { ViewerNodePtr thisShared = shared_from_this(); QString nodeName = QString::fromUtf8("ViewerProcess"); nodeName += QString::number(i + 1); CreateNodeArgsPtr args(CreateNodeArgs::create(PLUGINID_NATRON_VIEWER_INTERNAL, thisShared)); args->setProperty<bool>(kCreateNodeArgsPropAutoConnect, false); args->setProperty<bool>(kCreateNodeArgsPropAddUndoRedoCommand, false); args->setProperty<bool>(kCreateNodeArgsPropAllowNonUserCreatablePlugins, true); args->setProperty<bool>(kCreateNodeArgsPropSettingsOpened, false); args->setProperty<std::string>(kCreateNodeArgsPropNodeInitialName, nodeName.toStdString()); internalViewerNode[i] = getApp()->createNode(args); assert(internalViewerNode[i]); if (!internalViewerNode[i]) { throw std::invalid_argument("ViewerNode::setupGraph: No internal viewer process!"); } if (i == 1) { Point position; internalViewerNode[0]->getPosition(&position.x, &position.y); double w,h; internalViewerNode[0]->getSize(&w, &h); internalViewerNode[0]->setPosition(position.x - w /2. - w/2, position.y); internalViewerNode[1]->setPosition(position.x + w /2., position.y); } _imp->internalViewerProcessNode[i] = internalViewerNode[i]; // Link output layer and alpha channel to the viewer process choices KnobIPtr viewerProcessOutputLayerChoice = internalViewerNode[i]->getKnobByName(kViewerInstanceParamOutputLayer); viewerProcessOutputLayerChoice->linkTo(_imp->layersKnob.lock()); KnobIPtr viewerProcessAlphaChannelChoice = internalViewerNode[i]->getKnobByName(kViewerInstanceParamAlphaChannel); viewerProcessAlphaChannelChoice->linkTo(_imp->alphaChannelKnob.lock()); KnobIPtr viewerProcessDisplayChanelsChoice = internalViewerNode[i]->getKnobByName(kViewerInstanceParamDisplayChannels); viewerProcessDisplayChanelsChoice->linkTo(_imp->displayChannelsKnob[i].lock()); KnobIPtr viewerProcessGammaKnob = internalViewerNode[i]->getKnobByName(kViewerInstanceParamGamma); viewerProcessGammaKnob->linkTo(_imp->gammaSliderKnob.lock()); KnobIPtr viewerProcessGainKnob = internalViewerNode[i]->getKnobByName(kViewerInstanceNodeParamGain); viewerProcessGainKnob->linkTo(_imp->gainSliderKnob.lock()); KnobIPtr viewerProcessAutoContrastKnob = internalViewerNode[i]->getKnobByName(kViewerInstanceParamEnableAutoContrast); viewerProcessAutoContrastKnob->linkTo(_imp->enableAutoContrastButtonKnob.lock()); KnobIPtr viewerProcessAutoColorspaceKnob = internalViewerNode[i]->getKnobByName(kViewerInstanceParamColorspace); viewerProcessAutoColorspaceKnob->linkTo(_imp->colorspaceKnob.lock()); KnobIPtr userRoiEnabledKnob = internalViewerNode[i]->getKnobByName(kViewerInstanceParamEnableUserRoI); userRoiEnabledKnob->linkTo(_imp->toggleUserRoIButtonKnob.lock()); KnobIPtr userRoiBtmLeftKnob = internalViewerNode[i]->getKnobByName(kViewerInstanceParamUserRoIBottomLeft); userRoiBtmLeftKnob->linkTo(_imp->userRoIBtmLeftKnob.lock()); KnobIPtr userRoiSizeKnob = internalViewerNode[i]->getKnobByName(kViewerInstanceParamUserRoISize); userRoiSizeKnob->linkTo(_imp->userRoISizeKnob.lock()); KnobIPtr clipToFormatKnob = internalViewerNode[i]->getKnobByName(kViewerInstanceParamClipToFormat); clipToFormatKnob->linkTo(_imp->clipToFormatButtonKnob.lock()); // A ViewerNode is composed of 2 ViewerProcess nodes but it only has 1 layer and 1 alpha channel choices. // We thus disable the refreshing of the menu from the 2nd ViewerProcess node. if (i == 1) { ViewerInstancePtr instance = internalViewerNode[i]->isEffectViewerInstance(); instance->setRefreshLayerAndAlphaChoiceEnabled(false); } } Q_EMIT internalViewerCreated(); } // createViewerProcessNode
void DSMoveKeysAndNodesCommand::moveSelection(double dt) { /* The view is going to get MANY update() calls since every knob change will trigger a computeNodeRange() in DopeSheetView We explicitly disable update on the dopesheet view and re-enable it afterwards. */ DopeSheetView* view = _model->getDopesheetView(); view->setUpdatesEnabled(false); for (NodesWList::iterator khIt = _allDifferentNodes.begin(); khIt != _allDifferentNodes.end(); ++khIt) { NodePtr node = khIt->lock(); if (!node) { continue; } node->getEffectInstance()->beginChanges(); } //////////Handle selected keyframes for (DSKeyPtrList::iterator it = _keys.begin(); it != _keys.end(); ++it) { const DSKeyPtr& selectedKey = (*it); DSKnobPtr knobContext = selectedKey->context.lock(); if (!knobContext) { continue; } KnobIPtr knob = knobContext->getKnobGui()->getKnob(); knob->moveValueAtTime(eCurveChangeReasonDopeSheet, selectedKey->key.getTime(), ViewIdx(0), knobContext->getDimension(), dt, 0, &selectedKey->key); } ////////////Handle selected nodes for (std::vector<DSNodePtr >::iterator it = _nodes.begin(); it != _nodes.end(); ++it) { DopeSheetItemType type = (*it)->getItemType(); if (type == eDopeSheetItemTypeReader) { moveReader( (*it)->getInternalNode(), dt ); } else if (type == eDopeSheetItemTypeFrameRange) { moveFrameRange( (*it)->getInternalNode(), dt ); } else if (type == eDopeSheetItemTypeTimeOffset) { moveTimeOffset( (*it)->getInternalNode(), dt ); } else if (type == eDopeSheetItemTypeGroup) { moveGroupNode(_model, (*it)->getInternalNode(), dt); } } for (NodesWList::const_iterator khIt = _allDifferentNodes.begin(); khIt != _allDifferentNodes.end(); ++khIt) { NodePtr node = khIt->lock(); if (!node) { continue; } node->getEffectInstance()->endChanges(); } view->setUpdatesEnabled(true); _model->refreshSelectionBboxAndRedrawView(); } // DSMoveKeysAndNodesCommand::moveSelection
void MultipleKnobEditsUndoCommand::undo() { assert( !knobs.empty() ); KnobHolderPtr holder = knobs.begin()->first.lock()->getHolder(); if (holder) { holder->beginChanges(); } for (ParamsMap::iterator it = knobs.begin(); it != knobs.end(); ++it) { KnobIPtr knob = it->first.lock(); if (!knob) { continue; } if (it->second.empty()) { continue; } // All knobs must belong to the same node! assert(knob->getHolder() == holder); KnobIntBasePtr isInt = toKnobIntBase(knob); KnobBoolBasePtr isBool = toKnobBoolBase(knob); KnobDoubleBasePtr isDouble = toKnobDoubleBase(knob); KnobStringBasePtr isString = toKnobStringBase(knob); bool hasChanged = false; std::list<ValueToSet>::iterator next = it->second.begin(); ++next; if (it->second.size() > 1) { // block knobChanged handler for this knob until the last change so we don't clutter the main-thread with useless action calls knob->blockValueChanges(); } for (std::list<ValueToSet>::reverse_iterator it2 = it->second.rbegin(); it2 != it->second.rend(); ++it2) { if (next == it->second.end() && it->second.size() > 1) { // Re-enable knobChanged for the last change on this knob knob->unblockValueChanges(); } // If we added a keyframe (due to auto-keying or not) remove it if (it2->setValueRetCode == eValueChangedReturnCodeKeyframeAdded) { knob->deleteValueAtTime(it2->time, it2->view, it2->dimension, eValueChangedReasonUserEdited); } int nDims = knob->getNDimensions(); std::list<ViewIdx> allViews = knob->getViewsList(); if (it2->dimension.isAll()) { for (int i = 0; i < nDims; ++i) { if (it2->view.isAll()) { for (std::list<ViewIdx>::const_iterator it3 = allViews.begin(); it3!=allViews.end(); ++it3) { hasChanged |= setOldValueForDimView(isInt, isBool, isDouble, isString, it2->reason, it2->setKeyFrame, it2->time, hasChanged, it2->setValueRetCode, DimIdx(i), *it3, it2->oldValues) != eValueChangedReturnCodeNothingChanged; } } else { ViewIdx view_i = knob->getViewIdxFromGetSpec(ViewGetSpec(it2->view)); hasChanged |= setOldValueForDimView(isInt, isBool, isDouble, isString, it2->reason, it2->setKeyFrame, it2->time, hasChanged, it2->setValueRetCode, DimIdx(i), view_i, it2->oldValues) != eValueChangedReturnCodeNothingChanged; } } } else { if (it2->view.isAll()) { for (std::list<ViewIdx>::const_iterator it3 = allViews.begin(); it3!=allViews.end(); ++it3) { hasChanged |= setOldValueForDimView(isInt, isBool, isDouble, isString, it2->reason, it2->setKeyFrame, it2->time, hasChanged, it2->setValueRetCode, DimIdx(it2->dimension), *it3, it2->oldValues) != eValueChangedReturnCodeNothingChanged; } } else { ViewIdx view_i = knob->getViewIdxFromGetSpec(ViewGetSpec(it2->view)); hasChanged |= setOldValueForDimView(isInt, isBool, isDouble, isString, it2->reason, it2->setKeyFrame, it2->time, hasChanged, it2->setValueRetCode, DimIdx(it2->dimension), view_i, it2->oldValues) != eValueChangedReturnCodeNothingChanged; } } if (next != it->second.end()) { ++next; } } } // for all knobs if (holder) { holder->endChanges(); } } // MultipleKnobEditsUndoCommand::undo
EditNodeViewerContextDialog::EditNodeViewerContextDialog(const KnobIPtr& knob, QWidget* parent) : QDialog(parent) , _imp(new EditNodeViewerContextDialogPrivate(knob)) { setWindowTitle(tr("Edit %1 viewer interface").arg(QString::fromUtf8(knob->getName().c_str()))); _imp->vLayout = new QVBoxLayout(this); _imp->vLayout->setContentsMargins(0, 0, TO_DPIX(15), 0); _imp->mainContainer = new QWidget(this); _imp->mainLayout = new QFormLayout(_imp->mainContainer); _imp->mainLayout->setLabelAlignment(Qt::AlignVCenter | Qt::AlignRight); _imp->mainLayout->setFormAlignment(Qt::AlignVCenter | Qt::AlignLeft); _imp->mainLayout->setSpacing(TO_DPIX(3)); _imp->mainLayout->setContentsMargins(0, 0, TO_DPIX(15), 0); _imp->vLayout->addWidget(_imp->mainContainer); if (knob->isUserKnob()) { QWidget* rowContainer = new QWidget(this); QHBoxLayout* rowLayout = new QHBoxLayout(rowContainer); rowLayout->setContentsMargins(0, 0, 0, 0); _imp->viewerUILabelLabel = new Label(tr("Viewer Interface Label:"), this); _imp->viewerUILabelEdit = new LineEdit(rowContainer); QString labelTooltip = NATRON_NAMESPACE::convertFromPlainText(tr("The text label of the parameter that will appear in its viewer interface"), NATRON_NAMESPACE::WhiteSpaceNormal); _imp->viewerUILabelEdit->setToolTip(labelTooltip); _imp->viewerUILabelLabel->setToolTip(labelTooltip); if (knob) { _imp->viewerUILabelEdit->setText( QString::fromUtf8( knob->getInViewerContextLabel().c_str() ) ); } rowLayout->addWidget(_imp->viewerUILabelEdit); rowLayout->addStretch(); _imp->mainLayout->addRow(_imp->viewerUILabelLabel, rowContainer); } KnobButtonPtr isButtonKnob = toKnobButton(knob); if (knob->isUserKnob()) { QWidget* rowContainer = new QWidget(this); QHBoxLayout* rowLayout = new QHBoxLayout(rowContainer); rowLayout->setContentsMargins(0, 0, 0, 0); QString text; if (isButtonKnob) { text = tr("Button Checked Icon:"); } else { text = tr("Icon label:"); } QString tooltip; if (isButtonKnob) { tooltip = NATRON_NAMESPACE::convertFromPlainText(tr("The icon of the button when checked"), NATRON_NAMESPACE::WhiteSpaceNormal); } else { tooltip = NATRON_NAMESPACE::convertFromPlainText(tr("This icon will be used instead of the text label"), NATRON_NAMESPACE::WhiteSpaceNormal); } _imp->checkedIconLabel = new Label(text, this); _imp->checkedIconLineEdit = new LineEdit(rowContainer); _imp->checkedIconLineEdit->setToolTip(tooltip); _imp->checkedIconLabel->setToolTip(tooltip); _imp->checkedIconLineEdit->setText( QString::fromUtf8( knob->getInViewerContextIconFilePath(true).c_str() ) ); rowLayout->addWidget(_imp->checkedIconLineEdit); rowLayout->addStretch(); _imp->mainLayout->addRow(_imp->checkedIconLabel, rowContainer); } if (isButtonKnob && knob->isUserKnob()) { QWidget* rowContainer = new QWidget(this); QHBoxLayout* rowLayout = new QHBoxLayout(rowContainer); rowLayout->setContentsMargins(0, 0, 0, 0); QString text; text = tr("Button Unchecked Icon:"); QString tooltip; tooltip = NATRON_NAMESPACE::convertFromPlainText(tr("The icon of the button when unchecked"), NATRON_NAMESPACE::WhiteSpaceNormal); _imp->uncheckedIconLabel = new Label(text, this); _imp->uncheckedIconLineEdit = new LineEdit(rowContainer); _imp->uncheckedIconLineEdit->setToolTip(tooltip); _imp->uncheckedIconLabel->setToolTip(tooltip); _imp->uncheckedIconLineEdit->setText( QString::fromUtf8( knob->getInViewerContextIconFilePath(false).c_str() ) ); rowLayout->addWidget(_imp->uncheckedIconLineEdit); rowLayout->addStretch(); _imp->mainLayout->addRow(_imp->uncheckedIconLabel, rowContainer); } { QWidget* rowContainer = new QWidget(this); QHBoxLayout* rowLayout = new QHBoxLayout(rowContainer); rowLayout->setContentsMargins(0, 0, 0, 0); QString text = tr("Layout Type:"); QString tooltip = NATRON_NAMESPACE::convertFromPlainText(tr("The layout type for this parameter"), NATRON_NAMESPACE::WhiteSpaceNormal); _imp->layoutTypeLabel = new Label(text, this); _imp->layoutTypeChoice = new ComboBox(rowContainer); _imp->layoutTypeLabel->setToolTip(tooltip); _imp->layoutTypeChoice->setToolTip(tooltip); _imp->layoutTypeChoice->addItem(tr("Spacing (px)"), QIcon(), QKeySequence(), tr("The spacing in pixels to add after the parameter")); _imp->layoutTypeChoice->addItem(tr("Separator"), QIcon(), QKeySequence(), tr("A vertical line will be added after the parameter")); _imp->layoutTypeChoice->addItem(tr("Stretch After"), QIcon(), QKeySequence(), tr("The layout will be stretched between this parameter and the next")); _imp->layoutTypeChoice->addItem(tr("New Line"), QIcon(), QKeySequence(), tr("A new line will be added after this parameter")); ViewerContextLayoutTypeEnum type = knob->getInViewerContextLayoutType(); _imp->layoutTypeChoice->setCurrentIndex_no_emit((int)type); QObject::connect(_imp->layoutTypeChoice, SIGNAL(currentIndexChanged(int)), this, SLOT(onLayoutTypeChoiceChanged(int))); rowLayout->addWidget(_imp->layoutTypeChoice); _imp->itemSpacingSpinbox = new SpinBox(rowContainer, SpinBox::eSpinBoxTypeInt); _imp->itemSpacingSpinbox->setMinimum(0); _imp->itemSpacingSpinbox->setValue(_imp->knob->getInViewerContextItemSpacing()); _imp->itemSpacingSpinbox->setVisible(_imp->layoutTypeChoice->activeIndex() == 0); _imp->itemSpacingSpinbox->setToolTip(NATRON_NAMESPACE::convertFromPlainText(tr("The spacing in pixels to add after the parameter"), NATRON_NAMESPACE::WhiteSpaceNormal)); rowLayout->addWidget(_imp->itemSpacingSpinbox); rowLayout->addStretch(); _imp->mainLayout->addRow(_imp->layoutTypeLabel, rowContainer); } { QWidget* rowContainer = new QWidget(this); QHBoxLayout* rowLayout = new QHBoxLayout(rowContainer); rowLayout->setContentsMargins(0, 0, 0, 0); QString text = tr("Hidden:"); QString tooltip = NATRON_NAMESPACE::convertFromPlainText(tr("When checked, the parameter will be hidden from the viewer interface"), NATRON_NAMESPACE::WhiteSpaceNormal); _imp->hiddenLabel = new Label(text, this); _imp->hiddenCheckbox = new AnimatedCheckBox(rowContainer); _imp->hiddenLabel->setToolTip(tooltip); _imp->hiddenCheckbox->setToolTip(tooltip); _imp->hiddenCheckbox->setChecked(knob->getInViewerContextSecret()); rowLayout->addWidget(_imp->hiddenCheckbox); rowLayout->addStretch(); _imp->mainLayout->addRow(_imp->hiddenLabel, rowContainer); } /* if (isButtonKnob) { QWidget* rowContainer = new QWidget(this); QHBoxLayout* rowLayout = new QHBoxLayout(rowContainer); rowLayout->setContentsMargins(0, 0, 0, 0); QString text = tr("Add to Shortcut Editor:"); QString tooltip = GuiUtils::convertFromPlainText(tr("When checked, the parameter can be attributed a shortcut from the Shortcut Editor"), Qt::WhiteSpaceNormal); _imp->addToShortcutEditorLabel = new Label(text, this); _imp->addToShortcutEditorCheckbox = new AnimatedCheckBox(rowContainer); _imp->addToShortcutEditorLabel->setToolTip(tooltip); _imp->addToShortcutEditorCheckbox->setToolTip(tooltip); _imp->addToShortcutEditorCheckbox->setChecked(knob->getInViewerContextHasShortcut()); rowLayout->addWidget(_imp->addToShortcutEditorCheckbox); rowLayout->addStretch(); _imp->mainLayout->addRow(_imp->addToShortcutEditorLabel, rowContainer); }*/ QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::StandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel), Qt::Horizontal, this); QObject::connect( buttons, SIGNAL(rejected()), this, SLOT(reject()) ); QObject::connect( buttons, SIGNAL(accepted()), this, SLOT(onOkClicked()) ); _imp->vLayout->addWidget(buttons); }
void RestoreDefaultsCommand::redo() { KnobIPtr first = _knobs.front().lock(); AppInstancePtr app; KnobHolderPtr holder = first->getHolder(); EffectInstancePtr isEffect = toEffectInstance(holder); if (holder) { app = holder->getApp(); holder->beginChanges(); } // First reset all knobs values, this will not call instanceChanged action for (std::list<KnobIWPtr >::iterator it = _knobs.begin(); it != _knobs.end(); ++it) { KnobIPtr itKnob = it->lock(); if (!itKnob) { continue; } if ( itKnob->getHolder() ) { itKnob->getHolder()->beginChanges(); } itKnob->resetToDefaultValue(_targetDim, _targetView); if ( itKnob->getHolder() ) { itKnob->getHolder()->endChanges(true); } } // 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<KnobIWPtr >::iterator it = _knobs.begin(); it != _knobs.end(); ++it) { KnobIPtr itKnob = it->lock(); if (!itKnob) { continue; } if ( itKnob->getHolder() ) { itKnob->getHolder()->onKnobValueChanged_public(itKnob, eValueChangedReasonRestoreDefault, time, ViewIdx(0), true); } } if ( holder && holder->getApp() ) { holder->endChanges(); } if ( first->getHolder() ) { if ( first->getHolder()->getApp() ) { first->getHolder()->getApp()->redrawAllViewers(); } } } // RestoreDefaultsCommand::redo
void MultipleKnobEditsUndoCommand::redo() { // The first time, everything is handled within setValue/setValueAtTime already if (!firstRedoCalled) { firstRedoCalled = true; return; } assert( !knobs.empty() ); KnobHolderPtr holder = knobs.begin()->first.lock()->getHolder(); // Make sure we get a single evaluation if (holder) { holder->beginChanges(); } for (ParamsMap::iterator it = knobs.begin(); it != knobs.end(); ++it) { KnobIPtr knob = it->first.lock(); if (!knob) { continue; } if (it->second.empty()) { continue; } // All knobs must belong to the same node! assert(knob->getHolder() == holder); KnobIntBasePtr isInt = toKnobIntBase(knob); KnobBoolBasePtr isBool = toKnobBoolBase(knob); KnobDoubleBasePtr isDouble = toKnobDoubleBase(knob); KnobStringBasePtr isString = toKnobStringBase(knob); bool hasChanged = false; std::list<ValueToSet>::iterator next = it->second.begin(); ++next; if (it->second.size() > 1) { // block knobChanged handler for this knob until the last change so we don't clutter the main-thread with useless action calls knob->blockValueChanges(); } for (std::list<ValueToSet>::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) { if (next == it->second.end() && it->second.size() > 1) { // Re-enable knobChanged for the last change on this knob knob->unblockValueChanges(); } if (it2->setKeyFrame) { if (isInt) { it2->setValueRetCode = isInt->setValueAtTime(it2->time, it2->newValue.toInt(), it2->view, it2->dimension, it2->reason, 0, hasChanged); } else if (isBool) { it2->setValueRetCode = isBool->setValueAtTime(it2->time, it2->newValue.toBool(), it2->view, it2->dimension, it2->reason, 0, hasChanged); } else if (isDouble) { it2->setValueRetCode = isDouble->setValueAtTime(it2->time, it2->newValue.toDouble(), it2->view, it2->dimension, it2->reason, 0, hasChanged); } else if (isString) { it2->setValueRetCode = isString->setValueAtTime(it2->time, it2->newValue.toString().toStdString(), it2->view, it2->dimension, it2->reason, 0, hasChanged); } else { assert(false); } } else { if (isInt) { it2->setValueRetCode = isInt->setValue(it2->newValue.toInt(), it2->view, it2->dimension, it2->reason, 0, hasChanged); } else if (isBool) { it2->setValueRetCode = isBool->setValue(it2->newValue.toBool(), it2->view, it2->dimension, it2->reason, 0, hasChanged); } else if (isDouble) { it2->setValueRetCode = isDouble->setValue(it2->newValue.toDouble(), it2->view, it2->dimension, it2->reason, 0, hasChanged); } else if (isString) { it2->setValueRetCode = isString->setValue(it2->newValue.toString().toStdString(), it2->view, it2->dimension, it2->reason, 0, hasChanged); } else { assert(false); } } hasChanged |= it2->setValueRetCode != eValueChangedReturnCodeNothingChanged; if (next != it->second.end()) { ++next; } } } if (holder) { holder->endChanges(); } } // redo
void PasteKnobClipBoardUndoCommand::copyFrom(const SERIALIZATION_NAMESPACE::KnobSerializationPtr& serializedKnob, const KnobIPtr& fromKnob, bool isRedo) { KnobIPtr internalKnob = _imp->knob.lock(); if (!internalKnob) { return; } // Get the target type KnobIntBasePtr isInt = toKnobIntBase( internalKnob ); KnobBoolBasePtr isBool = toKnobBoolBase( internalKnob ); KnobDoubleBasePtr isDouble = toKnobDoubleBase( internalKnob ); KnobStringBasePtr isString = toKnobStringBase( internalKnob ); // Get view names std::vector<std::string> projectViewNames; if (internalKnob->getHolder() && internalKnob->getHolder()->getApp()) { projectViewNames = internalKnob->getHolder()->getApp()->getProject()->getProjectViewNames(); } // group changes under the same evaluation internalKnob->beginChanges(); std::list<ViewIdx> targetKnobViews = internalKnob->getViewsList(); StringAnimationManagerPtr fromAnimString; if (fromKnob) { fromAnimString = fromKnob->getStringAnimation(); } for (std::list<ViewIdx>::const_iterator it = targetKnobViews.begin(); it != targetKnobViews.end(); ++it) { if ( ( !_imp->targetView.isAll()) && ( *it != _imp->targetView) ) { continue; } // If dimensions are folded, expand them when linking if (_imp->targetDimension.isAll() && !internalKnob->getAllDimensionsVisible(*it)) { internalKnob->setAllDimensionsVisible(*it, true); } for (int i = 0; i < internalKnob->getNDimensions(); ++i) { if ( ( !_imp->targetDimension.isAll()) && ( i != _imp->targetDimension) ) { continue; } ViewIdx fromView; DimIdx fromDim; if ( !_imp->targetDimension.all() && !_imp->fromDimension.isAll() ) { fromDim = DimIdx(_imp->fromDimension); } else { // If the source knob dimension is all or target dimension is all copy dimension to dimension respectively fromDim = DimIdx(i); } if ( !_imp->targetView.isAll() && !_imp->fromView.isAll() ) { fromView = ViewIdx(_imp->fromView); } else { // If the source knob view is all or target view is all copy view to view respectively fromView = *it; } switch (_imp->type) { case eKnobClipBoardTypeCopyAnim: { std::string fromViewName; if (fromView >= 0 && fromView < (int)projectViewNames.size()) { fromViewName = projectViewNames[_imp->fromView]; } else { fromViewName = "Main"; } SERIALIZATION_NAMESPACE::KnobSerialization::PerViewValueSerializationMap::const_iterator foundFromView = serializedKnob->_values.find(fromViewName); if (foundFromView == serializedKnob->_values.end()) { continue; } if (fromDim < 0 || fromDim >= (int) foundFromView->second.size()) { continue; } // Read the curve from the clipboard CurvePtr fromCurve(new Curve()); if (!foundFromView->second[_imp->fromDimension]._animationCurve.keys.empty()) { fromCurve->fromSerialization(foundFromView->second[_imp->fromDimension]._animationCurve); } internalKnob->cloneCurve(*it, DimIdx(i), *fromCurve, 0 /*offset*/, 0 /*range*/, fromAnimString.get()); break; } case eKnobClipBoardTypeCopyValue: { std::string fromViewName; if (fromView >= 0 && fromView < (int)projectViewNames.size()) { fromViewName = projectViewNames[_imp->fromView]; } else { fromViewName = "Main"; } SERIALIZATION_NAMESPACE::KnobSerialization::PerViewValueSerializationMap::const_iterator foundFromView = serializedKnob->_values.find(fromViewName); if (foundFromView == serializedKnob->_values.end()) { continue; } if (fromDim < 0 || fromDim >= (int) foundFromView->second.size()) { continue; } internalKnob->restoreValueFromSerialization(foundFromView->second[fromDim], DimIdx(i), *it); break; } case eKnobClipBoardTypeCopyLink: { if (isRedo) { internalKnob->slaveTo(fromKnob, DimIdx(i), fromDim, *it, fromView); } else { internalKnob->unSlave(DimIdx(i), *it, false /*copyState*/); } break; } case eKnobClipBoardTypeCopyExpressionLink: case eKnobClipBoardTypeCopyExpressionMultCurveLink: { if (isRedo) { std::string expression = makeLinkExpression(projectViewNames, internalKnob, _imp->type == eKnobClipBoardTypeCopyExpressionMultCurveLink, fromKnob, _imp->fromDimension, _imp->fromView, _imp->targetDimension, _imp->targetView); const bool hasRetVar = false; try { // Don't fail if exception is invalid, it should have been tested prior to creating an undo/redo command, otherwise user is going // to hit CTRL-Z and nothing will happen internalKnob->setExpression(DimIdx(i), *it, expression, hasRetVar, /*failIfInvalid*/ false); } catch (...) { } } else { // !isRedo internalKnob->clearExpression(DimIdx(i), *it, true); } // isRedo break; } }; // switch } // for all dimensions } // for all views internalKnob->endChanges(); } // redo
void NodeAnim::initialize(AnimatedItemTypeEnum nodeType) { _imp->nodeType = nodeType; NodePtr internalNode = getNodeGui()->getNode(); AnimationModuleBasePtr model = getModel(); NodeAnimPtr thisShared = shared_from_this(); _imp->nameItem = new QTreeWidgetItem; _imp->nameItem->setData(0, QT_ROLE_CONTEXT_ITEM_POINTER, qVariantFromValue((void*)thisShared.get())); _imp->nameItem->setText( 0, QString::fromUtf8( internalNode->getLabel().c_str() ) ); _imp->nameItem->setData(0, QT_ROLE_CONTEXT_TYPE, nodeType); _imp->nameItem->setData(0, QT_ROLE_CONTEXT_IS_ANIMATED, true); _imp->nameItem->setExpanded(true); int nCols = getModel()->getTreeColumnsCount(); if (nCols > ANIMATION_MODULE_TREE_VIEW_COL_VISIBLE) { _imp->nameItem->setData(ANIMATION_MODULE_TREE_VIEW_COL_VISIBLE, QT_ROLE_CONTEXT_ITEM_VISIBLE, QVariant(true)); _imp->nameItem->setIcon(ANIMATION_MODULE_TREE_VIEW_COL_VISIBLE, model->getItemVisibilityIcon(true)); } if (nCols > ANIMATION_MODULE_TREE_VIEW_COL_PLUGIN_ICON) { QString iconFilePath = QString::fromUtf8(internalNode->getPluginIconFilePath().c_str()); AnimationModuleTreeView::setItemIcon(iconFilePath, _imp->nameItem); } connect( internalNode.get(), SIGNAL(labelChanged(QString, QString)), this, SLOT(onNodeLabelChanged(QString, QString)) ); initializeKnobsAnim(); initializeTableItems(); // Connect signals/slots to knobs to compute the frame range AnimationModulePtr animModel = toAnimationModule(model); assert(animModel); if (nodeType == eAnimatedItemTypeCommon) { // Also connect the lifetime knob KnobIntPtr lifeTimeKnob = internalNode->getLifeTimeKnob(); if (lifeTimeKnob) { connect( lifeTimeKnob->getSignalSlotHandler().get(), SIGNAL(mustRefreshKnobGui(ViewSetSpec,DimSpec,ValueChangedReasonEnum)), this, SLOT(onFrameRangeKnobChanged()) ); } } else if (nodeType == eAnimatedItemTypeReader) { // The dopesheet view must refresh if the user set some values in the settings panel // so we connect some signals/slots KnobIPtr lastFrameKnob = internalNode->getKnobByName(kReaderParamNameLastFrame); if (!lastFrameKnob) { return; } boost::shared_ptr<KnobSignalSlotHandler> lastFrameKnobHandler = lastFrameKnob->getSignalSlotHandler(); assert(lastFrameKnob); boost::shared_ptr<KnobSignalSlotHandler> startingTimeKnob = internalNode->getKnobByName(kReaderParamNameStartingTime)->getSignalSlotHandler(); assert(startingTimeKnob); connect( lastFrameKnobHandler.get(), SIGNAL(mustRefreshKnobGui(ViewSetSpec,DimSpec,ValueChangedReasonEnum)), this, SLOT(onFrameRangeKnobChanged()) ); connect( startingTimeKnob.get(), SIGNAL(mustRefreshKnobGui(ViewSetSpec,DimSpec,ValueChangedReasonEnum)), this, SLOT(onFrameRangeKnobChanged()) ); // We don't make the connection for the first frame knob, because the // starting time is updated when it's modified. Thus we avoid two // refreshes of the view. } else if (nodeType == eAnimatedItemTypeRetime) { boost::shared_ptr<KnobSignalSlotHandler> speedKnob = internalNode->getKnobByName(kRetimeParamNameSpeed)->getSignalSlotHandler(); assert(speedKnob); connect( speedKnob.get(), SIGNAL(mustRefreshKnobGui(ViewSetSpec,DimSpec,ValueChangedReasonEnum)), this, SLOT(onFrameRangeKnobChanged()) ); } else if (nodeType == eAnimatedItemTypeTimeOffset) { boost::shared_ptr<KnobSignalSlotHandler> timeOffsetKnob = internalNode->getKnobByName(kReaderParamNameTimeOffset)->getSignalSlotHandler(); assert(timeOffsetKnob); connect( timeOffsetKnob.get(), SIGNAL(mustRefreshKnobGui(ViewSetSpec,DimSpec,ValueChangedReasonEnum)), this, SLOT(onFrameRangeKnobChanged()) ); } else if (nodeType == eAnimatedItemTypeFrameRange) { boost::shared_ptr<KnobSignalSlotHandler> frameRangeKnob = internalNode->getKnobByName(kFrameRangeParamNameFrameRange)->getSignalSlotHandler(); assert(frameRangeKnob); connect( frameRangeKnob.get(), SIGNAL(mustRefreshKnobGui(ViewSetSpec,DimSpec,ValueChangedReasonEnum)), this, SLOT(onFrameRangeKnobChanged()) ); } refreshFrameRange(); } // initialize
bool DialogParamHolder::onKnobValueChanged(const KnobIPtr& k, ValueChangedReasonEnum reason, double time, ViewSetSpec view, bool originatedFromMainThread) { std::string callback; { QMutexLocker l(&_imp->paramChangedCBMutex); callback = _imp->paramChangedCB; } if ( !callback.empty() ) { bool userEdited = reason == eValueChangedReasonNatronGuiEdited || reason == eValueChangedReasonUserEdited; std::vector<std::string> args; std::string error; try { NATRON_PYTHON_NAMESPACE::getFunctionArguments(callback, &error, &args); } catch (const std::exception& e) { getApp()->appendToScriptEditor( std::string("Failed to run onParamChanged callback: ") + e.what() ); return false; } if ( !error.empty() ) { getApp()->appendToScriptEditor("Failed to run onParamChanged callback: " + error); return false; } std::string signatureError; signatureError.append("The param changed callback supports the following signature(s):\n"); signatureError.append("- callback(paramName,app,userEdited)"); if (args.size() != 3) { getApp()->appendToScriptEditor("Failed to run onParamChanged callback: " + signatureError); return false; } if ( ( (args[0] != "paramName") || (args[1] != "app") || (args[2] != "userEdited") ) ) { getApp()->appendToScriptEditor("Failed to run onParamChanged callback: " + signatureError); return false; } std::string appID = getApp()->getAppIDString(); std::stringstream ss; ss << callback << "(\"" << k->getName() << "\"," << appID << ","; if (userEdited) { ss << "True"; } else { ss << "False"; } ss << ")\n"; std::string script = ss.str(); std::string err; std::string output; if ( !NATRON_PYTHON_NAMESPACE::interpretPythonScript(script, &err, &output) ) { getApp()->appendToScriptEditor( tr("Failed to execute callback: %1").arg( QString::fromUtf8( err.c_str() ) ).toStdString() ); } else if ( !output.empty() ) { getApp()->appendToScriptEditor(output); } return true; } _imp->widget->onKnobValueChanged(k, reason, time, view, originatedFromMainThread); return false; } // DialogParamHolder::onKnobValueChanged