X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/89cafab0f40e8f876f374cc80434e3fecbbb7426..d07e1e0c13c99291bf1d81f5bcfe252f9d9d4010:/src/msw/listctrl.cpp?ds=sidebyside diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index 17edff1faf..baf52465ad 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -39,6 +39,7 @@ #endif #include "wx/imaglist.h" +#include "wx/vector.h" #include "wx/msw/private.h" @@ -90,7 +91,9 @@ namespace // 4.3+ // // this function does no error checking on item and subitem parameters, notice -// that subitem is 0 for whole item or 1-based for the individual columns +// that subitem 0 means the whole item so there is no way to retrieve the +// rectangle of the first subitem using this function, in particular notice +// that the index is *not* 1-based, in spite of what MSDN says inline bool wxGetListCtrlSubItemRect(HWND hwnd, int item, int subitem, int flags, RECT& rect) { @@ -184,7 +187,7 @@ private: LV_ITEM_NATIVE *m_pItem; LV_ITEM_NATIVE m_item; - DECLARE_NO_COPY_CLASS(wxLV_ITEM) + wxDECLARE_NO_COPY_CLASS(wxLV_ITEM); }; /////////////////////////////////////////////////////// @@ -232,7 +235,7 @@ public: delete attr; } - DECLARE_NO_COPY_CLASS(wxListItemInternalData) + wxDECLARE_NO_COPY_CLASS(wxListItemInternalData); }; // Get the internal data structure @@ -399,15 +402,15 @@ WXDWORD wxListCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const wstyle |= LVS_SHAREIMAGELISTS | LVS_SHOWSELALWAYS; -#ifdef __WXDEBUG__ +#if wxDEBUG_LEVEL size_t nModes = 0; #define MAP_MODE_STYLE(wx, ms) \ if ( style & (wx) ) { wstyle |= (ms); nModes++; } -#else // !__WXDEBUG__ +#else // !wxDEBUG_LEVEL #define MAP_MODE_STYLE(wx, ms) \ if ( style & (wx) ) wstyle |= (ms); -#endif // __WXDEBUG__ +#endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL MAP_MODE_STYLE(wxLC_ICON, LVS_ICON) MAP_MODE_STYLE(wxLC_SMALL_ICON, LVS_SMALLICON) @@ -721,33 +724,32 @@ bool wxListCtrl::SetColumnWidth(int col, int width) // columns order // ---------------------------------------------------------------------------- -int wxListCtrl::GetColumnOrder(int col) const +int wxListCtrl::GetColumnIndexFromOrder(int order) const { const int numCols = GetColumnCount(); - wxCHECK_MSG( col >= 0 && col < numCols, -1, _T("Col index out of bounds") ); + wxCHECK_MSG( order >= 0 && order < numCols, -1, + _T("Column position out of bounds") ); wxArrayInt indexArray(numCols); - if ( !ListView_GetColumnOrderArray(GetHwnd(), numCols, &indexArray[0]) ) return -1; - return indexArray[col]; + return indexArray[order]; } -int wxListCtrl::GetColumnIndexFromOrder(int order) const +int wxListCtrl::GetColumnOrder(int col) const { const int numCols = GetColumnCount(); - wxASSERT_MSG( order >= 0 && order < numCols, _T("Col order out of bounds") ); + wxASSERT_MSG( col >= 0 && col < numCols, _T("Column index out of bounds") ); wxArrayInt indexArray(numCols); - if ( !ListView_GetColumnOrderArray(GetHwnd(), numCols, &indexArray[0]) ) return -1; - for ( int col = 0; col < numCols; col++ ) + for ( int pos = 0; pos < numCols; pos++ ) { - if ( indexArray[col] == order ) - return col; + if ( indexArray[pos] == col ) + return pos; } wxFAIL_MSG( _T("no column with with given order?") ); @@ -802,7 +804,7 @@ wxTextCtrl* wxListCtrl::GetEditControl() const HWND hwndEdit = ListView_GetEditControl(GetHwnd()); if ( hwndEdit ) { - wxListCtrl * const self = wx_const_cast(wxListCtrl *, this); + wxListCtrl * const self = const_cast(this); if ( !m_textCtrl ) self->m_textCtrl = new wxTextCtrl; @@ -891,7 +893,7 @@ bool wxListCtrl::SetItem(wxListItem& info) data = new wxListItemInternalData(); item.lParam = (LPARAM) data; item.mask |= LVIF_PARAM; - }; + } // user data @@ -908,15 +910,14 @@ bool wxListCtrl::SetItem(wxListItem& info) 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 ) { - item.cchTextMax = 0; if ( !ListView_SetItem(GetHwnd(), &item) ) { wxLogDebug(_T("ListView_SetItem() failed")); @@ -1151,19 +1152,6 @@ bool wxListCtrl::GetItemRect(long item, wxRect& rect, int code) const return GetSubItemRect( item, wxLIST_GETSUBITEMRECT_WHOLEITEM, rect, code) ; } -/*! - * Retrieve coordinates and size of a specified subitem of a listview control. - * This function only works if the listview control is in the report mode. - * - * @param item : Item number - * @param subItem : Subitem or column number, use -1 for the whole row including - * all columns or subitems - * @param rect : A pointer to an allocated wxRect object - * @param code : Specify the part of the subitem coordinates you need. Choices are - * wxLIST_RECT_BOUNDS, wxLIST_RECT_ICON, wxLIST_RECT_LABEL - * - * @return bool : True if successful. - */ bool wxListCtrl::GetSubItemRect(long item, long subItem, wxRect& rect, int code) const { // ListView_GetSubItemRect() doesn't do subItem error checking and returns @@ -1173,6 +1161,10 @@ bool wxListCtrl::GetSubItemRect(long item, long subItem, wxRect& rect, int code) (subItem >= 0 && subItem < GetColumnCount()), false, _T("invalid sub item index") ); + // use wxCHECK_MSG against "item" too, for coherency with the generic implementation: + wxCHECK_MSG( item >= 0 && item < GetItemCount(), false, + _T("invalid item in GetSubItemRect") ); + int codeWin; if ( code == wxLIST_RECT_BOUNDS ) codeWin = LVIR_BOUNDS; @@ -1201,9 +1193,11 @@ bool wxListCtrl::GetSubItemRect(long item, long subItem, wxRect& rect, int code) wxCopyRECTToRect(rectWin, rect); - // for the first sub item, i.e. the main item itself, the returned rect is - // the whole line one, we need to truncate it at first column ourselves - rect.width = GetColumnWidth(0); + // 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 ) + rect.width = GetColumnWidth(0); return true; } @@ -1631,7 +1625,7 @@ long wxListCtrl::FindItem(long start, wxUIntPtr data) if (GetItemData(idx) == data) return idx; idx++; - }; + } return -1; } @@ -1751,7 +1745,7 @@ long wxListCtrl::InsertItem(const wxListItem& info) // and remember that we have some now... m_hasAnyAttr = true; } - }; + } long rv = ListView_InsertItem(GetHwnd(), & item); @@ -1871,12 +1865,12 @@ bool wxListCtrl::ScrollList(int dx, int dy) struct wxInternalDataSort { wxListCtrlCompare user_fn; - long data; + wxIntPtr data; }; int CALLBACK wxInternalDataCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { - struct wxInternalDataSort *internalData = (struct wxInternalDataSort *) lParamSort; + wxInternalDataSort * const internalData = (wxInternalDataSort *) lParamSort; wxListItemInternalData *data1 = (wxListItemInternalData *) lParam1; wxListItemInternalData *data2 = (wxListItemInternalData *) lParam2; @@ -1888,9 +1882,9 @@ int CALLBACK wxInternalDataCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM l } -bool wxListCtrl::SortItems(wxListCtrlCompare fn, long data) +bool wxListCtrl::SortItems(wxListCtrlCompare fn, wxIntPtr data) { - struct wxInternalDataSort internalData; + wxInternalDataSort internalData; internalData.user_fn = fn; internalData.data = data; @@ -2486,7 +2480,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) if ( lvi.mask & LVIF_TEXT ) { wxString text = OnGetItemText(item, lvi.iSubItem); - wxStrncpy(lvi.pszText, text, lvi.cchTextMax); + wxStrlcpy(lvi.pszText, text.c_str(), lvi.cchTextMax); } // see comment at the end of wxListCtrl::GetColumn() @@ -2718,8 +2712,12 @@ static void HandleItemPaint(LPNMLVCUSTOMDRAW pLVCD, HFONT hfont) } // same thing for CDIS_FOCUS (except simpler as there is only one of them) + // + // NB: cast is needed to work around the bug in mingw32 headers which don't + // have it inside ListView_GetNextItem() itself (unlike SDK ones) if ( ::GetFocus() == hwndList && - ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED) == item ) + ListView_GetNextItem( + hwndList, static_cast(-1), LVNI_FOCUSED) == item ) { nmcd.uItemState |= CDIS_FOCUS; } @@ -2826,14 +2824,22 @@ WXLPARAM wxListCtrl::OnCustomDraw(WXLPARAM lParam) break; case CDDS_ITEMPREPAINT: + // get a message for each subitem + return CDRF_NOTIFYITEMDRAW; + + case CDDS_SUBITEM | CDDS_ITEMPREPAINT: const int item = nmcd.dwItemSpec; + const int column = pLVCD->iSubItem; // we get this message with item == 0 for an empty control, we // must ignore it as calling OnGetItemAttr() would be wrong if ( item < 0 || item >= GetItemCount() ) break; + // same for columns + if ( column < 0 || column >= GetColumnCount() ) + break; - return HandleItemPrepaint(this, pLVCD, DoGetItemAttr(item)); + return HandleItemPrepaint(this, pLVCD, DoGetItemColumnAttr(item, column)); } return CDRF_DODEFAULT; @@ -2844,10 +2850,11 @@ WXLPARAM wxListCtrl::OnCustomDraw(WXLPARAM lParam) // Necessary for drawing hrules and vrules, if specified void wxListCtrl::OnPaint(wxPaintEvent& event) { + const int itemCount = GetItemCount(); const bool drawHRules = HasFlag(wxLC_HRULES); const bool drawVRules = HasFlag(wxLC_VRULES); - if (!InReportView() || !(drawHRules || drawVRules)) + if (!InReportView() || !(drawHRules || drawVRules) || !itemCount) { event.Skip(); return; @@ -2867,12 +2874,10 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) wxSize clientSize = GetClientSize(); wxRect itemRect; - int itemCount = GetItemCount(); - int i; if (drawHRules) { - long top = GetTopItem(); - for (i = top; i < top + GetCountPerPage() + 1; i++) + const long top = GetTopItem(); + for ( int i = top; i < top + GetCountPerPage() + 1; i++ ) { if (GetItemRect(i, itemRect)) { @@ -2886,17 +2891,18 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) { cy = itemRect.GetBottom(); dc.DrawLine(0, cy, clientSize.x, cy); + break; } } } } - i = itemCount - 1; - if (drawVRules && (i > -1)) + + if (drawVRules) { wxRect firstItemRect; GetItemRect(0, firstItemRect); - if (GetItemRect(i, itemRect)) + if (GetItemRect(itemCount - 1, itemRect)) { // this is a fix for bug 673394: erase the pixels which we would // otherwise leave on the screen @@ -2909,11 +2915,14 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) dc.SetPen(pen); dc.SetBrush(*wxTRANSPARENT_BRUSH); - int numCols = GetColumnCount(); - int* indexArray = new int[numCols]; - if ( !ListView_GetColumnOrderArray( GetHwnd(), numCols, indexArray) ) + const int numCols = GetColumnCount(); + wxVector indexArray(numCols); + if ( !ListView_GetColumnOrderArray(GetHwnd(), + numCols, + &indexArray[0]) ) { wxFAIL_MSG( _T("invalid column index array in OnPaint()") ); + return; } int x = itemRect.GetX(); @@ -2924,8 +2933,6 @@ void wxListCtrl::OnPaint(wxPaintEvent& event) dc.DrawLine(x-1, firstItemRect.GetY() - gap, x-1, itemRect.GetBottom()); } - - delete indexArray; } } } @@ -2994,9 +3001,9 @@ wxListItemAttr *wxListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item)) cons return NULL; } -wxListItemAttr *wxListCtrl::DoGetItemAttr(long item) const +wxListItemAttr *wxListCtrl::DoGetItemColumnAttr(long item, long column) const { - return IsVirtual() ? OnGetItemAttr(item) + return IsVirtual() ? OnGetItemColumnAttr(item, column) : wxGetInternalDataAttr(this, item); } @@ -3193,6 +3200,9 @@ static void wxConvertToMSWListItem(const wxListCtrl *ctrl, const wxListItem& info, LV_ITEM& lvItem) { + wxASSERT_MSG( 0 <= info.m_col && info.m_col < ctrl->GetColumnCount(), + "wxListCtrl column index out of bounds" ); + lvItem.iItem = (int) info.m_itemId; lvItem.iImage = info.m_image;