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 clicking here.

    def PluginMessage(kind, data) :
        if kind == c4d.C4DPL_BUILDMENU:
            bc = c4d.gui.GetMenuResource()
            # ... alter menu container
        return True
    

    Best,
    -Niklas



  • 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
    Martin

      
      
    import 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.


Log in to reply