cpython/Tools/pynche/PyncheWidget.py

314 lines
10 KiB
Python
Raw Normal View History

1998-01-31 19:39:01 -04:00
"""Main Pynche (Pythonically Natural Color and Hue Editor) widget.
1998-10-02 13:06:27 -03:00
This window provides the basic decorations, primarily including the menubar.
It is used to bring up other windows.
1998-01-31 19:39:01 -04:00
"""
1998-12-03 15:50:24 -04:00
import sys
import os
from tkinter import *
from tkinter import messagebox, filedialog
import ColorDB
1998-01-31 19:39:01 -04:00
1998-09-28 20:38:44 -03:00
# Milliseconds between interrupt checks
KEEPALIVE_TIMER = 500
1998-02-17 18:25:23 -04:00
1998-02-12 15:52:31 -04:00
1998-09-28 20:38:44 -03:00
class PyncheWidget:
def __init__(self, version, switchboard, master=None, extrapath=[]):
self.__sb = switchboard
self.__version = version
self.__textwin = None
1998-10-02 13:05:48 -03:00
self.__listwin = None
1998-10-05 18:14:46 -03:00
self.__detailswin = None
1998-12-03 15:50:24 -04:00
self.__helpwin = None
self.__dialogstate = {}
modal = self.__modal = not not master
# If a master was given, we are running as a modal dialog servant to
# some other application. We rearrange our UI in this case (there's
# no File menu and we get `Okay' and `Cancel' buttons), and we do a
# grab_set() to make ourselves modal
if modal:
self.__tkroot = tkroot = Toplevel(master, class_='Pynche')
tkroot.grab_set()
tkroot.withdraw()
else:
# Is there already a default root for Tk, say because we're
# running under Guido's IDE? :-) Two conditions say no, either the
# _default_root is None or it is unset.
tkroot = getattr(tkinter, '_default_root', None)
if not tkroot:
tkroot = Tk(className='Pynche')
self.__tkroot = tkroot
# but this isn't our top level widget, so make it invisible
tkroot.withdraw()
1998-09-28 20:38:44 -03:00
# create the menubar
1998-10-06 16:39:34 -03:00
menubar = self.__menubar = Menu(tkroot)
1998-09-28 20:38:44 -03:00
#
# File menu
#
filemenu = self.__filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label='Load palette...',
command=self.__load,
underline=0)
if not modal:
filemenu.add_command(label='Quit',
command=self.__quit,
accelerator='Alt-Q',
underline=0)
1998-09-28 20:38:44 -03:00
#
# View menu
#
views = make_view_popups(self.__sb, self.__tkroot, extrapath)
1998-10-06 16:39:34 -03:00
viewmenu = Menu(menubar, tearoff=0)
for v in views:
viewmenu.add_command(label=v.menutext(),
command=v.popup,
underline=v.underline())
1998-10-06 16:39:34 -03:00
#
1998-09-28 20:38:44 -03:00
# Help menu
#
1998-10-06 16:39:34 -03:00
helpmenu = Menu(menubar, name='help', tearoff=0)
2003-10-24 17:09:23 -03:00
helpmenu.add_command(label='About Pynche...',
1998-09-28 20:38:44 -03:00
command=self.__popup_about,
underline=0)
1998-12-03 15:50:24 -04:00
helpmenu.add_command(label='Help...',
command=self.__popup_usage,
underline=0)
1998-10-06 16:39:34 -03:00
#
# Tie them all together
#
menubar.add_cascade(label='File',
menu=filemenu,
underline=0)
1998-10-06 16:39:34 -03:00
menubar.add_cascade(label='View',
menu=viewmenu,
underline=0)
menubar.add_cascade(label='Help',
menu=helpmenu,
underline=0)
# now create the top level window
root = self.__root = Toplevel(tkroot, class_='Pynche', menu=menubar)
root.protocol('WM_DELETE_WINDOW',
1998-10-22 15:46:28 -03:00
modal and self.__bell or self.__quit)
1998-10-06 16:39:34 -03:00
root.title('Pynche %s' % version)
root.iconname('Pynche')
# Only bind accelerators for the File->Quit menu item if running as a
# standalone app
if not modal:
root.bind('<Alt-q>', self.__quit)
root.bind('<Alt-Q>', self.__quit)
else:
# We're a modal dialog so we have a new row of buttons
bframe = Frame(root, borderwidth=1, relief=RAISED)
bframe.grid(row=4, column=0, columnspan=2,
sticky='EW',
ipady=5)
okay = Button(bframe,
text='Okay',
command=self.__okay)
okay.pack(side=LEFT, expand=1)
cancel = Button(bframe,
text='Cancel',
command=self.__cancel)
cancel.pack(side=LEFT, expand=1)
1998-10-06 16:50:33 -03:00
def __quit(self, event=None):
self.__tkroot.quit()
1998-10-22 15:46:28 -03:00
def __bell(self, event=None):
self.__tkroot.bell()
def __okay(self, event=None):
self.__sb.withdraw_views()
self.__tkroot.grab_release()
self.__quit()
def __cancel(self, event=None):
self.__sb.canceled()
self.__okay()
1998-09-28 20:38:44 -03:00
def __keepalive(self):
# Exercise the Python interpreter regularly so keyboard interrupts get
# through.
1998-10-06 16:39:34 -03:00
self.__tkroot.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
1998-02-12 15:52:31 -04:00
1998-09-28 20:38:44 -03:00
def start(self):
if not self.__modal:
self.__keepalive()
1998-10-06 16:39:34 -03:00
self.__tkroot.mainloop()
1998-02-17 18:25:23 -04:00
def window(self):
1998-09-28 20:38:44 -03:00
return self.__root
1998-02-17 18:25:23 -04:00
def __popup_about(self, event=None):
from Main import __version__
messagebox.showinfo('About Pynche ' + __version__,
'''\
Pynche %s
The PYthonically Natural
Color and Hue Editor
For information
contact: Barry A. Warsaw
email: bwarsaw@python.org''' % __version__)
1998-12-03 15:50:24 -04:00
def __popup_usage(self, event=None):
if not self.__helpwin:
self.__helpwin = Helpwin(self.__root, self.__quit)
self.__helpwin.deiconify()
def __load(self, event=None):
while 1:
idir, ifile = os.path.split(self.__sb.colordb().filename())
file = filedialog.askopenfilename(
filetypes=[('Text files', '*.txt'),
('All files', '*'),
],
initialdir=idir,
initialfile=ifile)
if not file:
# cancel button
return
try:
colordb = ColorDB.get_colordb(file)
except IOError:
messagebox.showerror('Read error', '''\
Could not open file for reading:
%s''' % file)
continue
if colordb is None:
messagebox.showerror('Unrecognized color file type', '''\
Unrecognized color file type in file:
%s''' % file)
continue
break
self.__sb.set_colordb(colordb)
def withdraw(self):
self.__root.withdraw()
1998-10-22 15:46:28 -03:00
def deiconify(self):
self.__root.deiconify()
1998-12-03 15:50:24 -04:00
class Helpwin:
def __init__(self, master, quitfunc):
from Main import docstring
1998-12-03 15:50:24 -04:00
self.__root = root = Toplevel(master, class_='Pynche')
root.protocol('WM_DELETE_WINDOW', self.__withdraw)
root.title('Pynche Help Window')
root.iconname('Pynche Help Window')
root.bind('<Alt-q>', quitfunc)
root.bind('<Alt-Q>', quitfunc)
root.bind('<Alt-w>', self.__withdraw)
root.bind('<Alt-W>', self.__withdraw)
# more elaborate help is available in the README file
readmefile = os.path.join(sys.path[0], 'README')
try:
fp = None
try:
fp = open(readmefile)
contents = fp.read()
# wax the last page, it contains Emacs cruft
2001-07-10 18:44:24 -03:00
i = contents.rfind('\f')
1998-12-03 15:50:24 -04:00
if i > 0:
2001-07-10 18:44:24 -03:00
contents = contents[:i].rstrip()
1998-12-03 15:50:24 -04:00
finally:
if fp:
fp.close()
except IOError:
sys.stderr.write("Couldn't open Pynche's README, "
'using docstring instead.\n')
contents = docstring()
self.__text = text = Text(root, relief=SUNKEN,
width=80, height=24)
self.__text.focus_set()
1998-12-03 15:50:24 -04:00
text.insert(0.0, contents)
scrollbar = Scrollbar(root)
scrollbar.pack(fill=Y, side=RIGHT)
text.pack(fill=BOTH, expand=YES)
text.configure(yscrollcommand=(scrollbar, 'set'))
scrollbar.configure(command=(text, 'yview'))
def __withdraw(self, event=None):
self.__root.withdraw()
def deiconify(self):
self.__root.deiconify()
import functools
@functools.total_ordering
class PopupViewer:
def __init__(self, module, name, switchboard, root):
self.__m = module
self.__name = name
self.__sb = switchboard
self.__root = root
self.__menutext = module.ADDTOVIEW
# find the underline character
2001-07-10 18:44:24 -03:00
underline = module.ADDTOVIEW.find('%')
if underline == -1:
underline = 0
else:
2001-07-10 18:44:24 -03:00
self.__menutext = module.ADDTOVIEW.replace('%', '', 1)
self.__underline = underline
self.__window = None
def menutext(self):
return self.__menutext
def underline(self):
return self.__underline
def popup(self, event=None):
if not self.__window:
# class and module must have the same name
class_ = getattr(self.__m, self.__name)
self.__window = class_(self.__sb, self.__root)
self.__sb.add_view(self.__window)
self.__window.deiconify()
def __eq__(self, other):
if isinstance(self, PopupViewer):
return self.__menutext == other.__menutext
return NotImplemented
def __lt__(self, other):
if isinstance(self, PopupViewer):
return self.__menutext < other.__menutext
return NotImplemented
def make_view_popups(switchboard, root, extrapath):
viewers = []
# where we are in the file system
dirs = [os.path.dirname(__file__)] + extrapath
for dir in dirs:
if dir == '':
dir = '.'
for file in os.listdir(dir):
if file[-9:] == 'Viewer.py':
name = file[:-3]
try:
module = __import__(name)
except ImportError:
# Pynche is running from inside a package, so get the
# module using the explicit path.
pkg = __import__('pynche.'+name)
module = getattr(pkg, name)
if hasattr(module, 'ADDTOVIEW') and module.ADDTOVIEW:
# this is an external viewer
v = PopupViewer(module, name, switchboard, root)
viewers.append(v)
# sort alphabetically
viewers.sort()
return viewers