0
$\begingroup$

I want my dialog box to run a modal function while the user has the dialog box open, how can i do that?

$\endgroup$

1 Answer 1

0
$\begingroup$

It is possible to launch two instances of an operator simultaneously in this case a modal operator & a dialog props operator. when a dialog box stop being drawn, the __del__ dunder method will be called, therefore you can track the dialog state that way, & the modal operator can shut down if this dialog state is not active anymore

import bpy 

class PLUGIN_OT_modal_dialog(bpy.types.Operator):
    """modal state while the dialog box is active, call invoke default mandatory"""

    bl_idname  = "plugin.modal_dialog"
    bl_label   = ""
    bl_options = {'REGISTER', 'INTERNAL'}

    #find if dialog is currently active?

    def get_cls(self):
        cls = PLUGIN_OT_modal_dialog
        return cls

    dialog_state = False

    def get_dialog_state(self)->bool:
        return self.get_cls().dialog_state
        
    def set_dialog_state(self, value:bool,)->None:
        self.get_cls().dialog_state = value
        return None

    instance_type : bpy.props.StringProperty(default="UNDEFINED", options={'SKIP_SAVE',},)

    def invoke(self,context,event,):
        """decide if we'll invoke modal or dialog"""

        #launch both modal & dialog instance of this operator simultaneously
        if (self.instance_type=="UNDEFINED"):
            bpy.ops.plugin.modal_dialog('INVOKE_DEFAULT',instance_type="DIALOG",)
            bpy.ops.plugin.modal_dialog('INVOKE_DEFAULT',instance_type="MODAL",)
            return {'FINISHED'}

        #launch a dialog instance?
        if (self.instance_type=="DIALOG"):
            self.set_dialog_state(True)
            return context.window_manager.invoke_props_dialog(self)

        #launch a modal instance?
        if (self.instance_type=="MODAL"):
            self.modal_start(context)
            context.window_manager.modal_handler_add(self)  
            return {'RUNNING_MODAL'}

        return {'FINISHED'}

    def __del__(self):
        """called when the operator has finished"""

        #some of our instances might be gone from memory, 
        #therefore 'instance_type' is not available for some instance at this stage
        #not the dialog box instance tho & we need to update class status

        try:
            if (self.instance_type=="DIALOG"):
                self.set_dialog_state(False)
        except:
            pass
            
        return None

    def modal(self,context,event,):
        """for modal instance"""

        #modal state only active while dialog instance is! 
        if (self.get_dialog_state()==False):
            self.modal_quit(context)
            return {'FINISHED'}

        print("modal")

        return {'PASS_THROUGH'}

    def modal_start(self,context,):
        print("modal_start")
        return None

    def modal_quit(self,context,):
        print("modal_quit")
        return None

    def draw(self, context,):
        """dialog box ui code"""

        self.layout.label(text="my drawing")
        
        return None

    def execute(self, context,):
        """mandatory function called when user press on 'ok' """

        return {'FINISHED'}


if __name__ == "__main__":
    try:
        bpy.utils.unregister_class(PLUGIN_OT_modal_dialog)
    except: 
        pass
    bpy.utils.register_class(PLUGIN_OT_modal_dialog)

    bpy.ops.plugin.modal_dialog('INVOKE_DEFAULT')
$\endgroup$

You must log in to answer this question.

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