A boatload of changes and additions, all my Phoenix work for the past few days. Lots of lower level classes are wrapped, wxApp is working up through OnInit, plus there's a good start on some unit tests.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@66272 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2010-11-27 08:53:17 +00:00
parent 2279df7926
commit 96717983ad
44 changed files with 3495 additions and 1073 deletions

View File

@@ -51,7 +51,7 @@ class Configuration(object):
SIPOPTS = ' '.join(['-k', # turn on keyword args support
'-o', # turn on auto-docstrings
'-e', # turn on exceptions support
#'-e', # turn on exceptions support
'-T', # turn off writing the timestamp to the generated files
#'-g', # always release and reaquire the GIL
#'-r', # turn on function call tracing
@@ -96,7 +96,7 @@ class Configuration(object):
NO_SCRIPTS = False
# Don't install the tools/script files
PKGDIR = 'wx'
PKGDIR = 'wxPhoenix'
# The name of the top-level package
# ---------------------------------------------------------------
@@ -145,8 +145,10 @@ class Configuration(object):
self.WXDIR = '..' # assumes wxPython is subdir
msg("WARNING: WXWIN not set in environment. Assuming '%s'" % self.WXDIR)
self.includes = ['sip/siplib'] # to get our version of sip.h
self.includes = ['sip/siplib', # to get our version of sip.h
'src', # for any hand-written headers
]
#---------------------------------------
# MSW specific settings
if os.name == 'nt' and self.COMPILER == 'msvc':
@@ -512,10 +514,12 @@ def msg(text):
if not runSilently:
print text
def opj(*args):
path = os.path.join(*args)
return os.path.normpath(path)
def posixjoin(a, *p):
"""Join two or more pathname components, inserting sep as needed"""
path = a
@@ -527,3 +531,20 @@ def posixjoin(a, *p):
else:
path = path + '/' + b
return path
def loadETG(name):
"""
Execute an ETG script so we can load a namespace with its contents (such
as a list of dependencies, etc.) for use by setup.py
"""
class _Namespace(object):
def __init__(self):
self.__dict__['__name__'] = 'namespace'
def nsdict(self):
return self.__dict__
ns = _Namespace()
execfile(name, ns.nsdict())
return ns

View File

@@ -17,9 +17,9 @@ import distutils.command.install
import distutils.command.install_data
import distutils.command.install_headers
import distutils.command.clean
from distutils.dep_util import newer
from distutils.dep_util import newer, newer_group
from config import Config, posixjoin
from config import Config, posixjoin, loadETG
@@ -361,7 +361,11 @@ class etgsip_build_ext(build_ext):
for etg in etg_sources:
sipfile = self.etg2sip(etg)
if newer(etg, sipfile):
deps = [etg]
ns = loadETG(etg)
if hasattr(ns, 'OTHERDEPS'):
deps += ns.OTHERDEPS
if newer_group(deps, sipfile):
cmd = [sys.executable, etg, '--sip']
#if cfg.verbose:
# cmd.append('--verbose')

View File

@@ -1,5 +1,5 @@
#---------------------------------------------------------------------------
# Name: _core.py
# Name: etg/_core.py
# Author: Robin Dunn
#
# Created: 8-Nove-2010
@@ -7,88 +7,245 @@
# License: wxWindows License
#---------------------------------------------------------------------------
PACKAGE = "wx"
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wxPhoenix" # This is just temporary, rename to 'wx' later.
MODULE = "_core"
NAME = "_core" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [
'defs_8h.xml'
]
ITEMS = [ ]
#---------------------------------------------------------------------------
# Parse the XML file(s) building a collection of Extractor objects
import etgtools
import etgtools.tweaker_tools as tools
# The list of other ETG scripts and back-end generator modules that are
# included as part of this module. These items are in their own etg scripts
# for easier maintainability, but their class and function definitions are
# intended to be part of this module, not their own module. This also makes it
# easier to promote one of these to module status later if desired, simply
# remove it from this list of Includes, and change the MODULE value in the
# promoted script to be the same as its NAME.
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
INCLUDES = [ 'defs',
'wxpy_utils',
'string',
'clntdata',
'windowid',
'platinfo',
'display',
'vidmode',
'intl',
'gdiobj',
'font',
'gdicmn',
'geometry',
#---------------------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
'object',
'colour',
'tracker',
'kbdstate',
'mousestate',
'event',
'evtloop',
'apptrait',
'app',
]
module.addHeaderCode('#include <wx/wx.h>')
# These items are in their own etg scripts for easier maintainability,
# but their class and function definitions are intended to be part of
# this module, not their own module. This also makes it easier to
# promote one of these to module status later if desired, simply
# remove it fron this list of Includes, and change the MODULE value in
# the promoted script to be the same as its NAME.
module.addInclude(['string',
'clntdata',
'windowid',
'object',
'tracker',
'kbdstate',
'mousestate',
'event',
'gdicmn',
'geometry',
])
# tweaks for defs.h
module.find('wxInt16').type = 'short'
module.find('wxInt64').type = 'long long'
module.find('wxUint64').type = 'unsigned long long'
module.find('wxIntPtr').type = 'long' #'ssize_t'
module.find('wxUIntPtr').type = 'unsigned long' #'size_t'
module.find('wxDELETE').ignore()
module.find('wxDELETEA').ignore()
module.find('wxSwap').ignore()
module.find('wxVaCopy').ignore()
# add some typedefs for wxChar, wxUChar
td = module.find('wxUIntPtr')
module.insertItemAfter(td, etgtools.TypedefDef(type='wchar_t', name='wxUChar'))
module.insertItemAfter(td, etgtools.TypedefDef(type='wchar_t', name='wxChar'))
# Separate the list into those that are generated from ETG scripts and the
# rest. These lists can be used from setup.py for a list of sources and a list
# of additional dependencies when building this extension module
ETGFILES = ['etg/%s.py' % NAME] + tools.getEtgFiles(INCLUDES)
DEPENDS = tools.getNonEtgFiles(INCLUDES)
OTHERDEPS = [ 'src/core_ex.py' ]
#---------------------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#---------------------------------------------------------------------------
# Run the generators
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
module.addHeaderCode("""\
#if defined(__APPLE__)
// When it's possible that we're building universal binaries with both
// 32-bit and 64-bit architectures then these need to be undefed because
// otherwise the values set by configure could conflict with those set
// based on runtime flags in Python's headers. We also do something
// similar in wx/platform.h so it's okay to undef them now because they
// will be defined again soon.
#undef SIZEOF_VOID_P
#undef SIZEOF_LONG
#undef SIZEOF_SIZE_T
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
// Turn off the warning about converting string literals to char*
// TODO: fix these the right way...
#pragma GCC diagnostic ignored "-Wwrite-strings"
#endif
#ifdef _MSC_VER
#pragma warning(disable:4800)
#pragma warning(disable:4190)
#endif
#include <wx/wx.h>
""")
module.addPyCode("""\
# A little trick to make 'wx' be a reference to this module so wx.Names can
# be used in the python code here.
import sys as _sys
wx = _sys.modules[__name__]
""", order=10)
module.includePyCode('src/core_ex.py')
module.addInclude(INCLUDES)
# This code is inserted into the module initialization function
module.addPostInitializerCode("""
wxPyCoreModuleInject(sipModuleDict);
""")
# Here is the function it calls
module.addCppCode(wxPyCoreModuleInject)
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
wxPyPreInit = """
void wxPyPreInit(PyObject* moduleDict)
{
//#ifdef ISOLATION_AWARE_ENABLED
// wxPySetActivationContext();
//#endif
//#ifdef __WXMSW__
//// wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF
//// | _CRTDBG_CHECK_ALWAYS_DF
//// | _CRTDBG_DELAY_FREE_MEM_DF
//// );
//#endif
//
//#ifdef WXP_WITH_THREAD
//#if wxPyUSE_GIL_STATE
// PyEval_InitThreads();
//#else
// PyEval_InitThreads();
// wxPyTStates = new wxPyThreadStateArray;
// wxPyTMutex = new wxMutex;
//
// // Save the current (main) thread state in our array
// PyThreadState* tstate = wxPyBeginAllowThreads();
// wxPyEndAllowThreads(tstate);
//#endif
//#endif
// Ensure that the build options in the DLL (or whatever) match this build
wxApp::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, "wxPython");
wxInitAllImageHandlers();
}
"""
wxPyCoreModuleInject = """
void wxPyCoreModuleInject(PyObject* moduleDict)
{
// // Create an exception object to use for wxASSERTions
// wxPyAssertionError = PyErr_NewException("wx._core.PyAssertionError",
// PyExc_AssertionError, NULL);
// PyDict_SetItemString(moduleDict, "PyAssertionError", wxPyAssertionError);
//
// // Create an exception object to use when the app object hasn't been created yet
// wxPyNoAppError = PyErr_NewException("wx._core.PyNoAppError",
// PyExc_RuntimeError, NULL);
// PyDict_SetItemString(moduleDict, "PyNoAppError", wxPyNoAppError);
#ifdef __WXGTK__
#define wxPort "__WXGTK__"
#define wxPortName "wxGTK"
#endif
#ifdef __WXMSW__
#define wxPort "__WXMSW__"
#define wxPortName "wxMSW"
#endif
#ifdef __WXMAC__
#define wxPort "__WXMAC__"
#define wxPortName "wxMac"
#endif
PyDict_SetItemString(moduleDict, "Port", PyString_FromString(wxPort));
// Make a tuple of strings that gives more info about the platform and build.
PyObject* PortInfo = PyList_New(0);
PyObject* obj;
#define _AddInfoString(st) \
obj = PyString_FromString(st); \
PyList_Append(PortInfo, obj); \
Py_DECREF(obj)
_AddInfoString(wxPort);
_AddInfoString(wxPortName);
#if wxUSE_UNICODE
_AddInfoString("unicode");
#if wxUSE_UNICODE_WCHAR
_AddInfoString("unicode-wchar");
#else
_AddInfoString("unicode-utf8");
#endif
#else
_AddInfoString("ansi");
#endif
#ifdef __WXOSX__
_AddInfoString("wxOSX");
#endif
#ifdef __WXOSX_CARBON__
_AddInfoString("wxOSX-carbon");
#endif
#ifdef __WXOSX_COCOA__
_AddInfoString("wxOSX-cocoa");
#endif
#ifdef __WXGTK__
#ifdef __WXGTK20__
_AddInfoString("gtk2");
#else
_AddInfoString("gtk1");
#endif
#endif
#ifdef __WXDEBUG__
_AddInfoString("wx-assertions-on");
#else
_AddInfoString("wx-assertions-off");
#endif
#undef _AddInfoString
PyObject* PortInfoTuple = PyList_AsTuple(PortInfo);
Py_DECREF(PortInfo);
PyDict_SetItemString(moduleDict, "PortInfo", PortInfoTuple);
}
"""
if __name__ == '__main__':
run()

158
etg/app.py Normal file
View File

@@ -0,0 +1,158 @@
#---------------------------------------------------------------------------
# Name: etg/app.py
# Author: Robin Dunn
#
# Created:
# Copyright: (c) 2010 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "app" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [ 'wxAppConsole',
'wxApp',
]
OTHERDEPS = [ 'src/app_ex.py', # Some extra app-related Python code
'src/app_ex.cpp', # and some C++ code too
]
#---------------------------------------------------------------------------
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
c = module.find('wxAppConsole')
assert isinstance(c, etgtools.ClassDef)
# There's no need for the command line stuff as Python has its own ways to
# deal with that
c.find('argc').ignore()
c.find('argv').ignore()
c.find('OnCmdLineError').ignore()
c.find('OnCmdLineHelp').ignore()
c.find('OnCmdLineParsed').ignore()
c.find('OnInitCmdLine').ignore()
c.find('HandleEvent').ignore()
c.addProperty('AppDisplayName GetAppDisplayName SetAppDisplayName')
c.addProperty('AppName GetAppName SetAppName')
c.addProperty('ClassName GetClassName SetClassName')
c.addProperty('VendorDisplayName GetVendorDisplayName SetVendorDisplayName')
c.addProperty('VendorName GetVendorName SetVendorName')
c = module.find('wxApp')
# Add a new C++ wxPyApp class that adds empty Mac* methods for other
# 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
if item.name == 'wxApp':
item.name = 'wxPyApp'
if item.name == '~wxApp':
item.name = '~wxPyApp'
c.find('ProcessMessage').ignore()
c.addProperty('DisplayMode GetDisplayMode SetDisplayMode')
c.addProperty('ExitOnFrameDelete GetExitOnFrameDelete SetExitOnFrameDelete')
c.addProperty('LayoutDirection GetLayoutDirection')
c.addProperty('UseBestVisual GetUseBestVisual SetUseBestVisual')
c.addProperty('TopWindow GetTopWindow SetTopWindow')
c.addCppMethod('void', 'MacHideApp', '()',
doc="Hide all application windows just as the user can do with the\nsystem Hide command. Mac only.",
body="""\
#ifdef __WXMAC__
sipCpp->MacHideApp();
#endif
""")
# Methods we implement in wxPyApp beyond what are in wxApp
c.addItem(etgtools.WigCode("""\
wxAppAssertMode GetAssertMode();
void SetAssertMode(wxAppAssertMode mode);
void _BootstrapApp();
virtual void OnPreInit();
virtual bool OnInit();
static bool IsDisplayAvailable();
"""))
appHeaderCode = """\
enum wxAppAssertMode{
wxPYAPP_ASSERT_SUPPRESS = 1,
wxPYAPP_ASSERT_EXCEPTION = 2,
wxPYAPP_ASSERT_DIALOG = 4,
wxPYAPP_ASSERT_LOG = 8
};
"""
# Add it to both the header and the generator files
module.insertItemBefore(c, etgtools.WigCode(appHeaderCode))
module.addHeaderCode(appHeaderCode)
module.addHeaderCode("""\
class wxPyApp;
wxPyApp* wxGetApp();
""")
module.insertItemAfter(c, etgtools.WigCode("""\
wxPyApp* wxGetApp();
"""))
# This includes Python code for the on-demand output window, the Python
# derived wx.App class, etc.
module.includePyCode('src/app_ex.py')
module.find('wxTheApp').ignore()
module.find('wxGetApp').ignore()
module.find('wxInitialize').ignore()
module.find('wxUninitialize').ignore()
for item in module.allItems():
if item.name == 'wxEntry':
item.ignore()
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()

67
etg/apptrait.py Normal file
View File

@@ -0,0 +1,67 @@
#---------------------------------------------------------------------------
# Name: etg/apptrait.py
# Author: Robin Dunn
#
# Created: 22-Nov-2010
# Copyright: (c) 2010 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "apptrait" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [ 'wxAppTraits' ]
#---------------------------------------------------------------------------
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
c = module.find('wxAppTraits')
assert isinstance(c, etgtools.ClassDef)
c.abstract = True
# TODO: Enable these as their return types are added
for name in [ 'CreateConfig',
'CreateEventLoop',
'CreateFontMapper',
'CreateLogTarget',
'CreateMessageOutput',
'CreateRenderer',
'GetStandardPaths' ]:
c.find(name).ignore()
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()

298
etg/colour.py Normal file
View File

@@ -0,0 +1,298 @@
#---------------------------------------------------------------------------
# Name: etc/colour.py
# Author: Robin Dunn
#
# Created: 19-Nov-2010
# Copyright: (c) 2010 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "colour" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [ 'wxColour' ]
#---------------------------------------------------------------------------
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
# Add a ctor/factory for the Mac that can use the theme brush
module.addCppCode("""\
#ifdef __WXMAC__
#include <wx/osx/carbon/private.h>
#endif
""")
module.addCppFunction('wxColour', 'MacThemeColour', '(int themeBrushID)', """\
#ifdef __WXMAC__
sipRes = new wxColour(wxMacCreateCGColorFromHITheme(themeBrushID));
#else
wxPyRaiseNotImplemented();
sipIsErr = 1;
sipRes = NULL;
#endif
""", factory=True)
# Change this macro into a value so we wont have problems when SIP takes its
# address
module.addCppCode("""\
#undef wxTransparentColour
wxColour wxTransparentColour(0, 0, 0, wxALPHA_TRANSPARENT);
""")
module.find('wxFromString').ignore()
module.find('wxToString').ignore()
# TODO: fix this?
for name in [ 'wxBLACK',
'wxBLUE',
'wxCYAN',
'wxGREEN',
'wxYELLOW',
'wxLIGHT_GREY',
'wxRED',
'wxWHITE',
]:
module.find(name).ignore()
module.find('wxALPHA_TRANSPARENT').type = 'const int'
module.find('wxALPHA_OPAQUE').type = 'const int'
c = module.find('wxColour')
assert isinstance(c, etgtools.ClassDef)
tools.removeVirtuals(c)
# Hide the string ctor so our typemap will be invoked for the copy ctor instead.
c.find('wxColour').findOverload('wxString').ignore()
c.addProperty('Pixel GetPixel')
c.addProperty('RGB GetRGB SetRGB')
c.addProperty('RGBA GetRGBA SetRGBA')
c.addProperty('red Red')
c.addProperty('green Green')
c.addProperty('blue Blue')
c.addProperty('alpha Alpha')
c.find('GetPixel').ignore() # We need to add a typcast
c.addCppMethod('wxIntPtr', 'GetPixel', '()', """\
sipRes = (wxIntPtr)sipCpp->GetPixel();
""")
# Set a flag on the return value and parameter types that are 'unsigned char'
# such that they will be treated as an integer instead of a string.
for item in c.allItems():
if hasattr(item, 'type') and item.type == 'unsigned char':
item.pyInt = True
c.find('ChangeLightness.r').inOut = True
c.find('ChangeLightness.g').inOut = True
c.find('ChangeLightness.b').inOut = True
c.find('MakeDisabled.r').inOut = True
c.find('MakeDisabled.g').inOut = True
c.find('MakeDisabled.b').inOut = True
c.find('MakeGrey.r').inOut = True
c.find('MakeGrey.g').inOut = True
c.find('MakeGrey.b').inOut = True
c.find('MakeGrey').findOverload('double').find('r').inOut = True
c.find('MakeGrey').findOverload('double').find('g').inOut = True
c.find('MakeGrey').findOverload('double').find('b').inOut = True
c.find('MakeMono.r').out = True
c.find('MakeMono.g').out = True
c.find('MakeMono.b').out = True
c.addCppMethod('SIP_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 (includeAlpha)
sipRes = sipBuildResult(&sipIsErr, "(iiii)", red, green, blue, alpha);
else
sipRes = sipBuildResult(&sipIsErr, "(iii)", red, green, blue);
""", briefDoc="""\
Get(includeAlpha=Valse) -> (r,g,b) or (r,g,b,a)\n
Returns the RGB intensity values as a tuple, optionally the alpha value as well.""")
# Add sequence protocol methods and other goodies
c.addPyMethod('__str__', '(self)', 'return str(self.Get())')
c.addPyMethod('__repr__', '(self)', 'return "wx.Colour"+str(self.Get())')
c.addPyMethod('__len__', '(self)', 'return len(self.Get())')
c.addPyMethod('__nonzero__', '(self)', 'return self.IsOk()')
c.addPyMethod('__reduce__', '(self)', 'return (Colour, self.Get())')
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, 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
else: raise IndexError
""")
c.addPyCode('Rect.__safe_for_unpickling__ = True')
# Types that can be converted to wx.Colour:
# wxColour (duh)
# Sequence with 3 or 4 integers
# String with color name or #RRGGBB or #RRGGBBAA format
# None (converts to wxNullColour)
c.allowNone = True
c.convertFromPyObject = """\
// is it just a typecheck?
if (!sipIsErr) {
if (sipPy == Py_None)
return 1;
if (sipCanConvertToType(sipPy, sipType_wxColour, SIP_NO_CONVERTORS))
return 1;
if (PyString_Check(sipPy) || PyUnicode_Check(sipPy))
return 1;
if (PySequence_Check(sipPy)) {
size_t len = PySequence_Size(sipPy);
if (len != 3 && len != 4)
return 0;
// ensure all the items in the sequence are numbers
for (int idx=0; idx<len; idx+=1) {
PyObject* o = PySequence_ITEM(sipPy, idx);
bool isNum = PyNumber_Check(o);
Py_DECREF(o);
if (!isNum)
return 0;
}
return 1;
}
return 0;
}
// otherwise do the conversion
// is it None?
if (sipPy == Py_None) {
*sipCppPtr = new wxColour(wxNullColour);
return sipGetState(sipTransferObj);
}
// Is it a string?
else if (PyString_Check(sipPy) || PyUnicode_Check(sipPy)) {
wxString spec = Py2wxString(sipPy);
if (spec.GetChar(0) == '#'
&& (spec.length() == 7 || spec.length() == 9)) { // It's #RRGGBB[AA]
long red, green, blue;
red = green = blue = 0;
spec.Mid(1,2).ToLong(&red, 16);
spec.Mid(3,2).ToLong(&green, 16);
spec.Mid(5,2).ToLong(&blue, 16);
if (spec.length() == 7) // no alpha
*sipCppPtr = new wxColour(red, green, blue);
else { // yes alpha
long alpha;
spec.Mid(7,2).ToLong(&alpha, 16);
*sipCppPtr = new wxColour(red, green, blue, alpha);
}
return sipGetState(sipTransferObj);
}
else { // assume it's a colour name
// check if alpha is there too
int pos;
if (((pos = spec.Find(':', true)) != wxNOT_FOUND) && (pos == spec.length()-3)) {
long alpha;
spec.Right(2).ToLong(&alpha, 16);
wxColour c = wxColour(spec.Left(spec.length()-3));
*sipCppPtr = new wxColour(c.Red(), c.Green(), c.Blue(), alpha);
}
else
*sipCppPtr = new wxColour(spec);
return sipGetState(sipTransferObj);
}
}
// Is it a 3 or 4 element sequence?
else if (PySequence_Check(sipPy)) {
size_t len = PyObject_Length(sipPy);
PyObject* o1 = PySequence_GetItem(sipPy, 0);
PyObject* o2 = PySequence_GetItem(sipPy, 1);
PyObject* o3 = PySequence_GetItem(sipPy, 2);
if (len == 3)
*sipCppPtr = new wxColour(PyInt_AsLong(o1), PyInt_AsLong(o2), PyInt_AsLong(o3));
else {
PyObject* o4 = PySequence_GetItem(sipPy, 3);
*sipCppPtr = new wxColour(PyInt_AsLong(o1), PyInt_AsLong(o2), PyInt_AsLong(o3),
PyInt_AsLong(o4));
Py_DECREF(o4);
}
Py_DECREF(o1);
Py_DECREF(o2);
Py_DECREF(o3);
return sipGetState(sipTransferObj);
}
// if we get this far then it must already be a wxColour instance
*sipCppPtr = reinterpret_cast<wxColour*>(sipConvertToType(
sipPy, sipType_wxColour, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr));
return sipGetState(sipTransferObj);
"""
# Just for TESTING, remove it later
module.addCppCode("""\
wxColour testColourTypeMap(const wxColour& c)
{
return c;
}
extern void wxInitializeStockLists();
""")
module.addItem(etgtools.WigCode("""\
wxColour testColourTypeMap(const wxColour& c);
void wxInitializeStockLists();
"""))
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()

97
etg/defs.py Normal file
View File

@@ -0,0 +1,97 @@
#---------------------------------------------------------------------------
# Name: etg/defs.py
# Author: Robin Dunn
#
# Created: 19-Nov-2010
# Copyright: (c) 2010 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "defs" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [ 'defs_8h.xml' ]
#---------------------------------------------------------------------------
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
# tweaks for defs.h
module.find('wxInt16').type = 'short'
module.find('wxInt64').type = 'long long'
module.find('wxUint64').type = 'unsigned long long'
module.find('wxIntPtr').type = 'long' #'ssize_t'
module.find('wxUIntPtr').type = 'unsigned long' #'size_t'
module.find('wxDELETE').ignore()
module.find('wxDELETEA').ignore()
module.find('wxSwap').ignore()
module.find('wxVaCopy').ignore()
# add some typedefs for wxChar, wxUChar
td = module.find('wxUIntPtr')
module.insertItemAfter(td, etgtools.TypedefDef(type='wchar_t', name='wxUChar'))
module.insertItemAfter(td, etgtools.TypedefDef(type='wchar_t', name='wxChar'))
# Remove these when the classes are added for real
module.insertItem(0, etgtools.WigCode("class wxWindow; // forward declaration"))
module.insertItem(0, etgtools.WigCode("class wxDC; // forward declaration"))
module.insertItem(0, etgtools.WigCode("class wxMenu; // forward declaration"))
module.insertItem(0, etgtools.WigCode("class wxCursor; // forward declaration"))
# TBD: I've always disliked the WXK_* names. Should I rename all the items
# in the wxKeyCode enum to be KEY_* names?
# Add some code for getting the version numbers
module.addCppCode("""
#include <wx/version.h>
const int MAJOR_VERSION = wxMAJOR_VERSION;
const int MINOR_VERSION = wxMINOR_VERSION;
const int RELEASE_NUMBER = wxRELEASE_NUMBER;
const int SUBRELEASE_NUMBER = wxSUBRELEASE_NUMBER;
""")
module.addItem(etgtools.WigCode("""
const int MAJOR_VERSION;
const int MINOR_VERSION;
const int RELEASE_NUMBER;
const int SUBRELEASE_NUMBER;
"""))
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()

66
etg/display.py Normal file
View File

@@ -0,0 +1,66 @@
#---------------------------------------------------------------------------
# Name: etg/display.py
# Author: Robin Dunn
#
# Created:
# Copyright: (c) 2010 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "display" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [ 'wxDisplay', ]
#---------------------------------------------------------------------------
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
module.addHeaderCode("#include <wx/display.h>")
c = module.find('wxDisplay')
assert isinstance(c, etgtools.ClassDef)
c.addPrivateAssignOp()
c.addPrivateCopyCtor()
# TODO: SIP needs to know about wxArrayVideoModes before we can enable this
c.find('GetModes').ignore()
c.addProperty('ClientArea GetClientArea')
c.addProperty('CurrentMode GetCurrentMode')
c.addProperty('Geometry GetGeometry')
c.addProperty('Name GetName')
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()

View File

@@ -7,6 +7,9 @@
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "event" # Base name of the file to generate to for this script
@@ -61,267 +64,262 @@ ITEMS = [
]
#---------------------------------------------------------------------------
# Parse the XML file(s) building a collection of Extractor objects
import etgtools
import etgtools.tweaker_tools as tools
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#---------------------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
module.addCppCode("""
#if !wxUSE_HOTKEY
#define wxEVT_HOTKEY 0
#endif
""")
module.insertItem(0, etgtools.WigCode("class wxWindow; // forward declaration"))
module.insertItem(0, etgtools.WigCode("class wxDC; // forward declaration"))
module.insertItem(0, etgtools.WigCode("class wxMenu; // forward declaration"))
module.insertItem(0, etgtools.WigCode("class wxCursor; // forward declaration"))
# TODO:
# * PyEventBinder class
# * event binder instances for all the event types implemented here
# * Connect, Bind etc. methods for EvtHandler
#---------------------------------------
# wxEvtHandler
c = module.find('wxEvtHandler')
c.addPrivateCopyCtor()
# Ignore the Connect/Disconnect and Bind/Unbind methods (and overloads) for now.
for item in c.allItems():
if item.name in ['Connect', 'Disconnect', 'Bind', 'Unbind']:
item.ignore()
# wxEventTable is not documented so we have to ignore SearchEventTable.
# TODO: Should wxEventTable be available to language bindings?
c.find('SearchEventTable').ignore()
# TODO: If we don't need to use the wxEvtHandler's client data for our own
# tracking then enable these....
c.find('GetClientObject').ignore()
c.find('SetClientObject').ignore()
c.find('GetClientData').ignore()
c.find('SetClientData').ignore()
#---------------------------------------
# wxEvent
c = module.find('wxEvent')
assert isinstance(c, etgtools.ClassDef)
c.abstract = True
c.find('Clone').factory = True
c.addProperty('EventObject GetEventObject SetEventObject')
c.addProperty('EventType GetEventType SetEventType')
c.addProperty('Id GetId SetId')
c.addProperty('Skipped GetSkipped')
c.addProperty('Timestamp GetTimestamp SetTimestamp')
#---------------------------------------
# wxCommandEvent
c = module.find('wxCommandEvent')
c.find('GetClientObject').ignore()
c.find('SetClientObject').ignore()
c.find('GetClientData').ignore()
c.find('SetClientData').ignore()
c.addCppMethod('SIP_PYOBJECT', 'GetClientData', '()', """\
wxPyClientData* data = (wxPyClientData*)sipCpp->GetClientObject();
if (data) {
Py_INCREF(data->m_obj);
sipRes = data->m_obj;
} else {
Py_INCREF(Py_None);
sipRes = Py_None;
}
""")
c.addCppMethod('void', 'SetClientData', '(SIP_PYOBJECT clientData)', """\
wxPyClientData* data = new wxPyClientData(clientData);
sipCpp->SetClientObject(data);
""")
c.addProperty('ClientData GetClientData SetClientData')
c.addProperty('ExtraLong GetExtraLong SetExtraLong')
c.addProperty('Int GetInt SetInt')
c.addProperty('Selection GetSelection')
c.addProperty('String GetString SetString')
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
module.addCppCode("""
#if !wxUSE_HOTKEY
#define wxEVT_HOTKEY 0
#endif
""")
# TODO:
# * PyEventBinder class
# * event binder instances for all the event types implemented here
# * Connect, Bind etc. methods for EvtHandler
#---------------------------------------
# wxEvtHandler
c = module.find('wxEvtHandler')
c.addPrivateCopyCtor()
# Ignore the Connect/Disconnect and Bind/Unbind methods (and overloads) for now.
for item in c.allItems():
if item.name in ['Connect', 'Disconnect', 'Bind', 'Unbind']:
item.ignore()
# wxEventTable is not documented so we have to ignore SearchEventTable.
# TODO: Should wxEventTable be available to language bindings?
c.find('SearchEventTable').ignore()
# TODO: If we don't need to use the wxEvtHandler's client data for our own
# tracking then enable these....
c.find('GetClientObject').ignore()
c.find('SetClientObject').ignore()
c.find('GetClientData').ignore()
c.find('SetClientData').ignore()
#---------------------------------------
# wxEvent
c = module.find('wxEvent')
assert isinstance(c, etgtools.ClassDef)
c.abstract = True
c.find('Clone').factory = True
c.addProperty('EventObject GetEventObject SetEventObject')
c.addProperty('EventType GetEventType SetEventType')
c.addProperty('Id GetId SetId')
c.addProperty('Skipped GetSkipped')
c.addProperty('Timestamp GetTimestamp SetTimestamp')
#---------------------------------------
# wxCommandEvent
c = module.find('wxCommandEvent')
c.find('GetClientObject').ignore()
c.find('SetClientObject').ignore()
c.find('GetClientData').ignore()
c.find('SetClientData').ignore()
c.addCppMethod('SIP_PYOBJECT', 'GetClientData', '()', """\
wxPyClientData* data = (wxPyClientData*)sipCpp->GetClientObject();
if (data) {
Py_INCREF(data->m_obj);
sipRes = data->m_obj;
} else {
Py_INCREF(Py_None);
sipRes = Py_None;
}
""")
c.addCppMethod('void', 'SetClientData', '(SIP_PYOBJECT clientData)', """\
wxPyClientData* data = new wxPyClientData(clientData);
sipCpp->SetClientObject(data);
""")
c.addProperty('ClientData GetClientData SetClientData')
c.addProperty('ExtraLong GetExtraLong SetExtraLong')
c.addProperty('Int GetInt SetInt')
c.addProperty('Selection GetSelection')
c.addProperty('String GetString SetString')
#---------------------------------------
# wxKeyEvent
c = module.find('wxKeyEvent')
c.find('GetPosition').findOverload('long').ignore()
c.addProperty('X GetX')
c.addProperty('Y GetY')
c.addProperty('KeyCode GetKeyCode')
c.addProperty('Position GetPosition')
c.addProperty('RawKeyCode GetRawKeyCode')
c.addProperty('RawKeyFlags GetRawKeyFlags')
c.addProperty('UnicodeKey GetUnicodeKey')
#---------------------------------------
# wxScrollEvent
c = module.find('wxScrollEvent')
c.addProperty('Orientation GetOrientation SetOrientation')
c.addProperty('Position GetPosition SetPosition')
#---------------------------------------
# wxScrollWinEvent
c = module.find('wxScrollWinEvent')
c.addProperty('Orientation GetOrientation SetOrientation')
c.addProperty('Position GetPosition SetPosition')
#---------------------------------------
# wxMouseEvent
c = module.find('wxMouseEvent')
c.addProperty('LinesPerAction GetLinesPerAction')
c.addProperty('LogicalPosition GetLogicalPosition')
c.addProperty('WheelDelta GetWheelDelta')
c.addProperty('WheelRotation GetWheelRotation')
#---------------------------------------
# wxSetCursorEvent
c = module.find('wxSetCursorEvent')
c.addProperty('Cursor GetCursor SetCursor')
c.addProperty('X GetX')
c.addProperty('Y GetY')
#---------------------------------------
# wxSizeEvent
c = module.find('wxSizeEvent')
c.addProperty('Rect GetRect SetRect')
c.addProperty('Size GetSize SetSize')
#---------------------------------------
# wxMoveEvent
c = module.find('wxMoveEvent')
c.addProperty('Rect GetRect SetRect')
c.addProperty('Position GetPosition SetPosition')
#---------------------------------------
# wxEraseEvent
c = module.find('wxEraseEvent')
c.addProperty('DC GetDC')
#---------------------------------------
# wxFocusEvent
c = module.find('wxFocusEvent')
c.addProperty('Window GetWindow SetWindow')
#---------------------------------------
# wxChildFocusEvent
c = module.find('wxChildFocusEvent')
c.addProperty('Window GetWindow')
#---------------------------------------
# wxActivateEvent
c = module.find('wxActivateEvent')
c.addProperty('Active GetActive')
#---------------------------------------
# wxMenuEvent
c = module.find('wxMenuEvent')
c.addProperty('Menu GetMenu')
c.addProperty('MenuId GetMenuId')
#---------------------------------------
# wxShowEvent
c = module.find('wxShowEvent')
c.find('GetShow').ignore() # deprecated
c.addProperty('Show IsShown SetShow')
#---------------------------------------
# wxDropFilesEvent
c = module.find('wxDropFilesEvent')
c.addProperty('Files GetFiles')
c.addProperty('NumberOfFiles GetNumberOfFiles')
c.addProperty('Position GetPosition')
#---------------------------------------
# wxUpdateUIEvent
c = module.find('wxUpdateUIEvent')
c.addProperty('Checked GetChecked Check')
c.addProperty('Enabled GetEnabled Enable')
c.addProperty('Shown GetShown Show')
c.addProperty('Text GetText SetText')
#---------------------------------------
# wxMouseCaptureChangedEvent
c = module.find('wxMouseCaptureChangedEvent')
c.addProperty('CapturedWindow GetCapturedWindow')
#---------------------------------------
# wxPaletteChangedEvent
c = module.find('wxPaletteChangedEvent')
c.addProperty('ChangedWindow GetChangedWindow SetChangedWindow')
#---------------------------------------
# wxQueryNewPaletteEvent
c = module.find('wxQueryNewPaletteEvent')
c.addProperty('PaletteRealized GetPaletteRealized SetPaletteRealized')
#---------------------------------------
# wxNavigationKeyEvent
c = module.find('wxNavigationKeyEvent')
c.addProperty('CurrentFocus GetCurrentFocus SetCurrentFocus')
c.addProperty('Direction GetDirection SetDirection')
#---------------------------------------
# wxWindowCreateEvent
c = module.find('wxWindowCreateEvent')
c.addProperty('Window GetWindow')
#---------------------------------------
# wxWindowDestroyEvent
c = module.find('wxWindowDestroyEvent')
c.addProperty('Window GetWindow')
#---------------------------------------
# wxContextMenuEvent
c = module.find('wxContextMenuEvent')
c.addProperty('Position GetPosition SetPosition')
#---------------------------------------
# wxIconizeEvent
module.find('wxIconizeEvent.Iconized').deprecated = True
# Apply common fixups for all the event classes
for name in [n for n in ITEMS if n.endswith('Event')]:
c = module.find(name)
tools.fixEventClass(c)
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------
# wxKeyEvent
c = module.find('wxKeyEvent')
c.find('GetPosition').findOverload('long').ignore()
c.addProperty('X GetX')
c.addProperty('Y GetY')
c.addProperty('KeyCode GetKeyCode')
c.addProperty('Position GetPosition')
c.addProperty('RawKeyCode GetRawKeyCode')
c.addProperty('RawKeyFlags GetRawKeyFlags')
c.addProperty('UnicodeKey GetUnicodeKey')
#---------------------------------------
# wxScrollEvent
c = module.find('wxScrollEvent')
c.addProperty('Orientation GetOrientation SetOrientation')
c.addProperty('Position GetPosition SetPosition')
#---------------------------------------
# wxScrollWinEvent
c = module.find('wxScrollWinEvent')
c.addProperty('Orientation GetOrientation SetOrientation')
c.addProperty('Position GetPosition SetPosition')
#---------------------------------------
# wxMouseEvent
c = module.find('wxMouseEvent')
c.addProperty('LinesPerAction GetLinesPerAction')
c.addProperty('LogicalPosition GetLogicalPosition')
c.addProperty('WheelDelta GetWheelDelta')
c.addProperty('WheelRotation GetWheelRotation')
#---------------------------------------
# wxSetCursorEvent
c = module.find('wxSetCursorEvent')
c.addProperty('Cursor GetCursor SetCursor')
c.addProperty('X GetX')
c.addProperty('Y GetY')
#---------------------------------------
# wxSizeEvent
c = module.find('wxSizeEvent')
c.addProperty('Rect GetRect SetRect')
c.addProperty('Size GetSize SetSize')
#---------------------------------------
# wxMoveEvent
c = module.find('wxMoveEvent')
c.addProperty('Rect GetRect SetRect')
c.addProperty('Position GetPosition SetPosition')
#---------------------------------------
# wxEraseEvent
c = module.find('wxEraseEvent')
c.addProperty('DC GetDC')
#---------------------------------------
# wxFocusEvent
c = module.find('wxFocusEvent')
c.addProperty('Window GetWindow SetWindow')
#---------------------------------------
# wxChildFocusEvent
c = module.find('wxChildFocusEvent')
c.addProperty('Window GetWindow')
#---------------------------------------
# wxActivateEvent
c = module.find('wxActivateEvent')
c.addProperty('Active GetActive')
#---------------------------------------
# wxMenuEvent
c = module.find('wxMenuEvent')
c.addProperty('Menu GetMenu')
c.addProperty('MenuId GetMenuId')
#---------------------------------------
# wxShowEvent
c = module.find('wxShowEvent')
c.addProperty('Show IsShown SetShow')
#---------------------------------------
# wxDropFilesEvent
c = module.find('wxDropFilesEvent')
c.addProperty('Files GetFiles')
c.addProperty('NumberOfFiles GetNumberOfFiles')
c.addProperty('Position GetPosition')
#---------------------------------------
# wxUpdateUIEvent
c = module.find('wxUpdateUIEvent')
c.addProperty('Checked GetChecked Check')
c.addProperty('Enabled GetEnabled Enable')
c.addProperty('Shown GetShown Show')
c.addProperty('Text GetText SetText')
#---------------------------------------
# wxMouseCaptureChangedEvent
c = module.find('wxMouseCaptureChangedEvent')
c.addProperty('CapturedWindow GetCapturedWindow')
#---------------------------------------
# wxPaletteChangedEvent
c = module.find('wxPaletteChangedEvent')
c.addProperty('ChangedWindow GetChangedWindow SetChangedWindow')
#---------------------------------------
# wxQueryNewPaletteEvent
c = module.find('wxQueryNewPaletteEvent')
c.addProperty('PaletteRealized GetPaletteRealized SetPaletteRealized')
#---------------------------------------
# wxNavigationKeyEvent
c = module.find('wxNavigationKeyEvent')
c.addProperty('CurrentFocus GetCurrentFocus SetCurrentFocus')
c.addProperty('Direction GetDirection SetDirection')
#c.addProperty('FromTab IsFromTab SetFromTab')
#c.addProperty('WindowChange IsWindowChange SetWindowChange')
# ignore the copy ctor because we'll be adding a private one below
c.find('wxNavigationKeyEvent').findOverload('const wxNavigationKeyEvent').ignore()
#---------------------------------------
# wxWindowCreateEvent
c = module.find('wxWindowCreateEvent')
c.addProperty('Window GetWindow')
#---------------------------------------
# wxWindowDestroyEvent
c = module.find('wxWindowDestroyEvent')
c.addProperty('Window GetWindow')
#---------------------------------------
# wxContextMenuEvent
c = module.find('wxContextMenuEvent')
c.addProperty('Position GetPosition SetPosition')
# Apply common fixups for all the event classes
for name in [n for n in ITEMS if n.endswith('Event')]:
c = module.find(name)
tools.fixEventClass(c)
#---------------------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#---------------------------------------------------------------------------
# Run the generators
if __name__ == '__main__':
run()
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------

56
etg/evtloop.py Normal file
View File

@@ -0,0 +1,56 @@
#---------------------------------------------------------------------------
# Name: etg/evtloop.py
# Author: Robin Dunn
#
# Created: 22-Nov-2010
# Copyright: (c) 2010 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "evtloop" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [ 'wxEventLoopBase' ]
#---------------------------------------------------------------------------
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
c = module.find('wxEventLoopBase')
assert isinstance(c, etgtools.ClassDef)
c.abstract = True
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()

96
etg/font.py Normal file
View File

@@ -0,0 +1,96 @@
#---------------------------------------------------------------------------
# Name: etg/font.py
# Author: Robin Dunn
#
# Created:
# Copyright: (c) 2010 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "font" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [ 'wxFont',
#'wxFontList',
]
#---------------------------------------------------------------------------
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
module.find('wxFromString').ignore()
module.find('wxToString').ignore()
# TODOs
module.find('wxTheFontList').ignore()
module.find('wxNORMAL_FONT').ignore()
module.find('wxSMALL_FONT').ignore()
module.find('wxITALIC_FONT').ignore()
module.find('wxSWISS_FONT').ignore()
c = module.find('wxFont')
assert isinstance(c, etgtools.ClassDef)
tools.removeVirtuals(c)
c.addCppCtor("""(
int pointSize,
wxFontFamily family,
int flags = wxFONTFLAG_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;
""")
for item in c.findAll('New'):
item.factory = True
c.addProperty('Encoding GetEncoding SetEncoding')
c.addProperty('FaceName GetFaceName SetFaceName')
c.addProperty('Family GetFamily SetFamily')
c.addProperty('NativeFontInfoDesc GetNativeFontInfoDesc SetNativeFontInfo')
c.addProperty('NativeFontInfoUserDesc GetNativeFontInfoUserDesc SetNativeFontInfoUserDesc')
c.addProperty('PointSize GetPointSize SetPointSize')
c.addProperty('PixelSize GetPixelSize SetPixelSize')
c.addProperty('Style GetStyle SetStyle')
c.addProperty('Underlined GetUnderlined SetUnderlined')
c.addProperty('Weight GetWeight SetWeight')
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()

View File

@@ -1,5 +1,5 @@
#---------------------------------------------------------------------------
# Name: gdicmn.py
# Name: etg/gdicmn.py
# Author: Robin Dunn
#
# Created: 4-Nov-2010
@@ -7,6 +7,9 @@
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "gdicmn"
@@ -14,305 +17,306 @@ DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [
'wxPoint',
'wxSize',
'wxRect',
'wxRealPoint',
]
ITEMS = [ 'wxPoint',
'wxSize',
'wxRect',
'wxRealPoint',
'wxColourDatabase' ,
]
#---------------------------------------------------------------------------
# Parse the XML file(s) building a collection of Extractor objects
import etgtools
import etgtools.tweaker_tools as tools
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#---------------------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
# ignore some of these enum values
e = module.find('wxBitmapType')
for i in e:
if i.name.endswith('_RESOURCE'):
i.ignore()
module.addCppCode("""\
#if !defined(__WXMAC__)
#define wxCURSOR_COPY_ARROW wxCURSOR_ARROW
#endif
""")
# these are X11 only
e = module.find('wxStockCursor')
e.find('wxCURSOR_BASED_ARROW_DOWN').ignore()
e.find('wxCURSOR_BASED_ARROW_UP').ignore()
e.find('wxCURSOR_CROSS_REVERSE').ignore()
e.find('wxCURSOR_DOUBLE_ARROW').ignore()
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
# ignore some of these enum values
e = module.find('wxBitmapType')
for i in e:
if i.name.endswith('_RESOURCE'):
i.ignore()
module.addCppCode("""\
#if !defined(__WXMAC__)
#define wxCURSOR_COPY_ARROW wxCURSOR_ARROW
#endif
""")
# these are X11 only
e = module.find('wxStockCursor')
e.find('wxCURSOR_BASED_ARROW_DOWN').ignore()
e.find('wxCURSOR_BASED_ARROW_UP').ignore()
e.find('wxCURSOR_CROSS_REVERSE').ignore()
e.find('wxCURSOR_DOUBLE_ARROW').ignore()
module.find('wxTheColourDatabase').ignore()
module.find('wxSetCursor').ignore()
module.find('wxClientDisplayRect.x').out = True
module.find('wxClientDisplayRect.y').out = True
module.find('wxClientDisplayRect.width').out = True
module.find('wxClientDisplayRect.height').out = True
module.find('wxDisplaySize.width').out = True
module.find('wxDisplaySize.height').out = True
module.find('wxDisplaySizeMM.width').out = True
module.find('wxDisplaySizeMM.height').out = True
#---------------------------------------
# wxPoint tweaks
c = module.find('wxPoint')
# Some operators are documented within the class that shouldn't be, so just
# ignore them all.
tools.ignoreAllOperators(c)
# Undo a few of those ignores for legitimate items that were
# documented correctly
for f in c.find('operator+=').all() + c.find('operator-=').all():
f.ignore(False)
module.find('wxTheColourDatabase').ignore() # TODO
module.find('wxSetCursor').ignore() # TODO
module.find('wxClientDisplayRect.x').out = True
module.find('wxClientDisplayRect.y').out = True
module.find('wxClientDisplayRect.width').out = True
module.find('wxClientDisplayRect.height').out = True
module.find('wxDisplaySize.width').out = True
module.find('wxDisplaySize.height').out = True
module.find('wxDisplaySizeMM.width').out = True
module.find('wxDisplaySizeMM.height').out = True
#---------------------------------------
# wxPoint tweaks
c = module.find('wxPoint')
# Some operators are documented within the class that shouldn't be, so just
# ignore them all.
tools.ignoreAllOperators(c)
# Undo a few of those ignores for legitimate items that were
# documented correctly
for f in c.find('operator+=').all() + c.find('operator-=').all():
f.ignore(False)
# Add some stand-alone function declarations for the operators that really do
# exist.
wc = etgtools.WigCode("""\
bool operator==(const wxPoint& p1, const wxPoint& p2);
bool operator!=(const wxPoint& p1, const wxPoint& p2);
wxPoint operator+(const wxPoint& p, const wxSize& s);
wxPoint operator+(const wxPoint& p1, const wxPoint& p2);
wxPoint operator+(const wxSize& s, const wxPoint& p);
wxPoint operator-(const wxPoint& p);
wxPoint operator-(const wxPoint& p, const wxSize& s);
wxPoint operator-(const wxPoint& p1, const wxPoint& p2);
wxPoint operator-(const wxSize& s, const wxPoint& p);
wxPoint operator*(const wxPoint& s, int i);
wxPoint operator*(int i, const wxPoint& s);
wxPoint operator/(const wxPoint& s, int i);
""")
module.insertItemAfter(c, wc)
# Add some stand-alone function declarations for the operators that really do
# exist.
wc = etgtools.WigCode("""\
bool operator==(const wxPoint& p1, const wxPoint& p2);
bool operator!=(const wxPoint& p1, const wxPoint& p2);
wxPoint operator+(const wxPoint& p, const wxSize& s);
wxPoint operator+(const wxPoint& p1, const wxPoint& p2);
wxPoint operator+(const wxSize& s, const wxPoint& p);
wxPoint operator-(const wxPoint& p);
wxPoint operator-(const wxPoint& p, const wxSize& s);
wxPoint operator-(const wxPoint& p1, const wxPoint& p2);
wxPoint operator-(const wxSize& s, const wxPoint& p);
wxPoint operator*(const wxPoint& s, int i);
wxPoint operator*(int i, const wxPoint& s);
wxPoint operator/(const wxPoint& s, int i);
""")
module.insertItemAfter(c, wc)
# wxPoint typemap
c.convertFromPyObject = tools.convertTwoIntegersTemplate('wxPoint')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(ii)", sipCpp->x, sipCpp->y);
""", briefDoc="""\
Get() -> (x,y)\n
Return the x and y properties as a tuple.""")
# Add sequence protocol methods and other goodies
c.addPyMethod('__str__', '(self)', 'return str(self.Get())')
c.addPyMethod('__repr__', '(self)', 'return "wx.Point"+str(self.Get())')
c.addPyMethod('__len__', '(self)', 'return len(self.Get())')
c.addPyMethod('__nonzero__', '(self)', 'return self.Get() != (0,0)')
c.addPyMethod('__reduce__', '(self)', 'return (Point, self.Get())')
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, val)',
"""\
if idx == 0: self.x = val
elif idx == 1: self.y = val
else: raise IndexError
""")
c.addPyCode('Point.__safe_for_unpickling__ = True')
#---------------------------------------
# wxSize tweaks
c = module.find('wxSize')
c.addProperty("width GetWidth SetWidth")
c.addProperty("height GetHeight SetHeight")
# take care of the same issues as wxPoint
tools.ignoreAllOperators(c)
for f in c.find('operator+=').all() + \
c.find('operator-=').all() + \
c.find('operator*=').all() + \
c.find('operator/=').all():
f.ignore(False)
wc = etgtools.WigCode("""\
bool operator==(const wxSize& s1, const wxSize& s2);
bool operator!=(const wxSize& s1, const wxSize& s2);
wxSize operator*(const wxSize& s, int i);
wxSize operator*(int i, const wxSize& s);
wxSize operator+(const wxSize& s1, const wxSize& s2);
wxSize operator-(const wxSize& s1, const wxSize& s2);
wxSize operator/(const wxSize& s, int i);
""")
module.insertItemAfter(c, wc)
# wxSize typemap
c.convertFromPyObject = tools.convertTwoIntegersTemplate('wxSize')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(ii)", sipCpp->GetWidth(), sipCpp->GetHeight());
""", briefDoc="""\
Get() -> (width, height)\n
Return the width and height properties as a tuple.""")
# Add sequence protocol methods and other goodies
c.addPyMethod('__str__', '(self)', 'return str(self.Get())')
c.addPyMethod('__repr__', '(self)', 'return "wx.Size"+str(self.Get())')
c.addPyMethod('__len__', '(self)', 'return len(self.Get())')
c.addPyMethod('__nonzero__', '(self)', 'return self.Get() != (0,0)')
c.addPyMethod('__reduce__', '(self)', 'return (Size, self.Get())')
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, val)',
"""\
if idx == 0: self.width = val
elif idx == 1: self.height = val
else: raise IndexError
""")
c.addPyCode('Size.__safe_for_unpickling__ = True')
#---------------------------------------
# wxRect tweaks
c = module.find('wxRect')
c.addProperty("left GetLeft")
c.addProperty("top GetTop")
c.addProperty("right GetRight")
c.addProperty("bottom GetBottom")
c.addProperty("bottomLeft GetBottomLeft")
c.addProperty("bottomRight GetBottomRight")
c.addProperty("topLeft GetTopLeft")
c.addProperty("topRight GetTopRight")
# take care of the same issues as wxPoint
tools.ignoreAllOperators(c)
for f in c.find('operator+=').all() + \
c.find('operator*=').all():
f.ignore(False)
wc = etgtools.WigCode("""\
bool operator==(const wxRect& r1, const wxRect& r2);
bool operator!=(const wxRect& r1, const wxRect& r2);
wxRect operator+(const wxRect& r1, const wxRect& r2);
wxRect operator*(const wxRect& r1, const wxRect& r2);
""")
module.insertItemAfter(c, wc)
# Because of our add-ons that make wx.Point and wx.Size act like 2-element
# sequences, and also the typecheck code that allows 2-element sequences, then
# we end up with a bit of confusion about the (Point,Point) and the
# (Point,Size) overloads of the wx.Rect constructor. The confusion can be
# dealt with by using keyword args, but I think that the (Point,Size) version
# will be used more, so reorder the overloads so it is found first.
m = module.find('wxRect.wxRect')
mo = m.findOverload('topLeft')
del m.overloads[m.overloads.index(mo)]
m.overloads.append(mo)
# These methods have some overloads that will end up with the same signature
# in Python, so we have to remove one.
module.find('wxRect.Deflate').findOverload(') const').ignore()
module.find('wxRect.Inflate').findOverload(') const').ignore()
module.find('wxRect.Union').findOverload(') const').ignore()
module.find('wxRect.Intersect').findOverload(') const').ignore()
# wxRect typemap
c.convertFromPyObject = tools.convertFourIntegersTemplate('wxRect')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(iiii)",
sipCpp->x, sipCpp->y, sipCpp->width, sipCpp->height);
""", briefDoc="""\
Get() -> (x, y, width, height)\n
Return the rectangle's properties as a tuple.""")
# Add sequence protocol methods and other goodies
c.addPyMethod('__str__', '(self)', 'return str(self.Get())')
c.addPyMethod('__repr__', '(self)', 'return "wx.Rect"+str(self.Get())')
c.addPyMethod('__len__', '(self)', 'return len(self.Get())')
c.addPyMethod('__nonzero__', '(self)', 'return self.Get() != (0,0,0,0)')
c.addPyMethod('__reduce__', '(self)', 'return (Rect, self.Get())')
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, val)',
"""\
if idx == 0: self.x = val
elif idx == 1: self.y = val
elif idx == 2: self.width = val
elif idx == 3: self.height = val
else: raise IndexError
""")
c.addPyCode('Rect.__safe_for_unpickling__ = True')
#---------------------------------------
# wxRealPoint tweaks
c = module.find('wxRealPoint')
# take care of the same issues as wxPoint
tools.ignoreAllOperators(c)
for f in c.find('operator+=').all() + \
c.find('operator-=').all():
f.ignore(False)
wc = etgtools.WigCode("""\
bool operator==(const wxRealPoint& p1, const wxRealPoint& p2);
bool operator!=(const wxRealPoint& p1, const wxRealPoint& p2);
wxRealPoint operator*(const wxRealPoint& s, double i);
wxRealPoint operator*(double i, const wxRealPoint& s);
wxRealPoint operator+(const wxRealPoint& p1, const wxRealPoint& p2);
wxRealPoint operator-(const wxRealPoint& p1, const wxRealPoint& p2);
wxRealPoint operator/(const wxRealPoint& s, int i);
""")
module.insertItemAfter(c, wc)
# wxRealPoint typemap
c.convertFromPyObject = tools.convertTwoDoublesTemplate('wxRealPoint')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(dd)",
sipCpp->x, sipCpp->y);
""", briefDoc="""\
Get() -> (x, y, width, height)\n
Return the rectangle's properties as a tuple.""")
# Add sequence protocol methods and other goodies
c.addPyMethod('__str__', '(self)', 'return str(self.Get())')
c.addPyMethod('__repr__', '(self)', 'return "wx.RealPoint"+str(self.Get())')
c.addPyMethod('__len__', '(self)', 'return len(self.Get())')
c.addPyMethod('__nonzero__', '(self)', 'return self.Get() != (0,0)')
c.addPyMethod('__reduce__', '(self)', 'return (Rect, self.Get())')
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, val)',
"""\
if idx == 0: self.x = val
elif idx == 1: self.y = val
else: raise IndexError
""")
c.addPyCode('RealPoint.__safe_for_unpickling__ = True')
# wxPoint typemap
c.convertFromPyObject = tools.convertTwoIntegersTemplate('wxPoint')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(ii)", sipCpp->x, sipCpp->y);
""", briefDoc="""\
Get() -> (x,y)\n
Return the x and y properties as a tuple.""")
# Add sequence protocol methods and other goodies
c.addPyMethod('__str__', '(self)', 'return str(self.Get())')
c.addPyMethod('__repr__', '(self)', 'return "wx.Point"+str(self.Get())')
c.addPyMethod('__len__', '(self)', 'return len(self.Get())')
c.addPyMethod('__nonzero__', '(self)', 'return self.Get() != (0,0)')
c.addPyMethod('__reduce__', '(self)', 'return (Point, self.Get())')
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, val)',
"""\
if idx == 0: self.x = val
elif idx == 1: self.y = val
else: raise IndexError
""")
c.addPyCode('Point.__safe_for_unpickling__ = True')
#---------------------------------------
# wxSize tweaks
c = module.find('wxSize')
c.addProperty("width GetWidth SetWidth")
c.addProperty("height GetHeight SetHeight")
# take care of the same issues as wxPoint
tools.ignoreAllOperators(c)
for f in c.find('operator+=').all() + \
c.find('operator-=').all() + \
c.find('operator*=').all() + \
c.find('operator/=').all():
f.ignore(False)
wc = etgtools.WigCode("""\
bool operator==(const wxSize& s1, const wxSize& s2);
bool operator!=(const wxSize& s1, const wxSize& s2);
wxSize operator*(const wxSize& s, int i);
wxSize operator*(int i, const wxSize& s);
wxSize operator+(const wxSize& s1, const wxSize& s2);
wxSize operator-(const wxSize& s1, const wxSize& s2);
wxSize operator/(const wxSize& s, int i);
""")
module.insertItemAfter(c, wc)
# wxSize typemap
c.convertFromPyObject = tools.convertTwoIntegersTemplate('wxSize')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(ii)", sipCpp->GetWidth(), sipCpp->GetHeight());
""", briefDoc="""\
Get() -> (width, height)\n
Return the width and height properties as a tuple.""")
# Add sequence protocol methods and other goodies
c.addPyMethod('__str__', '(self)', 'return str(self.Get())')
c.addPyMethod('__repr__', '(self)', 'return "wx.Size"+str(self.Get())')
c.addPyMethod('__len__', '(self)', 'return len(self.Get())')
c.addPyMethod('__nonzero__', '(self)', 'return self.Get() != (0,0)')
c.addPyMethod('__reduce__', '(self)', 'return (Size, self.Get())')
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, val)',
"""\
if idx == 0: self.width = val
elif idx == 1: self.height = val
else: raise IndexError
""")
c.addPyCode('Size.__safe_for_unpickling__ = True')
#---------------------------------------
# wxRect tweaks
c = module.find('wxRect')
c.addProperty("left GetLeft")
c.addProperty("top GetTop")
c.addProperty("right GetRight")
c.addProperty("bottom GetBottom")
c.addProperty("bottomLeft GetBottomLeft")
c.addProperty("bottomRight GetBottomRight")
c.addProperty("topLeft GetTopLeft")
c.addProperty("topRight GetTopRight")
# take care of the same issues as wxPoint
tools.ignoreAllOperators(c)
for f in c.find('operator+=').all() + \
c.find('operator*=').all():
f.ignore(False)
wc = etgtools.WigCode("""\
bool operator==(const wxRect& r1, const wxRect& r2);
bool operator!=(const wxRect& r1, const wxRect& r2);
wxRect operator+(const wxRect& r1, const wxRect& r2);
wxRect operator*(const wxRect& r1, const wxRect& r2);
""")
module.insertItemAfter(c, wc)
# Because of our add-ons that make wx.Point and wx.Size act like 2-element
# sequences, and also the typecheck code that allows 2-element sequences, then
# we end up with a bit of confusion about the (Point,Point) and the
# (Point,Size) overloads of the wx.Rect constructor. The confusion can be
# dealt with by using keyword args, but I think that the (Point,Size) version
# will be used more, so reorder the overloads so it is found first.
m = module.find('wxRect.wxRect')
mo = m.findOverload('topLeft')
del m.overloads[m.overloads.index(mo)]
m.overloads.append(mo)
# These methods have some overloads that will end up with the same signature
# in Python, so we have to remove one.
module.find('wxRect.Deflate').findOverload(') const').ignore()
module.find('wxRect.Inflate').findOverload(') const').ignore()
module.find('wxRect.Union').findOverload(') const').ignore()
module.find('wxRect.Intersect').findOverload(') const').ignore()
# wxRect typemap
c.convertFromPyObject = tools.convertFourIntegersTemplate('wxRect')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(iiii)",
sipCpp->x, sipCpp->y, sipCpp->width, sipCpp->height);
""", briefDoc="""\
Get() -> (x, y, width, height)\n
Return the rectangle's properties as a tuple.""")
# Add sequence protocol methods and other goodies
c.addPyMethod('__str__', '(self)', 'return str(self.Get())')
c.addPyMethod('__repr__', '(self)', 'return "wx.Rect"+str(self.Get())')
c.addPyMethod('__len__', '(self)', 'return len(self.Get())')
c.addPyMethod('__nonzero__', '(self)', 'return self.Get() != (0,0,0,0)')
c.addPyMethod('__reduce__', '(self)', 'return (Rect, self.Get())')
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, val)',
"""\
if idx == 0: self.x = val
elif idx == 1: self.y = val
elif idx == 2: self.width = val
elif idx == 3: self.height = val
else: raise IndexError
""")
c.addPyCode('Rect.__safe_for_unpickling__ = True')
#---------------------------------------
# wxRealPoint tweaks
c = module.find('wxRealPoint')
# take care of the same issues as wxPoint
tools.ignoreAllOperators(c)
for f in c.find('operator+=').all() + \
c.find('operator-=').all():
f.ignore(False)
wc = etgtools.WigCode("""\
bool operator==(const wxRealPoint& p1, const wxRealPoint& p2);
bool operator!=(const wxRealPoint& p1, const wxRealPoint& p2);
wxRealPoint operator*(const wxRealPoint& s, double i);
wxRealPoint operator*(double i, const wxRealPoint& s);
wxRealPoint operator+(const wxRealPoint& p1, const wxRealPoint& p2);
wxRealPoint operator-(const wxRealPoint& p1, const wxRealPoint& p2);
wxRealPoint operator/(const wxRealPoint& s, int i);
""")
module.insertItemAfter(c, wc)
# wxRealPoint typemap
c.convertFromPyObject = tools.convertTwoDoublesTemplate('wxRealPoint')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(dd)",
sipCpp->x, sipCpp->y);
""", briefDoc="""\
Get() -> (x, y, width, height)\n
Return the rectangle's properties as a tuple.""")
# Add sequence protocol methods and other goodies
c.addPyMethod('__str__', '(self)', 'return str(self.Get())')
c.addPyMethod('__repr__', '(self)', 'return "wx.RealPoint"+str(self.Get())')
c.addPyMethod('__len__', '(self)', 'return len(self.Get())')
c.addPyMethod('__nonzero__', '(self)', 'return self.Get() != (0,0)')
c.addPyMethod('__reduce__', '(self)', 'return (Rect, self.Get())')
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, val)',
"""\
if idx == 0: self.x = val
elif idx == 1: self.y = val
else: raise IndexError
""")
c.addPyCode('RealPoint.__safe_for_unpickling__ = True')
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#---------------------------------------------------------------------------
# Run the generators
if __name__ == '__main__':
run()
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------

55
etg/gdiobj.py Normal file
View File

@@ -0,0 +1,55 @@
#---------------------------------------------------------------------------
# Name: etg/gdiobj.py
# Author: Robin Dunn
#
# Created:
# Copyright: (c) 2010 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "gdiobj" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [ 'wxGDIObject' ]
#---------------------------------------------------------------------------
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
module.find('wxGDIObject').abstract = True
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()

View File

@@ -1,5 +1,5 @@
#---------------------------------------------------------------------------
# Name: geometry.py
# Name: etg/geometry.py
# Author: Robin Dunn
#
# Created: 4-Nov-2010
@@ -7,6 +7,9 @@
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "geometry"
@@ -20,125 +23,126 @@ ITEMS = [
]
#---------------------------------------------------------------------------
# Parse the XML file(s) building a collection of Extractor objects
import etgtools
import etgtools.tweaker_tools as tools
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#---------------------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
module.addHeaderCode('#include <wx/wx.h>')
#---------------------------------------
# wxPoint2D and wxRect2D tweaks
c = module.find('wxPoint2DDouble')
c.pyName = 'Point2D'
c.find('wxPoint2DDouble').findOverload('wxPoint2DInt').ignore()
c.find('m_x').pyName = 'x'
c.find('m_y').pyName = 'y'
c.find('GetFloor.x').out = True
c.find('GetFloor.y').out = True
c.find('GetRounded.x').out = True
c.find('GetRounded.y').out = True
# these have link errors
c.find('SetPolarCoordinates').ignore()
c.find('operator/=').findOverload('wxDouble').ignore()
c.find('operator*=').findOverload('wxDouble').ignore()
c.convertFromPyObject = tools.convertTwoDoublesTemplate('wxPoint2DDouble')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(dd)", sipCpp->m_x, sipCpp->m_y);
""", briefDoc="""\
Get() -> (x,y)\n
Return the x and y properties as a tuple.""")
# Add sequence protocol methods and other goodies
c.addPyMethod('__str__', '(self)', 'return str(self.Get())')
c.addPyMethod('__repr__', '(self)', 'return "wx.Point2D"+str(self.Get())')
c.addPyMethod('__len__', '(self)', 'return len(self.Get())')
c.addPyMethod('__nonzero__', '(self)', 'return self.Get() != (0,0)')
c.addPyMethod('__reduce__', '(self)', 'return (Point2D, self.Get())')
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, val)',
"""\
if idx == 0: self.x = val
elif idx == 1: self.y = val
else: raise IndexError
""")
c.addPyCode('Point2D.__safe_for_unpickling__ = True')
# ignore these operator methods, since we are not wrapping the Int version
c.find('operator*=').findOverload('wxInt32').ignore()
c.find('operator/=').findOverload('wxInt32').ignore()
# ignore some of the global operators too
for item in module:
if isinstance(item, etgtools.FunctionDef) and item.type == 'wxPoint2DInt':
item.ignore()
if item.name in ['operator*', 'operator/'] and 'wxInt32' in item.argsString:
item.ignore()
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
module.addHeaderCode('#include <wx/wx.h>')
#---------------------------------------
# wxPoint2D and wxRect2D tweaks
c = module.find('wxPoint2DDouble')
c.pyName = 'Point2D'
c.find('wxPoint2DDouble').findOverload('wxPoint2DInt').ignore()
c.find('m_x').pyName = 'x'
c.find('m_y').pyName = 'y'
c.find('GetFloor.x').out = True
c.find('GetFloor.y').out = True
c.find('GetRounded.x').out = True
c.find('GetRounded.y').out = True
# these have link errors
c.find('SetPolarCoordinates').ignore()
c.find('operator/=').findOverload('wxDouble').ignore()
c.find('operator*=').findOverload('wxDouble').ignore()
c.convertFromPyObject = tools.convertTwoDoublesTemplate('wxPoint2DDouble')
c.addCppMethod('SIP_PYOBJECT', 'Get', '()', """\
sipRes = sipBuildResult(&sipIsErr, "(dd)", sipCpp->m_x, sipCpp->m_y);
""", briefDoc="""\
Get() -> (x,y)\n
Return the x and y properties as a tuple.""")
# Add sequence protocol methods and other goodies
c.addPyMethod('__str__', '(self)', 'return str(self.Get())')
c.addPyMethod('__repr__', '(self)', 'return "wx.Point2D"+str(self.Get())')
c.addPyMethod('__len__', '(self)', 'return len(self.Get())')
c.addPyMethod('__nonzero__', '(self)', 'return self.Get() != (0,0)')
c.addPyMethod('__reduce__', '(self)', 'return (Point2D, self.Get())')
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, val)',
"""\
if idx == 0: self.x = val
elif idx == 1: self.y = val
else: raise IndexError
""")
c.addPyCode('Point2D.__safe_for_unpickling__ = True')
# ignore these operator methods, since we are not wrapping the Int version
c.find('operator*=').findOverload('wxInt32').ignore()
c.find('operator/=').findOverload('wxInt32').ignore()
# ignore some of the global operators too
for item in module:
if isinstance(item, etgtools.FunctionDef) and item.type == 'wxPoint2DInt':
item.ignore()
if item.name in ['operator*', 'operator/'] and 'wxInt32' in item.argsString:
item.ignore()
c = module.find('wxRect2DDouble')
c.pyName = 'Rect2D'
c.find('m_x').pyName = 'x'
c.find('m_y').pyName = 'y'
c.find('m_width').pyName = 'width'
c.find('m_height').pyName = 'height'
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);
""", briefDoc="""\
Get() -> (x, y, width, height)\n
Return the rectangle's properties as a tuple.""")
# Add sequence protocol methods and other goodies
c.addPyMethod('__str__', '(self)', 'return str(self.Get())')
c.addPyMethod('__repr__', '(self)', 'return "wx.Rect2D"+str(self.Get())')
c.addPyMethod('__len__', '(self)', 'return len(self.Get())')
c.addPyMethod('__nonzero__', '(self)', 'return self.Get() != (0,0,0,0)')
c.addPyMethod('__reduce__', '(self)', 'return (Rect2D, self.Get())')
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, val)',
"""\
if idx == 0: self.x = val
elif idx == 1: self.y = val
elif idx == 2: self.width = val
elif idx == 3: self.height = val
else: raise IndexError
""")
c.addPyCode('Rect2D.__safe_for_unpickling__ = True')
c = module.find('wxRect2DDouble')
c.pyName = 'Rect2D'
c.find('m_x').pyName = 'x'
c.find('m_y').pyName = 'y'
c.find('m_width').pyName = 'width'
c.find('m_height').pyName = 'height'
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);
""", briefDoc="""\
Get() -> (x, y, width, height)\n
Return the rectangle's properties as a tuple.""")
# Add sequence protocol methods and other goodies
c.addPyMethod('__str__', '(self)', 'return str(self.Get())')
c.addPyMethod('__repr__', '(self)', 'return "wx.Rect2D"+str(self.Get())')
c.addPyMethod('__len__', '(self)', 'return len(self.Get())')
c.addPyMethod('__nonzero__', '(self)', 'return self.Get() != (0,0,0,0)')
c.addPyMethod('__reduce__', '(self)', 'return (Rect2D, self.Get())')
c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]')
c.addPyMethod('__setitem__', '(self, idx, val)',
"""\
if idx == 0: self.x = val
elif idx == 1: self.y = val
elif idx == 2: self.width = val
elif idx == 3: self.height = val
else: raise IndexError
""")
c.addPyCode('Rect2D.__safe_for_unpickling__ = True')
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#---------------------------------------------------------------------------
# Run the generators
if __name__ == '__main__':
run()
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------

66
etg/intl.py Normal file
View File

@@ -0,0 +1,66 @@
#---------------------------------------------------------------------------
# Name: etg/intl.py
# Author: Robin Dunn
#
# Created:
# Copyright: (c) 2010 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "intl" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [ 'wxLanguageInfo',
'wxLocale',
'language_8h.xml',
]
#---------------------------------------------------------------------------
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
c = module.find('wxLocale')
assert isinstance(c, etgtools.ClassDef)
c.addPrivateAssignOp()
c.addPrivateCopyCtor()
tools.removeVirtuals(c)
c = module.find('wxLanguageInfo')
c.find('WinLang').ignore()
c.find('WinSublang').ignore()
c.find('GetLCID').ignore()
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()

View File

@@ -7,6 +7,9 @@
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "kbdstate" # Base name of the file to generate to for this script
@@ -17,40 +20,41 @@ DOCSTRING = ""
ITEMS = [ 'wxKeyboardState' ]
#---------------------------------------------------------------------------
# Parse the XML file(s) building a collection of Extractor objects
import etgtools
import etgtools.tweaker_tools as tools
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
c = module.find('wxKeyboardState')
c.addProperty("controlDown ControlDown SetControlDown")
c.addProperty("shiftDown ShiftDown SetShiftDown")
c.addProperty("altDown AltDown SetAltDown")
c.addProperty("metaDown MetaDown SetMetaDown")
c.addProperty("cmdDown CmdDown")
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
if __name__ == '__main__':
run()
c = module.find('wxKeyboardState')
c.addProperty("controlDown ControlDown SetControlDown")
c.addProperty("shiftDown ShiftDown SetShiftDown")
c.addProperty("altDown AltDown SetAltDown")
c.addProperty("metaDown MetaDown SetMetaDown")
c.addProperty("cmdDown CmdDown")
#---------------------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#---------------------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------

View File

@@ -7,6 +7,9 @@
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "mousestate" # Base name of the file to generate to for this script
@@ -17,44 +20,45 @@ DOCSTRING = ""
ITEMS = [ 'wxMouseState' ]
#---------------------------------------------------------------------------
# Parse the XML file(s) building a collection of Extractor objects
import etgtools
import etgtools.tweaker_tools as tools
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
c = module.find('wxMouseState')
c.find('GetPosition').findOverload('int *x').ignore()
c.addProperty("x GetX SetX")
c.addProperty("y GetY SetY")
c.addProperty("leftIsDown LeftIsDown SetLeftDown")
c.addProperty("middleIsDown MiddleIsDown SetMiddleDown")
c.addProperty("rightIsDown RightIsDown SetRightDown")
c.addProperty("aux1IsDown Aux1IsDown SetAux1Down")
c.addProperty("aux2IsDown Aux2IsDown SetAux2Down")
c.addProperty("Position GetPosition SetPosition")
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
if __name__ == '__main__':
run()
c = module.find('wxMouseState')
c.find('GetPosition').findOverload('int *x').ignore()
c.addProperty("x GetX SetX")
c.addProperty("y GetY SetY")
c.addProperty("leftIsDown LeftIsDown SetLeftDown")
c.addProperty("middleIsDown MiddleIsDown SetMiddleDown")
c.addProperty("rightIsDown RightIsDown SetRightDown")
c.addProperty("aux1IsDown Aux1IsDown SetAux1Down")
c.addProperty("aux2IsDown Aux2IsDown SetAux2Down")
c.addProperty("Position GetPosition SetPosition")
#---------------------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#---------------------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------

View File

@@ -1,5 +1,5 @@
#---------------------------------------------------------------------------
# Name: object.py
# Name: etg/object.py
# Author: Robin Dunn
#
# Created: 9-Nov-2010
@@ -7,6 +7,9 @@
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "object" # Base name of the file to generate to for this script
@@ -17,45 +20,62 @@ DOCSTRING = ""
ITEMS = [
'wxRefCounter',
'wxObject',
'wxClassInfo',
# 'wxClassInfo',
]
#---------------------------------------------------------------------------
# Parse the XML file(s) building a collection of Extractor objects
import etgtools
import etgtools.tweaker_tools as tools
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
module.find('wxObject.operator delete').ignore()
module.find('wxObject.operator new').ignore()
module.find('wxCreateDynamicObject').ignore()
#module.find('wxClassInfo').abstract = True
#module.find('wxClassInfo.wxClassInfo').ignore()
module.find('wxObject.GetClassInfo').ignore()
module.find('wxObject.IsKindOf').ignore()
module.find('wxRefCounter.~wxRefCounter').ignore(False)
c = module.find('wxObject')
assert isinstance(c, etgtools.ClassDef)
c.addCppMethod('const wxChar*', 'GetClassName', '()',
body='sipRes = sipCpp->GetClassInfo()->GetClassName();',
doc='Returns the class name of the C++ class using wxRTTI.')
c.addCppMethod('void', 'Destroy', '()',
body='delete sipCpp;',
doc='Deletes the C++ object this Python object is a proxy for.',
transferThis=True) # TODO: Check this
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
if __name__ == '__main__':
run()
module.find('wxObject.operator delete').ignore()
module.find('wxObject.operator new').ignore()
module.find('wxCreateDynamicObject').ignore()
module.find('wxClassInfo').abstract = True
module.find('wxClassInfo.wxClassInfo').ignore()
module.find('wxRefCounter.~wxRefCounter').ignore(False)
#---------------------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#---------------------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------

59
etg/platinfo.py Normal file
View File

@@ -0,0 +1,59 @@
#---------------------------------------------------------------------------
# Name: etg/platinfo.py
# Author: Robin Dunn
#
# Created: 22-Nov-2010
# Copyright: (c) 2010 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "platinfo" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [ 'wxPlatformInfo' ]
#---------------------------------------------------------------------------
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
c = module.find('wxPlatformInfo')
assert isinstance(c, etgtools.ClassDef)
c.find('wxPlatformInfo').findOverload('()').ignore()
c.find('GetLinuxDistributionInfo').ignore()
c.find('SetLinuxDistributionInfo').ignore()
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()

View File

@@ -1,5 +1,5 @@
#---------------------------------------------------------------------------
# Name:
# Name: etg/????
# Author: Robin Dunn
#
# Created:
@@ -7,6 +7,9 @@
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = ""
MODULE = ""
NAME = "" # Base name of the file to generate to for this script
@@ -17,35 +20,36 @@ DOCSTRING = ""
ITEMS = [ ]
#---------------------------------------------------------------------------
# Parse the XML file(s) building a collection of Extractor objects
import etgtools
import etgtools.tweaker_tools as tools
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
if __name__ == '__main__':
run()
#---------------------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#---------------------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------

View File

@@ -7,6 +7,9 @@
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "tracker" # Base name of the file to generate to for this script
@@ -17,36 +20,37 @@ DOCSTRING = ""
ITEMS = [ 'wxTrackable' ]
#---------------------------------------------------------------------------
# Parse the XML file(s) building a collection of Extractor objects
import etgtools
import etgtools.tweaker_tools as tools
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
c = module.find('wxTrackable')
c.abstract = True
c.addDtor('private')
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
if __name__ == '__main__':
run()
c = module.find('wxTrackable')
c.abstract = True
c.addDtor('private')
#---------------------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#---------------------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------

54
etg/vidmode.py Normal file
View File

@@ -0,0 +1,54 @@
#---------------------------------------------------------------------------
# Name: etg/vidmode.py
# Author: Robin Dunn
#
# Created:
# Copyright: (c) 2010 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "vidmode" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [ 'wxVideoMode' ]
#---------------------------------------------------------------------------
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()

View File

@@ -7,6 +7,9 @@
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "windowid" # Base name of the file to generate to for this script
@@ -17,35 +20,36 @@ DOCSTRING = ""
ITEMS = [ 'wxIdManager' ]
#---------------------------------------------------------------------------
# Parse the XML file(s) building a collection of Extractor objects
import etgtools
import etgtools.tweaker_tools as tools
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
def run():
# Parse the XML file(s) building a collection of Extractor objects
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
etgtools.parseDoxyXML(module, ITEMS)
#-----------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for
# customizing the generated code and docstrings.
#-----------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#-----------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------
# Tweak the parsed meta objects in the module object as needed for customizing
# the generated code and docstrings.
if __name__ == '__main__':
run()
#---------------------------------------------------------------------------
tools.ignoreAssignmentOperators(module)
tools.removeWxPrefixes(module)
#---------------------------------------------------------------------------
# Run the generators
# Create the code generator and make the wrapper code
wg = etgtools.getWrapperGenerator()
wg.generate(module)
# Create a documentation generator and let it do its thing
dg = etgtools.getDocsGenerator()
dg.generate(module)
#---------------------------------------------------------------------------

View File

@@ -45,9 +45,9 @@ def parseDoxyXML(module, class_or_filename_list):
Doxygen XML output folder.
"""
def _classToDoxyName(name):
def _classToDoxyName(name, base='class'):
import string
filename = 'class'
filename = base
for c in name:
if c in string.ascii_uppercase:
filename += '_' + c.lower()
@@ -58,12 +58,19 @@ def parseDoxyXML(module, class_or_filename_list):
def _includeToDoxyName(name):
name = os.path.basename(name)
name = name.replace('.h', '_8h')
return os.path.join(XMLSRC, name) + '.xml', name + '.xml'
pathname = os.path.join(XMLSRC, name) + '.xml'
if os.path.exists(pathname):
return pathname, name + '.xml'
else:
name = 'interface_2wx_2' + name
return os.path.join(XMLSRC, name) + '.xml', name + '.xml'
for class_or_filename in class_or_filename_list:
pathname = _classToDoxyName(class_or_filename)
if not os.path.exists(pathname):
pathname = os.path.join(XMLSRC, class_or_filename)
pathname = _classToDoxyName(class_or_filename, 'struct')
if not os.path.exists(pathname):
pathname = os.path.join(XMLSRC, class_or_filename)
if verbose():
print "Loading %s..." % pathname
_filesparsed.add(pathname)

View File

@@ -17,12 +17,6 @@ import os
import pprint
import xml.etree.ElementTree as et
#---------------------------------------------------------------------------
# TODOs
#
# * Need a way to idicate that items are not available on certain platforms
#
# * Something for TypeHeader code for classes
#---------------------------------------------------------------------------
@@ -143,6 +137,17 @@ class BaseDef(object):
items.extend(o.allItems())
return items
def findAll(self, name):
"""
Search recursivly for items that have the given name.
"""
matches = list()
for item in self.allItems():
if item.name == name or item.pyName == name:
matches.append(item)
return matches
def _findItems(self):
# If there are more items to be searched than what is in self.items, a
@@ -240,9 +245,10 @@ class FunctionDef(BaseDef):
self.factory = False # a factory function that creates a new instance of the return value
self.pyReleaseGIL = False # release the Python GIL for this function call
self.noCopy = False # don't make a copy of the return value, just wrap the original
self.pyInt = False # treat char types as integers
self.transfer = False # transfer ownership of return value to C++?
self.transferBack = False # transfer ownership of return value from C++ to Python?
self.transferThis = False # ownership of 'this' pointer transfered to this arg
self.transferThis = False # ownership of 'this' pointer transfered to C++
self.__dict__.update(kw)
if element is not None:
self.extract(element)
@@ -338,7 +344,8 @@ class MethodDef(FunctionDef):
self.isCtor = False
self.isDtor = False
self.protection = ''
self.defaultCtor = False # use this ctor as the default one
self.defaultCtor = False # use this ctor as the default one
self.noDerivedCtor = False # don't generate a ctor in the derived class for this ctor
self.__dict__.update(kw)
if element is not None:
self.extract(element, className)
@@ -383,6 +390,7 @@ class ParamDef(BaseDef):
self.default = '' # default value
self.out = False # is it an output arg?
self.inOut = False # is it both input and output?
self.pyInt = False # treat char types as integers
self.array = False # the param is to be treated as an array
self.arraySize = False # the param is the size of the array
self.transfer = False # transfer ownership of arg to C++?
@@ -422,8 +430,9 @@ class ClassDef(BaseDef):
The information about a class that is needed to generate wrappers for it.
"""
nameTag = 'compoundname'
def __init__(self, element=None, **kw):
def __init__(self, element=None, kind='class', **kw):
super(ClassDef, self).__init__()
self.kind = kind
self.bases = [] # base class names
self.includes = [] # .h file for this class
self.abstract = False # is it an abstract base class?
@@ -431,8 +440,11 @@ class ClassDef(BaseDef):
self.external = False # class is in another module
self.noDefCtor = False # do not generate a default constructor
self.singlton = False # class is a singleton so don't call the dtor until the interpreter exits
self.convertFromPyObject = None
self.headerCode = []
self.cppCode = []
self.convertToPyObject = None
self.convertFromPyObject = None
self.allowNone = False # Allow the convertFrom code to handle None too.
# Stuff that needs to be generated after the class instead of within
# it. Some back-end generators need to put stuff inside the class, and
@@ -494,6 +506,23 @@ class ClassDef(BaseDef):
_print("\n", indent, stream)
def addHeaderCode(self, code):
if isinstance(code, list):
self.headerCode.extend(code)
else:
self.headerCode.append(code)
def addCppCode(self, code):
if isinstance(code, list):
self.cppCode.extend(code)
else:
self.cppCode.append(code)
def insertCppCode(self, filename):
self.addCppCode(file(filename).read())
def addProperty(self, *args, **kw):
"""
Add a property to a class, with a name, getter function and optionally
@@ -529,11 +558,12 @@ class ClassDef(BaseDef):
return md
def addCppCtor(self, argsString, body, doc=None, **kw):
def addCppCtor(self, argsString, body, doc=None, noDerivedCtor=True, **kw):
"""
Add a C++ method that is a constructor.
"""
md = CppMethodDef('', self.name, argsString, body, doc=doc, isCtor=True, **kw)
md = CppMethodDef('', self.name, argsString, body, doc=doc,
isCtor=True, noDerivedCtor=noDerivedCtor, **kw)
self.items.append(md)
return md
@@ -590,10 +620,9 @@ class ClassDef(BaseDef):
def addCopyCtor(self, prot='protected'):
# add declaration of a copy constructor to this class
wig = WigCode("""
wig = WigCode("""\
{PROT}:
{CLASS}(const {CLASS}&);
""".format(CLASS=self.name, PROT=prot))
{CLASS}(const {CLASS}&);""".format(CLASS=self.name, PROT=prot))
self.addItem(wig)
def addPrivateCopyCtor(self):
@@ -601,18 +630,16 @@ class ClassDef(BaseDef):
def addPrivateAssignOp(self):
# add declaration of an assignment opperator to this class
wig = WigCode("""
wig = WigCode("""\
private:
{CLASS}& operator=(const {CLASS}&);
""".format(CLASS=self.name))
{CLASS}& operator=(const {CLASS}&);""".format(CLASS=self.name))
self.addItem(wig)
def addDtor(self, prot='protected'):
# add declaration of a destructor to this class
wig = WigCode("""
wig = WigCode("""\
{PROT}:
~{CLASS}();
""".format(CLASS=self.name, PROT=prot))
~{CLASS}();""".format(CLASS=self.name, PROT=prot))
self.addItem(wig)
#---------------------------------------------------------------------------
@@ -702,14 +729,13 @@ class CppMethodDef(MethodDef):
NOTE: This one is not automatically extracted, but can be added to
classes in the tweaker stage
"""
def __init__(self, type, name, argsString, body, doc=None, isCtor=False, **kw):
def __init__(self, type, name, argsString, body, doc=None, **kw):
super(CppMethodDef, self).__init__()
self.type = type
self.name = name
self.argsString = argsString
self.body = body
self.briefDoc = doc
self.isCtor = isCtor
self.protection = 'public'
self.__dict__.update(kw)
@@ -745,9 +771,10 @@ class PyCodeDef(BaseDef):
This code held by this class will be written to a Python module
that wraps the import of the extension module.
"""
def __init__(self, code, **kw):
def __init__(self, code, order=None, **kw):
super(PyCodeDef, self).__init__()
self.code = code
self.order = order
self.__dict__.update(kw)
#---------------------------------------------------------------------------
@@ -838,6 +865,11 @@ class ModuleDef(BaseDef):
item = ClassDef(element)
self.items.append(item)
elif kind == 'struct':
extractingMsg(kind, element, ClassDef.nameTag)
item = ClassDef(element, kind='struct')
self.items.append(item)
elif kind == 'function':
extractingMsg(kind, element)
item = FunctionDef(element)
@@ -903,15 +935,29 @@ class ModuleDef(BaseDef):
return md
def addPyCode(self, code):
def addPyCode(self, code, order=None):
"""
Add a snippet of Python code to the wrapper module.
"""
pc = PyCodeDef(code)
pc = PyCodeDef(code, order)
self.items.append(pc)
return pc
def includePyCode(self, filename, order=None):
"""
Add a snippet of Python code from a file to the wrapper module.
"""
text = file(filename).read()
return self.addPyCode(
"#" + '-=' * 38 + '\n' +
("# This code block was included from %s\n%s\n" % (filename, text)) +
"# End of included code block\n"
"#" + '-=' * 38 + '\n' ,
order
)
#---------------------------------------------------------------------------
# Some helper functions and such
#---------------------------------------------------------------------------

View File

@@ -67,7 +67,7 @@ class SipWrapperGenerator(generators.WrapperGeneratorBase):
if module.docstring:
doc = '\n"""\n%s\n"""\n' % module.docstring
stream.write("""\
%%Extract pycode
%%Extract(id=pycode, order=5)
# This file is generated by wxPython's SIP generator. Do not edit by hand.
#
# Copyright: (c) 2010 by Total Control Software
@@ -140,6 +140,7 @@ from %s import *
extractors.TypedefDef : self.generateTypedef,
extractors.WigCode : self.generateWigCode,
extractors.PyCodeDef : self.generatePyCode,
extractors.CppMethodDef : self.generateCppMethod,
}
for item in module:
@@ -169,9 +170,9 @@ from %s import *
continue
stream.write(indent)
stream.write('%s %s' % (param.type, param.name))
stream.write(self.annotate(param))
if param.default:
stream.write(' = %s' % param.default)
stream.write(self.annotate(param))
if not idx == len(parameters)-1:
stream.write(',')
stream.write('\n')
@@ -226,7 +227,10 @@ from %s import *
if hasattr(pc, 'klass') and pc.klass.generatingInClass:
pc.klass.generateAfterClass.append(pc)
else:
stream.write('%Extract pycode\n')
stream.write('%Extract(id=pycode')
if pc.order is not None:
stream.write(', order=%d' % pc.order)
stream.write(')\n')
stream.write(nci(pc.code))
stream.write('\n%End\n\n')
@@ -238,18 +242,35 @@ from %s import *
return
# write the class header
stream.write('%sclass %s' % (indent, klass.name))
stream.write('%s%s %s' % (indent, klass.kind, klass.name))
if klass.bases:
stream.write(' : ')
stream.write(', '.join(klass.bases))
stream.write(self.annotate(klass))
stream.write('\n%s{\n' % indent)
indent2 = indent + ' '*4
if klass.includes:
stream.write('%s%%TypeHeaderCode\n' % indent)
stream.write('%s%%TypeHeaderCode\n' % indent2)
for inc in klass.includes:
stream.write('%s #include <%s>\n' % (indent, inc))
stream.write('%s%%End\n' % indent)
stream.write('\n%spublic:\n' % indent)
stream.write('%s #include <%s>\n' % (indent2, inc))
stream.write('%s%%End\n\n' % indent2)
# C++ code to be written to the Type's header
if klass.headerCode:
stream.write("%s%%TypeHeaderCode\n" % indent2)
for c in klass.headerCode:
stream.write(nci(c, len(indent2)+4))
stream.write("%s%%End\n" % indent2)
# C++ code to be written out to the this Type's wrapper code module
if klass.cppCode:
stream.write("%s%%TypeCode\n" % indent2)
for c in klass.cppCode:
stream.write(nci(c, len(indent2)+4))
stream.write("%s%%End\n" % indent2)
if klass.kind == 'class':
stream.write('\n%spublic:\n' % indent)
# is the generator currently inside the class or after it?
klass.generatingInClass = True
@@ -357,7 +378,7 @@ from %s import *
self.generateMethod(m, stream, indent)
def generateCppMethod(self, method, stream, indent):
def generateCppMethod(self, method, stream, indent=''):
assert isinstance(method, extractors.CppMethodDef)
if method.ignored:
return
@@ -385,6 +406,7 @@ from %s import *
stream.write(nci('"""\n%s\n"""\n' % pm.briefDoc, 4))
stream.write(nci(pm.body, 4))
stream.write('%s.%s = _%s_%s\n' % (klassName, pm.name, klassName, pm.name))
stream.write('del _%s_%s\n' % (klassName, pm.name))
stream.write('\n%End\n\n')
#-----------------------------------------------------------------------
@@ -412,6 +434,8 @@ from %s import *
annotations.append('TransferBack')
if item.transferThis:
annotations.append('TranserThis')
if item.pyInt:
annotations.append('PyInt')
if isinstance(item, extractors.FunctionDef):
if item.deprecated:
@@ -426,10 +450,14 @@ from %s import *
if isinstance(item, extractors.MethodDef):
if item.defaultCtor:
annotations.append('Default')
if item.noDerivedCtor:
annotations.append('NoDerived')
if isinstance(item, extractors.ClassDef):
if item.abstract:
annotations.append('Abstract')
if item.allowNone:
annotations.append('AllowNone')
if item.deprecated:
annotations.append('Deprecated')
if item.external:
@@ -454,7 +482,7 @@ def nci(text, numSpaces=0, stripLeading=True):
First use the count of leading spaces on the first line and remove that
many spaces from the front of all lines, and then indent each line by
adding numSpaces spaces. This is used so we can convert the arbitrary
indents that might be used by the treaker code into what is expected for
indents that might be used by the tweaker code into what is expected for
the context we are generating for.
"""
def _getLeadingSpaceCount(line):
@@ -464,8 +492,6 @@ def nci(text, numSpaces=0, stripLeading=True):
if c != ' ':
break
count += 1
else:
assert False, "First line should not be empty."
return count
def _allSpaces(text):

View File

@@ -13,7 +13,7 @@ stage of the ETG scripts.
"""
import extractors
import os
def removeWxPrefixes(node):
@@ -82,6 +82,48 @@ def fixEventClass(klass):
def removeVirtuals(klass):
"""
Sometimes methods are marked as virtual but probably don't ever need to be
overridden from Python. This function will unset the virtual flag for all
methods in a class, which can save some code-bloat in the wrapper code.
"""
assert isinstance(klass, extractors.ClassDef)
for item in klass.allItems():
if isinstance(item, extractors.MethodDef):
item.isVirtual = item.isPureVirtual = False
def getEtgFiles(names):
"""
Create a list of the files from the basenames in the names list that
corespond to files in the etg folder.
"""
return getMatchingFiles(names, 'etg/%s.py')
def getNonEtgFiles(names, template='src/%s.sip'):
"""
Get the files other than the ETG scripts from the list of names that match
the template. By default gets the SIP files in src.
"""
return getMatchingFiles(names, template)
def getMatchingFiles(names, template):
"""
Create a list of files from the basenames in names that match the template
and actually exist.
"""
files = list()
for name in names:
name = template % name
if os.path.exists(name):
files.append(name)
return files
def convertTwoIntegersTemplate(CLASS):
return """\
// is it just a typecheck?
@@ -113,7 +155,7 @@ def convertTwoIntegersTemplate(CLASS):
}}
*sipCppPtr = reinterpret_cast<{CLASS}*>(sipConvertToType(
sipPy, sipType_{CLASS}, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr));
return 0;
return sipGetState(sipTransferObj);
""".format(**locals())
@@ -155,7 +197,7 @@ def convertFourIntegersTemplate(CLASS):
}}
*sipCppPtr = reinterpret_cast<{CLASS}*>(sipConvertToType(
sipPy, sipType_{CLASS}, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr));
return 0;
return sipGetState(sipTransferObj);
""".format(**locals())
@@ -191,7 +233,7 @@ def convertTwoDoublesTemplate(CLASS):
}}
*sipCppPtr = reinterpret_cast<{CLASS}*>(sipConvertToType(
sipPy, sipType_{CLASS}, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr));
return 0;
return sipGetState(sipTransferObj);
""".format(**locals())
@@ -233,7 +275,7 @@ def convertFourDoublesTemplate(CLASS):
}}
*sipCppPtr = reinterpret_cast<{CLASS}*>(sipConvertToType(
sipPy, sipType_{CLASS}, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr));
return 0;
return sipGetState(sipTransferObj);
""".format(**locals())

View File

@@ -1,5 +1,11 @@
import sys
# stuff for debugging
import os
import wxPhoenix as wx
print "pid:", os.getpid()
#print "executable:", sys.executable; raw_input("Press Enter...")
if sys.version_info < (2,7):
# The unittest2 package has back-ported most of the new features of the
# unittest module in Python 2.7, you can get it at PyPI.

View File

@@ -14,10 +14,10 @@ import sys, os
from distutils.core import setup, Extension
from distutils.file_util import copy_file
from distutils.dir_util import mkpath
from distutils.dep_util import newer
from distutils.dep_util import newer, newer_group
from distutils.spawn import spawn
from buildtools.config import Config, msg, opj
from buildtools.config import Config, msg, opj, loadETG
import buildtools.distutils_hacks as hacks
@@ -76,20 +76,34 @@ HEADERS = None
BUILD_OPTIONS = { 'build_base' : cfg.BUILD_BASE }
if cfg.WXPORT == 'msw':
BUILD_OPTIONS[ 'compiler' ] = cfg.COMPILER
copy_file('src/__init__.py', cfg.PKGDIR, update=1, verbose=0)
cfg.CLEANUP.append(opj(cfg.PKGDIR, '__init__.py'))
# update the license files
mkpath('license')
for file in ['preamble.txt', 'licence.txt', 'licendoc.txt', 'lgpl.txt']:
copy_file(opj(cfg.WXDIR, 'docs', file), opj('license',file), update=1, verbose=0)
cfg.CLEANUP.append(opj('license',file))
for filename in ['preamble.txt', 'licence.txt', 'licendoc.txt', 'lgpl.txt']:
copy_file(opj(cfg.WXDIR, 'docs', filename), opj('license',filename), update=1, verbose=0)
cfg.CLEANUP.append(opj('license',filename))
cfg.CLEANUP.append('license')
# create the package's __version__ module
open(opj(cfg.PKGDIR, '__version__.py'), 'w').write("""\
# This file was generated by setup.py...
VERSION_STRING = '%(VERSION)s'
MAJOR_VERSION = %(VER_MAJOR)s
MINOR_VERSION = %(VER_MINOR)s
RELEASE_NUMBER = %(VER_RELEASE)s
SUBRELEASE_NUMBER = %(VER_SUBREL)s
VERSION = (MAJOR_VERSION, MINOR_VERSION, RELEASE_NUMBER,
SUBRELEASE_NUMBER, '%(VER_FLAGS)s')
""" % cfg.__dict__)
cfg.CLEANUP.append(opj(cfg.PKGDIR,'__version__.py'))
if sys.platform in ['win32', 'darwin']:
cfg.build_locale_dir(opj(cfg.PKGDIR, 'locale'))
DATA_FILES += cfg.build_locale_list(opj(cfg.PKGDIR, 'locale'))
@@ -103,9 +117,9 @@ else:
#----------------------------------------------------------------------
ext = []
extensions = []
ext.append(
extensions.append(
Extension('siplib', ['sip/siplib/apiversions.c',
'sip/siplib/bool.cpp',
'sip/siplib/descriptors.c',
@@ -122,30 +136,22 @@ ext.append(
extra_compile_args = cfg.cflags,
extra_link_args = cfg.lflags,
))
ext.append(
Extension('_core', ['etg/_core.py',
'etg/windowid.py',
'etg/object.py',
'etg/kbdstate.py',
'etg/mousestate.py',
'etg/tracker.py',
'etg/event.py',
'etg/gdicmn.py',
'etg/geometry.py',
] + rc_file,
depends = [ 'src/string.sip',
'src/clntdata.sip',
],
include_dirs = cfg.includes,
define_macros = cfg.defines,
library_dirs = cfg.libdirs,
libraries = cfg.libs,
extra_compile_args = cfg.cflags,
extra_link_args = cfg.lflags,
))
etg = loadETG('etg/_core.py')
ext = Extension('_core',
#['src/core_utils.cpp'] +
etg.ETGFILES + rc_file,
depends = etg.DEPENDS,
include_dirs = cfg.includes,
define_macros = cfg.defines,
library_dirs = cfg.libdirs,
libraries = cfg.libs,
extra_compile_args = cfg.cflags,
extra_link_args = cfg.lflags,
)
extensions.append(ext)
cfg.CLEANUP.append(opj(cfg.PKGDIR, 'core.py'))
@@ -168,7 +174,7 @@ if __name__ == '__main__':
packages = WX_PKGLIST,
#extra_path = EXTRA_PATH,
ext_package = cfg.PKGDIR,
ext_modules = ext,
ext_modules = extensions,
options = { 'build' : BUILD_OPTIONS,
'build_ext' : {'sip_opts' : cfg.SIPOPTS },

220
src/app_ex.cpp Normal file
View File

@@ -0,0 +1,220 @@
#ifdef __WXGTK__
#include <gdk/gdkx.h>
#include <wx/gtk/private/win_gtk.h>
#endif
#ifdef __WXMAC__
#include <wx/osx/private.h>
#endif
class wxPyApp : public wxApp
{
DECLARE_ABSTRACT_CLASS(wxPyApp)
public:
wxPyApp() : wxApp() {
m_assertMode = wxPYAPP_ASSERT_EXCEPTION;
m_startupComplete = false;
//m_callFilterEvent = false;
ms_appInstance = this;
}
~wxPyApp() {
ms_appInstance = NULL;
wxApp::SetInstance(NULL);
}
#ifndef __WXMAC__
virtual void MacNewFile() {}
virtual void MacOpenFile(const wxString &) {}
virtual void MacOpenURL(const wxString &) {}
virtual void MacPrintFile(const wxString &) {}
virtual void MacReopenApp() {}
#endif
#ifdef __WXMAC__
static long GetMacAboutMenuItemId() { return s_macAboutMenuItemId; }
static long GetMacPreferencesMenuItemId() { return s_macPreferencesMenuItemId; }
static long GetMacExitMenuItemId() { return s_macExitMenuItemId; }
static wxString GetMacHelpMenuTitleName() { return s_macHelpMenuTitleName; }
static void SetMacAboutMenuItemId(long val) { s_macAboutMenuItemId = val; }
static void SetMacPreferencesMenuItemId(long val) { s_macPreferencesMenuItemId = val; }
static void SetMacExitMenuItemId(long val) { s_macExitMenuItemId = val; }
static void SetMacHelpMenuTitleName(const wxString& val) { s_macHelpMenuTitleName = val; }
#else
static long GetMacAboutMenuItemId() { return 0; }
static long GetMacPreferencesMenuItemId() { return 0; }
static long GetMacExitMenuItemId() { return 0; }
static wxString GetMacHelpMenuTitleName() { return wxEmptyString; }
static void SetMacAboutMenuItemId(long) { }
static void SetMacPreferencesMenuItemId(long) { }
static void SetMacExitMenuItemId(long) { }
static void SetMacHelpMenuTitleName(const wxString&) { }
#endif
wxAppAssertMode GetAssertMode() { return m_assertMode; }
void SetAssertMode(wxAppAssertMode mode) { m_assertMode = mode; }
// virtual void OnAssertFailure(const wxChar *file,
// int line,
// const wxChar *func,
// const wxChar *cond,
// const wxChar *msg);
// Implementing OnInit is optional for wxPython apps
virtual bool OnInit() { return true; }
virtual void OnPreInit() { }
void _BootstrapApp();
static bool IsDisplayAvailable();
// implementation only
void SetStartupComplete(bool val) { m_startupComplete = val; }
static wxPyApp* ms_appInstance;
private:
wxAppAssertMode m_assertMode;
bool m_startupComplete;
//bool m_callFilterEvent;
};
IMPLEMENT_ABSTRACT_CLASS(wxPyApp, wxApp);
wxPyApp* wxPyApp::ms_appInstance = NULL;
void wxPyApp::_BootstrapApp()
{
static bool haveInitialized = false;
bool result;
wxPyBlock_t blocked;
PyObject* retval = NULL;
PyObject* pyint = NULL;
// Only initialize wxWidgets once
if (! haveInitialized) {
// Get any command-line args passed to this program from the sys module
int argc = 0;
char** argv = NULL;
blocked = wxPyBeginBlockThreads();
PyObject* sysargv = PySys_GetObject("argv");
PyObject* executable = PySys_GetObject("executable");
if (sysargv != NULL && executable != NULL) {
argc = PyList_Size(sysargv) + 1;
argv = new char*[argc+1];
argv[0] = strdup(PyString_AsString(executable));
int x;
for(x=1; x<argc; x++) {
PyObject *pyArg = PyList_GetItem(sysargv, x-1);
argv[x] = strdup(PyString_AsString(pyArg));
}
argv[argc] = NULL;
}
wxPyEndBlockThreads(blocked);
// Initialize wxWidgets
#ifdef __WXOSX__
wxMacAutoreleasePool autoreleasePool;
#endif
result = wxEntryStart(argc, argv);
// wxApp takes ownership of the argv array, don't delete it here
blocked = wxPyBeginBlockThreads();
if (! result) {
PyErr_SetString(PyExc_SystemError,
"wxEntryStart failed, unable to initialize wxWidgets!"
#ifdef __WXGTK__
" (Is DISPLAY set properly?)"
#endif
);
goto error;
}
wxPyEndBlockThreads(blocked);
haveInitialized = true;
}
else {
this->argc = 0;
}
// It's now ok to generate exceptions for assertion errors.
SetStartupComplete(true);
// Call the Python wxApp's OnPreInit and OnInit functions if they exist
OnPreInit();
result = OnInit();
blocked = wxPyBeginBlockThreads();
if (! result) {
PyErr_SetString(PyExc_SystemExit, "OnInit returned false, exiting...");
}
error:
wxPyEndBlockThreads(blocked);
}
// Function to test if the Display (or whatever is the platform equivallent)
// can be connected to. This is accessable from wxPython as a staticmethod of
// wx.App called IsDisplayAvailable().
bool wxPyApp::IsDisplayAvailable()
{
#ifdef __WXGTK__
Display* display;
display = XOpenDisplay(NULL);
if (display == NULL)
return false;
XCloseDisplay(display);
return true;
#endif
#ifdef __WXMAC__
// This is adapted from Python's Mac/Modules/MacOS.c in the
// MacOS_WMAvailable function.
bool rv;
ProcessSerialNumber psn;
/*
** This is a fairly innocuous call to make if we don't have a window
** manager, or if we have no permission to talk to it. It will print
** a message on stderr, but at least it won't abort the process.
** It appears the function caches the result itself, and it's cheap, so
** no need for us to cache.
*/
#ifdef kCGNullDirectDisplay
/* On 10.1 CGMainDisplayID() isn't available, and
** kCGNullDirectDisplay isn't defined.
*/
if (CGMainDisplayID() == 0) {
rv = false;
} else
#endif
{
// Also foreground the application on the first call as a side-effect.
if (GetCurrentProcess(&psn) < 0 || SetFrontProcess(&psn) < 0) {
rv = false;
} else {
rv = true;
}
}
return rv;
#endif
#ifdef __WXMSW__
// TODO...
return true;
#endif
}
wxPyApp* wxGetApp()
{
return wxPyApp::ms_appInstance;
}

275
src/app_ex.py Normal file
View File

@@ -0,0 +1,275 @@
class PyOnDemandOutputWindow:
"""
A class that can be used for redirecting Python's stdout and
stderr streams. It will do nothing until something is wrriten to
the stream at which point it will create a Frame with a text area
and write the text there.
"""
def __init__(self, title="wxPython: stdout/stderr"):
self.frame = None
self.title = title
self.pos = wx.DefaultPosition
self.size = (450, 300)
self.parent = None
def SetParent(self, parent):
"""Set the window to be used as the popup Frame's parent."""
self.parent = parent
def CreateOutputWindow(self, st):
self.frame = wx.Frame(self.parent, -1, self.title, self.pos, self.size,
style=wx.DEFAULT_FRAME_STYLE)
self.text = wx.TextCtrl(self.frame, -1, "",
style=wx.TE_MULTILINE|wx.TE_READONLY)
self.text.AppendText(st)
self.frame.Show(True)
self.frame.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
def OnCloseWindow(self, event):
if self.frame is not None:
self.frame.Destroy()
self.frame = None
self.text = None
self.parent = None
# These methods provide the file-like output behaviour.
def write(self, text):
"""
Create the output window if needed and write the string to it.
If not called in the context of the gui thread then uses
CallAfter to do the work there.
"""
if self.frame is None:
if not wx.Thread.IsMain():
wx.CallAfter(self.CreateOutputWindow, text)
else:
self.CreateOutputWindow(text)
else:
if not wx.Thread.IsMain():
wx.CallAfter(self.text.AppendText, text)
else:
self.text.AppendText(text)
def close(self):
if self.frame is not None:
wx.CallAfter(self.frame.Close)
def flush(self):
pass
#----------------------------------------------------------------------
class App(wx.PyApp):
"""
The ``wx.App`` class represents the application and is used to:
* bootstrap the wxPython system and initialize the underlying
gui toolkit
* set and get application-wide properties
* implement the native windowing system main message or event loop,
and to dispatch events to window instances
* etc.
Every wx application must have a single ``wx.App`` instance, and all
creation of UI objects should be delayed until after the ``wx.App`` object
has been created in order to ensure that the gui platform and wxWidgets
have been fully initialized.
Normally you would derive from this class and implement an ``OnInit``
method that creates a frame and then calls ``self.SetTopWindow(frame)``,
however ``wx.App`` is also usable on it's own without derivation.
"""
outputWindowClass = PyOnDemandOutputWindow
def __init__(self,
redirect=False,
filename=None,
useBestVisual=False,
clearSigInt=True):
"""
Construct a ``wx.App`` object.
:param redirect: Should ``sys.stdout`` and ``sys.stderr`` be
redirected? Defaults to False. If ``filename`` is None
then output will be redirected to a window that pops up
as needed. (You can control what kind of window is created
for the output by resetting the class variable
``outputWindowClass`` to a class of your choosing.)
:param filename: The name of a file to redirect output to, if
redirect is True.
:param useBestVisual: Should the app try to use the best
available visual provided by the system (only relevant on
systems that have more than one visual.) This parameter
must be used instead of calling `SetUseBestVisual` later
on because it must be set before the underlying GUI
toolkit is initialized.
:param clearSigInt: Should SIGINT be cleared? This allows the
app to terminate upon a Ctrl-C in the console like other
GUI apps will.
:note: You should override OnInit to do applicaition
initialization to ensure that the system, toolkit and
wxWidgets are fully initialized.
"""
wx.PyApp.__init__(self)
# make sure we can create a GUI
if not self.IsDisplayAvailable():
if wx.Port == "__WXMAC__":
msg = """This program needs access to the screen.
Please run with a Framework build of python, and only when you are
logged in on the main display of your Mac."""
elif wx.Port == "__WXGTK__":
msg ="Unable to access the X Display, is $DISPLAY set properly?"
else:
msg = "Unable to create GUI"
# TODO: more description is needed for wxMSW...
raise SystemExit(msg)
# This has to be done before OnInit
self.SetUseBestVisual(useBestVisual)
# Set the default handler for SIGINT. This fixes a problem
# where if Ctrl-C is pressed in the console that started this
# app then it will not appear to do anything, (not even send
# KeyboardInterrupt???) but will later segfault on exit. By
# setting the default handler then the app will exit, as
# expected (depending on platform.)
if clearSigInt:
try:
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
except:
pass
# Save and redirect the stdio to a window?
self.stdioWin = None
self.saveStdio = (_sys.stdout, _sys.stderr)
if redirect:
self.RedirectStdio(filename)
## # Use Python's install prefix as the default
## wx.StandardPaths.Get().SetInstallPrefix(_sys.prefix)
## # Until the new native control for wxMac is up to par, still use the generic one.
## wx.SystemOptions.SetOptionInt("mac.listctrl.always_use_generic", 1)
# This finishes the initialization of wxWindows and then calls
# the OnInit that should be present in the derived class
self._BootstrapApp()
def OnPreInit(self):
"""
Things that must be done after _BootstrapApp has done its
thing, but would be nice if they were already done by the time
that OnInit is called.
"""
print 'OnPreInit'
## wx.StockGDI._initStockObjects()
def __del__(self):
self.RestoreStdio() # Just in case the MainLoop was overridden
def Destroy(self):
## self.this.own(False)
wx.PyApp.Destroy(self)
def SetTopWindow(self, frame):
"""Set the \"main\" top level window"""
if self.stdioWin:
self.stdioWin.SetParent(frame)
wx.PyApp.SetTopWindow(self, frame)
def MainLoop(self):
"""Execute the main GUI event loop"""
wx.PyApp.MainLoop(self)
self.RestoreStdio()
def RedirectStdio(self, filename=None):
"""Redirect sys.stdout and sys.stderr to a file or a popup window."""
if filename:
_sys.stdout = _sys.stderr = open(filename, 'a')
else:
self.stdioWin = self.outputWindowClass()
_sys.stdout = _sys.stderr = self.stdioWin
def RestoreStdio(self):
try:
_sys.stdout, _sys.stderr = self.saveStdio
except:
pass
def SetOutputWindowAttributes(self, title=None, pos=None, size=None):
"""
Set the title, position and/or size of the output window if
the stdio has been redirected. This should be called before
any output would cause the output window to be created.
"""
if self.stdioWin:
if title is not None:
self.stdioWin.title = title
if pos is not None:
self.stdioWin.pos = pos
if size is not None:
self.stdioWin.size = size
## #----------------------------------------------------------------------------
## # TODO: Move this someplace else?
## def deprecated(func):
## def new_func(*args, **kwargs):
## import warnings
## warnings.warn("Call to deprecated function %s." % func.__name__,
## category=DeprecationWarning)
## return func(*args, **kwargs)
## new_func.__name__ = func.__name__
## new_func.__doc__ = func.__doc__
## new_func.__dict__.update(func.__dict__)
## return new_func
## @deprecated
## class PySimpleApp(App):
## """
## This class is deprecated. Please use wx.App isntead.
## """
## def __init__(self, *args, **kw):
## App.__init__(self, *args, **kw)
## #----------------------------------------------------------------------------
## # DO NOT hold any other references to this object. This is how we
## # know when to cleanup system resources that wxWidgets is holding. When
## # the sys module is unloaded, the refcount on sys.__wxPythonCleanup
## # goes to zero and it calls the wx.App_CleanUp function.
## #class __wxPyCleanup:
## #def __init__(self):
## #self.cleanup = _core_.App_CleanUp
## #def __del__(self):
## #self.cleanup()
## #_sys.__wxPythonCleanup = __wxPyCleanup()

219
src/core_ex.py Normal file
View File

@@ -0,0 +1,219 @@
# Load version numbers from __version__... Ensure that major and minor
# versions are the same for both wxPython and wxWidgets.
from __version__ import *
__version__ = VERSION_STRING
import _core
assert MAJOR_VERSION == _core.MAJOR_VERSION, "wxPython/wxWidgets version mismatch"
assert MINOR_VERSION == _core.MINOR_VERSION, "wxPython/wxWidgets version mismatch"
if RELEASE_NUMBER != _core.RELEASE_NUMBER:
import warnings
warnings.warn("wxPython/wxWidgets release number mismatch")
del _core
def version():
"""Returns a string containing version and port info"""
if wx.Platform == '__WXMSW__':
port = 'msw'
elif wx.Platform == '__WXMAC__':
if 'wxOSX-carbon' in wx.PlatformInfo:
port = 'osx-carbon'
else:
port = 'osx-cocoa'
elif wx.Platform == '__WXGTK__':
port = 'gtk'
if 'gtk2' in wx.PlatformInfo:
port = 'gtk2'
else:
port = '?'
return "%s %s" % (wx.VERSION_STRING, port)
## #----------------------------------------------------------------------------
## class PyDeadObjectError(AttributeError):
## pass
## class _wxPyDeadObject(object):
## """
## Instances of wx objects that are OOR capable will have their __class__
## changed to this class when the C++ object is deleted. This should help
## prevent crashes due to referencing a bogus C++ pointer.
## """
## reprStr = "wxPython wrapper for DELETED %s object! (The C++ object no longer exists.)"
## attrStr = "The C++ part of the %s object has been deleted, attribute access no longer allowed."
## def __repr__(self):
## if not hasattr(self, "_name"):
## self._name = "[unknown]"
## return self.reprStr % self._name
## def __getattr__(self, *args):
## if not hasattr(self, "_name"):
## self._name = "[unknown]"
## raise PyDeadObjectError(self.attrStr % self._name)
## def __nonzero__(self):
## return 0
## class PyUnbornObjectError(AttributeError):
## pass
## class _wxPyUnbornObject(object):
## """
## Some stock objects are created when the wx._core module is
## imported, but their C++ instance is not created until the wx.App
## object is created and initialized. These object instances will
## temporarily have their __class__ changed to this class so an
## exception will be raised if they are used before the C++ instance
## is ready.
## """
## reprStr = "wxPython wrapper for UNBORN object! (The C++ object is not initialized yet.)"
## attrStr = "The C++ part of this object has not been initialized, attribute access not allowed."
## def __repr__(self):
## #if not hasattr(self, "_name"):
## # self._name = "[unknown]"
## return self.reprStr #% self._name
## def __getattr__(self, *args):
## #if not hasattr(self, "_name"):
## # self._name = "[unknown]"
## raise PyUnbornObjectError(self.attrStr) # % self._name )
## def __nonzero__(self):
## return 0
## #----------------------------------------------------------------------------
## def CallAfter(callable, *args, **kw):
## """
## Call the specified function after the current and pending event
## handlers have been completed. This is also good for making GUI
## method calls from non-GUI threads. Any extra positional or
## keyword args are passed on to the callable when it is called.
## :see: `wx.CallLater`
## """
## app = wx.GetApp()
## assert app is not None, 'No wx.App created yet'
## if not hasattr(app, "_CallAfterId"):
## app._CallAfterId = wx.NewEventType()
## app.Connect(-1, -1, app._CallAfterId,
## lambda event: event.callable(*event.args, **event.kw) )
## evt = wx.PyEvent()
## evt.SetEventType(app._CallAfterId)
## evt.callable = callable
## evt.args = args
## evt.kw = kw
## wx.PostEvent(app, evt)
## #----------------------------------------------------------------------------
## class CallLater:
## """
## A convenience class for `wx.Timer`, that calls the given callable
## object once after the given amount of milliseconds, passing any
## positional or keyword args. The return value of the callable is
## availbale after it has been run with the `GetResult` method.
## If you don't need to get the return value or restart the timer
## then there is no need to hold a reference to this object. It will
## hold a reference to itself while the timer is running (the timer
## has a reference to self.Notify) but the cycle will be broken when
## the timer completes, automatically cleaning up the wx.CallLater
## object.
## :see: `wx.CallAfter`
## """
## def __init__(self, millis, callable, *args, **kwargs):
## self.millis = millis
## self.callable = callable
## self.SetArgs(*args, **kwargs)
## self.runCount = 0
## self.running = False
## self.hasRun = False
## self.result = None
## self.timer = None
## self.Start()
## def __del__(self):
## self.Stop()
## def Start(self, millis=None, *args, **kwargs):
## """
## (Re)start the timer
## """
## self.hasRun = False
## if millis is not None:
## self.millis = millis
## if args or kwargs:
## self.SetArgs(*args, **kwargs)
## self.Stop()
## self.timer = wx.PyTimer(self.Notify)
## self.timer.Start(self.millis, wx.TIMER_ONE_SHOT)
## self.running = True
## Restart = Start
## def Stop(self):
## """
## Stop and destroy the timer.
## """
## if self.timer is not None:
## self.timer.Stop()
## self.timer = None
## def GetInterval(self):
## if self.timer is not None:
## return self.timer.GetInterval()
## else:
## return 0
## def IsRunning(self):
## return self.timer is not None and self.timer.IsRunning()
## def SetArgs(self, *args, **kwargs):
## """
## (Re)set the args passed to the callable object. This is
## useful in conjunction with Restart if you want to schedule a
## new call to the same callable object but with different
## parameters.
## """
## self.args = args
## self.kwargs = kwargs
## def HasRun(self):
## return self.hasRun
## def GetResult(self):
## return self.result
## def Notify(self):
## """
## The timer has expired so call the callable.
## """
## if self.callable and getattr(self.callable, 'im_self', True):
## self.runCount += 1
## self.running = False
## self.result = self.callable(*self.args, **self.kwargs)
## self.hasRun = True
## if not self.running:
## # if it wasn't restarted, then cleanup
## wx.CallAfter(self.Stop)
## Interval = property(GetInterval)
## Result = property(GetResult)

26
src/core_utils.cpp Normal file
View File

@@ -0,0 +1,26 @@
//--------------------------------------------------------------------------
// Name: src/core_utils.cpp
// Purpose: Various utility and helper functions used by the _core
// wxPython(phoenix) extension module that are easier to maintain
// here than in the etg scripts that use them.
//
// Author: Robin Dunn
//
// Created: 24-Nov-2010
// RCS-ID: $Id: $
// Copyright: (c) 2010 by Total Control Software
// Licence: wxWindows license
//--------------------------------------------------------------------------
#undef DEBUG
#include <Python.h>
#include <wx/wx.h>
// Nothing is here yet, but there probably will be...
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------

17
src/core_utils.h Normal file
View File

@@ -0,0 +1,17 @@
//--------------------------------------------------------------------------
// Name: src/core_utils.h
// Purpose: Various utility and helper functions used by the _core
// wxPython(phoenix) extension module that are easier to maintain
// here than in the etg scripts that use them.
//
// Author: Robin Dunn
//
// Created: 24-Nov-2010
// RCS-ID: $Id: $
// Copyright: (c) 2010 by Total Control Software
// Licence: wxWindows license
//--------------------------------------------------------------------------
// Nothing is here yet, but there probably will be...

View File

@@ -14,31 +14,27 @@
// at all, so it will be mapped to and from Python Unicode objects using the
// code snippets below.
// NOTE: Currently we assume that string objects are encoding in utf-8. Decide if we
// want to do this or to use the default encoding for the locale like the old
// wxPython does.
// NOTE: Currently we assume that string objects are encoding in utf-8.
%MappedType wxString
{
// Code to test a PyObject for compatibility and to convert from a
// PyObject to a wxString
%ConvertToTypeCode
// just check the type?
// Code to test a PyObject for compatibility with wxString
if (!sipIsErr) {
if (PyString_Check(sipPy) || PyUnicode_Check(sipPy))
return 1;
return 0;
return TRUE;
return FALSE;
}
// Or do the conversion
#if wxUSE_UNICODE_WCHAR
// wxString will contain wide chars (wchar_t)
// Code to convert a compatible PyObject to a wxString
PyObject* uni = sipPy;
if (PyString_Check(sipPy)) {
// if it's a string object convert it to unicode first
uni = PyUnicode_FromEncodedObject(sipPy,
"utf-8", /*wxPyDefaultEncoding*/
"strict");
if (PyErr_Occurred()) return 0;
// if it's a string object convert it to unicode first, assuming utf-8
uni = PyUnicode_FromEncodedObject(sipPy, "utf-8", "strict");
if (PyErr_Occurred()) {
*sipIsErr = 1;
return 0;
}
}
*sipCppPtr = new wxString();
size_t len = PyUnicode_GET_SIZE(uni);
@@ -49,37 +45,24 @@
if (PyString_Check(sipPy))
Py_DECREF(uni); // release the temporary Unicode object we created
return sipGetState(sipTransferObj);
#else
// wxString will contain a utf-8 encoded byte string. If source is
// already a string then use it as-is, (assuming utf-8) otherwise
// the Unicode object to utf-8 and use the converted value.
char* tmpPtr; Py_ssize_t tmpSize;
PyObject* str = NULL;
//PyObject* uni = NULL;
if (PyString_Check(sipPy) /*&& wxPyDefaultEncodingIsUTF8 */) {
PyString_AsStringAndSize(sipPy, &tmpPtr, &tmpSize);
}
//else if (PyString_Check(sipPy)) {
// uni = PyUnicode_FromEncodedObject(sipPy, wxPyDefaultEncoding, "strict");
// if (PyErr_Occurred()) return NULL;
// str = PyUnicode_AsUTF8String(uni);
// PyString_AsStringAndSize(sipPy, &tmpPtr, &tmpSize);
//}
else {
str = PyUnicode_AsUTF8String(sipPy);
PyString_AsStringAndSize(str, &tmpPtr, &tmpSize);
}
*sipCppPtr = new wxString(tmpPtr, tmpSize);
Py_XDECREF(str);
//Py_XDECREF(uni);
return sipGetState(sipTransferObj);
#endif
%End
// Code to convert a wxString to a PyObject
%ConvertFromTypeCode
return sipBuildResult(NULL, "G", sipCpp->c_str(), sipCpp->length());
// Code to convert a wxString to a Python Unicode object.
return PyUnicode_FromWideChar(sipCpp->wc_str(), sipCpp->length());
%End
};
// Used just for testing the MappedType code
%ModuleCode
wxString testStringTypemap(const wxString& str)
{
wxString local = str;
return local;
}
%End
wxString testStringTypemap(const wxString& str);

104
src/wxpy_utils.sip Normal file
View File

@@ -0,0 +1,104 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wxpy_utils.sip
// Purpose: Some utility functions and such that can be used in other
// snippets of C++ code to help reduce complexity, etc.
//
// Author: Robin Dunn
//
// Created: 19-Nov-2010
// Copyright: (c) 2010 by Total Control Software
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
%ModuleHeaderCode
// Convert a PyObject to a wxString
wxString Py2wxString(PyObject* source);
// Raise NotImplemented exceptions
inline void wxPyRaiseNotImplemented() {
PyErr_SetNone(PyExc_NotImplementedError);
}
inline void wxPyRaiseNotImplementedMsg(const char* msg) {
PyErr_SetString(PyExc_NotImplementedError, msg);
}
typedef PyGILState_STATE wxPyBlock_t;
// Calls from Python to wxWindows code are wrapped in calls to these
// functions:
inline PyThreadState* wxPyBeginAllowThreads() {
PyThreadState* saved = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS;
return saved;
}
inline void wxPyEndAllowThreads(PyThreadState* saved) {
PyEval_RestoreThread(saved); // Py_END_ALLOW_THREADS;
}
// Calls from wxWindows back to Python code, or even any PyObject
// manipulations, PyDECREF's and etc. are wrapped in calls to these functions:
inline wxPyBlock_t wxPyBeginBlockThreads() {
if (! Py_IsInitialized()) {
return (wxPyBlock_t)0;
}
PyGILState_STATE state = PyGILState_Ensure();
return state;
}
inline void wxPyEndBlockThreads(wxPyBlock_t blocked) {
if (! Py_IsInitialized()) {
return;
}
PyGILState_Release(blocked);
}
%End
%ModuleCode
// Various wxPython helper/utility functions
// See also the wxString MappedType. This code is similar, but doesn't
// allocate a new wxString instance on the heap, is able to convert
// non-string/unicode objects to unicode, and won't raise exceptions
wxString Py2wxString(PyObject* source)
{
PyObject* uni = source;
if (PyString_Check(source)) {
// if it's a string object convert it to unicode first, assumes utf-8
uni = PyUnicode_FromEncodedObject(source, "utf-8", "strict");
if (PyErr_Occurred()) {
PyErr_Clear();
return wxEmptyString;
}
}
else if (!PyUnicode_Check(source)) {
uni = PyObject_Unicode(source);
if (PyErr_Occurred()) {
PyErr_Clear();
return wxEmptyString;
}
}
wxString target;
size_t len = PyUnicode_GET_SIZE(uni);
if (len) {
PyUnicode_AsWideChar((PyUnicodeObject*)uni,
wxStringBuffer(target, len), len);
}
if (!PyUnicode_Check(source))
Py_DECREF(uni); // release the temporary Unicode object we created
return target;
}
%End

28
unittests/test_app.py Normal file
View File

@@ -0,0 +1,28 @@
import unittest2
import wxPhoenix as wx
#---------------------------------------------------------------------------
class App(unittest2.TestCase):
def test_App(self):
app = wx.App()
def test_App_OnInit(self):
class MyApp(wx.App):
def OnInit(self):
self.onInit_called = True
return True
app = MyApp()
self.assertTrue(app.onInit_called)
#---------------------------------------------------------------------------
if __name__ == '__main__':
unittest2.main()

55
unittests/test_colour.py Normal file
View File

@@ -0,0 +1,55 @@
import unittest2
import wxPhoenix as wx
#---------------------------------------------------------------------------
class Colour(unittest2.TestCase):
def setUp(self):
if hasattr(wx, 'InitializeStockLists'):
wx.InitializeStockLists() # switch to wx.App once we have that class working
def test_default_ctor(self):
c = wx.Colour()
self.assertTrue(not c.IsOk())
self.assertTrue(c.Get() == (-1,-1,-1,255))
def test_rgb_ctor(self):
c = wx.Colour(1,2,3)
self.assertTrue(c.Get(False) == (1,2,3))
def test_rgba_ctor(self):
c = wx.Colour(1,2,3,4)
self.assertTrue(c.Get() == (1,2,3,4))
def test_copy_ctor(self):
c1 = wx.Colour(1,2,3,4)
c2 = wx.Colour(c1)
self.assertTrue(c1 == c2)
self.assertTrue(c1 is not c2)
self.assertTrue(c1.Get() == c2.Get())
if hasattr(wx, 'testColourTypeMap'):
def test_ColourTypemaps(self):
c = wx.testColourTypeMap('red')
self.assertTrue(c.Get() == (0xff, 0, 0, 0xff))
c = wx.testColourTypeMap('Blue:80')
self.assertTrue(c.Get() == (0, 0, 0xff, 0x80))
c = wx.testColourTypeMap('#112233')
self.assertTrue(c.Get() == (0x11, 0x22, 0x33, 0xff))
c = wx.testColourTypeMap('#11223344')
self.assertTrue(c.Get() == (0x11, 0x22, 0x33, 0x44))
c = wx.testColourTypeMap(None)
self.assertTrue(c.Get() == (-1, -1, -1, 0xff))
c = wx.testColourTypeMap( (1,2,3) )
self.assertTrue(c.Get() == (1, 2, 3, 0xff))
c = wx.testColourTypeMap( (1,2,3,4) )
self.assertTrue(c.Get() == (1, 2, 3, 4))
#---------------------------------------------------------------------------
if __name__ == '__main__':
unittest2.main()

View File

@@ -1,5 +1,5 @@
import unittest2
import wx
import wxPhoenix as wx
#---------------------------------------------------------------------------

View File

@@ -1,5 +1,5 @@
import unittest2
import wx
import wxPhoenix as wx
#---------------------------------------------------------------------------

View File

@@ -1,5 +1,5 @@
import unittest2
import wx
import wxPhoenix as wx
#---------------------------------------------------------------------------

View File

@@ -1,5 +1,5 @@
import unittest2
import wx
import wxPhoenix as wx
#---------------------------------------------------------------------------

View File

@@ -1,5 +1,5 @@
import unittest2
import wx
import wxPhoenix as wx
#---------------------------------------------------------------------------

62
unittests/test_string.py Normal file
View File

@@ -0,0 +1,62 @@
import unittest2
import wxPhoenix as wx
#---------------------------------------------------------------------------
class String(unittest2.TestCase):
if hasattr(wx, 'testStringTypemap'):
def test_StringTypemaps(self):
utf = '\xc3\xa9l\xc3\xa9phant' # utf-8 string
uni = utf.decode('utf-8') # convert to unicode
iso = uni.encode('iso-8859-1') # make a string with a different encoding
# wx.testStringTypemap() will accept a parameter that is a Unicode object
# or an 'ascii' or 'utf-8' string object, which will then be converted to
# a wxString. The return value is a Unicode object that has been
# converted from a wxString that is a copy of the wxString created for
# the parameter.
# ascii
result = wx.testStringTypemap('hello')
self.assertTrue(type(result) == unicode)
self.assertTrue(result == u'hello')
# unicode should pass through unmodified
result = wx.testStringTypemap(uni)
self.assertTrue(result == uni)
# utf-8 is converted
result = wx.testStringTypemap(utf)
self.assertTrue(result == uni)
# can't auto-convert this
with self.assertRaises(UnicodeDecodeError):
result = wx.testStringTypemap(iso)
# utf-16-be
val = "\x00\xe9\x00l\x00\xe9\x00p\x00h\x00a\x00n\x00t"
with self.assertRaises(UnicodeDecodeError):
result = wx.testStringTypemap(val)
result = wx.testStringTypemap( val.decode('utf-16-be'))
self.assertTrue(result == uni)
# utf-32-be
val = "\x00\x00\x00\xe9\x00\x00\x00l\x00\x00\x00\xe9\x00\x00\x00p\x00\x00\x00h\x00\x00\x00a\x00\x00\x00n\x00\x00\x00t"
with self.assertRaises(UnicodeDecodeError):
result = wx.testStringTypemap(val)
result = wx.testStringTypemap(val.decode('utf-32-be'))
self.assertTrue(result == uni)
# utf-8 with BOM
val = "\xef\xbb\xbfHello"
result = wx.testStringTypemap(val)
self.assertTrue(result == u'\ufeffHello')
#---------------------------------------------------------------------------
if __name__ == '__main__':
unittest2.main()