Undo for commanddata plugin principle
-
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
-
Totally forgot that Command() is receiving messages.
BFM_ACTION_INDRAG seems helpful. I'll see how far I get with this. -
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
toObjectData/BaseObject
bindings come to pass concretely.- You are correct about the undo system of
BaseDocument
only supporting scene elements. - 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 pressCTRL+Z
, it Windows will restore the filefoo.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 typeOmyplugin
as the frontend of theclass 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., aCommandData
orGeDialog
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
, orObjectData.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 ofNodeData
which often run on the main thread, e.g.,NodeData.Message
, you can technically check for being on the main thread and then modifynode
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
forEVMSG_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 - You are correct about the undo system of
-
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. -
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 -
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