2
$\begingroup$

I'm currently working on a python tool using a modal operator. Now I know to finish the operation I can use:

if event.type == 'LEFTMOUSE':
    return {'FINISHED'}

However it seems not to count as a 'LEFTMOUSE' when I click (select) an object! I also tried 'SELECTMOUSE' which doesn't do anything.

What I would like to do is store the clicked object, and then automatically finish the modal operator.

Any ideas? Thanks in advance!

$\endgroup$

3 Answers 3

2
$\begingroup$

I have a solution and it's actually very simple:

class OBJECT_OT_do_stuff(bpy.types.Operator):
    bl_idname = "object.do_stuff"
    bl_label = "Do Stuff"

    origSel: None

    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def modal(self, context, event):
        # Update selection
        curSel = context.selected_objects[-1]

        # On selecting new object
        if curSel is not self.origSel:
            print("selection was changed")
            return {'FINISHED'}

        elif event.type in {'RIGHTMOUSE', 'ESC'}:
            print("cancelled operation")
            return {'CANCELLED'}

        else:
            return {'PASS_THROUGH'}

        return {'RUNNING_MODAL'}

    def invoke(self, context, event):
        self.origSel = context.object
        # Execute Modal Operation
        context.window_manager.modal_handler_add(self)
        return {'RUNNING_MODAL'}

I assigned an attribute that in the invoke function gets filled with the active object. Then the modal function keeps comparing the current selection to the previous one!

An important thing to note is that in order for that to work you need to call the function with the invoke argument :bpy.ops.object.do_stuff('INVOKE_DEFAULT')

$\endgroup$
2
  • 1
    $\begingroup$ Using the last in the selected list could make this a little random, Would use curSel = context.object $\endgroup$
    – batFINGER
    May 15, 2019 at 8:50
  • $\begingroup$ You're right, thanks $\endgroup$
    – Mantikator
    May 15, 2019 at 14:24
1
$\begingroup$

Why type.event ?

You should get your event.type, and you may want to compare the event.value as well:

def modal(self, context, event):
    if event.type in {"LEFTMOUSE"} and event.value == "RELEASE":
        return {'FINISHED'}
    return {'PASS_THROUGH'}

Also, it might be possible that an event been stop propagate in most of the event handling system. You might need to check the context carefully to see what is the main problem.

$\endgroup$
2
  • 1
    $\begingroup$ sorry I actually meant event.type and also got that right in my script. when I use the value RELEASE, clicking an object does end the modal but therefore doesn't select the object... $\endgroup$
    – Mantikator
    May 14, 2019 at 8:32
  • $\begingroup$ So you want to check something after you click and select an object? I don't know if it is safe to do relative thing in a same event loop. Interesting problem, I will test a little bit for it. $\endgroup$
    – HikariTW
    May 14, 2019 at 11:59
0
$\begingroup$

Great script. I arranged it so that it responds even when not selected.

import bpy

class OBJECT_OT_do_stuff(bpy.types.Operator):
    bl_idname = "object.do_stuff"
    bl_label = "Do Stuff"

    origSel: None

    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def modal(self, context, event):
        # Update selection
        selobj=context.selected_objects
        
        if selobj != []:
            curSel = selobj[-1]
        else: 
            return {'PASS_THROUGH'}
    
        # On selecting new object
        if curSel is not self.origSel:
            self.report({'INFO'}, "selection was '{}' changed".format(curSel.name))
            return {'FINISHED'}

        elif event.type in {'RIGHTMOUSE', 'ESC'}:
            self.report({'INFO'}, "cancelled operation '{}'".format(curSel.name))
            return {'CANCELLED'}

        else:
            return {'PASS_THROUGH'}

        return {'RUNNING_MODAL'}

    def invoke(self, context, event):
        self.origSel = context.object
        # Execute Modal Operation
        context.window_manager.modal_handler_add(self)
        return {'RUNNING_MODAL'}
    
classes = (
    OBJECT_OT_do_stuff,
    
    )
def register():
    for cls in classes:
        bpy.utils.register_class(cls)


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)


if __name__ == "__main__":
    register()
$\endgroup$

You must log in to answer this question.

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