import PmwColor
Color = PmwColor
del PmwColor
import PmwBlt
Blt = PmwBlt
del PmwBlt
_VERSION = '1.2'
def setversion(version):

    if version != _VERSION:
        raise ValueError, 'Dynamic versioning not available'
def setalphaversions(*alpha_versions):

    if alpha_versions != ():
	raise ValueError, 'Dynamic versioning not available'
def version(alpha = 0):

    if alpha:
        return ()
    else:
        return _VERSION
def installedversions(alpha = 0):

    if alpha:
        return ()
    else:
        return (_VERSION,)
import os
import string
import sys
import traceback
import types
import Tkinter
END = ['end']
SELECT = ['select']
DEFAULT = ['default']
INITOPT = ['initopt']
_DEFAULT_OPTION_VALUE = ['default_option_value']
_useTkOptionDb = 0
_OPT_DEFAULT         = 0
_OPT_VALUE           = 1
_OPT_FUNCTION        = 2
_busyStack = []
_grabStack = []
def __methodDict(cls, dict):

    baseList = list(cls.__bases__)
    baseList.reverse()
    for super in baseList:
	__methodDict(super, dict)
    for key, value in cls.__dict__.items():
	if type(value) == types.FunctionType:
	    dict[key] = value
def __methods(cls):

    dict = {}
    __methodDict(cls, dict)
    return dict.keys()
__stringBody = (
    'def %(method)s(this, *args, **kw): return ' +
    'apply(this.%(attribute)s.%(method)s, args, kw)')
__counter = 0
def __unique():

  global __counter
  __counter = __counter + 1
  return str(__counter)
__funcBody = (
    'def %(method)s(this, *args, **kw): return ' +
    'apply(this.%(forwardFunc)s().%(method)s, args, kw)')
def forwardmethods(fromClass, toClass, toPart, exclude = ()):

    if type(toPart) != types.StringType:
	if callable(toPart):
	    if hasattr(toPart, 'im_func'):
		toPart = toPart.im_func
	    forwardName = '__fwdfunc__' + __unique()
	    fromClass.__dict__[forwardName] = toPart
	else:
	    raise TypeError, 'toPart must be attribute name, function or method'
    dict = {}
    __methodDict(toClass, dict)
    for ex in dict.keys():
	if ex[:1] == '_' or ex[-1:] == '_':
	    del dict[ex]
    for ex in exclude:
	if dict.has_key(ex):
	    del dict[ex]
    for ex in __methods(fromClass):
	if dict.has_key(ex):
	    del dict[ex]
    for method, func in dict.items():
	d = {'method': method, 'func': func}
	if type(toPart) == types.StringType:
	    execString = \
		__stringBody % {'method' : method, 'attribute' : toPart}
	else:
	    execString = \
		__funcBody % {'forwardFunc' : forwardName, 'method' : method}
	exec execString in d
	fromClass.__dict__[method] = d[method]
def setgeometryanddeiconify(window, geom):

    if os.name == 'nt' or \
            (os.name == 'posix' and sys.platform[:6] == 'cygwin'):
        redirect = window.overrideredirect()
        if not redirect:
            window.overrideredirect(1)
        window.deiconify()
        if geom is not None:
            window.geometry(geom)
        window.update_idletasks()
        window.tkraise()
        if not redirect:
            window.overrideredirect(0)
    else:
        if geom is not None:
            window.geometry(geom)
        window.deiconify()
        if window.overrideredirect():
            window.tkraise()
class MegaArchetype:


    def __init__(self, parent = None, hullClass = None):

	self.__componentInfo = {}
	self.__componentAliases = {}
	if hullClass is None:
	    self._hull = None
	else:
	    if parent is None:
		parent = Tkinter._default_root
	    self._hull = self.createcomponent('hull',
		    (), None,
		    hullClass, (parent,))
	    _hullToMegaWidget[self._hull] = self
	    if _useTkOptionDb:
		option_get = self.option_get
		_VALUE = _OPT_VALUE
		_DEFAULT = _OPT_DEFAULT
		for name, info in self._optionInfo.items():
		    value = info[_VALUE]
		    if value is _DEFAULT_OPTION_VALUE:
			resourceClass = string.upper(name[0]) + name[1:]
			value = option_get(name, resourceClass)
			if value != '':
			    try:
				value = eval(value, {'__builtins__': {}})
			    except:
				pass
			    info[_VALUE] = value
			else:
			    info[_VALUE] = info[_DEFAULT]
    def destroy(self):

	self._optionInfo = {}
        if self._hull is not None:
            del _hullToMegaWidget[self._hull]
            self._hull.destroy()
    def defineoptions(self, keywords, optionDefs, dynamicGroups = ()):

	if not hasattr(self, '_constructorKeywords'):
	    tmp = {}
	    for option, value in keywords.items():
		tmp[option] = [value, 0]
	    self._constructorKeywords = tmp
	    self._optionInfo = {}
	    self._initialiseoptions_counter = 0
        self._initialiseoptions_counter = self._initialiseoptions_counter + 1
        if not hasattr(self, '_dynamicGroups'):
            self._dynamicGroups = ()
        self._dynamicGroups = self._dynamicGroups + tuple(dynamicGroups)
	self.addoptions(optionDefs)
    def addoptions(self, optionDefs):

	optionInfo = self._optionInfo
	optionInfo_has_key = optionInfo.has_key
	keywords = self._constructorKeywords
	keywords_has_key = keywords.has_key
	FUNCTION = _OPT_FUNCTION
	for name, default, function in optionDefs:
	    if '_' not in name:
		if not optionInfo_has_key(name):
		    if keywords_has_key(name):
			value = keywords[name][0]
			optionInfo[name] = [default, value, function]
			del keywords[name]
		    else:
			if _useTkOptionDb:
			    optionInfo[name] = \
				    [default, _DEFAULT_OPTION_VALUE, function]
			else:
			    optionInfo[name] = [default, default, function]
		elif optionInfo[name][FUNCTION] is None:
		    optionInfo[name][FUNCTION] = function
	    else:
		if not keywords_has_key(name):
		    keywords[name] = [default, 0]
    def createcomponent(self, componentName, componentAliases,

            componentGroup, widgetClass, *widgetArgs, **kw):
	if self.__componentInfo.has_key(componentName):
	    raise ValueError, 'Component "%s" already exists' % componentName
	if '_' in componentName:
	    raise ValueError, \
                    'Component name "%s" must not contain "_"' % componentName
	if hasattr(self, '_constructorKeywords'):
	    keywords = self._constructorKeywords
	else:
	    keywords = {}
	for alias, component in componentAliases:
	    index = string.find(component, '_')
	    if index < 0:
		self.__componentAliases[alias] = (component, None)
	    else:
		mainComponent = component[:index]
		subComponent = component[(index + 1):]
		self.__componentAliases[alias] = (mainComponent, subComponent)
	    alias = alias + '_'
	    aliasLen = len(alias)
	    for option in keywords.keys():
		if len(option) > aliasLen and option[:aliasLen] == alias:
		    newkey = component + '_' + option[aliasLen:]
		    keywords[newkey] = keywords[option]
		    del keywords[option]
	componentPrefix = componentName + '_'
	nameLen = len(componentPrefix)
	for option in keywords.keys():
	    if len(option) > nameLen and option[:nameLen] == componentPrefix:
		kw[option[nameLen:]] = keywords[option][0]
		del keywords[option]
	    else:
		index = string.find(option, '_')
		if index >= 0 and componentGroup == option[:index]:
		    rest = option[(index + 1):]
		    kw[rest] = keywords[option][0]
		    keywords[option][1] = 1
	if kw.has_key('pyclass'):
	    widgetClass = kw['pyclass']
	    del kw['pyclass']
	if widgetClass is None:
	    return None
        if len(widgetArgs) == 1 and type(widgetArgs[0]) == types.TupleType:
            widgetArgs = widgetArgs[0]
	widget = apply(widgetClass, widgetArgs, kw)
	componentClass = widget.__class__.__name__
	self.__componentInfo[componentName] = (widget, widget.configure,
		componentClass, widget.cget, componentGroup)
	return widget
    def destroycomponent(self, name):

	self.__componentInfo[name][0].destroy()
	del self.__componentInfo[name]
    def createlabel(self, parent, childCols = 1, childRows = 1):

	labelpos = self['labelpos']
	labelmargin = self['labelmargin']
	if labelpos is None:
	    return
	label = self.createcomponent('label',
		(), None,
		Tkinter.Label, (parent,))
	if labelpos[0] in 'ns':
	    if labelpos[0] == 'n':
		row = 0
		margin = 1
	    else:
		row = childRows + 3
		margin = row - 1
	    label.grid(column=2, row=row, columnspan=childCols, sticky=labelpos)
	    parent.grid_rowconfigure(margin, minsize=labelmargin)
	else:
	    if labelpos[0] == 'w':
		col = 0
		margin = 1
	    else:
		col = childCols + 3
		margin = col - 1
	    label.grid(column=col, row=2, rowspan=childRows, sticky=labelpos)
	    parent.grid_columnconfigure(margin, minsize=labelmargin)
    def initialiseoptions(self, dummy = None):

        self._initialiseoptions_counter = self._initialiseoptions_counter - 1
	if self._initialiseoptions_counter == 0:
	    unusedOptions = []
	    keywords = self._constructorKeywords
	    for name in keywords.keys():
		used = keywords[name][1]
		if not used:
                    index = string.find(name, '_')
                    if index < 0 or name[:index] not in self._dynamicGroups:
                        unusedOptions.append(name)
	    if len(unusedOptions) > 0:
		if len(unusedOptions) == 1:
		    text = 'Unknown option "'
		else:
		    text = 'Unknown options "'
		raise KeyError, text + string.join(unusedOptions, ', ') + \
			'" for ' + self.__class__.__name__
	    FUNCTION = _OPT_FUNCTION
	    for info in self._optionInfo.values():
		func = info[FUNCTION]
		if func is not None and func is not INITOPT:
		    func()
    def configure(self, option=None, **kw):

	if len(kw) == 0:
	    if option is None:
		rtn = {}
		for option, config in self._optionInfo.items():
		    resourceClass = string.upper(option[0]) + option[1:]
		    rtn[option] = (option, option, resourceClass,
			    config[_OPT_DEFAULT], config[_OPT_VALUE])
		return rtn
	    else:
		config = self._optionInfo[option]
		resourceClass = string.upper(option[0]) + option[1:]
		return (option, option, resourceClass, config[_OPT_DEFAULT],
			config[_OPT_VALUE])
	optionInfo = self._optionInfo
	optionInfo_has_key = optionInfo.has_key
	componentInfo = self.__componentInfo
	componentInfo_has_key = componentInfo.has_key
	componentAliases = self.__componentAliases
	componentAliases_has_key = componentAliases.has_key
	VALUE = _OPT_VALUE
	FUNCTION = _OPT_FUNCTION
	directOptions = []
	indirectOptions = {}
	indirectOptions_has_key = indirectOptions.has_key
	for option, value in kw.items():
	    if optionInfo_has_key(option):
		if optionInfo[option][FUNCTION] is INITOPT:
		    raise KeyError, \
			    'Cannot configure initialisation option "' \
			    + option + '" for ' + self.__class__.__name__
		optionInfo[option][VALUE] = value
		directOptions.append(option)
	    else:
		index = string.find(option, '_')
		if index >= 0:
		    component = option[:index]
		    componentOption = option[(index + 1):]
		    if componentAliases_has_key(component):
			component, subComponent = componentAliases[component]
			if subComponent is not None:
			    componentOption = subComponent + '_' \
				    + componentOption
			option = component + '_' + componentOption
		    if componentInfo_has_key(component):
			componentConfigFuncs = [componentInfo[component][1]]
		    else:
			componentConfigFuncs = []
			for info in componentInfo.values():
			    if info[4] == component:
			        componentConfigFuncs.append(info[1])
                        if len(componentConfigFuncs) == 0 and \
                                component not in self._dynamicGroups:
			    raise KeyError, 'Unknown option "' + option + \
				    '" for ' + self.__class__.__name__
		    for componentConfigFunc in componentConfigFuncs:
			if not indirectOptions_has_key(componentConfigFunc):
			    indirectOptions[componentConfigFunc] = {}
			indirectOptions[componentConfigFunc][componentOption] \
				= value
		else:
		    raise KeyError, 'Unknown option "' + option + \
			    '" for ' + self.__class__.__name__
	map(apply, indirectOptions.keys(),
		((),) * len(indirectOptions), indirectOptions.values())
	for option in directOptions:
	    info = optionInfo[option]
	    func = info[_OPT_FUNCTION]
	    if func is not None:
	      func()
    def __setitem__(self, key, value):

        apply(self.configure, (), {key: value})
    def component(self, name):

	index = string.find(name, '_')
	if index < 0:
	    component = name
	    remainingComponents = None
	else:
	    component = name[:index]
	    remainingComponents = name[(index + 1):]
	if self.__componentAliases.has_key(component):
	    component, subComponent = self.__componentAliases[component]
	    if subComponent is not None:
		if remainingComponents is None:
		    remainingComponents = subComponent
		else:
		    remainingComponents = subComponent + '_' \
			    + remainingComponents
	widget = self.__componentInfo[component][0]
	if remainingComponents is None:
	    return widget
	else:
	    return widget.component(remainingComponents)
    def interior(self):

	return self._hull
    def hulldestroyed(self):

	return not _hullToMegaWidget.has_key(self._hull)
    def __str__(self):

	return str(self._hull)
    def cget(self, option):

	if self._optionInfo.has_key(option):
	    return self._optionInfo[option][_OPT_VALUE]
	else:
	    index = string.find(option, '_')
	    if index >= 0:
		component = option[:index]
		componentOption = option[(index + 1):]
		if self.__componentAliases.has_key(component):
		    component, subComponent = self.__componentAliases[component]
		    if subComponent is not None:
			componentOption = subComponent + '_' + componentOption
		    option = component + '_' + componentOption
		if self.__componentInfo.has_key(component):
		    componentCget = self.__componentInfo[component][3]
		    return componentCget(componentOption)
		else:
		    for info in self.__componentInfo.values():
			if info[4] == component:
			    componentCget = info[3]
			    return componentCget(componentOption)
	raise KeyError, 'Unknown option "' + option + \
		'" for ' + self.__class__.__name__
    __getitem__ = cget
    def isinitoption(self, option):

	return self._optionInfo[option][_OPT_FUNCTION] is INITOPT
    def options(self):

	options = []
	if hasattr(self, '_optionInfo'):
	    for option, info in self._optionInfo.items():
		isinit = info[_OPT_FUNCTION] is INITOPT
		default = info[_OPT_DEFAULT]

		options.append((option, default, isinit))
	    options.sort()
	return options
    def components(self):

	names = self.__componentInfo.keys()
	names.sort()
	return names
    def componentaliases(self):

	componentAliases = self.__componentAliases
	names = componentAliases.keys()
	names.sort()
	rtn = []
	for alias in names:
	    (mainComponent, subComponent) = componentAliases[alias]
	    if subComponent is None:
		rtn.append((alias, mainComponent))
	    else:
		rtn.append((alias, mainComponent + '_' + subComponent))
	return rtn
    def componentgroup(self, name):

	return self.__componentInfo[name][4]
def pushgrab(grabWindow, globalMode, deactivateFunction):

    prevFocus = grabWindow.tk.call('focus')
    grabInfo = {
        'grabWindow' : grabWindow,
        'globalMode' : globalMode,
        'previousFocus' : prevFocus,
        'deactivateFunction' : deactivateFunction,
    }
    _grabStack.append(grabInfo)
    _grabtop()
    grabWindow.focus_set()
def popgrab(window):

    if _grabStack[-1]['grabWindow'] != window:
        for index in range(len(_grabStack)):
            if _grabStack[index]['grabWindow'] == window:
                _grabStack[index + 1]['deactivateFunction']()
                break
    grabInfo = _grabStack[-1]
    del _grabStack[-1]
    topWidget = grabInfo['grabWindow']
    prevFocus = grabInfo['previousFocus']
    globalMode = grabInfo['globalMode']
    if globalMode != 'nograb':
        topWidget.grab_release()
    if len(_grabStack) > 0:
        _grabtop()
    if prevFocus != '':
        try:
            topWidget.tk.call('focus', prevFocus)
        except Tkinter.TclError:
            Tkinter._default_root.focus_set()
    else:
        if len(_grabStack) > 0:
            topWidget = _grabStack[-1]['grabWindow']
            topWidget.focus_set()
        else:
            Tkinter._default_root.focus_set()
def grabstacktopwindow():

    if len(_grabStack) == 0:
        return None
    else:
        return _grabStack[-1]['grabWindow']
def releasegrabs():

    current = Tkinter._default_root.grab_current()
    if current is not None:
        current.grab_release()
    _grabStack[:] = []
def _grabtop():

    grabInfo = _grabStack[-1]
    topWidget = grabInfo['grabWindow']
    globalMode = grabInfo['globalMode']
    if globalMode == 'nograb':
        return
    while 1:
        try:
            if globalMode:
                topWidget.grab_set_global()
            else:
                topWidget.grab_set()
            break
        except Tkinter.TclError:
            topWidget.after(100)
class MegaToplevel(MegaArchetype):


    def __init__(self, parent = None, **kw):

	optiondefs = (
            ('activatecommand',   None,                     None),
            ('deactivatecommand', None,                     None),
            ('master',            None,                     None),
            ('title',             None,                     self._settitle),
            ('hull_class',        self.__class__.__name__,  None),
	)
	self.defineoptions(kw, optiondefs)
	MegaArchetype.__init__(self, parent, Tkinter.Toplevel)
        if hasattr(self._hull, '_Pmw_WM_DELETE_name'):
            self._hull.tk.deletecommand(self._hull._Pmw_WM_DELETE_name)
        self._hull._Pmw_WM_DELETE_name = \
                self.register(self._userDeleteWindow, needcleanup = 0)
	self.protocol('WM_DELETE_WINDOW', self._hull._Pmw_WM_DELETE_name)
	self._firstShowing = 1
	self._wait = None
	self._active = 0
	self._userDeleteFunc = self.destroy
	self._userModalDeleteFunc = self.deactivate
	self.initialiseoptions()
    def _settitle(self):

	title = self['title']
	if title is not None:
	    self.title(title)
    def userdeletefunc(self, func=None):

        if func:
	    self._userDeleteFunc = func
	else:
	    return self._userDeleteFunc
    def usermodaldeletefunc(self, func=None):

        if func:
	    self._userModalDeleteFunc = func
	else:
	    return self._userModalDeleteFunc
    def _userDeleteWindow(self):

	if self.active():
	    self._userModalDeleteFunc()
	else:
	    self._userDeleteFunc()
    def destroy(self):

	if _hullToMegaWidget.has_key(self._hull):
	    self.deactivate()
            del self._userDeleteFunc
            del self._userModalDeleteFunc
            MegaArchetype.destroy(self)
    def show(self, master = None):

	if self.state() != 'normal':
	    if self._firstShowing:
		geom = None
	    else:
		geom = self._sameposition()
            setgeometryanddeiconify(self, geom)
        if self._firstShowing:
            self._firstShowing = 0
        else:
            if self.transient() == '':
                self.tkraise()
        if master is not None:
            if master == 'parent':
                parent = self.winfo_parent()
                if type(parent) == types.StringType:
                    parent = self._hull._nametowidget(parent)
                master = parent.winfo_toplevel()
            self.transient(master)
        self.focus()
    def _centreonscreen(self):

        parent = self.winfo_parent()
        if type(parent) == types.StringType:
            parent = self._hull._nametowidget(parent)
	self.update_idletasks()
        width = self.winfo_width()
        height = self.winfo_height()
        if width == 1 and height == 1:
            width = self.winfo_reqwidth()
            height = self.winfo_reqheight()
	x = (self.winfo_screenwidth() - width) / 2 - parent.winfo_vrootx()
	y = (self.winfo_screenheight() - height) / 3 - parent.winfo_vrooty()
	if x < 0:
	    x = 0
	if y < 0:
	    y = 0
        return '+%d+%d' % (x, y)
    def _sameposition(self):

	geometry = self.geometry()
	index = string.find(geometry, '+')
	if index >= 0:
	    return geometry[index:]
        else:
	    return None
    def activate(self, globalMode = 0, geometry = 'centerscreenfirst'):

	if self._active:
	    raise ValueError, 'Window is already active'
	if self.state() == 'normal':
	    self.withdraw()
	self._active = 1
	showbusycursor()
	if self._wait is None:
	    self._wait = Tkinter.IntVar()
	self._wait.set(0)
	if geometry == 'centerscreenalways':
	    geom = self._centreonscreen()
	elif geometry == 'centerscreenfirst':
	    if self._firstShowing:
		geom = self._centreonscreen()
	    else:
		geom = self._sameposition()
	elif geometry[:5] == 'first':
	    if self._firstShowing:
                geom = geometry[5:]
	    else:
		geom = self._sameposition()
        else:
            geom = geometry
	self._firstShowing = 0
        setgeometryanddeiconify(self, geom)
        master = self['master']
        if master is not None:
            if master == 'parent':
                parent = self.winfo_parent()
                if type(parent) == types.StringType:
                    parent = self._hull._nametowidget(parent)
                master = parent.winfo_toplevel()
            self.transient(master)
        pushgrab(self._hull, globalMode, self.deactivate)
	command = self['activatecommand']
	if callable(command):
	    command()
	self.wait_variable(self._wait)
	return self._result
    def deactivate(self, result=None):

	if not self._active:
	    return
	self._active = 0
        popgrab(self._hull)
        command = self['deactivatecommand']
        if callable(command):
            command()
        self.withdraw()
        hidebusycursor(forceFocusRestore = 1)
        self._result = result
        self._wait.set(1)
    def active(self):

	return self._active
forwardmethods(MegaToplevel, Tkinter.Toplevel, '_hull')
class MegaWidget(MegaArchetype):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('hull_class',       self.__class__.__name__,  None),
	)
	self.defineoptions(kw, optiondefs)
	MegaArchetype.__init__(self, parent, Tkinter.Frame)
	self.initialiseoptions()
forwardmethods(MegaWidget, Tkinter.Frame, '_hull')
_traceTk = 0
def tracetk(root = None, on = 1, withStackTrace = 0, file=None):

    global _withStackTrace
    global _traceTkFile
    global _traceTk
    if root is None:
        root = Tkinter._default_root
    _withStackTrace = withStackTrace
    _traceTk = on
    if on:
	if hasattr(root.tk, '__class__'):
	    return
	if file is None:
	    _traceTkFile = sys.stderr
	else:
	    _traceTkFile = file
	tk = _TraceTk(root.tk)
    else:
	if not hasattr(root.tk, '__class__'):
	    return
	tk = root.tk.getTclInterp()
    _setTkInterps(root, tk)
def showbusycursor():

    _addRootToToplevelBusyInfo()
    root = Tkinter._default_root
    busyInfo = {
        'newBusyWindows' : [],
        'previousFocus' : None,
        'busyFocus' : None,
    }
    _busyStack.append(busyInfo)
    if _disableKeyboardWhileBusy:
        busyInfo['previousFocus'] = root.tk.call('focus')
    if not _havebltbusy(root):
        return
    for (window, winInfo) in _toplevelBusyInfo.items():
	if (window.state() != 'withdrawn' and not winInfo['isBusy']
                and not winInfo['excludeFromBusy']):
            busyInfo['newBusyWindows'].append(window)
            winInfo['isBusy'] = 1
            _busy_hold(window, winInfo['busyCursorName'])
            window.tk.call('bindtags', winInfo['busyWindow'], 'Pmw_Dummy_Tag')
            if _disableKeyboardWhileBusy:
                winInfo['windowFocus'] = \
                        window.tk.call('focus', '-lastfor', window._w)
                window.tk.call('focus', winInfo['busyWindow'])
                busyInfo['busyFocus'] = winInfo['busyWindow']
    if len(busyInfo['newBusyWindows']) > 0:
        if os.name == 'nt':
            window.update()
        else:
            window.update_idletasks()
def hidebusycursor(forceFocusRestore = 0):

    root = Tkinter._default_root
    if _disableKeyboardWhileBusy:
        currentFocus = root.tk.call('focus')
    busyInfo = _busyStack[-1]
    del _busyStack[-1]
    for window in busyInfo['newBusyWindows']:
        if _toplevelBusyInfo.has_key(window):
            winInfo = _toplevelBusyInfo[window]
            winInfo['isBusy'] = 0
            _busy_release(window)
            if _disableKeyboardWhileBusy:
                windowFocusNow = window.tk.call('focus', '-lastfor', window._w)
                if windowFocusNow == winInfo['busyWindow']:
                    try:
                        window.tk.call('focus', winInfo['windowFocus'])
                    except Tkinter.TclError:
                        window.focus_set()
    if _disableKeyboardWhileBusy:
        if forceFocusRestore or busyInfo['busyFocus'] == currentFocus:
            previousFocus = busyInfo['previousFocus']
            if previousFocus is not None:
                try:
                    root.tk.call('focus', previousFocus)
                except Tkinter.TclError:
                    pass
        else:
            root.tk.call('focus', currentFocus)
def clearbusycursor():

    while len(_busyStack) > 0:
        hidebusycursor()
def setbusycursorattributes(window, **kw):

    _addRootToToplevelBusyInfo()
    for name, value in kw.items():
        if name == 'exclude':
            _toplevelBusyInfo[window]['excludeFromBusy'] = value
        elif name == 'cursorName':
            _toplevelBusyInfo[window]['busyCursorName'] = value
        else:
            raise KeyError, 'Unknown busycursor attribute "' + name + '"'
def _addRootToToplevelBusyInfo():

    root = Tkinter._default_root
    if root == None:
        root = Tkinter.Tk()
    if not _toplevelBusyInfo.has_key(root):
        _addToplevelBusyInfo(root)
def busycallback(command, updateFunction = None):

    if not callable(command):
	raise ValueError, \
	    'cannot register non-command busy callback %s %s' % \
	        (repr(command), type(command))
    wrapper = _BusyWrapper(command, updateFunction)
    return wrapper.callback
_errorReportFile = None
_errorWindow = None
def reporterrorstofile(file = None):

    global _errorReportFile
    _errorReportFile = file
def displayerror(text):

    global _errorWindow
    if _errorReportFile is not None:
	_errorReportFile.write(text + '\n')
    else:
        sys.stderr.write(text + '\n')
	if _errorWindow is None:
	    _errorWindow = _ErrorWindow()
	_errorWindow.showerror(text)
_root = None
_disableKeyboardWhileBusy = 1
def initialise(

        root = None,
        size = None,
        fontScheme = None,
        useTkOptionDb = 0,
        noBltBusy = 0,
        disableKeyboardWhileBusy = None,
):
    global _disableKeyboardWhileBusy
    if disableKeyboardWhileBusy is not None:
        _disableKeyboardWhileBusy = disableKeyboardWhileBusy
    global _haveBltBusy
    if noBltBusy:
        _haveBltBusy = 0
    global _useTkOptionDb
    _useTkOptionDb = useTkOptionDb
    if root is None:
	if Tkinter._default_root is None:
	    root = Tkinter.Tk()
	else:
	    root = Tkinter._default_root
    global _root
    if _root is not None and _root != root:
        global _busyStack
        global _errorWindow
        global _grabStack
        global _hullToMegaWidget
        global _toplevelBusyInfo
        _busyStack = []
        _errorWindow = None
        _grabStack = []
        _hullToMegaWidget = {}
        _toplevelBusyInfo = {}
    _root = root
    Tkinter.Toplevel.title = __TkinterToplevelTitle
    Tkinter.Toplevel.destroy = __TkinterToplevelDestroy
    Tkinter.Widget.destroy = __TkinterWidgetDestroy
    Tkinter.CallWrapper = __TkinterCallWrapper
    if root.protocol('WM_DELETE_WINDOW') == '':
	root.protocol('WM_DELETE_WINDOW', root.destroy)
    _font_initialise(root, size, fontScheme)
    return root
def alignlabels(widgets, sticky = None):

    if len(widgets) == 0:
    	return
    widgets[0].update_idletasks()
    maxLabelWidth = 0
    for iwid in widgets:
	labelWidth = iwid.grid_bbox(0, 1)[2]
	if labelWidth > maxLabelWidth:
	    maxLabelWidth = labelWidth
    for iwid in widgets:
	if sticky is not None:
	    iwid.component('label').grid(sticky=sticky)
	iwid.grid_columnconfigure(0, minsize = maxLabelWidth)
_callToTkReturned = 1
_recursionCounter = 1
class _TraceTk:


    def __init__(self, tclInterp):

        self.tclInterp = tclInterp
    def getTclInterp(self):

        return self.tclInterp
    def call(self, *args, **kw):

        global _callToTkReturned
        global _recursionCounter
        _callToTkReturned = 0
        if len(args) == 1 and type(args[0]) == types.TupleType:
            argStr = str(args[0])
        else:
            argStr = str(args)
	_traceTkFile.write('CALL  TK> %d:%s%s' %
                (_recursionCounter, '  ' * _recursionCounter, argStr))
	_recursionCounter = _recursionCounter + 1
        try:
            result = apply(self.tclInterp.call, args, kw)
	except Tkinter.TclError, errorString:
            _callToTkReturned = 1
            _recursionCounter = _recursionCounter - 1
            _traceTkFile.write('\nTK ERROR> %d:%s-> %s\n' %
                    (_recursionCounter, '  ' * _recursionCounter,
                            repr(errorString)))
            if _withStackTrace:
                _traceTkFile.write('CALL  TK> stack:\n')
                traceback.print_stack()
            raise Tkinter.TclError, errorString
        _recursionCounter = _recursionCounter - 1
        if _callToTkReturned:
            _traceTkFile.write('CALL RTN> %d:%s-> %s' %
                    (_recursionCounter, '  ' * _recursionCounter, repr(result)))
        else:
            _callToTkReturned = 1
            if result:
                _traceTkFile.write(' -> %s' % repr(result))
        _traceTkFile.write('\n')
        if _withStackTrace:
            _traceTkFile.write('CALL  TK> stack:\n')
            traceback.print_stack()
        _traceTkFile.flush()
        return result
    def __getattr__(self, key):

        return getattr(self.tclInterp, key)
def _setTkInterps(window, tk):

    window.tk = tk
    for child in window.children.values():
      _setTkInterps(child, tk)
_toplevelBusyInfo = {}
def _addToplevelBusyInfo(window):

    if window._w == '.':
        busyWindow = '._Busy'
    else:
        busyWindow = window._w + '._Busy'
    _toplevelBusyInfo[window] = {
        'isBusy' : 0,
        'windowFocus' : None,
        'busyWindow' : busyWindow,
        'excludeFromBusy' : 0,
        'busyCursorName' : None,
    }
def __TkinterToplevelTitle(self, *args):

    if not _toplevelBusyInfo.has_key(self):
        _addToplevelBusyInfo(self)
        self._Pmw_WM_DELETE_name = self.register(self.destroy, None, 0)
	self.protocol('WM_DELETE_WINDOW', self._Pmw_WM_DELETE_name)
    return apply(Tkinter.Wm.title, (self,) + args)
_haveBltBusy = None
def _havebltbusy(window):

    global _busy_hold, _busy_release, _haveBltBusy
    if _haveBltBusy is None:
        import PmwBlt
        _haveBltBusy = PmwBlt.havebltbusy(window)
        _busy_hold = PmwBlt.busy_hold
        if os.name == 'nt':
            _busy_release = PmwBlt.busy_forget
        else:
            _busy_release = PmwBlt.busy_release
    return _haveBltBusy
class _BusyWrapper:


    def __init__(self, command, updateFunction):

	self._command = command
	self._updateFunction = updateFunction
    def callback(self, *args):

	showbusycursor()
	rtn = apply(self._command, args)
	if callable(self._updateFunction):
	    self._updateFunction()
	hidebusycursor()
	return rtn
def drawarrow(canvas, color, direction, tag, baseOffset = 0.25, edgeOffset = 0.15):

    canvas.delete(tag)
    bw = (string.atoi(canvas['borderwidth']) +
            string.atoi(canvas['highlightthickness']))
    width = string.atoi(canvas['width'])
    height = string.atoi(canvas['height'])
    if direction in ('up', 'down'):
        majorDimension = height
        minorDimension = width
    else:
        majorDimension = width
        minorDimension = height
    offset = round(baseOffset * majorDimension)
    if direction in ('down', 'right'):
        base = bw + offset
        apex = bw + majorDimension - offset
    else:
        base = bw + majorDimension - offset
        apex = bw + offset
    if minorDimension > 3 and minorDimension % 2 == 0:
        minorDimension = minorDimension - 1
    half = int(minorDimension * (1 - 2 * edgeOffset)) / 2
    low = round(bw + edgeOffset * minorDimension)
    middle = low + half
    high = low + 2 * half
    if direction in ('up', 'down'):
        coords = (low, base, high, base, middle, apex)
    else:
        coords = (base, low, base, high, apex, middle)
    kw = {'fill' : color, 'outline' : color, 'tag' : tag}
    apply(canvas.create_polygon, coords, kw)
_hullToMegaWidget = {}
def __TkinterToplevelDestroy(tkWidget):

    if _hullToMegaWidget.has_key(tkWidget):
        mega = _hullToMegaWidget[tkWidget]
        try:
	    mega.destroy()
        except:
	    _reporterror(mega.destroy, ())
    else:
        if _toplevelBusyInfo.has_key(tkWidget):
            del _toplevelBusyInfo[tkWidget]
        if hasattr(tkWidget, '_Pmw_WM_DELETE_name'):
            tkWidget.tk.deletecommand(tkWidget._Pmw_WM_DELETE_name)
            del tkWidget._Pmw_WM_DELETE_name
        Tkinter.BaseWidget.destroy(tkWidget)
def __TkinterWidgetDestroy(tkWidget):

    if _hullToMegaWidget.has_key(tkWidget):
        mega = _hullToMegaWidget[tkWidget]
        try:
	    mega.destroy()
        except:
	    _reporterror(mega.destroy, ())
    else:
        Tkinter.BaseWidget.destroy(tkWidget)
class __TkinterCallWrapper:


    def __init__(self, func, subst, widget):

	self.func = func
	self.subst = subst
	self.widget = widget
    def __call__(self, *args):

	try:
	    if self.subst:
		args = apply(self.subst, args)
            if _traceTk:
                if not _callToTkReturned:
                    _traceTkFile.write('\n')
                if hasattr(self.func, 'im_class'):
                    name = self.func.im_class.__name__ + '.' + \
                        self.func.__name__
                else:
                    name = self.func.__name__
                if len(args) == 1 and hasattr(args[0], 'type'):
                    eventName = _eventTypeToName[string.atoi(args[0].type)]
                    if eventName in ('KeyPress', 'KeyRelease',):
                        argStr = '(%s %s Event: %s)' % \
                            (eventName, args[0].keysym, args[0].widget)
                    else:
                        argStr = '(%s Event, %s)' % (eventName, args[0].widget)
                else:
                    argStr = str(args)
                _traceTkFile.write('CALLBACK> %d:%s%s%s\n' %
                    (_recursionCounter, '  ' * _recursionCounter, name, argStr))
                _traceTkFile.flush()
	    return apply(self.func, args)
	except SystemExit, msg:
	    raise SystemExit, msg
	except:
	    _reporterror(self.func, args)
_eventTypeToName = {
    2 : 'KeyPress',         15 : 'VisibilityNotify',   28 : 'PropertyNotify',
    3 : 'KeyRelease',       16 : 'CreateNotify',       29 : 'SelectionClear',
    4 : 'ButtonPress',      17 : 'DestroyNotify',      30 : 'SelectionRequest',
    5 : 'ButtonRelease',    18 : 'UnmapNotify',        31 : 'SelectionNotify',
    6 : 'MotionNotify',     19 : 'MapNotify',          32 : 'ColormapNotify',
    7 : 'EnterNotify',      20 : 'MapRequest',         33 : 'ClientMessage',
    8 : 'LeaveNotify',      21 : 'ReparentNotify',     34 : 'MappingNotify',
    9 : 'FocusIn',          22 : 'ConfigureNotify',    35 : 'VirtualEvents',
    10 : 'FocusOut',        23 : 'ConfigureRequest',   36 : 'ActivateNotify',
    11 : 'KeymapNotify',    24 : 'GravityNotify',      37 : 'DeactivateNotify',
    12 : 'Expose',          25 : 'ResizeRequest',      38 : 'MouseWheelEvent',
    13 : 'GraphicsExpose',  26 : 'CirculateNotify',
    14 : 'NoExpose',        27 : 'CirculateRequest',
}
def _reporterror(func, args):

    exc_type, exc_value, exc_traceback = sys.exc_info()
    if type(exc_type) == types.ClassType:
	exc_type = exc_type.__name__
    msg = exc_type + ' Exception in Tk callback\n'
    msg = msg + '  Function: %s (type: %s)\n' % (repr(func), type(func))
    msg = msg + '  Args: %s\n' % str(args)
    if type(args) == types.TupleType and len(args) > 0 and \
	    hasattr(args[0], 'type'):
        eventArg = 1
    else:
        eventArg = 0
    if eventArg:
	eventNum = string.atoi(args[0].type)
        if eventNum in _eventTypeToName.keys():
            msg = msg + '  Event type: %s (type num: %d)\n' % \
                    (_eventTypeToName[eventNum], eventNum)
        else:
            msg = msg + '  Unknown event type (type num: %d)\n' % eventNum
    msg = msg + 'Traceback (innermost last):\n'
    for tr in traceback.extract_tb(exc_traceback):
	msg = msg + '  File "%s", line %s, in %s\n' % (tr[0], tr[1], tr[2])
	msg = msg + '    %s\n' % tr[3]
    msg = msg + '%s: %s\n' % (exc_type, exc_value)
    if eventArg:
	msg = msg + '\n================================================\n'
	msg = msg + '  Event contents:\n'
	keys = args[0].__dict__.keys()
	keys.sort()
	for key in keys:
	    msg = msg + '    %s: %s\n' % (key, args[0].__dict__[key])
    clearbusycursor()
    try:
	displayerror(msg)
    except:
        pass
class _ErrorWindow:


    def __init__(self):

	self._errorQueue = []
	self._errorCount = 0
	self._open = 0
        self._firstShowing = 1
	self._top = Tkinter.Toplevel()
	self._top.protocol('WM_DELETE_WINDOW', self._hide)
	self._top.title('Error in background function')
	self._top.iconname('Background error')
	upperframe = Tkinter.Frame(self._top)
	scrollbar = Tkinter.Scrollbar(upperframe, orient='vertical')
	scrollbar.pack(side = 'right', fill = 'y')
	self._text = Tkinter.Text(upperframe, yscrollcommand=scrollbar.set)
	self._text.pack(fill = 'both', expand = 1)
	scrollbar.configure(command=self._text.yview)
	lowerframe = Tkinter.Frame(self._top)
	ignore = Tkinter.Button(lowerframe,
	        text = 'Ignore remaining errors', command = self._hide)
	ignore.pack(side='left')
	self._nextError = Tkinter.Button(lowerframe,
	        text = 'Show next error', command = self._next)
	self._nextError.pack(side='left')
	self._label = Tkinter.Label(lowerframe, relief='ridge')
	self._label.pack(side='left', fill='x', expand=1)
	lowerframe.pack(side = 'bottom', fill = 'x')
	upperframe.pack(side = 'bottom', fill = 'both', expand = 1)
    def showerror(self, text):

	if self._open:
	    self._errorQueue.append(text)
	else:
	    self._display(text)
	    self._open = 1
	if self._top.state() == 'normal':
            pass
	else:
	    if self._firstShowing:
		geom = None
	    else:
                geometry = self._top.geometry()
                index = string.find(geometry, '+')
                if index >= 0:
                    geom = geometry[index:]
                else:
                    geom = None
            setgeometryanddeiconify(self._top, geom)
        if self._firstShowing:
            self._firstShowing = 0
        else:
            self._top.tkraise()
        self._top.focus()
	self._updateButtons()
        releasegrabs()
    def _hide(self):

	self._errorCount = self._errorCount + len(self._errorQueue)
	self._errorQueue = []
	self._top.withdraw()
	self._open = 0
    def _next(self):

	text = self._errorQueue[0]
	del self._errorQueue[0]
	self._display(text)
	self._updateButtons()
    def _display(self, text):

	self._errorCount = self._errorCount + 1
	text = 'Error: %d\n%s' % (self._errorCount, text)
	self._text.delete('1.0', 'end')
	self._text.insert('end', text)
    def _updateButtons(self):

	numQueued = len(self._errorQueue)
	if numQueued > 0:
	    self._label.configure(text='%d more errors' % numQueued)
	    self._nextError.configure(state='normal')
	else:
	    self._label.configure(text='No more errors')
	    self._nextError.configure(state='disabled')
import sys
import types
import Tkinter
class Dialog(MegaToplevel):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('buttonbox_hull_borderwidth',   1,         None),
	    ('buttonbox_hull_relief',        'raised',  None),
	    ('buttonboxpos',                 's',       INITOPT),
	    ('buttons',                      ('OK',),   self._buttons),
	    ('command',                      None,      None),
	    ('dialogchildsite_borderwidth',  1,         None),
	    ('dialogchildsite_relief',       'raised',  None),
	    ('defaultbutton',                None,      self._defaultButton),
            ('master',                       'parent',  None),
	    ('separatorwidth',               0,         INITOPT),
	)
	self.defineoptions(kw, optiondefs)
	MegaToplevel.__init__(self, parent)
	oldInterior = MegaToplevel.interior(self)
        pos = self['buttonboxpos']
	if pos not in 'nsew':
	    raise ValueError, \
	        'bad buttonboxpos option "%s":  should be n, s, e, or w' \
		    % pos
	if pos in 'ns':
	    orient = 'horizontal'
	    fill = 'x'
	    if pos == 'n':
	        side = 'top'
	    else:
	        side = 'bottom'
	else:
	    orient = 'vertical'
	    fill = 'y'
	    if pos == 'w':
	        side = 'left'
	    else:
	        side = 'right'
	self._buttonBox = self.createcomponent('buttonbox',
		(), None,
		ButtonBox, (oldInterior,), orient = orient)
	self._buttonBox.pack(side = side, fill = fill)
	width = self['separatorwidth']
	if width > 0:
	    self._separator = self.createcomponent('separator',
		    (), None,
		    Tkinter.Frame, (oldInterior,), relief = 'sunken',
		    height = width, width = width, borderwidth = width / 2)
	    self._separator.pack(side = side, fill = fill)
	self.__dialogChildSite = self.createcomponent('dialogchildsite',
		(), None,
		Tkinter.Frame, (oldInterior,))
	self.__dialogChildSite.pack(side=side, fill='both', expand=1)
	self.oldButtons = ()
	self.oldDefault = None
	self.bind('<Return>', self._invokeDefault)
        self.userdeletefunc(self._doCommand)
        self.usermodaldeletefunc(self._doCommand)
	self.initialiseoptions()
    def interior(self):

	return self.__dialogChildSite
    def invoke(self, index = DEFAULT):

	return self._buttonBox.invoke(index)
    def _invokeDefault(self, event):

	try:
	    self._buttonBox.index(DEFAULT)
	except ValueError:
	    return
	self._buttonBox.invoke()
    def _doCommand(self, name = None):

        if name is not None and self.active() and \
                grabstacktopwindow() != self.component('hull'):
            return
	command = self['command']
	if callable(command):
	    return command(name)
	else:
	    if self.active():
	        self.deactivate(name)
	    else:
	        self.withdraw()
    def _buttons(self):

	buttons = self['buttons']
	if type(buttons) != types.TupleType and type(buttons) != types.ListType:
	    raise ValueError, \
	        'bad buttons option "%s": should be a tuple' % str(buttons)
	if self.oldButtons == buttons:
	  return
	self.oldButtons = buttons
	for index in range(self._buttonBox.numbuttons()):
	    self._buttonBox.delete(0)
	for name in buttons:
	    self._buttonBox.add(name,
		command=lambda self=self, name=name: self._doCommand(name))
	if len(buttons) > 0:
	    defaultbutton = self['defaultbutton']

	    if defaultbutton is None:
		self._buttonBox.setdefault(None)
	    else:
		try:
		    self._buttonBox.index(defaultbutton)
		except ValueError:
		    pass
		else:
		    self._buttonBox.setdefault(defaultbutton)
	self._buttonBox.alignbuttons()
    def _defaultButton(self):

	defaultbutton = self['defaultbutton']

	if self.oldDefault == defaultbutton:
	  return
	self.oldDefault = defaultbutton
	if len(self['buttons']) > 0:
	    if defaultbutton is None:
		self._buttonBox.setdefault(None)
	    else:
		try:
		    self._buttonBox.index(defaultbutton)
		except ValueError:
		    pass
		else:
		    self._buttonBox.setdefault(defaultbutton)
import re
import string
def timestringtoseconds(text, separator = ':'):

  inputList = string.split(string.strip(text), separator)
  if len(inputList) != 3:
    raise ValueError, 'invalid value: ' + text
  sign = 1
  if len(inputList[0]) > 0 and inputList[0][0] in ('+', '-'):
    if inputList[0][0] == '-':
      sign = -1
    inputList[0] = inputList[0][1:]
  if re.search('[^0-9]', string.join(inputList, '')) is not None:
    raise ValueError, 'invalid value: ' + text
  hour = string.atoi(inputList[0])
  minute = string.atoi(inputList[1])
  second = string.atoi(inputList[2])
  if minute >= 60 or second >= 60:
    raise ValueError, 'invalid value: ' + text
  return sign * (hour * 60 * 60 + minute * 60 + second)
_year_pivot = 50
_century = 2000
def setyearpivot(pivot, century = None):

    global _year_pivot
    global _century
    oldvalues = (_year_pivot, _century)
    _year_pivot = pivot
    if century is not None:
	_century = century
    return oldvalues
def datestringtojdn(text, format = 'ymd', separator = '/'):

  inputList = string.split(string.strip(text), separator)
  if len(inputList) != 3:
    raise ValueError, 'invalid value: ' + text
  if re.search('[^0-9]', string.join(inputList, '')) is not None:
    raise ValueError, 'invalid value: ' + text
  formatList = list(format)
  day = string.atoi(inputList[formatList.index('d')])
  month = string.atoi(inputList[formatList.index('m')])
  year = string.atoi(inputList[formatList.index('y')])
  if _year_pivot is not None:
    if year >= 0 and year < 100:
      if year <= _year_pivot:
	year = year + _century
      else:
	year = year + _century - 100
  jdn = ymdtojdn(year, month, day)
  if jdntoymd(jdn) != (year, month, day):
    raise ValueError, 'invalid value: ' + text
  return jdn
def _cdiv(a, b):

    if a * b > 0:
	return a / b
    else:
	return -(abs(a) / abs(b))
def ymdtojdn(year, month, day, julian = -1, papal = 1):

    if julian < 0:
	if papal:
	    lastJulianDate = 15821004L
	else:
	    lastJulianDate = 17520902L
	julian = ((year * 100L) + month) * 100 + day  <=  lastJulianDate
    if year < 0:
	year = year + 1
    if julian:
	return 367L * year - _cdiv(7 * (year + 5001L + _cdiv((month - 9), 7)), 4) + \
	    _cdiv(275 * month, 9) + day + 1729777L
    else:
	return (day - 32076L) + \
	    _cdiv(1461L * (year + 4800L + _cdiv((month - 14), 12)), 4) + \
	    _cdiv(367 * (month - 2 - _cdiv((month - 14), 12) * 12), 12) - \
	    _cdiv((3 * _cdiv((year + 4900L + _cdiv((month - 14), 12)), 100)), 4) + \
	    1
def jdntoymd(jdn, julian = -1, papal = 1):

    if julian < 0:
	if papal:
	    lastJulianJdn = 2299160L
	else:
	    lastJulianJdn = 2361221L
	julian = (jdn <= lastJulianJdn);
    x = jdn + 68569L
    if julian:
	x = x + 38
	daysPer400Years = 146100L
	fudgedDaysPer4000Years = 1461000L + 1
    else:
	daysPer400Years = 146097L
	fudgedDaysPer4000Years = 1460970L + 31
    z = _cdiv(4 * x, daysPer400Years)
    x = x - _cdiv((daysPer400Years * z + 3), 4)
    y = _cdiv(4000 * (x + 1), fudgedDaysPer4000Years)
    x = x - _cdiv(1461 * y, 4) + 31
    m = _cdiv(80 * x, 2447)
    d = x - _cdiv(2447 * m, 80)
    x = _cdiv(m, 11)
    m = m + 2 - 12 * x
    y = 100 * (z - 49) + y + x
    yy = int(y)
    mm = int(m)
    dd = int(d)
    if yy <= 0:
	    yy = yy - 1
    return (yy, mm, dd)
def stringtoreal(text, separator = '.'):

    if separator != '.':
	if string.find(text, '.') >= 0:
	    raise ValueError, 'invalid value: ' + text
	index = string.find(text, separator)
	if index >= 0:
	    text = text[:index] + '.' + text[index + 1:]
    return string.atof(text)
import os
import string
import Tkinter
class Balloon(MegaToplevel):


    def __init__(self, parent = None, **kw):

	optiondefs = (
            ('initwait',                 500,            None),
            ('label_background',         'lightyellow',  None),
            ('label_foreground',         'black',        None),
            ('label_justify',            'left',         None),
            ('master',                   'parent',       None),
            ('relmouse',                 'none',         self._relmouse),
            ('state',                    'both',         self._state),
            ('statuscommand',            None,           None),
            ('xoffset',                  20,             None),
            ('yoffset',                  1,              None),
	    ('hull_highlightthickness',  1,              None),
	    ('hull_highlightbackground', 'black',        None),
	)
	self.defineoptions(kw, optiondefs)
	MegaToplevel.__init__(self, parent)
	self.withdraw()
	self.overrideredirect(1)
	interior = self.interior()
	self._label = self.createcomponent('label',
		(), None,
		Tkinter.Label, (interior,))
	self._label.pack()
        if not kw.has_key('hull_background'):
            self.configure(hull_background = \
                    str(self._label.cget('background')))
	self._timer = None
        self._currentTrigger = None
	self.initialiseoptions()
    def destroy(self):

	if self._timer is not None:
	    self.after_cancel(self._timer)
	    self._timer = None
	MegaToplevel.destroy(self)
    def bind(self, widget, balloonHelp, statusHelp = None):

        self.unbind(widget)
	if balloonHelp is None and statusHelp is None:
	    return
	if statusHelp is None:
	    statusHelp = balloonHelp
	enterId = widget.bind('<Enter>',
		lambda event, self = self, w = widget,
			sHelp = statusHelp, bHelp = balloonHelp:
				self._enter(event, w, sHelp, bHelp, 0))
	motionId = widget.bind('<Motion>',
		lambda event = None, self = self, statusHelp = statusHelp:
			self.showstatus(statusHelp))
	leaveId = widget.bind('<Leave>', self._leave)
	buttonId = widget.bind('<ButtonPress>', self._buttonpress)
	destroyId = widget.bind('<Destroy>', self._destroy)
        if not hasattr(widget, '_Pmw_BalloonBindIds'):
            widget._Pmw_BalloonBindIds = {}
        widget._Pmw_BalloonBindIds[None] = \
                (enterId, motionId, leaveId, buttonId, destroyId)
    def unbind(self, widget):

        if hasattr(widget, '_Pmw_BalloonBindIds'):
            if widget._Pmw_BalloonBindIds.has_key(None):
                (enterId, motionId, leaveId, buttonId, destroyId) = \
                        widget._Pmw_BalloonBindIds[None]
                widget.unbind('<Enter>', enterId)
                widget.unbind('<Motion>', motionId)
                widget.unbind('<Leave>', leaveId)
                widget.unbind('<ButtonPress>', buttonId)
                widget.unbind('<Destroy>', destroyId)
                del widget._Pmw_BalloonBindIds[None]
        if self._currentTrigger is not None and len(self._currentTrigger) == 1:
            triggerWidget = self._currentTrigger[0]
            if triggerWidget == widget:
                if self._timer is not None:
                    self.after_cancel(self._timer)
                    self._timer = None
                self.withdraw()
                self.clearstatus()
                self._currentTrigger = None
    def tagbind(self, widget, tagOrItem, balloonHelp, statusHelp = None):

        self.tagunbind(widget, tagOrItem)
	if balloonHelp is None and statusHelp is None:
	    return
	if statusHelp is None:
	    statusHelp = balloonHelp
	enterId = widget.tag_bind(tagOrItem, '<Enter>',
		lambda event, self = self, w = widget,
			sHelp = statusHelp, bHelp = balloonHelp:
				self._enter(event, w, sHelp, bHelp, 1))
	motionId = widget.tag_bind(tagOrItem, '<Motion>',
		lambda event = None, self = self, statusHelp = statusHelp:
			self.showstatus(statusHelp))
	leaveId = widget.tag_bind(tagOrItem, '<Leave>', self._leave)
	buttonId = widget.tag_bind(tagOrItem, '<ButtonPress>', self._buttonpress)
        if not hasattr(widget, '_Pmw_BalloonBindIds'):
            widget._Pmw_BalloonBindIds = {}
        widget._Pmw_BalloonBindIds[tagOrItem] = \
                (enterId, motionId, leaveId, buttonId)
    def tagunbind(self, widget, tagOrItem):

        if hasattr(widget, '_Pmw_BalloonBindIds'):
            if widget._Pmw_BalloonBindIds.has_key(tagOrItem):
                (enterId, motionId, leaveId, buttonId) = \
                        widget._Pmw_BalloonBindIds[tagOrItem]
                widget.tag_unbind(tagOrItem, '<Enter>', enterId)
                widget.tag_unbind(tagOrItem, '<Motion>', motionId)
                widget.tag_unbind(tagOrItem, '<Leave>', leaveId)
                widget.tag_unbind(tagOrItem, '<ButtonPress>', buttonId)
                del widget._Pmw_BalloonBindIds[tagOrItem]
        if self._currentTrigger is None:
            return
        if len(self._currentTrigger) == 1:
            return
        if len(self._currentTrigger) == 2:
            (triggerWidget, triggerItem) = self._currentTrigger
            if triggerWidget == widget and triggerItem == tagOrItem:
                if self._timer is not None:
                    self.after_cancel(self._timer)
                    self._timer = None
                self.withdraw()
                self.clearstatus()
                self._currentTrigger = None
        else:
            (triggerWidget, x, y) = self._currentTrigger
            if triggerWidget == widget:
                currentPos = widget.index('@%d,%d' % (x, y))
                currentTags = widget.tag_names(currentPos)
                if tagOrItem in currentTags:
                    if self._timer is not None:
                        self.after_cancel(self._timer)
                        self._timer = None
                    self.withdraw()
                    self.clearstatus()
                    self._currentTrigger = None
    def showstatus(self, statusHelp):

	if self['state'] in ('status', 'both'):
	    cmd = self['statuscommand']
	    if callable(cmd):
		cmd(statusHelp)
    def clearstatus(self):

        self.showstatus(None)
    def _state(self):

	if self['state'] not in ('both', 'balloon', 'status', 'none'):
	    raise ValueError, 'bad state option ' + repr(self['state']) + \
		': should be one of \'both\', \'balloon\', ' + \
		'\'status\' or \'none\''
    def _relmouse(self):

	if self['relmouse'] not in ('both', 'x', 'y', 'none'):
	    raise ValueError, 'bad relmouse option ' + repr(self['relmouse'])+ \
		': should be one of \'both\', \'x\', ' + '\'y\' or \'none\''
    def _enter(self, event, widget, statusHelp, balloonHelp, isItem):

        buttonPressed = (event.state & 0x1f00) != 0
	if not buttonPressed and balloonHelp is not None and \
                self['state'] in ('balloon', 'both'):
	    if self._timer is not None:
		self.after_cancel(self._timer)
		self._timer = None
	    self._timer = self.after(self['initwait'],
		    lambda self = self, widget = widget, help = balloonHelp,
			    isItem = isItem:
			    self._showBalloon(widget, help, isItem))
        if isItem:
            if hasattr(widget, 'canvasx'):
                item = widget.find_withtag('current')
                if len(item) > 0:
                    item = item[0]
                else:
                    item = None
                self._currentTrigger = (widget, item)
            else:
                self._currentTrigger = (widget, event.x, event.y)
        else:
            self._currentTrigger = (widget,)
	self.showstatus(statusHelp)
    def _leave(self, event):

	if self._timer is not None:
	    self.after_cancel(self._timer)
	    self._timer = None
	self.withdraw()
	self.clearstatus()
        self._currentTrigger = None
    def _destroy(self, event):

        if self._currentTrigger is None:
            return
        if len(self._currentTrigger) == 1:
            triggerWidget = self._currentTrigger[0]
            if str(triggerWidget) == event.widget:
                if self._timer is not None:
                    self.after_cancel(self._timer)
                    self._timer = None
                self.withdraw()
                self.clearstatus()
                self._currentTrigger = None
    def _buttonpress(self, event):

	if self._timer is not None:
	    self.after_cancel(self._timer)
	    self._timer = None
	self.withdraw()
        self._currentTrigger = None
    def _showBalloon(self, widget, balloonHelp, isItem):

	self._label.configure(text = balloonHelp)
        screenWidth = self.winfo_screenwidth()
        screenHeight = self.winfo_screenheight()
        self.geometry('+%d+0' % (screenWidth + 1))
        self.update_idletasks()
	if isItem:
            bbox = widget.bbox('current')
            if bbox is None:
                return
	    if hasattr(widget, 'canvasx'):
                leftrel = bbox[0] - widget.canvasx(0)
                toprel = bbox[1] - widget.canvasy(0)
                bottomrel = bbox[3] - widget.canvasy(0)
	    else:
		leftrel = bbox[0]
                toprel = bbox[1]
		bottomrel = bbox[1] + bbox[3]
	else:
	    leftrel = 0
            toprel = 0
	    bottomrel = widget.winfo_height()
        xpointer, ypointer = widget.winfo_pointerxy()
        if xpointer >= 0 and self['relmouse'] in ('both', 'x'):
            x = xpointer
        else:
            x = leftrel + widget.winfo_rootx()
        x = x + self['xoffset']
        if ypointer >= 0 and self['relmouse'] in ('both', 'y'):
            y = ypointer
        else:
            y = bottomrel + widget.winfo_rooty()
        y = y + self['yoffset']
        edges = (string.atoi(str(self.cget('hull_highlightthickness'))) +
            string.atoi(str(self.cget('hull_borderwidth')))) * 2
        if x + self._label.winfo_reqwidth() + edges > screenWidth:
            x = screenWidth - self._label.winfo_reqwidth() - edges
        if y + self._label.winfo_reqheight() + edges > screenHeight:
            if ypointer >= 0 and self['relmouse'] in ('both', 'y'):
                y = ypointer
            else:
                y = toprel + widget.winfo_rooty()
            y = y - self._label.winfo_reqheight() - self['yoffset'] - edges
        setgeometryanddeiconify(self, '+%d+%d' % (x, y))
import types
import Tkinter
class ButtonBox(MegaWidget):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('labelmargin',       0,              INITOPT),
	    ('labelpos',          None,           INITOPT),
	    ('orient',            'horizontal',   INITOPT),
	    ('padx',              3,              INITOPT),
	    ('pady',              3,              INITOPT),
	)
	self.defineoptions(kw, optiondefs, dynamicGroups = ('Button',))
	MegaWidget.__init__(self, parent)
	interior = self.interior()
	if self['labelpos'] is None:
	    self._buttonBoxFrame = self._hull
	    columnOrRow = 0
	else:
	    self._buttonBoxFrame = self.createcomponent('frame',
		    (), None,
		    Tkinter.Frame, (interior,))
	    self._buttonBoxFrame.grid(column=2, row=2, sticky='nsew')
	    columnOrRow = 2
	    self.createlabel(interior)
	orient = self['orient']
	if orient == 'horizontal':
	    interior.grid_columnconfigure(columnOrRow, weight = 1)
	elif orient == 'vertical':
	    interior.grid_rowconfigure(columnOrRow, weight = 1)
	else:
	    raise ValueError, 'bad orient option ' + repr(orient) + \
		': must be either \'horizontal\' or \'vertical\''
	self._buttonList = []
	self._defaultButton = None
	self._timerId = None
	self.initialiseoptions()
    def destroy(self):

	if self._timerId:
	    self.after_cancel(self._timerId)
	    self._timerId = None
	MegaWidget.destroy(self)
    def numbuttons(self):

        return len(self._buttonList)
    def index(self, index, forInsert = 0):

	listLength = len(self._buttonList)
	if type(index) == types.IntType:
	    if forInsert and index <= listLength:
		return index
	    elif not forInsert and index < listLength:
		return index
	    else:
		raise ValueError, 'index "%s" is out of range' % index
	elif index is END:
	    if forInsert:
		return listLength
	    elif listLength > 0:
		return listLength - 1
	    else:
		raise ValueError, 'ButtonBox has no buttons'
	elif index is DEFAULT:
	    if self._defaultButton is not None:
		return self._defaultButton
	    raise ValueError, 'ButtonBox has no default'
	else:
            names = map(lambda t: t[0], self._buttonList)
            if index in names:
                return names.index(index)
	    validValues = 'a name, a number, END or DEFAULT'
	    raise ValueError, \
		'bad index "%s": must be %s' % (index, validValues)
    def insert(self, componentName, beforeComponent = 0, **kw):

	if componentName in self.components():
	    raise ValueError, 'button "%s" already exists' % componentName
	if not kw.has_key('text'):
	    kw['text'] = componentName
        kw['default'] = 'normal'
	button = apply(self.createcomponent, (componentName,
		(), 'Button',
		Tkinter.Button, (self._buttonBoxFrame,)), kw)
	index = self.index(beforeComponent, 1)
	horizontal = self['orient'] == 'horizontal'
	numButtons = len(self._buttonList)
	for i in range(numButtons - 1, index - 1, -1):
	    widget = self._buttonList[i][1]
	    pos = i * 2 + 3
	    if horizontal:
		widget.grid(column = pos, row = 0)
	    else:
		widget.grid(column = 0, row = pos)
	if horizontal:
	    button.grid(column = index * 2 + 1, row = 0, sticky = 'ew',
		    padx = self['padx'], pady = self['pady'])
	    self._buttonBoxFrame.grid_columnconfigure(
		    numButtons * 2 + 2, weight = 1)
	else:
	    button.grid(column = 0, row = index * 2 + 1, sticky = 'ew',
		    padx = self['padx'], pady = self['pady'])
	    self._buttonBoxFrame.grid_rowconfigure(
		    numButtons * 2 + 2, weight = 1)
	self._buttonList.insert(index, (componentName, button))
	return button
    def add(self, componentName, **kw):

        return apply(self.insert, (componentName, len(self._buttonList)), kw)
    def delete(self, index):

        index = self.index(index)
	(name, widget) = self._buttonList[index]
	widget.grid_forget()
	self.destroycomponent(name)
	numButtons = len(self._buttonList)
	horizontal = self['orient'] == 'horizontal'
	for i in range(index + 1, numButtons):
	    widget = self._buttonList[i][1]
	    pos = i * 2 - 1
	    if horizontal:
		widget.grid(column = pos, row = 0)
	    else:
		widget.grid(column = 0, row = pos)
	if horizontal:
	    self._buttonBoxFrame.grid_columnconfigure(numButtons * 2 - 1,
		    minsize = 0)
	    self._buttonBoxFrame.grid_columnconfigure(numButtons * 2, weight = 0)
	else:
	    self._buttonBoxFrame.grid_rowconfigure(numButtons * 2, weight = 0)
	del self._buttonList[index]
    def setdefault(self, index):

	if self._defaultButton is not None:
	    button = self._buttonList[self._defaultButton][1]
	    button.configure(default = 'normal')
	    self._defaultButton = None
	if index is not None:
	    index = self.index(index)
	    self._defaultButton = index
	    button = self._buttonList[index][1]
	    button.configure(default = 'active')
    def invoke(self, index = DEFAULT, noFlash = 0):

	button = self._buttonList[self.index(index)][1]
	if not noFlash:
	    state = button.cget('state')
	    relief = button.cget('relief')
	    button.configure(state = 'active', relief = 'sunken')
	    self.update_idletasks()
	    self.after(100)
	    button.configure(state = state, relief = relief)
	return button.invoke()
    def button(self, buttonIndex):

	return self._buttonList[self.index(buttonIndex)][1]
    def alignbuttons(self, when = 'later'):

	if when == 'later':
	    if not self._timerId:
		self._timerId = self.after_idle(self.alignbuttons, 'now')
	    return
	self.update_idletasks()
	self._timerId = None
        max = 0
        horizontal = (self['orient'] == 'horizontal')
        for index in range(len(self._buttonList)):
            gridIndex = index * 2 + 1
            if horizontal:
                width = self._buttonBoxFrame.grid_bbox(gridIndex, 0)[2]
            else:
                width = self._buttonBoxFrame.grid_bbox(0, gridIndex)[2]
            if width > max:
                max = width
	if horizontal:
	    for index in range(len(self._buttonList)):
		self._buttonBoxFrame.grid_columnconfigure(index * 2 + 1,
			minsize = max)
	else:
	    self._buttonBoxFrame.grid_columnconfigure(0, minsize = max)
import re
import string
import types
import Tkinter
OK = 1
ERROR = 0
PARTIAL = -1
class EntryField(MegaWidget):


    _classBindingsDefinedFor = 0
    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('command',           None,        None),
	    ('errorbackground',   'pink',      None),
	    ('invalidcommand',    self.bell,   None),
	    ('labelmargin',       0,           INITOPT),
	    ('labelpos',          None,        INITOPT),
	    ('modifiedcommand',   None,        None),
	    ('sticky',            'ew',        INITOPT),
	    ('validate',          None,        self._validate),
	    ('extravalidators',   {},          None),
	    ('value',             '',          INITOPT),
	)
	self.defineoptions(kw, optiondefs)
	MegaWidget.__init__(self, parent)
	interior = self.interior()
	self._entryFieldEntry = self.createcomponent('entry',
		(), None,
		Tkinter.Entry, (interior,))
	self._entryFieldEntry.grid(column=2, row=2, sticky=self['sticky'])
	if self['value'] != '':
	    self.__setEntry(self['value'])
	interior.grid_columnconfigure(2, weight=1)
	interior.grid_rowconfigure(2, weight=1)
	self.createlabel(interior)
	self.normalBackground = None
        self._previousText = None
	_registerEntryField(self._entryFieldEntry, self)
        if EntryField._classBindingsDefinedFor != Tkinter._default_root:
	    tagList = self._entryFieldEntry.bindtags()
            root  = Tkinter._default_root
	    allSequences = {}
	    for tag in tagList:
                sequences = root.bind_class(tag)
                if type(sequences) is types.StringType:
                    sequences = root.tk.splitlist(sequences)
		for sequence in sequences:
		    allSequences[sequence] = None
	    for sequence in allSequences.keys():
		root.bind_class('EntryFieldPre', sequence, _preProcess)
		root.bind_class('EntryFieldPost', sequence, _postProcess)
	    EntryField._classBindingsDefinedFor = root
	self._entryFieldEntry.bindtags(('EntryFieldPre',) +
		self._entryFieldEntry.bindtags() + ('EntryFieldPost',))
	self._entryFieldEntry.bind('<Return>', self._executeCommand)
	self.initialiseoptions()
    def destroy(self):

	_deregisterEntryField(self._entryFieldEntry)
        MegaWidget.destroy(self)
    def _getValidatorFunc(self, validator, index):

	extraValidators = self['extravalidators']
	traversedValidators = []
	while 1:
	    traversedValidators.append(validator)
	    if extraValidators.has_key(validator):
		validator = extraValidators[validator][index]
	    elif _standardValidators.has_key(validator):
		validator = _standardValidators[validator][index]
	    else:
		return validator
	    if validator in traversedValidators:
		return validator
    def _validate(self):

	dict = {
	    'validator' : None,
	    'min' : None,
	    'max' : None,
	    'minstrict' : 1,
	    'maxstrict' : 1,
	}
	opt = self['validate']
	if type(opt) is types.DictionaryType:
	    dict.update(opt)
	else:
	    dict['validator'] = opt
	validator = dict['validator']
	valFunction = self._getValidatorFunc(validator, 0)
	self._checkValidateFunction(valFunction, 'validate', validator)
	dict['validator'] = valFunction
	if dict.has_key('stringtovalue'):
	    stringtovalue = dict['stringtovalue']
	    strFunction = self._getValidatorFunc(stringtovalue, 1)
	    self._checkValidateFunction(
		    strFunction, 'stringtovalue', stringtovalue)
	else:
	    strFunction = self._getValidatorFunc(validator, 1)
	    if strFunction == validator:
		strFunction = len
	dict['stringtovalue'] = strFunction
	self._validationInfo = dict
	args = dict.copy()
	del args['validator']
	del args['min']
	del args['max']
	del args['minstrict']
	del args['maxstrict']
	del args['stringtovalue']
	self._validationArgs = args
        self._previousText = None
	if type(dict['min']) == types.StringType and strFunction is not None:
	    dict['min'] = apply(strFunction, (dict['min'],), args)
	if type(dict['max']) == types.StringType and strFunction is not None:
	    dict['max'] = apply(strFunction, (dict['max'],), args)
	self._checkValidity()
    def _checkValidateFunction(self, function, option, validator):

	if function is not None and not callable(function):
	    extraValidators = self['extravalidators']
	    extra = extraValidators.keys()
	    extra.sort()
	    extra = tuple(extra)
	    standard = _standardValidators.keys()
	    standard.sort()
	    standard = tuple(standard)
	    msg = 'bad %s value "%s":  must be a function or one of ' \
		'the standard validators %s or extra validators %s'
	    raise ValueError, msg % (option, validator, standard, extra)
    def _executeCommand(self, event = None):

	cmd = self['command']
	if callable(cmd):
            if event is None:
                return cmd()
            else:
                cmd()
    def _preProcess(self):

        self._previousText = self._entryFieldEntry.get()
        self._previousICursor = self._entryFieldEntry.index('insert')
        self._previousXview = self._entryFieldEntry.index('@0')
	if self._entryFieldEntry.selection_present():
	    self._previousSel= (self._entryFieldEntry.index('sel.first'),
		self._entryFieldEntry.index('sel.last'))
	else:
	    self._previousSel = None
    def _postProcess(self):

	previousText = self._previousText
	if previousText == self._entryFieldEntry.get():
	    return self.valid()
	valid = self._checkValidity()
        if self.hulldestroyed():
            return valid
	cmd = self['modifiedcommand']
	if callable(cmd) and previousText != self._entryFieldEntry.get():
	    cmd()
	return valid
    def checkentry(self):

	self._previousText = None
	return self._postProcess()
    def _getValidity(self):

	text = self._entryFieldEntry.get()
	dict = self._validationInfo
	args = self._validationArgs
	if dict['validator'] is not None:
	    status = apply(dict['validator'], (text,), args)
	    if status != OK:
		return status
	if dict['stringtovalue'] is not None:
	    min = dict['min']
	    max = dict['max']
	    if min is None and max is None:
		return OK
	    val = apply(dict['stringtovalue'], (text,), args)
	    if min is not None and val < min:
		if dict['minstrict']:
		    return ERROR
		else:
		    return PARTIAL
	    if max is not None and val > max:
		if dict['maxstrict']:
		    return ERROR
		else:
		    return PARTIAL
	return OK
    def _checkValidity(self):

	valid = self._getValidity()
	oldValidity = valid
	if valid == ERROR:
	    cmd = self['invalidcommand']
	    if callable(cmd):
		cmd()
            if self.hulldestroyed():
                return oldValidity
	    if self._previousText is not None:
		self.__setEntry(self._previousText)
		self._entryFieldEntry.icursor(self._previousICursor)
		self._entryFieldEntry.xview(self._previousXview)
		if self._previousSel is not None:
		    self._entryFieldEntry.selection_range(self._previousSel[0],
			self._previousSel[1])
		valid = self._getValidity()
	self._valid = valid
        if self.hulldestroyed():
            return oldValidity
	if valid == OK:
	    if self.normalBackground is not None:
		self._entryFieldEntry.configure(
			background = self.normalBackground)
		self.normalBackground = None
	else:
	    if self.normalBackground is None:
		self.normalBackground = self._entryFieldEntry.cget('background')
		self._entryFieldEntry.configure(
			background = self['errorbackground'])
        return oldValidity
    def invoke(self):

	return self._executeCommand()
    def valid(self):

        return self._valid == OK
    def clear(self):

        self.setentry('')
    def __setEntry(self, text):

	oldState = str(self._entryFieldEntry.cget('state'))
	if oldState != 'normal':
	    self._entryFieldEntry.configure(state='normal')
	self._entryFieldEntry.delete(0, 'end')
	self._entryFieldEntry.insert(0, text)
	if oldState != 'normal':
	    self._entryFieldEntry.configure(state=oldState)
    def setentry(self, text):

	self._preProcess()
        self.__setEntry(text)
	return self._postProcess()
    def getvalue(self):

        return self._entryFieldEntry.get()
    def setvalue(self, text):

        return self.setentry(text)
forwardmethods(EntryField, Tkinter.Entry, '_entryFieldEntry')
_numericregex = re.compile('^[0-9]*$')
_alphabeticregex = re.compile('^[a-z]*$', re.IGNORECASE)
_alphanumericregex = re.compile('^[0-9a-z]*$', re.IGNORECASE)
def numericvalidator(text):

    if text == '':
        return PARTIAL
    else:
	if _numericregex.match(text) is None:
	    return ERROR
	else:
	    return OK
def integervalidator(text):

    if text in ('', '-', '+'):
        return PARTIAL
    try:
	string.atol(text)
	return OK
    except ValueError:
	return ERROR
def alphabeticvalidator(text):

    if _alphabeticregex.match(text) is None:
	return ERROR
    else:
	return OK
def alphanumericvalidator(text):

    if _alphanumericregex.match(text) is None:
	return ERROR
    else:
	return OK
def hexadecimalvalidator(text):

    if text in ('', '0x', '0X', '+', '+0x', '+0X', '-', '-0x', '-0X'):
        return PARTIAL
    try:
	string.atol(text, 16)
	return OK
    except ValueError:
	return ERROR
def realvalidator(text, separator = '.'):

    if separator != '.':
	if string.find(text, '.') >= 0:
	    return ERROR
	index = string.find(text, separator)
	if index >= 0:
	    text = text[:index] + '.' + text[index + 1:]
    try:
	string.atof(text)
	return OK
    except ValueError:
	if len(text) == 0:
	    return PARTIAL
	if text[-1] in string.digits:
	    return ERROR
	try:
	    string.atof(text + '0')
	    return PARTIAL
	except ValueError:
	    return ERROR
def timevalidator(text, separator = ':'):

    try:
	timestringtoseconds(text, separator)
	return OK
    except ValueError:
	if len(text) > 0 and text[0] in ('+', '-'):
	    text = text[1:]
	if re.search('[^0-9' + separator + ']', text) is not None:
	    return ERROR
	return PARTIAL
def datevalidator(text, format = 'ymd', separator = '/'):

    try:
	datestringtojdn(text, format, separator)
	return OK
    except ValueError:
	if re.search('[^0-9' + separator + ']', text) is not None:
	    return ERROR
	return PARTIAL
_standardValidators = {
    'numeric'      : (numericvalidator,      string.atol),
    'integer'      : (integervalidator,      string.atol),
    'hexadecimal'  : (hexadecimalvalidator,  lambda s: string.atol(s, 16)),
    'real'         : (realvalidator,         stringtoreal),
    'alphabetic'   : (alphabeticvalidator,   len),
    'alphanumeric' : (alphanumericvalidator, len),
    'time'         : (timevalidator,         timestringtoseconds),
    'date'         : (datevalidator,         datestringtojdn),
}
_entryCache = {}
def _registerEntryField(entry, entryField):

    _entryCache[entry] = entryField
def _deregisterEntryField(entry):

    del _entryCache[entry]
def _preProcess(event):

    _entryCache[event.widget]._preProcess()
def _postProcess(event):

    if _entryCache.has_key(event.widget):
        _entryCache[event.widget]._postProcess()
import string
import Tkinter
def aligngrouptags(groups):

    maxTagHeight = 0
    for group in groups:
	if group._tag is None:
	    height = (string.atoi(str(group._ring.cget('borderwidth'))) +
		    string.atoi(str(group._ring.cget('highlightthickness'))))
	else:
	    height = group._tag.winfo_reqheight()
	if maxTagHeight < height:
	    maxTagHeight = height
    for group in groups:
	ringBorder = (string.atoi(str(group._ring.cget('borderwidth'))) +
		string.atoi(str(group._ring.cget('highlightthickness'))))
	topBorder = maxTagHeight / 2 - ringBorder / 2
	group._hull.grid_rowconfigure(0, minsize = topBorder)
	group._ring.grid_rowconfigure(0,
		minsize = maxTagHeight - topBorder - ringBorder)
	if group._tag is not None:
	    group._tag.place(y = maxTagHeight / 2)
class Group( MegaWidget ):


    def __init__(self, parent = None, **kw):

        optiondefs = (
	    ('collapsedsize',    6,         INITOPT),
	    ('ring_borderwidth', 2,         None),
	    ('ring_relief',      'groove',  None),
	    ('tagindent',        10,        INITOPT),
        )
        self.defineoptions(kw, optiondefs)
        MegaWidget.__init__(self, parent)
        interior = MegaWidget.interior(self)
	self._ring = self.createcomponent(
	    'ring',
	    (), None,
	    Tkinter.Frame, (interior,),
	    )
	self._groupChildSite = self.createcomponent(
	    'groupchildsite',
	    (), None,
	    Tkinter.Frame, (self._ring,)
	    )
        self._tag = self.createcomponent(
	    'tag',
	    (), None,
	    Tkinter.Label, (interior,),
	    )
	ringBorder = (string.atoi(str(self._ring.cget('borderwidth'))) +
		string.atoi(str(self._ring.cget('highlightthickness'))))
	if self._tag is None:
	    tagHeight = ringBorder
	else:
	    tagHeight = self._tag.winfo_reqheight()
	    self._tag.place(
		    x = ringBorder + self['tagindent'],
		    y = tagHeight / 2,
		    anchor = 'w')
	topBorder = tagHeight / 2 - ringBorder / 2
	self._ring.grid(column = 0, row = 1, sticky = 'nsew')
	interior.grid_columnconfigure(0, weight = 1)
	interior.grid_rowconfigure(1, weight = 1)
	interior.grid_rowconfigure(0, minsize = topBorder)
	self._groupChildSite.grid(column = 0, row = 1, sticky = 'nsew')
	self._ring.grid_columnconfigure(0, weight = 1)
	self._ring.grid_rowconfigure(1, weight = 1)
	self._ring.grid_rowconfigure(0,
		minsize = tagHeight - topBorder - ringBorder)
        self.showing = 1
        self.initialiseoptions()
    def toggle(self):

        if self.showing:
            self.collapse()
        else:
            self.expand()
        self.showing = not self.showing
    def expand(self):

        self._groupChildSite.grid(column = 0, row = 1, sticky = 'nsew')
    def collapse(self):

        self._groupChildSite.grid_forget()
	if self._tag is None:
	    tagHeight = 0
	else:
            tagHeight = self._tag.winfo_reqheight()
        self._ring.configure(height=(tagHeight / 2) + self['collapsedsize'])
    def interior(self):

        return self._groupChildSite
import Tkinter
class LabeledWidget(MegaWidget):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('labelmargin',            0,      INITOPT),
	    ('labelpos',               None,   INITOPT),
	    ('sticky',                 'nsew', INITOPT),
	)
	self.defineoptions(kw, optiondefs)
	MegaWidget.__init__(self, parent)
	interior = MegaWidget.interior(self)
	self._labelChildSite = self.createcomponent('labelchildsite',
		(), None,
		Tkinter.Frame, (interior,))
	self._labelChildSite.grid(column=2, row=2, sticky=self['sticky'])
	interior.grid_columnconfigure(2, weight=1)
	interior.grid_rowconfigure(2, weight=1)
	self.createlabel(interior)
	self.initialiseoptions()
    def interior(self):

	return self._labelChildSite
import string
import types
import Tkinter
class MainMenuBar(MegaArchetype):


    def __init__(self, parent = None, **kw):

        optiondefs = (
            ('balloon',      None,       None),
            ('hotkeys',      1,          INITOPT),
            ('hull_tearoff', 0,          None),
        )
        self.defineoptions(kw, optiondefs, dynamicGroups = ('Menu',))
        MegaArchetype.__init__(self, parent, Tkinter.Menu)
        self._menuInfo = {}
        self._menuInfo[None] = (None, [])
        self._menu = self.interior()
        self._menu.bind('<Leave>', self._resetHelpmessage)
        self._menu.bind('<Motion>',
            lambda event=None, self=self: self._menuHelp(event, None))
        self.initialiseoptions()
    def deletemenuitems(self, menuName, start, end = None):

        self.component(menuName).delete(start, end)
        if end is None:
            del self._menuInfo[menuName][1][start]
        else:
            self._menuInfo[menuName][1][start:end+1] = []
    def deletemenu(self, menuName):

        """Delete should be called for cascaded menus before main menus.
        """
        parentName = self._menuInfo[menuName][0]
        del self._menuInfo[menuName]
        if parentName is None:
            parentMenu = self._menu
        else:
            parentMenu = self.component(parentName)
        menu = self.component(menuName)
        menuId = str(menu)
        for item in range(parentMenu.index('end') + 1):
            if parentMenu.type(item) == 'cascade':
                itemMenu = str(parentMenu.entrycget(item, 'menu'))
                if itemMenu == menuId:
                    parentMenu.delete(item)
                    del self._menuInfo[parentName][1][item]
                    break
        self.destroycomponent(menuName)
    def disableall(self):

        for index in range(len(self._menuInfo[None][1])):
            self.entryconfigure(index, state = 'disabled')
    def enableall(self):

        for index in range(len(self._menuInfo[None][1])):
            self.entryconfigure(index, state = 'normal')
    def addmenu(self, menuName, balloonHelp, statusHelp = None,

            traverseSpec = None, **kw):
        if statusHelp is None:
            statusHelp = balloonHelp
        self._addmenu(None, menuName, balloonHelp, statusHelp,
            traverseSpec, kw)
    def addcascademenu(self, parentMenuName, menuName, statusHelp='',

            traverseSpec = None, **kw):
        self._addmenu(parentMenuName, menuName, None, statusHelp,
            traverseSpec, kw)
    def _addmenu(self, parentMenuName, menuName, balloonHelp, statusHelp,

            traverseSpec, kw):
        if (menuName) in self.components():
            raise ValueError, 'menu "%s" already exists' % menuName
        menukw = {}
        if kw.has_key('tearoff'):
            menukw['tearoff'] = kw['tearoff']
            del kw['tearoff']
        else:
            menukw['tearoff'] = 0
        if kw.has_key('name'):
            menukw['name'] = kw['name']
            del kw['name']
        if not kw.has_key('label'):
            kw['label'] = menuName
        self._addHotkeyToOptions(parentMenuName, kw, traverseSpec)
        if parentMenuName is None:
            parentMenu = self._menu
            balloon = self['balloon']
        else:
            parentMenu = self.component(parentMenuName)
        apply(parentMenu.add_cascade, (), kw)
        menu = apply(self.createcomponent, (menuName,
                (), 'Menu',
                Tkinter.Menu, (parentMenu,)), menukw)
        parentMenu.entryconfigure('end', menu = menu)
        self._menuInfo[parentMenuName][1].append(statusHelp)
        self._menuInfo[menuName] = (parentMenuName, [])
        menu.bind('<Leave>', self._resetHelpmessage)
        menu.bind('<Motion>',
            lambda event=None, self=self, menuName=menuName:
                    self._menuHelp(event, menuName))
    def addmenuitem(self, menuName, itemType, statusHelp = '',

            traverseSpec = None, **kw):
        menu = self.component(menuName)
        if itemType != 'separator':
            self._addHotkeyToOptions(menuName, kw, traverseSpec)
        if itemType == 'command':
            command = menu.add_command
        elif itemType == 'separator':
            command = menu.add_separator
        elif itemType == 'checkbutton':
            command = menu.add_checkbutton
        elif itemType == 'radiobutton':
            command = menu.add_radiobutton
        elif itemType == 'cascade':
            command = menu.add_cascade
        else:
            raise ValueError, 'unknown menuitem type "%s"' % itemType
        self._menuInfo[menuName][1].append(statusHelp)
        apply(command, (), kw)
    def _addHotkeyToOptions(self, menuName, kw, traverseSpec):

        if (not self['hotkeys'] or kw.has_key('underline') or
                not kw.has_key('label')):
            return
        if type(traverseSpec) == types.IntType:
            kw['underline'] = traverseSpec
            return
        if menuName is None:
            menu = self._menu
        else:
            menu = self.component(menuName)
        hotkeyList = []
        end = menu.index('end')
        if end is not None:
            for item in range(end + 1):
                if menu.type(item) not in ('separator', 'tearoff'):
                    underline = \
                            string.atoi(str(menu.entrycget(item, 'underline')))
                    if underline != -1:
                        label = str(menu.entrycget(item, 'label'))
                        if underline < len(label):
                            hotkey = string.lower(label[underline])
                            if hotkey not in hotkeyList:
                                hotkeyList.append(hotkey)
        name = kw['label']
        if type(traverseSpec) == types.StringType:
            lowerLetter = string.lower(traverseSpec)
            if traverseSpec in name and lowerLetter not in hotkeyList:
                kw['underline'] = string.index(name, traverseSpec)
        else:
            targets = string.digits + string.letters
            lowerName = string.lower(name)
            for letter_index in range(len(name)):
                letter = lowerName[letter_index]
                if letter in targets and letter not in hotkeyList:
                    kw['underline'] = letter_index
                    break
    def _menuHelp(self, event, menuName):

        if menuName is None:
            menu = self._menu
            index = menu.index('@%d'% event.x)
        else:
            menu = self.component(menuName)
            index = menu.index('@%d'% event.y)
        balloon = self['balloon']
        if balloon is not None:
            if index is None:
                balloon.showstatus('')
            else:
                if str(menu.cget('tearoff')) == '1':
                    index = index - 1
                if index >= 0:
                    help = self._menuInfo[menuName][1][index]
                    balloon.showstatus(help)
    def _resetHelpmessage(self, event=None):

        balloon = self['balloon']
        if balloon is not None:
            balloon.clearstatus()
forwardmethods(MainMenuBar, Tkinter.Menu, '_hull')
import string
import types
import Tkinter
class MenuBar(MegaWidget):


    def __init__(self, parent = None, **kw):

        optiondefs = (
            ('balloon',      None,       None),
            ('hotkeys',      1,          INITOPT),
            ('padx',         0,          INITOPT),
        )
        self.defineoptions(kw, optiondefs, dynamicGroups = ('Menu', 'Button'))
        MegaWidget.__init__(self, parent)
        self._menuInfo = {}
        self._mydeletecommand = self.component('hull').tk.deletecommand
        self.initialiseoptions()
    def deletemenuitems(self, menuName, start, end = None):

        self.component(menuName + '-menu').delete(start, end)
        if end is None:
            del self._menuInfo[menuName][1][start]
        else:
            self._menuInfo[menuName][1][start:end+1] = []
    def deletemenu(self, menuName):

        """Delete should be called for cascaded menus before main menus.
        """
        parentName = self._menuInfo[menuName][0]
        bindId = self._menuInfo[menuName][2]
        _bindtag = 'PmwMenuBar' + str(self) + menuName
        self.unbind_class(_bindtag, '<Motion>')
        self._mydeletecommand(bindId)
        del self._menuInfo[menuName]
        if parentName is None:
            self.destroycomponent(menuName + '-button')
        else:
            parentMenu = self.component(parentName + '-menu')
            menu = self.component(menuName + '-menu')
            menuId = str(menu)
            for item in range(parentMenu.index('end') + 1):
                if parentMenu.type(item) == 'cascade':
                    itemMenu = str(parentMenu.entrycget(item, 'menu'))
                    if itemMenu == menuId:
                        parentMenu.delete(item)
                        del self._menuInfo[parentName][1][item]
                        break
        self.destroycomponent(menuName + '-menu')
    def disableall(self):

        for menuName in self._menuInfo.keys():
            if self._menuInfo[menuName][0] is None:
                menubutton = self.component(menuName + '-button')
                menubutton.configure(state = 'disabled')
    def enableall(self):

        for menuName in self._menuInfo.keys():
            if self._menuInfo[menuName][0] is None:
                menubutton = self.component(menuName + '-button')
                menubutton.configure(state = 'normal')
    def addmenu(self, menuName, balloonHelp, statusHelp = None,

            side = 'left', traverseSpec = None, **kw):
        self._addmenu(None, menuName, balloonHelp, statusHelp,
            traverseSpec, side, 'text', kw)
    def addcascademenu(self, parentMenuName, menuName, statusHelp = '',

            traverseSpec = None, **kw):
        self._addmenu(parentMenuName, menuName, None, statusHelp,
            traverseSpec, None, 'label', kw)
    def _addmenu(self, parentMenuName, menuName, balloonHelp, statusHelp,

            traverseSpec, side, textKey, kw):
        if (menuName + '-menu') in self.components():
            raise ValueError, 'menu "%s" already exists' % menuName
        menukw = {}
        if kw.has_key('tearoff'):
            menukw['tearoff'] = kw['tearoff']
            del kw['tearoff']
        else:
            menukw['tearoff'] = 0
        if not kw.has_key(textKey):
            kw[textKey] = menuName
        self._addHotkeyToOptions(parentMenuName, kw, textKey, traverseSpec)
        if parentMenuName is None:
            button = apply(self.createcomponent, (menuName + '-button',
                    (), 'Button',
                    Tkinter.Menubutton, (self.interior(),)), kw)
            button.pack(side=side, padx = self['padx'])
            balloon = self['balloon']
            if balloon is not None:
                balloon.bind(button, balloonHelp, statusHelp)
            parentMenu = button
        else:
            parentMenu = self.component(parentMenuName + '-menu')
            apply(parentMenu.add_cascade, (), kw)
            self._menuInfo[parentMenuName][1].append(statusHelp)
        menu = apply(self.createcomponent, (menuName + '-menu',
                (), 'Menu',
                Tkinter.Menu, (parentMenu,)), menukw)
        if parentMenuName is None:
            button.configure(menu = menu)
        else:
            parentMenu.entryconfigure('end', menu = menu)
        _bindtag = 'PmwMenuBar' + str(self) + menuName
        bindId = self.bind_class(_bindtag, '<Motion>',
            lambda event=None, self=self, menuName=menuName:
                    self._menuHelp(menuName))
        menu.bindtags(menu.bindtags() + (_bindtag,))
        menu.bind('<Leave>', self._resetHelpmessage)
        self._menuInfo[menuName] = (parentMenuName, [], bindId)
    def addmenuitem(self, menuName, itemType, statusHelp = '',

            traverseSpec = None, **kw):
        menu = self.component(menuName + '-menu')
        if itemType != 'separator':
            self._addHotkeyToOptions(menuName, kw, 'label', traverseSpec)
        if itemType == 'command':
            command = menu.add_command
        elif itemType == 'separator':
            command = menu.add_separator
        elif itemType == 'checkbutton':
            command = menu.add_checkbutton
        elif itemType == 'radiobutton':
            command = menu.add_radiobutton
        elif itemType == 'cascade':
            command = menu.add_cascade
        else:
            raise ValueError, 'unknown menuitem type "%s"' % itemType
        self._menuInfo[menuName][1].append(statusHelp)
        apply(command, (), kw)
    def _addHotkeyToOptions(self, menuName, kw, textKey, traverseSpec):

        if (not self['hotkeys'] or kw.has_key('underline') or
                not kw.has_key(textKey)):
            return
        if type(traverseSpec) == types.IntType:
            kw['underline'] = traverseSpec
            return
        hotkeyList = []
        if menuName is None:
            for menuName in self._menuInfo.keys():
                if self._menuInfo[menuName][0] is None:
                    menubutton = self.component(menuName + '-button')
                    underline = string.atoi(str(menubutton.cget('underline')))
                    if underline != -1:
                        label = str(menubutton.cget(textKey))
                        if underline < len(label):
                            hotkey = string.lower(label[underline])
                            if hotkey not in hotkeyList:
                                hotkeyList.append(hotkey)
        else:
            menu = self.component(menuName + '-menu')
            end = menu.index('end')
            if end is not None:
                for item in range(end + 1):
                    if menu.type(item) not in ('separator', 'tearoff'):
                        underline = string.atoi(
                            str(menu.entrycget(item, 'underline')))
                        if underline != -1:
                            label = str(menu.entrycget(item, textKey))
                            if underline < len(label):
                                hotkey = string.lower(label[underline])
                                if hotkey not in hotkeyList:
                                    hotkeyList.append(hotkey)
        name = kw[textKey]
        if type(traverseSpec) == types.StringType:
            lowerLetter = string.lower(traverseSpec)
            if traverseSpec in name and lowerLetter not in hotkeyList:
                kw['underline'] = string.index(name, traverseSpec)
        else:
            targets = string.digits + string.letters
            lowerName = string.lower(name)
            for letter_index in range(len(name)):
                letter = lowerName[letter_index]
                if letter in targets and letter not in hotkeyList:
                    kw['underline'] = letter_index
                    break
    def _menuHelp(self, menuName):

        menu = self.component(menuName + '-menu')
        index = menu.index('active')
        balloon = self['balloon']
        if balloon is not None:
            if index is None:
                balloon.showstatus('')
            else:
                if str(menu.cget('tearoff')) == '1':
                    index = index - 1
                if index >= 0:
                    help = self._menuInfo[menuName][1][index]
                    balloon.showstatus(help)
    def _resetHelpmessage(self, event=None):

        balloon = self['balloon']
        if balloon is not None:
            balloon.clearstatus()
import string
import Tkinter
class MessageBar(MegaWidget):


    def __init__(self, parent = None, **kw):

	defaultMessageTypes = {

	    'systemerror'  : (5, 10, 2, 1),
	    'usererror'    : (4, 5, 1, 0),
	    'busy'         : (3, 0, 0, 0),
	    'systemevent'  : (2, 5, 0, 0),
	    'userevent'    : (2, 5, 0, 0),
	    'help'         : (1, 5, 0, 0),
	    'state'        : (0, 0, 0, 0),
	}
	optiondefs = (
	    ('labelmargin',    0,                     INITOPT),
	    ('labelpos',       None,                  INITOPT),
	    ('messagetypes',   defaultMessageTypes,   INITOPT),
	    ('silent',         0,                     None),
	    ('sticky',         'ew',                  INITOPT),
	)
	self.defineoptions(kw, optiondefs)
	MegaWidget.__init__(self, parent)
	interior = self.interior()
	self._messageBarEntry = self.createcomponent('entry',
		(), None,
		Tkinter.Entry, (interior,))
        try:
            self._messageBarEntry.configure(state = 'readonly')
        except Tkinter.TclError:
            self._messageBarEntry.configure(state = 'disabled')
	self._messageBarEntry.grid(column=2, row=2, sticky=self['sticky'])
	interior.grid_columnconfigure(2, weight=1)
	interior.grid_rowconfigure(2, weight=1)
	self.createlabel(interior)
	self._numPriorities = 0
	for info in self['messagetypes'].values():
	    if self._numPriorities < info[0]:
		self._numPriorities = info[0]
	self._numPriorities = self._numPriorities + 1
	self._timer = [None] * self._numPriorities
	self._messagetext = [''] * self._numPriorities
	self._activemessage = [0] * self._numPriorities
	self.initialiseoptions()
    def destroy(self):

	for timerId in self._timer:
	    if timerId is not None:
		self.after_cancel(timerId)
	self._timer = [None] * self._numPriorities
	MegaWidget.destroy(self)
    def message(self, type, text):

	(priority, showtime, bells, logmessage) = self['messagetypes'][type]
	if not self['silent']:
	    for i in range(bells):
		if i != 0:
		    self.after(100)
		self.bell()
	self._activemessage[priority] = 1
	if text is None:
	    text = ''
	self._messagetext[priority] = string.replace(text, '\n', ' ')
	self._redisplayInfoMessage()
	if logmessage:
	    pass
	if showtime > 0:
	    if self._timer[priority] is not None:
		self.after_cancel(self._timer[priority])
	    def _clearmessage(self=self, priority=priority):

		self._clearActivemessage(priority)
	    mseconds = int(showtime * 1000)
	    self._timer[priority] = self.after(mseconds, _clearmessage)
    def helpmessage(self, text):

        if text is None:
            self.resetmessages('help')
        else:
            self.message('help', text)
    def resetmessages(self, type):

	priority = self['messagetypes'][type][0]
	self._clearActivemessage(priority)
	for messagetype, info in self['messagetypes'].items():
	    thisPriority = info[0]
	    showtime = info[1]
	    if thisPriority < priority and showtime != 0:
		self._clearActivemessage(thisPriority)
    def _clearActivemessage(self, priority):

	self._activemessage[priority] = 0
	if self._timer[priority] is not None:
	    self.after_cancel(self._timer[priority])
	    self._timer[priority] = None
	self._redisplayInfoMessage()
    def _redisplayInfoMessage(self):

	text = ''
        for priority in range(self._numPriorities - 1, -1, -1):
	    if self._activemessage[priority]:
		text = self._messagetext[priority]
	        break
	self._messageBarEntry.configure(state = 'normal')
	self._messageBarEntry.delete(0, 'end')
	self._messageBarEntry.insert('end', text)
        try:
            self._messageBarEntry.configure(state = 'readonly')
        except Tkinter.TclError:
            self._messageBarEntry.configure(state = 'disabled')
forwardmethods(MessageBar, Tkinter.Entry, '_messageBarEntry')
import Tkinter
class MessageDialog(Dialog):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('borderx',       20,    INITOPT),
	    ('bordery',       20,    INITOPT),
	    ('iconmargin',    20,    INITOPT),
	    ('iconpos',       None,  INITOPT),
	)
	self.defineoptions(kw, optiondefs)
	Dialog.__init__(self, parent)
	interior = self.interior()
	self._message = self.createcomponent('message',
		(), None,
		Tkinter.Label, (interior,))
        iconpos = self['iconpos']
	iconmargin = self['iconmargin']
	borderx = self['borderx']
	bordery = self['bordery']
	border_right = 2
	border_bottom = 2
	if iconpos is None:
	    self._message.grid(column = 1, row = 1)
	else:
	    self._icon = self.createcomponent('icon',
		    (), None,
		    Tkinter.Label, (interior,))
	    if iconpos not in 'nsew':
		raise ValueError, \
		    'bad iconpos option "%s":  should be n, s, e, or w' \
			% iconpos
	    if iconpos in 'nw':
		icon = 1
		message = 3
	    else:
		icon = 3
		message = 1
	    if iconpos in 'ns':
		self._icon.grid(column = 1, row = icon)
		self._message.grid(column = 1, row = message)
		interior.grid_rowconfigure(2, minsize = iconmargin)
		border_bottom = 4
	    else:
		self._icon.grid(column = icon, row = 1)
		self._message.grid(column = message, row = 1)
		interior.grid_columnconfigure(2, minsize = iconmargin)
		border_right = 4
	interior.grid_columnconfigure(0, minsize = borderx)
	interior.grid_rowconfigure(0, minsize = bordery)
	interior.grid_columnconfigure(border_right, minsize = borderx)
	interior.grid_rowconfigure(border_bottom, minsize = bordery)
	self.initialiseoptions()
import string
import types
import Tkinter
class NoteBook(MegaArchetype):


    def __init__(self, parent = None, **kw):

        optiondefs = (
	    ('hull_highlightthickness',  0,           None),
	    ('hull_borderwidth',         0,           None),
            ('arrownavigation',          1,           INITOPT),
            ('borderwidth',              2,           INITOPT),
            ('createcommand',            None,        None),
            ('lowercommand',             None,        None),
            ('pagemargin',               4,           INITOPT),
            ('raisecommand',             None,        None),
	    ('tabpos',                   'n',         INITOPT),
        )
	self.defineoptions(kw, optiondefs, dynamicGroups = ('Page', 'Tab'))
	MegaArchetype.__init__(self, parent, Tkinter.Canvas)
        self.bind('<Map>', self._handleMap)
        self.bind('<Configure>', self._handleConfigure)
        tabpos = self['tabpos']
	if tabpos is not None and tabpos != 'n':
            raise ValueError, \
                'bad tabpos option %s:  should be n or None' % repr(tabpos)
        self._withTabs = (tabpos is not None)
        self._pageMargin = self['pagemargin']
        self._borderWidth = self['borderwidth']
        self._pending = {}
        self._pending['size'] = 1
        self._pending['borderColor'] = 1
        self._pending['topPage'] = None
        if self._withTabs:
            self._pending['tabs'] = 1
        self._canvasSize = None
        if self._withTabs:
            self.tabBottom = 35
        else:
            self.tabBottom = 0
        self._lightBorderColor, self._darkBorderColor = \
                Color.bordercolors(self, self['hull_background'])
	self._pageNames   = []
	self._pageAttrs   = {}
	self._topPageName = None
        if self._withTabs:
            self._pageLeftBorder = self.create_polygon(0, 0, 0, 0, 0, 0,
                fill = self._lightBorderColor, tags = 'lighttag')
            self._pageBottomRightBorder = self.create_polygon(0, 0, 0, 0, 0, 0,
                fill = self._darkBorderColor, tags = 'darktag')
            self._pageTop1Border = self.create_polygon(0, 0, 0, 0, 0, 0,
                fill = self._darkBorderColor, tags = 'lighttag')
            self._pageTop2Border = self.create_polygon(0, 0, 0, 0, 0, 0,
                fill = self._darkBorderColor, tags = 'lighttag')
        else:
            self._pageLeftBorder = self.create_polygon(0, 0, 0, 0, 0, 0,
                fill = self._darkBorderColor, tags = 'darktag')
            self._pageBottomRightBorder = self.create_polygon(0, 0, 0, 0, 0, 0,
                fill = self._lightBorderColor, tags = 'lighttag')
            self._pageTopBorder = self.create_polygon(0, 0, 0, 0, 0, 0,
                fill = self._darkBorderColor, tags = 'darktag')
	self.initialiseoptions()
    def insert(self, pageName, before = 0, **kw):

	if self._pageAttrs.has_key(pageName):
	    msg = 'Page "%s" already exists.' % pageName
	    raise ValueError, msg
	beforeIndex = self.index(before, 1)
        pageOptions = {}
        if self._withTabs:
            tabOptions = {
                'text' : pageName,
                'borderwidth' : 0,
            }
        for key in kw.keys():
            if key[:5] == 'page_':
                pageOptions[key[5:]] = kw[key]
                del kw[key]
            elif self._withTabs and key[:4] == 'tab_':
                tabOptions[key[4:]] = kw[key]
                del kw[key]
            else:
		raise KeyError, 'Unknown option "' + key + '"'
	page = apply(self.createcomponent, (pageName,
		(), 'Page',
		Tkinter.Frame, self._hull), pageOptions)
        attributes = {}
        attributes['page'] = page
        attributes['created'] = 0
        if self._withTabs:
            def raiseThisPage(self = self, pageName = pageName):

                self.selectpage(pageName)
            tabOptions['command'] = raiseThisPage
            tab = apply(self.createcomponent, (pageName + '-tab',
                    (), 'Tab',
                    Tkinter.Button, self._hull), tabOptions)
            if self['arrownavigation']:
                def next(event, self = self, pageName = pageName):

                    self.nextpage(pageName)
                def prev(event, self = self, pageName = pageName):

                    self.previouspage(pageName)
                tab.bind('<Left>', prev)
                tab.bind('<Right>', next)
            attributes['tabbutton'] = tab
            attributes['tabreqwidth'] = tab.winfo_reqwidth()
            attributes['tabreqheight'] = tab.winfo_reqheight()
            windowitem = self.create_window(0, 0, window = tab, anchor = 'nw')
            lightshadow = self.create_polygon(0, 0, 0, 0, 0, 0,
                tags = 'lighttag', fill = self._lightBorderColor)
            darkshadow = self.create_polygon(0, 0, 0, 0, 0, 0,
                tags = 'darktag', fill = self._darkBorderColor)
            attributes['tabitems'] = (windowitem, lightshadow, darkshadow)
            self._pending['tabs'] = 1
        self._pageAttrs[pageName] = attributes
	self._pageNames.insert(beforeIndex, pageName)
        if self.getcurselection() is None:
            self._pending['topPage'] = pageName
            self._raiseNewTop(pageName)
        self._layout()
        return page
    def add(self, pageName, **kw):

        return apply(self.insert, (pageName, len(self._pageNames)), kw)
    def delete(self, *pageNames):

        newTopPage = 0
        for page in pageNames:
            pageIndex = self.index(page)
            pageName = self._pageNames[pageIndex]
            pageInfo = self._pageAttrs[pageName]
            if self.getcurselection() == pageName:
                if len(self._pageNames) == 1:
                    newTopPage = 0
                    self._pending['topPage'] = None
                elif pageIndex == len(self._pageNames) - 1:
                    newTopPage = 1
                    self._pending['topPage'] = self._pageNames[pageIndex - 1]
                else:
                    newTopPage = 1
                    self._pending['topPage'] = self._pageNames[pageIndex + 1]
            if self._topPageName == pageName:
                self._hull.delete(self._topPageItem)
                self._topPageName = None
            if self._withTabs:
                self.destroycomponent(pageName + '-tab')
                apply(self._hull.delete, pageInfo['tabitems'])
            self.destroycomponent(pageName)
            del self._pageAttrs[pageName]
            del self._pageNames[pageIndex]
        if newTopPage:
            pageName = self._pending['topPage']
            self._raiseNewTop(pageName)
        if self._withTabs:
            self._pending['tabs'] = 1
        self._layout()
    def page(self, pageIndex):

        pageName = self._pageNames[self.index(pageIndex)]
	return self._pageAttrs[pageName]['page']
    def pagenames(self):

	return list(self._pageNames)
    def getcurselection(self):

        if self._pending.has_key('topPage'):
            return self._pending['topPage']
        else:
            return self._topPageName
    def tab(self, pageIndex):

        if self._withTabs:
            pageName = self._pageNames[self.index(pageIndex)]
            return self._pageAttrs[pageName]['tabbutton']
        else:
            return None
    def index(self, index, forInsert = 0):

	listLength = len(self._pageNames)
	if type(index) == types.IntType:
	    if forInsert and index <= listLength:
		return index
	    elif not forInsert and index < listLength:
		return index
	    else:
		raise ValueError, 'index "%s" is out of range' % index
	elif index is END:
	    if forInsert:
		return listLength
	    elif listLength > 0:
		return listLength - 1
	    else:
		raise ValueError, 'NoteBook has no pages'
	elif index is SELECT:
	    if listLength == 0:
		raise ValueError, 'NoteBook has no pages'
            return self._pageNames.index(self.getcurselection())
	else:
            if index in self._pageNames:
                return self._pageNames.index(index)
	    validValues = 'a name, a number, END or SELECT'
	    raise ValueError, \
                'bad index "%s": must be %s' % (index, validValues)
    def selectpage(self, page):

        pageName = self._pageNames[self.index(page)]
        oldTopPage = self.getcurselection()
        if pageName != oldTopPage:
            self._pending['topPage'] = pageName
            if oldTopPage == self._topPageName:
                self._hull.delete(self._topPageItem)
            cmd = self['lowercommand']
            if cmd is not None:
                cmd(oldTopPage)
            self._raiseNewTop(pageName)
            self._layout()
        if self._withTabs and self['arrownavigation']:
            self._pageAttrs[pageName]['tabbutton'].focus_set()
    def previouspage(self, pageIndex = None):

        if pageIndex is None:
            curpage = self.index(SELECT)
        else:
            curpage = self.index(pageIndex)
	if curpage > 0:
	    self.selectpage(curpage - 1)
    def nextpage(self, pageIndex = None):

        if pageIndex is None:
            curpage = self.index(SELECT)
        else:
            curpage = self.index(pageIndex)
	if curpage < len(self._pageNames) - 1:
	    self.selectpage(curpage + 1)
    def setnaturalsize(self, pageNames = None):

        self.update_idletasks()
        maxPageWidth = 1
        maxPageHeight = 1
        if pageNames is None:
            pageNames = self.pagenames()
        for pageName in pageNames:
            pageInfo = self._pageAttrs[pageName]
            page = pageInfo['page']
            w = page.winfo_reqwidth()
            h = page.winfo_reqheight()
            if maxPageWidth < w:
                maxPageWidth = w
            if maxPageHeight < h:
                maxPageHeight = h
        pageBorder = self._borderWidth + self._pageMargin
        width = maxPageWidth + pageBorder * 2
        height = maxPageHeight + pageBorder * 2
        if self._withTabs:
            maxTabHeight = 0
            for pageInfo in self._pageAttrs.values():
                if maxTabHeight < pageInfo['tabreqheight']:
                    maxTabHeight = pageInfo['tabreqheight']
            height = height + maxTabHeight + self._borderWidth * 1.5
        self.configure(hull_width = width, hull_height = height)
    def recolorborders(self):

        self._pending['borderColor'] = 1
        self._layout()
    def _handleMap(self, event):

        self._layout()
    def _handleConfigure(self, event):

        self._canvasSize = (event.width, event.height)
        self._pending['size'] = 1
        self._layout()
    def _raiseNewTop(self, pageName):

        if not self._pageAttrs[pageName]['created']:
            self._pageAttrs[pageName]['created'] = 1
            cmd = self['createcommand']
            if cmd is not None:
                cmd(pageName)
        cmd = self['raisecommand']
        if cmd is not None:
            cmd(pageName)
    def _layout(self):

        if not self.winfo_ismapped() or self._canvasSize is None:
            return
        hullWidth, hullHeight = self._canvasSize
        borderWidth = self._borderWidth
        canvasBorder = string.atoi(self._hull['borderwidth']) + \
            string.atoi(self._hull['highlightthickness'])
        if not self._withTabs:
            self.tabBottom = canvasBorder
        oldTabBottom = self.tabBottom
        if self._pending.has_key('borderColor'):
            self._lightBorderColor, self._darkBorderColor = \
                    Color.bordercolors(self, self['hull_background'])
        if self._withTabs and (self._pending.has_key('tabs') or
                self._pending.has_key('size')):
            sumTabReqWidth = 0
            maxTabHeight = 0
            for pageInfo in self._pageAttrs.values():
                sumTabReqWidth = sumTabReqWidth + pageInfo['tabreqwidth']
                if maxTabHeight < pageInfo['tabreqheight']:
                    maxTabHeight = pageInfo['tabreqheight']
            if maxTabHeight != 0:
                self.tabBottom = canvasBorder + maxTabHeight + borderWidth * 1.5
            tabTop = canvasBorder
            tabTop2 = tabTop + borderWidth
            tabTop3 = tabTop + borderWidth * 1.5
            tabBottom2 = self.tabBottom
            tabBottom = self.tabBottom + borderWidth
            numTabs = len(self._pageNames)
            availableWidth = hullWidth - 2 * canvasBorder - \
                numTabs * 2 * borderWidth
            x = canvasBorder
            cumTabReqWidth = 0
            cumTabWidth = 0
            for pageName in self._pageNames:
                pageInfo = self._pageAttrs[pageName]
                (windowitem, lightshadow, darkshadow) = pageInfo['tabitems']
                if sumTabReqWidth <= availableWidth:
                    tabwidth = pageInfo['tabreqwidth']
                else:
                    cumTabReqWidth = cumTabReqWidth + pageInfo['tabreqwidth']
                    tmp = (2*cumTabReqWidth*availableWidth + sumTabReqWidth) \
                            / (2 * sumTabReqWidth)
                    tabwidth = tmp - cumTabWidth
                    cumTabWidth = tmp
                self.coords(windowitem, x + borderWidth, tabTop3)
                self.itemconfigure(windowitem,
                    width = tabwidth, height = maxTabHeight)
                left = x
                left2 = left + borderWidth
                left3 = left + borderWidth * 1.5
                right = left + tabwidth + 2 * borderWidth
                right2 = left + tabwidth + borderWidth
                right3 = left + tabwidth + borderWidth * 0.5
                self.coords(lightshadow,
                    left, tabBottom2, left, tabTop2, left2, tabTop,
                    right2, tabTop, right3, tabTop2, left3, tabTop2,
                    left2, tabTop3, left2, tabBottom,
                    )
                self.coords(darkshadow,
                    right2, tabTop, right, tabTop2, right, tabBottom2,
                    right2, tabBottom, right2, tabTop3, right3, tabTop2,
                    )
                pageInfo['left'] = left
                pageInfo['right'] = right
                x = x + tabwidth + 2 * borderWidth
        if self._withTabs and (self._pending.has_key('topPage') or
                self._pending.has_key('tabs') or self._pending.has_key('size')):
            if self.getcurselection() is None:
                self.coords(self._pageTop1Border,
                    canvasBorder, self.tabBottom,
                    hullWidth - canvasBorder, self.tabBottom,
                    hullWidth - canvasBorder - borderWidth,
                        self.tabBottom + borderWidth,
                    borderWidth + canvasBorder, self.tabBottom + borderWidth,
                    )
                self.coords(self._pageTop2Border, 0, 0, 0, 0, 0, 0)
            else:
                pageInfo = self._pageAttrs[self.getcurselection()]
                left = pageInfo['left']
                right = pageInfo['right']
                self.coords(self._pageTop1Border,
                    canvasBorder, self.tabBottom,
                    left, self.tabBottom,
                    left + borderWidth, self.tabBottom + borderWidth,
                    canvasBorder + borderWidth, self.tabBottom + borderWidth,
                    )
                self.coords(self._pageTop2Border,
                    right, self.tabBottom,
                    hullWidth - canvasBorder, self.tabBottom,
                    hullWidth - canvasBorder - borderWidth,
                        self.tabBottom + borderWidth,
                    right - borderWidth, self.tabBottom + borderWidth,
                    )
            self.tag_raise(self._pageTop1Border)
            self.tag_raise(self._pageTop2Border)
        if self._pending.has_key('size') or oldTabBottom != self.tabBottom:
            self.coords(self._pageLeftBorder,
                canvasBorder, self.tabBottom,
                borderWidth + canvasBorder,
                    self.tabBottom + borderWidth,
                borderWidth + canvasBorder,
                    hullHeight - canvasBorder - borderWidth,
                canvasBorder, hullHeight - canvasBorder,
                )
            self.coords(self._pageBottomRightBorder,
                hullWidth - canvasBorder, self.tabBottom,
                hullWidth - canvasBorder, hullHeight - canvasBorder,
                canvasBorder, hullHeight - canvasBorder,
                borderWidth + canvasBorder,
                    hullHeight - canvasBorder - borderWidth,
                hullWidth - canvasBorder - borderWidth,
                    hullHeight - canvasBorder - borderWidth,
                hullWidth - canvasBorder - borderWidth,
                    self.tabBottom + borderWidth,
                )
            if not self._withTabs:
                self.coords(self._pageTopBorder,
                    canvasBorder, self.tabBottom,
                    hullWidth - canvasBorder, self.tabBottom,
                    hullWidth - canvasBorder - borderWidth,
                        self.tabBottom + borderWidth,
                    borderWidth + canvasBorder, self.tabBottom + borderWidth,
                    )
        if self._pending.has_key('borderColor'):
            self.itemconfigure('lighttag', fill = self._lightBorderColor)
            self.itemconfigure('darktag', fill = self._darkBorderColor)
        newTopPage = self._pending.get('topPage')
        pageBorder = borderWidth + self._pageMargin
        if newTopPage is not None:
            self._topPageName = newTopPage
            self._topPageItem = self.create_window(
                pageBorder + canvasBorder, self.tabBottom + pageBorder,
                window = self._pageAttrs[newTopPage]['page'],
                anchor = 'nw',
                )
        if self._topPageName is not None and oldTabBottom != self.tabBottom:
            self.coords(self._topPageItem,
                    pageBorder + canvasBorder, self.tabBottom + pageBorder)
        if (newTopPage is not None or \
                self._pending.has_key('size') and self._topPageName is not None
                or oldTabBottom != self.tabBottom):
            self.itemconfigure(self._topPageItem,
                width = hullWidth - 2 * canvasBorder - pageBorder * 2,
                height = hullHeight - 2 * canvasBorder - pageBorder * 2 -
                    (self.tabBottom - canvasBorder),
                )
        self._pending = {}
forwardmethods(NoteBook, Tkinter.Canvas, '_hull')
import types
import Tkinter
class OptionMenu(MegaWidget):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('command',        None,       None),
            ('items',          (),         INITOPT),
            ('initialitem',    None,       INITOPT),
	    ('labelmargin',    0,          INITOPT),
	    ('labelpos',       None,       INITOPT),
	    ('sticky',         'ew',       INITOPT),
	)
	self.defineoptions(kw, optiondefs)
	MegaWidget.__init__(self, parent)
	interior = self.interior()
	self._menubutton = self.createcomponent('menubutton',
		(), None,
		Tkinter.Menubutton, (interior,),
		borderwidth = 2,
		indicatoron = 1,
		relief = 'raised',
		anchor = 'c',
		highlightthickness = 2,
		direction = 'flush',
                takefocus = 1,
	)
	self._menubutton.grid(column = 2, row = 2, sticky = self['sticky'])
	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)
        self.createlabel(interior)
	self._itemList = []
        self.setitems(self['items'], self['initialitem'])
	self.initialiseoptions()
    def setitems(self, items, index = None):

        for oldIndex in range(len(self._itemList)):
            tclCommandName = str(self._menu.entrycget(oldIndex, 'command'))
            if tclCommandName != '':
                self._menu.deletecommand(tclCommandName)
        self._menu.delete(0, 'end')
	self._itemList = list(items)
        for item in items:
            self._menu.add_command(label = item,
		command = lambda self = self, item = item: self._invoke(item))
	if index is None:
            var = str(self._menubutton.cget('textvariable'))
	    if var != '':
		return
	    if len(items) == 0:
		text = ''
	    elif str(self._menubutton.cget('text')) in items:
		return
	    else:
		text = items[0]
	else:
	    index = self.index(index)
	    text = self._itemList[index]
        self.setvalue(text)
    def getcurselection(self):

	var = str(self._menubutton.cget('textvariable'))
	if var == '':
	    return str(self._menubutton.cget('text'))
	else:
	    return self._menu.tk.globalgetvar(var)
    def getvalue(self):

        return self.getcurselection()
    def setvalue(self, text):

	var = str(self._menubutton.cget('textvariable'))
	if var == '':
	    self._menubutton.configure(text = text)
	else:
	    self._menu.tk.globalsetvar(var, text)
    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 END:
	    if listLength > 0:
		return listLength - 1
	    else:
		raise ValueError, 'OptionMenu has no items'
	else:
	    if index is SELECT:
		if listLength > 0:
		    index = self.getcurselection()
		else:
		    raise ValueError, 'OptionMenu has no items'
            if index in self._itemList:
                return self._itemList.index(index)
	    raise ValueError, \
		    'bad index "%s": must be a ' \
                    'name, a number, END or SELECT' % (index,)
    def invoke(self, index = SELECT):

	index = self.index(index)
	text = self._itemList[index]
        return self._invoke(text)
    def _invoke(self, text):

        self.setvalue(text)
	command = self['command']
	if callable(command):
	    return command(text)
import string
import sys
import types
import Tkinter
class PanedWidget(MegaWidget):


    def __init__(self, parent = None, **kw):

	optiondefs = (
            ('command',            None,         None),
            ('orient',             'vertical',   INITOPT),
            ('separatorrelief',    'sunken',     INITOPT),
            ('separatorthickness', 2,            INITOPT),
            ('handlesize',         8,            INITOPT),
            ('hull_width',         400,          None),
            ('hull_height',        400,          None),
	)
	self.defineoptions(kw, optiondefs,
                dynamicGroups = ('Frame', 'Separator', 'Handle'))
	MegaWidget.__init__(self, parent)
	self.bind('<Configure>', self._handleConfigure)
	if self['orient'] not in ('horizontal', 'vertical'):
	    raise ValueError, 'bad orient option ' + repr(self['orient']) + \
		': must be either \'horizontal\' or \'vertical\''
        self._separatorThickness = self['separatorthickness']
        self._handleSize = self['handlesize']
	self._paneNames = []
	self._paneAttrs = {}
	self._timerId = None
	self._frame = {}
	self._separator = []
	self._button = []
	self._totalSize = 0
	self._movePending = 0
	self._relsize = {}
	self._relmin = {}
	self._relmax = {}
	self._size = {}
	self._min = {}
	self._max = {}
	self._rootp = None
	self._curSize = None
	self._beforeLimit = None
	self._afterLimit = None
	self._buttonIsDown = 0
	self._majorSize = 100
	self._minorSize = 100
	self.initialiseoptions()
    def insert(self, name, before = 0, **kw):

        self._initPaneOptions(name)
	self._parsePaneOptions(name, kw)
	insertPos = self._nameToIndex(before)
	atEnd = (insertPos == len(self._paneNames))
	self._paneNames[insertPos:insertPos] = [name]
	self._frame[name] = self.createcomponent(name,
		(), 'Frame',
		Tkinter.Frame, (self.interior(),))
	if len(self._paneNames) > 1:
	    self._addSeparator()
	else:
	    self._separator.append(None)
	    self._button.append(None)
	if atEnd:
	    size = self._size[name]
	    if size > 0 or self._relsize[name] is not None:
		if self['orient'] == 'vertical':
		    self._frame[name].place(x=0, relwidth=1,
					    height=size, y=self._totalSize)
		else:
		    self._frame[name].place(y=0, relheight=1,
					    width=size, x=self._totalSize)
	    else:
		if self['orient'] == 'vertical':
		    self._frame[name].place(x=0, relwidth=1,
					    y=self._totalSize)
		else:
		    self._frame[name].place(y=0, relheight=1,
					    x=self._totalSize)
	else:
	    self._updateSizes()
	self._totalSize = self._totalSize + self._size[name]
	return self._frame[name]
    def add(self, name, **kw):

        return apply(self.insert, (name, len(self._paneNames)), kw)
    def delete(self, name):

	deletePos = self._nameToIndex(name)
	name = self._paneNames[deletePos]
	self.destroycomponent(name)
	del self._paneNames[deletePos]
	del self._frame[name]
	del self._size[name]
	del self._min[name]
	del self._max[name]
	del self._relsize[name]
	del self._relmin[name]
	del self._relmax[name]
	last = len(self._paneNames)
	del self._separator[last]
	del self._button[last]
        if last > 0:
            self.destroycomponent(self._sepName(last))
            self.destroycomponent(self._buttonName(last))
	self._plotHandles()
    def setnaturalsize(self):

        self.update_idletasks()
        totalWidth = 0
        totalHeight = 0
        maxWidth = 0
        maxHeight = 0
	for name in self._paneNames:
            frame = self._frame[name]
            w = frame.winfo_reqwidth()
            h = frame.winfo_reqheight()
            totalWidth = totalWidth + w
            totalHeight = totalHeight + h
            if maxWidth < w:
                maxWidth = w
            if maxHeight < h:
                maxHeight = h
        bw = string.atoi(str(self.cget('hull_borderwidth')))
        hl = string.atoi(str(self.cget('hull_highlightthickness')))
        extra = (bw + hl) * 2
        if str(self.cget('orient')) == 'horizontal':
            totalWidth = totalWidth + extra
            maxHeight = maxHeight + extra
            self.configure(hull_width = totalWidth, hull_height = maxHeight)
        else:
            totalHeight = (totalHeight + extra +
                    (len(self._paneNames) - 1) * self._separatorThickness)
            maxWidth = maxWidth + extra
            self.configure(hull_width = maxWidth, hull_height = totalHeight)
    def move(self, name, newPos, newPosOffset = 0):

        numPanes = len(self._paneNames)
        if numPanes < 2:
            return
        newPos = self._nameToIndex(newPos) + newPosOffset
        if newPos < 0 or newPos >=numPanes:
            return
        deletePos = self._nameToIndex(name)
        if deletePos == newPos:
            return
        name = self._paneNames[deletePos]
        del self._paneNames[deletePos]
        self._paneNames[newPos:newPos] = [name]
        self._plotHandles()
        self._updateSizes()
    def _nameToIndex(self, nameOrIndex):

	try:
	    pos = self._paneNames.index(nameOrIndex)
	except ValueError:
	    pos = nameOrIndex
	return pos
    def _initPaneOptions(self, name):

	self._size[name] = 0
	self._relsize[name] = None
	self._min[name] = 0
	self._relmin[name] = None
	self._max[name] = 100000
	self._relmax[name] = None
    def _parsePaneOptions(self, name, args):

	for arg, value in args.items():
	    if type(value) == types.FloatType:
		relvalue = value
		value = self._absSize(relvalue)
	    else:
		relvalue = None
	    if arg == 'size':
		self._size[name], self._relsize[name] = value, relvalue
	    elif arg == 'min':
		self._min[name], self._relmin[name] = value, relvalue
	    elif arg == 'max':
		self._max[name], self._relmax[name] = value, relvalue
	    else:
		raise ValueError, 'keyword must be "size", "min", or "max"'
    def _absSize(self, relvalue):

	return int(round(relvalue * self._majorSize))
    def _sepName(self, n):

	return 'separator-%d' % n
    def _buttonName(self, n):

	return 'handle-%d' % n
    def _addSeparator(self):

	n = len(self._paneNames) - 1
	downFunc = lambda event, s = self, num=n: s._btnDown(event, num)
	upFunc = lambda event, s = self, num=n: s._btnUp(event, num)
	moveFunc = lambda event, s = self, num=n: s._btnMove(event, num)
	sep = self.createcomponent(self._sepName(n),
		(), 'Separator',
		Tkinter.Frame, (self.interior(),),
		borderwidth = 1,
		relief = self['separatorrelief'])
	self._separator.append(sep)
	sep.bind('<ButtonPress-1>', downFunc)
	sep.bind('<Any-ButtonRelease-1>', upFunc)
	sep.bind('<B1-Motion>', moveFunc)
	if self['orient'] == 'vertical':
	    cursor = 'sb_v_double_arrow'
	    sep.configure(height = self._separatorThickness,
                    width = 10000, cursor = cursor)
	else:
	    cursor = 'sb_h_double_arrow'
	    sep.configure(width = self._separatorThickness,
                    height = 10000, cursor = cursor)
	self._totalSize = self._totalSize + self._separatorThickness
	handle = self.createcomponent(self._buttonName(n),
		(), 'Handle',
		Tkinter.Frame, (self.interior(),),
		    relief = 'raised',
		    borderwidth = 1,
		    width = self._handleSize,
		    height = self._handleSize,
		    cursor = cursor,
		)
	self._button.append(handle)
	handle.bind('<ButtonPress-1>', downFunc)
	handle.bind('<Any-ButtonRelease-1>', upFunc)
	handle.bind('<B1-Motion>', moveFunc)
	self._plotHandles()
	for i in range(1, len(self._paneNames)):
	    self._separator[i].tkraise()
	for i in range(1, len(self._paneNames)):
	    self._button[i].tkraise()
    def _btnUp(self, event, item):

	self._buttonIsDown = 0
	self._updateSizes()
	try:
	    self._button[item].configure(relief='raised')
	except:
	    pass
    def _btnDown(self, event, item):

	self._button[item].configure(relief='sunken')
	self._getMotionLimit(item)
	self._buttonIsDown = 1
	self._movePending = 0
    def _handleConfigure(self, event = None):

	self._getNaturalSizes()
	if self._totalSize == 0:
	    return
	iterRange = list(self._paneNames)
	iterRange.reverse()
	if self._majorSize > self._totalSize:
	    n = self._majorSize - self._totalSize
	    self._iterate(iterRange, self._grow, n)
	elif self._majorSize < self._totalSize:
	    n = self._totalSize - self._majorSize
	    self._iterate(iterRange, self._shrink, n)
	self._plotHandles()
	self._updateSizes()
    def _getNaturalSizes(self):

	self.update_idletasks()
	self._totalSize = 0
	if self['orient'] == 'vertical':
	    self._majorSize = self.winfo_height()
	    self._minorSize = self.winfo_width()
	    majorspec = Tkinter.Frame.winfo_reqheight
	else:
	    self._majorSize = self.winfo_width()
	    self._minorSize = self.winfo_height()
	    majorspec = Tkinter.Frame.winfo_reqwidth
        bw = string.atoi(str(self.cget('hull_borderwidth')))
        hl = string.atoi(str(self.cget('hull_highlightthickness')))
        extra = (bw + hl) * 2
        self._majorSize = self._majorSize - extra
        self._minorSize = self._minorSize - extra
	if self._majorSize < 0:
	    self._majorSize = 0
	if self._minorSize < 0:
	    self._minorSize = 0
	for name in self._paneNames:
	    if self._relsize[name] is None:
		if self._size[name] == 0:
		    self._size[name] = apply(majorspec, (self._frame[name],))
		    self._setrel(name)
	    else:
		self._size[name] = self._absSize(self._relsize[name])
	    if self._relmin[name] is not None:
		self._min[name] = self._absSize(self._relmin[name])
	    if self._relmax[name] is not None:
		self._max[name] = self._absSize(self._relmax[name])
	    if self._size[name] < self._min[name]:
		self._size[name] = self._min[name]
		self._setrel(name)
	    if self._size[name] > self._max[name]:
		self._size[name] = self._max[name]
		self._setrel(name)
	    self._totalSize = self._totalSize + self._size[name]
	self._totalSize = (self._totalSize +
                (len(self._paneNames) - 1) * self._separatorThickness)
    def _setrel(self, name):

	if self._relsize[name] is not None:
	    if self._majorSize != 0:
		self._relsize[name] = round(self._size[name]) / self._majorSize
    def _iterate(self, names, proc, n):

	for i in names:
	    n = apply(proc, (i, n))
	    if n == 0:
		break
    def _grow(self, name, n):

	canGrow = self._max[name] - self._size[name]
	if canGrow > n:
	    self._size[name] = self._size[name] + n
	    self._setrel(name)
	    return 0
	elif canGrow > 0:
	    self._size[name] = self._max[name]
	    self._setrel(name)
	    n = n - canGrow
	return n
    def _shrink(self, name, n):

	canShrink = self._size[name] - self._min[name]
	if canShrink > n:
	    self._size[name] = self._size[name] - n
	    self._setrel(name)
	    return 0
	elif canShrink > 0:
	    self._size[name] = self._min[name]
	    self._setrel(name)
	    n = n - canShrink
	return n
    def _updateSizes(self):

	totalSize = 0
	for name in self._paneNames:
	    size = self._size[name]
	    if self['orient'] == 'vertical':
		self._frame[name].place(x = 0, relwidth = 1,
					y = totalSize,
					height = size)
	    else:
		self._frame[name].place(y = 0, relheight = 1,
					x = totalSize,
					width = size)
	    totalSize = totalSize + size + self._separatorThickness
	cmd = self['command']
	if callable(cmd):
	    cmd(map(lambda x, s = self: s._size[x], self._paneNames))
    def _plotHandles(self):

	if len(self._paneNames) == 0:
	    return
	if self['orient'] == 'vertical':
	    btnp = self._minorSize - 13
	else:
	    h = self._minorSize
	    if h > 18:
		btnp = 9
	    else:
		btnp = h - 9
	firstPane = self._paneNames[0]
	totalSize = self._size[firstPane]
	first = 1
	last = len(self._paneNames) - 1
	for i in range(1, last + 1):
	    handlepos = totalSize - 3
	    prevSize = self._size[self._paneNames[i - 1]]
	    nextSize = self._size[self._paneNames[i]]
	    offset1 = 0
	    if i == first:
		if prevSize < 4:
		    offset1 = 4 - prevSize
	    else:
		if prevSize < 8:
		    offset1 = (8 - prevSize) / 2
	    offset2 = 0
	    if i == last:
		if nextSize < 4:
		    offset2 = nextSize - 4
	    else:
		if nextSize < 8:
		    offset2 = (nextSize - 8) / 2
	    handlepos = handlepos + offset1
	    if self['orient'] == 'vertical':
		height = 8 - offset1 + offset2
		if height > 1:
		    self._button[i].configure(height = height)
		    self._button[i].place(x = btnp, y = handlepos)
		else:
		    self._button[i].place_forget()
		self._separator[i].place(x = 0, y = totalSize,
					 relwidth = 1)
	    else:
		width = 8 - offset1 + offset2
		if width > 1:
		    self._button[i].configure(width = width)
		    self._button[i].place(y = btnp, x = handlepos)
		else:
		    self._button[i].place_forget()
		self._separator[i].place(y = 0, x = totalSize,
					 relheight = 1)
	    totalSize = totalSize + nextSize + self._separatorThickness
    def pane(self, name):

	return self._frame[self._paneNames[self._nameToIndex(name)]]
    def panes(self):

	return list(self._paneNames)
    def configurepane(self, name, **kw):

	name = self._paneNames[self._nameToIndex(name)]
	self._parsePaneOptions(name, kw)
	self._handleConfigure()
    def updatelayout(self):

	self._handleConfigure()
    def _getMotionLimit(self, item):

	curBefore = (item - 1) * self._separatorThickness
	minBefore, maxBefore = curBefore, curBefore
	for name in self._paneNames[:item]:
	    curBefore = curBefore + self._size[name]
	    minBefore = minBefore + self._min[name]
	    maxBefore = maxBefore + self._max[name]
	curAfter = (len(self._paneNames) - item) * self._separatorThickness
	minAfter, maxAfter = curAfter, curAfter
	for name in self._paneNames[item:]:
	    curAfter = curAfter + self._size[name]
	    minAfter = minAfter + self._min[name]
	    maxAfter = maxAfter + self._max[name]
	beforeToGo = min(curBefore - minBefore, maxAfter - curAfter)
	afterToGo = min(curAfter - minAfter, maxBefore - curBefore)
	self._beforeLimit = curBefore - beforeToGo
	self._afterLimit = curBefore + afterToGo
	self._curSize = curBefore
	self._plotHandles()
    def _btnMove(self, event, item):

	self._rootp = event
	if self._movePending == 0:
	    self._timerId = self.after_idle(
		    lambda s = self, i = item: s._btnMoveCompressed(i))
	    self._movePending = 1
    def destroy(self):

        if self._timerId is not None:
          self.after_cancel(self._timerId)
	  self._timerId = None
        MegaWidget.destroy(self)
    def _btnMoveCompressed(self, item):

	if not self._buttonIsDown:
	    return
	if self['orient'] == 'vertical':
	    p = self._rootp.y_root - self.winfo_rooty()
	else:
	    p = self._rootp.x_root - self.winfo_rootx()
	if p == self._curSize:
	    self._movePending = 0
	    return
	if p < self._beforeLimit:
	    p = self._beforeLimit
	if p >= self._afterLimit:
	    p = self._afterLimit
	self._calculateChange(item, p)
	self.update_idletasks()
	self._movePending = 0
    def _calculateChange(self, item, p):

	if p < self._curSize:
	    self._moveBefore(item, p)
	elif p > self._curSize:
	    self._moveAfter(item, p)
	self._plotHandles()
    def _moveBefore(self, item, p):

	n = self._curSize - p
	iterRange = list(self._paneNames[:item])
	iterRange.reverse()
	self._iterate(iterRange, self._shrink, n)
	iterRange = self._paneNames[item:]
	self._iterate(iterRange, self._grow, n)
	self._curSize = p
    def _moveAfter(self, item, p):

	n = p - self._curSize
	iterRange = self._paneNames[item:]
	self._iterate(iterRange, self._shrink, n)
	iterRange = list(self._paneNames[:item])
	iterRange.reverse()
	self._iterate(iterRange, self._grow, n)
	self._curSize = p
class PromptDialog(Dialog):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('borderx',     20,    INITOPT),
	    ('bordery',     20,    INITOPT),
	)
	self.defineoptions(kw, optiondefs)
	Dialog.__init__(self, parent)
	interior = self.interior()
	aliases = (
	    ('entry', 'entryfield_entry'),
	    ('label', 'entryfield_label'),
	)
	self._promptDialogEntry = self.createcomponent('entryfield',
		aliases, None,
		EntryField, (interior,))
	self._promptDialogEntry.pack(fill='x', expand=1,
		padx = self['borderx'], pady = self['bordery'])
        if not kw.has_key('activatecommand'):
            tkentry = self.component('entry')
            self.configure(activatecommand = tkentry.focus_set)
	self.initialiseoptions()
    def insertentry(self, index, text):

	self._promptDialogEntry.insert(index, text)
    def deleteentry(self, first, last=None):

	self._promptDialogEntry.delete(first, last)
    def indexentry(self, index):

	return self._promptDialogEntry.index(index)
forwardmethods(PromptDialog, EntryField, '_promptDialogEntry')
import types
import Tkinter
class RadioSelect(MegaWidget):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('buttontype',    'button',      INITOPT),
	    ('command',       None,          None),
	    ('labelmargin',   0,             INITOPT),
	    ('labelpos',      None,          INITOPT),
	    ('orient',       'horizontal',   INITOPT),
	    ('padx',          5,             INITOPT),
	    ('pady',          5,             INITOPT),
	    ('selectmode',    'single',      INITOPT),
	)
	self.defineoptions(kw, optiondefs, dynamicGroups = ('Button',))
	MegaWidget.__init__(self, parent)
	interior = self.interior()
	if self['labelpos'] is None:
	    self._radioSelectFrame = self._hull
	else:
	    self._radioSelectFrame = self.createcomponent('frame',
		    (), None,
		    Tkinter.Frame, (interior,))
	    self._radioSelectFrame.grid(column=2, row=2, sticky='nsew')
	    interior.grid_columnconfigure(2, weight=1)
	    interior.grid_rowconfigure(2, weight=1)
	    self.createlabel(interior)
	self._buttonList = []
	if self['selectmode'] == 'single':
	    self._singleSelect = 1
	elif self['selectmode'] == 'multiple':
	    self._singleSelect = 0
	else:
	    raise ValueError, 'bad selectmode option "' + \
		    self['selectmode'] + '": should be single or multiple'
	if self['buttontype'] == 'button':
	    self.buttonClass = Tkinter.Button
	elif self['buttontype'] == 'radiobutton':
	    self._singleSelect = 1
	    self.var = Tkinter.StringVar()
	    self.buttonClass = Tkinter.Radiobutton
	elif self['buttontype'] == 'checkbutton':
	    self._singleSelect = 0
	    self.buttonClass = Tkinter.Checkbutton
	else:
	    raise ValueError, 'bad buttontype option "' + \
		    self['buttontype'] + \
		    '": should be button, radiobutton or checkbutton'
	if self._singleSelect:
	    self.selection = None
	else:
	    self.selection = []
	if self['orient'] not in ('horizontal', 'vertical'):
	    raise ValueError, 'bad orient option ' + repr(self['orient']) + \
		': must be either \'horizontal\' or \'vertical\''
	self.initialiseoptions()
    def getcurselection(self):

	if self._singleSelect:
            return self.selection
        else:
            return tuple(self.selection)
    def getvalue(self):

        return self.getcurselection()
    def setvalue(self, textOrList):

	if self._singleSelect:
            self.__setSingleValue(textOrList)
        else:
            oldselection = self.selection
            self.selection = textOrList
            for button in self._buttonList:
                if button in oldselection:
                    if button not in self.selection:
                        widget = self.component(button)
                        if self['buttontype'] == 'checkbutton':
                            widget.deselect()
                        else:
                            widget.configure(relief='raised')
                else:
                    if button in self.selection:
                        widget = self.component(button)
                        if self['buttontype'] == 'checkbutton':
                            widget.select()
                        else:
                            widget.configure(relief='sunken')
    def numbuttons(self):

        return len(self._buttonList)
    def index(self, index):

	listLength = len(self._buttonList)
	if type(index) == types.IntType:
	    if index < listLength:
		return index
	    else:
		raise ValueError, 'index "%s" is out of range' % index
	elif index is END:
	    if listLength > 0:
		return listLength - 1
	    else:
		raise ValueError, 'RadioSelect has no buttons'
	else:
	    for count in range(listLength):
		name = self._buttonList[count]
		if index == name:
		    return count
	    validValues = 'a name, a number or END'
	    raise ValueError, \
		    'bad index "%s": must be %s' % (index, validValues)
    def button(self, buttonIndex):

	name = self._buttonList[self.index(buttonIndex)]
        return self.component(name)
    def add(self, componentName, **kw):

	if componentName in self._buttonList:
	    raise ValueError, 'button "%s" already exists' % componentName
	kw['command'] = \
                lambda self=self, name=componentName: self.invoke(name)
	if not kw.has_key('text'):
	    kw['text'] = componentName
	if self['buttontype'] == 'radiobutton':
	    if not kw.has_key('anchor'):
		kw['anchor'] = 'w'
	    if not kw.has_key('variable'):
		kw['variable'] = self.var
	    if not kw.has_key('value'):
		kw['value'] = kw['text']
	elif self['buttontype'] == 'checkbutton':
	    if not kw.has_key('anchor'):
		kw['anchor'] = 'w'
	button = apply(self.createcomponent, (componentName,
		(), 'Button',
		self.buttonClass, (self._radioSelectFrame,)), kw)
	if self['orient'] == 'horizontal':
	    self._radioSelectFrame.grid_rowconfigure(0, weight=1)
	    col = len(self._buttonList)
	    button.grid(column=col, row=0, padx = self['padx'],
		    pady = self['pady'], sticky='nsew')
	    self._radioSelectFrame.grid_columnconfigure(col, weight=1)
	else:
	    self._radioSelectFrame.grid_columnconfigure(0, weight=1)
	    row = len(self._buttonList)
	    button.grid(column=0, row=row, padx = self['padx'],
		    pady = self['pady'], sticky='ew')
	    self._radioSelectFrame.grid_rowconfigure(row, weight=1)
	self._buttonList.append(componentName)
	return button
    def deleteall(self):

	for name in self._buttonList:
	    self.destroycomponent(name)
	self._buttonList = []
	if self._singleSelect:
	    self.selection = None
	else:
	    self.selection = []
    def __setSingleValue(self, value):

            self.selection = value
            if self['buttontype'] == 'radiobutton':
                widget = self.component(value)
                widget.select()
            else:
                for button in self._buttonList:
                    widget = self.component(button)
                    if button == value:
                        widget.configure(relief='sunken')
                    else:
                        widget.configure(relief='raised')
    def invoke(self, index):

	index = self.index(index)
	name = self._buttonList[index]
	if self._singleSelect:
            self.__setSingleValue(name)
	    command = self['command']
	    if callable(command):
		return command(name)
        else:
	    widget = self.component(name)
	    if name in self.selection:
		if self['buttontype'] == 'checkbutton':
		    widget.deselect()
		else:
		    widget.configure(relief='raised')
		self.selection.remove(name)
		state = 0
	    else:
		if self['buttontype'] == 'checkbutton':
		    widget.select()
		else:
		    widget.configure(relief='sunken')
		self.selection.append(name)
		state = 1
	    command = self['command']
	    if callable(command):
	      return command(name, state)
import Tkinter
class ScrolledCanvas(MegaWidget):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('borderframe',    0,            INITOPT),
	    ('canvasmargin',   0,            INITOPT),
	    ('hscrollmode',    'dynamic',    self._hscrollMode),
	    ('labelmargin',    0,            INITOPT),
	    ('labelpos',       None,         INITOPT),
	    ('scrollmargin',   2,            INITOPT),
	    ('usehullsize',    0,            INITOPT),
	    ('vscrollmode',    'dynamic',    self._vscrollMode),
	)
	self.defineoptions(kw, optiondefs)
	MegaWidget.__init__(self, parent)
	self.origInterior = MegaWidget.interior(self)
	if self['usehullsize']:
	    self.origInterior.grid_propagate(0)
	if self['borderframe']:
	    self._borderframe = self.createcomponent('borderframe',
		    (), None,
		    Tkinter.Frame, (self.origInterior,),
		    relief = 'sunken',
		    borderwidth = 2,
	    )
	    self._borderframe.grid(row = 2, column = 2, sticky = 'news')
	    self._canvas = self.createcomponent('canvas',
		    (), None,
		    Tkinter.Canvas, (self._borderframe,),
		    highlightthickness = 0,
		    borderwidth = 0,
	    )
	    self._canvas.pack(fill = 'both', expand = 1)
	else:
	    self._canvas = self.createcomponent('canvas',
		    (), None,
		    Tkinter.Canvas, (self.origInterior,),
		    relief = 'sunken',
		    borderwidth = 2,
	    )
	    self._canvas.grid(row = 2, column = 2, sticky = 'news')
	self.origInterior.grid_rowconfigure(2, weight = 1, minsize = 0)
	self.origInterior.grid_columnconfigure(2, weight = 1, minsize = 0)
	self._horizScrollbar = self.createcomponent('horizscrollbar',
		(), 'Scrollbar',
		Tkinter.Scrollbar, (self.origInterior,),
	        orient='horizontal',
		command=self._canvas.xview
	)
	self._vertScrollbar = self.createcomponent('vertscrollbar',
		(), 'Scrollbar',
		Tkinter.Scrollbar, (self.origInterior,),
		orient='vertical',
		command=self._canvas.yview
	)
	self.createlabel(self.origInterior, childCols = 3, childRows = 3)
	self._horizScrollbarOn = 0
	self._vertScrollbarOn = 0
	self.scrollTimer = None
        self._scrollRecurse = 0
	self._horizScrollbarNeeded = 0
	self._vertScrollbarNeeded = 0
	self.setregionTimer = None
	self.initialiseoptions()
    def destroy(self):

	if self.scrollTimer is not None:
	    self.after_cancel(self.scrollTimer)
	    self.scrollTimer = None
	if self.setregionTimer is not None:
	    self.after_cancel(self.setregionTimer)
	    self.setregionTimer = None
	MegaWidget.destroy(self)
    def interior(self):

	return self._canvas
    def resizescrollregion(self):

	if self.setregionTimer is None:
	    self.setregionTimer = self.after_idle(self._setRegion)
    def _hscrollMode(self):

	mode = self['hscrollmode']
	if mode == 'static':
	    if not self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	elif mode == 'dynamic':
	    if self._horizScrollbarNeeded != self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	elif mode == 'none':
	    if self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	else:
	    message = 'bad hscrollmode option "%s": should be static, dynamic, or none' % mode
	    raise ValueError, message
        self._configureScrollCommands()
    def _vscrollMode(self):

	mode = self['vscrollmode']
	if mode == 'static':
	    if not self._vertScrollbarOn:
		self._toggleVertScrollbar()
	elif mode == 'dynamic':
	    if self._vertScrollbarNeeded != self._vertScrollbarOn:
		self._toggleVertScrollbar()
	elif mode == 'none':
	    if self._vertScrollbarOn:
		self._toggleVertScrollbar()
	else:
	    message = 'bad vscrollmode option "%s": should be static, dynamic, or none' % mode
	    raise ValueError, message
        self._configureScrollCommands()
    def _configureScrollCommands(self):

        tclCommandName = str(self._canvas.cget('xscrollcommand'))
        if tclCommandName != '':
            self._canvas.deletecommand(tclCommandName)
        tclCommandName = str(self._canvas.cget('yscrollcommand'))
        if tclCommandName != '':
            self._canvas.deletecommand(tclCommandName)
	if self['hscrollmode'] == self['vscrollmode'] == 'dynamic':
            self._canvas.configure(
                    xscrollcommand=self._scrollBothLater,
                    yscrollcommand=self._scrollBothLater
            )
        else:
            self._canvas.configure(
                    xscrollcommand=self._scrollXNow,
                    yscrollcommand=self._scrollYNow
            )
    def _scrollXNow(self, first, last):

        self._horizScrollbar.set(first, last)
        self._horizScrollbarNeeded = ((first, last) != ('0', '1'))
	if self['hscrollmode'] == 'dynamic':
	    if self._horizScrollbarNeeded != self._horizScrollbarOn:
		self._toggleHorizScrollbar()
    def _scrollYNow(self, first, last):

        self._vertScrollbar.set(first, last)
        self._vertScrollbarNeeded = ((first, last) != ('0', '1'))
        if self['vscrollmode'] == 'dynamic':
            if self._vertScrollbarNeeded != self._vertScrollbarOn:
                self._toggleVertScrollbar()
    def _scrollBothLater(self, first, last):

	if self.scrollTimer is None:
	    self.scrollTimer = self.after_idle(self._scrollBothNow)
    def _scrollBothNow(self):

	self.scrollTimer = None
        self._scrollRecurse = self._scrollRecurse + 1
        self.update_idletasks()
        self._scrollRecurse = self._scrollRecurse - 1
        if self._scrollRecurse != 0:
            return
	xview = self._canvas.xview()
	yview = self._canvas.yview()
	self._horizScrollbar.set(xview[0], xview[1])
	self._vertScrollbar.set(yview[0], yview[1])
	self._horizScrollbarNeeded = (xview != (0.0, 1.0))
	self._vertScrollbarNeeded = (yview != (0.0, 1.0))
	if (self['hscrollmode'] == self['vscrollmode'] == 'dynamic' and
		self._horizScrollbarNeeded != self._horizScrollbarOn and
		self._vertScrollbarNeeded != self._vertScrollbarOn and
		self._vertScrollbarOn != self._horizScrollbarOn):
	    if self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	    else:
		self._toggleVertScrollbar()
	    return
	if self['hscrollmode'] == 'dynamic':
	    if self._horizScrollbarNeeded != self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	if self['vscrollmode'] == 'dynamic':
	    if self._vertScrollbarNeeded != self._vertScrollbarOn:
		self._toggleVertScrollbar()
    def _toggleHorizScrollbar(self):

	self._horizScrollbarOn = not self._horizScrollbarOn
	interior = self.origInterior
	if self._horizScrollbarOn:
	    self._horizScrollbar.grid(row = 4, column = 2, sticky = 'news')
	    interior.grid_rowconfigure(3, minsize = self['scrollmargin'])
	else:
	    self._horizScrollbar.grid_forget()
	    interior.grid_rowconfigure(3, minsize = 0)
    def _toggleVertScrollbar(self):

	self._vertScrollbarOn = not self._vertScrollbarOn
	interior = self.origInterior
	if self._vertScrollbarOn:
	    self._vertScrollbar.grid(row = 2, column = 4, sticky = 'news')
	    interior.grid_columnconfigure(3, minsize = self['scrollmargin'])
	else:
	    self._vertScrollbar.grid_forget()
	    interior.grid_columnconfigure(3, minsize = 0)
    def _setRegion(self):

	self.setregionTimer = None
	region = self._canvas.bbox('all')
        if region is not None:
	    canvasmargin = self['canvasmargin']
	    region = (region[0] - canvasmargin, region[1] - canvasmargin,
		region[2] + canvasmargin, region[3] + canvasmargin)
	    self._canvas.configure(scrollregion = region)
    def bbox(self, *args):

	return apply(self._canvas.bbox, args)
forwardmethods(ScrolledCanvas, Tkinter.Canvas, '_canvas')
import Tkinter
class ScrolledField(MegaWidget):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('labelmargin',   0,      INITOPT),
	    ('labelpos',      None,   INITOPT),
	    ('sticky',        'ew',   INITOPT),
	    ('text',          '',     self._text),
	)
	self.defineoptions(kw, optiondefs)
	MegaWidget.__init__(self, parent)
	interior = self.interior()
	self._scrolledFieldEntry = self.createcomponent('entry',
		(), None,
		Tkinter.Entry, (interior,))
        try:
            self._scrolledFieldEntry.configure(state = 'readonly')
        except Tkinter.TclError:
            self._scrolledFieldEntry.configure(state = 'disabled')
	self._scrolledFieldEntry.grid(column=2, row=2, sticky=self['sticky'])
	interior.grid_columnconfigure(2, weight=1)
	interior.grid_rowconfigure(2, weight=1)
	self.createlabel(interior)
	self.initialiseoptions()
    def _text(self):

        text = self['text']
        self._scrolledFieldEntry.configure(state = 'normal')
        self._scrolledFieldEntry.delete(0, 'end')
        self._scrolledFieldEntry.insert('end', text)
        try:
            self._scrolledFieldEntry.configure(state = 'readonly')
        except Tkinter.TclError:
            self._scrolledFieldEntry.configure(state = 'disabled')
forwardmethods(ScrolledField, Tkinter.Entry, '_scrolledFieldEntry')
import string
import types
import Tkinter
class ScrolledFrame(MegaWidget):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('borderframe',    1,            INITOPT),
	    ('horizflex',      'fixed',      self._horizflex),
	    ('horizfraction',  0.05,         INITOPT),
	    ('hscrollmode',    'dynamic',    self._hscrollMode),
	    ('labelmargin',    0,            INITOPT),
	    ('labelpos',       None,         INITOPT),
	    ('scrollmargin',   2,            INITOPT),
	    ('usehullsize',    0,            INITOPT),
	    ('vertflex',       'fixed',      self._vertflex),
	    ('vertfraction',   0.05,         INITOPT),
	    ('vscrollmode',    'dynamic',    self._vscrollMode),
	)
	self.defineoptions(kw, optiondefs)
	MegaWidget.__init__(self, parent)
	self.origInterior = MegaWidget.interior(self)
	if self['usehullsize']:
	    self.origInterior.grid_propagate(0)
	if self['borderframe']:
	    self._borderframe = self.createcomponent('borderframe',
		    (), None,
		    Tkinter.Frame, (self.origInterior,),
		    relief = 'sunken',
		    borderwidth = 2,
	    )
	    self._borderframe.grid(row = 2, column = 2, sticky = 'news')
	    self._clipper = self.createcomponent('clipper',
		    (), None,
		    Tkinter.Frame, (self._borderframe,),
		    width = 400,
		    height = 300,
		    highlightthickness = 0,
		    borderwidth = 0,
	    )
	    self._clipper.pack(fill = 'both', expand = 1)
	else:
	    self._clipper = self.createcomponent('clipper',
		    (), None,
		    Tkinter.Frame, (self.origInterior,),
		    width = 400,
		    height = 300,
		    relief = 'sunken',
		    borderwidth = 2,
	    )
	    self._clipper.grid(row = 2, column = 2, sticky = 'news')
	self.origInterior.grid_rowconfigure(2, weight = 1, minsize = 0)
	self.origInterior.grid_columnconfigure(2, weight = 1, minsize = 0)
	self._horizScrollbar = self.createcomponent('horizscrollbar',
		(), 'Scrollbar',
		Tkinter.Scrollbar, (self.origInterior,),
	        orient='horizontal',
		command=self.xview
	)
	self._vertScrollbar = self.createcomponent('vertscrollbar',
		(), 'Scrollbar',
		Tkinter.Scrollbar, (self.origInterior,),
		orient='vertical',
		command=self.yview
	)
	self.createlabel(self.origInterior, childCols = 3, childRows = 3)
	self._horizScrollbarOn = 0
	self._vertScrollbarOn = 0
	self.scrollTimer = None
	self._scrollRecurse = 0
	self._horizScrollbarNeeded = 0
	self._vertScrollbarNeeded = 0
	self.startX = 0
	self.startY = 0
	self._flexoptions = ('fixed', 'expand', 'shrink', 'elastic')
	self._frame = self.createcomponent('frame',
		(), None,
		Tkinter.Frame, (self._clipper,)
	)
	self._frame.bind('<Configure>', self._reposition)
	self._clipper.bind('<Configure>', self._reposition)
        self._horizScrollbar.set(0.0, 1.0)
        self._vertScrollbar.set(0.0, 1.0)
	self.initialiseoptions()
    def destroy(self):

	if self.scrollTimer is not None:
	    self.after_cancel(self.scrollTimer)
	    self.scrollTimer = None
	MegaWidget.destroy(self)
    def interior(self):

	return self._frame
    def reposition(self):

	if self.scrollTimer is None:
	    self.scrollTimer = self.after_idle(self._scrollBothNow)
    def xview(self, mode = None, value = None, units = None):

        if type(value) == types.StringType:
            value = string.atof(value)
        if mode is None:
            return self._horizScrollbar.get()
	elif mode == 'moveto':
	    frameWidth = self._frame.winfo_reqwidth()
	    self.startX = value * float(frameWidth)
	else:
	    clipperWidth = self._clipper.winfo_width()
	    if units == 'units':
		jump = int(clipperWidth * self['horizfraction'])
	    else:
		jump = clipperWidth
            self.startX = self.startX + value * jump
	self.reposition()
    def yview(self, mode = None, value = None, units = None):

        if type(value) == types.StringType:
            value = string.atof(value)
        if mode is None:
            return self._vertScrollbar.get()
	elif mode == 'moveto':
	    frameHeight = self._frame.winfo_reqheight()
	    self.startY = value * float(frameHeight)
	else:
	    clipperHeight = self._clipper.winfo_height()
	    if units == 'units':
		jump = int(clipperHeight * self['vertfraction'])
	    else:
		jump = clipperHeight
            self.startY = self.startY + value * jump
	self.reposition()
    def _hscrollMode(self):

	mode = self['hscrollmode']
	if mode == 'static':
	    if not self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	elif mode == 'dynamic':
	    if self._horizScrollbarNeeded != self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	elif mode == 'none':
	    if self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	else:
	    message = 'bad hscrollmode option "%s": should be static, dynamic, or none' % mode
	    raise ValueError, message
    def _vscrollMode(self):

	mode = self['vscrollmode']
	if mode == 'static':
	    if not self._vertScrollbarOn:
		self._toggleVertScrollbar()
	elif mode == 'dynamic':
	    if self._vertScrollbarNeeded != self._vertScrollbarOn:
		self._toggleVertScrollbar()
	elif mode == 'none':
	    if self._vertScrollbarOn:
		self._toggleVertScrollbar()
	else:
	    message = 'bad vscrollmode option "%s": should be static, dynamic, or none' % mode
	    raise ValueError, message
    def _horizflex(self):

	flex = self['horizflex']
	if flex not in self._flexoptions:
	    message = 'bad horizflex option "%s": should be one of %s' % \
		    (flex, str(self._flexoptions))
	    raise ValueError, message
	self.reposition()
    def _vertflex(self):

	flex = self['vertflex']
	if flex not in self._flexoptions:
	    message = 'bad vertflex option "%s": should be one of %s' % \
		    (flex, str(self._flexoptions))
	    raise ValueError, message
	self.reposition()
    def _reposition(self, event):

	self.reposition()
    def _getxview(self):

	clipperWidth = self._clipper.winfo_width()
	frameWidth = self._frame.winfo_reqwidth()
	if frameWidth <= clipperWidth:
	    self.startX = 0
	    endScrollX = 1.0
	    if self['horizflex'] in ('expand', 'elastic'):
		relwidth = 1
	    else:
		relwidth = ''
	else:
	    if self['horizflex'] in ('shrink', 'elastic'):
		self.startX = 0
		endScrollX = 1.0
		relwidth = 1
	    else:
		if self.startX + clipperWidth > frameWidth:
		    self.startX = frameWidth - clipperWidth
		    endScrollX = 1.0
		else:
		    if self.startX < 0:
			self.startX = 0
		    endScrollX = (self.startX + clipperWidth) / float(frameWidth)
		relwidth = ''
	self._frame.place(x = -self.startX, relwidth = relwidth)
	return (self.startX / float(frameWidth), endScrollX)
    def _getyview(self):

	clipperHeight = self._clipper.winfo_height()
	frameHeight = self._frame.winfo_reqheight()
	if frameHeight <= clipperHeight:
	    self.startY = 0
	    endScrollY = 1.0
	    if self['vertflex'] in ('expand', 'elastic'):
		relheight = 1
	    else:
		relheight = ''
	else:
	    if self['vertflex'] in ('shrink', 'elastic'):
		self.startY = 0
		endScrollY = 1.0
		relheight = 1
	    else:
		if self.startY + clipperHeight > frameHeight:
		    self.startY = frameHeight - clipperHeight
		    endScrollY = 1.0
		else:
		    if self.startY < 0:
			self.startY = 0
		    endScrollY = (self.startY + clipperHeight) / float(frameHeight)
		relheight = ''
	self._frame.place(y = -self.startY, relheight = relheight)
	return (self.startY / float(frameHeight), endScrollY)
    def _scrollBothNow(self):

	self.scrollTimer = None
        self._scrollRecurse = self._scrollRecurse + 1
        self.update_idletasks()
        self._scrollRecurse = self._scrollRecurse - 1
        if self._scrollRecurse != 0:
            return
	xview = self._getxview()
	yview = self._getyview()
	self._horizScrollbar.set(xview[0], xview[1])
	self._vertScrollbar.set(yview[0], yview[1])
	self._horizScrollbarNeeded = (xview != (0.0, 1.0))
	self._vertScrollbarNeeded = (yview != (0.0, 1.0))
	if (self['hscrollmode'] == self['vscrollmode'] == 'dynamic' and
		self._horizScrollbarNeeded != self._horizScrollbarOn and
		self._vertScrollbarNeeded != self._vertScrollbarOn and
		self._vertScrollbarOn != self._horizScrollbarOn):
	    if self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	    else:
		self._toggleVertScrollbar()
	    return
	if self['hscrollmode'] == 'dynamic':
	    if self._horizScrollbarNeeded != self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	if self['vscrollmode'] == 'dynamic':
	    if self._vertScrollbarNeeded != self._vertScrollbarOn:
		self._toggleVertScrollbar()
    def _toggleHorizScrollbar(self):

	self._horizScrollbarOn = not self._horizScrollbarOn
	interior = self.origInterior
	if self._horizScrollbarOn:
	    self._horizScrollbar.grid(row = 4, column = 2, sticky = 'news')
	    interior.grid_rowconfigure(3, minsize = self['scrollmargin'])
	else:
	    self._horizScrollbar.grid_forget()
	    interior.grid_rowconfigure(3, minsize = 0)
    def _toggleVertScrollbar(self):

	self._vertScrollbarOn = not self._vertScrollbarOn
	interior = self.origInterior
	if self._vertScrollbarOn:
	    self._vertScrollbar.grid(row = 2, column = 4, sticky = 'news')
	    interior.grid_columnconfigure(3, minsize = self['scrollmargin'])
	else:
	    self._vertScrollbar.grid_forget()
	    interior.grid_columnconfigure(3, minsize = 0)
import types
import Tkinter
class ScrolledListBox(MegaWidget):


    _classBindingsDefinedFor = 0
    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('dblclickcommand',    None,            None),
	    ('hscrollmode',        'dynamic',       self._hscrollMode),
	    ('items',              (),              INITOPT),
	    ('labelmargin',        0,               INITOPT),
	    ('labelpos',           None,            INITOPT),
	    ('scrollmargin',       2,               INITOPT),
	    ('selectioncommand',   None,            None),
	    ('usehullsize',        0,               INITOPT),
	    ('vscrollmode',        'dynamic',       self._vscrollMode),
	)
	self.defineoptions(kw, optiondefs)
	MegaWidget.__init__(self, parent)
	interior = self.interior()
	if self['usehullsize']:
	    interior.grid_propagate(0)
	self._listbox = self.createcomponent('listbox',
		(), None,
		Tkinter.Listbox, (interior,))
	self._listbox.grid(row = 2, column = 2, sticky = 'news')
	interior.grid_rowconfigure(2, weight = 1, minsize = 0)
	interior.grid_columnconfigure(2, weight = 1, minsize = 0)
	self._horizScrollbar = self.createcomponent('horizscrollbar',
		(), 'Scrollbar',
		Tkinter.Scrollbar, (interior,),
	        orient='horizontal',
		command=self._listbox.xview
	)
	self._vertScrollbar = self.createcomponent('vertscrollbar',
		(), 'Scrollbar',
		Tkinter.Scrollbar, (interior,),
		orient='vertical',
		command=self._listbox.yview
	)
	self.createlabel(interior, childCols = 3, childRows = 3)
	items = self['items']
	if type(items) != types.TupleType:
	    items = tuple(items)
	if len(items) > 0:
	    apply(self._listbox.insert, ('end',) + items)
	_registerScrolledList(self._listbox, self)
        theTag = 'ScrolledListBoxTag'
        if ScrolledListBox._classBindingsDefinedFor != Tkinter._default_root:
            root  = Tkinter._default_root
            def doubleEvent(event):

                _handleEvent(event, 'double')
            def keyEvent(event):

                _handleEvent(event, 'key')
            def releaseEvent(event):

                _handleEvent(event, 'release')
            root.bind_class(theTag, '<Key-space>', keyEvent)
            root.bind_class(theTag, '<Key-Return>', keyEvent)
            root.bind_class(theTag, '<ButtonRelease-1>', releaseEvent)
            root.bind_class(theTag, '<Double-ButtonRelease-1>', doubleEvent)
	    ScrolledListBox._classBindingsDefinedFor = root
	bindtags = self._listbox.bindtags()
	self._listbox.bindtags(bindtags + (theTag,))
	self._horizScrollbarOn = 0
	self._vertScrollbarOn = 0
	self.scrollTimer = None
        self._scrollRecurse = 0
	self._horizScrollbarNeeded = 0
	self._vertScrollbarNeeded = 0
	self.initialiseoptions()
    def destroy(self):

	if self.scrollTimer is not None:
	    self.after_cancel(self.scrollTimer)
	    self.scrollTimer = None
	_deregisterScrolledList(self._listbox)
	MegaWidget.destroy(self)
    def clear(self):

	self.setlist(())
    def getcurselection(self):

	rtn = []
	for sel in self.curselection():
	    rtn.append(self._listbox.get(sel))
	return tuple(rtn)
    def getvalue(self):

        return self.getcurselection()
    def setvalue(self, textOrList):

        self._listbox.selection_clear(0, 'end')
        listitems = list(self._listbox.get(0, 'end'))
        if type(textOrList) == types.StringType:
            if textOrList in listitems:
                self._listbox.selection_set(listitems.index(textOrList))
            else:
                raise ValueError, 'no such item "%s"' % textOrList
        else:
            for item in textOrList:
                if item in listitems:
                    self._listbox.selection_set(listitems.index(item))
                else:
                    raise ValueError, 'no such item "%s"' % item
    def setlist(self, items):

        self._listbox.delete(0, 'end')
	if len(items) > 0:
	    if type(items) != types.TupleType:
		items = tuple(items)
	    apply(self._listbox.insert, (0,) + items)
    def get(self, first=None, last=None):

	if first is None:
	    return self._listbox.get(0, 'end')
	else:
	    return self._listbox.get(first, last)
    def _hscrollMode(self):

	mode = self['hscrollmode']
	if mode == 'static':
	    if not self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	elif mode == 'dynamic':
	    if self._horizScrollbarNeeded != self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	elif mode == 'none':
	    if self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	else:
	    message = 'bad hscrollmode option "%s": should be static, dynamic, or none' % mode
	    raise ValueError, message
        self._configureScrollCommands()
    def _vscrollMode(self):

	mode = self['vscrollmode']
	if mode == 'static':
	    if not self._vertScrollbarOn:
		self._toggleVertScrollbar()
	elif mode == 'dynamic':
	    if self._vertScrollbarNeeded != self._vertScrollbarOn:
		self._toggleVertScrollbar()
	elif mode == 'none':
	    if self._vertScrollbarOn:
		self._toggleVertScrollbar()
	else:
	    message = 'bad vscrollmode option "%s": should be static, dynamic, or none' % mode
	    raise ValueError, message
        self._configureScrollCommands()
    def _configureScrollCommands(self):

        tclCommandName = str(self._listbox.cget('xscrollcommand'))
        if tclCommandName != '':
            self._listbox.deletecommand(tclCommandName)
        tclCommandName = str(self._listbox.cget('yscrollcommand'))
        if tclCommandName != '':
            self._listbox.deletecommand(tclCommandName)
	if self['hscrollmode'] == self['vscrollmode'] == 'dynamic':
            self._listbox.configure(
                    xscrollcommand=self._scrollBothLater,
                    yscrollcommand=self._scrollBothLater
            )
        else:
            self._listbox.configure(
                    xscrollcommand=self._scrollXNow,
                    yscrollcommand=self._scrollYNow
            )
    def _scrollXNow(self, first, last):

        self._horizScrollbar.set(first, last)
        self._horizScrollbarNeeded = ((first, last) != ('0', '1'))
	if self['hscrollmode'] == 'dynamic':
	    if self._horizScrollbarNeeded != self._horizScrollbarOn:
		self._toggleHorizScrollbar()
    def _scrollYNow(self, first, last):

        self._vertScrollbar.set(first, last)
        self._vertScrollbarNeeded = ((first, last) != ('0', '1'))
        if self['vscrollmode'] == 'dynamic':
            if self._vertScrollbarNeeded != self._vertScrollbarOn:
                self._toggleVertScrollbar()
    def _scrollBothLater(self, first, last):

	if self.scrollTimer is None:
	    self.scrollTimer = self.after_idle(self._scrollBothNow)
    def _scrollBothNow(self):

	self.scrollTimer = None
        self._scrollRecurse = self._scrollRecurse + 1
        self.update_idletasks()
        self._scrollRecurse = self._scrollRecurse - 1
        if self._scrollRecurse != 0:
            return
	xview = self._listbox.xview()
	yview = self._listbox.yview()
	self._horizScrollbar.set(xview[0], xview[1])
	self._vertScrollbar.set(yview[0], yview[1])
	self._horizScrollbarNeeded = (xview != (0.0, 1.0))
	self._vertScrollbarNeeded = (yview != (0.0, 1.0))
	if (self['hscrollmode'] == self['vscrollmode'] == 'dynamic' and
		self._horizScrollbarNeeded != self._horizScrollbarOn and
		self._vertScrollbarNeeded != self._vertScrollbarOn and
		self._vertScrollbarOn != self._horizScrollbarOn):
	    if self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	    else:
		self._toggleVertScrollbar()
	    return
	if self['hscrollmode'] == 'dynamic':
	    if self._horizScrollbarNeeded != self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	if self['vscrollmode'] == 'dynamic':
	    if self._vertScrollbarNeeded != self._vertScrollbarOn:
		self._toggleVertScrollbar()
    def _toggleHorizScrollbar(self):

	self._horizScrollbarOn = not self._horizScrollbarOn
	interior = self.interior()
	if self._horizScrollbarOn:
	    self._horizScrollbar.grid(row = 4, column = 2, sticky = 'news')
	    interior.grid_rowconfigure(3, minsize = self['scrollmargin'])
	else:
	    self._horizScrollbar.grid_forget()
	    interior.grid_rowconfigure(3, minsize = 0)
    def _toggleVertScrollbar(self):

	self._vertScrollbarOn = not self._vertScrollbarOn
	interior = self.interior()
	if self._vertScrollbarOn:
	    self._vertScrollbar.grid(row = 2, column = 4, sticky = 'news')
	    interior.grid_columnconfigure(3, minsize = self['scrollmargin'])
	else:
	    self._vertScrollbar.grid_forget()
	    interior.grid_columnconfigure(3, minsize = 0)
    def _handleEvent(self, event, eventType):

        if eventType == 'double':
            command = self['dblclickcommand']
        elif eventType == 'key':
            command = self['selectioncommand']
        else:
            if (event.x < 0 or self._listbox.winfo_width() <= event.x or
                    event.y < 0 or self._listbox.winfo_height() <= event.y):
                return
            command = self['selectioncommand']
        if callable(command):
            command()
    def size(self):

	return self._listbox.size()
    def bbox(self, index):

	return self._listbox.bbox(index)
forwardmethods(ScrolledListBox, Tkinter.Listbox, '_listbox')
_listboxCache = {}
def _registerScrolledList(listbox, scrolledList):

    _listboxCache[listbox] = scrolledList
def _deregisterScrolledList(listbox):

    del _listboxCache[listbox]
def _handleEvent(event, eventType):

    if _listboxCache.has_key(event.widget):
        _listboxCache[event.widget]._handleEvent(event, eventType)
import Tkinter
class ScrolledText(MegaWidget):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('borderframe',    0,            INITOPT),
	    ('columnheader',   0,            INITOPT),
	    ('hscrollmode',    'dynamic',    self._hscrollMode),
	    ('labelmargin',    0,            INITOPT),
	    ('labelpos',       None,         INITOPT),
	    ('rowcolumnheader',0,            INITOPT),
	    ('rowheader',      0,            INITOPT),
	    ('scrollmargin',   2,            INITOPT),
	    ('usehullsize',    0,            INITOPT),
	    ('vscrollmode',    'dynamic',    self._vscrollMode),
	)
	self.defineoptions(kw, optiondefs)
	MegaWidget.__init__(self, parent)
	interior = self.interior()
	if self['usehullsize']:
	    interior.grid_propagate(0)
	if self['borderframe']:
	    self._borderframe = self.createcomponent('borderframe',
		    (), None,
		    Tkinter.Frame, (interior,),
		    relief = 'sunken',
		    borderwidth = 2,
	    )
	    self._borderframe.grid(row = 4, column = 4, sticky = 'news')
	    self._textbox = self.createcomponent('text',
		    (), None,
		    Tkinter.Text, (self._borderframe,),
		    highlightthickness = 0,
		    borderwidth = 0,
	    )
	    self._textbox.pack(fill = 'both', expand = 1)
            bw = self._borderframe.cget('borderwidth'),
            ht = self._borderframe.cget('highlightthickness'),
	else:
	    self._textbox = self.createcomponent('text',
		    (), None,
		    Tkinter.Text, (interior,),
	    )
	    self._textbox.grid(row = 4, column = 4, sticky = 'news')
            bw = self._textbox.cget('borderwidth'),
            ht = self._textbox.cget('highlightthickness'),
        if self['columnheader']:
            self._columnheader = self.createcomponent('columnheader',
                    (), 'Header',
                    Tkinter.Text, (interior,),
                    height=1,
                    wrap='none',
                    borderwidth = bw,
                    highlightthickness = ht,
            )
            self._columnheader.grid(row = 2, column = 4, sticky = 'ew')
            self._columnheader.configure(
                    xscrollcommand = self._columnheaderscrolled)
        if self['rowheader']:
            self._rowheader = self.createcomponent('rowheader',
                    (), 'Header',
                    Tkinter.Text, (interior,),
                    wrap='none',
                    borderwidth = bw,
                    highlightthickness = ht,
            )
            self._rowheader.grid(row = 4, column = 2, sticky = 'ns')
            self._rowheader.configure(
                    yscrollcommand = self._rowheaderscrolled)
        if self['rowcolumnheader']:
            self._rowcolumnheader = self.createcomponent('rowcolumnheader',
                    (), 'Header',
                    Tkinter.Text, (interior,),
                    height=1,
                    wrap='none',
                    borderwidth = bw,
                    highlightthickness = ht,
            )
            self._rowcolumnheader.grid(row = 2, column = 2, sticky = 'nsew')
	interior.grid_rowconfigure(4, weight = 1, minsize = 0)
	interior.grid_columnconfigure(4, weight = 1, minsize = 0)
	self._horizScrollbar = self.createcomponent('horizscrollbar',
		(), 'Scrollbar',
		Tkinter.Scrollbar, (interior,),
	        orient='horizontal',
		command=self._textbox.xview
	)
	self._vertScrollbar = self.createcomponent('vertscrollbar',
		(), 'Scrollbar',
		Tkinter.Scrollbar, (interior,),
		orient='vertical',
		command=self._textbox.yview
	)
	self.createlabel(interior, childCols = 5, childRows = 5)
	self._horizScrollbarOn = 0
	self._vertScrollbarOn = 0
	self.scrollTimer = None
        self._scrollRecurse = 0
	self._horizScrollbarNeeded = 0
	self._vertScrollbarNeeded = 0
	self._textWidth = None
	self._textboxLastX = None
	self._textboxLastY = None
	self._columnheaderLastX = None
	self._rowheaderLastY = None
	self.initialiseoptions()
    def destroy(self):

	if self.scrollTimer is not None:
	    self.after_cancel(self.scrollTimer)
	    self.scrollTimer = None
	MegaWidget.destroy(self)
    def clear(self):

	self.settext('')
    def importfile(self, fileName, where = 'end'):

	file = open(fileName, 'r')
	self._textbox.insert(where, file.read())
	file.close()
    def exportfile(self, fileName):

	file = open(fileName, 'w')
	file.write(self._textbox.get('1.0', 'end'))
	file.close()
    def settext(self, text):

	disabled = (str(self._textbox.cget('state')) == 'disabled')
	if disabled:
	    self._textbox.configure(state='normal')
	self._textbox.delete('0.0', 'end')
	self._textbox.insert('end', text)
	if disabled:
	    self._textbox.configure(state='disabled')
    def get(self, first=None, last=None):

	if first is None:
	    return self._textbox.get('1.0', 'end')
	else:
	    return self._textbox.get(first, last)
    def getvalue(self):

        return self.get()
    def setvalue(self, text):

        return self.settext(text)
    def appendtext(self, text):

        oldTop, oldBottom = self._textbox.yview()
        disabled = (str(self._textbox.cget('state')) == 'disabled')
        if disabled:
            self._textbox.configure(state='normal')
        self._textbox.insert('end', text)
        if disabled:
            self._textbox.configure(state='disabled')
        if oldBottom == 1.0:
            self._textbox.yview('moveto', 1.0)
    def _hscrollMode(self):

	mode = self['hscrollmode']
	if mode == 'static':
	    if not self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	elif mode == 'dynamic':
	    if self._horizScrollbarNeeded != self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	elif mode == 'none':
	    if self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	else:
	    message = 'bad hscrollmode option "%s": should be static, dynamic, or none' % mode
	    raise ValueError, message
        self._configureScrollCommands()
    def _vscrollMode(self):

	mode = self['vscrollmode']
	if mode == 'static':
	    if not self._vertScrollbarOn:
		self._toggleVertScrollbar()
	elif mode == 'dynamic':
	    if self._vertScrollbarNeeded != self._vertScrollbarOn:
		self._toggleVertScrollbar()
	elif mode == 'none':
	    if self._vertScrollbarOn:
		self._toggleVertScrollbar()
	else:
	    message = 'bad vscrollmode option "%s": should be static, dynamic, or none' % mode
	    raise ValueError, message
        self._configureScrollCommands()
    def _configureScrollCommands(self):

        tclCommandName = str(self._textbox.cget('xscrollcommand'))
        if tclCommandName != '':
            self._textbox.deletecommand(tclCommandName)
        tclCommandName = str(self._textbox.cget('yscrollcommand'))
        if tclCommandName != '':
            self._textbox.deletecommand(tclCommandName)
	if self['hscrollmode'] == self['vscrollmode'] == 'dynamic':
            self._textbox.configure(
                    xscrollcommand=self._scrollBothLater,
                    yscrollcommand=self._scrollBothLater
            )
        else:
            self._textbox.configure(
                    xscrollcommand=self._scrollXNow,
                    yscrollcommand=self._scrollYNow
            )
    def _scrollXNow(self, first, last):

        self._horizScrollbar.set(first, last)
        self._horizScrollbarNeeded = ((first, last) != ('0', '1'))
        if self['hscrollmode'] == 'dynamic':
            currentWidth = self._textbox.winfo_width()
            if self._horizScrollbarNeeded != self._horizScrollbarOn:
                if self._horizScrollbarNeeded or \
                        self._textWidth != currentWidth:
                    self._toggleHorizScrollbar()
            self._textWidth = currentWidth
        if self['columnheader']:
	    if self._columnheaderLastX != first:
		self._columnheaderLastX = first
		self._columnheader.xview('moveto', first)
    def _scrollYNow(self, first, last):

        if first == '0' and last == '0':
            return
        self._vertScrollbar.set(first, last)
        self._vertScrollbarNeeded = ((first, last) != ('0', '1'))
        if self['vscrollmode'] == 'dynamic':
            if self._vertScrollbarNeeded != self._vertScrollbarOn:
                self._toggleVertScrollbar()
        if self['rowheader']:
	    if self._rowheaderLastY != first:
		self._rowheaderLastY = first
		self._rowheader.yview('moveto', first)
    def _scrollBothLater(self, first, last):

	if self.scrollTimer is None:
	    self.scrollTimer = self.after_idle(self._scrollBothNow)
    def _scrollBothNow(self):

	self.scrollTimer = None
        self._scrollRecurse = self._scrollRecurse + 1
        self.update_idletasks()
        self._scrollRecurse = self._scrollRecurse - 1
        if self._scrollRecurse != 0:
            return
	xview = self._textbox.xview()
	yview = self._textbox.yview()
	if yview == (0.0, 0.0):
	    return
        if self['columnheader']:
	    if self._columnheaderLastX != xview[0]:
		self._columnheaderLastX = xview[0]
		self._columnheader.xview('moveto', xview[0])
        if self['rowheader']:
	    if self._rowheaderLastY != yview[0]:
		self._rowheaderLastY = yview[0]
		self._rowheader.yview('moveto', yview[0])
	self._horizScrollbar.set(xview[0], xview[1])
	self._vertScrollbar.set(yview[0], yview[1])
	self._horizScrollbarNeeded = (xview != (0.0, 1.0))
	self._vertScrollbarNeeded = (yview != (0.0, 1.0))
	if (self['hscrollmode'] == self['vscrollmode'] == 'dynamic' and
		self._horizScrollbarNeeded != self._horizScrollbarOn and
		self._vertScrollbarNeeded != self._vertScrollbarOn and
		self._vertScrollbarOn != self._horizScrollbarOn):
	    if self._horizScrollbarOn:
		self._toggleHorizScrollbar()
	    else:
		self._toggleVertScrollbar()
	    return
	if self['hscrollmode'] == 'dynamic':
	    currentWidth = self._textbox.winfo_width()
	    if self._horizScrollbarNeeded != self._horizScrollbarOn:
		if self._horizScrollbarNeeded or \
			self._textWidth != currentWidth:
		    self._toggleHorizScrollbar()
	    self._textWidth = currentWidth
	if self['vscrollmode'] == 'dynamic':
	    if self._vertScrollbarNeeded != self._vertScrollbarOn:
		self._toggleVertScrollbar()
    def _columnheaderscrolled(self, first, last):

	if self._textboxLastX != first:
	    self._textboxLastX = first
	    self._textbox.xview('moveto', first)
    def _rowheaderscrolled(self, first, last):

	if self._textboxLastY != first:
	    self._textboxLastY = first
	    self._textbox.yview('moveto', first)
    def _toggleHorizScrollbar(self):

	self._horizScrollbarOn = not self._horizScrollbarOn
	interior = self.interior()
	if self._horizScrollbarOn:
	    self._horizScrollbar.grid(row = 6, column = 4, sticky = 'news')
	    interior.grid_rowconfigure(5, minsize = self['scrollmargin'])
	else:
	    self._horizScrollbar.grid_forget()
	    interior.grid_rowconfigure(5, minsize = 0)
    def _toggleVertScrollbar(self):

	self._vertScrollbarOn = not self._vertScrollbarOn
	interior = self.interior()
	if self._vertScrollbarOn:
	    self._vertScrollbar.grid(row = 4, column = 6, sticky = 'news')
	    interior.grid_columnconfigure(5, minsize = self['scrollmargin'])
	else:
	    self._vertScrollbar.grid_forget()
	    interior.grid_columnconfigure(5, minsize = 0)
    def bbox(self, index):

	return self._textbox.bbox(index)
forwardmethods(ScrolledText, Tkinter.Text, '_textbox')
_ORIGINAL = 0
_MODIFIED = 1
_DISPLAY = 2
class HistoryText(ScrolledText):


    def __init__(self, parent = None, **kw):

        optiondefs = (
	    ('compressany',         1,          None),
	    ('compresstail',        1,          None),
            ('historycommand',      None,       None),
        )
        self.defineoptions(kw, optiondefs)
        ScrolledText.__init__(self, parent)
	self._list = []
	self._currIndex = 0
	self._pastIndex = None
	self._lastIndex = 0
        self.initialiseoptions()
    def addhistory(self):

	text = self.get()
	if text[-1] == '\n':
	    text = text[:-1]
	if len(self._list) == 0:
	    self._list.append([text, text, _MODIFIED])
            return
        currentEntry =  self._list[self._currIndex]
        if text == currentEntry[_ORIGINAL]:
            if self['compresstail'] and self._currIndex == self._lastIndex:
                return
            if self['compressany']:
                return
        currentEntry[_MODIFIED] = currentEntry[_ORIGINAL]
        historycommand = self['historycommand']
        if self._currIndex == self._lastIndex:
            self._pastIndex = None
            nextState = 'disabled'
        else:
            self._pastIndex = self._currIndex
            nextState = 'normal'
        if callable(historycommand):
            historycommand('normal', nextState)
        self._list.append([text, text, _MODIFIED])
        self._lastIndex = self._lastIndex + 1
        self._currIndex = self._lastIndex
    def next(self):

	if self._currIndex == self._lastIndex and self._pastIndex is None:
	    self.bell()
        else:
            self._modifyDisplay('next')
    def prev(self):

        self._pastIndex = None
	if self._currIndex == 0:
	    self.bell()
        else:
            self._modifyDisplay('prev')
    def undo(self):

	if len(self._list) != 0:
            self._modifyDisplay('undo')
    def redo(self):

	if len(self._list) != 0:
            self._modifyDisplay('redo')
    def gethistory(self):

        return self._list
    def _modifyDisplay(self, command):

        currentText = self.get()
        if currentText[-1] == '\n':
            currentText = currentText[:-1]
        currentEntry =  self._list[self._currIndex]
        if currentEntry[_DISPLAY] == _MODIFIED:
            currentEntry[_MODIFIED] = currentText
        elif currentEntry[_ORIGINAL] != currentText:
            currentEntry[_MODIFIED] = currentText
            if command in ('next', 'prev'):
                currentEntry[_DISPLAY] = _MODIFIED
        if command in ('next', 'prev'):
            prevstate = 'normal'
            nextstate = 'normal'
            if command == 'next':
                if self._pastIndex is not None:
                    self._currIndex = self._pastIndex
                    self._pastIndex = None
                self._currIndex = self._currIndex + 1
                if self._currIndex == self._lastIndex:
                    nextstate = 'disabled'
            elif command == 'prev':
                self._currIndex = self._currIndex - 1
                if self._currIndex == 0:
                    prevstate = 'disabled'
            historycommand = self['historycommand']
            if callable(historycommand):
                historycommand(prevstate, nextstate)
            currentEntry =  self._list[self._currIndex]
        else:
            if command == 'undo':
                currentEntry[_DISPLAY] = _ORIGINAL
            elif command == 'redo':
                currentEntry[_DISPLAY] = _MODIFIED
        self.delete('1.0', 'end')
        self.insert('end', currentEntry[currentEntry[_DISPLAY]])
class SelectionDialog(Dialog):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('borderx',     10,    INITOPT),
	    ('bordery',     10,    INITOPT),
	)
	self.defineoptions(kw, optiondefs)
	Dialog.__init__(self, parent)
	interior = self.interior()
	aliases = (
	    ('listbox', 'scrolledlist_listbox'),
	    ('label', 'scrolledlist_label'),
	)
	self._list = self.createcomponent('scrolledlist',
		aliases, None,
		ScrolledListBox, (interior,),
		dblclickcommand = self.invoke)
	self._list.pack(side='top', expand='true', fill='both',
		padx = self['borderx'], pady = self['bordery'])
        if not kw.has_key('activatecommand'):
            listbox = self.component('listbox')
            self.configure(activatecommand = listbox.focus_set)
	self.initialiseoptions()
    def size(self):

	return self.component('listbox').size()
    def bbox(self, index):

	return self.component('listbox').size(index)
forwardmethods(SelectionDialog, ScrolledListBox, '_list')
class TextDialog(Dialog):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('borderx',     10,    INITOPT),
	    ('bordery',     10,    INITOPT),
	)
	self.defineoptions(kw, optiondefs)
	Dialog.__init__(self, parent)
	interior = self.interior()
	aliases = (
	    ('text', 'scrolledtext_text'),
	    ('label', 'scrolledtext_label'),
	)
	self._text = self.createcomponent('scrolledtext',
		aliases, None,
		ScrolledText, (interior,))
	self._text.pack(side='top', expand=1, fill='both',
		padx = self['borderx'], pady = self['bordery'])
	self.initialiseoptions()
    def bbox(self, index):

	return self._text.bbox(index)
forwardmethods(TextDialog, ScrolledText, '_text')
import string
import sys
import time
import Tkinter
class TimeCounter(MegaWidget):


    """Up-down counter
    A TimeCounter is a single-line entry widget with Up and Down arrows
    which increment and decrement the Time value in the entry.
    """
    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('autorepeat',    1,    None),
	    ('buttonaspect',  1.0,  INITOPT),
	    ('command',       None, None),
	    ('initwait',      300,  None),
	    ('labelmargin',   0,    INITOPT),
	    ('labelpos',      None, INITOPT),
	    ('max',           None, self._max),
	    ('min',           None, self._min),
	    ('padx',          0,    INITOPT),
	    ('pady',          0,    INITOPT),
	    ('repeatrate',    50,   None),
	    ('value',         None, INITOPT),
	)
	self.defineoptions(kw, optiondefs)
	MegaWidget.__init__(self, parent)
    	self.arrowDirection = {}
	self._flag = 'stopped'
	self._timerId = None
	self._createComponents(kw)
	value = self['value']
	if value is None:
	    now = time.time()
	    value = time.strftime('%H:%M:%S', time.localtime(now))
    	self.setvalue(value)
	self.initialiseoptions()
    def _createComponents(self, kw):

	interior = self.interior()
	if self['labelpos'] is None:
	    frame = interior
            if not kw.has_key('hull_relief'):
                frame.configure(relief = 'raised')
            if not kw.has_key('hull_borderwidth'):
                frame.configure(borderwidth = 1)
	else:
	    frame = self.createcomponent('frame',
		    (), None,
		    Tkinter.Frame, (interior,),
                    relief = 'raised', borderwidth = 1)
	    frame.grid(column=2, row=2, sticky='nsew')
	    interior.grid_columnconfigure(2, weight=1)
	    interior.grid_rowconfigure(2, weight=1)
	self._downHourArrowBtn = self.createcomponent('downhourarrow',
		(), 'Arrow',
		Tkinter.Canvas, (frame,),
		width = 16, height = 16, relief = 'raised', borderwidth = 2)
    	self.arrowDirection[self._downHourArrowBtn] = 'down'
	self._downHourArrowBtn.grid(column = 0, row = 2)
	self._downMinuteArrowBtn = self.createcomponent('downminutearrow',
		(), 'Arrow',
		Tkinter.Canvas, (frame,),
		width = 16, height = 16, relief = 'raised', borderwidth = 2)
    	self.arrowDirection[self._downMinuteArrowBtn] = 'down'
	self._downMinuteArrowBtn.grid(column = 1, row = 2)
	self._downSecondArrowBtn = self.createcomponent('downsecondarrow',
		(), 'Arrow',
		Tkinter.Canvas, (frame,),
		width = 16, height = 16, relief = 'raised', borderwidth = 2)
    	self.arrowDirection[self._downSecondArrowBtn] = 'down'
	self._downSecondArrowBtn.grid(column = 2, row = 2)
	self._hourCounterEntry = self.createcomponent('hourentryfield',
		(('hourentry', 'hourentryfield_entry'),), None,
		EntryField, (frame,), validate='integer', entry_width = 2)
	self._hourCounterEntry.grid(column = 0, row = 1, sticky = 'news')
	self._minuteCounterEntry = self.createcomponent('minuteentryfield',
		(('minuteentry', 'minuteentryfield_entry'),), None,
		EntryField, (frame,), validate='integer', entry_width = 2)
	self._minuteCounterEntry.grid(column = 1, row = 1, sticky = 'news')
	self._secondCounterEntry = self.createcomponent('secondentryfield',
		(('secondentry', 'secondentryfield_entry'),), None,
		EntryField, (frame,), validate='integer', entry_width = 2)
	self._secondCounterEntry.grid(column = 2, row = 1, sticky = 'news')
	self._upHourArrowBtn = self.createcomponent('uphourarrow',
		(), 'Arrow',
		Tkinter.Canvas, (frame,),
		width = 16, height = 16, relief = 'raised', borderwidth = 2)
    	self.arrowDirection[self._upHourArrowBtn] = 'up'
	self._upHourArrowBtn.grid(column = 0, row = 0)
	self._upMinuteArrowBtn = self.createcomponent('upminutearrow',
		(), 'Arrow',
		Tkinter.Canvas, (frame,),
		width = 16, height = 16, relief = 'raised', borderwidth = 2)
    	self.arrowDirection[self._upMinuteArrowBtn] = 'up'
	self._upMinuteArrowBtn.grid(column = 1, row = 0)
	self._upSecondArrowBtn = self.createcomponent('upsecondarrow',
		(), 'Arrow',
		Tkinter.Canvas, (frame,),
		width = 16, height = 16, relief = 'raised', borderwidth = 2)
    	self.arrowDirection[self._upSecondArrowBtn] = 'up'
	self._upSecondArrowBtn.grid(column = 2, row = 0)
	padx = self['padx']
	pady = self['pady']
	for col in range(3):
	    frame.grid_columnconfigure(col, weight = 1, pad = padx)
	frame.grid_rowconfigure(0, pad = pady)
	frame.grid_rowconfigure(2, pad = pady)
	frame.grid_rowconfigure(1, weight = 1)
	self.createlabel(interior)
	self._upHourArrowBtn.bind('<Configure>',
		lambda  event, s=self,button=self._upHourArrowBtn:
		s._drawArrow(button, 'up'))
	self._upHourArrowBtn.bind('<1>',
    	    	lambda event, s=self,button=self._upHourArrowBtn:
		s._countUp(button, 3600))
	self._upHourArrowBtn.bind('<Any-ButtonRelease-1>',
		lambda event, s=self, button=self._upHourArrowBtn:
		s._stopUpDown(button))
	self._upMinuteArrowBtn.bind('<Configure>',
		lambda  event, s=self,button=self._upMinuteArrowBtn:
		s._drawArrow(button, 'up'))
	self._upMinuteArrowBtn.bind('<1>',
    	    	lambda event, s=self,button=self._upMinuteArrowBtn:
		s._countUp(button, 60))
	self._upMinuteArrowBtn.bind('<Any-ButtonRelease-1>',
		lambda event, s=self, button=self._upMinuteArrowBtn:
		s._stopUpDown(button))
	self._upSecondArrowBtn.bind('<Configure>',
		lambda  event, s=self,button=self._upSecondArrowBtn:
		s._drawArrow(button, 'up'))
	self._upSecondArrowBtn.bind('<1>',
    	    	lambda event, s=self,button=self._upSecondArrowBtn:
		s._countUp(button, 1))
	self._upSecondArrowBtn.bind('<Any-ButtonRelease-1>',
		lambda event, s=self, button=self._upSecondArrowBtn:
		s._stopUpDown(button))
	self._downHourArrowBtn.bind('<Configure>',
		lambda  event, s=self,button=self._downHourArrowBtn:
		s._drawArrow(button, 'down'))
	self._downHourArrowBtn.bind('<1>',
    	    	lambda event, s=self,button=self._downHourArrowBtn:
		s._countDown(button, 3600))
	self._downHourArrowBtn.bind('<Any-ButtonRelease-1>',
		lambda event, s=self, button=self._downHourArrowBtn:
		s._stopUpDown(button))
	self._downMinuteArrowBtn.bind('<Configure>',
		lambda  event, s=self,button=self._downMinuteArrowBtn:
		s._drawArrow(button, 'down'))
	self._downMinuteArrowBtn.bind('<1>',
    	    	lambda event, s=self,button=self._downMinuteArrowBtn:
                s._countDown(button, 60))
	self._downMinuteArrowBtn.bind('<Any-ButtonRelease-1>',
		lambda event, s=self, button=self._downMinuteArrowBtn:
		s._stopUpDown(button))
	self._downSecondArrowBtn.bind('<Configure>',
		lambda  event, s=self,button=self._downSecondArrowBtn:
		s._drawArrow(button, 'down'))
	self._downSecondArrowBtn.bind('<1>',
    	    	lambda event, s=self, button=self._downSecondArrowBtn:
		s._countDown(button,1))
	self._downSecondArrowBtn.bind('<Any-ButtonRelease-1>',
		lambda event, s=self, button=self._downSecondArrowBtn:
		s._stopUpDown(button))
	self._hourCounterEntry.component('entry').bind(
                '<Return>', self._invoke)
	self._minuteCounterEntry.component('entry').bind(
        	'<Return>', self._invoke)
	self._secondCounterEntry.component('entry').bind(
        	'<Return>', self._invoke)
	self._hourCounterEntry.bind('<Configure>', self._resizeArrow)
	self._minuteCounterEntry.bind('<Configure>', self._resizeArrow)
	self._secondCounterEntry.bind('<Configure>', self._resizeArrow)
    def _drawArrow(self, arrow, direction):

        drawarrow(arrow, self['hourentry_foreground'], direction, 'arrow')
    def _resizeArrow(self, event = None):

	for btn in (self._upHourArrowBtn, self._upMinuteArrowBtn,
		self._upSecondArrowBtn,
		self._downHourArrowBtn,
		self._downMinuteArrowBtn, self._downSecondArrowBtn):
	    bw = (string.atoi(btn['borderwidth']) +
		    string.atoi(btn['highlightthickness']))
	    newHeight = self._hourCounterEntry.winfo_reqheight() - 2 * bw
	    newWidth = int(newHeight * self['buttonaspect'])
	    btn.configure(width=newWidth, height=newHeight)
	    self._drawArrow(btn, self.arrowDirection[btn])
    def _min(self):

	min = self['min']
        if min is None:
	    self._minVal = 0
	else:
	    self._minVal = timestringtoseconds(min)
    def _max(self):

	max = self['max']
	if max is None:
	    self._maxVal = None
	else:
	    self._maxVal = timestringtoseconds(max)
    def getvalue(self):

        return self.getstring()
    def setvalue(self, text):

        list = string.split(text, ':')
	if len(list) != 3:
	    raise ValueError, 'invalid value: ' + text
	self._hour = string.atoi(list[0])
	self._minute = string.atoi(list[1])
	self._second = string.atoi(list[2])
    	self._setHMS()
    def getstring(self):

    	return '%02d:%02d:%02d' % (self._hour, self._minute, self._second)
    def getint(self):

    	return self._hour * 3600 + self._minute * 60 + self._second
    def _countUp(self, button, increment):

	self._relief = self._upHourArrowBtn.cget('relief')
	button.configure(relief='sunken')
	self._count(1, 'start', increment)
    def _countDown(self, button, increment):

	self._relief = self._downHourArrowBtn.cget('relief')
	button.configure(relief='sunken')
	self._count(-1, 'start', increment)
    def increment(self, seconds = 1):

	self._count(1, 'force', seconds)
    def decrement(self, seconds = 1):

	self._count(-1, 'force', seconds)
    def _count(self, factor, newFlag = None, increment = 1):

	if newFlag != 'force':
	  if newFlag is not None:
	    self._flag = newFlag
	  if self._flag == 'stopped':
	    return
	value = (string.atoi(self._hourCounterEntry.get()) *3600) + \
	      (string.atoi(self._minuteCounterEntry.get()) *60) + \
	      string.atoi(self._secondCounterEntry.get()) + \
	      factor * increment
	min = self._minVal
	max = self._maxVal
	if value < min:
	  value = min
	if max is not None and value > max:
	  value = max
	self._hour = value /3600
	self._minute = (value - (self._hour*3600)) / 60
	self._second = value - (self._hour*3600) - (self._minute*60)
	self._setHMS()
	if newFlag != 'force':
	  if self['autorepeat']:
	    if self._flag == 'start':
	      delay = self['initwait']
	      self._flag = 'running'
	    else:
	      delay = self['repeatrate']
	    self._timerId = self.after(
		delay, lambda self=self, factor=factor,increment=increment:
		  self._count(factor,'running', increment))
    def _setHMS(self):

        self._hourCounterEntry.setentry('%02d' % self._hour)
        self._minuteCounterEntry.setentry('%02d' % self._minute)
        self._secondCounterEntry.setentry('%02d' % self._second)
    def _stopUpDown(self, button):

        if self._timerId is not None:
            self.after_cancel(self._timerId)
	    self._timerId = None
        button.configure(relief=self._relief)
        self._flag = 'stopped'
    def _invoke(self, event):

        cmd = self['command']
        if callable(cmd):
	    cmd()
    def invoke(self):

        cmd = self['command']
        if callable(cmd):
	    return cmd()
    def destroy(self):

        if self._timerId is not None:
            self.after_cancel(self._timerId)
	    self._timerId = None
        MegaWidget.destroy(self)
class AboutDialog(MessageDialog):


    _version = ''
    _copyright = ''
    _contact = ''
    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('applicationname',   '',          INITOPT),
	    ('iconpos',           'w',         None),
	    ('icon_bitmap',       'info',      None),
	    ('buttons',           ('Close',),  None),
	    ('defaultbutton',     0,           None),
	)
	self.defineoptions(kw, optiondefs)
	MessageDialog.__init__(self, parent)
	applicationname = self['applicationname']
        if not kw.has_key('title'):
            self.configure(title = 'About ' + applicationname)
        if not kw.has_key('message_text'):
            text = applicationname + '\n\n'
            if AboutDialog._version != '':
              text = text + 'Version ' + AboutDialog._version + '\n'
            if AboutDialog._copyright != '':
              text = text + AboutDialog._copyright + '\n\n'
            if AboutDialog._contact != '':
              text = text + AboutDialog._contact
            self.configure(message_text=text)
	self.initialiseoptions()
def aboutversion(value):

    AboutDialog._version = value
def aboutcopyright(value):

    AboutDialog._copyright = value
def aboutcontact(value):

    AboutDialog._contact = value
import os
import string
import types
import Tkinter
class ComboBox(MegaWidget):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('autoclear',          0,          INITOPT),
	    ('buttonaspect',       1.0,        INITOPT),
	    ('dropdown',           1,          INITOPT),
	    ('fliparrow',          0,          INITOPT),
	    ('history',            1,          INITOPT),
	    ('labelmargin',        0,          INITOPT),
	    ('labelpos',           None,       INITOPT),
	    ('listheight',         200,        INITOPT),
	    ('selectioncommand',   None,       None),
	    ('sticky',            'ew',        INITOPT),
	    ('unique',             1,          INITOPT),
	)
	self.defineoptions(kw, optiondefs)
	MegaWidget.__init__(self, parent)
	interior = self.interior()
	self._entryfield = self.createcomponent('entryfield',
		(('entry', 'entryfield_entry'),), None,
		EntryField, (interior,))
	self._entryfield.grid(column=2, row=2, sticky=self['sticky'])
	interior.grid_columnconfigure(2, weight = 1)
	self._entryWidget = self._entryfield.component('entry')
	if self['dropdown']:
	    self._isPosted = 0
            interior.grid_rowconfigure(2, weight = 1)
	    self._arrowBtn = self.createcomponent('arrowbutton',
		    (), None,
		    Tkinter.Canvas, (interior,), borderwidth = 2,
		    relief = 'raised',
		    width = 16, height = 16)
            if 'n' in self['sticky']:
                sticky = 'n'
            else:
                sticky = ''
            if 's' in self['sticky']:
                sticky = sticky + 's'
	    self._arrowBtn.grid(column=3, row=2, sticky = sticky)
	    self._arrowRelief = self._arrowBtn.cget('relief')
	    self.createlabel(interior, childCols=2)
	    self._popup = self.createcomponent('popup',
		    (), None,
		    Tkinter.Toplevel, (interior,))
	    self._popup.withdraw()
	    self._popup.overrideredirect(1)
	    self._list = self.createcomponent('scrolledlist',
		    (('listbox', 'scrolledlist_listbox'),), None,
		    ScrolledListBox, (self._popup,),
		    hull_borderwidth = 2,
		    hull_relief = 'raised',
		    hull_height = self['listheight'],
		    usehullsize = 1,
		    listbox_exportselection = 0)
	    self._list.pack(expand=1, fill='both')
	    self.__listbox = self._list.component('listbox')
	    self._arrowBtn.bind('<1>', self._postList)
	    self._arrowBtn.bind('<Configure>', self._drawArrow)
	    self._arrowBtn.bind('<3>', self._next)
	    self._arrowBtn.bind('<Shift-3>', self._previous)
	    self._arrowBtn.bind('<Down>', self._next)
	    self._arrowBtn.bind('<Up>', self._previous)
	    self._arrowBtn.bind('<Control-n>', self._next)
	    self._arrowBtn.bind('<Control-p>', self._previous)
	    self._arrowBtn.bind('<Shift-Down>', self._postList)
	    self._arrowBtn.bind('<Shift-Up>', self._postList)
	    self._arrowBtn.bind('<F34>', self._postList)
	    self._arrowBtn.bind('<F28>', self._postList)
	    self._arrowBtn.bind('<space>', self._postList)
	    self._popup.bind('<Escape>', self._unpostList)
	    self._popup.bind('<space>', self._selectUnpost)
	    self._popup.bind('<Return>', self._selectUnpost)
	    self._popup.bind('<ButtonRelease-1>', self._dropdownBtnRelease)
	    self._popup.bind('<ButtonPress-1>', self._unpostOnNextRelease)
	    self.__listbox.bind('<Enter>', self._unpostOnNextRelease)
	    self._entryWidget.bind('<Configure>', self._resizeArrow)
	    self._entryWidget.bind('<Shift-Down>', self._postList)
	    self._entryWidget.bind('<Shift-Up>', self._postList)
	    self._entryWidget.bind('<F34>', self._postList)
	    self._entryWidget.bind('<F28>', self._postList)
            self._entryWidget.bind('<Unmap>', self._unpostList)
	else:
	    self._list = self.createcomponent('scrolledlist',
		    (('listbox', 'scrolledlist_listbox'),), None,
		    ScrolledListBox, (interior,),
                    selectioncommand = self._selectCmd)
	    self._list.grid(column=2, row=3, sticky='nsew')
	    self.__listbox = self._list.component('listbox')
	    interior.grid_rowconfigure(3, weight = 1)
	    self.createlabel(interior, childRows=2)
	self._entryWidget.bind('<Down>', self._next)
	self._entryWidget.bind('<Up>', self._previous)
	self._entryWidget.bind('<Control-n>', self._next)
	self._entryWidget.bind('<Control-p>', self._previous)
	self.__listbox.bind('<Control-n>', self._next)
	self.__listbox.bind('<Control-p>', self._previous)
	if self['history']:
	    self._entryfield.configure(command=self._addHistory)
	self.initialiseoptions()
    def destroy(self):

	if self['dropdown'] and self._isPosted:
            popgrab(self._popup)
        MegaWidget.destroy(self)
    def get(self, first = None, last=None):

	if first is None:
	    return self._entryWidget.get()
	else:
	    return self._list.get(first, last)
    def invoke(self):

	if self['dropdown']:
	    self._postList()
	else:
	    return self._selectCmd()
    def selectitem(self, index, setentry=1):

	if type(index) == types.StringType:
	    text = index
	    items = self._list.get(0, 'end')
	    if text in items:
		index = list(items).index(text)
	    else:
	    	raise IndexError, 'index "%s" not found' % text
	elif setentry:
	    text = self._list.get(0, 'end')[index]
	self._list.select_clear(0, 'end')
	self._list.select_set(index, index)
	self._list.activate(index)
	self.see(index)
	if setentry:
	    self._entryfield.setentry(text)
    def size(self):

	return self._list.size()
    def bbox(self, index):

	return self._list.bbox(index)
    def clear(self):

	self._entryfield.clear()
	self._list.clear()
    def _addHistory(self):

	input = self._entryWidget.get()
	if input != '':
	    index = None
	    if self['unique']:
		items = self._list.get(0, 'end')
		if input in items:
		    index = list(items).index(input)
	    if index is None:
		index = self._list.index('end')
		self._list.insert('end', input)
	    self.selectitem(index)
	    if self['autoclear']:
		self._entryWidget.delete(0, 'end')
	    self._selectCmd()
    def _next(self, event):

	size = self.size()
	if size <= 1:
	    return
	cursels = self.curselection()
	if len(cursels) == 0:
	    index = 0
	else:
	    index = string.atoi(cursels[0])
	    if index == size - 1:
		index = 0
	    else:
		index = index + 1
	self.selectitem(index)
    def _previous(self, event):

	size = self.size()
	if size <= 1:
	    return
	cursels = self.curselection()
	if len(cursels) == 0:
	    index = size - 1
	else:
	    index = string.atoi(cursels[0])
	    if index == 0:
		index = size - 1
	    else:
		index = index - 1
	self.selectitem(index)
    def _selectCmd(self, event=None):

	sels = self.getcurselection()
	if len(sels) == 0:
	    item = None
	else:
	    item = sels[0]
	    self._entryfield.setentry(item)
	cmd = self['selectioncommand']
	if callable(cmd):
            if event is None:
                return cmd(item)
            else:
                cmd(item)
    def _drawArrow(self, event=None, sunken=0):

        arrow = self._arrowBtn
	if sunken:
	    self._arrowRelief = arrow.cget('relief')
	    arrow.configure(relief = 'sunken')
	else:
	    arrow.configure(relief = self._arrowRelief)
	if self._isPosted and self['fliparrow']:
            direction = 'up'
        else:
            direction = 'down'
        drawarrow(arrow, self['entry_foreground'], direction, 'arrow')
    def _postList(self, event = None):

        self._isPosted = 1
        self._drawArrow(sunken=1)
        self.update_idletasks()
        x = self._entryfield.winfo_rootx()
        y = self._entryfield.winfo_rooty() + \
            self._entryfield.winfo_height()
        w = self._entryfield.winfo_width() + self._arrowBtn.winfo_width()
        h =  self.__listbox.winfo_height()
        sh = self.winfo_screenheight()
        if y + h > sh and y > sh / 2:
            y = self._entryfield.winfo_rooty() - h
        self._list.configure(hull_width=w)
        setgeometryanddeiconify(self._popup, '+%d+%d' % (x, y))
        pushgrab(self._popup, 1, self._unpostList)
        self.__listbox.focus_set()
        self._drawArrow()
        self._ignoreRelease = 1
    def _dropdownBtnRelease(self, event):

	if (event.widget == self._list.component('vertscrollbar') or
		event.widget == self._list.component('horizscrollbar')):
	    return
	if self._ignoreRelease:
	    self._unpostOnNextRelease()
	    return
        self._unpostList()
	if (event.x >= 0 and event.x < self.__listbox.winfo_width() and
		event.y >= 0 and event.y < self.__listbox.winfo_height()):
	    self._selectCmd()
    def _unpostOnNextRelease(self, event = None):

	self._ignoreRelease = 0
    def _resizeArrow(self, event):

	bw = (string.atoi(self._arrowBtn['borderwidth']) +
		string.atoi(self._arrowBtn['highlightthickness']))
	newHeight = self._entryfield.winfo_reqheight() - 2 * bw
	newWidth = int(newHeight * self['buttonaspect'])
	self._arrowBtn.configure(width=newWidth, height=newHeight)
	self._drawArrow()
    def _unpostList(self, event=None):

	if not self._isPosted:
            return
        popgrab(self._popup)
	self._popup.withdraw()
	self._isPosted = 0
	self._drawArrow()
    def _selectUnpost(self, event):

        self._unpostList()
	self._selectCmd()
forwardmethods(ComboBox, ScrolledListBox, '_list')
forwardmethods(ComboBox, EntryField, '_entryfield')
class ComboBoxDialog(Dialog):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('borderx',    10,              INITOPT),
	    ('bordery',    10,              INITOPT),
	)
	self.defineoptions(kw, optiondefs)
	Dialog.__init__(self, parent)
	interior = self.interior()
	aliases = (
	    ('listbox', 'combobox_listbox'),
	    ('scrolledlist', 'combobox_scrolledlist'),
	    ('entry', 'combobox_entry'),
	    ('label', 'combobox_label'),
	)
	self._combobox = self.createcomponent('combobox',
		aliases, None,
		ComboBox, (interior,),
		scrolledlist_dblclickcommand = self.invoke,
		dropdown = 0,
	)
	self._combobox.pack(side='top', expand='true', fill='both',
		padx = self['borderx'], pady = self['bordery'])
        if not kw.has_key('activatecommand'):
            listbox = self.component('listbox')
            self.configure(activatecommand = listbox.focus_set)
	self.initialiseoptions()
    def size(self):

	return self._combobox.size()
    def bbox(self, index):

	return self._combobox.bbox(index)
forwardmethods(ComboBoxDialog, ComboBox, '_combobox')
import string
import sys
import types
import Tkinter
class Counter(MegaWidget):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('autorepeat',     1,             None),
	    ('buttonaspect',   1.0,           INITOPT),
	    ('datatype',       'numeric',     self._datatype),
	    ('increment',      1,             None),
	    ('initwait',       300,           None),
	    ('labelmargin',    0,             INITOPT),
	    ('labelpos',       None,          INITOPT),
	    ('orient',         'horizontal',  INITOPT),
	    ('padx',           0,             INITOPT),
	    ('pady',           0,             INITOPT),
	    ('repeatrate',     50,            None),
	    ('sticky',         'ew',          INITOPT),
	)
	self.defineoptions(kw, optiondefs)
	MegaWidget.__init__(self, parent)
	self._timerId = None
	self._normalRelief = None
	interior = self.interior()
	if self['labelpos'] is None:
	    frame = interior
            if not kw.has_key('hull_relief'):
                frame.configure(relief = 'raised')
            if not kw.has_key('hull_borderwidth'):
                frame.configure(borderwidth = 1)
	else:
	    frame = self.createcomponent('frame',
		    (), None,
		    Tkinter.Frame, (interior,),
                    relief = 'raised', borderwidth = 1)
	    frame.grid(column=2, row=2, sticky=self['sticky'])
	    interior.grid_columnconfigure(2, weight=1)
	    interior.grid_rowconfigure(2, weight=1)
	self._downArrowBtn = self.createcomponent('downarrow',
		(), 'Arrow',
		Tkinter.Canvas, (frame,),
		width = 16, height = 16, relief = 'raised', borderwidth = 2)
	self._counterEntry = self.createcomponent('entryfield',
		(('entry', 'entryfield_entry'),), None,
		EntryField, (frame,))
	self._upArrowBtn = self.createcomponent('uparrow',
		(), 'Arrow',
		Tkinter.Canvas, (frame,),
		width = 16, height = 16, relief = 'raised', borderwidth = 2)
	padx = self['padx']
	pady = self['pady']
	orient = self['orient']
	if orient == 'horizontal':
	    self._downArrowBtn.grid(column = 0, row = 0)
	    self._counterEntry.grid(column = 1, row = 0,
                    sticky = self['sticky'])
	    self._upArrowBtn.grid(column = 2, row = 0)
	    frame.grid_columnconfigure(1, weight = 1)
	    frame.grid_rowconfigure(0, weight = 1)
	    if Tkinter.TkVersion >= 4.2:
		frame.grid_columnconfigure(0, pad = padx)
		frame.grid_columnconfigure(2, pad = padx)
		frame.grid_rowconfigure(0, pad = pady)
	elif orient == 'vertical':
	    self._upArrowBtn.grid(column = 0, row = 0, sticky = 's')
	    self._counterEntry.grid(column = 0, row = 1,
                    sticky = self['sticky'])
	    self._downArrowBtn.grid(column = 0, row = 2, sticky = 'n')
	    frame.grid_columnconfigure(0, weight = 1)
	    frame.grid_rowconfigure(0, weight = 1)
	    frame.grid_rowconfigure(2, weight = 1)
	    if Tkinter.TkVersion >= 4.2:
		frame.grid_rowconfigure(0, pad = pady)
		frame.grid_rowconfigure(2, pad = pady)
		frame.grid_columnconfigure(0, pad = padx)
	else:
	    raise ValueError, 'bad orient option ' + repr(orient) + \
		': must be either \'horizontal\' or \'vertical\''
	self.createlabel(interior)
	self._upArrowBtn.bind('<Configure>', self._drawUpArrow)
	self._upArrowBtn.bind('<1>', self._countUp)
	self._upArrowBtn.bind('<Any-ButtonRelease-1>', self._stopCounting)
	self._downArrowBtn.bind('<Configure>', self._drawDownArrow)
	self._downArrowBtn.bind('<1>', self._countDown)
	self._downArrowBtn.bind('<Any-ButtonRelease-1>', self._stopCounting)
	self._counterEntry.bind('<Configure>', self._resizeArrow)
	entry = self._counterEntry.component('entry')
	entry.bind('<Down>', lambda event, s = self: s._key_decrement(event))
	entry.bind('<Up>', lambda event, s = self: s._key_increment(event))
	self._upArrowBtn.bind('<Unmap>', self._stopCounting)
	self._downArrowBtn.bind('<Unmap>', self._stopCounting)
	self.initialiseoptions()
    def _resizeArrow(self, event):

	for btn in (self._upArrowBtn, self._downArrowBtn):
	    bw = (string.atoi(btn['borderwidth']) +
		    string.atoi(btn['highlightthickness']))
	    newHeight = self._counterEntry.winfo_reqheight() - 2 * bw
	    newWidth = int(newHeight * self['buttonaspect'])
	    btn.configure(width=newWidth, height=newHeight)
	    self._drawArrow(btn)
    def _drawUpArrow(self, event):

	self._drawArrow(self._upArrowBtn)
    def _drawDownArrow(self, event):

	self._drawArrow(self._downArrowBtn)
    def _drawArrow(self, arrow):

        if self['orient'] == 'vertical':
            if arrow == self._upArrowBtn:
                direction = 'up'
            else:
                direction = 'down'
        else:
            if arrow == self._upArrowBtn:
                direction = 'right'
            else:
                direction = 'left'
        drawarrow(arrow, self['entry_foreground'], direction, 'arrow')
    def _stopCounting(self, event = None):

        if self._timerId is not None:
            self.after_cancel(self._timerId)
	    self._timerId = None
	if self._normalRelief is not None:
	    button, relief = self._normalRelief
	    button.configure(relief=relief)
	    self._normalRelief = None
    def _countUp(self, event):

	self._normalRelief = (self._upArrowBtn, self._upArrowBtn.cget('relief'))
	self._upArrowBtn.configure(relief='sunken')
	self._upArrowBtn.update_idletasks()
	self._count(1, 1)
    def _countDown(self, event):

	self._normalRelief = (self._downArrowBtn, self._downArrowBtn.cget('relief'))
	self._downArrowBtn.configure(relief='sunken')
	self._downArrowBtn.update_idletasks()
	self._count(-1, 1)
    def increment(self):

	self._forceCount(1)
    def decrement(self):

	self._forceCount(-1)
    def _key_increment(self, event):

	self._forceCount(1)
	self.update_idletasks()
    def _key_decrement(self, event):

	self._forceCount(-1)
	self.update_idletasks()
    def _datatype(self):

	datatype = self['datatype']
	if type(datatype) is types.DictionaryType:
	    self._counterArgs = datatype.copy()
	    if self._counterArgs.has_key('counter'):
		datatype = self._counterArgs['counter']
		del self._counterArgs['counter']
	    else:
		datatype = 'numeric'
	else:
	    self._counterArgs = {}
	if _counterCommands.has_key(datatype):
	    self._counterCommand = _counterCommands[datatype]
	elif callable(datatype):
	    self._counterCommand = datatype
	else:
	    validValues = _counterCommands.keys()
	    validValues.sort()
	    raise ValueError, ('bad datatype value "%s":  must be a' +
		    ' function or one of %s') % (datatype, validValues)
    def _forceCount(self, factor):

	if not self.valid():
	    self.bell()
	    return
	text = self._counterEntry.get()
	try:
	    value = apply(self._counterCommand,
		    (text, factor, self['increment']), self._counterArgs)
	except ValueError:
	    self.bell()
	    return
        previousICursor = self._counterEntry.index('insert')
	if self._counterEntry.setentry(value) == OK:
	    self._counterEntry.xview('end')
	    self._counterEntry.icursor(previousICursor)
    def _count(self, factor, first):

	if not self.valid():
	    self.bell()
	    return
	self._timerId = None
	origtext = self._counterEntry.get()
	try:
	    value = apply(self._counterCommand,
		    (origtext, factor, self['increment']), self._counterArgs)
	except ValueError:
	    self._stopCounting()
	    self.bell()
	    return
        previousICursor = self._counterEntry.index('insert')
	valid = self._counterEntry.setentry(value)
	if valid != OK:
	    self._stopCounting()
	    self._counterEntry.setentry(origtext)
	    if valid == PARTIAL:
		self.bell()
	    return
	self._counterEntry.xview('end')
	self._counterEntry.icursor(previousICursor)
	if self['autorepeat']:
	    if first:
		delay = self['initwait']
	    else:
		delay = self['repeatrate']
	    self._timerId = self.after(delay,
		    lambda self=self, factor=factor: self._count(factor, 0))
    def destroy(self):

	self._stopCounting()
        MegaWidget.destroy(self)
forwardmethods(Counter, EntryField, '_counterEntry')
def _changeNumber(text, factor, increment):

  value = string.atol(text)
  if factor > 0:
    value = (value / increment) * increment + increment
  else:
    value = ((value - 1) / increment) * increment
  rtn = str(value)
  if rtn[-1] == 'L':
      return rtn[:-1]
  else:
      return rtn
def _changeReal(text, factor, increment, separator = '.'):

  value = stringtoreal(text, separator)
  div = value / increment
  if str(div)[-2:] == '.0':
    div = round(div) + factor
  else:
    div = int(div) * 1.0
    if value < 0:
      div = div - 1
    if factor > 0:
      div = (div + 1)
  value = div * increment
  text = str(value)
  if separator != '.':
      index = string.find(text, '.')
      if index >= 0:
	text = text[:index] + separator + text[index + 1:]
  return text
def _changeDate(value, factor, increment, format = 'ymd',

	separator = '/', yyyy = 0):
  jdn = datestringtojdn(value, format, separator) + factor * increment
  y, m, d = jdntoymd(jdn)
  result = ''
  for index in range(3):
    if index > 0:
      result = result + separator
    f = format[index]
    if f == 'y':
      if yyyy:
        result = result + '%02d' % y
      else:
        result = result + '%02d' % (y % 100)
    elif f == 'm':
      result = result + '%02d' % m
    elif f == 'd':
      result = result + '%02d' % d
  return result
_SECSPERDAY = 24 * 60 * 60
def _changeTime(value, factor, increment, separator = ':', time24 = 0):

  unixTime = timestringtoseconds(value, separator)
  if factor > 0:
    chunks = unixTime / increment + 1
  else:
    chunks = (unixTime - 1) / increment
  unixTime = chunks * increment
  if time24:
      while unixTime < 0:
	  unixTime = unixTime + _SECSPERDAY
      while unixTime >= _SECSPERDAY:
	  unixTime = unixTime - _SECSPERDAY
  if unixTime < 0:
    unixTime = -unixTime
    sign = '-'
  else:
    sign = ''
  secs = unixTime % 60
  unixTime = unixTime / 60
  mins = unixTime % 60
  hours = unixTime / 60
  return '%s%02d%s%02d%s%02d' % (sign, hours, separator, mins, separator, secs)
_counterCommands = {
    'numeric'   : _changeNumber,
    'integer'   : _changeNumber,
    'real'      : _changeReal,
    'time'      : _changeTime,
    'date'      : _changeDate,
}
class CounterDialog(Dialog):


    def __init__(self, parent = None, **kw):

	optiondefs = (
	    ('borderx',    20,  INITOPT),
	    ('bordery',    20,  INITOPT),
	)
	self.defineoptions(kw, optiondefs)
	Dialog.__init__(self, parent)
	interior = self.interior()
	aliases = (
	    ('entryfield', 'counter_entryfield'),
	    ('entry', 'counter_entryfield_entry'),
	    ('label', 'counter_label')
	)
	self._cdCounter = self.createcomponent('counter',
		aliases, None,
		Counter, (interior,))
	self._cdCounter.pack(fill='x', expand=1,
		padx = self['borderx'], pady = self['bordery'])
        if not kw.has_key('activatecommand'):
            tkentry = self.component('entry')
            self.configure(activatecommand = tkentry.focus_set)
	self.initialiseoptions()
    def insertentry(self, index, text):

	self._cdCounter.insert(index, text)
    def deleteentry(self, first, last=None):

	self._cdCounter.delete(first, last)
    def indexentry(self, index):

	return self._cdCounter.index(index)
forwardmethods(CounterDialog, Counter, '_cdCounter')
import os
import string
def _font_initialise(root, size=None, fontScheme = None):

    global _fontSize
    if size is not None:
        _fontSize = size
    if fontScheme in ('pmw1', 'pmw2'):
        if os.name == 'posix':
            defaultFont = logicalfont('Helvetica')

            menuFont = logicalfont('Helvetica', weight='bold', slant='italic')
            scaleFont = logicalfont('Helvetica', slant='italic')
            root.option_add('*Font',            defaultFont,  'userDefault')
            root.option_add('*Menu*Font',       menuFont,     'userDefault')
            root.option_add('*Menubutton*Font', menuFont,     'userDefault')
            root.option_add('*Scale.*Font',     scaleFont,    'userDefault')
            if fontScheme == 'pmw1':
                balloonFont = logicalfont('Helvetica', -6, pixel = '12')
            else:
                balloonFont = logicalfont('Helvetica', -2)
            root.option_add('*Balloon.*Font', balloonFont, 'userDefault')
        else:
            defaultFont = logicalfont('Helvetica')

            root.option_add('*Font', defaultFont,  'userDefault')
    elif fontScheme == 'default':
        defaultFont = ('Helvetica', '-%d' % (_fontSize,), 'bold')

        entryFont = ('Helvetica', '-%d' % (_fontSize,))
        textFont = ('Courier', '-%d' % (_fontSize,))
        root.option_add('*Font',            defaultFont,  'userDefault')
        root.option_add('*Entry*Font',      entryFont,    'userDefault')
        root.option_add('*Text*Font',       textFont,     'userDefault')
def logicalfont(name='Helvetica', sizeIncr = 0, **kw):

  if not _fontInfo.has_key(name):
    raise ValueError, 'font %s does not exist' % name
  rtn = []
  for field in _fontFields:
    if kw.has_key(field):
      logicalValue = kw[field]
    elif _fontInfo[name].has_key(field):
      logicalValue = _fontInfo[name][field]
    else:
      logicalValue = '*'
    if _propertyAliases[name].has_key((field, logicalValue)):
      realValue = _propertyAliases[name][(field, logicalValue)]
    elif _propertyAliases[name].has_key((field, None)):
      realValue = _propertyAliases[name][(field, None)]
    elif _propertyAliases[None].has_key((field, logicalValue)):
      realValue = _propertyAliases[None][(field, logicalValue)]
    elif _propertyAliases[None].has_key((field, None)):
      realValue = _propertyAliases[None][(field, None)]
    else:
      realValue = logicalValue
    if field == 'size':
      if realValue == '*':
	  realValue = _fontSize
      realValue = str((realValue + sizeIncr) * 10)
    rtn.append(realValue)
  return string.join(rtn, '-')
def logicalfontnames():

  return _fontInfo.keys()
if os.name == 'nt':
    _fontSize = 16
else:
    _fontSize = 14
_fontFields = (
  'registry', 'foundry', 'family', 'weight', 'slant', 'width', 'style',
  'pixel', 'size', 'xres', 'yres', 'spacing', 'avgwidth', 'charset', 'encoding')
_propertyAliases = {}
_propertyAliases[None] = {
  ('slant', 'italic') : 'i',
  ('slant', 'normal') : 'r',
  ('weight', 'light') : 'normal',
  ('width', 'wide') : 'normal',
  ('width', 'condensed') : 'normal',
}
_fontInfo = {}
_fontInfo['Helvetica'] = {
  'foundry' : 'adobe',
  'family' : 'helvetica',
  'registry' : '',
  'charset' : 'iso8859',
  'encoding' : '1',
  'spacing' : 'p',
  'slant' : 'normal',
  'width' : 'normal',
  'weight' : 'normal',
}
_propertyAliases['Helvetica'] = {
  ('slant', 'italic') : 'o',
  ('weight', 'normal') : 'medium',
  ('weight', 'light') : 'medium',
}
_fontInfo['Times'] = {
  'foundry' : 'adobe',
  'family' : 'times',
  'registry' : '',
  'charset' : 'iso8859',
  'encoding' : '1',
  'spacing' : 'p',
  'slant' : 'normal',
  'width' : 'normal',
  'weight' : 'normal',
}
_propertyAliases['Times'] = {
  ('weight', 'normal') : 'medium',
  ('weight', 'light') : 'medium',
}
_fontInfo['Fixed'] = {
  'foundry' : 'misc',
  'family' : 'fixed',
  'registry' : '',
  'charset' : 'iso8859',
  'encoding' : '1',
  'spacing' : 'c',
  'slant' : 'normal',
  'width' : 'normal',
  'weight' : 'normal',
}
_propertyAliases['Fixed'] = {
  ('weight', 'normal') : 'medium',
  ('weight', 'light') : 'medium',
  ('style', None) : '',
  ('width', 'condensed') : 'semicondensed',
}
_fontInfo['Courier'] = {
  'foundry' : 'adobe',
  'family' : 'courier',
  'registry' : '',
  'charset' : 'iso8859',
  'encoding' : '1',
  'spacing' : 'm',
  'slant' : 'normal',
  'width' : 'normal',
  'weight' : 'normal',
}
_propertyAliases['Courier'] = {
  ('weight', 'normal') : 'medium',
  ('weight', 'light') : 'medium',
  ('style', None) : '',
}
_fontInfo['Typewriter'] = {
  'foundry' : 'b&h',
  'family' : 'lucidatypewriter',
  'registry' : '',
  'charset' : 'iso8859',
  'encoding' : '1',
  'spacing' : 'm',
  'slant' : 'normal',
  'width' : 'normal',
  'weight' : 'normal',
}
_propertyAliases['Typewriter'] = {
  ('weight', 'normal') : 'medium',
  ('weight', 'light') : 'medium',
}
if os.name == 'nt':
    _fontInfo['Fixed'] = _fontInfo['Courier']
    _propertyAliases['Fixed'] = _propertyAliases['Courier']