Detect Button States

Hello guys, it it possible to detect button states using python?

What I’m looking for in particular is the state of bpy.ops.mesh.select_mode whether its (type=‘VERT’)/ (type=‘EDGE’)/ (type=‘FACE’). I’m new to scripting in blender using python but I do understand maxscript for 3ds max.

What I did typically in maxscript would be checking subobjectlevel == 1(vertex)/ 2(edge)/ 4(face), but in blender it seems like it working slightly different, since there is no states of sub-object level in blender that I’m aware of, it even possible to activate all 3 of them (but I want to check the state either 1 of the 3 is active).

Can anyone help me on this?
Thanks.

You can read the mesh select mode from bpy.context.tool_settings.mesh_select_mode (tuple of 3 booleans) and also set it. Not sure what you wanna do with the operator.

Hi man, thanks for the reply. Yeah, it kinda works if I assign the 3 tupples into that, but I can’t seems to be able to check the state with if-statement. Running this simply always return false.


if bpy.context.tool_settings.mesh_select_mode == (True, False, False):
    print("OK")

What I want to do with this is I’m trying to write a smart function that combine few hotkeys into one depends on what mode I’m in. So what’s wrong with the above statement?

Alright! I think I figure it out, after more search on google and I come out with this toolSettings.mesh_select_mode[]
A small example of what I had in mind:


import bpy

toolSettings = bpy.context.tool_settings

if toolSettings.mesh_select_mode[0]:
    bpy.ops.mesh.vert_connect()
elif toolSettings.mesh_select_mode[1]:
    bpy.ops.mesh.subdivide()
elif toolSettings.mesh_select_mode[2]:
    bpy.ops.mesh.bridge_edge_loops()

So this kind of smart function that I try to adapt in blender from my maxscript setup. Basically using similar hotkey to perform similar task based on what mode we are working right now. So in my case I will map the script into “C”, so when I press C on vertex mode, it’ll connect verts, C on edge mode it’ll subdivide the edges (in 3ds max it’s still called connect edges, instead of subdivide edges), C on face mode it’ll bridge those faces. So for me “C” key is for all creation (create a new edge by connecting face/ edge, create new face by bridging faces/etc).

…ok, so now I need to find a way where should I place the script and how to assign to a hotkey, haha!

Check this out: http://www.blender.org/api/blender_python_api_2_73a_release/info_tutorial_addon.html

Hey man thanks for the link! after reading few documents, I’ve manage to assing a hotkey to my script.
So here it is what I got so far, pretty much complete in what i initially wanted it to do.


bl_info = \
{
    "name": "Create Smart",
    "description": "Smart Function: Create",
    "author": "Wahyu Nugraha (Revel)",
    "category": "_Smart"
}

import bpy
import bmesh

class create_smart(bpy.types.Operator):
    """Smart Function: Create"""
    bl_idname = "_smart.create_smart"
    bl_label = "Create Smart"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        # ---------------------- #
        # --- INIT VARIABLES --- #
        # ---------------------- #
        obj = bpy.context.active_object
        bm = bmesh.from_edit_mesh(obj.data)
        toolSettings = bpy.context.tool_settings
        toolOps = bpy.ops
        if bpy.context.mode == 'EDIT_MESH':
            verts = [v.index for v in bm.verts if v.select == True]
            edges = [e.index for e in bm.edges if e.select == True]
            faces = [f.index for f in bm.faces if f.select == True]

        # ----------------------- #
        # --- SMART FUNCTIONS --- #
        # ----------------------- #
        # vertex mode
        if toolSettings.mesh_select_mode[0]:
            if len(verts) <= 1:
                toolOps.mesh.dupli_extrude_cursor('INVOKE_DEFAULT')
            else:
                vSel = verts
                vFloating = False
                fElm = []
                
                # check whether it's a floating verts or not
                toolOps.mesh.select_linked()
                for f in [f.index for f in bm.faces if f.select == True]:
                    fElm.append(f)
                if len(fElm) == 0:
                    vFloating = True
                else:
                    vFloating = False
                toolOps.mesh.select_all(action='DESELECT')
                for v in vSel:
                    bm.verts[v].select = True
                
                # operation
                if vFloating == True:
                    toolOps.mesh.edge_face_add()
                else:
                    toolOps.mesh.vert_connect()

        # edge mode
        elif toolSettings.mesh_select_mode[1]:
            if len(edges) == 0:
                toolOps.mesh.loopcut_slide('INVOKE_DEFAULT')
            else:
                eSel = edges
                eBound = []
                selBound = []
                
                # get edge boundary
                toolOps.mesh.select_all(action='DESELECT')
                toolOps.mesh.select_non_manifold(use_boundary=True)
                for e in [e.index for e in bm.edges if e.select == True]:
                    eBound.append(e)
                for e in set(eSel).intersection(set(eBound)):
                    selBound.append(e)
                toolOps.mesh.select_all(action='DESELECT')
                for e in eSel:
                    bm.edges[e].select = True
                
                # sorted index
                eSel = sorted(eSel)
                eBound = sorted(eBound)
                selBound = sorted(selBound)
                
                # operation
                if eSel == selBound:
                    try:
                        toolOps.mesh.bridge_edge_loops()
                    except RuntimeError:
                        toolOps.mesh.edge_face_add()
                else:
                    toolOps.mesh.subdivide()

        # face mode
        elif toolSettings.mesh_select_mode[2]:
            if len(faces) == 0:
                toolOps.mesh.knife_tool('INVOKE_DEFAULT')
            else:
                try:
                    toolOps.mesh.bridge_edge_loops()
                except RuntimeError:
                    pass

        return {'FINISHED'}

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

def unregister():
    bpy.utils.unregister_class(create_smart)

if __name__ == "__main__":
    register()

@CoDEmanX - I had abit of trouble getting loop cut and knife tool to work properly and keep on giving me “wm_operator_invoke” error for some reason, till I found your post to someone else’s thread suggesting to pu (‘INVOKE_DEFAULT’), and it did fix my problem as well. What does it do actually? Does it run the scrpt with all the default parameters? if so when do we need to use it? since some of the script with a blank () will run just fine.

I explain it in these posts: