1998-10-03 00:20:14 +08:00
|
|
|
|
"""Strip viewer and related widgets.
|
|
|
|
|
|
|
|
|
|
The classes in this file implement the StripViewer shown in the top two thirds
|
|
|
|
|
of the main Pynche window. It consists of three StripWidgets which display
|
|
|
|
|
the variations in red, green, and blue respectively of the currently selected
|
|
|
|
|
r/g/b color value.
|
|
|
|
|
|
|
|
|
|
Each StripWidget shows the color variations that are reachable by varying an
|
|
|
|
|
axis of the currently selected color. So for example, if the color is
|
|
|
|
|
|
|
|
|
|
(R,G,B)=(127,163,196)
|
|
|
|
|
|
|
|
|
|
then the Red variations show colors from (0,163,196) to (255,163,196), the
|
|
|
|
|
Green variations show colors from (127,0,196) to (127,255,196), and the Blue
|
|
|
|
|
variations show colors from (127,163,0) to (127,163,255).
|
|
|
|
|
|
|
|
|
|
The selected color is always visible in all three StripWidgets, and in fact
|
|
|
|
|
each StripWidget highlights the selected color, and has an arrow pointing to
|
|
|
|
|
the selected chip, which includes the value along that particular axis.
|
|
|
|
|
|
|
|
|
|
Clicking on any chip in any StripWidget selects that color, and updates all
|
|
|
|
|
arrows and other windows. By toggling on Update while dragging, Pynche will
|
|
|
|
|
select the color under the cursor while you drag it, but be forewarned that
|
|
|
|
|
this can be slow.
|
|
|
|
|
"""
|
|
|
|
|
|
1998-02-18 08:05:59 +08:00
|
|
|
|
import string
|
1998-02-13 03:51:57 +08:00
|
|
|
|
from Tkinter import *
|
|
|
|
|
import ColorDB
|
|
|
|
|
|
1998-02-19 00:22:22 +08:00
|
|
|
|
# Load this script into the Tcl interpreter and call it in
|
|
|
|
|
# StripWidget.set_color(). This is about as fast as it can be with the
|
|
|
|
|
# current _tkinter.c interface, which doesn't support Tcl Objects.
|
|
|
|
|
TCLPROC = '''\
|
|
|
|
|
proc setcolor {canv colors} {
|
|
|
|
|
set i 1
|
|
|
|
|
foreach c $colors {
|
|
|
|
|
$canv itemconfigure $i -fill $c -outline $c
|
|
|
|
|
incr i
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
'''
|
|
|
|
|
|
1998-03-17 23:59:26 +08:00
|
|
|
|
# Tcl event types
|
|
|
|
|
BTNDOWN = 4
|
|
|
|
|
BTNUP = 5
|
|
|
|
|
BTNDRAG = 6
|
|
|
|
|
|
1998-02-19 00:22:22 +08:00
|
|
|
|
|
1998-09-29 06:42:44 +08:00
|
|
|
|
def constant(numchips):
|
|
|
|
|
step = 255.0 / (numchips - 1)
|
|
|
|
|
start = 0.0
|
|
|
|
|
seq = []
|
|
|
|
|
while numchips > 0:
|
|
|
|
|
seq.append(int(start))
|
|
|
|
|
start = start + step
|
|
|
|
|
numchips = numchips - 1
|
|
|
|
|
return seq
|
|
|
|
|
|
|
|
|
|
# red variations, green+blue = cyan constant
|
|
|
|
|
def constant_cyan_generator(numchips, red, green, blue):
|
|
|
|
|
seq = constant(numchips)
|
|
|
|
|
return map(None, seq, [green] * numchips, [blue] * numchips)
|
|
|
|
|
|
|
|
|
|
# green variations, red+blue = magenta constant
|
|
|
|
|
def constant_magenta_generator(numchips, red, green, blue):
|
|
|
|
|
seq = constant(numchips)
|
|
|
|
|
return map(None, [red] * numchips, seq, [blue] * numchips)
|
|
|
|
|
|
|
|
|
|
# blue variations, red+green = yellow constant
|
|
|
|
|
def constant_yellow_generator(numchips, red, green, blue):
|
|
|
|
|
seq = constant(numchips)
|
|
|
|
|
return map(None, [red] * numchips, [green] * numchips, seq)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1998-02-18 08:05:59 +08:00
|
|
|
|
|
1998-02-13 03:51:57 +08:00
|
|
|
|
class LeftArrow:
|
|
|
|
|
_ARROWWIDTH = 30
|
|
|
|
|
_ARROWHEIGHT = 15
|
|
|
|
|
_YOFFSET = 13
|
|
|
|
|
_TEXTYOFFSET = 1
|
|
|
|
|
_TAG = ('leftarrow',)
|
|
|
|
|
|
|
|
|
|
def __init__(self, canvas, x):
|
|
|
|
|
self._canvas = canvas
|
|
|
|
|
self.__arrow, self.__text = self._create(x)
|
|
|
|
|
self.move_to(x)
|
|
|
|
|
|
|
|
|
|
def _create(self, x):
|
|
|
|
|
arrow = self._canvas.create_line(
|
|
|
|
|
x, self._ARROWHEIGHT + self._YOFFSET,
|
|
|
|
|
x, self._YOFFSET,
|
|
|
|
|
x + self._ARROWWIDTH, self._YOFFSET,
|
|
|
|
|
arrow='first',
|
|
|
|
|
width=3.0,
|
|
|
|
|
tags=self._TAG)
|
|
|
|
|
text = self._canvas.create_text(
|
|
|
|
|
x + self._ARROWWIDTH + 13,
|
|
|
|
|
self._ARROWHEIGHT - self._TEXTYOFFSET,
|
1998-02-14 05:28:47 +08:00
|
|
|
|
tags=self._TAG,
|
1998-02-13 03:51:57 +08:00
|
|
|
|
text='128')
|
|
|
|
|
return arrow, text
|
|
|
|
|
|
|
|
|
|
def _x(self):
|
|
|
|
|
coords = self._canvas.coords(self._TAG)
|
|
|
|
|
assert coords
|
|
|
|
|
return coords[0]
|
|
|
|
|
|
|
|
|
|
def move_to(self, x):
|
|
|
|
|
deltax = x - self._x()
|
|
|
|
|
self._canvas.move(self._TAG, deltax, 0)
|
|
|
|
|
|
1998-02-14 05:28:47 +08:00
|
|
|
|
def set_text(self, text):
|
|
|
|
|
self._canvas.itemconfigure(self.__text, text=text)
|
|
|
|
|
|
1998-02-13 03:51:57 +08:00
|
|
|
|
|
|
|
|
|
class RightArrow(LeftArrow):
|
|
|
|
|
_TAG = ('rightarrow',)
|
|
|
|
|
|
|
|
|
|
def _create(self, x):
|
|
|
|
|
arrow = self._canvas.create_line(
|
|
|
|
|
x, self._YOFFSET,
|
|
|
|
|
x + self._ARROWWIDTH, self._YOFFSET,
|
|
|
|
|
x + self._ARROWWIDTH, self._ARROWHEIGHT + self._YOFFSET,
|
|
|
|
|
arrow='last',
|
|
|
|
|
width=3.0,
|
|
|
|
|
tags=self._TAG)
|
|
|
|
|
text = self._canvas.create_text(
|
1998-02-14 05:28:47 +08:00
|
|
|
|
x - self._ARROWWIDTH + 15, # TBD: kludge
|
1998-02-13 03:51:57 +08:00
|
|
|
|
self._ARROWHEIGHT - self._TEXTYOFFSET,
|
1998-10-07 07:04:55 +08:00
|
|
|
|
justify=RIGHT,
|
1998-02-14 05:28:47 +08:00
|
|
|
|
text='128',
|
|
|
|
|
tags=self._TAG)
|
1998-02-13 03:51:57 +08:00
|
|
|
|
return arrow, text
|
|
|
|
|
|
|
|
|
|
def _x(self):
|
|
|
|
|
coords = self._canvas.bbox(self._TAG)
|
|
|
|
|
assert coords
|
|
|
|
|
return coords[2] - 6 # TBD: kludge
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1998-09-29 04:58:06 +08:00
|
|
|
|
class StripWidget:
|
1998-02-13 03:51:57 +08:00
|
|
|
|
_CHIPHEIGHT = 50
|
|
|
|
|
_CHIPWIDTH = 10
|
|
|
|
|
_NUMCHIPS = 40
|
|
|
|
|
|
1998-09-29 04:58:06 +08:00
|
|
|
|
def __init__(self, switchboard,
|
|
|
|
|
parent = None,
|
1998-09-29 06:42:44 +08:00
|
|
|
|
chipwidth = _CHIPWIDTH,
|
|
|
|
|
chipheight = _CHIPHEIGHT,
|
|
|
|
|
numchips = _NUMCHIPS,
|
1998-09-29 04:58:06 +08:00
|
|
|
|
generator = None,
|
|
|
|
|
axis = None,
|
1998-10-01 11:08:07 +08:00
|
|
|
|
label = '',
|
1998-10-07 00:13:35 +08:00
|
|
|
|
uwdvar = None,
|
|
|
|
|
hexvar = None):
|
1998-09-29 05:01:55 +08:00
|
|
|
|
# instance variables
|
|
|
|
|
self.__generator = generator
|
|
|
|
|
self.__axis = axis
|
1998-09-29 06:42:44 +08:00
|
|
|
|
self.__numchips = numchips
|
1998-09-29 05:01:55 +08:00
|
|
|
|
assert self.__axis in (0, 1, 2)
|
1998-10-01 11:08:07 +08:00
|
|
|
|
self.__uwd = uwdvar
|
1998-10-07 00:13:35 +08:00
|
|
|
|
self.__hexp = hexvar
|
1998-09-29 04:58:06 +08:00
|
|
|
|
# the last chip selected
|
1998-03-17 23:59:26 +08:00
|
|
|
|
self.__lastchip = None
|
1998-09-29 04:58:06 +08:00
|
|
|
|
self.__sb = switchboard
|
1998-09-29 05:01:55 +08:00
|
|
|
|
|
1998-02-13 03:51:57 +08:00
|
|
|
|
canvaswidth = numchips * (chipwidth + 1)
|
1998-02-17 11:09:40 +08:00
|
|
|
|
canvasheight = chipheight + 43 # TBD: Kludge
|
1998-02-13 03:51:57 +08:00
|
|
|
|
|
1998-02-17 11:09:40 +08:00
|
|
|
|
# create the canvas and pack it
|
1998-02-19 01:00:24 +08:00
|
|
|
|
canvas = self.__canvas = Canvas(
|
1998-02-13 03:51:57 +08:00
|
|
|
|
parent,
|
|
|
|
|
width=canvaswidth,
|
1998-02-17 11:09:40 +08:00
|
|
|
|
height=canvasheight,
|
|
|
|
|
## borderwidth=2,
|
|
|
|
|
## relief=GROOVE
|
|
|
|
|
)
|
|
|
|
|
|
1998-02-19 01:00:24 +08:00
|
|
|
|
canvas.pack()
|
1998-03-17 23:59:26 +08:00
|
|
|
|
canvas.bind('<ButtonPress-1>', self.__select_chip)
|
1998-02-19 01:00:24 +08:00
|
|
|
|
canvas.bind('<ButtonRelease-1>', self.__select_chip)
|
1998-03-17 23:59:26 +08:00
|
|
|
|
canvas.bind('<B1-Motion>', self.__select_chip)
|
1998-02-13 03:51:57 +08:00
|
|
|
|
|
1998-02-19 00:22:22 +08:00
|
|
|
|
# Load a proc into the Tcl interpreter. This is used in the
|
|
|
|
|
# set_color() method to speed up setting the chip colors.
|
1998-02-19 01:00:24 +08:00
|
|
|
|
canvas.tk.eval(TCLPROC)
|
1998-02-19 00:22:22 +08:00
|
|
|
|
|
1998-02-13 03:51:57 +08:00
|
|
|
|
# create the color strip
|
|
|
|
|
chips = self.__chips = []
|
|
|
|
|
x = 1
|
|
|
|
|
y = 30
|
1998-02-19 01:00:24 +08:00
|
|
|
|
tags = ('chip',)
|
1998-02-13 03:51:57 +08:00
|
|
|
|
for c in range(self.__numchips):
|
1998-02-18 08:05:59 +08:00
|
|
|
|
color = 'grey'
|
1998-02-19 01:00:24 +08:00
|
|
|
|
rect = canvas.create_rectangle(
|
1998-02-13 03:51:57 +08:00
|
|
|
|
x, y, x+chipwidth, y+chipheight,
|
1998-02-19 01:00:24 +08:00
|
|
|
|
fill=color, outline=color,
|
|
|
|
|
tags=tags)
|
1998-02-13 03:51:57 +08:00
|
|
|
|
x = x + chipwidth + 1 # for outline
|
1998-02-18 08:05:59 +08:00
|
|
|
|
chips.append(color)
|
1998-02-13 03:51:57 +08:00
|
|
|
|
|
1998-09-29 04:58:06 +08:00
|
|
|
|
# create the strip label
|
1998-02-19 01:00:24 +08:00
|
|
|
|
self.__label = canvas.create_text(
|
1998-02-17 11:09:40 +08:00
|
|
|
|
3, y + chipheight + 8,
|
1998-09-29 06:42:44 +08:00
|
|
|
|
text=label,
|
1998-02-17 11:09:40 +08:00
|
|
|
|
anchor=W)
|
|
|
|
|
|
1998-02-13 03:51:57 +08:00
|
|
|
|
# create the arrow and text item
|
|
|
|
|
chipx = self.__arrow_x(0)
|
1998-02-19 01:00:24 +08:00
|
|
|
|
self.__leftarrow = LeftArrow(canvas, chipx)
|
1998-02-13 03:51:57 +08:00
|
|
|
|
|
|
|
|
|
chipx = self.__arrow_x(len(chips) - 1)
|
1998-02-19 01:00:24 +08:00
|
|
|
|
self.__rightarrow = RightArrow(canvas, chipx)
|
1998-02-13 03:51:57 +08:00
|
|
|
|
|
1998-02-17 11:09:40 +08:00
|
|
|
|
def __arrow_x(self, chipnum):
|
1998-02-18 08:05:59 +08:00
|
|
|
|
coords = self.__canvas.coords(chipnum+1)
|
1998-02-17 11:09:40 +08:00
|
|
|
|
assert coords
|
|
|
|
|
x0, y0, x1, y1 = coords
|
|
|
|
|
return (x1 + x0) / 2.0
|
|
|
|
|
|
1998-09-29 06:42:44 +08:00
|
|
|
|
# Invoked when one of the chips is clicked. This should just tell the
|
|
|
|
|
# switchboard to set the color on all the output components
|
1998-02-17 11:09:40 +08:00
|
|
|
|
def __select_chip(self, event=None):
|
1998-09-29 06:42:44 +08:00
|
|
|
|
x = event.x
|
|
|
|
|
y = event.y
|
|
|
|
|
canvas = self.__canvas
|
|
|
|
|
chip = canvas.find_overlapping(x, y, x, y)
|
|
|
|
|
if chip and (1 <= chip[0] <= self.__numchips):
|
|
|
|
|
color = self.__chips[chip[0]-1]
|
|
|
|
|
red, green, blue = ColorDB.rrggbb_to_triplet(color)
|
|
|
|
|
etype = int(event.type)
|
1998-10-01 11:08:07 +08:00
|
|
|
|
if (etype == BTNUP or self.__uwd.get()):
|
1998-09-29 06:42:44 +08:00
|
|
|
|
# update everyone
|
|
|
|
|
self.__sb.update_views(red, green, blue)
|
|
|
|
|
else:
|
|
|
|
|
# just track the arrows
|
|
|
|
|
self.__trackarrow(chip[0], (red, green, blue))
|
1998-02-17 11:09:40 +08:00
|
|
|
|
|
1998-03-17 23:59:26 +08:00
|
|
|
|
def __trackarrow(self, chip, rgbtuple):
|
|
|
|
|
# invert the last chip
|
|
|
|
|
if self.__lastchip is not None:
|
|
|
|
|
color = self.__canvas.itemcget(self.__lastchip, 'fill')
|
|
|
|
|
self.__canvas.itemconfigure(self.__lastchip, outline=color)
|
|
|
|
|
self.__lastchip = chip
|
1998-02-18 08:05:59 +08:00
|
|
|
|
# get the arrow's text
|
|
|
|
|
coloraxis = rgbtuple[self.__axis]
|
1998-10-07 00:13:35 +08:00
|
|
|
|
if self.__hexp.get():
|
|
|
|
|
# hex
|
|
|
|
|
text = hex(coloraxis)
|
|
|
|
|
else:
|
|
|
|
|
# decimal
|
|
|
|
|
text = repr(coloraxis)
|
1998-02-18 08:05:59 +08:00
|
|
|
|
# move the arrow, and set it's text
|
|
|
|
|
if coloraxis <= 128:
|
1998-09-29 04:58:06 +08:00
|
|
|
|
# use the left arrow
|
1998-02-18 08:05:59 +08:00
|
|
|
|
self.__leftarrow.set_text(text)
|
|
|
|
|
self.__leftarrow.move_to(self.__arrow_x(chip-1))
|
|
|
|
|
self.__rightarrow.move_to(-100)
|
|
|
|
|
else:
|
1998-09-29 04:58:06 +08:00
|
|
|
|
# use the right arrow
|
1998-02-18 08:05:59 +08:00
|
|
|
|
self.__rightarrow.set_text(text)
|
|
|
|
|
self.__rightarrow.move_to(self.__arrow_x(chip-1))
|
|
|
|
|
self.__leftarrow.move_to(-100)
|
|
|
|
|
# and set the chip's outline
|
1998-09-29 04:58:06 +08:00
|
|
|
|
brightness = ColorDB.triplet_to_brightness(rgbtuple)
|
1998-09-29 06:52:02 +08:00
|
|
|
|
if brightness <= 128:
|
1998-02-18 08:05:59 +08:00
|
|
|
|
outline = 'white'
|
|
|
|
|
else:
|
|
|
|
|
outline = 'black'
|
|
|
|
|
self.__canvas.itemconfigure(chip, outline=outline)
|
1998-03-17 07:08:53 +08:00
|
|
|
|
|
1998-03-17 23:59:26 +08:00
|
|
|
|
|
1998-09-29 04:58:06 +08:00
|
|
|
|
def update_yourself(self, red, green, blue):
|
1998-03-17 23:59:26 +08:00
|
|
|
|
assert self.__generator
|
|
|
|
|
i = 1
|
|
|
|
|
chip = 0
|
|
|
|
|
chips = self.__chips = []
|
|
|
|
|
tclcmd = []
|
|
|
|
|
tk = self.__canvas.tk
|
1998-09-29 04:58:06 +08:00
|
|
|
|
# get the red, green, and blue components for all chips
|
1998-09-29 06:42:44 +08:00
|
|
|
|
for t in self.__generator(self.__numchips, red, green, blue):
|
1998-03-17 23:59:26 +08:00
|
|
|
|
rrggbb = ColorDB.triplet_to_rrggbb(t)
|
|
|
|
|
chips.append(rrggbb)
|
|
|
|
|
tred, tgreen, tblue = t
|
|
|
|
|
if tred <= red and tgreen <= green and tblue <= blue:
|
|
|
|
|
chip = i
|
|
|
|
|
i = i + 1
|
|
|
|
|
# call the raw tcl script
|
|
|
|
|
colors = string.join(chips)
|
|
|
|
|
tk.eval('setcolor %s {%s}' % (self.__canvas._w, colors))
|
|
|
|
|
# move the arrows around
|
1998-09-29 04:58:06 +08:00
|
|
|
|
self.__trackarrow(chip, (red, green, blue))
|
1998-03-17 23:59:26 +08:00
|
|
|
|
|
1998-09-29 06:42:44 +08:00
|
|
|
|
|
|
|
|
|
class StripViewer:
|
|
|
|
|
def __init__(self, switchboard, parent=None):
|
|
|
|
|
self.__sb = switchboard
|
1998-10-21 04:45:46 +08:00
|
|
|
|
optiondb = switchboard.optiondb()
|
1998-09-30 01:36:43 +08:00
|
|
|
|
# create a frame inside the parent
|
1998-10-01 22:26:04 +08:00
|
|
|
|
self.__frame = Frame(parent) #, relief=GROOVE, borderwidth=2)
|
|
|
|
|
self.__frame.grid(row=1, column=0, columnspan=2, sticky='EW')
|
1998-10-21 04:45:46 +08:00
|
|
|
|
uwd = self.__uwdvar = BooleanVar()
|
|
|
|
|
uwd.set(optiondb.get('UPWHILEDRAG', 0))
|
|
|
|
|
hexp = self.__hexpvar = BooleanVar()
|
|
|
|
|
hexp.set(optiondb.get('HEXSTRIP', 0))
|
1998-09-30 01:36:43 +08:00
|
|
|
|
self.__reds = StripWidget(switchboard, self.__frame,
|
1998-09-29 06:42:44 +08:00
|
|
|
|
generator=constant_cyan_generator,
|
|
|
|
|
axis=0,
|
1998-10-01 11:08:07 +08:00
|
|
|
|
label='Red Variations',
|
1998-10-07 00:13:35 +08:00
|
|
|
|
uwdvar=uwd, hexvar=hexp)
|
1998-09-29 06:42:44 +08:00
|
|
|
|
|
1998-09-30 01:36:43 +08:00
|
|
|
|
self.__greens = StripWidget(switchboard, self.__frame,
|
1998-09-29 06:42:44 +08:00
|
|
|
|
generator=constant_magenta_generator,
|
|
|
|
|
axis=1,
|
1998-10-01 11:08:07 +08:00
|
|
|
|
label='Green Variations',
|
1998-10-07 00:13:35 +08:00
|
|
|
|
uwdvar=uwd, hexvar=hexp)
|
1998-09-29 06:42:44 +08:00
|
|
|
|
|
1998-09-30 01:36:43 +08:00
|
|
|
|
self.__blues = StripWidget(switchboard, self.__frame,
|
1998-09-29 06:42:44 +08:00
|
|
|
|
generator=constant_yellow_generator,
|
|
|
|
|
axis=2,
|
1998-10-01 11:08:07 +08:00
|
|
|
|
label='Blue Variations',
|
1998-10-07 00:13:35 +08:00
|
|
|
|
uwdvar=uwd, hexvar=hexp)
|
|
|
|
|
|
|
|
|
|
frame = self.__frame1 = Frame(self.__frame)
|
|
|
|
|
frame.pack()
|
|
|
|
|
|
|
|
|
|
self.__uwd = Checkbutton(frame,
|
1998-10-01 11:08:07 +08:00
|
|
|
|
text='Update while dragging',
|
|
|
|
|
variable=uwd)
|
1998-10-07 00:13:35 +08:00
|
|
|
|
self.__uwd.grid(row=0, column=0, sticky=W)
|
|
|
|
|
|
|
|
|
|
self.__hex = Checkbutton(frame,
|
|
|
|
|
text='Hexadecimal',
|
|
|
|
|
variable=hexp,
|
|
|
|
|
command=self.__togglehex)
|
|
|
|
|
self.__hex.grid(row=1, column=0, sticky=W)
|
|
|
|
|
|
1998-10-01 22:26:04 +08:00
|
|
|
|
self.__div = Frame(self.__frame,
|
|
|
|
|
height=2,
|
|
|
|
|
borderwidth=2,
|
|
|
|
|
relief=RAISED)
|
|
|
|
|
self.__div.pack(expand=1, fill=X)
|
1998-09-29 06:42:44 +08:00
|
|
|
|
|
|
|
|
|
def update_yourself(self, red, green, blue):
|
|
|
|
|
self.__reds.update_yourself(red, green, blue)
|
|
|
|
|
self.__greens.update_yourself(red, green, blue)
|
|
|
|
|
self.__blues.update_yourself(red, green, blue)
|
1998-10-07 00:13:35 +08:00
|
|
|
|
|
|
|
|
|
def __togglehex(self, event=None):
|
|
|
|
|
red, green, blue = self.__sb.current_rgb()
|
|
|
|
|
self.update_yourself(red, green, blue)
|
1998-10-21 04:45:46 +08:00
|
|
|
|
|
|
|
|
|
def save_options(self, optiondb):
|
|
|
|
|
optiondb['UPWHILEDRAG'] = self.__uwdvar.get()
|
|
|
|
|
optiondb['HEXSTRIP'] = self.__hexpvar.get()
|