Files
Phoenix/etg/listctrl.py
2025-02-02 20:17:45 -05:00

403 lines
16 KiB
Python

#---------------------------------------------------------------------------
# Name: etg/listctrl.py
# Author: Robin Dunn
#
# Created: 23-Mar-2012
# Copyright: (c) 2012-2020 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "listctrl" # 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 = [ "wxItemAttr", # TODO: technically this should be in its own etg script...
"wxListItem",
"wxListCtrl",
"wxListView",
"wxListEvent",
]
#---------------------------------------------------------------------------
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.
# Compatibility alias
module.addPyCode("""\
ListItemAttr = wx.deprecated(ItemAttr, 'Use ItemAttr instead')
""")
#-------------------------------------------------------
c = module.find('wxListItem')
assert isinstance(c, etgtools.ClassDef)
c.find('SetData').findOverload('void *').ignore()
c.find('GetData').type = 'long'
#-------------------------------------------------------
c = module.find('wxListCtrl')
tools.fixWindowClass(c)
module.addGlobalStr('wxListCtrlNameStr', before=c)
# Unignore some protected virtual methods that we want to allow to be
# overridden in derived classes
for name in [ 'OnGetItemAttr',
#'OnGetItemColumnAttr', # MSW only?
'OnGetItemColumnImage',
'OnGetItemImage',
'OnGetItemText',
'OnGetItemIsChecked',
]:
c.find(name).ignore(False)
c.find(name).isVirtual = True
tools.addEnableSystemTheme(c, 'wx.ListCtrl')
# Tweaks to allow passing and using a Python callable object for the sort
# compare function. First provide a sort callback function that can call the
# Python function.
c.addCppCode("""\
static int wxCALLBACK wxPyListCtrl_SortItems(wxIntPtr item1, wxIntPtr item2, wxIntPtr funcPtr)
{
int retval = 0;
PyObject* func = (PyObject*)funcPtr;
wxPyThreadBlocker blocker;
#if SIZEOF_LONG >= SIZEOF_VOID_P
PyObject* args = Py_BuildValue("(ll)", item1, item2);
#else
PyObject* args = Py_BuildValue("(LL)", item1, item2);
#endif
PyObject* result = PyObject_CallObject(func, args);
Py_DECREF(args);
if (result) {
retval = wxPyInt_AsLong(result);
Py_DECREF(result);
}
return retval;
}
""")
# Next, provide an alternate implementation of SortItems that will use that callback.
sim = c.find('SortItems')
assert isinstance(sim, etgtools.MethodDef)
sim.find('fnSortCallBack').type = 'PyObject*'
sim.find('data').ignore() # we will be using it to pass the python callback function
sim.argsString = sim.argsString.replace('wxListCtrlCompare', 'PyObject*')
sim.setCppCode("""\
if (!PyCallable_Check(fnSortCallBack))
return false;
return self->SortItems((wxListCtrlCompare)wxPyListCtrl_SortItems,
(wxIntPtr)fnSortCallBack);
""")
# SetItemData takes a long, so lets return that type from GetItemData too,
# instead of a wxUIntPtr.
c.find('GetItemData').type = 'long'
c.find('SetItemPtrData').ignore()
# Change the semantics of GetColumn to return the item as the return
# value instead of through a parameter.
# bool GetColumn(int col, wxListItem& item) const;
c.find('GetColumn').ignore()
c.addCppMethod('wxListItem*', 'GetColumn', '(int col)',
doc='Gets information about this column. See SetItem() for more information.',
factory=True,
body="""\
wxListItem item;
item.SetMask( wxLIST_MASK_STATE |
wxLIST_MASK_TEXT |
wxLIST_MASK_IMAGE |
wxLIST_MASK_DATA |
wxLIST_SET_ITEM |
wxLIST_MASK_WIDTH |
wxLIST_MASK_FORMAT
);
if (self->GetColumn(col, item))
return new wxListItem(item);
else
return NULL;
""")
# Do the same for GetItem
# bool GetItem(wxListItem& info) const;
c.find('GetItem').ignore()
c.addCppMethod('wxListItem*', 'GetItem', '(int itemIdx, int col=0)',
doc='Gets information about the item. See SetItem() for more information.',
factory=True,
body="""\
wxListItem* info = new wxListItem;
info->m_itemId = itemIdx;
info->m_col = col;
info->m_mask = 0xFFFF;
info->m_stateMask = 0xFFFF;
self->GetItem(*info);
return info;
""")
# bool GetItemPosition(long item, wxPoint& pos) const;
c.find('GetItemPosition').ignore()
c.addCppMethod('wxPoint*', 'GetItemPosition', '(long item)',
doc='Returns the position of the item, in icon or small icon view.',
factory=True,
body="""\
wxPoint* pos = new wxPoint;
self->GetItemPosition(item, *pos);
return pos;
""")
# bool GetItemRect(long item, wxRect& rect, int code = wxLIST_RECT_BOUNDS) const;
c.find('GetItemRect').ignore()
c.addCppMethod('wxRect*', 'GetItemRect', '(long item, int code = wxLIST_RECT_BOUNDS)',
doc="""\
Returns the rectangle representing the item's size and position, in physical coordinates.
code is one of wx.LIST_RECT_BOUNDS, wx.LIST_RECT_ICON, wx.LIST_RECT_LABEL.""",
factory=True,
body="""\
wxRect* rect = new wxRect;
self->GetItemRect(item, *rect, code);
return rect;
""")
c.find('EditLabel.textControlClass').ignore()
c.find('EndEditLabel').ignore()
c.find('AssignImageList.imageList').transfer = True
c.find('HitTest.flags').out = True
c.find('HitTest.ptrSubItem').ignore()
c.addCppMethod(
'PyObject*', 'HitTestSubItem', '(const wxPoint& point)',
pyArgsString="(point) -> (item, flags, subitem)",
doc="Determines which item (if any) is at the specified point, giving details in flags.",
body="""\
long item, subitem;
int flags;
item = self->HitTest(*point, flags, &subitem);
wxPyThreadBlocker blocker;
PyObject* rv = PyTuple_New(3);
PyTuple_SetItem(rv, 0, wxPyInt_FromLong(item));
PyTuple_SetItem(rv, 1, wxPyInt_FromLong(flags));
PyTuple_SetItem(rv, 2, wxPyInt_FromLong(subitem));
return rv;
""")
c.find('CheckItem.check').default = 'true'
# Some deprecated aliases for Classic renames
c.addPyCode('ListCtrl.FindItemData = wx.deprecated(ListCtrl.FindItem, "Use FindItem instead.")')
c.addPyCode('ListCtrl.FindItemAtPos = wx.deprecated(ListCtrl.FindItem, "Use FindItem instead.")')
c.addPyCode('ListCtrl.InsertStringItem = wx.deprecated(ListCtrl.InsertItem, "Use InsertItem instead.")')
c.addPyCode('ListCtrl.InsertImageItem = wx.deprecated(ListCtrl.InsertItem, "Use InsertItem instead.")')
c.addPyCode('ListCtrl.InsertImageStringItem = wx.deprecated(ListCtrl.InsertItem, "Use InsertItem instead.")')
c.addPyCode('ListCtrl.SetStringItem = wx.deprecated(ListCtrl.SetItem, "Use SetItem instead.")')
# Provide a way to determine if column ordering is possible
c.addCppMethod('bool', 'HasColumnOrderSupport', '()',
"""\
#ifdef wxHAS_LISTCTRL_COLUMN_ORDER
return true;
#else
return false;
#endif
""")
# And provide implementation of those methods that will work whether or
# not wx has column ordering support
c.find('GetColumnOrder').setCppCode("""\
#ifdef wxHAS_LISTCTRL_COLUMN_ORDER
return self->GetColumnOrder(col);
#else
wxPyRaiseNotImplemented();
return 0;
#endif
""")
c.find('GetColumnIndexFromOrder').setCppCode("""\
#ifdef wxHAS_LISTCTRL_COLUMN_ORDER
return self->GetColumnIndexFromOrder(pos);
#else
wxPyRaiseNotImplemented();
return 0;
#endif
""")
c.find('GetColumnsOrder').type = 'wxArrayInt*'
c.find('GetColumnsOrder').factory=True
c.find('GetColumnsOrder').setCppCode("""\
#ifdef wxHAS_LISTCTRL_COLUMN_ORDER
return new wxArrayInt(self->GetColumnsOrder());
#else
wxPyRaiseNotImplemented();
return new wxArrayInt();
#endif
""")
c.find('SetColumnsOrder').setCppCode("""\
#ifdef wxHAS_LISTCTRL_COLUMN_ORDER
return self->SetColumnsOrder(*orders);
#else
wxPyRaiseNotImplemented();
return false;
#endif
""")
# Add some Python helper methods
c.addPyMethod('Select', '(self, idx, on=1)',
doc='Selects/deselects an item.',
body="""\
if on: state = wx.LIST_STATE_SELECTED
else: state = 0
self.SetItemState(idx, state, wx.LIST_STATE_SELECTED)
""")
c.addPyMethod('Focus', '(self, idx)',
doc='Focus and show the given item.',
body="""\
self.SetItemState(idx, wx.LIST_STATE_FOCUSED, wx.LIST_STATE_FOCUSED)
self.EnsureVisible(idx)
""")
c.addPyMethod('GetFocusedItem', '(self)',
doc='Gets the currently focused item or -1 if none is focused.',
body='return self.GetNextItem(-1, wx.LIST_NEXT_ALL, wx.LIST_STATE_FOCUSED)')
c.addPyMethod('GetFirstSelected', '(self, *args)',
doc='Returns the first selected item, or -1 when none is selected.',
body="return self.GetNextSelected(-1)")
c.addPyMethod('GetNextSelected', '(self, item)',
doc='Returns subsequent selected items, or -1 when no more are selected.',
body="return self.GetNextItem(item, wx.LIST_NEXT_ALL, wx.LIST_STATE_SELECTED)")
c.addPyMethod('IsSelected', '(self, idx)',
doc='Returns ``True`` if the item is selected.',
body="return (self.GetItemState(idx, wx.LIST_STATE_SELECTED) & wx.LIST_STATE_SELECTED) != 0")
c.addPyMethod('SetColumnImage', '(self, col, image)',
body="""\
item = self.GetColumn(col)
# preserve all other attributes too
item.SetMask( wx.LIST_MASK_STATE |
wx.LIST_MASK_TEXT |
wx.LIST_MASK_IMAGE |
wx.LIST_MASK_DATA |
wx.LIST_SET_ITEM |
wx.LIST_MASK_WIDTH |
wx.LIST_MASK_FORMAT )
item.SetImage(image)
self.SetColumn(col, item)
""")
c.addPyMethod('ClearColumnImage', '(self, col)',
body="self.SetColumnImage(col, -1)")
c.addPyMethod('Append', '(self, entry)',
doc='''\
Append an item to the list control. The `entry` parameter should be a
sequence with an item for each column''',
body="""\
if len(entry):
pos = self.InsertItem(self.GetItemCount(), str(entry[0]))
for i in range(1, len(entry)):
self.SetItem(pos, i, str(entry[i]))
return pos
""")
c.addCppMethod('wxWindow*', 'GetMainWindow', '()',
body="""\
#if defined(__WXMSW__) || defined(__WXMAC__)
return self;
#else
return (wxWindow*)self->m_mainWin;
#endif
""")
# Documented wrongly in 3.1.6
c.find('RemoveSortIndicator').type = 'void'
c.find('RemoveSortIndicator').isConst = False
#-------------------------------------------------------
c = module.find('wxListView')
tools.fixWindowClass(c)
#-------------------------------------------------------
c = module.find('wxListEvent')
tools.fixEventClass(c)
module.addPyCode("""\
EVT_LIST_BEGIN_DRAG = PyEventBinder(wxEVT_LIST_BEGIN_DRAG , 1)
EVT_LIST_BEGIN_RDRAG = PyEventBinder(wxEVT_LIST_BEGIN_RDRAG , 1)
EVT_LIST_BEGIN_LABEL_EDIT = PyEventBinder(wxEVT_LIST_BEGIN_LABEL_EDIT , 1)
EVT_LIST_END_LABEL_EDIT = PyEventBinder(wxEVT_LIST_END_LABEL_EDIT , 1)
EVT_LIST_DELETE_ITEM = PyEventBinder(wxEVT_LIST_DELETE_ITEM , 1)
EVT_LIST_DELETE_ALL_ITEMS = PyEventBinder(wxEVT_LIST_DELETE_ALL_ITEMS , 1)
EVT_LIST_ITEM_SELECTED = PyEventBinder(wxEVT_LIST_ITEM_SELECTED , 1)
EVT_LIST_ITEM_DESELECTED = PyEventBinder(wxEVT_LIST_ITEM_DESELECTED , 1)
EVT_LIST_KEY_DOWN = PyEventBinder(wxEVT_LIST_KEY_DOWN , 1)
EVT_LIST_INSERT_ITEM = PyEventBinder(wxEVT_LIST_INSERT_ITEM , 1)
EVT_LIST_COL_CLICK = PyEventBinder(wxEVT_LIST_COL_CLICK , 1)
EVT_LIST_ITEM_RIGHT_CLICK = PyEventBinder(wxEVT_LIST_ITEM_RIGHT_CLICK , 1)
EVT_LIST_ITEM_MIDDLE_CLICK = PyEventBinder(wxEVT_LIST_ITEM_MIDDLE_CLICK, 1)
EVT_LIST_ITEM_ACTIVATED = PyEventBinder(wxEVT_LIST_ITEM_ACTIVATED , 1)
EVT_LIST_CACHE_HINT = PyEventBinder(wxEVT_LIST_CACHE_HINT , 1)
EVT_LIST_COL_RIGHT_CLICK = PyEventBinder(wxEVT_LIST_COL_RIGHT_CLICK , 1)
EVT_LIST_COL_BEGIN_DRAG = PyEventBinder(wxEVT_LIST_COL_BEGIN_DRAG , 1)
EVT_LIST_COL_DRAGGING = PyEventBinder(wxEVT_LIST_COL_DRAGGING , 1)
EVT_LIST_COL_END_DRAG = PyEventBinder(wxEVT_LIST_COL_END_DRAG , 1)
EVT_LIST_ITEM_FOCUSED = PyEventBinder(wxEVT_LIST_ITEM_FOCUSED , 1)
EVT_LIST_ITEM_CHECKED = PyEventBinder(wxEVT_LIST_ITEM_CHECKED , 1)
EVT_LIST_ITEM_UNCHECKED = PyEventBinder(wxEVT_LIST_ITEM_UNCHECKED , 1)
# deprecated wxEVT aliases
wxEVT_COMMAND_LIST_BEGIN_DRAG = wxEVT_LIST_BEGIN_DRAG
wxEVT_COMMAND_LIST_BEGIN_RDRAG = wxEVT_LIST_BEGIN_RDRAG
wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT = wxEVT_LIST_BEGIN_LABEL_EDIT
wxEVT_COMMAND_LIST_END_LABEL_EDIT = wxEVT_LIST_END_LABEL_EDIT
wxEVT_COMMAND_LIST_DELETE_ITEM = wxEVT_LIST_DELETE_ITEM
wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS = wxEVT_LIST_DELETE_ALL_ITEMS
wxEVT_COMMAND_LIST_ITEM_SELECTED = wxEVT_LIST_ITEM_SELECTED
wxEVT_COMMAND_LIST_ITEM_DESELECTED = wxEVT_LIST_ITEM_DESELECTED
wxEVT_COMMAND_LIST_KEY_DOWN = wxEVT_LIST_KEY_DOWN
wxEVT_COMMAND_LIST_INSERT_ITEM = wxEVT_LIST_INSERT_ITEM
wxEVT_COMMAND_LIST_COL_CLICK = wxEVT_LIST_COL_CLICK
wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK = wxEVT_LIST_ITEM_RIGHT_CLICK
wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK = wxEVT_LIST_ITEM_MIDDLE_CLICK
wxEVT_COMMAND_LIST_ITEM_ACTIVATED = wxEVT_LIST_ITEM_ACTIVATED
wxEVT_COMMAND_LIST_CACHE_HINT = wxEVT_LIST_CACHE_HINT
wxEVT_COMMAND_LIST_COL_RIGHT_CLICK = wxEVT_LIST_COL_RIGHT_CLICK
wxEVT_COMMAND_LIST_COL_BEGIN_DRAG = wxEVT_LIST_COL_BEGIN_DRAG
wxEVT_COMMAND_LIST_COL_DRAGGING = wxEVT_LIST_COL_DRAGGING
wxEVT_COMMAND_LIST_COL_END_DRAG = wxEVT_LIST_COL_END_DRAG
wxEVT_COMMAND_LIST_ITEM_FOCUSED = wxEVT_LIST_ITEM_FOCUSED
""")
#-----------------------------------------------------------------
tools.doCommonTweaks(module)
tools.runGenerators(module)
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()