2
$\begingroup$

The bl_context class variable defines what mode the drawn property appears in, e.g. bl_context=posemode makes whatever drawn via the draw method appear only in the pose mode. What if we want the property to appear in both objectmode and posemode, and what are the values for other modes, like: particle edit mode, vertex paint mode, sculpt mode?

EDIT: I'm setting up a panel for rigging, here's the full code:

import bpy

CUSTOM_CATEGORY = 'RIG OPTIONS'

class RigUI(bpy.types.Panel):
    bl_idname = 'POSE_PT_RigUI'
    bl_label = "Rig Controls"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_context = "posemode"
    bl_category = CUSTOM_CATEGORY

    #bones in use
    head = "head"
    neck = "neck_bone"

    hip = "hip"
    rib = "rib"


    shoulder_L = "shoulder.L"
    upper_arm_FK_L = "upper_arm_FK.L"
    forearm_FK_L = "forearm_FK.L"
    hand_FK_L = "hand_FK.L"


    shoulder_R = "shoulder.R"
    upper_arm_FK_R = "upper_arm_FK.R"
    forearm_FK_R= "forearm_FK.R"
    hand_FK_R = "hand_FK.R"


    thigh_FK_L = "thigh_FK.L"
    shin_FK_L = "shin_FK.L"
    foot_FK_L = "foot_FK.L"
    toe_FK_L = "toe_FK.L"


    thigh_FK_R = "thigh_FK.R"
    shin_FK_R = "shin_FK.R"
    foot_FK_R = "foot_FK.R"
    toe_FK_R= "toe_FK.R"

    elbow_pole_IK_L = "elbow_pole.L"
    hand_IK_L = "hand_IK.L"
    forearm_viz_IK_L = "forearm_viz.L"


    elbow_pole_IK_R = "elbow_pole.R"
    hand_IK_R = "hand_IK.R"
    forearm_viz_IK_R = "forearm_viz.R"

    knee_pole_IK_L = "knee_pole.L"
    knee_viz_IK_L = "knee_viz.L"
    foot_IK_L = "foot_IK.L"

    knee_pole_IK_R = "knee_pole.R"
    knee_viz_IK_R = "knee_viz.R"
    foot_IK_R = "foot_IK.R"



    #group bone for convienience
    groups = {
                'isolate_head' : ['head', head, neck],
                'isolated_torso': ['rib', hip, rib],

                'pivot_slide' : ['hip', hip, rib],

                'isolate_left_arm' : ['upper_arm_FK.L', upper_arm_FK_L, forearm_FK_L, hand_FK_L, shoulder_L],
                'isolate_right_arm' : ['upper_arm_FK.R',upper_arm_FK_R, forearm_FK_R, hand_FK_R, shoulder_R],

                'isolate_left_leg' : ['thigh_FK.L', thigh_FK_L, shin_FK_L, foot_FK_L, toe_FK_L],
                'isolate_right_leg' : ['thigh_FK.R', thigh_FK_R, shin_FK_R, foot_FK_R, toe_FK_R],

                'switch_IK/FK_left_arm' :['hand_IK.L', elbow_pole_IK_L, hand_IK_L, forearm_viz_IK_L, upper_arm_FK_L, forearm_FK_L, hand_FK_L],    
                'switch_IK/FK_right_arm' : ['hand_IK.R', elbow_pole_IK_R, hand_IK_R, forearm_viz_IK_R, upper_arm_FK_R, forearm_FK_R, hand_FK_R],


                'switch_IK/FK_left_leg' : ['foot_IK.L', knee_pole_IK_L, knee_viz_IK_L, foot_IK_L,thigh_FK_L, shin_FK_L, foot_FK_L, toe_FK_L],
                'switch_IK/FK_right_leg' : ['foot_IK.R', knee_pole_IK_R, knee_viz_IK_R, foot_IK_R, thigh_FK_R, shin_FK_R, foot_FK_R, toe_FK_R],
              }

    #print("READING VARIABLES")    



    def is_selected(self, names, selected_bones):
        """Returns whether any of the named bones are selected"""
        if type(names) == list:
            for name in names:
                if name in selected_bones:
                    return True
        elif names in selected_bones:
            return True
        return False



    def draw(self, context):
        layout = self.layout
        #row = layout.row()

        pose_bones = context.active_object.pose.bones
        #this excetion handler is redundant
        try:
            selected_bones = [bone.name for bone in context.selected_pose_bones]
            if context.active_pose_bone not in selected_bones: selected_bones.append(context.active_pose_bone.name)
        except(AttributeError, TypeError):
            return


        layout.prop(context.scene, "global_view")
        #print("The context type is: ", type(context))

        #print("In draw function")
        if context.scene.global_view:
            for property in self.groups.keys():
                bone_assoc = self.groups[property][0]
                required_prop = '["{}"]'.format(property)


                layout.prop(pose_bones[bone_assoc], required_prop, slider=True)

            #print("bpy.types.Scene.global_view", bpy.types.Scene.global_view, type(bpy.types.Scene.global_view))




        else:
            for property in self.groups.keys():
                cur_bones = self.groups[property][1:]
                bone_assoc = self.groups[property][0]
                required_prop = '["{}"]'.format(property)

                if self.is_selected(cur_bones, selected_bones):
                    layout.prop(pose_bones[bone_assoc], required_prop, slider=True)

                #print('in second view')







class RigLayers(bpy.types.Panel):
    bl_idname = 'POSE_PT_RigLayers'
    bl_label = "Rig Layers"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_context = "posemode"
    bl_category = CUSTOM_CATEGORY

    bone_groups ={

                'Root bone': 0,
                'FK bones': 1,
                'IK bones': 2,
                'Facial bones':3,
                'Manual spine':14
    }

    #control_layers = [0,1,2,3,14]
    #total_layers = 32



#    def dctv_other_pose_lyr(self, bone_layer):
#        """deactivate layers except bone_layer"""
#        for i in range(0,self.total_layers):
#            if i!=bone_layer:
#                bpy.context.object.data.layers[i] = False
#                




    def draw(self, context):
        column = self.layout.column() #items are placed under each other in a column

        #column.prop(context.scene, "switch_mode")
        contexts = []
        #if context.scene.switch_mode==False:
        for item in self.bone_groups.keys():

            column.prop(context.active_object.data, 'layers',
             index=self.bone_groups[item],
             toggle=True, text=item, 
             emboss=True)



#        else:
#            for item in self.bone_groups.keys():
#                column.prop(context.active_object.data, 'layers',
#                 index=self.bone_groups[item],
#                 event = lambda item: self.dctv_other_pose_lyr(self.bone_groups[item]),
#                  toggle=True, text=item)




class facial_exp(bpy.types.Panel):

    bl_idname = 'FACE_PT_RigUI'
    bl_label = "Facial controls"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_context = "posemode"
    bl_category = CUSTOM_CATEGORY

    def draw(self, context):
        pose_bones = context.active_object.pose.bones
        layout=self.layout
        layout.prop(pose_bones["eyebrow.L"], '["angry.L"]', slider=True)
        layout.prop(pose_bones["eyebrow.L"], '["sad.L"]', slider=True)
        layout.prop(pose_bones["eyebrow.L"], '["surprise.L"]', slider=True)
        layout.label(text=" ")
        layout.prop(pose_bones["eyebrow.R"], '["angry.R"]', slider=True)
        layout.prop(pose_bones["eyebrow.R"], '["sad.R"]', slider=True)
        layout.prop(pose_bones["eyebrow.R"], '["surprise.R"]', slider=True)






def register():
    bpy.types.Scene.global_view = bpy.props.BoolProperty(
                                    name = "Toggle Global View",
                                    description = "toggles all sliders irrespective of selection",
                                    default = True)

    #TO-DO
#    bpy.types.Scene.switch_mode = bpy.props.BoolProperty(
#                                    name = "Toggle Switch Mode",
#                                    description = "toggles A radio button behaviour",
#                                    default = False)
    bpy.utils.register_class(RigUI)
    bpy.utils.register_class(RigLayers)
    bpy.utils.register_class(facial_exp)





register()  

Now, this generates a panel, somewhat like this:

nice panel

Now, everything's nice and handy but, I want the "Facial Control" panel to appear both in posemode, edit mode, object mode and sculpt mode, and as you have seen in the code, this to my knowledge is controlled by the bl_context parameter, but, if the panel is to appear in all these modes, what should I set the bl_context parameter to?

$\endgroup$
8
  • $\begingroup$ It would be helpful if you provided a bit more context about your question. Where are you drawing what? How? What are you trying to do? What do you have so far? Where does it fail? $\endgroup$ Aug 5 '19 at 9:47
  • $\begingroup$ You could have a parent panel or operator object from which the children inherit. All the children need to do is set the bl_context to the right value. The properties would need to be in a separate object though, since otherwise the children wouldn't sync the state. $\endgroup$
    – Robert Gützkow
    Aug 5 '19 at 12:01
  • $\begingroup$ @MartinZ, I'm asking for the string parameter for bl_context that makes a property availabe in more than one "mode" in blender eg. sculpt, object, edit. I have been placing the property "facial expression" in posemode so far with bl_context=posemode, but I want it to appear also in object mode. The default is in every mode i.e. if we don't set bl_context at all, but it then appears in every mode which I would not want., and I'd like it to appear in the N panel. $\endgroup$ Aug 6 '19 at 4:13
  • $\begingroup$ @rjg,I'm sorry but I didn't really understand that. I'm having trouble how is inheriting a certain property make the property appear in more than one context or "modes" $\endgroup$ Aug 6 '19 at 4:14
  • $\begingroup$ @mathmaniage, the problem with you not telling what you are doing exactly and how and not sharing the code you are struggling with is that one might put a lot of effort trying to help you just to find out they misunderstood your question. This wastes time for people who are trying to help you. State clearly what you are trying to do and post some code you have so far and explain where it fails if you want to improve the chances for this question to get good answers. $\endgroup$ Aug 6 '19 at 11:21
3
$\begingroup$

You can leave the bl_context out altogether and control the appearance of the panels with poll method. Only if it returns True, the panel is shown.

import bpy

CUSTOM_CATEGORY = 'RIG OPTIONS'

class facial_exp(bpy.types.Panel):
    bl_idname = 'FACE_PT_RigUI'
    bl_label = "Facial controls"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = CUSTOM_CATEGORY


    def draw(self, context):
        layout=self.layout
        layout.operator("render.render")

    @classmethod
    def poll(cls, context):
        return context.mode in {'EDIT_MESH','SCULPT'}#list all the modes you want here

def register():
    bpy.utils.register_class(facial_exp)

register()  

You can test the current mode by typing C.mode or bpy.context.mode in the Python console it can be ‘EDIT_MESH’, ‘EDIT_CURVE’, ‘EDIT_SURFACE’, ‘EDIT_TEXT’, ‘EDIT_ARMATURE’, ‘EDIT_METABALL’, ‘EDIT_LATTICE’, ‘POSE’, ‘SCULPT’, ‘PAINT_WEIGHT’, ‘PAINT_VERTEX’, ‘PAINT_TEXTURE’, ‘PARTICLE’, ‘OBJECT’, ‘PAINT_GPENCIL’, ‘EDIT_GPENCIL’, ‘SCULPT_GPENCIL’, ‘WEIGHT_GPENCIL’

$\endgroup$
2
  • $\begingroup$ wow, thanks, that actually worked, but it seems there's no way to get facial deformations in sculpt mode, no particular reason but thought it'd to fun to sculpt deformed faces, because, my script dependent on the current selection of objects, and when I selected the mesh as the active object, the bones were deselected and hence the panel's gone anyways. Do you know any work arounds on that? $\endgroup$ Aug 6 '19 at 16:55
  • $\begingroup$ I figured it out, instead of bpy.context.active_object.pose.bones we gotta use bpy.data.objects[<armature_name>].pose.bones $\endgroup$ Aug 7 '19 at 2:22

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.