Implementing Special Port Cases

Describes implementing special port types and node commands for a user node.

Implementing a Port Bundle

A port bundle is a port composed of multiple child ports that realize a data structure. This parent port bundle can be connected to other bundles without having to connect every nested port one by one. But nested ports can still be used and connected individually. For example, a spline object is composed of one or several vertices, but the user will only connect the spline port to another spline port without having to connect each point one by one. A port bundle is created using the resource editor in two steps. The first is to create the port bundle itself. The second step is to create a user node and insert the port bundle. To create a port bundle with two ports, follow the steps as listed out below.

  • In the database for the plugin, invoke Data Type -> Add Data Type to add a new data type and define its name as net.maxonexample.handbook.portbundle.colorandfloat.
  • Add a new attribute and include net.maxon.object.base with the check-boxes Data, UI and String checked. Update the information of the node using the buttons < or > to move to another element and come back.
  • On the attribute list, select net.maxon.object.base.name that should have an icon with an exclamation mark and define the string to Color Bundle.
  • Deselect any parameter on the attribute list and define the classification of the data type as portbundle.
  • Add a new color attribute with the identifier color with the check-boxes Data, UI and String checked. Define the datatype as color and set the string to Color. Define the Gui Type ID to net.maxon.ui.coloralpha.
  • Add a new float attribute with the identifier power with the check-boxes Data, UI and String checked. Define the datatype as float and the string to Power. Define the Gui Type ID to net.maxon.ui.number.

Now the port bundle has been created, insert it into a user node.

  • Add a new DataType and define its identifier to: net.maxsonexample.handbook.noderenderer.nodewithbundle.
  • Add a new attribute and include net.maxon.node.base. Update the information of the node using the button < or > to move to another element and come back.
  • Add a new attribute and define the datatype by clicking the v button, next to the data type field, and select Edit DataType. It will open a popup box into the port bundle identifier net.maxonexample.handbook.portbundle.colorandfloat must be entered.
  • Define a string for this attribute.
  • Cinema 4D must to be rebooted, as otherwise the port will not be visible in the Node Editor.

Implementing a Variadic Port

Variadic ports are ports which can be added at runtime by the user. This can happen in the context of a port bundle, where then the number of ports attached to the bundle can change, and in the context of true nodes, where new ports can be attached to the true node at runtime. An example for variadic ports can be found in the ports for the Gradient datatype, where each gradient knot is exposed as a variadic port in the port bundle of the Gradient port. In the resource editor, a variadic port is a regular port that is declared as variadic. An additional field is created to store the number of ports that must be created. Also, two functions must be defined as an action to add or remove a sub-port. The usage of variadic ports in conjunction with micronodes is documented in the function AddVariadicPort.

Creating a variadic port is done with the resource editor. Be sure to start Cinema 4D with the correct option, see Implementing Custom Node Spaces.

  • In the database for the plugin, invoke Data Type -> Add Data Type to add a new data type and define its name as: net.maxonexample.handbook.noderenderer.nodewithvariadic.
  • Add a new attribute and include net.maxon.node.base with the check-boxes Data, UI and String checked. Update the information of the node using the button < or > to move to another element and come back.
  • On the attribute list, select net.maxon.object.base.name that should have an icon with an exclamation mark and define the string to Node With Variadic Port.
  • Add a new attribute with the identifier handbook.variadic.color and its data type to Color. Set the classification to Input. Because only input ports can be variadic. On the string tab, define the string of that attribute as Color.
  • After the classification is defined, a new option appears called is variadic. It must to be checked to define this port as a variadic port. Once checked, two new fields appear, one named variadic count and the other variadic commands.
  • In the field Variadic Commands, add two lines. In the first, enter addvariadicport and in the second removevariadicport.
  • In the UI tab, set the Gui Type ID to net.maxon.ui.variadicport and update the information of the node using the button < or > to move to another element and come back.
  • On the attribute list, under the color attribute, there are now two attributes, one for the add and one for the remove command, define the string for the ports, select addvariadicport and define the string to Add a Color, select removevariadicport and define the string to Remove a Color.
  • Save the database and exit the Resource Editor.

The user node is now available with two buttons to add or remove a color port.

Implementing a Command Inside a Node

Nodes can have node commands associated with them. A node command provides a specific functionality for their associated node which can be executed on demand, as for example a button that must be pressed to initialize a node or to execute a custom function. Commands can be represented as buttons, but they can also be represented as menus. When the button is pressed, it will call a message to attempt to retrieve the delegate function which has been registered for that message, and execute that delegate. This message must be registered when Cinema 4D is being launched, by invoking the function RegisterMessage within the initialization macro MAXON_INITIALIZATION.

  • In the Resource Editor and the database for the plugin, invoke Data Type -> Add Data Type to add a new data type and define its name as: net.maxonexample.handbook.nodewithcommand.
  • Add a new attribute and include net.maxon.node.base. with the check-boxes Data, UI and String checked. Update the information of the node using the button < or > to move to another element and come back.
  • Add a new attribute, set the field Command to command and the Identifier field to buttoncommand.
  • Check the UI and String check-boxes in the attribute list for that new attribute.
  • In the field Command Type select button and define the label of the button in the field String.
  • Do not forget to define the field classification of the data type as a node and its menu category.

Now that the user node is defined, the function that will be used as the delegate must be created. To register the message, two command must be defined. One will be used to check if the command is enabled or not, the other will be executed when the button is pressed.

// Allow to define a series of operations that will be process,
// whenever a message is triggered to execute that function
//
static maxon::Result<void> ButtonClicked(const maxon::DataDictionary& userData,
maxon::DataDictionary& multiSelectionStorage)
{
maxon::GraphModelRef graph = userData.Get(maxon::ARGUMENTS::NODECORE::GRAPHMODEL) iferr_return;
// Node that owns the port (NODECORE::PORTPATH).
maxon::IoNodePath ioNodePath = userData.Get(maxon::ARGUMENTS::NODECORE::NODEPATH) iferr_return;
// Internal port on which the callback was registered.
maxon::NodePath nodePath = ioNodePath.first;
ApplicationOutput("Handbook Button example Message");
return maxon::OK;
}
Definition: tuple.h:611
void * userData
Definition: fileobject.h:20
return OK
Definition: apibase.h:2690
#define ApplicationOutput(formatString,...)
Definition: debugdiagnostics.h:210
#define iferr_scope
Definition: resultbase.h:1384
#define iferr_return
Definition: resultbase.h:1519

The last thing to do is to register the message. A DescriptionMessageFunction must be created to store the function that will be called.

{
// Register the function that will be executed when the button is pressed inside our node.
// The node identifier and the command identifier need to be defined.
maxonexample::HANDBOOK::NODE::NODEWITHCOMMAND::GetId(),
maxonexample::HANDBOOK::NODE::NODEWITHCOMMAND::BUTTONCOMMAND,
maxon::DESCRIPTION::UI::BASE::COMMANDCONTEXT.ENUM_NIMBUSCORE,
nullptr,
nullptr,
ButtonClicked)
return maxon::OK;
}, nullptr);
static MAXON_METHOD Result< void > RegisterMessage(const Id &dataTypeId, const Id &attributeId, const Id &cmdId, const DescriptionMessageFunction &func)
Definition: apibaseid.h:253
#define MAXON_INITIALIZATION(...)
Definition: module.h:795

Using the Show Condition Inside the Resource Editor

Parameters can be displayed or not based on a condition. This is convenient to hide some descriptions when the end user does not need to see them.

A boolean attribute can be created that has its identifier defined as showbutton and Show the button as string. Now a button attribute can be created, and its field show condition defined to the id of the parameter that will act as the condition. Once the id showbutton is entered, it will be replaced by the string of the parameter with brackets like so {Show the button}. Now, the button will be hidden by default unless the checkbox is checked.