Package gui :: Package analyses :: Module base
[hide private]
[frames] | no frames]

Source Code for Module gui.analyses.base

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2009 Michael Bieri                                            # 
  4  # Copyright (C) 2010-2012 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 class for all frames.""" 
 25   
 26  # Python module imports. 
 27  from os import sep 
 28  import wx 
 29  from wx.lib import buttons 
 30  from wx.lib import scrolledpanel 
 31    
 32  # relax module imports. 
 33  from generic_fns.mol_res_spin import count_spins 
 34  from generic_fns.pipes import cdp_name 
 35  from user_functions.data import Uf_info; uf_info = Uf_info() 
 36  from user_functions.data import Uf_tables; uf_tables = Uf_tables() 
 37   
 38  # relax GUI module imports. 
 39  from gui import paths 
 40  from gui.analyses.elements import Text_ctrl 
 41  from gui.fonts import font 
 42  from gui.misc import add_border, bitmap_setup, format_table 
 43  from gui.string_conv import int_to_gui, str_to_gui 
 44  from gui.wizard import Wiz_page 
 45   
 46   
47 -class Base_analysis(wx.lib.scrolledpanel.ScrolledPanel):
48 """The base class for all frames.""" 49 50 # Hard coded variables. 51 border = 10 52 size_graphic_panel = 200 53 spacer_horizontal = 5 54 width_text = 240 55 width_button = 100 56 width_main_separator = 40 57
58 - def __init__(self, parent, id=wx.ID_ANY, pos=None, size=None, style=None, name=None, gui=None):
59 """Initialise the scrolled window. 60 61 @param parent: The parent wx element. 62 @type parent: wx object 63 @keyword id: The unique ID number. 64 @type id: int 65 @keyword pos: The position. 66 @type pos: wx.Size object 67 @keyword size: The size. 68 @type size: wx.Size object 69 @keyword style: The style. 70 @type style: int 71 @keyword name: The name for the panel. 72 @type name: unicode 73 """ 74 75 # Execute the base class method. 76 super(Base_analysis, self).__init__(parent, id=id, pos=pos, size=size, style=style, name=name) 77 78 # Determine the size of the scrollers. 79 self.width_vscroll = wx.SystemSettings_GetMetric(wx.SYS_VSCROLL_X) 80 81 # Pack a sizer into the panel. 82 box_main = wx.BoxSizer(wx.HORIZONTAL) 83 self.SetSizer(box_main) 84 85 # Build the central sizer, with borders. 86 box_centre = add_border(box_main, border=self.border, packing=wx.HORIZONTAL) 87 88 # Build and pack the main sizer box, then add it to the automatic model-free analysis frame. 89 self.build_main_box(box_centre) 90 91 # Set up the scrolled panel. 92 self.SetAutoLayout(True) 93 self.SetupScrolling(scroll_x=False, scroll_y=True) 94 95 # Bind resize events. 96 self.Bind(wx.EVT_SIZE, self.resize)
97 98
99 - def add_button_open(self, box, parent, icon=paths.icon_16x16.open, text=" Change", fn=None, width=-1, height=-1):
100 """Add a button for opening and changing files and directories. 101 102 @param box: The box element to pack the control into. 103 @type box: wx.BoxSizer instance 104 @param parent: The parent GUI element. 105 @type parent: wx object 106 @keyword icon: The path of the icon to use for the button. 107 @type icon: str 108 @keyword text: The text to display on the button. 109 @type text: str 110 @keyword fn: The function or method to execute when clicking on the button. 111 @type fn: func 112 @keyword width: The minimum width of the control. 113 @type width: int 114 @keyword height: The minimum height of the control. 115 @type height: int 116 @return: The button. 117 @rtype: wx.lib.buttons.ThemedGenBitmapTextButton instance 118 """ 119 120 # The button. 121 button = buttons.ThemedGenBitmapTextButton(parent, -1, None, str_to_gui(text)) 122 button.SetBitmapLabel(wx.Bitmap(icon, wx.BITMAP_TYPE_ANY)) 123 124 # The font and button properties. 125 button.SetMinSize((width, height)) 126 button.SetFont(font.normal) 127 128 # Bind the click. 129 self.gui.Bind(wx.EVT_BUTTON, fn, button) 130 131 # Add the button to the box. 132 box.Add(button, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) 133 134 # Return the button. 135 return button
136 137
138 - def add_execute_relax(self, box, method):
139 """Create and add the relax execution GUI element to the given box. 140 141 @param box: The box element to pack the relax execution GUI element into. 142 @type box: wx.BoxSizer instance 143 @param method: The method to execute when the button is clicked. 144 @type method: method 145 @return: The button. 146 @rtype: wx.lib.buttons.ThemedGenBitmapTextButton instance 147 """ 148 149 # A horizontal sizer for the contents. 150 sizer = wx.BoxSizer(wx.HORIZONTAL) 151 152 # A unique ID. 153 id = wx.NewId() 154 155 # The button. 156 button = buttons.ThemedGenBitmapTextButton(self, id, None, " Execute relax") 157 button.SetBitmapLabel(wx.Bitmap(paths.IMAGE_PATH+'relax_start.gif', wx.BITMAP_TYPE_ANY)) 158 button.SetFont(font.normal) 159 self.gui.Bind(wx.EVT_BUTTON, method, button) 160 sizer.Add(button, 0, wx.ADJUST_MINSIZE, 0) 161 162 # Add the element to the box. 163 box.Add(sizer, 0, wx.ALIGN_RIGHT, 0) 164 165 # Return the button. 166 return button
167 168
169 - def add_spin_control(self, box, parent, text='', min=None, max=None, control=wx.SpinCtrl, width=-1, height=-1):
170 """Add a text control field to the box. 171 172 @param box: The box element to pack the control into. 173 @type box: wx.BoxSizer instance 174 @param parent: The parent GUI element. 175 @type parent: wx object 176 @keyword text: The default text of the control. 177 @type text: str 178 @keyword min: The minimum value allowed. 179 @type min: int 180 @keyword max: The maximum value allowed. 181 @type max: int 182 @keyword control: The control class to use. 183 @type control: wx.TextCtrl derived class 184 @keyword width: The minimum width of the control. 185 @type width: int 186 @keyword height: The minimum height of the control. 187 @type height: int 188 @return: The text control object. 189 @rtype: control object 190 """ 191 192 # The control. 193 field = control(parent, -1, text, min=min, max=max) 194 195 # The font and control properties. 196 field.SetMinSize((width, height)) 197 field.SetFont(font.normal) 198 199 # Add the control to the box. 200 box.Add(field, 1, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) 201 202 # Return the text field. 203 return field
204 205
206 - def add_spin_systems(self, box, parent):
207 """Add a special control for spin systems. 208 209 Only one of these per analysis are allowed. 210 211 @param box: The box element to pack the control into. 212 @type box: wx.BoxSizer instance 213 @param parent: The parent GUI element. 214 @type parent: wx object 215 """ 216 217 # Add the element. 218 self.spin_systems = Text_ctrl(box, self, text="Spin systems", button_text=" Spin editor", default=self.spin_count(), icon=paths.icon_16x16.spin, fn=self.launch_spin_editor, editable=False, button=True, width_text=self.width_text, width_button=self.width_button, spacer=self.spacer_horizontal)
219 220
221 - def add_static_text(self, box, parent, text='', width=-1, height=-1):
222 """Add a text control field to the box. 223 224 @param box: The box element to pack the control into. 225 @type box: wx.BoxSizer instance 226 @param parent: The parent GUI element. 227 @type parent: wx object 228 @keyword text: The default text of the control. 229 @type text: str 230 @keyword width: The minimum width of the control. 231 @type width: int 232 @keyword height: The minimum height of the control. 233 @type height: int 234 @return: The label. 235 @rtype: wx.StaticText instance 236 """ 237 238 # The label. 239 label = wx.StaticText(parent, -1, text) 240 241 # The font and label properties. 242 label.SetMinSize((width, height)) 243 label.SetFont(font.normal) 244 245 # Add the label to the box. 246 box.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) 247 248 # Return the label. 249 return label
250 251
252 - def add_subtitle(self, box, text):
253 """Create and add the subtitle. 254 255 @param box: The box element to pack the subtitle into. 256 @type box: wx.BoxSizer instance 257 @param text: The text of the subtitle. 258 @type text: str 259 """ 260 261 # The title. 262 label = wx.StaticText(self, -1, text) 263 264 # The font properties. 265 label.SetFont(font.subtitle) 266 267 # Add the subtitle to the box, with spacing. 268 box.AddSpacer(20) 269 box.Add(label) 270 box.AddSpacer(5)
271 272
273 - def add_subsubtitle(self, box, text):
274 """Create and add the subsubtitle. 275 276 @param box: The box element to pack the text into. 277 @type box: wx.BoxSizer instance 278 @param text: The text of the subsubtitle. 279 @type text: str 280 """ 281 282 # The text. 283 label = wx.StaticText(self, -1, text) 284 285 # The font properties. 286 label.SetFont(font.normal) 287 288 # Add the text to the box, with spacing. 289 box.AddSpacer(10) 290 box.Add(label)
291 292
293 - def add_text_control(self, box, parent, text='', control=wx.TextCtrl, width=-1, height=-1, editable=True):
294 """Add a text control field to the box. 295 296 @param box: The box element to pack the control into. 297 @type box: wx.BoxSizer instance 298 @param parent: The parent GUI element. 299 @type parent: wx object 300 @keyword text: The default text of the control. 301 @type text: str 302 @keyword control: The control class to use. 303 @type control: wx.TextCtrl derived class 304 @keyword width: The minimum width of the control. 305 @type width: int 306 @keyword height: The minimum height of the control. 307 @type height: int 308 @keyword editable: A flag specifying if the control is editable or not. 309 @type editable: bool 310 @return: The text control object. 311 @rtype: control object 312 """ 313 314 # The control. 315 field = control(parent, -1, str_to_gui(text)) 316 317 # The font and control properties. 318 field.SetMinSize((width, height)) 319 field.SetFont(font.normal) 320 321 # Editable (change the colour if not). 322 field.SetEditable(editable) 323 if not editable: 324 colour = self.GetBackgroundColour() 325 field.SetOwnBackgroundColour(colour) 326 327 # Add the control to the box. 328 box.Add(field, 1, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) 329 330 # Return the text field. 331 return field
332 333
334 - def add_title(self, box, text):
335 """Create and add the frame title. 336 337 @param box: The box element to pack the frame title into. 338 @type box: wx.BoxSizer instance 339 @param text: The text of the title. 340 @type text: str 341 """ 342 343 # The title. 344 label = wx.StaticText(self, -1, text) 345 346 # The font properties. 347 label.SetFont(font.title) 348 349 # Pack the title, with spacing. 350 box.AddSpacer(10) 351 box.Add(label) 352 box.AddSpacer(5)
353 354
355 - def build_left_box(self):
356 """Construct the left hand box to pack into the automatic Rx analysis frame. 357 358 @return: The left hand box element containing the bitmap. 359 @rtype: wx.BoxSizer instance 360 """ 361 362 # Use a vertical packing of elements. 363 box = wx.BoxSizer(wx.VERTICAL) 364 365 # Convert the bitmap names to a list. 366 if not isinstance(self.bitmap, list): 367 bitmaps = [self.bitmap] 368 else: 369 bitmaps = self.bitmap 370 371 # Add the bitmaps. 372 for i in range(len(bitmaps)): 373 # The bitmap. 374 bitmap = wx.StaticBitmap(self, -1, bitmap_setup(bitmaps[i])) 375 376 # Add it. 377 box.Add(bitmap, 0, wx.ADJUST_MINSIZE, 10) 378 379 # Return the box. 380 return box
381 382
383 - def build_main_box(self, box):
384 """Construct the highest level box to pack into the automatic analysis frames. 385 386 @param box: The horizontal box element to pack the elements into. 387 @type box: wx.BoxSizer instance 388 """ 389 390 # Build the left hand box and add to the main box. 391 left_box = self.build_left_box() 392 box.Add(left_box, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 0) 393 394 # Central spacer. 395 box.AddSpacer(self.width_main_separator) 396 397 # Build the right hand box and pack it next to the bitmap. 398 right_box = self.build_right_box() 399 box.Add(right_box, 1, wx.ALL|wx.EXPAND, 0)
400 401
402 - def launch_spin_editor(self, event):
403 """The spin editor GUI element. 404 405 @param event: The wx event. 406 @type event: wx event 407 """ 408 409 # Show the molecule, residue, and spin tree window. 410 self.gui.show_tree(None)
411 412
413 - def observer_register(self, remove=False):
414 """Register and unregister methods with the observer objects. 415 416 This is a dummy method. 417 418 419 @keyword remove: If set to True, then the methods will be unregistered. 420 @type remove: False 421 """
422 423
424 - def resize(self, event):
425 """The spin editor GUI element. 426 427 @param event: The wx event. 428 @type event: wx event 429 """ 430 431 # Set the virtual size to have the width of the visible size and the height of the virtual size. 432 x = self.GetSize()[0] - self.width_vscroll 433 y = self.GetVirtualSize()[1] 434 self.SetVirtualSize((x, y))
435 436
437 - def spin_count(self):
438 """Count the number of loaded spins, returning a string formatted as 'xxx spins loaded'. 439 440 @return: The number of loaded spins in the format 'xxx spins loaded'. 441 @rtype: str 442 """ 443 444 # The data pipe. 445 if hasattr(self.data, 'pipe_name'): 446 pipe = self.data.pipe_name 447 else: 448 pipe = cdp_name() 449 450 # The count. 451 num = count_spins(pipe=pipe) 452 453 # Return the formatted string. 454 return "%s spins loaded and selected" % num
455 456
457 - def update_spin_count(self):
458 """Update the spin count.""" 459 460 # Set the new value. 461 wx.CallAfter(self.spin_systems.SetValue, str_to_gui(self.spin_count()))
462 463 464
465 -class Spectral_error_type_page(Wiz_page):
466 """The NOE peak intensity reading wizard page for specifying the type of error to be used.""" 467 468 # Class variables. 469 image_path = paths.WIZARD_IMAGE_PATH + 'spectrum' + sep + 'spectrum_200.png' 470 title = "Specify the type of error to be used" 471 main_text = "Please specify from where the peak intensity errors will be obtained. The is required for the execution of the spectrum.error_analysis user function which will be postponed until after clicking on the 'Execute relax' button at the end of the automatic analysis page. To understand how the errors will be propagated and analysed, the main parts of the spectrum.error_analysis user function description are given below." 472 uf_path = ['spectrum', 'error_analysis'] 473
474 - def _on_select(self, event):
475 """Handle the radio button switching. 476 477 @param event: The wx event. 478 @type event: wx event 479 """ 480 481 # The button. 482 button = event.GetEventObject() 483 484 # RMSD. 485 if button == self.radio_rmsd: 486 self.selection = 'rmsd' 487 elif button == self.radio_repl: 488 self.selection = 'repl'
489 490
491 - def add_contents(self, sizer):
492 """Add the specific GUI elements. 493 494 @param sizer: A sizer object. 495 @type sizer: wx.Sizer instance 496 """ 497 498 # A box sizer for placing the box sizer in. 499 sizer2 = wx.BoxSizer(wx.HORIZONTAL) 500 sizer.Add(sizer2, 1, wx.ALL|wx.EXPAND, 0) 501 502 # Bottom spacing. 503 sizer.AddStretchSpacer() 504 505 # A bit of indentation. 506 sizer2.AddStretchSpacer() 507 508 # A vertical sizer for the radio buttons. 509 sizer_radio = wx.BoxSizer(wx.VERTICAL) 510 sizer2.Add(sizer_radio, 1, wx.ALL|wx.EXPAND, 0) 511 512 # The RMSD radio button. 513 self.radio_rmsd = wx.RadioButton(self, -1, "Baseplane RMSD.", style=wx.RB_GROUP) 514 sizer_radio.Add(self.radio_rmsd, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 0) 515 516 # Spacing. 517 sizer_radio.AddSpacer(10) 518 519 # The replicated spectra radio button. 520 self.radio_repl = wx.RadioButton(self, -1, "Replicated spectra.") 521 sizer_radio.Add(self.radio_repl, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 0) 522 523 # Bind the buttons. 524 self.Bind(wx.EVT_RADIOBUTTON, self._on_select, self.radio_rmsd) 525 self.Bind(wx.EVT_RADIOBUTTON, self._on_select, self.radio_repl) 526 527 # Right side spacing. 528 sizer2.AddStretchSpacer(3) 529 530 # Bottom spacing. 531 sizer.AddStretchSpacer() 532 533 # Set the default selection. 534 self.selection = 'rmsd'
535 536
537 - def add_desc(self, sizer, max_y=520):
538 """Add the description to the dialog. 539 540 @param sizer: A sizer object. 541 @type sizer: wx.Sizer instance 542 @keyword max_y: The maximum height, in number of pixels, for the description. 543 @type max_y: int 544 """ 545 546 # Initialise. 547 spacing = 15 548 549 # A line with spacing. 550 sizer.AddSpacer(5) 551 sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0) 552 sizer.AddSpacer(5) 553 554 # Create a scrolled panel. 555 panel = scrolledpanel.ScrolledPanel(self, -1, name="desc") 556 557 # A sizer for the panel. 558 panel_sizer = wx.BoxSizer(wx.VERTICAL) 559 560 # Initialise the text elements. 561 tot_y = 0 562 text_elements = [] 563 text_types = [] 564 565 # The wrapped text. 566 text = wx.StaticText(panel, -1, self.main_text, style=wx.TE_MULTILINE) 567 text.SetFont(font.normal) 568 text.Wrap(self._main_size - 20) 569 text_elements.append(text) 570 text_types.append('title') 571 572 # The text size, then spacing. 573 x, y = text.GetSizeTuple() 574 tot_y += y 575 tot_y += spacing 576 577 # Get the spectrum.error_analysis user function data object. 578 uf_data = uf_info.get_uf('spectrum.error_analysis') 579 580 # The description sections. 581 if uf_data.desc != None: 582 # Loop over the sections. 583 for i in range(len(uf_data.desc)): 584 # Alias. 585 desc = uf_data.desc[i] 586 587 # Skip the prompt examples. 588 if desc.get_title() == 'Prompt examples': 589 continue 590 591 # Loop over the text elements. 592 for type, element in desc.element_loop(title=True): 593 # The text version of the elements. 594 text = '' 595 if isinstance(element, str): 596 text = element 597 598 # Format the tables. 599 if type == 'table': 600 text = format_table(uf_tables.get_table(element)) 601 602 # Format the lists. 603 elif type == 'list': 604 # Loop over the list elements. 605 for j in range(len(element)): 606 text += " - %s\n" % element[j] 607 608 # Format the item lists. 609 elif type == 'item list': 610 # Loop over the list elements. 611 for j in range(len(element)): 612 # No item. 613 if element[j][0] in [None, '']: 614 text += " %s\n" % element[j][1] 615 else: 616 text += " %s: %s\n" % (element[j][0], element[j][1]) 617 618 # The text object. 619 text_obj = wx.StaticText(panel, -1, text, style=wx.TE_MULTILINE) 620 621 # Format. 622 if type == 'title': 623 text_obj.SetFont(font.subtitle) 624 elif type == 'paragraph': 625 text_obj.SetFont(font.normal) 626 elif type in ['table', 'verbatim']: 627 text_obj.SetFont(font.modern_small) 628 else: 629 text_obj.SetFont(font.normal) 630 631 # Wrap the paragraphs and lists (with spacing for scrollbars). 632 if type in ['paragraph', 'list', 'item list']: 633 text_obj.Wrap(self._main_size - 20) 634 635 # The text size. 636 x, y = text_obj.GetSizeTuple() 637 tot_y += y 638 639 # The spacing after each element (except the last). 640 tot_y += spacing 641 642 # The spacing before each section (not including the first). 643 if i != 0 and type == 'title': 644 tot_y += spacing 645 646 # Append the text objects. 647 text_elements.append(text_obj) 648 text_types.append(type) 649 650 # Some extra space for who knows what?! 651 tot_y -= spacing 652 tot_y += 20 653 654 # Set the panel size - scrolling needed. 655 if tot_y > max_y: 656 panel.SetInitialSize((self._main_size, max_y)) 657 658 # Set the panel size - no scrolling. 659 else: 660 panel.SetInitialSize((self._main_size, tot_y)) 661 662 # Add the text. 663 n = len(text_elements) 664 for i in range(n): 665 # Spacing before each section (not including the first). 666 if i > 1 and text_types[i] == 'title': 667 panel_sizer.AddSpacer(spacing) 668 669 # The text. 670 panel_sizer.Add(text_elements[i], 0, wx.ALIGN_LEFT, 0) 671 672 # Spacer after all sections (except the end). 673 if i != n - 1: 674 panel_sizer.AddSpacer(spacing) 675 676 # Set up and add the panel to the sizer. 677 panel.SetSizer(panel_sizer) 678 panel.SetAutoLayout(1) 679 panel.SetupScrolling(scroll_x=False, scroll_y=True) 680 sizer.Add(panel, 0, wx.ALL|wx.EXPAND) 681 682 # A line with spacing. 683 sizer.AddSpacer(5) 684 sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0) 685 sizer.AddSpacer(5)
686