1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """GUI element for the user input of values."""
24
25
26 from copy import deepcopy
27 import wx
28
29
30 from gui.errors import gui_raise
31 from gui.fonts import font
32 from gui.string_conv import float_to_gui, gui_to_float, gui_to_int, gui_to_str, int_to_gui, str_to_gui
33 from lib.errors import RelaxError
34
35
37 """GUI element for the input of all types of simple Python objects.
38
39 The supported Python types include:
40 - floats
41 - integers
42 - strings
43 """
44
45 - def __init__(self, name=None, default=None, parent=None, element_type='default', value_type=None, sizer=None, desc=None, combo_choices=None, combo_data=None, min=0, max=1000, tooltip=None, divider=None, padding=0, spacer=None, height_element=27, read_only=False, can_be_none=False):
46 """Set up the base value element.
47
48 @keyword name: The name of the element to use in titles, etc.
49 @type name: str
50 @keyword default: The default value of the element.
51 @type default: float or int or str
52 @keyword parent: The parent GUI element.
53 @type parent: wx.Panel instance
54 @keyword element_type: The type of GUI element to create. This can be set to:
55 - 'text', a wx.TextCtrl element will be used.
56 - 'combo', a wx.ComboBox element will be used.
57 - 'spin', a wx.SpinCtrl element will be used. This is only valid for integer types!
58 @type element_type: str
59 @keyword value_type: The type of Python object that the value should be. This can be one of 'float', 'int', or 'str'.
60 @type value_type: str
61 @keyword sizer: The sizer to put the input field widget into.
62 @type sizer: wx.Sizer instance
63 @keyword desc: The text description.
64 @type desc: str
65 @keyword combo_choices: The list of choices to present to the user. This is only used if the element_type is set to 'combo'.
66 @type combo_choices: list of str
67 @keyword combo_data: The data returned by a call to GetValue(). This is only used if the element_type is set to 'combo'. If supplied, it should be the same length at the combo_choices list. If not supplied, the combo_choices list will be used for the returned data.
68 @type combo_data: list
69 @keyword min: For a SpinCtrl, the minimum value allowed.
70 @type min: int
71 @keyword max: For a SpinCtrl, the maximum value allowed.
72 @type max: int
73 @keyword tooltip: The tooltip which appears on hovering over the text or input field.
74 @type tooltip: str
75 @keyword divider: The position of the divider.
76 @type divider: int
77 @keyword padding: Spacing to the left and right of the widgets.
78 @type padding: int
79 @keyword spacer: The amount of spacing to add below the field in pixels. If None, a stretchable spacer will be used.
80 @type spacer: None or int
81 @keyword height_element: The height in pixels of the GUI element.
82 @type height_element: int
83 @keyword read_only: A flag which if True means that the text of the element cannot be edited.
84 @type read_only: bool
85 @keyword can_be_none: A flag which specifies if the element is allowed to have the None value.
86 @type can_be_none: bool
87 """
88
89
90 if element_type == 'default':
91
92 if value_type == 'int' and not can_be_none:
93 element_type = 'spin'
94
95
96 else:
97 element_type = 'text'
98
99
100 if element_type == "spin" and value_type != 'int':
101 raise RelaxError("A wx.SpinCtrl element can only be used together with integers.")
102
103
104 self.name = name
105 self.default = default
106 self.element_type = element_type
107 self.can_be_none = can_be_none
108 self.read_only = read_only
109
110
111 if value_type in ['float', 'num']:
112 self.convert_from_gui = gui_to_float
113 self.convert_to_gui = float_to_gui
114 self.type_string = 'float'
115 elif value_type == 'int':
116 self.convert_from_gui = gui_to_int
117 self.convert_to_gui = int_to_gui
118 self.type_string = 'integer'
119 elif value_type == 'str':
120 self.convert_from_gui = gui_to_str
121 self.convert_to_gui = str_to_gui
122 self.type_string = 'string'
123 else:
124 raise RelaxError("Unknown value type '%s'." % value_type)
125
126
127 sub_sizer = wx.BoxSizer(wx.HORIZONTAL)
128
129
130 sub_sizer.AddSpacer(padding)
131
132
133 text = wx.StaticText(parent, -1, desc, style=wx.ALIGN_LEFT)
134 text.SetFont(font.normal)
135 sub_sizer.Add(text, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 0)
136
137
138 if not divider:
139 raise RelaxError("The divider position has not been supplied.")
140
141
142 x, y = text.GetSize()
143 sub_sizer.AddSpacer((divider - x, 0))
144
145
146 if self.element_type == 'text':
147
148 self._field = wx.TextCtrl(parent, -1, '')
149
150
151 if read_only:
152
153 self._field.SetEditable(False)
154
155
156 colour = parent.GetBackgroundColour()
157 self._field.SetOwnBackgroundColour(colour)
158
159
160 if self.default != None:
161 self._field.SetValue(self.convert_to_gui(self.default))
162
163
164 elif self.element_type == 'spin':
165
166 if min == None:
167 min = 0
168 if max == None:
169 max = 100
170
171
172 self._field = wx.SpinCtrl(parent, -1, min=min, max=max)
173
174
175 if read_only:
176
177 colour = parent.GetBackgroundColour()
178 self._field.SetOwnBackgroundColour(colour)
179
180
181 if self.default != None:
182 self._field.SetValue(self.default)
183
184
185 elif self.element_type == 'combo':
186
187 style = wx.CB_DROPDOWN
188 if read_only:
189 style = style | wx.CB_READONLY
190
191
192 self._field = wx.ComboBox(parent, -1, '', style=style)
193
194
195 self.UpdateChoices(combo_choices=combo_choices, combo_data=combo_data, combo_default=default)
196
197
198 else:
199 raise RelaxError("Unknown element type '%s'." % self.element_type)
200
201
202 self._field.SetMinSize((50, height_element))
203 self._field.SetFont(font.normal)
204 sub_sizer.Add(self._field, 1, wx.ADJUST_MINSIZE|wx.ALIGN_CENTER_VERTICAL, 0)
205
206
207 sub_sizer.AddSpacer(padding)
208
209
210 sizer.Add(sub_sizer, 1, wx.EXPAND|wx.ALL, 0)
211
212
213 if spacer == None:
214 sizer.AddStretchSpacer()
215 else:
216 sizer.AddSpacer(spacer)
217
218
219 if tooltip:
220 text.SetToolTipString(tooltip)
221 self._field.SetToolTipString(tooltip)
222
223
225 """Special method for clearing or resetting the GUI element."""
226
227
228 if self.element_type == 'text':
229 self._field.Clear()
230
231
232 if self.element_type == 'combo':
233 self._field.Clear()
234 self._field.SetValue('')
235
236
238 """Special method for returning the value of the GUI element.
239
240 @return: The string list value.
241 @rtype: list of str
242 """
243
244
245 if self.element_type == 'text':
246
247 value = self._field.GetValue()
248
249
250 try:
251 value = self.convert_from_gui(value)
252
253
254 except:
255 gui_raise(RelaxError("The value '%s' is not of the Python %s type." % (value, self.type_string)))
256 return None
257
258 return value
259
260
261 if self.element_type == 'spin':
262
263 return self._field.GetValue()
264
265
266 if self.element_type == 'combo':
267
268 sel_index = self._field.GetSelection()
269 if sel_index == wx.NOT_FOUND:
270 value = None
271 else:
272 value = self.convert_from_gui(self._field.GetClientData(sel_index))
273
274
275 if value == None:
276 value = self.convert_from_gui(self._field.GetValue())
277
278
279 return value
280
281
283 """Special method for setting the value of the GUI element.
284
285 @param value: The value to set.
286 @type value: list of str or None
287 """
288
289
290 if self.element_type == 'text':
291 self._field.SetValue(self.convert_to_gui(value))
292
293
294 elif self.element_type == 'spin':
295 self._field.SetValue(value)
296
297
298 elif self.element_type == 'combo':
299
300 found = False
301 for i in range(self._field.GetCount()):
302 if self._field.GetClientData(i) == value:
303 self._field.SetSelection(i)
304 found = True
305 break
306
307
308 if not found:
309
310 if self.read_only:
311 if value != None:
312 raise RelaxError("The Value element is read only, cannot set the value '%s'." % value)
313
314
315 else:
316 self._field.SetSelection(wx.NOT_FOUND)
317 self._field.SetValue(self.convert_to_gui(value))
318
319
320 - def UpdateChoices(self, combo_choices=None, combo_data=None, combo_default=None):
321 """Special wizard method for updating the list of choices in a ComboBox type element.
322
323 @keyword combo_choices: The list of choices to present to the user. This is only used if the element_type is set to 'combo'.
324 @type combo_choices: list of str
325 @keyword combo_data: The data returned by a call to GetValue(). This is only used if the element_type is set to 'combo'. If supplied, it should be the same length at the combo_choices list. If not supplied, the combo_choices list will be used for the returned data.
326 @type combo_data: list
327 @keyword combo_default: The default value of the ComboBox. This is only used if the element_type is set to 'combo'.
328 @type combo_default: str or None
329 """
330
331
332 if self.element_type == 'text':
333 raise RelaxError("Cannot update the list of ComboBox choices as this is a TextCtrl!")
334
335
336 if self.element_type == 'spin':
337 raise RelaxError("Cannot update the list of ComboBox choices as this is a SpinCtrl!")
338
339
340 if self.element_type == 'combo':
341
342 sel_index = self._field.GetSelection()
343 if sel_index == wx.NOT_FOUND:
344 sel = None
345 else:
346 sel = self._field.GetClientData(sel_index)
347
348
349 self.Clear()
350
351
352 if combo_data == None:
353 combo_data = deepcopy(combo_choices)
354
355
356 if self.can_be_none:
357 combo_choices.insert(0, '')
358 combo_data.insert(0, None)
359
360
361 for i in range(len(combo_choices)):
362 self._field.Insert(self.convert_to_gui(combo_choices[i]), i, combo_data[i])
363
364
365 if sel == None and combo_default != None:
366
367 if combo_default in combo_choices:
368 string = str_to_gui(str(combo_default))
369 set_sel = True
370 elif combo_default not in combo_data:
371 string = str_to_gui(str(combo_default))
372 set_sel = False
373 else:
374 string = combo_choices[combo_data.index(combo_default)]
375 set_sel = True
376
377
378 if set_sel:
379 self._field.SetStringSelection(string)
380
381
382 else:
383 self._field.SetValue(string)
384
385
386 else:
387 for j in range(self._field.GetCount()):
388 if self._field.GetClientData(j) == sel:
389 self._field.SetSelection(j)
390