Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Adding Undos for CommandData Changes

    Cinema 4D SDK
    python
    3
    7
    713
    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.
    • ?
      A Former User
      last edited by A Former User

      Hello,
      I'd like to add undos for changes made in a CommandData plugin: changes to the GeDialog and changes made to Hyperfile data.

      Is this possible? My guess is not because these changes are not on the main thread, but it would be incredible to add this functionality to my plugin if so. I had to ask.

      I have seen the mention of undo messages from the Attribute Manager in the C++ documentation and posts on the forum which mention MSG_DESCRIPTION_INITUNDO but only saw mention of C4DAtom objects and ToolData/NodeData plugins.

      If this does work by some chance, how would I add interactions with my plugin as an undo?

      Thank you.

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

        Hi,

        Cinema's undo stack is limited to the content of documents, i.e. nodes, i.e. anything that is derived from C4DAtom. Neither GeDialog nor HyperFile do meet this requirement. To apply undos to a tool, that tool has to be a DescriptionToolData tool, something that is not available in Python (we do only have ToolData tools), which will effectively encapsulate the tool in a node.

        Personally I would just implement my own tool specific undo stack if I did need one in Python. An alternative route could be to implement your tool GUI as a NodeData node and then display that node via a DescriptionCustumGui in the dialog of the CommandData or ToolData plugin you want to write. The undos would then have to be applied to that dummy GUI node.

        I am not quite sure what you would expect an undo to do in the context of a HyperFile, but it will probably be rather hard to implement or even simply impossible on a logical/theoretical level.

        Cheers,
        zipit

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • ManuelM
          Manuel
          last edited by

          hi,

          this is not possible out of the box.

          About the GeDialog, this could be possible if you create an object in the document, hide it and store your data there.
          In c++ you could create a sceneHook to store that NodeData.

          About the HyperFile, you have to create your own undo stack.

          I'm not sure MSG_DESCRIPTION_INITUNDO will help a lot in that case. But MSG_DOCUMENTINFO_TYPE_UNDO will.

          Cheers,
          Manuel

          MAXON SDK Specialist

          MAXON Registered Developer

          1 Reply Last reply Reply Quote 0
          • ?
            A Former User
            last edited by A Former User

            Thank you both for the replies.

            @m_magalhaes How would I hide it in a way that would be least noticeable to the user? In the past I've added things to layers and turned off their visibility in the Viewport and the Object Manager. Is there another way?

            How does the MSG_DOCUMENTINFO_TYPE_UNDO method work with GeDialog? This is for building my own undo stack, I assume? I found this snippet on the forum, but I believe it's for ToolData. When I tried listening to Messages from the GeDialog, MSG_DOCUMENTINFO and MSG_DOCUMENTINFO_TYPE_UNDO never came up.

              def Message(self, doc, data, type, t_data):
                  if type==c4d.MSG_DOCUMENTINFO:
                      info = t_data
                      if info['type']==c4d.MSG_DOCUMENTINFO_TYPE_UNDO:
                          print "Undo Performed"
                  return True
            

            Thank you!

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

              Hi,

              you do not really have to hide the node. I would just attach a dummy document containing that node to your tool instance. It would also remove the necessity to clean up after yourself, because you do not want to leave (hidden) node bloat in your active document when the document is being closed. Another (dis-)advantage would be that this approach would be document agnostic (i.e. you could unfold the undo stack of your tool back to any point in any document that has been opened since Cinema started - within the bounds of Cinema's stack depth value).

              Cheers,
              zipit

              MAXON SDK Specialist
              developers.maxon.net

              1 Reply Last reply Reply Quote 0
              • ManuelM
                Manuel
                last edited by

                hi,

                sorry, the DoUndo function is broadcasting the message but not to GeDialog.
                But only to those Branches:

                70d0ea54-e354-4584-95f7-93fe7b21b99d-image.png

                So you can't catch the Undo Message in a GeDialog.

                About hiding the object, as the object will not be display anything, you can simply hide it in the object manager.
                The problem is that you have to find it in the hierarchy to retrieve the information (or store a baselink to it in the basecontainer's document)

                import c4d
                from c4d import gui
                
                # Main function
                def main():
                    doc.StartUndo()
                    doc.AddUndo(c4d.UNDO_CHANGE, op)
                    op.ChangeNBit(c4d.NBIT_OHIDE, c4d.NBITCONTROL_SET)
                    doc.EndUndo()
                    
                    c4d.EventAdd()
                    
                # Execute main()
                if __name__=='__main__':
                    main()
                

                To make it short, what you are asking is somehow possible, but not out of the box and not without taking care of a lot possible error to do it.

                Catching the "Undo" action from user isn't easy in a GeDialog, and storing its information and retrieve it, isn't easy.
                In c++ you could your life easier with a scenehook, but not that mush.

                Cheers,
                Manuel

                MAXON SDK Specialist

                MAXON Registered Developer

                ? 1 Reply Last reply Reply Quote 0
                • ?
                  A Former User @Manuel
                  last edited by

                  @m_magalhaes That's helpful, thank you, Manuel! 😄

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