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
// ----------------------------------------------------------------------------
// 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;
}
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;
}
*/
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 )
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;
}
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;
}
wxLIST_STATE_SELECTED);
// <Enter> or <Space> 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;
}
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
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];
// 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;
}
// 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;