diff --git a/build.py b/build.py index 5b366549..d25316a3 100755 --- a/build.py +++ b/build.py @@ -560,7 +560,7 @@ def build_py(options, args): if arg.startswith("clean"): waf_args = "clean distclean" - command = "./waf %s -v -j6" % waf_args + command = "./waf %s -v -j6 --wx-config=%s/wx-config" % (waf_args, BUILD_DIR) else: command = PYTHON + " -u ./setup.py %s %s %s" % \ (build_mode, " ".join(build_options), options.extra_setup) diff --git a/etg/_core.py b/etg/_core.py index fec40676..9df83f87 100644 --- a/etg/_core.py +++ b/etg/_core.py @@ -97,8 +97,12 @@ INCLUDES = [ 'defs', 'splitter', 'collpane', 'statline', - 'stdpaths', - + 'stdpaths', + 'snglinst', + 'accel', + 'cursor', + 'userdata', + 'log', ] diff --git a/etg/accel.py b/etg/accel.py new file mode 100644 index 00000000..7a9edea5 --- /dev/null +++ b/etg/accel.py @@ -0,0 +1,48 @@ +#--------------------------------------------------------------------------- +# Name: etg/accel.py +# Author: Kevin Ollivier +# +# Created: 06-Sept-2011 +# Copyright: (c) 2011 by Wide Open Technologies +# License: wxWindows License +#--------------------------------------------------------------------------- + +import etgtools +import etgtools.tweaker_tools as tools + +PACKAGE = "wx" +MODULE = "_core" +NAME = "accel" # 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 = [ 'wxAcceleratorEntry', 'wxAcceleratorTable', ] + +#--------------------------------------------------------------------------- + +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('wxAcceleratorTable') + # Mac doesn't have this? + c.find('wxAcceleratorTable').findOverload('resource').ignore() + c.find('wxAcceleratorTable.n').arraySize = True + c.find('wxAcceleratorTable.entries').array = True + c.find('wxAcceleratorTable.entries').type += '*' + #----------------------------------------------------------------- + tools.doCommonTweaks(module) + tools.addGetterSetterProps(module) + tools.runGenerators(module) + + +#--------------------------------------------------------------------------- +if __name__ == '__main__': + run() + diff --git a/etg/app.py b/etg/app.py index fed8bc39..ca869f08 100644 --- a/etg/app.py +++ b/etg/app.py @@ -92,7 +92,9 @@ def run(): item.name = '~wxPyApp' c.find('ProcessMessage').ignore() - + # The deprecation macros unfortunately get used as the method name. + # Until we fix this in the extraction code, just ignore any method marked this way. + c.find('wxDEPRECATED_BUT_USED_INTERNALLY').ignore() c.addCppMethod('void', 'MacHideApp', '()', doc="Hide all application windows just as the user can do with the\nsystem Hide command. Mac only.", diff --git a/etg/bookctrl.py b/etg/bookctrl.py index 531abed5..d4c3e360 100644 --- a/etg/bookctrl.py +++ b/etg/bookctrl.py @@ -33,6 +33,7 @@ def run(): # customizing the generated code and docstrings. c = module.find('wxBookCtrlBase') + c.bases.append('wxWithImages') assert isinstance(c, etgtools.ClassDef) c.abstract = True diff --git a/etg/cursor.py b/etg/cursor.py new file mode 100644 index 00000000..79b92702 --- /dev/null +++ b/etg/cursor.py @@ -0,0 +1,51 @@ +#--------------------------------------------------------------------------- +# Name: etg/cursor.py +# Author: Kevin Ollivier +# +# Created: 06-Sept-2011 +# Copyright: (c) 2011 by Wide Open Technologies +# License: wxWindows License +#--------------------------------------------------------------------------- + +import etgtools +import etgtools.tweaker_tools as tools + +PACKAGE = "wx" +MODULE = "_core" +NAME = "cursor" # 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 = [ 'wxCursor', ] + +#--------------------------------------------------------------------------- + +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('wxCursor') + c.find('wxCursor').findOverload('bits').ignore() + + module.find('wxCROSS_CURSOR').ignore() + module.find('wxHOURGLASS_CURSOR').ignore() + module.find('wxSTANDARD_CURSOR').ignore() + + module.addPyCode('StockCursor = wx.deprecated(Cursor)') + + #----------------------------------------------------------------- + tools.doCommonTweaks(module) + tools.addGetterSetterProps(module) + tools.runGenerators(module) + + +#--------------------------------------------------------------------------- +if __name__ == '__main__': + run() + diff --git a/etg/defs.py b/etg/defs.py index 3b5f6690..5ebcec35 100644 --- a/etg/defs.py +++ b/etg/defs.py @@ -40,7 +40,6 @@ def run(): module.find('wxUint8').pyInt = True module.find('wxByte').pyInt = True - module.find('wxDELETE').ignore() module.find('wxDELETEA').ignore() module.find('wxSwap').ignore() @@ -60,9 +59,7 @@ def run(): # TODO: Add these classes for real :-) module.insertItem(0, etgtools.WigCode("""\ // forward declarations - class wxCursor; class wxPalette; - class wxAcceleratorTable; class wxDropTarget; class wxCaret; class wxImageHandler; diff --git a/etg/dialog.py b/etg/dialog.py index 50cdf4f7..8da074f0 100644 --- a/etg/dialog.py +++ b/etg/dialog.py @@ -20,6 +20,7 @@ DOCSTRING = "" ITEMS = [ 'wxDialog', 'wxDialogLayoutAdapter', + 'wxProgressDialog', ] #--------------------------------------------------------------------------- @@ -32,7 +33,9 @@ def run(): #----------------------------------------------------------------- # Tweak the parsed meta objects in the module object as needed for # customizing the generated code and docstrings. - + + module.addHeaderCode("#include ") + c = module.find('wxDialog') assert isinstance(c, etgtools.ClassDef) tools.fixWindowClass(c) @@ -52,7 +55,11 @@ def run(): # TODO: Restore when wxArrayInt is working c.find('GetMainButtonIds').ignore() - + + c = module.find('wxProgressDialog') + assert isinstance(c, etgtools.ClassDef) + tools.fixWindowClass(c) + tools.removeVirtuals(c) tools.addWindowVirtuals(c) diff --git a/etg/image.py b/etg/image.py index 41475a2b..e0df38ce 100644 --- a/etg/image.py +++ b/etg/image.py @@ -17,7 +17,7 @@ DOCSTRING = "" # The classes and/or the basename of the Doxygen XML files to be processed by # this script. -ITEMS = [ 'wxImage', 'wxImageHistogram' ] +ITEMS = [ 'wxImage', 'wxImageHistogram', 'wxWithImages' ] #--------------------------------------------------------------------------- @@ -43,6 +43,9 @@ def run(): f.find('g').out = True f.find('b').out = True + c = module.find('wxWithImages') + c.addPrivateCopyCtor() + c.addPrivateAssignOp() #----------------------------------------------------------------- tools.doCommonTweaks(module) diff --git a/etg/log.py b/etg/log.py new file mode 100644 index 00000000..4bf39a6c --- /dev/null +++ b/etg/log.py @@ -0,0 +1,59 @@ +#--------------------------------------------------------------------------- +# Name: etg/log.py +# Author: Kevin Ollivier +# +# Created: 08-Sept-2011 +# Copyright: (c) 2011 by Wide Open Technologies +# License: wxWindows License +#--------------------------------------------------------------------------- + +import etgtools +import etgtools.tweaker_tools as tools + +PACKAGE = "wx" +MODULE = "_core" +NAME = "log" # 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 = [ + 'wxLog', + 'wxLogGui', + 'wxLogNull', + 'wxLogRecordInfo', + + ] + +#--------------------------------------------------------------------------- + +def run(): + # Parse the XML file(s) building a collection of Extractor objects + module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING) + module.items.append(etgtools.TypedefDef(type='long', name='time_t')) + etgtools.parseDoxyXML(module, ITEMS) + + # do not use the va_list forms of the functions + for func in module.allItems(): + if 'wxVLog' in func.name: + func.ignore() + module.find('wxLogTrace').ignore() # deprecated in 2.8, do we support? + + c = module.find('wxLogRecordInfo') + c.find('threadId').ignore() + + # deprecated, do we want to keep supporting these? + #----------------------------------------------------------------- + # Tweak the parsed meta objects in the module object as needed for + # customizing the generated code and docstrings. + + #----------------------------------------------------------------- + tools.doCommonTweaks(module) + tools.addGetterSetterProps(module) + tools.runGenerators(module) + + +#--------------------------------------------------------------------------- +if __name__ == '__main__': + run() + diff --git a/etg/sizer.py b/etg/sizer.py index 70a358fa..6c39f798 100644 --- a/etg/sizer.py +++ b/etg/sizer.py @@ -44,8 +44,17 @@ def run(): c.find('Remove').findOverload('(wxWindow *window)').ignore() c = module.find('wxSizerItem') - c.addPrivateCopyCtor() + gud = c.find('GetUserData') + gud.type = 'wxPyUserData*' + gud.setCppCode('sipRes = dynamic_cast(sipCpp->GetUserData());') + sud = c.find('SetUserData') + sud.find('userData').transfer = True + sud.find('userData').type = 'wxPyUserData*' + sud.setCppCode('sipCpp->SetUserData(dynamic_cast(userData));') + + c.addPrivateCopyCtor() + c = module.find('wxFlexGridSizer') c.addPrivateCopyCtor() @@ -62,6 +71,7 @@ def run(): #----------------------------------------------------------------- tools.doCommonTweaks(module) + tools.addGetterSetterProps(module) tools.runGenerators(module) diff --git a/etg/snglinst.py b/etg/snglinst.py new file mode 100644 index 00000000..271a7776 --- /dev/null +++ b/etg/snglinst.py @@ -0,0 +1,45 @@ +#--------------------------------------------------------------------------- +# Name: etg/snglinst.py +# Author: Kevin Ollivier +# +# Created: 6-Sept-2011 +# Copyright: (c) 2011 by Wide Open Technologies +# License: wxWindows License +#--------------------------------------------------------------------------- + +import etgtools +import etgtools.tweaker_tools as tools + +PACKAGE = "wx" +MODULE = "_core" +NAME = "snglinst" # 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 = [ 'wxSingleInstanceChecker' ] + +#--------------------------------------------------------------------------- + +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('wxSingleInstanceChecker') + c.addPrivateCopyCtor() + c.addPrivateAssignOp() + + #----------------------------------------------------------------- + tools.doCommonTweaks(module) + tools.runGenerators(module) + + +#--------------------------------------------------------------------------- +if __name__ == '__main__': + run() + diff --git a/etg/toplevel.py b/etg/toplevel.py index ec5236a9..2002c178 100644 --- a/etg/toplevel.py +++ b/etg/toplevel.py @@ -43,7 +43,7 @@ def run(): c.find('IsUsingNativeDecorations').ignore() c.find('UseNativeDecorations').ignore() c.find('UseNativeDecorationsByDefault').ignore() - + c.find('MSWGetSystemMenu').ignore() # what is this? c.addCppMethod('void', 'MacSetMetalAppearance', '(bool on)', """\ int style = self->GetExtraStyle(); diff --git a/etgtools/extractors.py b/etgtools/extractors.py index cd84f023..506cf50e 100644 --- a/etgtools/extractors.py +++ b/etgtools/extractors.py @@ -356,8 +356,12 @@ class ParamDef(BaseDef): self.extract(element) def extract(self, element): - self.name = element.find('declname').text self.type = flattenNode(element.find('type')) + # we've got varags + if self.type == '...': + self.name = '' + else: + self.name = element.find('declname').text if element.find('defval') is not None: self.default = flattenNode(element.find('defval')) diff --git a/etgtools/tweaker_tools.py b/etgtools/tweaker_tools.py index 9e87e0d2..64155cf2 100644 --- a/etgtools/tweaker_tools.py +++ b/etgtools/tweaker_tools.py @@ -105,8 +105,11 @@ def fixWindowClass(klass): for func in klass.findAll(klass.name) + klass.findAll('Create'): if isinstance(func, extractors.MethodDef): func.find('parent').transferThis = True - # give the id param a default value - func.find('id').default = 'wxID_ANY' + # give the id param a default value if it has one + # some classes like wxProgressDialog don't + id = func.findItem('id') + if id: + id.default = 'wxID_ANY' # if there is a pos or size parameter without a default then give it one. p = func.findItem('pos') diff --git a/src/userdata.sip b/src/userdata.sip new file mode 100644 index 00000000..f71d6d91 --- /dev/null +++ b/src/userdata.sip @@ -0,0 +1,80 @@ +//-------------------------------------------------------------------------- +// Name: userdata.sip +// Purpose: +// +// Author: Kevin Ollivier +// +// Created: 06-Sept-2011 +// Copyright: (c) 2011 by Wide Open Technologies +// Licence: wxWindows license +//-------------------------------------------------------------------------- + + +%ModuleHeaderCode + // A wxPyUserData object that holds a reference to a Python object + class wxPyUserData : public wxObject + { + public: + wxPyUserData() : wxObject() + { + m_obj = NULL; + m_incRef = false; + } + + wxPyUserData(PyObject* obj, bool incref=true) + : wxObject() + { + m_obj = obj; + m_incRef = incref; + if (incref) + Py_INCREF(m_obj); + } + virtual ~wxPyUserData() + { + if (m_incRef) { + // TODO: wxPyBlock_t blocked = wxPyBeginBlockThreads(); + Py_DECREF(m_obj); + //wxPyEndBlockThreads(blocked); + } + m_obj = NULL; + } + PyObject* m_obj; + bool m_incRef; + }; + +%End + + +// We'll use the wxPyUserData defined above wherever a wxObject parameter or +// return value is specified in the API. This MappedType code will convert to/from a +// PyObject so it will be totally transparent to the programmer and from their +// perspective any python object is being stored as the client data. +%MappedType wxPyUserData +{ + %ConvertToTypeCode + // Code to test a PyObject for compatibility + if (!sipIsErr) { + return TRUE; // any python object is valid + } + + // Code to create a new wxPyUserData from the PyObject + wxPyUserData* data = new wxPyUserData(sipPy); + *sipCppPtr = data; + return sipGetState(sipTransferObj); + %End + + + %ConvertFromTypeCode + // Code to convert a wxClientData back to the PyObject. + PyObject* obj; + if (sipCpp == NULL) { + obj = Py_None; + } else { + wxPyUserData* data = static_cast(sipCpp); // TODO: verify pointer type? + obj = data->m_obj; + } + Py_INCREF(obj); + return obj; + %End + +}; diff --git a/unittests/test_windowlist.py b/unittests/test_windowlist.py index 162800f3..f7d1a0c4 100644 --- a/unittests/test_windowlist.py +++ b/unittests/test_windowlist.py @@ -34,7 +34,7 @@ class WindowList(unittest2.TestCase): self.assertTrue(type(tlw) == wx.Frame) self.assertTrue(tlw.Title.startswith('frm')) - def test_WindowList_GetChildren(self): boo + def test_WindowList_GetChildren(self): children = self.frames[0].GetChildren() self.assertTrue(len(children) == 0) children = self.frames[4].GetChildren() diff --git a/wscript b/wscript new file mode 100644 index 00000000..9dfd4eed --- /dev/null +++ b/wscript @@ -0,0 +1,169 @@ +#!/usr/bin/python + +import os +import sys + +import TaskGen +import Utils + +from buildtools.config import Config, msg, opj, loadETG + +from distutils.file_util import copy_file +from distutils.dir_util import mkpath +from distutils.dep_util import newer, newer_group +from distutils.spawn import spawn + +source_exts = [".cpp"] +out = 'build_waf' + +from waflib.TaskGen import feature, after +from waflib.Task import Task +from waflib.Tools import c_preproc + +os.environ["MACOSX_DEPLOYMENT_TARGET"] = "10.4" + +def options(opt): + opt.load('compiler_cc compiler_cxx') + opt.add_option('--wx-config', dest='wx_config', default='wx-config', action='store') + +def configure(conf): + conf.load('compiler_cc compiler_cxx python') + conf.check_python_headers() + wx_config = conf.options.wx_config + + conf.env.append_value('CFLAGS', '-g') + conf.env.append_value('CXXFLAGS', '-g') + conf.check_cfg(path=wx_config, package='', args='--cxxflags --libs', uselib_store='WX', mandatory=True) + + + +def build(bld): + #---------------------------------------------------------------------- + + # Create a buildtools.config.Configuration object + cfg = Config() + + + # Ensure that the directory containing this script is on the python + # path for spawned commands so the builder and phoenix packages can be + # found. + thisdir = os.path.abspath(".") + os.environ['PYTHONPATH'] = thisdir + os.pathsep + os.environ.get('PYTHONPATH', '') + + + WX_PKGLIST = [ cfg.PKGDIR ] + + SCRIPTS = None + DATA_FILES = [] + 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 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')) + + + if os.name == 'nt': + rc_file = ['src/wxc.rc'] + else: + rc_file = [] + + source_dirs = [ + "sip/cpp", + ] + + print "Calling loadETG with %s" % os.path.abspath('etg/_core.py') + etg = loadETG('etg/_core.py') + + def remove_archs(var): + result = [] + skipnext = False + for flag in var: + index = var.index(flag) + nextflag = var[index+1] + if flag == '-arch' or flag == '-isysroot': + skipnext = True + elif not skipnext: + result.append(flag) + else: + skipnext = False + + return result + + bld.env.CFLAGS_PYEXT = remove_archs(bld.env.CFLAGS_PYEXT) + bld.env.CFLAGS_PYEMBED = remove_archs(bld.env.CFLAGS_PYEMBED) + + bld.env.CXXFLAGS_PYEXT = remove_archs(bld.env.CXXFLAGS_PYEXT) + bld.env.CXXFLAGS_PYEMBED = remove_archs(bld.env.CXXFLAGS_PYEMBED) + + bld.env.LINKFLAGS_PYEXT = remove_archs(bld.env.LINKFLAGS_PYEXT) + bld.env.LINKFLAGS_PYEMBED = remove_archs(bld.env.LINKFLAGS_PYEMBED) + + archs = ['-arch', 'i386', '-mmacosx-version-min=10.5'] + bld.env.append_value('CFLAGS_PYEXT', archs) + bld.env.append_value('CFLAGS_PYEMBED', archs) + + bld.env.append_value('CXXFLAGS_PYEXT', archs) + bld.env.append_value('CXXFLAGS_PYEMBED', archs) + + bld.env.append_value('LINKFLAGS_PYEXT', archs) + bld.env.append_value('LINKFLAGS_PYEMBED', archs) + + siplib = bld( + features='c cxx cshlib pyext', + target='siplib', + name='sip', + includes=cfg.includes + ['sip/siplib'], + cflags=cfg.cflags, + defines=cfg.defines, + libpath=cfg.libdirs, + uselib='WX', + install_path="wx" + ) + + siplib.source = siplib.path.ant_glob("sip/siplib/*.c sip/siplib/*.cpp", incl=source_exts) + + bld.add_group() + + wxlib = bld( + features='c cxx cxxshlib pyext', + target='_core', + includes=cfg.includes + ['sip/siplib'], + cflags=cfg.cflags, + defines=cfg.defines, + libpath=cfg.libdirs, + linkflags='./siplib.so', + use= ['WX'], + install_path="wx" + ) + + wxlib.source = wxlib.path.ant_glob("sip/cpp/*.cpp", incl=source_exts, remove=False, maxdepth=3)