How to update the attribute manager's view?
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 24/11/2009 at 06:29, xxxxxxxx wrote:
I can't really see anything wrong (unless I missed something). The only important thing is to send the MSG_CHANGE message to the tag after adding the additional data to the tag's container. It's also a good idea to add an undo.
Here the code of my message method (it's an object plugin but the same applies to tags) :
Bool MorphMixerObject::Message(GeListNode *node, LONG type, void *data) { switch (type) { case MSG_DESCRIPTION_COMMAND: { DescriptionCommand *dc = (DescriptionCommand* ) data; if (dc->id[0].id==MORPHMIXER_ADD) { BaseList2D *op = (BaseList2D* ) node; BaseDocument *doc = op->GetDocument(); if (!doc) return FALSE; BaseContainer *bc = ((BaseList2D* )node)->GetDataInstance(); if (!bc) return FALSE; BaseContainer *main = bc->GetContainerInstance(ID_MORPHMIXER_OBJECT); if (!main) return FALSE; doc->StartUndo(); doc->AddUndo(UNDO_CHANGE_SMALL,node); main->SetLong(MORPH_CNT, main->GetLong(MORPH_CNT,0)+1); doc->EndUndo(); op->Message(MSG_CHANGE); } } } return SUPER::Message(node,type,data); }cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 24/11/2009 at 06:43, xxxxxxxx wrote:
Changing the value of a basecontainer's entry works and is updated immediately in the attribute manager.
But what I'm trying to do is to add or remove entries of the basecontainer while the tag's attributes are visible in the attribute manager. Then those added or removed entries should also be visibly (the GUI-elements) added or removed in the attribute manager's view.So that's the point where it doesn't work - the attribute manager (=AM) only updates the values of its GUI-elements, but it doesn't add or remove GUI-elements (unless you close the AM and open it again by clicking on some other object and then back to the tag).
As far as I understood, adding and removing of GUI elements is done by calling the tag's GetDDescription function, which then prepares the Description element for the AM. But I don't get the AM to call the GetDDescription function again to request a new Description and to realize that there are new GUI elements to show.
Besides, the adding of undo is really a good idea, I didn't think of that, thanks.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 24/11/2009 at 06:57, xxxxxxxx wrote:
Originally posted by xxxxxxxx
Changing the value of a basecontainer's entry works and is updated immediately in the attribute manager.
But what I'm trying to do is to add or remove entries of the basecontainer while the tag's attributes are visible in the attribute manager. Then those added or removed entries should also be visibly (the GUI-elements) added or removed in the attribute manager's view.What I am doing here is to store all the data of the dynamic description elements in a sub-container in the object's container. So in my message method I just store the number of dynamic description elements and the initialized values for the dynamic elements in the sub-container of the object's container. After this I send the MSG_CHANGE message.
cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 24/11/2009 at 07:16, xxxxxxxx wrote:
Originally posted by xxxxxxxx
What I am doing here is to store all the data of the dynamic description elements in a sub-container in the object's container. So in my message method I just store the number of dynamic description elements and the initialized values for the dynamic elements in the sub-container of the object's container. After this I send the MSG_CHANGE message.
I doubt if I can follow you here... You mean you're adding gui elements just by inserting them into the basecontainer which is a subcontainer of the object's container?
Don't you have to call the Description::SetParameter function to insert a new dynamic description as I do it in my GetDDescription function?In your example, I see that you're just incrementing the count-value in the Message function when the user clicks on the button and then trigger MSG_CHANGE. But what makes the new GUI-elements appear? There must be some code called which sais: ok, the count has been incremented, now we need to create an additional checkbox and a link field and maybe a slider. Or am I missing something?
cheers
Joachimbtw.: I've added the undo as you suggested and now the behaviour is interesting: If I click on my button to add a new GUI-element, I see nothing (as before), but if I then click on undo and redo multiple times, I see the GUI element appear and disappear. So the undo and redo obviously makes the AM call the GetDDescription function as it should be done when the user clicks my button.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 24/11/2009 at 08:47, xxxxxxxx wrote:
Originally posted by xxxxxxxx
I doubt if I can follow you here... You mean you're adding gui elements just by inserting them into the basecontainer which is a subcontainer of the object's container?
Don't you have to call the Description::SetParameter function to insert a new dynamic description as I do it in my GetDDescription function?No, it's just to store the information for the dynamic description elements in the object's container to read them out in GetDDescription. This way they are saved with the document.
Here the complete code of my simple example (it's just dynamically adding Bool description elementsL.
///////////////////////////////////////////////////////////// // CINEMA 4D SDK // ///////////////////////////////////////////////////////////// // (c) 1989-2004 MAXON Computer GmbH, all rights reserved // ///////////////////////////////////////////////////////////// // morph mixing example #include "c4d.h" #include "c4d_symbols.h" #include "omorphmixer.h" // be sure to use unique IDs obtained from www.plugincafe.com #define ID_MORPHMIXER_OBJECT 1001156 enum { MORPH_CNT = 1000, MORPH_INDEX }; class MorphMixerObject : public ObjectData { INSTANCEOF(MorphMixerObject,ObjectData) public: virtual Bool Init(GeListNode *node); virtual Bool Message(GeListNode *node, LONG type, void *data); virtual BaseObject* GetVirtualObjects(PluginObject *op, HierarchyHelp *hh); virtual Bool GetDDescription(GeListNode *node, Description *description,LONG &flags); static NodeData *Alloc(void) { return gNew MorphMixerObject; } }; Bool MorphMixerObject::Init(GeListNode *node) { BaseObject *op = (BaseObject* )node; BaseContainer *data = op->GetDataInstance(); BaseContainer main; main.SetLong(MORPH_CNT,0); data->InsData(ID_MORPHMIXER_OBJECT, main); return TRUE; } Bool MorphMixerObject::GetDDescription(GeListNode *node, Description *description,LONG &flags) { if (!description->LoadDescription(node->GetType())) return FALSE; // important to check for speedup c4d! const DescID *singleid = description->GetSingleDescID(); LONG index = MORPH_INDEX; BaseObject *op = (BaseObject* )node; BaseContainer *data = op->GetDataInstance(); BaseContainer *main = data->GetContainerInstance(ID_MORPHMIXER_OBJECT); LONG i,cnt = main->GetLong(MORPH_CNT,0); Bool initbc2 = FALSE; BaseContainer bc2; for (i=0; i<cnt; i++) { DescID cid = DescLevel(index,DTYPE_BOOL,0); if (!singleid || cid.IsPartOf(*singleid,NULL)) // important to check for speedup c4d! { if (!initbc2) { initbc2 = TRUE; bc2 = GetCustomDataTypeDefault(DTYPE_BOOL); bc2.SetLong(DESC_ANIMATE,DESC_ANIMATE_ON); bc2.SetBool(DESC_REMOVEABLE,FALSE); } bc2.SetString(DESC_NAME,"On "+LongToString(i)); bc2.SetString(DESC_SHORT_NAME,"On "+LongToString(i)); if (!description->SetParameter(cid,bc2,DescLevel(ID_OBJECTPROPERTIES))) return FALSE; } index++; } flags |= DESCFLAGS_DESC_LOADED; return SUPER::GetDDescription(node,description,flags); } Bool MorphMixerObject::Message(GeListNode *node, LONG type, void *data) { switch (type) { case MSG_DESCRIPTION_COMMAND: { DescriptionCommand *dc = (DescriptionCommand* ) data; if (dc->id[0].id==MORPHMIXER_ADD) { BaseList2D *op = (BaseList2D* ) node; BaseDocument *doc = op->GetDocument(); if (!doc) return FALSE; BaseContainer *bc = ((BaseList2D* )node)->GetDataInstance(); if (!bc) return FALSE; BaseContainer *main = bc->GetContainerInstance(ID_MORPHMIXER_OBJECT); if (!main) return FALSE; doc->StartUndo(); doc->AddUndo(UNDO_CHANGE_SMALL,node); main->SetLong(MORPH_CNT, main->GetLong(MORPH_CNT,0)+1); doc->EndUndo(); op->Message(MSG_CHANGE); } } } return SUPER::Message(node,type,data); } // create morphed object BaseObject *MorphMixerObject::GetVirtualObjects(PluginObject *op, HierarchyHelp *hh) { return NULL; } Bool RegisterMorphMixer(void) { // decide by name if the plugin shall be registered - just for user convenience String name=GeLoadString(IDS_MORPHMIXER); if (!name.Content()) return TRUE; return RegisterObjectPlugin(ID_MORPHMIXER_OBJECT,name,OBJECT_GENERATOR|OBJECT_INPUT,MorphMixerObject::Alloc,"Omorphmixer","morphmixer.tif",0); }cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 24/11/2009 at 09:51, xxxxxxxx wrote:
Thanks a lot for posting the example code, that helped to clarify the issue.
First thing is that my code isn't that different from yours, I also store the elements in a basecontainer and read from that container in the GetDDescription function to create the gui-element-descriptions.
But to be sure, I copy&pasted; your code into an empty tag-plugin. Then I ran C4D with the new plugin, created a box, attached the new tag, pushed the button and...: nothing happened!
It has exactly the same behaviour I described earlier: it just doesn't call the GetDDescription-function to update the gui-elements int the AM.Then I copy&pasted; your code into a new object-plugin. Running C4D, creating a new object of the new type and pushing the button worked as you predicted - I see a new GUI element appear each time I click the button.
Now I investigated the case with the debugger, which showed that in case of an object plugin, C4D calls the GetDDescription function right after the button is pushed, but in case of a tag plugin, it doesn't!
I guess that's a bug, isn't it?
cheers
JoachimBtw.: I'm using R11.026 on Windows XP if that was going to be the next question

-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 24/11/2009 at 10:01, xxxxxxxx wrote:
ok, thanks. I'll investigate and report back later.
cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 25/11/2009 at 02:27, xxxxxxxx wrote:
Ok, I can confirm the issue. I'll ask the developers for a solution.
cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 27/11/2009 at 06:45, xxxxxxxx wrote:
Got an answer from the developers. What you have to do is to set the tag dirty instead of sending MSG_CHANGE.
tag->SetDirty(DIRTY_DATA);Unfortunatly this is currently not very consistent, send MSG_CHANGE is OK for object but not for tags.
cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 27/11/2009 at 06:54, xxxxxxxx wrote:
Great, that indeed worked!
You're right, it's very unintuitive to assume that a tag needs another updating mechanism than an object. Especially when sending the MSG_CHANGE syntactically works.Thanks a lot for your help!