2
$\begingroup$

I'm wondering what the best way is to handle this case:

I want a change of one Propertygroup in a Collectionproperty, to affect the others inside that CollectionProperty. Say if an EnumProperty in the Propertygroup is set to a specific option, all other members of that collection should have their enum be set back to default. Essentially only one member of the collection is allowed to have this option.

import bpy
from bpy.types import Operator, PropertyGroup, UIList
from bpy.props import IntProperty, EnumProperty, CollectionProperty, PointerProperty

class NodesPanel(bpy.types.Panel):
    bl_label = "Nodes Panel"
    bl_idname = "OBJECT_PT_nodes"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"
        
    def draw(self, context):
        layout = self.layout
        col = layout.column()
        col.operator("object.addcustomnode")
        col.template_list(
                "Nodes_UL_List", "",
                context.object.nodes_list, "collection", context.object.nodes_list, "list_index")

class OBJECT_OT_addnode(Operator):
    bl_idname = "object.addcustomnode"
    bl_label = "Add Node"
    
    def execute(self,context):
        obj = context.object
        obj.nodes_list.collection.add()
        return {'FINISHED'}

class NodeProp(PropertyGroup):
    type : EnumProperty(
        items=(
            ('CHILD', "Child", ""),
            ('PARENT', "Parent", ""),
        )
    )
    val : IntProperty()
    
class NodesList(PropertyGroup):
    collection : CollectionProperty(
        name = "Nodes",
        type = NodeProp)
    list_index : IntProperty()
        
class Nodes_UL_List(UIList):
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): 
        if self.layout_type in {'DEFAULT', 'COMPACT'}:
            layout.prop(item, "type", text="Type")
        elif self.layout_type in {'GRID'}:
            layout.alignment = 'CENTER'
            layout.prop(item, "type", text="Type")

             
classes = (
        OBJECT_OT_addnode,
        NodeProp, 
        Nodes_UL_List,
        NodesList,
        NodesPanel
        )
        
def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.Object.nodes_list = PointerProperty(type= NodesList)
if __name__ == "__main__":
    register()

teh above example is a simplified representation. I would want there to be only one Node per object that can ever be set to "Parent", it should force all others back to child.

I've read about callbacks on adding to the collection but this goes deeper.

I'm assuming I could do something contrived with set, get or update functions on the enumproperty, and in one of those functions derive the selected object from context to find the collectionproperty, iterate over it to fix the others. That seems a bit roundabout, so perhaps I'm missing something?

$\endgroup$
3
  • $\begingroup$ you can get the collection the item is from with self.id_data.nodes_list.collection in the callback $\endgroup$
    – Gorgious
    Feb 8 at 16:34
  • $\begingroup$ Thanks Gorgious, You've got my back again! To confirm: you're talking about 'self' in the context of a callback in NodeProp (like set or get)? Where id_data points back to the original object the whole collection is on ? $\endgroup$
    – Xoliul
    Feb 8 at 18:33
  • $\begingroup$ yup, see docs.blender.org/api/current/… and docs.blender.org/api/current/… I suggest you use the update callback, its less overhead in that case imo, and also be careful not to cause an infinite recursion by filtering out self in the collection items $\endgroup$
    – Gorgious
    Feb 8 at 19:43

1 Answer 1

1
$\begingroup$

You could do something like this in your property group definition :

def update_node_prop(self, context):
    obj = self.id_data
    nodes_list = obj.nodes_list
    collection = nodes_list.collection
    for node_prop in collection:
        if node_prop == self:
            continue
        if self.type == "PARENT":
            node_prop.type = "CHILD"


class NodeProp(PropertyGroup):
    type : EnumProperty(
        items=(
            ('CHILD', "Child", ""),
            ('PARENT', "Parent", ""),
        ),
        update=update_node_prop,
    )
    val : IntProperty()
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .