I want my dialog box to run a modal function while the user has the dialog box open, how can i do that?
1 Answer
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')