Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Capture the dragging and release of a marker via python

    Cinema 4D SDK
    2024 python
    2
    4
    489
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • B
      BretBays
      last edited by

      I have an idea, where I want something to happen when I click and drag on a marker in the timeline, but I am not sure where to begin with getting that sort of event trigger, or if it is even possible in Python.

      Simplest example would be to print the new frame number of the marker's location once I release it.

      Would I need to like, enter a tool/context in order to track that?

      For more context, I wrote a script that Based on whatever marker I had selected(if the key was within the length of the marker), and I thought it might be cool to be able to shift those keys when I moved the marker as well, but I got a bit lost.

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand @BretBays
        last edited by ferdinand

        Hello @BretBays,

        Thank you for reaching out to us. Doing what you want to do will be tricky.

        1. You cannot implement handling drag events for things (a scene element, a dialog, a UI element) you do not implement yourself in Cinema 4D.
        2. The GUI event streams are sealed, i.e., you cannot just hook into the event stream of a dialog or UI element you do not own - which would contain the mouse interaction messages.

        What you can relatively easy do, is figure out which markers are selected. The caveat is here as always that asking for the selection state of an element in "the" timeline is an ambiguous question as there can be up to four timelines.

        """Prints out the name of all timeline markers contained in a document and their selection state
        in the first timeline.
        """
        
        import c4d
        
        doc: c4d.documents.BaseDocument  # The currently active document.
        op: c4d.BaseObject | None  # The primary selected object in `doc`. Can be `None`.
        
        def main() -> None:
            """Called by Cinema 4D when the script is being executed.
            """
            # Get the first marker in #doc and loop over them.
            marker: c4d.BaseList2D = c4d.documents.GetFirstMarker(doc)
            while marker:
                # Print out the name of the marker and its selection state in timeline 1.
                print(f"Name: {marker.GetName()}, selected: {bool(marker.GetNBit(c4d.NBIT_TL1_SELECT))}")
                marker = marker.GetNext()
        
        if __name__ == '__main__':
            main()
        

        2dc12d23-645a-4323-acc1-52eb15996975-image.png

        What you could then do, is write a MessageData plugin and register a timer with a stride of 100ms. You then would have to capture drag events yourself by the conditions isSelected and changed time since the last check.

        What you could also do, is hook into the message stream of each marker in a scene with BaseList2D.AddEventNotification and then listen for MSG_DESCRIPTION_POSTSETPARAMETER as the marker will likely receive these messages while being dragged for its TLMARKER_TIME parameter. To attach yourself to the marker message streams in a document, you would need a MessageData plugin which would check on each EVMSG_CHANGE if there is a new marker and then attach your callbacks. But it will likely be very hard to detect the end of a drag event with this message alone and we will need a timer too. But we could do this here:

        1. Via an event notification capture that the time value of a marker is changing.
        2. Turn on your MessageData timer event to further check on markers.
        3. Once we concluded all markers are being not dragged anymore because their time value has not changed anymore for a certain time or the markers are not selected anymore, we can turn off the timer again, saving resources.

        ⚠ BaseList2D.AddEventNotification is private for a reason, you can easily crash Cinema 4D with it especially with NOTIFY_EVENT::MESSAGE. We cannot share additional information on this method other than that what can already be found on the forum.

        The second approach hinges on MSG_DESCRIPTION_POSTSETPARAMETER being sent to markers while being dragged (seems likely at least for the case when the marker is released) but bears the risk of misusing AddEventNotification. You would also need a node to which you can route the messages which is a bit tricky in Python because there are no SceneHookData plugins there. You could try to abuse a PreferenceData plugin as they must not be instantiated manually and are also nodes (i.e., have a Message function you could route your events). But be aware that some nodes are being excluded from certain parts of a message stream they technically should receive. E.g., a PreferenceData plugin won't receive document and rendering notifications. But I doubt that a MSG_DESCRIPTION_POSTSETPARAMETER event notification will be filtered. Otherwise you would have to inject and manage a hidden dummy object into the scene to which you route all event notifications.

        The first approach is a bit iffy performance wise due to the constantly running timer, but you would be here on less shaky ground. It is also less technical implementationswise.

        Cheers,
        Ferdinand

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • B
          BretBays
          last edited by

          Hey Ferdinand,

          Thank you for your detailed response. It sounds like it may be a bit overkill for what I was thinking, and thats ok. I will read over it more and evaluate from there.

          1 Reply Last reply Reply Quote 0
          • B
            BretBays
            last edited by

            Follow up but slightly unrelated question. If I have a GeDialog plugin with an edit field(for changing the Frame of a marker for example), is it possible to have it update while dragging vs on release? Is that some sort of CoreMessage thing? Right now I have a call inside of my Command function that basically says if the ID matches the edit field then set the marker frame. But I would like to be able to click and drag and see the marker's position move as I drag. Is that possible

            1 Reply Last reply Reply Quote 0
            • First post
              Last post