I am trying to use an external addon and its operator which runs in modal mode. The solution that I would like to achieve is to stall the execution of my initial script that calls the operator until the modal operator is done. I found a solution about how to wrap the modal operator with a callback function described here and here. Which I've tried to adapt for my use case as seen below:

import bpy

from quad_remesher_1_1 import QREMESHER_OT_remesh as op

def _cleanup():
    """ Cleanup the scene by removing the hidden objects"""

def _remove_hidden_objects():
    """ Removes all objects of the current scene """
    # Select all
    for obj in bpy.context.scene.objects:
        if obj.hide_get() == True:
            # Delete selection

def remesh_object(obs):
    if obs:
        ob = obs.pop(0)
        bpy.ops.object.select_all(action='DESELECT') # Deselect all objects    
        #Set active object to variable
        bpy.context.view_layer.objects.active = ob
        if ob: ob.select_set(True)

        print("Object: {}".format(ob.name))

        # remesh object!!!!!    

# some callback function - here we put what shall be run after the modal is finished
def callback(ret):
    print('Callback triggered: {} !!'.format(ret))

def modal_wrap(modal_func, callback):

    def wrap(self, context, event):
        ret, = retset = modal_func(self, context, event)
        if ret in {'FINISHED'}: # my plugin emits the FINISHED event on finish - yours might do FINISH or CANCELED, you might have to look it up in the source code, __init__.py , there look at the modal() function for things like return {'FINISHED'} or function calls that return things alike.
            print(f"{self.bl_idname} returned {ret}")
        return retset
    return wrap

op._modal_org = op.modal
op.modal = modal_wrap(op.modal, callback)    

# set quadremesher parameters
bpy.context.scene.qremesher.use_materials = True
bpy.context.scene.qremesher.adaptive_size = 100
bpy.context.scene.qremesher.target_count = 5000
bpy.context.scene.qremesher.adapt_quad_count = True
bpy.context.scene.qremesher.autodetect_hard_edges = True

obs = [o for o in bpy.data.objects
        if o.type == 'MESH']

############### <------------------TODO: WAIT HERE UNTILL ALL OBJECTS HAVE BEEN REMESHED

# clean scene collection

This worked quite nicely for addressing my multi-call to the operator. However, the script continues to the _cleanup() function without waiting all the calls to the operator to be done. Searching around I've seen quite a few threads (some quite old) wanting to achieve something similar but their solution does not seem to be applicable in my case or to be honest I do not really understand what they do. Thus, I would appreciated any help about how to solve this somehow since I am stuck on this issue quite some time now.

Here are some other threads, in case they help somehow:

Wait until the action is done (in script)

How to wait for an operation - to another operator - to complete within an operator (import_scene)


Running code after a modal operator finished its job



Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.