Plugin Cafe Homepage
Forum Home Forum Home > Plugin Cafe > PYTHON Development
  New Posts New Posts
  FAQ FAQ  Forum Search   Register Register  Login Login

How to add a plugin to a toolbar menu?

 Post Reply Post Reply
Author
Message
jameshcoppens View Drop Down
Member
Member


Joined: 2011 Mar 25
Location: Brooklyn
Online Status: Offline
Posts: 53
Post Options Post Options   Quote jameshcoppens Quote  Post ReplyReply Direct Link To This Post Topic: How to add a plugin to a toolbar menu?
    Posted: 2014 May 08 at 8:16am
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.
-Jimmy
http://www.jimmycoppens.com
Back to Top
Donovan Keith View Drop Down
Member
Member


Joined: 2002 Oct 30
Location: United States
Online Status: Offline
Posts: 199
Post Options Post Options   Quote Donovan Keith Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 09 at 11:35am
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
Back to Top
NiklasR View Drop Down
Member
Member


Joined: 2010 Dec 13
Location: Germany
Online Status: Offline
Posts: 2573
Post Options Post Options   Quote NiklasR Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 10 at 12:54am
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
Back to Top
jameshcoppens View Drop Down
Member
Member


Joined: 2011 Mar 25
Location: Brooklyn
Online Status: Offline
Posts: 53
Post Options Post Options   Quote jameshcoppens Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 15 at 10:46am
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
-Jimmy
http://www.jimmycoppens.com
Back to Top
NiklasR View Drop Down
Member
Member


Joined: 2010 Dec 13
Location: Germany
Online Status: Offline
Posts: 2573
Post Options Post Options   Quote NiklasR Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 15 at 1:29pm
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


Edited by NiklasR - 2014 May 15 at 1:36pm
Back to Top
ScottA View Drop Down
Member
Member


Joined: 2011 Jan 07
Online Status: Offline
Posts: 2288
Post Options Post Options   Quote ScottA Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 15 at 4:38pm
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


Edited by ScottA - 2014 May 16 at 7:22am
Back to Top
ScottA View Drop Down
Member
Member


Joined: 2011 Jan 07
Online Status: Offline
Posts: 2288
Post Options Post Options   Quote ScottA Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 18 at 10:26am
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
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Post Options Post Options   Quote monkeytack Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 18 at 1:51pm
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

Back to Top
ScottA View Drop Down
Member
Member


Joined: 2011 Jan 07
Online Status: Offline
Posts: 2288
Post Options Post Options   Quote ScottA Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 18 at 2:59pm
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? Wacko

It's a worse tangled mess than the nested containers system used for the UserData.

-ScottA


Edited by ScottA - 2014 May 18 at 3:28pm
Back to Top
jameshcoppens View Drop Down
Member
Member


Joined: 2011 Mar 25
Location: Brooklyn
Online Status: Offline
Posts: 53
Post Options Post Options   Quote jameshcoppens Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 22 at 10:58am
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
-Jimmy
http://www.jimmycoppens.com
Back to Top
Donovan Keith View Drop Down
Member
Member


Joined: 2002 Oct 30
Location: United States
Online Status: Offline
Posts: 199
Post Options Post Options   Quote Donovan Keith Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 23 at 5:21pm
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()
Back to Top
Donovan Keith View Drop Down
Member
Member


Joined: 2002 Oct 30
Location: United States
Online Status: Offline
Posts: 199
Post Options Post Options   Quote Donovan Keith Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 23 at 5:23pm
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.
Back to Top
ScottA View Drop Down
Member
Member


Joined: 2011 Jan 07
Online Status: Offline
Posts: 2288
Post Options Post Options   Quote ScottA Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 24 at 8:23am
@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
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Post Options Post Options   Quote monkeytack Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 25 at 1:05pm
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()



Back to Top
ScottA View Drop Down
Member
Member


Joined: 2011 Jan 07
Online Status: Offline
Posts: 2288
Post Options Post Options   Quote ScottA Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 25 at 1:47pm
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! Wink

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
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Post Options Post Options   Quote monkeytack Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 25 at 2:02pm
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
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Post Options Post Options   Quote monkeytack Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 25 at 2:12pm
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)

Back to Top
ScottA View Drop Down
Member
Member


Joined: 2011 Jan 07
Online Status: Offline
Posts: 2288
Post Options Post Options   Quote ScottA Quote  Post ReplyReply Direct Link To This Post Posted: 2014 May 25 at 2:43pm
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.


Edited by ScottA - 2014 May 25 at 4:14pm
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down

Bulletin Board Software by Web Wiz Forums® version 9.61 [Free Express Edition]
Copyright ©2001-2009 Web Wiz

This page was generated in 0.125 seconds.