Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    How to Add Enum Values to a Node Attribute?

    Cinema 4D SDK
    c++ 2023
    1
    1
    317
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • ferdinandF
      ferdinand
      last edited by ferdinand

      Dear Community,

      This question reached us via mail and since answering it does not require confidential information and since I thought others find this interesting too, I am sharing my answer here. The question was How to add enum values dynamically to a node attribute that uses an Enum GUI?".

      Find my answer below.

      Cheers,
      Ferdinand

      Result:
      enum_values.gif

      Code:

      #include "c4d_basematerial.h"
      #include "maxon/datadescription_nodes.h"
      #include "maxon/graph.h"
      #include "maxon/graph_helper.h"
      #include "maxon/nodesgraph.h"
      #include "maxon/nodesystem.h"
      
      namespace maxon 
      {
        /// @brief Demonstrates how to modify the enum values of an attribute.
        /// @details One place where one could do this is inside the #::InstantiateImpl method of a 
        /// #NodeTemplateInterface one is implementing so that every new node is being populated with
        /// enum values of our liking. But as demonstrated by the example below, nothing prevents us
        /// from doing the same thing at runtime on a graph.
        Result<void> AddEnumValues(BaseDocument* doc)
        {
          iferr_scope;
          
          // Get the active material's node graph and start a transaction.
          NodeMaterial* const material = static_cast<NodeMaterial*>(doc->GetActiveMaterial());
          CheckArgument(material);
          nodes::NodesGraphModelRef graph = material->GetGraph(GetActiveNodeSpaceId()) iferr_return;
      
          GraphTransaction transaction = graph.BeginTransaction() iferr_return;
          {
            // Get the mutable root for #graph. This way is not only shorter than first getting the
            // mutable node system for #graph and then its mutable root, but also the only way that
            // actually works here. We can do this because starting a transaction on a graph model also
            // implies modifying the node system. So, we do not have to call NodeSystem::BeginModification
            // in this case.
            nodes::MutableNode root = nodes::ToMutableNode(graph.GetRoot()) iferr_return;
      
            // Iterate over all children of the root to get hold of nodes which have our port.
            for (auto node : root.GetChildren())
            {
              // Attempt to get hold of our enum port.
              nodes::MutablePort enumPort = node.GetInputs().FindPort(
                Id("in@eSp1K8T8GNcuPwKSds8Lvs")) iferr_return;
      
              // We could also add a non-existing port here with MutableNode::AddPort
              if (!enumPort || !enumPort.IsValid())
                continue;
      
              // NodeTemplateInterface::InstantiateImpl code would start here.
      
              // Set the data type and label of the port, doing this is obviously optional.
              enumPort.SetType<String>() iferr_return;
              enumPort.SetValue(NODE::BASE::NAME, "My Enumeration"_s) iferr_return;
      
              // Build the enum data and write it into the port.
              BaseArray<Tuple<Id, Data>> entries;
              for (const Int32 i : {1, 2, 3, 4, 5})
              {
                const String data = FormatString("Item @", i);
                const Id id = Id::Create(label) iferr_return;
                entries.Append(Tuple<Id, Data>(id, data)) iferr_return;
              }
      
              DataDictionary enumPortData;
              enumPortData.Set(DESCRIPTION::DATA::BASE::ENUM, entries) iferr_return;
              enumPort.SetValue(nodes::PortDescriptionData, std::move(enumPortData)) iferr_return;
      
              // And set the default value of the port.
              enumPort.SetDefaultValue("Item 1"_s) iferr_return;
            }
          // Commit the transaction and with it the node system modification.
          } transaction.Commit() iferr_return;
      
          return OK;
        }
      }
      

      MAXON SDK Specialist
      developers.maxon.net

      1 Reply Last reply Reply Quote 3
      • First post
        Last post