| Home | Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding: utf-8 -*-
2 __doc__ = """GNUmed StyledTextCtrl subclass for SOAP editing.
3
4 based on: 11/21/2003 - Jeff Grimmett (grimmtooth@softhome.net)"""
5 #================================================================
6 __author__ = "K. Hilbert <Karsten.Hilbert@gmx.net>"
7 __license__ = "GPL v2 or later (details at http://www.gnu.org)"
8
9 import logging
10 import sys
11
12
13 import wx
14 import wx.stc
15
16
17 if __name__ == '__main__':
18 sys.path.insert(0, '../../')
19 from Gnumed.business import gmSoapDefs
20 from Gnumed.wxpython import gmKeywordExpansionWidgets
21 from Gnumed.wxpython.gmTextCtrl import cUnicodeInsertion_TextCtrlMixin
22
23
24 _log = logging.getLogger('gm.stc')
25
26 #================================================================
28
30 if not isinstance(self, wx.stc.StyledTextCtrl):
31 raise TypeError('[%s]: can only be applied to wx.stc.StyledTextCtrl, not [%s]' % (cWxTextCtrlCompatibility_StcMixin, self.__class__.__name__))
32
33 #--------------------------------------------------
34 # wx.TextCtrl compatibility
35 #--------------------------------------------------
37 _log.debug('%s.GetValue() - %s', cWxTextCtrlCompatibility_StcMixin, self.__class__.__name__)
38 return self.GetText()
39
40 #--------------------------------------------------
42 _log.debug('%s.SetValue() - %s', cWxTextCtrlCompatibility_StcMixin, self.__class__.__name__)
43 return self.SetText(value)
44
45 #--------------------------------------------------
48
49 #--------------------------------------------------
52
53 LastPosition = property(GetLastPosition, lambda x:x)
54
55 #--------------------------------------------------
58
59 #--------------------------------------------------
62
63 #--------------------------------------------------
66
69
70 InsertionPoint = property(GetInsertionPoint, SetInsertionPoint)
71
72 #--------------------------------------------------
74 #self.ScrollToLine(self.LineFromPosition(position))
75 self.CurrentPos = position
76 self.EnsureCaretVisible()
77
78 #--------------------------------------------------
81
82 #--------------------------------------------------
84 try:
85 #return wx.stc.StyledTextCtrl.PositionToXY(position) # does not work
86 #return wx.TextAreaBase.PositionToXY(position) # does not work
87 return super(wx.TextAreaBase, self).PositionToXY(position)
88 except AttributeError:
89 # reimplement for wxPython 2.8,
90 # this is moot now, hwoever, since 2.8 returned an (x, y) tuple
91 return (True, self.GetColumn(position), self.LineFromPosition(position))
92
93 #--------------------------------------------------
95 self.SetSelection(start, end)
96 self.ReplaceSelection(replacement)
97 wx.CallAfter(self.SetSelection, 0, 0)
98
99 #----------------------------------------------------------------------
100 -class cSoapSTC(cUnicodeInsertion_TextCtrlMixin, gmKeywordExpansionWidgets.cKeywordExpansion_TextCtrlMixin, cWxTextCtrlCompatibility_StcMixin, wx.stc.StyledTextCtrl):
101
102 _MARKER_ADM = 0
103 _MARKER_S = 1
104 _MARKER_O = 2
105 _MARKER_A = 3
106 _MARKER_P = 4
107 _MARKER_U = 5
108 _MARKER_LINE_BG_LIGHT_GREY = 31
109
110 _DEFINED_MARKERS_MASK = (
111 _MARKER_ADM
112 |
113 _MARKER_S
114 |
115 _MARKER_O
116 |
117 _MARKER_A
118 |
119 _MARKER_P
120 |
121 _MARKER_U
122 |
123 _MARKER_LINE_BG_LIGHT_GREY
124 )
125
126 _DEFINED_MARKER_NUMS = [
127 _MARKER_ADM,
128 _MARKER_S,
129 _MARKER_O,
130 _MARKER_A,
131 _MARKER_P,
132 _MARKER_U,
133 _MARKER_LINE_BG_LIGHT_GREY
134 ]
135 _SOAP_MARKER_NUMS = [
136 _MARKER_ADM,
137 _MARKER_S,
138 _MARKER_O,
139 _MARKER_A,
140 _MARKER_P,
141 _MARKER_U
142 ]
143 _SOAP2MARKER = {
144 None: _MARKER_ADM,
145 ' ': _MARKER_ADM,
146 '.': _MARKER_ADM,
147 's': _MARKER_S,
148 'o': _MARKER_O,
149 'a': _MARKER_A,
150 'p': _MARKER_P,
151 'u': _MARKER_U,
152 'S': _MARKER_S,
153 'O': _MARKER_O,
154 'A': _MARKER_A,
155 'P': _MARKER_P,
156 'U': _MARKER_U
157 }
158 _MARKER2SOAP = {
159 _MARKER_ADM: None,
160 _MARKER_S: 's',
161 _MARKER_O: 'o',
162 _MARKER_A: 'a',
163 _MARKER_P: 'p',
164 _MARKER_U: 'u'
165 }
166 _SOAPMARKER2BACKGROUND = {
167 _MARKER_ADM: False,
168 _MARKER_S: True,
169 _MARKER_O: False,
170 _MARKER_A: True,
171 _MARKER_P: False,
172 _MARKER_U: True
173 }
174
176
177 # normalize wxGlade output
178 if args[2] == '':
179 l_args = list(args)
180 l_args[2] = wx.DefaultPosition
181 args = tuple(l_args)
182 wx.stc.StyledTextCtrl.__init__(self, *args, **kwargs)
183 cWxTextCtrlCompatibility_StcMixin.__init__(self)
184 gmKeywordExpansionWidgets.cKeywordExpansion_TextCtrlMixin.__init__(self)
185 cUnicodeInsertion_TextCtrlMixin.__init__(self)
186
187 # wrapping and overflow
188 self.SetWrapMode(wx.stc.STC_WRAP_NONE)
189 # said to be problematic:
190 self.SetEdgeColumn(80)
191 self.SetEdgeColour('grey')
192 #self.SetEdgeMode(wx.stc.STC_EDGE_LINE)
193 self.SetEdgeMode(wx.stc.STC_EDGE_BACKGROUND)
194
195 # EOL style
196 self.SetEOLMode(wx.stc.STC_EOL_LF)
197 #self.SetViewEOL(1) # visual debugging
198 self.SetViewEOL(0)
199
200 # whitespace handling
201 #self.SetViewWhiteSpace(wx.stc.STC_WS_VISIBLEAFTERINDENT) # visual debugging
202 self.SetViewWhiteSpace(wx.stc.STC_WS_INVISIBLE)
203 #self.SetWhitespaceBackground(1, a_color) # 1 = override lexer
204 #self.SetWhitespaceForeground(1, a_color) # 1 = override lexer
205
206 # caret handling
207 #self.SetCaretLineBackground('light goldenrod yellow')
208 self.SetCaretLineBackground('khaki')
209 self.SetCaretLineVisible(1)
210
211 # margins
212 # left margin: 0 pixel widths
213 self.SetMarginLeft(0)
214 # margin 0: SOAP markers
215 self.SetMarginType(0, wx.stc.STC_MARGIN_SYMBOL)
216 self.SetMarginWidth(0, 16)
217 self.SetMarginMask(0, cSoapSTC._DEFINED_MARKERS_MASK)
218 # margin 1 and 2: additional 2-letter markers (not yet supported)
219 self.SetMarginType(1, wx.stc.STC_MARGIN_SYMBOL)
220 self.SetMarginMask(1, 0)
221 self.SetMarginWidth(1, 0)
222 self.SetMarginType(2, wx.stc.STC_MARGIN_SYMBOL)
223 self.SetMarginMask(2, 0)
224 self.SetMarginWidth(2, 0)
225
226 # markers
227 # can only use ASCII so far, so must make sure translations are ASCII:
228 self.MarkerDefine(cSoapSTC._MARKER_ADM, wx.stc.STC_MARK_CHARACTER + ord('.'), 'blue', 'white')
229 self.MarkerDefine(cSoapSTC._MARKER_S, wx.stc.STC_MARK_CHARACTER + ord(gmSoapDefs.soap_cat2l10n['s']), 'blue', 'grey96')
230 self.MarkerDefine(cSoapSTC._MARKER_O, wx.stc.STC_MARK_CHARACTER + ord(gmSoapDefs.soap_cat2l10n['o']), 'blue', 'white')
231 self.MarkerDefine(cSoapSTC._MARKER_A, wx.stc.STC_MARK_CHARACTER + ord(gmSoapDefs.soap_cat2l10n['a']), 'blue', 'grey96')
232 self.MarkerDefine(cSoapSTC._MARKER_P, wx.stc.STC_MARK_CHARACTER + ord(gmSoapDefs.soap_cat2l10n['p']), 'blue', 'white')
233 self.MarkerDefine(cSoapSTC._MARKER_U, wx.stc.STC_MARK_CHARACTER + ord(gmSoapDefs.soap_cat2l10n['u']), 'blue', 'grey96')
234 self.MarkerDefine(cSoapSTC._MARKER_LINE_BG_LIGHT_GREY, wx.stc.STC_MARK_BACKGROUND, 'grey96', 'grey96')
235
236 # unset hotkeys we want to re-define
237 #self.CmdKeyClear('t', wx.stc.STC_SCMOD_CTRL) # does not seem to work
238 self.__changing_SOAP_cat = False
239 self.__markers_of_prev_line = None
240 self.__ensure_has_all_soap_types = False
241
242 # we do our own popup menu
243 self.UsePopUp(0)
244 self.__build_context_menu()
245
246 # always keep one line of each of .SOAP around
247 self.SetText_from_SOAP()
248
249 self.__register_events()
250
251 # text expansion mixin
252 self.enable_keyword_expansions()
253
254 #-------------------------------------------------------
255 # SOAP-enhanced text setting
256 #-------------------------------------------------------
258 _log.debug('%s.SetText()', self.__class__.__name__)
259 wx.stc.StyledTextCtrl.SetText(self, *args, **kwargs)
260
262 _log.debug('%s.AddText()', self.__class__.__name__)
263 wx.stc.StyledTextCtrl.AddText(self, *args, **kwargs)
264
266 _log.debug('%s.AddStyledText()', self.__class__.__name__)
267 wx.stc.StyledTextCtrl.AddStyledText(self, *args, **kwargs)
268
270 _log.debug('%s.InsertText()', self.__class__.__name__)
271 wx.stc.StyledTextCtrl.InsertText(self, *args, **kwargs)
272
273 #-------------------------------------------------------
275 sel_start, sel_end = self.GetSelection()
276 start_line = self.LineFromPosition(sel_start)
277 end_line = start_line + text.count('\n')
278 start_line_soap_cat = self.MarkerGet(start_line)
279 #_log.debug(u'replacing @ pos %s-%s with %s lines (line %s to line %s)', sel_start, sel_end, text.count(u'\n'), start_line, end_line)
280 wx.stc.StyledTextCtrl.ReplaceSelection(self, text)
281 if start_line != end_line:
282 for target_line in range(start_line, end_line):
283 self.MarkerDelete(target_line, -1)
284 self.__set_markers_of_line(target_line, start_line_soap_cat)
285
286 #-------------------------------------------------------
288 _log.debug('%s.ReplaceTarget()', self.__class__.__name__)
289 wx.stc.StyledTextCtrl.ReplaceTarget(self, *args, **kwargs)
290
292 _log.debug('%s.ReplaceTargetRE()', self.__class__.__name__)
293 wx.stc.StyledTextCtrl.ReplaceTargetRE(self, *args, **kwargs)
294
295 #-------------------------------------------------------
296 # external API
297 #-------------------------------------------------------
299 # defaults
300 if soap is None:
301 #soap = {None: [u'']} # 'soap' will be added below by normalization
302 soap = {}
303 if sort_order is None:
304 sort_order = ['s', 'o', 'a', 'p', None, 'u']
305
306 # normalize input
307 for cat in 'soap':
308 try:
309 soap[cat]
310 except KeyError:
311 soap[cat] = ['']
312 for cat in ['u', None]:
313 try:
314 soap[cat]
315 except KeyError:
316 soap[cat] = []
317 if '.' in soap:
318 soap[None].extend(soap['.'])
319 del soap['.']
320 if ' ' in soap:
321 soap[None].extend(soap[' '])
322 del soap[' ']
323
324 # normalize sort order
325 for cat in 'soapu':
326 if cat not in sort_order:
327 sort_order.append(cat)
328 if None not in sort_order:
329 sort_order.append(None)
330
331 # sort and flatten
332 soap_lines = []
333 line_categories = []
334 for cat in sort_order:
335 lines = soap[cat]
336 if len(lines) == 0:
337 continue
338 for line in lines:
339 soap_lines.append(line.strip())
340 line_categories.append(cat)
341
342 _log.debug('%s.SetText_from_SOAP(): 1 controlled use of .SetText() follows', self.__class__.__name__)
343 self.SetText('\n'.join(soap_lines))
344
345 for idx in range(len(line_categories)):
346 self.set_soap_cat_of_line(idx, line_categories[idx])
347
348 #-------------------------------------------------------
350 lines = self.GetText().split('\n')
351 soap = {}
352 for line_idx in range(len(lines)):
353 cat = self.get_soap_cat_of_line(line_idx)
354 if cat == -1:
355 cat = 'u'
356 try:
357 soap[cat]
358 except KeyError:
359 soap[cat] = []
360 soap[cat].append(lines[line_idx])
361 return soap
362
363 soap = property(GetText_as_SOAP, lambda x:x)
364
365 #--------------------------------------------------------
367 soap = self.GetText_as_SOAP()
368 for cat in soap:
369 if ''.join([ l.strip() for l in soap[cat] ]) != '':
370 return False
371 return True
372
373 empty = property(_get_empty, lambda x:x)
374
375 #-------------------------------------------------------
378
379 #-------------------------------------------------------
381 caret_pos = self.CurrentPos
382 self.GotoPos(self.Length)
383 self.AddText('\n')
384 self.set_soap_cat_of_line(self.LineCount, soap_cat)
385
386 #-------------------------------------------------------
387 # generic helpers
388 #-------------------------------------------------------
390 line_text = self.GetLine(line)
391 line_start = self.PositionFromLine(line)
392 line_end = self.GetLineEndPosition(line)
393 self.SetTargetStart(line_start)
394 self.SetTargetEnd(line_end)
395 self.ReplaceTarget(line_text.rstrip())
396
397 #-------------------------------------------------------
400
401 #-------------------------------------------------------
403 return self.ClientToScreen(self.caret_coords_in_stc())
404
405 #-------------------------------------------------------
406 # internal helpers
407 #-------------------------------------------------------
477
478 #-------------------------------------------------------
488
489 #-------------------------------------------------------
491 if wx.TheClipboard.IsOpened():
492 _log.debug('clipboard already open')
493 return ''
494 if not wx.TheClipboard.Open():
495 _log.debug('cannot open clipboard')
496 return ''
497 data_obj = wx.TextDataObject()
498 got_it = wx.TheClipboard.GetData(data_obj)
499 if not got_it:
500 return ''
501 return data_obj.Text
502
503 #-------------------------------------------------------
504 # context menu handlers
505 #-------------------------------------------------------
507 self.attempt_expansion(show_list_if_needed = True)
508
509 #-------------------------------------------------------
511 self.mixin_insert_unicode_character()
512
513 #-------------------------------------------------------
519
520 #-------------------------------------------------------
522 txt = self.GetText().strip()
523 if txt == '':
524 return
525 txt = self.__get_clipboard_text() + '\n' + txt
526 self.CopyText(len(txt), txt)
527
528 #-------------------------------------------------------
531
532 #-------------------------------------------------------
534 region = self.GetTextRange(self.SelectionStart, self.SelectionEnd)
535 if region.strip() == '':
536 return
537 txt = self.__get_clipboard_text() + '\n' + region
538 self.CopyText(len(txt), txt)
539
540 #-------------------------------------------------------
542 txt = self.GetLine(self.CurrentLine).strip()
543 if txt == '':
544 return
545 self.CopyText(len(txt), txt)
546
547 #-------------------------------------------------------
549 txt = self.GetLine(self.CurrentLine).strip()
550 if txt == '':
551 return
552 txt = self.__get_clipboard_text() + '\n' + txt
553 self.CopyText(len(txt), txt)
554
555 #-------------------------------------------------------
559
560 #-------------------------------------------------------
564
565 #-------------------------------------------------------
569
570 #-------------------------------------------------------
574
575 #-------------------------------------------------------
579
580 #-------------------------------------------------------
584
585 #-------------------------------------------------------
587 self.sort_by_SOAP()
588
589 #-------------------------------------------------------
590 # marker related helpers
591 #-------------------------------------------------------
595
596 #-------------------------------------------------------
598 for marker_num in cSoapSTC._DEFINED_MARKER_NUMS:
599 if markers & (1 << marker_num):
600 self.MarkerAdd(line, marker_num)
601
602 #-------------------------------------------------------
604 markers = self.MarkerGet(line)
605 for marker_num in cSoapSTC._SOAP_MARKER_NUMS:
606 if markers & (1 << marker_num):
607 return marker_num
608
609 return -1 # should only happen when deleting all lines -> STC empties out INCLUDING existing markers ...
610
611 #-------------------------------------------------------
613 markers = self.MarkerGet(line)
614 for marker_num in cSoapSTC._SOAP_MARKER_NUMS:
615 if markers & (1 << marker_num):
616 return cSoapSTC._MARKER2SOAP[marker_num]
617
618 return -1 # should only happen when deleting all lines -> STC empties out INCLUDING existing markers ...
619
620 #-------------------------------------------------------
622 # remove all SOAP markers of this line
623 for marker_num in cSoapSTC._SOAP_MARKER_NUMS:
624 self.MarkerDelete(line, marker_num)
625 self.MarkerDelete(line, cSoapSTC._MARKER_LINE_BG_LIGHT_GREY)
626 # set desired marker
627 new_marker_num = cSoapSTC._SOAP2MARKER[soap_category]
628 self.MarkerAdd(line, new_marker_num)
629 if cSoapSTC._SOAPMARKER2BACKGROUND[new_marker_num]:
630 self.MarkerAdd(line, cSoapSTC._MARKER_LINE_BG_LIGHT_GREY)
631 return True
632
633 #-------------------------------------------------------
635 for marker_num in [ cSoapSTC._MARKER_S, cSoapSTC._MARKER_O, cSoapSTC._MARKER_A, cSoapSTC._MARKER_P ]:
636 if self.MarkerNext(0, (1 << marker_num)) == -1:
637 return False
638 return True
639
640 #-------------------------------------------------------
644
645 #-------------------------------------------------------
647 line_count = 0
648 line_w_marker = -1
649 while True:
650 line_w_marker = self.MarkerNext(line_w_marker + 1, (1 << marker))
651 if line_w_marker == -1:
652 break
653 line_count += 1
654 return line_count
655
656 #-------------------------------------------------------
660
661 #-------------------------------------------------------
662 # key handlers
663 #-------------------------------------------------------
665
666 if evt.HasModifiers():
667 # we only handle DELETE w/o modifiers so far
668 evt.Skip()
669 return False
670
671 sel_start, sel_end = self.GetSelection()
672 if sel_start != sel_end:
673 evt.Skip()
674 sel_start_line = self.LineFromPosition(sel_start)
675 sel_end_line = self.LineFromPosition(sel_end)
676 # within one line -> allow in any case
677 if sel_start_line == sel_end_line:
678 return
679 sel_start_soap_marker = self.get_soap_marker_of_line(sel_start_line)
680 sel_end_soap_marker = self.get_soap_marker_of_line(sel_end_line)
681 if sel_start_soap_marker == sel_end_soap_marker:
682 # across lines of the same SOAP type -> allow
683 return
684 self.__ensure_has_all_soap_types = True
685 return
686
687 curr_line = self.CurrentLine
688 if (curr_line + 1) == self.LineCount: # adjust for line index being 0-based
689 # we are on the last line, therefore we cannot end up
690 # pulling up a next line (and thereby remove the only
691 # line with a given SOAP category in case the last+1
692 # line would happen to be the only one of that category)
693 evt.Skip()
694 return False
695
696 # in last column
697 caret_pos = self.GetColumn(self.CurrentPos)
698 max_pos = self.LineLength(curr_line) - 1
699 if caret_pos < max_pos:
700 # DELETE _inside_ a line (as opposed to at the
701 # _end_ of one) will not pull up the next line
702 # so no special SOAP checking
703 evt.Skip()
704 return False
705
706 soap_marker_current_line = self.get_soap_marker_of_line(curr_line)
707 soap_marker_next_line = self.get_soap_marker_of_line(curr_line + 1)
708 if soap_marker_current_line == soap_marker_next_line:
709 # pulling up a line of the _same_ SOAP category
710 # is fine - and exactly what the user intended
711 # so allow that to happen (IOW no special DELETE
712 # handling)
713 evt.Skip()
714 return False
715
716 # now we have got
717 # - a DELETE
718 # - without modifier keys
719 # - _not_ on the last line
720 # - in the last column of the current line
721 # - but the next line is of a different SOAP category
722 # so, do NOT evt.Skip() - IOW, ignore this DELETE
723 return True
724
725 #-------------------------------------------------------
727
728 if evt.HasModifiers():
729 # we only handle BACKSPACE w/o modifiers so far
730 evt.Skip()
731 return False
732
733 sel_start, sel_end = self.GetSelection()
734 if sel_start != sel_end:
735 evt.Skip()
736 sel_start_line = self.LineFromPosition(sel_start)
737 sel_end_line = self.LineFromPosition(sel_end)
738 # within one line -> allow in any case
739 if sel_start_line == sel_end_line:
740 return
741 sel_start_soap_marker = self.get_soap_marker_of_line(sel_start_line)
742 sel_end_soap_marker = self.get_soap_marker_of_line(sel_end_line)
743 if sel_start_soap_marker == sel_end_soap_marker:
744 # across lines of the same SOAP type -> allow
745 return
746 self.__ensure_has_all_soap_types = True
747 return
748
749 curr_line = self.LineFromPosition(self.CurrentPos)
750 if curr_line == 0:
751 # cannot BACKSPACE into line -1 anyway
752 evt.Skip()
753 return False
754
755 if self.GetColumn(self.CurrentPos) > 0:
756 # not in first column, so not BACKSPACing into previous line
757 evt.Skip()
758 return False
759
760 soap_marker_current_line = self.get_soap_marker_of_line(curr_line)
761 soap_marker_next_line = self.get_soap_marker_of_line(curr_line - 1)
762 if soap_marker_current_line == soap_marker_next_line:
763 # backspacing into previous line of the _same_ SOAP
764 # category is fine - and exactly what the user
765 # intended so allow that to happen (IOW no special
766 # DELETE handling)
767 evt.Skip()
768 return False
769
770 # now we have got
771 # - a BACKSPACE
772 # - without modifier keys
773 # - _not_ on the first line
774 # - in the first column of the current line
775 # - but the previous line is of a different SOAP category
776 # so, do NOT evt.Skip() - IOW, ignore this BACKSPACE
777 return True
778
779 #-------------------------------------------------------
781 # currently we always want to pass on the RETURN (but remember the markers)
782 evt.Skip()
783 if evt.HasModifiers():
784 # we only handle RETURN w/o modifiers so far
785 self.__markers_of_prev_line = None
786 return
787 self.__markers_of_prev_line = self.MarkerGet(self.CurrentLine)
788
789 #-------------------------------------------------------
791 self.__changing_SOAP_cat = False
792 try:
793 soap_category = gmSoapDefs.l10n2soap_cat[key]
794 except KeyError:
795 if key.islower():
796 key = key.upper()
797 else:
798 key = key.lower()
799 try:
800 soap_category = gmSoapDefs.l10n2soap_cat[key]
801 except KeyError:
802 return
803 self.set_soap_cat_of_line(line, soap_category)
804 wx.CallAfter(self.sort_by_SOAP)
805
806 #-------------------------------------------------------
814
815 #-------------------------------------------------------
823
824 #-------------------------------------------------------
825 # event setup and handlers
826 #-------------------------------------------------------
828 # wxPython events
829 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down) # happens before key gets into STC
830 #self.Bind(wx.EVT_CHAR, self._on_wx_char) # happens before char gets into STC
831 self.Bind(wx.EVT_CONTEXT_MENU, self._on_context_menu_activated)
832
833 # STC events
834 self.Bind(wx.stc.EVT_STC_CHARADDED, self._on_stc_char_added)
835 self.Bind(wx.stc.EVT_STC_CHANGE, self._on_stc_change)
836
837 #self.Bind(stc.EVT_STC_DO_DROP, self.OnDoDrop)
838 #self.Bind(stc.EVT_STC_DRAG_OVER, self.OnDragOver)
839 #self.Bind(stc.EVT_STC_START_DRAG, self.OnStartDrag)
840 #self.Bind(stc.EVT_STC_MODIFIED, self.OnModified)
841
842 #self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
843
844 #-------------------------------------------------------
847
848 #-------------------------------------------------------
850
851 # CTRL-T has been pressed last, now another character has been pressed
852 if self.__changing_SOAP_cat:
853 self.__handle_soap_category_key_down(chr(evt.GetUnicodeKey()).lower(), self.CurrentLine)
854 # somehow put cursor into the changed (and possibly moved) line
855 return
856
857 key = evt.KeyCode
858
859 # ENTER
860 if key == wx.WXK_RETURN:
861 self.__handle_return_key_down(evt)
862 return
863
864 # BACKSPACE
865 if key == wx.WXK_BACK:
866 self.__handle_backspace_key(evt)
867 return
868
869 # DELETE
870 if key == wx.WXK_DELETE:
871 self.__handle_delete_key(evt)
872 return
873
874 # MENU
875 if key == wx.WXK_MENU:
876 self.__handle_menu_key_down(evt)
877 return
878
879 # CTRL-T: set Type
880 if key == ord('T'):
881 if evt.HasModifiers():
882 if evt.CmdDown(): # CTRL-T or APPLE-T
883 self.__changing_SOAP_cat = True
884 return
885
886 evt.Skip() # make sure unhandled keys get to the STC
887
888 #-------------------------------------------------------
890 evt.Skip()
891 key = evt.GetKey()
892 if key == 10:
893 # we cannot simply transfer the markers of the previous
894 # line (where we pressed RETURN) into the current line
895 # (which appeared after the RETURN) because the STC handles
896 # creating the "new" line differently based on where in the
897 # previous line RETURN was pressed (!) -- if it happened
898 # to be in position 0 (at the start of the line) the previous
899 # line is pushed DOWN and an empty line is inserted BEFORE
900 # the previous line (likely an optimization)
901 # hence we need to remember the markers of the real previous
902 # line from _before_ the new line gets created and use that
903 # auto-set the markers of the new line... |-)
904 if self.__markers_of_prev_line is None:
905 return
906 self.__set_markers_of_line(self.CurrentLine - 1, self.__markers_of_prev_line)
907 self.__set_markers_of_line(self.CurrentLine, self.__markers_of_prev_line)
908 self.__markers_of_prev_line = None
909 return
910
911 #-------------------------------------------------------
915
916 #-------------------------------------------------------
917 #-------------------------------------------------------
918 #-------------------------------------------------------
919 #-------------------------------------------------------
920 # unused:
921 #-------------------------------------------------------
923 # This is how the clipboard contents can be preserved after
924 # the app has exited.
925 wx.TheClipboard.Flush()
926 evt.Skip()
927
928
930 #self.log.write("OnStartDrag: %d, %s\n"
931 # % (evt.GetDragAllowMove(), evt.GetDragText()))
932
933 if debug and evt.GetPosition() < 250:
934 evt.SetDragAllowMove(False) # you can prevent moving of text (only copy)
935 evt.SetDragText("DRAGGED TEXT") # you can change what is dragged
936 #evt.SetDragText("") # or prevent the drag with empty text
937
938
940 #self.log.write(
941 # "OnDragOver: x,y=(%d, %d) pos: %d DragResult: %d\n"
942 # % (evt.GetX(), evt.GetY(), evt.GetPosition(), evt.GetDragResult())
943 # )
944
945 if debug and evt.GetPosition() < 250:
946 evt.SetDragResult(wx.DragNone) # prevent dropping at the beginning of the buffer
947
948
950 #self.log.write("OnDoDrop: x,y=(%d, %d) pos: %d DragResult: %d\n"
951 # "\ttext: %s\n"
952 # % (evt.GetX(), evt.GetY(), evt.GetPosition(), evt.GetDragResult(),
953 # evt.GetDragText()))
954
955 if debug and evt.GetPosition() < 500:
956 evt.SetDragText("DROPPED TEXT") # Can change text if needed
957 #evt.SetDragResult(wx.DragNone) # Can also change the drag operation, but it
958 # is probably better to do it in OnDragOver so
959 # there is visual feedback
960
961 #evt.SetPosition(25) # Can also change position, but I'm not sure why
962 # you would want to...
963
964
966 #self.log.write("""OnModified
967 # Mod type: %s
968 # At position: %d
969 # Lines added: %d
970 # Text Length: %d
971 # Text: %s\n""" % ( self.transModType(evt.GetModificationType()),
972 # evt.GetPosition(),
973 # evt.GetLinesAdded(),
974 # evt.GetLength(),
975 # repr(evt.GetText()) ))
976 pass
977
978
980 st = ""
981 table = [(stc.STC_MOD_INSERTTEXT, "InsertText"),
982 (stc.STC_MOD_DELETETEXT, "DeleteText"),
983 (stc.STC_MOD_CHANGESTYLE, "ChangeStyle"),
984 (stc.STC_MOD_CHANGEFOLD, "ChangeFold"),
985 (stc.STC_PERFORMED_USER, "UserFlag"),
986 (stc.STC_PERFORMED_UNDO, "Undo"),
987 (stc.STC_PERFORMED_REDO, "Redo"),
988 (stc.STC_LASTSTEPINUNDOREDO, "Last-Undo/Redo"),
989 (stc.STC_MOD_CHANGEMARKER, "ChangeMarker"),
990 (stc.STC_MOD_BEFOREINSERT, "B4-Insert"),
991 (stc.STC_MOD_BEFOREDELETE, "B4-Delete")
992 ]
993
994 for flag,text in table:
995 if flag & modType:
996 st = st + text + " "
997
998 if not st:
999 st = 'UNKNOWN'
1000
1001 return st
1002
1003 #----------------------------------------------------------------------
1004 #----------------------------------------------------------------------
1005 #----------------------------------------------------------------------
1006 if wx.Platform == '__WXMSW__':
1007 face1 = 'Arial'
1008 face2 = 'Times New Roman'
1009 face3 = 'Courier New'
1010 pb = 12
1011 else:
1012 face1 = 'Helvetica'
1013 face2 = 'Times'
1014 face3 = 'Courier'
1015 pb = 14
1016
1017
1018 _USE_PANEL = 1
1019
1021 if not _USE_PANEL:
1022 ed = p = cSoapSTC(nb, -1)
1023
1024 else:
1025 p = wx.Panel(nb, -1, style=wx.NO_FULL_REPAINT_ON_RESIZE)
1026 ed = cSoapSTC(p, -1, log)
1027 s = wx.BoxSizer(wx.HORIZONTAL)
1028 s.Add(ed, 1, wx.EXPAND)
1029 p.SetSizer(s)
1030 p.SetAutoLayout(True)
1031
1032
1033 #ed.SetBufferedDraw(False)
1034 #ed.StyleClearAll()
1035 #ed.SetScrollWidth(800)
1036 #ed.SetWrapMode(True)
1037 #ed.SetUseAntiAliasing(False)
1038 #ed.SetViewEOL(True)
1039
1040 #ed.CmdKeyClear(stc.STC_KEY_BACK,
1041 # stc.STC_SCMOD_CTRL)
1042 #ed.CmdKeyAssign(stc.STC_KEY_BACK,
1043 # stc.STC_SCMOD_CTRL,
1044 # stc.STC_CMD_DELWORDLEFT)
1045
1046 ed.SetText(demoText)
1047
1048 if wx.USE_UNICODE:
1049 import codecs
1050 decode = codecs.lookup("utf-8")[1]
1051
1052 ed.GotoPos(ed.GetLength())
1053 ed.AddText("\n\nwx.StyledTextCtrl can also do Unicode:\n")
1054 uniline = ed.GetCurrentLine()
1055 unitext, l = decode('\xd0\x9f\xd0\xb8\xd1\x82\xd0\xbe\xd0\xbd - '
1056 '\xd0\xbb\xd1\x83\xd1\x87\xd1\x88\xd0\xb8\xd0\xb9 '
1057 '\xd1\x8f\xd0\xb7\xd1\x8b\xd0\xba \xd0\xbf\xd1\x80\xd0\xbe\xd0\xb3\xd1\x80\xd0\xb0\xd0\xbc\xd0\xbc\xd0\xb8\xd1\x80\xd0\xbe\xd0\xb2\xd0\xb0\xd0\xbd\xd0\xb8\xd1\x8f!\n\n')
1058 ed.AddText('\tRussian: ')
1059 ed.AddText(unitext)
1060 ed.GotoPos(0)
1061 #else:
1062 # #ed.StyleSetFontEncoding(stc.STC_STYLE_DEFAULT, wx.FONTENCODING_KOI8)
1063 # #text = u'\u041f\u0438\u0442\u043e\u043d - \u043b\u0443\u0447\u0448\u0438\u0439 \u044f\u0437\u044b\u043a \n\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f!'
1064 # #text = text.encode('koi8-r')
1065 # #ed.StyleSetFontEncoding(stc.STC_STYLE_DEFAULT, wx.FONTENCODING_BIG5)
1066 # #text = u'Python \u662f\u6700\u597d\u7684\u7de8\u7a0b\u8a9e\u8a00\uff01'
1067 # #text = text.encode('big5')
1068 # ed.GotoPos(ed.GetLength())
1069 # ed.AddText('\n\n' + text)
1070
1071 ed.EmptyUndoBuffer()
1072
1073 # make some styles
1074 ed.StyleSetSpec(stc.STC_STYLE_DEFAULT, "size:%d,face:%s" % (pb, face3))
1075 ed.StyleClearAll()
1076 ed.StyleSetSpec(1, "size:%d,bold,face:%s,fore:#0000FF" % (pb, face1))
1077 ed.StyleSetSpec(2, "face:%s,italic,fore:#FF0000,size:%d" % (face2, pb))
1078 ed.StyleSetSpec(3, "face:%s,bold,size:%d" % (face2, pb))
1079 ed.StyleSetSpec(4, "face:%s,size:%d" % (face1, pb-1))
1080
1081 # Now set some text to those styles... Normally this would be
1082 # done in an event handler that happens when text needs displayed.
1083 ed.StartStyling(98, 0xff)
1084 ed.SetStyling(6, 1) # set style for 6 characters using style 1
1085
1086 ed.StartStyling(190, 0xff)
1087 ed.SetStyling(20, 2)
1088
1089 ed.StartStyling(310, 0xff)
1090 ed.SetStyling(4, 3)
1091 ed.SetStyling(2, 0)
1092 ed.SetStyling(10, 4)
1093
1094
1095 # line numbers in the margin
1096 ed.SetMarginType(0, stc.STC_MARGIN_NUMBER)
1097 ed.SetMarginWidth(0, 22)
1098 ed.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "size:%d,face:%s" % (pb-2, face1))
1099
1100 # setup some markers
1101 ed.SetMarginType(1, stc.STC_MARGIN_SYMBOL)
1102 ed.MarkerDefine(0, stc.STC_MARK_ROUNDRECT, "#CCFF00", "RED")
1103 ed.MarkerDefine(1, stc.STC_MARK_CIRCLE, "FOREST GREEN", "SIENNA")
1104 ed.MarkerDefine(2, stc.STC_MARK_SHORTARROW, "blue", "blue")
1105 ed.MarkerDefine(3, stc.STC_MARK_ARROW, "#00FF00", "#00FF00")
1106
1107 # put some markers on some lines
1108 ed.MarkerAdd(17, 0)
1109 ed.MarkerAdd(18, 1)
1110 ed.MarkerAdd(19, 2)
1111 ed.MarkerAdd(20, 3)
1112 ed.MarkerAdd(20, 0)
1113
1114
1115 # and finally, an indicator or two
1116 ed.IndicatorSetStyle(0, stc.STC_INDIC_SQUIGGLE)
1117 ed.IndicatorSetForeground(0, wx.RED)
1118 ed.IndicatorSetStyle(1, stc.STC_INDIC_DIAGONAL)
1119 ed.IndicatorSetForeground(1, wx.BLUE)
1120 ed.IndicatorSetStyle(2, stc.STC_INDIC_STRIKE)
1121 ed.IndicatorSetForeground(2, wx.RED)
1122
1123 ed.StartStyling(836, stc.STC_INDICS_MASK)
1124 ed.SetStyling(10, stc.STC_INDIC0_MASK)
1125 ed.SetStyling(8, stc.STC_INDIC1_MASK)
1126 ed.SetStyling(10, stc.STC_INDIC2_MASK | stc.STC_INDIC1_MASK)
1127
1128
1129 # some test stuff...
1130 if debug:
1131 print("GetTextLength(): ", ed.GetTextLength(), len(ed.GetText()))
1132 print("GetText(): ", repr(ed.GetText()))
1133 print()
1134 print("GetStyledText(98, 104): ", repr(ed.GetStyledText(98, 104)), len(ed.GetStyledText(98, 104)))
1135 print()
1136 print("GetCurLine(): ", repr(ed.GetCurLine()))
1137 ed.GotoPos(5)
1138 print("GetCurLine(): ", repr(ed.GetCurLine()))
1139 print()
1140 print("GetLine(1): ", repr(ed.GetLine(1)))
1141 print()
1142 ed.SetSelection(25, 35)
1143 print("GetSelectedText(): ", repr(ed.GetSelectedText()))
1144 print("GetTextRange(25, 35): ", repr(ed.GetTextRange(25, 35)))
1145 print("FindText(0, max, 'indicators'): ", end=' ')
1146 print(ed.FindText(0, ed.GetTextLength(), "indicators"))
1147 if wx.USE_UNICODE:
1148 end = ed.GetLength()
1149 start = ed.PositionFromLine(uniline)
1150 print("GetTextRange(%d, %d): " % (start, end), end=' ')
1151 print(repr(ed.GetTextRange(start, end)))
1152
1153
1154 wx.CallAfter(ed.GotoPos, 0)
1155 return p
1156
1157
1158 #----------------------------------------------------------------------
1159 overview = """\
1160 <html><body>
1161 Once again, no docs yet. <b>Sorry.</b> But <a href="data/stc.h.html">this</a>
1162 and <a href="http://www.scintilla.org/ScintillaDoc.html">this</a> should
1163 be helpful.
1164 </body><html>
1165 """
1166
1167 #===================================================
1168 # main
1169 #---------------------------------------------------
1170 if __name__ == '__main__':
1171
1172 if len(sys.argv) < 2:
1173 sys.exit()
1174
1175 if sys.argv[1] != 'test':
1176 sys.exit()
1177
1178 import wx.lib.colourdb
1179
1180 from Gnumed.pycommon import gmI18N
1181 gmI18N.activate_locale()
1182 gmI18N.install_domain(domain = 'gnumed')
1183
1184 #-----------------------------------------------
1186 app = wx.PyWidgetTester(size = (600, 600))
1187 wx.lib.colourdb.updateColourDB()
1188 #print wx.lib.colourdb.getColourList()
1189 app.SetWidget(cSoapSTC, -1, (100,50))
1190 app.MainLoop()
1191 return True
1192
1193 # app = wx.PyWidgetTester(size = (200, 50))
1194 # tc = cTextCtrl(app.frame, -1)
1195 # #tc.enable_keyword_expansions()
1196 # app.frame.Show(True)
1197 # app.MainLoop()
1198 # return True
1199
1200 #-----------------------------------------------
1201 test_stc()
1202
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Fri Jan 25 02:55:27 2019 | http://epydoc.sourceforge.net |