NodeData::Message() Manual

About

NodeData based Cinema API plugin classes can implement NodeData::Message() to receive various messages that are sent for several reasons. This page shows how to handle the most important messages.

Note
Messages sent to C4DAtom::Message() and received by NodeData::Message() are synchronous messages.

NodeData::Message() corresponds to C4DAtom::Message() and C4DAtom::MultiMessage().

Usage

Basics

NodeData::Message() is called by Cinema 4D to inform the plugin class about an event or to request some information from it. Additional data is handed over in form of a void pointer that has to be cast into the correct type depending on the message.

// 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
Note
If the plugin class hosts a subshader, HandleShaderMessage() must be used to relay certain messages to this subshader. Especially MSG_GETALLASSETS, MSG_RENAMETEXTURES and MSG_MULTI_CLEARSUGGESTEDFOLDER should be handled.

Filter

With C4DAtom::MultiMessage() it is possible to send messages to the complete object hierarchy or branches (see also Heads and Branches). In this case it is possible to filter certain messages so they are not sent to the child elements of the given element.

  • MSG_FILTER: A message filter that lets one block C4DAtom::MultiMessage() calls.

Return true to let the message pass and false to block it.

The data of this message is MessageFilter:

  • MessageFilter::type: The message type.
  • MessageFilter::route: Message route flags.
  • MessageFilter::data: The message data. Depends on the message type.

Data

Messages can be used to retrieve data from an entity. For generic purposes this message exists:

The data of this message is RetrievePrivateData:

  • RetrievePrivateData::flags: Custom flags.
  • RetrievePrivateData::data: Custom data pointer.
// This example sends MSG_RETRIEVEPRIVATEDATA to the generator to get its internal data.
RetrievePrivateData data;
data.flags = 0;
data.data = nullptr;
// send message to retrieve private data
if (object->Message(MSG_RETRIEVEPRIVATEDATA, &data))
{
// got data
if (data.data != nullptr)
{
Int32* const value = static_cast<Int32*>(data.data);
ApplicationOutput("Got value: @"_s, *value);
}
}
PyObject * value
Definition: abstract.h:715
#define MSG_RETRIEVEPRIVATEDATA
A generic private message to retrieve data from an object. Specific for every type of object so no pu...
Definition: c4d_baselist.h:418
#define ApplicationOutput(formatString,...)
Definition: debugdiagnostics.h:204
Definition: object.h:105
// This example receives a MSG_RETRIEVEPRIVATEDATA message
// and sets the pointer to the internal data.
{
RetrievePrivateData* const pdata = static_cast<RetrievePrivateData*>(data);
if (pdata)
{
pdata->data = &(this->_value);
return true;
}
break;
}

Assets

Plugins use external assets typically by referencing the asset file in a Filename parameter. When the document is saved with "Save Project with Assets" or is rendered via Team Render these assets have to be collected. To collect these assets Cinema 4D sends these messages to all scene elements:

Warning
MSG_GETALLASSETS is not sent to MaterialData plugins.
// This example adds the file path stored in a parameter to the asset list.
{
AssetData* const assetData = static_cast<AssetData*>(data);
if (assetData == nullptr)
return true;
// checks if only texture assets should be added
if (assetData->_flags & ASSETDATA_FLAG::TEXTURESONLY)
return true;
BaseList2D* const baseList2D = static_cast<BaseList2D*>(node);
if (baseList2D)
{
// get the file name
const Filename path = baseList2D->GetDataInstanceRef().GetFilename(EXAMPLE_GENERATOR_PARAMETER_FILE);
// check if the file name is set
if (path.IsPopulated())
{
// add the file name
assetData->Add(path, nullptr);
}
}
break;
}
// This example removes the folder part of the file path of the object's parameter.
{
BaseContainer& bc = (static_cast<BaseList2D*>(node))->GetDataInstanceRef();
const Filename path = bc.GetFilename(EXAMPLE_GENERATOR_PARAMETER_FILE);
// check if the directory part of the path contains anything
if (path.GetDirectory().IsPopulated())
{
bc.SetFilename(EXAMPLE_GENERATOR_PARAMETER_FILE, path.GetFile());
}
break;
}
TEXTURESONLY
Only return texture assets.
Definition: ge_prepass.h:2
#define MSG_MULTI_CLEARSUGGESTEDFOLDER
Definition: c4d_baselist.h:570
#define MSG_GETALLASSETS
Definition: c4d_shader.h:1209
struct _node node

Further asset related messages are:

  • MSG_MULTI_MARKMATERIALS: When the given data is nullptr this is sent to scene elements to let them mark the materials they use (with BIT_MATMARK). Otherwise the message is sent to get material links translated, for example when a material is replaced. In this case the corresponding data is MarkMaterials. This is needed for example when an object that is using a material is copied.
  • MSG_RENAMETEXTURES: This message is sent to all scene elements when a bitmap image was renamed (e.g. by "Save Project" or by BodyPaint 3D) and all shaders etc. need to adjust the name. The message data is RenameTextureMessage.

See also BaseDocument Convert and Export and Disc I/O.

Icon

Cinema 4D sends a message to ObjectData and TagData based plugins so they can change their icon dynamically.

The data of this message is GetCustomIconData:

  • GetCustomIconData::dat: The icon data.
  • GetCustomIconData::filled: Set this to true if the icon data was changed or set.
// This example simply sets a standard icon as the object's icon.
{
// get data
GetCustomIconData* const iconData = static_cast<GetCustomIconData*>(data);
if (iconData == nullptr)
return true;
// set as filled
iconData->filled = true;
// load a standard Cinema icon
return GetIcon(RESOURCEIMAGE_OK, iconData->dat);
}
#define MSG_GETCUSTOMICON
Every atom can return a custom icon with this message. The corresponding data is GetCustomIconData.
Definition: c4d_baselist.h:472
#define RESOURCEIMAGE_OK
Definition: ge_prepass.h:3723
Bool GetIcon(Int32 lIconID, IconData *pData)

An object or tag can include the ID_BASELIST_ICON_SETTINGS_GROUP parameter group. It is possible to add a custom color mode to that group and to define that custom color when reacting to MSG_GETCUSTOMICON.

// This example adds a new color mode to the object's "Icon Settings" in the Init() function.
BaseObject* const op = static_cast<BaseObject*>(node);
BaseContainer* const bc = op->GetDataInstance();
// add custom color mode
BaseContainer iconSettings, iconSpecialModes;
iconSpecialModes.SetString(0, "Custom Color Mode"_s);
iconSettings.SetContainer(ID_ICONCHOOSER_SETTINGS_SPECIALCASES, iconSpecialModes);
// set icon settings container into baselist2d data container
bc->SetContainer(ID_ICONCHOOSER_SETTINGS, iconSettings);
// default color mode: custom mode
#define ID_ICONCHOOSER_SETTINGS
Id to store icon settings data into BaseList2D basecontainer.
Definition: customgui_iconchooser.h:28
@ ID_ICONCHOOSER_SETTINGS_SPECIALCASES
Definition: customgui_iconchooser.h:32
@ ID_BASELIST_ICON_COLORIZE_MODE
Definition: obaselist.h:10
@ ID_BASELIST_ICON_COLORIZE_MODE_CUSTOM
Definition: obaselist.h:12
PyObject * op
Definition: object.h:520
// This example defines the color of the custom color mode as well as the ID of the used icon.
{
GetCustomIconData* const cid = static_cast<GetCustomIconData*>(data);
if (cid == nullptr)
return false;
BaseObject* const baseObject = static_cast<BaseObject*>(node);
const BaseContainer& bc = baseObject->GetDataInstanceRef();
// define color for custom color mode
CustomIconSettings settings;
FillCustomIconSettingsFromBaseList2D(settings, bc, node->GetType(), true);
settings._specialColors.Resize(1) iferr_ignore("Can't do anything about it here."_s);
// get some float value from the object itself
GeData parameterData;
node->GetParameter(ConstDescID(DescLevel(ICONTEST_OBJECT_VALUE)), parameterData, DESCFLAGS_GET::NONE);
// create RGB value for custom color mode
const maxon::Float value = parameterData.GetFloat() / 360.0;
const maxon::Color hsv { value, 1.0, 1.0 };
const maxon::Color rgb = maxon::HsvToRgb(hsv);
// set custom color
settings._specialColors[0] = rgb;
// callback defining the icon ID
CustomIconGetIdDelegate getIdCallback = [node]() -> Int32
{
// read a parameter from the object
GeData data;
node->GetParameter(ConstDescID(DescLevel(ICONTEST_OBJECT_ID)), data, DESCFLAGS_GET::NONE);
const Int32 id = data.GetInt32();
// set the icon ID based on that parameter value
if (id > 0)
return Ocube;
return Osphere;
};
// define custom ID
GetCustomIcon(*cid, settings, false, &getIdCallback);
break;
}
NONE
Definition: asset_browser.h:1
Float64 Float
Definition: apibase.h:196
#define Ocube
Cube.
Definition: ge_prepass.h:1118
#define Osphere
Sphere.
Definition: ge_prepass.h:1119
#define ConstDescID(...)
Definition: lib_description.h:592
Bool GetCustomIcon(GetCustomIconData &cid, const CustomIconSettings &settings, Bool drawBeforeColoring=false, CustomIconGetIdDelegate *getIdCallback=nullptr, CustomIconDrawDelegate *drawCallback=nullptr)
maxon::Delegate< Int32()> CustomIconGetIdDelegate
Definition: customgui_iconchooser.h:38
void FillCustomIconSettingsFromBaseList2D(CustomIconSettings &settings, const BaseContainer &data, Int32 defaultIconId, Bool fillDefault)
Private.
MAXON_ATTRIBUTE_FORCE_INLINE COLORTYPE HsvToRgb(const COLORTYPE &hsv)
Definition: gfx_image_functions_color_conversions.h:51
#define iferr_ignore(...)
Definition: resultbase.h:1496

Interaction

It is possible to drag and drop something onto objects and tags in the Object Manager. These elements are informed about this event with this message:

  • MSG_DRAGANDDROP: Received by an element in the Object Manager when something is dropped on it. The corresponding data is DragAndDrop.
// This example checks if the file dropped onto an object is neither image nor scene file.
// If so, the file path will be stored in one of the object's parameters.
{
// get data
DragAndDrop* const dnd = static_cast<DragAndDrop*>(data);
if (dnd == nullptr)
return false;
// ignore this when the object itself is dragged
if (dnd->flags & DRAGANDDROP_FLAG_SOURCE)
return true;
// check if a file (scene or image) is dragged onto the object
const Bool typeIsNotFilename = dnd->type != DRAGTYPE_FILENAME_OTHER;
const Bool dataNotSet = dnd->data == nullptr;
if (typeIsNotFilename || dataNotSet)
return false;
// drop
if (dnd->flags & DRAGANDDROP_FLAG_DROP)
{
// get filename
Filename* const file = static_cast<Filename*>(dnd->data);
// set parameter
node->SetParameter(ConstDescID(DescLevel(EXAMPLE_GENERATOR_PARAMETER_FILE)), *file, DESCFLAGS_SET::NONE);
}
dnd->flags |= DRAGANDDROP_FLAG_ACCEPT;
return true;
}
@ DRAGTYPE_FILENAME_OTHER
Other filename.
Definition: gui.h:790
#define DRAGANDDROP_FLAG_SOURCE
Drag and drop message is send to the source objects (objects that were dragged).
Definition: c4d_baselist.h:964
#define DRAGANDDROP_FLAG_ACCEPT
Accept.
Definition: c4d_baselist.h:960
#define DRAGANDDROP_FLAG_DROP
Drop.
Definition: c4d_baselist.h:959
#define MSG_DRAGANDDROP
Received by an element in the Object manager when something is dropped on it. The corresponding data ...
Definition: c4d_baselist.h:477
const char const char const char * file
Definition: object.h:439

When the user double clicks on an icon in the Object Manger this message is sent to the corresponding element.

  • MSG_EDIT: Allows elements to do some action if the user edits the element. This is also triggered by calling BaseList2D::Edit() (see BaseList2D Functionality).
// This example simply opens a message dialog when one
// double-clicks on the icon in the Object Manager.
case MSG_EDIT:
{
MessageDialog("You double-clicked on this object!"_s);
break;
}
#define MSG_EDIT
Allows elements to do some action if the user edits the element (double-click e.g....
Definition: c4d_baselist.h:416
void MessageDialog(const maxon::String &str)

Attribute Manager Interaction

Users edit scene elements and their parameters with the Attribute Manager. The Attribute Manager sends multiple messages to the edited object to inform about the interaction.

  • MSG_DESCRIPTION_CHECKDRAGANDDROP: Asks the element if a drag and drop onto for example a LINK description element or IN_EXCLUDE description element field should be accepted. Note that not all parameter types that might appear eligible do support this message, it is for example not supported by FieldList parameters. The corresponding data is DescriptionCheckDragAndDrop.
  • MSG_DESCRIPTION_INITUNDO: Allows elements to create undo actions for the following parameter changes in the Attribute Manager.
  • MSG_DESCRIPTION_POSTSETPARAMETER: Sent after a C4DAtom::SetParameter() call. The corresponding data is DescriptionPostSetValue.
  • MSG_DESCRIPTION_COMMAND: Sent when a button in the parameter description was pressed. Data is DescriptionCommand.
  • MSG_DESCRIPTION_CHECKUPDATE: Allows elements to determine the type of refresh after a parameter has been changed in the active manager. The corresponding data is DescriptionCheckUpdate.
  • MSG_DESCRIPTION_VALIDATE: Allows to update dependencies or to check for invalid values after a parameter has been changed. The corresponding data is DescriptionValidate.
  • MSG_DESCRIPTION_USERINTERACTION_END: End of user interaction.
// This example just opens a message dialog when a button was pressed.
{
DescriptionCommand* const dc = (DescriptionCommand*)data;
if (dc == nullptr)
return false;
// check the ID of the pressed button
if (dc->_descId[0].id == EXAMPLE_GENERATOR_BUTTON)
{
MessageDialog("You pressed the button."_s);
}
break;
}
#define MSG_DESCRIPTION_COMMAND
Sent by for example BUTTON description element. The corresponding data is DescriptionCommand.
Definition: c4d_baselist.h:408

Further messages are:

  • MSG_DESCRIPTION_POPUP: Allows popup menu handling in the Attribute Manager. The corresponding data is DescriptionPopup.
  • MSG_DESCRIPTION_EDIT_ENTRY: Sent when a userdata parameter was edited. The corresponding data is DescriptionCommand.
  • MSG_DESCRIPTION_REMOVE_ENTRY: Sent when a userdata parameter was removed. The corresponding data is DescriptionCommand.
  • MSG_DESCRIPTION_GETBITMAP: Queries the element for updated bitmaps for BitmapButtonCustomGui elements in the description. The corresponding data is DescriptionGetBitmap. . MSG_DESCRIPTION_CUSTOMGUI_NOTIFICATION: Sent by a custom GUI in the Attribute Manager when some internal data has changed. The corresponding data is DescriptionCustomGuiNotification.
// This example defines the content of a popup menu of a "POPUP" parameter element.
{
DescriptionPopup* const dp = static_cast<DescriptionPopup*>(data);
// check the ID of the popup element
if (dp->_descId[0] == EXAMPLE_GENERATOR_POPUP)
{
// if nothing is chosen
// the menu should be build
if (dp->_chosen == 0)
{
BaseContainer menu;
menu.InsData(1, "Options"_s);
menu.InsData(10, "Option A"_s);
menu.InsData(20, "Option B"_s);
dp->_popup.InsData(0, menu);
}
else
{
const Int32 option = dp->_chosen;
ApplicationOutput("You chose option @", option);
}
}
break;
}
#define MSG_DESCRIPTION_POPUP
Allows popup menu handling in the Attribute Manager. The corresponding data is DescriptionPopup.
Definition: c4d_baselist.h:409
// This example receives a custom GUI messages sent from
// the Attribute Manager. If the messages is sent from
// a specific custom GUI type, the message data is printed.
{
DescriptionCustomGuiNotification* dcgn = static_cast<DescriptionCustomGuiNotification*>(data);
if (dcgn)
{
// get parameter ID
const Int32 parameterID = dcgn->_descId[-1].id;
ApplicationOutput("Message from parameter: " + String::IntToString(parameterID));
// check the type of custom GUI
if (dcgn->_customGuiId == ID_CUSTOMGUI_COLORSTRING_GFG)
{
// check the message ID
if (dcgn->_subId == MSG_DESCRIPTION_COLORSTRING_COLORCHANGE)
{
// get data from the message
const BaseContainer* messageData = dcgn->_data;
if (messageData)
{
const Vector color = messageData->GetVector(MSG_DESCRIPTION_COLORSTRING_COLOR);
ApplicationOutput("New Color: " + String::VectorToString(color));
}
}
}
}
break;
}
#define MSG_DESCRIPTION_CUSTOMGUI_NOTIFICATION
Sent by a custom GUI to the parent. The corresponding data is DescriptionCustomGuiNotification.
Definition: c4d_baselist.h:438
maxon::Vec3< maxon::Float64, 1 > Vector
Definition: ge_math.h:140

See also Description Notifications.

These messages are related to the Take system:

  • MSG_DESCRIPTION_ALLOWOVERRIDE: Sent before the Take system overrides a value. Can be used to forbid an override. The corresponding data is DescriptionAllowOverride.
  • MSG_DESCRIPTION_TAKECHANGED: Sent to each overridden node when the user changes the current Take. Sent to both the node storing the data in the Take and the node releasing the data to the document. The corresponding data is DescriptionTakeChanged.

Creation

  • MSG_MENUPREPARE: Allows tags, objects, shaders etc. to do some setup work when called from the menu. The corresponding data is the current BaseDocument. Is called before the object is added to the document.
// This example adds a tag to the object when it is created from the menu.
{
BaseObject* const op = static_cast<BaseObject*>(node);
BaseTag* const annotationTag = op->MakeTag(Tannotation);
if (annotationTag)
{
const String annotation { "This is a new object." };
annotationTag->SetParameter(ConstDescID(DescLevel(ANNOTATIONTAG_TEXT)), annotation, DESCFLAGS_SET::NONE);
}
break;
}
#define MSG_MENUPREPARE
Allows tags, objects, shaders etc. to do some setup work when called from the menu....
Definition: c4d_baselist.h:417
#define Tannotation
Annotation.
Definition: ge_prepass.h:1426
@ ANNOTATIONTAG_TEXT
Definition: tannotation.h:21

Document Related

Certain events trigger a broadcast message that is sent to all elements of a BaseDocument.

  • MSG_DOCUMENTINFO: Sent by the document when it is loaded, saved, merged etc. The corresponding data is DocumentInfoData.

Some messages are just send to SceneHookData plugins. See also BaseDocument::SendInfo().

// This example catches MSG_DOCUMENTINFO in a ObjectData::Message() function.
// When the document is loaded the value of a old (legacy) parameter is copied
// into a new parameter.
{
DocumentInfoData* const msg = static_cast<DocumentInfoData*>(data);
if (msg == nullptr)
return false;
// switch message sub-type
switch (msg->type)
{
{
BaseObject* const op = static_cast<BaseObject*>(node);
if (!op)
return false;
BaseContainer& bc = op->GetDataInstanceRef();
bc.SetInt32(NEW_PARAMETER, bc.GetInt32(OLD_PARAMETER));
ApplicationOutput("document is loaded"_s);
break;
}
}
break;
}
#define MSG_DOCUMENTINFO_TYPE_LOAD
Document was loaded.
Definition: c4d_baselist.h:493
#define MSG_DOCUMENTINFO
Sent as broadcast message by the document when it is loaded, saved , merged etc. The corresponding da...
Definition: c4d_baselist.h:482
const char const char * msg
Definition: object.h:438

Also these messages are sent to all elements:

A special message is sent when the element is animated:

  • MSG_ANIMATE: Sent to elements after they have been animated. Only sent to objects with keyframes.

Further Reading