<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[IN_EXCLUDE list with virtual objects with parameters]]></title><description><![CDATA[<p dir="auto"><img src="https://developers.maxon.net/forum/assets/uploads/files/1675205669869-screenshot-2023-01-31-at-23.51.25.png" alt="Voronoi Sources Tab" class=" img-fluid img-markdown" /></p>
<p dir="auto">Hello guys!<br />
In my plugin i want to create functionality like on the Sources tab of Voronoy Fracture object. There is a InExclude list and a button below. With a button user can add to the list a "virtual" objects that no present on Object Manager. Below the button, after selecting an item in the list, appears some UI elements to edit "virtual" object data.<br />
So how it can be done? May be there is some code examples.<br />
Thank you!</p>
]]></description><link>http://developers.maxon.net/forum/topic/14370/in_exclude-list-with-virtual-objects-with-parameters</link><generator>RSS for Node</generator><lastBuildDate>Fri, 16 Oct 2026 12:27:14 GMT</lastBuildDate><atom:link href="http://developers.maxon.net/forum/topic/14370.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 31 Jan 2023 23:03:00 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to IN_EXCLUDE list with virtual objects with parameters on Thu, 02 Feb 2023 10:17:41 GMT]]></title><description><![CDATA[<p dir="auto">Thank you for response <a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/ferdinand">@<bdi>ferdinand</bdi></a>! Will try to make it with hidden tags <img src="http://developers.maxon.net/forum/assets/plugins/nodebb-plugin-emoji/emoji/android/1f914.png?v=0b8ddba251d" class="not-responsive emoji emoji-android emoji--thinking_face" style="height:23px;width:auto;vertical-align:middle" title="🤔" alt="🤔" /></p>
]]></description><link>http://developers.maxon.net/forum/post/70693</link><guid isPermaLink="true">http://developers.maxon.net/forum/post/70693</guid><dc:creator><![CDATA[mikeudin]]></dc:creator><pubDate>Thu, 02 Feb 2023 10:17:41 GMT</pubDate></item><item><title><![CDATA[Reply to IN_EXCLUDE list with virtual objects with parameters on Fri, 23 Jun 2023 12:28:00 GMT]]></title><description><![CDATA[<p dir="auto">Hello <a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/mikeudin">@<bdi>mikeudin</bdi></a>,</p>
<p dir="auto">Thank you for reaching out to us. I will split my answer into three parts, the <em>List UI</em>, the <em>Node Storage</em>, and the <em>Node UI</em>, to give it more structure. There are also no Python (or C++) examples for what you want to be done. In C++ due to the very/too specific nature of the example, in Python also due to API limitations.</p>
<p dir="auto">TLDR: What you want to do is possible with <code>NBIT_OHIDE</code> and <code>NodeData::GetDDescription</code> in Python, but depending on the nature of your nodes, it can be quite labor intensive to implement.</p>
<h4>List UI</h4>
<p dir="auto">The question here is how to display lists or trees of nodes inside another node, i.e., a description. There are multiple solutions with advantages and disadvantages.</p>
<ul>
<li>[C++/Python] <code>InExcludeData</code>: You already mentioned it, and it is a good choice, but the disadvantages are no hierarchical information, only one image/icon as additional data per node, and quite manual workflows when it comes to adding and deleting nodes. The node hosting the parameter must create new nodes and also make sure that they are deleted when they have been removed from the <code>InExcludeData</code>.</li>
<li>[C++] <code>customgui_itemtree</code>: This is a semi-public type used by multiple of the character animation tools, and used to display trees or lists of things. The data type is <code>ItemTreeData</code>. Here you have more control over the UI with its flags and can also display trees.</li>
<li>[C++] <code>iCustomGui</code>: The most versatile variant is to create your own custom GUI, building for example on top of <code>c4d_listview.h</code>. The only drawback is here that it is time consuming to implement a custom GUI.</li>
</ul>
<h4>Node Storage</h4>
<p dir="auto">The question here is how to store nodes in a scene, there are again two approaches whose viability heavily depends on the type of node one does implement.</p>
<ul>
<li>[C++/Python] <code>NBIT_OHIDE</code>. With <code>GeListNode.ChangeNBit</code> and <code>NBIT_OHIDE</code> you can hide objects, tags, and materials from the object and material manager. They will still be visible in the viewport (you can change that too with <code>NBIT_EHIDE</code>) but the user will otherwise not be aware of them. The disadvantage is data garbage here. What happens to these hidden nodes when the node managing them is being deleted? In cases such as a <code>BaseObject</code> instance managing hidden <code>BaseTag</code> instances on itself, this is no problem and an internally frequently used technique because the tags will always be deleted and moved with the tag. A <code>BaseObject</code> which holds hidden nodes as its direct children is likely also fine, but a <code>BaseObject</code> which has hidden materials or inserts hidden objects at the scene root is prone to inflating scenes with garbage data on deletion, being copied, etc.</li>
<li>[C++] Branching: The natural answer to this problem is branching, we recently talked about it <a href="https://developers.maxon.net/forum/topic/14298/unpacking-animation-data-wrapped-by-the-motion-system-nla/3" target="_blank" rel="noopener noreferrer nofollow ugc">here</a>. The link shows the example case of 'Motion System' tags which holds a custom branch holding the motion data as objects. Accessing and populating custom branches is possible in Python, but implementing them is not, due to <code>NodeData::GetBranchInfo</code> not being exposed/overwritable in Python. Find a brief example for C++ at the end of this posting. We will add <code>NodeData::GetBranchInfo</code>  in an upcoming release for Python.</li>
</ul>
<h4>Node UI</h4>
<p dir="auto">Here it is about displaying a node inside the UI of another node. The natural GUI for that is <code>DescriptionCustomGui</code> but it cannot be used directly inside a description. There are again multiple options here.</p>
<ul>
<li>[C++/Python] <code>NodeData::GetDDescription</code>: Here you basically have a group inside your description, which upon the right (when the description single ID is equal to the group ID) <code>GetDDescription</code> call is being flushed and then manually repopulated with gadgets for the currently selected item. We have some <a href="https://github.com/search?l=Python&amp;q=org%3APluginCafe+GetDDescription&amp;type=Code" target="_blank" rel="noopener noreferrer nofollow ugc">examples</a> for this, but when your to be displayed node has more than two or three parameters, I would really not recommend doing this, as it will be quite a bit of work.</li>
<li>[C++/Python] <code>BaseLink</code>: You can use a <code>BaseLink</code> parameter with the <code>LINKBOX_NODE_MODE</code> flag to hide the link field of the link, giving you a result close to the native <code>DescriptionCustomGui</code>. You would have still to use <code>NodeData::GetDDescription</code> to make sure the parameter is/keeps unfolded (should be the field <code>DESC_GUIOPEN</code>).</li>
<li>[C++] <code>iCustomGui</code>: The most versatile variant is again to create your own custom GUI, for example targeting the <code>BaseLink</code> data type. Here you can then use <code>DescriptionCustomGui</code>.</li>
</ul>
<p dir="auto">Cheers,<br />
Ferdinand</p>
<p dir="auto">The custom branching example. I lifted the code from the answer to a question which reached us via mail, I just obfuscated the user code a bit and added stuff specific for this case here:</p>
<pre><code class="language-cpp">/// @short Inspects the passed in tag for having an ID_STUFF_OBJECT branch.
/// @details This is an example for accessing custom branching data.
maxon::Result&lt;void&gt; InspectStuffTag(BaseTag* const tag)
{
    iferr_scope_handler
    {
        ApplicationOutput("@: @", MAXON_FUNCTIONNAME, err);
        return err;
    };

    // When this is not a StuffTag, i.e., the only thing which can hold ID_STUFF_OBJECT branches.
    if (MAXON_UNLIKELY(!tag || tag-&gt;GetType() != ID_STUFF_TAG))
        return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION, "Passed tag is not a stuff tag."_s);

    GeListHead* stuffBranchHead (nullptr); // Will hold the ID_STUFF_OBJECT branch head.
    BaseObject* firstStuffObject (nullptr); // Will hold the first StuffObject in that branch.

    // Get the branches for the tag. A maximum of 24 branches is very generous and will never be
    // exceeded by native Cinema 4D nodes (there could always be a rogue 3rd-party plugin which is 
    // creating hundreds of branches on its node type, but that is very unlikely).
    BranchInfo branches[24];
    Int32 count = tag-&gt;GetBranchInfo(branches, 24, GETBRANCHINFO::GELISTNODES);

    // Iterate over the branches to find our "Stuff Objects" branch.
    for (Int32 i = 0; i &lt; count; i++)
    {
        GeListHead* const head = branches[i].head;
        GeListNode* const firstChild = head-&gt;GetFirst();

        ApplicationOutput(
            "Branch @ | name: @, id: @, head: @{X}", 
            i, branches[i].name, branches[i].id, (void*)branches[i].head);

        // Continue searching when the branch is not ID_STUFF_OBJECT.
        if (branches[i].id != ID_STUFF_OBJECT)
            continue;

        // Will always be there when the branch does exist.
        stuffBranchHead = head;
        // Can be the null pointer as branches are commonly empty.
        firstStuffObject = static_cast&lt;BaseObject*&gt;(firstChild);

        break;
    }

    // Will always trigger when we did not implement StuffTag::GetBranchInfo().
    if (!stuffBranchHead)
    {
        return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not find stuff branch for tag."_s);
    }
    else
    {
        // Print out the stuff tag, its stuff object branch head, and the first object in it.
        ApplicationOutput("Stuff Tag: @", tag);
        ApplicationOutput("Stuff Branch Head: @", stuffBranchHead);
        ApplicationOutput("Stuff Branch First Object: @", firstStuffObject); 
    }

    return maxon::OK;
}

// -------------------------------------------------------------------------------------------------

class StuffTag : public TagData
{
    INSTANCEOF(StuffTag , TagData);

public:
    StuffTag();
    virtual ~StuffTag();
    virtual Bool Init(GeListNode* node);
    virtual Int32 GetBranchInfo(GeListNode* node, BranchInfo* info, Int32 max, GETBRANCHINFO flags);

    bool AddObject(BaseObject* obj);

    static NodeData* Alloc() { return NewObjClear(StuffTag); }

private:
    AutoAlloc&lt;GeListHead&gt; _head; // The list head for our custom object branch.
};


/// @short Called by Cinema 4D to traverse the branches of a node.
/// @details Used in this case to expose the GeListHead _head as an ID_STUFF_OBJECT branch of the
/// node.
Int32 StuffTag::GetBranchInfo(GeListNode* node, BranchInfo* info, Int32 max, GETBRANCHINFO flags)
{
    // Get out when the tag has not established yet the field with the GeListHead holding the 
    // objects or when this GetBranchInfo() was called for less than one element (does not make too
    // much sense in this case, but could if you would want to have more than one custom branch).
    if (!_head || max &lt; 1)
        return 0;

    info[0].head = _head;                  // The list head for the new branch, holding its content, 
                                           // in this case objects.
    info[0].id = ID_STUFF_OBJECT;          // The ID of the branch. It is usually the ID of the base
                                           // class of the things contained in the branch, e.g., 
                                           // Obase. Here we customized it and used instead the custom
                                           // ID_STUFF_OBJECT ID. Which will cause the branch to be
                                           // be invisible for someone searching for Obase branches.
    info[0].name = "stuff"_s;              // A label for humans for the branch.
    info[0].flags = BRANCHINFOFLAGS::NONE; // The flags for this branch, see docs for details.

    return 1;
}

/// @brief Adds an object to the custom stuff object branch of the tag.
/// @details All objects are handled as a flat list in this simple scenario.
bool StuffTag::AddObject(BaseObject* obj)
{
    if(!obj | !_head)
        return false;

    _head.InsertLast(obj);
    return true;
}
</code></pre>
]]></description><link>http://developers.maxon.net/forum/post/70676</link><guid isPermaLink="true">http://developers.maxon.net/forum/post/70676</guid><dc:creator><![CDATA[ferdinand]]></dc:creator><pubDate>Fri, 23 Jun 2023 12:28:00 GMT</pubDate></item></channel></rss>