1#---------------------------------------------------------------------------
2# Name:        etg/_stc.py
3# Author:      Robin Dunn
4#
5# Created:     24-Oct-2012
6# Copyright:   (c) 2012-2018 by Total Control Software
7# License:     wxWindows License
8#---------------------------------------------------------------------------
9
10import etgtools
11import etgtools.tweaker_tools as tools
12
13PACKAGE   = "wx"
14MODULE    = "_stc"
15NAME      = "_stc"   # Base name of the file to generate to for this script
16DOCSTRING = """\
17The :ref:`wx.stc.StyledTextCrtl` class provided by this module is a text widget
18primarily intended for use as a syntax highlighting source code editor.  It is
19based on the popular Scintilla widget.
20"""
21
22# The classes and/or the basename of the Doxygen XML files to be processed by
23# this script.
24ITEMS  = [ 'wxStyledTextCtrl',
25           'wxStyledTextEvent',
26          ]
27
28
29# The list of other ETG scripts and back-end generator modules that are
30# included as part of this module. These should all be items that are put in
31# the wxWidgets "stc" library in a multi-lib build.
32INCLUDES = [ ]
33
34
35# Separate the list into those that are generated from ETG scripts and the
36# rest. These lists can be used from the build scripts to get a list of
37# sources and/or additional dependencies when building this extension module.
38ETGFILES = ['etg/%s.py' % NAME] + tools.getEtgFiles(INCLUDES)
39DEPENDS = tools.getNonEtgFiles(INCLUDES)
40OTHERDEPS = [  ]
41
42
43#---------------------------------------------------------------------------
44
45def run():
46    # Parse the XML file(s) building a collection of Extractor objects
47    module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
48    etgtools.parseDoxyXML(module, ITEMS)
49    module.check4unittest = False
50
51    #-----------------------------------------------------------------
52    # Tweak the parsed meta objects in the module object as needed for
53    # customizing the generated code and docstrings.
54
55    module.addHeaderCode('#include <wxPython/wxpy_api.h>')
56    module.addImport('_core')
57    module.addPyCode('''\
58    import wx
59    ID_ANY = wx.ID_ANY  # Needed for some parameter defaults in this module
60    ''', order=10)
61    module.addInclude(INCLUDES)
62
63
64    #-----------------------------------------------------------------
65
66    module.addHeaderCode('#include <wx/stc/stc.h>')
67    module.addHeaderCode('#include "wxpybuffer.h"')
68
69
70    c = module.find('wxStyledTextCtrl')
71    assert isinstance(c, etgtools.ClassDef)
72    c.bases = ['wxControl']  # wxTextCtrlIface is also a base...
73    c.piBases = ['wx.Control', 'wx.TextEntry']
74    tools.fixWindowClass(c, False)
75    module.addGlobalStr('wxSTCNameStr', c)
76
77
78    c.find('GetCurLine.linePos').out = True
79    c.find('GetCurLineRaw.linePos').out = True
80    for name in ['Remove', 'Replace', 'SetSelection', 'GetSelection']:
81        m = c.find(name)
82        m.find('from').name = 'from_'
83        m.find('to').name = 'to_'
84
85    c.find('GetSelection.from_').out = True
86    c.find('GetSelection.to_').out = True
87    c.find('PositionToXY.x').out = True
88    c.find('PositionToXY.y').out = True
89
90    # Split the HitTest overloads into separately named methods since once
91    # the output parameters are applied they will have the same function
92    # signature.
93    ht1 = c.find('HitTest')
94    ht2 = ht1.overloads[0]
95    ht1.overloads = []
96    c.insertItemAfter(ht1, ht2)
97    ht1.pyName = 'HitTestPos'
98    ht1.find('pos').out = True
99    ht2.find('row').out = True
100    ht2.find('col').out = True
101
102
103    # Replace the *Pointer methods with ones that return a memoryview object instead.
104    c.find('GetCharacterPointer').ignore()
105    c.addCppMethod('PyObject*', 'GetCharacterPointer', '()',
106        doc="""\
107            Compact the document buffer and return a read-only memoryview
108            object of the characters in the document.""",
109        body="""
110            const char* ptr = self->GetCharacterPointer();
111            Py_ssize_t len = self->GetLength();
112            PyObject* rv;
113            wxPyBLOCK_THREADS( rv = wxPyMakeBuffer((void*)ptr, len, true) );
114            return rv;
115            """)
116
117    c.find('GetRangePointer').ignore()
118    c.addCppMethod('PyObject*', 'GetRangePointer', '(int position, int rangeLength)',
119        doc="""\
120            Return a read-only pointer to a range of characters in the
121            document. May move the gap so that the range is contiguous,
122            but will only move up to rangeLength bytes.""",
123        body="""
124            const char* ptr = self->GetRangePointer(position, rangeLength);
125            Py_ssize_t len = rangeLength;
126            PyObject* rv;
127            wxPyBLOCK_THREADS( rv = wxPyMakeBuffer((void*)ptr, len, true) );
128            return rv;
129            """)
130
131
132    # Generate the code for this differently because it needs to be
133    # forcibly mashed into an int in the C code
134    module.find('wxSTC_MASK_FOLDERS').forcedInt = True
135
136
137    # Make sure that all the methods from wxTextEntry and wxTextCtrl are
138    # included. This is needed because we are pretending that this class only
139    # derives from wxControl but the real C++ class also derives from
140    # wxTextCtrlIface which derives from wxTextEntryBase.
141    import textentry
142    mod = textentry.parseAndTweakModule()
143    klass = mod.find('wxTextEntry')
144    items = [item for item in klass.items if isinstance(item, etgtools.MethodDef) and
145                                             not item.isCtor and
146                                             not item.isDtor and
147                                             not c.findItem(item.name)]
148    c.items.extend(items)
149
150    import textctrl
151    mod = textctrl.parseAndTweakModule()
152    klass = mod.find('wxTextCtrl')
153    items = [item for item in klass.items if isinstance(item, etgtools.MethodDef) and
154                                             not item.isCtor and
155                                             not item.isDtor and
156                                             not c.findItem(item.name)]
157    c.items.extend(items)
158
159    c.find('EmulateKeyPress').ignore()
160    c.find('IsMultiLine').ignore()
161    c.find('IsSingleLine').ignore()
162    c.find('MacCheckSpelling').ignore()
163    c.find('ShowNativeCaret').ignore()
164    c.find('HideNativeCaret').ignore()
165
166    # Change the *RGBAImage methods to accept any buffer object
167    c.find('MarkerDefineRGBAImage').ignore()
168    c.addCppMethod('void', 'MarkerDefineRGBAImage', '(int markerNumber, wxPyBuffer* pixels)',
169        doc="""\
170            Define a marker from RGBA data.\n
171            It has the width and height from RGBAImageSetWidth/Height. You must
172            ensure that the buffer is at least width*height*4 bytes long.
173            """,
174        body="""\
175            self->MarkerDefineRGBAImage(markerNumber, (unsigned char*)pixels->m_ptr);
176            """)
177
178    c.find('RegisterRGBAImage').ignore()
179    c.addCppMethod('void', 'RegisterRGBAImage', '(int type, wxPyBuffer* pixels)',
180        doc="""\
181            Register an RGBA image for use in autocompletion lists.\n
182            It has the width and height from RGBAImageSetWidth/Height. You must
183            ensure that the buffer is at least width*height*4 bytes long.
184            """,
185        body="""\
186            self->RegisterRGBAImage(type, (unsigned char*)pixels->m_ptr);
187            """)
188
189
190    # TODO:  Add the UTF8 PyMethods from classic (see _stc_utf8_methods.py)
191
192
193    #-----------------------------------------------------------------
194    c = module.find('wxStyledTextEvent')
195    tools.fixEventClass(c)
196
197    module.addPyCode("""\
198        EVT_STC_CHANGE = wx.PyEventBinder( wxEVT_STC_CHANGE, 1 )
199        EVT_STC_STYLENEEDED = wx.PyEventBinder( wxEVT_STC_STYLENEEDED, 1 )
200        EVT_STC_CHARADDED = wx.PyEventBinder( wxEVT_STC_CHARADDED, 1 )
201        EVT_STC_SAVEPOINTREACHED = wx.PyEventBinder( wxEVT_STC_SAVEPOINTREACHED, 1 )
202        EVT_STC_SAVEPOINTLEFT = wx.PyEventBinder( wxEVT_STC_SAVEPOINTLEFT, 1 )
203        EVT_STC_ROMODIFYATTEMPT = wx.PyEventBinder( wxEVT_STC_ROMODIFYATTEMPT, 1 )
204        EVT_STC_KEY = wx.PyEventBinder( wxEVT_STC_KEY, 1 )
205        EVT_STC_DOUBLECLICK = wx.PyEventBinder( wxEVT_STC_DOUBLECLICK, 1 )
206        EVT_STC_UPDATEUI = wx.PyEventBinder( wxEVT_STC_UPDATEUI, 1 )
207        EVT_STC_MODIFIED = wx.PyEventBinder( wxEVT_STC_MODIFIED, 1 )
208        EVT_STC_MACRORECORD = wx.PyEventBinder( wxEVT_STC_MACRORECORD, 1 )
209        EVT_STC_MARGINCLICK = wx.PyEventBinder( wxEVT_STC_MARGINCLICK, 1 )
210        EVT_STC_NEEDSHOWN = wx.PyEventBinder( wxEVT_STC_NEEDSHOWN, 1 )
211        EVT_STC_PAINTED = wx.PyEventBinder( wxEVT_STC_PAINTED, 1 )
212        EVT_STC_USERLISTSELECTION = wx.PyEventBinder( wxEVT_STC_USERLISTSELECTION, 1 )
213        EVT_STC_URIDROPPED = wx.PyEventBinder( wxEVT_STC_URIDROPPED, 1 )
214        EVT_STC_DWELLSTART = wx.PyEventBinder( wxEVT_STC_DWELLSTART, 1 )
215        EVT_STC_DWELLEND = wx.PyEventBinder( wxEVT_STC_DWELLEND, 1 )
216        EVT_STC_START_DRAG = wx.PyEventBinder( wxEVT_STC_START_DRAG, 1 )
217        EVT_STC_DRAG_OVER = wx.PyEventBinder( wxEVT_STC_DRAG_OVER, 1 )
218        EVT_STC_DO_DROP = wx.PyEventBinder( wxEVT_STC_DO_DROP, 1 )
219        EVT_STC_ZOOM = wx.PyEventBinder( wxEVT_STC_ZOOM, 1 )
220        EVT_STC_HOTSPOT_CLICK = wx.PyEventBinder( wxEVT_STC_HOTSPOT_CLICK, 1 )
221        EVT_STC_HOTSPOT_DCLICK = wx.PyEventBinder( wxEVT_STC_HOTSPOT_DCLICK, 1 )
222        EVT_STC_HOTSPOT_RELEASE_CLICK = wx.PyEventBinder( wxEVT_STC_HOTSPOT_RELEASE_CLICK, 1 )
223        EVT_STC_CALLTIP_CLICK = wx.PyEventBinder( wxEVT_STC_CALLTIP_CLICK, 1 )
224        EVT_STC_AUTOCOMP_SELECTION = wx.PyEventBinder( wxEVT_STC_AUTOCOMP_SELECTION, 1 )
225        EVT_STC_INDICATOR_CLICK = wx.PyEventBinder( wxEVT_STC_INDICATOR_CLICK, 1 )
226        EVT_STC_INDICATOR_RELEASE = wx.PyEventBinder( wxEVT_STC_INDICATOR_RELEASE, 1 )
227        EVT_STC_AUTOCOMP_CANCELLED = wx.PyEventBinder( wxEVT_STC_AUTOCOMP_CANCELLED, 1 )
228        EVT_STC_AUTOCOMP_CHAR_DELETED = wx.PyEventBinder( wxEVT_STC_AUTOCOMP_CHAR_DELETED, 1 )
229        """)
230
231    #-----------------------------------------------------------------
232
233
234    #-----------------------------------------------------------------
235    tools.doCommonTweaks(module)
236    tools.runGenerators(module)
237
238
239
240#---------------------------------------------------------------------------
241
242if __name__ == '__main__':
243    run()
244