Add Commands to ShowPopupDialog
-
Hi,
Is there a way I can add commands to ShowPopupDialog?
In the documentation, it offers commands but built-in ones such asc4d.Ocube
orc4d.IDM_COPY
.I want my own functions such as
menu.InsData(some_function(), 'some_function')
. But when I do so, it gives me an error.It requires that the first parameter should be an integer(i.e. ID). Is there a way I can convert a function to an integer? Or am I approaching this entirely wrong?
Thank you for looking at my problem
-
Hi @bentraje this is not possible out of the box, you have to register a CommandData and the Execute method of this CommandData will be executed.
If you don't want to go to this way and keep using only a script, you can assign a unique ID for each menu entry, check for the clicked ID (contained in the return value of ShowPopupDialog) and then call the correct function.
Cheers,
Maxime. -
Thanks for the response.
RE: you have to register a CommandData and the Execute method of this CommandData will be executed.
By register, I was thinking of the linec4d.plugins.RegisterCommandPlugin
which is included for every single.pyp
file. Does this mean I have to create several.pyp
files for each separate command then map them in a universal.pyp
file?RE: check for the clicked ID (contained in the return value of ShowPopupDialog) and then call the correct function.
I have a working code below.
It works when you click on theMenu 1
it printsYou selected Menu 1
. in the console as a test.My concern is I have it under the
Message()
and not under theCommand()
since it does not seem to recognize theShowPopupDialog
ids (or sub-ids).Is this okay?
import c4d class TestDialog(c4d.gui.GeDialog): def __init__(self): self._showPopup = False, 0, 0 def CreateLayout(self): self.GroupBegin(10002, c4d.BFH_SCALEFIT| c4d.BFH_SCALEFIT, initw=100, inith=100) self.AddButton(id=20002, flags=c4d.BFH_CENTER, initw=50, inith=50, name="Button Me") self.GroupEnd() return True def IsPositionOnGadget(self, gadgetId, x, y): # Be sure that the windows is opened, # in our case since we call it in BFM_INTERACTSTART it's ok buttonData = self.GetItemDim(gadgetId) if not buttonData["x"] < x < buttonData["x"] + buttonData["w"]: return False if not buttonData["y"] < y < buttonData["y"] + buttonData["h"]: return False return True def IsPositionInGuiArea(self, x, y): # Check click is within the GeDialog if not 0 < x < self._x: return False if not 0 < y < self._y: return False return True def Message(self, msg, result): if msg.GetId() == c4d.BFM_ADJUSTSIZE: self._x = msg[3] # Retrieve Y size of the GeDialog self._y = msg[4] # Retrieve Y size of the GeDialog # We are on the main thread here elif msg.GetId() == c4d.BFM_INTERACTSTART: c4d.StopAllThreads() state = c4d.BaseContainer() self.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSERIGHT, state) if state.GetInt32(c4d.BFM_INPUT_VALUE) == True: x = state.GetInt32(c4d.BFM_INPUT_X) y = state.GetInt32(c4d.BFM_INPUT_Y) g2l = self.Global2Local() x += g2l['x'] y += g2l['y'] if self.IsPositionOnGadget(gadgetId=20002, x=x, y=y): IDM_MENU1 = c4d.FIRST_POPUP_ID IDM_MENU2 = c4d.FIRST_POPUP_ID + 1 IDM_MENU3 = c4d.FIRST_POPUP_ID + 2 menu = c4d.BaseContainer() menu.InsData(IDM_MENU1, 'Menu 1') menu.InsData(IDM_MENU2, 'Menu 2') menu.InsData(IDM_MENU3, 'Menu 3') l2s = self.Local2Screen() #print str(x+l2s['x']) + " :: " + str(y+l2s['y']) self.KillEvents() self.res = c4d.gui.ShowPopupDialog(cd=self, bc=menu, x=x+l2s['x'], y=y+l2s['y']) if self.res == 900000: print "You selected Menu 1" elif self.res == 900001: print "You selected Menu 2" elif self.res == 900002: print "You selected Menu 3" else: return return True return c4d.gui.GeDialog.Message(self, msg, result) def Command(self, id, msg): return True if __name__ == '__main__': global dlg dlg = TestDialog() dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC)
-
@bentraje
Hope this will help you out its a small demo I did.
Quick video on how it look inside Cinema 4d. Here
Download Demo Test : GitHub Link
Code:# Imports import os import sys import c4d from c4d import plugins, gui, bitmaps, documents, storage, utils from c4d.gui import GeDialog as WindowDialog from c4d.plugins import CommandData, TagData, ObjectData iPath = os.path.join(os.path.dirname(__file__), 'res', "yourIcon.png") def CustomCommandPopupMenu(): """" Popup Commands Ids Only Menu """ menu = c4d.BaseContainer() menu.InsData(0, '') # Append separator menu.InsData(PLUG_2['ID'], "CMD") # eg: menu.InsData(00000000, "CMD") menu.InsData(0, '') # Append separator menu.InsData(PLUG_3['ID'], "CMD") result = gui.ShowPopupDialog(cd=None, bc=menu, x=c4d.MOUSEPOS, y=c4d.MOUSEPOS) return True class CMDTool(CommandData): def __init__(self, CMD): super(CMDTool, self).__init__() self.CMDTool = CMD def Init(self, op): return True def Message(self, type, data): return True def Execute(self, doc): if self.CMDTool == "PCT": CustomCommandPopupMenu() if self.CMDTool == "PCT1": gui.MessageDialog("PlugCafeTool2") if self.CMDTool == "PCT2": gui.MessageDialog("PlugCafeTool2") def RestoreLayout(self, sec_ref): return True def ExecuteOptionID(self, doc, plugid, subid): gui.MessageDialog("PlugCafeTool2 Options") return True # ---------------------------------------------------- # Plugin Registration # ---------------------------------------------------- # // Plugin Flags Tpyes // class PluginFlags: """ Register Info Plugin Flags Tpyes """ # Plugin General Flags : HidePlugin = c4d.PLUGINFLAG_HIDE HideTool = c4d.PLUGINFLAG_HIDEPLUGINMENU RefreshPlugin = c4d.PLUGINFLAG_REFRESHALWAYS SmallNodePlugin = c4d.PLUGINFLAG_SMALLNODE # Command Plugin Flags: OptionGear = c4d.PLUGINFLAG_COMMAND_OPTION_DIALOG # A info flag / Command has additional options. The user can access them through a small gadget. # Tag Plugin Flags : TagVis = c4d.TAG_VISIBLE # The tag can be seen in the object manager. TagMul = c4d.TAG_MULTIPLE # Multiple copies of the tag allowed on a single object. TagHier = c4d.TAG_HIERARCHICAL # The tag works hierarchical, so that sub-objects inherit its properties (e.g. the material tag). TagExp = c4d.TAG_EXPRESSION # The tag is an expression. TagTem = c4d.TAG_TEMPORARY # Private. # Object Plugin Flags: oMod = c4d.OBJECT_MODIFIER # Modifier object. Deforms the surrounding object. (E.g. bend.) oHier = c4d.OBJECT_HIERARCHYMODIFIER # Hierarchical modifier. Deforms the surrounding objects together with other instances in a hierarchy chain. Only the top-most instance of the plugin in a chain is called. (E.g. bones.)Hierarchical modifier. Deforms the surrounding objects together with other instances in a hierarchy chain. Only the top-most instance of the plugin in a chain is called. (E.g. bones.) oGen = c4d.OBJECT_GENERATOR # Generator object. Produces a polygonal or spline representation on its own. (E.g. primitive cube.) oInput = c4d.OBJECT_INPUT # Used in combination with OBJECT_GENERATOR. Specifies that the generator uses builds a polygon or spline, using its subobjects as input. (E.g. Sweep Subdivision Surface, Boolean.) oPart = c4d.OBJECT_PARTICLEMODIFIER # Particle modifier. oSpline = c4d.OBJECT_ISSPLINE # The object is a spline. oCamera = c4d.OBJECT_CAMERADEPENDENT # Camera dependent. oPointObj = c4d.OBJECT_POINTOBJECT # Point Object. oPolyObj = c4d.OBJECT_POLYGONOBJECT # Polygon object. PF = PluginFlags() # // Register Plugin Add-on Tool Tpyes to Cinema 4D // def RegisterCommandData(id, str_name, infoflags, iconName, helpInfo, dataClass): """ A CommandData Tool Plugin Register """ DESCRIPTIONS = "" #ToolInfo_Description(helpInfo) plugin_Icon = c4d.bitmaps.BaseBitmap() plugin_Icon.InitWith(iconName) result = plugins.RegisterCommandPlugin(id=id, # Plugin register ID. str=str_name, # This is for the Plugin Name to show in the Plugins lic4d.storage. info=infoflags, # If you want a option button once you have a ExecuteOptionID in Data Class, # then put in Flags info=c4d.PLUGINFLAG_COMMAND_OPTION_DIALOG|c4d.PLUGINFLAG_COMMAND_HOTKEY, icon=plugin_Icon, # Plugin Icon Image. help=DESCRIPTIONS, # The plugin help info is on what the plugin does. dat=dataClass) # The plugin data class. return True # // Register Tools // PLUG_1 = {'ID':1050002, 'Icon':iPath, 'Name':"CommandTools Menu",'flags':0, 'Data':CMDTool("PCT"), 'Info':""} PLUG_2 = {'ID':1051421, 'Icon':iPath, 'Name':"PlugCafeTool-1", 'flags':PF.HideTool, 'Data':CMDTool("PCT1"), 'Info':""} PLUG_3 = {'ID':1054336, 'Icon':iPath, 'Name':"PlugCafeTool-2", 'flags':PF.HideTool|PF.OptionGear, 'Data':CMDTool("PCT2"), 'Info':""} if __name__ == '__main__': dir, file = os.path.split(__file__) RegisterCommandData(PLUG_1["ID"], PLUG_1["Name"], PLUG_1["flags"], PLUG_1["Icon"], PLUG_1["Info"], PLUG_1["Data"]) RegisterCommandData(PLUG_2["ID"], PLUG_2["Name"], PLUG_2["flags"], PLUG_2["Icon"], PLUG_2["Info"], PLUG_2["Data"]) RegisterCommandData(PLUG_3["ID"], PLUG_3["Name"], PLUG_3["flags"], PLUG_3["Icon"], PLUG_3["Info"], PLUG_3["Data"])
cheers & good luck!
Ap Ashton -
Thanks for the demo. It works as advertised.
It certainly answers one of the two options presented by @m_adam on how to approach it.- you have to register a CommandData
- you can assign a unique ID for each menu entry, check for the clicked ID
Hope you'll excuse me if I keep the thread open. I'm interested on @m_adam 's response on my execution of #2 option under the
Message()
(see above).Thanks again for the response. Have a great day ahead!
-
As @Ashton_FCS_PluginDev demonstrates, you can call multiple RegisterXX in your pyp file.
So yes you have to register a CommandData for each in the first situation.You don't have to react about it on the Message function since the whole script/Cinema 4D will be blocked until you clicked/selected answers and the clicked ID will be the return value of ShowPopupDialog but as explained and demonstrated in the ShowPopupDialog documentation.
Cheers,
Maxime. -
@m_adam Thanks for further clarification.
@Ashton_FCS_PluginDev 's code works but I guess I'll just use the
result
of theShowPopupDialog
to trigger commands, as I added in the previous code.