How to add a plugin to a toolbar menu?
-
On 08/05/2014 at 08:16, xxxxxxxx wrote:
Does anyone know how to add a plugin to a specific menu? I am trying to add a custom character animation plugin to the "Character Tags" in the object manager.
Thanks for any response.
-
On 09/05/2014 at 11:35, xxxxxxxx wrote:
Hi Jimmy,
I know it's possible to create your own top-level menu entry, but I seem to remember reading it's not possible to insert your own commands into existing pull-downs.
-Donovan
-
On 10/05/2014 at 00:54, xxxxxxxx wrote:
In PluginMessage, listen to C4DPL_BUILDMENU. You can use c4d.gui.GetMenuResource() to get a container structure of the menu.
Modify this container. The changes should be reflected without any Set~() call.You can try it in the script manager to examine the structure of the
container. The Menu Editor in Cinema 4D will help you a little bit, too.-Niklas
-
On 15/05/2014 at 10:46, xxxxxxxx wrote:
Niklas,
Can you be a little more descriptive about "listen to C4DPL_BUILDMENU",I have the following code in my
def Message(self, op, type, data) :
if type==C4DPL_BUILDMENU:method for my plugins.TagData inherited class.
Is that the syntax that I should use to listen for that message? How would I use c4d.gui.GetMenuResource() to get a container structure of the menu? What do you mean by the changes should be reflected without any Set call?Thanks for your help
Jimmy -
On 15/05/2014 at 13:29, xxxxxxxx wrote:
Hi Jimmy,
put a global function into your plugin that is called PluginMessage(). You can find more information
by searching for this name in the docs or by clickinghere
[URL-REMOVED].def PluginMessage(kind, data) : if kind == c4d.C4DPL_BUILDMENU: bc = c4d.gui.GetMenuResource() # ... alter menu container return True
Best,
-Niklas
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
-
On 15/05/2014 at 16:38, xxxxxxxx wrote:
That's ok if we want to add new menus to the main C4D UI.
But what about adding sub menu's to the existing menus?
I can't get that one to work:import c4d import sys,os from c4d import gui,plugins #This is a custom method that will insert a new menu into C4D when it starts up def EnhanceMainMenu() : #Start off by getting the main menu resource container mainMenuBc = gui.GetMenuResource("M_EDITOR") ################################################################## ########## Add a new sub menu to the File menu ################### ########## This does not work!! ################################# #The new menu item we want to add under the File menu new_menu1 = c4d.BaseContainer() #Create a container to hold a new menu information new_menu1.InsData(c4d.MENURESOURCE_SUBTITLE, "Scott1") #Set the name of the menu new_menu1.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_5159") #Add command 'Cube' with ID 5159 to the menu #Get the first tuple in the mainMenuBc. Which is the "File" menu fileBc = mainMenuBc[1] #Add the new menu item's container to the File menu's container fileBc.InsData(c4d.MENURESOURCE_STRING, new_menu1) #<--- Does not work!! ################################################################## ########## Adds a new menu to the C4D UI ####################### ########## This works properly as expected ####################### new_menu2 = c4d.BaseContainer() #Create a container to hold a new menu information new_menu2.InsData(c4d.MENURESOURCE_SUBTITLE, "Scott2") #Set the name of the menu new_menu2.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_5159") #Add command 'Cube' with ID 5159 to the menu mainMenuBc.InsData(c4d.MENURESOURCE_STRING, new_menu2) #Add the new container to the main menu's container def PluginMessage(id, data) : #This is where we check the build status of the menus. And also inserts any new ones if id==c4d.C4DPL_BUILDMENU: EnhanceMainMenu() return False
-ScottA
-
On 18/05/2014 at 10:26, xxxxxxxx wrote:
Nobody knows how to do this?
I've been able to add menu items to the "File" menu in memory only (but they don't show up).
Or
Create a complete copy of the File menu. With my added menu items in it.
But I've not been able to change the existing "File" menu.import c4d, sys,os from c4d import gui,plugins #This is a custom method that will insert a new menu into C4D when it starts up def EnhanceMainMenu() : #Create some new menu items that we want to add to the File menu menu = c4d.BaseContainer() #Create a container to hold our new menu information menu.InsData(c4d.MENURESOURCE_SUBTITLE, "Scott1") #Set the name of the menu menu.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_5159") #Add the already registered command to the menu mainMenu = gui.GetMenuResource("M_EDITOR") #Get main menu resource subBC = mainMenu.GetContainer(1) #Get the container <---I think this is wrong??? for i,v in mainMenu: names = v.GetString(c4d.MENURESOURCE_SUBTITLE) #The sub menu names(File,Edit,Create,etc...) if names == "IDS_EDITOR_FILE": subBC.InsData(c4d.MENURESOURCE_SUBMENU, menu) #Now re-check all the items in the "File" menu to see if our new item was added for j,v2 in subBC: print v2 #<--- The new menu is there in memory <c4d.BaseContainer object at 0x0000000013199618> #But it does not show up!? #If I do this it adds a new sub menu in M_EDITOR called "IDS_EDITOR_FILE" #This is a copy of the "File menu. **Plus my new menu item** #I don't want to do that...I want to update the existing "File" menu. Not create a copy of it #How do I do that? mainMenu.InsData(c4d.MENURESOURCE_STRING, subBC) def PluginMessage(id, data) : if id==c4d.C4DPL_BUILDMENU: EnhanceMainMenu() return False
-ScottA
-
On 18/05/2014 at 13:51, xxxxxxxx wrote:
Hi Jimmy, Hi Scott,
with get and set data...
and UpdateMenus()def EnhanceMainMenu() : #Create some new menu items that we want to add to the File menu menu = c4d.BaseContainer() #Create a container to hold our new menu information menu.InsData(c4d.MENURESOURCE_SUBTITLE, "Scott1") #Set the name of the menu menu.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_5159") #Add the already registered command to the menu mainMenu = gui.GetMenuResource("M_EDITOR") #Get main menu resource filemenue= mainMenu.GetData(1) filemenue.InsData(c4d.MENURESOURCE_SUBMENU, menu) mainMenu.SetData(1, filemenue) def PluginMessage(id, data) : if id==c4d.C4DPL_BUILDMENU: EnhanceMainMenu() c4d.gui.UpdateMenus()
Cheers
Martin -
On 18/05/2014 at 14:59, xxxxxxxx wrote:
Thanks.
I guess we do need to use GetData() & SetData() for the sub menus.Do you know how to put things in the other other sub menus (Edit, Create, etc...)?
mainMenu.GetData(1) gets a list of BaseContainers. And setting it to something other than 1 does not work.The menu system in C4D is a winding maze of nested containers and tuples.
It has a master BaseContainer(M_EDITOR, M_CONSOLE, etc...). And that container has a bunch of sub containers. And those SubContainers have tuples in them. Which can also have BaseContainers.
Who dreams up these nightmares?It's a worse tangled mess than the nested containers system used for the UserData.
-ScottA
-
On 22/05/2014 at 10:58, xxxxxxxx wrote:
Guys,
So can you modify the menu structure if you are creating a TagPlugin? I am trying to modify the object manager popup but I can't find the specific menu to add it to. Any ideas?
Jimmy -
On 23/05/2014 at 17:21, xxxxxxxx wrote:
Hi Jimmy,
Put this code in your .pyp file to modify your object manager menus:
def EnhanceObjectManagerMenu() : omMenu = c4d.gui.GetMenuResource("M_OBJECT_MANAGER") menu = c4d.BaseContainer() menu.InsData(c4d.MENURESOURCE_SUBTITLE, "Py-Test") menu.InsData(c4d.MENURESOURCE_COMMAND, "IDM_NEU") # Add registered default command 'New Scene' to the menu menu.InsData(c4d.MENURESOURCE_SEPERATOR, True); # Add a separator menu.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_5159") # Add command 'Cube' with ID 5159 to the menu omMenu.InsData(c4d.MENURESOURCE_STRING, menu) def PluginMessage(id, data) : if id == c4d.C4DPL_BUILDMENU: EnhanceObjectManagerMenu()
-
On 23/05/2014 at 17:23, xxxxxxxx wrote:
That said, does anyone have any suggestions for how to insert custom menus into managers that don't seem to have a MenuResource file?
Specifically I'm trying to add a "Bookmarks" pulldown to the Scene Layers manager (Access it from Window > Layer Manager...). I can't find a resource file for it's menus anywhere, and I suspect they're added in code.
-
On 24/05/2014 at 08:23, xxxxxxxx wrote:
@Jimmy-
You can't add things to the "Character Tags" menu because that's being generated from a plugin. And not the menu manager.@Donovan-
The ID for the Bookmarks sub menu is: IDS_SB_BOOKMARKS
But the big problem is how to add new menus to anything but the "File" menu?
I can do it in C++. But I cannot figure out how to do it in Python.
I can't figure out how to update the menu's container after I add my new sub menu to it.This example plugin attempts to add a new sub menu to the "Create" menu:
import c4d,sys,os from c4d import gui,plugins #This is a custom method that will insert a new menu into C4D when it starts up def EnhanceMainMenu() : #Start off by getting the main menu resource container mainMenu = gui.GetMenuResource("M_EDITOR") #This is a BaseContainer type #Create some new menu items that we want to add to the "Create" menu newMenu = c4d.BaseContainer() #Create a container to hold our new menu information newMenu.InsData(c4d.MENURESOURCE_SUBTITLE, "Scott") #Set the name of the menu newMenu.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_5159") #Add the already registered command to the menu subMenus = mainMenu.GetData(1) #The BaseContainers in the M_EDITOR's container #First we have to get the "Create" menu somehow #So I loop through the menus and grab it this way CreateMenu = None for i,v in mainMenu: if i==1: if v.GetString(c4d.MENURESOURCE_SUBTITLE) == "IDS_MENU_CREATE": CreateMenu = v #Now that I have the "Create" menu stored in it's own variable #I add my new menu to the Create menu by inserting it's container into the "Create" menu's container #The same way that we add a new menu to the "File" menu (which seems to work fine) CreateMenu.InsData(c4d.MENURESOURCE_SUBMENU, newMenu) #Now I check the Create menu's container to see if I successfully added the new menu to it #for i,v in CreateMenu: print v #<---Yes...A new BaseContainer(my new menu) was successfully added to the "Create" menu #PROBLEM!! The new menu does not show up in the Create menu! :-( #It's not showing up because I have not updated the "Create" menu's container after I added my new menu to it #How do I update the "Create" menu's BaseContainer? #mainMenu.SetData(1, subMenus) #<---WRONG!!! #mainMenu.SetData(1, CreateMenu) #<---WRONG!!! #This method adds our new menus dynamically(not just when C4D launches) def PluginMessage(id, data) : #This is where we check the build status of the menus. And also inserts any new ones if id==c4d.C4DPL_BUILDMENU: gui.UpdateMenus() EnhanceMainMenu() return False
It's weird how we can only add sub menus to the "File" menus. But not any of the other ones.
I can do it in C++ so we should be able to do it with Python. Unless it's a bug.
It would be really nice if support would answer how to add menus to anything other than the "File" sub menu.-ScottA
-
On 25/05/2014 at 13:05, xxxxxxxx wrote:
Hi ,
it took a while to figure this out.
It seems to me that the only id in the main menu we are able to access is id=1.
I thought about storing the menu items in a list, deleting them from the main menu and inserting the converted menus afterwards!
It´s a huge workaround, but it works!cheers
Martinimport c4d from c4d import gui def main() : #getting the main menu resource container mainMenu= gui.GetMenuResource("M_EDITOR") MenuList= [] #create some new menu items menu = c4d.BaseContainer() menu.InsData(c4d.MENURESOURCE_SUBTITLE, "Scott1") menu.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_5159") for m in mainMenu: #collect the menus in a list and remove them from the main menu until you´ll find your destintion menu if m[c4d.MENURESOURCE_SUBMENU][c4d.MENURESOURCE_SUBTITLE]!= "IDS_EDITOR_CA": MenuList.append(m) mainMenu.RemoveData(1) elif m[c4d.MENURESOURCE_SUBMENU][c4d.MENURESOURCE_SUBTITLE]== "IDS_EDITOR_CA": ca_menue= m[c4d.MENURESOURCE_SUBMENU] ca_menue.InsData(c4d.MENURESOURCE_SUBMENU, menu) MenuList.append((1,ca_menue)) break print MenuList #print NameList #set the file menu as the first entry mainMenu.SetData(1,MenuList[0][1]) #reverse the list to get the right order MenuList.reverse() #delete the file menu from the list del MenuList[-1] # rewrite all menus to the main menu for i,men in enumerate(MenuList) : mainMenu.InsDataAfter(c4d.MENURESOURCE_SUBMENU, men[1], c4d.gui.SearchPluginMenuResource("IDS_EDITOR_FILE")) #update menus c4d.gui.UpdateMenus() if __name__=='__main__': main()
-
On 25/05/2014 at 13:47, xxxxxxxx wrote:
That's the same thing that this line of code does in my example: mainMenu.SetData(1, CreateMenu)
It creates a whole new duplicate Character menu. Then replaces the "File" menu with it.
OUCH!The C++ SDK has a Browse() function that handles traversing the nested containers mess.
And when we find one we want to change. We use GeData to add new ones and then update the changes. But Python does not have these things.
The Python file menus seem to be type casted to something called PYObjects. Which don't seem to be finished yet?There should be a way to update the menus after we've added a new menu to it. But I can't figure it out.
-ScottA
-
On 25/05/2014 at 14:02, xxxxxxxx wrote:
Hi Scott,
don´t know your c4d version and your os, but with c4d 15 on my mac it works like a charme.
Cheers
Martin -
On 25/05/2014 at 14:12, xxxxxxxx wrote:
I tried it with a tag plugin and again it works....
def EnhanceMainMenu(self,op) : rootobject=op.GetObject() #getting the main menu resource container mainMenu= gui.GetMenuResource("M_EDITOR") MenuList= [] #create some new menu items menu = c4d.BaseContainer() menu.InsData(c4d.MENURESOURCE_SUBTITLE, "Scott1") menu.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_5159") for m in mainMenu: #collect the menus in a list and remove them from the main menu until you´ll find your destintion menu if m[c4d.MENURESOURCE_SUBMENU][c4d.MENURESOURCE_SUBTITLE]!= "IDS_EDITOR_CA": MenuList.append(m) mainMenu.RemoveData(1) elif m[c4d.MENURESOURCE_SUBMENU][c4d.MENURESOURCE_SUBTITLE]== "IDS_EDITOR_CA": ca_menue= m[c4d.MENURESOURCE_SUBMENU] ca_menue.InsData(c4d.MENURESOURCE_SUBMENU, menu) MenuList.append((1,ca_menue)) break print MenuList #print NameList #set the file menu as the first entry mainMenu.SetData(1,MenuList[0][1]) #reverse the list to get the right order MenuList.reverse() #delete the file menu from the list del MenuList[-1] # rewrite all menus to the main menu for i,men in enumerate(MenuList) : mainMenu.InsDataAfter(c4d.MENURESOURCE_SUBMENU, men[1], c4d.gui.SearchPluginMenuResource("IDS_EDITOR_FILE")) #update menus c4d.gui.UpdateMenus() return
and the message function.
def Message(self, node, type, data) : if type== c4d.MSG_MENUPREPARE: EnhanceMainMenu(self,node)
-
On 25/05/2014 at 14:43, xxxxxxxx wrote:
Sorry for not being clear. Yes it works for me too in R13 on the PC.
What I meant was that I was already doing it that same way in my previous example. Only I did it on one specific sub menu("Create"). Rather than doing it on the entire "M_EDITOR" menu.We should not have to physically remove every single sub menu ("File", Edit, "Create") in the master "M_EDITOR" menu. And then put it all back in again. Just to get one of the sub menus to update after we've added something to it.
There should be a way to just update the existing menus like we do in C++.-ScottA
Edit - Also. Be careful with that code. Because it's removing some of the menus and not putting them back. And you won't notice this until you try to use things like: pluginsMenu = gui.SearchPluginMenuResource("IDS_EDITOR_FILE").
If you try to add a new menu next to the plugins menu. And also use your code. The plugins menu will not be there anymore. And the new menu gets inserted as the first menu.
This is why it's a bad idea to completely remove all of the menus just to add one.
It's too dangerous and weird things like this are bound to occur.