For a process like baking a number of frequencies from an audio file, I use the modal timer operator. Eg If I have a long audio file and it takes 5mins to bake one frequency out of a set of 16, I bake one then have a small wait time to allow the handler to catch an escape key which throws up a menu to cancel (and clean up) or continue, rather than have to wait 16x5 or kill blender. It doesn't however let me cancel amid a bake.
For convenience I have used the BakeSoundPanel Panel class to store data on the status of the bake.
class SD_ContinueBakeOperator(Operator):
"""Continue Baking"""
bl_idname = "sounddrivers.continue_baking"
bl_label = "Continue"
def execute(self, context):
BakeSoundPanel.wait = 2
BakeSoundPanel.cancel_baking = False
return {'FINISHED'}
class SD_CancelBakeOperator(Operator):
"""Cancel Baking"""
bl_idname = "sounddrivers.cancel_baking"
bl_label = "Cancel"
def execute(self, context):
BakeSoundPanel.cancel_baking = True
return {'FINISHED'}
class ModalTimerOperator(bpy.types.Operator):
"""Operator which runs its self from a timer"""
bl_idname = "wm.modal_timer_operator"
bl_label = "Modal Timer Operator"
_timer = None
def modal(self, context, event):
def confirm_cancel(self, context):
layout = self.layout
layout.operator("sounddrivers.cancel_baking")
layout.operator("sounddrivers.continue_baking")
if BakeSoundPanel.cancel_baking:
self.clean()
return self.cancel(context)
if event.type == 'ESC' or not BakeSoundPanel.baking:
context.window_manager.popup_menu(confirm_cancel, title="Baking", icon='SOUND')
BakeSoundPanel.wait = 1000000
return {'PASS_THROUGH'}
self.clean()
return self.cancel(context)
if BakeSoundPanel.wait > 0:
BakeSoundPanel.wait -= 1
return {'PASS_THROUGH'}
if event.type == 'TIMER':
BakeSoundPanel.baking = True
# bake a sound, when finished set self.wait to some "wait time"
# to enable a cancel
return {'PASS_THROUGH'}