Generate CppMethods as a separate function that is called from the wrapper, instead of embedding it in the wrapper itself. This helps us be less SIP-specific and also be able to do things like 'return' the value and use 'self->' instead of having to use variable names that make less sense.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@66348 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2010-12-07 02:58:21 +00:00
parent 75fcd3dcc1
commit 9a7f1269c1
12 changed files with 333 additions and 101 deletions

View File

@@ -62,7 +62,6 @@ def run():
# platforms, and other goodies, then change the c.name so SIP will
# generate code wrapping this class as if it was the wxApp class seen in
# the DoxyXML.
##c.addCppCode(wxPyApp)
c.insertCppCode('src/app_ex.cpp')
for item in c.allItems(): # change the class name, ctors and dtor names
@@ -84,7 +83,7 @@ def run():
doc="Hide all application windows just as the user can do with the\nsystem Hide command. Mac only.",
body="""\
#ifdef __WXMAC__
sipCpp->MacHideApp();
self->MacHideApp();
#endif
""")

View File

@@ -36,18 +36,18 @@ def run():
#ifdef __WXMAC__
#include <wx/osx/private.h>
#endif
""")
module.addCppFunction('wxColour', 'MacThemeColour', '(int themeBrushID)', """\
""")
module.addCppFunction('wxColour*', 'MacThemeColour', '(int themeBrushID)', """\
#ifdef __WXMAC__
sipRes = new wxColour(wxMacCreateCGColorFromHITheme(themeBrushID));
return new wxColour(wxMacCreateCGColorFromHITheme(themeBrushID));
#else
wxPyRaiseNotImplemented();
sipIsErr = 1;
sipRes = NULL;
return NULL;
#endif
""", factory=True)
# Change this macro into a value so we wont have problems when SIP takes its
# address
module.addCppCode("""\
@@ -93,7 +93,7 @@ def run():
c.find('GetPixel').ignore() # We need to add a typcast
c.addCppMethod('wxIntPtr', 'GetPixel', '()', """\
sipRes = (wxIntPtr)sipCpp->GetPixel();
return (wxIntPtr)self->GetPixel();
""")
# Set a flag on the return value and parameter types that are 'unsigned char'
@@ -123,23 +123,23 @@ def run():
c.find('MakeMono.b').out = True
c.addCppMethod('SIP_PYOBJECT', 'Get', '(bool includeAlpha=true)', """\
c.addCppMethod('PyObject*', 'Get', '(bool includeAlpha=true)', """\
int red = -1;
int green = -1;
int blue = -1;
int alpha = wxALPHA_OPAQUE;
if (sipCpp->IsOk()) {
red = sipCpp->Red();
green = sipCpp->Green();
blue = sipCpp->Blue();
alpha = sipCpp->Alpha();
if (self->IsOk()) {
red = self->Red();
green = self->Green();
blue = self->Blue();
alpha = self->Alpha();
}
if (includeAlpha)
sipRes = sipBuildResult(&sipIsErr, "(iiii)", red, green, blue, alpha);
return sipBuildResult(&_isErr, "(iiii)", red, green, blue, alpha);
else
sipRes = sipBuildResult(&sipIsErr, "(iii)", red, green, blue);
return sipBuildResult(&_isErr, "(iii)", red, green, blue);
""", briefDoc="""\
Get(includeAlpha=Valse) -> (r,g,b) or (r,g,b,a)\n
Get(includeAlpha=False) -> (r,g,b) or (r,g,b,a)\n
Returns the RGB intensity values as a tuple, optionally the alpha value as well.""")
@@ -152,7 +152,7 @@ def run():
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, val)',
"""\
if idx == 0: self.red = val
if idx == 0: self.red = val
elif idx == 1: self.green = val
elif idx == 2: self.blue = val
elif idx == 3: self.alpha = val

View File

@@ -133,20 +133,20 @@ def run():
c.find('GetClientData').ignore()
c.find('SetClientData').ignore()
c.addCppMethod('SIP_PYOBJECT', 'GetClientData', '()', """\
wxPyClientData* data = (wxPyClientData*)sipCpp->GetClientObject();
c.addCppMethod('PyObject*', 'GetClientData', '()', """\
wxPyClientData* data = (wxPyClientData*)self->GetClientObject();
if (data) {
Py_INCREF(data->m_obj);
sipRes = data->m_obj;
return data->m_obj;
} else {
Py_INCREF(Py_None);
sipRes = Py_None;
return Py_None;
}
""")
c.addCppMethod('void', 'SetClientData', '(SIP_PYOBJECT clientData)', """\
c.addCppMethod('void', 'SetClientData', '(PyObject* clientData)', """\
wxPyClientData* data = new wxPyClientData(clientData);
sipCpp->SetClientObject(data);
self->SetClientObject(data);
""")

View File

@@ -48,19 +48,33 @@ def run():
assert isinstance(c, etgtools.ClassDef)
tools.removeVirtuals(c)
c.addCppCtor("""(
# TODO: Since the TypeCode is inserted before the derived class
# (sipwxFont) is defined, we can't use the new version of addCppCtor. Can
# this be fixed?
c.addCppCtor_sip("""(
int pointSize,
wxFontFamily family,
int flags = wxFONTFLAG_DEFAULT,
const wxString & faceName = wxEmptyString,
wxFontEncoding encoding = wxFONTENCODING_DEFAULT
)""",
const wxString& faceName = wxEmptyString,
wxFontEncoding encoding = wxFONTENCODING_DEFAULT )""",
body="""\
// YUCK!
wxFont* font = wxFont::New(pointSize, family, flags, *faceName, encoding);
sipCpp = new sipwxFont(*font);
delete font;
""")
# Same as the above, but as a factory function
module.addCppFunction('wxFont*', 'FFont', """(
int pointSize,
wxFontFamily family,
int flags = wxFONTFLAG_DEFAULT,
const wxString& faceName = wxEmptyString,
wxFontEncoding encoding = wxFONTENCODING_DEFAULT )""",
body="""\
wxFont* font = wxFont::New(pointSize, family, flags, *faceName, encoding);
return font;
""", factory=True)
for item in c.findAll('New'):
item.factory = True
@@ -76,6 +90,7 @@ def run():
c.addProperty('Underlined GetUnderlined SetUnderlined')
c.addProperty('Weight GetWeight SetWeight')
#-----------------------------------------------------------------
tools.doCommonTweaks(module)

View File

@@ -104,8 +104,8 @@ def run():
# wxPoint typemap
c.convertFromPyObject = tools.convertTwoIntegersTemplate('wxPoint')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(ii)", sipCpp->x, sipCpp->y);
c.addCppMethod('PyObject*', 'Get', '()', """\
return sipBuildResult(&_isErr, "(ii)", self->x, self->y);
""", briefDoc="""\
Get() -> (x,y)\n
Return the x and y properties as a tuple.""")
@@ -157,8 +157,8 @@ def run():
# wxSize typemap
c.convertFromPyObject = tools.convertTwoIntegersTemplate('wxSize')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(ii)", sipCpp->GetWidth(), sipCpp->GetHeight());
c.addCppMethod('PyObject*', 'Get', '()', """\
return sipBuildResult(&_isErr, "(ii)", self->GetWidth(), self->GetHeight());
""", briefDoc="""\
Get() -> (width, height)\n
Return the width and height properties as a tuple.""")
@@ -183,7 +183,8 @@ def run():
#---------------------------------------
# wxRect tweaks
c = module.find('wxRect')
assert isinstance(c, etgtools.ClassDef)
c.addProperty("left GetLeft")
c.addProperty("top GetTop")
c.addProperty("right GetRight")
@@ -228,9 +229,9 @@ def run():
# wxRect typemap
c.convertFromPyObject = tools.convertFourIntegersTemplate('wxRect')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(iiii)",
sipCpp->x, sipCpp->y, sipCpp->width, sipCpp->height);
c.addCppMethod('PyObject*', 'Get', '()', """\
return sipBuildResult(&_isErr, "(iiii)",
self->x, self->y, self->width, self->height);
""", briefDoc="""\
Get() -> (x, y, width, height)\n
Return the rectangle's properties as a tuple.""")
@@ -277,10 +278,9 @@ def run():
# wxRealPoint typemap
c.convertFromPyObject = tools.convertTwoDoublesTemplate('wxRealPoint')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(dd)",
sipCpp->x, sipCpp->y);
c.addCppMethod('PyObject*', 'Get', '()', """\
return sipBuildResult(&_isErr, "(dd)", self->x, self->y);
""", briefDoc="""\
Get() -> (x, y, width, height)\n
Return the rectangle's properties as a tuple.""")

View File

@@ -59,8 +59,8 @@ def run():
c.convertFromPyObject = tools.convertTwoDoublesTemplate('wxPoint2DDouble')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(dd)", sipCpp->m_x, sipCpp->m_y);
c.addCppMethod('PyObject*', 'Get', '()', """\
return sipBuildResult(&_isErr, "(dd)", self->m_x, self->m_y);
""", briefDoc="""\
Get() -> (x,y)\n
Return the x and y properties as a tuple.""")
@@ -93,7 +93,6 @@ def run():
item.ignore()
c = module.find('wxRect2DDouble')
c.pyName = 'Rect2D'
c.find('m_x').pyName = 'x'
@@ -103,9 +102,9 @@ def run():
c.convertFromPyObject = tools.convertFourDoublesTemplate('wxRect2DDouble')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(dddd)",
sipCpp->m_x, sipCpp->m_y, sipCpp->m_width, sipCpp->m_height);
c.addCppMethod('PyObject*', 'Get', '()', """\
return sipBuildResult(&_isErr, "(dddd)",
self->m_x, self->m_y, self->m_width, self->m_height);
""", briefDoc="""\
Get() -> (x, y, width, height)\n
Return the rectangle's properties as a tuple.""")

View File

@@ -52,11 +52,11 @@ def run():
assert isinstance(c, etgtools.ClassDef)
c.addCppMethod('const wxChar*', 'GetClassName', '()',
body='sipRes = sipCpp->GetClassInfo()->GetClassName();',
body='return self->GetClassInfo()->GetClassName();',
doc='Returns the class name of the C++ class using wxRTTI.')
c.addCppMethod('void', 'Destroy', '()',
body='delete sipCpp;',
body='delete self;',
doc='Deletes the C++ object this Python object is a proxy for.',
transferThis=True) # TODO: Check this

View File

@@ -42,8 +42,8 @@ def run():
c = module.find('wxRegionIterator')
c.find('operator++').ignore()
c.addCppMethod('void', 'Next', '()', 'sipCpp->operator++();')
c.addCppMethod('int', '__nonzero__', '()', 'sipRes = (int)sipCpp->operator bool();')
c.addCppMethod('void', 'Next', '()', 'self->operator++();')
c.addCppMethod('int', '__nonzero__', '()', 'return (int)self->operator bool();')
c.addProperty('H GetH')
c.addProperty('Height GetHeight')

View File

@@ -20,6 +20,9 @@ DOCSTRING = ""
ITEMS = [ 'wxVisualAttributes',
'wxWindow' ]
OTHERDEPS = [ 'src/window_ex.cpp', # some helper C++ code
]
#---------------------------------------------------------------------------
def run():
@@ -30,10 +33,12 @@ def run():
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
c = module.find('wxWindow')
assert isinstance(c, etgtools.ClassDef)
c.insertCppCode('src/window_ex.cpp')
# ignore some overloads that will be ambiguous afer wrapping
c.find('GetChildren').overloads = []
c.find('GetClientSize').findOverload('int *').ignore()
@@ -44,6 +49,10 @@ def run():
c.find('ClientToScreen').findOverload('int *').ignore()
c.find('ScreenToClient').findOverload('int *').ignore()
# Rename these overloads for symmetry with the getters of the same name
c.find('SetSize').findOverload('wxRect').pyName = 'SetRect'
c.find('SetClientSize').findOverload('wxRect').pyName = 'SetClientRect'
m = c.find('GetTextExtent').findOverload('int *')
m.pyName = 'GetFullTextExtent'
m.find('w').out = True
@@ -52,32 +61,82 @@ def run():
m.find('externalLeading').out = True
c.find('GetHandle').type = 'void*'
c.find('GetHandle').setCppCode("sipRes = wxPyGetWinHandle(sipCpp);")
# Rename these overloads for symmetry with the getters of the same name
c.find('SetSize').findOverload('wxRect').pyName = 'SetRect'
c.find('SetClientSize').findOverload('wxRect').pyName = 'SetClientRect'
c.addCppMethod('void*', 'GetGtkWidget', '()', """\
#ifdef __WXGTK__
return (void*)self->GetHandle();
#else
return NULL;
#endif
""")
# Add this method
# Add some new methods
c.addCppMethod('wxWindow*', 'GetTopLevelParent', '()',
'sipRes = wxGetTopLevelParent(sipCpp);')
'return wxGetTopLevelParent(self);')
#c.addCppMethod('wxWindow*', 'FindWindowByLabel', '(const wxString& label)',
# 'return wxWindow::FindWindowByLabel(label, self);')
# TODO: make these be available on Windows, and empty stubs otherwise
c.find('RegisterHotKey').ignore()
c.find('UnregisterHotKey').ignore()
c.addCppMethod('bool', 'MacIsWindowScrollbar', '(const wxWindow* sb)', """\
#ifdef __WXMAC__
return self->MacIsWindowScrollbar(sb);
#else
return false;
#endif
""")
# Make these be available on Windows, and empty stubs otherwise
c.find('RegisterHotKey').setCppCode("""\
#ifdef __WXMSW__
sipRes = sipCpp->RegisterHotKey(hotkeyId, modifiers, virtualKeyCode);
#else
sipRes = false;
#endif
""")
c.find('UnregisterHotKey').setCppCode("""\
#ifdef __WXMSW__
sipRes = sipCpp->UnregisterHotKey(hotkeyId);
#else
sipRes = false;
#endif
""")
c.find('RegisterHotKey').isVirtual = False
c.find('UnregisterHotKey').isVirtual = False
# maybe these too
c.find('SetDoubleBuffered').setCppCode("""\
#if defined(__WXGTK20__) || defined(__WXMSW__)
sipCpp->SetDoubleBuffered(on);
#endif
""")
#%Rename(ConvertDialogPointToPixels, wxPoint, ConvertDialogToPixels(const wxPoint& pt));
#%Rename(ConvertDialogSizeToPixels, wxSize, ConvertDialogToPixels(const wxSize& sz));
#%Rename(ConvertPixelPointToDialog, wxPoint, ConvertPixelsToDialog(const wxPoint& pt));
#%Rename(ConvertPixelSizeToDialog, wxSize, ConvertPixelsToDialog(const wxSize& sz));
# MSW only. Do we want them wrapped?
c.find('GetAccessible').ignore()
c.find('SetAccessible').ignore()
# Make some of the protected methods overridable from Python
# Make some of the protected methods visible and overridable from Python
c.find('DoCentre').ignore(False)
c.find('DoGetBestSize').ignore(False)
c.find('SetInitialBestSize').ignore(False)
c.find('SendDestroyEvent').ignore(False)
c.find('ProcessEvent').ignore(False)
c.addPyMethod('PostCreate', '()', 'pass')
# Define some properties using the getters and setters
# transfer ownership of these parameters to the C++ object
c.find('SetCaret.caret').transfer = True
c.find('SetToolTip.tip').transfer = True
c.find('SetDropTarget.target').transfer = True
c.find('SetConstraints.constraints').transfer = True
c.find('SetSizer.sizer').transfer = True
c.find('SetSizerAndFit.sizer').transfer = True
# Define some properties using the getter and setter methods
c.addProperty('AcceleratorTable GetAcceleratorTable SetAcceleratorTable')
c.addProperty('AutoLayout GetAutoLayout SetAutoLayout')
c.addProperty('BackgroundColour GetBackgroundColour SetBackgroundColour')
@@ -143,9 +202,9 @@ def run():
c.addProperty('MaxClientSize GetMaxClientSize SetMaxClientSize')
tools.fixWindowClass(c)
#-----------------------------------------------------------------
tools.doCommonTweaks(module)
tools.runGenerators(module)

View File

@@ -87,8 +87,6 @@ class BaseDef(object):
raise ExtractorError("Unable to find item named '%s' within %s named '%s'" %
(head, self.__class__.__name__, self.name))
def addItem(self, item):
self.items.append(item)
@@ -155,6 +153,7 @@ class VariableDef(BaseDef):
self.type = None
self.definition = ''
self.argsString = ''
self.pyInt = False
self.__dict__.update(**kw)
if element is not None:
self.extract(element)
@@ -230,7 +229,7 @@ class FunctionDef(BaseDef):
self.extract(element)
def releaseGIL(self, release=True):
self.pyReleaseGIL = hold
self.pyReleaseGIL = release
def extract(self, element):
super(FunctionDef, self).extract(element)
@@ -450,6 +449,9 @@ class ClassDef(BaseDef):
return p
#------------------------------------------------------------------
def addCppMethod(self, type, name, argsString, body, doc=None, **kw):
"""
Add a new C++ method to a class. This method doesn't have to actually
@@ -457,20 +459,42 @@ class ClassDef(BaseDef):
back-end wrapper generator such that it is visible in the class in the
target language.
"""
md = CppMethodDef(type, name, argsString, body, doc, **kw)
md = CppMethodDef(type, name, argsString, body, doc, klass=self, **kw)
self.items.append(md)
return md
def addCppCtor(self, argsString, body, doc=None, noDerivedCtor=True, **kw):
def addCppCtor(self, argsString, body, doc=None, noDerivedCtor=True, useDerivedName=False, **kw):
"""
Add a C++ method that is a constructor.
"""
md = CppMethodDef('', self.name, argsString, body, doc=doc,
isCtor=True, noDerivedCtor=noDerivedCtor, **kw)
isCtor=True, klass=self, noDerivedCtor=noDerivedCtor,
useDerivedName=useDerivedName, **kw)
self.items.append(md)
return md
def addCppMethod_sip(self, type, name, argsString, body, doc=None, **kw):
"""
Just like the above but can do more things that are SIP specific in
the code body, instead of using the general purpose implementation.
"""
md = CppMethodDef_sip(type, name, argsString, body, doc, klass=self, **kw)
self.items.append(md)
return md
def addCppCtor_sip(self, argsString, body, doc=None, noDerivedCtor=True, **kw):
"""
Add a C++ method that is a constructor.
"""
md = CppMethodDef_sip('', self.name, argsString, body, doc=doc,
isCtor=True, klass=self, noDerivedCtor=noDerivedCtor, **kw)
self.items.append(md)
return md
#------------------------------------------------------------------
def addPyMethod(self, name, argsString, body, doc=None, **kw):
"""
@@ -627,9 +651,20 @@ class CppMethodDef(MethodDef):
self.body = body
self.briefDoc = doc
self.protection = 'public'
self.klass = None
self.noDerivedCtor = False
self.__dict__.update(kw)
class CppMethodDef_sip(CppMethodDef):
"""
Just like the above, but instead of generating a new function from the
privided code, the code is used inline inside SIP's %MethodCode directive.
This makes it possible to use additional SIP magic for things that are
beyond the general scope of the other C++ Method implementation.
"""
pass
#---------------------------------------------------------------------------
@@ -784,7 +819,6 @@ class ModuleDef(BaseDef):
return item
def addCppFunction(self, type, name, argsString, body, doc=None, **kw):
"""
@@ -795,6 +829,16 @@ class ModuleDef(BaseDef):
self.items.append(md)
return md
def addCppFunction_sip(self, type, name, argsString, body, doc=None, **kw):
"""
Add a new C++ function into the module that is written by hand, not
wrapped.
"""
md = CppMethodDef_sip(type, name, argsString, body, doc, **kw)
self.items.append(md)
return md
def addPyCode(self, code, order=None):
"""

View File

@@ -12,7 +12,7 @@ The generator class for creating SIP definition files from the data
objects produced by the ETG scripts.
"""
import sys, os
import sys, os, re
import extractors
import generators
from cStringIO import StringIO
@@ -53,7 +53,7 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase):
%%Module(name=%s.%s, use_argument_names=True, language="C++")
{
%%AutoPyName(remove_leading="wx")
}
};
%%Copying
Copyright: (c) 2010 by Total Control Software
@@ -92,12 +92,15 @@ from %s import *
stream.write("%End\n\n")
# %Imports and %Includes
for i in module.imports:
stream.write("%%Import %s.sip\n" % i)
stream.write("\n")
for i in module.includes:
stream.write("%%Include %s.sip\n" % i)
if module.imports:
for i in module.imports:
stream.write("%%Import %s.sip\n" % i)
stream.write("\n")
if module.includes:
for i in module.includes:
stream.write("%%Include %s.sip\n" % i)
stream.write("\n")
# C++ code to be written out to the generated module
if module.cppCode:
stream.write("%ModuleCode\n")
@@ -133,14 +136,15 @@ from %s import *
def generateModuleItems(self, module, stream):
methodMap = {
extractors.ClassDef : self.generateClass,
extractors.FunctionDef : self.generateFunction,
extractors.EnumDef : self.generateEnum,
extractors.GlobalVarDef : self.generateGlobalVar,
extractors.TypedefDef : self.generateTypedef,
extractors.WigCode : self.generateWigCode,
extractors.PyCodeDef : self.generatePyCode,
extractors.CppMethodDef : self.generateCppMethod,
extractors.ClassDef : self.generateClass,
extractors.FunctionDef : self.generateFunction,
extractors.EnumDef : self.generateEnum,
extractors.GlobalVarDef : self.generateGlobalVar,
extractors.TypedefDef : self.generateTypedef,
extractors.WigCode : self.generateWigCode,
extractors.PyCodeDef : self.generatePyCode,
extractors.CppMethodDef : self.generateCppMethod,
extractors.CppMethodDef_sip : self.generateCppMethod_sip,
}
for item in module:
@@ -287,14 +291,15 @@ from %s import *
protected = [i for i in klass if i.protection == 'protected']
dispatch = {
extractors.MemberVarDef : self.generateMemberVar,
extractors.PropertyDef : self.generateProperty,
extractors.MethodDef : self.generateMethod,
extractors.EnumDef : self.generateEnum,
extractors.CppMethodDef : self.generateCppMethod,
extractors.PyMethodDef : self.generatePyMethod,
extractors.PyCodeDef : self.generatePyCode,
extractors.WigCode : self.generateWigCode,
extractors.MemberVarDef : self.generateMemberVar,
extractors.PropertyDef : self.generateProperty,
extractors.MethodDef : self.generateMethod,
extractors.EnumDef : self.generateEnum,
extractors.CppMethodDef : self.generateCppMethod,
extractors.CppMethodDef_sip : self.generateCppMethod_sip,
extractors.PyMethodDef : self.generatePyMethod,
extractors.PyCodeDef : self.generatePyCode,
extractors.WigCode : self.generateWigCode,
# TODO: nested classes too?
}
for item in ctors:
@@ -388,7 +393,94 @@ from %s import *
def generateCppMethod(self, method, stream, indent=''):
# Add a new C++ method to a class. This one adds the code as a
# separate function and then adds a call to that function in the
# MethodCode directive.
assert isinstance(method, extractors.CppMethodDef)
if method.ignored:
return
klass = method.klass
if klass:
assert isinstance(klass, extractors.ClassDef)
# create the new function
fargs = method.argsString.strip('()').split(',')
for idx, arg in enumerate(fargs):
# take only the part before the =, if there is one
arg = arg.split('=')[0].strip()
arg = arg.replace('&', '*') # SIP will always want to use pointers for parameters
fargs[idx] = arg
fargs = ', '.join(fargs)
if fargs:
fargs = ', ' + fargs
if method.isCtor:
fname = '_%s_newCtor' % klass.name
fargs = '(int& _isErr%s)' % fargs
stream.write('%s%%TypeCode\n' % indent)
typ = klass.name
if method.useDerivedName:
typ = 'sip'+klass.name
stream.write('%sclass %s;\n' % (indent, typ)) # forward decalre the derived class
stream.write('%s%s* %s%s\n%s{\n' % (indent, typ, fname, fargs, indent))
stream.write(nci(method.body, len(indent)+4))
stream.write('%s}\n' % indent)
stream.write('%s%%End\n' % indent)
else:
if klass:
fname = '_%s_%s' % (klass.name, method.name)
fargs = '(%s* self, int& _isErr%s)' % (klass.name, fargs)
stream.write('%s%%TypeCode\n' % indent)
else:
fname = '_%s_function' % method.name
fargs = '(int& _isErr%s)' % fargs
stream.write('%s%%ModuleCode\n' % indent)
stream.write('%s%s %s%s\n%s{\n' % (indent, method.type, fname, fargs, indent))
stream.write(nci(method.body, len(indent)+4))
stream.write('%s}\n' % indent)
stream.write('%s%%End\n' % indent)
# now insert the method declaration and the code to call the new function
# find the parameter names
pnames = method.argsString.strip('()').split(',')
for idx, pn in enumerate(pnames):
# take only the part before the =, if there is one
name = pn.split('=')[0].strip()
# now get just the part after and space, * or &, which should be
# the parameter name
name = re.split(r'[ \*\&]+', name)[-1]
pnames[idx] = name
pnames = ', '.join(pnames)
if pnames:
pnames = ', ' + pnames
# convert PyObject* to SIP_PYOBJECT in the return type and param types
typ = method.type.replace('PyObject*', 'SIP_PYOBJECT')
argsString = method.argsString.replace('PyObject*', 'SIP_PYOBJECT')
# spit it all out
if method.isCtor:
stream.write('%s%s%s%s;\n' %
(indent, method.name, argsString, self.annotate(method)))
else:
stream.write('%s%s %s%s%s;\n' %
(indent, typ, method.name, argsString, self.annotate(method)))
stream.write('%s%%MethodCode\n' % indent)
stream.write(indent+' '*4)
if method.isCtor:
stream.write('sipCpp = %s(sipIsErr%s);\n' % (fname, pnames))
else:
if method.type != 'void':
stream.write('sipRes = ')
if klass:
stream.write('%s(sipCpp, sipIsErr%s);\n' % (fname, pnames))
else:
stream.write('%s(sipIsErr%s);\n' % (fname, pnames))
stream.write('%s%%End\n\n' % indent)
def generateCppMethod_sip(self, method, stream, indent=''):
# Add a new C++ method to a class without the extra generated
# function, so SIP specific stuff can be done in the function body.
assert isinstance(method, extractors.CppMethodDef_sip)
if method.ignored:
return
if method.isCtor:
@@ -401,7 +493,8 @@ from %s import *
stream.write('%s%%MethodCode\n' % indent)
stream.write(nci(method.body, len(indent)+4))
stream.write('%s%%End\n\n' % indent)
def generatePyMethod(self, pm, stream, indent):
assert isinstance(pm, extractors.PyMethodDef)
@@ -409,7 +502,7 @@ from %s import *
pm.klass.generateAfterClass.append(pm)
else:
klassName = pm.klass.pyName or pm.klass.name
stream.write("%Extract pycode\n")
stream.write("%Extract(id=pycode)\n")
stream.write("def _%s_%s%s:\n" % (klassName, pm.name, pm.argsString))
if pm.briefDoc:
stream.write(nci('"""\n%s\n"""\n' % pm.briefDoc, 4))
@@ -445,6 +538,10 @@ from %s import *
annotations.append('TranserThis')
if item.pyInt:
annotations.append('PyInt')
if isinstance(item, extractors.VariableDef):
if item.pyInt:
annotations.append('PyInt')
if isinstance(item, extractors.FunctionDef):
if item.deprecated:
@@ -524,4 +621,8 @@ def nci(text, numSpaces=0, stripLeading=True):
return newText
class SipGeneratorError(RuntimeError):
pass
#---------------------------------------------------------------------------

View File

@@ -81,7 +81,22 @@ def fixEventClass(klass):
klass.addPrivateAssignOp()
def fixWindowClass(klass):
"""
Do common tweaks for a window class.
"""
# The ctor and Create method transfer ownership of the this pointer
klass.find('%s.parent' % klass.name).transferThis = True
klass.find('Create.parent').transferThis = True
# give the id param a default value
klass.find('%s.id' % klass.name).default = 'wxID_ANY'
klass.find('Create.id').default = 'wxID_ANY'
# look for wxByte parameters
#for item in klass.allItems():
# if hasattr(item, 'type') and item.type == 'wxByte':
# item.pyInt = True
def removeVirtuals(klass):
"""
Sometimes methods are marked as virtual but probably don't ever need to be