Dynamically changing custom icon of TagData Plugin
-
Hi guys,
I have a tag plugin which makes use of
c4d.MSG_GETCUSTOMICON
stole the code from here to dynamically change its icon based on a parameter of the tag.While this is all fine and dandy, I encountered the problem that this only works if I add the tag to a single object. The minute I have multiple objects selected and add my tag plugin to them, the first (or last, depending how you want to see it) always loads the wrong icon while the other objects get the correct one. See pictures below.
Wrong behaviour:
Expected behaviour:
My feeling is, that
c4d.MSG_MENUPREPARE
is the culprit here and only gets called for a single instance of the tag. Not sure though.To circumvent this I implemented a
c4d.plugins.MessageData
plugin which reacts to ac4d.SpecialEventAdd()
call I send every timec4d.MSG_MENUPREPARE
is called received in the tag plugin. So in essence I delegate the work to the MessageData plugin which is now responsible to set the parameter on the tag plugin instances.Long story short - it works.
But I wonder if this is "the right" way to do it. As it feels a little bit clunky and also somehow overkill for such a small feature. Imagine having a couple of plugins which all implement some similar feature. All of these plugins would then need a MessageData plugin which communicates with them.So, to finish this of. Could someone tell me if this is the intended approach or if I#m missing something here and doing things unnecessarily complicated?
I attached the project so that its easier to follow.
Cheers,
Sebastian -
Hello @HerrMay.
Thank you for reaching out to us. While I sort of understand what you are talking about, I struggle quite a bit with this:
While this is all fine and dandy, I encountered the problem that this only works if I add the tag to a single object. The minute I have multiple objects selected and add my tag plugin to them, the first (or last, depending how you want to see it) always loads the wrong icon while the other objects get the correct one. See pictures below.
When I run your plugin on
2023.2.1
, and try to roughly mimic what you are talking about, I end up with this: -
Hi @ferdinand,
ah stupid me. I forgot to remove the
GetDEnabling
part. Didn't mean to bring that along.My problem is not so much about enabling or disabling the node(s) but more the fact that some nodes are simply getting the "wrong" icon status when the tag is apllied from the menu.
Try to comment
def CoreMessage(self, id, bc)
in theTagTestMessageHandler
class and then reload the plugin and apply the tag to your object selection again. You should see that the topmost object gets the red icon while the others get the expected green one.Cheers,
Sebastian -
Hello @HerrMay,
I unfortunately do not have the time to go bug hunting on my own. Debugging of user projects is out of scope of support in general as stated in our guidelines. I doubt there is a bug in our icon handling, so there is more likely a problem in your logic.
Please provide code and clear instructions on how to reproduce the problem, preferably in the (1, 2, 3, ...) manner as shown above. Otherwise, I will not be able to make here an exception and help you debugging this.
Cheers,
Ferdiand -
Hi @ferdinand,
alrighty, understood. I know you don't have either the time nor the permission to go on deep bug hunting tours. So no worries there.
I stripped down the code to the bare minimum. That way it should be easier.
Please find below the new project.
To mimic what I've down please follow these steps. Tested in 2023.2.1
-
Install the "Do Nothing Tag" Plugin from the ZIP-Archive.
-
Create some objects. Doesn't matter what kind.
-
Select all of these objects and apply the "Do Nothing Tag" from the extensions submenu inside the tag menu.
-
You see the topmost object of the selection gets the red icon while the others get the green one.
I hope I could be more helpful with these informations. If not, don't hesitate to tell me what I could provide additionally.
Thank you,
Sebastian -
-
Hello @HerrMay,
Thank you for the updated information. I had a look at your problem, and I could reproduce it, but it is primarily a problem of your code as suspected.
I document below how I analyzed this problem not as a passive aggressive expression of "look how easy that is!". But to give an insight on how to approach such debugging task. The core rule is here to question one's own assumptions and assure that things are indeed how we think they are.
Debugging
So, when one follows your steps, one indeed ends up with something like this:
Your assumption here was that the icon handling is bugged on our side. For that to be true, the tag on
Null.2
would have to beIDC_ACTIVE_ON
but with the icon handling failing and Cinemas 4D rendering it as disabled.So, I checked the value with this code:
# Set custom icon for node. if id == c4d.MSG_GETCUSTOMICON: host: c4d.BaseObject = tag.GetObject() isFirst: bool = host.GetUp() == None and host.GetPred() == None if isFirst: print(f"TOP: {host.GetName() = }, {tag[IDC_ACTIVE] = }") else: print(f"OTHER: {host.GetName() = }, {tag[IDC_ACTIVE] = }") icon = self.PLUGIN_ICON_INACTIVE if tag[IDC_ACTIVE] == IDC_ACTIVE_OFF else self.PLUGIN_ICON_ACTIVE data["bmp"] = icon data["w"] = icon.GetBw() data["h"] = icon.GetBh() data["filled"] = True
Which will print this when you add the tags:
So, the topmost tag is indeed inactive and the icon rendering is correct. The question is now: 'Why is that tag inactive because we initialize all tags as
node[IDC_ACTIVE] = IDC_ACTIVE_ON
?' The likely culprit is just a few lines above, as we toggle there the active state of our tag.# Handle double click on tag. if id == c4d.MSG_EDIT: if tag[IDC_ACTIVE] == IDC_ACTIVE_OFF: tag[IDC_ACTIVE] = IDC_ACTIVE_ON else: tag[IDC_ACTIVE] = IDC_ACTIVE_OFF
And indeed, when we comment out these lines, we end up with this when creating multiple new tags.
Moreover, when we revert our change of commenting out that code and test our assumption 'only happens for multi-object selections', we can see that this does not hold true:
We can now check our own comment:
# Handle double click on tag. if id == c4d.MSG_EDIT: ...
and check
MSG_EDIT
:The documentation says, "for example". So, the event does not capture a double click, but double clicking a
BaseObject
to edit its name is one example of an edit event. Adding a tag to an object apparently also emitsMSG_EDIT
to the tag, and when you have a multi-selection,MSG_EDIT
is only emitted to the first element in the selection.Conclusion
That behavior of
MSG_EDIT
in regard to tags and multi-selections is of course quite odd, but I would not consider it to be a bug, as an edit event is not really defined for tags in the first place. And while I understand what you want to do here, I would also say that what you do inMSG_EDIT
is a violation of the UX principles of Cinema 4D. Double clicking a tag should not edit a random parameter in it. We strive for Cinema 4D having a seamless UX-experience for users including plugins. So, we rather not support it when plugin authors are trying to break these UX rules.But I will nevertheless talk with my colleagues about the subject and if we want to consider this behavior of
MSG_EDIT
to be a bug.Cheers,
Ferdinand