Your browser does not seem to support JavaScript. As a result, your viewing experience will be diminished, and you have been placed in read-only mode.
Please download a browser that supports JavaScript, or enable it if it's disabled (i.e. NoScript).
Hello, I have seen tag plugins that, when they are double-clicked, open a dialog.
Using the py-look_at_camera_r13 example from the SDK, I came up with the code below. I'm trying to open the Dialog with the Execute method of the plugin class which is clearly the wrong place for it.
import c4d, os from c4d import plugins, utils, bitmaps, gui, documents TAG_ID = 1234567 PLUGIN_ID = 2345678 global dlg class MyDlg(gui.GeDialog): def CreateLayout(self): self.SetTitle("MyDlg") self.GroupBegin(1, c4d.BFH_CENTER, 2, 1, None, 640) self.GroupBorderSpace(10, 20, 10, 20) self.AddButton(2, c4d.BFH_FIT, name="Yes", initw=100) self.AddButton(3, c4d.BFH_FIT, name="No", initw=100) self.GroupEnd() return True def Command(self, id, msg): return True class MyTagPlugin(c4d.plugins.TagData): def Init(self, node): pd = c4d.PriorityData() if pd is None: raise MemoryError("Failed to create a priority data.") pd.SetPriorityValue(c4d.PRIORITYVALUE_CAMERADEPENDENT, True) node[c4d.EXPRESSION_PRIORITY] = pd return True def Execute(self, tag, doc, op, bt, priority, flags): global dlg if dlg == None: dlg = MyDlg() dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC, xpos=-1, ypos=-1, pluginid=PLUGIN_ID, defaultw=540, defaulth=640) return c4d.EXECUTIONRESULT_OK if __name__ == "__main__": # Retrieves the icon path directory, _ = os.path.split(__file__) fn = os.path.join(directory, "res", "icon.png") # Creates a BaseBitmap bmp = c4d.bitmaps.BaseBitmap() if bmp is None: raise MemoryError("Failed to create a BaseBitmap.") # Init the BaseBitmap with the icon if bmp.InitWith(fn)[0] != c4d.IMAGERESULT_OK: raise MemoryError("Failed to initialize the BaseBitmap.") c4d.plugins.RegisterTagPlugin(id=TAG_ID , str="MyTagPlugin", info=c4d.TAG_EXPRESSION | c4d.TAG_VISIBLE, g=MyTagPlugin, description="Tmytagplugin", icon=bmp)
This code throws the following error:
RuntimeError: illegal operation, invalid cross-thread call
I'm guessing it's because it's a gui call off of the main thread.
It seems the Tag plugins launch a Command Plugin somehow. I have a few questions about this:
Thank you.
Hi,
you answered your own question (almost) correctly: GUI functionalities are only allowed to be invoked from the main thread and c4d.TagData.Excute() is not being executed from the main thread. Some thoughts / solutions for your problem:
c4d.TagData.Excute()
NodeData.Message()
c4d.threading.GeIsMainThread()
BFM_INPUT
c4d.MSG_EDIT
Cheers zipit
Hello. In addition to @zipit's excellent answer, you might consider also implementing a Message Plugin and react to CoreMessages, sent via c4d.SpecialEventAdd()
@zipit:
May I ask for practical examples on where you have seen this behavior?
There are actually some tags with GUI interaction. The MographCache Tag for example.
@zipit Thank you for the reply. A practical example would be storing data about a set of objects (as in a character pose) in a tag. The Command plugin would have the UI used for organizing the multiple tags' data (adding/deleting poses to the tag, renaming poses, etc.). Here's one example. I'd be very happy to hear ideas for other paradigms.
Here's what I have now in my Tag:
def Message(self, op, type, data): if type == c4d.MSG_EDIT: try: global dlg dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC, xpos=-1, ypos=-1, pluginid=COMMANDPLUGIN_ID, defaultw=540, defaulth=640) except NameError: global myDlg dlg = MyDlg() dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC, xpos=-1, ypos=-1, pluginid=COMMANDPLUGIN_ID, defaultw=540, defaulth=640) return True
This method only opens the dialog once. If I close and try to reopen it, however, nothing happens. Opening it this way creates double menu bars:
Also, I'm still unsure of how to check if the Command Plugin UI is already open from the Tag Plugin?
@mp5gosu Thank you. I'll check out the Message Plugin.
@blastframe said in How to Open a Dialog Plugin from a Tag Plugin?:
@zipit Thank you for the reply. A practical example would be storing data about a set of objects (as in a character pose) in a tag.
With an example I actually meant where you have seen this before in 'the wild', but @mp5gosu already did provide such an example. I however would remain on my point that this is a rather exotic feature and I would still suggest contemplating if this is really what you want. Weird GUIs are really good way to alienate users. I am not saying this is a bad idea, I am just saying: Really make sure that this is not a bad idea.
I am not quite sure, if I have missed the CommandData stuff before or if this is new information. I would lean more into the direction of @mp5gosu suggestion now.
CommandData
c4d.CallCommand()
# In the tag def Message(self, node, type, data): if type == c4d.MSG_EDIT: c4d.GePluginMessage(ID_OPEN_YOUR_DIALOG, data=some_data) [...] # In the command data: def Message(self, type, data): if type == ID_OPEN_YOUR_DIALOG: self._open_my_dialog(data) [...]
edit: Jeah, there it is, CommandData, in your first posting, mea culpa
Hello,
the important question is, if you want to open a modal or asynchronous dialog.
An asynchronous dialog must be hosted by a CommandData plugin (GeDialog Manual) (e.g. py-memory_viewer).
As mentioned above, a double-click on a tag can be detected by looking for the MSG_EDIT message (NodeData::Message() Manual).
MSG_EDIT
So, when you detect MSG_EDIT, you simply have to execute the command that hosts you dialog. You can simply do that using CallCommand() (Command Utility Manual).
MSG_EDIT,
CallCommand()
Within your dialog, you can find your tag by getting the active tag.
best wishes, Sebastian