| """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 as 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() |