ยปCore Development>Code coverage>Tools/pynche/StripViewer.py

Python code coverage for Tools/pynche/StripViewer.py

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