2
$\begingroup$

Blender 2.8 Windows 10 x64

I have a start and stop button operator on my panel. The start button executes the modal as expected but I don't know how to get the stop button to exit the model via return('CANCELED')

Below is my code if you need it for testing

bl_info = {
    "name": "Brush strength mousewheel",
    "blender": (2, 80, 0),
    "category": "Brush",
}


import bpy
from bpy.props import EnumProperty
from bpy.types import Operator, Panel, PropertyGroup



# ------------------------------------------------------------------------
#    Scene Properties
# ------------------------------------------------------------------------

class MY_Properties(PropertyGroup):

    float_slider: bpy.props.FloatProperty(
        name = "Float Value",
        description = "A float property",
        default = 1.0,
        min = 0.010,
        max = 10.0
        )

class SCULPT_PT_CustomPanel(Panel):
    bl_label = "My Panel"
    bl_idname = "SCULPT_PT_custom_panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "UI"
    bl_category = "Tool"
    bl_context = "sculpt_mode"

    def draw(self, context):  
        layout = self.layout
        scene = context.scene
        mytool = scene.my_tool

        layout.operator('my.brush_stregth_op', text='Start').action = 'Start'
        layout.operator('my.brush_stregth_op', text='Stop').action = 'Stop'
        layout.prop(mytool, "float_slider")

class MY_OT_brush_stregth_op(Operator):
    bl_idname = 'my.brush_stregth_op'
    bl_label = 'Test'
    bl_description = 'Test'
    bl_options = {'REGISTER', 'UNDO'}

#    _timer = None

#    Determines which button was clicke by .action attachd to operator from panel

#    action: EnumProperty(
#        items=[
#            ('Start', 'start', 'start'),
#            ('Stop', 'stop', 'stop')
#        ]
#    )

     # if self.action == "Start"
     # do something

    def modal(self, context, event):
            scene = context.scene
            if event.type == 'WHEELDOWNMOUSE':  
                scene.my_tool.float_slider = scene.my_tool.float_slider - .1
                self.report({'INFO'}, "The value of the slider: " + str(scene.my_tool.float_slider))
            elif event.type == 'WHEELUPMOUSE':
                self.report({'INFO'}, "The value of the slider: " + str(scene.my_tool.float_slider))
                scene.my_tool.float_slider = scene.my_tool.float_slider + .1
            elif event.type in {'ESC', 'RIGHTMOUSE'}:  # Cancel
                self.report({'INFO'}, "The value of the: " + str(self.action))
                return {'CANCELLED'}
            elif event.type == 'TIMER':
                self.report({'INFO'}, "The value of the: " + str(self.action))
                if self.action == 'Stop':
                    return {'CANCELLED'} 
            else:
                bpy.context.tool_settings.sculpt.brush.strength = scene.my_tool.float_slider
                return {'PASS_THROUGH'} 

            bpy.context.tool_settings.sculpt.brush.strength = scene.my_tool.float_slider
            return {'RUNNING_MODAL'}

    def invoke(self, context, event):
        wm = context.window_manager
#        self._timer = wm.event_timer_add(0.1, window=context.window)
#        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}


classes = (
    MY_Properties,
    SCULPT_PT_CustomPanel,
    MY_OT_brush_stregth_op
)
def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

    bpy.types.Scene.my_tool = bpy.props.PointerProperty(type=MY_Properties)
        # handle the keymap
#    wm = bpy.context.window_manager
#   
#    # handle the keymap
#    wm = bpy.context.window_manager
#    km = wm.keyconfigs.addon.keymaps.new(name='Sculpt Mode', space_type='EMPTY')

#    kmi = km.keymap_items.new(ModalOperator.bl_idname, 'T', 'PRESS', ctrl=True, shift=True)

#    addon_keymaps.append((km, kmi))

def unregister():

       # Note: when unregistering, it's usually good practice to do it in reverse order you registered.
    # Can avoid strange issues like keymap still referring to operators already unregistered...
#    # handle the keymap
#    for km, kmi in addon_keymaps:
#        km.keymap_items.remove(kmi)
#    addon_keymaps.clear()

    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)
    del bpy.types.Scene.my_tool


if __name__ == "__main__":
    register()
$\endgroup$
5
$\begingroup$

Use a property switch

Declare a boolean property with an update method.

def toggle_op(self, context):
    if self.toggle:
        bpy.ops.foo.bar()  # start the operator

bpy.types.Scene.toggle = BoolProperty(update=toggle_op)

In your modal

if not scene.toggle:
    return {'CANCELLED'} # or self.cancel(context) to do some clean up

Related example for 2.7x

Link selection between VSE strip and object?

$\endgroup$
2
  • $\begingroup$ In which class do I define the toggle_op method? $\endgroup$
    – taichi
    Sep 1 '20 at 21:30
  • $\begingroup$ @taichi None, that's a pure update function only been called when toggle is updated with new value $\endgroup$
    – HikariTW
    Sep 1 '20 at 23:37

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.