Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Add Commands to ShowPopupDialog

    Cinema 4D SDK
    r21 python
    3
    7
    1.0k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • B
      bentraje
      last edited by

      Hi,

      Is there a way I can add commands to ShowPopupDialog?
      In the documentation, it offers commands but built-in ones such as c4d.Ocube or c4d.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

      1 Reply Last reply Reply Quote 0
      • M
        m_adam
        last edited by m_adam

        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.

        MAXON SDK Specialist

        Development Blog, MAXON Registered Developer

        1 Reply Last reply Reply Quote 1
        • B
          bentraje
          last edited by

          @m_adam

          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 line c4d.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 the Menu 1 it prints You selected Menu 1. in the console as a test.

          My concern is I have it under the Message() and not under the Command() since it does not seem to recognize the ShowPopupDialog 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)
          
          A 1 Reply Last reply Reply Quote 0
          • A
            Ashton_FCS_PluginDev @bentraje
            last edited by Ashton_FCS_PluginDev

            @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

            1 Reply Last reply Reply Quote 1
            • B
              bentraje
              last edited by

              Hi @Ashton_FCS_PluginDev

              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.

              1. you have to register a CommandData
              2. 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!

              1 Reply Last reply Reply Quote 0
              • M
                m_adam
                last edited by

                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.

                MAXON SDK Specialist

                Development Blog, MAXON Registered Developer

                1 Reply Last reply Reply Quote 1
                • B
                  bentraje
                  last edited by

                  @m_adam Thanks for further clarification.

                  @Ashton_FCS_PluginDev 's code works but I guess I'll just use the result of the ShowPopupDialog to trigger commands, as I added in the previous code.

                  1 Reply Last reply Reply Quote 0
                  • First post
                    Last post