1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """Module containing the special objects for auto-generating the GUI user functions and classes."""
24
25
26 from re import search
27 import wx
28 from wx.lib import scrolledpanel
29 import sys
30
31
32 import lib.arg_check
33 from graphics import fetch_icon
34 from gui.components.free_file_format import Free_file_format
35 from gui.components.menu import build_menu_item
36 from gui.errors import gui_raise
37 from gui.fonts import font
38 from gui.input_elements.bool import Selector_bool
39 from gui.input_elements.dir import Selector_dir
40 from gui.input_elements.file import Selector_file, Selector_file_multiple
41 from gui.input_elements.sequence import Sequence
42 from gui.input_elements.sequence_2D import Sequence_2D
43 from gui.input_elements.spin_id import Spin_id
44 from gui.input_elements.value import Value
45 from gui.interpreter import Interpreter; interpreter = Interpreter()
46 from gui.misc import format_table
47 from gui.wizards.wiz_objects import Wiz_page, Wiz_window
48 from lib.errors import AllRelaxErrors, RelaxError
49 from lib.text.string import strip_lead
50 from status import Status; status = Status()
51 from user_functions.data import Uf_info; uf_info = Uf_info()
52 from user_functions.data import Uf_tables; uf_tables = Uf_tables()
53
54
56 """Auto-generate the user function sub-menu.
57
58 @keyword parent: The parent window to bind the events to.
59 @type parent: wx instance
60 @keyword menubar: The menubar to attach the user function menus to.
61 @type menubar: wx.MenuBar instance
62 @return: The menu ID.
63 @rtype: int
64 """
65
66
67 menu1 = wx.Menu()
68 menu2 = wx.Menu()
69
70
71 pattern = '^[a-m]'
72
73
74 class_list = []
75 uf_store = Uf_storage()
76
77
78 class_item = None
79 menu = menu1
80 menu_index = 0
81 for name, data in uf_info.uf_loop():
82
83 if search('\.', name):
84 class_name, uf_name = name.split('.')
85 else:
86 class_name = None
87
88
89 if class_name:
90 if class_name not in class_list:
91
92 if class_item != None:
93 menu.AppendItem(class_item)
94
95
96 class_data = uf_info.get_class(class_name)
97
98
99 class_id = wx.NewId()
100
101
102 class_item = build_menu_item(menu, id=class_id, text=class_data.menu_text, icon=fetch_icon(class_data.gui_icon, size='16x16'))
103
104
105 sub_menu = wx.Menu()
106 class_item.SetSubMenu(sub_menu)
107
108
109 class_list.append(class_name)
110
111
112 sub_menu.AppendItem(build_menu_item(sub_menu, id=uf_store[name]._uf_id, text=data.menu_text, icon=fetch_icon(data.gui_icon, size='16x16')))
113
114
115 else:
116
117 if class_item != None:
118 menu.AppendItem(class_item)
119 class_item = None
120
121
122 menu.AppendItem(build_menu_item(menu, id=uf_store[name]._uf_id, text=data.menu_text, icon=fetch_icon(data.gui_icon, size='16x16')))
123
124
125 if menu_index == 0 and not search(pattern, name):
126 menu = menu2
127 menu_index = 1
128
129
130 parent.Bind(wx.EVT_MENU, parent.uf_call, id=uf_store[name]._uf_id)
131
132
133 if class_item != None:
134 menu.AppendItem(class_item)
135
136
137 title1 = "&User functions (a-m)"
138 title2 = "&User functions (n-z)"
139 menubar.Append(menu1, title1)
140 menubar.Append(menu2, title2)
141
142
143 return [menubar.FindMenu(title1), menubar.FindMenu(title2)]
144
145
146
148 """A special user function arg element which always returns True."""
149
151 """Initialise the object."""
152
153
154 self._value = True
155
156
158 """Simple method for returning the internal value."""
159
160
161 return self._value
162
163
165 """Internally store the value being set."""
166
167
168 self._value = value
169
170
171
173 """The object for auto-generating the GUI user functions."""
174
175 - def __call__(self, event=None, wx_parent=None, wx_wizard_sync=None, wx_wizard_run=True, wx_wizard_modal=False, **kwds):
176 """Make the GUI user function executable.
177
178 All keyword args, apart from 'event', 'wx_parent' and 'wx_wizard_run' will be assumed to be user function arguments and the Uf_page.SetValue() method of the page will be used to set the GUI arg elements to the values supplied.
179
180
181 @keyword event: The wx event.
182 @type event: wx event or None
183 @keyword wx_parent: The parent wx object to associate the user function wizard to.
184 @type wx_parent: wx object
185 @keyword wx_wizard_sync: A flag which if given will switch between synchronous and asynchronous user function operation.
186 @type wx_wizard_sync: None or bool
187 @keyword wx_wizard_run: A flag which if True will call the wizard run() method.
188 @type wx_wizard_run: bool
189 @keyword wx_wizard_modal: A flag which if True will cause the wizard run() method to have the modal flag set so that the wizard is modal.
190 @type wx_wizard_modal: bool
191 @return: The status of the call. If the call failed, False will be returned.
192 @rtype: bool
193 """
194
195
196 if wx_wizard_sync != None:
197 self._sync = wx_wizard_sync
198
199
200 if self.wizard == None or (wx_parent != None and wx_parent != self.wizard.GetParent()) or self.wizard._pages[0] == None:
201 status = self.create_wizard(wx_parent)
202 if not status:
203 return False
204
205
206 else:
207 self.wizard.reset()
208
209
210 if not self.page.update_args():
211 return False
212
213
214 for key in kwds:
215 self.page.SetValue(key, kwds[key])
216
217
218 if wx_wizard_run:
219 self.wizard.run(modal=wx_wizard_modal)
220
221
222 - def __init__(self, name, title=None, size=None, height_desc=None, apply_button=True, sync=False):
223 """Set up the object.
224
225 @param name: The name of the user function.
226 @type name: str
227 @keyword title: The long title of the user function to set as the window title.
228 @type title: str
229 @keyword size: The window size.
230 @type size: tuple of int
231 @keyword height_desc: The height in pixels of the description part of the wizard.
232 @type height_desc: int or None
233 @keyword apply_button: A flag specifying if the apply button should be shown or not. This defaults to True.
234 @type apply_button: bool
235 @keyword sync: A flag which if True will call user functions via interpreter.apply and if False via interpreter.queue.
236 @type sync: bool
237 """
238
239
240 self._name = name
241 self._title = title
242 self._size = size
243 self._height_desc = height_desc
244 self._apply_button = apply_button
245 self._sync = sync
246
247
248 self.wizard = None
249
250
251 self._uf_id = wx.NewId()
252
253
254 - def create_page(self, wizard=None, sync=None, execute=True):
255 """Create the user function wizard page GUI object.
256
257 @keyword wizard: The parent wizard.
258 @type wizard: Wiz_window instance
259 @keyword sync: A flag which if True will call user functions via interpreter.apply and if False via interpreter.queue.
260 @type sync: None or bool
261 @keyword execute: A flag which if True will prevent the user function from being executed when clicking on 'Next', 'Ok', or 'Apply'. This can be useful for delaying the execution of the user function.
262 @type execute: bool
263 @return: The user function page object.
264 @rtype: Uf_page instance
265 """
266
267
268 if sync != None:
269 self._sync = sync
270
271
272 return Uf_page(self._name, parent=wizard, height_desc=self._height_desc, sync=self._sync, execute=execute)
273
274
276 """Create the user function wizard GUI object, with embedded wizard page.
277
278 @keyword parent: The parent wx window.
279 @type parent: wx.Window instance
280 @return: True if the wizard was created, False if a problem was encountered.
281 @rtype: bool
282 """
283
284
285 if parent == None:
286 app = wx.GetApp()
287 parent = app.gui
288
289
290 self.wizard = Wiz_window(parent=parent, size_x=self._size[0], size_y=self._size[1], title=self._title)
291
292
293 self.page = self.create_page(self.wizard, sync=self._sync)
294
295
296 if not self.page.update_args():
297 return False
298
299
300 self.wizard.add_page(self.page, apply_button=self._apply_button)
301
302
303 return True
304
305
306
307 -class Uf_page(Wiz_page):
308 """User function specific pages for the wizards."""
309
310 - def __init__(self, name, parent=None, height_desc=220, sync=False, execute=True):
311 """Set up the window.
312
313 @param name: The name of the user function.
314 @type name: str
315 @keyword parent: The parent class containing the GUI.
316 @type parent: class instance
317 @keyword height_desc: The height in pixels of the description part of the wizard.
318 @type height_desc: int or None
319 @keyword sync: A flag which if True will call user functions via interpreter.apply and if False via interpreter.queue.
320 @type sync: bool
321 @keyword execute: A flag which if True will prevent the user function from being executed when clicking on 'Next', 'Ok', or 'Apply'. This can be useful for delaying the execution of the user function.
322 @type execute: bool
323 """
324
325
326 self.name = name
327 self.sync = sync
328 self.execute_flag = execute
329
330
331 self.uf_args = {}
332
333
334 wx.Yield()
335
336
337 wx.BeginBusyCursor()
338
339
340 self.uf_data = uf_info.get_uf(name)
341
342
343 self.image_path = self.uf_data.wizard_image
344
345
346 if self.uf_data.title_short != None:
347 self.title = self.uf_data.title_short
348 else:
349 self.title = self.uf_data.title
350
351
352 super(Uf_page, self).__init__(parent, height_desc=height_desc)
353
354
355 if wx.IsBusy():
356 wx.EndBusyCursor()
357
358
360 """Format the text by stripping whitespace.
361
362 @param text: The text to strip.
363 @type text: str
364 @return: The stripped text.
365 @rtype: str
366 """
367
368
369 stripped_text = strip_lead(text)
370
371
372 while True:
373 if stripped_text[0] == "\n":
374 stripped_text = stripped_text[1:]
375 else:
376 break
377
378
379 while True:
380 if stripped_text[-1] == "\n":
381 stripped_text = stripped_text[:-1]
382 else:
383 break
384
385
386 return stripped_text
387
388
389 - def _intro_text(self, keys, values, prompt=True):
390 """Build and return the user function intro text.
391
392 @param keys: The user function keys.
393 @type keys: list of str
394 @param values: The values corresponding to the keys.
395 @type values: list
396 @keyword prompt: A flag which if True will cause the prompt text to be included.
397 @type prompt: bool
398 @return: The user function intro text.
399 @rtype: str
400 """
401
402
403 text = ""
404
405
406 if prompt:
407 text += status.ps3
408
409
410 text += "%s(" % self.name
411
412
413 for i in range(len(keys)):
414
415 if i >= 1:
416 text += ", "
417
418
419 text += "%s=%s" % (keys[i], repr(values[i]))
420
421
422 text += ")"
423
424
425 return text
426
427
428 - def Clear(self, key):
429 """Special wizard method for clearing the value of the GUI element corresponding to the key.
430
431 @param key: The key corresponding to the desired GUI element.
432 @type key: str
433 """
434
435
436 self.uf_args[key].Clear()
437
438
439 - def GetValue(self, key):
440 """Special wizard method for getting the value of the GUI element corresponding to the key.
441
442 @param key: The key corresponding to the desired GUI element.
443 @type key: str
444 @return: The value that the specific GUI element's GetValue() method returns.
445 @rtype: unknown
446 """
447
448
449 if key not in self.uf_args.keys():
450 return None
451
452
453 return self.uf_args[key].GetValue()
454
455
456 - def SetValue(self, key, value):
457 """Special wizard method for setting the value of the GUI element corresponding to the key.
458
459 @param key: The key corresponding to the desired GUI element.
460 @type key: str
461 @param value: The value that the specific GUI element's SetValue() method expects.
462 @type value: unknown
463 """
464
465
466 arg = None
467 for i in range(len(self.uf_data.kargs)):
468 if self.uf_data.kargs[i]['name'] == key:
469 arg = self.uf_data.kargs[i]
470
471
472 if arg == None:
473 raise RelaxError("The key '%s' is unknown." % key)
474
475
476 if 'free_file_format' in self.uf_args and key in ['spin_id_col', 'mol_name_col', 'res_num_col', 'res_name_col', 'spin_num_col', 'spin_name_col', 'data_col', 'error_col', 'sep']:
477 self.uf_args['free_file_format'].SetValue(key, value)
478
479
480 elif arg['arg_type'] in ['func', 'func args']:
481 pass
482
483
484 else:
485 self.uf_args[key].SetValue(value)
486
487
488 - def UpdateChoices(self, key, combo_choices=None, combo_data=None, combo_default=None):
489 """Special user function page method for updating the list of choices in a ComboBox type element.
490
491 @param key: The key corresponding to the desired GUI element.
492 @type key: str
493 @keyword combo_choices: The list of choices to present to the user. This is only used if the element_type is set to 'combo'.
494 @type combo_choices: list of str
495 @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.
496 @type combo_data: list
497 @keyword combo_default: The default value of the ComboBox. This is only used if the element_type is set to 'combo'.
498 @type combo_default: str or None
499 """
500
501
502 self.uf_args[key].UpdateChoices(combo_choices=combo_choices, combo_data=combo_data, combo_default=combo_default)
503
504
505 - def add_contents(self, sizer):
506 """Add the specific GUI elements.
507
508 @param sizer: A sizer object.
509 @type sizer: wx.Sizer instance
510 """
511
512
513 free_format = False
514 free_format_data = False
515
516
517 for i in range(len(self.uf_data.kargs)):
518
519 arg = self.uf_data.kargs[i]
520
521
522 desc = "The %s:" % arg['desc_short']
523
524
525 if arg['arg_type'] == 'file sel':
526 self.uf_args[arg['name']] = Selector_file(name=arg['name'], parent=self, default=arg['default'], sizer=sizer, desc=desc, wildcard=arg['wiz_filesel_wildcard'], style=arg['wiz_filesel_style'], tooltip=arg['desc'], divider=self._div_left, height_element=self.height_element, preview=arg['wiz_filesel_preview'], read_only=arg['wiz_read_only'])
527
528
529 elif arg['arg_type'] == 'file sel multi':
530 self.uf_args[arg['name']] = Selector_file_multiple(name=arg['name'], parent=self, default=arg['default'], sizer=sizer, desc=desc, wildcard=arg['wiz_filesel_wildcard'], style=arg['wiz_filesel_style'], tooltip=arg['desc'], divider=self._div_left, height_element=self.height_element, preview=arg['wiz_filesel_preview'], read_only=arg['wiz_read_only'])
531
532
533 elif arg['arg_type'] == 'dir':
534 pass
535
536
537 elif arg['arg_type'] == 'dir sel':
538 self.uf_args[arg['name']] = Selector_dir(name=arg['name'], parent=self, default=arg['default'], sizer=sizer, desc=desc, style=arg['wiz_dirsel_style'], tooltip=arg['desc'], divider=self._div_left, height_element=self.height_element, read_only=arg['wiz_read_only'])
539
540
541 elif arg['arg_type'] == 'free format':
542
543 free_format = True
544 if arg['name'] == 'data_col':
545 free_format_data = True
546
547
548 elif arg['arg_type'] in ['func', 'func args']:
549 pass
550
551
552 elif arg['arg_type'] in ['force flag']:
553 self.uf_args[arg['name']] = Force_true()
554
555
556 elif arg['arg_type'] in ['spin ID']:
557 self.uf_args[arg['name']] = Spin_id(name=arg['name'], parent=self, default=arg['default'], element_type=arg['wiz_element_type'], sizer=sizer, desc=desc, combo_choices=arg['wiz_combo_choices'], combo_data=arg['wiz_combo_data'], tooltip=arg['desc'], divider=self._div_left, height_element=self.height_element, can_be_none=arg['can_be_none'])
558
559
560 elif arg['py_type'] in ['float', 'int', 'num', 'str']:
561 self.uf_args[arg['name']] = Value(name=arg['name'], parent=self, default=arg['default'], element_type=arg['wiz_element_type'], value_type=arg['py_type'], min=arg['min'], max=arg['max'], sizer=sizer, desc=desc, combo_choices=arg['wiz_combo_choices'], combo_data=arg['wiz_combo_data'], tooltip=arg['desc'], divider=self._div_left, height_element=self.height_element, read_only=arg['wiz_read_only'], can_be_none=arg['can_be_none'])
562
563
564 elif arg['py_type'] == 'bool':
565 self.uf_args[arg['name']] = Selector_bool(name=arg['name'], parent=self, element_type=arg['wiz_element_type'], sizer=sizer, desc=desc, tooltip=arg['desc'], default=arg['default'], divider=self._div_left, height_element=self.height_element)
566
567
568 elif arg['py_type'] in ['float_list', 'int_list', 'num_list', 'str_list', 'float_tuple', 'int_tuple', 'num_tuple', 'str_tuple', 'float_array', 'int_array', 'float_or_float_list', 'int_or_int_list', 'num_or_num_list', 'str_or_str_list', 'float_or_float_tuple', 'int_or_int_tuple', 'num_or_num_tuple', 'str_or_str_tuple', 'val_or_list', 'float_object']:
569
570 if arg['py_type'] in ['float_list', 'int_list', 'num_list', 'str_list', 'float_array', 'int_array', 'float_or_float_list', 'int_or_int_list', 'num_or_num_list', 'str_or_str_list', 'val_or_list', 'float_object']:
571 seq_type = 'list'
572 else:
573 seq_type = 'tuple'
574
575
576 if arg['py_type'] in ['float_list', 'num_list', 'float_tuple', 'num_tuple', 'float_array', 'float_or_float_list', 'num_or_num_list', 'float_or_float_tuple', 'num_or_num_tuple', 'float_object']:
577 value_type = 'float'
578 elif arg['py_type'] in ['int_list', 'int_tuple', 'int_array', 'int_or_int_list', 'int_or_int_tuple']:
579 value_type = 'int'
580 elif arg['py_type'] in ['str_list', 'str_tuple', 'str_array', 'str_or_str_list', 'str_or_str_tuple']:
581 value_type = 'str'
582 else:
583 value_type = None
584
585
586 single_value = False
587 if arg['py_type'] in ['float_or_float_list', 'int_or_int_list', 'num_or_num_list', 'str_or_str_list', 'float_or_float_tuple', 'int_or_int_tuple', 'num_or_num_tuple', 'str_or_str_tuple', 'val_or_list']:
588 single_value = True
589
590
591 dim = None
592 if isinstance(arg['dim'], int):
593 dim = arg['dim']
594
595 self.uf_args[arg['name']] = Sequence(name=arg['name'], parent=self, default=arg['default'], element_type=arg['wiz_element_type'], seq_type=seq_type, value_type=value_type, dim=dim, min=arg['min'], max=arg['max'], titles=arg['list_titles'], sizer=sizer, desc=desc, combo_choices=arg['wiz_combo_choices'], combo_data=arg['wiz_combo_data'], combo_list_min=arg['wiz_combo_list_min'], tooltip=arg['desc'], single_value=single_value, divider=self._div_left, height_element=self.height_element, read_only=arg['wiz_read_only'], can_be_none=arg['can_be_none'])
596
597
598 elif arg['py_type'] in ['float_list_of_lists', 'int_list_of_lists', 'num_list_of_lists', 'str_list_of_lists', 'float_tuple_of_tuples', 'int_tuple_of_tuples', 'num_tuple_of_tuples', 'str_tuple_of_tuples', 'float_matrix', 'int_matrix', 'list_val_or_list_of_list_val']:
599
600 if arg['py_type'] in ['float_list_of_lists', 'int_list_of_lists', 'num_list_of_lists', 'str_list_of_lists', 'float_matrix', 'int_matrix', 'list_val_or_list_of_list_val']:
601 seq_type = 'list'
602 else:
603 seq_type = 'tuple'
604
605
606 if arg['py_type'] in ['float_list_of_lists', 'float_tuple_of_tuples', 'num_list_of_lists', 'num_tuple_of_tuples', 'float_matrix', 'list_val_or_list_of_list_val']:
607 value_type = 'float'
608 elif arg['py_type'] in ['int_list_of_lists', 'int_tuple_of_tuples', 'int_matrix']:
609 value_type = 'int'
610 else:
611 value_type = 'str'
612
613 self.uf_args[arg['name']] = Sequence_2D(name=arg['name'], parent=self, default=arg['default'], sizer=sizer, element_type=arg['wiz_element_type'], seq_type=seq_type, value_type=value_type, dim=arg['dim'], min=arg['min'], max=arg['max'], titles=arg['list_titles'], desc=desc, combo_choices=arg['wiz_combo_choices'], combo_data=arg['wiz_combo_data'], combo_list_min=arg['wiz_combo_list_min'], tooltip=arg['desc'], divider=self._div_left, height_element=self.height_element, read_only=arg['wiz_read_only'], can_be_none=arg['can_be_none'])
614
615
616 else:
617 raise RelaxError("The Python object type '%s' cannot be handled." % arg['py_type'])
618
619
620 if free_format:
621 self.uf_args['free_file_format'] = Free_file_format(parent=self, sizer=sizer, element_type='mini', data_cols=free_format_data, divider=self._div_left, height_element=self.height_element, padding=0, spacer=None)
622
623
624 - def add_desc(self, sizer, max_y=220):
625 """Add the description to the dialog.
626
627 @param sizer: A sizer object.
628 @type sizer: wx.Sizer instance
629 @keyword max_y: The maximum height, in number of pixels, for the description.
630 @type max_y: int
631 """
632
633
634 spacing = 15
635
636
637 sizer.AddSpacer(5)
638 sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0)
639 sizer.AddSpacer(5)
640
641
642 panel = scrolledpanel.ScrolledPanel(self, -1, name="desc")
643
644
645 panel_sizer = wx.BoxSizer(wx.VERTICAL)
646
647
648 tot_y = 0
649 text_elements = []
650 text_types = []
651
652
653 name = "The %s user function" % self.name
654 text = wx.StaticText(panel, -1, name, style=wx.TE_MULTILINE)
655 text.SetFont(font.subtitle)
656 text_elements.append(text)
657 text_types.append('title')
658
659
660 x, y = text.GetSizeTuple()
661 tot_y += y
662 tot_y += spacing
663
664
665 if self.uf_data.title:
666
667 text = wx.StaticText(panel, -1, self.uf_data.title, style=wx.TE_MULTILINE)
668
669
670 text.SetFont(font.normal_italic)
671
672
673 x, y = text.GetSizeTuple()
674 tot_y += y
675
676
677 tot_y += spacing
678
679
680 text_elements.append(text)
681 text_types.append('synopsis')
682
683
684 if self.uf_data.desc != None:
685
686 for i in range(len(self.uf_data.desc)):
687
688 desc = self.uf_data.desc[i]
689
690
691 if desc.get_title() == 'Prompt examples':
692 continue
693
694
695 for type, element in desc.element_loop(title=True):
696
697 text = ''
698 if isinstance(element, str):
699 text = element
700
701
702 if type == 'table':
703 text = format_table(uf_tables.get_table(element))
704
705
706 elif type == 'list':
707
708 for j in range(len(element)):
709 text += " - %s\n" % element[j]
710
711
712 elif type == 'item list':
713
714 for j in range(len(element)):
715
716 if element[j][0] in [None, '']:
717 text += " %s\n" % element[j][1]
718 else:
719 text += " %s: %s\n" % (element[j][0], element[j][1])
720
721
722 elif type == 'prompt':
723 for j in range(len(element)):
724 text += "%s\n" % element[j]
725
726
727 text_obj = wx.StaticText(panel, -1, text, style=wx.TE_MULTILINE)
728
729
730 if type == 'title':
731 text_obj.SetFont(font.subtitle)
732 elif type == 'paragraph':
733 text_obj.SetFont(font.normal)
734 elif type in ['table', 'verbatim', 'prompt']:
735 text_obj.SetFont(font.modern_small)
736 else:
737 text_obj.SetFont(font.normal)
738
739
740 if type in ['paragraph', 'list', 'item list']:
741 text_obj.Wrap(self._main_size - 20)
742
743
744 x, y = text_obj.GetSizeTuple()
745 tot_y += y
746
747
748 tot_y += spacing
749
750
751 if i != 0 and type == 'title':
752 tot_y += spacing
753
754
755 text_elements.append(text_obj)
756 text_types.append(type)
757
758
759 tot_y -= spacing
760 tot_y += 20
761
762
763 if tot_y > max_y:
764 panel.SetInitialSize((self._main_size, max_y))
765
766
767 else:
768 panel.SetInitialSize((self._main_size, tot_y))
769
770
771 n = len(text_elements)
772 for i in range(n):
773
774 if i > 1 and text_types[i] == 'title':
775 panel_sizer.AddSpacer(spacing)
776
777
778 panel_sizer.Add(text_elements[i], 0, wx.ALIGN_LEFT, 0)
779
780
781 if i != n - 1:
782 panel_sizer.AddSpacer(spacing)
783
784
785 panel.SetSizer(panel_sizer)
786 panel.SetAutoLayout(1)
787 panel.SetupScrolling(scroll_x=False, scroll_y=True)
788 sizer.Add(panel, 0, wx.ALL|wx.EXPAND)
789
790
791 sizer.AddSpacer(5)
792 sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 0)
793 sizer.AddSpacer(5)
794
795
796 - def execute(self, uf, *args, **kwds):
797 """Execute the user function, either asynchronously or synchronously.
798
799 @param uf: The user function as a string.
800 @type uf: str
801 @param args: The user function arguments.
802 @type args: any arguments
803 @param kwds: The user function keyword arguments.
804 @type kwds: any keyword arguments
805 """
806
807
808 if self.sync or status.gui_uf_force_sync:
809 return_status = interpreter.apply(uf, *args, **kwds)
810 return return_status
811
812
813 else:
814 interpreter.queue(uf, *args, **kwds)
815 return True
816
817
819 """Remove this page from the observers."""
820
821
822 status.observers.gui_uf.unregister(self.name)
823
824
825 - def on_display(self):
826 """Clear and update the data if needed."""
827
828
829 status.observers.gui_uf.register(self.name, self.update_args, method_name='update_args')
830
831
832 return self.update_args()
833
834
835 - def on_execute(self, force_exec=False):
836 """Execute the user function.
837
838 @keyword force_exec: A flag which if True will cause the execution flag to be ignored and the user function to be executed.
839 @type force_exec: bool
840 """
841
842
843 if not force_exec and not self.execute_flag:
844 return
845
846
847 kargs = {}
848 for i in range(len(self.uf_data.kargs)):
849
850 name = self.uf_data.kargs[i]['name']
851
852
853 kargs[name] = self.GetValue(name)
854
855
856 if self.uf_data.kargs[i]['wiz_combo_list_min'] != None and kargs[name] == None:
857 return True
858
859
860 if 'free_file_format' in self.uf_args:
861 kargs.update(self.uf_args['free_file_format'].GetValue())
862
863
864 if self.uf_data.display:
865
866 app = wx.GetApp()
867
868
869 app.gui.show_controller(None)
870
871
872 app.gui.controller.log_panel.on_goto_end(None)
873
874
875 if status.uf_intro:
876
877 keys = []
878 values = []
879 for i in range(len(self.uf_data.kargs)):
880 keys.append(self.uf_data.kargs[i]['name'])
881 values.append(kargs[self.uf_data.kargs[i]['name']])
882
883
884 print(self._intro_text(keys, values))
885
886
887 return_status = self.execute(self.name, **kargs)
888
889
890 if status.show_gui and self.uf_data.display:
891 wx.CallAfter(app.gui.controller.Raise)
892
893
894 return return_status
895
896
898 """Remove this page from the observers."""
899
900
901 status.observers.gui_uf.unregister(self.name)
902
903
904 - def update_args(self):
905 """Update all the argument ComboBox choices.
906
907 @return: The status of the update - False if a RelaxError occurs, True otherwise.
908 @rtype: bool
909 """
910
911
912 for i in range(len(self.uf_data.kargs)):
913
914 name = self.uf_data.kargs[i]['name']
915
916
917 iterator = self.uf_data.kargs[i]['wiz_combo_iter']
918 if iterator == None:
919 continue
920
921
922 try:
923 choices = []
924 data = []
925 for vals in iterator():
926 if lib.arg_check.is_tuple(vals, size=2, raise_error=False) or lib.arg_check.is_list(vals, size=2, raise_error=False):
927 choices.append(vals[0])
928 data.append(vals[1])
929 else:
930 choices.append(vals)
931 data.append(vals)
932
933
934 except AllRelaxErrors:
935 instance = sys.exc_info()[1]
936
937
938 self.setup_fail = True
939
940
941 gui_raise(instance)
942
943
944 return False
945
946
947 val = self.uf_args[name].GetValue()
948
949
950 self.UpdateChoices(name, combo_choices=choices, combo_data=data, combo_default=val)
951
952
953 return True
954
955
956
958 """A singleton container for holding all the GUI user functions."""
959
960
961 _instance = None
962
963 - def __new__(self, *args, **kargs):
986
987
989 """Return the name of the user function corresponding to the given wx ID.
990
991 @keyword id: The unique wx ID number.
992 @type id: int
993 @return: The name of the user function.
994 @rtype: str
995 """
996
997
998 for name in self.keys():
999 if self[name]._uf_id == id:
1000 return name
1001