I have a modal operator which I use to move UVs directly in the 3d viewport (modalOP
).
I also have an operator which sets up a selection and a few parameters (setupOP
).
I want to launch the modal operator automatically when the setupOP
is finished but I need modalOP
to be able to launch separately because it fills more than one role.
Here is an example code, cobbled together from the python templates, of how Id want it to work (but running the modal_starter
currently doesnt start the modal_draw_operator
)
import bpy
import blf
import gpu
from gpu_extras.batch import batch_for_shader
def draw_callback_px(self, context):
print("mouse points", len(self.mouse_path))
font_id = 0 # XXX, need to find out how best to get this.
# draw some text
blf.position(font_id, 15, 30, 0)
blf.size(font_id, 20, 72)
blf.draw(font_id, "Hello Word " + str(len(self.mouse_path)))
# 50% alpha, 2 pixel width line
shader = gpu.shader.from_builtin('UNIFORM_COLOR')
gpu.state.blend_set('ALPHA')
gpu.state.line_width_set(2.0)
batch = batch_for_shader(shader, 'LINE_STRIP', {"pos": self.mouse_path})
shader.uniform_float("color", (0.0, 0.0, 0.0, 0.5))
batch.draw(shader)
# restore opengl defaults
gpu.state.line_width_set(1.0)
gpu.state.blend_set('NONE')
class ModalDrawOperator(bpy.types.Operator):
"""Draw a line with the mouse"""
bl_idname = "view3d.modal_draw_operator"
bl_label = "Simple Modal View3D Operator"
def modal(self, context, event):
context.area.tag_redraw()
if event.type == 'MOUSEMOVE':
self.mouse_path.append((event.mouse_region_x, event.mouse_region_y))
elif event.type == 'LEFTMOUSE':
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
return {'FINISHED'}
elif event.type in {'RIGHTMOUSE', 'ESC'}:
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
return {'CANCELLED'}
return {'RUNNING_MODAL'}
def invoke(self, context, event):
if context.area.type == 'VIEW_3D':
# the arguments we pass the the callback
args = (self, context)
# Add the region OpenGL drawing callback
# draw in view space with 'POST_VIEW' and 'PRE_VIEW'
self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL')
self.mouse_path = []
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
else:
self.report({'WARNING'}, "View3D not found, cannot run operator")
return {'CANCELLED'}
def menu_func(self, context):
self.layout.operator(ModalOperator.bl_idname, text=ModalOperator.bl_label)
class ModalStarter(bpy.types.Operator):
"""Translate the view using mouse events"""
bl_idname = "view3d.modal_starter"
bl_label = "Modal Starter"
def execute(self, context):
print("Doing stuff")
bpy.ops.view3d.modal_draw_operator()
return {'FINISHED'}
# Register and add to the "view" menu (required to also use F3 search "Simple View Modal Operator" for quick access).
def register():
bpy.utils.register_class(ModalDrawOperator)
bpy.utils.register_class(ModalStarter)
bpy.types.VIEW3D_MT_view.append(menu_func)
def unregister():
bpy.utils.unregister_class(ModalDrawOperator)
bpy.utils.register_class(ModalStarter)
bpy.types.VIEW3D_MT_view.remove(menu_func)
if __name__ == "__main__":
register()
Is there a way to get this to work or am I going about this the wrong way?