2
$\begingroup$

I'm fiddling around with an add-on to set Vertice Axis, and the add-on seems to work.

The addon creates a button in Tool Panel, and a menu entry in Mesh-Vertices.

The Problem is the missing 'add shortcut' entry in the right-click-menu.

I have tried for days to figure it out. If I add the entry manually in the shortcut menu with the rna 'mesh.move_verts_axis' it works.

the missing shortcut entry

import bpy
import bmesh

def _setupVertEdit():
    _set3DViewModeEdit()
    _initMeshEdit()
    return

def _initMeshEdit():
    global gObj, gObjData, gBMesh, gMat_world
    gObj = bpy.context.active_object
    gObjData = gObj.data
    gBMesh=bmesh.from_edit_mesh(gObjData)
    gMat_world = gObj.matrix_world
    return

def _get3DViewMode():
    return bpy.ops.mesh.select_mode()

def _set3DViewModeEdit():
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_mode(type="VERT")
    return

def _updateData():
    bmesh.update_edit_mesh(gObjData)
    return

def _countVerts():
    return (len(gObjData.vertices))

def _getSelectedVerts():
    return [ v for v in gBMesh.verts if v.select ]

def _countSelectedVerts():
    return (len(_getSelectedVerts()))

def _getActiveVert(optSel=0):
    elem = gBMesh.select_history.active
    if elem is not None and isinstance(elem, bmesh.types.BMVert):
        return elem
    elif optSel == 'sel' and _countSelectedVerts() > 0:
            elem = gBMesh.verts[0]
            gBMesh.select_history.add(elem)
            return elem
    return None

def _SetActiveVert(vert):
    if (type(vert)=='int'):
        gBMesh.select_history.add(gBMesh.verts[vert])
    else:
        gBMesh.select_history.add(vert)

    _updateData()
    return

def _selectVert(vert):
    gBMesh.verts[vert].select = True
    return

def _deSelectVert(vert):
    gBMesh.verts[vert].select = False
    return

def _getVertCoor(vert):
    return gBMesh.verts[vert].co

def _getVertCoorGlo(vert):
    gBMesh.verts.ensure_lookup_table()
    return gMat_world * gBMesh.verts[vert].co

def _setVectorCoor(vert,x=0,y=0,z=0):
    if x>0:
        gBMesh.verts[vert].co.x=x

    if y>0:
        gBMesh.verts[vert].co.y=y

    if z>0:
        gBMesh.verts[vert].co.z=z
    return

def _setVectorCoorGlo(vert,x=None,y=None,z=None):
    vert = gBMesh.verts[vert]
    pos_world = gMat_world * vert.co
    if x!=None:
        pos_world.x = x
        vert.co = gMat_world.inverted() * pos_world
    if y!=None:
        pos_world.y = y
        vert.co = gMat_world.inverted() * pos_world
    if z!=None:
        pos_world.z = z
        vert.co = gMat_world.inverted() * pos_world
    return

def _adaptVerts(vert1,vert2,x=False,y=False,z=False):
    if x:
        _setVectorCoorGlo(vert1,x=_getVertCoorGlo(vert2).x)
    if y:
        _setVectorCoorGlo(vert1,y=_getVertCoorGlo(vert2).y)
    if z:
        _setVectorCoorGlo(vert1,z=_getVertCoorGlo(vert2).z)
    return

def _setVertsAxis(axis):
    selV=_getSelectedVerts()
    actV=_getActiveVert(optSel='sel')

    if axis=='x':
        for vert in selV:
            _adaptVerts(vert.index,actV.index,x=True)

    if axis=='y':
        for vert in selV:
            _adaptVerts(vert.index,actV.index,y=True)

    if axis=='z':
        for vert in selV:
            _adaptVerts(vert.index,actV.index,z=True)

    _updateData()
    return

def checkVerts():
    global lVerts
    lVerts=_countSelectedVerts()
    # print('Selected Verts: '+str(lVerts))
    if lVerts<2:
        return False

    if _getActiveVert() == None:
        return False
    return True

def getVertsData():
    obj = bpy.context.active_object
    return 'Mesh: '+obj.name+', '+str(lVerts)+' Verts selected, move Axis ...'

def moveVerts(boolX,boolY,boolZ):
    if boolX:
        _setVertsAxis('x')
    if boolY:
        _setVertsAxis('y')
    if boolZ:
        _setVertsAxis('z')
    _updateData()
    return

def menu_func(self, context):
    self.layout.separator()
    self.layout.operator(OBJECT_OT_VertsButton.bl_idname)
    self.layout.separator()

# store keymaps here to access after registration
addon_keymaps = []

# Registration
#   All panels and operators must be registered with Blender; otherwise
#   they do not show up. The simplest way to register everything in the
#   file is with a call to bpy.utils.register_module(__name__).
#

def register():
    bpy.utils.register_module(__name__)
    bpy.types.VIEW3D_MT_edit_mesh_vertices.append(menu_func)

    # this does not work !!!
    # handle the keymap
    wm = bpy.context.window_manager
    km = wm.keyconfigs.addon.keymaps.new(name='Mesh', space_type='EMPTY')
    kmi = km.keymap_items.new('mesh.move_verts_axis', 'SPACE', 'PRESS', shift=True, ctrl=True)
    kmi.properties.boolX = False
    kmi.properties.boolY = False
    kmi.properties.boolZ = False
    addon_keymaps.append(km)

    print('register done')


def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.VIEW3D_MT_edit_mesh_vertices.remove(menu_func)

    # handle the keymap
    wm = bpy.context.window_manager
    for km in addon_keymaps:
        wm.keyconfigs.addon.keymaps.remove(km)
    # clear the list
    del addon_keymaps[:]

    print('unregister done')

    # bpy.utils.unregister_class(OBJECT_OT_VertsButton)
    # bpy.utils.unregister_class(ToolsPanel)
    # bpy.utils.unregister_class(SetVertsDialogOperator)

#
#    Menu in tools region
#
class ToolsPanel(bpy.types.Panel):
    bl_label = "Adjust"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_category = 'Tools'
    bl_context = "mesh_edit"
    bl_options = {'DEFAULT_CLOSED'}

    def draw(self, context):
        self.layout.operator("op.adjust_verts")

#
#    The  button Function
#
class OBJECT_OT_VertsButton(bpy.types.Operator):
    bl_idname = "op.adjust_verts"
    bl_label = "Set Verts"

    def execute(self, context):
        #       if checkVerts():
        bpy.ops.mesh.move_verts_axis('INVOKE_DEFAULT')
        return {'FINISHED'}


# Dialog from Toolpanel-Button 'Set Verts'
#       https://www.blender.org/api/blender_python_api_2_57_release/bpy.types.Operator.html

class SetVertsDialogOperator(bpy.types.Operator):
    bl_idname = "mesh.move_verts_axis"
    bl_label = 'Move verts to Active Vert Axis'
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "data"
    bl_options = {'REGISTER', 'UNDO'}   #Important for F6-Menu

    # Properties default=False
    boolX = bpy.props.BoolProperty(name="X", description="Move selected Verts to Active Vert X-Axis", default=False)
    boolY = bpy.props.BoolProperty(name="Y", description="Move selected Verts to Active Vert Y-Axis", default=False)
    boolZ = bpy.props.BoolProperty(name="Z", description="Move selected Verts to Active Vert Z-Axis", default=False)

    #   Execution
    def execute(self, context):
        # print('execute:' + str(self.boolX))
        _initMeshEdit()
        moveVerts(self.boolX, self.boolY, self.boolZ)

        # this does not work !!!
        #        message = "Popup Values: %d, %d, %d" % \
        #            (self.boolX, self.boolY, self.boolZ)
        #        self.report({'INFO'}, message)
        return {'FINISHED'}

    def invoke(self, context, event):
        # print('invoke:')
        wm = context.window_manager
        return wm.invoke_props_dialog(self)

    def draw(self, context):
        _initMeshEdit()
        if checkVerts():
            check_msg = getVertsData()
            self.layout.label(check_msg)
#            row = self.layout.split(0.35)
            row = self.layout.row()
            row.prop(self, "boolX")
            row.prop(self, "boolY")
            row.prop(self, "boolZ")
        else:
            self.layout.label('* Need more than one selected Verts')
            self.layout.label('* 1 vert must be active [shift click]')

if __name__ == "__main__":
    register()
$\endgroup$
4
  • $\begingroup$ i think you need to register all your ops bl_idname as mesh.something and not op.something , it's the custom op. path messing things up (which arguably it shouldn't ). $\endgroup$ – zeffii Sep 7 '16 at 22:10
  • $\begingroup$ regarding the register/unregister of keymap entries, see tutorial in the blender API docs --...addon_keymaps.append((km, kmi)) $\endgroup$ – zeffii Sep 7 '16 at 22:18
  • $\begingroup$ thks, after change code "bl_idname = "op.adjust_verts" to "bl_idname = "mesh.adjust_verts" it works in Menu and Button. $\endgroup$ – UncleTeo Sep 8 '16 at 5:59
  • $\begingroup$ I think this is hardcoded in Blender, it could be reported to the bugtracker as a bug. I don't know of ways around it so can't offer a better solution. $\endgroup$ – zeffii Sep 8 '16 at 8:25
2
$\begingroup$

Unless someone knows a way around this, this seems to be the answer:

Although it's convenient to use a new namespace for the operators of your addon, this does seem to break the Add Shortcut feature. Which seems to be hardcoded to include only existing namespaces like mesh.some_operator_name or object.some_operator_name.

These will work:

# bpy.ops.mesh   
bl_idname = "mesh.some_operator_name"

# bpy.ops.object
bl_idname = "object.some_operator_name"

this will work functionally, but won't it show the Add Shortcut menu item

bl_idname = "op.some_operator_name"
$\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.