1 """Strip viewer and related widgets.
3 The classes in this file implement the StripViewer shown in the top two thirds
4 of the main Pynche window. It consists of three StripWidgets which display
5 the variations in red, green, and blue respectively of the currently selected
8 Each StripWidget shows the color variations that are reachable by varying an
9 axis of the currently selected color. So for example, if the color is
13 then the Red variations show colors from (0,163,196) to (255,163,196), the
14 Green variations show colors from (127,0,196) to (127,255,196), and the Blue
15 variations show colors from (127,163,0) to (127,163,255).
17 The selected color is always visible in all three StripWidgets, and in fact
18 each StripWidget highlights the selected color, and has an arrow pointing to
19 the selected chip, which includes the value along that particular axis.
21 Clicking on any chip in any StripWidget selects that color, and updates all
22 arrows and other windows. By toggling on Update while dragging, Pynche will
23 select the color under the cursor while you drag it, but be forewarned that
30 # Load this script into the Tcl interpreter and call it in
31 # StripWidget.set_color(). This is about as fast as it can be with the
32 # current _tkinter.c interface, which doesn't support Tcl Objects.
34 proc setcolor {canv colors} {
37 $canv itemconfigure $i -fill $c -outline $c
52 def constant(numchips
):
53 step
= 255.0 / (numchips
- 1)
57 seq
.append(int(start
))
59 numchips
= numchips
- 1
62 # red variations, green+blue = cyan constant
63 def constant_red_generator(numchips
, red
, green
, blue
):
64 seq
= constant(numchips
)
65 return map(None, [red
] * numchips
, seq
, seq
)
67 # green variations, red+blue = magenta constant
68 def constant_green_generator(numchips
, red
, green
, blue
):
69 seq
= constant(numchips
)
70 return map(None, seq
, [green
] * numchips
, seq
)
72 # blue variations, red+green = yellow constant
73 def constant_blue_generator(numchips
, red
, green
, blue
):
74 seq
= constant(numchips
)
75 return map(None, seq
, seq
, [blue
] * numchips
)
77 # red variations, green+blue = cyan constant
78 def constant_cyan_generator(numchips
, red
, green
, blue
):
79 seq
= constant(numchips
)
80 return map(None, seq
, [green
] * numchips
, [blue
] * numchips
)
82 # green variations, red+blue = magenta constant
83 def constant_magenta_generator(numchips
, red
, green
, blue
):
84 seq
= constant(numchips
)
85 return map(None, [red
] * numchips
, seq
, [blue
] * numchips
)
87 # blue variations, red+green = yellow constant
88 def constant_yellow_generator(numchips
, red
, green
, blue
):
89 seq
= constant(numchips
)
90 return map(None, [red
] * numchips
, [green
] * numchips
, seq
)
101 def __init__(self
, canvas
, x
):
102 self
._canvas
= canvas
103 self
.__arrow
, self
.__text
= self
._create
(x
)
106 def _create(self
, x
):
107 arrow
= self
._canvas
.create_line(
108 x
, self
._ARROWHEIGHT
+ self
._YOFFSET
,
110 x
+ self
._ARROWWIDTH
, self
._YOFFSET
,
114 text
= self
._canvas
.create_text(
115 x
+ self
._ARROWWIDTH
+ 13,
116 self
._ARROWHEIGHT
- self
._TEXTYOFFSET
,
122 coords
= self
._canvas
.coords(self
._TAG
)
126 def move_to(self
, x
):
127 deltax
= x
- self
._x
()
128 self
._canvas
.move(self
._TAG
, deltax
, 0)
130 def set_text(self
, text
):
131 self
._canvas
.itemconfigure(self
.__text
, text
=text
)
134 class RightArrow(LeftArrow
):
135 _TAG
= ('rightarrow',)
137 def _create(self
, x
):
138 arrow
= self
._canvas
.create_line(
140 x
+ self
._ARROWWIDTH
, self
._YOFFSET
,
141 x
+ self
._ARROWWIDTH
, self
._ARROWHEIGHT
+ self
._YOFFSET
,
145 text
= self
._canvas
.create_text(
146 x
- self
._ARROWWIDTH
+ 15, # BAW: kludge
147 self
._ARROWHEIGHT
- self
._TEXTYOFFSET
,
154 coords
= self
._canvas
.coords(self
._TAG
)
156 return coords
[0] + self
._ARROWWIDTH
165 def __init__(self
, switchboard
,
167 chipwidth
= _CHIPWIDTH
,
168 chipheight
= _CHIPHEIGHT
,
169 numchips
= _NUMCHIPS
,
176 self
.__generator
= generator
178 self
.__numchips
= numchips
179 assert self
.__axis
in (0, 1, 2)
182 # the last chip selected
183 self
.__lastchip
= None
184 self
.__sb
= switchboard
186 canvaswidth
= numchips
* (chipwidth
+ 1)
187 canvasheight
= chipheight
+ 43 # BAW: Kludge
189 # create the canvas and pack it
190 canvas
= self
.__canvas
= Canvas(master
,
198 canvas
.bind('<ButtonPress-1>', self
.__select
_chip
)
199 canvas
.bind('<ButtonRelease-1>', self
.__select
_chip
)
200 canvas
.bind('<B1-Motion>', self
.__select
_chip
)
202 # Load a proc into the Tcl interpreter. This is used in the
203 # set_color() method to speed up setting the chip colors.
204 canvas
.tk
.eval(TCLPROC
)
206 # create the color strip
207 chips
= self
.__chips
= []
211 for c
in range(self
.__numchips
):
213 canvas
.create_rectangle(
214 x
, y
, x
+chipwidth
, y
+chipheight
,
215 fill
=color
, outline
=color
,
217 x
= x
+ chipwidth
+ 1 # for outline
220 # create the strip label
221 self
.__label
= canvas
.create_text(
222 3, y
+ chipheight
+ 8,
226 # create the arrow and text item
227 chipx
= self
.__arrow
_x
(0)
228 self
.__leftarrow
= LeftArrow(canvas
, chipx
)
230 chipx
= self
.__arrow
_x
(len(chips
) - 1)
231 self
.__rightarrow
= RightArrow(canvas
, chipx
)
233 def __arrow_x(self
, chipnum
):
234 coords
= self
.__canvas
.coords(chipnum
+1)
236 x0
, y0
, x1
, y1
= coords
237 return (x1
+ x0
) / 2.0
239 # Invoked when one of the chips is clicked. This should just tell the
240 # switchboard to set the color on all the output components
241 def __select_chip(self
, event
=None):
244 canvas
= self
.__canvas
245 chip
= canvas
.find_overlapping(x
, y
, x
, y
)
246 if chip
and (1 <= chip
[0] <= self
.__numchips
):
247 color
= self
.__chips
[chip
[0]-1]
248 red
, green
, blue
= ColorDB
.rrggbb_to_triplet(color
)
249 etype
= int(event
.type)
250 if (etype
== BTNUP
or self
.__uwd
.get()):
252 self
.__sb
.update_views(red
, green
, blue
)
254 # just track the arrows
255 self
.__trackarrow
(chip
[0], (red
, green
, blue
))
257 def __trackarrow(self
, chip
, rgbtuple
):
258 # invert the last chip
259 if self
.__lastchip
is not None:
260 color
= self
.__canvas
.itemcget(self
.__lastchip
, 'fill')
261 self
.__canvas
.itemconfigure(self
.__lastchip
, outline
=color
)
262 self
.__lastchip
= chip
263 # get the arrow's text
264 coloraxis
= rgbtuple
[self
.__axis
]
265 if self
.__hexp
.get():
267 text
= hex(coloraxis
)
270 text
= repr(coloraxis
)
271 # move the arrow, and set its text
274 self
.__leftarrow
.set_text(text
)
275 self
.__leftarrow
.move_to(self
.__arrow
_x
(chip
-1))
276 self
.__rightarrow
.move_to(-100)
278 # use the right arrow
279 self
.__rightarrow
.set_text(text
)
280 self
.__rightarrow
.move_to(self
.__arrow
_x
(chip
-1))
281 self
.__leftarrow
.move_to(-100)
282 # and set the chip's outline
283 brightness
= ColorDB
.triplet_to_brightness(rgbtuple
)
284 if brightness
<= 128:
288 self
.__canvas
.itemconfigure(chip
, outline
=outline
)
291 def update_yourself(self
, red
, green
, blue
):
292 assert self
.__generator
295 chips
= self
.__chips
= []
296 tk
= self
.__canvas
.tk
297 # get the red, green, and blue components for all chips
298 for t
in self
.__generator
(self
.__numchips
, red
, green
, blue
):
299 rrggbb
= ColorDB
.triplet_to_rrggbb(t
)
301 tred
, tgreen
, tblue
= t
302 if tred
<= red
and tgreen
<= green
and tblue
<= blue
:
305 # call the raw tcl script
306 colors
= SPACE
.join(chips
)
307 tk
.eval('setcolor %s {%s}' % (self
.__canvas
._w
, colors
))
308 # move the arrows around
309 self
.__trackarrow
(chip
, (red
, green
, blue
))
311 def set(self
, label
, generator
):
312 self
.__canvas
.itemconfigure(self
.__label
, text
=label
)
313 self
.__generator
= generator
317 def __init__(self
, switchboard
, master
=None):
318 self
.__sb
= switchboard
319 optiondb
= switchboard
.optiondb()
320 # create a frame inside the master.
321 frame
= Frame(master
, relief
=RAISED
, borderwidth
=1)
322 frame
.grid(row
=1, column
=0, columnspan
=2, sticky
='NSEW')
323 # create the options to be used later
324 uwd
= self
.__uwdvar
= BooleanVar()
325 uwd
.set(optiondb
.get('UPWHILEDRAG', 0))
326 hexp
= self
.__hexpvar
= BooleanVar()
327 hexp
.set(optiondb
.get('HEXSTRIP', 0))
328 # create the red, green, blue strips inside their own frame
329 frame1
= Frame(frame
)
330 frame1
.pack(expand
=YES
, fill
=BOTH
)
331 self
.__reds
= StripWidget(switchboard
, frame1
,
332 generator
=constant_cyan_generator
,
334 label
='Red Variations',
335 uwdvar
=uwd
, hexvar
=hexp
)
337 self
.__greens
= StripWidget(switchboard
, frame1
,
338 generator
=constant_magenta_generator
,
340 label
='Green Variations',
341 uwdvar
=uwd
, hexvar
=hexp
)
343 self
.__blues
= StripWidget(switchboard
, frame1
,
344 generator
=constant_yellow_generator
,
346 label
='Blue Variations',
347 uwdvar
=uwd
, hexvar
=hexp
)
349 # create a frame to contain the controls
350 frame2
= Frame(frame
)
351 frame2
.pack(expand
=YES
, fill
=BOTH
)
352 frame2
.columnconfigure(0, weight
=20)
353 frame2
.columnconfigure(2, weight
=20)
357 # create the black button
358 blackbtn
= Button(frame2
,
360 command
=self
.__toblack
)
361 blackbtn
.grid(row
=0, column
=0, rowspan
=2, sticky
=W
, padx
=padx
)
363 # create the controls
364 uwdbtn
= Checkbutton(frame2
,
365 text
='Update while dragging',
367 uwdbtn
.grid(row
=0, column
=1, sticky
=W
)
368 hexbtn
= Checkbutton(frame2
,
371 command
=self
.__togglehex
)
372 hexbtn
.grid(row
=1, column
=1, sticky
=W
)
374 # XXX: ignore this feature for now; it doesn't work quite right yet
376 ## gentypevar = self.__gentypevar = IntVar()
377 ## self.__variations = Radiobutton(frame,
378 ## text='Variations',
379 ## variable=gentypevar,
381 ## command=self.__togglegentype)
382 ## self.__variations.grid(row=0, column=1, sticky=W)
383 ## self.__constants = Radiobutton(frame,
385 ## variable=gentypevar,
387 ## command=self.__togglegentype)
388 ## self.__constants.grid(row=1, column=1, sticky=W)
390 # create the white button
391 whitebtn
= Button(frame2
,
393 command
=self
.__towhite
)
394 whitebtn
.grid(row
=0, column
=2, rowspan
=2, sticky
=E
, padx
=padx
)
396 def update_yourself(self
, red
, green
, blue
):
397 self
.__reds
.update_yourself(red
, green
, blue
)
398 self
.__greens
.update_yourself(red
, green
, blue
)
399 self
.__blues
.update_yourself(red
, green
, blue
)
401 def __togglehex(self
, event
=None):
402 red
, green
, blue
= self
.__sb
.current_rgb()
403 self
.update_yourself(red
, green
, blue
)
405 ## def __togglegentype(self, event=None):
406 ## which = self.__gentypevar.get()
408 ## self.__reds.set(label='Red Variations',
409 ## generator=constant_cyan_generator)
410 ## self.__greens.set(label='Green Variations',
411 ## generator=constant_magenta_generator)
412 ## self.__blues.set(label='Blue Variations',
413 ## generator=constant_yellow_generator)
415 ## self.__reds.set(label='Red Constant',
416 ## generator=constant_red_generator)
417 ## self.__greens.set(label='Green Constant',
418 ## generator=constant_green_generator)
419 ## self.__blues.set(label='Blue Constant',
420 ## generator=constant_blue_generator)
423 ## self.__sb.update_views_current()
425 def __toblack(self
, event
=None):
426 self
.__sb
.update_views(0, 0, 0)
428 def __towhite(self
, event
=None):
429 self
.__sb
.update_views(255, 255, 255)
431 def save_options(self
, optiondb
):
432 optiondb
['UPWHILEDRAG'] = self
.__uwdvar
.get()
433 optiondb
['HEXSTRIP'] = self
.__hexpvar
.get()