Package gui :: Package components :: Module base_list
[hide private]
[frames] | no frames]

Source Code for Module gui.components.base_list

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2009-2011 Michael Bieri                                       # 
  4  # Copyright (C) 2010-2013 Edward d'Auvergne                                   # 
  5  #                                                                             # 
  6  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  7  #                                                                             # 
  8  # This program is free software: you can redistribute it and/or modify        # 
  9  # it under the terms of the GNU General Public License as published by        # 
 10  # the Free Software Foundation, either version 3 of the License, or           # 
 11  # (at your option) any later version.                                         # 
 12  #                                                                             # 
 13  # This program is distributed in the hope that it will be useful,             # 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 16  # GNU General Public License for more details.                                # 
 17  #                                                                             # 
 18  # You should have received a copy of the GNU General Public License           # 
 19  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23  # Module docstring. 
 24  """Module containing the base GUI element for listing things.""" 
 25   
 26  # Python module imports. 
 27  import wx 
 28  import wx.lib.buttons 
 29   
 30  # relax module imports. 
 31  from gui.components.menu import build_menu_item 
 32  from gui.fonts import font 
 33  from gui.misc import add_border 
 34  from gui.string_conv import str_to_gui 
 35  from gui.uf_objects import Uf_storage; uf_store = Uf_storage() 
 36  from status import Status; status = Status() 
 37  from user_functions.data import Uf_info; uf_info = Uf_info() 
 38   
 39   
40 -class Base_list(object):
41 """The GUI element for listing the software used in the analysis.""" 42
43 - def __init__(self, gui=None, parent=None, box=None, id=None, proportion=0, button_placement='default'):
44 """Build the base list GUI element. 45 46 @keyword gui: The main GUI object. 47 @type gui: wx.Frame instance 48 @keyword parent: The parent GUI element that this is to be attached to. 49 @type parent: wx object 50 @keyword box: The box sizer to pack this GUI component into. 51 @type box: wx.BoxSizer instance 52 @keyword id: A unique identification string. This is used to register the update method with the GUI user function observer object. 53 @type id: str 54 @keyword proportion: The window proportion parameter. 55 @type proportion: bool 56 @keyword button_placement: Override the button visibility and placement. The value of 'default' will leave the buttons at the default setting. The value of 'top' will place the buttons at the top, 'bottom' will place them at the bottom, and None will turn off the buttons. 57 @type button_placement: str or None 58 """ 59 60 # Store the arguments. 61 self.gui = gui 62 self.parent = parent 63 self.proportion = proportion 64 65 # Variables to be overridden. 66 self.title = "" 67 self.spacing = 5 68 self.border = 5 69 self.observer_base_name = None 70 self.columns = [] 71 self.button_placement = None 72 self.button_size = (120, 40) 73 self.button_spacing = 5 74 self.button_info = [] 75 self.popup_menus = [] 76 77 # Override these base values. 78 self.setup() 79 80 # Button placement second override on initialisation. 81 if button_placement != 'default': 82 self.button_placement = button_placement 83 84 # First create a panel (to allow for tooltips on the buttons). 85 self.panel = wx.Panel(self.parent) 86 box.Add(self.panel, self.proportion, wx.ALL|wx.EXPAND, 0) 87 88 # Add a sizer to the panel. 89 panel_sizer = wx.BoxSizer(wx.VERTICAL) 90 self.panel.SetSizer(panel_sizer) 91 92 # A static box to hold all the widgets, and its sizer. 93 self.data_box = wx.StaticBox(self.panel, -1) 94 self.set_box_label() 95 self.data_box.SetFont(font.subtitle) 96 sub_sizer = wx.StaticBoxSizer(self.data_box, wx.VERTICAL) 97 98 # Add the sizer to the static box and the static box to the main box. 99 panel_sizer.Add(sub_sizer, self.proportion, wx.ALL|wx.EXPAND, 0) 100 101 # Add a border. 102 box_centre = add_border(sub_sizer, border=self.border) 103 104 # Add buttons to the top. 105 if self.button_placement == 'top': 106 self.add_buttons(box_centre) 107 box_centre.AddSpacer(self.spacing) 108 109 # Initialise the element. 110 self.init_element(box_centre) 111 112 # Build the element. 113 self.build_element() 114 115 # Add buttons to the bottom. 116 if self.button_placement == 'bottom': 117 box_centre.AddSpacer(self.spacing) 118 self.add_buttons(box_centre) 119 120 # Initialise observer name. 121 if self.observer_base_name: 122 self.name = '%s: %s' % (self.observer_base_name, id) 123 else: 124 self.name = id 125 126 # Register the element for updating when a user function completes. 127 self.observer_register()
128 129
130 - def Enable(self, enable=True):
131 """Enable or disable the element. 132 133 @keyword enable: The flag specifying if the element should be enabled or disabled. 134 @type enable: bool 135 """ 136 137 # Call the buttons' methods. 138 for i in range(len(self.button_info)): 139 # Get the button. 140 button = getattr(self, self.button_info[i]['object']) 141 142 # Call the botton's method. 143 button.Enable(enable)
144 145
146 - def add_buttons(self, sizer):
147 """Add the buttons for manipulating the data. 148 149 @param sizer: The sizer element to pack the buttons into. 150 @type sizer: wx.BoxSizer instance 151 """ 152 153 # Button Sizer 154 button_sizer = wx.BoxSizer(wx.HORIZONTAL) 155 sizer.Add(button_sizer, 0, wx.ALL|wx.EXPAND, 0) 156 157 # Loop over the buttons. 158 for i in range(len(self.button_info)): 159 # The button. 160 button = wx.lib.buttons.ThemedGenBitmapTextButton(self.panel, -1, None, self.button_info[i]['label']) 161 button.SetBitmapLabel(wx.Bitmap(self.button_info[i]['icon'])) 162 163 # Format. 164 button.SetFont(font.normal) 165 button.SetMinSize(self.button_size) 166 167 # Add to the sizer. 168 button_sizer.Add(button, 0, 0, 0) 169 170 # Bind the method. 171 self.parent.Bind(wx.EVT_BUTTON, self.button_info[i]['method'], button) 172 173 # Set the tooltip. 174 button.SetToolTipString(self.button_info[i]['tooltip']) 175 176 # Store as a class object. 177 setattr(self, self.button_info[i]['object'], button) 178 179 # Spacing. 180 if self.button_spacing: 181 button_sizer.AddSpacer(self.button_spacing)
182 183
184 - def build_element(self):
185 """Build the grid.""" 186 187 # Execution lock, so do nothing. 188 if status.exec_lock.locked(): 189 return 190 191 # Build the GUI element in a thread safe way. 192 wx.CallAfter(self.build_element_safe)
193 194
195 - def build_element_safe(self):
196 """Build the spectra listing GUI element in a thread safe wx.CallAfter call.""" 197 198 # First freeze the element, so that the GUI element doesn't update until the end. 199 self.element.Freeze() 200 201 # Update the label if needed. 202 self.set_box_label() 203 204 # Delete the previous data. 205 self.element.DeleteAllItems() 206 207 # Update the data. 208 self.update_data() 209 210 # Size the columns. 211 self.size_cols() 212 213 # Post a size event to get the scroll panel to update correctly. 214 event = wx.PyCommandEvent(wx.EVT_SIZE.typeId, self.parent.GetId()) 215 wx.PostEvent(self.parent.GetEventHandler(), event) 216 217 # Set the minimum height. 218 if not self.proportion: 219 # The number of rows. 220 n = self.element.GetItemCount() 221 222 # Size of the header, plus a bit. 223 head = self.height_char + 10 224 225 # Size of the table central element. 226 centre = (self.height_char + 6) * n 227 228 # Size of the scrollbar for the end of the table. 229 foot = wx.SystemSettings_GetMetric(wx.SYS_HSCROLL_Y) 230 231 # Sum. 232 height = head + centre + foot 233 234 # Set the minimum size, and force a redraw. 235 self.element.SetMinSize((-1, height)) 236 self.element.Layout() 237 238 # Unfreeze. 239 self.element.Thaw()
240 241
242 - def delete(self):
243 """Unregister the class.""" 244 245 # Unregister the observer methods. 246 self.observer_register(remove=True)
247 248
249 - def init_element(self, sizer):
250 """Initialise the GUI element. 251 252 @param sizer: The sizer element to pack the element into. 253 @type sizer: wx.BoxSizer instance 254 """ 255 256 # The list. 257 self.element = wx.ListCtrl(self.panel, -1, style=wx.BORDER_SUNKEN|wx.LC_REPORT) 258 259 # Initialise the columns. 260 for i in range(len(self.columns)): 261 self.element.InsertColumn(i, str_to_gui(self.columns[i])) 262 263 # Properties. 264 self.element.SetFont(font.normal) 265 266 # Store the base heights. 267 self.height_char = self.element.GetCharHeight() 268 269 # Bind some events. 270 self.element.Bind(wx.EVT_SIZE, self.resize) 271 self.element.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.on_right_click) # For wxMSW! 272 self.element.Bind(wx.EVT_RIGHT_UP, self.on_right_click) # For wxGTK! 273 274 # Add list to sizer. 275 sizer.Add(self.element, self.proportion, wx.ALL|wx.EXPAND, 0)
276 277
278 - def is_complete(self):
279 """Base method which always returns True. 280 281 @return: The answer to the question. 282 @rtype: bool 283 """ 284 285 # Assume everything is complete. 286 return True
287 288
289 - def observer_register(self, remove=False):
290 """Register and unregister methods with the observer objects. 291 292 @keyword remove: If set to True, then the methods will be unregistered. 293 @type remove: False 294 """ 295 296 # Register. 297 if not remove: 298 status.observers.gui_uf.register(self.name, self.build_element, method_name='build_element') 299 status.observers.pipe_alteration.register(self.name, self.build_element, method_name='build_element') 300 301 # Unregister. 302 else: 303 status.observers.gui_uf.unregister(self.name) 304 status.observers.pipe_alteration.unregister(self.name)
305 306
307 - def on_right_click(self, event):
308 """Pop up menu for the right click. 309 310 @param event: The wx event. 311 @type event: wx event 312 """ 313 314 # No popup menus defined. 315 if self.popup_menus == []: 316 return 317 318 # Execution lock, so do nothing. 319 if status.exec_lock.locked(): 320 return 321 322 # Initialise the menu. 323 menu = wx.Menu() 324 325 # Loop over the menu items. 326 for i in range(len(self.popup_menus)): 327 # Alias. 328 info = self.popup_menus[i] 329 330 # Add the menu item. 331 menu.AppendItem(build_menu_item(menu, id=info['id'], text=info['text'], icon=info['icon'])) 332 333 # Bind clicks. 334 self.element.Bind(wx.EVT_MENU, info['method'], id=info['id']) 335 336 # Pop up the menu. 337 if status.show_gui: 338 self.element.PopupMenu(menu) 339 menu.Destroy()
340 341
342 - def resize(self, event):
343 """Catch the resize to allow the element to be resized. 344 345 @param event: The wx event. 346 @type event: wx event 347 """ 348 349 # Set the column sizes. 350 self.size_cols() 351 352 # Continue with the normal resizing. 353 event.Skip()
354 355
356 - def set_box_label(self):
357 """Set the label of the StaticBox.""" 358 359 # Set the label. 360 self.data_box.SetLabel(self.title)
361 362
363 - def size_cols(self):
364 """Set the column sizes.""" 365 366 # The element size. 367 x, y = self.element.GetSize() 368 369 # Number of columns. 370 n = self.element.GetColumnCount() 371 372 # Set to equal sizes. 373 if n == 0: 374 width = x 375 else: 376 width = int(x / n) 377 378 # Set the column sizes. 379 for i in range(n): 380 self.element.SetColumnWidth(i, width)
381