Change UserData ID#?
-
On 27/02/2013 at 13:14, xxxxxxxx wrote:
User Information:
Cinema 4D Version: 13
Platform: Windows ;
Language(s) : C++ ;---------
Hi,I'm adding and deleting UserData items in my plugin. But the way the ID#s stay local to each UD item. That is throwing everything out of sync when I delete them.
In order to keep everything in sync in my plugin. I need to force the UserData items ID#s to always be in numerical order as they exist in the stack.How do we change the DescLevel() values of UserData items?
BaseObject *obj = doc->GetActiveObject(); DynamicDescription *ud = obj->GetDynamicDescription(); DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), DescLevel(3)); //<----I want to change this value from 3 to 2
Also.
What's the deal with GetDepth()?
Instead of returning the stack position of each UD item. It gets stuck at 2.DescID dscID; const BaseContainer *bc; void *dscHnd = ud->BrowseInit(); //Initialize the Browse function counter = 1; while(ud->BrowseGetNext(dscHnd, &dscID, &bc)) //Loop through the UserData entries { DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), DescLevel(counter)); LONG level = udEntry.GetDepth(); GePrint(LongToString(level)); <---- Prints 1, 2, 2, 2, 2, etc... counter ++; } ud->BrowseFree(dscHnd);
ScottA
-
On 27/02/2013 at 13:17, xxxxxxxx wrote:
Not sure about ID numbering, but GetDepth() probably isn't getting what you think. It is getting the number of levels of a DescID (subids, basically).
-
On 28/02/2013 at 12:52, xxxxxxxx wrote:
Maxon?...Yannick?
Can we do this?
Is there no SDK function to change the UD's position on the stack?If not.
I figured out a possible way to maybe work around it by copying the user data entry. Then deleting the original.
But this is an awful lot of work to do. Just to change a UD's levelID#.
I.E. Change the UD position on the stack://Get the object or tag the UserData is on //Then get the master UserData container BaseObject *obj = doc->GetActiveObject(); DynamicDescription *ud = obj->GetDynamicDescription(); //The master UD container //Get the specific UD we want to copy DescID udSource(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), DescLevel(3)); //The UD entry to copy const BaseContainer *sourceBC = ud->Find(udSource); GeData d; obj->GetParameter(udSource, d, DESCFLAGS_GET_0); //Get the values for the gizmos in the source UD we want to copy and store them in d String name = sourceBC->GetString(DESC_NAME); //Get the name of the source UD we want to copy LONG type = sourceBC->GetLong(DESC_CUSTOMGUI); //Get the data type setting LONG unit = sourceBC->GetLong(DESC_UNIT); //Get the units setting(Real, Percent. etc..) LONG min = sourceBC->GetLong(DESC_MIN); //Get the min value LONG max = sourceBC->GetLong(DESC_MAX); //Get the max value GePrint(LongToString(max)); //<--always returns Zero!? //Now we create a brand new UserData from scratch //The copy the data from the source to the copy...Then delete the source BaseContainer CopyBC; DescID udCopy(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), DescLevel(2)); //The new ID level where the copy will end up udCopy = ud->Alloc(CopyBC); //Create the new UD object in memory only ud->FillDefaultContainer(CopyBC, type, name); //Fill the UD with some basic information and use the source's name and data type CopyBC.SetLong(DESC_UNIT, unit); //Set the units value using the source's units value in memory only CopyBC.SetLong(DESC_MIN, min); //Set the min value using the source's units value in memory only CopyBC.SetLong(DESC_MAX, max); //Set the max value using the source's units value in memory only ud->Set(udCopy, CopyBC, obj); //Execute the changes made to the UD from memory obj->SetParameter(DescID(udCopy), GeData(d), DESCFLAGS_SET_0); //Copy the gizmo values from the source UD and copy them to this new UD ud->Remove(DescID(DescLevel(ID_USERDATA),DescLevel(3))); //Delete the original(source) UserData entry SendCoreMessage(COREMSG_CINEMA, BaseContainer(COREMSG_CINEMA_FORCE_AM_UPDATE));//Update the object the UD is on to reflect the deletion(mandatory when deleting UD) if(obj->IsDirty(DIRTYFLAGS_DATA)) GePrint("Changed"); //Sends a message that the UD was changed
One small problem though. DESC_MIN & DESC_MAX are not working properly.
I can't copy these values and set them in the new copy UD.
How are we supposed to use these?-ScottA
-
On 01/03/2013 at 01:04, xxxxxxxx wrote:
Hi,
Here's how you can simply change the ID of a user data:
BaseObject *op = doc->GetActiveObject(); if (op==NULL) return FALSE; DynamicDescription *dynDesc = op->GetDynamicDescription(); if (dynDesc==NULL) return FALSE; DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), 1); const BaseContainer *data = dynDesc->Find(udEntry); if (data!=NULL) { BaseContainer bc = *data->GetClone(COPYFLAGS_0, NULL); dynDesc->Remove(udEntry); // Get the ID sub-level and increment it DescLevel level = udEntry[1]; level.id++; udEntry.PopId(); udEntry.PushId(level); dynDesc->Set(udEntry, bc, NULL); EventAdd(); }
-
On 01/03/2013 at 07:24, xxxxxxxx wrote:
Thank you sir.
I was also having trouble figuring out how to use PopId() & PushId(). And your example answered my questions about them too.
-ScottA
-
On 01/03/2013 at 13:27, xxxxxxxx wrote:
Uh Oh.
I take it back. That code doesn't work properly.While it does change the level. It also deletes the current values in the fields.
-ScottA
-
On 01/03/2013 at 14:03, xxxxxxxx wrote:
Since the code Yannick posted wacks any previous UD values.
Here is an example that uses a combination of his code and mine. Which won't delete the UserData values when changing the level value://This example creates a copy of a specific UserData entry (ID#1) with a different ID# (ID#2) (DescLevel) //Then deletes the original UD entry (optional) //This version also copies the values from the old UD to the new UD BaseObject *op = doc->GetActiveObject(); if (op==NULL) return FALSE; DynamicDescription *dynDesc = op->GetDynamicDescription(); //The master UD container if (dynDesc==NULL) return FALSE; DescID udEntry(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), 1); //The ID is #1...The first UD item on the stack const BaseContainer *data = dynDesc->Find(udEntry); //Get the data for this specific UD item if (data!=NULL) { BaseContainer bc = *data->GetClone(COPYFLAGS_0, NULL); //Get a copy of the UD's BaseContainer GeData d; op->GetParameter(udEntry, d, DESCFLAGS_GET_0); //Get the values for the gizmos in the source UD we want to copy and store them in d String name = data->GetString(DESC_NAME); //Get the name of the source UD we want to copy LONG type = data->GetLong(DESC_CUSTOMGUI); //Get the data type setting LONG unit = data->GetLong(DESC_UNIT); //Get the units setting(Real, Percent. etc..) dynDesc->Remove(udEntry); //Delete the UD entry (Note: The UD's level is still there on the stack) //We have to handle the UD's level data(DescLevel) too //Get the ID sub-level and increment it DescLevel level = udEntry[1]; //Gets the level of the UD item and assigns it to a variable level.id++; //Change the level to some other number udEntry.PopId(); //Remove the UD's level data from the stack udEntry.PushId(level); //Add the UD's new level data to the stack (this is what changes the ID#) dynDesc->Set(udEntry, bc, NULL); //Execute all these changes made to the UD from memory op->SetParameter(DescID(udEntry), GeData(d), DESCFLAGS_SET_0); //Paste the gizmo values from the original UD to this new version of the UD EventAdd(); }
-ScottA
-
On 04/03/2013 at 01:26, xxxxxxxx wrote:
Thanks for sharing your code with the complete solution.