From 986d868ccb57f93f0cab43a7009d0df8435629e7 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Fri, 13 May 2016 18:51:53 -0700 Subject: [PATCH] Begin merging the remaining parts for PR #35. Add _msw module for wxMSW-only things, starting with the metafile classes. --- demo/ActiveX_IEHtmlWindow.py | 2 +- etg/_msw.py | 69 ++++++++++++++++++++++++++++++++++++ etg/mediactrl.py | 8 +++++ etg/metafile.py | 52 +++++++++++++++++++++++++++ unittests/test_mediactrl.py | 3 +- unittests/test_metafile.py | 25 +++++++++++++ wscript | 27 +++++++++----- wx/lib/activex.py | 10 +++--- wx/lib/activexwrapper.py | 7 ++-- 9 files changed, 184 insertions(+), 19 deletions(-) create mode 100644 etg/_msw.py create mode 100644 etg/metafile.py create mode 100644 unittests/test_metafile.py diff --git a/demo/ActiveX_IEHtmlWindow.py b/demo/ActiveX_IEHtmlWindow.py index 86a40955..ef1c20db 100644 --- a/demo/ActiveX_IEHtmlWindow.py +++ b/demo/ActiveX_IEHtmlWindow.py @@ -66,7 +66,7 @@ class TestPanel(wx.Panel): btnSizer.Add(txt, 0, wx.CENTER|wx.ALL, 2) self.location = wx.ComboBox( - self, -1, "", style=wx.CB_DROPDOWN|wx.PROCESS_ENTER + self, -1, "", style=wx.CB_DROPDOWN|wx.TE_PROCESS_ENTER ) self.Bind(wx.EVT_COMBOBOX, self.OnLocationSelect, self.location) diff --git a/etg/_msw.py b/etg/_msw.py new file mode 100644 index 00000000..2133f342 --- /dev/null +++ b/etg/_msw.py @@ -0,0 +1,69 @@ +# --------------------------------------------------------------------------- +# Name: etg/_msw.py +# Author: Dietmar Schwertberger +# +# Created: 13-Nov-2015 +# Copyright: (c) 2015-2016 by Total Control Software +# License: wxWindows License +# --------------------------------------------------------------------------- + +import etgtools +import etgtools.tweaker_tools as tools + +PACKAGE = "wx" +MODULE = "_msw" +NAME = "_msw" # 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 = [] + +# 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. + +INCLUDES = ['metafile', + # 'pyaxbase', + # 'activex' + ] + +# Separate the list into those that are generated from ETG scripts and the +# rest. These lists can be used from the build scripts to get a list of +# sources and/or additional dependencies when building this extension module. +ETGFILES = ['etg/%s.py' % NAME] + tools.getEtgFiles(INCLUDES) +DEPENDS = tools.getNonEtgFiles(INCLUDES) +OTHERDEPS = [] + + +# --------------------------------------------------------------------------- + +def run(): + # Parse the XML file(s) building a collection of Extractor objects + module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING) + etgtools.parseDoxyXML(module, ITEMS) + module.check4unittest = False + + # ----------------------------------------------------------------- + # Tweak the parsed meta objects in the module object as needed for + # customizing the generated code and docstrings. + + module.addHeaderCode('#include ') + module.addImport('_core') + module.addPyCode('import wx', order=10) + module.addInclude(INCLUDES) + + # ----------------------------------------------------------------- + # ----------------------------------------------------------------- + tools.doCommonTweaks(module) + tools.runGenerators(module) + + +# --------------------------------------------------------------------------- + +if __name__ == '__main__': + run() \ No newline at end of file diff --git a/etg/mediactrl.py b/etg/mediactrl.py index 7a23f762..6faa559a 100644 --- a/etg/mediactrl.py +++ b/etg/mediactrl.py @@ -49,6 +49,14 @@ def run(): # keep e.g. '(const wxString &fileName)' item.ignore() + # Transplant the docstrings from the ignored Load methods into the + # appropriate compatibility method + if 'proxy' in item.argsString: + m = c.find('LoadURIWithProxy') + else: + m = c.find('LoadURI') + m.briefDoc = item.briefDoc + m.detailedDoc = item.detailedDoc c = module.find('wxMediaEvent') diff --git a/etg/metafile.py b/etg/metafile.py new file mode 100644 index 00000000..3cfd7570 --- /dev/null +++ b/etg/metafile.py @@ -0,0 +1,52 @@ +#--------------------------------------------------------------------------- +# Name: etg/metafile.py +# Author: Robin Dunn +# Dietmar Schwertberger +# +# Created: 01-Nov-2015 +# Copyright: (c) 2015 by Wide Open Technologies +# License: wxWindows License +#--------------------------------------------------------------------------- + +import etgtools +import etgtools.tweaker_tools as tools + +PACKAGE = "wx" +MODULE = "_core" +NAME = "metafile" # 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 = [ 'wxMetafile', + 'wxMetafileDC', + ] + + +#--------------------------------------------------------------------------- + +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('wxMetafile') + c.addPrivateCopyCtor() + + c = module.find('wxMetafileDC') + c.addPrivateCopyCtor() + + module.find("wxMakeMetafilePlaceable").ignore() + + #----------------------------------------------------------------- + tools.doCommonTweaks(module) + tools.runGenerators(module) + + +#--------------------------------------------------------------------------- +if __name__ == '__main__': + run() diff --git a/unittests/test_mediactrl.py b/unittests/test_mediactrl.py index a20a17fa..99187e47 100644 --- a/unittests/test_mediactrl.py +++ b/unittests/test_mediactrl.py @@ -33,7 +33,8 @@ class mediactrl_Tests(wtc.WidgetTestCase): def test_mediactrl4(self): evt = wx.media.MediaEvent() - + + def test_mediactrl5(self): wx.media.wxEVT_MEDIA_LOADED wx.media.wxEVT_MEDIA_STOP diff --git a/unittests/test_metafile.py b/unittests/test_metafile.py new file mode 100644 index 00000000..d622a96a --- /dev/null +++ b/unittests/test_metafile.py @@ -0,0 +1,25 @@ +import unittest +import wtc +import wx +import wx.msw +import os + +fileName = 'metafiletest.emf' + +#--------------------------------------------------------------------------- + +class MetafileDCTests(wtc.WidgetTestCase): + + @unittest.skipIf('wxMSW' in wx.PlatformInfo, "Metafile classes only implemented on Windows") + def test_MetafileDC1(self): + dc = wx.msw.MetafileDC(fileName) + dc.DrawLine(0,0, 50,50) + del dc + + os.remove(fileName) + +#--------------------------------------------------------------------------- + + +if __name__ == '__main__': + unittest.main() diff --git a/wscript b/wscript index 26f129a6..c278308e 100644 --- a/wscript +++ b/wscript @@ -225,10 +225,10 @@ def configure(conf): # ** Add code for new modules here - # NOTE: This assumes that if the platform is not win32 (from - # the test above) and not darwin then we must be using the - # GTK2 port of wxWidgets. If we ever support other ports then - # this code will need to be adjusted. + # NOTE: This assumes that if the platform is not win32 (from the test + # above) and not darwin then we must be using the GTK2 or GTK3 port of + # wxWidgets. If we ever support other ports then this code will need + # to be adjusted. if not isDarwin: if conf.options.gtk3: gtkflags = os.popen('pkg-config gtk+-3.0 --cflags', 'r').read()[:-1] @@ -288,8 +288,9 @@ from waflib.Configure import conf @conf def my_check_python_headers(conf): """ - Check for headers and libraries necessary to extend or embed python by using the module *distutils*. - On success the environment variables xxx_PYEXT and xxx_PYEMBED are added: + Check for headers and libraries necessary to extend or embed python by + using the module *distutils*. On success the environment variables + xxx_PYEXT and xxx_PYEMBED are added: * PYEXT: for compiling python extensions * PYEMBED: for embedding a python interpreter @@ -403,7 +404,7 @@ def my_check_python_headers(conf): def build(bld): # Ensure that the directory containing this script is on the python - # path for spawned commands so the builder and phoenix packages can be + # sys.path for spawned commands so the builder and phoenix packages can be # found. thisdir = os.path.abspath(".") sys.path.insert(0, thisdir) @@ -578,6 +579,15 @@ def build(bld): ) makeExtCopyRule(bld, '_media') + if isWindows: + etg = loadETG('etg/_msw.py') + bld(features = 'c cxx cxxshlib pyext', + target = makeTargetName(bld, '_msw'), + source = getEtgSipCppFiles(etg) + rc, + uselib = 'WX WXPY', + ) + makeExtCopyRule(bld, '_msw') + # ** Add code for new modules here @@ -621,8 +631,7 @@ def copyFileToPkg(task): from buildtools.config import opj src = task.inputs[0].abspath() tgt = task.outputs[0].abspath() - #task.exec_command('touch %s' % tgt) - open(tgt, "wb").close() # 'touch' + open(tgt, "wb").close() # essentially just a unix 'touch' command tgt = opj(cfg.PKGDIR, os.path.basename(src)) copy_file(src, tgt, verbose=1) return 0 diff --git a/wx/lib/activex.py b/wx/lib/activex.py index 5ff72c98..c8e66864 100644 --- a/wx/lib/activex.py +++ b/wx/lib/activex.py @@ -90,7 +90,7 @@ class ActiveXCtrl(wx.PyAxBaseWindow): # create the control atl.AtlAxWinInit() hInstance = kernel32.GetModuleHandleA(None) - hwnd = user32.CreateWindowExA(0, "AtlAxWin", axID, + hwnd = user32.CreateWindowExA(0, b"AtlAxWin", axID.encode("ASCII"), WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, x,y, w,h, parent.GetHandle(), None, @@ -112,10 +112,12 @@ class ActiveXCtrl(wx.PyAxBaseWindow): self._evt_connections = [] self.AddEventSink(self) - # Turn the window handle into a wx.Window and set this object to be that window - win = wx.PyAxBaseWindow_FromHWND(parent, hwnd) - self.PostCreate(win) + wx.Window.__init__(self, parent, wxid, pos, size, style, name) + # Turn the window handle into a wx.Window and set this object to be that window + #win = wx.PyAxBaseWindow_FromHWND(parent, hwnd) + self.AssociateHandle(hwnd) + # Set some wx.Window properties if wxid == wx.ID_ANY: wxid = wx.Window.NewControlId() diff --git a/wx/lib/activexwrapper.py b/wx/lib/activexwrapper.py index ec7d626d..29325557 100644 --- a/wx/lib/activexwrapper.py +++ b/wx/lib/activexwrapper.py @@ -90,8 +90,7 @@ def MakeActiveXClass(CoClass, eventClass=None, eventObj=None): } # make a new class object - import new - classObj = new.classobj(className, baseClasses, classDict) + classObj = type(className, baseClasses, classDict) return classObj @@ -103,7 +102,7 @@ def axw__init__(self, parent, ID=-1, pos=wx.DefaultPosition, size=wx.DefaultSize # init base classes pywin.mfc.activex.Control.__init__(self) wx.Window.__init__( self, parent, -1, pos, size, style|wx.NO_FULL_REPAINT_ON_RESIZE) - self.this.own(False) # this should be set in wx.Window.__init__ when it calls _setOORInfo, but... + #self.this.own(False) # this should be set in wx.Window.__init__ when it calls _setOORInfo, but... win32ui.EnableControlContainer() self._eventObj = self._eventObj # move from class to instance @@ -126,7 +125,7 @@ def axw__init__(self, parent, ID=-1, pos=wx.DefaultPosition, size=wx.DefaultSize def axw__getattr__(self, attr): try: return pywin.mfc.activex.Control.__getattr__(self, attr) - except AttributeError: + except (AttributeError, win32ui.error): try: eo = self.__dict__['_eventObj'] return getattr(eo, attr)