Solved FieldList Enable Clamping

Hi.

I'm working on a plugin that utilizes a FieldList control that I am creating using custom data type CUSTOMDATATYPE_FIELDLIST. My issue comes in with the "Enable/Disable Value Clamping" control and not being able to change it using code.

I've looked through the sdk in relation to the FieldList entry and couldn't find anything that refrences it. The closest thing I could find was the FIELDLIST_FLAGS::CLAMPOUTPUT which not suprisingly had no effect on the control when used with SetFlags.

This is my code for creating my FieldList control.

	DescID DescFieldGroup = DescLevel(idFieldGroup, DTYPE_GROUP, 0);
	if (!singleid || DescFieldGroup.IsPartOf(*singleid, NULL))
	{
		BaseContainer bc;
		bc = GetCustomDataTypeDefault(DTYPE_GROUP);
		bc.SetInt32(DESC_COLUMNS, 1);
		bc.SetBool(DESC_SCALEH, TRUE);
		if (!description->SetParameter(DescFieldGroup, bc, idMainGroup))
			return TRUE;
	}
	cid = DescLevel(idGrowField, CUSTOMDATATYPE_FIELDLIST, 0);
	if (!singleid || cid.IsPartOf(*singleid, NULL))
	{

		BaseContainer bc;
		bc = GetCustomDataTypeDefault(CUSTOMDATATYPE_FIELDLIST);
		bc.SetBool(DESC_FIELDLIST_NOCOLOR, TRUE);
		
		bc.SetBool(DESC_FIELDLIST_NODIRECTION, TRUE);
		bc.SetBool(DESC_FIELDLIST_NOROTATION, TRUE);

		if (!description->SetParameter(cid, bc, DescFieldGroup))
			return TRUE;
	}

Is it possible to change the control via code or can it only be changed manually by a user.

Any help would be greatly appreciated.

John Terenece

hi,

It is not clear what parameter you want to modify. The code you are sharing is inside GetDDescription i suppose.
You need to user SetParameter on your node itself. The tricky part is to build the DescID to target the right parameter.
You need the ID of your fieldList, the ID of the layer on that list and the parameter ID on that layer. All level must be defined as CUSTOMDATATYPE_FIELDLIST.

You must search for the layer inside your field list and call GetUniqueID on it. This will return the correct ID you must use in your DescLevel. Below a script that will flip/flop the parameter "enable/value" for the first layer in the list.
7be77196-b02c-4830-8ea6-6fbf8fef22bd-image.png

I created a python script for r20 and for more recent version

R20 version


import c4d

def main():
    # Called when the plugin is selected by the user. Similar to CommandData.Execute.
    effector = op
    if effector is None:
        raise ValueError("there is no active objet")
    
    fieldList  = effector[c4d.FIELDS]
    root = fieldList.GetLayersRoot()
    clampLayer = root.GetDown()
    
    # Retriving the unique ID allows to construct the DescID to target the right parameter.
    clampUniqueID = clampLayer.GetUniqueID()
    
    # Building the DescID
    # This ID is composed of three level:
    # the first one define the field list parameter,
    # the second define  the layer, that is why we need its UniqueID,
    # the last level define the parameter in this layer.
    # Note that all DescLevel are of DataType CUSTOMDATATYPE_FIELDLIST
    enableID = c4d.DescID(c4d.DescLevel(c4d.FIELDS, c4d.CUSTOMDATATYPE_FIELDLIST), c4d.DescLevel(clampUniqueID,  c4d.CUSTOMDATATYPE_FIELDLIST),  c4d.DescLevel(c4d.ID_FIELDLAYER_ENABLE_VALUE, c4d.CUSTOMDATATYPE_FIELDLIST))

    # Retreving the value using GetParameter on the effector itself.
    value  = effector.GetParameter(enableID, c4d.DESCFLAGS_GET_NONE)
    # Define the oposite value
    effector.SetParameter(enableID, not value, c4d.DESCFLAGS_SET_NONE)


    c4d.EventAdd()
if __name__ == '__main__':
    main()

Same example but for more recent version of c4d.

from typing import Optional
import c4d

doc: c4d.documents.BaseDocument  # The active document
op: Optional[c4d.BaseObject]  # The active object, None if unselected

def main() -> None:
    # Called when the plugin is selected by the user. Similar to CommandData.Execute.
    effector :c4d.BaseObject = op
    if effector is None:
        raise ValueError("there is no active objet")
    
    fieldList :c4d.FieldList = effector[c4d.FIELDS]
    root :c4d.GeListHead = fieldList.GetLayersRoot()
    clampLayer :c4d.modules.mograph.FieldLayer = root.GetDown()
    
    # Retriving the unique ID allows to construct the DescID to target the right parameter.
    clampUniqueID = clampLayer.GetUniqueID()
    
    # Building the DescID
    # This ID is composed of three level:
    # the first one define the field list parameter,
    # the second define  the layer, that is why we need its UniqueID,
    # the last level define the parameter in this layer.
    # Note that all DescLevel are of DataType CUSTOMDATATYPE_FIELDLIST
    enableID :c4d.DescID = c4d.DescID(c4d.DescLevel(c4d.FIELDS, c4d.CUSTOMDATATYPE_FIELDLIST), c4d.DescLevel(clampUniqueID,  c4d.CUSTOMDATATYPE_FIELDLIST),  c4d.DescLevel(c4d.ID_FIELDLAYER_ENABLE_VALUE, c4d.CUSTOMDATATYPE_FIELDLIST))

    # Retreving the value using GetParameter on the effector itself.
    value : bool  = effector.GetParameter(enableID, c4d.DESCFLAGS_GET_NONE)
    # Define the oposite value
    effector.SetParameter(enableID, not value, c4d.DESCFLAGS_SET_NONE)


    c4d.EventAdd()
if __name__ == '__main__':
    main()

Cheers,
Manuel

MAXON SDK Specialist

MAXON Registered Developer

@Manuel
Thanks for the reply.

What I'm trying to change is this control.

Clamp.png

John Terenece

hi,

for this, you must use the function SetFlags on the Field data and update the data on the object. The flag that must be set is FIELDLIST_FLAGS::CLAMPOUTPUT

Unfortunately, the UI do not update, you must deselect and reselect the object. I did not find anything yet to address this issue.
I used c++ this time to be sure nothing was wrong with python.

BaseObject* op = doc->GetActiveObject();
if (!op)
	return maxon::NullptrError(MAXON_SOURCE_LOCATION);

GeData data;
op->GetParameter(FIELDS, data, DESCFLAGS_GET::NONE);
FieldList* fl = static_cast<FieldList*>(data.GetCustomDataType(CUSTOMDATATYPE_FIELDLIST));
fl->SetFlags(FIELDLIST_FLAGS::CLAMPOUTPUT, false);
op->SetParameter(FIELDS, GeData(CUSTOMDATATYPE_FIELDLIST, *fl), DESCFLAGS_SET::NONE);

python code just in case

    fl = op[c4d.FIELDS]
    toggle = fl.CheckFlag(c4d.FIELDLIST_FLAGS_CLAMPOUTPUT)
    fl.SetFlags(c4d.FIELDLIST_FLAGS_CLAMPOUTPUT, not toggle)
    op[c4d.FIELDS] = fl

Cheers,
Manuel

MAXON SDK Specialist

MAXON Registered Developer

Thanks, that was exactly what I was looking for.

John Terenece