wxDECLARE_NO_COPY_CLASS(wxMSWListItemData);
};
-BEGIN_EVENT_TABLE(wxListCtrl, wxControl)
+BEGIN_EVENT_TABLE(wxListCtrl, wxListCtrlBase)
EVT_PAINT(wxListCtrl::OnPaint)
+ EVT_CHAR_HOOK(wxListCtrl::OnCharHook)
END_EVENT_TABLE()
// ============================================================================
WXDWORD wxListCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
{
- WXDWORD wstyle = wxControl::MSWGetStyle(style, exstyle);
+ WXDWORD wstyle = wxListCtrlBase::MSWGetStyle(style, exstyle);
wstyle |= LVS_SHAREIMAGELISTS | LVS_SHOWSELALWAYS;
{
if ( flag != m_windowStyle )
{
- wxControl::SetWindowStyleFlag(flag);
+ wxListCtrlBase::SetWindowStyleFlag(flag);
UpdateStyle();
// 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
+ // (e.g. from a user wxEVT_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() )
m_ownsImageListState = true;
}
+// ----------------------------------------------------------------------------
+// Geometry
+// ----------------------------------------------------------------------------
+
+wxSize wxListCtrl::MSWGetBestViewRect(int x, int y) const
+{
+ const DWORD rc = ListView_ApproximateViewRect(GetHwnd(), x, y, -1);
+
+ wxSize size(LOWORD(rc), HIWORD(rc));
+
+ // We have to add space for the scrollbars ourselves, they're not taken
+ // into account by ListView_ApproximateViewRect(), at least not with
+ // commctrl32.dll v6.
+ const DWORD mswStyle = ::GetWindowLong(GetHwnd(), GWL_STYLE);
+
+ if ( mswStyle & WS_HSCROLL )
+ size.y += wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y);
+ if ( mswStyle & WS_VSCROLL )
+ size.x += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
+
+ return size;
+}
+
// ----------------------------------------------------------------------------
// Operations
// ----------------------------------------------------------------------------
wxTextCtrl* wxListCtrl::EditLabel(long item, wxClassInfo* textControlClass)
{
- wxCHECK_MSG( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)), NULL,
+ wxCHECK_MSG( textControlClass->IsKindOf(wxCLASSINFO(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
+ // generates wxEVT_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
findInfo.flags = LVFI_STRING;
if ( partial )
findInfo.flags |= LVFI_PARTIAL;
- findInfo.psz = str.wx_str();
+ findInfo.psz = str.t_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
{
wxASSERT_MSG( !IsVirtual(), wxT("can't be used with virtual controls") );
+ // In 2.8 it was possible to succeed inserting an item without initializing
+ // its ID as it defaulted to 0. This was however never supported and in 2.9
+ // the ID is -1 by default and inserting it simply fails, but it might be
+ // not obvious why does it happen, so check it proactively.
+ wxASSERT_MSG( info.m_itemId != -1, wxS("Item ID must be set.") );
+
LV_ITEM item;
wxConvertToMSWListItem(this, info, item);
item.mask &= ~LVIF_PARAM;
}
// For list view mode (only), inserts a column.
-long wxListCtrl::InsertColumn(long col, const wxListItem& item)
+long wxListCtrl::DoInsertColumn(long col, const wxListItem& item)
{
LV_COLUMN lvCol;
wxConvertToMSWListCol(GetHwnd(), col, item, lvCol);
- if ( !(lvCol.mask & LVCF_WIDTH) )
+ // LVSCW_AUTOSIZE_USEHEADER is not supported when inserting new column,
+ // we'll deal with it below instead. Plain LVSCW_AUTOSIZE is not supported
+ // neither but it doesn't need any special handling as we use fixed value
+ // for it here, both because we can't do anything else (there are no items
+ // with values in this column to compute the size from yet) and for
+ // compatibility as wxLIST_AUTOSIZE == -1 and -1 as InsertColumn() width
+ // parameter used to mean "arbitrary fixed width".
+ if ( !(lvCol.mask & LVCF_WIDTH) || lvCol.cx < 0 )
{
// always give some width to the new column: this one is compatible
// with the generic version
}
long n = ListView_InsertColumn(GetHwnd(), col, &lvCol);
- if ( n != -1 )
- {
- m_colCount++;
- }
- else // failed to insert?
+ if ( n == -1 )
{
wxLogDebug(wxT("Failed to insert the column '%s' into listview!"),
lvCol.pszText);
+ return -1;
}
- return n;
-}
+ m_colCount++;
-long wxListCtrl::InsertColumn(long col,
- const wxString& heading,
- int format,
- int width)
-{
- wxListItem item;
- item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
- item.m_text = heading;
- if ( width > -1 )
+ // Now adjust the new column size.
+ if ( (item.GetMask() & wxLIST_MASK_WIDTH) &&
+ (item.GetWidth() == wxLIST_AUTOSIZE_USEHEADER) )
{
- item.m_mask |= wxLIST_MASK_WIDTH;
- item.m_width = width;
+ SetColumnWidth(n, wxLIST_AUTOSIZE_USEHEADER);
}
- item.m_format = format;
- return InsertColumn(col, item);
+ return n;
}
// scroll the control by the given number of pixels (exception: in list view,
// conjunction with modifiers
if ( msg->wParam == VK_RETURN && !wxIsAnyModifierDown() )
{
- // we need VK_RETURN to generate wxEVT_COMMAND_LIST_ITEM_ACTIVATED
+ // we need VK_RETURN to generate wxEVT_LIST_ITEM_ACTIVATED
return false;
}
}
- return wxControl::MSWShouldPreProcessMessage(msg);
+ return wxListCtrlBase::MSWShouldPreProcessMessage(msg);
}
bool wxListCtrl::MSWCommand(WXUINT cmd, WXWORD id_)
const int id = (signed short)id_;
if (cmd == EN_UPDATE)
{
- wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, id);
+ wxCommandEvent event(wxEVT_TEXT, id);
event.SetEventObject( this );
ProcessCommand(event);
return true;
// need to use HDN_ITEMCHANGING instead of it
case HDN_BEGINTRACKA:
case HDN_BEGINTRACKW:
- eventType = wxEVT_COMMAND_LIST_COL_BEGIN_DRAG;
+ eventType = wxEVT_LIST_COL_BEGIN_DRAG;
// fall through
case HDN_ITEMCHANGING:
break;
}
- eventType = wxEVT_COMMAND_LIST_COL_DRAGGING;
+ eventType = wxEVT_LIST_COL_DRAGGING;
}
// fall through
case HDN_ENDTRACKA:
case HDN_ENDTRACKW:
if ( eventType == wxEVT_NULL )
- eventType = wxEVT_COMMAND_LIST_COL_END_DRAG;
+ eventType = wxEVT_LIST_COL_END_DRAG;
event.m_item.m_width = nmHDR->pitem->cxy;
event.m_col = nmHDR->iItem;
{
POINT ptClick;
- eventType = wxEVT_COMMAND_LIST_COL_RIGHT_CLICK;
+ eventType = wxEVT_LIST_COL_RIGHT_CLICK;
event.m_col = wxMSWGetColumnClicked(nmhdr, &ptClick);
event.m_pointDrag.x = ptClick.x;
event.m_pointDrag.y = ptClick.y;
}
if ( ignore )
- return wxControl::MSWOnNotify(idCtrl, lParam, result);
+ return wxListCtrlBase::MSWOnNotify(idCtrl, lParam, result);
}
else
#endif // defined(HDN_BEGINTRACKA)
switch ( nmhdr->code )
{
case LVN_BEGINRDRAG:
- eventType = wxEVT_COMMAND_LIST_BEGIN_RDRAG;
+ eventType = wxEVT_LIST_BEGIN_RDRAG;
// fall through
case LVN_BEGINDRAG:
if ( eventType == wxEVT_NULL )
{
- eventType = wxEVT_COMMAND_LIST_BEGIN_DRAG;
+ eventType = wxEVT_LIST_BEGIN_DRAG;
}
event.m_itemIndex = iItem;
item.Init(((LV_DISPINFOW *)lParam)->item);
}
- eventType = wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT;
+ eventType = wxEVT_LIST_BEGIN_LABEL_EDIT;
wxConvertFromMSWListItem(GetHwnd(), event.m_item, item);
event.m_itemIndex = event.m_item.m_itemId;
}
event.SetEditCanceled(true);
}
- eventType = wxEVT_COMMAND_LIST_END_LABEL_EDIT;
+ eventType = wxEVT_LIST_END_LABEL_EDIT;
wxConvertFromMSWListItem(NULL, event.m_item, item);
event.m_itemIndex = event.m_item.m_itemId;
}
break;
case LVN_COLUMNCLICK:
- eventType = wxEVT_COMMAND_LIST_COL_CLICK;
+ eventType = wxEVT_LIST_COL_CLICK;
event.m_itemIndex = -1;
event.m_col = nmLV->iSubItem;
break;
case LVN_DELETEALLITEMS:
- eventType = wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS;
+ eventType = wxEVT_LIST_DELETE_ALL_ITEMS;
event.m_itemIndex = -1;
break;
return false;
}
- eventType = wxEVT_COMMAND_LIST_DELETE_ITEM;
+ eventType = wxEVT_LIST_DELETE_ITEM;
event.m_itemIndex = iItem;
break;
case LVN_INSERTITEM:
- eventType = wxEVT_COMMAND_LIST_INSERT_ITEM;
+ eventType = wxEVT_LIST_INSERT_ITEM;
event.m_itemIndex = iItem;
break;
// has the focus changed?
if ( !(stOld & LVIS_FOCUSED) && (stNew & LVIS_FOCUSED) )
{
- eventType = wxEVT_COMMAND_LIST_ITEM_FOCUSED;
+ eventType = wxEVT_LIST_ITEM_FOCUSED;
event.m_itemIndex = iItem;
}
}
eventType = stNew & LVIS_SELECTED
- ? wxEVT_COMMAND_LIST_ITEM_SELECTED
- : wxEVT_COMMAND_LIST_ITEM_DESELECTED;
+ ? wxEVT_LIST_ITEM_SELECTED
+ : wxEVT_LIST_ITEM_DESELECTED;
}
}
(wVKey == VK_RETURN || wVKey == VK_SPACE) &&
!wxIsAnyModifierDown() )
{
- eventType = wxEVT_COMMAND_LIST_ITEM_ACTIVATED;
+ eventType = wxEVT_LIST_ITEM_ACTIVATED;
}
else
{
- eventType = wxEVT_COMMAND_LIST_KEY_DOWN;
+ eventType = wxEVT_LIST_KEY_DOWN;
event.m_code = wxMSWKeyboard::VKToWX(wVKey);
case NM_DBLCLK:
// if the user processes it in wxEVT_COMMAND_LEFT_CLICK(), don't do
// anything else
- if ( wxControl::MSWOnNotify(idCtrl, lParam, result) )
+ if ( wxListCtrlBase::MSWOnNotify(idCtrl, lParam, result) )
{
return true;
}
- // else translate it into wxEVT_COMMAND_LIST_ITEM_ACTIVATED event
+ // else translate it into wxEVT_LIST_ITEM_ACTIVATED event
// if it happened on an item (and not on empty place)
if ( iItem == -1 )
{
return false;
}
- eventType = wxEVT_COMMAND_LIST_ITEM_ACTIVATED;
+ eventType = wxEVT_LIST_ITEM_ACTIVATED;
event.m_itemIndex = iItem;
event.m_item.m_text = GetItemText(iItem);
event.m_item.m_data = GetItemData(iItem);
case NM_RCLICK:
// if the user processes it in wxEVT_COMMAND_RIGHT_CLICK(),
// don't do anything else
- if ( wxControl::MSWOnNotify(idCtrl, lParam, result) )
+ if ( wxListCtrlBase::MSWOnNotify(idCtrl, lParam, result) )
{
return true;
}
- // else translate it into wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK event
+ // else translate it into wxEVT_LIST_ITEM_RIGHT_CLICK event
LV_HITTESTINFO lvhti;
wxZeroMemory(lvhti);
{
if ( lvhti.flags & LVHT_ONITEM )
{
- eventType = wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK;
+ eventType = wxEVT_LIST_ITEM_RIGHT_CLICK;
event.m_itemIndex = lvhti.iItem;
event.m_pointDrag.x = lvhti.pt.x;
event.m_pointDrag.y = lvhti.pt.y;
{
const NM_CACHEHINT *cacheHint = (NM_CACHEHINT *)lParam;
- eventType = wxEVT_COMMAND_LIST_CACHE_HINT;
+ eventType = wxEVT_LIST_CACHE_HINT;
// we get some really stupid cache hints like ones for
// items in range 0..0 for an empty control or, after
}
if ( !processed )
- return wxControl::MSWOnNotify(idCtrl, lParam, result);
+ return wxListCtrlBase::MSWOnNotify(idCtrl, lParam, result);
}
else
{
// fill in the item before passing it to the event handler if we do have a
// valid item index and haven't filled it yet (e.g. for LVN_ITEMCHANGED)
- if ( event.m_itemIndex != -1 && !event.m_item.GetMask() )
+ // and we're not using a virtual control as in this case the program
+ // already has the data anyhow and we don't want to call GetItem() for
+ // potentially many items
+ if ( event.m_itemIndex != -1 && !event.m_item.GetMask()
+ && !IsVirtual() )
{
wxListItem& item = event.m_item;
SelectInHDC selFont(hdc, hfont);
// get the rectangle to paint
- int subitem = colCount ? col + 1 : col;
RECT rc;
- wxGetListCtrlSubItemRect(hwndList, item, subitem, LVIR_BOUNDS, rc);
- rc.left += 6;
+ wxGetListCtrlSubItemRect(hwndList, item, col, LVIR_BOUNDS, rc);
+ if ( !col && colCount > 1 )
+ {
+ // ListView_GetSubItemRect() returns the entire item rect for 0th
+ // subitem while we really need just the part for this column
+ RECT rc2;
+ wxGetListCtrlSubItemRect(hwndList, item, 1, LVIR_BOUNDS, rc2);
+ rc.right = rc2.left;
+ rc.left += 4;
+ }
+ else // not first subitem
+ {
+ rc.left += 6;
+ }
// get the image and text to draw
wxChar text[512];
wxPaintDC dc(this);
- wxControl::OnPaint(event);
+ wxListCtrlBase::OnPaint(event);
// Reset the device origin since it may have been set
dc.SetDeviceOrigin(0, 0);
}
}
+void wxListCtrl::OnCharHook(wxKeyEvent& event)
+{
+ if ( GetEditControl() )
+ {
+ // We need to ensure that Escape is not stolen from the in-place editor
+ // by the containing dialog.
+ //
+ // Notice that we don't have to care about Enter key here as we return
+ // false from MSWShouldPreProcessMessage() for it.
+ if ( event.GetKeyCode() == WXK_ESCAPE )
+ {
+ EndEditLabel(true /* cancel */);
+
+ // Don't call Skip() below.
+ return;
+ }
+ }
+
+ event.Skip();
+}
+
WXLRESULT
wxListCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{
// because this message is propagated upwards the child-parent
// chain, we get it for the right clicks on the header window but
// this is confusing in wx as right clicking there already
- // generates a separate wxEVT_COMMAND_LIST_COL_RIGHT_CLICK event
+ // generates a separate wxEVT_LIST_COL_RIGHT_CLICK event
// so just ignore them
if ( (HWND)wParam == ListView_GetHeader(GetHwnd()) )
return 0;
//else: break
}
- return wxControl::MSWWindowProc(nMsg, wParam, lParam);
+ return wxListCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
}
// ----------------------------------------------------------------------------
return -1;
}
-wxListItemAttr *wxListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item)) const
-{
- wxASSERT_MSG( item >= 0 && item < GetItemCount(),
- wxT("invalid item index in OnGetItemAttr()") );
-
- // no attributes by default
- return NULL;
-}
-
wxListItemAttr *wxListCtrl::DoGetItemColumnAttr(long item, long column) const
{
if ( IsVirtual() )
else
{
// pszText is not const, hence the cast
- lvItem.pszText = (wxChar *)info.m_text.wx_str();
+ lvItem.pszText = wxMSW_CONV_LPTSTR(info.m_text);
if ( lvItem.pszText )
lvItem.cchTextMax = info.m_text.length();
else
if ( item.m_mask & wxLIST_MASK_TEXT )
{
lvCol.mask |= LVCF_TEXT;
- lvCol.pszText = (wxChar *)item.m_text.wx_str(); // cast is safe
+ lvCol.pszText = wxMSW_CONV_LPTSTR(item.m_text);
}
if ( item.m_mask & wxLIST_MASK_FORMAT )