Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / devtools / amd64 / lib / python2.4 / site-packages / Pmw / Pmw_1_2 / lib / PmwScrolledFrame.py
CommitLineData
920dae64
AT
1import string
2import types
3import Tkinter
4import Pmw
5
6class ScrolledFrame(Pmw.MegaWidget):
7 def __init__(self, parent = None, **kw):
8
9 # Define the megawidget options.
10 INITOPT = Pmw.INITOPT
11 optiondefs = (
12 ('borderframe', 1, INITOPT),
13 ('horizflex', 'fixed', self._horizflex),
14 ('horizfraction', 0.05, INITOPT),
15 ('hscrollmode', 'dynamic', self._hscrollMode),
16 ('labelmargin', 0, INITOPT),
17 ('labelpos', None, INITOPT),
18 ('scrollmargin', 2, INITOPT),
19 ('usehullsize', 0, INITOPT),
20 ('vertflex', 'fixed', self._vertflex),
21 ('vertfraction', 0.05, INITOPT),
22 ('vscrollmode', 'dynamic', self._vscrollMode),
23 )
24 self.defineoptions(kw, optiondefs)
25
26 # Initialise the base class (after defining the options).
27 Pmw.MegaWidget.__init__(self, parent)
28
29 # Create the components.
30 self.origInterior = Pmw.MegaWidget.interior(self)
31
32 if self['usehullsize']:
33 self.origInterior.grid_propagate(0)
34
35 if self['borderframe']:
36 # Create a frame widget to act as the border of the clipper.
37 self._borderframe = self.createcomponent('borderframe',
38 (), None,
39 Tkinter.Frame, (self.origInterior,),
40 relief = 'sunken',
41 borderwidth = 2,
42 )
43 self._borderframe.grid(row = 2, column = 2, sticky = 'news')
44
45 # Create the clipping window.
46 self._clipper = self.createcomponent('clipper',
47 (), None,
48 Tkinter.Frame, (self._borderframe,),
49 width = 400,
50 height = 300,
51 highlightthickness = 0,
52 borderwidth = 0,
53 )
54 self._clipper.pack(fill = 'both', expand = 1)
55 else:
56 # Create the clipping window.
57 self._clipper = self.createcomponent('clipper',
58 (), None,
59 Tkinter.Frame, (self.origInterior,),
60 width = 400,
61 height = 300,
62 relief = 'sunken',
63 borderwidth = 2,
64 )
65 self._clipper.grid(row = 2, column = 2, sticky = 'news')
66
67 self.origInterior.grid_rowconfigure(2, weight = 1, minsize = 0)
68 self.origInterior.grid_columnconfigure(2, weight = 1, minsize = 0)
69
70 # Create the horizontal scrollbar
71 self._horizScrollbar = self.createcomponent('horizscrollbar',
72 (), 'Scrollbar',
73 Tkinter.Scrollbar, (self.origInterior,),
74 orient='horizontal',
75 command=self.xview
76 )
77
78 # Create the vertical scrollbar
79 self._vertScrollbar = self.createcomponent('vertscrollbar',
80 (), 'Scrollbar',
81 Tkinter.Scrollbar, (self.origInterior,),
82 orient='vertical',
83 command=self.yview
84 )
85
86 self.createlabel(self.origInterior, childCols = 3, childRows = 3)
87
88 # Initialise instance variables.
89 self._horizScrollbarOn = 0
90 self._vertScrollbarOn = 0
91 self.scrollTimer = None
92 self._scrollRecurse = 0
93 self._horizScrollbarNeeded = 0
94 self._vertScrollbarNeeded = 0
95 self.startX = 0
96 self.startY = 0
97 self._flexoptions = ('fixed', 'expand', 'shrink', 'elastic')
98
99 # Create a frame in the clipper to contain the widgets to be
100 # scrolled.
101 self._frame = self.createcomponent('frame',
102 (), None,
103 Tkinter.Frame, (self._clipper,)
104 )
105
106 # Whenever the clipping window or scrolled frame change size,
107 # update the scrollbars.
108 self._frame.bind('<Configure>', self._reposition)
109 self._clipper.bind('<Configure>', self._reposition)
110
111 # Work around a bug in Tk where the value returned by the
112 # scrollbar get() method is (0.0, 0.0, 0.0, 0.0) rather than
113 # the expected 2-tuple. This occurs if xview() is called soon
114 # after the Pmw.ScrolledFrame has been created.
115 self._horizScrollbar.set(0.0, 1.0)
116 self._vertScrollbar.set(0.0, 1.0)
117
118 # Check keywords and initialise options.
119 self.initialiseoptions()
120
121 def destroy(self):
122 if self.scrollTimer is not None:
123 self.after_cancel(self.scrollTimer)
124 self.scrollTimer = None
125 Pmw.MegaWidget.destroy(self)
126
127 # ======================================================================
128
129 # Public methods.
130
131 def interior(self):
132 return self._frame
133
134 # Set timer to call real reposition method, so that it is not
135 # called multiple times when many things are reconfigured at the
136 # same time.
137 def reposition(self):
138 if self.scrollTimer is None:
139 self.scrollTimer = self.after_idle(self._scrollBothNow)
140
141 # Called when the user clicks in the horizontal scrollbar.
142 # Calculates new position of frame then calls reposition() to
143 # update the frame and the scrollbar.
144 def xview(self, mode = None, value = None, units = None):
145
146 if type(value) == types.StringType:
147 value = string.atof(value)
148 if mode is None:
149 return self._horizScrollbar.get()
150 elif mode == 'moveto':
151 frameWidth = self._frame.winfo_reqwidth()
152 self.startX = value * float(frameWidth)
153 else: # mode == 'scroll'
154 clipperWidth = self._clipper.winfo_width()
155 if units == 'units':
156 jump = int(clipperWidth * self['horizfraction'])
157 else:
158 jump = clipperWidth
159 self.startX = self.startX + value * jump
160
161 self.reposition()
162
163 # Called when the user clicks in the vertical scrollbar.
164 # Calculates new position of frame then calls reposition() to
165 # update the frame and the scrollbar.
166 def yview(self, mode = None, value = None, units = None):
167
168 if type(value) == types.StringType:
169 value = string.atof(value)
170 if mode is None:
171 return self._vertScrollbar.get()
172 elif mode == 'moveto':
173 frameHeight = self._frame.winfo_reqheight()
174 self.startY = value * float(frameHeight)
175 else: # mode == 'scroll'
176 clipperHeight = self._clipper.winfo_height()
177 if units == 'units':
178 jump = int(clipperHeight * self['vertfraction'])
179 else:
180 jump = clipperHeight
181 self.startY = self.startY + value * jump
182
183 self.reposition()
184
185 # ======================================================================
186
187 # Configuration methods.
188
189 def _hscrollMode(self):
190 # The horizontal scroll mode has been configured.
191
192 mode = self['hscrollmode']
193
194 if mode == 'static':
195 if not self._horizScrollbarOn:
196 self._toggleHorizScrollbar()
197 elif mode == 'dynamic':
198 if self._horizScrollbarNeeded != self._horizScrollbarOn:
199 self._toggleHorizScrollbar()
200 elif mode == 'none':
201 if self._horizScrollbarOn:
202 self._toggleHorizScrollbar()
203 else:
204 message = 'bad hscrollmode option "%s": should be static, dynamic, or none' % mode
205 raise ValueError, message
206
207 def _vscrollMode(self):
208 # The vertical scroll mode has been configured.
209
210 mode = self['vscrollmode']
211
212 if mode == 'static':
213 if not self._vertScrollbarOn:
214 self._toggleVertScrollbar()
215 elif mode == 'dynamic':
216 if self._vertScrollbarNeeded != self._vertScrollbarOn:
217 self._toggleVertScrollbar()
218 elif mode == 'none':
219 if self._vertScrollbarOn:
220 self._toggleVertScrollbar()
221 else:
222 message = 'bad vscrollmode option "%s": should be static, dynamic, or none' % mode
223 raise ValueError, message
224
225 def _horizflex(self):
226 # The horizontal flex mode has been configured.
227
228 flex = self['horizflex']
229
230 if flex not in self._flexoptions:
231 message = 'bad horizflex option "%s": should be one of %s' % \
232 (flex, str(self._flexoptions))
233 raise ValueError, message
234
235 self.reposition()
236
237 def _vertflex(self):
238 # The vertical flex mode has been configured.
239
240 flex = self['vertflex']
241
242 if flex not in self._flexoptions:
243 message = 'bad vertflex option "%s": should be one of %s' % \
244 (flex, str(self._flexoptions))
245 raise ValueError, message
246
247 self.reposition()
248
249 # ======================================================================
250
251 # Private methods.
252
253 def _reposition(self, event):
254 self.reposition()
255
256 def _getxview(self):
257
258 # Horizontal dimension.
259 clipperWidth = self._clipper.winfo_width()
260 frameWidth = self._frame.winfo_reqwidth()
261 if frameWidth <= clipperWidth:
262 # The scrolled frame is smaller than the clipping window.
263
264 self.startX = 0
265 endScrollX = 1.0
266
267 if self['horizflex'] in ('expand', 'elastic'):
268 relwidth = 1
269 else:
270 relwidth = ''
271 else:
272 # The scrolled frame is larger than the clipping window.
273
274 if self['horizflex'] in ('shrink', 'elastic'):
275 self.startX = 0
276 endScrollX = 1.0
277 relwidth = 1
278 else:
279 if self.startX + clipperWidth > frameWidth:
280 self.startX = frameWidth - clipperWidth
281 endScrollX = 1.0
282 else:
283 if self.startX < 0:
284 self.startX = 0
285 endScrollX = (self.startX + clipperWidth) / float(frameWidth)
286 relwidth = ''
287
288 # Position frame relative to clipper.
289 self._frame.place(x = -self.startX, relwidth = relwidth)
290 return (self.startX / float(frameWidth), endScrollX)
291
292 def _getyview(self):
293
294 # Vertical dimension.
295 clipperHeight = self._clipper.winfo_height()
296 frameHeight = self._frame.winfo_reqheight()
297 if frameHeight <= clipperHeight:
298 # The scrolled frame is smaller than the clipping window.
299
300 self.startY = 0
301 endScrollY = 1.0
302
303 if self['vertflex'] in ('expand', 'elastic'):
304 relheight = 1
305 else:
306 relheight = ''
307 else:
308 # The scrolled frame is larger than the clipping window.
309
310 if self['vertflex'] in ('shrink', 'elastic'):
311 self.startY = 0
312 endScrollY = 1.0
313 relheight = 1
314 else:
315 if self.startY + clipperHeight > frameHeight:
316 self.startY = frameHeight - clipperHeight
317 endScrollY = 1.0
318 else:
319 if self.startY < 0:
320 self.startY = 0
321 endScrollY = (self.startY + clipperHeight) / float(frameHeight)
322 relheight = ''
323
324 # Position frame relative to clipper.
325 self._frame.place(y = -self.startY, relheight = relheight)
326 return (self.startY / float(frameHeight), endScrollY)
327
328 # According to the relative geometries of the frame and the
329 # clipper, reposition the frame within the clipper and reset the
330 # scrollbars.
331 def _scrollBothNow(self):
332 self.scrollTimer = None
333
334 # Call update_idletasks to make sure that the containing frame
335 # has been resized before we attempt to set the scrollbars.
336 # Otherwise the scrollbars may be mapped/unmapped continuously.
337 self._scrollRecurse = self._scrollRecurse + 1
338 self.update_idletasks()
339 self._scrollRecurse = self._scrollRecurse - 1
340 if self._scrollRecurse != 0:
341 return
342
343 xview = self._getxview()
344 yview = self._getyview()
345 self._horizScrollbar.set(xview[0], xview[1])
346 self._vertScrollbar.set(yview[0], yview[1])
347
348 self._horizScrollbarNeeded = (xview != (0.0, 1.0))
349 self._vertScrollbarNeeded = (yview != (0.0, 1.0))
350
351 # If both horizontal and vertical scrollmodes are dynamic and
352 # currently only one scrollbar is mapped and both should be
353 # toggled, then unmap the mapped scrollbar. This prevents a
354 # continuous mapping and unmapping of the scrollbars.
355 if (self['hscrollmode'] == self['vscrollmode'] == 'dynamic' and
356 self._horizScrollbarNeeded != self._horizScrollbarOn and
357 self._vertScrollbarNeeded != self._vertScrollbarOn and
358 self._vertScrollbarOn != self._horizScrollbarOn):
359 if self._horizScrollbarOn:
360 self._toggleHorizScrollbar()
361 else:
362 self._toggleVertScrollbar()
363 return
364
365 if self['hscrollmode'] == 'dynamic':
366 if self._horizScrollbarNeeded != self._horizScrollbarOn:
367 self._toggleHorizScrollbar()
368
369 if self['vscrollmode'] == 'dynamic':
370 if self._vertScrollbarNeeded != self._vertScrollbarOn:
371 self._toggleVertScrollbar()
372
373 def _toggleHorizScrollbar(self):
374
375 self._horizScrollbarOn = not self._horizScrollbarOn
376
377 interior = self.origInterior
378 if self._horizScrollbarOn:
379 self._horizScrollbar.grid(row = 4, column = 2, sticky = 'news')
380 interior.grid_rowconfigure(3, minsize = self['scrollmargin'])
381 else:
382 self._horizScrollbar.grid_forget()
383 interior.grid_rowconfigure(3, minsize = 0)
384
385 def _toggleVertScrollbar(self):
386
387 self._vertScrollbarOn = not self._vertScrollbarOn
388
389 interior = self.origInterior
390 if self._vertScrollbarOn:
391 self._vertScrollbar.grid(row = 2, column = 4, sticky = 'news')
392 interior.grid_columnconfigure(3, minsize = self['scrollmargin'])
393 else:
394 self._vertScrollbar.grid_forget()
395 interior.grid_columnconfigure(3, minsize = 0)