|
1 """Pynche -- The PYthon Natural Color and Hue Editor. |
|
2 |
|
3 Contact: %(AUTHNAME)s |
|
4 Email: %(AUTHEMAIL)s |
|
5 Version: %(__version__)s |
|
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 |
|
9 Editor. I'd always wanted to port the editor to X but didn't feel like |
|
10 hacking X and C code to do it. Fast forward many years, to where Python + |
|
11 Tkinter provides such a nice programming environment, with enough power, that |
|
12 I finally buckled down and implemented it. I changed the name because these |
|
13 days, too many other systems have the acronym `ICE'. |
|
14 |
|
15 This program currently requires Python 2.2 with Tkinter. |
|
16 |
|
17 Usage: %(PROGRAM)s [-d file] [-i file] [-X] [-v] [-h] [initialcolor] |
|
18 |
|
19 Where: |
|
20 --database file |
|
21 -d file |
|
22 Alternate location of a color database file |
|
23 |
|
24 --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 |
|
37 --version |
|
38 -v |
|
39 print the version number and exit |
|
40 |
|
41 --help |
|
42 -h |
|
43 print this message |
|
44 |
|
45 initialcolor |
|
46 initial color, as a color name or #RRGGBB format |
|
47 """ |
|
48 |
|
49 __version__ = '1.4.1' |
|
50 |
|
51 import sys |
|
52 import os |
|
53 import getopt |
|
54 import ColorDB |
|
55 |
|
56 from PyncheWidget import PyncheWidget |
|
57 from Switchboard import Switchboard |
|
58 from StripViewer import StripViewer |
|
59 from ChipViewer import ChipViewer |
|
60 from TypeinViewer import TypeinViewer |
|
61 |
|
62 |
|
63 |
|
64 PROGRAM = sys.argv[0] |
|
65 AUTHNAME = 'Barry Warsaw' |
|
66 AUTHEMAIL = 'barry@python.org' |
|
67 |
|
68 # Default locations of rgb.txt or other textual color database |
|
69 RGB_TXT = [ |
|
70 # Solaris OpenWindows |
|
71 '/usr/openwin/lib/rgb.txt', |
|
72 # Linux |
|
73 '/usr/lib/X11/rgb.txt', |
|
74 # The X11R6.4 rgb.txt file |
|
75 os.path.join(sys.path[0], 'X/rgb.txt'), |
|
76 # add more here |
|
77 ] |
|
78 |
|
79 |
|
80 |
|
81 # Do this because PyncheWidget.py wants to get at the interpolated docstring |
|
82 # too, for its Help menu. |
|
83 def docstring(): |
|
84 return __doc__ % globals() |
|
85 |
|
86 |
|
87 def usage(code, msg=''): |
|
88 print docstring() |
|
89 if msg: |
|
90 print msg |
|
91 sys.exit(code) |
|
92 |
|
93 |
|
94 |
|
95 def 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: |
|
114 print 'Bad initial color, using gray50:', s |
|
115 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 |
|
123 def build(master=None, initialcolor=None, initfile=None, ignore=None, |
|
124 dbfile=None): |
|
125 # create all output widgets |
|
126 s = Switchboard(not ignore and initfile) |
|
127 # defer to the command line chosen color database, falling back to the one |
|
128 # in the .pynche file. |
|
129 if dbfile is None: |
|
130 dbfile = s.optiondb().get('DBFILE') |
|
131 # find a parseable color database |
|
132 colordb = None |
|
133 files = RGB_TXT[:] |
|
134 if dbfile is None: |
|
135 dbfile = files.pop() |
|
136 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) |
|
145 if not colordb: |
|
146 usage(1, 'No color database file found, see the -d option.') |
|
147 s.set_colordb(colordb) |
|
148 |
|
149 # create the application window decorations |
|
150 app = PyncheWidget(__version__, s, master=master) |
|
151 w = app.window() |
|
152 |
|
153 # these built-in viewers live inside the main Pynche window |
|
154 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 |
|
159 # there was no initial color given on the command line, use the one that's |
|
160 # 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 |
|
175 def run(app, s): |
|
176 try: |
|
177 app.start() |
|
178 except KeyboardInterrupt: |
|
179 pass |
|
180 |
|
181 |
|
182 |
|
183 def main(): |
|
184 try: |
|
185 opts, args = getopt.getopt( |
|
186 sys.argv[1:], |
|
187 'hd:i:Xv', |
|
188 ['database=', 'initfile=', 'ignore', 'help', 'version']) |
|
189 except getopt.error, msg: |
|
190 usage(1, msg) |
|
191 |
|
192 if len(args) == 0: |
|
193 initialcolor = None |
|
194 elif len(args) == 1: |
|
195 initialcolor = args[0] |
|
196 else: |
|
197 usage(1) |
|
198 |
|
199 ignore = False |
|
200 dbfile = None |
|
201 initfile = os.path.expanduser('~/.pynche') |
|
202 for opt, arg in opts: |
|
203 if opt in ('-h', '--help'): |
|
204 usage(0) |
|
205 elif opt in ('-v', '--version'): |
|
206 print """\ |
|
207 Pynche -- The PYthon Natural Color and Hue Editor. |
|
208 Contact: %(AUTHNAME)s |
|
209 Email: %(AUTHEMAIL)s |
|
210 Version: %(__version__)s""" % globals() |
|
211 sys.exit(0) |
|
212 elif opt in ('-d', '--database'): |
|
213 dbfile = arg |
|
214 elif opt in ('-X', '--ignore'): |
|
215 ignore = True |
|
216 elif opt in ('-i', '--initfile'): |
|
217 initfile = arg |
|
218 |
|
219 app, sb = build(initialcolor=initialcolor, |
|
220 initfile=initfile, |
|
221 ignore=ignore, |
|
222 dbfile=dbfile) |
|
223 run(app, sb) |
|
224 sb.save_views() |
|
225 |
|
226 |
|
227 |
|
228 if __name__ == '__main__': |
|
229 main() |