import types
import Tkinter
import Pmw

class OptionMenu(Pmw.MegaWidget):

    def __init__(self, parent = None, **kw):

	# Define the megawidget options.
	INITOPT = Pmw.INITOPT
	optiondefs = (
	    ('command',        None,       None),
            ('items',          (),         INITOPT),
            ('initialitem',    None,       INITOPT),
	    ('labelmargin',    0,          INITOPT),
	    ('labelpos',       None,       INITOPT),
	)
	self.defineoptions(kw, optiondefs)

	# Initialise the base class (after defining the options).
	Pmw.MegaWidget.__init__(self, parent)

	# Create the components.
	interior = self.interior()

	self._menubutton = self.createcomponent('menubutton',
		(), None,
		Tkinter.Menubutton, (interior,),
		borderwidth = 2,
		indicatoron = 1,
		relief = 'raised',
		anchor = 'c',
		highlightthickness = 2,
		direction = 'flush',
	)
	self._menubutton.grid(column = 2, row = 2, sticky = 'nsew')

	self._menu = self.createcomponent('menu',
		(), None,
		Tkinter.Menu, (self._menubutton,),
		tearoff=0
	)
	self._menubutton.configure(menu = self._menu)

	interior.grid_columnconfigure(2, weight = 1)
	interior.grid_rowconfigure(2, weight = 1)

        # Create the label.
        self.createlabel(interior)

        # Add the items specified by the initialisation option.
	self._itemList = []
        self.setitems(self['items'], self['initialitem'])

	# Check keywords and initialise options.
	self.initialiseoptions(OptionMenu)

    def setitems(self, items, index = None):

        # Clean up old items and callback commands.
        for oldIndex in range(len(self._itemList)):
            tclCommandName = self._menu.entrycget(oldIndex, 'command')
            if tclCommandName != '':   
                self._menu.deletecommand(tclCommandName)
        self._menu.delete(0, 'end')
	self._itemList = list(items)

	# Set the items in the menu component.
        for item in items:
            self._menu.add_command(label = item,
		command = lambda self = self, item = item: self.invoke(item))

	# Set the currently selected value.
	var = self._menubutton.cget('textvariable')

	if index is None:
	    if var != '':
		# None means do not change text variable.
		return
	    if len(items) == 0:
		text = ''
	    elif self.getcurselection() in items:
                # Do not change selection if it is still valid
		return
	    else:
		text = items[0]
	else:
	    index = self.index(index)
	    text = self._itemList[index]

	if var == '':
	    self._menubutton.configure(text = text)
	else:
	    self._menu.tk.globalsetvar(var, text)

    def getcurselection(self):
	var = self._menubutton.cget('textvariable')
	if var == '':
	    return self._menubutton.cget('text')
	else:
	    return self._menu.tk.globalgetvar(var)

    def index(self, index):
	listLength = len(self._itemList)
	if type(index) == types.IntType:
	    if index < listLength:
		return index
	    else:
		raise ValueError, 'index "%s" is out of range' % index
	elif index is Pmw.END:
	    if listLength > 0:
		return listLength - 1
	    else:
		raise ValueError, 'OptionMenu has no items'
	else:
	    if index is Pmw.SELECT:
		if listLength > 0:
		    index = self.getcurselection()
		else:
		    raise ValueError, 'OptionMenu has no items'
            if index in self._itemList:
                return self._itemList.index(index)
	    validValues = 'a name, a number, Pmw.END or Pmw.SELECT'
	    raise ValueError, \
		    'bad index "%s": must be %s' % (index, validValues)

    def invoke(self, index = Pmw.SELECT):
	index = self.index(index)
	text = self._itemList[index]

	var = self._menubutton.cget('textvariable')
	if var == '':
	    self._menubutton.configure(text = text)
	else:
	    self._menu.tk.globalsetvar(var, text)

	command = self['command']
	if callable(command):
	    return command(text)
