X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5cd4cb75ee776215a4de0f0af694b4334a0fd97b..0c75b29e1ed19810546de38b646b5b901be873e2:/src/msw/listctrl.cpp?ds=inline diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index 16cf30a914..17edff1faf 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -82,6 +82,31 @@ static void wxConvertToMSWListCol(HWND hwndList, const wxListItem& item, LV_COLUMN& lvCol); +namespace +{ + +// replacement for ListView_GetSubItemRect() which provokes warnings like +// "the address of 'rc' will always evaluate as 'true'" when used with mingw32 +// 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 +inline bool +wxGetListCtrlSubItemRect(HWND hwnd, int item, int subitem, int flags, RECT& rect) +{ + rect.top = subitem; + rect.left = flags; + return ::SendMessage(hwnd, LVM_GETSUBITEMRECT, item, (LPARAM)&rect) != 0; +} + +inline bool +wxGetListCtrlItemRect(HWND hwnd, int item, int flags, RECT& rect) +{ + return wxGetListCtrlSubItemRect(hwnd, item, 0, flags, rect); +} + +} // anonymous namespace + // ---------------------------------------------------------------------------- // private helper classes // ---------------------------------------------------------------------------- @@ -766,6 +791,25 @@ int wxListCtrl::GetCountPerPage() const // Gets the edit control for editing labels. wxTextCtrl* wxListCtrl::GetEditControl() const { + // first check corresponds to the case when the label editing was started + // by user and hence m_textCtrl wasn't created by EditLabel() at all, while + // the second case corresponds to us being called from inside EditLabel() + // (e.g. from a user wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT handler): in this + // case EditLabel() did create the control but it didn't have an HWND to + // initialize it with yet + if ( !m_textCtrl || !m_textCtrl->GetHWND() ) + { + HWND hwndEdit = ListView_GetEditControl(GetHwnd()); + if ( hwndEdit ) + { + wxListCtrl * const self = wx_const_cast(wxListCtrl *, this); + + if ( !m_textCtrl ) + self->m_textCtrl = new wxTextCtrl; + self->InitEditControl((WXHWND)hwndEdit); + } + } + return m_textCtrl; } @@ -1063,19 +1107,40 @@ bool wxListCtrl::SetItemPtrData(long item, wxUIntPtr data) wxRect wxListCtrl::GetViewRect() const { - wxASSERT_MSG( !HasFlag(wxLC_REPORT | wxLC_LIST), - _T("wxListCtrl::GetViewRect() only works in icon mode") ); + wxRect rect; - RECT rc; - if ( !ListView_GetViewRect(GetHwnd(), &rc) ) + // 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) ) { - wxLogDebug(_T("ListView_GetViewRect() failed.")); + RECT rc; + if ( !ListView_GetViewRect(GetHwnd(), &rc) ) + { + wxLogDebug(_T("ListView_GetViewRect() failed.")); - wxZeroMemory(rc); + wxZeroMemory(rc); + } + + wxCopyRECTToRect(rc, rect); } + else if ( HasFlag(wxLC_REPORT) ) + { + const long count = GetItemCount(); + if ( count ) + { + GetItemRect(wxMin(GetTopItem() + GetCountPerPage(), count - 1), rect); - wxRect rect; - wxCopyRECTToRect(rc, 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( _T("not implemented in this mode") ); + } return rect; } @@ -1101,7 +1166,12 @@ bool wxListCtrl::GetItemRect(long item, wxRect& rect, int code) const */ bool wxListCtrl::GetSubItemRect(long item, long subItem, wxRect& rect, int code) const { - RECT rectWin; + // 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, _T("invalid sub item index") ); int codeWin; if ( code == wxLIST_RECT_BOUNDS ) @@ -1116,27 +1186,26 @@ bool wxListCtrl::GetSubItemRect(long item, long subItem, wxRect& rect, int code) codeWin = LVIR_BOUNDS; } - bool success; - if( subItem == wxLIST_GETSUBITEMRECT_WHOLEITEM) - { - success = ListView_GetItemRect(GetHwnd(), (int) item, &rectWin, codeWin) != 0; - } - else if( subItem >= 0) - { - success = ListView_GetSubItemRect( GetHwnd(), (int) item, (int) subItem, codeWin, &rectWin) != 0; - } - else + RECT rectWin; + if ( !wxGetListCtrlSubItemRect + ( + GetHwnd(), + item, + subItem == wxLIST_GETSUBITEMRECT_WHOLEITEM ? 0 : subItem, + codeWin, + rectWin + ) ) { - wxFAIL_MSG( _T("incorrect subItem number in GetSubItemRect()") ); - return false; + return false; } - rect.x = rectWin.left; - rect.y = rectWin.top; - rect.width = rectWin.right - rectWin.left; - rect.height = rectWin.bottom - rectWin.top; + wxCopyRECTToRect(rectWin, rect); - return success; + // 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); + + return true; } @@ -1455,33 +1524,49 @@ void wxListCtrl::ClearAll() 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) { - wxASSERT( (textControlClass->IsKindOf(CLASSINFO(wxTextCtrl))) ); + 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 + delete m_textCtrl; + m_textCtrl = NULL; + return NULL; } - // [re]create the text control wrapping the HWND we got - DeleteEditControl(); - - m_textCtrl = (wxTextCtrl *)textControlClass->CreateObject(); - 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); + // if GetEditControl() hasn't been called, we need to initialize the edit + // control ourselves + if ( !m_textCtrl->GetHWND() ) + InitEditControl(hWnd); return m_textCtrl; } @@ -2204,11 +2289,11 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) wxLIST_STATE_SELECTED); // or activate the selected item if any (but - // not with Shift and/or Ctrl as then they have a predefined - // meaning for the list view) + // not with any modifiers as they have a predefined meaning + // then) if ( lItem != -1 && (wVKey == VK_RETURN || wVKey == VK_SPACE) && - !(wxIsShiftDown() || wxIsCtrlDown()) ) + !wxIsAnyModifierDown() ) { eventType = wxEVT_COMMAND_LIST_ITEM_ACTIVATED; } @@ -2491,10 +2576,10 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) static RECT GetCustomDrawnItemRect(const NMCUSTOMDRAW& nmcd) { RECT rc; - ListView_GetItemRect(nmcd.hdr.hwndFrom, nmcd.dwItemSpec, &rc, LVIR_BOUNDS); + wxGetListCtrlItemRect(nmcd.hdr.hwndFrom, nmcd.dwItemSpec, LVIR_BOUNDS, rc); RECT rcIcon; - ListView_GetItemRect(nmcd.hdr.hwndFrom, nmcd.dwItemSpec, &rcIcon, LVIR_ICON); + wxGetListCtrlItemRect(nmcd.hdr.hwndFrom, nmcd.dwItemSpec, LVIR_ICON, rcIcon); // exclude the icon part, neither the selection background nor focus rect // should cover it @@ -2517,22 +2602,10 @@ bool HandleSubItemPrepaint(LPNMLVCUSTOMDRAW pLVCD, HFONT hfont, int colCount) SelectInHDC selFont(hdc, hfont); // get the rectangle to paint + int subitem = colCount ? col + 1 : col; RECT rc; - ListView_GetSubItemRect(hwndList, item, col, LVIR_BOUNDS, &rc); - if ( !col && colCount > 1 ) - { - // broken ListView_GetSubItemRect() returns the entire item rect for - // 0th subitem while we really need just the part for this column - RECT rc2; - ListView_GetSubItemRect(hwndList, item, 1, LVIR_BOUNDS, &rc2); - - rc.right = rc2.left; - rc.left += 4; - } - else // not first subitem - { - rc.left += 6; - } + wxGetListCtrlSubItemRect(hwndList, item, subitem, LVIR_BOUNDS, rc); + rc.left += 6; // get the image and text to draw wxChar text[512]; @@ -2646,7 +2719,7 @@ static void HandleItemPaint(LPNMLVCUSTOMDRAW pLVCD, HFONT hfont) // same thing for CDIS_FOCUS (except simpler as there is only one of them) if ( ::GetFocus() == hwndList && - ListView_GetNextItem(hwndList, (WPARAM)-1, LVNI_FOCUSED) == item ) + ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED) == item ) { nmcd.uItemState |= CDIS_FOCUS; } @@ -2771,10 +2844,10 @@ WXLPARAM wxListCtrl::OnCustomDraw(WXLPARAM lParam) // Necessary for drawing hrules and vrules, if specified void wxListCtrl::OnPaint(wxPaintEvent& event) { - bool drawHRules = HasFlag(wxLC_HRULES); - bool drawVRules = HasFlag(wxLC_VRULES); + const bool drawHRules = HasFlag(wxLC_HRULES); + const bool drawVRules = HasFlag(wxLC_VRULES); - if (!InReportView() || !drawHRules && !drawVRules) + if (!InReportView() || !(drawHRules || drawVRules)) { event.Skip(); return;