Tag plugin

On 13/11/2017 at 06:10, xxxxxxxx wrote:

User Information:
Cinema 4D Version:   R19 
Platform:   Windows  ;   
Language(s) :     C++  ;

I am using a TagData to store information for an object.
There is a reason why i don't store this information into a container in the object itself, but out of scope of this question.

I would like -inside of the tag plugin- to use GetObject() to obtain the object the tag was assigned to.
But I haven't found a way for the TagData to know when the tag is being added to the object.
At time of TagData::Init the GetObject returns a nullptr since the tag is not yet assigned.

In a scenehook I have noticed I can do following in Message() :

  if (type == MSG_DOCUMENTINFO)  
      DocumentInfoData* did = static_cast<DocumentInfoData*>(data);  
      if (did && (did->type == MSG_DOCUMENTINFO_TYPE_TAG_INSERT))  
          BaseTag* tag = static_cast<BaseTag*>(did->bl);  

At this point the tag is assigned to the object and I can thus get the object from:


I would prefer to do so in the TagData itself, but the message isn't sent to the TagData.
Is there any method which gets called (or message sent) to indicate the tag is assigned to an object.

I am not using the Execute() method of the TagData, as this gets called more than once during the lifetime of the tag. Should I focus my effort on this method to be triggered with the appropriate object, and keep some state to only handle this once? Or is there a better way to get notified when the object is available to the tag instance?


On 14/11/2017 at 10:30, xxxxxxxx wrote:


in general storing information in a tag is perfectly fine and a common use-case of tags.

I'm not so sure about storing the object a tag is assigned to in any way. After all the user can decide to move the tag to other objects for example. So it's probably better to make use of Execute() roughly in the way you describe.

On 15/11/2017 at 04:46, xxxxxxxx wrote:

The purpose of obtaining the object the tag is assigned to is in order to initialize tag data which is specific to the object the tag is assigned to (number of points and polygons).
When the tag is moved (or duplicated) onto another object, the tag data needs to be re-initialized with the then applicable number of points and polygons.

Doing this in the tag's Execute() seemed to be a plausible solution, until I read about the fact that this Execute is called in a thread context, and from further reading I understood it was then forbidden to:
- add an event
- call a Draw() function
- display messagebox
- create undos

The main action does happen as a result of user interaction, but the initialization will need to display message box in some cases (unsupported features depending number of points/polygons).

The initialization will also need to trigger redrawing of a UserArea, which is performed by a CallCommand to a separate CommandData plugin's ExecuteSubID(), so probably not a problem since no drawing is actually performed in the Tag::Execute()

I 'll probably also need to create undos since in some cases polygons will need to be selected as a result of the initialization. This needs to be added to some undo, otherwise the polygon remains selected when user undoes the step which triggers the initialization.

Unless I can manage to let the initialization within Tag::Execute() send a (custom) message to the tag itself, which would then perform the whole thing in the main thread (if I understand correctly).

EDIT: Right, I forgot once more that NodeData::Message is synchronous

On 15/11/2017 at 06:23, xxxxxxxx wrote:

I assumed incorrectly that sending a message was the solution to the threading issue.
Well it can be, but then it needs to be one meant for MessageData::CoreMessage()
as the "Important Threading Information" indicates.
It lists an example that uses the SpecialEventAdd to sent the message, but adding an event was forbidden? Confused!