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