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

Source Code for Module gui.user_functions.base

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2010-2011 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax.                                     # 
  6  #                                                                             # 
  7  # relax 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 2 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # relax 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 relax; if not, write to the Free Software                        # 
 19  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23  # Module docstring. 
 24  """Base class module for the user function GUI elements.""" 
 25   
 26  # Python module imports. 
 27  from re import search 
 28  from string import split 
 29  import wx 
 30  from wx.lib import scrolledpanel 
 31   
 32  # relax module imports. 
 33  from prompt.base_class import _strip_lead 
 34  from status import Status; status = Status() 
 35   
 36  # relax GUI imports. 
 37  from gui.fonts import font 
 38  from gui.interpreter import Interpreter; interpreter = Interpreter() 
 39  from gui.misc import str_to_gui 
 40  from gui.wizard import Wiz_page, Wiz_window 
 41   
 42   
43 -class UF_base:
44 """User function GUI element base class.""" 45
46 - def __init__(self, parent):
47 """Set up the window. 48 49 @param parent: The parent window. 50 @type parent: wx.Window instance 51 """ 52 53 # Store the arg. 54 self.parent = parent
55 56
57 - def create_wizard(self, size_x=600, size_y=400, name=None, uf_page=None, apply_button=True, return_page=False):
58 """Create and return the wizard window. 59 60 @keyword size_x: The width of the wizard. 61 @type size_x: int 62 @keyword size_y: The height of the wizard. 63 @type size_y: int 64 @keyword name: The name of the user function, such as 'deselect.all'. 65 @type name: str 66 @keyword uf_page: The user function page class. 67 @type uf_page: class 68 @keyword apply_button: A flag which if true will show the apply button for that page. This will be passed to the wizard's add_page() method. 69 @type apply_button: bool 70 @keyword return_page: A flag which if True will cause the user function page to be returned. 71 @type return_page: bool 72 @return: The wizard dialog (and wizard page if the return flag is given). 73 @rtype: gui.wizard.Wiz_window instance, wizard page instance 74 """ 75 76 # Split the name. 77 comps = split(name, '.') 78 if len(comps) == 2: 79 base = comps[0] 80 fn = comps[1] 81 else: 82 base = None 83 fn = comps[0] 84 85 # Create the wizard dialog. 86 wizard = Wiz_window(parent=self.parent, size_x=size_x, size_y=size_y, title=self.get_title(base=base, fn=fn)) 87 88 # Creat the page and add it to the wizard. 89 page = uf_page(wizard) 90 wizard.add_page(page, apply_button=apply_button) 91 92 # Return the wizard and the page. 93 if return_page: 94 return wizard, page 95 else: 96 return wizard
97 98
99 - def get_title(self, base=None, fn=None):
100 """Get the title for the wizard window from the user function documentation. 101 102 @keyword base: The name of the user function base class, if it exists. 103 @type base: str 104 @keyword fn: The name of the function of the base class, or the user function itself if there is no base class. 105 @type fn: str 106 @return: The title for the window. 107 @rtype: GUI str 108 """ 109 110 # Prefix. 111 title = 'relax: ' 112 113 # Add the base. 114 if base: 115 title = "%s%s." % (title, base) 116 117 # Add the function. 118 title = "%s%s" % (title, fn) 119 120 # Return the title as a GUI string. 121 return str_to_gui(title)
122 123
124 -class UF_page(Wiz_page):
125 """User function specific pages for the wizards.""" 126 127 # The path to the user function. 128 uf_path = None 129
130 - def __init__(self, parent, sync=False):
131 """Set up the window. 132 133 @param parent: The parent class containing the GUI. 134 @type parent: class instance 135 @keyword sync: A flag which if True will call user functions via interpreter.apply and if False via interpreter.queue. 136 @type sync: bool 137 """ 138 139 # Store the args. 140 self.sync = sync 141 142 # Default value data structure. 143 self.defaults = {} 144 145 # Yield to allow the cursor to be changed. 146 wx.Yield() 147 148 # Change the cursor to waiting. 149 wx.BeginBusyCursor() 150 151 # Get the user function class (or function). 152 uf_class = getattr(interpreter._instance._interpreter, self.uf_path[0]) 153 154 # Get the user function. 155 if len(self.uf_path) == 1: 156 self.uf = uf_class 157 else: 158 self.uf = getattr(uf_class, self.uf_path[1]) 159 160 # Set the user function title. 161 if hasattr(self.uf, '_doc_title_short'): 162 self.title = self.uf._doc_title_short 163 else: 164 self.title = self.uf._doc_title 165 166 # Execute the base class method. 167 super(UF_page, self).__init__(parent) 168 169 # Reset the cursor. 170 if wx.IsBusy(): 171 wx.EndBusyCursor()
172 173
174 - def _format_text(self, text):
175 """Format the text by stripping whitespace. 176 177 @param text: The text to strip. 178 @type text: str 179 @return: The stripped text. 180 @rtype: str 181 """ 182 183 # First strip whitespace. 184 stripped_text = _strip_lead(text) 185 186 # Remove the first characters if newlines. 187 while True: 188 if stripped_text[0] == "\n": 189 stripped_text = stripped_text[1:] 190 else: 191 break 192 193 # Remove the last character if a newline. 194 while True: 195 if stripped_text[-1] == "\n": 196 stripped_text = stripped_text[:-1] 197 else: 198 break 199 200 # Return the text. 201 return stripped_text
202 203
204 - def add_desc(self, sizer, max_y=220):
205 """Add the description to the dialog. 206 207 @param sizer: A sizer object. 208 @type sizer: wx.Sizer instance 209 @keyword max_y: The maximum height, in number of pixels, for the description. 210 @type max_y: int 211 """ 212 213 # Initialise. 214 spacing = 5 215 216 # A line with spacing. 217 sizer.AddSpacer(5) 218 sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0) 219 sizer.AddSpacer(5) 220 221 # Create a scrolled panel. 222 panel = scrolledpanel.ScrolledPanel(self, -1, name="desc") 223 224 # A sizer for the panel. 225 panel_sizer = wx.BoxSizer(wx.VERTICAL) 226 227 # Initialise the text elements. 228 text_list = [] 229 230 # The description. 231 if hasattr(self.uf, '_doc_desc'): 232 for element, type in self.process_doc([self.uf._doc_title, self.uf._doc_desc]): 233 text_list.append([element, type]) 234 235 # Additional documentation. 236 if hasattr(self.uf, '_doc_additional'): 237 for i in range(len(self.uf._doc_additional)): 238 for element, type in self.process_doc(self.uf._doc_additional[i]): 239 text_list.append([element, type]) 240 241 # Loop over the elements. 242 tot_x = 0 243 tot_y = 0 244 text_elements = [] 245 i = 0 246 for text, type in text_list: 247 # The text. 248 text_elements.append(wx.StaticText(panel, -1, text, style=wx.TE_MULTILINE)) 249 250 # Format. 251 if type == 'title': 252 text_elements[-1].SetFont(font.subtitle) 253 elif type == 'desc': 254 text_elements[-1].SetFont(font.normal) 255 elif type == 'table': 256 text_elements[-1].SetFont(font.modern_small) 257 258 # Wrap the text. 259 text_elements[-1].Wrap(self._main_size - 20) 260 261 # The text size. 262 x, y = text_elements[-1].GetSizeTuple() 263 tot_x += x 264 tot_y += y 265 266 # Size for the spacing. 267 tot_y += spacing 268 if i != 0: 269 tot_y += spacing 270 271 # Increment. 272 i += 1 273 274 # Scrolling needed. 275 if tot_y > max_y-10: 276 # Set the panel size. 277 panel.SetInitialSize((self._main_size, max_y)) 278 279 # No scrolling. 280 else: 281 # Rewrap the text. 282 for i in range(len(text_elements)): 283 text_elements[i].Wrap(self._main_size) 284 285 # Set the panel size. 286 panel.SetInitialSize((tot_x, tot_y)) 287 288 # Add the text. 289 for i in range(len(text_elements)): 290 # Initial spacing. 291 if i != 0: 292 panel_sizer.AddSpacer(spacing) 293 294 # The text. 295 panel_sizer.Add(text_elements[i], 0, wx.ALIGN_LEFT, 0) 296 297 # Spacer after titles. 298 if text_list[i][1] == 'title': 299 panel_sizer.AddSpacer(spacing) 300 301 # Set up and add the panel to the sizer. 302 panel.SetSizer(panel_sizer) 303 panel.SetAutoLayout(1) 304 panel.SetupScrolling(scroll_x=False, scroll_y=True) 305 sizer.Add(panel, 0, wx.ALL|wx.EXPAND) 306 307 # A line with spacing. 308 sizer.AddSpacer(5) 309 sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0) 310 sizer.AddSpacer(5)
311 312
313 - def execute(self, uf, *args, **kwds):
314 """Execute the user function, either asynchronously or synchronously. 315 316 @param uf: The user function as a string. 317 @type uf: str 318 @param args: The user function arguments. 319 @type args: any arguments 320 @param kwds: The user function keyword arguments. 321 @type kwds: any keyword arguments 322 """ 323 324 # Synchronous execution. 325 if self.sync: 326 interpreter.apply(uf, *args, **kwds) 327 328 # Asynchronous execution. 329 else: 330 interpreter.queue(uf, *args, **kwds)
331 332
333 - def process_doc(self, doc):
334 """Process the documentation list. 335 336 @param doc: The documentation in the form of a list of the title and description. 337 @type doc: list of str 338 """ 339 340 # The title. 341 yield doc[0], 'title' 342 343 # Split up the description. 344 docstring_lines = split(doc[1], "\n") 345 346 # Initialise. 347 text = [""] 348 type = ['desc'] 349 in_table = False 350 351 # Loop over the lines of the docstring. 352 for line in docstring_lines: 353 # Start of the table. 354 if not in_table and search('___', line): 355 in_table = True 356 text.append("") 357 type.append("table") 358 359 # Add the line to the text. 360 text[-1] = "%s%s\n" % (text[-1], line) 361 362 # End of the table. 363 if in_table and search('^\\|_', line): 364 in_table = False 365 text.append("") 366 type.append("desc") 367 368 # Yield the bits. 369 for i in range(len(text)): 370 yield text[i], type[i]
371