1 """gmResizingWidgets - Resizing widgets for use in GNUmed.
2
3 Design by Richard Terry and Ian Haywood.
4 """
5
6 __author__ = "Ian Haywood, Karsten Hilbert, Richard Terry"
7 __license__ = 'GPL v2 or later (details at http://www.gnu.org)'
8
9 import sys, logging, re as regex
10
11
12 import wx
13 import wx.stc
14
15
16 from Gnumed.pycommon import gmI18N, gmDispatcher, gmPG2
17 from Gnumed.business import gmKeywordExpansion
18 from Gnumed.wxpython import gmGuiHelpers, gmTimer
19
20 _log = logging.getLogger('gm.ui')
21
22 STYLE_ERROR=1
23 STYLE_TEXT=2
24 STYLE_EMBED=4
25
26
28 - def __init__ (self, parent, pos, size, callback):
29 wx.ListBox.__init__(self, parent, -1, pos, size, style=wx.LB_SINGLE | wx.LB_NEEDED_SB)
30 self.callback = callback
31 self.alive = 1
32 wx.EVT_LISTBOX (self, self.GetId(), self.OnList)
33
35 """
36 Sets the items, Items is a dict with label, data, weight items
37 """
38 items.sort (lambda a,b: cmp(b['weight'], a['weight']))
39 self.Clear()
40 self.Set([item['label'] for item in items])
41 n = 0
42 for item in items:
43 self.SetClientData(n, item['data'])
44
45 self.SetSelection(0)
46
48 line = self.GetSelection()
49 if line > 0:
50 self.SetSelection(line-1)
51
53 line = self.GetSelection()
54 if line < self.GetCount()-1:
55 self.SetSelection(line+1)
56
58 line = self.GetSelection()
59 if line >= 0:
60 text = self.GetString(line)
61 data = self.GetClientData(line)
62 self.callback(text, data)
63 self.alive = 2
64 self.Destroy()
65
67 event.Skip()
68 if self.alive != 2:
69 line = self.GetSelection()
70 if line >= 0:
71 text = self.GetString(line)
72 data = self.GetClientData(line)
73 self.callback (text, data)
74 self.alive = 2
75 else:
76 wx.CallAfter (self.Destroy)
77
78
80 self.alive = 0
81 wx.ListBox.Destroy (self)
82
83
84
86
87
88
90 wx.Frame.__init__(self, None, wx.NewId(), widget.__class__.__name__, pos=pos, style=wx.SIMPLE_BORDER)
91 widget.set_completion_callback(self.OnOK)
92 self.win = widget
93 self.embed_header = embed_header
94 self.originator = originator
95
96 self.__do_layout()
97
98 wx.EVT_BUTTON(self.__BTN_OK, self.__BTN_OK.GetId(), self.OnOK)
99 wx.EVT_BUTTON(self.__BTN_Cancel, self.__BTN_Cancel.GetId(), self._on_close)
100 self.win.SetFocus ()
101
103 self.__BTN_OK = wx.Button (self, -1, _("OK"), style=wx.BU_EXACTFIT)
104 self.__BTN_Cancel = wx.Button (self, -1, _("Cancel"), style=wx.BU_EXACTFIT)
105 szr_btns = wx.BoxSizer (wx.HORIZONTAL)
106 szr_btns.Add(self.__BTN_OK, 0, 0)
107 szr_btns.Add(self.__BTN_Cancel, 0, 0)
108
109 szr_main = wx.BoxSizer(wx.VERTICAL)
110 szr_main.Add(self.win, 1, wx.EXPAND, 0)
111 szr_main.Add(szr_btns, 0, wx.EXPAND)
112
113 self.SetAutoLayout(1)
114 self.SetSizer(szr_main)
115 szr_main.Fit(self)
116 szr_main.SetSizeHints(self)
117 self.Layout()
118
121
123 if self.originator:
124 self.originator.Embed ("%s: %s" % (self.embed_header, self.win.GetSummary()))
125 self.Close ()
126
129 self.text = None
130 self.data = None
131
133 """A vertically-scrolled window which allows subwindows
134 to change their size, and adjusts accordingly.
135 """
136 - def __init__ (self, parent, id, pos = wx.DefaultPosition, size = wx.DefaultSize):
137
138 wx.ScrolledWindow.__init__(self, parent, id, pos = pos, size = size, style=wx.VSCROLL)
139 self.SetScrollRate(0, 20)
140
141
142
143
144 self.__input_lines = [[]]
145 self.__szr_main = None
146 self.DoLayout()
147 self.__szr_main = wx.FlexGridSizer(len(self.__input_lines), 2)
148 for line in self.__input_lines:
149 if len(line) != 0:
150
151 if line[0]['label'] is not None:
152 self.__szr_main.Add(line[0]['label'], 1)
153 else:
154 self.__szr_main.Add((1, 1))
155
156 h_szr = wx.BoxSizer (wx.HORIZONTAL)
157 h_szr.Add(line[0]['instance'], 1, wx.EXPAND)
158 for widget in line[1:]:
159 if widget['label'] is not None:
160 h_szr.Add(widget['label'], 0)
161 h_szr.Add(widget['instance'], 1, wx.EXPAND)
162 self.__szr_main.Add(h_szr, 1, wx.EXPAND)
163 self.__szr_main.AddGrowableCol(1)
164 self.__szr_main.Add((1, 1))
165
166 self.SetSizer(self.__szr_main)
167 self.__szr_main.Fit(self)
168 self.FitInside()
169
184
186 """
187 Starts a newline on the widget
188 """
189 self.__input_lines.append([])
190
192 """
193 Overridden by descendants, this function uses AddWidget and Newline to form
194 the outline of the widget
195 """
196 _log.error('[%s] forgot to override DoLayout()' % self.__class__.__name__)
197
198 - def ReSize (self, widget, new_height):
199 """Called when a child widget has a new height, redoes the layout.
200 """
201 if self.__szr_main is not None:
202 self.__szr_main.SetItemMinSize(widget, -1, new_height)
203 self.__szr_main.FitInside(self)
204
206 """
207 Ensures widget is visible
208
209 @param widget: a child widget
210 @type cur_x: integer
211 @param cur_x: the X co-ordinate of the cursor inside widget, if applicable
212 @type cur_y: integer
213 @param cur_y: the Y co-ordinate of the cursor inside widget
214 """
215
216 x, y = widget.GetPositionTuple()
217
218 x += cur_x
219 y += cur_y
220
221 x, y = self.CalcUnscrolledPosition(x, y)
222 x_dimension, y_dimension = self.GetScrollPixelsPerUnit()
223 y = y / y_dimension
224
225 self.Scroll (-1, y)
226
228 """
229 Runs SetValue() on all the fields
230
231 @type values: dictionary
232 @param values: keys are the labels, values are passed to SetValue()
233 """
234
235 for line in self.__input_lines:
236 for widget in line:
237 if values.has_key(widget['ID']):
238 if isinstance(widget['instance'], wx.stc.StyledTextCtrl):
239 widget['instance'].SetText(values[widget['ID']])
240 elif isinstance(widget['instance'], (wx.Choice, wx.RadioBox)):
241 widget['instance'].SetSelection(values[widget['ID']])
242 else:
243 widget['instance'].SetValue(values[widget['ID']])
244
246 """Return dict of values of inner widgets.
247
248 Returns a dictionary of the results of GetValue()
249 called on all widgets, keyed by label
250 Unlabelled widgets don't get called
251 """
252
253 vals = {}
254 for line in self.__input_lines:
255 for widget in line:
256 if widget['ID'] is None:
257 continue
258 result = cSTCval()
259 if isinstance(widget['instance'], cResizingSTC):
260 result.text = widget['instance'].GetText()
261 result.data = widget['instance'].GetData()
262 elif isinstance(widget['instance'], wx.stc.StyledTextCtrl):
263 result.text = widget['instance'].GetText()
264 elif isinstance(widget['instance'], (wx.Choice, wx.RadioBox)):
265 result.selection = widget['instance'].GetSelection()
266 else:
267 result.value = widget['instance'].GetValue()
268 vals[widget['ID']] = result
269 return vals
270
272 """
273 Clears all widgets where this makes sense
274 """
275 for line in self.__input_lines:
276 for widget in line:
277 if isinstance (widget['instance'], wx.stc.StyledTextCtrl):
278 widget['instance'].ClearAll()
279 elif isinstance (widget['instance'], wx.TextCtrl):
280 widget['instance'].Clear()
281 elif isinstance (widget['instance'], (wx.ToggleButton, wx.CheckBox, wx.RadioButton, wx.Gauge)):
282 widget['instance'].SetValue(0)
283 elif isinstance (widget['instance'], (wx.Choice, wx.ComboBox, wx.RadioBox)):
284 widget['instance'].SetSelection(0)
285 elif isinstance (widget['instance'], wx.SpinCtrl):
286 widget['instance'].SetValue(widget['instance'].GetMin())
287
289
290 try:
291 self.lines[0][0]['instance'].SetFocus()
292 except IndexError:
293 pass
294 except AttributeError:
295 pass
296
297 - def GetPickList (self, callback, x_intended, y_intended):
298 """
299 Returns a pick list, destroying a pre-existing pick list for this widget
300
301 the alive member is true until the object is Destroy ()'ed
302
303 @param callback: called when a item is selected,
304 @type callback: callable
305 @param x_intended: the X-position where the list should appear
306 @type x_intended: int
307 @param x: the Y-position where the list should appear
308 @type y_intended: int
309
310 @return: PickList
311 """
312
313
314
315 our_width, our_height = self.GetSizeTuple()
316 char_height = self.GetCharHeight()
317
318 list_height = char_height * 9
319
320
321 if (list_height + char_height) > our_height:
322 list_height = our_height
323 y_final = 0
324 elif (y_intended + list_height + char_height) > our_height:
325 y_final = our_height - list_height
326 else:
327 y_final = y_intended + char_height
328
329 list_width = int(list_height / 1.4)
330 if list_width > our_width:
331 list_width = our_width
332 x_final = 0
333 elif (x_intended + list_width) > our_width:
334 x_final = our_width - list_width
335 else:
336 x_final = x_intended
337
338
339 list = cPickList(self, wx.Point(x_final, y_final), wx.Size(list_width, list_height), callback=callback)
340 return list
341
342
343
344
346 """Gets a terse summary string for the data in the widget"""
347 return ""
348
350 """
351 A StyledTextCrl that monitors the size of its internal text and
352 resizes the parent accordingly.
353
354 MUST ONLY be used inside ResizingWindow !
355
356 FIXME: override standard STC popup menu
357 """
358 - def __init__ (self, parent, id, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, data=None):
359 if not isinstance(parent, cResizingWindow):
360 raise ValueError, 'parent of %s MUST be a ResizingWindow' % self.__class__.__name__
361
362 wx.stc.StyledTextCtrl.__init__ (self, parent, id, pos, size, style)
363
364 self.SetWrapMode (wx.stc.STC_WRAP_WORD)
365
366 self.StyleSetSpec (STYLE_ERROR, "fore:#7F11010,bold")
367 self.StyleSetSpec (STYLE_EMBED, "fore:#4040B0")
368 self.StyleSetChangeable (STYLE_EMBED, 0)
369
370 self.SetEOLMode (wx.stc.STC_EOL_LF)
371
372 self.__register_interests()
373
374 self.next_in_tab_order = None
375 self.prev_in_tab_order = None
376
377 self.__parent = parent
378
379 self.__popup_keywords = {}
380
381
382
383
384
385
386 self.__matcher = None
387
388 self.__show_list = 1
389 self.__embed = {}
390 self.list = None
391 self.no_list = 0
392
393 self.__data = data
394
395 self.__keyword_separators = regex.compile("[!?'\".,:;)}\]\r\n\s\t]+")
396
397
398
400 if popup_keywords is None:
401 return
402 self.__popup_keywords = popup_keywords
403
404 - def SetText(self, text):
405 self.__show_list = 0
406 wx.stc.StyledTextCtrl.SetText(self, text)
407 self.__show_list = 1
408
409 - def ReplaceText (self, start, end, text, style=None):
410 self.replace_text(start, end, text, style)
411
412 - def Embed (self, text, data=None):
413 self.no_list = 1
414 self.ReplaceText(self.fragment_start, self.fragment_end, text+';', STYLE_EMBED)
415 self.GotoPos(self.fragment_start+len (text)+1)
416 self.SetFocus()
417
418
419 self.no_list = 0
420
422
423 end = pos+1
424 while (end < self.GetLength()) and (self.GetCharAt(end) != ord(';')):
425 end += 1
426 start = pos
427 while (start > 0) and (self.GetCharAt(start and start-1) != ord(';')):
428 start -= 1
429 self.SetTargetStart(start)
430 self.SetTargetEnd(end)
431 self.ReplaceTarget('')
432
434 """Set focus to current position in STC.
435
436 - make sure that's visible, too
437 """
438 wx.stc.StyledTextCtrl.SetFocus(self)
439
440 if line == 1:
441 if x is None:
442 x = 0
443 self.GotoPos(self.PositionFromPoint(wx.Point(x,0)))
444 return
445
446 if line == -1:
447 _log.debug('going to last line in STC')
448 last_char_pos = self.GetLength()
449 if x is None:
450 self.GotoPos(last_char_pos)
451 _log.debug('no X given, use X=%s' % last_char_pos.x)
452 return
453 y = self.PointFromPosition(last_char_pos).y
454 _log.debug('going to given X=%s' % x)
455 self.GotoPos(self.PositionFromPoint(wx.Point(x,y)))
456 return
457
458 cur = self.PointFromPosition(self.GetCurrentPos())
459 self.__parent.EnsureVisible (self, cur.x, cur.y)
460
462 """
463 Attaches a gmMatchProvider to the STC,this will be used to drive auto-completion
464 """
465 self.__matcher = matcher
466
468 """
469 Configures the data associated with this STC
470 @param data The associated data
471 @type data Any object
472 """
473 self.__data = data
474
476 """
477 Retrieves the data associated with this STC
478 """
479 return self.__data
480
481 - def replace_text(self, start=None, end=None, text=None, style=None):
482 """
483 Oddly, the otherwise very rich wx.STC API does not provide an
484 easy way to replace text, so we provide it here.
485
486 @param start: the position in the text to start from
487 @param length: the length of the string to replace
488 @param text: the new string
489 @param style: the style for the replaced string
490 """
491 self.SetTargetStart(start)
492 self.SetTargetEnd(end)
493 self.ReplaceTarget(text)
494 if style is not None:
495 self.StartStyling(start, 0xFF)
496 self.SetStyling(len(text), style)
497
521
522
523
525 self.SetModEventMask (wx.stc.STC_MOD_INSERTTEXT | wx.stc.STC_MOD_DELETETEXT | wx.stc.STC_PERFORMED_USER)
526
527 wx.stc.EVT_STC_MODIFIED (self, self.GetId(), self.__on_STC_modified)
528
529 wx.EVT_KEY_DOWN (self, self.__on_key_down)
530 wx.EVT_KEY_UP (self, self.__OnKeyUp)
531 wx.EVT_CHAR(self, self.__on_char)
532
534
535
536 if not (event.GetModificationType() & (wx.stc.STC_MOD_INSERTTEXT | wx.stc.STC_MOD_DELETETEXT)):
537 event.Skip()
538 return
539
540 last_char_pos = self.GetLength()
541
542
543 if last_char_pos == 0:
544
545 return
546
547
548 line_height = self.TextHeight(0)
549 true_txt_height = (self.PointFromPosition(last_char_pos).y - self.PointFromPosition(0).y) + line_height
550 x, visible_height = self.GetSizeTuple()
551 if visible_height < true_txt_height:
552
553
554
555
556 n, remainder = divmod((true_txt_height - visible_height), line_height)
557 if remainder > 0: n = n + 1
558 target_height = visible_height + (n * line_height)
559 self.__parent.ReSize(self, target_height)
560
561 x, y = self.GetSizeTuple()
562
563
564 if ((visible_height - line_height) > true_txt_height):
565
566
567
568
569
570
571 target_height = visible_height - line_height
572 self.__parent.ReSize(self, target_height)
573
574 x, y = self.GetSizeTuple()
575
576
577
578 fragment = self.__get_focussed_fragment()
579 if fragment in self.__popup_keywords.keys():
580
581 self.__handle_keyword(fragment)
582 return
583
584
585
586 return
587
589 """Act on some key presses we want to process ourselves."""
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635 if event.GetKeyCode() == wx.WXK_TAB:
636 if event.m_shiftDown:
637 if self.prev_in_tab_order is not None:
638 self.prev_in_tab_order.SetFocus()
639 else:
640 if self.next_in_tab_order is not None:
641 self.next_in_tab_order.SetFocus()
642 return
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666 event.Skip()
667
669 if not self.list:
670 curs_pos = self.PointFromPosition(self.GetCurrentPos())
671 self.__parent.EnsureVisible (self, curs_pos.x, curs_pos.y)
672
674
675 char = unichr(evt.GetUnicodeKey())
676
677 if self.__keyword_separators.match(char) is not None:
678 if self.GetLength() == 1:
679 evt.Skip()
680 return
681
682 line, caret_pos = self.GetCurLine()
683 word = self.__keyword_separators.split(line[:caret_pos])[-1]
684 if (word not in [ r[0] for r in gmKeywordExpansion.get_textual_expansion_keywords() ]) and (word != u'$$steffi'):
685 evt.Skip()
686 return
687
688 start = self.GetCurrentPos() - len(word)
689 wx.CallAfter(self.replace_keyword_with_expansion, word, start)
690 evt.Skip()
691 return
692
693 evt.Skip()
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
717
718 fragment = self.__get_focussed_fragment()
719 if fragment.strip() == '':
720 return 1
721
722
723 return 1
724
725
726 if self.no_list:
727 return
728 if self.__matcher is None:
729 return
730 if not self.__show_list:
731 return
732
733
734 if len(fragment) == 0:
735 if (self.list is not None) and self.list.alive:
736 self.list.Destroy()
737 return
738 matches_found, matches = self.__matcher.getMatches(fragment)
739 if not matches_found:
740 if (self.list is not None) and self.list.alive:
741 self.list.Destroy()
742 return
743 if not ((self.list is not None) and self.list.alive):
744 x, y = self.GetPositionTuple()
745 p = self.PointFromPosition(curs_pos)
746 self.list = self.__parent.GetPickList(self.__userlist, x+p.x, y+p.y)
747 self.list.SetItems(matches)
748
749
750
752 curs_pos = self.GetCurrentPos()
753 text = self.GetText()
754 self.fragment_start = text.rfind(';', 0, curs_pos)
755 if self.fragment_start == -1:
756 self.fragment_start = 0
757 else:
758 self.fragment_start += 1
759 last_char_pos = self.GetLength()
760 self.fragment_end = text.find(';', curs_pos, last_char_pos)
761 if self.fragment_end == -1:
762 self.fragment_end = last_char_pos
763 return text[self.fragment_start:self.fragment_end].strip()
764
766
767 parent_width, parent_height = self.__parent.GetSizeTuple()
768
769
770 parent_char_height = self.__parent.GetCharHeight()
771
772
773
774 popup_height = parent_char_height * 9
775
776
777 stc_origin_x, stc_origin_y = self.GetPositionTuple()
778
779
780 curs_pos = self.PointFromPosition(self.GetCurrentPos())
781
782
783
784 if (popup_height + parent_char_height) > parent_height:
785
786 popup_height = parent_height
787 popup_y_pos = 0
788 elif ((popup_height + parent_char_height) + (curs_pos.y + stc_origin_y)) > parent_height:
789
790
791 popup_y_pos = parent_height - popup_height
792 else:
793 popup_y_pos = (curs_pos.y + stc_origin_y) + parent_char_height
794
795 popup_width = int(popup_height / 1.4)
796 if popup_width > parent_width:
797
798 popup_width = parent_width
799 popup_x_pos = 0
800 elif (popup_width + (curs_pos.x + stc_origin_x)) > parent_width:
801
802
803 popup_x_pos = parent_width - popup_width
804 else:
805 popup_x_pos = curs_pos.x + stc_origin_x
806
807 return (wx.Point(popup_x_pos, popup_y_pos), wx.Size(popup_width, popup_height))
808
810 try:
811 create_widget = self.__popup_keywords[kwd]['widget_factory']
812 except KeyError:
813 gmDispatcher.send(signal='statustext', msg=_('No action configured for keyword [%s].') % kwd)
814 return False
815
816
817 screen_pos = self.ClientToScreen(self.PointFromPosition(self.GetCurrentPos()))
818 top_parent = wx.GetTopLevelParent(self)
819 best_pos = top_parent.ScreenToClient(screen_pos)
820 try:
821 popup = create_widget (
822 parent = top_parent,
823 pos = best_pos,
824 size = wx.Size(400, 300),
825 style = wx.SUNKEN_BORDER,
826 data_sink = self.__popup_keywords[kwd]['widget_data_sink']
827 )
828 except StandardError:
829 _log.exception('cannot call [%s] on keyword [%s] to create widget' % (create_widget, kwd))
830 gmGuiHelpers.gm_show_error (
831 aMessage = _('Cannot invoke [%s] for keyword [%s].') % (create_widget, kwd),
832 aTitle = _('showing keyword popup')
833 )
834 return False
835
836 if not isinstance(popup, wx.Dialog):
837 gmDispatcher.send(signal='statustext', msg=_('Action [%s] on keyword [%s] is invalid.') % (create_widget, kwd))
838 _log.error('keyword [%s] triggered action [%s]' % (kwd, create_widget))
839 _log.error('the result (%s) is not a wx.Dialog subclass instance, however' % str(popup))
840 return False
841
842
843 result = popup.ShowModal()
844 if result == wx.ID_OK:
845 summary = popup.get_summary()
846 wx.CallAfter(self.Embed, summary)
847 popup.Destroy()
848
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869 if self.MakePopup (text, data, self, self.ClientToScreen (self.PointFromPosition (self.GetCurrentPos ()))):
870 pass
871 else:
872 self.Embed (text, data)
873
875 """
876 An overrideable method, called whenever a match is made in this STC
877 Designed for producing popups, but the overrider can in fact, do
878 whatever they please.
879
880 @return True if a poup-up or similar actually happened (which suppresses inserting the match string in the text
881 @rtype boolean
882 """
883
884 return False
885
886
887 if __name__ == '__main__':
888
889
890
891
899
913
916 wx.Panel.__init__ (
917 self,
918 parent,
919 -1,
920 pos,
921 size,
922 style
923 )
924 self.__completion_callback = completion_callback
925 self._wx.ID_BTN_OK = wx.NewId()
926 self._wx.ID_BTN_Cancel = wx.NewId()
927 self.__do_layout()
928 self.__register_interests()
929 self.Show()
930
932
933 msg = "test keyword popup"
934 text = wx.StaticText (self, -1, msg)
935
936 self.btn_OK = wx.Button(self, self._wx.ID_BTN_OK, _("OK"))
937 self.btn_OK.SetToolTipString(_('dismiss popup and embed data'))
938 self.btn_Cancel = wx.Button(self, self._wx.ID_BTN_Cancel, _("Cancel"))
939 self.btn_Cancel.SetToolTipString(_('dismiss popup and throw away data'))
940 szr_buttons = wx.BoxSizer(wx.HORIZONTAL)
941 szr_buttons.Add(self.btn_OK, 1, wx.EXPAND | wx.ALL, 1)
942 szr_buttons.Add(5, 0, 0)
943 szr_buttons.Add(self.btn_Cancel, 1, wx.EXPAND | wx.ALL, 1)
944
945 szr_main = wx.BoxSizer(wx.VERTICAL)
946 szr_main.Add(text, 1, wx.EXPAND | wx.ALL, 1)
947 szr_main.Add(szr_buttons, 0)
948
949 self.SetAutoLayout(True)
950 self.SetSizer(szr_main)
951 szr_main.Fit(self)
952
954 wx.EVT_BUTTON(self.btn_OK, self._wx.ID_BTN_OK, self._on_ok)
955 wx.EVT_BUTTON(self.btn_Cancel, self._wx.ID_BTN_Cancel, self._on_cancel)
956
958 self.__completion_callback(was_cancelled = False)
959
961 self.__completion_callback(was_cancelled = True)
962
972
975 self.input1 = cResizingSTC(self, -1)
976 self.input2 = cResizingSTC(self, -1)
977 self.input3 = cResizingSTC(self, -1)
978
979 self.input1.prev_in_tab_order = None
980 self.input1.next_in_tab_order = self.input2
981 self.input2.prev_in_tab_order = self.input1
982 self.input2.next_in_tab_order = self.input3
983 self.input3.prev_in_tab_order = self.input2
984 self.input3.next_in_tab_order = None
985
986 self.AddWidget (widget=self.input1, label="S")
987 self.Newline()
988 self.AddWidget (widget=self.input2, label="O")
989 self.Newline()
990 self.AddWidget (widget=self.input3, label="A+P")
991
992 kwds = {}
993 kwds['$test_keyword'] = {'widget_factory': create_widget_on_test_kwd3}
994 self.input2.set_keywords(popup_keywords=kwds)
995
998 wx.Panel.__init__(self, parent, id)
999 sizer = wx.BoxSizer(wx.VERTICAL)
1000 self.soap = cSoapWin(self, -1)
1001 self.save = wx.Button (self, -1, _(" Save "))
1002 self.delete = wx.Button (self, -1, _(" Delete "))
1003 self.new = wx.Button (self, -1, _(" New "))
1004
1005 wx.EVT_BUTTON (self.save, self.save.GetId (), self.OnSave)
1006 wx.EVT_BUTTON (self.delete, self.delete.GetId (), self.OnDelete)
1007 wx.EVT_BUTTON (self.new, self.new.GetId (), self.OnNew)
1008
1009 self.__do_layout()
1010
1012 sizer_1 = wx.BoxSizer(wx.VERTICAL)
1013 sizer_1.Add(self.soap, 3, wx.EXPAND, 0)
1014 sizer_2 = wx.BoxSizer (wx.HORIZONTAL)
1015 sizer_2.Add(self.save, 0, 0)
1016 sizer_2.Add(self.delete, 0, 0)
1017 sizer_2.Add(self.new, 0, 0)
1018 sizer_1.Add(sizer_2, 0, wx.EXPAND)
1019
1020 self.SetAutoLayout(1)
1021 self.SetSizer(sizer_1)
1022 sizer_1.Fit(self)
1023 sizer_1.SetSizeHints(self)
1024 self.Layout()
1025
1028
1029
1030
1031
1032 - def OnNew (self, event):
1037
1038
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1055 wx.Frame.__init__ (self, None, wx.NewId(), "test SOAP", size = wx.Size (350, 500))
1056 wx.EVT_CLOSE (self, self.OnClose)
1057 panel = cSoapPanel(self, -1)
1058 sizer = wx.BoxSizer(wx.VERTICAL)
1059 sizer.Add (panel, 1, wx.GROW)
1060 self.SetSizer(sizer)
1061 self.SetAutoLayout(1)
1062 sizer.Fit (self)
1063 self.Layout ()
1064
1067
1070 self.frame = testFrame ("testFrame")
1071 self.frame.Show()
1072 return 1
1073
1074 app = testApp(0)
1075 app.MainLoop()
1076
1077