NodeData::Message() Manual
NodeData based classic 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.
NodeData::Message() corresponds to C4DAtom::Message() and C4DAtom::MultiMessage() .
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().// more cases
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.
返回
true
to let the message pass and
false
to block it.
The data of this message is MessageFilter :
Messages can be used to retrieve data from an entity. For generic purposes this message exists:
The data of this message is RetrievePrivateData :
// send message to retrieve private data if (object-> 消息 ( MSG_RETRIEVEPRIVATEDATA , &data)) { // got data if (data. data != nullptr ) { Int32 * const value = static_cast< Int32 * > (data. data ); ApplicationOutput ( "Got value: @" _s, *value); } }
// This example receives a MSG_RETRIEVEPRIVATEDATA message // and sets the pointer to the internal data.
case MSG_RETRIEVEPRIVATEDATA : { RetrievePrivateData * const pdata = static_cast< RetrievePrivateData * > (data); if (pdata) { pdata-> data = &(this->_value); return true ; } break ; }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:
// 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-> GetData (). GetFilename (EXAMPLE_GENERATOR_PARAMETER_FILE);
// check if the file name is set if (path. IsPopulated ()) { // add the file name assetData-> 添加 (path, nullptr ); } } break ; }
// This example removes the folder part of the file path of the object's parameter.
case MSG_MULTI_CLEARSUGGESTEDFOLDER : { 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 ; }
Further asset related messages are:
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.
另请参阅 BaseDocument Convert and Export and Disc I/O .
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 :
// set as filled iconData-> filled = true ;
// load a standard Cinema icon return GetIcon ( RESOURCEIMAGE_OK , iconData-> dat ); }
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);
// since we are going to use our custom MSG_GETCUSTOMICONS code, set this to true so parent object (e.g. BaseObject) will ignore MSG_GETCUSTOMICONS messages. iconSettings. SetBool ( ID_ICONCHOOSER_SETTINGS_PARENT_IGNORE , true );
// set icon settings container into baselist2d data container bc-> SetContainer ( ID_ICONCHOOSER_SETTINGS , iconSettings);
// default color mode: custom mode bc-> SetInt32 ( ID_BASELIST_ICON_COLORIZE_MODE , ID_BASELIST_ICON_COLORIZE_MODE_CUSTOM + 1);
// This example defines the color of the custom color mode as well as the ID of the used icon.
case ( MSG_GETCUSTOMICON ): { 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 ); 设置。 _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 (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 设置。 _specialColors [0] = rgb;
// callback defining the icon ID CustomIconGetIdDelegate getIdCallback = [node]() -> Int32 { // read a parameter from the object GeData data; node-> GetParameter (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 ; }
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:
// 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 (EXAMPLE_GENERATOR_PARAMETER_FILE, *file, DESCFLAGS_SET::NONE ); } dnd-> flags |= DRAGANDDROP_FLAG_ACCEPT ; return true ; }
When the user double clicks on an icon in the Object Manger this message is sent to the corresponding element.
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.
// check the ID of the pressed button if (dc-> _descId [0].id == EXAMPLE_GENERATOR_BUTTON) { MessageDialog ( "You pressed the button." _s); } break ; }
Further messages are:
// 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; 菜单。 InsData (1, "Options" _s); 菜单。 InsData (10, "Option A" _s); 菜单。 InsData (20, "Option B" _s); dp-> _popup . InsData (0, menu); } else { const Int32 option = dp-> _chosen ; ApplicationOutput ( "You chose option @" , option); } } break ; }
// 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.
case MSG_DESCRIPTION_CUSTOMGUI_NOTIFICATION : { 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 向量 color = messageData-> GetVector (MSG_DESCRIPTION_COLORSTRING_COLOR); ApplicationOutput ( "New Color: " + String::VectorToString (color)); } } } } break ; }
另请参阅 Description Notifications .
These messages are related to the Take system:
Certain events trigger a broadcast message that is sent to all elements of a BaseDocument .
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. case MSG_DOCUMENTINFO : { DocumentInfoData * const msg = static_cast< DocumentInfoData * > (data); if (msg == nullptr ) return false ;// switch message sub-type switch (msg-> type ) { case MSG_DOCUMENTINFO_TYPE_LOAD : { 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 ; }
Also these messages are sent to all elements:
A special message is sent when the element is animated: