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-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 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, has_pipe 
 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 if not has_pipe(pipe): 452 num = 0 453 else: 454 num = count_spins(pipe=pipe) 455 456 # Return the formatted string. 457 return "%s spins loaded and selected" % num
458 459
460 - def update_spin_count(self):
461 """Update the spin count.""" 462 463 # Set the new value. 464 wx.CallAfter(self.spin_systems.SetValue, str_to_gui(self.spin_count()))
465 466 467
468 -class Spectral_error_type_page(Wiz_page):
469 """The NOE peak intensity reading wizard page for specifying the type of error to be used.""" 470 471 # Class variables. 472 image_path = paths.WIZARD_IMAGE_PATH + 'spectrum' + sep + 'spectrum_200.png' 473 title = "Specify the type of error to be used" 474 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." 475 uf_path = ['spectrum', 'error_analysis'] 476
477 - def _on_select(self, event):
478 """Handle the radio button switching. 479 480 @param event: The wx event. 481 @type event: wx event 482 """ 483 484 # The button. 485 button = event.GetEventObject() 486 487 # RMSD. 488 if button == self.radio_rmsd: 489 self.selection = 'rmsd' 490 elif button == self.radio_repl: 491 self.selection = 'repl'
492 493
494 - def add_contents(self, sizer):
495 """Add the specific GUI elements. 496 497 @param sizer: A sizer object. 498 @type sizer: wx.Sizer instance 499 """ 500 501 # A box sizer for placing the box sizer in. 502 sizer2 = wx.BoxSizer(wx.HORIZONTAL) 503 sizer.Add(sizer2, 1, wx.ALL|wx.EXPAND, 0) 504 505 # Bottom spacing. 506 sizer.AddStretchSpacer() 507 508 # A bit of indentation. 509 sizer2.AddStretchSpacer() 510 511 # A vertical sizer for the radio buttons. 512 sizer_radio = wx.BoxSizer(wx.VERTICAL) 513 sizer2.Add(sizer_radio, 1, wx.ALL|wx.EXPAND, 0) 514 515 # The RMSD radio button. 516 self.radio_rmsd = wx.RadioButton(self, -1, "Baseplane RMSD.", style=wx.RB_GROUP) 517 sizer_radio.Add(self.radio_rmsd, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 0) 518 519 # Spacing. 520 sizer_radio.AddSpacer(10) 521 522 # The replicated spectra radio button. 523 self.radio_repl = wx.RadioButton(self, -1, "Replicated spectra.") 524 sizer_radio.Add(self.radio_repl, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 0) 525 526 # Bind the buttons. 527 self.Bind(wx.EVT_RADIOBUTTON, self._on_select, self.radio_rmsd) 528 self.Bind(wx.EVT_RADIOBUTTON, self._on_select, self.radio_repl) 529 530 # Right side spacing. 531 sizer2.AddStretchSpacer(3) 532 533 # Bottom spacing. 534 sizer.AddStretchSpacer() 535 536 # Set the default selection. 537 self.selection = 'rmsd'
538 539
540 - def add_desc(self, sizer, max_y=520):
541 """Add the description to the dialog. 542 543 @param sizer: A sizer object. 544 @type sizer: wx.Sizer instance 545 @keyword max_y: The maximum height, in number of pixels, for the description. 546 @type max_y: int 547 """ 548 549 # Initialise. 550 spacing = 15 551 552 # A line with spacing. 553 sizer.AddSpacer(5) 554 sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0) 555 sizer.AddSpacer(5) 556 557 # Create a scrolled panel. 558 panel = scrolledpanel.ScrolledPanel(self, -1, name="desc") 559 560 # A sizer for the panel. 561 panel_sizer = wx.BoxSizer(wx.VERTICAL) 562 563 # Initialise the text elements. 564 tot_y = 0 565 text_elements = [] 566 text_types = [] 567 568 # The wrapped text. 569 text = wx.StaticText(panel, -1, self.main_text, style=wx.TE_MULTILINE) 570 text.SetFont(font.normal) 571 text.Wrap(self._main_size - 20) 572 text_elements.append(text) 573 text_types.append('title') 574 575 # The text size, then spacing. 576 x, y = text.GetSizeTuple() 577 tot_y += y 578 tot_y += spacing 579 580 # Get the spectrum.error_analysis user function data object. 581 uf_data = uf_info.get_uf('spectrum.error_analysis') 582 583 # The description sections. 584 if uf_data.desc != None: 585 # Loop over the sections. 586 for i in range(len(uf_data.desc)): 587 # Alias. 588 desc = uf_data.desc[i] 589 590 # Skip the prompt examples. 591 if desc.get_title() == 'Prompt examples': 592 continue 593 594 # Loop over the text elements. 595 for type, element in desc.element_loop(title=True): 596 # The text version of the elements. 597 text = '' 598 if isinstance(element, str): 599 text = element 600 601 # Format the tables. 602 if type == 'table': 603 text = format_table(uf_tables.get_table(element)) 604 605 # Format the lists. 606 elif type == 'list': 607 # Loop over the list elements. 608 for j in range(len(element)): 609 text += " - %s\n" % element[j] 610 611 # Format the item lists. 612 elif type == 'item list': 613 # Loop over the list elements. 614 for j in range(len(element)): 615 # No item. 616 if element[j][0] in [None, '']: 617 text += " %s\n" % element[j][1] 618 else: 619 text += " %s: %s\n" % (element[j][0], element[j][1]) 620 621 # The text object. 622 text_obj = wx.StaticText(panel, -1, text, style=wx.TE_MULTILINE) 623 624 # Format. 625 if type == 'title': 626 text_obj.SetFont(font.subtitle) 627 elif type == 'paragraph': 628 text_obj.SetFont(font.normal) 629 elif type in ['table', 'verbatim']: 630 text_obj.SetFont(font.modern_small) 631 else: 632 text_obj.SetFont(font.normal) 633 634 # Wrap the paragraphs and lists (with spacing for scrollbars). 635 if type in ['paragraph', 'list', 'item list']: 636 text_obj.Wrap(self._main_size - 20) 637 638 # The text size. 639 x, y = text_obj.GetSizeTuple() 640 tot_y += y 641 642 # The spacing after each element (except the last). 643 tot_y += spacing 644 645 # The spacing before each section (not including the first). 646 if i != 0 and type == 'title': 647 tot_y += spacing 648 649 # Append the text objects. 650 text_elements.append(text_obj) 651 text_types.append(type) 652 653 # Some extra space for who knows what?! 654 tot_y -= spacing 655 tot_y += 20 656 657 # Set the panel size - scrolling needed. 658 if tot_y > max_y: 659 panel.SetInitialSize((self._main_size, max_y)) 660 661 # Set the panel size - no scrolling. 662 else: 663 panel.SetInitialSize((self._main_size, tot_y)) 664 665 # Add the text. 666 n = len(text_elements) 667 for i in range(n): 668 # Spacing before each section (not including the first). 669 if i > 1 and text_types[i] == 'title': 670 panel_sizer.AddSpacer(spacing) 671 672 # The text. 673 panel_sizer.Add(text_elements[i], 0, wx.ALIGN_LEFT, 0) 674 675 # Spacer after all sections (except the end). 676 if i != n - 1: 677 panel_sizer.AddSpacer(spacing) 678 679 # Set up and add the panel to the sizer. 680 panel.SetSizer(panel_sizer) 681 panel.SetAutoLayout(1) 682 panel.SetupScrolling(scroll_x=False, scroll_y=True) 683 sizer.Add(panel, 0, wx.ALL|wx.EXPAND) 684 685 # A line with spacing. 686 sizer.AddSpacer(5) 687 sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0) 688 sizer.AddSpacer(5)
689