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
    Commented Sep 7, 2016 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
    Commented Sep 7, 2016 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
    Commented Sep 8, 2016 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
    Commented Sep 8, 2016 at 8:25

1 Answer 1

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$

You must log in to answer this question.

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