Open Search
    Description Manual

    About

    A Description object stores information on how C4DAtom parameters are to be displayed in the GUI (Attribute Manager). It contains information on:

    • the parameter type and valid parameter values.
    • optional information on the (custom) GUI that is used to display the parameter in the Attribute Manager.

    The information is stored using description setting IDs, see Description Settings Manual.

    Note
    A Description is displayed in a GeDialog using the DescriptionCustomGui custom GUI element.
    User data parameters are stored in a DynamicDescription object, see DynamicDescription Manual.

    Access

    To add dynamic parameters to a NodeData based plugin one can implement NodeData::GetDDescription(). This function receives a given Description object that should be filled with the description of the visible parameters.

    See NodeData::GetDDescription() Manual.

    // This example defines the element's parameter description by loading the registered description of the plugin type.
    virtual Bool GetDDescription(const GeListNode* node, Description* description, DESCFLAGS_DESC& flags) const
    {
    const Bool invalidNode = node == nullptr;
    const Bool invalidDescription = description == nullptr;
    if (invalidNode || invalidDescription)
    return false;
    // load the description of this type
    if (description->LoadDescription(node->GetType()) == false)
    return false;
    return SUPER::GetDDescription(node, description, flags);
    }
    PyCompilerFlags * flags
    Definition: ast.h:14
    LOADED
    Set if elements have been added to the description, either by loading or manual addition.
    Definition: ge_prepass.h:2
    DESCFLAGS_DESC
    Definition: ge_prepass.h:3358
    maxon::Bool Bool
    Definition: ge_sys_math.h:46
    Definition: node.h:10

    Correspondingly it is possible to get the parameter description from a C4DAtom:

    • C4DAtom::GetDescription(): Gets the currently used parameter description of the entity.

    See C4DAtom Parameter Properties.

    // This example prints the names of all parameters in the current parameter description.
    AutoAlloc<Description> description;
    if (description == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    // get the Description of the given object
    if (!object->GetDescription(description, DESCFLAGS_DESC::NONE))
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    void* handle = description->BrowseInit();
    const BaseContainer* bc = nullptr;
    DescID id, gid;
    // loop through all elements of the description
    while (description->GetNext(handle, &bc, id, gid))
    {
    ApplicationOutput("Parameter Name: " + bc->GetString(DESC_NAME));
    }
    description->BrowseFree(handle);
    NONE
    Definition: asset_browser.h:1
    @ DESC_NAME
    String Name for standalone use.
    Definition: lib_description.h:90
    #define MAXON_SOURCE_LOCATION
    Definition: memoryallocationbase.h:69
    #define ApplicationOutput(formatString,...)
    Definition: debugdiagnostics.h:204
    Definition: object.h:105

    Allocation/Deallocation

    A Description object can be created with the usual tools:

    • Description::Alloc(): Creates a new Description object.
    • Description::Free(): Deletes the given Description object.

    This is needed to access the parameter description of a given object:

    // This example accesses the Description of the given object.
    // check if an object is selected
    BaseObject* const activeObject = doc->GetActiveObject();
    if (activeObject == nullptr)
    return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
    // check if the Description object could be allocated
    AutoAlloc<Description> description;
    if (description == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    // read the Description from the active object
    if (activeObject->GetDescription(description, DESCFLAGS_DESC::NONE))
    {
    ApplicationOutput("Got Description");
    }
    const char * doc
    Definition: pyerrors.h:226

    Load Description

    The description of an plugin's static parameters is defined in the plugin's *.res file. This *.res file is typically registered using the "Register" function of the plugin (see Common Plugin Concepts). Such a registered description can then be loaded:

    • Description::LoadDescription(): Loads a registered Description. It is also possible to load the Descriptions of data types and custom GUIs. See Resource Files Manual.

    A custom data type can also define its own description. This sub-description (or sub-channels) can be loaded with:

    • Description::GetSubDescriptionWithData(): Loads the dynamic sub-description of the given custom data type.
    // This example reads and prints the sub-description
    // of the "Scale" spline parameter of the given "Sweep" generator.
    const DescID completeID = ConstDescID(DescLevel(SWEEPOBJECT_SPLINESCALE, CUSTOMDATATYPE_SPLINE, 0));
    // load parameter sub-description
    AutoAlloc<AtomArray> elements;
    if (elements == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    elements->Append(sweepObj);
    AutoAlloc<Description> desc;
    if (desc == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    // get plugin structure for the given resource plugin
    RESOURCEDATATYPEPLUGIN* resDataType = FindResourceDataTypePlugin(completeID[-1].dtype);
    if (resDataType == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // load sub-description
    const Bool gotSubDescription = desc->GetSubDescriptionWithData(
    completeID, elements, resDataType, BaseContainer(), nullptr);
    if (!gotSubDescription)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // print names of sub-description parameters
    void* handle = desc->BrowseInit();
    const BaseContainer* bc = nullptr;
    DescID loopID, gid;
    // loop through sub-description parameters
    while (desc->GetNext(handle, &bc, loopID, gid))
    ApplicationOutput(bc->GetString(DESC_NAME));
    desc->BrowseFree(handle);
    #define CUSTOMDATATYPE_SPLINE
    Spline data type ID.
    Definition: customgui_splinecontrol.h:29
    #define ConstDescID(...)
    Definition: lib_description.h:592
    RESOURCEDATATYPEPLUGIN * FindResourceDataTypePlugin(Int32 type)
    @ SWEEPOBJECT_SPLINESCALE
    Definition: osweep.h:20
    PyStructSequence_Desc * desc
    Definition: structseq.h:26

    Parameter Descriptions

    Edit

    In certain situations NodeData::GetDDescription() is not called to get the description of all parameters but of only one specific parameter.

    • Description::GetSingleDescID(): Returns the single DescID in single mode.

    Existing parameter descriptions are stored in BaseContainers that can be accessed with:

    • Description::GetParameter(): Returns the read-only BaseContainer describing the given parameter.
    • Description::GetParameterI(): Returns an editable BaseContainer describing the given parameter.
    Note
    The parameter IDs are described in Description Settings Manual.
    // This example changes the name of a description element.
    const DescID* const singleid = description->GetSingleDescID();
    // parameter ID
    DescID cid = ConstDescID(DescLevel(EXAMPLE_GENERATOR_BUTTON, DTYPE_BUTTON, 0));
    // check if this parameter ID is requested
    if (singleid == nullptr || cid.IsPartOf(*singleid, nullptr))
    {
    BaseContainer* settings = nullptr;
    settings = description->GetParameterI(cid, nullptr);
    if (settings)
    settings->SetString(DESC_SHORT_NAME, "New Button Name"_s);
    }
    @ DESC_SHORT_NAME
    String Short name, for attributes dialog.
    Definition: lib_description.h:91
    @ DTYPE_BUTTON
    Button.
    Definition: lib_description.h:60

    Also a new parameter description can be added:

    • Description::SetParameter(): Inserts a parameter description.
    // This example adds a new parameter description.
    const DescID* const singleid = description->GetSingleDescID();
    // add a parameter description
    DescID cid = ConstDescID(DescLevel(1003, DTYPE_REAL, 0));
    // check if this parameter ID is requested (NOTE: this check is important for speed)
    if (singleid == nullptr || cid.IsPartOf(*singleid, nullptr))
    {
    // define the new parameter description
    BaseContainer settings = GetCustomDataTypeDefault(DTYPE_REAL);
    settings.SetString(DESC_NAME, "A new parameter"_s);
    // set the new parameter
    if (!description->SetParameter(cid, settings, ConstDescID(DescLevel(ID_OBJECTPROPERTIES))))
    return;
    }
    @ DTYPE_REAL
    Float
    Definition: lib_description.h:67
    BaseContainer GetCustomDataTypeDefault(Int32 type)
    @ ID_OBJECTPROPERTIES
    Definition: obase.h:56

    Iterate

    There are two ways to iterate over all elements stored in a Description object. The first way is to loop over all stored parameters in a list:

    • Description::BrowseInit(): Starts browsing the parameters and returns the browse handle.
    • Description::GetNext(): Retrieves the next parameter description in the list.
    • Description::BrowseFree(): Frees the browse handle.
    // This example shows how to load an existing description into a temporary
    // description and to copy the data into the actual description.
    AutoAlloc<Description> tempDesc;
    // load the Description of the material preview element
    if (tempDesc && tempDesc->LoadDescription("Mpreview"))
    {
    void* handle = tempDesc->BrowseInit();
    const BaseContainer* settings = nullptr;
    DescID id, gid;
    // loop through the elements of the description
    while (tempDesc->GetNext(handle, &settings, id, gid))
    {
    description->SetParameter(id, *settings, gid);
    }
    tempDesc->BrowseFree(handle);
    }

    The other way to iterate over all elements is to navigate down the tree hierarchy defined by parameter groups:

    • Description::GetFirst(): Returns a handle to the first description entry.
    • Description::GetNext(): Returns the next description entry handle.
    • Description::GetDown(): Returns the child description entry handle.
    • Description::GetDescEntry(): Retrieves the data for a description entry handle.
    // This example loops through the top level parameter descriptions.
    BaseObject* const object = doc->GetActiveObject();
    if (object == nullptr)
    return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
    AutoAlloc<Description> description;
    if (description == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    // read the Description from the active object
    if (!object->GetDescription(description, DESCFLAGS_DESC::NONE))
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // loop through description
    // get the first element
    AutoAlloc<AtomArray> ar;
    if (ar == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    DescEntry* entry = description->GetFirst(ar);
    while (entry != nullptr)
    {
    // get element
    const BaseContainer* bc = nullptr;
    DescID descid;
    description->GetDescEntry(entry, &bc, descid);
    // print description name
    if (bc != nullptr)
    ApplicationOutput(bc->GetString(DESC_NAME));
    // handle sub-entries (elements of parameter groups etc.)
    // HandleSubEntries() is a custom function
    DescEntry* const subEntries = description->GetDown(entry);
    HandleSubEntries(subEntries);
    entry = description->GetNext(entry);
    }

    Miscellaneous

    This convenience function allows to fill the BaseContainer for a pop-up menu based on the content of the Description:

    • Description::CreatePopupMenu(): Builds a popup menu for choosing a parameter.
    // This example creates a pop up menu based on the given Description.
    BaseContainer descriptionPopUp;
    if (!description->CreatePopupMenu(descriptionPopUp))
    return maxon::UnknownError(MAXON_SOURCE_LOCATION);
    ShowPopupMenu(nullptr, MOUSEPOS, MOUSEPOS, descriptionPopUp);
    #define MOUSEPOS
    Mouse position constant for ShowPopupMenu().
    Definition: c4d_gui.h:3328
    Int32 ShowPopupMenu(CDialog *cd, Int32 screenx, Int32 screeny, const BaseContainer &bc, Int32 flags=POPUP_RIGHT|POPUP_EXECUTECOMMANDS|POPUP_ALLOW_FILTERING, Int32 *res_mainid=nullptr)

    This function allows to complete a given DescID:

    • Description::CheckDescID(): Returns true if the given ID exists in the Description.
    // This example completes the given DescID.
    const DescID incompleteID = ConstDescID(DescLevel(1110, 0, 0));
    DescID completeID;
    AutoAlloc<AtomArray> arr;
    if (arr == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    // check if the ID exists and complete it
    if (description->CheckDescID(incompleteID, arr, &completeID))
    {
    // check if the completed ID describes a float parameter
    if (completeID[-1].dtype == DTYPE_REAL)
    ApplicationOutput("This is a float parameter");
    }

    Further Reading