From b9e74764ec8fcd4646ff0091be78bd825be24ddb Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Sun, 14 Nov 2010 07:57:09 +0000 Subject: [PATCH] More properties, magic methods and unit tests for gdicmn git-svn-id: https://svn.wxwidgets.org/svn/wx/sandbox/trunk/Phoenix@66148 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- etg/gdicmn.py | 63 +++++++++++++++++++++++++++++++ etgtools/tweaker_tools.py | 79 +++++++++++++++++++++++++++++++++++++++ unittests/test_gdicmn.py | 63 +++++++++++++++++++++++++++++-- 3 files changed, 201 insertions(+), 4 deletions(-) diff --git a/etg/gdicmn.py b/etg/gdicmn.py index a1997074..d377480d 100644 --- a/etg/gdicmn.py +++ b/etg/gdicmn.py @@ -182,6 +182,16 @@ 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() + \ @@ -202,6 +212,34 @@ 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 @@ -224,6 +262,31 @@ 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') + #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- diff --git a/etgtools/tweaker_tools.py b/etgtools/tweaker_tools.py index b0f43671..92be4d4b 100644 --- a/etgtools/tweaker_tools.py +++ b/etgtools/tweaker_tools.py @@ -90,3 +90,82 @@ def convertTwoIntegersTemplate(CLASS): return 0; """.format(**locals()) + +def convertFourIntegersTemplate(CLASS): + return """\ + // is it just a typecheck? + if (!sipIsErr) {{ + if (sipCanConvertToType(sipPy, sipType_{CLASS}, SIP_NO_CONVERTORS)) + return 1; + + if (PySequence_Check(sipPy) && PySequence_Size(sipPy) == 4) {{ + int rval = 1; + PyObject* o1 = PySequence_ITEM(sipPy, 0); + PyObject* o2 = PySequence_ITEM(sipPy, 1); + PyObject* o3 = PySequence_ITEM(sipPy, 2); + PyObject* o4 = PySequence_ITEM(sipPy, 3); + if (!PyNumber_Check(o1) || !PyNumber_Check(o2) || !PyNumber_Check(o3) || !PyNumber_Check(o4)) + rval = 0; + Py_DECREF(o1); + Py_DECREF(o2); + Py_DECREF(o3); + Py_DECREF(o4); + return rval; + }} + return 0; + }} + + // otherwise do the conversion + if (PySequence_Check(sipPy)) {{ + PyObject* o1 = PySequence_ITEM(sipPy, 0); + PyObject* o2 = PySequence_ITEM(sipPy, 1); + PyObject* o3 = PySequence_ITEM(sipPy, 2); + PyObject* o4 = PySequence_ITEM(sipPy, 3); + *sipCppPtr = new {CLASS}(PyInt_AsLong(o1), PyInt_AsLong(o2), + PyInt_AsLong(o3), PyInt_AsLong(o4)); + Py_DECREF(o1); + Py_DECREF(o2); + return sipGetState(sipTransferObj); + }} + *sipCppPtr = reinterpret_cast<{CLASS}*>(sipConvertToType( + sipPy, sipType_{CLASS}, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr)); + return 0; + """.format(**locals()) + + + +def convertTwoDoublesTemplate(CLASS): + return """\ + // is it just a typecheck? + if (!sipIsErr) {{ + if (sipCanConvertToType(sipPy, sipType_{CLASS}, SIP_NO_CONVERTORS)) + return 1; + + if (PySequence_Check(sipPy) && PySequence_Size(sipPy) == 2) {{ + int rval = 1; + PyObject* o1 = PySequence_ITEM(sipPy, 0); + PyObject* o2 = PySequence_ITEM(sipPy, 1); + if (!PyNumber_Check(o1) || !PyNumber_Check(o2)) + rval = 0; + Py_DECREF(o1); + Py_DECREF(o2); + return rval; + }} + return 0; + }} + + // otherwise do the conversion + if (PySequence_Check(sipPy)) {{ + PyObject* o1 = PySequence_ITEM(sipPy, 0); + PyObject* o2 = PySequence_ITEM(sipPy, 1); + *sipCppPtr = new {CLASS}(PyFloat_AsDouble(o1), PyFloat_AsDouble(o2)); + Py_DECREF(o1); + Py_DECREF(o2); + return sipGetState(sipTransferObj); + }} + *sipCppPtr = reinterpret_cast<{CLASS}*>(sipConvertToType( + sipPy, sipType_{CLASS}, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr)); + return 0; + """.format(**locals()) + + diff --git a/unittests/test_gdicmn.py b/unittests/test_gdicmn.py index fc5e2eee..e43888fc 100644 --- a/unittests/test_gdicmn.py +++ b/unittests/test_gdicmn.py @@ -164,6 +164,10 @@ class Size(unittest2.TestCase): s = s1 - s2 s = s1 / 5 + def test_DefaultSize(self): + ds = wx.DefaultSize + self.assertRaises(ds == (-1,-1)) + def test_GetSet(self): s = wx.Size(100,200) t = s.Get() @@ -196,14 +200,65 @@ class Size(unittest2.TestCase): s[2] +#--------------------------------------------------------------------------- +class RealPoint(unittest2.TestCase): + + def test_default_ctor(self): + p = wx.RealPoint() + + def test_xy_ctor(self): + p = wx.RealPoint(12.3, 34.5) + + def test_Point_ctor(self): + p = wx.RealPoint(wx.Point(3,5)) + p = wx.RealPoint( (3,5) ) + + def test_copy_ctor(self): + p1 = wx.RealPoint(12.3, 45.6) + p2 = wx.RealPoint(p1) + + def test_properties(self): + p = wx.RealPoint(12.3, 45.6) + p.x += 2 + p.y += 2 + + + +#--------------------------------------------------------------------------- + +class Rect(unittest2.TestCase): + + def test_default_ctor(self): + r = wx.Rect() + + def test_xywh_ctor(self): + r = wx.Rect(1, 2, 3, 4) + + def test_tlbr_ctor(self): + r = wx.Rect(wx.Point(10,10), wx.Point(100,100)) + self.assertTrue(r.width == 91 and r.height == 91) + self.assertTrue(r.bottomRight == wx.Point(100,100)) + self.assertTrue(r.topLeft == wx.Point(10,10)) + + def test_possize_ctor(self): + # TODO: we have to use keyword args here since wx.Size has sequence + # protocol methods then it can also match the typemap for wxPoint and + # the other ctor is found first. Check if there is a way to fix or + # work around this. + r = wx.Rect(wx.Point(10,10), size=wx.Size(100,100)) + self.assertTrue(r.width == 100 and r.height == 100) + self.assertTrue(r.x == 10 and r.y == 10) + self.assertTrue(r == wx.Rect(pos=(10,10), size=(100,100))) + + def test_size_ctor(self): + r = wx.Rect(wx.Size(50,100)) + self.assertTrue(r.width == 50 and r.height == 100) + self.assertTrue(r.x == 0 and r.y == 0) - - - - + # TODO: more tests!