| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- """Main Pynche (Pythonically Natural Color and Hue Editor) widget.
- This window provides the basic decorations, primarily including the menubar.
- It is used to bring up other windows.
- """
- import sys
- import os
- from tkinter import *
- from tkinter import messagebox, filedialog
- import ColorDB
- # Milliseconds between interrupt checks
- KEEPALIVE_TIMER = 500
- class PyncheWidget:
- def __init__(self, version, switchboard, master=None, extrapath=[]):
- self.__sb = switchboard
- self.__version = version
- self.__textwin = None
- self.__listwin = None
- self.__detailswin = None
- 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
- # import fails or _default_root is None.
- tkroot = None
- try:
- from Tkinter import _default_root
- tkroot = self.__tkroot = _default_root
- except ImportError:
- pass
- if not tkroot:
- tkroot = self.__tkroot = Tk(className='Pynche')
- # but this isn't our top level widget, so make it invisible
- tkroot.withdraw()
- # create the menubar
- menubar = self.__menubar = Menu(tkroot)
- #
- # 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)
- #
- # View menu
- #
- views = make_view_popups(self.__sb, self.__tkroot, extrapath)
- viewmenu = Menu(menubar, tearoff=0)
- for v in views:
- viewmenu.add_command(label=v.menutext(),
- command=v.popup,
- underline=v.underline())
- #
- # Help menu
- #
- helpmenu = Menu(menubar, name='help', tearoff=0)
- helpmenu.add_command(label='About Pynche...',
- command=self.__popup_about,
- underline=0)
- helpmenu.add_command(label='Help...',
- command=self.__popup_usage,
- underline=0)
- #
- # Tie them all together
- #
- menubar.add_cascade(label='File',
- menu=filemenu,
- underline=0)
- 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',
- modal and self.__bell or self.__quit)
- 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)
- def __quit(self, event=None):
- self.__tkroot.quit()
- 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()
- def __keepalive(self):
- # Exercise the Python interpreter regularly so keyboard interrupts get
- # through.
- self.__tkroot.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
- def start(self):
- if not self.__modal:
- self.__keepalive()
- self.__tkroot.mainloop()
- def window(self):
- return self.__root
- 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__)
- 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()
- def deiconify(self):
- self.__root.deiconify()
- class Helpwin:
- def __init__(self, master, quitfunc):
- from Main import docstring
- 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
- i = contents.rfind('\f')
- if i > 0:
- contents = contents[:i].rstrip()
- 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()
- 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
- underline = module.ADDTOVIEW.find('%')
- if underline == -1:
- underline = 0
- else:
- 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):
- return self.__menutext == other.__menutext
- def __lt__(self, other):
- return self.__menutext < other.__menutext
- 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
|