1 """DetailsViewer class. 2 3 This class implements a pure input window which allows you to meticulously 4 edit the current color. You have both mouse control of the color (via the 5 buttons along the bottom row), and there are keyboard bindings for each of the 6 increment/decrement buttons. 7 8 The top three check buttons allow you to specify which of the three color 9 variations are tied together when incrementing and decrementing. Red, green, 10 and blue are self evident. By tying together red and green, you can modify 11 the yellow level of the color. By tying together red and blue, you can modify 12 the magenta level of the color. By tying together green and blue, you can 13 modify the cyan level, and by tying all three together, you can modify the 14 grey level. 15 16 The behavior at the boundaries (0 and 255) are defined by the `At boundary' 17 option menu: 18 19 Stop 20 When the increment or decrement would send any of the tied variations 21 out of bounds, the entire delta is discarded. 22 23 Wrap Around 24 When the increment or decrement would send any of the tied variations 25 out of bounds, the out of bounds variation is wrapped around to the 26 other side. Thus if red were at 238 and 25 were added to it, red 27 would have the value 7. 28 29 Preserve Distance 30 When the increment or decrement would send any of the tied variations 31 out of bounds, all tied variations are wrapped as one, so as to 32 preserve the distance between them. Thus if green and blue were tied, 33 and green was at 238 while blue was at 223, and an increment of 25 34 were applied, green would be at 15 and blue would be at 0. 35 36 Squash 37 When the increment or decrement would send any of the tied variations 38 out of bounds, the out of bounds variation is set to the ceiling of 39 255 or floor of 0, as appropriate. In this way, all tied variations 40 are squashed to one edge or the other. 41 42 The following key bindings can be used as accelerators. Note that Pynche can 43 fall behind if you hold the key down as a key repeat: 44 45 Left arrow == -1 46 Right arrow == +1 47 48 Control + Left == -10 49 Control + Right == 10 50 51 Shift + Left == -25 52 Shift + Right == +25 53 """ 54 55 from Tkinter import * 56 57 STOP = 'Stop' 58 WRAP = 'Wrap Around' 59 RATIO = 'Preserve Distance' 60 GRAV = 'Squash' 61 62 ADDTOVIEW = 'Details Window...' 63 64 66 class DetailsViewer: 67 def __init__(self, switchboard, master=None): 68 self.__sb = switchboard 69 optiondb = switchboard.optiondb() 70 self.__red, self.__green, self.__blue = switchboard.current_rgb() 71 # GUI 72 root = self.__root = Toplevel(master, class_='Pynche') 73 root.protocol('WM_DELETE_WINDOW', self.withdraw) 74 root.title('Pynche Details Window') 75 root.iconname('Pynche Details Window') 76 root.bind('<Alt-q>', self.__quit) 77 root.bind('<Alt-Q>', self.__quit) 78 root.bind('<Alt-w>', self.withdraw) 79 root.bind('<Alt-W>', self.withdraw) 80 # accelerators 81 root.bind('<KeyPress-Left>', self.__minus1) 82 root.bind('<KeyPress-Right>', self.__plus1) 83 root.bind('<Control-KeyPress-Left>', self.__minus10) 84 root.bind('<Control-KeyPress-Right>', self.__plus10) 85 root.bind('<Shift-KeyPress-Left>', self.__minus25) 86 root.bind('<Shift-KeyPress-Right>', self.__plus25) 87 # 88 # color ties 89 frame = self.__frame = Frame(root) 90 frame.pack(expand=YES, fill=X) 91 self.__l1 = Label(frame, text='Move Sliders:') 92 self.__l1.grid(row=1, column=0, sticky=E) 93 self.__rvar = IntVar() 94 self.__rvar.set(optiondb.get('RSLIDER', 4)) 95 self.__radio1 = Checkbutton(frame, text='Red', 96 variable=self.__rvar, 97 command=self.__effect, 98 onvalue=4, offvalue=0) 99 self.__radio1.grid(row=1, column=1, sticky=W) 100 self.__gvar = IntVar() 101 self.__gvar.set(optiondb.get('GSLIDER', 2)) 102 self.__radio2 = Checkbutton(frame, text='Green', 103 variable=self.__gvar, 104 command=self.__effect, 105 onvalue=2, offvalue=0) 106 self.__radio2.grid(row=2, column=1, sticky=W) 107 self.__bvar = IntVar() 108 self.__bvar.set(optiondb.get('BSLIDER', 1)) 109 self.__radio3 = Checkbutton(frame, text='Blue', 110 variable=self.__bvar, 111 command=self.__effect, 112 onvalue=1, offvalue=0) 113 self.__radio3.grid(row=3, column=1, sticky=W) 114 self.__l2 = Label(frame) 115 self.__l2.grid(row=4, column=1, sticky=W) 116 self.__effect() 117 # 118 # Boundary behavior 119 self.__l3 = Label(frame, text='At boundary:') 120 self.__l3.grid(row=5, column=0, sticky=E) 121 self.__boundvar = StringVar() 122 self.__boundvar.set(optiondb.get('ATBOUND', STOP)) 123 self.__omenu = OptionMenu(frame, self.__boundvar, 124 STOP, WRAP, RATIO, GRAV) 125 self.__omenu.grid(row=5, column=1, sticky=W) 126 self.__omenu.configure(width=17) 127 # 128 # Buttons 129 frame = self.__btnframe = Frame(frame) 130 frame.grid(row=0, column=0, columnspan=2, sticky='EW') 131 self.__down25 = Button(frame, text='-25', 132 command=self.__minus25) 133 self.__down10 = Button(frame, text='-10', 134 command=self.__minus10) 135 self.__down1 = Button(frame, text='-1', 136 command=self.__minus1) 137 self.__up1 = Button(frame, text='+1', 138 command=self.__plus1) 139 self.__up10 = Button(frame, text='+10', 140 command=self.__plus10) 141 self.__up25 = Button(frame, text='+25', 142 command=self.__plus25) 143 self.__down25.pack(expand=YES, fill=X, side=LEFT) 144 self.__down10.pack(expand=YES, fill=X, side=LEFT) 145 self.__down1.pack(expand=YES, fill=X, side=LEFT) 146 self.__up1.pack(expand=YES, fill=X, side=LEFT) 147 self.__up10.pack(expand=YES, fill=X, side=LEFT) 148 self.__up25.pack(expand=YES, fill=X, side=LEFT) 149 150 def __effect(self, event=None): 151 tie = self.__rvar.get() + self.__gvar.get() + self.__bvar.get() 152 if tie in (0, 1, 2, 4): 153 text = '' 154 else: 155 text = '(= %s Level)' % {3: 'Cyan', 156 5: 'Magenta', 157 6: 'Yellow', 158 7: 'Grey'}[tie] 159 self.__l2.configure(text=text) 160 161 def __quit(self, event=None): 162 self.__root.quit() 163 164 def withdraw(self, event=None): 165 self.__root.withdraw() 166 167 def deiconify(self, event=None): 168 self.__root.deiconify() 169 170 def __minus25(self, event=None): 171 self.__delta(-25) 172 173 def __minus10(self, event=None): 174 self.__delta(-10) 175 176 def __minus1(self, event=None): 177 self.__delta(-1) 178 179 def __plus1(self, event=None): 180 self.__delta(1) 181 182 def __plus10(self, event=None): 183 self.__delta(10) 184 185 def __plus25(self, event=None): 186 self.__delta(25) 187 188 def __delta(self, delta): 189 tie = [] 190 if self.__rvar.get(): 191 red = self.__red + delta 192 tie.append(red) 193 else: 194 red = self.__red 195 if self.__gvar.get(): 196 green = self.__green + delta 197 tie.append(green) 198 else: 199 green = self.__green 200 if self.__bvar.get(): 201 blue = self.__blue + delta 202 tie.append(blue) 203 else: 204 blue = self.__blue 205 # now apply at boundary behavior 206 atbound = self.__boundvar.get() 207 if atbound == STOP: 208 if red < 0 or green < 0 or blue < 0 or \ 209 red > 255 or green > 255 or blue > 255: 210 # then 211 red, green, blue = self.__red, self.__green, self.__blue 212 elif atbound == WRAP or (atbound == RATIO and len(tie) < 2): 213 if red < 0: 214 red += 256 215 if green < 0: 216 green += 256 217 if blue < 0: 218 blue += 256 219 if red > 255: 220 red -= 256 221 if green > 255: 222 green -= 256 223 if blue > 255: 224 blue -= 256 225 elif atbound == RATIO: 226 # for when 2 or 3 colors are tied together 227 dir = 0 228 for c in tie: 229 if c < 0: 230 dir = -1 231 elif c > 255: 232 dir = 1 233 if dir == -1: 234 delta = max(tie) 235 if self.__rvar.get(): 236 red = red + 255 - delta 237 if self.__gvar.get(): 238 green = green + 255 - delta 239 if self.__bvar.get(): 240 blue = blue + 255 - delta 241 elif dir == 1: 242 delta = min(tie) 243 if self.__rvar.get(): 244 red = red - delta 245 if self.__gvar.get(): 246 green = green - delta 247 if self.__bvar.get(): 248 blue = blue - delta 249 elif atbound == GRAV: 250 if red < 0: 251 red = 0 252 if green < 0: 253 green = 0 254 if blue < 0: 255 blue = 0 256 if red > 255: 257 red = 255 258 if green > 255: 259 green = 255 260 if blue > 255: 261 blue = 255 262 self.__sb.update_views(red, green, blue) 263 self.__root.update_idletasks() 264 265 def update_yourself(self, red, green, blue): 266 self.__red = red 267 self.__green = green 268 self.__blue = blue 269 270 def save_options(self, optiondb): 271 optiondb['RSLIDER'] = self.__rvar.get() 272 optiondb['GSLIDER'] = self.__gvar.get() 273 optiondb['BSLIDER'] = self.__bvar.get() 274 optiondb['ATBOUND'] = self.__boundvar.get() 275