Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / tools / src / nas,5.n2.os.2 / lib / python / lib / python2.4 / site-packages / Pmw / Pmw_1_2 / lib / PmwScrolledListBox.py
CommitLineData
86530b38
AT
1# Based on iwidgets2.2.0/scrolledlistbox.itk code.
2
3import types
4import Tkinter
5import Pmw
6
7class ScrolledListBox(Pmw.MegaWidget):
8 _classBindingsDefinedFor = 0
9
10 def __init__(self, parent = None, **kw):
11
12 # Define the megawidget options.
13 INITOPT = Pmw.INITOPT
14 optiondefs = (
15 ('dblclickcommand', None, None),
16 ('hscrollmode', 'dynamic', self._hscrollMode),
17 ('items', (), INITOPT),
18 ('labelmargin', 0, INITOPT),
19 ('labelpos', None, INITOPT),
20 ('scrollmargin', 2, INITOPT),
21 ('selectioncommand', None, None),
22 ('usehullsize', 0, INITOPT),
23 ('vscrollmode', 'dynamic', self._vscrollMode),
24 )
25 self.defineoptions(kw, optiondefs)
26
27 # Initialise the base class (after defining the options).
28 Pmw.MegaWidget.__init__(self, parent)
29
30 # Create the components.
31 interior = self.interior()
32
33 if self['usehullsize']:
34 interior.grid_propagate(0)
35
36 # Create the listbox widget.
37 self._listbox = self.createcomponent('listbox',
38 (), None,
39 Tkinter.Listbox, (interior,))
40 self._listbox.grid(row = 2, column = 2, sticky = 'news')
41 interior.grid_rowconfigure(2, weight = 1, minsize = 0)
42 interior.grid_columnconfigure(2, weight = 1, minsize = 0)
43
44 # Create the horizontal scrollbar
45 self._horizScrollbar = self.createcomponent('horizscrollbar',
46 (), 'Scrollbar',
47 Tkinter.Scrollbar, (interior,),
48 orient='horizontal',
49 command=self._listbox.xview
50 )
51
52 # Create the vertical scrollbar
53 self._vertScrollbar = self.createcomponent('vertscrollbar',
54 (), 'Scrollbar',
55 Tkinter.Scrollbar, (interior,),
56 orient='vertical',
57 command=self._listbox.yview
58 )
59
60 self.createlabel(interior, childCols = 3, childRows = 3)
61
62 # Add the items specified by the initialisation option.
63 items = self['items']
64 if type(items) != types.TupleType:
65 items = tuple(items)
66 if len(items) > 0:
67 apply(self._listbox.insert, ('end',) + items)
68
69 _registerScrolledList(self._listbox, self)
70
71 # Establish the special class bindings if not already done.
72 # Also create bindings if the Tkinter default interpreter has
73 # changed. Use Tkinter._default_root to create class
74 # bindings, so that a reference to root is created by
75 # bind_class rather than a reference to self, which would
76 # prevent object cleanup.
77 theTag = 'ScrolledListBoxTag'
78 if ScrolledListBox._classBindingsDefinedFor != Tkinter._default_root:
79 root = Tkinter._default_root
80
81 def doubleEvent(event):
82 _handleEvent(event, 'double')
83 def keyEvent(event):
84 _handleEvent(event, 'key')
85 def releaseEvent(event):
86 _handleEvent(event, 'release')
87
88 # Bind space and return keys and button 1 to the selectioncommand.
89 root.bind_class(theTag, '<Key-space>', keyEvent)
90 root.bind_class(theTag, '<Key-Return>', keyEvent)
91 root.bind_class(theTag, '<ButtonRelease-1>', releaseEvent)
92
93 # Bind double button 1 click to the dblclickcommand.
94 root.bind_class(theTag, '<Double-ButtonRelease-1>', doubleEvent)
95
96 ScrolledListBox._classBindingsDefinedFor = root
97
98 bindtags = self._listbox.bindtags()
99 self._listbox.bindtags(bindtags + (theTag,))
100
101 # Initialise instance variables.
102 self._horizScrollbarOn = 0
103 self._vertScrollbarOn = 0
104 self.scrollTimer = None
105 self._scrollRecurse = 0
106 self._horizScrollbarNeeded = 0
107 self._vertScrollbarNeeded = 0
108
109 # Check keywords and initialise options.
110 self.initialiseoptions()
111
112 def destroy(self):
113 if self.scrollTimer is not None:
114 self.after_cancel(self.scrollTimer)
115 self.scrollTimer = None
116 _deregisterScrolledList(self._listbox)
117 Pmw.MegaWidget.destroy(self)
118
119 # ======================================================================
120
121 # Public methods.
122
123 def clear(self):
124 self.setlist(())
125
126 def getcurselection(self):
127 rtn = []
128 for sel in self.curselection():
129 rtn.append(self._listbox.get(sel))
130 return tuple(rtn)
131
132 def getvalue(self):
133 return self.getcurselection()
134
135 def setvalue(self, textOrList):
136 self._listbox.selection_clear(0, 'end')
137 listitems = list(self._listbox.get(0, 'end'))
138 if type(textOrList) == types.StringType:
139 if textOrList in listitems:
140 self._listbox.selection_set(listitems.index(textOrList))
141 else:
142 raise ValueError, 'no such item "%s"' % textOrList
143 else:
144 for item in textOrList:
145 if item in listitems:
146 self._listbox.selection_set(listitems.index(item))
147 else:
148 raise ValueError, 'no such item "%s"' % item
149
150 def setlist(self, items):
151 self._listbox.delete(0, 'end')
152 if len(items) > 0:
153 if type(items) != types.TupleType:
154 items = tuple(items)
155 apply(self._listbox.insert, (0,) + items)
156
157 # Override Tkinter.Listbox get method, so that if it is called with
158 # no arguments, return all list elements (consistent with other widgets).
159 def get(self, first=None, last=None):
160 if first is None:
161 return self._listbox.get(0, 'end')
162 else:
163 return self._listbox.get(first, last)
164
165 # ======================================================================
166
167 # Configuration methods.
168
169 def _hscrollMode(self):
170 # The horizontal scroll mode has been configured.
171
172 mode = self['hscrollmode']
173
174 if mode == 'static':
175 if not self._horizScrollbarOn:
176 self._toggleHorizScrollbar()
177 elif mode == 'dynamic':
178 if self._horizScrollbarNeeded != self._horizScrollbarOn:
179 self._toggleHorizScrollbar()
180 elif mode == 'none':
181 if self._horizScrollbarOn:
182 self._toggleHorizScrollbar()
183 else:
184 message = 'bad hscrollmode option "%s": should be static, dynamic, or none' % mode
185 raise ValueError, message
186
187 self._configureScrollCommands()
188
189 def _vscrollMode(self):
190 # The vertical scroll mode has been configured.
191
192 mode = self['vscrollmode']
193
194 if mode == 'static':
195 if not self._vertScrollbarOn:
196 self._toggleVertScrollbar()
197 elif mode == 'dynamic':
198 if self._vertScrollbarNeeded != self._vertScrollbarOn:
199 self._toggleVertScrollbar()
200 elif mode == 'none':
201 if self._vertScrollbarOn:
202 self._toggleVertScrollbar()
203 else:
204 message = 'bad vscrollmode option "%s": should be static, dynamic, or none' % mode
205 raise ValueError, message
206
207 self._configureScrollCommands()
208
209 # ======================================================================
210
211 # Private methods.
212
213 def _configureScrollCommands(self):
214 # If both scrollmodes are not dynamic we can save a lot of
215 # time by not having to create an idle job to handle the
216 # scroll commands.
217
218 # Clean up previous scroll commands to prevent memory leak.
219 tclCommandName = str(self._listbox.cget('xscrollcommand'))
220 if tclCommandName != '':
221 self._listbox.deletecommand(tclCommandName)
222 tclCommandName = str(self._listbox.cget('yscrollcommand'))
223 if tclCommandName != '':
224 self._listbox.deletecommand(tclCommandName)
225
226 if self['hscrollmode'] == self['vscrollmode'] == 'dynamic':
227 self._listbox.configure(
228 xscrollcommand=self._scrollBothLater,
229 yscrollcommand=self._scrollBothLater
230 )
231 else:
232 self._listbox.configure(
233 xscrollcommand=self._scrollXNow,
234 yscrollcommand=self._scrollYNow
235 )
236
237 def _scrollXNow(self, first, last):
238 self._horizScrollbar.set(first, last)
239 self._horizScrollbarNeeded = ((first, last) != ('0', '1'))
240
241 if self['hscrollmode'] == 'dynamic':
242 if self._horizScrollbarNeeded != self._horizScrollbarOn:
243 self._toggleHorizScrollbar()
244
245 def _scrollYNow(self, first, last):
246 self._vertScrollbar.set(first, last)
247 self._vertScrollbarNeeded = ((first, last) != ('0', '1'))
248
249 if self['vscrollmode'] == 'dynamic':
250 if self._vertScrollbarNeeded != self._vertScrollbarOn:
251 self._toggleVertScrollbar()
252
253 def _scrollBothLater(self, first, last):
254 # Called by the listbox to set the horizontal or vertical
255 # scrollbar when it has scrolled or changed size or contents.
256
257 if self.scrollTimer is None:
258 self.scrollTimer = self.after_idle(self._scrollBothNow)
259
260 def _scrollBothNow(self):
261 # This performs the function of _scrollXNow and _scrollYNow.
262 # If one is changed, the other should be updated to match.
263 self.scrollTimer = None
264
265 # Call update_idletasks to make sure that the containing frame
266 # has been resized before we attempt to set the scrollbars.
267 # Otherwise the scrollbars may be mapped/unmapped continuously.
268 self._scrollRecurse = self._scrollRecurse + 1
269 self.update_idletasks()
270 self._scrollRecurse = self._scrollRecurse - 1
271 if self._scrollRecurse != 0:
272 return
273
274 xview = self._listbox.xview()
275 yview = self._listbox.yview()
276 self._horizScrollbar.set(xview[0], xview[1])
277 self._vertScrollbar.set(yview[0], yview[1])
278
279 self._horizScrollbarNeeded = (xview != (0.0, 1.0))
280 self._vertScrollbarNeeded = (yview != (0.0, 1.0))
281
282 # If both horizontal and vertical scrollmodes are dynamic and
283 # currently only one scrollbar is mapped and both should be
284 # toggled, then unmap the mapped scrollbar. This prevents a
285 # continuous mapping and unmapping of the scrollbars.
286 if (self['hscrollmode'] == self['vscrollmode'] == 'dynamic' and
287 self._horizScrollbarNeeded != self._horizScrollbarOn and
288 self._vertScrollbarNeeded != self._vertScrollbarOn and
289 self._vertScrollbarOn != self._horizScrollbarOn):
290 if self._horizScrollbarOn:
291 self._toggleHorizScrollbar()
292 else:
293 self._toggleVertScrollbar()
294 return
295
296 if self['hscrollmode'] == 'dynamic':
297 if self._horizScrollbarNeeded != self._horizScrollbarOn:
298 self._toggleHorizScrollbar()
299
300 if self['vscrollmode'] == 'dynamic':
301 if self._vertScrollbarNeeded != self._vertScrollbarOn:
302 self._toggleVertScrollbar()
303
304 def _toggleHorizScrollbar(self):
305
306 self._horizScrollbarOn = not self._horizScrollbarOn
307
308 interior = self.interior()
309 if self._horizScrollbarOn:
310 self._horizScrollbar.grid(row = 4, column = 2, sticky = 'news')
311 interior.grid_rowconfigure(3, minsize = self['scrollmargin'])
312 else:
313 self._horizScrollbar.grid_forget()
314 interior.grid_rowconfigure(3, minsize = 0)
315
316 def _toggleVertScrollbar(self):
317
318 self._vertScrollbarOn = not self._vertScrollbarOn
319
320 interior = self.interior()
321 if self._vertScrollbarOn:
322 self._vertScrollbar.grid(row = 2, column = 4, sticky = 'news')
323 interior.grid_columnconfigure(3, minsize = self['scrollmargin'])
324 else:
325 self._vertScrollbar.grid_forget()
326 interior.grid_columnconfigure(3, minsize = 0)
327
328 def _handleEvent(self, event, eventType):
329 if eventType == 'double':
330 command = self['dblclickcommand']
331 elif eventType == 'key':
332 command = self['selectioncommand']
333 else: #eventType == 'release'
334 # Do not execute the command if the mouse was released
335 # outside the listbox.
336 if (event.x < 0 or self._listbox.winfo_width() <= event.x or
337 event.y < 0 or self._listbox.winfo_height() <= event.y):
338 return
339
340 command = self['selectioncommand']
341
342 if callable(command):
343 command()
344
345 # Need to explicitly forward this to override the stupid
346 # (grid_)size method inherited from Tkinter.Frame.Grid.
347 def size(self):
348 return self._listbox.size()
349
350 # Need to explicitly forward this to override the stupid
351 # (grid_)bbox method inherited from Tkinter.Frame.Grid.
352 def bbox(self, index):
353 return self._listbox.bbox(index)
354
355Pmw.forwardmethods(ScrolledListBox, Tkinter.Listbox, '_listbox')
356
357# ======================================================================
358
359_listboxCache = {}
360
361def _registerScrolledList(listbox, scrolledList):
362 # Register an ScrolledList widget for a Listbox widget
363
364 _listboxCache[listbox] = scrolledList
365
366def _deregisterScrolledList(listbox):
367 # Deregister a Listbox widget
368 del _listboxCache[listbox]
369
370def _handleEvent(event, eventType):
371 # Forward events for a Listbox to it's ScrolledListBox
372
373 # A binding earlier in the bindtags list may have destroyed the
374 # megawidget, so need to check.
375 if _listboxCache.has_key(event.widget):
376 _listboxCache[event.widget]._handleEvent(event, eventType)