SOLVED Modified Pop Up Menu

Hi,

I'm trying to create a pop-up menu with a modified layout. Currently, the default layout of c4d.gui.ShowPopupDialog is vertical. I was looking forward to a columnar layout where its easier to see everything.

You can see an illustration of what I am after here:
https://www.dropbox.com/s/8dhs505yz34lap3/c4d140_modified_popup_menu.mp4?dl=0

A few notable behaviors are that

  1. modified columnar layout
  2. it disappears once you click a command (pop-up)

I initially thought the DLG_TYPE_ASYNC_POPUPEDIT or DLG_TYPE_ASYNC_POPUP_RESIZEABLE would do the trick but unfortunately, when you click a command, the dialog does not disappear.

You can see an illustration code below:

import c4d
import os
from c4d import gui, plugins, bitmaps, utils, documents


PLUGIN_ID   = 1011325

MAIN_TAB    = 10001
MY_BUTTON   = 11002

class MyDialog(gui.GeDialog):

    def get_all_objects(op):

      output = []

      while op:
          output.append(op)
          get_all_objects(op.GetDown())
          op = op.GetNext()
      return output


    def CreateLayout(self):

      self.GroupBegin(id=1013, flags=c4d.BFH_SCALEFIT, cols=5, rows=4)  
      self.AddButton(MY_BUTTON, c4d.BFV_MASK, initw=100, name="Button1")
      self.AddButton(MY_BUTTON, c4d.BFV_MASK, initw=100, name="Button2")
      self.AddButton(MY_BUTTON, c4d.BFV_MASK, initw=100, name="Button3")
      self.AddButton(MY_BUTTON, c4d.BFV_MASK, initw=100, name="Button4")
      self.AddButton(MY_BUTTON, c4d.BFV_MASK, initw=100, name="Button5")
      self.AddButton(MY_BUTTON, c4d.BFV_MASK, initw=100, name="Button6")

      self.GroupEnd()

      return True


    def Command(self, id, msg):

        if (id == MY_BUTTON):
            print "Button is clicked"
            return True

        return True

class MyMenuPlugin(plugins.CommandData):

    dialog = None
    def Execute(self, doc):
    # create the dialog
       if self.dialog is None:
          self.dialog = MyDialog()

       return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC_POPUPEDIT, pluginid=PLUGIN_ID, defaultw=200, defaulth=150, xpos=-1, ypos=-1)

    def RestoreLayout(self, sec_ref):
    # manage the dialog
       if self.dialog is None:
          self.dialog = MyDialog()
       return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)


if __name__ == "__main__":

    okyn = plugins.RegisterCommandPlugin(PLUGIN_ID, "BT Popup",0, None, "Python Menu", MyMenuPlugin())
    if (okyn):
        print "Utilities Pop Up"

Thank you for looking at my problem

Hi,

as @Cairyn said the problem is unreachable code. I also just saw now that you did assign the same ID to all your buttons in your CreateLayout(). Ressource and dialog element IDs should be unique. I would generally recommend to define your dialogs using a resource, but here is an example on how to do it in code.

BUTTON_BASE_ID = 1000
BUTTON_NAMES = ["Button1", "Button2", "Button3", "Button4", "Button5"]
BUTTON_DATA = {BUTTON_BASE_ID + i: name for i, name in enumerate(BUTTON_NAMES)}

class MyDialog(gui.GeDialog):

    def CreateLayout(self):
        """
        """
        self.GroupBegin(id=1013, flags=c4d.BFH_SCALEFIT, cols=5, rows=4)
        for element_id, element_name in BUTTON_DATA.items():
            self.AddButton(element_id, c4d.BFV_MASK, initw=100, 
                           name=element_name)
        self.GroupEnd()
        return True

    def Command(self, id, msg):
        """
        """
        if id == BUTTON_BASE_ID:
            print "First button has been clicked"
        elif id == BUTTON_BASE_ID + 1:
            print "Second button has been clicked"
        # ...
        if id in BUTTON_DATA.keys(): # or just if id in BUTTON_DATA
            self.Close()
        return True

Hi,

@bentraje said in Modified Pop Up Menu:

I initially thought the DLG_TYPE_ASYNC_POPUPEDIT or DLG_TYPE_ASYNC_POPUP_RESIZEABLE would do the trick but unfortunately, when you click a command, the dialog does not disappear.

To programmatically close a dialog you have to invoke GeDialog.Close(). So if you want to mimic a popup menu, you should do that after the button event handling.

all_button_ids = [ID_BUTTON_1, ID_BUTTON_2, ...]

def Command(self, id, msg):
    
    if id == ID_BUTTON_1:
        # your button logic ...

    if id in all_button_ids:
        self.Close()

Cheers
zipit

@zipit said in Modified Pop Up Menu:

if id in all_button_ids:

Thanks for the response. I tried adding it. It didn't error out but it also didn't close.

You can see the current code here:

import c4d
import os
from c4d import gui, plugins, bitmaps, utils, documents


PLUGIN_ID   = 1011325

MAIN_TAB    = 10001
MY_BUTTON   = 11002

all_button_ids = [MY_BUTTON]

class MyDialog(gui.GeDialog):

    def get_all_objects(op):

      output = []

      while op:
          output.append(op)
          get_all_objects(op.GetDown())
          op = op.GetNext()
      return output


    def CreateLayout(self):

      self.GroupBegin(id=1013, flags=c4d.BFH_SCALEFIT, cols=5, rows=4)  
      self.AddButton(MY_BUTTON, c4d.BFV_MASK, initw=100, name="Button1")
      self.AddButton(MY_BUTTON, c4d.BFV_MASK, initw=100, name="Button2")
      self.AddButton(MY_BUTTON, c4d.BFV_MASK, initw=100, name="Button3")
      self.AddButton(MY_BUTTON, c4d.BFV_MASK, initw=100, name="Button4")
      self.AddButton(MY_BUTTON, c4d.BFV_MASK, initw=100, name="Button5")
      self.AddButton(MY_BUTTON, c4d.BFV_MASK, initw=100, name="Changed")

      self.GroupEnd()

      return True


    def Command(self, id, msg):

        if (id == MY_BUTTON):
            print "Button is clicked"
            return True

        if id in all_button_ids:
            self.Close()
            return True

        return True

class MyMenuPlugin(plugins.CommandData):

    dialog = None
    def Execute(self, doc):
    # create the dialog
       if self.dialog is None:
          self.dialog = MyDialog()

       return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC_POPUPEDIT, pluginid=PLUGIN_ID, defaultw=200, defaulth=150, xpos=-1, ypos=-1)

    def RestoreLayout(self, sec_ref):
    # manage the dialog
       if self.dialog is None:
          self.dialog = MyDialog()
       return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)


if __name__ == "__main__":

    okyn = plugins.RegisterCommandPlugin(PLUGIN_ID, "BT Popup",0, None, "Python Menu", MyMenuPlugin())
    if (okyn):
        print "Utilities Pop Up"

@bentraje said in Modified Pop Up Menu:

Thanks for the response. I tried adding it. It didn't error out but it also didn't close

Unreached code. You return true when MY_BUTTON is clicked, and never get to the self.Close() part.
(You can remove two of the three returns from that method.)

Hi,

as @Cairyn said the problem is unreachable code. I also just saw now that you did assign the same ID to all your buttons in your CreateLayout(). Ressource and dialog element IDs should be unique. I would generally recommend to define your dialogs using a resource, but here is an example on how to do it in code.

BUTTON_BASE_ID = 1000
BUTTON_NAMES = ["Button1", "Button2", "Button3", "Button4", "Button5"]
BUTTON_DATA = {BUTTON_BASE_ID + i: name for i, name in enumerate(BUTTON_NAMES)}

class MyDialog(gui.GeDialog):

    def CreateLayout(self):
        """
        """
        self.GroupBegin(id=1013, flags=c4d.BFH_SCALEFIT, cols=5, rows=4)
        for element_id, element_name in BUTTON_DATA.items():
            self.AddButton(element_id, c4d.BFV_MASK, initw=100, 
                           name=element_name)
        self.GroupEnd()
        return True

    def Command(self, id, msg):
        """
        """
        if id == BUTTON_BASE_ID:
            print "First button has been clicked"
        elif id == BUTTON_BASE_ID + 1:
            print "Second button has been clicked"
        # ...
        if id in BUTTON_DATA.keys(): # or just if id in BUTTON_DATA
            self.Close()
        return True

@Cairyn and @zipit

Thanks for the clarification. Your solution works as expected.

Hello,

Thanks for sharing your answer @zipit and @Cairyn

Cheers,
Manuel