diff --git a/etg/_core.py b/etg/_core.py index fa29638d..711defcd 100644 --- a/etg/_core.py +++ b/etg/_core.py @@ -86,8 +86,7 @@ INCLUDES = [ 'defs', 'pyevent', 'process', 'utils', - 'sizer', - 'wrapsizer', + 'sizer', 'gbsizer', 'wrapsizer', 'eventfilter', 'evtloop', diff --git a/etg/gbsizer.py b/etg/gbsizer.py new file mode 100644 index 00000000..62ec8d5f --- /dev/null +++ b/etg/gbsizer.py @@ -0,0 +1,171 @@ +#--------------------------------------------------------------------------- +# Name: etg/gbsizer.py +# Author: Robin Dunn +# +# Created: 06-Dec-2011 +# Copyright: (c) 2011 by Total Control Software +# License: wxWindows License +#--------------------------------------------------------------------------- + +import etgtools +import etgtools.tweaker_tools as tools + +PACKAGE = "wx" +MODULE = "_core" +NAME = "gbsizer" # 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 = [ "wxGBPosition", + "wxGBSpan", + "wxGBSizerItem", + "wxGridBagSizer", + ] + +#--------------------------------------------------------------------------- + +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('wxGBPosition') + assert isinstance(c, etgtools.ClassDef) + c.find('operator!').ignore() + + # allow a 2 element sequence to be auto converted + c.convertFromPyObject = tools.convertTwoIntegersTemplate('wxGBPosition') + + c.addCppMethod('PyObject*', 'Get', '()', """\ + return sipBuildResult(0, "(ii)", self->GetRow(), self->GetCol()); + """, + pyArgsString="Get() -> (row, col)", + briefDoc="Return the row and col properties as a tuple.") + c.addCppMethod('void', 'Set', '(int row=0, int col=0)', """\ + self->SetRow(row); + self->SetCol(col); + """, + briefDoc="Set both the row and column properties.") + + # Add sequence protocol methods and other goodies + c.addPyMethod('__str__', '(self)', 'return str(self.Get())') + c.addPyMethod('__repr__', '(self)', 'return "wx.GBPosition"+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 (GBPosition, self.Get())') + c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]') + c.addPyMethod('__setitem__', '(self, idx, val)', + """\ + if idx == 0: self.Row = val + elif idx == 1: self.Col = val + else: raise IndexError + """) + c.addPyCode('GBPosition.__safe_for_unpickling__ = True') + + # In addition to the normal Row and Col properties let's also have lower + # case versions. + c.addProperty("Row GetRow SetRow") + c.addProperty("Col GetCol SetCol") + c.addProperty("row GetRow SetRow") + c.addProperty("col GetCol SetCol") + + + #----------------------------------------------------------------- + c = module.find('wxGBSpan') + assert isinstance(c, etgtools.ClassDef) + c.find('operator!').ignore() + + # allow a 2 element sequence to be auto converted + c.convertFromPyObject = tools.convertTwoIntegersTemplate('wxGBSpan') + + c.addCppMethod('PyObject*', 'Get', '()', """\ + return sipBuildResult(0, "(ii)", self->GetRowspan(), self->GetColspan()); + """, + pyArgsString="Get() -> (rowspan, colspan)", + briefDoc="Return the rowspan and colspan properties as a tuple.") + c.addCppMethod('void', 'Set', '(int rowspan=0, int colspan=0)', """\ + self->SetRowspan(rowspan); + self->SetColspan(colspan); + """, + briefDoc="Set both the rowspan and colspan properties.") + + # Add sequence protocol methods and other goodies + c.addPyMethod('__str__', '(self)', 'return str(self.Get())') + c.addPyMethod('__repr__', '(self)', 'return "wx.GBSpan"+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 (GBSpan, self.Get())') + c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]') + c.addPyMethod('__setitem__', '(self, idx, val)', + """\ + if idx == 0: self.Rowspan = val + elif idx == 1: self.Colspan = val + else: raise IndexError + """) + c.addPyCode('GBSpan.__safe_for_unpickling__ = True') + + # In addition to the normal Rowspan and Colspan properties let's also have lower + # case versions. + c.addProperty("Rowspan GetRowspan SetRowspan") + c.addProperty("Colspan GetColspan SetColspan") + c.addProperty("rowspan GetRowspan SetRowspan") + c.addProperty("colspan GetColspan SetColspan") + + + #----------------------------------------------------------------- + c = module.find('wxGBSizerItem') + assert isinstance(c, etgtools.ClassDef) + + # transfer ownership of a sizer if the item is managing one + c.find('wxGBSizerItem.sizer').transfer = True + + # deal with userData args in the ctors + for m in c.find('wxGBSizerItem').all(): + if isinstance(m, etgtools.MethodDef) and m.findItem('userData'): + m.find('userData').transfer = True + m.find('userData').type = 'wxPyUserData*' + + # ignore some overloads that would be ambiguous from Python + c.find('GetPos').findOverload('row').ignore() + c.find('GetSpan').findOverload('rowspan').ignore() + + c.find('GetEndPos.row').out = True + c.find('GetEndPos.col').out = True + + #----------------------------------------------------------------- + c = module.find('wxGridBagSizer') + assert isinstance(c, etgtools.ClassDef) + + tools.fixSizerClass(c) + + for func in c.findAll('Add'): + if func.findItem('sizer'): + func.find('sizer').transfer = True + if func.findItem('userData'): + func.find('userData').transfer = True + func.find('userData').type = 'wxPyUserData*' + if func.findItem('item'): + func.find('item').transfer = True + + + # TODO: In Classic we had GetChildren return a list of wxGBSizerItems (in + # a faked out way). Figure out how to do that here too.... + + #module.addItem( + # tools.wxListWrapperTemplate('wxGBSizerItemList', 'wxGBSizerItem', module, 'wxSizerItem')) + + + #----------------------------------------------------------------- + tools.doCommonTweaks(module) + tools.runGenerators(module) + + +#--------------------------------------------------------------------------- +if __name__ == '__main__': + run() + \ No newline at end of file diff --git a/etg/sizer.py b/etg/sizer.py index 84d85c76..c48dd96b 100644 --- a/etg/sizer.py +++ b/etg/sizer.py @@ -84,6 +84,8 @@ def run(): if func.findItem('userData'): func.find('userData').transfer = True func.find('userData').type = 'wxPyUserData*' + if func.findItem('item'): + func.find('item').transfer = True c.find('GetChildren').overloads = [] @@ -163,7 +165,7 @@ def run(): module.addItem(tools.wxListWrapperTemplate('wxSizerItemList', 'wxSizerItem', module)) - + #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module) diff --git a/unittests/test_gbsizer.py b/unittests/test_gbsizer.py new file mode 100644 index 00000000..2d7e154b --- /dev/null +++ b/unittests/test_gbsizer.py @@ -0,0 +1,100 @@ +import imp_unittest, unittest +import wtc +import wx + +#--------------------------------------------------------------------------- + +class gbsizer_Tests(wtc.WidgetTestCase): + + def test_gbsizer_pos1(self): + p1 = wx.GBPosition() + p2 = wx.GBPosition(1,2) + p3 = wx.GBPosition(p2) + p4 = wx.GBPosition( (2,1) ) + + def test_gbsizer_pos2(self): + p1 = wx.GBPosition(3,4) + p1.row + p1.col + p1.Row + p1.Col + p1.row = 5 + p1.col = 6 + self.assertTrue(p1.Row == 5 and p1.Col == 6) + self.assertTrue(p1 == wx.GBPosition(5,6)) + self.assertTrue(p1 != wx.GBPosition(3,4)) + + def test_gbsizer_pos3(self): + p1 = wx.GBPosition(3,4) + self.assertTrue(p1 == (3,4)) + self.assertTrue(p1.Get() == (3,4)) + p1.Set(5,6) + self.assertTrue(p1 == (5,6)) + + def test_gbsizer_pos4(self): + p1 = wx.GBPosition(3,4) + r,c = p1 + self.assertTrue(len(p1) == 2) + p1[0] = 5 + p1[1] = 6 + self.assertTrue((p1.row, p1.col) == (5,6)) + + + + + def test_gbsizer_span1(self): + s1 = wx.GBSpan() + s2 = wx.GBSpan(1,2) + s3 = wx.GBSpan(s2) + s4 = wx.GBSpan( (2,1) ) + + def test_gbsizer_span2(self): + s1 = wx.GBSpan(3,4) + s1.rowspan + s1.colspan + s1.Rowspan + s1.Colspan + s1.rowspan = 5 + s1.colspan = 6 + self.assertTrue(s1.Rowspan == 5 and s1.Colspan == 6) + self.assertTrue(s1 == wx.GBSpan(5,6)) + self.assertTrue(s1 != wx.GBSpan(3,4)) + + def test_gbsizer_span3(self): + s1 = wx.GBSpan(3,4) + self.assertTrue(s1 == (3,4)) + self.assertTrue(s1.Get() == (3,4)) + s1.Set(5,6) + self.assertTrue(s1 == (5,6)) + + def test_gbsizer_span4(self): + s1 = wx.GBSpan(3,4) + r,c = s1 + self.assertTrue(len(s1) == 2) + s1[0] = 5 + s1[1] = 6 + self.assertTrue((s1.rowspan, s1.colspan) == (5,6)) + + + + def test_gbsizer_sizer1(self): + gbs = wx.GridBagSizer(2, 4) + gbs.Add(wx.Panel(self.frame), (1,1), flag=wx.ALL, border=5) # window + gbs.Add(wx.BoxSizer(), (1,2)) # sizer + gbs.Add(5, 25, (1,3)) # spacer + item = wx.GBSizerItem(wx.Panel(self.frame), (1,4), (1,3)) + gbs.Add(item) # item + return gbs + + def test_gbsizer_sizer2(self): + gbs = wx.GridBagSizer() + gbs.Add(wx.Panel(self.frame), (1,1)) + with self.assertRaises(wx.wxAssertionError): + gbs.Add(wx.Panel(self.frame), (0, 0), (2,2)) + + +#--------------------------------------------------------------------------- + + +if __name__ == '__main__': + unittest.main()