0
$\begingroup$

Alright, this might be one of the more complicated questions I've asked on here. However, due to my lack of experience coding in Blender, it might be a more simple solution than I realize.

Summary:

I'm coding an addon that allows the user to select one camera from the scene, up to three light objects from the scene, and up to three mesh objects from the scene. At first, there is no option to add another light object or mesh object, but once an option has been selected the operator button pops up.

enter image description here enter image description here

I want the operator button that pops up to increase the count of the associated pointer so that it will create another pointer for that category. I begin to run into issues when I try to reference the variable "num_lights" or "num_layers" from either operator in the "ADDON_PT_main_panel" class, though. I feel like it should be easy to do that but I can't get it to work nor can I find any helpful information on Google.

Question 1:

How can I reference the variables from "ADDON_OT_add_layer" and "ADDON_OT_add_light" in the "ADDON_PT_main_panel" class?

Question 1a:

Am I using the correct script to update the "ADDON_PT_main_panel" class once either of the operators has been executed?

I know this is kind of a loaded question but if anyone could help me figure this out I would really appreciate it!

My Code:

class ADDON_OT_add_light(bpy.types.Operator):
    
# Operator that increases "num_lights" by one every time
# that it's clicked as long as "num_lights" is less than 3,
# then reloads the script to update the variable within ADDON_PT_main_panel.    
    
    bl_label = ''
    bl_idname = "add_light.operator"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'addon'
    
    num_lights = 1
    
    # Increases count for number of light sources by 1 when clicked until it hits the limit.
    # of 3 light sources.
    def execute(self, context):
        if num_lights < 3:
            num_lights += 1
        return num_lights
        bpy.ops.script.reload() #<-- I believe this the code to update/reload a script...?


class ADDON_OT_add_layer(bpy.types.Operator):
    
# Operator that increases "num_layers" by one every time
# that it's clicked as long as "num_layers" is less than 3,
# then reloads the script to update the variable within ADDON_PT_main_panel.

    bl_label = ''
    bl_idname = "add_layer.operator"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'addon'
    
    num_layers = 1
    
    # Increases count for number of base layers by 1 when clicked until it hits the limit.
    # of 3 base layers.
    def execute(self, context):
        if num_layers < 3:
            num_layers += 1
        return num_layers
        bpy.ops.script.reload() #<-- I believe this the code to update/reload a script...?
        
class ADDON_PT_main_panel(bpy.types.Panel):
    bl_label = "addon"
    bl_idname = "addon_PT_main_panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "addon"

    def draw(self, context):
        layout = self.layout
        scene = context.scene
        mytool = scene.my_tool
        
        base_layers = #<-- Insert reference to "num_layers" from ADDON_OT_add_layer here.
        light_sources = #<-- Insert reference to "num_lights" from ADDON_OT_add_light here.
        
        layout.label(text= "Camera:")
        layout.prop(mytool, "camera_pointer")
        
        layout.label(text= "Light Source(s):")
        layout.prop(mytool, "lights_pointers")
        
        # Determines whether or not an option has been selected for "lights_pointers".
        light_pointer_status = str(bpy.context.scene.my_tool.lights_pointers)
        
        # If number of light sources is updated to 2, then add another "lights_pointers".
        if light_sources > 1:
            layout.prop(mytool, "lights_pointers")
            
        # If number of light sources is updated to 3, then add another "lights_pointers".
        if light_sources > 2:
            layout.prop(mytool, "lights_pointers")
        
        # Only allows a new light source to be added if a first option has been chosen.
        if light_pointer_status != 'None':
            layout.operator("add_light.operator", text= "New Light", icon= "PLUS")
        
        layout.label(text= "Base Layer Object(s):")
        layout.prop(mytool, "objects_pointers")
        
        # Determines whether or not an option has been selected for "layers_pointers".
        object_pointer_status = str(bpy.context.scene.my_tool.objects_pointers)
        
        # If number of base layers is updated to 2, then add another "objects_pointers".
        if base_layers > 1:
            layout.prop(mytool, "objects_pointers")
            
        # If number of base layers is updated to 3, then add another "objects_pointers".
        if base_layers > 2:
            layout.prop(mytool, "objects_pointers")

        # Only allows a new base layer to be added if a first option has been chosen.
        if object_pointer_status != 'None':
            layout.operator("add_layer.operator", text= "New Layer", icon= "PLUS")
            
classes = [ADDON_pointers, ADDON_OT_add_light, ADDON_OT_add_layer, ADDON_PT_main_panel]
 
def register():
    for cls in classes:
        bpy.utils.register_class(cls)
        bpy.types.Scene.my_tool = bpy.props.PointerProperty(type= ADDON_pointers)
 
def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)
        del bpy.types.Scene.my_tool
 
 
 
if __name__ == "__main__":
    register()
$\endgroup$

2 Answers 2

4
$\begingroup$

You shouldn't use global variables or reloading scripts.

First, you need to put all your state somewhere Blender can keep track of it. So you should handle the number of items just like the other properties, with an IntProperty. Here's an example with three object properties.


class ADDON_pointers(bpy.types.PropertyGroup):
    num_objects: bpy.props.IntProperty(
        name= "Number of Objects",
        description= "",
        min=0,
        max=3,
    )
    
    object0 : bpy.props.PointerProperty(
        name= "Object", 
        description= "",
        type= bpy.types.Object,   
    )

    object1 : bpy.props.PointerProperty(
        name= "Object", 
        description= "",
        type= bpy.types.Object,   
    )

    object2 : bpy.props.PointerProperty(
        name= "Object", 
        description= "",
        type= bpy.types.Object,   
    )

Let's add an operator to increase num_objects:


class ADDON_OT_add_object(bpy.types.Operator):    
    bl_label = ''
    bl_idname = "my_tool.add_object"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'addon'
    
    # poll returns True if the operator can be called now
    @classmethod
    def poll(cls, context):
        scene = context.scene
        if not scene: return False
        mytool = scene.my_tool
    
        # If already 3 objects, can't add any more
        if mytool.num_objects >= 3:
            return False
        
        # If the current slots are not all filled, can't add any more
        objs = [mytool.object0, mytool.object1, mytool.object2] 
        objs = objs[:mytool.num_objects]
        if not all(objs):
            return False
        
        return True
    
    def execute(self, context):
        context.scene.my_tool.num_objects += 1
        return {'FINISHED'}

Now the panel

class ADDON_PT_main_panel(bpy.types.Panel):
    bl_label = "addon"
    bl_idname = "ADDON_PT_main_panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "addon"

    def draw(self, context):
        layout = self.layout
        scene = context.scene
        mytool = scene.my_tool
        
        for i in range(mytool.num_objects):
            layout.prop(mytool, "object%d" % i)
        
        # Skip drawing the button if it can't be clicked
        if bpy.ops.my_tool.add_object.poll():
            layout.operator("my_tool.add_object", text= "New Object", icon= "PLUS")
$\endgroup$
1
  • $\begingroup$ Thank you so much! It worked, and I even created a second operator that removes a pointer using the same code, except I converted it to subtract 1 rather than add. You've definitely made my night a lot easier! $\endgroup$
    – leoprd
    Nov 9, 2021 at 22:50
3
$\begingroup$

Here's another answer: get rid of the variable for the number of objects and the button for adding a new slot. Instead just show all the slots up the last filled one, plus one more (up to a max of 3).

Simpler code, simpler UI.

class ADDON_PT_main_panel(bpy.types.Panel):
    bl_label = "addon"
    bl_idname = "ADDON_PT_main_panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "addon"

    def draw(self, context):
        layout = self.layout
        scene = context.scene
        mytool = scene.my_tool

        if mytool.object2: num_objects = 3
        elif mytool.object1: num_objects = 3
        elif mytool.object0: num_objects = 2
        else: num_objects = 1
        
        for i in range(num_objects):
            layout.prop(mytool, "object%d" % i)
$\endgroup$

You must log in to answer this question.

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