1 | """ListViewer class.
|
---|
2 |
|
---|
3 | This class implements an input/output view on the color model. It lists every
|
---|
4 | unique color (e.g. unique r/g/b value) found in the color database. Each
|
---|
5 | color is shown by small swatch and primary color name. Some colors have
|
---|
6 | aliases -- more than one name for the same r/g/b value. These aliases are
|
---|
7 | displayed in the small listbox at the bottom of the screen.
|
---|
8 |
|
---|
9 | Clicking on a color name or swatch selects that color and updates all other
|
---|
10 | windows. When a color is selected in a different viewer, the color list is
|
---|
11 | scrolled to the selected color and it is highlighted. If the selected color
|
---|
12 | is an r/g/b value without a name, no scrolling occurs.
|
---|
13 |
|
---|
14 | You can turn off Update On Click if all you want to see is the alias for a
|
---|
15 | given name, without selecting the color.
|
---|
16 | """
|
---|
17 |
|
---|
18 | from Tkinter import *
|
---|
19 | import ColorDB
|
---|
20 |
|
---|
21 | ADDTOVIEW = 'Color %List Window...'
|
---|
22 |
|
---|
23 | class ListViewer:
|
---|
24 | def __init__(self, switchboard, master=None):
|
---|
25 | self.__sb = switchboard
|
---|
26 | optiondb = switchboard.optiondb()
|
---|
27 | self.__lastbox = None
|
---|
28 | self.__dontcenter = 0
|
---|
29 | # GUI
|
---|
30 | root = self.__root = Toplevel(master, class_='Pynche')
|
---|
31 | root.protocol('WM_DELETE_WINDOW', self.withdraw)
|
---|
32 | root.title('Pynche Color List')
|
---|
33 | root.iconname('Pynche Color List')
|
---|
34 | root.bind('<Alt-q>', self.__quit)
|
---|
35 | root.bind('<Alt-Q>', self.__quit)
|
---|
36 | root.bind('<Alt-w>', self.withdraw)
|
---|
37 | root.bind('<Alt-W>', self.withdraw)
|
---|
38 | #
|
---|
39 | # create the canvas which holds everything, and its scrollbar
|
---|
40 | #
|
---|
41 | frame = self.__frame = Frame(root)
|
---|
42 | frame.pack()
|
---|
43 | canvas = self.__canvas = Canvas(frame, width=160, height=300,
|
---|
44 | borderwidth=2, relief=SUNKEN)
|
---|
45 | self.__scrollbar = Scrollbar(frame)
|
---|
46 | self.__scrollbar.pack(fill=Y, side=RIGHT)
|
---|
47 | canvas.pack(fill=BOTH, expand=1)
|
---|
48 | canvas.configure(yscrollcommand=(self.__scrollbar, 'set'))
|
---|
49 | self.__scrollbar.configure(command=(canvas, 'yview'))
|
---|
50 | self.__populate()
|
---|
51 | #
|
---|
52 | # Update on click
|
---|
53 | self.__uoc = BooleanVar()
|
---|
54 | self.__uoc.set(optiondb.get('UPONCLICK', 1))
|
---|
55 | self.__uocbtn = Checkbutton(root,
|
---|
56 | text='Update on Click',
|
---|
57 | variable=self.__uoc,
|
---|
58 | command=self.__toggleupdate)
|
---|
59 | self.__uocbtn.pack(expand=1, fill=BOTH)
|
---|
60 | #
|
---|
61 | # alias list
|
---|
62 | self.__alabel = Label(root, text='Aliases:')
|
---|
63 | self.__alabel.pack()
|
---|
64 | self.__aliases = Listbox(root, height=5,
|
---|
65 | selectmode=BROWSE)
|
---|
66 | self.__aliases.pack(expand=1, fill=BOTH)
|
---|
67 |
|
---|
68 | def __populate(self):
|
---|
69 | #
|
---|
70 | # create all the buttons
|
---|
71 | colordb = self.__sb.colordb()
|
---|
72 | canvas = self.__canvas
|
---|
73 | row = 0
|
---|
74 | widest = 0
|
---|
75 | bboxes = self.__bboxes = []
|
---|
76 | for name in colordb.unique_names():
|
---|
77 | exactcolor = ColorDB.triplet_to_rrggbb(colordb.find_byname(name))
|
---|
78 | canvas.create_rectangle(5, row*20 + 5,
|
---|
79 | 20, row*20 + 20,
|
---|
80 | fill=exactcolor)
|
---|
81 | textid = canvas.create_text(25, row*20 + 13,
|
---|
82 | text=name,
|
---|
83 | anchor=W)
|
---|
84 | x1, y1, textend, y2 = canvas.bbox(textid)
|
---|
85 | boxid = canvas.create_rectangle(3, row*20+3,
|
---|
86 | textend+3, row*20 + 23,
|
---|
87 | outline='',
|
---|
88 | tags=(exactcolor, 'all'))
|
---|
89 | canvas.bind('<ButtonRelease>', self.__onrelease)
|
---|
90 | bboxes.append(boxid)
|
---|
91 | if textend+3 > widest:
|
---|
92 | widest = textend+3
|
---|
93 | row += 1
|
---|
94 | canvheight = (row-1)*20 + 25
|
---|
95 | canvas.config(scrollregion=(0, 0, 150, canvheight))
|
---|
96 | for box in bboxes:
|
---|
97 | x1, y1, x2, y2 = canvas.coords(box)
|
---|
98 | canvas.coords(box, x1, y1, widest, y2)
|
---|
99 |
|
---|
100 | def __onrelease(self, event=None):
|
---|
101 | canvas = self.__canvas
|
---|
102 | # find the current box
|
---|
103 | x = canvas.canvasx(event.x)
|
---|
104 | y = canvas.canvasy(event.y)
|
---|
105 | ids = canvas.find_overlapping(x, y, x, y)
|
---|
106 | for boxid in ids:
|
---|
107 | if boxid in self.__bboxes:
|
---|
108 | break
|
---|
109 | else:
|
---|
110 | ## print 'No box found!'
|
---|
111 | return
|
---|
112 | tags = self.__canvas.gettags(boxid)
|
---|
113 | for t in tags:
|
---|
114 | if t[0] == '#':
|
---|
115 | break
|
---|
116 | else:
|
---|
117 | ## print 'No color tag found!'
|
---|
118 | return
|
---|
119 | red, green, blue = ColorDB.rrggbb_to_triplet(t)
|
---|
120 | self.__dontcenter = 1
|
---|
121 | if self.__uoc.get():
|
---|
122 | self.__sb.update_views(red, green, blue)
|
---|
123 | else:
|
---|
124 | self.update_yourself(red, green, blue)
|
---|
125 | self.__red, self.__green, self.__blue = red, green, blue
|
---|
126 |
|
---|
127 | def __toggleupdate(self, event=None):
|
---|
128 | if self.__uoc.get():
|
---|
129 | self.__sb.update_views(self.__red, self.__green, self.__blue)
|
---|
130 |
|
---|
131 | def __quit(self, event=None):
|
---|
132 | self.__root.quit()
|
---|
133 |
|
---|
134 | def withdraw(self, event=None):
|
---|
135 | self.__root.withdraw()
|
---|
136 |
|
---|
137 | def deiconify(self, event=None):
|
---|
138 | self.__root.deiconify()
|
---|
139 |
|
---|
140 | def update_yourself(self, red, green, blue):
|
---|
141 | canvas = self.__canvas
|
---|
142 | # turn off the last box
|
---|
143 | if self.__lastbox:
|
---|
144 | canvas.itemconfigure(self.__lastbox, outline='')
|
---|
145 | # turn on the current box
|
---|
146 | colortag = ColorDB.triplet_to_rrggbb((red, green, blue))
|
---|
147 | canvas.itemconfigure(colortag, outline='black')
|
---|
148 | self.__lastbox = colortag
|
---|
149 | # fill the aliases
|
---|
150 | self.__aliases.delete(0, END)
|
---|
151 | try:
|
---|
152 | aliases = self.__sb.colordb().aliases_of(red, green, blue)[1:]
|
---|
153 | except ColorDB.BadColor:
|
---|
154 | self.__aliases.insert(END, '<no matching color>')
|
---|
155 | return
|
---|
156 | if not aliases:
|
---|
157 | self.__aliases.insert(END, '<no aliases>')
|
---|
158 | else:
|
---|
159 | for name in aliases:
|
---|
160 | self.__aliases.insert(END, name)
|
---|
161 | # maybe scroll the canvas so that the item is visible
|
---|
162 | if self.__dontcenter:
|
---|
163 | self.__dontcenter = 0
|
---|
164 | else:
|
---|
165 | ig, ig, ig, y1 = canvas.coords(colortag)
|
---|
166 | ig, ig, ig, y2 = canvas.coords(self.__bboxes[-1])
|
---|
167 | h = int(canvas['height']) * 0.5
|
---|
168 | canvas.yview('moveto', (y1-h) / y2)
|
---|
169 |
|
---|
170 | def save_options(self, optiondb):
|
---|
171 | optiondb['UPONCLICK'] = self.__uoc.get()
|
---|
172 |
|
---|
173 | def colordb_changed(self, colordb):
|
---|
174 | self.__canvas.delete('all')
|
---|
175 | self.__populate()
|
---|