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

Source Code for Module gui.input_elements.sequence

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2012-2013 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  """Module containing a set of special GUI elements to be used in the relax wizards.""" 
 24   
 25  # Python module imports. 
 26  import wx 
 27  import wx.lib.mixins.listctrl 
 28   
 29  # relax module imports. 
 30  from graphics import fetch_icon 
 31  from gui.input_elements.combo_list import Combo_list 
 32  from gui.fonts import font 
 33  from gui.misc import add_border 
 34  from gui.string_conv import float_to_gui, gui_to_float, gui_to_int, gui_to_list, gui_to_py, gui_to_str, gui_to_tuple, int_to_gui, list_to_gui, py_to_gui, str_to_gui, tuple_to_gui 
 35  from lib.errors import RelaxError 
 36  from status import Status; status = Status() 
 37   
 38   
39 -class Sequence:
40 """Wizard GUI element for the input of all types of Python sequence objects. 41 42 The supported Python types include: 43 - list of floats 44 - list of integers 45 - list of strings 46 - tuple of floats 47 - tuple of integers 48 - tuple of strings 49 """ 50
51 - def __init__(self, name=None, default=None, parent=None, element_type='default', seq_type=None, value_type=None, dim=None, min=0, max=1000, sizer=None, desc=None, combo_choices=None, combo_data=None, combo_list_min=None, tooltip=None, divider=None, padding=0, spacer=None, height_element=27, single_value=False, read_only=False, can_be_none=False):
52 """Set up the element. 53 54 @keyword name: The name of the element to use in titles, etc. 55 @type name: str 56 @keyword default: The default value of the element. 57 @type default: sequence object 58 @keyword parent: The wizard GUI element. 59 @type parent: wx.Panel instance 60 @keyword element_type: The type of GUI element to create. If set to 'default', the wx.TextCtrl element with a button to bring up a dialog with ListCtrl will be used. If set to 'combo_list', the special gui.components.combo_list.Combo_list element will be used. 61 @type element_type: str 62 @keyword seq_type: The type of Python sequence. This should be one of 'list' or 'tuple'. 63 @type seq_type: str 64 @keyword value_type: The type of Python object that the value should be. This can be one of 'float', 'int', or 'str'. 65 @type value_type: str 66 @keyword dim: The dimensions that a list or tuple must conform to. For a 1D sequence, this can be a single value or a tuple of possible sizes. For a 2D sequence (a numpy matrix or list of lists), this must be a tuple of the fixed dimension sizes, e.g. a 3x5 matrix should be specified as (3, 5). 67 @type dim: int, tuple of int or None 68 @keyword min: For a SpinCtrl, the minimum value allowed. 69 @type min: int 70 @keyword max: For a SpinCtrl, the maximum value allowed. 71 @type max: int 72 @keyword sizer: The sizer to put the input field widget into. 73 @type sizer: wx.Sizer instance 74 @keyword desc: The text description. 75 @type desc: str 76 @keyword combo_choices: The list of choices to present to the user. This is only used if the element_type is set to 'combo'. 77 @type combo_choices: list of str 78 @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. 79 @type combo_data: list 80 @keyword combo_list_min: The minimum length for the Combo_list object. 81 @type combo_list_min: int or None 82 @keyword tooltip: The tooltip which appears on hovering over the text or input field. 83 @type tooltip: str 84 @keyword divider: The position of the divider. 85 @type divider: int 86 @keyword padding: Spacing to the left and right of the widgets. 87 @type padding: int 88 @keyword spacer: The amount of spacing to add below the field in pixels. If None, a stretchable spacer will be used. 89 @type spacer: None or int 90 @keyword height_element: The height in pixels of the GUI element. 91 @type height_element: int 92 @keyword single_value: A flag which if True will cause single input values to be treated as single values rather than a list or tuple. 93 @type single_value: bool 94 @keyword read_only: A flag which if True means that the text of the element cannot be edited. 95 @type read_only: bool 96 @keyword can_be_none: A flag which specifies if the element is allowed to have the None value. 97 @type can_be_none: bool 98 """ 99 100 # Store the args. 101 self.parent = parent 102 self.name = name 103 self.default = default 104 self.element_type = element_type 105 self.seq_type = seq_type 106 self.value_type = value_type 107 self.dim = dim 108 self.min = min 109 self.max = max 110 self.single_value = single_value 111 self.can_be_none = can_be_none 112 113 # The base 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 elif value_type == 'int': 118 self.convert_from_gui = gui_to_int 119 self.convert_to_gui = int_to_gui 120 elif value_type == 'str': 121 self.convert_from_gui = gui_to_str 122 self.convert_to_gui = str_to_gui 123 else: 124 self.convert_from_gui = gui_to_py 125 self.convert_to_gui = py_to_gui 126 127 # The sequence types. 128 if seq_type == 'list': 129 self.convert_from_gui_seq = gui_to_list 130 self.convert_to_gui_seq = list_to_gui 131 elif seq_type == 'tuple': 132 self.convert_from_gui_seq = gui_to_tuple 133 self.convert_to_gui_seq = tuple_to_gui 134 else: 135 raise RelaxError("Unknown sequence type '%s'." % seq_type) 136 137 # Initialise the default element. 138 if self.element_type == 'default': 139 # Translate the read_only flag if None. 140 if read_only == None: 141 read_only = False 142 143 # Init. 144 sub_sizer = wx.BoxSizer(wx.HORIZONTAL) 145 146 # Left padding. 147 sub_sizer.AddSpacer(padding) 148 149 # The description. 150 text = wx.StaticText(parent, -1, desc, style=wx.ALIGN_LEFT) 151 text.SetFont(font.normal) 152 sub_sizer.Add(text, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 0) 153 154 # The divider. 155 if not divider: 156 raise RelaxError("The divider position has not been supplied.") 157 158 # Spacing. 159 x, y = text.GetSize() 160 sub_sizer.AddSpacer((divider - x, 0)) 161 162 # The input field. 163 self._field = wx.TextCtrl(parent, -1, '') 164 self._field.SetMinSize((50, height_element)) 165 self._field.SetFont(font.normal) 166 sub_sizer.Add(self._field, 1, wx.ADJUST_MINSIZE|wx.ALIGN_CENTER_VERTICAL, 0) 167 168 # Read-only. 169 if read_only: 170 self._field.SetEditable(False) 171 colour = parent.GetBackgroundColour() 172 self._field.SetOwnBackgroundColour(colour) 173 174 # A little spacing. 175 sub_sizer.AddSpacer(5) 176 177 # The edit button. 178 button = wx.BitmapButton(parent, -1, wx.Bitmap(fetch_icon('oxygen.actions.edit-rename', "16x16"), wx.BITMAP_TYPE_ANY)) 179 button.SetMinSize((height_element, height_element)) 180 button.SetToolTipString("Edit the values.") 181 sub_sizer.Add(button, 0, wx.ADJUST_MINSIZE|wx.ALIGN_CENTER_VERTICAL, 0) 182 parent.Bind(wx.EVT_BUTTON, self.open_dialog, button) 183 184 # Right padding. 185 sub_sizer.AddSpacer(padding) 186 187 # Add to the main sizer. 188 sizer.Add(sub_sizer, 1, wx.EXPAND|wx.ALL, 0) 189 190 # Spacing below the widget. 191 if spacer == None: 192 sizer.AddStretchSpacer() 193 else: 194 sizer.AddSpacer(spacer) 195 196 # Tooltip. 197 if tooltip: 198 text.SetToolTipString(tooltip) 199 self._field.SetToolTipString(tooltip) 200 201 # Set the default value. 202 if self.default != None: 203 self._field.SetValue(self.convert_to_gui_seq(self.default)) 204 205 # Initialise the combo list input field. 206 elif self.element_type == 'combo_list': 207 # Translate the read_only flag if None. 208 if read_only == None: 209 read_only = False 210 211 # Set up the Combo_list object. 212 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) 213 214 # Unknown field. 215 else: 216 raise RelaxError("Unknown element type '%s'." % self.element_type)
217 218
219 - def Clear(self):
220 """Special method for clearing or resetting the GUI element.""" 221 222 # Clear the value from a TextCtrl or ComboBox. 223 if self.element_type in ['default', 'combo_list']: 224 self._field.Clear()
225 226
227 - def GetValue(self):
228 """Special method for returning the sequence values of the GUI element. 229 230 @return: The sequence of values. 231 @rtype: sequence type 232 """ 233 234 # The value. 235 value = self._field.GetValue() 236 237 # Handle Combo_list elements. 238 if self.element_type == 'combo_list': 239 # Empty lists. 240 if value == [] or value == None: 241 return None 242 243 # Non Combo_list elements. 244 else: 245 # Handle single values. 246 value_set = False 247 if self.single_value: 248 try: 249 # Convert. 250 value = self.convert_from_gui(value) 251 252 # Check that the conversion was successful. 253 if value == None and self.can_be_none: 254 value_set = True 255 elif self.value_type == None: 256 value_set = True 257 elif self.value_type in ['float', 'num']: 258 if isinstance(value, int) or isinstance(value, float): 259 value_set = True 260 elif self.value_type == 'int': 261 if isinstance(value, int): 262 value_set = True 263 elif self.value_type == 'str': 264 if self.seq_type == 'list' and value[0] != '[': 265 value_set = True 266 elif self.seq_type == 'tuple' and value[0] != '(': 267 value_set = True 268 except: 269 pass 270 271 # Convert to a sequence, handling bad user behaviour. 272 if not value_set: 273 try: 274 value = self.convert_from_gui_seq(value) 275 276 # Set the value to None or an empty sequence. 277 except RelaxError: 278 if self.can_be_none: 279 value = None 280 elif self.seq_type == 'list': 281 value = [] 282 else: 283 value = () 284 285 # Convert sequences to single values as needed. 286 if self.single_value: 287 if (isinstance(value, list) or isinstance(value, tuple)) and len(value) == 1: 288 value = value[0] 289 290 # Convert single values to sequences as needed. 291 elif value != None: 292 if self.seq_type == 'list' and not isinstance(value, list): 293 value = [value] 294 elif self.seq_type == 'tuple' and not isinstance(value, tuple): 295 value = (value,) 296 297 # Handle empty list and tuple values. 298 if not self.single_value and len(value) == 0: 299 return None 300 301 # Return the value. 302 return value
303 304
305 - def SetValue(self, value=None, index=None):
306 """Special method for setting the value of the GUI element. 307 308 @keyword value: The value to set. 309 @type value: value or list of values 310 @keyword index: The index of the value to set, if the full list is not given. 311 @type index: int or None 312 """ 313 314 # The ComboBox list. 315 if self.element_type == 'combo_list': 316 self._field.SetValue(value=value, index=index) 317 318 # The other elements. 319 else: 320 # Handle single values. 321 if self.single_value and isinstance(value, list) and len(value) == 1: 322 value = value[0] 323 324 # Convert and set the value. 325 self._field.SetValue(self.convert_to_gui_seq(value))
326 327
328 - def UpdateChoices(self, combo_choices=None, combo_data=None, combo_default=None):
329 """Special wizard method for updating the list of choices in a ComboBox type element. 330 331 @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'. 332 @type combo_choices: list of str 333 @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. 334 @type combo_data: list 335 @keyword combo_default: The default value of the ComboBox. This is only used if the element_type is set to 'combo_list'. 336 @type combo_default: str or None 337 """ 338 339 # The ComboBox list. 340 if self.element_type == 'combo_list': 341 self._field.UpdateChoices(combo_choices=combo_choices, combo_data=combo_data, combo_default=combo_default)
342 343
344 - def open_dialog(self, event):
345 """Open a special dialog for inputting a list of text values. 346 347 @param event: The wx event. 348 @type event: wx event 349 """ 350 351 # Show the window. 352 self.selection_win_show() 353 354 # Extract the data from the selection window once closed. 355 self.selection_win_data() 356 357 # Destroy the window. 358 del self.sel_win
359 360
361 - def selection_win_data(self):
362 """Extract the data from the selection window.""" 363 364 # Get the value. 365 value = self.sel_win.GetValue() 366 367 # No sequence data. 368 if not len(value): 369 self.Clear() 370 371 # Set the values. 372 else: 373 self.SetValue(value)
374 375
376 - def selection_win_show(self):
377 """Show the selection window.""" 378 379 # Initialise the model selection window. 380 self.sel_win = Sequence_window(parent=self.parent, name=self.name, seq_type=self.seq_type, value_type=self.value_type, dim=self.dim) 381 382 # Set the model selector window selections. 383 self.sel_win.SetValue(self.GetValue()) 384 385 # Show the model selector window. 386 if status.show_gui: 387 self.sel_win.ShowModal() 388 self.sel_win.Close()
389 390 391
392 -class Sequence_list_ctrl(wx.ListCtrl, wx.lib.mixins.listctrl.TextEditMixin, wx.lib.mixins.listctrl.ListCtrlAutoWidthMixin):
393 """The string list ListCtrl object.""" 394
395 - def __init__(self, parent):
396 """Initialise the control. 397 398 @param parent: The parent window. 399 @type parent: wx.Frame instance 400 """ 401 402 # Execute the parent __init__() methods. 403 wx.ListCtrl.__init__(self, parent, -1, style=wx.BORDER_SUNKEN|wx.LC_REPORT|wx.LC_HRULES|wx.LC_VRULES) 404 wx.lib.mixins.listctrl.TextEditMixin.__init__(self) 405 wx.lib.mixins.listctrl.ListCtrlAutoWidthMixin.__init__(self) 406 407 # Catch edits. 408 self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.begin_label_edit)
409 410
411 - def begin_label_edit(self, event):
412 """Catch edits to make the first column read only. 413 414 @param event: The wx event. 415 @type event: wx event 416 """ 417 418 # Prevent edits in the first column. 419 if event.m_col == 0: 420 event.Veto() 421 422 # Otherwise the user is free to edit. 423 else: 424 event.Skip()
425 426 427
428 -class Sequence_window(wx.Dialog):
429 """The Python sequence object editor window.""" 430 431 # The window size. 432 SIZE = (800, 600) 433 434 # A border. 435 BORDER = 10 436 437 # Sizes. 438 SIZE_BUTTON = (150, 33) 439
440 - def __init__(self, parent=None, name='', seq_type='list', value_type='str', dim=None):
441 """Set up the string list editor window. 442 443 @keyword parent: The parent GUI element. 444 @type parent: wx.Window instance or None 445 @keyword name: The name of the window. 446 @type name: str 447 @keyword seq_type: The type of Python sequence. This should be one of 'list' or 'tuple'. 448 @type seq_type: str 449 @keyword value_type: The type of Python data expected in the sequence. This should be one of 'float', 'int', or 'str'. 450 @type value_type: str 451 @keyword dim: The fixed dimension that the sequence must conform to. 452 @type dim: int or None 453 """ 454 455 # Store the args. 456 self.name = name 457 self.seq_type = seq_type 458 self.value_type = value_type 459 self.dim = dim 460 461 # The base types. 462 if value_type in ['float', 'num']: 463 self.convert_from_gui = gui_to_float 464 self.convert_to_gui = float_to_gui 465 elif value_type == 'int': 466 self.convert_from_gui = gui_to_int 467 self.convert_to_gui = int_to_gui 468 elif value_type == 'str': 469 self.convert_from_gui = gui_to_str 470 self.convert_to_gui = str_to_gui 471 else: 472 raise RelaxError("Unknown base data type '%s'." % value_type) 473 474 # The title of the dialog. 475 title = "Edit the %s values." % name 476 477 # Set up the dialog. 478 wx.Dialog.__init__(self, parent, id=-1, title=title) 479 480 # Initialise some values 481 self.width = self.SIZE[0] - 2*self.BORDER 482 483 # Set the frame properties. 484 self.SetSize(self.SIZE) 485 self.Centre() 486 self.SetFont(font.normal) 487 488 # The main box sizer. 489 main_sizer = wx.BoxSizer(wx.VERTICAL) 490 491 # Pack the sizer into the frame. 492 self.SetSizer(main_sizer) 493 494 # Build the central sizer, with borders. 495 sizer = add_border(main_sizer, border=self.BORDER, packing=wx.VERTICAL) 496 497 # Add the list control. 498 self.add_list(sizer) 499 500 # Some spacing. 501 sizer.AddSpacer(self.BORDER) 502 503 # Add the bottom buttons. 504 self.add_buttons(sizer) 505 506 # Initialise the list of elements to a single element. 507 if not self.sequence.GetItemCount(): 508 self.add_element()
509 510
511 - def GetValue(self):
512 """Return the values as a sequence of values. 513 514 @return: The sequence of values. 515 @rtype: sequence type 516 """ 517 518 # Init. 519 values = [] 520 521 # Loop over the entries. 522 for i in range(self.sequence.GetItemCount()): 523 # Get the text. 524 item = self.sequence.GetItem(i, col=1) 525 text = item.GetText() 526 527 # Store the text. 528 values.append(self.convert_from_gui(text)) 529 530 # Sequence conversion. 531 if self.seq_type == 'tuple': 532 values = tuple(values) 533 534 # Return the sequence. 535 return values
536 537
538 - def SetValue(self, values):
539 """Set up the list values. 540 541 @param values: The list of values to add to the list. 542 @type values: list of str or None 543 """ 544 545 # No value. 546 if values == None: 547 return 548 549 # Single values. 550 try: 551 len(values) 552 except TypeError: 553 if self.seq_type == 'list': 554 values = [values] 555 elif self.seq_type == 'tuple': 556 values = (values,) 557 558 # Loop over the entries. 559 for i in range(len(values)): 560 # Fixed dimension sequences - set the values of the pre-created list. 561 if self.dim: 562 self.sequence.SetStringItem(index=i, col=1, label=self.convert_to_gui(values[i])) 563 564 # Variable dimension sequences - append the item to the end of the blank list. 565 else: 566 # The first element already exists. 567 if i != 0: 568 # First add the index+1. 569 self.sequence.InsertStringItem(i, int_to_gui(i+1)) 570 571 # Then set the value. 572 self.sequence.SetStringItem(index=i, col=1, label=self.convert_to_gui(values[i]))
573 574
575 - def add_buttons(self, sizer):
576 """Add the buttons to the sizer. 577 578 @param sizer: A sizer object. 579 @type sizer: wx.Sizer instance 580 """ 581 582 # Create a horizontal layout for the buttons. 583 button_sizer = wx.BoxSizer(wx.HORIZONTAL) 584 sizer.Add(button_sizer, 0, wx.ALIGN_CENTER|wx.ALL, 0) 585 586 # The non-fixed sequence buttons. 587 if self.dim == None or (isinstance(self.dim, tuple) and self.dim[0] == None): 588 # The add button. 589 button = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " Add") 590 button.SetBitmapLabel(wx.Bitmap(fetch_icon('oxygen.actions.list-add-relax-blue', "22x22"), wx.BITMAP_TYPE_ANY)) 591 button.SetFont(font.normal) 592 button.SetToolTipString("Add an item to the list.") 593 button.SetMinSize(self.SIZE_BUTTON) 594 button_sizer.Add(button, 0, wx.ADJUST_MINSIZE, 0) 595 self.Bind(wx.EVT_BUTTON, self.add_element, button) 596 597 # Spacer. 598 button_sizer.AddSpacer(20) 599 600 # The delete button. 601 button = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " Delete") 602 button.SetBitmapLabel(wx.Bitmap(fetch_icon('oxygen.actions.list-remove', "22x22"), wx.BITMAP_TYPE_ANY)) 603 button.SetFont(font.normal) 604 button.SetToolTipString("Delete the last item.") 605 button.SetMinSize(self.SIZE_BUTTON) 606 button_sizer.Add(button, 0, wx.ADJUST_MINSIZE, 0) 607 self.Bind(wx.EVT_BUTTON, self.delete, button) 608 609 # Spacer. 610 button_sizer.AddSpacer(20) 611 612 # The delete all button. 613 button = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " Delete all") 614 button.SetBitmapLabel(wx.Bitmap(fetch_icon('oxygen.actions.edit-delete', "22x22"), wx.BITMAP_TYPE_ANY)) 615 button.SetFont(font.normal) 616 button.SetToolTipString("Delete all items.") 617 button.SetMinSize(self.SIZE_BUTTON) 618 button_sizer.Add(button, 0, wx.ADJUST_MINSIZE, 0) 619 self.Bind(wx.EVT_BUTTON, self.delete_all, button) 620 621 # Spacer. 622 button_sizer.AddSpacer(20) 623 624 # The Ok button. 625 button = wx.lib.buttons.ThemedGenBitmapTextButton(self, -1, None, " Ok") 626 button.SetBitmapLabel(wx.Bitmap(fetch_icon('oxygen.actions.dialog-ok', "22x22"), wx.BITMAP_TYPE_ANY)) 627 button.SetFont(font.normal) 628 button.SetMinSize(self.SIZE_BUTTON) 629 button_sizer.Add(button, 0, wx.ADJUST_MINSIZE, 0) 630 self.Bind(wx.EVT_BUTTON, self.close, button)
631 632
633 - def add_element(self, event=None):
634 """Append a new row to the list. 635 636 @keyword event: The wx event. 637 @type event: wx event 638 """ 639 640 # The next index. 641 next = self.sequence.GetItemCount() 642 643 # Add a new empty row. 644 self.sequence.InsertStringItem(next, int_to_gui(next+1))
645 646
647 - def add_list(self, sizer):
648 """Set up the list control. 649 650 @param sizer: A sizer object. 651 @type sizer: wx.Sizer instance 652 """ 653 654 # The control. 655 self.sequence = Sequence_list_ctrl(self) 656 657 # Set the column title. 658 title = "%s%s" % (self.name[0].upper(), self.name[1:]) 659 660 # Add the index column. 661 self.sequence.InsertColumn(0, "Position") 662 self.sequence.SetColumnWidth(0, 70) 663 664 # Add a single column, full width. 665 self.sequence.InsertColumn(1, title) 666 self.sequence.SetColumnWidth(1, wx.LIST_AUTOSIZE) 667 668 # Add the table to the sizer. 669 sizer.Add(self.sequence, 1, wx.ALL|wx.EXPAND, 0) 670 671 # The fixed dimension sequence - add all the rows needed. 672 if self.dim: 673 for i in range(self.dim): 674 self.add_element()
675 676
677 - def close(self, event):
678 """Close the window. 679 680 @param event: The wx event. 681 @type event: wx event 682 """ 683 684 # Destroy the window. 685 self.Destroy()
686 687
688 - def delete(self, event):
689 """Remove the last item from the list. 690 691 @param event: The wx event. 692 @type event: wx event 693 """ 694 695 # Delete the last item. 696 item = self.sequence.GetItemCount() 697 self.sequence.DeleteItem(item-1) 698 699 # If the list is empty, start again with a single blank element. 700 if not self.sequence.GetItemCount(): 701 self.add_element()
702 703
704 - def delete_all(self, event):
705 """Remove all items from the list. 706 707 @param event: The wx event. 708 @type event: wx event 709 """ 710 711 # Delete. 712 self.sequence.DeleteAllItems() 713 714 # Start again with a single blank element. 715 self.add_element()
716