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

    Implementing a simple list

    PYTHON Development
    0
    23
    14.2k
    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.
    • H
      Helper
      last edited by

      On 28/05/2013 at 07:49, xxxxxxxx wrote:

      Originally posted by xxxxxxxx

      Yes, that is what I need, Scott. But, how do I define it in the resource file?

      It probably won't do you any good to create it if there's nothing in the python SDK to use it.
      But I'll post how to create it anyway so you at least know how to create it.

        
      ###### This is the code for the ListView gizmo in the .res file ######  
        
        GROUP LIST_GROUP    
        {     
        LISTVIEW MY_LISTBOX  {ALIGN_TOP; ALIGN_LEFT; SIZE 150, 50;}   
        }  
        
        
        
        
        
        
      ###### This is the code that goes in the plugin's .pyp file ######  
        
      CUSTOMGUI_LISTVIEW = 1018398    #The text Id for the ListView gizmo is not set up yet. So do it manually   
      MY_LISTBOX = 10001  
        
        
      #The CreateLayout method   
        def CreateLayout(self) :      
        
            res = self.LoadDialogResource(ResBasedMenu)                        #Loads GUI stuff from the .res file  
              
            self.listbox = self.FindCustomGui(MY_LISTBOX, CUSTOMGUI_LISTVIEW)  #Creates the ListView gizmo          
              
            return res
      

      -Scott

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 28/05/2013 at 08:05, xxxxxxxx wrote:

        Thank you.
        So, we can create it but we cant add anything to it, right?

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 28/05/2013 at 08:20, xxxxxxxx wrote:

          And, shouldn't it be AddCustomGui instead of FindCustomGui?

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 28/05/2013 at 08:27, xxxxxxxx wrote:

            So, it all indicates that I need to create a SCROLLGROUP with a USERAREA inside it an implement a LISTVIEW manually.
            Am I correct into assuming this?

            Rui Batista

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 28/05/2013 at 08:39, xxxxxxxx wrote:

              1. The QuickTabGui is documented under c4d.gui.BaseCustomGui.QuickTabGui

              2. You have to call FindCustomGui to get hold of the CustomGui class providing methods
                  to interact with the gadget. It will return the helper class for the CustomGui at that id.
                  For a ListView it will be None, as there is no such class in python.

              3. I am not sure if you did understand the difference between the definition of a CustomGui
                  in a resource file and its wrapping class. Defining a ListView is no problem, it will show
                  up in your gui, but you won't be able to read or write data to it, as there is no wrapping
                  CustomGui class in python providing methods like SetItem() or GetItem() to change the
                  the items in your ListView.

              4. Not sure where to search. I just know that he once wrote it. Just start a google search
                  for Nikklas Rosenstein ListView.

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 28/05/2013 at 08:54, xxxxxxxx wrote:

                Originally posted by xxxxxxxx

                And, shouldn't it be AddCustomGui instead of FindCustomGui?

                AddCustomGui returns an error when used with CustomGui. Don't ask me why.
                If you want to see a working example of this. Use CUSTOMGUI_LINKBOX instead of CUSTOMGUI_LISTVIEW.
                The custom .res based LinkBox gizmo seems to be supported....Or it works by accident.
                And using FindCustomGui is the only way it works for me.

                Originally posted by xxxxxxxx

                So, it all indicates that I need to create a SCROLLGROUP with a USERAREA inside it an implement a LISTVIEW manually.
                Am I correct into assuming this?

                That's one possible option. But it sounds like a fairly ugly proposal to me.
                Another option is switching to C++ so you stop running into things that are not supported in Python. 😉

                -ScottA

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  On 28/05/2013 at 09:17, xxxxxxxx wrote:

                  I don't intend to switch to C++ soon as it is much more complex than python and, also, requires different compilation for Mac an Windows.
                  I may have to create my own implementation of a LIST_VIEW 😞

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    On 28/05/2013 at 09:26, xxxxxxxx wrote:

                    ^Yeah. I know. I was just kidding you about that. Tongue

                    -ScottA

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      On 28/05/2013 at 11:40, xxxxxxxx wrote:

                      Hi Rui,

                      this is a very very old implementation of a simple ListView of mine. I've used it in Description Editor
                      plugin. Works relatively fine, very basic. Please don't judge my coding style, this snippet is about 2
                      years old. 🙂

                      Maybe you can use it.

                      class ListView(GeUserArea) :
                          MOUSEWHEEL_MODE         = 1027215       # Registered at Plugincafe.com
                          SELECTEDROW_UP          = 1027216       # Registered at Plugincafe.com
                          SELECTEDROW_DOWN        = 1027217       # Registered at Plugincafe.com     
                          SELECTEDROW_CHANGED     = 1027218       # Registered at Plugincafe.com
                          SELECTEDROW_PREVIOUS    = 1027219       # Registered at Plugincafe.com
                        
                          colors             = {
                              "background":       Vector(.2),
                              "lighterRow":       Vector(.31),
                              "darkerRow":        Vector(.29),
                              "markedRow":        Vector(.38),
                              "text":             Vector(.64705),
                              "markedText":       Vector(1., .66, .024)
                          }
                        
                          def __init__(
                                  self,
                                  parentDialog    = None,                 # The parent-dialog, can be None if the 'Command'-Method should not be invoked on an Input-Event
                                  initialData     = (()),                 # Data to display, must be 2 dimensional
                                  rowHeight       = 16,                   # Height of a row in the ListView
                                  columnWidths    = (100,),               # Widths of the columns in the ListView
                                  minSize         = (300, 100),           # Minimum size of the area. If second is None, it will be calculated.
                              ) :
                        
                              self.parentDialog       = parentDialog
                        
                              self.rowHeight          = rowHeight
                              self.columnWidths       = tuple(columnWidths)
                              self.data               = list(initialData)
                              self.selectedRow        = -1
                        
                              self.minSize            = tuple(minSize)
                        
                          # Overriden
                          def DrawMsg(self, x1, y1, x2, y2, msg) :
                              """ Called when redrawing the UserArea """
                              self.SetClippingRegion(x1, y1, x2, y2)
                        
                              self.DrawSetPen(self.colors["background"])  # Set Background Color
                              self.DrawRectangle(x1, y1, x2, y2)          # Fill Background
                        
                              """
                              Draw lighter rows
                              """
                              self.DrawSetPen(self.colors["lighterRow"])
                              for i in xrange(0,len(self.data), 2) :           # Iterate the  specified rows
                                  Rectangle       = {
                                      'x1':               0,
                                      'x2':               x2,
                                      'y1':               self.rowHeight * i,
                                      'y2':               self.rowHeight * (i + 1)
                                  }
                                  # If the selected Row is about to be drawn
                                  if i == self.selectedRow and self.colors["markedRow"]:
                                      self.DrawSetPen(self.colors["markedRow"])
                                      self.DrawRectangle(**Rectangle)
                                      self.DrawSetPen(self.colors["lighterRow"])
                                  else:
                                      self.DrawRectangle(**Rectangle)
                        
                              """
                              Draw darker rows
                              """
                              self.DrawSetPen(self.colors["darkerRow"]) 
                              for i in xrange(1,len(self.data), 2) :           # Iterate the  specified rows
                                  Rectangle       = {
                                      'x1':               0,
                                      'x2':               x2,
                                      'y1':               self.rowHeight * i,
                                      'y2':               self.rowHeight * (i + 1)
                                  }
                                  # If the selected Row is about to be drawn
                                  if i == self.selectedRow and self.colors["markedRow"]:
                                      self.DrawSetPen(self.colors["markedRow"])
                                      self.DrawRectangle(**Rectangle)
                                      self.DrawSetPen(self.colors["darkerRow"])
                                  else:
                                      self.DrawRectangle(**Rectangle)
                        
                              """
                              Draw data.
                              """
                              self.DrawSetTextCol(self.colors["text"], c4d.COLOR_TRANS)
                              for i in xrange(len(self.data)) :                # Iterate the  specified rows
                                  previousItemPosX    = x1 + 5
                                  for j in xrange(len(self.data[i])) :         # Iterate the datas columns
                                      if j >= len(self.columnWidths) :
                                          width       = self.columnWidths[-1]
                                      else:
                                          width       = self.columnWidths[j]
                        
                                      textToDraw          = str(self.data[i][j])
                        
                                      # If the selected Row is about to be drawn
                                      if i == self.selectedRow:
                                          self.DrawSetTextCol(self.colors["markedText"], c4d.COLOR_TRANS)
                                          self.DrawText(  txt     = textToDraw,
                                                          x1      = x1 + previousItemPosX ,
                                                          y1      = y1 + i *  self.rowHeight + self.rowHeight - 14,
                                          )
                                          self.DrawSetTextCol(self.colors["text"], c4d.COLOR_TRANS)
                                      else:
                                          self.DrawText(  txt     = textToDraw,
                                                          x1      = x1 + previousItemPosX ,
                                                          y1      = y1 + i *  self.rowHeight + self.rowHeight - 14,
                                          )
                                      previousItemPosX   += width
                        
                          def InputEvent(self, msg) :
                              inputChannel            = msg[c4d.BFM_INPUT_CHANNEL]
                        
                              # Left or Right Mousebutton
                              if inputChannel in (c4d.BFM_INPUT_MOUSELEFT, c4d.BFM_INPUT_MOUSERIGHT, c4d.BFM_INPUT_MOUSEMIDDLE) :
                                  positionInDialog    = self.Global2Local()
                                  mousePosX           = msg[c4d.BFM_INPUT_X] + positionInDialog["x"]
                                  mousePosY           = msg[c4d.BFM_INPUT_Y] + positionInDialog["y"]
                        
                                  clickedRow          = int(mousePosY/self.rowHeight)
                        
                                  msg[self.SELECTEDROW_PREVIOUS]  = self.selectedRow
                        
                                  if clickedRow > len(self.data) - 1:
                                      self.selectedRow    = -1
                                  else:
                                      self.selectedRow    = clickedRow
                        
                                  self.Redraw()
                        
                              # MouseWheel switching of elements
                              elif inputChannel == c4d.BFM_INPUT_MOUSEWHEEL:
                                  inputValue      = msg[c4d.BFM_INPUT_VALUE]
                                  selectedRow     = self.selectedRow
                        
                                  # Go up (in visual), means to go back in the list 
                                  if inputValue > 0:
                                      # Do not if data-begin is reached
                                      if selectedRow > 0:
                                          if self.parentDialog:
                                              bc         = c4d.BaseContainer()
                        
                                              bc[self.MOUSEWHEEL_MODE]        = self.SELECTEDROW_UP
                                              bc[self.SELECTEDROW_CHANGED]    = -1    # Selected row + SELECTEDROW_CHANGED = newSelectedRow
                        
                                              self.parentDialog.Command(self.GetId(), bc) 
                        
                                          self.selectedRow   -= 1
                        
                                  # Go down (in visual), means to go further in the list
                                  elif inputValue < 0:
                                      # Do not if data-end is reached
                                      if selectedRow <= len(self.data) -2:
                                          if self.parentDialog:
                                              bc         = c4d.BaseContainer()
                        
                                              bc[self.MOUSEWHEEL_MODE]        = self.SELECTEDROW_DOWN
                                              bc[self.SELECTEDROW_CHANGED]    = 1     # Selected row + SELECTEDROW_CHANGED = newSelectedRow
                        
                                              self.parentDialog.Command(self.GetId(), bc)
                        
                                          self.selectedRow   += 1
                        
                                  self.Redraw()
                        
                              # if parentDialog is defined, send Command-Message
                              if self.parentDialog:
                                  self.parentDialog.Command(self.GetId(), msg)
                        
                        
                              return True
                        
                          def GetMinSize(self) :
                              """ Returns the minimum size of the area. """
                              return tuple(self.minSize)
                        
                          # Getters
                          def GetMinHeight(self) :
                              return self.minSize[1]
                        
                          def GetSelectedRow(self) :
                              return self.selectedRow
                        
                          def GetRowHeight(self) :
                              return self.rowHeight
                        
                          def GetColumnWidths(self) :
                              return self.columnWidths
                        
                          def GetParentDialog(self) :
                              return self.parentDialog
                        
                          # Setters
                          def SetColors(self, **kwargs) :
                              for k, v in kwargs.iteritems() :
                                  if k in self.colors.keys() :
                                      self.colors[k]  = v
                        
                          def SetData(self, data) :
                              self.data   = data
                        
                          def SetRowHeight(self, height) :
                              self.rowHeight      = height
                              self.minSize[1]     = self.rowHeight * len(self.data)
                        
                          def SetColumnWidths(self, columnWidths) :
                              self.columnWidths   = columnWidths
                        
                          def SetSelectedRow(self, index) :
                              if index >= len(self.data) :
                                  self.selectedRow    = -1
                                  return False
                              else:
                                  self.selectedRow    = index
                                  return True
                        
                          def SetParentDialog(self, parent) :
                              self.parentDialog       = parent
                        
                          # Adders
                          def AppendData(self, data) :
                              self.data.append(data)
                        
                          def InsertData_AtIndex(self, data, index) :
                              if index > len( self.data ) :
                                  return False
                              else:
                                  self.data.insert(index, data)
                        
                          # Removers
                          def RemoveData(self, subData) :
                              if subData in self.data:
                                  del self.data[ self.data.index(subData) ]
                                  return True
                              else:
                                  return False
                        
                          def RemoveData_ByIndex(self, index) :
                              if index > len( self.data ) :
                                  return False
                              else:
                                  del self.data[index]
                        
                          # Update
                          pass
                      

                      -Nik

                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        On 29/05/2013 at 09:06, xxxxxxxx wrote:

                        Thank you very muck, Nikklas.
                        I will check it out, to see if I can use it.
                        This creates color bars, right?
                        I want to create a list of text items. Should not be too complicated to change this to my needs 🙂

                        Rui Batista

                        1 Reply Last reply Reply Quote 0
                        • H
                          Helper
                          last edited by

                          On 29/05/2013 at 09:25, xxxxxxxx wrote:

                          Yep, it looks like this:

                          The data it uses to display must be a two dimensional list with each row having the same number of columns! A selected item can be moved up and down by scrolling the mouse-wheel. But scrolling the view is not implemented in this user area.

                          1 Reply Last reply Reply Quote 0
                          • H
                            Helper
                            last edited by

                            On 29/05/2013 at 15:38, xxxxxxxx wrote:

                            It is working fine, Nikklas 🙂
                            However, if I add more than a certain number of items, they just disappear down the bottom.
                            Is there any way to implement a vertical scroll bar?

                            1 Reply Last reply Reply Quote 0
                            • H
                              Helper
                              last edited by

                              On 30/05/2013 at 01:57, xxxxxxxx wrote:

                              Sure. I think the easiest way would be to implement GetMinSize() and call LayoutChange() on the
                              dialog when the elements in the list have changed and put the user area into a scroll-group.

                              -Nik

                              1 Reply Last reply Reply Quote 0
                              • H
                                Helper
                                last edited by

                                On 30/05/2013 at 02:14, xxxxxxxx wrote:

                                You code already has a GetMinSize() and the user area it already inside a SCROLLGROUP, like this:

                                SCROLLGROUP DC_SCRIPT_CONTAINER
                                     {
                                     SCALE_V;
                                     SCALE_H;
                                     SCROLL_V;
                                     SCROLL_BORDER;

                                USERAREA DC_SCRIPT_LIST { SCALE_V; SCALE_H; }
                                     }

                                In my main code, I already filled the data with many, many items, just to test if a vertical scroll bar would appear. But it doesn't. Even if I change the size of my plugin window 😞

                                1 Reply Last reply Reply Quote 0
                                • H
                                  Helper
                                  last edited by

                                  On 30/05/2013 at 02:42, xxxxxxxx wrote:

                                  But the current GetMinSize() implementation does not calculate the height based on the number
                                  of elements. 🙂

                                  http://pastebin.com/Jz2yPqK8

                                  But I see it is a bit buggy, I don't know why actually. While the background is drawn correctly, the
                                  text is not.. Not sure where this comes from, maybe you can figure it out.

                                  -Nik

                                  1 Reply Last reply Reply Quote 0
                                  • H
                                    Helper
                                    last edited by

                                    On 30/05/2013 at 03:29, xxxxxxxx wrote:

                                    Actually, it is working but the userarea is not refreshing correctly when I scroll down and back up again.
                                    I should be able to intercept a message that tells me that the scrollgroup changed and refresh the userarea when that happens.
                                    But I don't know how 😞

                                    Rui Batista

                                    1 Reply Last reply Reply Quote 0
                                    • H
                                      Helper
                                      last edited by

                                      On 30/05/2013 at 03:46, xxxxxxxx wrote:

                                      I'm trying to detect that the scrollgroup is being dragged with msg[c4d.BFM_ACTION_INDRAG]

                                      but when I use this code:

                                      def Message(self, msg, result) :
                                          dragging=msg[c4d.BFM_ACTION_INDRAG]
                                          return GeDialog.Message(self, msg, result)

                                      I get a crash while starting up Cinema4D.

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