Open Search
    GeListNode Manual

    About

    The class GeListNode is based on C4DAtom and is a base class for many entities of the Cinema API API. It mostly provides the functionality to organize elements in linked lists and trees.

    GeListNode objects are an instance of Tgelistnode.

    Access

    • NodeData::Get(): Returns the GeListNode connected with a NodeData instance.

    NodeData::Get() is rarely needed, as a pointer to a GeListNode is typically handed over to virtual functions of NodeData and derived classes:

    // This example shows a primitive implementation of Message().
    virtual Bool Message(GeListNode* node, Int32 type, void* data)
    {
    switch (type)
    {
    case (MSG_UPDATE):
    {
    break;
    }
    // more cases
    #define MSG_UPDATE
    Must be sent if the bounding box has to be recalculated. (Otherwise use MSG_CHANGE....
    Definition: c4d_baselist.h:372
    maxon::Bool Bool
    Definition: ge_sys_math.h:46
    maxon::Int32 Int32
    Definition: ge_sys_math.h:51
    PyObject ** type
    Definition: pycore_pyerrors.h:34
    Definition: node.h:10

    GeListNode is also used in the context of object hierarchies with GeListHead elements.

    Allocation/Deallocation

    It is possible to create a GeListNode instance of a RegisterNodePlugin() registered node with

    Note
    These functions are typically not used with third party plugins. They are only useful to handle custom NodeData plugins.
    // This example allocates a node of the type ID_PYTHONSCRIPT.
    // This node can be used to execute a Python script.
    String python;
    python += "print(\"this is python\")";
    BaseList2D* op = static_cast<BaseList2D*>(AllocListNode(ID_PYTHONSCRIPT));
    if (op == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    BaseContainer& data = op->GetDataInstanceRef();
    data.SetString(PYTHONSCRIPT_TEXT, python);
    op->Message(MSG_SCRIPT_EXECUTE, nullptr);
    #define ID_PYTHONSCRIPT
    Definition: ge_prepass.h:5099
    #define MSG_SCRIPT_EXECUTE
    Execute the script. (No arguments.)
    Definition: ge_prepass.h:5149
    #define PYTHONSCRIPT_TEXT
    String Script.
    Definition: ge_prepass.h:5160
    #define MAXON_SOURCE_LOCATION
    Definition: memoryallocationbase.h:69
    GeListNode * AllocListNode(Int32 id)
    #define blDelete(v)
    Destructs objects derived from BaseList2D. It is basically the same as BaseList2D::Free().
    Definition: c4d_baselist.h:3120
    PyObject * op
    Definition: object.h:520

    Lists and Trees

    Navigation in Lists and Trees

    GeListNode based elements can be organized in lists and trees. A GeListNode based entity can reference the accompanying elements in that hierarchy. If no element is referenced, nullptr is returned.

    • GeListNode::GetNext(): Returns the next GeListNode in the list.
    • GeListNode::GetPred(): Returns the previous GeListNode in the list.
    • GeListNode::GetDown(): Returns the child GeListNode.
    • GeListNode::GetUp(): Returns the parent GeListNode.
    • GeListNode::GetDownLast(): Returns the last child GeListNode.
    Note
    Derived classes often provide overwritten versions of these functions for convenience.

    The typical Cinema 4D workflow would be:

    // This example iterates over a linked list.
    // In this case it is the list of all tags of the given BaseObject.
    // loop through all tags
    for (BaseTag* tag = object->GetFirstTag(); tag; tag = tag->GetNext())
    {
    ApplicationOutput("Tag: " + tag->GetName());
    }
    #define ApplicationOutput(formatString,...)
    Definition: debugdiagnostics.h:204
    Definition: object.h:105

    and

    // This function walks recursively over the tree of nodes.
    static void WalkTreeRec(GeListNode* node)
    {
    while (node != nullptr)
    {
    // check if the current node is a BaseList2D object
    if (node->IsInstanceOf(Tbaselist2d))
    {
    const BaseList2D* const baseList2d = static_cast<BaseList2D*>(node);
    ApplicationOutput("Name: " + baseList2d->GetName());
    }
    // check child objects
    WalkTreeRec(node->GetDown());
    // check next objects in the list
    node = node->GetNext();
    }
    }
    #define Tbaselist2d
    2D list.
    Definition: ge_prepass.h:995
    struct _node node
    Note
    Avoid unnecessary recursion to prevent a stack overflow.

    Edit Lists and Trees

    A given GeListNode can be inserted into a list or tree or it can be removed from that list or tree:

    • GeListNode::InsertBefore(): Inserts the element before the given GeListNode in the list.
    • GeListNode::InsertAfter(): Inserts the element after the given GeListNode in the list.
    • GeListNode::InsertUnder(): Inserts the element under the given GeListNode.
    • GeListNode::InsertUnderLast(): Inserts the element as the last child element under the given GeListNode.
    • GeListNode::Remove(): Removes the element from the list or tree.
    Note
    If a GeListNode is supposed to be deleted it must be removed from its list before.
    At any given time a GeListNode can only be inserted into one single list or tree. Before inserting a node into a new list, make sure to remove it from the old one.
    // This example switches the position of the given object
    // and its parent object in the object tree.
    BaseObject* const parentObject = selectedObject->GetUp();
    if (parentObject == nullptr)
    return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
    // the parent object may or may not have a parent itself
    BaseObject* const parentParent = parentObject->GetUp();
    // remove both objects from the tree
    selectedObject->Remove();
    parentObject->Remove();
    // insert the selected object
    doc->InsertObject(selectedObject, parentParent, nullptr);
    // insert the parent object as a child
    parentObject->InsertUnder(selectedObject);
    const char * doc
    Definition: pyerrors.h:226

    Heads and Branches

    A GeListHead element is used as the root of a list or tree:

    • GeListNode::GetListHead(): Returns the GeListHead root of the element's list or tree.

    See GeListHead Manual.

    A given GeListNode can host multiple internal lists and trees by storing multiple GeListHead objects, called branches. For example the list of tags is a branch of BaseObject. These branches can be accessed with this function:

    • GeListNode::GetBranchInfo(): Fills the given array with information about the element's internal branches.

    Valid flags are:

    The used BranchInfo struct has the following members:

    • BranchInfo::head: Pointer to the GeListHead element.
    • BranchInfo::name: Pointer to a String with the branch name. May be nullptr.
    • BranchInfo::id: The ID of the branch.
    • BranchInfo::flags: Branch flags

    The branch flags are:

    // This example loops through all branches of a given BaseDocument.
    // If possible the name of the first branch child object is printed.
    maxon::BufferedBaseArray<BranchInfo, 20> branches; // 20 is just an arbitrary number, that should be enough to catch all branches
    const Int32 branchCount = branches.GetCount();
    for (Int32 i = 0; i < branchCount; ++i)
    {
    ApplicationOutput("Branch " + String::IntToString(i));
    const String branchName = branches[i].name;
    ApplicationOutput(" - Name: " + branchName);
    const GeListHead* branchHead = branches[i].head;
    if (branchHead != nullptr)
    {
    const GeListNode* child = branchHead->GetFirst();
    // check if the child is a BaseList2D object
    if (child && child->IsInstanceOf(Tbaselist2d))
    {
    const BaseList2D* child2D = static_cast<const BaseList2D*>(child);
    ApplicationOutput(" - First Child Element: " + child2D->GetName());
    }
    }
    }
    Py_ssize_t i
    Definition: abstract.h:645
    ONLYWITHCHILDREN
    Only return branch if it is in use, i.e. has content.
    Definition: ge_prepass.h:1
    typename BufferedBaseArraySelector< COUNT, MINCHUNKSIZE, MEMFLAGS, ALLOCATOR >::template Type< T > BufferedBaseArray
    Definition: basearray.h:1814
    #define iferr_return
    Definition: resultbase.h:1531

    NodeData

    The base class for most Cinema API plugins is NodeData. NodeData based plugin classes build the "core" of any plugin based entity of the Cinema API API. This "core" class can be obtained with:

    • GeListNode::GetNodeData(): Gets the internal NodeData based plugin class.

    See also Basic Classes and Plugin Classes.

    // This example checks if the given object has the type of a custom plugin class.
    // If so, GetNodeData<T>() can be used to get the pointer to the plugin class.
    // check if the selected object is an "ExampleGenerator"
    if (selectedObject->GetType() == g_exampleGeneratorID)
    {
    ExampleGenerator* const exampleGenerator = selectedObject->GetNodeData<ExampleGenerator>();
    if (exampleGenerator)
    {
    exampleGenerator->MemberFunction();
    }
    }
    Warning
    It is only possible to cast the retrieved object into a specific class in the module where this class is defined.
    Some components of Cinema 4D are not implemented as a plugin so there is no NodeData instance to access.

    Document

    GeListNode based objects can also be part of a BaseDocument:

    • GeListNode::IsDocumentRelated(): Returns true if the element can be inserted directly into a document.
    • GeListNode::GetDocument(): Returns the BaseDocument that owns this element. Usually this function should be used in NodeData based plugins.
    Warning
    Always check the returned document pointer for nullptr, as the element might not be part of any document.
    // This example from a NodeData::Message() function uses
    // the BaseDocument of the given GeListNode.
    // get the document that hosts the given node
    const BaseDocument* doc = node->GetDocument();
    if (doc)
    {
    GeData geData;
    // read the BaseLink parameter from the node
    if (node->GetParameter(ConstDescID(DescLevel(EXAMPLE_GENERATOR_LINK)), geData, DESCFLAGS_GET::NONE))
    {
    // resolve the link using the received document
    const C4DAtomGoal* const atom = geData.GetLinkAtom(doc, Tbaselist2d);
    if (atom)
    {
    const BaseList2D* baseList2D = static_cast<const BaseList2D*>(atom);
    ApplicationOutput(baseList2D->GetName());
    }
    }
    }
    NONE
    Definition: asset_browser.h:1
    #define atom
    Definition: graminit.h:72
    #define ConstDescID(...)
    Definition: lib_description.h:592

    Infos

    Additional information can be accessed:

    • GeListNode::GetNodeID(): Returns the ID of a multinode with the given index. In most cases it just returns the type ID.
    • GeListNode::GetInfo(): Returns the flags defined with the "Register" function. See Registration.
    // This example casts the given BaseObject into SplineObject
    // if it is a spline or if it is a spline generator.
    SplineObject* spline = nullptr;
    // check if the object is a "Spline" object
    if (object->IsInstanceOf(Ospline))
    spline = ToSpline(object);
    // check if the object is a spline generator
    else if (object->GetInfo() & OBJECT_ISSPLINE)
    spline = object->GetRealSpline();
    if (spline != nullptr)
    ApplicationOutput("Spline Object: " + spline->GetName());
    #define OBJECT_ISSPLINE
    Spline object.
    Definition: ge_prepass.h:951
    #define Ospline
    Spline - SplineObject.
    Definition: ge_prepass.h:1042
    MAXON_ATTRIBUTE_FORCE_INLINE const SplineObject * ToSpline(const T *op)
    Casts a BaseObject* to a SplineObject*.
    Definition: c4d_baseobject.h:2405

    NBits

    Various settings of an element can be configured by changing a corresponding bit. A list of available bits is defined in ::NBIT.

    • GeListNode::GetNBit(): Returns true if the given bit is set.
    • GeListNode::ChangeNBit(): Changes the given bit.

    The change operations are:

    // This example toggles the NBIT_EHIDE of the active object.
    BaseObject* const object = doc->GetActiveObject();
    if (object == nullptr)
    return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
    object->ChangeNBit(NBIT::EHIDE, NBITCONTROL::TOGGLE);
    EHIDE
    Hide in viewport.
    Definition: ge_prepass.h:98
    TOGGLE
    Toggle bit.
    Definition: ge_prepass.h:2

    Further Reading