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