Author: bugman Date: Tue May 22 10:27:42 2012 New Revision: 16365 URL: http://svn.gna.org/viewcvs/relax?rev=16365&view=rev Log: The Sequence GUI element now better handles single values in the GetValue() method. Modified: branches/uf_redesign/gui/input_elements/sequence.py Modified: branches/uf_redesign/gui/input_elements/sequence.py URL: http://svn.gna.org/viewcvs/relax/branches/uf_redesign/gui/input_elements/sequence.py?rev=16365&r1=16364&r2=16365&view=diff ============================================================================== --- branches/uf_redesign/gui/input_elements/sequence.py (original) +++ branches/uf_redesign/gui/input_elements/sequence.py Tue May 22 10:27:42 2012 @@ -111,249 +111,6 @@ self.single_value = single_value self.can_be_none = can_be_none - # The sequence types. - if seq_type == 'list': - self.convert_from_gui = gui_to_list - self.convert_to_gui = list_to_gui - elif seq_type == 'tuple': - self.convert_from_gui = gui_to_tuple - self.convert_to_gui = tuple_to_gui - else: - raise RelaxError("Unknown sequence type '%s'." % seq_type) - - # Initialise the default element. - if self.element_type == 'default': - # Translate the read_only flag if None. - if read_only == None: - read_only = False - - # Init. - sub_sizer = wx.BoxSizer(wx.HORIZONTAL) - - # Left padding. - sub_sizer.AddSpacer(padding) - - # The description. - text = wx.StaticText(parent, -1, desc, style=wx.ALIGN_LEFT) - text.SetFont(font.normal) - sub_sizer.Add(text, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 0) - - # The divider. - if not divider: - raise RelaxError("The divider position has not been supplied.") - - # Spacing. - x, y = text.GetSize() - sub_sizer.AddSpacer((divider - x, 0)) - - # The input field. - self._field = wx.TextCtrl(parent, -1, '') - self._field.SetMinSize((50, height_element)) - self._field.SetFont(font.normal) - sub_sizer.Add(self._field, 1, wx.ADJUST_MINSIZE|wx.ALIGN_CENTER_VERTICAL, 0) - - # Read-only. - if read_only: - self._field.SetEditable(False) - colour = parent.GetBackgroundColour() - self._field.SetOwnBackgroundColour(colour) - - # A little spacing. - sub_sizer.AddSpacer(5) - - # The edit button. - button = wx.BitmapButton(parent, -1, wx.Bitmap(paths.icon_16x16.edit_rename, wx.BITMAP_TYPE_ANY)) - button.SetMinSize((height_element, height_element)) - button.SetToolTipString("Edit the values.") - sub_sizer.Add(button, 0, wx.ADJUST_MINSIZE|wx.ALIGN_CENTER_VERTICAL, 0) - parent.Bind(wx.EVT_BUTTON, self.open_dialog, button) - - # Right padding. - sub_sizer.AddSpacer(padding) - - # Add to the main sizer. - sizer.Add(sub_sizer, 1, wx.EXPAND|wx.ALL, 0) - - # Spacing below the widget. - if spacer == None: - sizer.AddStretchSpacer() - else: - sizer.AddSpacer(spacer) - - # Tooltip. - if tooltip: - text.SetToolTipString(tooltip) - self._field.SetToolTipString(tooltip) - - # Set the default value. - if self.default != None: - self._field.SetValue(self.convert_to_gui(self.default)) - - # Initialise the combo list input field. - elif self.element_type == 'combo_list': - # Translate the read_only flag if None. - if read_only == None: - read_only = False - - # Set up the Combo_list object. - self._field = Combo_list(parent, sizer, desc, value_type=value_type, min_length=combo_list_min, choices=combo_choices, data=combo_data, default=default, tooltip=tooltip, read_only=read_only, can_be_none=can_be_none) - - # Unknown field. - else: - raise RelaxError("Unknown element type '%s'." % self.element_type) - - - def Clear(self): - """Special method for clearing or resetting the GUI element.""" - - # Clear the value from a TextCtrl or ComboBox. - if self.element_type in ['default', 'combo_list']: - self._field.Clear() - - - def GetValue(self): - """Special method for returning the sequence values of the GUI element. - - @return: The sequence of values. - @rtype: sequence type - """ - - # The value. - value = self._field.GetValue() - - # Convert, handling bad user behaviour. - try: - value = self.convert_from_gui(value) - except RelaxError: - if self.seq_type == 'list': - value = [] - else: - value = () - - # Handle single values. - if self.single_value and len(value) == 1: - if self.seq_type == 'list' and not isinstance(value, list): - value = [value] - elif self.seq_type == 'tuple' and not isinstance(value, tuple): - value = (value,) - - # Handle empty values. - if len(value) == 0: - return None - - # Return the value. - return value - - - def ResetChoices(self, combo_choices=None, combo_data=None, combo_default=None): - """Special wizard method for resetting the list of choices in a ComboBox type element. - - @param key: The key corresponding to the desired GUI element. - @type key: str - @keyword combo_choices: The list of choices to present to the user. This is only used if the element_type is set to 'combo_list'. - @type combo_choices: list of str - @keyword combo_data: The data returned by a call to GetValue(). This is only used if the element_type is set to 'combo_list'. 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. - @type combo_data: list - @keyword combo_default: The default value of the ComboBox. This is only used if the element_type is set to 'combo_list'. - @type combo_default: str or None - """ - - # The ComboBox list. - if self.element_type == 'combo_list': - self._field.ResetChoices(combo_choices=combo_choices, combo_data=combo_data, combo_default=combo_default) - - - def SetValue(self, value=None, index=None): - """Special method for setting the value of the GUI element. - - @keyword value: The value to set. - @type value: value or list of values - @keyword index: The index of the value to set, if the full list is not given. - @type index: int or None - """ - - # The ComboBox list. - if self.element_type == 'combo_list': - self._field.SetValue(value=value, index=index) - - # The other elements. - else: - # Handle single values. - if self.single_value and isinstance(value, list): - if len(value) == 1: - value = value[0] - else: - raise RelaxError("The list of values '%s' cannot be converted to a single value." % value) - - # Convert and set the value. - self._field.SetValue(self.convert_to_gui(value)) - - - def open_dialog(self, event): - """Open a special dialog for inputting a list of text values. - - @param event: The wx event. - @type event: wx event - """ - - # Initialise the model selection window. - win = Sequence_window(name=self.name, seq_type=self.seq_type, value_type=self.value_type, dim=self.dim) - - # Set the model selector window selections. - win.SetValue(self.GetValue()) - - # Show the model selector window. - if status.show_gui: - win.ShowModal() - win.Close() - - # Get the value. - value = win.GetValue() - - # No sequence data. - if not len(value): - self.Clear() - - # Set the values. - else: - self.SetValue(value) - - # Destroy the window. - del win - - - -class Sequence_window(wx.Dialog): - """The Python sequence object editor window.""" - - # The window size. - SIZE = (600, 600) - - # A border. - BORDER = 10 - - # Sizes. - SIZE_BUTTON = (150, 33) - - def __init__(self, name='', seq_type='list', value_type='str', dim=None): - """Set up the string list editor window. - - @keyword name: The name of the window. - @type name: str - @keyword seq_type: The type of Python sequence. This should be one of 'list' or 'tuple'. - @type seq_type: str - @keyword value_type: The type of Python data expected in the sequence. This should be one of 'float', 'int', or 'str'. - @type value_type: str - @keyword dim: The fixed dimension that the sequence must conform to. - @type dim: int or None - """ - - # Store the args. - self.name = name - self.seq_type = seq_type - self.value_type = value_type - self.dim = dim - # The base types. if value_type in ['float', 'num']: self.convert_from_gui = gui_to_float @@ -367,6 +124,271 @@ else: raise RelaxError("Unknown base data type '%s'." % value_type) + # The sequence types. + if seq_type == 'list': + self.convert_from_gui_seq = gui_to_list + self.convert_to_gui_seq = list_to_gui + elif seq_type == 'tuple': + self.convert_from_gui_seq = gui_to_tuple + self.convert_to_gui_seq = tuple_to_gui + else: + raise RelaxError("Unknown sequence type '%s'." % seq_type) + + # Initialise the default element. + if self.element_type == 'default': + # Translate the read_only flag if None. + if read_only == None: + read_only = False + + # Init. + sub_sizer = wx.BoxSizer(wx.HORIZONTAL) + + # Left padding. + sub_sizer.AddSpacer(padding) + + # The description. + text = wx.StaticText(parent, -1, desc, style=wx.ALIGN_LEFT) + text.SetFont(font.normal) + sub_sizer.Add(text, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 0) + + # The divider. + if not divider: + raise RelaxError("The divider position has not been supplied.") + + # Spacing. + x, y = text.GetSize() + sub_sizer.AddSpacer((divider - x, 0)) + + # The input field. + self._field = wx.TextCtrl(parent, -1, '') + self._field.SetMinSize((50, height_element)) + self._field.SetFont(font.normal) + sub_sizer.Add(self._field, 1, wx.ADJUST_MINSIZE|wx.ALIGN_CENTER_VERTICAL, 0) + + # Read-only. + if read_only: + self._field.SetEditable(False) + colour = parent.GetBackgroundColour() + self._field.SetOwnBackgroundColour(colour) + + # A little spacing. + sub_sizer.AddSpacer(5) + + # The edit button. + button = wx.BitmapButton(parent, -1, wx.Bitmap(paths.icon_16x16.edit_rename, wx.BITMAP_TYPE_ANY)) + button.SetMinSize((height_element, height_element)) + button.SetToolTipString("Edit the values.") + sub_sizer.Add(button, 0, wx.ADJUST_MINSIZE|wx.ALIGN_CENTER_VERTICAL, 0) + parent.Bind(wx.EVT_BUTTON, self.open_dialog, button) + + # Right padding. + sub_sizer.AddSpacer(padding) + + # Add to the main sizer. + sizer.Add(sub_sizer, 1, wx.EXPAND|wx.ALL, 0) + + # Spacing below the widget. + if spacer == None: + sizer.AddStretchSpacer() + else: + sizer.AddSpacer(spacer) + + # Tooltip. + if tooltip: + text.SetToolTipString(tooltip) + self._field.SetToolTipString(tooltip) + + # Set the default value. + if self.default != None: + self._field.SetValue(self.convert_to_gui_seq(self.default)) + + # Initialise the combo list input field. + elif self.element_type == 'combo_list': + # Translate the read_only flag if None. + if read_only == None: + read_only = False + + # Set up the Combo_list object. + self._field = Combo_list(parent, sizer, desc, value_type=value_type, min_length=combo_list_min, choices=combo_choices, data=combo_data, default=default, tooltip=tooltip, read_only=read_only, can_be_none=can_be_none) + + # Unknown field. + else: + raise RelaxError("Unknown element type '%s'." % self.element_type) + + + def Clear(self): + """Special method for clearing or resetting the GUI element.""" + + # Clear the value from a TextCtrl or ComboBox. + if self.element_type in ['default', 'combo_list']: + self._field.Clear() + + + def GetValue(self): + """Special method for returning the sequence values of the GUI element. + + @return: The sequence of values. + @rtype: sequence type + """ + + # The value. + value = self._field.GetValue() + + # Handle single values. + if self.single_value: + try: + value = self.convert_from_gui(value) + value_set = True + except: + value_set = False + + # Convert to a sequence, handling bad user behaviour. + if not value_set: + try: + value = self.convert_from_gui_seq(value) + except RelaxError: + if self.seq_type == 'list': + value = [] + else: + value = () + + # Handle single values. + if self.single_value and isinstance(value, list): + if self.seq_type == 'list' and not isinstance(value, list): + value = [value] + elif self.seq_type == 'tuple' and not isinstance(value, tuple): + value = (value,) + + # Handle empty values. + if len(value) == 0: + return None + + # Return the value. + return value + + + def ResetChoices(self, combo_choices=None, combo_data=None, combo_default=None): + """Special wizard method for resetting the list of choices in a ComboBox type element. + + @param key: The key corresponding to the desired GUI element. + @type key: str + @keyword combo_choices: The list of choices to present to the user. This is only used if the element_type is set to 'combo_list'. + @type combo_choices: list of str + @keyword combo_data: The data returned by a call to GetValue(). This is only used if the element_type is set to 'combo_list'. 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. + @type combo_data: list + @keyword combo_default: The default value of the ComboBox. This is only used if the element_type is set to 'combo_list'. + @type combo_default: str or None + """ + + # The ComboBox list. + if self.element_type == 'combo_list': + self._field.ResetChoices(combo_choices=combo_choices, combo_data=combo_data, combo_default=combo_default) + + + def SetValue(self, value=None, index=None): + """Special method for setting the value of the GUI element. + + @keyword value: The value to set. + @type value: value or list of values + @keyword index: The index of the value to set, if the full list is not given. + @type index: int or None + """ + + # The ComboBox list. + if self.element_type == 'combo_list': + self._field.SetValue(value=value, index=index) + + # The other elements. + else: + # Handle single values. + if self.single_value and isinstance(value, list): + if len(value) == 1: + value = value[0] + else: + raise RelaxError("The list of values '%s' cannot be converted to a single value." % value) + + # Convert and set the value. + self._field.SetValue(self.convert_to_gui(value)) + + + def open_dialog(self, event): + """Open a special dialog for inputting a list of text values. + + @param event: The wx event. + @type event: wx event + """ + + # Initialise the model selection window. + win = Sequence_window(name=self.name, seq_type=self.seq_type, value_type=self.value_type, dim=self.dim) + + # Set the model selector window selections. + win.SetValue(self.GetValue()) + + # Show the model selector window. + if status.show_gui: + win.ShowModal() + win.Close() + + # Get the value. + value = win.GetValue() + + # No sequence data. + if not len(value): + self.Clear() + + # Set the values. + else: + self.SetValue(value) + + # Destroy the window. + del win + + + +class Sequence_window(wx.Dialog): + """The Python sequence object editor window.""" + + # The window size. + SIZE = (600, 600) + + # A border. + BORDER = 10 + + # Sizes. + SIZE_BUTTON = (150, 33) + + def __init__(self, name='', seq_type='list', value_type='str', dim=None): + """Set up the string list editor window. + + @keyword name: The name of the window. + @type name: str + @keyword seq_type: The type of Python sequence. This should be one of 'list' or 'tuple'. + @type seq_type: str + @keyword value_type: The type of Python data expected in the sequence. This should be one of 'float', 'int', or 'str'. + @type value_type: str + @keyword dim: The fixed dimension that the sequence must conform to. + @type dim: int or None + """ + + # Store the args. + self.name = name + self.seq_type = seq_type + self.value_type = value_type + self.dim = dim + + # The base types. + if value_type in ['float', 'num']: + self.convert_from_gui = gui_to_float + self.convert_to_gui = float_to_gui + elif value_type == 'int': + self.convert_from_gui = gui_to_int + self.convert_to_gui = int_to_gui + elif value_type == 'str': + self.convert_from_gui = gui_to_str + self.convert_to_gui = str_to_gui + else: + raise RelaxError("Unknown base data type '%s'." % value_type) + # The title of the dialog. title = "Edit the %s values." % name