From a8d55739f87d26e5cec7ed0566b8f7c9c44a9fa5 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Mon, 3 May 2004 17:13:48 +0000 Subject: [PATCH] Misc tests, scripts, etc. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@27078 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- wxPython/misc/fixdc.py | 130 ++++++++++++ wxPython/misc/widgetLayoutTest.cfg | 38 ++++ wxPython/misc/widgetLayoutTest.py | 311 +++++++++++++++++++++++++++++ 3 files changed, 479 insertions(+) create mode 100644 wxPython/misc/fixdc.py create mode 100644 wxPython/misc/widgetLayoutTest.cfg create mode 100644 wxPython/misc/widgetLayoutTest.py diff --git a/wxPython/misc/fixdc.py b/wxPython/misc/fixdc.py new file mode 100644 index 0000000000..29e98000c5 --- /dev/null +++ b/wxPython/misc/fixdc.py @@ -0,0 +1,130 @@ +""" +This module will do surgery on the wx.DC class in wxPython 2.5.1.5 to +make it act like the wx.DC class in later versions will. To use this +module simply import it in one of your program's modules before you +use any DC's. It does its work upon import and then is done. + +This module will *only* do something if it is imported in an app +running on wxPython 2.5.1.5, for all other versions it will do +nothing. This means that you can include it with your application and +then if your user is on 2.5.1.5 the DC methods will be updated, but if +they are on a newer version (or an older one for that matter) then +nothing will be done and your code using DCs will still be compatible. + +So what does it do? In a nutshell, the old 2.4.x style of method +names, where the 'normal' name takes separate parameters for x, y, +width and height will be restored, and the new methods that take +wx.Point and/or wx.Size (which can also be converted from 2-element +sequences) will be given new non-default method names. The 2.5.1.5 +'XY' style names will be removed. The new names for the 'Point/Size' +methods are: + + * BlitPointSize + * CrossHairPoint + * DrawArcPoint + * DrawBitmapPoint + * DrawCheckMarkRect + * DrawCirclePoint + * DrawEllipsePointSize + * DrawEllipticArcPointSize + * DrawIconPoint + * DrawLinePoint + * DrawPointPoint + * DrawRectanglePointSize + * DrawRotatedTextPoint + * DrawRoundedRectanglePointSize + * DrawTextPoint + * FloodFillPoint + * GetPixelPoint + * SetClippingRegionPointSize + +Please note that only the names that you access the methods by will be +changed. The names used in docstrings as well as the names used to +call the extenaion functions and the names used when raising +exceptions will still use the old names. (Of course once a new +version of wxPython has been built with this new style then this will +no longer apply. The new names will be the real names.) For +example:: + + Traceback (most recent call last): + File "/usr/lib/python2.3/site-packages/wx/lib/buttons.py", line 272, in OnPaint + self.DrawBezel(dc, x1, y1, x2, y2) + File "/usr/lib/python2.3/site-packages/wx/lib/buttons.py", line 220, in DrawBezel + dc.DrawLine((x1+i, y1), (x1+i, y2-i)) + File "/usr/lib/python2.3/site-packages/wx/gdi.py", line 2293, in DrawLine + return _gdi.DC_DrawLineXY(*args, **kwargs) + TypeError: DC_DrawLineXY() takes exactly 5 arguments (3 given) + + +WARNING: If you import this module then the wx.DC class will be + changed for the entire application, so if you use code from + the wx.lib package (or 3rd party modules that have already + been converted to the doomed 2.5.1.5 implementaion of the DC + Draw methods) then that code will break as shown above. This + is an all-or-nothing fix, (just like the next version of + wxPython will be,) so you *will* need to do something to + resolve this situation if you run into it. The best thing to + do of course is to correct the library module to work with + the corrected DC semantics and then send me a patch, although + it probably won't be too long before the library modules are + updated in CVS so you could get a copy of them there. + +--Robin +""" + +import wx + +_names = [ + ("BlitXY", "Blit", "BlitPointSize"), + ("CrossHairXY", "CrossHair", "CrossHairPoint"), + ("DrawArcXY", "DrawArc", "DrawArcPoint"), + ("DrawBitmapXY", "DrawBitmap", "DrawBitmapPoint"), + ("DrawCheckMarkXY", "DrawCheckMark", "DrawCheckMarkRect"), + ("DrawCircleXY", "DrawCircle", "DrawCirclePoint"), + ("DrawEllipseXY", "DrawEllipse", "DrawEllipsePointSize"), + ("DrawEllipticArcXY", "DrawEllipticArc", "DrawEllipticArcPointSize"), + ("DrawIconXY", "DrawIcon", "DrawIconPoint"), + ("DrawLineXY", "DrawLine", "DrawLinePoint"), + ("DrawPointXY", "DrawPoint", "DrawPointPoint"), + ("DrawRectangleXY", "DrawRectangle", "DrawRectanglePointSize"), + ("DrawRotatedTextXY", "DrawRotatedText", "DrawRotatedTextPoint"), + ("DrawRoundedRectangleXY", "DrawRoundedRectangle", "DrawRoundedRectanglePointSize"), + ("DrawTextXY", "DrawText", "DrawTextPoint"), + ("FloodFillXY", "FloodFill", "FloodFillPoint"), + ("GetPixelXY", "GetPixel", "GetPixelPoint"), + ("SetClippingRegionXY", "SetClippingRegion", "SetClippingRegionPointSize"), +] + + +# this is a bit of handy code from the Python Cookbook +def _renamefunction(function, name): + """ + This function returns a function identical to the given one, but + with the given name. + """ + from types import FunctionType, CodeType + + c = function.func_code + if c.co_name != name: + # rename the code object. + c = CodeType(c.co_argcount, c.co_nlocals, c.co_stacksize, + c.co_flags, c.co_code, c.co_consts, + c.co_names, c.co_varnames, c.co_filename, + name, c.co_firstlineno, c.co_lnotab) + if function.func_defaults != None: + return FunctionType(c, function.func_globals, name, + function.func_defaults) + return FunctionType(c, function.func_globals, name) + + +if wx.VERSION[:4] == (2,5,1,5): + for old, norm, new in _names: + m_old = getattr(wx.DC, old) + m_norm = getattr(wx.DC, norm) + setattr(wx.DC, new, _renamefunction(m_norm, new)) + setattr(wx.DC, norm, _renamefunction(m_old, norm)) + delattr(wx.DC, old) + + del old, norm, new, m_old, m_norm + + diff --git a/wxPython/misc/widgetLayoutTest.cfg b/wxPython/misc/widgetLayoutTest.cfg new file mode 100644 index 0000000000..9a1c4d8d07 --- /dev/null +++ b/wxPython/misc/widgetLayoutTest.cfg @@ -0,0 +1,38 @@ +[ +['wx', 'Button', '-1, "normal"'], +['wx', 'Button', '-1, "with a longer, longer label"'], +['wx', 'Button', '-1, "sized", size=(200,100)'], +['wx', 'CheckBox', '-1, "checkbox"'], +['wx', 'CheckBox', '-1, "checkbox with longer label"'], +['wx', 'TextCtrl', '-1, "default"'], +['wx', 'TextCtrl', '-1, "small", size=(30,-1)'], +['wx', 'TextCtrl', '-1, "larger size", size=(200, -1)'], +['wx', 'BitmapButton', '-1, wx.Bitmap("image.png")'], +['wx', 'StaticBitmap', '-1, wx.Bitmap("image.png")'], +['wx.calendar', 'CalendarCtrl', '-1'], +['wx', 'CheckListBox', '-1, choices="one two three four five six seven eight".split()'], +['wx', 'Choice', '-1, choices="one two three four five six seven eight".split()'], +['wx', 'ComboBox', '-1, choices="one two three four five six seven eight".split(), value="default"'], +['wx', 'Gauge', '-1, 100'], +['wx', 'Gauge', '-1, 100, style=wx.GA_VERTICAL'], +['wx', 'ListBox', '-1, choices="one two three four five six seven eight".split()'], +['wx', 'ListCtrl', ''], +['wx', 'TreeCtrl', ''], +['wx', 'ScrollBar', ''], +['wx', 'ScrollBar', 'style=wx.SB_VERTICAL'], +['wx', 'SpinButton', ''], +['wx', 'SpinButton', 'style=wx.SP_VERTICAL'], +['wx', 'SpinCtrl', ''], +['wx', 'StaticText', '-1, "static text"'], +['wx', 'RadioBox', '-1, "label", choices="one two three four".split()'], +['wx', 'RadioBox', '-1, "label", choices="one two three four".split(), style=wx.RA_VERTICAL'], +['wx', 'RadioBox', '-1, "label", choices="one two three four five six seven eight".split(), majorDimension=2'], +['wx', 'RadioBox', '-1, "label", choices="one two three four five six seven eight".split(), style=wx.RA_VERTICAL, majorDimension=2'], +['wx', 'RadioButton', '-1, "radio button"'], +['wx', 'Slider', '-1, 20, 0, 100'], +['wx', 'Slider', '-1, 20, 0, 100, size=(400, -1)'], +['wx', 'Slider', '-1, 20, 0, 100, style=wx.SL_VERTICAL'], +['wx', 'Slider', '-1, 20, 0, 100, style=wx.SL_LABELS'], +['wx', 'Slider', '-1, 20, 0, 100, style=wx.SL_LABELS, size=(400,-1)'], +['wx', 'Slider', '-1, 20, 0, 100, style=wx.SL_VERTICAL|wx.SL_LABELS'], +] diff --git a/wxPython/misc/widgetLayoutTest.py b/wxPython/misc/widgetLayoutTest.py new file mode 100644 index 0000000000..e9f61c6bbb --- /dev/null +++ b/wxPython/misc/widgetLayoutTest.py @@ -0,0 +1,311 @@ +""" +This test app is meant to help check if a widget has a good +DoGetBestSize method (in C++) by allowing the user to dynamically +create any non-toplevel widget which will be placed in a Sizer +designed to show how the widget will be sized naturally. +""" + +import wx +import sys +import os + + +class LayoutTestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "Widget Layout Tester") + + p = wx.Panel(self) + + # Create control widgets + self.testHistory = wx.ListBox(p, -1, size=(150, 250)) + self.moduleName = wx.TextCtrl(p, -1, "wx") + self.className = wx.TextCtrl(p, -1, "") + self.parameters = wx.TextCtrl(p, -1, "") + self.expression = wx.TextCtrl(p, -1, "", style=wx.TE_READONLY) + self.docstring = wx.TextCtrl(p, -1, "", size=(1,125), + style=wx.TE_READONLY|wx.TE_MULTILINE|wx.TE_DONTWRAP) + + + addBtn = wx.Button(p, -1, "Add") + remBtn = wx.Button(p, -1, "Remove") + repBtn = wx.Button(p, -1, "Replace") + createBtn = wx.Button(p, -1, " Create Widget ") + createBtn.SetDefault() + destroyBtn = wx.Button(p, -1, "Destroy Widget") + clearBtn = wx.Button(p, -1, "Clear") + + self.createBtn = createBtn + self.destroyBtn = destroyBtn + + bottomPanel = wx.Panel(p, style=wx.SUNKEN_BORDER, name="bottomPanel") + bottomPanel.SetSizeHints((640,240)) + bottomPanel.SetDefaultBackgroundColour("light blue") + + self.testPanel = wx.Panel(bottomPanel, name="testPanel") + self.testPanel.SetSizeHints((20,20)) + #self.testPanel.SetDefaultBackgroundColour("dark red") + self.testWidget = None + + + # setup event bindings + self.Bind(wx.EVT_TEXT, self.OnUpdate, self.moduleName) + self.Bind(wx.EVT_TEXT, self.OnUpdate, self.className) + self.Bind(wx.EVT_TEXT, self.OnUpdate, self.parameters) + self.Bind(wx.EVT_UPDATE_UI, self.OnEnableCreate, createBtn) + self.Bind(wx.EVT_UPDATE_UI, self.OnEnableDestroy, destroyBtn) + self.Bind(wx.EVT_BUTTON, self.OnCreateWidget, createBtn) + self.Bind(wx.EVT_BUTTON, self.OnDestroyWidget, destroyBtn) + self.Bind(wx.EVT_BUTTON, self.OnClear, clearBtn) + + self.Bind(wx.EVT_CLOSE, self.OnSaveHistory) + + self.Bind(wx.EVT_BUTTON, self.OnAddHistory, addBtn) + self.Bind(wx.EVT_BUTTON, self.OnRemoveHistory, remBtn) + self.Bind(wx.EVT_BUTTON, self.OnReplaceHistory, repBtn) + self.Bind(wx.EVT_LISTBOX, self.OnHistorySelect, self.testHistory) + self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnHistoryActivate, self.testHistory) + + + # setup the layout + mainSizer = wx.BoxSizer(wx.VERTICAL) + topSizer = wx.BoxSizer(wx.HORIZONTAL) + ctlsSizer = wx.FlexGridSizer(2, 2, 5, 5) + ctlsSizer.AddGrowableCol(1) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + + topSizer.Add(self.testHistory, 0, wx.RIGHT, 30) + + ctlsSizer.Add((1,25)) + ctlsSizer.Add((1,25)) + ctlsSizer.Add(wx.StaticText(p, -1, "Module name:"), + 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + ctlsSizer.Add(self.moduleName, 0, wx.EXPAND) + ctlsSizer.Add(wx.StaticText(p, -1, "Class name:"), + 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + ctlsSizer.Add(self.className, 0, wx.EXPAND) + ctlsSizer.Add(wx.StaticText(p, -1, "Parameters:"), + 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + ctlsSizer.Add(self.parameters, 0, wx.EXPAND) + ctlsSizer.Add(wx.StaticText(p, -1, "Expression:"), + 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + ctlsSizer.Add(self.expression, 0, wx.EXPAND) + ctlsSizer.Add(wx.StaticText(p, -1, "DocString:"), 0, wx.ALIGN_RIGHT) + ctlsSizer.Add(self.docstring, 0, wx.EXPAND) + topSizer.Add(ctlsSizer, 1) + + btnSizer.Add((5,5)) + btnSizer.Add(addBtn, 0, wx.RIGHT, 5) + btnSizer.Add(remBtn, 0, wx.RIGHT, 5) + btnSizer.Add(repBtn, 0, wx.RIGHT, 5) + btnSizer.Add((0,0), 1) + btnSizer.Add(createBtn, 0, wx.RIGHT, 5) + btnSizer.Add(destroyBtn, 0, wx.RIGHT, 5) + btnSizer.Add(clearBtn, 0, wx.RIGHT, 5) + btnSizer.Add((0,0), 1) + + mainSizer.Add(topSizer, 0, wx.EXPAND|wx.ALL, 10) + mainSizer.Add(btnSizer, 0, wx.EXPAND) + mainSizer.Add((10,10)) + ##mainSizer.Add(wx.StaticLine(p, -1), 0, wx.EXPAND) + mainSizer.Add(bottomPanel, 1, wx.EXPAND) + + self.bottomSizer = sz = wx.BoxSizer(wx.VERTICAL) + sz.Add((0,0), 1) + sz.Add(self.testPanel, 0, wx.ALIGN_CENTER) + sz.Add((0,0), 1) + bottomPanel.SetSizer(sz) + + p.SetSizerAndFit(mainSizer) + self.Fit() + + self.PopulateHistory() + + + + + def PopulateHistory(self): + """ + Load and eval a list of lists from a file, load the contents + into self.testHistory + """ + fname = os.path.join(os.path.dirname(sys.argv[0]), + 'widgetLayoutTest.cfg') + try: + self.history = eval(open(fname).read()) + except: + self.history = [] + + self.testHistory.Clear() + + for idx in range(len(self.history)): + item = self.history[idx] + # check if it is too short + while len(item) < 3: + item.append('') + + # add it to the listbox + self.testHistory.Append(item[0] + '.' + item[1]) + + self.needSaved = False + + + def OnSaveHistory(self, evt): + if self.needSaved: + fname = os.path.join(os.path.dirname(sys.argv[0]), + 'widgetLayoutTest.cfg') + f = open(fname, 'wb') + f.write('[\n') + for item in self.history: + f.write(str(item) + ',\n') + f.write(']\n') + f.close() + evt.Skip() + + + def OnAddHistory(self, evt): + moduleName = self.moduleName.GetValue() + className = self.className.GetValue() + parameters = self.parameters.GetValue() + + item = [str(moduleName), str(className), str(parameters)] + self.history.append(item) + self.testHistory.Append(item[0] + '.' + item[1]) + + self.testHistory.SetSelection(len(self.history)-1) + self.needSaved = True + + + def OnRemoveHistory(self, evt): + idx = self.testHistory.GetSelection() + if idx != wx.NOT_FOUND: + del self.history[idx] + self.testHistory.Delete(idx) + self.needSaved = True + + + def OnReplaceHistory(self, evt): + idx = self.testHistory.GetSelection() + if idx != wx.NOT_FOUND: + moduleName = self.moduleName.GetValue() + className = self.className.GetValue() + parameters = self.parameters.GetValue() + + item = [str(moduleName), str(className), str(parameters)] + self.history[idx] = item + self.testHistory.SetString(idx, item[0] + '.' + item[1]) + self.needSaved = True + + + def OnHistorySelect(self, evt): + idx = self.testHistory.GetSelection() + if idx != wx.NOT_FOUND: + item = self.history[idx] + self.moduleName.SetValue(item[0]) + self.className.SetValue(item[1]) + self.parameters.SetValue(item[2]) + + + def OnHistoryActivate(self, evt): + btn = self.testHistory.GetParent().GetDefaultItem() + if btn is not None: + e = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, btn.GetId()) + btn.Command(e) + + + + def OnUpdate(self, evt): + # get the details from the form + moduleName = self.moduleName.GetValue() + className = self.className.GetValue() + parameters = self.parameters.GetValue() + + expr = "%s.%s(self.testPanel, %s)" % (moduleName, className, parameters) + self.expression.SetValue(expr) + + docstring = "" + try: + docstring = eval("%s.%s.__init__.__doc__" % (moduleName, className)) + except: + pass + self.docstring.SetValue(docstring) + + + def OnEnableDestroy(self, evt): + evt.Enable(self.testWidget is not None) + + def OnEnableCreate(self, evt): + evt.Enable(self.testWidget is None) + + + def OnCreateWidget(self, evt): + if self.testWidget is not None: + return + + # get the details from the form + moduleName = self.moduleName.GetValue() + className = self.className.GetValue() + parameters = self.parameters.GetValue() + expr = self.expression.GetValue() + + # make sure the module is imported already + if not sys.modules.has_key(moduleName): + try: + m = __import__(moduleName) + except importError: + wx.MessageBox("Unable to import module!", "Error") + return + + # create the widget + try: + w = eval(expr) + except Exception, e: + wx.MessageBox("Got a '%s' Exception!" % e.__class__.__name__, "Error") + import traceback + traceback.print_exc() + return + + # Put the widget in a sizer and the sizer in the testPanel + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(w, 0, wx.ALL, 5) + self.testPanel.SetSizer(sizer) + self.testWidget = w + self.bottomSizer.Layout() + + # make the destroy button be default now + self.destroyBtn.SetDefault() + + + + def OnDestroyWidget(self, evt): + self.testWidget.Destroy() + self.testWidget = None + self.testPanel.SetSizer(None, True) + self.bottomSizer.Layout() + + # make the create button be default now + self.createBtn.SetDefault() + +## tp = self.testPanel +## print tp.GetSizer() +## print 'size', tp.GetSize() +## print 'minsize', tp.GetMinSize() +## print 'bestsize', tp.GetBestSize() +## print 'abstsize', tp.GetAdjustedBestSize() + + + + def OnClear(self, evt): + self.moduleName.SetValue("") + self.className.SetValue("") + self.parameters.SetValue("") + self.expression.SetValue("") + self.docstring.SetValue("") + + + +app = wx.PySimpleApp(redirect=False) +frame = LayoutTestFrame() +app.SetTopWindow(frame) +frame.Show() +app.MainLoop() + -- 2.47.2