Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | # Based on iwidgets2.2.0/buttonbox.itk code. |
2 | ||
3 | import types | |
4 | import Tkinter | |
5 | import Pmw | |
6 | ||
7 | class ButtonBox(Pmw.MegaWidget): | |
8 | def __init__(self, parent = None, **kw): | |
9 | ||
10 | # Define the megawidget options. | |
11 | INITOPT = Pmw.INITOPT | |
12 | optiondefs = ( | |
13 | ('labelmargin', 0, INITOPT), | |
14 | ('labelpos', None, INITOPT), | |
15 | ('orient', 'horizontal', INITOPT), | |
16 | ('padx', 3, INITOPT), | |
17 | ('pady', 3, INITOPT), | |
18 | ) | |
19 | self.defineoptions(kw, optiondefs, dynamicGroups = ('Button',)) | |
20 | ||
21 | # Initialise the base class (after defining the options). | |
22 | Pmw.MegaWidget.__init__(self, parent) | |
23 | ||
24 | # Create the components. | |
25 | interior = self.interior() | |
26 | if self['labelpos'] is None: | |
27 | self._buttonBoxFrame = self._hull | |
28 | columnOrRow = 0 | |
29 | else: | |
30 | self._buttonBoxFrame = self.createcomponent('frame', | |
31 | (), None, | |
32 | Tkinter.Frame, (interior,)) | |
33 | self._buttonBoxFrame.grid(column=2, row=2, sticky='nsew') | |
34 | columnOrRow = 2 | |
35 | ||
36 | self.createlabel(interior) | |
37 | ||
38 | orient = self['orient'] | |
39 | if orient == 'horizontal': | |
40 | interior.grid_columnconfigure(columnOrRow, weight = 1) | |
41 | elif orient == 'vertical': | |
42 | interior.grid_rowconfigure(columnOrRow, weight = 1) | |
43 | else: | |
44 | raise ValueError, 'bad orient option ' + repr(orient) + \ | |
45 | ': must be either \'horizontal\' or \'vertical\'' | |
46 | ||
47 | # Initialise instance variables. | |
48 | ||
49 | # List of tuples describing the buttons: | |
50 | # - name | |
51 | # - button widget | |
52 | self._buttonList = [] | |
53 | ||
54 | # The index of the default button. | |
55 | self._defaultButton = None | |
56 | ||
57 | self._timerId = None | |
58 | ||
59 | # Check keywords and initialise options. | |
60 | self.initialiseoptions() | |
61 | ||
62 | def destroy(self): | |
63 | if self._timerId: | |
64 | self.after_cancel(self._timerId) | |
65 | self._timerId = None | |
66 | Pmw.MegaWidget.destroy(self) | |
67 | ||
68 | def numbuttons(self): | |
69 | return len(self._buttonList) | |
70 | ||
71 | def index(self, index, forInsert = 0): | |
72 | listLength = len(self._buttonList) | |
73 | if type(index) == types.IntType: | |
74 | if forInsert and index <= listLength: | |
75 | return index | |
76 | elif not forInsert and index < listLength: | |
77 | return index | |
78 | else: | |
79 | raise ValueError, 'index "%s" is out of range' % index | |
80 | elif index is Pmw.END: | |
81 | if forInsert: | |
82 | return listLength | |
83 | elif listLength > 0: | |
84 | return listLength - 1 | |
85 | else: | |
86 | raise ValueError, 'ButtonBox has no buttons' | |
87 | elif index is Pmw.DEFAULT: | |
88 | if self._defaultButton is not None: | |
89 | return self._defaultButton | |
90 | raise ValueError, 'ButtonBox has no default' | |
91 | else: | |
92 | names = map(lambda t: t[0], self._buttonList) | |
93 | if index in names: | |
94 | return names.index(index) | |
95 | validValues = 'a name, a number, Pmw.END or Pmw.DEFAULT' | |
96 | raise ValueError, \ | |
97 | 'bad index "%s": must be %s' % (index, validValues) | |
98 | ||
99 | def insert(self, componentName, beforeComponent = 0, **kw): | |
100 | if componentName in self.components(): | |
101 | raise ValueError, 'button "%s" already exists' % componentName | |
102 | if not kw.has_key('text'): | |
103 | kw['text'] = componentName | |
104 | kw['default'] = 'normal' | |
105 | button = apply(self.createcomponent, (componentName, | |
106 | (), 'Button', | |
107 | Tkinter.Button, (self._buttonBoxFrame,)), kw) | |
108 | ||
109 | index = self.index(beforeComponent, 1) | |
110 | horizontal = self['orient'] == 'horizontal' | |
111 | numButtons = len(self._buttonList) | |
112 | ||
113 | # Shift buttons up one position. | |
114 | for i in range(numButtons - 1, index - 1, -1): | |
115 | widget = self._buttonList[i][1] | |
116 | pos = i * 2 + 3 | |
117 | if horizontal: | |
118 | widget.grid(column = pos, row = 0) | |
119 | else: | |
120 | widget.grid(column = 0, row = pos) | |
121 | ||
122 | # Display the new button. | |
123 | if horizontal: | |
124 | button.grid(column = index * 2 + 1, row = 0, sticky = 'ew', | |
125 | padx = self['padx'], pady = self['pady']) | |
126 | self._buttonBoxFrame.grid_columnconfigure( | |
127 | numButtons * 2 + 2, weight = 1) | |
128 | else: | |
129 | button.grid(column = 0, row = index * 2 + 1, sticky = 'ew', | |
130 | padx = self['padx'], pady = self['pady']) | |
131 | self._buttonBoxFrame.grid_rowconfigure( | |
132 | numButtons * 2 + 2, weight = 1) | |
133 | self._buttonList.insert(index, (componentName, button)) | |
134 | ||
135 | return button | |
136 | ||
137 | def add(self, componentName, **kw): | |
138 | return apply(self.insert, (componentName, len(self._buttonList)), kw) | |
139 | ||
140 | def delete(self, index): | |
141 | index = self.index(index) | |
142 | (name, widget) = self._buttonList[index] | |
143 | widget.grid_forget() | |
144 | self.destroycomponent(name) | |
145 | ||
146 | numButtons = len(self._buttonList) | |
147 | ||
148 | # Shift buttons down one position. | |
149 | horizontal = self['orient'] == 'horizontal' | |
150 | for i in range(index + 1, numButtons): | |
151 | widget = self._buttonList[i][1] | |
152 | pos = i * 2 - 1 | |
153 | if horizontal: | |
154 | widget.grid(column = pos, row = 0) | |
155 | else: | |
156 | widget.grid(column = 0, row = pos) | |
157 | ||
158 | if horizontal: | |
159 | self._buttonBoxFrame.grid_columnconfigure(numButtons * 2 - 1, | |
160 | minsize = 0) | |
161 | self._buttonBoxFrame.grid_columnconfigure(numButtons * 2, weight = 0) | |
162 | else: | |
163 | self._buttonBoxFrame.grid_rowconfigure(numButtons * 2, weight = 0) | |
164 | del self._buttonList[index] | |
165 | ||
166 | def setdefault(self, index): | |
167 | # Turn off the default ring around the current default button. | |
168 | if self._defaultButton is not None: | |
169 | button = self._buttonList[self._defaultButton][1] | |
170 | button.configure(default = 'normal') | |
171 | self._defaultButton = None | |
172 | ||
173 | # Turn on the default ring around the new default button. | |
174 | if index is not None: | |
175 | index = self.index(index) | |
176 | self._defaultButton = index | |
177 | button = self._buttonList[index][1] | |
178 | button.configure(default = 'active') | |
179 | ||
180 | def invoke(self, index = Pmw.DEFAULT, noFlash = 0): | |
181 | # Invoke the callback associated with the *index* button. If | |
182 | # *noFlash* is not set, flash the button to indicate to the | |
183 | # user that something happened. | |
184 | ||
185 | button = self._buttonList[self.index(index)][1] | |
186 | if not noFlash: | |
187 | state = button.cget('state') | |
188 | relief = button.cget('relief') | |
189 | button.configure(state = 'active', relief = 'sunken') | |
190 | self.update_idletasks() | |
191 | self.after(100) | |
192 | button.configure(state = state, relief = relief) | |
193 | return button.invoke() | |
194 | ||
195 | def button(self, buttonIndex): | |
196 | return self._buttonList[self.index(buttonIndex)][1] | |
197 | ||
198 | def alignbuttons(self, when = 'later'): | |
199 | if when == 'later': | |
200 | if not self._timerId: | |
201 | self._timerId = self.after_idle(self.alignbuttons, 'now') | |
202 | return | |
203 | self.update_idletasks() | |
204 | self._timerId = None | |
205 | ||
206 | # Determine the width of the maximum length button. | |
207 | max = 0 | |
208 | horizontal = (self['orient'] == 'horizontal') | |
209 | for index in range(len(self._buttonList)): | |
210 | gridIndex = index * 2 + 1 | |
211 | if horizontal: | |
212 | width = self._buttonBoxFrame.grid_bbox(gridIndex, 0)[2] | |
213 | else: | |
214 | width = self._buttonBoxFrame.grid_bbox(0, gridIndex)[2] | |
215 | if width > max: | |
216 | max = width | |
217 | ||
218 | # Set the width of all the buttons to be the same. | |
219 | if horizontal: | |
220 | for index in range(len(self._buttonList)): | |
221 | self._buttonBoxFrame.grid_columnconfigure(index * 2 + 1, | |
222 | minsize = max) | |
223 | else: | |
224 | self._buttonBoxFrame.grid_columnconfigure(0, minsize = max) |