1998-10-02 13:06:27 -03:00
|
|
|
"""ListViewer class.
|
|
|
|
|
|
|
|
This class implements an input/output view on the color model. It lists every
|
|
|
|
unique color (e.g. unique r/g/b value) found in the color database. Each
|
|
|
|
color is shown by small swatch and primary color name. Some colors have
|
|
|
|
aliases -- more than one name for the same r/g/b value. These aliases are
|
|
|
|
displayed in the small listbox at the bottom of the screen.
|
|
|
|
|
|
|
|
Clicking on a color name or swatch selects that color and updates all other
|
|
|
|
windows. When a color is selected in a different viewer, the color list is
|
|
|
|
scrolled to the selected color and it is highlighted. If the selected color
|
|
|
|
is an r/g/b value without a name, no scrolling occurs.
|
|
|
|
|
|
|
|
You can turn off Update On Click if all you want to see is the alias for a
|
|
|
|
given name, without selecting the color.
|
|
|
|
"""
|
|
|
|
|
1998-10-01 18:40:48 -03:00
|
|
|
from Tkinter import *
|
|
|
|
import ColorDB
|
|
|
|
|
1999-04-27 15:54:12 -03:00
|
|
|
ADDTOVIEW = 'Color %List Window...'
|
|
|
|
|
1998-10-01 18:40:48 -03:00
|
|
|
class ListViewer:
|
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 __init__(self, switchboard, master=None):
|
1998-10-01 18:40:48 -03:00
|
|
|
self.__sb = switchboard
|
1998-10-20 17:45:46 -03:00
|
|
|
optiondb = switchboard.optiondb()
|
1998-10-01 18:40:48 -03:00
|
|
|
self.__lastbox = None
|
1998-10-02 12:52:10 -03:00
|
|
|
self.__dontcenter = 0
|
1998-10-05 18:15:08 -03:00
|
|
|
# GUI
|
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
|
|
|
root = self.__root = Toplevel(master, class_='Pynche')
|
|
|
|
root.protocol('WM_DELETE_WINDOW', self.withdraw)
|
1998-10-05 18:31:37 -03:00
|
|
|
root.title('Pynche Color List')
|
1998-10-01 18:40:48 -03:00
|
|
|
root.iconname('Pynche Color List')
|
|
|
|
root.bind('<Alt-q>', self.__quit)
|
|
|
|
root.bind('<Alt-Q>', self.__quit)
|
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
|
|
|
root.bind('<Alt-w>', self.withdraw)
|
|
|
|
root.bind('<Alt-W>', self.withdraw)
|
1998-10-01 18:40:48 -03:00
|
|
|
#
|
|
|
|
# create the canvas which holds everything, and its scrollbar
|
|
|
|
#
|
1998-10-01 19:03:25 -03:00
|
|
|
frame = self.__frame = Frame(root)
|
|
|
|
frame.pack()
|
1998-10-02 12:52:10 -03:00
|
|
|
canvas = self.__canvas = Canvas(frame, width=160, height=300,
|
|
|
|
borderwidth=2, relief=SUNKEN)
|
1998-10-01 19:03:25 -03:00
|
|
|
self.__scrollbar = Scrollbar(frame)
|
1998-10-01 18:40:48 -03:00
|
|
|
self.__scrollbar.pack(fill=Y, side=RIGHT)
|
|
|
|
canvas.pack(fill=BOTH, expand=1)
|
|
|
|
canvas.configure(yscrollcommand=(self.__scrollbar, 'set'))
|
|
|
|
self.__scrollbar.configure(command=(canvas, 'yview'))
|
1999-04-26 20:17:16 -03:00
|
|
|
self.__populate()
|
|
|
|
#
|
|
|
|
# Update on click
|
|
|
|
self.__uoc = BooleanVar()
|
|
|
|
self.__uoc.set(optiondb.get('UPONCLICK', 1))
|
|
|
|
self.__uocbtn = Checkbutton(root,
|
|
|
|
text='Update on Click',
|
|
|
|
variable=self.__uoc,
|
|
|
|
command=self.__toggleupdate)
|
|
|
|
self.__uocbtn.pack(expand=1, fill=BOTH)
|
|
|
|
#
|
|
|
|
# alias list
|
|
|
|
self.__alabel = Label(root, text='Aliases:')
|
|
|
|
self.__alabel.pack()
|
|
|
|
self.__aliases = Listbox(root, height=5,
|
|
|
|
selectmode=BROWSE)
|
|
|
|
self.__aliases.pack(expand=1, fill=BOTH)
|
|
|
|
|
|
|
|
def __populate(self):
|
1998-10-01 18:40:48 -03:00
|
|
|
#
|
|
|
|
# create all the buttons
|
1999-04-26 20:17:16 -03:00
|
|
|
colordb = self.__sb.colordb()
|
|
|
|
canvas = self.__canvas
|
1998-10-01 18:40:48 -03:00
|
|
|
row = 0
|
|
|
|
widest = 0
|
|
|
|
bboxes = self.__bboxes = []
|
1998-10-02 12:52:10 -03:00
|
|
|
for name in colordb.unique_names():
|
1998-10-01 18:40:48 -03:00
|
|
|
exactcolor = ColorDB.triplet_to_rrggbb(colordb.find_byname(name))
|
|
|
|
canvas.create_rectangle(5, row*20 + 5,
|
|
|
|
20, row*20 + 20,
|
|
|
|
fill=exactcolor)
|
|
|
|
textid = canvas.create_text(25, row*20 + 13,
|
|
|
|
text=name,
|
|
|
|
anchor=W)
|
|
|
|
x1, y1, textend, y2 = canvas.bbox(textid)
|
|
|
|
boxid = canvas.create_rectangle(3, row*20+3,
|
|
|
|
textend+3, row*20 + 23,
|
|
|
|
outline='',
|
1999-04-26 20:17:16 -03:00
|
|
|
tags=(exactcolor, 'all'))
|
1998-10-01 19:03:25 -03:00
|
|
|
canvas.bind('<ButtonRelease>', self.__onrelease)
|
1998-10-01 18:40:48 -03:00
|
|
|
bboxes.append(boxid)
|
|
|
|
if textend+3 > widest:
|
|
|
|
widest = textend+3
|
2001-07-10 18:39:41 -03:00
|
|
|
row += 1
|
1998-10-01 18:40:48 -03:00
|
|
|
canvheight = (row-1)*20 + 25
|
|
|
|
canvas.config(scrollregion=(0, 0, 150, canvheight))
|
|
|
|
for box in bboxes:
|
|
|
|
x1, y1, x2, y2 = canvas.coords(box)
|
|
|
|
canvas.coords(box, x1, y1, widest, y2)
|
|
|
|
|
1998-10-02 11:34:03 -03:00
|
|
|
def __onrelease(self, event=None):
|
1998-10-01 18:40:48 -03:00
|
|
|
canvas = self.__canvas
|
|
|
|
# find the current box
|
|
|
|
x = canvas.canvasx(event.x)
|
|
|
|
y = canvas.canvasy(event.y)
|
|
|
|
ids = canvas.find_overlapping(x, y, x, y)
|
|
|
|
for boxid in ids:
|
|
|
|
if boxid in self.__bboxes:
|
|
|
|
break
|
|
|
|
else:
|
1998-10-01 19:03:25 -03:00
|
|
|
## print 'No box found!'
|
1998-10-01 18:40:48 -03:00
|
|
|
return
|
1998-10-02 11:34:03 -03:00
|
|
|
tags = self.__canvas.gettags(boxid)
|
|
|
|
for t in tags:
|
|
|
|
if t[0] == '#':
|
|
|
|
break
|
1998-10-01 18:40:48 -03:00
|
|
|
else:
|
1998-10-02 11:34:03 -03:00
|
|
|
## print 'No color tag found!'
|
|
|
|
return
|
|
|
|
red, green, blue = ColorDB.rrggbb_to_triplet(t)
|
1998-10-02 12:52:10 -03:00
|
|
|
self.__dontcenter = 1
|
|
|
|
if self.__uoc.get():
|
|
|
|
self.__sb.update_views(red, green, blue)
|
|
|
|
else:
|
|
|
|
self.update_yourself(red, green, blue)
|
1998-10-06 15:56:31 -03:00
|
|
|
self.__red, self.__green, self.__blue = red, green, blue
|
|
|
|
|
|
|
|
def __toggleupdate(self, event=None):
|
|
|
|
if self.__uoc.get():
|
|
|
|
self.__sb.update_views(self.__red, self.__green, self.__blue)
|
1998-10-01 19:03:25 -03:00
|
|
|
|
1998-10-01 18:40:48 -03:00
|
|
|
def __quit(self, event=None):
|
1998-10-06 16:48:35 -03:00
|
|
|
self.__root.quit()
|
1998-10-01 18:40:48 -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 withdraw(self, event=None):
|
1998-10-01 18:40:48 -03:00
|
|
|
self.__root.withdraw()
|
|
|
|
|
|
|
|
def deiconify(self, event=None):
|
|
|
|
self.__root.deiconify()
|
|
|
|
|
|
|
|
def update_yourself(self, red, green, blue):
|
1998-10-02 11:34:03 -03:00
|
|
|
canvas = self.__canvas
|
|
|
|
# turn off the last box
|
|
|
|
if self.__lastbox:
|
|
|
|
canvas.itemconfigure(self.__lastbox, outline='')
|
|
|
|
# turn on the current box
|
|
|
|
colortag = ColorDB.triplet_to_rrggbb((red, green, blue))
|
|
|
|
canvas.itemconfigure(colortag, outline='black')
|
|
|
|
self.__lastbox = colortag
|
1998-10-02 12:52:10 -03:00
|
|
|
# fill the aliases
|
|
|
|
self.__aliases.delete(0, END)
|
|
|
|
try:
|
|
|
|
aliases = self.__sb.colordb().aliases_of(red, green, blue)[1:]
|
|
|
|
except ColorDB.BadColor:
|
|
|
|
self.__aliases.insert(END, '<no matching color>')
|
|
|
|
return
|
|
|
|
if not aliases:
|
|
|
|
self.__aliases.insert(END, '<no aliases>')
|
|
|
|
else:
|
|
|
|
for name in aliases:
|
|
|
|
self.__aliases.insert(END, name)
|
|
|
|
# maybe scroll the canvas so that the item is visible
|
|
|
|
if self.__dontcenter:
|
|
|
|
self.__dontcenter = 0
|
|
|
|
else:
|
|
|
|
ig, ig, ig, y1 = canvas.coords(colortag)
|
|
|
|
ig, ig, ig, y2 = canvas.coords(self.__bboxes[-1])
|
|
|
|
h = int(canvas['height']) * 0.5
|
|
|
|
canvas.yview('moveto', (y1-h) / y2)
|
1998-10-20 17:45:46 -03:00
|
|
|
|
|
|
|
def save_options(self, optiondb):
|
|
|
|
optiondb['UPONCLICK'] = self.__uoc.get()
|
1999-04-26 20:17:16 -03:00
|
|
|
|
1999-04-27 15:54:12 -03:00
|
|
|
def colordb_changed(self, colordb):
|
1999-04-26 20:17:16 -03:00
|
|
|
self.__canvas.delete('all')
|
|
|
|
self.__populate()
|