#! /usr/local/bin/python

# A Python function that generates dialog boxes with a text message,
# optional bitmap, and any number of buttons.
# Cf. Ousterhout, Tcl and the Tk Toolkit, Figs. 27.2-3, pp. 269-270.

from Tkinter import *

mainWidget = None

def dialog(master, title, text, bitmap, default, *args):

    # 1. Create the top-level window and divide it into top
    # and bottom parts.

    w = Toplevel(master, {'class': 'Dialog'})
    w.title(title)
    w.iconname('Dialog')

    top = Frame(w, {'relief': 'raised', 'bd': 1,
		    Pack: {'side': 'top', 'fill': 'both'}})
    bot = Frame(w, {'relief': 'raised', 'bd': 1,
		    Pack: {'side': 'bottom', 'fill': 'both'}})

    # 2. Fill the top part with the bitmap and message.

    msg = Message(top,
		  {'width': '3i',
		   'text': text,
		   'font': '-Adobe-Times-Medium-R-Normal-*-180-*',
		   Pack: {'side': 'right', 'expand': 1,
			  'fill': 'both',
			  'padx': '3m', 'pady': '3m'}})
    if bitmap:
	bm = Label(top, {'bitmap': bitmap,
			 Pack: {'side': 'left',
				'padx': '3m', 'pady': '3m'}})

    # 3. Create a row of buttons at the bottom of the dialog.

    buttons = []
    i = 0
    for but in args:
	b = Button(bot, {'text': but,
			 'command': ('set', 'button', i)})
	buttons.append(b)
	if i == default:
	    bd = Frame(bot, {'relief': 'sunken', 'bd': 1,
			     Pack: {'side': 'left', 'expand': 1,
				    'padx': '3m', 'pady': '2m'}})
	    b.lift()
	    b.pack ({'in': bd, 'side': 'left',
		     'padx': '2m', 'pady': '2m',
		     'ipadx': '2m', 'ipady': '1m'})
	else:
	    b.pack ({'side': 'left', 'expand': 1,
		     'padx': '3m', 'pady': '3m',
		     'ipady': '2m', 'ipady': '1m'})
	i = i+1

    # 4. Set up a binding for <Return>, if there's a default,
    # set a grab, and claim the focus too.

    if default >= 0:
	w.bind('<Return>',
	       lambda e, b=buttons[default], i=default:
	       (b.flash(),
		b.setvar('button', i)))

    oldFocus = w.tk.call('focus') # XXX
    w.grab_set()
    w.focus()

    # 5. Wait for the user to respond, then restore the focus
    # and return the index of the selected button.

    w.waitvar('button')
    w.destroy()
    w.tk.call('focus', oldFocus) # XXX
    return w.getint(w.getvar('button'))

def strdialog(master, title, text, bitmap, default, *args):

    # 1. Create the top-level window and divide it into top
    # and bottom parts.

    w = Toplevel(master, {'class': 'Dialog'})
    w.title(title)
    w.iconname('Dialog')

    top = Frame(w, {'relief': 'raised', 'bd': 1,
		    Pack: {'side': 'top', 'fill': 'both'}})
    if args:
	bot = Frame(w, {'relief': 'raised', 'bd': 1,
		    Pack: {'side': 'bottom', 'fill': 'both'}})

    # 2. Fill the top part with the bitmap, message and input field.

    if bitmap:
	bm = Label(top, {'bitmap': bitmap,
			 Pack: {'side': 'left',
				'padx': '3m', 'pady': '3m'}})

    msg = Message(top,
		  {'width': '3i',
		   'text': text,
		   'font': '-Adobe-Times-Medium-R-Normal-*-180-*',
		   Pack: {'side': 'left', 
			  'fill': 'both',
			  'padx': '3m', 'pady': '3m'}})

    field = Entry(top,
		  {'relief':'sunken',
		   Pack:{'side':'left',
			 'fill':'x',
			 'expand':1,
			 'padx':'3m', 'pady':'3m'}})
    # 3. Create a row of buttons at the bottom of the dialog.

    buttons = []
    i = 0
    for but in args:
	b = Button(bot, {'text': but,
			 'command': ('set', 'button', i)})
	buttons.append(b)
	if i == default:
	    bd = Frame(bot, {'relief': 'sunken', 'bd': 1,
			     Pack: {'side': 'left', 'expand': 1,
				    'padx': '3m', 'pady': '2m'}})
	    b.lift()
	    b.pack ({'in': bd, 'side': 'left',
		     'padx': '2m', 'pady': '2m',
		     'ipadx': '2m', 'ipady': '1m'})
	else:
	    b.pack ({'side': 'left', 'expand': 1,
		     'padx': '3m', 'pady': '3m',
		     'ipady': '2m', 'ipady': '1m'})
	i = i+1

    # 4. Set up a binding for <Return>, if there's a default,
    # set a grab, and claim the focus too.

    if not args:
	w.bind('<Return>', lambda arg, top=top: top.setvar('button', 0))
	field.bind('<Return>', lambda arg, top=top: top.setvar('button', 0))
    elif default >= 0:
	w.bind('<Return>',
	       lambda e, b=buttons[default], i=default:
	       (b.flash(),
		b.setvar('button', i)))
	field.bind('<Return>',
	       lambda e, b=buttons[default], i=default:
	       (b.flash(),
		b.setvar('button', i)))

    oldFocus = w.tk.call('focus') # XXX
    w.grab_set()
    field.focus()

    # 5. Wait for the user to respond, then restore the focus
    # and return the index of the selected button.

    w.waitvar('button')
    v = field.get()
    w.destroy()
    w.tk.call('focus', oldFocus) # XXX
    if args:
	return v, w.getint(w.getvar('button'))
    else:
	return v

def message(str):
    i = dialog(mainWidget, 'Message', str, '', 0, 'OK')

def askyn(str):
    i = dialog(mainWidget, 'Question', str, '', 0, 'No', 'Yes')
    return i

def askync(str):
    i = dialog(mainWidget, 'Question', str, '', 0, 'Cancel', 'No', 'Yes')
    return i-1

def askstr(str):
    i = strdialog(mainWidget, 'Question', str, '', 0)
    return i

def askfile(str):	# XXXX For now...
    i = strdialog(mainWidget, 'Question', str, '', 0)
    return i
    
# The rest is the test program.

def _go():
    i = dialog(mainWidget,
	       'Not Responding',
	       "The file server isn't responding right now; "
	       "I'll keep trying.",
	       '',
	       -1,
	       'OK')
    print 'pressed button', i
    i = dialog(mainWidget,
	       'File Modified',
	       'File "tcl.h" has been modified since '
	       'the last time it was saved. '
	       'Do you want to save it before exiting the application?',
	       'warning',
	       0,
	       'Save File',
	       'Discard Changes',
	       'Return To Editor')
    print 'pressed button', i
    print message('Test of message')
    print askyn('Test of yes/no')
    print askync('Test of yes/no/cancel')
    print askstr('Type a string:')
    print strdialog(mainWidget, 'Question', 'Another string:', '',
		  0, 'Save', 'Save as text')

def _test():
    import sys
    global mainWidget
    mainWidget = Frame()
    Pack.config(mainWidget)
    start = Button(mainWidget,
		   {'text': 'Press Here To Start', 'command': _go})
    start.pack()
    endit = Button(mainWidget,
		   {'text': 'Exit',
		    'command': 'exit',
		    Pack: {'fill' : 'both'}})
    mainWidget.mainloop()

if __name__ == '__main__':
    _test()
