1
$\begingroup$

I'm writing a modal operator that needs to keep track of mouse movement and mouse clicks. A side effect of this is that it makes any panels or workspace tools completely inoperable. Since my operator is getting first dibs on any mouse events, all the buttons and other controls in the layover panels are being ignored. I also cannot pass through these events, since I do not know if any given mouse event has occurred within one of the overlaid controls or is in the main part of the viewport. Is there any any way to make sure that if the user clicks on a button, the signal is sent to that button first?

$\endgroup$

1 Answer 1

1
$\begingroup$

Your modal handler needs to return {'PASS_THROUGH'} for any event it doesn't handle. Here's an example modal event handler that does that:

    def modal(self, context, event):
        v3d = context.space_data
        rv3d = v3d.region_3d

        if event.type == 'MOUSEMOVE':
            mouse_pos = Vector((event.mouse_x, event.mouse_y, 0.0))
            mouse_move = self._initial_mouse - mouse_pos
            self.offset = mouse_move * 0.02
            self.execute(context)
            context.area.header_text_set("Offset %.4f %.4f %.4f" % tuple(self.offset))

        elif event.type == 'LEFTMOUSE':
            context.area.header_text_set(None)
            return {'FINISHED'}

        elif event.type in {'RIGHTMOUSE', 'ESC'}:
            v3d = context.space_data
            rv3d = v3d.region_3d
            rv3d.view_location = self._initial_location
            context.area.header_text_set(None)
            return {'CANCELLED'}
        
        elif event.type in {'WHEELUPMOUSE', 'WHEELDOWNMOUSE'}:
            return {'PASS_THROUGH'}

        return {'RUNNING_MODAL'}

This is a very simple example that only deals with mouse events, not keyboard or others. You'll have to organize your own tests for whatever you want, but the example should give you a guide. The example is taken from this tutorial. It might be worth your time to watch the tutorial as well.

Your handler should recognize a specific event to trigger completing. This one uses Left Mouse click. Return {'FINISHED'} in that case.

Your handler should recognize a specific event to trigger cancelling. This one uses typing Esc while holding the right mouse button. Return {'CANCELLED'} in that case.

Your handler should pass through any events it doesn't want to handle.. This one ignores the third (wheel) mouse button. Return {'PASS_THROUGH'} in that case.

Implicit in this example is that in cases that your handler doesn't explicitly handle or ignore it should do whatever it wants with the event and return {'RUNNING_MODAL'} to continue running as a modal event. Don't fall off the end of the function without returning one of these things. This one is just throwing "handled" events away. A useful modal might do some work between the if statement and the final return.

$\endgroup$
1
  • $\begingroup$ The problem here is that I need to know the locations of the various buttons and overlays before I can know if I need to pass the events through. So if I've created a panel which is accessible through the N menu, I am unable to use it while my operator is running because my operator gets passed the events before the panel controls do. $\endgroup$
    – kitfox
    Commented Jun 29, 2022 at 3:18

You must log in to answer this question.

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