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
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 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 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 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
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 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