0
$\begingroup$

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"""
    _remove_hidden_objects()

def _remove_hidden_objects():
    """ Removes all objects of the current scene """
    # Select all
    bpy.ops.object.select_all(action='DESELECT')
    for obj in bpy.context.scene.objects:
        if obj.hide_get() == True:
            obj.hide_set(False)
            obj.select_set(True)
            # Delete selection
            bpy.ops.object.delete()


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!!!!!    
        bpy.ops.qremesher.remesh()

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

    remesh_object(obs)
    
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}")
            callback(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']
        
remesh_object(obs)

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

# clean scene collection
_cleanup()

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)

https://stackoverflow.com/questions/58054792/about-modal-operators-in-blender-python

Running code after a modal operator finished its job

Thanks.

$\endgroup$

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.