This start at a  pulldown list accepts insertions, accepts a callback
method.
It does /not/ yet accept parenting or keys during initialization.
There is a problem with packing with the 'pd = PullDown.new.pack' statement.

Is there a better way to hide/show widgets that unpack/pack?

-----------------------------------------------------------------------
require 'tk'

# accepts callback as follows: pd.callback proc{|selection| <do something
with it>}
# ignores parent and keys for the moment
# test code at end

class PullDown < TkListbox
 def initialize (parent = nil, keys = nil)
  @list_up = false
  @up_button = '/\\'
  @down_button = '\/'
  @cb = nil

  @keys = {'height'=> 20,
                 'width'=> 20,
        'background'=> 'white'
      }

  @frame = TkFrame.new
  @topframe = TkFrame.new(@frame).pack('side'=>'top')
        @pulldown = TkFrame.new(@frame).pack('side'=>'bottom')

  super(@pulldown, @keys)
  #put up our scroll bars
  @sb = TkScrollbar.new(@pulldown,
                  'command' => proc { |*args| self.yview *args })
  self.yscrollcommand(proc { |first,last|
                             @sb.set(first,last) })
  @pulldown.pack('side'=>'bottom')

  #build the top part of the display
  @label = TkLabel.new(@topframe) {
      background  'white'
      width 20
      height 1
      }.pack('side'=>'left',
           'fill'=>'x',
           'expand'=>'yes')

  @button = TkButton.new(@topframe){
                       width 1
        height 1
        text @down_button
        }.pack('side'=>'right')

  @button.bind('Button-1'){
    if !@list_up then
     show
    else
     hide
    end}


  self.bind('ButtonRelease-1'){
     @label.text self.get(self.curselection[0])
     @cb.call(@label.text) if @cb
     hide
     @list_up = false
     }
  @frame.pack
 end

  def callback(&method)
   @cb = method
  end

 def add (value)
  self.insert('end',value)
  @label.text self.get(0)
 end

 #This is a real ugly way to hide/show something
 private
 def hide
  @pulldown.unpack
  @sb.unpack
  self.unpack
  @list_up = false
  @button.text(@down_button)
 end

 def show
  self.pack('side'=>'left')
  @sb.pack('side' => 'right', 'fill' => 'y')
  @pulldown.pack('side'=>'bottom')
  @list_up = true
  @button.text(@up_button)
 end
end

#---------------------------test
code-----------------------------------------
# problems with pack (which I haven't figured out yet)
pd = PullDown.new #.pack

# callback works just fine
# pd.callback {|f| p f}
TkFont.families.each{|f| pd.add(f)}

Tk.mainloop
----------------------------------------------------------------------------
-----