1998-11-17 23:45:09 -04:00
|
|
|
|
"""Pynche -- The PYthon Natural Color and Hue Editor.
|
|
|
|
|
|
1998-12-14 21:02:51 -04:00
|
|
|
|
Contact: Barry Warsaw
|
1998-11-17 23:45:09 -04:00
|
|
|
|
Email: bwarsaw@python.org
|
|
|
|
|
Version: %(__version__)s
|
1998-01-26 23:19:00 -04:00
|
|
|
|
|
|
|
|
|
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 +
|
1998-09-28 13:28:04 -03:00
|
|
|
|
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'.
|
1998-01-26 23:19:00 -04:00
|
|
|
|
|
1998-09-28 13:28:04 -03:00
|
|
|
|
This program currently requires Python 1.5 with Tkinter. It has only been
|
|
|
|
|
tested on Solaris 2.6. Feedback is greatly appreciated. Send email to
|
|
|
|
|
bwarsaw@python.org
|
1998-01-31 19:39:28 -04:00
|
|
|
|
|
1998-11-17 23:45:09 -04:00
|
|
|
|
Usage: %(PROGRAM)s [-d file] [-i file] [-X] [-v] [-h] [initialcolor]
|
1998-01-26 23:19:00 -04:00
|
|
|
|
|
|
|
|
|
Where:
|
1998-09-28 13:28:04 -03:00
|
|
|
|
--database file
|
|
|
|
|
-d file
|
|
|
|
|
Alternate location of a color database file
|
1998-02-11 14:56:13 -04:00
|
|
|
|
|
1998-10-20 17:45:46 -03:00
|
|
|
|
--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.
|
|
|
|
|
|
1998-11-17 23:45:09 -04:00
|
|
|
|
--version
|
|
|
|
|
-v
|
|
|
|
|
print the version number
|
|
|
|
|
|
1998-01-26 23:19:00 -04:00
|
|
|
|
--help
|
|
|
|
|
-h
|
|
|
|
|
print this message
|
|
|
|
|
|
1998-09-28 13:28:04 -03:00
|
|
|
|
initialcolor
|
|
|
|
|
initial color, as a color name or #RRGGBB format
|
|
|
|
|
|
1998-01-26 23:19:00 -04:00
|
|
|
|
"""
|
|
|
|
|
|
1999-04-26 20:18:07 -03:00
|
|
|
|
__version__ = '1.0'
|
1998-01-26 23:19:00 -04:00
|
|
|
|
|
1998-01-31 19:39:28 -04:00
|
|
|
|
import sys
|
1998-10-06 17:44:14 -03:00
|
|
|
|
import os
|
1998-12-03 15:49:13 -04:00
|
|
|
|
import string
|
1998-01-31 19:39:28 -04:00
|
|
|
|
import getopt
|
|
|
|
|
import ColorDB
|
|
|
|
|
from PyncheWidget import PyncheWidget
|
1998-09-28 13:28:04 -03:00
|
|
|
|
from Switchboard import Switchboard
|
1998-09-28 20:41:53 -03:00
|
|
|
|
from StripViewer import StripViewer
|
1998-10-01 13:47:06 -03:00
|
|
|
|
from ChipViewer import ChipViewer
|
|
|
|
|
from TypeinViewer import TypeinViewer
|
1998-01-31 19:39:28 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PROGRAM = sys.argv[0]
|
|
|
|
|
|
|
|
|
|
# Default locations of rgb.txt or other textual color database
|
|
|
|
|
RGB_TXT = [
|
|
|
|
|
# Solaris OpenWindows
|
|
|
|
|
'/usr/openwin/lib/rgb.txt',
|
1999-04-23 13:24:00 -03:00
|
|
|
|
# Linux
|
|
|
|
|
'/usr/lib/X11/rgb.txt',
|
1998-10-06 17:44:14 -03:00
|
|
|
|
# The X11R6.4 rgb.txt file
|
1998-10-20 17:45:46 -03:00
|
|
|
|
os.path.join(sys.path[0], 'X/rgb.txt'),
|
1998-01-31 19:39:28 -04:00
|
|
|
|
# add more here
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1998-12-03 15:49:13 -04:00
|
|
|
|
def docstring():
|
|
|
|
|
return string.rstrip(__doc__ % globals())
|
|
|
|
|
|
|
|
|
|
|
1998-01-31 19:39:28 -04:00
|
|
|
|
def usage(status, msg=''):
|
1998-12-03 15:49:13 -04:00
|
|
|
|
print docstring()
|
1998-01-31 19:39:28 -04:00
|
|
|
|
if msg:
|
1998-11-17 23:45:09 -04:00
|
|
|
|
print msg
|
1998-01-31 19:39:28 -04:00
|
|
|
|
sys.exit(status)
|
|
|
|
|
|
|
|
|
|
|
1998-10-06 16:50:33 -03:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
1998-01-31 19:39:28 -04:00
|
|
|
|
|
Many changes to support a second mode of operation. Pynche can now be
run either as a standalone application (by running pynche or
pynche.pyw), or as a modal dialog inside another application. This
can be done by importing pyColorChooser and running askcolor(). The
API for this is the same as the tkColorChooser.askcolor() API, namely:
When `Okay' is hit, askcolor() returns ((r, g, b), "name"). When
`Cancel' is hit, askcolor() returns (None, None).
Note the following differences:
1. pyColorChooser.askcolor() takes an optional keyword `master'
which if set tells Pynche to run as a modal dialog. `master'
is a Tkinter parent window. Without the `master' keyword
Pynche runs standalone.
2. in pyColorChooser.askcolor() will return a Tk/X11 color name as
"name" if there is an exact match, otherwise it will return a
color spec, e.g. "#rrggbb". tkColorChooser can't return a
color name.
There are also some UI differences when running standalone vs. modal.
When modal, there is no "File" menu, but instead there are "Okay" and
"Cancel" buttons.
The implementation of all this is a bit of a hack, but it seems to
work moderately well. I'm not guaranteeing the pyColorChooser.Chooser
class has the same semantics as the tkColorChooser.Chooser class.
1998-10-22 00:25:59 -03:00
|
|
|
|
def build(master=None, initialcolor=None, initfile=None, ignore=None):
|
1998-09-28 20:41:53 -03:00
|
|
|
|
# create all output widgets
|
1999-04-26 20:17:16 -03:00
|
|
|
|
s = Switchboard(not ignore and initfile)
|
|
|
|
|
|
|
|
|
|
# load the color database
|
|
|
|
|
colordb = None
|
|
|
|
|
try:
|
|
|
|
|
dbfile = s.optiondb()['DBFILE']
|
|
|
|
|
colordb = ColorDB.get_colordb(dbfile)
|
|
|
|
|
except (KeyError, IOError):
|
|
|
|
|
# scoot through the files listed above to try to find a usable color
|
|
|
|
|
# database file
|
|
|
|
|
for f in RGB_TXT:
|
|
|
|
|
try:
|
|
|
|
|
colordb = ColorDB.get_colordb(f)
|
|
|
|
|
if colordb:
|
|
|
|
|
break
|
|
|
|
|
except IOError:
|
|
|
|
|
pass
|
|
|
|
|
if not colordb:
|
|
|
|
|
usage(1, 'No color database file found, see the -d option.')
|
|
|
|
|
s.set_colordb(colordb)
|
1998-10-01 13:47:06 -03:00
|
|
|
|
|
|
|
|
|
# create the application window decorations
|
Many changes to support a second mode of operation. Pynche can now be
run either as a standalone application (by running pynche or
pynche.pyw), or as a modal dialog inside another application. This
can be done by importing pyColorChooser and running askcolor(). The
API for this is the same as the tkColorChooser.askcolor() API, namely:
When `Okay' is hit, askcolor() returns ((r, g, b), "name"). When
`Cancel' is hit, askcolor() returns (None, None).
Note the following differences:
1. pyColorChooser.askcolor() takes an optional keyword `master'
which if set tells Pynche to run as a modal dialog. `master'
is a Tkinter parent window. Without the `master' keyword
Pynche runs standalone.
2. in pyColorChooser.askcolor() will return a Tk/X11 color name as
"name" if there is an exact match, otherwise it will return a
color spec, e.g. "#rrggbb". tkColorChooser can't return a
color name.
There are also some UI differences when running standalone vs. modal.
When modal, there is no "File" menu, but instead there are "Okay" and
"Cancel" buttons.
The implementation of all this is a bit of a hack, but it seems to
work moderately well. I'm not guaranteeing the pyColorChooser.Chooser
class has the same semantics as the tkColorChooser.Chooser class.
1998-10-22 00:25:59 -03:00
|
|
|
|
app = PyncheWidget(__version__, s, master=master)
|
|
|
|
|
w = app.window()
|
1998-10-01 13:47:06 -03:00
|
|
|
|
|
1999-04-27 15:43:47 -03:00
|
|
|
|
# these built-in viewers live inside the main Pynche window
|
Many changes to support a second mode of operation. Pynche can now be
run either as a standalone application (by running pynche or
pynche.pyw), or as a modal dialog inside another application. This
can be done by importing pyColorChooser and running askcolor(). The
API for this is the same as the tkColorChooser.askcolor() API, namely:
When `Okay' is hit, askcolor() returns ((r, g, b), "name"). When
`Cancel' is hit, askcolor() returns (None, None).
Note the following differences:
1. pyColorChooser.askcolor() takes an optional keyword `master'
which if set tells Pynche to run as a modal dialog. `master'
is a Tkinter parent window. Without the `master' keyword
Pynche runs standalone.
2. in pyColorChooser.askcolor() will return a Tk/X11 color name as
"name" if there is an exact match, otherwise it will return a
color spec, e.g. "#rrggbb". tkColorChooser can't return a
color name.
There are also some UI differences when running standalone vs. modal.
When modal, there is no "File" menu, but instead there are "Okay" and
"Cancel" buttons.
The implementation of all this is a bit of a hack, but it seems to
work moderately well. I'm not guaranteeing the pyColorChooser.Chooser
class has the same semantics as the tkColorChooser.Chooser class.
1998-10-22 00:25:59 -03:00
|
|
|
|
s.add_view(StripViewer(s, w))
|
|
|
|
|
s.add_view(ChipViewer(s, w))
|
|
|
|
|
s.add_view(TypeinViewer(s, w))
|
1998-10-20 17:45:46 -03:00
|
|
|
|
|
|
|
|
|
# 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)
|
1998-09-28 20:41:53 -03:00
|
|
|
|
s.update_views(red, green, blue)
|
Many changes to support a second mode of operation. Pynche can now be
run either as a standalone application (by running pynche or
pynche.pyw), or as a modal dialog inside another application. This
can be done by importing pyColorChooser and running askcolor(). The
API for this is the same as the tkColorChooser.askcolor() API, namely:
When `Okay' is hit, askcolor() returns ((r, g, b), "name"). When
`Cancel' is hit, askcolor() returns (None, None).
Note the following differences:
1. pyColorChooser.askcolor() takes an optional keyword `master'
which if set tells Pynche to run as a modal dialog. `master'
is a Tkinter parent window. Without the `master' keyword
Pynche runs standalone.
2. in pyColorChooser.askcolor() will return a Tk/X11 color name as
"name" if there is an exact match, otherwise it will return a
color spec, e.g. "#rrggbb". tkColorChooser can't return a
color name.
There are also some UI differences when running standalone vs. modal.
When modal, there is no "File" menu, but instead there are "Okay" and
"Cancel" buttons.
The implementation of all this is a bit of a hack, but it seems to
work moderately well. I'm not guaranteeing the pyColorChooser.Chooser
class has the same semantics as the tkColorChooser.Chooser class.
1998-10-22 00:25:59 -03:00
|
|
|
|
return app, s
|
|
|
|
|
|
1998-09-28 20:41:53 -03:00
|
|
|
|
|
Many changes to support a second mode of operation. Pynche can now be
run either as a standalone application (by running pynche or
pynche.pyw), or as a modal dialog inside another application. This
can be done by importing pyColorChooser and running askcolor(). The
API for this is the same as the tkColorChooser.askcolor() API, namely:
When `Okay' is hit, askcolor() returns ((r, g, b), "name"). When
`Cancel' is hit, askcolor() returns (None, None).
Note the following differences:
1. pyColorChooser.askcolor() takes an optional keyword `master'
which if set tells Pynche to run as a modal dialog. `master'
is a Tkinter parent window. Without the `master' keyword
Pynche runs standalone.
2. in pyColorChooser.askcolor() will return a Tk/X11 color name as
"name" if there is an exact match, otherwise it will return a
color spec, e.g. "#rrggbb". tkColorChooser can't return a
color name.
There are also some UI differences when running standalone vs. modal.
When modal, there is no "File" menu, but instead there are "Okay" and
"Cancel" buttons.
The implementation of all this is a bit of a hack, but it seems to
work moderately well. I'm not guaranteeing the pyColorChooser.Chooser
class has the same semantics as the tkColorChooser.Chooser class.
1998-10-22 00:25:59 -03:00
|
|
|
|
def run(app, s):
|
1998-01-31 19:39:28 -04:00
|
|
|
|
try:
|
1998-09-28 20:41:53 -03:00
|
|
|
|
app.start()
|
1998-01-31 19:39:28 -04:00
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
|
pass
|
Many changes to support a second mode of operation. Pynche can now be
run either as a standalone application (by running pynche or
pynche.pyw), or as a modal dialog inside another application. This
can be done by importing pyColorChooser and running askcolor(). The
API for this is the same as the tkColorChooser.askcolor() API, namely:
When `Okay' is hit, askcolor() returns ((r, g, b), "name"). When
`Cancel' is hit, askcolor() returns (None, None).
Note the following differences:
1. pyColorChooser.askcolor() takes an optional keyword `master'
which if set tells Pynche to run as a modal dialog. `master'
is a Tkinter parent window. Without the `master' keyword
Pynche runs standalone.
2. in pyColorChooser.askcolor() will return a Tk/X11 color name as
"name" if there is an exact match, otherwise it will return a
color spec, e.g. "#rrggbb". tkColorChooser can't return a
color name.
There are also some UI differences when running standalone vs. modal.
When modal, there is no "File" menu, but instead there are "Okay" and
"Cancel" buttons.
The implementation of all this is a bit of a hack, but it seems to
work moderately well. I'm not guaranteeing the pyColorChooser.Chooser
class has the same semantics as the tkColorChooser.Chooser class.
1998-10-22 00:25:59 -03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
try:
|
|
|
|
|
opts, args = getopt.getopt(
|
|
|
|
|
sys.argv[1:],
|
1998-11-17 23:45:09 -04:00
|
|
|
|
'hd:i:Xv',
|
|
|
|
|
['database=', 'initfile=', 'ignore', 'help', 'version'])
|
Many changes to support a second mode of operation. Pynche can now be
run either as a standalone application (by running pynche or
pynche.pyw), or as a modal dialog inside another application. This
can be done by importing pyColorChooser and running askcolor(). The
API for this is the same as the tkColorChooser.askcolor() API, namely:
When `Okay' is hit, askcolor() returns ((r, g, b), "name"). When
`Cancel' is hit, askcolor() returns (None, None).
Note the following differences:
1. pyColorChooser.askcolor() takes an optional keyword `master'
which if set tells Pynche to run as a modal dialog. `master'
is a Tkinter parent window. Without the `master' keyword
Pynche runs standalone.
2. in pyColorChooser.askcolor() will return a Tk/X11 color name as
"name" if there is an exact match, otherwise it will return a
color spec, e.g. "#rrggbb". tkColorChooser can't return a
color name.
There are also some UI differences when running standalone vs. modal.
When modal, there is no "File" menu, but instead there are "Okay" and
"Cancel" buttons.
The implementation of all this is a bit of a hack, but it seems to
work moderately well. I'm not guaranteeing the pyColorChooser.Chooser
class has the same semantics as the tkColorChooser.Chooser class.
1998-10-22 00:25:59 -03:00
|
|
|
|
except getopt.error, msg:
|
|
|
|
|
usage(1, msg)
|
|
|
|
|
|
|
|
|
|
if len(args) == 0:
|
|
|
|
|
initialcolor = None
|
|
|
|
|
elif len(args) == 1:
|
|
|
|
|
initialcolor = args[0]
|
|
|
|
|
else:
|
|
|
|
|
usage(1)
|
|
|
|
|
|
|
|
|
|
ignore = 0
|
|
|
|
|
initfile = os.path.expanduser('~/.pynche')
|
|
|
|
|
for opt, arg in opts:
|
|
|
|
|
if opt in ('-h', '--help'):
|
|
|
|
|
usage(0)
|
1998-11-17 23:45:09 -04:00
|
|
|
|
elif opt in ('-v', '--version'):
|
|
|
|
|
print '''\
|
|
|
|
|
Pynche -- The PYthon Natural Color and Hue Editor.
|
1998-12-14 21:02:51 -04:00
|
|
|
|
Contact: Barry Warsaw
|
1998-11-17 23:45:09 -04:00
|
|
|
|
Email: bwarsaw@python.org
|
|
|
|
|
Version: %s''' % __version__
|
|
|
|
|
sys.exit(0)
|
Many changes to support a second mode of operation. Pynche can now be
run either as a standalone application (by running pynche or
pynche.pyw), or as a modal dialog inside another application. This
can be done by importing pyColorChooser and running askcolor(). The
API for this is the same as the tkColorChooser.askcolor() API, namely:
When `Okay' is hit, askcolor() returns ((r, g, b), "name"). When
`Cancel' is hit, askcolor() returns (None, None).
Note the following differences:
1. pyColorChooser.askcolor() takes an optional keyword `master'
which if set tells Pynche to run as a modal dialog. `master'
is a Tkinter parent window. Without the `master' keyword
Pynche runs standalone.
2. in pyColorChooser.askcolor() will return a Tk/X11 color name as
"name" if there is an exact match, otherwise it will return a
color spec, e.g. "#rrggbb". tkColorChooser can't return a
color name.
There are also some UI differences when running standalone vs. modal.
When modal, there is no "File" menu, but instead there are "Okay" and
"Cancel" buttons.
The implementation of all this is a bit of a hack, but it seems to
work moderately well. I'm not guaranteeing the pyColorChooser.Chooser
class has the same semantics as the tkColorChooser.Chooser class.
1998-10-22 00:25:59 -03:00
|
|
|
|
elif opt in ('-d', '--database'):
|
|
|
|
|
RGB_TXT.insert(0, arg)
|
|
|
|
|
elif opt in ('-X', '--ignore'):
|
|
|
|
|
ignore = 1
|
|
|
|
|
elif opt in ('-i', '--initfile'):
|
|
|
|
|
initfile = arg
|
1998-10-20 17:45:46 -03:00
|
|
|
|
|
1998-10-22 15:45:52 -03:00
|
|
|
|
app, sb = build(initialcolor=initialcolor,
|
|
|
|
|
initfile=initfile,
|
|
|
|
|
ignore=ignore)
|
|
|
|
|
run(app, sb)
|
|
|
|
|
sb.save_views()
|
1998-01-31 19:39:28 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
main()
|