New dialog routines (Fred Lundh)
diff --git a/Lib/lib-tk/tkColorChooser.py b/Lib/lib-tk/tkColorChooser.py
new file mode 100644
index 0000000..7ef63b4
--- /dev/null
+++ b/Lib/lib-tk/tkColorChooser.py
@@ -0,0 +1,72 @@
+#
+# Instant Python
+# $Id$
+#
+# tk common colour chooser dialogue
+#
+# this module provides an interface to the native color dialogue
+# available in Tk 4.2 and newer.
+#
+# written by Fredrik Lundh, May 1997
+#
+
+#
+# options (all have default values):
+#
+# - initialcolor: colour to mark as selected when dialog is displayed
+#   (given as an RGB triplet or a Tk color string)
+#
+# - parent: which window to place the dialog on top of
+#
+# - title: dialog title
+#
+
+# FIXME: as of Tk 8.0a2, the Unix colour picker is really ugly, and
+# doesn't seem to work properly on a true colour display.  maybe we
+# should use the instant python version instead?
+
+from tkCommonDialog import Dialog
+
+
+#
+# color chooser class
+
+class Chooser(Dialog):
+    "Ask for a color"
+
+    command = "tk_chooseColor"
+
+    def _fixoptions(self):
+        try:
+            # make sure initialcolor is a tk color string
+            color = self.options["initialcolor"]
+            if type(color) == type(()):
+                # assume an RGB triplet
+                self.options["initialcolor"] = "%02x%02x%02x" % color
+        except KeyError:
+            pass
+
+    def _fixresult(self, widget, result):
+        # to simplify application code, the color chooser returns
+        # an RGB tuple together with the Tk color string
+        if not result:
+            return None, None # cancelled
+        r, g, b = widget.winfo_rgb(result)
+        return (r/256, g/256, b/256), result
+
+
+#
+# convenience stuff
+
+def askcolor(color = None, **options):
+    "Ask for a color"
+
+    return apply(Chooser, (), options).show()
+
+
+# --------------------------------------------------------------------
+# test stuff
+
+if __name__ == "__main__":
+
+    print "color", askcolor()
diff --git a/Lib/lib-tk/tkCommonDialog.py b/Lib/lib-tk/tkCommonDialog.py
new file mode 100644
index 0000000..33126c5
--- /dev/null
+++ b/Lib/lib-tk/tkCommonDialog.py
@@ -0,0 +1,63 @@
+#
+# Instant Python
+# $Id$
+#
+# base class for tk common dialogues
+#
+# this module provides a base class for accessing the common
+# dialogues available in Tk 4.2 and newer.  use tkFileDialog,
+# tkColorChooser, and tkMessageBox to access the individual
+# dialogs.
+#
+# written by Fredrik Lundh, May 1997
+#
+
+from Tkinter import *
+import os
+
+class Dialog:
+
+    command  = None
+
+    def __init__(self, master=None, **options):
+
+        # FIXME: should this be placed on the module level instead?
+        if TkVersion < 4.2:
+            raise TclError, "this module requires Tk 4.2 or newer"
+
+	self.master  = master
+        self.options = options
+
+    def _fixoptions(self):
+        pass # hook
+
+    def _fixresult(self, widget, result):
+        return result # hook
+
+    def show(self, **options):
+
+        # update instance options
+	for k, v in options.items():
+	    self.options[k] = v
+
+        self._fixoptions()
+
+        # we need a stub widget to properly process the options
+        # (at least as long as we use Tkinter 1.63)
+        w = Frame(self.master)
+
+        try:
+
+            s = apply(w.tk.call, (self.command,) + w._options(self.options))
+
+            s = self._fixresult(w, s)
+
+        finally:
+
+            try:
+                # get rid of the widget
+                w.destroy()
+            except:
+                pass
+
+        return s
diff --git a/Lib/lib-tk/tkFileDialog.py b/Lib/lib-tk/tkFileDialog.py
new file mode 100644
index 0000000..e0d5ae5
--- /dev/null
+++ b/Lib/lib-tk/tkFileDialog.py
@@ -0,0 +1,106 @@
+#
+# Instant Python
+# $Id$
+#
+# tk common file dialogues
+#
+# this module provides interfaces to the native file dialogues
+# available in Tk 4.2 and newer.
+#
+# written by Fredrik Lundh, May 1997.
+#
+
+#
+# options (all have default values):
+#
+# - defaultextension: added to filename if not explicitly given
+#
+# - filetypes: sequence of (label, pattern) tuples.  the same pattern
+#   may occur with several patterns.  use "*" as pattern to indicate
+#   all files.
+#
+# - initialdir: initial directory.  preserved by dialog instance.
+#
+# - initialfile: initial file (ignored by the open dialog).  preserved
+#   by dialog instance.
+#
+# - parent: which window to place the dialog on top of
+#
+# - title: dialog title
+#
+
+from tkCommonDialog import Dialog
+
+class _Dialog(Dialog):
+
+    def _fixoptions(self):
+        try:
+            # make sure "filetypes" is a tuple
+            self.options["filetypes"] = tuple(self.options["filetypes"])
+        except KeyError:
+            pass
+
+    def _fixresult(self, widget, result):
+	if result:
+	    # keep directory and filename until next time
+            import os
+	    path, file = os.path.split(result)
+	    self.options["initialdir"] = path
+	    self.options["initialfile"] = file
+        self.filename = result # compatibility
+	return result
+
+
+#
+# file dialogs
+
+class Open(_Dialog):
+    "Ask for a filename to open"
+
+    command = "tk_getOpenFile"
+
+class SaveAs(_Dialog):
+    "Ask for a filename to save as"
+
+    command = "tk_getSaveFile"
+
+
+#
+# convenience stuff
+
+def askopenfilename(**options):
+    "Ask for a filename to open"
+
+    return apply(Open, (), options).show()
+
+def asksaveasfilename(**options):
+    "Ask for a filename to save as"
+
+    return apply(SaveAs, (), options).show()
+
+# FIXME: are the following two perhaps a bit too convenient?
+
+def askopenfile(mode = "r", **options):
+    "Ask for a filename to open, and returned the opened file"
+
+    filename = apply(Open, (), options).show()
+    if filename:
+        return open(filename, mode)
+    return None
+
+def asksaveasfile(mode = "w", **options):
+    "Ask for a filename to save as, and returned the opened file"
+
+    filename = apply(SaveAs, (), options).show()
+    if filename:
+        return open(filename, mode)
+    return None
+
+
+# --------------------------------------------------------------------
+# test stuff
+
+if __name__ == "__main__":
+
+    print "open", askopenfilename(filetypes=[("all filez", "*")])
+    print "saveas", asksaveasfilename()
diff --git a/Lib/lib-tk/tkMessageBox.py b/Lib/lib-tk/tkMessageBox.py
new file mode 100644
index 0000000..a6de8c6
--- /dev/null
+++ b/Lib/lib-tk/tkMessageBox.py
@@ -0,0 +1,120 @@
+#
+# Instant Python
+# $Id$
+#
+# tk common message boxes
+#
+# this module provides an interface to the native message boxes
+# available in Tk 4.2 and newer.
+#
+# written by Fredrik Lundh, May 1997
+#
+
+#
+# options (all have default values):
+#
+# - default: which button to make default (one of the reply codes)
+#
+# - icon: which icon to display (see below)
+#
+# - message: the message to display
+#
+# - parent: which window to place the dialog on top of
+#
+# - title: dialog title
+#
+# - type: dialog type; that is, which buttons to display (see below)
+#
+
+from tkCommonDialog import Dialog
+
+#
+# constants
+
+# icons
+ERROR = "error"
+INFO = "info"
+QUESTION = "question"
+WARNING = "warning"
+
+# types
+ABORTRETRYIGNORE = "abortretryignore"
+OK = "ok"
+OKCANCEL = "okcancel"
+RETRYCANCEL = "retrycancel"
+YESNO = "yesno"
+YESNOCANCEL = "yesnocancel"
+
+# replies
+ABORT = "abort"
+RETRY = "retry"
+IGNORE = "ignore"
+OK = "ok"
+CANCEL = "cancel"
+YES = "yes"
+NO = "no"
+
+
+#
+# message dialog class
+
+class Message(Dialog):
+    "A message box"
+
+    command  = "tk_messageBox"
+
+
+#
+# convenience stuff
+
+def _show(title=None, message=None, icon=None, type=None, **options):
+    if icon:    options["icon"] = icon
+    if type:    options["type"] = type
+    if title:   options["title"] = title
+    if message: options["message"] = message
+    return apply(Message, (), options).show()
+
+def showinfo(title=None, message=None, **options):
+    "Show an info message"
+    return apply(_show, (title, message, INFO, OK), options)
+
+def showwarning(title=None, message=None, **options):
+    "Show a warning message"
+    return apply(_show, (title, message, WARNING, OK), options)
+
+def showerror(title=None, message=None, **options):
+    "Show an error message"
+    return apply(_show, (title, message, ERROR, OK), options)
+
+def askquestion(title=None, message=None, **options):
+    "Ask a question"
+    return apply(_show, (title, message, QUESTION, YESNO), options)
+
+def askokcancel(title=None, message=None, **options):
+    "Ask if operation should proceed; return true if the answer is ok"
+    s = apply(_show, (title, message, QUESTION, OKCANCEL), options)
+    return s == OK
+
+def askyesno(title=None, message=None, **options):
+    "Ask a question; return true if the answer is yes"
+    s = apply(_show, (title, message, QUESTION, YESNO), options)
+    return s == YES
+
+def askretrycancel(title=None, message=None, **options):
+    "Ask if operation should be retried; return true if the answer is yes"
+    s = apply(_show, (title, message, WARNING, RETRYCANCEL), options)
+    return s == RETRY
+
+
+# --------------------------------------------------------------------
+# test stuff
+
+if __name__ == "__main__":
+
+    print "info", showinfo("Spam", "Egg Information")
+    print "warning", showwarning("Spam", "Egg Warning")
+    print "error", showerror("Spam", "Egg Alert")
+    print "question", askquestion("Spam", "Question?")
+    print "proceed", askokcancel("Spam", "Proceed?")
+    print "yes/no", askyesno("Spam", "Got it?")
+    print "try again", askretrycancel("Spam", "Try again?")
diff --git a/Lib/tkinter/tkColorChooser.py b/Lib/tkinter/tkColorChooser.py
new file mode 100644
index 0000000..7ef63b4
--- /dev/null
+++ b/Lib/tkinter/tkColorChooser.py
@@ -0,0 +1,72 @@
+#
+# Instant Python
+# $Id$
+#
+# tk common colour chooser dialogue
+#
+# this module provides an interface to the native color dialogue
+# available in Tk 4.2 and newer.
+#
+# written by Fredrik Lundh, May 1997
+#
+
+#
+# options (all have default values):
+#
+# - initialcolor: colour to mark as selected when dialog is displayed
+#   (given as an RGB triplet or a Tk color string)
+#
+# - parent: which window to place the dialog on top of
+#
+# - title: dialog title
+#
+
+# FIXME: as of Tk 8.0a2, the Unix colour picker is really ugly, and
+# doesn't seem to work properly on a true colour display.  maybe we
+# should use the instant python version instead?
+
+from tkCommonDialog import Dialog
+
+
+#
+# color chooser class
+
+class Chooser(Dialog):
+    "Ask for a color"
+
+    command = "tk_chooseColor"
+
+    def _fixoptions(self):
+        try:
+            # make sure initialcolor is a tk color string
+            color = self.options["initialcolor"]
+            if type(color) == type(()):
+                # assume an RGB triplet
+                self.options["initialcolor"] = "%02x%02x%02x" % color
+        except KeyError:
+            pass
+
+    def _fixresult(self, widget, result):
+        # to simplify application code, the color chooser returns
+        # an RGB tuple together with the Tk color string
+        if not result:
+            return None, None # cancelled
+        r, g, b = widget.winfo_rgb(result)
+        return (r/256, g/256, b/256), result
+
+
+#
+# convenience stuff
+
+def askcolor(color = None, **options):
+    "Ask for a color"
+
+    return apply(Chooser, (), options).show()
+
+
+# --------------------------------------------------------------------
+# test stuff
+
+if __name__ == "__main__":
+
+    print "color", askcolor()
diff --git a/Lib/tkinter/tkCommonDialog.py b/Lib/tkinter/tkCommonDialog.py
new file mode 100644
index 0000000..33126c5
--- /dev/null
+++ b/Lib/tkinter/tkCommonDialog.py
@@ -0,0 +1,63 @@
+#
+# Instant Python
+# $Id$
+#
+# base class for tk common dialogues
+#
+# this module provides a base class for accessing the common
+# dialogues available in Tk 4.2 and newer.  use tkFileDialog,
+# tkColorChooser, and tkMessageBox to access the individual
+# dialogs.
+#
+# written by Fredrik Lundh, May 1997
+#
+
+from Tkinter import *
+import os
+
+class Dialog:
+
+    command  = None
+
+    def __init__(self, master=None, **options):
+
+        # FIXME: should this be placed on the module level instead?
+        if TkVersion < 4.2:
+            raise TclError, "this module requires Tk 4.2 or newer"
+
+	self.master  = master
+        self.options = options
+
+    def _fixoptions(self):
+        pass # hook
+
+    def _fixresult(self, widget, result):
+        return result # hook
+
+    def show(self, **options):
+
+        # update instance options
+	for k, v in options.items():
+	    self.options[k] = v
+
+        self._fixoptions()
+
+        # we need a stub widget to properly process the options
+        # (at least as long as we use Tkinter 1.63)
+        w = Frame(self.master)
+
+        try:
+
+            s = apply(w.tk.call, (self.command,) + w._options(self.options))
+
+            s = self._fixresult(w, s)
+
+        finally:
+
+            try:
+                # get rid of the widget
+                w.destroy()
+            except:
+                pass
+
+        return s
diff --git a/Lib/tkinter/tkFileDialog.py b/Lib/tkinter/tkFileDialog.py
new file mode 100644
index 0000000..e0d5ae5
--- /dev/null
+++ b/Lib/tkinter/tkFileDialog.py
@@ -0,0 +1,106 @@
+#
+# Instant Python
+# $Id$
+#
+# tk common file dialogues
+#
+# this module provides interfaces to the native file dialogues
+# available in Tk 4.2 and newer.
+#
+# written by Fredrik Lundh, May 1997.
+#
+
+#
+# options (all have default values):
+#
+# - defaultextension: added to filename if not explicitly given
+#
+# - filetypes: sequence of (label, pattern) tuples.  the same pattern
+#   may occur with several patterns.  use "*" as pattern to indicate
+#   all files.
+#
+# - initialdir: initial directory.  preserved by dialog instance.
+#
+# - initialfile: initial file (ignored by the open dialog).  preserved
+#   by dialog instance.
+#
+# - parent: which window to place the dialog on top of
+#
+# - title: dialog title
+#
+
+from tkCommonDialog import Dialog
+
+class _Dialog(Dialog):
+
+    def _fixoptions(self):
+        try:
+            # make sure "filetypes" is a tuple
+            self.options["filetypes"] = tuple(self.options["filetypes"])
+        except KeyError:
+            pass
+
+    def _fixresult(self, widget, result):
+	if result:
+	    # keep directory and filename until next time
+            import os
+	    path, file = os.path.split(result)
+	    self.options["initialdir"] = path
+	    self.options["initialfile"] = file
+        self.filename = result # compatibility
+	return result
+
+
+#
+# file dialogs
+
+class Open(_Dialog):
+    "Ask for a filename to open"
+
+    command = "tk_getOpenFile"
+
+class SaveAs(_Dialog):
+    "Ask for a filename to save as"
+
+    command = "tk_getSaveFile"
+
+
+#
+# convenience stuff
+
+def askopenfilename(**options):
+    "Ask for a filename to open"
+
+    return apply(Open, (), options).show()
+
+def asksaveasfilename(**options):
+    "Ask for a filename to save as"
+
+    return apply(SaveAs, (), options).show()
+
+# FIXME: are the following two perhaps a bit too convenient?
+
+def askopenfile(mode = "r", **options):
+    "Ask for a filename to open, and returned the opened file"
+
+    filename = apply(Open, (), options).show()
+    if filename:
+        return open(filename, mode)
+    return None
+
+def asksaveasfile(mode = "w", **options):
+    "Ask for a filename to save as, and returned the opened file"
+
+    filename = apply(SaveAs, (), options).show()
+    if filename:
+        return open(filename, mode)
+    return None
+
+
+# --------------------------------------------------------------------
+# test stuff
+
+if __name__ == "__main__":
+
+    print "open", askopenfilename(filetypes=[("all filez", "*")])
+    print "saveas", asksaveasfilename()
diff --git a/Lib/tkinter/tkMessageBox.py b/Lib/tkinter/tkMessageBox.py
new file mode 100644
index 0000000..a6de8c6
--- /dev/null
+++ b/Lib/tkinter/tkMessageBox.py
@@ -0,0 +1,120 @@
+#
+# Instant Python
+# $Id$
+#
+# tk common message boxes
+#
+# this module provides an interface to the native message boxes
+# available in Tk 4.2 and newer.
+#
+# written by Fredrik Lundh, May 1997
+#
+
+#
+# options (all have default values):
+#
+# - default: which button to make default (one of the reply codes)
+#
+# - icon: which icon to display (see below)
+#
+# - message: the message to display
+#
+# - parent: which window to place the dialog on top of
+#
+# - title: dialog title
+#
+# - type: dialog type; that is, which buttons to display (see below)
+#
+
+from tkCommonDialog import Dialog
+
+#
+# constants
+
+# icons
+ERROR = "error"
+INFO = "info"
+QUESTION = "question"
+WARNING = "warning"
+
+# types
+ABORTRETRYIGNORE = "abortretryignore"
+OK = "ok"
+OKCANCEL = "okcancel"
+RETRYCANCEL = "retrycancel"
+YESNO = "yesno"
+YESNOCANCEL = "yesnocancel"
+
+# replies
+ABORT = "abort"
+RETRY = "retry"
+IGNORE = "ignore"
+OK = "ok"
+CANCEL = "cancel"
+YES = "yes"
+NO = "no"
+
+
+#
+# message dialog class
+
+class Message(Dialog):
+    "A message box"
+
+    command  = "tk_messageBox"
+
+
+#
+# convenience stuff
+
+def _show(title=None, message=None, icon=None, type=None, **options):
+    if icon:    options["icon"] = icon
+    if type:    options["type"] = type
+    if title:   options["title"] = title
+    if message: options["message"] = message
+    return apply(Message, (), options).show()
+
+def showinfo(title=None, message=None, **options):
+    "Show an info message"
+    return apply(_show, (title, message, INFO, OK), options)
+
+def showwarning(title=None, message=None, **options):
+    "Show a warning message"
+    return apply(_show, (title, message, WARNING, OK), options)
+
+def showerror(title=None, message=None, **options):
+    "Show an error message"
+    return apply(_show, (title, message, ERROR, OK), options)
+
+def askquestion(title=None, message=None, **options):
+    "Ask a question"
+    return apply(_show, (title, message, QUESTION, YESNO), options)
+
+def askokcancel(title=None, message=None, **options):
+    "Ask if operation should proceed; return true if the answer is ok"
+    s = apply(_show, (title, message, QUESTION, OKCANCEL), options)
+    return s == OK
+
+def askyesno(title=None, message=None, **options):
+    "Ask a question; return true if the answer is yes"
+    s = apply(_show, (title, message, QUESTION, YESNO), options)
+    return s == YES
+
+def askretrycancel(title=None, message=None, **options):
+    "Ask if operation should be retried; return true if the answer is yes"
+    s = apply(_show, (title, message, WARNING, RETRYCANCEL), options)
+    return s == RETRY
+
+
+# --------------------------------------------------------------------
+# test stuff
+
+if __name__ == "__main__":
+
+    print "info", showinfo("Spam", "Egg Information")
+    print "warning", showwarning("Spam", "Egg Warning")
+    print "error", showerror("Spam", "Egg Alert")
+    print "question", askquestion("Spam", "Question?")
+    print "proceed", askokcancel("Spam", "Proceed?")
+    print "yes/no", askyesno("Spam", "Got it?")
+    print "try again", askretrycancel("Spam", "Try again?")