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