#define LVS_OWNERDATA 0x1000
#endif
+// mingw32/cygwin don't have declarations for comctl32.dll 4.70+ stuff
+#ifndef NM_CACHEHINT
+ typedef struct tagNMLVCACHEHINT
+ {
+ NMHDR hdr;
+ int iFrom;
+ int iTo;
+ } NMLVCACHEHINT;
+
+ #define NM_CACHEHINT NMLVCACHEHINT
+#endif
+
+#ifndef LVN_ODCACHEHINT
+ #define LVN_ODCACHEHINT (-113)
+#endif
+
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
-static void wxConvertToMSWListItem(const wxListCtrl *ctrl, wxListItem& info, LV_ITEM& tvItem);
-static void wxConvertFromMSWListItem(const wxListCtrl *ctrl, wxListItem& info, LV_ITEM& tvItem, HWND getFullInfo = 0);
+// convert our state and mask flags to LV_ITEM constants
+static void wxConvertToMSWFlags(long state, long mask, LV_ITEM& lvItem);
+
+// convert wxListItem to LV_ITEM
+static void wxConvertToMSWListItem(const wxListCtrl *ctrl,
+ const wxListItem& info, LV_ITEM& lvItem);
+
+// convert LV_ITEM to wxListItem
+static void wxConvertFromMSWListItem(HWND hwndListCtrl,
+ wxListItem& info,
+ /* const */ LV_ITEM& lvItem);
// ----------------------------------------------------------------------------
// events
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT)
IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxControl)
IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
}
else
{
- wxConvertFromMSWListItem(this, info, lvItem);
+ // give NULL as hwnd as we already have everything we need
+ wxConvertFromMSWListItem(NULL, info, lvItem);
}
if (lvItem.pszText)
// Sets the item state
bool wxListCtrl::SetItemState(long item, long state, long stateMask)
{
- wxListItem info;
+ // NB: don't use SetItem() here as it doesn't work with the virtual list
+ // controls
+ LV_ITEM lvItem;
+ wxZeroMemory(lvItem);
- info.m_mask = wxLIST_MASK_STATE;
- info.m_state = state;
- info.m_stateMask = stateMask;
- info.m_itemId = item;
+ wxConvertToMSWFlags(state, stateMask, lvItem);
- return SetItem(info);
+ if ( !::SendMessage(GetHwnd(), LVM_SETITEMSTATE,
+ (WPARAM)item, (LPARAM)&lvItem) )
+ {
+ wxLogLastError(_T("ListView_SetItemState"));
+
+ return FALSE;
+ }
+
+ return TRUE;
}
// Sets the item image
{
eventType = wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT;
LV_DISPINFO *info = (LV_DISPINFO *)lParam;
- wxConvertFromMSWListItem(this, event.m_item, info->item, GetHwnd());
+ wxConvertFromMSWListItem(GetHwnd(), event.m_item, info->item);
event.m_itemIndex = event.m_item.m_itemId;
}
break;
{
eventType = wxEVT_COMMAND_LIST_END_LABEL_EDIT;
LV_DISPINFO *info = (LV_DISPINFO *)lParam;
- wxConvertFromMSWListItem(this, event.m_item, info->item);
+ wxConvertFromMSWListItem(GetHwnd(), event.m_item, info->item);
if ( info->item.pszText == NULL || info->item.iItem == -1 )
return FALSE;
{
eventType = wxEVT_COMMAND_LIST_SET_INFO;
LV_DISPINFO *info = (LV_DISPINFO *)lParam;
- wxConvertFromMSWListItem(this, event.m_item, info->item, GetHwnd());
+ wxConvertFromMSWListItem(GetHwnd(), event.m_item, info->item);
}
break;
return TRUE;
#endif // _WIN32_IE >= 0x300
+ case LVN_ODCACHEHINT:
+ {
+ const NM_CACHEHINT *cacheHint = (NM_CACHEHINT *)lParam;
+
+ eventType = wxEVT_COMMAND_LIST_CACHE_HINT;
+
+ // we get some really stupid cache hints like ones for items in
+ // range 0..0 for an empty control or, after deleting an item,
+ // for items in invalid range - filter this garbage out
+ if ( cacheHint->iFrom < cacheHint->iTo )
+ {
+ event.m_oldItemIndex = cacheHint->iFrom;
+
+ long iMax = GetItemCount();
+ event.m_itemIndex = cacheHint->iTo < iMax ? cacheHint->iTo
+ : iMax - 1;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ break;
+
case LVN_GETDISPINFO:
if ( IsVirtual() )
{
return TRUE;
case LVN_ENDLABELEDIT:
- {
- *result = event.IsAllowed();
- return TRUE;
- }
+ // logic here is inversed compared to all the other messages
+ *result = event.IsAllowed();
+
+ return TRUE;
}
*result = !event.IsAllowed();
case CDDS_ITEMPREPAINT:
{
size_t item = (size_t)nmcd.dwItemSpec;
+ if ( item >= (size_t)GetItemCount() )
+ {
+ // we get this message with item == 0 for an empty control,
+ // we must ignore it as calling OnGetItemAttr() would be
+ // wrong
+ return CDRF_DODEFAULT;
+ }
+
wxListItemAttr *attr =
IsVirtual() ? OnGetItemAttr(item)
: (wxListItemAttr *)m_attrs.Get(item);
}
}
+void wxListCtrl::RefreshItem(long item)
+{
+ if ( !ListView_Update(GetHwnd(), item) )
+ {
+ wxLogLastError(_T("ListView_Update"));
+ }
+}
+
+void wxListCtrl::RefreshItems(long itemFrom, long itemTo)
+{
+ for ( long item = itemFrom; item <= itemTo; item++ )
+ {
+ RefreshItem(item);
+ }
+}
+
// ----------------------------------------------------------------------------
// wxListItem
// ----------------------------------------------------------------------------
m_attr = NULL;
}
-static void wxConvertFromMSWListItem(const wxListCtrl *WXUNUSED(ctrl), wxListItem& info, LV_ITEM& lvItem, HWND getFullInfo)
+static void wxConvertFromMSWListItem(HWND hwndListCtrl,
+ wxListItem& info,
+ LV_ITEM& lvItem)
{
info.m_data = lvItem.lParam;
info.m_mask = 0;
long oldMask = lvItem.mask;
bool needText = FALSE;
- if (getFullInfo != 0)
+ if (hwndListCtrl != 0)
{
if ( lvItem.mask & LVIF_TEXT )
needText = FALSE;
lvItem.pszText = new wxChar[513];
lvItem.cchTextMax = 512;
}
- // lvItem.mask |= TVIF_HANDLE | TVIF_STATE | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN | TVIF_PARAM;
lvItem.mask |= LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
- ::SendMessage(getFullInfo, LVM_GETITEM, 0, (LPARAM)& lvItem);
+ ::SendMessage(hwndListCtrl, LVM_GETITEM, 0, (LPARAM)& lvItem);
}
if ( lvItem.mask & LVIF_STATE )
lvItem.mask = oldMask;
}
-static void wxConvertToMSWListItem(const wxListCtrl *ctrl, wxListItem& info, LV_ITEM& lvItem)
+static void wxConvertToMSWFlags(long state, long stateMask, LV_ITEM& lvItem)
+{
+ if (stateMask & wxLIST_STATE_CUT)
+ {
+ lvItem.stateMask |= LVIS_CUT;
+ if (state & wxLIST_STATE_CUT)
+ lvItem.state |= LVIS_CUT;
+ }
+ if (stateMask & wxLIST_STATE_DROPHILITED)
+ {
+ lvItem.stateMask |= LVIS_DROPHILITED;
+ if (state & wxLIST_STATE_DROPHILITED)
+ lvItem.state |= LVIS_DROPHILITED;
+ }
+ if (stateMask & wxLIST_STATE_FOCUSED)
+ {
+ lvItem.stateMask |= LVIS_FOCUSED;
+ if (state & wxLIST_STATE_FOCUSED)
+ lvItem.state |= LVIS_FOCUSED;
+ }
+ if (stateMask & wxLIST_STATE_SELECTED)
+ {
+ lvItem.stateMask |= LVIS_SELECTED;
+ if (state & wxLIST_STATE_SELECTED)
+ lvItem.state |= LVIS_SELECTED;
+ }
+}
+
+static void wxConvertToMSWListItem(const wxListCtrl *ctrl,
+ const wxListItem& info,
+ LV_ITEM& lvItem)
{
lvItem.iItem = (int) info.m_itemId;
if (info.m_mask & wxLIST_MASK_STATE)
{
lvItem.mask |= LVIF_STATE;
- if (info.m_stateMask & wxLIST_STATE_CUT)
- {
- lvItem.stateMask |= LVIS_CUT;
- if (info.m_state & wxLIST_STATE_CUT)
- lvItem.state |= LVIS_CUT;
- }
- if (info.m_stateMask & wxLIST_STATE_DROPHILITED)
- {
- lvItem.stateMask |= LVIS_DROPHILITED;
- if (info.m_state & wxLIST_STATE_DROPHILITED)
- lvItem.state |= LVIS_DROPHILITED;
- }
- if (info.m_stateMask & wxLIST_STATE_FOCUSED)
- {
- lvItem.stateMask |= LVIS_FOCUSED;
- if (info.m_state & wxLIST_STATE_FOCUSED)
- lvItem.state |= LVIS_FOCUSED;
- }
- if (info.m_stateMask & wxLIST_STATE_SELECTED)
- {
- lvItem.stateMask |= LVIS_SELECTED;
- if (info.m_state & wxLIST_STATE_SELECTED)
- lvItem.state |= LVIS_SELECTED;
- }
+
+ wxConvertToMSWFlags(info.m_state, info.m_stateMask, lvItem);
}
if (info.m_mask & wxLIST_MASK_TEXT)