14
$\begingroup$

Iam searching for a method to get a EnumProperty by the type of the object (Lamp, Geo, Camera) thats selected in the viewport.

E.g. If the selected object is a lamp, it would be nice the enum dynamically adds new properties to the existing ones, like Energy and Color.

Here is my Code:

bl_info = {
    "name": "tester",
    "description": "",
    "author": "",
    "version": (0, 0, 1),
    "blender": (2, 7, 0),
    "location": "3D View > Toolbox",
    "warning": "", # used for warning icon and text in addons panel
    "wiki_url": "",
    "tracker_url": "",
    "category": "Test"
    }


import bpy
import re
import math
from mathutils import Vector
from math import pi

from bpy.types import Panel
from bpy.props import (StringProperty,
                       BoolProperty,
                       IntProperty,
                       FloatProperty,
                       FloatVectorProperty,
                       EnumProperty,
                       PointerProperty,
                       )
from bpy.types import (Operator,
                       AddonPreferences,
                       PropertyGroup,
                       )


# ------------------------------------------------------------------------
#    store properties in the active scene
# ------------------------------------------------------------------------

class mySettings(PropertyGroup):

    # apply values to LOC ROT SCL
    TransformationProperty_ = EnumProperty(
        name="Apply Data to:",
        description="Apply Data to attribute.",
        items=(('LOC', "Location", ""),
               ('ROT', "Rotation", ""),
               ('SCL', "Scale", "")),
        default='LOC',
        )


# ------------------------------------------------------------------------
#    myTool in objectmode
# ------------------------------------------------------------------------

class myTool_panel_objectMode:
    bl_label = "myTool"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    #bl_context = "objectmode"

    @classmethod
    def poll(self,context):
        #scene = context.scene
        return context.active_object is not None

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

        row = layout.row()
        col = layout.column(align=True)
        rowsub = col.row(align=True)
        rowsub.prop(mytool, "TransformationProperty_", text="")


# ------------------------------------------------------------------------
#     classes for new tab system since 2.7.0
# ------------------------------------------------------------------------

class myTool_ObjectMode(Panel, myTool_panel_objectMode):
    bl_category = "Test"
    bl_idname = "my_objectmode"
    bl_context = "objectmode"


# ------------------------------------------------------------------------
# register and unregister functions
# ------------------------------------------------------------------------

def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.myTool = PointerProperty(type=mySettings)

def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.Scene.myTool

if __name__ == "__main__":
    register()

Thanks in Advance,
Christian


Thanks for this great explanation CoDEmanX! Code works nicely and logic makes sense to me. Also thanks for your BTW - never thougt about Blender/Python conventions - nice to know.

For those who wants a multiple selection callback, Ive updated the code a bit:

bl_info = {
    "name": "tester",
    "description": "",
    "author": "",
    "version": (0, 0, 3),
    "blender": (2, 70, 0),
    "location": "3D View > Toolbox",
    "warning": "", # used for warning icon and text in addons panel
    "wiki_url": "",
    "tracker_url": "",
    "category": "Test"
}

import bpy
import re
import math
from mathutils import Vector
from math import pi

from bpy.props import (StringProperty,
                       BoolProperty,
                       IntProperty,
                       FloatProperty,
                       FloatVectorProperty,
                       EnumProperty,
                       PointerProperty,
                       )
from bpy.types import (Panel,
                       Operator,
                       AddonPreferences,
                       PropertyGroup,
                       )


# ------------------------------------------------------------------------------------------------
# get object type list
# ------------------------------------------------------------------------------------------------

def get_object_type_list(object_list):
    objectTypes = []
    for i in object_list:
        objectTypes.append(bpy.data.objects[i.name].type)

    return list(set(objectTypes))

# ------------------------------------------------------------------------
#    store properties in the active scene
# ------------------------------------------------------------------------

def my_settings_callback(scene, context):

    items = [
        ('LOC', "Location", ""),
        ('ROT', "Rotation", ""),
        ('SCL', "Scale", ""),
    ]

    # get selection
    selection = bpy.context.selected_objects

    # get selection type list
    selection_types = get_object_type_list(selection)

    if len(selection_types) == 1:

        # check for lamps
        if selection_types[0] == 'LAMP':
            items.append(('NRG', "Energy", ""))
            items.append(('COL', "Color", ""))

    return items


class MySettings(PropertyGroup):

    # apply values to LOC ROT SCL
    transform = EnumProperty(
        name="Apply Data to:",
        description="Apply Data to attribute.",
        items=my_settings_callback
        )


# ------------------------------------------------------------------------
#    myTool in objectmode
# ------------------------------------------------------------------------

class OBJECT_PT_my_panel(Panel):
    bl_idname = "OBJECT_PT_my_panel"
    bl_label = "My Panel"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_category = "TESTER"
    bl_context = "objectmode"

    @classmethod
    def poll(self,context):
        return context.object is not None

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

        layout.prop(mytool, "transform", text="")

        # print selected property
        print (mytool.transform)


# ------------------------------------------------------------------------
# register and unregister functions
# ------------------------------------------------------------------------

def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.my_tool = PointerProperty(type=MySettings)

def unregister():
    bpy.utils.unregister_module(__name__)
    del bpy.types.Scene.my_tool

if __name__ == "__main__":
    register()

Thanks again,
Christian

$\endgroup$

1 Answer 1

23
$\begingroup$

You can supply EnumProperty() with a callback function for the items-argument and create a list of tuples based on context:

bl_info = {
    "name": "tester",
    "description": "",
    "author": "",
    "version": (0, 0, 2),
    "blender": (2, 80, 0),
    "location": "3D View > Toolbox",
    "warning": "", # used for warning icon and text in addons panel
    "wiki_url": "",
    "tracker_url": "",
    "category": "Test"
}

import bpy
import re
import math
from mathutils import Vector
from math import pi

from bpy.props import (StringProperty,
                       BoolProperty,
                       IntProperty,
                       FloatProperty,
                       FloatVectorProperty,
                       EnumProperty,
                       PointerProperty,
                       )
from bpy.types import (Panel,
                       Operator,
                       AddonPreferences,
                       PropertyGroup,
                       )


# ------------------------------------------------------------------------
#    Scene Properties
# ------------------------------------------------------------------------

def my_settings_callback(scene, context):

    items = [
        ('LOC', "Location", ""),
        ('ROT', "Rotation", ""),
        ('SCL', "Scale", ""),
    ]

    ob = context.object
    if ob is not None:
        if ob.type == 'LIGHT':
            items.append(('NRG', "Energy", ""))
            items.append(('COL', "Color", ""))

    return items

class MySettings(PropertyGroup):

    # apply values to LOC ROT SCL
    transform : EnumProperty(
        name="Apply Data to:",
        description="Apply Data to attribute.",
        items=my_settings_callback
        )


# ------------------------------------------------------------------------
#    Panel in Object Mode
# ------------------------------------------------------------------------

class OBJECT_PT_my_panel(Panel):
    bl_label = "My Panel"
    bl_idname = "OBJECT_PT_custom_panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "UI"
    bl_category = "Tools"
    bl_context = "objectmode" 

    @classmethod
    def poll(self,context):
        return context.object is not None

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

        layout.prop(mytool, "transform", text="")


# ------------------------------------------------------------------------
#   Registration
# ------------------------------------------------------------------------

classes = (
    MySettings,
    OBJECT_PT_my_panel
)

def register():
    
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)
        
    bpy.types.Scene.my_tool = PointerProperty(type=MySettings)

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

if __name__ == "__main__":
    register()

Note that if you select a Lamp, set the property to e.g. Color and then select a non-lamp object, the enum will show no label in the panel, but return LOC (the first item) to a script. If you select a Lamp object again, it will return COL again!

You can not set a default item if a dynamic enum is used.

https://docs.blender.org/api/current/bpy.props.html#bpy.props.EnumProperty

BTW:

  • Your Blender version tuple is wrong, it needs to be (2, 80, 0)
  • You don't need an extra class to support vertical tabs
  • In unregister(), the del keyword is missing to remove the PointerProperty
  • Blender / Python conventions are to use snake_case for names like bl_idname, but CamelCase for e.g. classes (with capital first letter)
$\endgroup$
0

You must log in to answer this question.

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