@@ -58,6 +58,65 @@ class ExecMode(Enum):
5858 LOCAL = 1
5959 EXTERN = 2
6060
61+ class ForLoopData (BaseObject ):
62+ """
63+ """
64+
65+ def __init__ (self , parentNode = None , connectedAttribute = None , parent = None ):
66+ super (ForLoopData , self ).__init__ (parent )
67+ self ._countForLoop = 0
68+ self ._iterations = ListModel (parent = self ) # list of nodes for each iteration
69+ self ._parentNode = parentNode # parent node
70+ self .connectedAttribute = connectedAttribute # attribute connected to the ForLoop node from parent node
71+
72+ def update (self , currentNode = None ):
73+ # set the connectedAttribute
74+ forLoopAttribute = None
75+ if currentNode is not None :
76+ for attr in currentNode ._attributes :
77+ if attr .isInput and attr .isLink :
78+ forLoopAttribute = currentNode ._attributes .indexOf (attr )
79+ srcAttr = attr .getLinkParam ()
80+ # If the srcAttr is a ListAttribute, it means that the node is in a ForLoop
81+ if isinstance (srcAttr .root , ListAttribute ) and srcAttr .type == attr .type :
82+ self .connectedAttribute = srcAttr .root
83+ self ._parentNode = srcAttr .root .node
84+ break
85+
86+ # set the countForLoop
87+ if self .connectedAttribute is not None :
88+ self ._countForLoop = self ._parentNode ._forLoopData ._countForLoop + 1
89+ if self .connectedAttribute .isInput :
90+ self ._countForLoop -= 1 if self ._countForLoop > 1 else 1
91+
92+ # set the iterations by creating iteration nodes for each connected attribute value and will add them to the core graph and not the ui one
93+ for i in range (len (self .connectedAttribute .value )):
94+ # name of the iteration node
95+ name = "{}_{}" .format (currentNode .name , i )
96+ # check if node already exists
97+ if name not in [n .name for n in self ._parentNode .graph .nodes ]:
98+ iterationNode = IterationNode (currentNode , i , forLoopAttribute )
99+ self ._parentNode .graph .addNode (iterationNode , iterationNode .name )
100+ else :
101+ # find node by name
102+ iterationNode = self ._parentNode .graph .node (name )
103+ iterationNode ._updateChunks ()
104+
105+ self ._iterations .append (iterationNode )
106+
107+ print ("parent internal folder: " , currentNode .internalFolder )
108+ self .parentNodeChanged .emit ()
109+ self .iterationsChanged .emit ()
110+ self .countForLoopChanged .emit ()
111+
112+ countForLoopChanged = Signal ()
113+ countForLoop = Property (int , lambda self : self ._countForLoop , notify = countForLoopChanged )
114+ iterationsChanged = Signal ()
115+ iterations = Property (Variant , lambda self : self ._iterations , notify = iterationsChanged )
116+ parentNodeChanged = Signal ()
117+ parentNode = Property (Variant , lambda self : self ._parentNode , notify = parentNodeChanged )
118+
119+
61120
62121class StatusData (BaseObject ):
63122 """
@@ -513,6 +572,7 @@ def __init__(self, nodeType, position=None, parent=None, uids=None, **kwargs):
513572 self ._locked = False
514573 self ._duplicates = ListModel (parent = self ) # list of nodes with the same uid
515574 self ._hasDuplicates = False
575+ self ._forLoopData = ForLoopData ()
516576
517577 self .globalStatusChanged .connect (self .updateDuplicatesStatusAndLocked )
518578
@@ -979,6 +1039,10 @@ def updateInternals(self, cacheDir=None):
9791039 }
9801040 self ._computeUids ()
9811041 self ._buildCmdVars ()
1042+
1043+ # try to update for loopdata as node is created
1044+ self ._forLoopData .update (self )
1045+
9821046 if self .nodeDesc :
9831047 self .nodeDesc .postUpdate (self )
9841048 # Notify internal folder change if needed
@@ -1321,23 +1385,11 @@ def has3DOutputAttribute(self):
13211385 return True
13221386 return False
13231387
1324- def _countForLoop (self ):
1388+ def getForLoopData (self ):
13251389 """
1326- Return in how many ForLoop nodes this node is .
1390+ Return the ForLoopData of the node.
13271391 """
1328- count = 0
1329- # Access to the input attributes of the node
1330- for attr in self ._attributes :
1331- if attr .isInput and attr .isLink :
1332- # Access to the attribute connected to the input attribute
1333- srcAttr = attr .getLinkParam ()
1334- # If the srcAttr is a ListAttribute, it means that the node is in a ForLoop
1335- if isinstance (srcAttr .root , ListAttribute ) and srcAttr .type == attr .type :
1336- # Access the countForLoop of the node of the ListAttribute
1337- count = srcAttr .root .node .countForLoop + 1
1338- if srcAttr .root .isInput :
1339- count = count - 1 if count > 1 else 1
1340- return count
1392+ return self ._forLoopData
13411393
13421394
13431395
@@ -1392,8 +1444,8 @@ def _countForLoop(self):
13921444 hasSequenceOutput = Property (bool , hasSequenceOutputAttribute , notify = outputAttrEnabledChanged )
13931445 has3DOutput = Property (bool , has3DOutputAttribute , notify = outputAttrEnabledChanged )
13941446
1395- countForLoopChanged = Signal ()
1396- countForLoop = Property (int , _countForLoop , notify = countForLoopChanged )
1447+ forLoopDataChanged = Signal ()
1448+ forLoopData = Property (Variant , getForLoopData , notify = forLoopDataChanged )
13971449
13981450class Node (BaseNode ):
13991451 """
@@ -1552,7 +1604,39 @@ def _updateChunks(self):
15521604 else :
15531605 self ._chunks [0 ].range = desc .Range ()
15541606
1607+ class IterationNode (Node ):
1608+ """
1609+ A node that is not added to the graph but used to process a specific iteration of a ForLoop node.
1610+ """
1611+ def __init__ (self , node , iteration , attributeIndex ):
1612+ super (IterationNode , self ).__init__ (node .nodeType , parent = node .graph )
1613+ self ._name = f"{ node .name } _{ iteration } "
1614+ self ._originalNode = node
1615+
1616+ # By recognizing the connected attribute linked to the ForLoop node, we can set the value of the iteration
1617+ # attribute to the current iteration value
1618+ self ._attributes .at (attributeIndex ).value = node ._forLoopData .connectedAttribute .at (iteration ).value
1619+
1620+ print ("Attributes of IterationNode: " , [attr .value for attr in self ._attributes .values ()])
1621+
1622+ # Internal folder should correspond to each possibility of uid
1623+ # print(self._uids)
1624+ # self._buildCmdVars()
1625+ # self._computeUids()
1626+ # print("after: ", self._uids)
1627+ print (self .nodeType )
1628+ print (self ._cmdVars )
1629+ print (self ._internalFolder )
15551630
1631+ def _updateChunks (self ):
1632+ # find node in graph
1633+ node = self .graph .node (self ._originalNode .name )
1634+ # Setting chunks to the same chunks as the parent node
1635+ self ._chunks .setObjectList ([NodeChunk (self , desc .Range ()) for _ in node ._chunks ])
1636+ for c in self ._chunks :
1637+ c .statusChanged .connect (self .globalStatusChanged )
1638+
1639+ self .chunksChanged .emit ()
15561640class CompatibilityIssue (Enum ):
15571641 """
15581642 Enum describing compatibility issues when deserializing a Node.
0 commit comments