Package gui :: Package input_elements :: Module value
[hide private]
[frames] | no frames]

Source Code for Module gui.input_elements.value

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