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 65 PROGRAM = sys.argv[0] 66 AUTHNAME = 'Barry Warsaw' 67 AUTHEMAIL = 'barry@python.org' 68 69 # Default locations of rgb.txt or other textual color database 70 RGB_TXT = [ 71 # Solaris OpenWindows 72 '/usr/openwin/lib/rgb.txt', 73 # Linux 74 '/usr/lib/X11/rgb.txt', 75 # The X11R6.4 rgb.txt file 76 os.path.join(sys.path[0], 'X/rgb.txt'), 77 # add more here 78 ] 79 80 81 83 # Do this because PyncheWidget.py wants to get at the interpolated docstring 84 # too, for its Help menu. 85 def docstring(): 86 return __doc__ % globals() 87 88 89 def usage(code, msg=''): 90 print docstring() 91 if msg: 92 print msg 93 sys.exit(code) 94 95 96 98 def initial_color(s, colordb): 99 # function called on every color 100 def scan_color(s, colordb=colordb): 101 try: 102 r, g, b = colordb.find_byname(s) 103 except ColorDB.BadColor: 104 try: 105 r, g, b = ColorDB.rrggbb_to_triplet(s) 106 except ColorDB.BadColor: 107 return None, None, None 108 return r, g, b 109 # 110 # First try the passed in color 111 r, g, b = scan_color(s) 112 if r is None: 113 # try the same color with '#' prepended, since some shells require 114 # this to be escaped, which is a pain 115 r, g, b = scan_color('#' + s) 116 if r is None: 117 print 'Bad initial color, using gray50:', s 118 r, g, b = scan_color('gray50') 119 if r is None: 120 usage(1, 'Cannot find an initial color to use') 121 # does not return 122 return r, g, b 123 124 125 127 def build(master=None, initialcolor=None, initfile=None, ignore=None, 128 dbfile=None): 129 # create all output widgets 130 s = Switchboard(not ignore and initfile) 131 # defer to the command line chosen color database, falling back to the one 132 # in the .pynche file. 133 if dbfile is None: 134 dbfile = s.optiondb().get('DBFILE') 135 # find a parseable color database 136 colordb = None 137 files = RGB_TXT[:] 138 if dbfile is None: 139 dbfile = files.pop() 140 while colordb is None: 141 try: 142 colordb = ColorDB.get_colordb(dbfile) 143 except (KeyError, IOError): 144 pass 145 if colordb is None: 146 if not files: 147 break 148 dbfile = files.pop(0) 149 if not colordb: 150 usage(1, 'No color database file found, see the -d option.') 151 s.set_colordb(colordb) 152 153 # create the application window decorations 154 app = PyncheWidget(__version__, s, master=master) 155 w = app.window() 156 157 # these built-in viewers live inside the main Pynche window 158 s.add_view(StripViewer(s, w)) 159 s.add_view(ChipViewer(s, w)) 160 s.add_view(TypeinViewer(s, w)) 161 162 # get the initial color as components and set the color on all views. if 163 # there was no initial color given on the command line, use the one that's 164 # stored in the option database 165 if initialcolor is None: 166 optiondb = s.optiondb() 167 red = optiondb.get('RED') 168 green = optiondb.get('GREEN') 169 blue = optiondb.get('BLUE') 170 # but if there wasn't any stored in the database, use grey50 171 if red is None or blue is None or green is None: 172 red, green, blue = initial_color('grey50', colordb) 173 else: 174 red, green, blue = initial_color(initialcolor, colordb) 175 s.update_views(red, green, blue) 176 return app, s 177 178 179 def run(app, s): 180 try: 181 app.start() 182 except KeyboardInterrupt: 183 pass 184 185 186 188 def main(): 189 try: 190 opts, args = getopt.getopt( 191 sys.argv[1:], 192 'hd:i:Xv', 193 ['database=', 'initfile=', 'ignore', 'help', 'version']) 194 except getopt.error, msg: 195 usage(1, msg) 196 197 if len(args) == 0: 198 initialcolor = None 199 elif len(args) == 1: 200 initialcolor = args[0] 201 else: 202 usage(1) 203 204 ignore = False 205 dbfile = None 206 initfile = os.path.expanduser('~/.pynche') 207 for opt, arg in opts: 208 if opt in ('-h', '--help'): 209 usage(0) 210 elif opt in ('-v', '--version'): 211 print """\ 212 Pynche -- The PYthon Natural Color and Hue Editor. 213 Contact: %(AUTHNAME)s 214 Email: %(AUTHEMAIL)s 215 Version: %(__version__)s""" % globals() 216 sys.exit(0) 217 elif opt in ('-d', '--database'): 218 dbfile = arg 219 elif opt in ('-X', '--ignore'): 220 ignore = True 221 elif opt in ('-i', '--initfile'): 222 initfile = arg 223 224 app, sb = build(initialcolor=initialcolor, 225 initfile=initfile, 226 ignore=ignore, 227 dbfile=dbfile) 228 run(app, sb) 229 sb.save_views() 230 231 232 234 if __name__ == '__main__': 235 main() 236