Main.py 6.25 KB
Newer Older
Barry Warsaw's avatar
Barry Warsaw committed
1 2
"""Pynche -- The PYthon Natural Color and Hue Editor.

3 4
Contact: %(AUTHNAME)s
Email:   %(AUTHEMAIL)s
Barry Warsaw's avatar
Barry Warsaw committed
5
Version: %(__version__)s
Barry Warsaw's avatar
Barry Warsaw committed
6 7

Pynche is based largely on a similar color editor I wrote years ago for the
8
SunView window system.  That editor was called ICE: the Interactive Color
Barry Warsaw's avatar
Barry Warsaw committed
9 10
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 +
Barry Warsaw's avatar
Barry Warsaw committed
11 12 13
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'.
Barry Warsaw's avatar
Barry Warsaw committed
14

15
This program currently requires Python 2.2 with Tkinter.
16

Barry Warsaw's avatar
Barry Warsaw committed
17
Usage: %(PROGRAM)s [-d file] [-i file] [-X] [-v] [-h] [initialcolor]
Barry Warsaw's avatar
Barry Warsaw committed
18 19

Where:
Barry Warsaw's avatar
Barry Warsaw committed
20 21 22
    --database file
    -d file
        Alternate location of a color database file
23

24 25 26 27 28 29 30 31 32 33 34 35 36
    --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.

Barry Warsaw's avatar
Barry Warsaw committed
37 38
    --version
    -v
39
        print the version number and exit
Barry Warsaw's avatar
Barry Warsaw committed
40

Barry Warsaw's avatar
Barry Warsaw committed
41 42 43 44
    --help
    -h
        print this message

Barry Warsaw's avatar
Barry Warsaw committed
45 46
    initialcolor
        initial color, as a color name or #RRGGBB format
Barry Warsaw's avatar
Barry Warsaw committed
47 48
"""

49
__version__ = '1.4.1'
Barry Warsaw's avatar
Barry Warsaw committed
50

51
import sys
52
import os
53 54
import getopt
import ColorDB
Barry Warsaw's avatar
Barry Warsaw committed
55

56
from PyncheWidget import PyncheWidget
Barry Warsaw's avatar
Barry Warsaw committed
57
from Switchboard import Switchboard
Barry Warsaw's avatar
Barry Warsaw committed
58
from StripViewer import StripViewer
Barry Warsaw's avatar
Barry Warsaw committed
59 60
from ChipViewer import ChipViewer
from TypeinViewer import TypeinViewer
61 62 63 64



PROGRAM = sys.argv[0]
65 66
AUTHNAME = 'Barry Warsaw'
AUTHEMAIL = 'barry@python.org'
67 68 69 70 71

# Default locations of rgb.txt or other textual color database
RGB_TXT = [
    # Solaris OpenWindows
    '/usr/openwin/lib/rgb.txt',
72 73
    # Linux
    '/usr/lib/X11/rgb.txt',
74
    # The X11R6.4 rgb.txt file
75
    os.path.join(sys.path[0], 'X/rgb.txt'),
76 77 78 79 80
    # add more here
    ]



Barry Warsaw's avatar
Barry Warsaw committed
81 82
# Do this because PyncheWidget.py wants to get at the interpolated docstring
# too, for its Help menu.
83
def docstring():
Barry Warsaw's avatar
Barry Warsaw committed
84
    return __doc__ % globals()
85 86


Barry Warsaw's avatar
Barry Warsaw committed
87
def usage(code, msg=''):
88
    print docstring()
89
    if msg:
Barry Warsaw's avatar
Barry Warsaw committed
90
        print msg
Barry Warsaw's avatar
Barry Warsaw committed
91
    sys.exit(code)
92 93 94



95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
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



123 124
def build(master=None, initialcolor=None, initfile=None, ignore=None,
          dbfile=None):
Barry Warsaw's avatar
Barry Warsaw committed
125
    # create all output widgets
126
    s = Switchboard(not ignore and initfile)
127 128 129
    # defer to the command line chosen color database, falling back to the one
    # in the .pynche file.
    if dbfile is None:
130
        dbfile = s.optiondb().get('DBFILE')
131 132 133
    # find a parseable color database
    colordb = None
    files = RGB_TXT[:]
134 135
    if dbfile is None:
        dbfile = files.pop()
136 137 138 139 140 141 142 143 144
    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)
145 146 147
    if not colordb:
        usage(1, 'No color database file found, see the -d option.')
    s.set_colordb(colordb)
Barry Warsaw's avatar
Barry Warsaw committed
148 149

    # create the application window decorations
150 151
    app = PyncheWidget(__version__, s, master=master)
    w = app.window()
Barry Warsaw's avatar
Barry Warsaw committed
152

Barry Warsaw's avatar
Barry Warsaw committed
153
    # these built-in viewers live inside the main Pynche window
154 155 156
    s.add_view(StripViewer(s, w))
    s.add_view(ChipViewer(s, w))
    s.add_view(TypeinViewer(s, w))
157 158

    # get the initial color as components and set the color on all views.  if
159
    # there was no initial color given on the command line, use the one that's
160 161 162 163 164 165 166 167 168 169 170
    # 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)
Barry Warsaw's avatar
Barry Warsaw committed
171
    s.update_views(red, green, blue)
172 173
    return app, s

Barry Warsaw's avatar
Barry Warsaw committed
174

175
def run(app, s):
176
    try:
177
        app.start()
178
    except KeyboardInterrupt:
179
        pass
180 181 182 183 184



def main():
    try:
185
        opts, args = getopt.getopt(
186
            sys.argv[1:],
Barry Warsaw's avatar
Barry Warsaw committed
187 188
            'hd:i:Xv',
            ['database=', 'initfile=', 'ignore', 'help', 'version'])
189
    except getopt.error, msg:
190
        usage(1, msg)
191 192 193 194 195 196

    if len(args) == 0:
        initialcolor = None
    elif len(args) == 1:
        initialcolor = args[0]
    else:
197
        usage(1)
198

199 200
    ignore = False
    dbfile = None
201 202
    initfile = os.path.expanduser('~/.pynche')
    for opt, arg in opts:
203 204
        if opt in ('-h', '--help'):
            usage(0)
Barry Warsaw's avatar
Barry Warsaw committed
205
        elif opt in ('-v', '--version'):
206
            print """\
Barry Warsaw's avatar
Barry Warsaw committed
207
Pynche -- The PYthon Natural Color and Hue Editor.
208 209 210
Contact: %(AUTHNAME)s
Email:   %(AUTHEMAIL)s
Version: %(__version__)s""" % globals()
Barry Warsaw's avatar
Barry Warsaw committed
211
            sys.exit(0)
212 213
        elif opt in ('-d', '--database'):
            dbfile = arg
214
        elif opt in ('-X', '--ignore'):
215
            ignore = True
216 217
        elif opt in ('-i', '--initfile'):
            initfile = arg
218

219 220
    app, sb = build(initialcolor=initialcolor,
                    initfile=initfile,
221 222
                    ignore=ignore,
                    dbfile=dbfile)
223 224
    run(app, sb)
    sb.save_views()
225

Barry Warsaw's avatar
Barry Warsaw committed
226

227 228 229

if __name__ == '__main__':
    main()