source: vendor/python/2.5/Tools/pynche/StripViewer.py

Last change on this file was 3225, checked in by bird, 18 years ago

Python 2.5

File size: 15.1 KB
Line 
1"""Strip viewer and related widgets.
2
3The classes in this file implement the StripViewer shown in the top two thirds
4of the main Pynche window. It consists of three StripWidgets which display
5the variations in red, green, and blue respectively of the currently selected
6r/g/b color value.
7
8Each StripWidget shows the color variations that are reachable by varying an
9axis of the currently selected color. So for example, if the color is
10
11 (R,G,B)=(127,163,196)
12
13then the Red variations show colors from (0,163,196) to (255,163,196), the
14Green variations show colors from (127,0,196) to (127,255,196), and the Blue
15variations show colors from (127,163,0) to (127,163,255).
16
17The selected color is always visible in all three StripWidgets, and in fact
18each StripWidget highlights the selected color, and has an arrow pointing to
19the selected chip, which includes the value along that particular axis.
20
21Clicking on any chip in any StripWidget selects that color, and updates all
22arrows and other windows. By toggling on Update while dragging, Pynche will
23select the color under the cursor while you drag it, but be forewarned that
24this can be slow.
25"""
26
27from Tkinter import *
28import ColorDB
29
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.
33TCLPROC = '''\
34proc setcolor {canv colors} {
35 set i 1
36 foreach c $colors {
37 $canv itemconfigure $i -fill $c -outline $c
38 incr i
39 }
40}
41'''
42
43# Tcl event types
44BTNDOWN = 4
45BTNUP = 5
46BTNDRAG = 6
47
48SPACE = ' '
49
50
51
52
53def constant(numchips):
54 step = 255.0 / (numchips - 1)
55 start = 0.0
56 seq = []
57 while numchips > 0:
58 seq.append(int(start))
59 start = start + step
60 numchips = numchips - 1
61 return seq
62
63# red variations, green+blue = cyan constant
64def constant_red_generator(numchips, red, green, blue):
65 seq = constant(numchips)
66 return map(None, [red] * numchips, seq, seq)
67
68# green variations, red+blue = magenta constant
69def constant_green_generator(numchips, red, green, blue):
70 seq = constant(numchips)
71 return map(None, seq, [green] * numchips, seq)
72
73# blue variations, red+green = yellow constant
74def constant_blue_generator(numchips, red, green, blue):
75 seq = constant(numchips)
76 return map(None, seq, seq, [blue] * numchips)
77
78# red variations, green+blue = cyan constant
79def constant_cyan_generator(numchips, red, green, blue):
80 seq = constant(numchips)
81 return map(None, seq, [green] * numchips, [blue] * numchips)
82
83# green variations, red+blue = magenta constant
84def constant_magenta_generator(numchips, red, green, blue):
85 seq = constant(numchips)
86 return map(None, [red] * numchips, seq, [blue] * numchips)
87
88# blue variations, red+green = yellow constant
89def constant_yellow_generator(numchips, red, green, blue):
90 seq = constant(numchips)
91 return map(None, [red] * numchips, [green] * numchips, seq)
92
93
94
95
96class LeftArrow:
97 _ARROWWIDTH = 30
98 _ARROWHEIGHT = 15
99 _YOFFSET = 13
100 _TEXTYOFFSET = 1
101 _TAG = ('leftarrow',)
102
103 def __init__(self, canvas, x):
104 self._canvas = canvas
105 self.__arrow, self.__text = self._create(x)
106 self.move_to(x)
107
108 def _create(self, x):
109 arrow = self._canvas.create_line(
110 x, self._ARROWHEIGHT + self._YOFFSET,
111 x, self._YOFFSET,
112 x + self._ARROWWIDTH, self._YOFFSET,
113 arrow='first',
114 width=3.0,
115 tags=self._TAG)
116 text = self._canvas.create_text(
117 x + self._ARROWWIDTH + 13,
118 self._ARROWHEIGHT - self._TEXTYOFFSET,
119 tags=self._TAG,
120 text='128')
121 return arrow, text
122
123 def _x(self):
124 coords = self._canvas.coords(self._TAG)
125 assert coords
126 return coords[0]
127
128 def move_to(self, x):
129 deltax = x - self._x()
130 self._canvas.move(self._TAG, deltax, 0)
131
132 def set_text(self, text):
133 self._canvas.itemconfigure(self.__text, text=text)
134
135
136class RightArrow(LeftArrow):
137 _TAG = ('rightarrow',)
138
139 def _create(self, x):
140 arrow = self._canvas.create_line(
141 x, self._YOFFSET,
142 x + self._ARROWWIDTH, self._YOFFSET,
143 x + self._ARROWWIDTH, self._ARROWHEIGHT + self._YOFFSET,
144 arrow='last',
145 width=3.0,
146 tags=self._TAG)
147 text = self._canvas.create_text(
148 x - self._ARROWWIDTH + 15, # BAW: kludge
149 self._ARROWHEIGHT - self._TEXTYOFFSET,
150 justify=RIGHT,
151 text='128',
152 tags=self._TAG)
153 return arrow, text
154
155 def _x(self):
156 coords = self._canvas.coords(self._TAG)
157 assert coords
158 return coords[0] + self._ARROWWIDTH
159
160
161
162
163class StripWidget:
164 _CHIPHEIGHT = 50
165 _CHIPWIDTH = 10
166 _NUMCHIPS = 40
167
168 def __init__(self, switchboard,
169 master = None,
170 chipwidth = _CHIPWIDTH,
171 chipheight = _CHIPHEIGHT,
172 numchips = _NUMCHIPS,
173 generator = None,
174 axis = None,
175 label = '',
176 uwdvar = None,
177 hexvar = None):
178 # instance variables
179 self.__generator = generator
180 self.__axis = axis
181 self.__numchips = numchips
182 assert self.__axis in (0, 1, 2)
183 self.__uwd = uwdvar
184 self.__hexp = hexvar
185 # the last chip selected
186 self.__lastchip = None
187 self.__sb = switchboard
188
189 canvaswidth = numchips * (chipwidth + 1)
190 canvasheight = chipheight + 43 # BAW: Kludge
191
192 # create the canvas and pack it
193 canvas = self.__canvas = Canvas(master,
194 width=canvaswidth,
195 height=canvasheight,
196## borderwidth=2,
197## relief=GROOVE
198 )
199
200 canvas.pack()
201 canvas.bind('<ButtonPress-1>', self.__select_chip)
202 canvas.bind('<ButtonRelease-1>', self.__select_chip)
203 canvas.bind('<B1-Motion>', self.__select_chip)
204
205 # Load a proc into the Tcl interpreter. This is used in the
206 # set_color() method to speed up setting the chip colors.
207 canvas.tk.eval(TCLPROC)
208
209 # create the color strip
210 chips = self.__chips = []
211 x = 1
212 y = 30
213 tags = ('chip',)
214 for c in range(self.__numchips):
215 color = 'grey'
216 canvas.create_rectangle(
217 x, y, x+chipwidth, y+chipheight,
218 fill=color, outline=color,
219 tags=tags)
220 x = x + chipwidth + 1 # for outline
221 chips.append(color)
222
223 # create the strip label
224 self.__label = canvas.create_text(
225 3, y + chipheight + 8,
226 text=label,
227 anchor=W)
228
229 # create the arrow and text item
230 chipx = self.__arrow_x(0)
231 self.__leftarrow = LeftArrow(canvas, chipx)
232
233 chipx = self.__arrow_x(len(chips) - 1)
234 self.__rightarrow = RightArrow(canvas, chipx)
235
236 def __arrow_x(self, chipnum):
237 coords = self.__canvas.coords(chipnum+1)
238 assert coords
239 x0, y0, x1, y1 = coords
240 return (x1 + x0) / 2.0
241
242 # Invoked when one of the chips is clicked. This should just tell the
243 # switchboard to set the color on all the output components
244 def __select_chip(self, event=None):
245 x = event.x
246 y = event.y
247 canvas = self.__canvas
248 chip = canvas.find_overlapping(x, y, x, y)
249 if chip and (1 <= chip[0] <= self.__numchips):
250 color = self.__chips[chip[0]-1]
251 red, green, blue = ColorDB.rrggbb_to_triplet(color)
252 etype = int(event.type)
253 if (etype == BTNUP or self.__uwd.get()):
254 # update everyone
255 self.__sb.update_views(red, green, blue)
256 else:
257 # just track the arrows
258 self.__trackarrow(chip[0], (red, green, blue))
259
260 def __trackarrow(self, chip, rgbtuple):
261 # invert the last chip
262 if self.__lastchip is not None:
263 color = self.__canvas.itemcget(self.__lastchip, 'fill')
264 self.__canvas.itemconfigure(self.__lastchip, outline=color)
265 self.__lastchip = chip
266 # get the arrow's text
267 coloraxis = rgbtuple[self.__axis]
268 if self.__hexp.get():
269 # hex
270 text = hex(coloraxis)
271 else:
272 # decimal
273 text = repr(coloraxis)
274 # move the arrow, and set its text
275 if coloraxis <= 128:
276 # use the left arrow
277 self.__leftarrow.set_text(text)
278 self.__leftarrow.move_to(self.__arrow_x(chip-1))
279 self.__rightarrow.move_to(-100)
280 else:
281 # use the right arrow
282 self.__rightarrow.set_text(text)
283 self.__rightarrow.move_to(self.__arrow_x(chip-1))
284 self.__leftarrow.move_to(-100)
285 # and set the chip's outline
286 brightness = ColorDB.triplet_to_brightness(rgbtuple)
287 if brightness <= 128:
288 outline = 'white'
289 else:
290 outline = 'black'
291 self.__canvas.itemconfigure(chip, outline=outline)
292
293
294 def update_yourself(self, red, green, blue):
295 assert self.__generator
296 i = 1
297 chip = 0
298 chips = self.__chips = []
299 tk = self.__canvas.tk
300 # get the red, green, and blue components for all chips
301 for t in self.__generator(self.__numchips, red, green, blue):
302 rrggbb = ColorDB.triplet_to_rrggbb(t)
303 chips.append(rrggbb)
304 tred, tgreen, tblue = t
305 if tred <= red and tgreen <= green and tblue <= blue:
306 chip = i
307 i = i + 1
308 # call the raw tcl script
309 colors = SPACE.join(chips)
310 tk.eval('setcolor %s {%s}' % (self.__canvas._w, colors))
311 # move the arrows around
312 self.__trackarrow(chip, (red, green, blue))
313
314 def set(self, label, generator):
315 self.__canvas.itemconfigure(self.__label, text=label)
316 self.__generator = generator
317
318
319
320class StripViewer:
321 def __init__(self, switchboard, master=None):
322 self.__sb = switchboard
323 optiondb = switchboard.optiondb()
324 # create a frame inside the master.
325 frame = Frame(master, relief=RAISED, borderwidth=1)
326 frame.grid(row=1, column=0, columnspan=2, sticky='NSEW')
327 # create the options to be used later
328 uwd = self.__uwdvar = BooleanVar()
329 uwd.set(optiondb.get('UPWHILEDRAG', 0))
330 hexp = self.__hexpvar = BooleanVar()
331 hexp.set(optiondb.get('HEXSTRIP', 0))
332 # create the red, green, blue strips inside their own frame
333 frame1 = Frame(frame)
334 frame1.pack(expand=YES, fill=BOTH)
335 self.__reds = StripWidget(switchboard, frame1,
336 generator=constant_cyan_generator,
337 axis=0,
338 label='Red Variations',
339 uwdvar=uwd, hexvar=hexp)
340
341 self.__greens = StripWidget(switchboard, frame1,
342 generator=constant_magenta_generator,
343 axis=1,
344 label='Green Variations',
345 uwdvar=uwd, hexvar=hexp)
346
347 self.__blues = StripWidget(switchboard, frame1,
348 generator=constant_yellow_generator,
349 axis=2,
350 label='Blue Variations',
351 uwdvar=uwd, hexvar=hexp)
352
353 # create a frame to contain the controls
354 frame2 = Frame(frame)
355 frame2.pack(expand=YES, fill=BOTH)
356 frame2.columnconfigure(0, weight=20)
357 frame2.columnconfigure(2, weight=20)
358
359 padx = 8
360
361 # create the black button
362 blackbtn = Button(frame2,
363 text='Black',
364 command=self.__toblack)
365 blackbtn.grid(row=0, column=0, rowspan=2, sticky=W, padx=padx)
366
367 # create the controls
368 uwdbtn = Checkbutton(frame2,
369 text='Update while dragging',
370 variable=uwd)
371 uwdbtn.grid(row=0, column=1, sticky=W)
372 hexbtn = Checkbutton(frame2,
373 text='Hexadecimal',
374 variable=hexp,
375 command=self.__togglehex)
376 hexbtn.grid(row=1, column=1, sticky=W)
377
378 # XXX: ignore this feature for now; it doesn't work quite right yet
379
380## gentypevar = self.__gentypevar = IntVar()
381## self.__variations = Radiobutton(frame,
382## text='Variations',
383## variable=gentypevar,
384## value=0,
385## command=self.__togglegentype)
386## self.__variations.grid(row=0, column=1, sticky=W)
387## self.__constants = Radiobutton(frame,
388## text='Constants',
389## variable=gentypevar,
390## value=1,
391## command=self.__togglegentype)
392## self.__constants.grid(row=1, column=1, sticky=W)
393
394 # create the white button
395 whitebtn = Button(frame2,
396 text='White',
397 command=self.__towhite)
398 whitebtn.grid(row=0, column=2, rowspan=2, sticky=E, padx=padx)
399
400 def update_yourself(self, red, green, blue):
401 self.__reds.update_yourself(red, green, blue)
402 self.__greens.update_yourself(red, green, blue)
403 self.__blues.update_yourself(red, green, blue)
404
405 def __togglehex(self, event=None):
406 red, green, blue = self.__sb.current_rgb()
407 self.update_yourself(red, green, blue)
408
409## def __togglegentype(self, event=None):
410## which = self.__gentypevar.get()
411## if which == 0:
412## self.__reds.set(label='Red Variations',
413## generator=constant_cyan_generator)
414## self.__greens.set(label='Green Variations',
415## generator=constant_magenta_generator)
416## self.__blues.set(label='Blue Variations',
417## generator=constant_yellow_generator)
418## elif which == 1:
419## self.__reds.set(label='Red Constant',
420## generator=constant_red_generator)
421## self.__greens.set(label='Green Constant',
422## generator=constant_green_generator)
423## self.__blues.set(label='Blue Constant',
424## generator=constant_blue_generator)
425## else:
426## assert 0
427## self.__sb.update_views_current()
428
429 def __toblack(self, event=None):
430 self.__sb.update_views(0, 0, 0)
431
432 def __towhite(self, event=None):
433 self.__sb.update_views(255, 255, 255)
434
435 def save_options(self, optiondb):
436 optiondb['UPWHILEDRAG'] = self.__uwdvar.get()
437 optiondb['HEXSTRIP'] = self.__hexpvar.get()
Note: See TracBrowser for help on using the repository browser.