diff options
-rw-r--r-- | Tools/pynche/ChipViewer.py | 22 | ||||
-rw-r--r-- | Tools/pynche/DetailsViewer.py | 12 | ||||
-rw-r--r-- | Tools/pynche/ListViewer.py | 12 | ||||
-rw-r--r-- | Tools/pynche/Main.py | 76 | ||||
-rw-r--r-- | Tools/pynche/PyncheWidget.py | 104 | ||||
-rw-r--r-- | Tools/pynche/StripViewer.py | 27 | ||||
-rw-r--r-- | Tools/pynche/Switchboard.py | 20 | ||||
-rw-r--r-- | Tools/pynche/TextViewer.py | 12 | ||||
-rw-r--r-- | Tools/pynche/TypeinViewer.py | 4 | ||||
-rw-r--r-- | Tools/pynche/pyColorChooser.py | 87 |
10 files changed, 256 insertions, 120 deletions
diff --git a/Tools/pynche/ChipViewer.py b/Tools/pynche/ChipViewer.py index fbf9aad..5bd0bdf 100644 --- a/Tools/pynche/ChipViewer.py +++ b/Tools/pynche/ChipViewer.py @@ -23,7 +23,7 @@ class ChipWidget: _HEIGHT = 80 def __init__(self, - parent = None, + master = None, width = _WIDTH, height = _HEIGHT, text = 'Color', @@ -31,16 +31,16 @@ class ChipWidget: presscmd = None, releasecmd = None): # create the text label - self.__label = Label(parent, text=text) + self.__label = Label(master, text=text) self.__label.grid(row=0, column=0) # create the color chip, implemented as a frame - self.__chip = Frame(parent, relief=RAISED, borderwidth=2, + self.__chip = Frame(master, relief=RAISED, borderwidth=2, width=width, height=height, background=initialcolor) self.__chip.grid(row=1, column=0) # create the color name, ctor argument must be a string - self.__name = Label(parent, text=initialcolor) + self.__name = Label(master, text=initialcolor) self.__name.grid(row=2, column=0) # # set bindings @@ -65,10 +65,10 @@ class ChipWidget: class ChipViewer: - def __init__(self, switchboard, parent=None): + def __init__(self, switchboard, master=None): self.__sb = switchboard - self.__frame = Frame(parent) #, relief=GROOVE, borderwidth=2) - self.__frame.grid(row=3, column=0) + self.__frame = Frame(master, relief=RAISED, borderwidth=1) + self.__frame.grid(row=3, column=0, ipadx=5) # create the chip that will display the currently selected color # exactly self.__sframe = Frame(self.__frame) @@ -81,11 +81,6 @@ class ChipViewer: self.__nearest = ChipWidget(self.__nframe, text='Nearest', presscmd = self.__buttonpress, releasecmd = self.__buttonrelease) - self.__div = Frame(self.__frame, - width=2, - borderwidth=2, - relief=RAISED) - self.__div.grid(row=0, column=2, sticky='NS', padx=5) def update_yourself(self, red, green, blue): # TBD: should exactname default to X11 color name if their is an exact @@ -110,6 +105,3 @@ class ChipViewer: colorname = self.__nearest.get_color() red, green, blue = self.__sb.colordb().find_byname(colorname) self.__sb.update_views(red, green, blue) - - def save_options(self, optiondb): - pass diff --git a/Tools/pynche/DetailsViewer.py b/Tools/pynche/DetailsViewer.py index da9bbf9..6996423 100644 --- a/Tools/pynche/DetailsViewer.py +++ b/Tools/pynche/DetailsViewer.py @@ -61,19 +61,19 @@ GRAV = 'Squash' class DetailsViewer: - def __init__(self, switchboard, parent=None): + def __init__(self, switchboard, master=None): self.__sb = switchboard optiondb = switchboard.optiondb() self.__red, self.__green, self.__blue = switchboard.current_rgb() # GUI - root = self.__root = Toplevel(parent, class_='Pynche') - root.protocol('WM_DELETE_WINDOW', self.__withdraw) + root = self.__root = Toplevel(master, class_='Pynche') + root.protocol('WM_DELETE_WINDOW', self.withdraw) root.title('Pynche Details Window') root.iconname('Pynche Details Window') root.bind('<Alt-q>', self.__quit) root.bind('<Alt-Q>', self.__quit) - root.bind('<Alt-w>', self.__withdraw) - root.bind('<Alt-W>', self.__withdraw) + root.bind('<Alt-w>', self.withdraw) + root.bind('<Alt-W>', self.withdraw) # accelerators root.bind('<KeyPress-Left>', self.__minus1) root.bind('<KeyPress-Right>', self.__plus1) @@ -158,7 +158,7 @@ class DetailsViewer: def __quit(self, event=None): self.__root.quit() - def __withdraw(self, event=None): + def withdraw(self, event=None): self.__root.withdraw() def deiconify(self, event=None): diff --git a/Tools/pynche/ListViewer.py b/Tools/pynche/ListViewer.py index 9ba2a53..eb43a92 100644 --- a/Tools/pynche/ListViewer.py +++ b/Tools/pynche/ListViewer.py @@ -19,20 +19,20 @@ from Tkinter import * import ColorDB class ListViewer: - def __init__(self, switchboard, parent=None): + def __init__(self, switchboard, master=None): self.__sb = switchboard optiondb = switchboard.optiondb() self.__lastbox = None self.__dontcenter = 0 # GUI - root = self.__root = Toplevel(parent, class_='Pynche') - root.protocol('WM_DELETE_WINDOW', self.__withdraw) + root = self.__root = Toplevel(master, class_='Pynche') + root.protocol('WM_DELETE_WINDOW', self.withdraw) root.title('Pynche Color List') root.iconname('Pynche Color List') root.bind('<Alt-q>', self.__quit) root.bind('<Alt-Q>', self.__quit) - root.bind('<Alt-w>', self.__withdraw) - root.bind('<Alt-W>', self.__withdraw) + root.bind('<Alt-w>', self.withdraw) + root.bind('<Alt-W>', self.withdraw) # # create the canvas which holds everything, and its scrollbar # @@ -125,7 +125,7 @@ class ListViewer: def __quit(self, event=None): self.__root.quit() - def __withdraw(self, event=None): + def withdraw(self, event=None): self.__root.withdraw() def deiconify(self, event=None): diff --git a/Tools/pynche/Main.py b/Tools/pynche/Main.py index bb5329e..f266a8d 100644 --- a/Tools/pynche/Main.py +++ b/Tools/pynche/Main.py @@ -104,34 +104,7 @@ def initial_color(s, colordb): -def main(): - try: - opts, args = getopt.getopt( - sys.argv[1:], - 'hd:i:X', - ['database=', 'initfile=', 'ignore', 'help']) - except getopt.error, msg: - usage(1, msg) - - if len(args) == 0: - initialcolor = None - elif len(args) == 1: - initialcolor = args[0] - else: - usage(1) - - ignore = 0 - initfile = os.path.expanduser('~/.pynche') - for opt, arg in opts: - if opt in ('-h', '--help'): - usage(0) - elif opt in ('-d', '--database'): - RGB_TXT.insert(0, arg) - elif opt in ('-X', '--ignore'): - ignore = 1 - elif opt in ('-i', '--initfile'): - initfile = arg - +def build(master=None, initialcolor=None, initfile=None, ignore=None): # create the windows and go for f in RGB_TXT: try: @@ -147,12 +120,12 @@ def main(): s = Switchboard(colordb, not ignore and initfile) # create the application window decorations - app = PyncheWidget(__version__, s) - parent = app.parent() + app = PyncheWidget(__version__, s, master=master) + w = app.window() - s.add_view(StripViewer(s, parent)) - s.add_view(ChipViewer(s, parent)) - s.add_view(TypeinViewer(s, parent)) + s.add_view(StripViewer(s, w)) + s.add_view(ChipViewer(s, w)) + s.add_view(TypeinViewer(s, w)) # get the initial color as components and set the color on all views. if # there was no initial color given on the command line, use the one that's @@ -168,15 +141,48 @@ def main(): else: red, green, blue = initial_color(initialcolor, colordb) s.update_views(red, green, blue) + return app, s + +def run(app, s): try: app.start() except KeyboardInterrupt: pass - # save the option database - s.save_views(initfile) + s.save_views() + + + +def main(): + try: + opts, args = getopt.getopt( + sys.argv[1:], + 'hd:i:X', + ['database=', 'initfile=', 'ignore', 'help']) + except getopt.error, msg: + usage(1, msg) + + if len(args) == 0: + initialcolor = None + elif len(args) == 1: + initialcolor = args[0] + else: + usage(1) + + ignore = 0 + initfile = os.path.expanduser('~/.pynche') + for opt, arg in opts: + if opt in ('-h', '--help'): + usage(0) + elif opt in ('-d', '--database'): + RGB_TXT.insert(0, arg) + elif opt in ('-X', '--ignore'): + ignore = 1 + elif opt in ('-i', '--initfile'): + initfile = arg + run() if __name__ == '__main__': diff --git a/Tools/pynche/PyncheWidget.py b/Tools/pynche/PyncheWidget.py index 4052357..fcabd24 100644 --- a/Tools/pynche/PyncheWidget.py +++ b/Tools/pynche/PyncheWidget.py @@ -13,36 +13,46 @@ KEEPALIVE_TIMER = 500 class PyncheWidget: - def __init__(self, version, switchboard): + def __init__(self, version, switchboard, master=None): self.__sb = switchboard self.__version = version self.__textwin = None self.__listwin = None self.__detailswin = None - # - # 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() + 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='Quit', - command=self.__quit, - accelerator='Alt-Q', - underline=0) + if not modal: + filemenu = self.__filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Quit', + command=self.__quit, + accelerator='Alt-Q', + underline=0) # # View menu # @@ -66,9 +76,10 @@ class PyncheWidget: # # Tie them all together # - menubar.add_cascade(label='File', - menu=filemenu, - underline=0) + if not modal: + menubar.add_cascade(label='File', + menu=filemenu, + underline=0) menubar.add_cascade(label='View', menu=viewmenu, underline=0) @@ -78,15 +89,44 @@ class PyncheWidget: # now create the top level window root = self.__root = Toplevel(tkroot, class_='Pynche', menu=menubar) - root.protocol('WM_DELETE_WINDOW', self.__quit) + root.protocol('WM_DELETE_WINDOW', + modal and self.__beep or self.__quit) root.title('Pynche %s' % version) root.iconname('Pynche') - root.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive) - root.bind('<Alt-q>', self.__quit) - root.bind('<Alt-Q>', self.__quit) + # 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.__root.quit() + self.__tkroot.quit() + + def __beep(self, event=None): + self.__tkroot.beep() + + 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 @@ -94,10 +134,11 @@ class PyncheWidget: self.__tkroot.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive) def start(self): - self.__keepalive() + if not self.__modal: + self.__keepalive() self.__tkroot.mainloop() - def parent(self): + def window(self): return self.__root def __popup_about(self, event=None): @@ -135,3 +176,6 @@ email : bwarsaw@python.org''' % __version__) self.__detailswin = DetailsViewer(self.__sb, self.__root) self.__sb.add_view(self.__detailswin) self.__detailswin.deiconify() + + def withdraw(self): + self.__root.withdraw() diff --git a/Tools/pynche/StripViewer.py b/Tools/pynche/StripViewer.py index 7bbfcca..f085fec 100644 --- a/Tools/pynche/StripViewer.py +++ b/Tools/pynche/StripViewer.py @@ -147,7 +147,7 @@ class StripWidget: _NUMCHIPS = 40 def __init__(self, switchboard, - parent = None, + master = None, chipwidth = _CHIPWIDTH, chipheight = _CHIPHEIGHT, numchips = _NUMCHIPS, @@ -171,13 +171,12 @@ class StripWidget: canvasheight = chipheight + 43 # TBD: Kludge # create the canvas and pack it - canvas = self.__canvas = Canvas( - parent, - width=canvaswidth, - height=canvasheight, -## borderwidth=2, -## relief=GROOVE - ) + canvas = self.__canvas = Canvas(master, + width=canvaswidth, + height=canvasheight, +## borderwidth=2, +## relief=GROOVE + ) canvas.pack() canvas.bind('<ButtonPress-1>', self.__select_chip) @@ -296,11 +295,11 @@ class StripWidget: class StripViewer: - def __init__(self, switchboard, parent=None): + def __init__(self, switchboard, master=None): self.__sb = switchboard optiondb = switchboard.optiondb() - # create a frame inside the parent - self.__frame = Frame(parent) #, relief=GROOVE, borderwidth=2) + # create a frame inside the master + self.__frame = Frame(master, relief=RAISED, borderwidth=1) self.__frame.grid(row=1, column=0, columnspan=2, sticky='EW') uwd = self.__uwdvar = BooleanVar() uwd.set(optiondb.get('UPWHILEDRAG', 0)) @@ -338,12 +337,6 @@ class StripViewer: command=self.__togglehex) self.__hex.grid(row=1, column=0, sticky=W) - self.__div = Frame(self.__frame, - height=2, - borderwidth=2, - relief=RAISED) - self.__div.pack(expand=1, fill=X) - def update_yourself(self, red, green, blue): self.__reds.update_yourself(red, green, blue) self.__greens.update_yourself(red, green, blue) diff --git a/Tools/pynche/Switchboard.py b/Tools/pynche/Switchboard.py index 7ac3df1..d8fd14c 100644 --- a/Tools/pynche/Switchboard.py +++ b/Tools/pynche/Switchboard.py @@ -17,12 +17,14 @@ import marshal class Switchboard: def __init__(self, colordb, initfile): + self.__initfile = initfile self.__colordb = colordb self.__optiondb = {} self.__views = [] self.__red = 0 self.__green = 0 self.__blue = 0 + self.__canceled = 0 # read the initialization file fp = None if initfile: @@ -61,17 +63,18 @@ class Switchboard: def optiondb(self): return self.__optiondb - def save_views(self, file): + def save_views(self): # save the current color self.__optiondb['RED'] = self.__red self.__optiondb['GREEN'] = self.__green self.__optiondb['BLUE'] = self.__blue for v in self.__views: - v.save_options(self.__optiondb) + if hasattr(v, 'save_options'): + v.save_options(self.__optiondb) fp = None try: try: - fp = open(file, 'w') + fp = open(self.__initfile, 'w') except IOError: print 'Cannot write options to file:', file else: @@ -79,3 +82,14 @@ class Switchboard: finally: if fp: fp.close() + + def withdraw_views(self): + for v in self.__views: + if hasattr(v, 'withdraw'): + v.withdraw() + + def canceled(self): + self.__canceled = 1 + + def canceled_p(self): + return self.__canceled diff --git a/Tools/pynche/TextViewer.py b/Tools/pynche/TextViewer.py index 7e8cec5..a3e9ac5 100644 --- a/Tools/pynche/TextViewer.py +++ b/Tools/pynche/TextViewer.py @@ -19,17 +19,17 @@ from Tkinter import * import ColorDB class TextViewer: - def __init__(self, switchboard, parent=None): + def __init__(self, switchboard, master=None): self.__sb = switchboard optiondb = switchboard.optiondb() - root = self.__root = Toplevel(parent, class_='Pynche') - root.protocol('WM_DELETE_WINDOW', self.__withdraw) + root = self.__root = Toplevel(master, class_='Pynche') + root.protocol('WM_DELETE_WINDOW', self.withdraw) root.title('Pynche Text Window') root.iconname('Pynche Text Window') root.bind('<Alt-q>', self.__quit) root.bind('<Alt-Q>', self.__quit) - root.bind('<Alt-w>', self.__withdraw) - root.bind('<Alt-W>', self.__withdraw) + root.bind('<Alt-w>', self.withdraw) + root.bind('<Alt-W>', self.withdraw) # # create the text widget # @@ -114,7 +114,7 @@ and choosing a color.''')) def __quit(self, event=None): self.__root.quit() - def __withdraw(self, event=None): + def withdraw(self, event=None): self.__root.withdraw() def deiconify(self, event=None): diff --git a/Tools/pynche/TypeinViewer.py b/Tools/pynche/TypeinViewer.py index 13cb9c7..d10d2a9 100644 --- a/Tools/pynche/TypeinViewer.py +++ b/Tools/pynche/TypeinViewer.py @@ -17,7 +17,7 @@ import string import re class TypeinViewer: - def __init__(self, switchboard, parent=None): + def __init__(self, switchboard, master=None): # non-gui ivars self.__sb = switchboard optiondb = switchboard.optiondb() @@ -26,7 +26,7 @@ class TypeinViewer: self.__uwtyping = BooleanVar() self.__uwtyping.set(optiondb.get('UPWHILETYPE', 0)) # create the gui - self.__frame = Frame(parent) #, relief=GROOVE, borderwidth=2) + self.__frame = Frame(master, relief=RAISED, borderwidth=1) self.__frame.grid(row=3, column=1, sticky='NS') # Red self.__xl = Label(self.__frame, text='Red:') diff --git a/Tools/pynche/pyColorChooser.py b/Tools/pynche/pyColorChooser.py new file mode 100644 index 0000000..f2dc6ac --- /dev/null +++ b/Tools/pynche/pyColorChooser.py @@ -0,0 +1,87 @@ +"""Color chooser implementing (almost) the tkColorColor interface +""" + +import os +from PyncheWidget import PyncheWidget +import Main +import ColorDB + +class Chooser: + """Ask for a color""" + def __init__(self, + master = None, + initialcolor = None, + databasefile = None, + initfile = None, + ignore = None): + self.__master = master + self.__initialcolor = initialcolor + self.__databasefile = databasefile + self.__initfile = initfile or os.path.expanduser('~/.pynche') + self.__ignore = ignore + self.__pw = None + + def show(self): + if not self.__pw: + self.__pw, self.__sb = \ + Main.build(master = self.__master, + initialcolor = self.__initialcolor, + initfile = self.__initfile, + ignore = self.__ignore) + Main.run(self.__pw, self.__sb) + rgbtuple = self.__sb.current_rgb() + self.__pw.withdraw() + # check to see if the cancel button was pushed + if self.__sb.canceled_p(): + return None, None + colordb = self.__sb.colordb() + # try to return the color name from the database if there is an exact + # match, otherwise use the "#rrggbb" spec. TBD: Forget about color + # aliases for now, maybe later we should return these too. + try: + name = colordb.find_byrgb(rgbtuple)[0] + except ColorDB.BadColor: + name = ColorDB.triplet_to_rrggbb(rgbtuple) + return rgbtuple, name + + + +# convenience stuff +def askcolor(color = None, **options): + """Ask for a color""" + return apply(Chooser, (), options).show() + + + +# test stuff +if __name__ == '__main__': + class Tester: + def __init__(self): + from Tkinter import * + self.__root = tk = Tk() + b = Button(tk, text='Choose Color...', command=self.__choose) + b.pack() + self.__l = Label(tk) + self.__l.pack() + q = Button(tk, text='Quit', command=self.__quit) + q.pack() + + def __choose(self, event=None): + rgb, name = askcolor(master=self.__root) + if rgb is None: + text = 'You hit CANCEL!' + else: + r, g, b = rgb + text = 'You picked %s (%3d/%3d/%3d)' % (name, r, g, b) + self.__l.configure(text=text) + + def __quit(self, event=None): + self.__root.quit() + + def run(self): + self.__root.mainloop() + t = Tester() + t.run() + # simpler +## print 'color:', askcolor() +## print 'color:', askcolor() |