2
$\begingroup$

I'm trying to create mouse-based cut and trim functions for the VSE, to allow for fast edits when scrubbing the timeline. Using Ctrl Right Mouse as a keyboard shortcut, Blender handles the strip's selection with the Right Mouse button, and then triggers the operator.

The problem is that I can't find a way to move the time cursor where the user clicks from a Python script. I looked into the reference API, and in Blender's python console, I also set:

bpy.app.debug_wm = True

To no success. Nothing shows up in the console when you left click in the VSE. And I looked up online, couldn't find an answer.

So, do you know how I could set the current frame/place the time cursor based on where the mouse is from a python operator?

Kind regards, Nathan

$\endgroup$

1 Answer 1

3
$\begingroup$

Here's an adjustment of the answer to this q Getting area (region.view2d) pixel coordinates of 2D views (VSE, NLA)

Run the script, use the spacebar to search out the "Simple Modal Sequencer Operator" and the current frame will change with the mouse.

The key method is region.view2d.region_to_view which returns, in this case, the frame in x and the strip channel in y, from the regions pixel coords.

import bpy
import bgl
import blf


def draw_callback_px(self, context):
    print("mouse points", len(self.mouse_path))

    region = context.region
    strip = context.scene.sequence_editor.active_strip
    if strip is None:
        return

    x = strip.frame_final_start
    y = strip.channel
    x, y = region.view2d.view_to_region(x, y)
    font_id = 0  # XXX, need to find out how best to get this.

    # draw some text
    blf.position(font_id, x, y, 0)
    blf.size(font_id, 20, 72)
    # region_to_view gives the region coords.  x is frame, y is channel.
    x, y = region.view2d.region_to_view(*self.mouse_path[-1] )
    blf.draw(font_id, "Hello Word %d %d" % (x, y))
    # move the frame to the mouse
    context.scene.frame_set(x)


class ModalDrawOperator(bpy.types.Operator):
    """Draw a line with the mouse"""
    bl_idname = "sequencer.modal_operator"
    bl_label = "Simple Modal Sequencer Operator"

    def modal(self, context, event):
        context.area.tag_redraw()
        region = context.region

        if event.type == 'MOUSEMOVE':
            self.mouse_path.append((event.mouse_region_x, event.mouse_region_y))

        elif event.type == 'LEFTMOUSE':
            bpy.types.SpaceSequenceEditor.draw_handler_remove(self._handle, 'WINDOW')
            return {'FINISHED'}

        elif event.type in {'RIGHTMOUSE', 'ESC'}:
            bpy.types.SpaceSequenceEditor.draw_handler_remove(self._handle, 'WINDOW')
            return {'CANCELLED'}

        return {'RUNNING_MODAL'}

    def invoke(self, context, event):
        if context.area.type == 'SEQUENCE_EDITOR':
            # 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.SpaceSequenceEditor.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'}, "SequenceEditor not found, cannot run operator")
            return {'CANCELLED'}


def register():
    bpy.utils.register_class(ModalDrawOperator)


def unregister():
    bpy.utils.unregister_class(ModalDrawOperator)

if __name__ == "__main__":
    register()

PS I slapped this together pretty quickly and put code in the draw hander rather than the event loop of the operator. Will fix later...

$\endgroup$
1
  • $\begingroup$ This is super duper cool! It actually solves multiple questions I had at once (how to make this tool modal, and how to print info on the screen). Thanks a lot! :) $\endgroup$
    – gdquest
    Mar 31, 2016 at 12:24

You must log in to answer this question.

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