0
$\begingroup$

I am working on a modal operator which is How to maintain the ratio of the gizmo while zooming in and out?.

I want to run the modal operator via BoolProperty

Is it possible?

$\endgroup$
2

1 Answer 1

0
$\begingroup$

This answer was pointed out by pyCod3R in the comments and only needs two trivial changes to provide the solution to your problem:

  1. It doesn't follow the naming convention for operator classes, but that would only generate a warning. In the example, change SomeModalOperator to STRING_OT_modal_operator replacing "STRING" by a prefix of your choice.

  2. event_timer_add now requires the window = keyword for its second argument: event_timer_add(0.01, window=context.window)

That said, the answer gives a step by step guide for what code to add to your operator but it doesn't really explain how it works and it doesn't deal with the case where a modal operator also uses the event information it receives.

For this code to work for you, you need to do these things:

  • Modify your modal operator to set up a timer in the invoke function.
  • Modify your modal operator to check the Boolean in the modal function.
  • Add the Boolean property
  • Add a panel entry somewhere that make the Boolean property available to be toggled.

Here's a very stripped down version of the kind of code you need to add. You should be able to use the original answer plus this answer plus this code sample to add the changes you need to your own operator.

import bpy
from bpy.types import Operator, Panel

class TEST_OT_modal_operator(Operator):
    bl_idname = "test.modal"
    bl_label = "Demo modal operator"

    def modal(self, context, event):
        if not context.window_manager.test_toggle:
            context.window_manager.event_timer_remove(self._timer)
            print("done")
            return {'FINISHED'}
        print("pass through")
        return {'PASS_THROUGH'}

    def invoke(self, context, event):
        self._timer = context.window_manager.event_timer_add(0.01, window=context.window)
        context.window_manager.modal_handler_add(self)
        print("modal")
        return {'RUNNING_MODAL'}

class TEST_PT_side_panel(Panel):
    """This is the parent of the whole mess"""
    bl_label = "TEST panel"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "TEST"
    bl_options = {"DEFAULT_CLOSED"}

    def draw(self, context):
        label = "Operator ON" if context.window_manager.test_toggle else "Operator OFF"
        self.layout.prop(context.window_manager, 'test_toggle', text=label, toggle=True)  

def update_function(self, context):
    print("invoke modal")
    if self.test_toggle:
        bpy.ops.test.modal('INVOKE_DEFAULT')
    return

classes = [
    TEST_PT_side_panel,
    TEST_OT_modal_operator,
]

def register():
    for c in classes:
        bpy.utils.register_class(c)
    bpy.types.WindowManager.test_toggle = bpy.props.BoolProperty(
         default = False,
         update = update_function
    )

def unregister():
    del bpy.types.WindowManager.test_toggle
    for c in classes:
        bpy.utils.unregister_class(c)

if __name__ == '__main__':
    register()

How It Works

The Boolean property is an ordinary Boolean, except that it has an update function that invokes the modal operator when the Boolean toggles to True. This is what jump starts the modal operator by invoking it.

The invoke function of the modal operator adds a timer and sets up a handler for it. The timer allows the modal operator to periodically sample the value of the Boolean to determine if it should keep running.

The modal function of the modal operator checks the Boolean to determine if it has finished. Arguably it could return {'CANCELLED'} rather than {'FINISHED'} depending on what the modal operator required at a toggle.

$\endgroup$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.