Detecting Grease Pencil Click Release

I would like to perform an operation immediately upon the completion of a grease pencil drawing session (for an add-on). How can I detect when a grease pencil session has completed? That is, when the user releases the left mouse button after drawing a single curve? I am running modal, but the grease pencil operator seems to eat the LMB release event, as nothing gets passed through to my event detection.

Any tips would be appreciated, thanks.

Did you try to set up a shortcut to see if there’s any event raised on mouse-up?

Inside the general def modal(self, context, event), printing event.type and event.value catches no event on the mouse release at the end of the grease pencil. So it seems that the grease pencil itself is not passing these events through. But Blender is obviously aware of them (for example, the “draw” button is grayed out until the click release), so there must be some way of catching this event.

Yeah, the event is “consumed”, but can you make Blender call another operator if you bind one to the keys/mouse buttons that are used when releasing the GP?

I’m not sure I understand your idea. I am trying to avoid any extra key strokes, as my users have to draw a very large number of lines and they have explicitly requested that a certain action take place immediately upon grease pencil release, without having to take another action. I am not able to detect the grease pencil click release in standard modal mode, so binding anything to LMB-release doesn’t help because the event is not detected.

But there must be some event or flag in Blender that signals the end of the grease pencil stroke that can be detected somehow: the only change I can find is the existence of a new grease pencil stroke object, but I don’t know how to turn this existence into a detectable event.

Thanks again for any suggestions.

No, there is no real callback system. See:
http://www.blender.org/api/blender_python_api_2_75_release/info_quickstart.html

The Blender/Python API can’t (yet)…

  • Create new space types.
  • Assign custom properties to every type.
  • Define callbacks or listeners to be notified when data is changed

What I meant was to try to set up a hotkey to capture the release event after a GP stroke, and bind it to some operator…

import bpy
import time
from datetime import datetime


class SimpleOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"


    def execute(self, context):
        timestamp = datetime.strftime(datetime.now(), "%H:%M:%S.%f")[:-3]
        self.report({'INFO'}, "GP end {}".format(timestamp))
        return {'FINISHED'}




def register():
    bpy.utils.register_class(SimpleOperator)




def unregister():
    bpy.utils.unregister_class(SimpleOperator)




if __name__ == "__main__":
    register()

but it seems to be fully consumed… Left Mouse + D doesn’t trigger it if I make a hotkey for the same combination. If I remove the key modifier D, then it is only captured if no stroke is make :frowning:
So not looking good.

Okay, that’s definitely too bad. But thank you for considering my problem!

Instead of trying to “catch” the event, a better approach is to create a Macro Operator that chains together the Grease Pencil operator and any other operator(s) that you may wish to run after it. At least in the internal C-API, this is rather straightforward, and is simply a matter of defining a new macro operator and then attaching each of the operators you wish to call to it (along with the necessary parameters for getting those to do what you need). Examples of tools built this way include the Extrude and Duplicate tools, where a normal operator is used for the data creation part, and the transform operator gets called afterwards to operate on the newly created geometry.

I’m not too familiar with the Python API, but either one of the following solutions may work:

  1. Create a macro operator somehow
  2. Create a new operator that calls the required operators one by one. You’ll probably want to stick these things in the “invoke()” method (so that the Grease Pencil interactive drawing part will work)

That’s a good idea! Macros can be defined in Python, too. You would need to let your addon “replace” the keybindings however. AFAIK keyconfigs.addons takes precedence over keyconfigs.default, so that you shouldn’t have to actually replace the default keybindings.

How about executing after an event.type?

def modal(self,context,event):          
           bpy.ops.gpencil.draw('INVOKE_DEFAULT',mode ="DRAW")
           if event.type in {'RET', 'NUMPAD_ENTER'}:

cause I cant figure out how to do it after the stroke ending.

I haven’t used macros before, but this is an interesting idea.

Q0: Is there any documentation of macro usage from python somewhere beyond this example http://blender.stackexchange.com/questions/3032/alternate-between-user-input-and-automation-in-one-step-script that I’m not finding?

With the syntax I am trying, the later functions do not wait for the grease pencil drawing to complete before being called, but I’m just making this up as I go along.

Q1: Is it possible to call a macro while remaining inside a modal session?

I have also discovered that the poll() function of active operators (eg the class for my modal operator which is activated from a panel button) does get called on the grease pencil click release. Unfortunately, it is not possible to modify data from the poll function: “RuntimeError: Calling operator “bpy.ops.gpencil.convert” error, can’t modify blend data in this state (drawing/rendering)”.

Q2: Is there a hack to be able to modify data when an event is detected from an operator’s poll() function, when the operator itself is not called?

Thanks again for your help.

PS - Thanks for the suggestion Albertofx, but my users really want to be able to have an action performed immediately on click release without having to hit any other keys, because they are drawing a large number of curves, so I am hoping there is still a way.

How about this?

def modal(self, context, event):
        bpy.ops.gpencil.draw('INVOKE_DEFAULT',mode ="DRAW")
        if event.type == 'LEFTMOUSE':
            if event.value == 'PRESS':
             #do this
            elif event.value == 'RELEASE':
                      #do this
                   

If you figure how to fit this in for the grease pencil, like have the RELEASE event work after drawing out a stroke, please share. I’m developing an add-on and i need the same idea. Thanks.

@Animik, have you figured out how to do this? I wants this feature too. Thanks.