void NodeAnimPrivate::computeTimeOffsetRange() { NodeGuiPtr nodeUI = nodeGui.lock(); NodePtr node = nodeUI->getNode(); if (!node) { return; } // Retrieve nearest reader useful values { AnimationModulePtr isAnimModel = toAnimationModule(model.lock()); NodeAnimPtr nearestReader = isAnimModel->getNearestReaderInternal(node); if (nearestReader) { // Retrieve the time offset values KnobIntBasePtr timeOffsetKnob = toKnobIntBase(node->getKnobByName(kReaderParamNameTimeOffset)); assert(timeOffsetKnob); int timeOffsetValue = timeOffsetKnob->getValue(); frameRange = nearestReader->getFrameRange(); frameRange.min += timeOffsetValue; frameRange.max += timeOffsetValue; } } } // computeTimeOffsetRange
void NodeAnimPrivate::refreshParentContainerRange() { NodeGuiPtr nodeUI = nodeGui.lock(); NodePtr node = nodeUI->getNode(); if (!node) { return; } AnimationModulePtr isAnimModule = toAnimationModule(model.lock()); assert(isAnimModule); // If inside a group, refresh the group { NodeGroupPtr parentGroup = toNodeGroup( node->getGroup() ); NodeAnimPtr parentGroupNodeAnim; if (parentGroup) { parentGroupNodeAnim = isAnimModule->findNodeAnim( parentGroup->getNode() ); } if (parentGroupNodeAnim) { parentGroupNodeAnim->refreshFrameRange(); } } // if modified by a time node, refresh its frame range as well { NodeAnimPtr isConnectedToTimeNode = isAnimModule->getNearestTimeNodeFromOutputsInternal(node); if (isConnectedToTimeNode) { isConnectedToTimeNode->refreshFrameRange(); } } } // refreshParentContainerRange
void AnimationModule::addNode(const NodeGuiPtr& nodeGui) { // Check if it already exists for (std::list<NodeAnimPtr>::const_iterator it = _imp->nodes.begin(); it != _imp->nodes.end(); ++it) { if ((*it)->getNodeGui() == nodeGui) { (*it)->refreshVisibility(); return; } } // Determinate the node type // It will be useful to identify and sort tree items AnimatedItemTypeEnum nodeType = eAnimatedItemTypeCommon; NodePtr node = nodeGui->getNode(); assert(node && node->getGroup()); if ( !node || !node->getGroup() ) { return; } EffectInstancePtr effectInstance = node->getEffectInstance(); // Don't add an item for this node if it doesn't have any knob that may animate //if ( !getNodeCanAnimate(node) ) { // return; //} std::string pluginID = node->getPluginID(); NodeGroupPtr isGroup = toNodeGroup(effectInstance); if (effectInstance->isReader()) { nodeType = eAnimatedItemTypeReader; } else if (isGroup) { nodeType = eAnimatedItemTypeGroup; } else if (pluginID == PLUGINID_OFX_RETIME) { nodeType = eAnimatedItemTypeRetime; } else if (pluginID == PLUGINID_OFX_TIMEOFFSET) { nodeType = eAnimatedItemTypeTimeOffset; } else if (pluginID == PLUGINID_OFX_FRAMERANGE) { nodeType = eAnimatedItemTypeFrameRange; } // The NodeAnim should not be created if there's no settings panel. assert(nodeGui->getSettingPanel()); NodeAnimPtr anim(NodeAnim::create(toAnimationModule(shared_from_this()), nodeType, nodeGui) ); _imp->nodes.push_back(anim); Q_EMIT nodeAdded(anim); } // AnimationModule::addNode
void AnimationModuleViewPrivate::addMenuCurveEditorMenuOptions(Menu* menu) { Menu* fileMenu = new Menu(menu); //fileMenu->setFont( QFont(appFont,appFontSize) ); fileMenu->setTitle( tr("File") ); menu->addAction( fileMenu->menuAction() ); AnimationModulePtr isAnimModule = toAnimationModule(_model.lock()); Menu* predefMenu = 0; if (isAnimModule) { predefMenu = new Menu(menu); predefMenu->setTitle( tr("Predefined") ); menu->addAction( predefMenu->menuAction() ); } QAction* exportCurveToAsciiAction = new QAction(tr("Export curve to Ascii file..."), fileMenu); QObject::connect( exportCurveToAsciiAction, SIGNAL(triggered()), _publicInterface, SLOT(onExportCurveToAsciiActionTriggered()) ); fileMenu->addAction(exportCurveToAsciiAction); QAction* importCurveFromAsciiAction = new QAction(tr("Import curve from Ascii file..."), fileMenu); QObject::connect( importCurveFromAsciiAction, SIGNAL(triggered()), _publicInterface, SLOT(onImportCurveFromAsciiActionTriggered()) ); fileMenu->addAction(importCurveFromAsciiAction); if (predefMenu) { QAction* loop = new QAction(tr("Loop"), menu); QObject::connect( loop, SIGNAL(triggered()), _publicInterface, SLOT(onApplyLoopExpressionOnSelectedCurveActionTriggered()) ); predefMenu->addAction(loop); QAction* reverse = new QAction(tr("Reverse"), menu); QObject::connect( reverse, SIGNAL(triggered()), _publicInterface, SLOT(onApplyReverseExpressionOnSelectedCurveActionTriggered()) ); predefMenu->addAction(reverse); QAction* negate = new QAction(tr("Negate"), menu); QObject::connect( negate, SIGNAL(triggered()), _publicInterface, SLOT(onApplyNegateExpressionOnSelectedCurveActionTriggered()) ); predefMenu->addAction(negate); } } // addMenuCurveEditorMenuOptions
void NodeAnimPrivate::computeGroupRange() { NodeGuiPtr nodeUI = nodeGui.lock(); NodePtr node = nodeUI->getNode(); if (!node) { return; } AnimationModulePtr isAnimModel = toAnimationModule(model.lock()); if (!isAnimModel) { return; } NodeGroupPtr nodegroup = node->isEffectNodeGroup(); assert(nodegroup); if (!nodegroup) { return; } AnimationModuleTreeView* treeView = isAnimModel->getEditor()->getTreeView(); NodesList nodes = nodegroup->getNodes(); std::set<double> times; for (NodesList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) { NodeAnimPtr childAnim = isAnimModel->findNodeAnim(*it); if (!childAnim) { continue; } if (!treeView->isItemVisibleRecursive(childAnim->getTreeItem())) { continue; } childAnim->refreshFrameRange(); RangeD childRange = childAnim->getFrameRange(); times.insert(childRange.min); times.insert(childRange.max); // Also check the child knobs keyframes NodeGuiPtr childGui = childAnim->getNodeGui(); const KnobsVec &knobs = childGui->getNode()->getKnobs(); for (KnobsVec::const_iterator it2 = knobs.begin(); it2 != knobs.end(); ++it2) { if ( !(*it2)->isAnimationEnabled() || !(*it2)->hasAnimation() ) { continue; } else { // For each dimension and for each split view get the first/last keyframe (if any) int nDims = (*it2)->getNDimensions(); std::list<ViewIdx> views = (*it2)->getViewsList(); for (std::list<ViewIdx>::const_iterator it3 = views.begin(); it3 != views.end(); ++it3) { for (int i = 0; i < nDims; ++i) { CurvePtr curve = (*it2)->getCurve(*it3, DimIdx(i)); if (!curve) { continue; } int nKeys = curve->getKeyFramesCount(); if (nKeys > 0) { KeyFrame k; if (curve->getKeyFrameWithIndex(0, &k)) { times.insert( k.getTime() ); } if (curve->getKeyFrameWithIndex(nKeys - 1, &k)) { times.insert( k.getTime() ); } } } } } } // for all knobs } // for all children nodes if (times.size() <= 1) { frameRange.min = 0; frameRange.max = 0; } else { frameRange.min = *times.begin(); frameRange.max = *times.rbegin(); } } // computeGroupRange
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