Your browser does not seem to support JavaScript. As a result, your viewing experience will be diminished, and you have been placed in read-only mode.
Please download a browser that supports JavaScript, or enable it if it's disabled (i.e. NoScript).
Hi,
Normally, you'd have to add specific interger, float, slider UI etc for every parameter. Manually. Just wondering if there is an an efficient way of doing a complete replica of a native objects UI?
Hey @bentraje,
Thank you for reaching out to us. The answer to this depends on what you mean by complete replica here.
User Interface > Copy User Data Interface
DescriptionCustomGui
BaseLink
CustomGui
Cheers, Ferdinand
Copying a set of GUI elements manually:
Hi @ferdinand
Thanks for the response. Yep the User Interface > Copy User Data Interface is a handy workflow. That's what I am looking but in python.
Something like.
user_data_ui = obj_a.copy_user_data_interface() obj_b.paste_user_data_interface()
Is there such an existing API for this?
===
RE: dynamically show a node I want it to be dynamic but not always. I just want to replicate the user data once.
Here's an illustration to the problem
This is why I'm trying to create dialog where it replicates the UI of the selected object. Then as I input the value it changes on the relevant objects (i.e. if the selected object is a light it will change the other lights based on a criteria). Logic wise I can by with that.
It just the replica of UI I'm troubled with. I don't want to hand code the UI for each object type hehe
Hi, @bentraje For each parameter input box, formula expressions are supported in c4d, x : represents the parameter's current value. If you want to change the intensity by 125% than their current value for each light, you can select all of them and simply input x * 1.25 . The document for Expanded Formula Entry by Multiple Selections is here:
x
x * 1.25
Hello @bentraje,
Is there such an existing API for this? user_data_ui = obj_a.copy_user_data_interface() obj_b.paste_user_data_interface()
It depends on what you would call an API. But there are no high-level functions akin to Copy/SaveGui in your example. But there is of course c4d.C4DAtom.GetDescription and the fact that you can iterate over such description, getting the data container, the "GUI", yielded for a parameter in the node. You could then add each of these description containers as a user data paramater container in your node you want to copy to. Instead of calling c4d.GetCustomDataTypeDefault to get a data type default container and then modifying it, you would use a source node parameter data container yielded by its description to call c4d.BaseList2D.AddUserData.
Copy/SaveGui
c4d.C4DAtom.GetDescription
c4d.GetCustomDataTypeDefault
c4d.BaseList2D.AddUserData
Adding the tangible parameters itself would be no problem with that. The problem are parameters of type DTYPE_GROUP. They are also yielded with the description, but you would have to remap them, as elements refer to their parent group over DESC_PARENTGROUP. So when you add the parameter Foo which in the source node was in a group with the ID 1000, DTYPE_GROUP, 0 you would have first to add the group to the target node as a user data parameter which will give you a new ID. And then for all parameters which reference that group in DESC_PARENTGROUP, replace the reference with the new ID. I do not have the time to write an example right now, if you need help with this, you would have to wait until the new year.
DTYPE_GROUP
DESC_PARENTGROUP
Foo
1000, DTYPE_GROUP, 0
Alternatively, you could also ignore groups, i.e., ignore all parameters of type DTYPE_GROUP and simply flush all group references. All in all, this can probably get a bit tricky, and you might be better off with the manual approach lined out by @iplai .
There is a third-party module to serialize and deserialize the user data of any BaseList2D object in python dict format. Here's an example:
BaseList2D
c4d.ID_USERDATA: { (c4d.ID_USERDATA, 1): { c4d.DTYPE_: c4d.DTYPE_REAL, c4d.DESC_NAME: 'Data', c4d.DESC_SHORT_NAME: 'Data', c4d.DESC_MIN: 0, c4d.DESC_MAX: 1, c4d.DESC_STEP: 0.01, c4d.DESC_UNIT: c4d.DESC_UNIT_PERCENT, c4d.DESC_CUSTOMGUI: c4d.CUSTOMGUI_REAL, c4d.DESC_PARENTGROUP: (700, 5, 0), }, (c4d.ID_USERDATA, 2): { c4d.DTYPE_: c4d.DTYPE_GROUP, c4d.DESC_NAME: 'Group', c4d.DESC_SHORT_NAME: 'Group', c4d.DESC_ANIMATE: c4d.DESC_ANIMATE_OFF, c4d.DESC_COLUMNS: 1, c4d.DESC_TITLEBAR: 1, c4d.DESC_DEFAULT: 1, c4d.DESC_PARENTGROUP: (), }, (c4d.ID_USERDATA, 3): { c4d.DTYPE_: c4d.DTYPE_LONG, c4d.DESC_NAME: 'Data', c4d.DESC_SHORT_NAME: 'Data', c4d.DESC_UNIT: c4d.DESC_UNIT_INT, c4d.DESC_CUSTOMGUI: c4d.CUSTOMGUI_LONGSLIDER, c4d.DESC_MIN: 0, c4d.DESC_MAX: 100, c4d.DESC_STEP: 1, c4d.DESC_PARENTGROUP: ((700, 5, 0), (2, 1, 0)), }, }
The module is not fully tested, but it's enough for me for my daily scripting work. The processing of parameters is implemented in a way described by @ferdinand . Sort of like the .res file used by plugins developing, the json data defines the details of a parameter. If you feel like it, you can implement it yourself by refering to following functions: DumpParams DumpParamDetails DumpUserDataDetails LoadUserData ... Considering sometimes there's a huge amount of parameters, I spent a lot of time to judge and handle dirty parameters, namely the parameter has been changed, there is still no perfect way. If you don't care whether the parameter is dirty, problem goes easier. Maybe do some filters by restricting DescLevel.creator to a specific value etc.
.res
DescLevel.creator
@iplai @ferdinand
Thanks for providing details especially the third party API. Seems like a handy utility library I'll see what I can do with it.