void ImageView::insertConverter( Gaffer::NodePtr converter ) { PlugPtr converterInput = converter->getChild<Plug>( "in" ); if( !converterInput ) { throw IECore::Exception( "Converter has no Plug named \"in\"" ); } ImagePlugPtr converterOutput = converter->getChild<ImagePlug>( "out" ); if( !converterOutput ) { throw IECore::Exception( "Converter has no ImagePlug named \"out\"" ); } PlugPtr newInput = converterInput->createCounterpart( "in", Plug::In ); setChild( "in", newInput ); NodePtr preprocessor = getPreprocessor<Node>(); Plug::OutputContainer outputsToRestore = preprocessor->getChild<ImagePlug>( "in" )->outputs(); PlugPtr newPreprocessorInput = converterInput->createCounterpart( "in", Plug::In ); preprocessor->setChild( "in", newPreprocessorInput ); newPreprocessorInput->setInput( newInput ); preprocessor->setChild( "__converter", converter ); converterInput->setInput( newPreprocessorInput ); for( Plug::OutputContainer::const_iterator it = outputsToRestore.begin(), eIt = outputsToRestore.end(); it != eIt; ++it ) { (*it)->setInput( converterOutput ); } }
void Expression::addPlug( ValuePlug *parentPlug, const std::string &plugPath ) { Node *p = parent<Node>(); if( !p ) { throw IECore::Exception( "No parent" ); } ValuePlug *plug = p->descendant<ValuePlug>( plugPath ); if( !plug ) { throw IECore::Exception( boost::str( boost::format( "Plug \"%s\" does not exist" ) % plugPath ) ); } PlugPtr childPlug = plug->createCounterpart( "p0", parentPlug->direction() ); childPlug->setFlags( Plug::Dynamic, true ); parentPlug->addChild( childPlug ); if( childPlug->direction() == Plug::In ) { childPlug->setInput( plug ); } else { plug->setInput( childPlug ); } }
void Expression::updatePlug( ValuePlug *parentPlug, size_t childIndex, ValuePlug *plug ) { if( parentPlug->children().size() > childIndex ) { // See if we can reuse the existing plug Plug *existingChildPlug = parentPlug->getChild<Plug>( childIndex ); if( ( existingChildPlug->direction() == Plug::In && existingChildPlug->getInput<Plug>() == plug ) || ( existingChildPlug->direction() == Plug::Out && plug->getInput<Plug>() == existingChildPlug ) ) { return; } } // Existing plug not OK, so we need to create one. First we must remove all // plugs from childIndex onwards, so that when we add the new plug it gets // the right index. removeChildren( parentPlug, childIndex ); // Finally we can add the plug we need. PlugPtr childPlug = plug->createCounterpart( "p0", parentPlug->direction() ); childPlug->setFlags( Plug::Dynamic, true ); parentPlug->addChild( childPlug ); if( childPlug->direction() == Plug::In ) { childPlug->setInput( plug ); } else { plug->setInput( childPlug ); } }
Plug *Box::promotePlug( Plug *descendantPlug ) { validatePromotability( descendantPlug, /* throwExceptions = */ true ); PlugPtr externalPlug = descendantPlug->createCounterpart( promotedCounterpartName( descendantPlug ), descendantPlug->direction() ); externalPlug->setFlags( Plug::Dynamic, true ); // Flags are not automatically propagated to the children of compound plugs, // so we need to do that ourselves. We don't want to propagate them to the // children of plug types which create the children themselves during // construction though, hence the typeId checks for the base classes // which add no children during construction. I'm not sure this approach is // necessarily the best - the alternative would be to set everything dynamic // unconditionally and then implement Serialiser::childNeedsConstruction() // for types like CompoundNumericPlug that create children in their constructors. const Gaffer::TypeId compoundTypes[] = { PlugTypeId, ValuePlugTypeId, CompoundPlugTypeId, ArrayPlugTypeId }; const Gaffer::TypeId *compoundTypesEnd = compoundTypes + 4; if( find( compoundTypes, compoundTypesEnd, (Gaffer::TypeId)externalPlug->typeId() ) != compoundTypesEnd ) { for( RecursivePlugIterator it( externalPlug.get() ); it != it.end(); ++it ) { (*it)->setFlags( Plug::Dynamic, true ); if( find( compoundTypes, compoundTypesEnd, (Gaffer::TypeId)(*it)->typeId() ) != compoundTypesEnd ) { it.prune(); } } } if( externalPlug->direction() == Plug::In ) { if( ValuePlug *externalValuePlug = IECore::runTimeCast<ValuePlug>( externalPlug.get() ) ) { externalValuePlug->setFrom( static_cast<ValuePlug *>( descendantPlug ) ); } } // Copy over the metadata for nodule position, so the nodule appears in the expected spot. // This must be done before parenting the new plug, as the nodule is created from childAddedSignal(). copyMetadata( descendantPlug, externalPlug.get() ); addChild( externalPlug ); if( externalPlug->direction() == Plug::In ) { descendantPlug->setInput( externalPlug ); } else { externalPlug->setInput( descendantPlug ); } return externalPlug.get(); }
static void loadCoshaderParameter( Gaffer::CompoundPlug *parametersPlug, const std::string &name ) { Plug *existingPlug = parametersPlug->getChild<Plug>( name ); if( existingPlug && existingPlug->typeId() == Plug::staticTypeId() ) { return; } PlugPtr plug = new Plug( name, Plug::In, Plug::Default | Plug::Dynamic ); if( existingPlug && existingPlug->getInput<Plug>() ) { plug->setInput( existingPlug->getInput<Plug>() ); } parametersPlug->setChild( name, plug ); }
void Expression::updatePlugs( const std::string &dstPlugPath, std::vector<std::string> &srcPlugPaths ) { Node *p = parent<Node>(); // if the expression was invalid, remove our plugs if( !dstPlugPath.size() ) { Plug *in = getChild<Plug>( "in" ); if( in ) { removeChild( in ); } Plug *out = getChild<Plug>( "out" ); if( out ) { removeChild( out ); } return; } // otherwise try to create connections to the plugs the expression wants ValuePlug *dstPlug = p->descendant<ValuePlug>( dstPlugPath ); if( !dstPlug ) { throw IECore::Exception( boost::str( boost::format( "Destination plug \"%s\" does not exist" ) % dstPlugPath ) ); } CompoundPlugPtr inPlugs = new CompoundPlug( "in", Plug::In, Plug::Default | Plug::Dynamic ); setChild( "in", inPlugs ); for( std::vector<std::string>::const_iterator it = srcPlugPaths.begin(); it!=srcPlugPaths.end(); it++ ) { ValuePlug *srcPlug = p->descendant<ValuePlug>( *it ); if( !srcPlug ) { throw IECore::Exception( boost::str( boost::format( "Source plug \"%s\" does not exist" ) % *it ) ); } PlugPtr inPlug = srcPlug->createCounterpart( "plug", Plug::In ); inPlugs->addChild( inPlug ); inPlug->setInput( srcPlug ); } PlugPtr outPlug = dstPlug->createCounterpart( "out", Plug::Out ); setChild( "out", outPlug ); dstPlug->setInput( outPlug ); }
void Plug::parentChanging( Gaffer::GraphComponent *newParent ) { if( getFlags( Dynamic ) ) { // When a dynamic plug is removed from a node, we // need to propagate dirtiness based on that. We // must call DependencyNode::affects() now, while the // plug is still a child of the node, but we push // scope so that the emission of plugDirtiedSignal() // is deferred until parentChanged() when the operation // is complete. It is essential that exceptions don't // prevent us getting to parentChanged() where we pop // scope, so propateDirtiness() takes care of handling // exceptions thrown by DependencyNode::affects(). pushDirtyPropagationScope(); if( node() ) { propagateDirtinessForParentChange( this ); } } // This method manages the connections between plugs when // additional child plugs are added or removed. We only // want to react to these changes when they are first made - // after this our own actions will have been recorded in the // undo buffer anyway and will be undone/redone automatically. // So here we early out if we're in such an Undo/Redo situation. ScriptNode *scriptNode = ancestor<ScriptNode>(); scriptNode = scriptNode ? scriptNode : ( newParent ? newParent->ancestor<ScriptNode>() : NULL ); if( scriptNode && ( scriptNode->currentActionStage() == Action::Undo || scriptNode->currentActionStage() == Action::Redo ) ) { return; } // Now we can take the actions we need to based on the new parent // we're getting. if( !newParent ) { // We're losing our parent - remove all our connections first. // this must be done here (rather than in a parentChangedSignal() slot) // because we need a current parent for the operation to be undoable. setInput( 0 ); // Deal with outputs whose parent is an output of our parent. // For these we actually remove the destination plug itself, // so that the parent plugs may remain connected. if( Plug *oldParent = parent<Plug>() ) { for( OutputContainer::iterator it = m_outputs.begin(); it!=m_outputs.end(); ) { Plug *output = *it++; Plug *outputParent = output->parent<Plug>(); if( outputParent && outputParent->getInput<Plug>() == oldParent ) { // We're removing the child precisely so that the parent connection // remains valid, so we can block its updateInputFromChildInputs() call. assert( outputParent->m_skipNextUpdateInputFromChildInputs == false ); ScopedAssignment<bool> blocker( outputParent->m_skipNextUpdateInputFromChildInputs, true ); outputParent->removeChild( output ); } } } // Remove any remaining output connections. removeOutputs(); } else if( Plug *newParentPlug = IECore::runTimeCast<Plug>( newParent ) ) { // we're getting a new parent - update its input connection from // all the children including the pending one. newParentPlug->updateInputFromChildInputs( this ); // and add a new child plug to any of its outputs to maintain // the output connections. const OutputContainer &outputs = newParentPlug->outputs(); for( OutputContainer::const_iterator it = outputs.begin(), eIt = outputs.end(); it != eIt; ++it ) { Plug *output = *it; if( output->acceptsChild( this ) ) { PlugPtr outputChildPlug = createCounterpart( getName(), direction() ); { // We're adding the child so that the parent connection remains valid, // but the parent connection wouldn't be considered valid until the // child has both been added and had its input connected. We therefore // block the call to updateInputFromChildInputs() to keep the parent // connection intact. assert( output->m_skipNextUpdateInputFromChildInputs == false ); ScopedAssignment<bool> blocker( output->m_skipNextUpdateInputFromChildInputs, true ); output->addChild( outputChildPlug ); } outputChildPlug->setInput( this, /* setChildInputs = */ true, /* updateParentInput = */ false ); } } } }
BoxPtr Box::create( Node *parent, const Set *childNodes ) { BoxPtr result = new Box; parent->addChild( result ); // it's pretty natural to call this function passing childNodes == ScriptNode::selection(). // unfortunately nodes will be removed from the selection as we reparent // them, so we have to make a copy of childNodes so our iteration isn't befuddled by // the changing contents. we can use this opportunity to weed out anything in childNodes // which isn't a direct child of parent though. StandardSetPtr verifiedChildNodes = new StandardSet(); for( NodeIterator nodeIt( parent ); nodeIt != nodeIt.end(); nodeIt++ ) { if( childNodes->contains( nodeIt->get() ) ) { verifiedChildNodes->add( *nodeIt ); } } // when a node we're putting in the box has connections to // a node remaining outside, we need to reroute the connection // via an intermediate plug on the box. this mapping maps input // plugs (be they internal or external) to intermediate input plugs. typedef std::pair<const Plug *, Plug *> PlugPair; typedef std::map<const Plug *, Plug *> PlugMap; PlugMap plugMap; for( size_t i = 0, e = verifiedChildNodes->size(); i < e; i++ ) { Node *childNode = static_cast<Node *>( verifiedChildNodes->member( i ) ); // reroute any connections to external nodes for( RecursivePlugIterator plugIt( childNode ); plugIt != plugIt.end(); plugIt++ ) { Plug *plug = plugIt->get(); if( plug->direction() == Plug::In ) { Plug *input = plug->getInput<Plug>(); if( input && !verifiedChildNodes->contains( input->node() ) ) { PlugMap::const_iterator mapIt = plugMap.find( input ); if( mapIt == plugMap.end() ) { PlugPtr intermediateInput = plug->createCounterpart( result->promotedCounterpartName( plug ), Plug::In ); // we want intermediate inputs to appear on the same side of the node as the // equivalent internal plug, so we copy the relevant metadata over. copyMetadata( plug, intermediateInput.get() ); intermediateInput->setFlags( Plug::Dynamic, true ); result->addChild( intermediateInput ); intermediateInput->setInput( input ); mapIt = plugMap.insert( PlugPair( input, intermediateInput.get() ) ).first; } plug->setInput( mapIt->second ); plugIt.prune(); } } else { // take a copy of the outputs, because we might be modifying the // original as we iterate. Plug::OutputContainer outputs = plug->outputs(); if( !outputs.empty() ) { typedef Plug::OutputContainer::const_iterator OutputIterator; for( OutputIterator oIt = outputs.begin(), eIt = outputs.end(); oIt != eIt; oIt++ ) { Plug *output = *oIt; const Node *outputNode = output->node(); if( outputNode->parent<Node>() == parent && !verifiedChildNodes->contains( outputNode ) ) { PlugMap::const_iterator mapIt = plugMap.find( plug ); if( mapIt == plugMap.end() ) { PlugPtr intermediateOutput = plug->createCounterpart( result->promotedCounterpartName( plug ), Plug::Out ); copyMetadata( plug, intermediateOutput.get() ); intermediateOutput->setFlags( Plug::Dynamic, true ); result->addChild( intermediateOutput ); intermediateOutput->setInput( plug ); mapIt = plugMap.insert( PlugPair( plug, intermediateOutput.get() ) ).first; } output->setInput( mapIt->second ); } } plugIt.prune(); } } } // reparent the child under the Box. it's important that we do this after adding the intermediate // input plugs, so that when they are serialised and reloaded, the inputs to the box are set before // the inputs to the nodes inside the box - see GafferSceneTest.ShaderAssignmentTest.testAssignShaderFromOutsideBox // for a test case highlighting this necessity. result->addChild( childNode ); } return result; }