Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python 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
    • Recent
    • Tags
    • Users
    • Register
    • Login

    TreeView DropDown Menu

    Scheduled Pinned Locked Moved Cinema 4D SDK
    5 Posts 3 Posters 1.2k Views 2 Watching
    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.
    • S Offline
      simonator420
      last edited by simonator420

      Hi, it may be a foolish task but I would like to have different value in each row after I make the selection in the dropdown menu. This way it displays same value for every row. Could you help me with that?

      class ListView(c4d.gui.TreeViewFunctions):
       
          def __init__(self):
              self.selectedEntry = 1000
      
          def GetDropDownMenu(self, root, userdata, obj, lColumn, menuInfo):
              doc = c4d.documents.GetActiveDocument()
              menuInfo["entry"] = self.selectedEntry
              menuInfo["menu"][1000] = "Material 1"
              menuInfo["menu"][1001] = "Material 2"
              menuInfo["menu"][1002] = "Material 3"
              menuInfo["menu"][1003] = "Material 4"
              menuInfo["state"] = int(menuInfo["state"])
      
          def SetDropDownMenu(self, root, userdata, obj, lColumn, entry):
              self.selectedEntry = entry
              print(f"User selected the entry with the ID: {entry}")
      
      
      1 Reply Last reply Reply Quote 0
      • M Offline
        mogh
        last edited by

        Hi @simonator420,

        you use the same ID for each row I guess, in your code above you would need to ofset every row by a certain amount for the IDs

        I can not give you a working code from your snippet.

        self.selectedEntry = 1000 + offset
        

        kind regards,
        mogh

        ferdinandF 1 Reply Last reply Reply Quote 0
        • ferdinandF Offline
          ferdinand @mogh
          last edited by ferdinand

          Hello @simonator420,

          Thank you for reaching out to us. As announced here, Maxon is currently conducting a company meeting. Please understand that our capability to answer questions is therefore limited at the moment.

          I am slightly confused about the nature of your questions, especially in the context of the reply from @mogh. TreeViewFunctions.GetDropDownMenu lets you define the content of drop down menus in a TreeView, and the slightly ill named SetDropDownMenu lets you react to an item being selected in such menu.

          The 'problem' with your code snippet is that you do not differentiate the drop down gadgets which are set in GetDropDownMenu. Like many methods of TreeViewFunctions it is called for each cell in the tree view table, where lColumn denotes the column as defined in your TreeViewCustomGui.SetLayout call, and obj denotes an item in your root, so sort of the row in the tree.

          lColumn becomes meaningless when your tree view has only one column of type LV_DROPDOWN. How to make sense of obj, depends on the shape of the data you passed as root. When root root is just a list[object], you could for example alternate between even and odd rows like this.

          def GetDropDownMenu(
              self, root: list[object], userdata: any, obj: object, lColumn: int, menuInfo: dict):
              """Simple example for defining the menu content based on the position of #obj in #root.
              """
              index: int = root.index(obj)
              if index % 2 == 0:
                  menuInfo["menu"][1000] = "Even row first option"
                  menuInfo["menu"][1001] = "Even row second option"
              else:
                  menuInfo["menu"][1000] = "Odd row first option"
                  menuInfo["menu"][1001] = "Odd row second option"
          
              menuInfo["state"] = int(menuInfo["state"])
          

          In practice, the content of a drop down is more likely to be determined based on the fields of obj (e.g., if obj.a == "foo" then Menu1 else Menu2)rather than its relative position in root (be it a list-like or tree-like data structure).

          Cheers,
          Ferdinand

          MAXON SDK Specialist
          developers.maxon.net

          1 Reply Last reply Reply Quote 0
          • M Offline
            mogh
            last edited by

            I am addiong to this thread hence it is related ... feel free to fork

            I am trying to only display a dropdown on certain rows ... is that possible ....?

            Here is a minimal dummy plugin where I only want to show the dropdown on "stp" files ....
            even though the dropdown gets no content it is still displayed ....

            thank you

            import c4d 
            
            
            PLUGIN_ID = 12345678
            PLUGIN_NAME = "ListView Dropdown Prototype"
            
            ID_TREE_VIEW = 1000
            ID_FILE_NAME = 1001
            ID_IMPORT_OPTION = 1002
            
            ID_IMPORT_OPTION_DEFAULT = 1100
            ID_IMPORT_OPTION_HIGH = 1101
            ID_IMPORT_OPTION_MEDIUM = 1102
            ID_IMPORT_OPTION_LOW = 1103
            
            dummyfile_list = ["hud.stp", "material_reference.wrl", "front_axle.stp", "body.wrl", "wheel_variant.stp"]
            
            
            class DummyFile:
            	def __init__(self, file_name, import_option="Default"):
            		self.file_name = file_name
            		self.import_option = import_option
            
            
            class DummyFileListView(c4d.gui.TreeViewFunctions):
            	def __init__(self, dialog):
            		self.dialog = dialog
            		self.files = [DummyFile(file_name) for file_name in dummyfile_list]
            
            	def GetFirst(self, root, userdata):
            		return self.files[0] if self.files else None
            
            	def GetNext(self, root, userdata, dummy_file):
            		current_index = self.files.index(dummy_file)
            		next_index = current_index + 1
            		return self.files[next_index] if next_index < len(self.files) else None
            
            	def GetDown(self, root, userdata, dummy_file):
            		return None
            
            	def GetId(self, root, userdata, dummy_file):
            		return id(dummy_file)
            
            	def GetName(self, root, userdata, dummy_file):
            		return dummy_file.file_name
            
            	def IsSelected(self, root, userdata, dummy_file):
            		return False
            
            	def GetColumnWidth(self, root, userdata, dummy_file, column_id, area):
            		if column_id == ID_FILE_NAME:
            			return area.DrawGetTextWidth(dummy_file.file_name) + 24
            		if column_id == ID_IMPORT_OPTION:
            			return 120
            		return 96
            
            	def GetDropDownMenu(self, root, userdata, dummy_file, column_id, menu_info):
            		if column_id != ID_IMPORT_OPTION:
            			return
            
                # this is logical but does not do the trick ....
            		if not dummy_file.file_name.lower().endswith(".stp"):
            			return
            
            		options = {
            			ID_IMPORT_OPTION_DEFAULT: "Default",
            			ID_IMPORT_OPTION_HIGH: "High",
            			ID_IMPORT_OPTION_MEDIUM: "Medium",
            			ID_IMPORT_OPTION_LOW: "Low",
            		}
            		for option_id, label in options.items():
            			menu_info["menu"].SetString(option_id, label)
            		menu_info["entry"] = next(
            			option_id for option_id, label in options.items()
            			if label == dummy_file.import_option
            		)
            
            	def SetDropDownMenu(self, root, userdata, dummy_file, column_id, entry):
            		if column_id != ID_IMPORT_OPTION:
            			return
            
                #this is logical but does not do the trick ....
            
            		if not dummy_file.file_name.lower().endswith(".stp"):
            			return
            
            		options = {
            			ID_IMPORT_OPTION_DEFAULT: "Default",
            			ID_IMPORT_OPTION_HIGH: "High",
            			ID_IMPORT_OPTION_MEDIUM: "Medium",
            			ID_IMPORT_OPTION_LOW: "Low",
            		}
            		dummy_file.import_option = options.get(entry, dummy_file.import_option)
            		self.dialog.tree_view.Refresh()
            
            
            class ListViewDropdownDialog(c4d.gui.GeDialog):
            	def __init__(self):
            		self.tree_view = None
            		self.file_list_view = DummyFileListView(self)
            
            	def CreateLayout(self):
            		self.SetTitle(PLUGIN_NAME)
            
            		tree_view_settings = c4d.BaseContainer()
            		tree_view_settings.SetBool(c4d.TREEVIEW_BORDER, c4d.BORDER_THIN_IN)
            		tree_view_settings.SetBool(c4d.TREEVIEW_HAS_HEADER, True)
            		tree_view_settings.SetBool(c4d.TREEVIEW_HIDE_LINES, True)
            		tree_view_settings.SetBool(c4d.TREEVIEW_RESIZE_HEADER, True)
            		tree_view_settings.SetBool(c4d.TREEVIEW_FIXED_LAYOUT, True)
            		tree_view_settings.SetBool(c4d.TREEVIEW_ALTERNATE_BG, True)
            		if c4d.GetC4DVersion() >= 24000:
            			tree_view_settings.SetInt32(c4d.TREEVIEW_VERTICAL_SPACE, 4)
            
            		self.tree_view = self.AddCustomGui(ID_TREE_VIEW, c4d.CUSTOMGUI_TREEVIEW, "", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 500, 220, tree_view_settings, )
            		if not self.tree_view:
            			return False
            
            		layout = c4d.BaseContainer()
            		layout.SetLong(ID_FILE_NAME, c4d.LV_TREE)
            		layout.SetLong(ID_IMPORT_OPTION, c4d.LV_DROPDOWN)
            		self.tree_view.SetLayout(2, layout)
            		self.tree_view.SetHeaderText(ID_FILE_NAME, "Dummy file")
            		self.tree_view.SetHeaderText(ID_IMPORT_OPTION, "STP import option")
            		self.tree_view.SetRoot(self.tree_view, self.file_list_view, None)
            		return True
            
            	def InitValues(self):
            		self.tree_view.Refresh()
            		return True
            
            
            class ListViewDropdownCommand(c4d.plugins.CommandData):
            	def __init__(self):
            		self.dialog = ListViewDropdownDialog()
            
            	def Execute(self, document):
            		return self.dialog.Open(
            			c4d.DLG_TYPE_ASYNC,
            			PLUGIN_ID,
            			defaultw=520,
            			defaulth=280,
            		)
            
            
            
            
            if __name__ == "__main__":
            	c4d.plugins.RegisterCommandPlugin(
            		id=PLUGIN_ID,
            		str=PLUGIN_NAME,
            		info=0,
            		icon=None,
            		help="TreeView dropdown.",
            		dat=ListViewDropdownCommand(),
            	)
            
            
            1 Reply Last reply Reply Quote 0
            • ferdinandF Offline
              ferdinand
              last edited by

              Hey,

              yes it is. The trick is c4d.LV_CHECKBOX_HIDE, the relevant bits happen in GetDropDownMenu.

              Cheers,
              Ferdinand

              I removed the command, you can directly run this in the script manager:

              import c4d 
              
              
              PLUGIN_ID = 12345678
              PLUGIN_NAME = "ListView Dropdown Prototype"
              
              ID_TREE_VIEW = 1000
              ID_FILE_NAME = 1001
              ID_IMPORT_OPTION = 1002
              
              ID_IMPORT_OPTION_DEFAULT = 1100
              ID_IMPORT_OPTION_HIGH = 1101
              ID_IMPORT_OPTION_MEDIUM = 1102
              ID_IMPORT_OPTION_LOW = 1103
              
              dummyfile_list = ["hud.stp", "material_reference.wrl", "front_axle.stp", "body.wrl", "wheel_variant.stp"]
              
              
              class DummyFile:
                  def __init__(self, file_name, import_option="Default"):
                      self.file_name = file_name
                      self.import_option = import_option
              
              
              class DummyFileListView(c4d.gui.TreeViewFunctions):
                  def __init__(self, dialog):
                      self.dialog = dialog
                      self.files = [DummyFile(file_name) for file_name in dummyfile_list]
              
                  def GetFirst(self, root, userdata):
                      return self.files[0] if self.files else None
              
                  def GetNext(self, root, userdata, dummy_file):
                      current_index = self.files.index(dummy_file)
                      next_index = current_index + 1
                      return self.files[next_index] if next_index < len(self.files) else None
              
                  def GetDown(self, root, userdata, dummy_file):
                      return None
              
                  def GetId(self, root, userdata, dummy_file):
                      return id(dummy_file)
              
                  def GetName(self, root, userdata, dummy_file):
                      return dummy_file.file_name
              
                  def IsSelected(self, root, userdata, dummy_file):
                      return False
              
                  def GetColumnWidth(self, root, userdata, dummy_file, column_id, area):
                      if column_id == ID_FILE_NAME:
                          return area.DrawGetTextWidth(dummy_file.file_name) + 24
                      if column_id == ID_IMPORT_OPTION:
                          return 120
                      return 96
              
                  def GetDropDownMenu(self, root, userdata, dummy_file, column_id, menu_info):
                      if column_id != ID_IMPORT_OPTION:
                          menu_info["state"] = c4d.LV_CHECKBOX_HIDE
                          return
              
                      if not dummy_file.file_name.lower().endswith(".stp"):
                          menu_info["state"] = c4d.LV_CHECKBOX_HIDE
                          return
              
                      options = {
                          ID_IMPORT_OPTION_DEFAULT: "Default",
                          ID_IMPORT_OPTION_HIGH: "High",
                          ID_IMPORT_OPTION_MEDIUM: "Medium",
                          ID_IMPORT_OPTION_LOW: "Low",
                      }
                      for option_id, label in options.items():
                          menu_info["menu"].SetString(option_id, label)
                      menu_info["entry"] = next(
                          option_id for option_id, label in options.items()
                          if label == dummy_file.import_option
                      )
                      menu_info["state"] = c4d.LV_CHECKBOX_ENABLED
              
                  def SetDropDownMenu(self, root, userdata, dummy_file, column_id, entry):
                      if column_id != ID_IMPORT_OPTION:
                          return
              
                  #this is logical but does not do the trick ....
              
                      if not dummy_file.file_name.lower().endswith(".stp"):
                          return
              
                      options = {
                          ID_IMPORT_OPTION_DEFAULT: "Default",
                          ID_IMPORT_OPTION_HIGH: "High",
                          ID_IMPORT_OPTION_MEDIUM: "Medium",
                          ID_IMPORT_OPTION_LOW: "Low",
                      }
                      dummy_file.import_option = options.get(entry, dummy_file.import_option)
                      self.dialog.tree_view.Refresh()
              
              
              class ListViewDropdownDialog(c4d.gui.GeDialog):
                  def __init__(self):
                      self.tree_view = None
                      self.file_list_view = DummyFileListView(self)
              
                  def CreateLayout(self):
                      self.SetTitle(PLUGIN_NAME)
              
                      tree_view_settings = c4d.BaseContainer()
                      tree_view_settings.SetBool(c4d.TREEVIEW_BORDER, c4d.BORDER_THIN_IN)
                      tree_view_settings.SetBool(c4d.TREEVIEW_HAS_HEADER, True)
                      tree_view_settings.SetBool(c4d.TREEVIEW_HIDE_LINES, True)
                      tree_view_settings.SetBool(c4d.TREEVIEW_RESIZE_HEADER, True)
                      tree_view_settings.SetBool(c4d.TREEVIEW_FIXED_LAYOUT, True)
                      tree_view_settings.SetBool(c4d.TREEVIEW_ALTERNATE_BG, True)
                      if c4d.GetC4DVersion() >= 24000:
                          tree_view_settings.SetInt32(c4d.TREEVIEW_VERTICAL_SPACE, 4)
              
                      self.tree_view = self.AddCustomGui(ID_TREE_VIEW, c4d.CUSTOMGUI_TREEVIEW, "", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 500, 220, tree_view_settings, )
                      if not self.tree_view:
                          return False
              
                      layout = c4d.BaseContainer()
                      layout.SetLong(ID_FILE_NAME, c4d.LV_TREE)
                      layout.SetLong(ID_IMPORT_OPTION, c4d.LV_DROPDOWN)
                      self.tree_view.SetLayout(2, layout)
                      self.tree_view.SetHeaderText(ID_FILE_NAME, "Dummy file")
                      self.tree_view.SetHeaderText(ID_IMPORT_OPTION, "STP import option")
                      self.tree_view.SetRoot(self.tree_view, self.file_list_view, None)
                      return True
              
                  def InitValues(self):
                      self.tree_view.Refresh()
                      return True
              
              if __name__ == "__main__":
                  dialog = ListViewDropdownDialog()
                  dialog.Open(c4d.DLG_TYPE_MODAL, 0, -1, -1, 500, 220)
              

              MAXON SDK Specialist
              developers.maxon.net

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