4
$\begingroup$

I'm building a Blender (2.75) plugin for our 3D engine (https://github.com/aerys/minko). So far so good.

One of the things I'd like to do is to mimic Unity's feature that scripts can be directly added to scene nodes in the editor. Such scripts properties can then be edited directly through a dynamic property inspector built by parsing the script public members.

I've already done what I think is the worst part: using libclang and the python bindings to parse my C++ headers and retrieve a list of the public properties (each property being a public getter/setter pair). I can use this list to generate a list of Blender properties like so:

def get_properties(self):
    if not self._props:
        c = self._get_minko_script_classes(self._clangSource.cursor)
        setters = self._get_class_setters(c[0])

        self._props = {}
        for name, set_type in setters.items():
            if set_type == 'bool':
                self._props[name] = bpy.props.BoolProperty(name=name)
            elif set_type == 'int':
                self._props[name] = bpy.props.IntProperty(name=name)
            elif set_type == 'minko::math::ivec2':
                self._props[name] = bpy.props.IntVectorProperty(name=name, size=2)
            elif set_type == 'minko::math::ivec3':
                self._props[name] = bpy.props.IntVectorProperty(name=name, size=3)
            elif set_type == 'minko::math::ivec4':
                self._props[name] = bpy.props.IntVectorProperty(name=name, size=4)
            elif set_type == 'float':
                self._props[name] = bpy.props.FloatProperty(name=name)
            elif set_type == 'minko::math::vec2':
                self._props[name] = bpy.props.FloatVectorProperty(name=name, size=2)
            elif set_type == 'minko::math::vec3':
                self._props[name] = bpy.props.FloatVectorProperty(name=name, size=3)
            elif set_type == 'minko::math::vec4':
                self._props[name] = bpy.props.FloatVectorProperty(name=name, size=4)
            elif set_type == 'std::string':
                self._props[name] = bpy.props.StringProperty(name=name)

    return self._props

Now I want to display those properties (self._props) in a panel. But Blender examples are all about "static" property definition, declaring properties as class members... I guess Python would let me create dynamic classes definitions. But it sounds hacky.

So my question is: how to pass this list of Blender *Property to the UI to display it properly in a Blender friendly way?

Thank you,

$\endgroup$
4
  • 1
    $\begingroup$ Is every type (set_type) repeatable? Are they globals, or may individual objects use any and any amount of these properties? bpy.props properties need to registered globally, e.g. on bpy.types.Scene, and will be available on every instance. For individual properties, ID props should be used instead, but there's not as much control UI-wise over them compared to bpy.props. $\endgroup$ – CodeManX Aug 15 '15 at 10:05
  • $\begingroup$ Each object/mesh will have it's own set of properties because each mesh will have its own set of scripts: I've already made a panel where the user can select a script file, and the code above is called in a AddNewScriptOperator. Now I want that operator to create the proper PropertyGroup/UI. What do you mean by "repeatable"? $\endgroup$ – Jean-Marc Le Roux Aug 15 '15 at 10:23
  • $\begingroup$ By repeatable I mean 0..n properties of type minko::math::ivec4 for instance per object (which would translate to bpy.props.CollectionProperty). It seems like you would need one property group class for every object, because they are all different. I would actually try to use ID properties instead, as they are much more suitable. $\endgroup$ – CodeManX Aug 16 '15 at 19:17
  • $\begingroup$ You may be interested in pynodes, there is a custom nodes template in blender's text editor. Luxblend uses pynodes. sverchok and animation nodes would be the largest projects using them, both have videos demoing what they can do. $\endgroup$ – sambler Aug 17 '15 at 11:16
3
$\begingroup$

Using Custom Properties (ID properties) works:

for key, key_type in props.items():
    context.active_object[MinkoScript.format_property_name(i, key)] = script.get_property_default_value(key)

In order to be able to iterate on a specific script properties to draw the panel, I also store the properties dict in an ID property:

context.active_object[MinkoScript.format_property_name(i, '$properties')] = props

Then in the panel:

for i in range(0, context.active_object['minko_num_scripts']):
    layout.label(
        context.active_object[MinkoScript.format_property_name(i, '$name')] + ':',
        icon='TEXT'
    )
    box = layout.box()
    script_id = 'minko_script_' + str(i)
    script_props = context.active_object[MinkoScript.format_property_name(i, '$properties')]
    keys = sorted(script_props.keys())
    for key in keys:
        row = box.row(True)
        col = row.column(True)
        col.label(key + ':')
        col = row.column(True)
        col.prop(
            context.active_object,
            '["' + MinkoScript.format_property_name(i, key) + '"]',
            text=''
        )
    row = box.row(True)
    row.operator(MinkoRemoveScriptOperator.bl_idname, text="Remove").script_id = i
    row.operator(MinkoReloadScriptOperator.bl_idname, text="Reload").script_id = i
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.