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?
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?
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:
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.
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
. I assume you are aware of this, and this is not what you mean. Find an example below.DescriptionCustomGui
. You can use this element in dialogs directly. For descriptions (e.g. user data) you must either use a BaseLink
as a standin or implement you own CustomGui
which then uses the DescriptionCustomGui
. The latter is only possible in C++.Cheers,
Ferdinand
Copying a set of GUI elements manually:
MAXON SDK Specialist
developers.maxon.net
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:
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
.
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.
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 .
Cheers,
Ferdinand
MAXON SDK Specialist
developers.maxon.net
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:
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.