2
$\begingroup$

First of all sorry, I don't have coding background and maybe this question is not formulated in a proper way.

Basically I want to have control over the number of variables (properties) of an add-on. Normally, if I want to have an input in an add-on I would have a property (for example my_float) and then:

row= layout.row()
row.prop(mytool, "my_float_4")

Then this value can be easily changed:

enter image description here

Now, if I want to link the number of this inputs to a parameter of the scene (let's say, one per object of the scene or one per Geometry Nodes input of an object), because I have to declare the properties in a class a priori, I can't have this flexibility.

Is there a way to avoid this problem?

I made this code, in this case for having a property per GN input, but this DOESN´T mean that I want to control the GN tree with with the add-on, I just want to match the number of inputs with the number of properties.

import bpy
from bpy.props import (BoolProperty,
                       PointerProperty,
                       )
from bpy.types import (Panel,
                       Operator,
                       PropertyGroup,
                       )
import bmesh
from math import fabs,sin,cos,sqrt,atan2,pi
import numpy as np
import mathutils

class MyPropertiesTool(bpy.types.PropertyGroup):
    
    
    my_float :bpy.props.FloatProperty (name = "Float" )
    
    
    
class ADDONNAME_PT_main_panel(bpy.types.Panel):
    bl_label= "Test"
    bl_idname = "TEst"
    bl_space_type = 'VIEW_3D'
    bl_region_type= 'UI'
    bl_category= 'Test'
    
    def draw(self,context):
        layout = self.layout
        scene= context.scene
        mytool= scene.my_tool

        row= layout.row()
        row.prop_search(scene, "Source", scene, "objects")      
        
        obj = scene.Source 
        modifiers = []
        for modifier in obj.modifiers:
            if modifier.type == 'NODES':
                modifiers.append(modifier)
                

        modifier = modifiers[0]
        
        for input in modifier.node_group.inputs:
              
             row= layout.row()
             row.label (text=input.name )                
             row.label() 
             # HERE IS WHERE I WANT TO ADD THE VALUES, SO I WOULD NEED SOMETHING LIKE THIS LINKED TO 
             #THE INPUTS OF THE GEOMETRY NODES SET UP
     
             #row.prop(mytool, "my_float", slider= True)
                   
classes = [ADDONNAME_PT_main_panel,MyPropertiesTool]
 
def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

    bpy.types.Scene.my_tool = PointerProperty(type=MyPropertiesTool)
    bpy.types.Scene.prop = PointerProperty(type=bpy.types.Object)

    bpy.types.Scene.Source = PointerProperty(type=bpy.types.Object)
def unregister():
    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)
    del bpy.types.Scene.my_tool
    del bpy.types.Object.Source

 
if __name__ == "__main__":
    register() 

   
$\endgroup$
4
  • 2
    $\begingroup$ You may find this similar $\endgroup$
    – Ratt
    Commented Jan 25, 2023 at 12:48
  • $\begingroup$ You may be able to get something out of that too I've recently added this in a personal addon as a qol when I'm working on GN trees i.sstatic.net/PrDg7.png $\endgroup$
    – Gorgious
    Commented Jan 25, 2023 at 17:15
  • $\begingroup$ Thanks, this definitely helps. I edited the question because I feel that I didn't explain myself very well, sorry about that. What I want is a controllable number of properties, no a GN input controler. $\endgroup$
    – Artichoke
    Commented Jan 25, 2023 at 18:12
  • $\begingroup$ I'm not sure if i understand your meaning. Are you looking for a controller that can control a number of variables at once? If so, you can write a update function for your FloatProperty. $\endgroup$ Commented Jan 30, 2023 at 13:19

2 Answers 2

1
$\begingroup$

You could change your loop to:

for input in modifier.node_group.inputs:    
     row= layout.row()
     row.label (text=input.name )                
     row.label() 
     row.prop(modifier, '["' + input.identifier + '"]')

If you want the properties to be somewhere else, you can make them as custom properties. Pretty much anything in Blender can have custom properties. You can do that in a loop as well:

import bpy

for i in range(1, 10):
    bpy.context.window_manager["some_prop_" + str(i).zfill(3)] = 0
    
print( list(bpy.context.window_manager.keys()))

It doesn't need to be window_manager could be any type of datablock: objects, nodes, scenes, materials and so on.

$\endgroup$
3
  • $\begingroup$ Thanks. But how could I store the data, so later I can use it in an operator? (That´s the main problem that I need to solve) $\endgroup$
    – Artichoke
    Commented Feb 2, 2023 at 13:12
  • $\begingroup$ What do you mean? It's already stored in the modifier. $\endgroup$ Commented Feb 2, 2023 at 13:26
  • $\begingroup$ I updated the answer. Is that what you are after? $\endgroup$ Commented Feb 2, 2023 at 13:43
1
$\begingroup$

In your code, you are creating a property group called MyPropertiesTool which holds a single property my_float. This property is meant to be used in the UI as a float input.

If you want to have a different number of my_float inputs in your UI depending on the number of inputs in the Geometry Nodes setup, you can use a loop and dynamically create new properties in the property group for each Geometry Nodes input.

One way to do this is to store the dynamic properties in a dictionary and add a getter and setter method to the property group to access the values in the dictionary. Here's an example of how you can modify your code:

class MyPropertiesTool(bpy.types.PropertyGroup):
    dynamic_props = {}
    
    def get_prop(self, name):
        return self.dynamic_props.get(name, 0.0)
    
    def set_prop(self, value, name):
        self.dynamic_props[name] = value

class ADDONNAME_PT_main_panel(bpy.types.Panel):
    bl_label= "Test"
    bl_idname = "TEst"
    bl_space_type = 'VIEW_3D'
    bl_region_type= 'UI'
    bl_category= 'Test'
    
    def draw(self,context):
        layout = self.layout
        scene= context.scene
        mytool= scene.my_tool
        
        row= layout.row()
        row.prop_search(scene, "Source", scene, "objects")      
        
        obj = scene.Source 
        modifiers = []
        for modifier in obj.modifiers:
            if modifier.type == 'NODES':
                modifiers.append(modifier)
                
        modifier = modifiers[0]
        
        for input in modifier.node_group.inputs:
              
             row= layout.row()
             row.label (text=input.name )                
             row.label() 
             row.prop(mytool, "dynamic_props[\"" + input.name + "\"]", text="", slider=True)
                   
classes = [ADDONNAME_PT_main_panel,MyPropertiesTool]
 
def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

    bpy.types.Scene.my_tool = PointerProperty(type=MyPropertiesTool)
    bpy.types.Scene.prop = PointerProperty(type=bpy.types.Object)

    bpy.types.Scene.Source = PointerProperty(type=bpy.types.Object)
def unregister():
    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)
    del bpy.types.Scene.my_tool
    del bpy.types.Object.Source

 
if __name__ == "__main__":
    register()
$\endgroup$
1
  • $\begingroup$ Thanks! And if I would need to access one of those properties later on on? Like for example in an operator, how could I do that? $\endgroup$
    – Artichoke
    Commented Feb 3, 2023 at 8:30

You must log in to answer this question.

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