blob: 4db560b568179cd83eba1b0b9b85fc75467b2ec3 [file] [log] [blame]
Barry Warsaw3fe1b141998-11-18 03:45:09 +00001"""Pynche -- The PYthon Natural Color and Hue Editor.
2
Barry Warsawd9e0e1f2002-10-21 14:23:48 +00003Contact: %(AUTHNAME)s
4Email: %(AUTHEMAIL)s
Barry Warsaw3fe1b141998-11-18 03:45:09 +00005Version: %(__version__)s
Barry Warsaw516f1891998-01-27 03:19:00 +00006
7Pynche is based largely on a similar color editor I wrote years ago for the
Barry Warsawd9e0e1f2002-10-21 14:23:48 +00008SunView window system. That editor was called ICE: the Interactive Color
Barry Warsaw516f1891998-01-27 03:19:00 +00009Editor. I'd always wanted to port the editor to X but didn't feel like
10hacking X and C code to do it. Fast forward many years, to where Python +
Barry Warsaw04c78861998-09-28 16:28:04 +000011Tkinter provides such a nice programming environment, with enough power, that
12I finally buckled down and implemented it. I changed the name because these
13days, too many other systems have the acronym `ICE'.
Barry Warsaw516f1891998-01-27 03:19:00 +000014
Barry Warsawd9e0e1f2002-10-21 14:23:48 +000015This program currently requires Python 2.2 with Tkinter.
Barry Warsawf7c1e5a1998-01-31 23:39:28 +000016
Barry Warsaw3fe1b141998-11-18 03:45:09 +000017Usage: %(PROGRAM)s [-d file] [-i file] [-X] [-v] [-h] [initialcolor]
Barry Warsaw516f1891998-01-27 03:19:00 +000018
19Where:
Barry Warsaw04c78861998-09-28 16:28:04 +000020 --database file
21 -d file
22 Alternate location of a color database file
Barry Warsaweab81a91998-02-11 18:56:13 +000023
Barry Warsaw8a09e1c1998-10-20 20:45:46 +000024 --initfile file
25 -i file
26 Alternate location of the initialization file. This file contains a
27 persistent database of the current Pynche options and color. This
28 means that Pynche restores its option settings and current color when
29 it restarts, using this file (unless the -X option is used). The
30 default is ~/.pynche
31
32 --ignore
33 -X
34 Ignore the initialization file when starting up. Pynche will still
35 write the current option settings to this file when it quits.
36
Barry Warsaw3fe1b141998-11-18 03:45:09 +000037 --version
38 -v
Barry Warsawd9e0e1f2002-10-21 14:23:48 +000039 print the version number and exit
Barry Warsaw3fe1b141998-11-18 03:45:09 +000040
Barry Warsaw516f1891998-01-27 03:19:00 +000041 --help
42 -h
43 print this message
44
Barry Warsaw04c78861998-09-28 16:28:04 +000045 initialcolor
46 initial color, as a color name or #RRGGBB format
Barry Warsaw516f1891998-01-27 03:19:00 +000047"""
48
Barry Warsaweb296d92003-09-03 03:15:50 +000049__version__ = '1.4.1'
Barry Warsaw516f1891998-01-27 03:19:00 +000050
Barry Warsawf7c1e5a1998-01-31 23:39:28 +000051import sys
Barry Warsaw6bfd6551998-10-06 20:44:14 +000052import os
Barry Warsawf7c1e5a1998-01-31 23:39:28 +000053import getopt
Barry Warsawf7c1e5a1998-01-31 23:39:28 +000054import ColorDB
Barry Warsaw60e18862001-07-10 21:42:04 +000055
Barry Warsawf7c1e5a1998-01-31 23:39:28 +000056from PyncheWidget import PyncheWidget
Barry Warsaw04c78861998-09-28 16:28:04 +000057from Switchboard import Switchboard
Barry Warsaw63c9e981998-09-28 23:41:53 +000058from StripViewer import StripViewer
Barry Warsaw4ab5d851998-10-01 16:47:06 +000059from ChipViewer import ChipViewer
60from TypeinViewer import TypeinViewer
Barry Warsawf7c1e5a1998-01-31 23:39:28 +000061
62
63
64PROGRAM = sys.argv[0]
Barry Warsawd9e0e1f2002-10-21 14:23:48 +000065AUTHNAME = 'Barry Warsaw'
66AUTHEMAIL = 'barry@python.org'
Barry Warsawf7c1e5a1998-01-31 23:39:28 +000067
Barry Warsawf7c1e5a1998-01-31 23:39:28 +000068# Default locations of rgb.txt or other textual color database
69RGB_TXT = [
70 # Solaris OpenWindows
71 '/usr/openwin/lib/rgb.txt',
Barry Warsawc2aadcd1999-04-23 16:24:00 +000072 # Linux
73 '/usr/lib/X11/rgb.txt',
Barry Warsaw6bfd6551998-10-06 20:44:14 +000074 # The X11R6.4 rgb.txt file
Barry Warsaw8a09e1c1998-10-20 20:45:46 +000075 os.path.join(sys.path[0], 'X/rgb.txt'),
Barry Warsawf7c1e5a1998-01-31 23:39:28 +000076 # add more here
77 ]
78
79
80
Barry Warsaw60e18862001-07-10 21:42:04 +000081# Do this because PyncheWidget.py wants to get at the interpolated docstring
82# too, for its Help menu.
Barry Warsawd0e1e511998-12-03 19:49:13 +000083def docstring():
Barry Warsaw60e18862001-07-10 21:42:04 +000084 return __doc__ % globals()
Barry Warsawd0e1e511998-12-03 19:49:13 +000085
86
Barry Warsaw60e18862001-07-10 21:42:04 +000087def usage(code, msg=''):
Collin Winter6afaeb72007-08-03 17:06:41 +000088 print(docstring())
Barry Warsawf7c1e5a1998-01-31 23:39:28 +000089 if msg:
Collin Winter6afaeb72007-08-03 17:06:41 +000090 print(msg)
Barry Warsaw60e18862001-07-10 21:42:04 +000091 sys.exit(code)
Barry Warsawf7c1e5a1998-01-31 23:39:28 +000092
93
94
Barry Warsawe7f4a471998-10-06 19:50:33 +000095def initial_color(s, colordb):
96 # function called on every color
97 def scan_color(s, colordb=colordb):
98 try:
99 r, g, b = colordb.find_byname(s)
100 except ColorDB.BadColor:
101 try:
102 r, g, b = ColorDB.rrggbb_to_triplet(s)
103 except ColorDB.BadColor:
104 return None, None, None
105 return r, g, b
106 #
107 # First try the passed in color
108 r, g, b = scan_color(s)
109 if r is None:
110 # try the same color with '#' prepended, since some shells require
111 # this to be escaped, which is a pain
112 r, g, b = scan_color('#' + s)
113 if r is None:
Collin Winter6afaeb72007-08-03 17:06:41 +0000114 print('Bad initial color, using gray50:', s)
Barry Warsawe7f4a471998-10-06 19:50:33 +0000115 r, g, b = scan_color('gray50')
116 if r is None:
117 usage(1, 'Cannot find an initial color to use')
118 # does not return
119 return r, g, b
120
121
122
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000123def build(master=None, initialcolor=None, initfile=None, ignore=None,
124 dbfile=None):
Barry Warsawca07ba01998-10-22 03:25:59 +0000125 # create all output widgets
Barry Warsaw0604d721999-04-26 23:17:16 +0000126 s = Switchboard(not ignore and initfile)
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000127 # defer to the command line chosen color database, falling back to the one
128 # in the .pynche file.
129 if dbfile is None:
Barry Warsaweb296d92003-09-03 03:15:50 +0000130 dbfile = s.optiondb().get('DBFILE')
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000131 # find a parseable color database
132 colordb = None
133 files = RGB_TXT[:]
Barry Warsaweb296d92003-09-03 03:15:50 +0000134 if dbfile is None:
135 dbfile = files.pop()
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000136 while colordb is None:
137 try:
138 colordb = ColorDB.get_colordb(dbfile)
139 except (KeyError, IOError):
140 pass
141 if colordb is None:
142 if not files:
143 break
144 dbfile = files.pop(0)
Barry Warsaw0604d721999-04-26 23:17:16 +0000145 if not colordb:
146 usage(1, 'No color database file found, see the -d option.')
147 s.set_colordb(colordb)
Barry Warsawca07ba01998-10-22 03:25:59 +0000148
149 # create the application window decorations
150 app = PyncheWidget(__version__, s, master=master)
151 w = app.window()
152
Barry Warsawb61a28e1999-04-27 18:43:47 +0000153 # these built-in viewers live inside the main Pynche window
Barry Warsawca07ba01998-10-22 03:25:59 +0000154 s.add_view(StripViewer(s, w))
155 s.add_view(ChipViewer(s, w))
156 s.add_view(TypeinViewer(s, w))
157
158 # get the initial color as components and set the color on all views. if
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000159 # there was no initial color given on the command line, use the one that's
Barry Warsawca07ba01998-10-22 03:25:59 +0000160 # stored in the option database
161 if initialcolor is None:
162 optiondb = s.optiondb()
163 red = optiondb.get('RED')
164 green = optiondb.get('GREEN')
165 blue = optiondb.get('BLUE')
166 # but if there wasn't any stored in the database, use grey50
167 if red is None or blue is None or green is None:
168 red, green, blue = initial_color('grey50', colordb)
169 else:
170 red, green, blue = initial_color(initialcolor, colordb)
171 s.update_views(red, green, blue)
172 return app, s
173
174
175def run(app, s):
176 try:
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000177 app.start()
Barry Warsawca07ba01998-10-22 03:25:59 +0000178 except KeyboardInterrupt:
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000179 pass
Barry Warsawca07ba01998-10-22 03:25:59 +0000180
181
182
Barry Warsawf7c1e5a1998-01-31 23:39:28 +0000183def main():
Barry Warsawf7c1e5a1998-01-31 23:39:28 +0000184 try:
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000185 opts, args = getopt.getopt(
Barry Warsaw04c78861998-09-28 16:28:04 +0000186 sys.argv[1:],
Barry Warsaw3fe1b141998-11-18 03:45:09 +0000187 'hd:i:Xv',
188 ['database=', 'initfile=', 'ignore', 'help', 'version'])
Guido van Rossumb940e112007-01-10 16:19:56 +0000189 except getopt.error as msg:
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000190 usage(1, msg)
Barry Warsawf7c1e5a1998-01-31 23:39:28 +0000191
Barry Warsaw04c78861998-09-28 16:28:04 +0000192 if len(args) == 0:
Barry Warsaw8a09e1c1998-10-20 20:45:46 +0000193 initialcolor = None
Barry Warsaw04c78861998-09-28 16:28:04 +0000194 elif len(args) == 1:
195 initialcolor = args[0]
196 else:
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000197 usage(1)
Barry Warsawf7c1e5a1998-01-31 23:39:28 +0000198
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000199 ignore = False
200 dbfile = None
Barry Warsaw8a09e1c1998-10-20 20:45:46 +0000201 initfile = os.path.expanduser('~/.pynche')
Barry Warsawf7c1e5a1998-01-31 23:39:28 +0000202 for opt, arg in opts:
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000203 if opt in ('-h', '--help'):
204 usage(0)
Barry Warsaw3fe1b141998-11-18 03:45:09 +0000205 elif opt in ('-v', '--version'):
Collin Winter6afaeb72007-08-03 17:06:41 +0000206 print("""\
Barry Warsaw3fe1b141998-11-18 03:45:09 +0000207Pynche -- The PYthon Natural Color and Hue Editor.
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000208Contact: %(AUTHNAME)s
209Email: %(AUTHEMAIL)s
Collin Winter6afaeb72007-08-03 17:06:41 +0000210Version: %(__version__)s""" % globals())
Barry Warsaw3fe1b141998-11-18 03:45:09 +0000211 sys.exit(0)
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000212 elif opt in ('-d', '--database'):
213 dbfile = arg
Barry Warsaw8a09e1c1998-10-20 20:45:46 +0000214 elif opt in ('-X', '--ignore'):
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000215 ignore = True
Barry Warsaw8a09e1c1998-10-20 20:45:46 +0000216 elif opt in ('-i', '--initfile'):
217 initfile = arg
Barry Warsawf7c1e5a1998-01-31 23:39:28 +0000218
Barry Warsaw877d2991998-10-22 18:45:52 +0000219 app, sb = build(initialcolor=initialcolor,
220 initfile=initfile,
Barry Warsawd9e0e1f2002-10-21 14:23:48 +0000221 ignore=ignore,
222 dbfile=dbfile)
Barry Warsaw877d2991998-10-22 18:45:52 +0000223 run(app, sb)
224 sb.save_views()
Barry Warsawf7c1e5a1998-01-31 23:39:28 +0000225
Barry Warsaw60e18862001-07-10 21:42:04 +0000226
Barry Warsawf7c1e5a1998-01-31 23:39:28 +0000227
228if __name__ == '__main__':
229 main()