| """Pynche -- The PYthon Natural Color and Hue Editor. | |
| Contact: %(AUTHNAME)s | |
| Email: %(AUTHEMAIL)s | |
| Version: %(__version__)s | |
| Pynche is based largely on a similar color editor I wrote years ago for the | |
| SunView window system. That editor was called ICE: the Interactive Color | |
| Editor. I'd always wanted to port the editor to X but didn't feel like | |
| hacking X and C code to do it. Fast forward many years, to where Python + | |
| Tkinter provides such a nice programming environment, with enough power, that | |
| I finally buckled down and implemented it. I changed the name because these | |
| days, too many other systems have the acronym `ICE'. | |
| This program currently requires Python 2.2 with Tkinter. | |
| Usage: %(PROGRAM)s [-d file] [-i file] [-X] [-v] [-h] [initialcolor] | |
| Where: | |
| --database file | |
| -d file | |
| Alternate location of a color database file | |
| --initfile file | |
| -i file | |
| Alternate location of the initialization file. This file contains a | |
| persistent database of the current Pynche options and color. This | |
| means that Pynche restores its option settings and current color when | |
| it restarts, using this file (unless the -X option is used). The | |
| default is ~/.pynche | |
| --ignore | |
| -X | |
| Ignore the initialization file when starting up. Pynche will still | |
| write the current option settings to this file when it quits. | |
| --version | |
| -v | |
| print the version number and exit | |
| --help | |
| -h | |
| print this message | |
| initialcolor | |
| initial color, as a color name or #RRGGBB format | |
| """ | |
| __version__ = '1.4.1' | |
| import sys | |
| import os | |
| import getopt | |
| import ColorDB | |
| from PyncheWidget import PyncheWidget | |
| from Switchboard import Switchboard | |
| from StripViewer import StripViewer | |
| from ChipViewer import ChipViewer | |
| from TypeinViewer import TypeinViewer | |
| PROGRAM = sys.argv[0] | |
| AUTHNAME = 'Barry Warsaw' | |
| AUTHEMAIL = 'barry@python.org' | |
| # Default locations of rgb.txt or other textual color database | |
| RGB_TXT = [ | |
| # Solaris OpenWindows | |
| '/usr/openwin/lib/rgb.txt', | |
| # Linux | |
| '/usr/lib/X11/rgb.txt', | |
| # The X11R6.4 rgb.txt file | |
| os.path.join(sys.path[0], 'X/rgb.txt'), | |
| # add more here | |
| ] | |
| # Do this because PyncheWidget.py wants to get at the interpolated docstring | |
| # too, for its Help menu. | |
| def docstring(): | |
| return __doc__ % globals() | |
| def usage(code, msg=''): | |
| print docstring() | |
| if msg: | |
| print msg | |
| sys.exit(code) | |
| def initial_color(s, colordb): | |
| # function called on every color | |
| def scan_color(s, colordb=colordb): | |
| try: | |
| r, g, b = colordb.find_byname(s) | |
| except ColorDB.BadColor: | |
| try: | |
| r, g, b = ColorDB.rrggbb_to_triplet(s) | |
| except ColorDB.BadColor: | |
| return None, None, None | |
| return r, g, b | |
| # | |
| # First try the passed in color | |
| r, g, b = scan_color(s) | |
| if r is None: | |
| # try the same color with '#' prepended, since some shells require | |
| # this to be escaped, which is a pain | |
| r, g, b = scan_color('#' + s) | |
| if r is None: | |
| print 'Bad initial color, using gray50:', s | |
| r, g, b = scan_color('gray50') | |
| if r is None: | |
| usage(1, 'Cannot find an initial color to use') | |
| # does not return | |
| return r, g, b | |
| def build(master=None, initialcolor=None, initfile=None, ignore=None, | |
| dbfile=None): | |
| # create all output widgets | |
| s = Switchboard(not ignore and initfile) | |
| # defer to the command line chosen color database, falling back to the one | |
| # in the .pynche file. | |
| if dbfile is None: | |
| dbfile = s.optiondb().get('DBFILE') | |
| # find a parseable color database | |
| colordb = None | |
| files = RGB_TXT[:] | |
| if dbfile is None: | |
| dbfile = files.pop() | |
| while colordb is None: | |
| try: | |
| colordb = ColorDB.get_colordb(dbfile) | |
| except (KeyError, IOError): | |
| pass | |
| if colordb is None: | |
| if not files: | |
| break | |
| dbfile = files.pop(0) | |
| if not colordb: | |
| usage(1, 'No color database file found, see the -d option.') | |
| s.set_colordb(colordb) | |
| # create the application window decorations | |
| app = PyncheWidget(__version__, s, master=master) | |
| w = app.window() | |
| # these built-in viewers live inside the main Pynche window | |
| 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 | |
| # stored in the option database | |
| if initialcolor is None: | |
| optiondb = s.optiondb() | |
| red = optiondb.get('RED') | |
| green = optiondb.get('GREEN') | |
| blue = optiondb.get('BLUE') | |
| # but if there wasn't any stored in the database, use grey50 | |
| if red is None or blue is None or green is None: | |
| red, green, blue = initial_color('grey50', colordb) | |
| 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 | |
| def main(): | |
| try: | |
| opts, args = getopt.getopt( | |
| sys.argv[1:], | |
| 'hd:i:Xv', | |
| ['database=', 'initfile=', 'ignore', 'help', 'version']) | |
| except getopt.error, msg: | |
| usage(1, msg) | |
| if len(args) == 0: | |
| initialcolor = None | |
| elif len(args) == 1: | |
| initialcolor = args[0] | |
| else: | |
| usage(1) | |
| ignore = False | |
| dbfile = None | |
| initfile = os.path.expanduser('~/.pynche') | |
| for opt, arg in opts: | |
| if opt in ('-h', '--help'): | |
| usage(0) | |
| elif opt in ('-v', '--version'): | |
| print """\ | |
| Pynche -- The PYthon Natural Color and Hue Editor. | |
| Contact: %(AUTHNAME)s | |
| Email: %(AUTHEMAIL)s | |
| Version: %(__version__)s""" % globals() | |
| sys.exit(0) | |
| elif opt in ('-d', '--database'): | |
| dbfile = arg | |
| elif opt in ('-X', '--ignore'): | |
| ignore = True | |
| elif opt in ('-i', '--initfile'): | |
| initfile = arg | |
| app, sb = build(initialcolor=initialcolor, | |
| initfile=initfile, | |
| ignore=ignore, | |
| dbfile=dbfile) | |
| run(app, sb) | |
| sb.save_views() | |
| if __name__ == '__main__': | |
| main() |