diff --git a/wxPython/docs/CHANGES.txt b/wxPython/docs/CHANGES.txt index 54fab946ea..dc29152f51 100644 --- a/wxPython/docs/CHANGES.txt +++ b/wxPython/docs/CHANGES.txt @@ -1,6 +1,28 @@ Recent Changes for wxPython ===================================================================== +2.8.4.1 +------- +* + +Added some SWIG magic that allows wx C++ lists to be exposed to +wxPython as sqequence-like wrappers around the real list, instead of +making a Python list that is a copy of the real list as was done +before. These sequence-like objects support indexing, iteration and +containment tests ("obj in seq") but not anything that would modify the +sequence. If you need to have a real list object like before you can +pass the sequence to Python's list() function to convert it. Current +functions that are affected by this are wx.Window.GetChildren, +wx.GetTopLevelWindows, wx.Sizer.GetChildren, and +wx.Menu.GetMenuItems. Care should be taken to be sure that you don't +try to use the sequence after the C++ object the list belongs to has +been destroyed. + + + + + + 2.8.4.0 ------- * 14-May-2007 diff --git a/wxPython/src/_defs.i b/wxPython/src/_defs.i index 7723185846..980e6ac0a9 100644 --- a/wxPython/src/_defs.i +++ b/wxPython/src/_defs.i @@ -408,6 +408,19 @@ typedef unsigned long wxUIntPtr; %enddef #endif +#ifdef _DO_FULL_DOCS + %define %RenameDocStr(newname, docstr, details, type, decl) + %feature("docstring") decl docstr; + %rename(newname) decl; + type decl + %enddef +#else + %define %RenameDocStr(newname, docstr, details, type, decl) + %feature("docstring") decl docstr details; + %rename(newname) decl; + type decl + %enddef +#endif //--------------------------------------------------------------------------- // Generates a base_On* method that just wraps a call to the On*, and mark it @@ -459,6 +472,204 @@ FORWARD_DECLARE(wxIcon, Icon); FORWARD_DECLARE(wxStaticBox, StaticBox); +//--------------------------------------------------------------------------- +// This macro makes a class to wrap a type specific class derived from wxList, +// and make it look like a Python sequence, including with iterator support + +%define wxLIST_WRAPPER(ListClass, ItemClass) +// first a bit of C++ code... +%{ +class ListClass##_iterator +{ +public: + ListClass##_iterator(ListClass::compatibility_iterator start) + : m_node(start) {} + + ItemClass* next() { + ItemClass* obj = NULL; + if (m_node) { + obj = m_node->GetData(); + m_node = m_node->GetNext(); + } + else PyErr_SetString(PyExc_StopIteration, ""); + return obj; + } +private: + ListClass::compatibility_iterator m_node; +}; +%} + +// Now declare the classes for SWIG + +DocStr(ListClass##_iterator, +"This class serves as an iterator for a ListClass object.", ""); + +class ListClass##_iterator +{ +public: + //ListClass##_iterator(); + ~ListClass_iterator(); + KeepGIL(next); + ItemClass* next(); +}; + + +DocStr(ListClass, +"This class wraps a wxList-based class and gives it a Python +sequence-like interface. Sequence operations supported are length, +index access and iteration.", ""); + +class ListClass +{ +public: + //ListClass(); This will always be created by some C++ function + ~ListClass(); + + %extend { + KeepGIL(__len__); + size_t __len__() { + return self->size(); + } + + KeepGIL(__getitem__); + ItemClass* __getitem__(size_t index) { + if (index < self->size()) { + ListClass::compatibility_iterator node = self->Item(index); + if (node) return node->GetData(); + } + PyErr_SetString(PyExc_IndexError, "Invalid list index"); + return NULL; + } + + KeepGIL(__contains__); + bool __contains__(const ItemClass* obj) { + return self->Find(obj) != NULL; + } + + KeepGIL(__iter__); + %newobject __iter__; + ListClass##_iterator* __iter__() { + return new ListClass##_iterator(self->GetFirst()); + } + } + %pythoncode { + def __repr__(self): + return "ListClass: " + repr(list(self)) + } +}; +%enddef + + + +// This macro is similar to the above, but it is to be used when there isn't a +// type-specific C++ list class to use. In other words the C++ code is using +// a plain wxList and typecasting the node values, so we'll do the same. +%define wxUNTYPED_LIST_WRAPPER(ListClass, ItemClass) +// first a bit of C++ code... +%{ +class ListClass +{ +public: + ListClass(wxList* theList) + : m_list(theList) {} + ~ListClass() {} +public: + wxList* m_list; +}; + +class ListClass##_iterator +{ +public: + ListClass##_iterator(wxList::compatibility_iterator start) + : m_node(start) {} + + ItemClass* next() { + ItemClass* obj = NULL; + if (m_node) { + obj = (ItemClass*)m_node->GetData(); + m_node = m_node->GetNext(); + } + else PyErr_SetString(PyExc_StopIteration, ""); + return obj; + } +private: + wxList::compatibility_iterator m_node; +}; +%} + +// Now declare the classes for SWIG + +DocStr(ListClass##_iterator, +"This class serves as an iterator for a ListClass object.", ""); + +class ListClass##_iterator +{ +public: + //ListClass##_iterator(); + ~ListClass_iterator(); + KeepGIL(next); + ItemClass* next(); +}; + + +DocStr(ListClass, +"This class wraps a wxList-based class and gives it a Python +sequence-like interface. Sequence operations supported are length, +index access and iteration.", ""); +class ListClass +{ +public: + //ListClass(); This will always be created by some C++ function + ~ListClass(); + + %extend { + KeepGIL(__len__); + size_t __len__() { + return self->m_list->size(); + } + + KeepGIL(__getitem__); + ItemClass* __getitem__(size_t index) { + if (index < self->m_list->size()) { + wxList::compatibility_iterator node = self->m_list->Item(index); + if (node) return (ItemClass*)node->GetData(); + } + PyErr_SetString(PyExc_IndexError, "Invalid list index"); + return NULL; + } + + KeepGIL(__contains__); + bool __contains__(const ItemClass* obj) { + return self->m_list->Find(obj) != NULL; + } + + KeepGIL(__iter__); + %newobject __iter__; + ListClass##_iterator* __iter__() { + return new ListClass##_iterator(self->m_list->GetFirst()); + } + } + %pythoncode { + def __repr__(self): + return "ListClass: " + repr(list(self)) + } +}; + +// A typemap to handle converting a wxList& return value to this new list +// type. To use this just change the return value type in the class +// definition to this typedef instead of wxList, then SWIG will use the +// typemap. +%{ +typedef wxList ListClass##_t; +%} +%typemap(out) ListClass##_t& { + ListClass* mylist = new ListClass($1); + $result = SWIG_NewPointerObj(SWIG_as_voidptr(mylist), SWIGTYPE_p_##ListClass, SWIG_POINTER_OWN ); +} +%enddef + + + //--------------------------------------------------------------------------- %{ diff --git a/wxPython/src/_menu.i b/wxPython/src/_menu.i index db3c33ce71..de7e75939e 100644 --- a/wxPython/src/_menu.i +++ b/wxPython/src/_menu.i @@ -16,6 +16,9 @@ //--------------------------------------------------------------------------- %newgroup +wxLIST_WRAPPER(wxMenuItemList, wxMenuItem); + + MustHaveApp(wxMenu); @@ -169,12 +172,7 @@ public: // get the items size_t GetMenuItemCount() const; - %extend { - PyObject* GetMenuItems() { - wxMenuItemList& list = self->GetMenuItems(); - return wxPy_ConvertList(&list); - } - } + wxMenuItemList& GetMenuItems(); // search int FindItem(const wxString& item) const; diff --git a/wxPython/src/_panel.i b/wxPython/src/_panel.i index 6dc14e0f6f..783cb8fb48 100644 --- a/wxPython/src/_panel.i +++ b/wxPython/src/_panel.i @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: _window.i +// Name: _panel.i // Purpose: SWIG interface for wxPanel and wxScrolledWindow // // Author: Robin Dunn diff --git a/wxPython/src/_sizers.i b/wxPython/src/_sizers.i index d86fae7441..644fab2d08 100644 --- a/wxPython/src/_sizers.i +++ b/wxPython/src/_sizers.i @@ -169,6 +169,11 @@ border size.", ""); }; //--------------------------------------------------------------------------- +%newgroup + +wxLIST_WRAPPER( wxSizerItemList, wxSizerItem ); + + DocStr(wxSizerItem, "The wx.SizerItem class is used to track the position, size and other @@ -1223,21 +1228,12 @@ as well.", ""); - // wxList& GetChildren(); - %extend { - DocAStr(GetChildren, - "GetChildren(self) -> list", - "Returns a list of all the `wx.SizerItem` objects managed by the sizer.", ""); - PyObject* GetChildren() { - wxSizerItemList& list = self->GetChildren(); - return wxPy_ConvertList(&list); - } - } + DocStr(GetChildren, + "Returns all of the `wx.SizerItem` objects managed by the sizer in a +list-like object.", ""); + wxSizerItemList& GetChildren(); - // Manage whether individual windows or subsizers are considered - // in the layout calculations or not. - %extend { DocAStr(Show, "Show(self, item, bool show=True, bool recursive=false) -> bool", diff --git a/wxPython/src/_window.i b/wxPython/src/_window.i index 53a83214f4..faebaa4ddd 100644 --- a/wxPython/src/_window.i +++ b/wxPython/src/_window.i @@ -24,6 +24,9 @@ MAKE_CONST_WXSTRING(PanelNameStr); %newgroup +wxLIST_WRAPPER(wxWindowList, wxWindow); + + DocStr(wxVisualAttributes, "struct containing all the visual attributes of a control", ""); @@ -956,26 +959,16 @@ before win instead of putting it right after it.", ""); - - - - // parent/children relations // ------------------------- - //wxWindowList& GetChildren(); // TODO: Do a typemap or a wrapper for wxWindowList - %extend { DocStr(GetChildren, - "Returns a list of the window's children. NOTE: Currently this is a -copy of the child window list maintained by the window, so the return -value of this function is only valid as long as the window's children -do not change.", ""); - PyObject* GetChildren() { - wxWindowList& list = self->GetChildren(); - return wxPy_ConvertList(&list); - } - } + "Returns an object containing a list of the window's children. The +object provides a Python sequence-like interface over the internal +list maintained by the window..", ""); + wxWindowList& GetChildren(); + DocDeclStr( wxWindow *, GetParent() const, @@ -2284,14 +2277,11 @@ MustHaveApp(wxWindow_FromHWND); //--------------------------------------------------------------------------- DocStr(GetTopLevelWindows, -"Returns a list of the the application's top-level windows, (frames, -dialogs, etc.) NOTE: Currently this is a copy of the list maintained -by wxWidgets, and so it is only valid as long as no top-level windows -are closed or new top-level windows are created. -", ""); +"Returns a list-like object of the the application's top-level windows, (frames, +dialogs, etc.)", ""); %inline %{ - PyObject* GetTopLevelWindows() { - return wxPy_ConvertList(&wxTopLevelWindows); + wxWindowList& GetTopLevelWindows() { + return wxTopLevelWindows; } %}