diff -r 000000000000 -r ae805ac0140d python-2.5.2/win32/Tools/pynche/StripViewer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python-2.5.2/win32/Tools/pynche/StripViewer.py Fri Apr 03 17:19:34 2009 +0100 @@ -0,0 +1,433 @@ +"""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. +""" + +from Tkinter import * +import ColorDB + +# 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 + } +} +''' + +# Tcl event types +BTNDOWN = 4 +BTNUP = 5 +BTNDRAG = 6 + +SPACE = ' ' + + + +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_red_generator(numchips, red, green, blue): + seq = constant(numchips) + return map(None, [red] * numchips, seq, seq) + +# green variations, red+blue = magenta constant +def constant_green_generator(numchips, red, green, blue): + seq = constant(numchips) + return map(None, seq, [green] * numchips, seq) + +# blue variations, red+green = yellow constant +def constant_blue_generator(numchips, red, green, blue): + seq = constant(numchips) + return map(None, seq, seq, [blue] * numchips) + +# 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) + + + +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, + tags=self._TAG, + 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) + + def set_text(self, text): + self._canvas.itemconfigure(self.__text, text=text) + + +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( + x - self._ARROWWIDTH + 15, # BAW: kludge + self._ARROWHEIGHT - self._TEXTYOFFSET, + justify=RIGHT, + text='128', + tags=self._TAG) + return arrow, text + + def _x(self): + coords = self._canvas.coords(self._TAG) + assert coords + return coords[0] + self._ARROWWIDTH + + + +class StripWidget: + _CHIPHEIGHT = 50 + _CHIPWIDTH = 10 + _NUMCHIPS = 40 + + def __init__(self, switchboard, + master = None, + chipwidth = _CHIPWIDTH, + chipheight = _CHIPHEIGHT, + numchips = _NUMCHIPS, + generator = None, + axis = None, + label = '', + uwdvar = None, + hexvar = None): + # instance variables + self.__generator = generator + self.__axis = axis + self.__numchips = numchips + assert self.__axis in (0, 1, 2) + self.__uwd = uwdvar + self.__hexp = hexvar + # the last chip selected + self.__lastchip = None + self.__sb = switchboard + + canvaswidth = numchips * (chipwidth + 1) + canvasheight = chipheight + 43 # BAW: Kludge + + # create the canvas and pack it + canvas = self.__canvas = Canvas(master, + width=canvaswidth, + height=canvasheight, +## borderwidth=2, +## relief=GROOVE + ) + + canvas.pack() + canvas.bind('', self.__select_chip) + canvas.bind('', self.__select_chip) + canvas.bind('', self.__select_chip) + + # Load a proc into the Tcl interpreter. This is used in the + # set_color() method to speed up setting the chip colors. + canvas.tk.eval(TCLPROC) + + # create the color strip + chips = self.__chips = [] + x = 1 + y = 30 + tags = ('chip',) + for c in range(self.__numchips): + color = 'grey' + canvas.create_rectangle( + x, y, x+chipwidth, y+chipheight, + fill=color, outline=color, + tags=tags) + x = x + chipwidth + 1 # for outline + chips.append(color) + + # create the strip label + self.__label = canvas.create_text( + 3, y + chipheight + 8, + text=label, + anchor=W) + + # create the arrow and text item + chipx = self.__arrow_x(0) + self.__leftarrow = LeftArrow(canvas, chipx) + + chipx = self.__arrow_x(len(chips) - 1) + self.__rightarrow = RightArrow(canvas, chipx) + + def __arrow_x(self, chipnum): + coords = self.__canvas.coords(chipnum+1) + assert coords + x0, y0, x1, y1 = coords + return (x1 + x0) / 2.0 + + # Invoked when one of the chips is clicked. This should just tell the + # switchboard to set the color on all the output components + def __select_chip(self, event=None): + 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) + if (etype == BTNUP or self.__uwd.get()): + # update everyone + self.__sb.update_views(red, green, blue) + else: + # just track the arrows + self.__trackarrow(chip[0], (red, green, blue)) + + 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 + # get the arrow's text + coloraxis = rgbtuple[self.__axis] + if self.__hexp.get(): + # hex + text = hex(coloraxis) + else: + # decimal + text = repr(coloraxis) + # move the arrow, and set its text + if coloraxis <= 128: + # use the left arrow + self.__leftarrow.set_text(text) + self.__leftarrow.move_to(self.__arrow_x(chip-1)) + self.__rightarrow.move_to(-100) + else: + # use the right arrow + 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 + brightness = ColorDB.triplet_to_brightness(rgbtuple) + if brightness <= 128: + outline = 'white' + else: + outline = 'black' + self.__canvas.itemconfigure(chip, outline=outline) + + + def update_yourself(self, red, green, blue): + assert self.__generator + i = 1 + chip = 0 + chips = self.__chips = [] + tk = self.__canvas.tk + # get the red, green, and blue components for all chips + for t in self.__generator(self.__numchips, red, green, blue): + 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 = SPACE.join(chips) + tk.eval('setcolor %s {%s}' % (self.__canvas._w, colors)) + # move the arrows around + self.__trackarrow(chip, (red, green, blue)) + + def set(self, label, generator): + self.__canvas.itemconfigure(self.__label, text=label) + self.__generator = generator + + +class StripViewer: + def __init__(self, switchboard, master=None): + self.__sb = switchboard + optiondb = switchboard.optiondb() + # create a frame inside the master. + frame = Frame(master, relief=RAISED, borderwidth=1) + frame.grid(row=1, column=0, columnspan=2, sticky='NSEW') + # create the options to be used later + uwd = self.__uwdvar = BooleanVar() + uwd.set(optiondb.get('UPWHILEDRAG', 0)) + hexp = self.__hexpvar = BooleanVar() + hexp.set(optiondb.get('HEXSTRIP', 0)) + # create the red, green, blue strips inside their own frame + frame1 = Frame(frame) + frame1.pack(expand=YES, fill=BOTH) + self.__reds = StripWidget(switchboard, frame1, + generator=constant_cyan_generator, + axis=0, + label='Red Variations', + uwdvar=uwd, hexvar=hexp) + + self.__greens = StripWidget(switchboard, frame1, + generator=constant_magenta_generator, + axis=1, + label='Green Variations', + uwdvar=uwd, hexvar=hexp) + + self.__blues = StripWidget(switchboard, frame1, + generator=constant_yellow_generator, + axis=2, + label='Blue Variations', + uwdvar=uwd, hexvar=hexp) + + # create a frame to contain the controls + frame2 = Frame(frame) + frame2.pack(expand=YES, fill=BOTH) + frame2.columnconfigure(0, weight=20) + frame2.columnconfigure(2, weight=20) + + padx = 8 + + # create the black button + blackbtn = Button(frame2, + text='Black', + command=self.__toblack) + blackbtn.grid(row=0, column=0, rowspan=2, sticky=W, padx=padx) + + # create the controls + uwdbtn = Checkbutton(frame2, + text='Update while dragging', + variable=uwd) + uwdbtn.grid(row=0, column=1, sticky=W) + hexbtn = Checkbutton(frame2, + text='Hexadecimal', + variable=hexp, + command=self.__togglehex) + hexbtn.grid(row=1, column=1, sticky=W) + + # XXX: ignore this feature for now; it doesn't work quite right yet + +## gentypevar = self.__gentypevar = IntVar() +## self.__variations = Radiobutton(frame, +## text='Variations', +## variable=gentypevar, +## value=0, +## command=self.__togglegentype) +## self.__variations.grid(row=0, column=1, sticky=W) +## self.__constants = Radiobutton(frame, +## text='Constants', +## variable=gentypevar, +## value=1, +## command=self.__togglegentype) +## self.__constants.grid(row=1, column=1, sticky=W) + + # create the white button + whitebtn = Button(frame2, + text='White', + command=self.__towhite) + whitebtn.grid(row=0, column=2, rowspan=2, sticky=E, padx=padx) + + 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) + + def __togglehex(self, event=None): + red, green, blue = self.__sb.current_rgb() + self.update_yourself(red, green, blue) + +## def __togglegentype(self, event=None): +## which = self.__gentypevar.get() +## if which == 0: +## self.__reds.set(label='Red Variations', +## generator=constant_cyan_generator) +## self.__greens.set(label='Green Variations', +## generator=constant_magenta_generator) +## self.__blues.set(label='Blue Variations', +## generator=constant_yellow_generator) +## elif which == 1: +## self.__reds.set(label='Red Constant', +## generator=constant_red_generator) +## self.__greens.set(label='Green Constant', +## generator=constant_green_generator) +## self.__blues.set(label='Blue Constant', +## generator=constant_blue_generator) +## else: +## assert 0 +## self.__sb.update_views_current() + + def __toblack(self, event=None): + self.__sb.update_views(0, 0, 0) + + def __towhite(self, event=None): + self.__sb.update_views(255, 255, 255) + + def save_options(self, optiondb): + optiondb['UPWHILEDRAG'] = self.__uwdvar.get() + optiondb['HEXSTRIP'] = self.__hexpvar.get()