I’m looking for a way to override the operator bpy.types.OBJECT_OT_shape_key_move as well as a few others. I’ve basically finished writing labels into shape keys, but I need other scripts/users to call my functions instead of the originals, so the state of my labels don’t become invalid. I still need to be able to call the original function bpy.ops.object.shape_key_move in the operator I replace it with, but other scripts in blender should only see mine. Basically something like this, but with an operator that was originally written in C. At least, I think these were written in C.
sorry for bumping, but in case anyone finds this thread, here’s an easy solution:
wrap the “original” operator inside a custom python operator, e.g.:
import bpy
class SimpleOperator(bpy.types.Operator):
"""Tooltip"""
bl_idname = "object.simple_operator"
bl_label = "Simple Object Operator"
@classmethod
def poll(cls, context):
return context.active_object is not None
def execute(self, context):
# Call any operator (C/python) here...
bpy.ops.transform.translate(value=(0,0,1))
return {'FINISHED'}
def register():
bpy.utils.register_class(SimpleOperator)
def unregister():
bpy.utils.unregister_class(SimpleOperator)
if __name__ == "__main__":
register()
# test call
bpy.ops.object.simple_operator()
The example you’ve given is indeed the standard method of creating an operator. I certainly hope it’s useful to anyone who finds this thread. However, the original question was asking how to override/monkey patch a C operator, in order to extend the original functionality. The essential idea was that ALL parts of blender, including scripts written by other authors would continue to call the original operator (bpy.ops.object.shape_key_move in my example) but that operator would be extended to support further functionality (labels in my example).
i admit it’s the most simple “wrapping” of a c-operator. However, it shows what is possible: you can perform tasks before, then call c-op (may pass parameters), perform tasks afterwards. There is nothing more you can do, and probably won’t be able in future as well. How could python hook up to the middle of the compiled c-code? Unless you inject into the exe, i don’t see a way here.
This is the most i could money-hijack (?) the border select for my task:
import bpy, bmesh
bl_info = {
"name": "Border Select Intersection",
"author": "CoDEmanX",
"version": (1, 1),
"blender": (2, 66, 0),
"location": "View3D > Spacebar > Border Select Intersect",
"description": "Make a selection, then run this operator to border select the desired selection intersection",
"warning": "",
"wiki_url": "",
"tracker_url": "",
"category": "3D View"}
def store_sel():
bm = MESH_OT_select_border_intersect.bm
if 'select_old' in bm.loops.layers.int.keys():
sel = bm.loops.layers.int['select_old']
else:
sel = bm.loops.layers.int.new("select_old")
for v in bm.verts:
if not v.link_loops: # IndexError?!
continue
v.link_loops[0][sel] = v.select
def restore_sel(me):
bm = MESH_OT_select_border_intersect.bm
sel = bm.loops.layers.int['select_old']
for v in bm.verts:
if not v.link_loops:
continue
if not (v.select and v.link_loops[0][sel]):
v.select_set(False)
#bm.select_mode = {'VERT'}
#bm.select_flush_mode()
bm.select_flush(False)
me.update()
def changed_sel():
bm = MESH_OT_select_border_intersect.bm
sel = bm.loops.layers.int['select_old']
for v in bm.verts:
if not v.link_loops:
continue
if v.select != v.link_loops[0][sel]:
return True
return False
class MESH_OT_select_border_intersect(bpy.types.Operator):
"""Border select an existing selection and make only the intersection selected"""
bl_idname = "mesh.select_border_intersect"
bl_label = "Border Select Intersect"
bl_options = {'REGISTER'}
init = True
bm = None
def modal(self, context, event):
if changed_sel():
restore_sel(context.object.data)
return {'FINISHED'}
elif event.type in {'RIGHTMOUSE', 'ESC'}:
return {'CANCELLED'}
if self.init:
bpy.ops.view3d.select_border('INVOKE_DEFAULT', extend=False)
self.init = False
return {'RUNNING_MODAL'}
#return {'PASS_THROUGH'} # Makes no difference
def invoke(self, context, event):
if (context.object and
context.object.type == 'MESH' and
context.object.mode == 'EDIT'):
MESH_OT_select_border_intersect.bm = bmesh.from_edit_mesh(context.object.data)
store_sel()
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
else:
self.report({'WARNING'}, "No active editmesh, could not finish")
return {'CANCELLED'}
def register():
bpy.utils.register_class(MESH_OT_select_border_intersect)
def unregister():
bpy.utils.unregister_class(MESH_OT_select_border_intersect)
if __name__ == "__main__":
register()