Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | import types |
2 | import Tkinter | |
3 | import Pmw | |
4 | ||
5 | class RadioSelect(Pmw.MegaWidget): | |
6 | # A collection of several buttons. In single mode, only one | |
7 | # button may be selected. In multiple mode, any number of buttons | |
8 | # may be selected. | |
9 | ||
10 | def __init__(self, parent = None, **kw): | |
11 | ||
12 | # Define the megawidget options. | |
13 | INITOPT = Pmw.INITOPT | |
14 | optiondefs = ( | |
15 | ('buttontype', 'button', INITOPT), | |
16 | ('command', None, None), | |
17 | ('labelmargin', 0, INITOPT), | |
18 | ('labelpos', None, INITOPT), | |
19 | ('orient', 'horizontal', INITOPT), | |
20 | ('padx', 5, INITOPT), | |
21 | ('pady', 5, INITOPT), | |
22 | ('selectmode', 'single', INITOPT), | |
23 | ) | |
24 | self.defineoptions(kw, optiondefs, dynamicGroups = ('Button',)) | |
25 | ||
26 | # Initialise the base class (after defining the options). | |
27 | Pmw.MegaWidget.__init__(self, parent) | |
28 | ||
29 | # Create the components. | |
30 | interior = self.interior() | |
31 | if self['labelpos'] is None: | |
32 | self._radioSelectFrame = self._hull | |
33 | else: | |
34 | self._radioSelectFrame = self.createcomponent('frame', | |
35 | (), None, | |
36 | Tkinter.Frame, (interior,)) | |
37 | self._radioSelectFrame.grid(column=2, row=2, sticky='nsew') | |
38 | interior.grid_columnconfigure(2, weight=1) | |
39 | interior.grid_rowconfigure(2, weight=1) | |
40 | ||
41 | self.createlabel(interior) | |
42 | ||
43 | # Initialise instance variables. | |
44 | self._buttonList = [] | |
45 | if self['selectmode'] == 'single': | |
46 | self._singleSelect = 1 | |
47 | elif self['selectmode'] == 'multiple': | |
48 | self._singleSelect = 0 | |
49 | else: | |
50 | raise ValueError, 'bad selectmode option "' + \ | |
51 | self['selectmode'] + '": should be single or multiple' | |
52 | ||
53 | if self['buttontype'] == 'button': | |
54 | self.buttonClass = Tkinter.Button | |
55 | elif self['buttontype'] == 'radiobutton': | |
56 | self._singleSelect = 1 | |
57 | self.var = Tkinter.StringVar() | |
58 | self.buttonClass = Tkinter.Radiobutton | |
59 | elif self['buttontype'] == 'checkbutton': | |
60 | self._singleSelect = 0 | |
61 | self.buttonClass = Tkinter.Checkbutton | |
62 | else: | |
63 | raise ValueError, 'bad buttontype option "' + \ | |
64 | self['buttontype'] + \ | |
65 | '": should be button, radiobutton or checkbutton' | |
66 | ||
67 | if self._singleSelect: | |
68 | self.selection = None | |
69 | else: | |
70 | self.selection = [] | |
71 | ||
72 | if self['orient'] not in ('horizontal', 'vertical'): | |
73 | raise ValueError, 'bad orient option ' + repr(self['orient']) + \ | |
74 | ': must be either \'horizontal\' or \'vertical\'' | |
75 | ||
76 | # Check keywords and initialise options. | |
77 | self.initialiseoptions() | |
78 | ||
79 | def getcurselection(self): | |
80 | if self._singleSelect: | |
81 | return self.selection | |
82 | else: | |
83 | return tuple(self.selection) | |
84 | ||
85 | def getvalue(self): | |
86 | return self.getcurselection() | |
87 | ||
88 | def setvalue(self, textOrList): | |
89 | if self._singleSelect: | |
90 | self.__setSingleValue(textOrList) | |
91 | else: | |
92 | # Multiple selections | |
93 | oldselection = self.selection | |
94 | self.selection = textOrList | |
95 | for button in self._buttonList: | |
96 | if button in oldselection: | |
97 | if button not in self.selection: | |
98 | # button is currently selected but should not be | |
99 | widget = self.component(button) | |
100 | if self['buttontype'] == 'checkbutton': | |
101 | widget.deselect() | |
102 | else: # Button | |
103 | widget.configure(relief='raised') | |
104 | else: | |
105 | if button in self.selection: | |
106 | # button is not currently selected but should be | |
107 | widget = self.component(button) | |
108 | if self['buttontype'] == 'checkbutton': | |
109 | widget.select() | |
110 | else: # Button | |
111 | widget.configure(relief='sunken') | |
112 | ||
113 | def numbuttons(self): | |
114 | return len(self._buttonList) | |
115 | ||
116 | def index(self, index): | |
117 | # Return the integer index of the button with the given index. | |
118 | ||
119 | listLength = len(self._buttonList) | |
120 | if type(index) == types.IntType: | |
121 | if index < listLength: | |
122 | return index | |
123 | else: | |
124 | raise ValueError, 'index "%s" is out of range' % index | |
125 | elif index is Pmw.END: | |
126 | if listLength > 0: | |
127 | return listLength - 1 | |
128 | else: | |
129 | raise ValueError, 'RadioSelect has no buttons' | |
130 | else: | |
131 | for count in range(listLength): | |
132 | name = self._buttonList[count] | |
133 | if index == name: | |
134 | return count | |
135 | validValues = 'a name, a number or Pmw.END' | |
136 | raise ValueError, \ | |
137 | 'bad index "%s": must be %s' % (index, validValues) | |
138 | ||
139 | def button(self, buttonIndex): | |
140 | name = self._buttonList[self.index(buttonIndex)] | |
141 | return self.component(name) | |
142 | ||
143 | def add(self, componentName, **kw): | |
144 | if componentName in self._buttonList: | |
145 | raise ValueError, 'button "%s" already exists' % componentName | |
146 | ||
147 | kw['command'] = \ | |
148 | lambda self=self, name=componentName: self.invoke(name) | |
149 | if not kw.has_key('text'): | |
150 | kw['text'] = componentName | |
151 | ||
152 | if self['buttontype'] == 'radiobutton': | |
153 | if not kw.has_key('anchor'): | |
154 | kw['anchor'] = 'w' | |
155 | if not kw.has_key('variable'): | |
156 | kw['variable'] = self.var | |
157 | if not kw.has_key('value'): | |
158 | kw['value'] = kw['text'] | |
159 | elif self['buttontype'] == 'checkbutton': | |
160 | if not kw.has_key('anchor'): | |
161 | kw['anchor'] = 'w' | |
162 | ||
163 | button = apply(self.createcomponent, (componentName, | |
164 | (), 'Button', | |
165 | self.buttonClass, (self._radioSelectFrame,)), kw) | |
166 | ||
167 | if self['orient'] == 'horizontal': | |
168 | self._radioSelectFrame.grid_rowconfigure(0, weight=1) | |
169 | col = len(self._buttonList) | |
170 | button.grid(column=col, row=0, padx = self['padx'], | |
171 | pady = self['pady'], sticky='nsew') | |
172 | self._radioSelectFrame.grid_columnconfigure(col, weight=1) | |
173 | else: | |
174 | self._radioSelectFrame.grid_columnconfigure(0, weight=1) | |
175 | row = len(self._buttonList) | |
176 | button.grid(column=0, row=row, padx = self['padx'], | |
177 | pady = self['pady'], sticky='ew') | |
178 | self._radioSelectFrame.grid_rowconfigure(row, weight=1) | |
179 | ||
180 | self._buttonList.append(componentName) | |
181 | return button | |
182 | ||
183 | def deleteall(self): | |
184 | for name in self._buttonList: | |
185 | self.destroycomponent(name) | |
186 | self._buttonList = [] | |
187 | if self._singleSelect: | |
188 | self.selection = None | |
189 | else: | |
190 | self.selection = [] | |
191 | ||
192 | def __setSingleValue(self, value): | |
193 | self.selection = value | |
194 | if self['buttontype'] == 'radiobutton': | |
195 | widget = self.component(value) | |
196 | widget.select() | |
197 | else: # Button | |
198 | for button in self._buttonList: | |
199 | widget = self.component(button) | |
200 | if button == value: | |
201 | widget.configure(relief='sunken') | |
202 | else: | |
203 | widget.configure(relief='raised') | |
204 | ||
205 | def invoke(self, index): | |
206 | index = self.index(index) | |
207 | name = self._buttonList[index] | |
208 | ||
209 | if self._singleSelect: | |
210 | self.__setSingleValue(name) | |
211 | command = self['command'] | |
212 | if callable(command): | |
213 | return command(name) | |
214 | else: | |
215 | # Multiple selections | |
216 | widget = self.component(name) | |
217 | if name in self.selection: | |
218 | if self['buttontype'] == 'checkbutton': | |
219 | widget.deselect() | |
220 | else: | |
221 | widget.configure(relief='raised') | |
222 | self.selection.remove(name) | |
223 | state = 0 | |
224 | else: | |
225 | if self['buttontype'] == 'checkbutton': | |
226 | widget.select() | |
227 | else: | |
228 | widget.configure(relief='sunken') | |
229 | self.selection.append(name) | |
230 | state = 1 | |
231 | ||
232 | command = self['command'] | |
233 | if callable(command): | |
234 | return command(name, state) |