Custom XPRESSO graph editor, show nodes in object manager
-
Hi,
I have a dialog that displays an XPRESSO style node graph - a NodeGUI, showing a gvnodemaster that is managed by my plugin. This works fine, with one exception: When I select a node in the dialog, it´s attributes are not shown in the object manager.How can I make that happen? I have looked at the ActiveObjectManager_RegisterMode function, but I can´t seem to get that to work. Any suggestions or relevant examples I could look at?
(I am using the C++ SDK)
Thanks!
/Filip Malmberg -
Hello @Filip,
Thank you for reaching out to us. It is unfortunately extremely hard to answer your question concretely as the information provided by you is very general.
I assume you are implementing your own nodes UI from scratch; you are neither using the
GraphView
(i.e., Xpresso), nor Nodes API? But the entities in your graph are instances ofBaseList2D
, right?ActiveObjectManager_RegisterMode
allows you to register your own mode for the Attribute Manager (Fig. 1) which in turn allows you to shield yourself from a displayed node from being replaced when you do not want to.
Fig 1: The Attribute Manager separates its displayed entities into bins called Modes.
So, when you set a
BaseObject
in your code withActiveObjectManager_SetObject
as the entity to be displayed in theACTIVEOBJECTMODE::OBJECT
mode, the user then changing for example the Object Manager selection will overwrite that "set object". When you register your own mode, you can prevent that, because it is only you who sets the displayed entities there.Registering your own mode also allows you to pass a
MessageData
hook which streamlines
setting the displayed object viaActiveObjectManager_SetObject
, but in the end you still must call this method every time you want to change the displayed entity. Because how should Cinema 4D otherwise know what you are doing in your dialog?In case this is all old news for you, and you are only struggling with objects not updating correctly their parameter GUIs and/or values when you have changed a value, the instruction
SpecialEventAdd(COREMSG_CINEMA_FORCE_AM_UPDATE)
will be the solution. In some cases the Attribute Manager needs a little nudge to get over the finish line.Cheers,
Ferdinand -
Thanks for the answer! I will look into this and see if it helps!
"I assume you are implementing your own nodes UI from scratch; you are neither using the GraphView (i.e., Xpresso), nor Nodes API? But the entities in your graph are instances of BaseList2D, right?"
No, I am using GraphView/Xpresso! But the GvNodeMaster is not from an Xpresso tag, it is stored in a BaseMaterial plugin. I also have a dialog that displays a GvNodeGUI for this nodemaster, when an item of this BaseMaterial type is selected by the user.Does this change your answer, i.e., is there an easier way to get a selected GvNode to show up in the attribute manager, even when it does not belong to an Xpresso tag?
-
Hey @Filip,
Does this change your answer, i.e., is there an easier way to get a selected GvNode to show up in the attribute manager, even when it does not belong to an Xpresso tag?
I doubt it. I would have to look up the details of the Xpressso handling, my guess would be that the hook only looks into
doc->Obase->Tbase->GVbase
[1] branches, i.e., the selected entities inside an Xpresso branch inside a tag. When that is the case, you cannot piggback onto the Xpresso handling because you are insidedoc->Mbase->YourBranchId
. Assuming that you implemented branching in the first place. You could quickly try it out by exactly matching the branching information of an Xpresso tag.But that all is quite unlikely because why would the xpresso handler monitor the whole document when it could get away with monitoring only everything below
doc->Obase
?Cheers,
Ferdinand[1] At least I think the ID of Xpresso branches is
GvBase
, could also beTbaselist2d
, I always forget what they chose there. -
OK, thanks! I will continue looking into this and will post here when I find a good solution for my case.
/Filip
-
Making some progress on this! I have registered a custom mode with ActiveObjectManager_RegisterMode(), and wrote a message hook that traverses the nodes in my GvNodeMaster and fills the atom array with the currently active one.
When I select a node in the GvNodeGui of my dialog, and manually set the active object manager to show my custom mode, the attributes of the selected node are correctly shown in the active object manager. So far so good!
A remaining problem, however, is that whenever I click something in the GvNodeGui, the active object manager immediately switches its mode back to "Node", and then the active object manager no longer shows the active node in my dialog!
Is there some way to get around this? I.e. is there some message I could intercept when the user interacts with my dialog, and from there set the active object manager mode to my custom mode?
The context here (as you may have guessed from me mentioning BaseMaterials) is that I'm writing a node editor for a 3rd party render engine, and I would like for the shader nodes to be visible in the active object manager. From what I can tell, the Arnold plugin does show shading nodes in the active object manager in this way from a custom XPRESSO-based dialog, which leads me to believe it should be possible. A fallback approach would be to add a DescriptionCustomGUI to my shader editor dialog, and just show the attributes there (Like Redshift does?), but I would prefer using the active object manager if possible!
Best regards
/Filip -
Hey @Filip,
A remaining problem, however, is that whenever I click something in the GvNodeGui, the active object manager immediately switches its mode back to "Node", and then the active object manager no longer shows the active node in my dialog!
Yeah, good point, did not think of that. As a quick tip, have you tried simply setting your node for
ACTIVEOBJECTMODE::NODE
, i.e., the graph view mode? You could then of course not register your own mode and the hook, and instead would have to use aMessageData
plugin listening to the core messageEVMSG_CHANGE
(i.e., the result ofEventAdd()
) so that you can detect selection changes in your node graph. I will have a look tomorrow how we have solved such things in the past.But you still did not tell us how you store your node graph. When you haven't implemented the branching yet and are storing the graph in some "wild" manner, you are fighting a losing battle here. You must implement
NodeData::GetBranchInfo
and actually store your nodes in the scene graph.Cheers,
Ferdinand -
"I will have a look tomorrow how we have solved such things in the past."
-Awesome, thanks!"But you still did not tell us how you store your node graph. ..."
-The GvNodeMaster is stored as a private member of a BaseMaterial plugin. I have implemented the Read(), Write(), CopyTo() and GetBranchInfo() functions for this BaseMaterial as follows, where "node_master" is the GvNodeMaster member:Bool DL_NodeMaterial::Read(GeListNode *node, HyperFile *hf, Int32 level) { return node_master->ReadObject(hf,true); } Bool DL_NodeMaterial::Write(GeListNode *node, HyperFile *hf) { return node_master->WriteObject(hf); } Bool DL_NodeMaterial::CopyTo(NodeData *dest, GeListNode *snode, GeListNode *dnode, COPYFLAGS flags, AliasTrans *trn) { DL_NodeMaterial* dst = (DL_NodeMaterial*)dest; return node_master->CopyTo(dst->GetNodeMaster(), flags, trn); } Int32 DL_NodeMaterial::GetBranchInfo(GeListNode *node, BranchInfo *info, Int32 max, GETBRANCHINFO flags){ return node_master->GetBranchInfo(info, max, GETBRANCHINFO::NONE); }
Out of these, I am mainly unsure about the GetBranchInfo() function, as this is a part of the SDK I have not worked with before. Any input on this part would be greatly appreciated!
/Filip
-
Hey @Filip,
Thank you for your reply. I should have thought of that earlier, but the only time we internally hooked into
GraphView
is the Redshift Xpresso Material editor. And there we effectively duplicated the functionality of the Attribute Manager to sidestep the exact problem you are running into.Problem
The problem is that
GvNodeGUI
, the custom GUI you and Redshift are using has been written very much with the Xpresso editor dialog in mind, which also registers and Attribute Manager mode hook just as you do. The primary culprit is this method in an backend interface which realizesGvNodeGUI
:void GvNodeGuiBackend::DeactivateSelectedNodes() { AutoAlloc<AtomArray> objects; if (!objects) return; ActiveObjectManager_SetObjects(ACTIVEOBJECTMODE::NODE, objects, false); }
And this thing is indeed being called every time a user does deselect something in a GV graph and then flushes the AM selection by setting its state to the empty atom array (Fig. I). In the context of the Xpresso tag this works because there the hook takes then over after that. But all other users of that interface are somewhat screwed because we either do not have an AM mode hook or the hook we have is not the native one and therefore not called. I also had a look at how the xpresso tag dialog is implemented, in the hopes one could simulate its branching information to smuggle oneself into the hunting grounds of its AM mode hook, but unfortunately that is not possible too.
-
Great, thanks a lot for looking into this and for the detailed explanations!
Now I know better what my options are! I am marking this thread as "solved".
Best regards
Filip Malmberg