Unsolved 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:
Not_Working.jpg

Expected behaviour:
Working.jpg

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 a c4d.SpecialEventAdd() call I send every time c4d.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. :D
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.

TagTest.zip

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:

First, I thought something is broken with tri states (i.e., being able to select multiple nodes and edit parameters with overlapping IDs in all selected nodes at once), because the tri states seemingly break as soon as you select "off". But in the video above I realized then that also a singular parameter is being grayed out when you select "off", meaning that you must have implemented GetDEnabling.

And sure enough, you do this:

def GetDEnabling(self, node, id, t_data, flags, itemdesc):
    """
    """
    if node[IDC_ACTIVE] == IDC_ACTIVE_OFF:
        return False

    return True

Which is a bit odd to say the least, because toggling IDC_ACTIVE to "off" will effectively brick your tag, since it will disable all parameters, including IDC_ACTIVE itself.

Other than that, and as shown in the video, I was not able to reproduce your problem. You should share a step-by-step reproduction in a form as such:

Reproduce
---------

1. With the Create/Mesh/Cube entry add a cube object to a scene.
2. For that new cube object, in the Attribute Manager:
  I. Set the Segments.X parameter to 42.
  II. Check the Separate Surfaces parameter.

Result
------

1. The cube object is shown as a sphere in the viewport.
2. All parameter changes made to the Attribute Manager for such malformed cube object are being ignored, the object is permanently broken.

Cheers,
Ferdinand

MAXON SDK Specialist
developers.maxon.net

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 the TagTestMessageHandler 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

MAXON SDK Specialist
developers.maxon.net

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.

DoNothingTag.zip

To mimic what I've down please follow these steps. Tested in 2023.2.1

  1. Install the "Do Nothing Tag" Plugin from the ZIP-Archive.

  2. Create some objects. Doesn't matter what kind.

  3. Select all of these objects and apply the "Do Nothing Tag" from the extensions submenu inside the tag menu.

  4. 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:

8fdef1aa-1a5e-43d8-8cdb-42b480fd4f0d-image.png

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 be IDC_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:

baebed6a-fdc0-4d53-8214-1d6b2011cad8-image.png

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.

ebddd8e2-ff78-47f3-a4ca-40cbd26ac047-image.png

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:

e5f2a8dd-2ebd-4555-8188-d769b84895e3-image.png

We can now check our own comment:

# Handle double click on tag.
if id == c4d.MSG_EDIT:
    ...

and check MSG_EDIT:

de39ee11-81d9-4e68-a2a6-a4c4dd182b84-image.png

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 emits MSG_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 in MSG_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

MAXON SDK Specialist
developers.maxon.net