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$

1 Answer 1

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
    Commented Sep 1, 2020 at 21:30
  • $\begingroup$ @taichi None, that's a pure update function only been called when toggle is updated with new value $\endgroup$
    – HikariTW
    Commented Sep 1, 2020 at 23:37

You must log in to answer this question.

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