+ if ( info.m_mask & wxLIST_MASK_TEXT )
+ {
+ lvItem.mask |= LVIF_TEXT;
+ lvItem.pszText = new wxChar[513];
+ lvItem.cchTextMax = 512;
+ }
+ else
+ {
+ lvItem.pszText = NULL;
+ }
+
+ if (info.m_mask & wxLIST_MASK_DATA)
+ lvItem.mask |= LVIF_PARAM;
+
+ if (info.m_mask & wxLIST_MASK_IMAGE)
+ lvItem.mask |= LVIF_IMAGE;
+
+ if ( info.m_mask & wxLIST_MASK_STATE )
+ {
+ lvItem.mask |= LVIF_STATE;
+ wxConvertToMSWFlags(0, info.m_stateMask, lvItem);
+ }
+
+ bool success = ListView_GetItem((HWND)GetHWND(), &lvItem) != 0;
+ if ( !success )
+ {
+ wxLogError(_("Couldn't retrieve information about list control item %d."),
+ lvItem.iItem);
+ }
+ else
+ {
+ // give NULL as hwnd as we already have everything we need
+ wxConvertFromMSWListItem(NULL, info, lvItem);
+ }
+
+ if (lvItem.pszText)
+ delete[] lvItem.pszText;
+
+ return success;
+}
+
+// Sets information about the item
+bool wxListCtrl::SetItem(wxListItem& info)
+{
+ const long id = info.GetId();
+ wxCHECK_MSG( id >= 0 && id < GetItemCount(), false,
+ wxT("invalid item index in SetItem") );
+
+ LV_ITEM item;
+ wxConvertToMSWListItem(this, info, item);
+
+ // we never update the lParam if it contains our pointer
+ // to the wxMSWListItemData structure
+ item.mask &= ~LVIF_PARAM;
+
+ // check if setting attributes or lParam
+ if ( info.HasAttributes() || (info.m_mask & wxLIST_MASK_DATA) )
+ {
+ // get internal item data
+ wxMSWListItemData *data = MSWGetItemData(id);
+
+ if ( !data )
+ {
+ // need to allocate the internal data object
+ data = new wxMSWListItemData;
+ m_internalData.push_back(data);
+ item.lParam = (LPARAM) data;
+ item.mask |= LVIF_PARAM;
+ }
+
+
+ // user data
+ if ( info.m_mask & wxLIST_MASK_DATA )
+ data->lParam = info.m_data;
+
+ // attributes
+ if ( info.HasAttributes() )
+ {
+ const wxListItemAttr& attrNew = *info.GetAttributes();
+
+ // don't overwrite the already set attributes if we have them
+ if ( data->attr )
+ data->attr->AssignFrom(attrNew);
+ else
+ data->attr = new wxListItemAttr(attrNew);
+ }
+ }
+
+
+ // we could be changing only the attribute in which case we don't need to
+ // call ListView_SetItem() at all
+ if ( item.mask )
+ {
+ if ( !ListView_SetItem(GetHwnd(), &item) )
+ {
+ wxLogDebug(wxT("ListView_SetItem() failed"));
+
+ return false;
+ }
+ }
+
+ // we need to update the item immediately to show the new image
+ bool updateNow = (info.m_mask & wxLIST_MASK_IMAGE) != 0;
+
+ // check whether it has any custom attributes
+ if ( info.HasAttributes() )
+ {
+ m_hasAnyAttr = true;
+
+ // if the colour has changed, we must redraw the item
+ updateNow = true;
+ }
+
+ if ( updateNow )
+ {
+ // we need this to make the change visible right now
+ RefreshItem(item.iItem);
+ }
+
+ return true;
+}
+
+long wxListCtrl::SetItem(long index, int col, const wxString& label, int imageId)
+{
+ wxListItem info;
+ info.m_text = label;
+ info.m_mask = wxLIST_MASK_TEXT;
+ info.m_itemId = index;
+ info.m_col = col;
+ if ( imageId > -1 )
+ {
+ info.m_image = imageId;
+ info.m_mask |= wxLIST_MASK_IMAGE;
+ }
+ return SetItem(info);
+}
+
+
+// Gets the item state
+int wxListCtrl::GetItemState(long item, long stateMask) const
+{
+ wxListItem info;
+
+ info.m_mask = wxLIST_MASK_STATE;
+ info.m_stateMask = stateMask;
+ info.m_itemId = item;
+
+ if (!GetItem(info))
+ return 0;
+
+ return info.m_state;
+}
+
+// Sets the item state
+bool wxListCtrl::SetItemState(long item, long state, long stateMask)
+{
+ // NB: don't use SetItem() here as it doesn't work with the virtual list
+ // controls
+ LV_ITEM lvItem;
+ wxZeroMemory(lvItem);
+
+ wxConvertToMSWFlags(state, stateMask, lvItem);
+
+ const bool changingFocus = (stateMask & wxLIST_STATE_FOCUSED) &&
+ (state & wxLIST_STATE_FOCUSED);
+
+ // for the virtual list controls we need to refresh the previously focused
+ // item manually when changing focus without changing selection
+ // programmatically because otherwise it keeps its focus rectangle until
+ // next repaint (yet another comctl32 bug)
+ long focusOld;
+ if ( IsVirtual() && changingFocus )
+ {
+ focusOld = GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
+ }
+ else
+ {
+ focusOld = -1;
+ }
+
+ if ( !::SendMessage(GetHwnd(), LVM_SETITEMSTATE,
+ (WPARAM)item, (LPARAM)&lvItem) )
+ {
+ wxLogLastError(wxT("ListView_SetItemState"));
+
+ return false;
+ }
+
+ if ( focusOld != -1 )
+ {
+ // no need to refresh the item if it was previously selected, it would
+ // only result in annoying flicker
+ if ( !(GetItemState(focusOld,
+ wxLIST_STATE_SELECTED) & wxLIST_STATE_SELECTED) )
+ {
+ RefreshItem(focusOld);
+ }
+ }
+
+ // we expect the selection anchor, i.e. the item from which multiple
+ // selection (such as performed with e.g. Shift-arrows) starts, to be the
+ // same as the currently focused item but the native control doesn't update
+ // it when we change focus and leaves at the last item it set itself focus
+ // to, so do it explicitly
+ if ( changingFocus && !HasFlag(wxLC_SINGLE_SEL) )
+ {
+ ListView_SetSelectionMark(GetHwnd(), item);
+ }
+
+ return true;
+}
+
+// Sets the item image
+bool wxListCtrl::SetItemImage(long item, int image, int WXUNUSED(selImage))
+{
+ return SetItemColumnImage(item, 0, image);
+}
+
+// Sets the item image
+bool wxListCtrl::SetItemColumnImage(long item, long column, int image)
+{
+ wxListItem info;
+
+ info.m_mask = wxLIST_MASK_IMAGE;
+ info.m_image = image;
+ info.m_itemId = item;
+ info.m_col = column;
+
+ return SetItem(info);
+}
+
+// Gets the item text
+wxString wxListCtrl::GetItemText(long item, int col) const
+{
+ wxListItem info;
+
+ info.m_mask = wxLIST_MASK_TEXT;
+ info.m_itemId = item;
+ info.m_col = col;
+
+ if (!GetItem(info))
+ return wxEmptyString;
+ return info.m_text;
+}
+
+// Sets the item text
+void wxListCtrl::SetItemText(long item, const wxString& str)
+{
+ wxListItem info;
+
+ info.m_mask = wxLIST_MASK_TEXT;
+ info.m_itemId = item;
+ info.m_text = str;
+
+ SetItem(info);
+}
+
+// Gets the internal item data
+wxMSWListItemData *wxListCtrl::MSWGetItemData(long itemId) const
+{
+ LV_ITEM it;
+ it.mask = LVIF_PARAM;
+ it.iItem = itemId;
+
+ if ( !ListView_GetItem(GetHwnd(), &it) )
+ return NULL;
+
+ return (wxMSWListItemData *) it.lParam;
+}
+
+// Gets the item data
+wxUIntPtr wxListCtrl::GetItemData(long item) const
+{
+ wxListItem info;
+
+ info.m_mask = wxLIST_MASK_DATA;
+ info.m_itemId = item;
+
+ if (!GetItem(info))
+ return 0;
+ return info.m_data;
+}
+
+// Sets the item data
+bool wxListCtrl::SetItemPtrData(long item, wxUIntPtr data)
+{
+ wxListItem info;
+
+ info.m_mask = wxLIST_MASK_DATA;
+ info.m_itemId = item;
+ info.m_data = data;
+
+ return SetItem(info);
+}
+
+wxRect wxListCtrl::GetViewRect() const
+{
+ wxRect rect;
+
+ // ListView_GetViewRect() can only be used in icon and small icon views
+ // (this is documented in MSDN and, indeed, it returns bogus results in
+ // report view, at least with comctl32.dll v6 under Windows 2003)
+ if ( HasFlag(wxLC_ICON | wxLC_SMALL_ICON) )
+ {
+ RECT rc;
+ if ( !ListView_GetViewRect(GetHwnd(), &rc) )
+ {
+ wxLogDebug(wxT("ListView_GetViewRect() failed."));
+
+ wxZeroMemory(rc);
+ }
+
+ wxCopyRECTToRect(rc, rect);
+ }
+ else if ( HasFlag(wxLC_REPORT) )
+ {
+ const long count = GetItemCount();
+ if ( count )
+ {
+ GetItemRect(wxMin(GetTopItem() + GetCountPerPage(), count - 1), rect);
+
+ // extend the rectangle to start at the top (we include the column
+ // headers, if any, for compatibility with the generic version)
+ rect.height += rect.y;
+ rect.y = 0;
+ }
+ }
+ else
+ {
+ wxFAIL_MSG( wxT("not implemented in this mode") );
+ }
+
+ return rect;
+}
+
+// Gets the item rectangle
+bool wxListCtrl::GetItemRect(long item, wxRect& rect, int code) const
+{
+ return GetSubItemRect( item, wxLIST_GETSUBITEMRECT_WHOLEITEM, rect, code) ;
+}
+
+bool wxListCtrl::GetSubItemRect(long item, long subItem, wxRect& rect, int code) const
+{
+ // ListView_GetSubItemRect() doesn't do subItem error checking and returns
+ // true even for the out of range values of it (even if the results are
+ // completely bogus in this case), so we check item validity ourselves
+ wxCHECK_MSG( subItem == wxLIST_GETSUBITEMRECT_WHOLEITEM ||
+ (subItem >= 0 && subItem < GetColumnCount()),
+ false, wxT("invalid sub item index") );
+
+ // use wxCHECK_MSG against "item" too, for coherency with the generic implementation:
+ wxCHECK_MSG( item >= 0 && item < GetItemCount(), false,
+ wxT("invalid item in GetSubItemRect") );
+
+ int codeWin;
+ if ( code == wxLIST_RECT_BOUNDS )
+ codeWin = LVIR_BOUNDS;
+ else if ( code == wxLIST_RECT_ICON )
+ codeWin = LVIR_ICON;
+ else if ( code == wxLIST_RECT_LABEL )
+ codeWin = LVIR_LABEL;
+ else
+ {
+ wxFAIL_MSG( wxT("incorrect code in GetItemRect() / GetSubItemRect()") );
+ codeWin = LVIR_BOUNDS;
+ }
+
+ RECT rectWin;
+ if ( !wxGetListCtrlSubItemRect
+ (
+ GetHwnd(),
+ item,
+ subItem == wxLIST_GETSUBITEMRECT_WHOLEITEM ? 0 : subItem,
+ codeWin,
+ rectWin
+ ) )
+ {
+ return false;
+ }
+
+ wxCopyRECTToRect(rectWin, rect);
+
+ // there is no way to retrieve the first sub item bounding rectangle using
+ // wxGetListCtrlSubItemRect() as 0 means the whole item, so we need to
+ // truncate it at first column ourselves
+ if ( subItem == 0 && code == wxLIST_RECT_BOUNDS )
+ rect.width = GetColumnWidth(0);
+
+ return true;
+}
+
+
+
+
+// Gets the item position
+bool wxListCtrl::GetItemPosition(long item, wxPoint& pos) const
+{
+ POINT pt;
+
+ bool success = (ListView_GetItemPosition(GetHwnd(), (int) item, &pt) != 0);
+
+ pos.x = pt.x; pos.y = pt.y;
+ return success;
+}
+
+// Sets the item position.
+bool wxListCtrl::SetItemPosition(long item, const wxPoint& pos)
+{
+ return (ListView_SetItemPosition(GetHwnd(), (int) item, pos.x, pos.y) != 0);
+}
+
+// Gets the number of items in the list control
+int wxListCtrl::GetItemCount() const
+{
+ return m_count;
+}
+
+wxSize wxListCtrl::GetItemSpacing() const
+{
+ const int spacing = ListView_GetItemSpacing(GetHwnd(), (BOOL)HasFlag(wxLC_SMALL_ICON));
+
+ return wxSize(LOWORD(spacing), HIWORD(spacing));
+}
+
+#if WXWIN_COMPATIBILITY_2_6
+
+int wxListCtrl::GetItemSpacing(bool isSmall) const
+{
+ return ListView_GetItemSpacing(GetHwnd(), (BOOL) isSmall);
+}
+
+#endif // WXWIN_COMPATIBILITY_2_6
+
+void wxListCtrl::SetItemTextColour( long item, const wxColour &col )
+{
+ wxListItem info;
+ info.m_itemId = item;
+ info.SetTextColour( col );
+ SetItem( info );
+}
+
+wxColour wxListCtrl::GetItemTextColour( long item ) const
+{
+ wxColour col;
+ wxMSWListItemData *data = MSWGetItemData(item);
+ if ( data && data->attr )
+ col = data->attr->GetTextColour();
+
+ return col;
+}
+
+void wxListCtrl::SetItemBackgroundColour( long item, const wxColour &col )
+{
+ wxListItem info;
+ info.m_itemId = item;
+ info.SetBackgroundColour( col );
+ SetItem( info );
+}
+
+wxColour wxListCtrl::GetItemBackgroundColour( long item ) const
+{
+ wxColour col;
+ wxMSWListItemData *data = MSWGetItemData(item);
+ if ( data && data->attr )
+ col = data->attr->GetBackgroundColour();
+
+ return col;
+}
+
+void wxListCtrl::SetItemFont( long item, const wxFont &f )
+{
+ wxListItem info;
+ info.m_itemId = item;
+ info.SetFont( f );
+ SetItem( info );
+}
+
+wxFont wxListCtrl::GetItemFont( long item ) const
+{
+ wxFont f;
+ wxMSWListItemData *data = MSWGetItemData(item);
+ if ( data && data->attr )
+ f = data->attr->GetFont();
+
+ return f;
+}
+
+// Gets the number of selected items in the list control
+int wxListCtrl::GetSelectedItemCount() const
+{
+ return ListView_GetSelectedCount(GetHwnd());
+}
+
+// Gets the text colour of the listview
+wxColour wxListCtrl::GetTextColour() const
+{
+ COLORREF ref = ListView_GetTextColor(GetHwnd());
+ wxColour col(GetRValue(ref), GetGValue(ref), GetBValue(ref));
+ return col;
+}
+
+// Sets the text colour of the listview
+void wxListCtrl::SetTextColour(const wxColour& col)
+{
+ ListView_SetTextColor(GetHwnd(), PALETTERGB(col.Red(), col.Green(), col.Blue()));
+}
+
+// Gets the index of the topmost visible item when in
+// list or report view
+long wxListCtrl::GetTopItem() const
+{
+ return (long) ListView_GetTopIndex(GetHwnd());
+}
+
+// Searches for an item, starting from 'item'.
+// 'geometry' is one of
+// wxLIST_NEXT_ABOVE/ALL/BELOW/LEFT/RIGHT.
+// 'state' is a state bit flag, one or more of
+// wxLIST_STATE_DROPHILITED/FOCUSED/SELECTED/CUT.
+// item can be -1 to find the first item that matches the
+// specified flags.
+// Returns the item or -1 if unsuccessful.
+long wxListCtrl::GetNextItem(long item, int geom, int state) const
+{
+ long flags = 0;
+
+ if ( geom == wxLIST_NEXT_ABOVE )
+ flags |= LVNI_ABOVE;
+ if ( geom == wxLIST_NEXT_ALL )
+ flags |= LVNI_ALL;
+ if ( geom == wxLIST_NEXT_BELOW )
+ flags |= LVNI_BELOW;
+ if ( geom == wxLIST_NEXT_LEFT )
+ flags |= LVNI_TOLEFT;
+ if ( geom == wxLIST_NEXT_RIGHT )
+ flags |= LVNI_TORIGHT;
+
+ if ( state & wxLIST_STATE_CUT )
+ flags |= LVNI_CUT;
+ if ( state & wxLIST_STATE_DROPHILITED )
+ flags |= LVNI_DROPHILITED;
+ if ( state & wxLIST_STATE_FOCUSED )
+ flags |= LVNI_FOCUSED;
+ if ( state & wxLIST_STATE_SELECTED )
+ flags |= LVNI_SELECTED;
+
+ return (long) ListView_GetNextItem(GetHwnd(), item, flags);
+}
+
+
+wxImageList *wxListCtrl::GetImageList(int which) const
+{
+ if ( which == wxIMAGE_LIST_NORMAL )
+ {
+ return m_imageListNormal;
+ }
+ else if ( which == wxIMAGE_LIST_SMALL )
+ {
+ return m_imageListSmall;
+ }
+ else if ( which == wxIMAGE_LIST_STATE )
+ {
+ return m_imageListState;
+ }
+ return NULL;
+}
+
+void wxListCtrl::SetImageList(wxImageList *imageList, int which)
+{
+ int flags = 0;
+ if ( which == wxIMAGE_LIST_NORMAL )
+ {
+ flags = LVSIL_NORMAL;
+ if (m_ownsImageListNormal) delete m_imageListNormal;
+ m_imageListNormal = imageList;
+ m_ownsImageListNormal = false;
+ }
+ else if ( which == wxIMAGE_LIST_SMALL )
+ {
+ flags = LVSIL_SMALL;
+ if (m_ownsImageListSmall) delete m_imageListSmall;
+ m_imageListSmall = imageList;
+ m_ownsImageListSmall = false;
+ }
+ else if ( which == wxIMAGE_LIST_STATE )
+ {
+ flags = LVSIL_STATE;
+ if (m_ownsImageListState) delete m_imageListState;
+ m_imageListState = imageList;
+ m_ownsImageListState = false;
+ }
+ (void) ListView_SetImageList(GetHwnd(), (HIMAGELIST) imageList ? imageList->GetHIMAGELIST() : 0, flags);
+}
+
+void wxListCtrl::AssignImageList(wxImageList *imageList, int which)
+{
+ SetImageList(imageList, which);
+ if ( which == wxIMAGE_LIST_NORMAL )
+ m_ownsImageListNormal = true;
+ else if ( which == wxIMAGE_LIST_SMALL )
+ m_ownsImageListSmall = true;
+ else if ( which == wxIMAGE_LIST_STATE )
+ m_ownsImageListState = true;
+}
+
+// ----------------------------------------------------------------------------
+// Operations
+// ----------------------------------------------------------------------------
+
+// Arranges the items
+bool wxListCtrl::Arrange(int flag)
+{
+ UINT code = 0;
+ if ( flag == wxLIST_ALIGN_LEFT )
+ code = LVA_ALIGNLEFT;
+ else if ( flag == wxLIST_ALIGN_TOP )
+ code = LVA_ALIGNTOP;
+ else if ( flag == wxLIST_ALIGN_DEFAULT )
+ code = LVA_DEFAULT;
+ else if ( flag == wxLIST_ALIGN_SNAP_TO_GRID )
+ code = LVA_SNAPTOGRID;
+
+ return (ListView_Arrange(GetHwnd(), code) != 0);
+}
+
+// Deletes an item
+bool wxListCtrl::DeleteItem(long item)
+{
+ if ( !ListView_DeleteItem(GetHwnd(), (int) item) )
+ {
+ wxLogLastError(wxT("ListView_DeleteItem"));
+ return false;
+ }
+
+ m_count--;
+ wxASSERT_MSG( m_count == ListView_GetItemCount(GetHwnd()),
+ wxT("m_count should match ListView_GetItemCount"));
+
+ // the virtual list control doesn't refresh itself correctly, help it
+ if ( IsVirtual() )
+ {
+ // we need to refresh all the lines below the one which was deleted
+ wxRect rectItem;
+ if ( item > 0 && GetItemCount() )
+ {
+ GetItemRect(item - 1, rectItem);
+ }
+ else
+ {
+ rectItem.y =
+ rectItem.height = 0;
+ }
+
+ wxRect rectWin = GetRect();
+ rectWin.height = rectWin.GetBottom() - rectItem.GetBottom();
+ rectWin.y = rectItem.GetBottom();
+
+ RefreshRect(rectWin);
+ }
+
+ return true;
+}
+
+// Deletes all items
+bool wxListCtrl::DeleteAllItems()
+{
+ // Calling ListView_DeleteAllItems() will always generate an event but we
+ // shouldn't do it if the control is empty
+ return !GetItemCount() || ListView_DeleteAllItems(GetHwnd()) != 0;
+}
+
+// Deletes all items
+bool wxListCtrl::DeleteAllColumns()
+{
+ while ( m_colCount > 0 )
+ {
+ if ( ListView_DeleteColumn(GetHwnd(), 0) == 0 )
+ {
+ wxLogLastError(wxT("ListView_DeleteColumn"));
+
+ return false;
+ }
+
+ m_colCount--;
+ }
+
+ wxASSERT_MSG( m_colCount == 0, wxT("no columns should be left") );
+
+ return true;
+}
+
+// Deletes a column
+bool wxListCtrl::DeleteColumn(int col)
+{
+ bool success = (ListView_DeleteColumn(GetHwnd(), col) != 0);
+
+ if ( success && (m_colCount > 0) )
+ m_colCount --;
+ return success;
+}
+
+// Clears items, and columns if there are any.
+void wxListCtrl::ClearAll()
+{
+ DeleteAllItems();
+ if ( m_colCount > 0 )
+ DeleteAllColumns();
+}
+
+void wxListCtrl::InitEditControl(WXHWND hWnd)
+{
+ m_textCtrl->SetHWND(hWnd);
+ m_textCtrl->SubclassWin(hWnd);
+ m_textCtrl->SetParent(this);
+
+ // we must disallow TABbing away from the control while the edit contol is
+ // shown because this leaves it in some strange state (just try removing
+ // this line and then pressing TAB while editing an item in listctrl
+ // inside a panel)
+ m_textCtrl->SetWindowStyle(m_textCtrl->GetWindowStyle() | wxTE_PROCESS_TAB);
+}
+
+wxTextCtrl* wxListCtrl::EditLabel(long item, wxClassInfo* textControlClass)
+{
+ wxCHECK_MSG( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)), NULL,
+ "control used for label editing must be a wxTextCtrl" );
+
+ // ListView_EditLabel requires that the list has focus.
+ SetFocus();
+
+ // create m_textCtrl here before calling ListView_EditLabel() because it
+ // generates wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT event from inside it and
+ // the user handler for it can call GetEditControl() resulting in an on
+ // demand creation of a stock wxTextCtrl instead of the control of a
+ // (possibly) custom wxClassInfo
+ DeleteEditControl();
+ m_textCtrl = (wxTextCtrl *)textControlClass->CreateObject();
+
+ WXHWND hWnd = (WXHWND) ListView_EditLabel(GetHwnd(), item);
+ if ( !hWnd )
+ {
+ // failed to start editing
+ wxDELETE(m_textCtrl);
+
+ return NULL;
+ }
+
+ // if GetEditControl() hasn't been called, we need to initialize the edit
+ // control ourselves
+ if ( !m_textCtrl->GetHWND() )
+ InitEditControl(hWnd);
+
+ return m_textCtrl;
+}
+
+// End label editing, optionally cancelling the edit
+bool wxListCtrl::EndEditLabel(bool cancel)
+{
+ // m_textCtrl is not always ready, ie. in EVT_LIST_BEGIN_LABEL_EDIT
+ HWND hwnd = ListView_GetEditControl(GetHwnd());
+ if ( !hwnd )
+ return false;
+
+ // Newer versions of Windows have a special message for cancelling editing,
+ // use it if available.
+#ifdef ListView_CancelEditLabel
+ if ( cancel && (wxApp::GetComCtl32Version() >= 600) )
+ {
+ ListView_CancelEditLabel(GetHwnd());
+ }
+ else
+#endif // ListView_CancelEditLabel
+ {
+ // We shouldn't destroy the control ourselves according to MSDN, which
+ // proposes WM_CANCELMODE to do this, but it doesn't seem to work so
+ // emulate the corresponding user action instead.
+ ::SendMessage(hwnd, WM_KEYDOWN, cancel ? VK_ESCAPE : VK_RETURN, 0);
+ }
+
+ return true;
+}
+
+// Ensures this item is visible
+bool wxListCtrl::EnsureVisible(long item)
+{
+ return ListView_EnsureVisible(GetHwnd(), (int) item, FALSE) != FALSE;
+}
+
+// Find an item whose label matches this string, starting from the item after 'start'
+// or the beginning if 'start' is -1.
+long wxListCtrl::FindItem(long start, const wxString& str, bool partial)
+{
+ LV_FINDINFO findInfo;
+
+ findInfo.flags = LVFI_STRING;
+ if ( partial )
+ findInfo.flags |= LVFI_PARTIAL;
+ findInfo.psz = str.wx_str();
+
+ // ListView_FindItem() excludes the first item from search and to look
+ // through all the items you need to start from -1 which is unnatural and
+ // inconsistent with the generic version - so we adjust the index
+ if (start != -1)
+ start --;
+ return ListView_FindItem(GetHwnd(), start, &findInfo);
+}
+
+// Find an item whose data matches this data, starting from the item after
+// 'start' or the beginning if 'start' is -1.
+long wxListCtrl::FindItem(long start, wxUIntPtr data)
+{
+ // we can't use ListView_FindItem() directly as we don't store the data
+ // pointer itself in the control but rather our own internal data, so first
+ // we need to find the right value to search for (and there can be several
+ // of them)
+ int idx = wxNOT_FOUND;
+ const unsigned count = m_internalData.size();
+ for ( unsigned n = 0; n < count; n++ )
+ {
+ if ( m_internalData[n]->lParam == (LPARAM)data )
+ {
+ LV_FINDINFO findInfo;
+ findInfo.flags = LVFI_PARAM;
+ findInfo.lParam = (LPARAM)wxPtrToUInt(m_internalData[n]);
+
+ int rc = ListView_FindItem(GetHwnd(), start, &findInfo);
+ if ( rc != -1 )
+ {
+ if ( idx == wxNOT_FOUND || rc < idx )
+ {
+ idx = rc;
+ if ( idx == start + 1 )
+ {
+ // we can stop here, we don't risk finding a closer
+ // match
+ break;
+ }
+ }
+ //else: this item is after the previously found one
+ }
+ }
+ }
+
+ return idx;
+}
+
+// Find an item nearest this position in the specified direction, starting from
+// the item after 'start' or the beginning if 'start' is -1.
+long wxListCtrl::FindItem(long start, const wxPoint& pt, int direction)
+{
+ LV_FINDINFO findInfo;
+
+ findInfo.flags = LVFI_NEARESTXY;
+ findInfo.pt.x = pt.x;
+ findInfo.pt.y = pt.y;
+ findInfo.vkDirection = VK_RIGHT;
+
+ if ( direction == wxLIST_FIND_UP )
+ findInfo.vkDirection = VK_UP;
+ else if ( direction == wxLIST_FIND_DOWN )
+ findInfo.vkDirection = VK_DOWN;
+ else if ( direction == wxLIST_FIND_LEFT )
+ findInfo.vkDirection = VK_LEFT;
+ else if ( direction == wxLIST_FIND_RIGHT )
+ findInfo.vkDirection = VK_RIGHT;
+
+ return ListView_FindItem(GetHwnd(), start, &findInfo);
+}
+
+// Determines which item (if any) is at the specified point,
+// giving details in 'flags' (see wxLIST_HITTEST_... flags above)
+long
+wxListCtrl::HitTest(const wxPoint& point, int& flags, long *ptrSubItem) const
+{
+ LV_HITTESTINFO hitTestInfo;
+ hitTestInfo.pt.x = (int) point.x;
+ hitTestInfo.pt.y = (int) point.y;
+
+ long item;
+#ifdef LVM_SUBITEMHITTEST
+ if ( ptrSubItem && wxApp::GetComCtl32Version() >= 470 )
+ {
+ item = ListView_SubItemHitTest(GetHwnd(), &hitTestInfo);
+ *ptrSubItem = hitTestInfo.iSubItem;
+ }
+ else
+#endif // LVM_SUBITEMHITTEST
+ {
+ item = ListView_HitTest(GetHwnd(), &hitTestInfo);
+ }
+
+ flags = 0;
+
+ if ( hitTestInfo.flags & LVHT_ABOVE )
+ flags |= wxLIST_HITTEST_ABOVE;
+ if ( hitTestInfo.flags & LVHT_BELOW )
+ flags |= wxLIST_HITTEST_BELOW;
+ if ( hitTestInfo.flags & LVHT_TOLEFT )
+ flags |= wxLIST_HITTEST_TOLEFT;
+ if ( hitTestInfo.flags & LVHT_TORIGHT )
+ flags |= wxLIST_HITTEST_TORIGHT;
+
+ if ( hitTestInfo.flags & LVHT_NOWHERE )
+ flags |= wxLIST_HITTEST_NOWHERE;
+
+ // note a bug or at least a very strange feature of comtl32.dll (tested
+ // with version 4.0 under Win95 and 6.0 under Win 2003): if you click to
+ // the right of the item label, ListView_HitTest() returns a combination of
+ // LVHT_ONITEMICON, LVHT_ONITEMLABEL and LVHT_ONITEMSTATEICON -- filter out
+ // the bits which don't make sense
+ if ( hitTestInfo.flags & LVHT_ONITEMLABEL )
+ {
+ flags |= wxLIST_HITTEST_ONITEMLABEL;
+
+ // do not translate LVHT_ONITEMICON here, as per above
+ }
+ else
+ {
+ if ( hitTestInfo.flags & LVHT_ONITEMICON )
+ flags |= wxLIST_HITTEST_ONITEMICON;
+ if ( hitTestInfo.flags & LVHT_ONITEMSTATEICON )
+ flags |= wxLIST_HITTEST_ONITEMSTATEICON;
+ }
+
+ return item;
+}
+
+
+// Inserts an item, returning the index of the new item if successful,
+// -1 otherwise.
+long wxListCtrl::InsertItem(const wxListItem& info)
+{
+ wxASSERT_MSG( !IsVirtual(), wxT("can't be used with virtual controls") );
+
+ LV_ITEM item;
+ wxConvertToMSWListItem(this, info, item);
+ item.mask &= ~LVIF_PARAM;
+
+ // check whether we need to allocate our internal data
+ bool needInternalData = (info.m_mask & wxLIST_MASK_DATA) ||
+ info.HasAttributes();
+ if ( needInternalData )
+ {
+ item.mask |= LVIF_PARAM;
+
+ wxMSWListItemData * const data = new wxMSWListItemData;
+ m_internalData.push_back(data);
+ item.lParam = (LPARAM)data;
+
+ if ( info.m_mask & wxLIST_MASK_DATA )
+ data->lParam = info.m_data;
+
+ // check whether it has any custom attributes
+ if ( info.HasAttributes() )
+ {
+ // take copy of attributes
+ data->attr = new wxListItemAttr(*info.GetAttributes());
+
+ // and remember that we have some now...
+ m_hasAnyAttr = true;
+ }
+ }
+
+ const long rv = ListView_InsertItem(GetHwnd(), & item);
+
+ // failing to insert the item is really unexpected
+ wxCHECK_MSG( rv != -1, rv, "failed to insert an item in wxListCtrl" );
+
+ m_count++;
+ wxASSERT_MSG( m_count == ListView_GetItemCount(GetHwnd()),
+ wxT("m_count should match ListView_GetItemCount"));
+
+ return rv;
+}