2
$\begingroup$

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?

$\endgroup$

1 Answer 1

3
$\begingroup$

You're almost there. The ModalDrawOperator has an invoke function, so in ModalStarter you have to call it like this:

bpy.ops.view3d.modal_draw_operator('INVOKE_DEFAULT')

See the example in the Blender docs about invoke functions.

$\endgroup$
0

You must log in to answer this question.

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