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
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Register
    • Login

    Undo for commanddata plugin principle

    Cinema 4D SDK
    python
    3
    6
    679
    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.
    • D
      datamilch
      last edited by

      I‘m writing a commanddata plugin in combination with an objectdata plugin to store data in the document. This works so far. Now I wanted to implement undo and I read that Cinema's undo stack is limited to the content of documents, i.e. nodes. So I thought I would use my objectdata plugin to handle the undos, as ferdinand suggested in an older thread.

      There are some theoretical questions on how to approach this:

      When I change something in the gui, it is registered by command function in the commanddata plugin. From there I send a message to my storage node to update the value. I suppose I could start an undo before setting the value and end the undo afterwards.
      But if I drag a slider in the command-gui, the message is sent multiple times before I release it at the final value. So there will be 20 undos in a row. That‘s clearly not the way to go. (I didn't actually test.)
      Do i have to track the mouse-down and up states? And what if I want to type in a value – that would also create a separate undo. Any suggestions?

      Is it right, that I could create the undos in the commanddata OR the objectdata plugin? It is just the doundo-message, that I can only receive with the objectdata plugin.
      So if I doundo, i could send a custom-message to the commanddata plugin to update the gui.

      thanks, Sebastian

      1 Reply Last reply Reply Quote 0
      • D
        datamilch
        last edited by

        Totally forgot that Command() is receiving messages.
        BFM_ACTION_INDRAG seems helpful. I'll see how far I get with this.

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

          Hello @datamilch,

          Thank you for reaching out to us. I am struggling with understanding the basic premise of your question when you say ' a commanddata plugin in combination with an objectdata plugin to store data in the document'. While I understand that statement in an abstract sense, it is unclear to me how these CommandData/GeDialog to ObjectData/BaseObject bindings come to pass concretely.

          1. You are correct about the undo system of BaseDocument only supporting scene elements.
          2. That is however the common approach, undo's usually only include the data layer of an application and not the interface layer. When you delete the file foo.bar in the Windows explorer, then change the view mode from List to Details, and finally press CTRL+Z, it Windows will restore the file foo.bar and not change the view mode of that Explorer window. Most applications, including Cinema 4D, handle it in that way.

          With that being said, it is unclear to me for which entity you want to crate undo's. Manually creating undo's for scene elements, e.g., a BaseObject instance of type Omyplugin as the frontend of the class MyPluginData (ObjectData) hook, is usually not necessary. Simply setting parameter values will create the necessary undo steps. Manual undo handling only becomes necessary when you want to consolidate multiple actions into one undo step.

          You cannot create undo steps for anything that is not of type BaseList2D, e.g., a CommandData or GeDialog instance. You would have to implement your own undo stack here. That is, however, not advisable as undo's for GUIs are a very odd thing to do.

          "is it right, that I could create the undos in the commanddata OR the objectdata plugin?"

          No, that is not correct. In all non-main thread NodeData methods, e.g., Shaderdata.Output, TagData.Execute, or ObjectData.GetVirtualObjects, creating undo's is strictly forbidden as lined out under the threading restrictions. Cinema 4D will definitely crash if you ignore this. In methods of NodeData which often run on the main thread, e.g., NodeData.Message, you can technically check for being on the main thread and then modify node and create undo's for these modifications. This is however only something that one should do as a last ditch effort when one has no other option. In general, a node should not mess with its own undo steps.

          So if I doundo, i could send a custom-message to the commanddata plugin to update the gui.

          Sort of. My problem is here still that I do not know what you want to do. But to tie a dialog G to the state of an object O, one usually goes the other way around. G simply listens in its GeDialog.CoreMessage for EVMSG_CHANGE, and then checks the state of O.

          But if I drag a slider in the command-gui, the message is sent multiple times before I release it at the final value.

          If you want to consolidate multiple actions, you must that in your dialog. You could either only write what you consider to be the final value, or simply write all values but wrap them as one undo item. We recently talked about slider handling here.

          I would recommend that you describe what you practically want to achieve and show code. Otherwise, I will have to do a lot guessing, which then leads to fuzzy answers such as this one here (my apologies).

          Cheers,
          Ferdinand

          MAXON SDK Specialist
          developers.maxon.net

          D 1 Reply Last reply Reply Quote 0
          • D
            datamilch @ferdinand
            last edited by

            hi @ferdinand,
            thanks for your answer. I'm the one how has to apologize, I'm aware that my question was quite fuzzy.
            your answer still helps allot in giving me some direction. the link about slider handling seems also very helpful.
            I'll see how far I get with this and maybe come back with specific questions and code.

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

              Hey @datamilch,

              there is one thing I forgot to mention. It is a bit of an off-shot, but looking at c4d.gui.DescriptionCustomGui might be an alternative for you. It is the custom GUI that is used for example by the BaseLink GUI or the Attribute Manager. It will render the description of the node you set it to in a dialog of your choice.

              I used it for example here to display the Redshift render settings in a dialog, but you can use it anything that has a description, i.e., any BaseList2D, e.g., your object plugin instances. There all the value setting, including sliders, is then handled by this custom GUI.

              Cheers,
              Ferdinand

              MAXON SDK Specialist
              developers.maxon.net

              J 1 Reply Last reply Reply Quote 0
              • J
                jana @ferdinand
                last edited by

                Hello @datamilch ,

                without further questions or postings, we will consider this topic as solved by Friday, the 11th of august 2023 and flag it accordingly.

                Thank you for your understanding,
                Maxon SDK Group

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