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