text: """Undocumented Module"""
  
  __all__ = ['DirectScrolledListItem', 'DirectScrolledList']
  
  from panda3d.core import *
  import DirectGuiGlobals as DGG
  from direct.directnotify import DirectNotifyGlobal
  from direct.task.Task import Task
  from DirectFrame import *
  from DirectButton import *
  import types
  
  
  class DirectScrolledListItem(DirectButton):
      """
      While you are not required to use a DirectScrolledListItem for a
      DirectScrolledList, doing so takes care of the highlighting and
      unhighlighting of the list items.
      """
      notify = DirectNotifyGlobal.directNotify.newCategory("DirectScrolledListItem")
  
      def __init__(self, parent=None, **kw):
          assert self.notify.debugStateCall(self)
          self.parent = parent
          if "command" in kw:
              self.nextCommand = kw.get("command")
              del kw["command"]
          if "extraArgs" in kw:
              self.nextCommandExtraArgs = kw.get("extraArgs")
              del kw["extraArgs"]
          optiondefs = (
              ('parent', self.parent,    None),
              ('command', self.select, None),
              )
          # Merge keyword options with default options
          self.defineoptions(kw, optiondefs)
          DirectButton.__init__(self)
          self.initialiseoptions(DirectScrolledListItem)
  
      def select(self):
          assert self.notify.debugStateCall(self)
          apply(self.nextCommand, self.nextCommandExtraArgs)
          self.parent.selectListItem(self)
  
  
  class DirectScrolledList(DirectFrame):
      notify = DirectNotifyGlobal.directNotify.newCategory("DirectScrolledList")
  
      def __init__(self, parent = None, **kw):
          assert self.notify.debugStateCall(self)
          self.index = 0
          self.forceHeight = None
  
          """ If one were to want a scrolledList that makes and adds its items
             as needed, simply pass in an items list of strings (type 'str')
             and when that item is needed, itemMakeFunction will be called
             with the text, the index, and itemMakeExtraArgs.  If itemMakeFunction
             is not specified, it will create a DirectFrame with the text."""
  
          # if 'items' is a list of strings, make a copy for our use
          # so we can modify it without mangling the user's list
          if 'items' in kw:
              for item in kw['items']:
                  if type(item) != type(''):
                      break
              else:
                  # we get here if every item in 'items' is a string
                  # make a copy
                  kw['items'] = kw['items'][:]
  
          self.nextItemID = 10
  
          # Inherits from DirectFrame
          optiondefs = (
              # Define type of DirectGuiWidget
              ('items',              [],        None),
              ('itemsAlign',  TextNode.ACenter, DGG.INITOPT),
              ('itemsWordwrap',      None,      DGG.INITOPT),
              ('command',            None,      None),
              ('extraArgs',          [],        None),
              ('itemMakeFunction',   None,      None),
              ('itemMakeExtraArgs',  [],        None),
              ('numItemsVisible',    1,         self.setNumItemsVisible),
              ('scrollSpeed',        8,         self.setScrollSpeed),
              ('forceHeight',        None,      self.setForceHeight),
              ('incButtonCallback',  None,      self.setIncButtonCallback),
              ('decButtonCallback',  None,      self.setDecButtonCallback),
              )
          # Merge keyword options with default options
          self.defineoptions(kw, optiondefs)
  
          # Initialize superclasses
          DirectFrame.__init__(self, parent)
  
          self.incButton = self.createcomponent("incButton", (), None,
                                                DirectButton, (self,),
                                                )
          self.incButton.bind(DGG.B1PRESS, self.__incButtonDown)
          self.incButton.bind(DGG.B1RELEASE, self.__buttonUp)
          self.decButton = self.createcomponent("decButton", (), None,
                                                DirectButton, (self,),
                                                )
          self.decButton.bind(DGG.B1PRESS, self.__decButtonDown)
          self.decButton.bind(DGG.B1RELEASE, self.__buttonUp)
          self.itemFrame = self.createcomponent("itemFrame", (), None,
                                                DirectFrame, (self,),
                                                )
          for item in self["items"]:
              if item.__class__.__name__ != 'str':
                  item.reparentTo(self.itemFrame)
  
          self.initialiseoptions(DirectScrolledList)
          self.recordMaxHeight()
          self.scrollTo(0)
  
      def setForceHeight(self):
          assert self.notify.debugStateCall(self)
          self.forceHeight = self["forceHeight"]
  
      def recordMaxHeight(self):
          assert self.notify.debugStateCall(self)
          if self.forceHeight is not None:
              self.maxHeight = self.forceHeight
          else:
              self.maxHeight = 0.0
              for item in self["items"]:
                  if item.__class__.__name__ != 'str':
                      self.maxHeight = max(self.maxHeight, item.getHeight())
  
      def setScrollSpeed(self):
          assert self.notify.debugStateCall(self)
          # Items per second to move
          self.scrollSpeed = self["scrollSpeed"]
          if self.scrollSpeed <= 0:
              self.scrollSpeed = 1
  
      def setNumItemsVisible(self):
          assert self.notify.debugStateCall(self)
          # Items per second to move
          self.numItemsVisible = self["numItemsVisible"]
  
      def destroy(self):
          assert self.notify.debugStateCall(self)
          taskMgr.remove(self.taskName("scroll"))
          if hasattr(self, "currentSelected"):
              del self.currentSelected
          if self.incButtonCallback:
              self.incButtonCallback = None
          if self.decButtonCallback:
              self.decButtonCallback = None
          self.incButton.destroy()
          self.decButton.destroy()       
          DirectFrame.destroy(self)
  
      def selectListItem(self, item):
          assert self.notify.debugStateCall(self)
          if hasattr(self, "currentSelected"):
              self.currentSelected['state']=DGG.NORMAL
          item['state']=DGG.DISABLED
          self.currentSelected=item
  
      def scrollBy(self, delta):
          assert self.notify.debugStateCall(self)
          #print "scrollBy[", delta,"]"
          return self.scrollTo(self.index + delta)
  
      def getItemIndexForItemID(self, itemID):
          assert self.notify.debugStateCall(self)
          #for i in range(len(self["items"])):
          #    print "buttontext[", i,"]", self["items"][i]["text"]
  
          if(len(self["items"])==0):
              return 0
  
          if(type(self["items"][0])!=types.InstanceType):
              self.notify.warning("getItemIndexForItemID: cant find itemID for non-class list items!")
              return 0
  
          for i in range(len(self["items"])):
              if(self["items"][i].itemID == itemID):
                  return i
          self.notify.warning("getItemIndexForItemID: item not found!")
          return 0
  
      def scrollToItemID(self, itemID, centered=0):
          assert self.notify.debugStateCall(self)
          self.scrollTo(self.getItemIndexForItemID(itemID), centered)
  
      def scrollTo(self, index, centered=0):
          """ scrolls list so selected index is at top, or centered in box"""
          assert self.notify.debugStateCall(self)
          #print "scrollTo[", index,"] called, len(self[items])=", len(self["items"])," self[numItemsVisible]=", self["numItemsVisible"]
          try:
              self["numItemsVisible"]
          except:
              # RAU hack to kill 27633
              self.notify.info('crash 27633 fixed!')
              return
  
          numItemsVisible = self["numItemsVisible"]
          numItemsTotal = len(self["items"])
          if(centered):
              self.index = index - (numItemsVisible/2)
          else:
              self.index = index
  
          # Not enough items to even worry about scrolling,
          # just disable the buttons and do nothing
          if (len(self["items"]) <= numItemsVisible):
              self.incButton['state'] = DGG.DISABLED
              self.decButton['state'] = DGG.DISABLED
              # Hmm.. just reset self.index to 0 and bail out
              self.index = 0
              ret = 0
          else:
              if (self.index <= 0):
                  self.index = 0
                  #print "at list start, ", len(self["items"]),"  ", self["numItemsVisible"]
                  self.decButton['state'] = DGG.DISABLED
                  self.incButton['state'] = DGG.NORMAL
                  ret = 0
              elif (self.index >= (numItemsTotal - numItemsVisible)):
                  self.index = numItemsTotal - numItemsVisible
                  #print "at list end, ", len(self["items"]),"  ", self["numItemsVisible"]
                  self.incButton['state'] = DGG.DISABLED
                  self.decButton['state'] = DGG.NORMAL
                  ret = 0
              else:
                  # deal with an edge condition - make sure any tasks are removed from the disabled arrows.
                  if (self.incButton['state'] == DGG.DISABLED) or (self.decButton['state'] == DGG.DISABLED):
                      #print "leaving list start/end, ", len(self["items"]),"  ", self["numItemsVisible"]
                      self.__buttonUp(0)
                  self.incButton['state'] = DGG.NORMAL
                  self.decButton['state'] = DGG.NORMAL
                  ret = 1
  
          #print "self.index set to ", self.index
  
          # Hide them all
          for item in self["items"]:
              if item.__class__.__name__ != 'str':
                  item.hide()
  
          # Then show the ones in range, and stack their positions
          upperRange = min(numItemsTotal, numItemsVisible)
          for i in range(self.index, self.index + upperRange):
              item = self["items"][i]
              #print "stacking buttontext[", i,"]", self["items"][i]["text"]
              # If the item is a 'str', then it has not been created (scrolled list is 'as needed')
              #  Therefore, use the the function given to make it or just make it a frame
              if item.__class__.__name__ == 'str':
                  if self['itemMakeFunction']:
                      # If there is a function to create the item
                      item = apply(self['itemMakeFunction'], (item, i, self['itemMakeExtraArgs']))
                  else:
                      item = DirectFrame(text = item,
                                         text_align = self['itemsAlign'],
                                         text_wordwrap = self['itemsWordwrap'],
                                         relief = None)
                  #print "str stacking buttontext[", i,"]", self["items"][i]["text"]
                  # Then add the newly formed item back into the normal item list
                  self["items"][i] = item
                  item.reparentTo(self.itemFrame)
                  self.recordMaxHeight()
  
              item.show()
              item.setPos(0, 0,  -(i-self.index) * self.maxHeight)
              #print 'height bug tracker: i-%s idx-%s h-%s' % (i, self.index, self.maxHeight)
  
          if self['command']:
              # Pass any extra args to command
              apply(self['command'], self['extraArgs'])
          return ret
  
      def makeAllItems(self):
          assert self.notify.debugStateCall(self)
          for i in range(len(self['items'])):
              item = self["items"][i]
              # If the item is a 'str', then it has not been created
              # Therefore, use the the function given to make it or
              # just make it a frame
              #print "Making " + str(item)
              if item.__class__.__name__ == 'str':
                  if self['itemMakeFunction']:
                      # If there is a function to create the item
                      item = apply(self['itemMakeFunction'],
                                   (item, i, self['itemMakeExtraArgs']))
                  else:
                      item = DirectFrame(text = item,
                                         text_align = self['itemsAlign'],
                                         text_wordwrap = self['itemsWordwrap'],
                                         relief = None)
                  # Then add the newly formed item back into the normal item list
                  self["items"][i] = item
                  item.reparentTo(self.itemFrame)
          self.recordMaxHeight()
  
      def __scrollByTask(self, task):
          assert self.notify.debugStateCall(self)
          if ((task.time - task.prevTime) < task.delayTime):
              return Task.cont
          else:
              ret = self.scrollBy(task.delta)
              task.prevTime = task.time
              if ret:
                  return Task.cont
              else:
                  return Task.done
  
      def __incButtonDown(self, event):
          assert self.notify.debugStateCall(self)
          task = Task(self.__scrollByTask)
          task.setDelay(1.0 / self.scrollSpeed)
          task.prevTime = 0.0
          task.delta = 1
          taskName = self.taskName("scroll")
          #print "incButtonDown: adding ", taskName
          taskMgr.add(task, taskName)
          self.scrollBy(task.delta)
          messenger.send('wakeup')
          if self.incButtonCallback:
              self.incButtonCallback()
          
      def __decButtonDown(self, event):
          assert self.notify.debugStateCall(self)
          task = Task(self.__scrollByTask)
          task.setDelay(1.0 / self.scrollSpeed)
          task.prevTime = 0.0
          task.delta = -1
          taskName = self.taskName("scroll")
          #print "decButtonDown: adding ", taskName
          taskMgr.add(task, taskName)
          self.scrollBy(task.delta)
          messenger.send('wakeup')
          if self.decButtonCallback:
              self.decButtonCallback()        
                 
      def __buttonUp(self, event):
          assert self.notify.debugStateCall(self)
          taskName = self.taskName("scroll")
          #print "buttonUp: removing ", taskName
          taskMgr.remove(taskName)
          
      def addItem(self, item, refresh=1):
          """
          Add this string and extraArg to the list
          """
          assert self.notify.debugStateCall(self)
          if(type(item) == types.InstanceType):
              # cant add attribs to non-classes (like strings & ints)
              item.itemID = self.nextItemID
              self.nextItemID += 1
          self['items'].append(item)
          if type(item) != type(''):
              item.reparentTo(self.itemFrame)
          if refresh:
              self.refresh()
          if(type(item) == types.InstanceType):
              return item.itemID  # to pass to scrollToItemID
  
      def removeItem(self, item, refresh=1):
          """
          Remove this item from the panel
          """
          assert self.notify.debugStateCall(self)
          #print "remove item called", item
          #print "items list", self['items']
          if item in self["items"]:
              #print "removing item", item
              if hasattr(self, "currentSelected") and self.currentSelected is item:
                  del self.currentSelected
              self["items"].remove(item)
              if type(item) != type(''):
                  item.reparentTo(hidden)
              self.refresh()
              return 1
          else:
              return 0
          
      def removeAndDestroyItem(self, item, refresh = 1):
          """
          Remove and destroy this item from the panel.
          """
          assert self.notify.debugStateCall(self)
          if item in self["items"]:
              if hasattr(self, "currentSelected") and self.currentSelected is item:
                  del self.currentSelected
              if (hasattr(item, 'destroy') and hasattr(item.destroy, '__call__')):
                  item.destroy()
              self["items"].remove(item)
              if type(item) != type(''):
                  item.reparentTo(hidden)
              self.refresh()
              return 1
          else:
              return 0
  
      def removeAllItems(self, refresh=1):
          """
          Remove this item from the panel
          Warning 2006_10_19 tested only in the trolley metagame
          """
          assert self.notify.debugStateCall(self)
          retval = 0
          #print "remove item called", item
          #print "items list", self['items']
          while len (self["items"]):
              item = self['items'][0]
              #print "removing item", item
              if hasattr(self, "currentSelected") and self.currentSelected is item:
                  del self.currentSelected
              self["items"].remove(item)
              if type(item) != type(''):
                  #RAU possible leak here, let's try to do the right thing 
                  #item.reparentTo(hidden)
                  item.removeNode()
              retval = 1
  
          if (refresh):
              self.refresh()
              
          return retval
      
      def removeAndDestroyAllItems(self, refresh = 1):
          """
          Remove and destroy all items from the panel.
          Warning 2006_10_19 tested only in the trolley metagame
          """
          assert self.notify.debugStateCall(self)
          retval = 0
          while len (self["items"]):
              item = self['items'][0]
              if hasattr(self, "currentSelected") and self.currentSelected is item:
                  del self.currentSelected
              if (hasattr(item, 'destroy') and hasattr(item.destroy, '__call__')):
                  item.destroy()
              self["items"].remove(item)
              if type(item) != type(''):
                  #RAU possible leak here, let's try to do the right thing 
                  #item.reparentTo(hidden)
                  item.removeNode()
              retval = 1
          if (refresh):
              self.refresh()            
          return retval
  
      def refresh(self):
          """
          Update the list - useful when adding or deleting items
          or changing properties that would affect the scrolling
          """
          assert self.notify.debugStateCall(self)
          self.recordMaxHeight()
          #print "refresh called"
          self.scrollTo(self.index)
  
      def getSelectedIndex(self):
          assert self.notify.debugStateCall(self)
          return self.index
  
      def getSelectedText(self):
          assert self.notify.debugStateCall(self)
          if self['items'][self.index].__class__.__name__ == 'str':
            return self['items'][self.index]
          else:
            return self['items'][self.index]['text']
  
      def setIncButtonCallback(self):
          assert self.notify.debugStateCall(self)
          self.incButtonCallback = self["incButtonCallback"]
  
      def setDecButtonCallback(self):
          assert self.notify.debugStateCall(self)
          self.decButtonCallback = self["decButtonCallback"]        
  
  
  """
  from DirectGui import *
  
  def makeButton(itemName, itemNum, *extraArgs):
      def buttonCommand():
          print itemName, itemNum
      return DirectButton(text = itemName,
                          relief = DGG.RAISED,
                          frameSize = (-3.5, 3.5, -0.2, 0.8),
                          scale = 0.85,
                          command = buttonCommand)
  
  s = scrollList = DirectScrolledList(
      parent = aspect2d,
      relief = None,
      # Use the default dialog box image as the background
      image = DGG.getDefaultDialogGeom(),
      # Scale it to fit around everyting
      image_scale = (0.7, 1, .8),
      # Give it a label
      text = "Scrolled List Example",
      text_scale = 0.06,
      text_align = TextNode.ACenter,
      text_pos = (0, 0.3),
      text_fg = (0, 0, 0, 1),
      # inc and dec are DirectButtons
      # They can contain a combination of text, geometry and images
      # Just a simple text one for now
      incButton_text = 'Increment',
      incButton_relief = DGG.RAISED,
      incButton_pos = (0.0, 0.0, -0.36),
      incButton_scale = 0.1,
      # Same for the decrement button
      decButton_text = 'Decrement',
      decButton_relief = DGG.RAISED,
      decButton_pos = (0.0, 0.0, 0.175),
      decButton_scale = 0.1,
      # each item is a button with text on it
      numItemsVisible = 4,
      itemMakeFunction = makeButton,
      items = ['Able', 'Baker', 'Charlie', 'Delta', 'Echo', 'Foxtrot',
               'Golf', 'Hotel', 'India', 'Juliet', 'Kilo', 'Lima'],
      # itemFrame is a DirectFrame
      # Use it to scale up or down the items and to place it relative
      # to eveything else
      itemFrame_pos = (0, 0, 0.06),
      itemFrame_scale = 0.1,
      itemFrame_frameSize = (-3.1, 3.1, -3.3, 0.8),
      itemFrame_relief = DGG.GROOVE,
      )
  """
  