#ifdef __GNUG__
#pragma implementation "listctrl.h"
+ #pragma implementation "listctrlbase.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#pragma hdrstop
#endif
+#ifdef __WIN95__
+
#ifndef WX_PRECOMP
- #include "wx/wx.h"
+ #include "wx/app.h"
+ #include "wx/intl.h"
+ #include "wx/log.h"
+ #include "wx/settings.h"
#endif
-#ifdef __WIN95__
+#include "wx/textctrl.h"
+#include "wx/imaglist.h"
#include "wx/listctrl.h"
-#include "wx/log.h"
#include "wx/msw/private.h"
-#if defined(__GNUWIN32__) && !defined(wxUSE_NORLANDER_HEADERS)
+#ifdef __GNUWIN32_OLD__
#include "wx/msw/gnuwin32/extra.h"
#else
#include <commctrl.h>
(LVHT_ONITEMICON | LVHT_ONITEMLABEL | LVHT_ONITEMSTATEICON)
#endif
+#ifndef LVM_SETEXTENDEDLISTVIEWSTYLE
+ #define LVM_SETEXTENDEDLISTVIEWSTYLE (0x1000 + 54)
+#endif
+
+#ifndef LVS_EX_FULLROWSELECT
+ #define LVS_EX_FULLROWSELECT 0x00000020
+#endif
+
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
if ( !m_hWnd )
{
- wxLogError(wxT("Can't create list control window."));
+ wxLogError(_("Can't create list control window, check that comctl32.dll is installed."));
return FALSE;
}
// for comctl32.dll v 4.70+ we want to have this attribute because it's
// prettier (and also because wxGTK does it like this)
-#ifdef ListView_SetExtendedListViewStyle
- if ( wstyle & LVS_REPORT )
+ if ( (wstyle & LVS_REPORT) && wxTheApp->GetComCtl32Version() >= 470 )
{
- ListView_SetExtendedListViewStyle(GetHwnd(),
- LVS_EX_FULLROWSELECT);
+ ::SendMessage(GetHwnd(), LVM_SETEXTENDEDLISTVIEWSTYLE,
+ 0, LVS_EX_FULLROWSELECT);
}
-#endif // ListView_SetExtendedListViewStyle
SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
SetForegroundColour(GetParent()->GetForegroundColour());
}
}
-wxListCtrl::~wxListCtrl()
+void wxListCtrl::FreeAllAttrs(bool dontRecreate)
{
if ( m_hasAnyAttr )
{
{
delete (wxListItemAttr *)node->Data();
}
+
+ m_attrs.Destroy();
+ if ( !dontRecreate )
+ {
+ m_attrs.Create(wxKEY_INTEGER, 1000); // just as def ctor
+ }
+
+ m_hasAnyAttr = FALSE;
}
+}
+
+wxListCtrl::~wxListCtrl()
+{
+ FreeAllAttrs(TRUE /* no need to recreate hash any more */);
if ( m_textCtrl )
{
// accessors
// ----------------------------------------------------------------------------
-// Sets the background colour (GetBackgroundColour already implicit in
-// wxWindow class)
+// Sets the foreground, i.e. text, colour
+bool wxListCtrl::SetForegroundColour(const wxColour& col)
+{
+ if ( !wxWindow::SetForegroundColour(col) )
+ return FALSE;
+
+ ListView_SetTextColor(GetHwnd(), wxColourToRGB(col));
+
+ return TRUE;
+}
+
+// Sets the background colour
bool wxListCtrl::SetBackgroundColour(const wxColour& col)
{
if ( !wxWindow::SetBackgroundColour(col) )
return FALSE;
- ListView_SetBkColor(GetHwnd(), PALETTERGB(col.Red(), col.Green(), col.Blue()));
+ // we set the same colour for both the "empty" background and the items
+ // background
+ COLORREF color = wxColourToRGB(col);
+ ListView_SetBkColor(GetHwnd(), color);
+ ListView_SetTextBkColor(GetHwnd(), color);
return TRUE;
}
// visible area of the list control (list or report view)
// or the total number of items in the list control (icon
// or small icon view)
-int wxListCtrl::GetCountPerPage(void) const
+int wxListCtrl::GetCountPerPage() const
{
return ListView_GetCountPerPage(GetHwnd());
}
// Gets the edit control for editing labels.
-wxTextCtrl* wxListCtrl::GetEditControl(void) const
+wxTextCtrl* wxListCtrl::GetEditControl() const
{
return m_textCtrl;
}
}
// Gets the number of items in the list control
-int wxListCtrl::GetItemCount(void) const
+int wxListCtrl::GetItemCount() const
{
return ListView_GetItemCount(GetHwnd());
}
}
// Gets the number of selected items in the list control
-int wxListCtrl::GetSelectedItemCount(void) const
+int wxListCtrl::GetSelectedItemCount() const
{
return ListView_GetSelectedCount(GetHwnd());
}
// Gets the text colour of the listview
-wxColour wxListCtrl::GetTextColour(void) const
+wxColour wxListCtrl::GetTextColour() const
{
COLORREF ref = ListView_GetTextColor(GetHwnd());
wxColour col(GetRValue(ref), GetGValue(ref), GetBValue(ref));
// Gets the index of the topmost visible item when in
// list or report view
-long wxListCtrl::GetTopItem(void) const
+long wxListCtrl::GetTopItem() const
{
return (long) ListView_GetTopIndex(GetHwnd());
}
{
if ( ListView_DeleteColumn(GetHwnd(), 0) == 0 )
{
- wxLogLastError("ListView_DeleteColumn");
+ wxLogLastError(wxT("ListView_DeleteColumn"));
return FALSE;
}
findInfo.flags = LVFI_STRING;
if ( partial )
- findInfo.flags |= LVFI_STRING;
- findInfo.psz = WXSTRINGCAST str;
+ findInfo.flags |= LVFI_PARTIAL;
+ findInfo.psz = str;
- return ListView_FindItem(GetHwnd(), (int) start, & findInfo);
+ // 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
+ // inconsitent with the generic version - so we adjust the index
+ return ListView_FindItem(GetHwnd(), (int) start - 1, &findInfo);
}
// Find an item whose data matches this data, starting from the item after 'start'
wxListEvent event(wxEVT_NULL, m_windowId);
wxEventType eventType = wxEVT_NULL;
+
NMHDR *nmhdr = (NMHDR *)lParam;
+
+ // almost all messages use NM_LISTVIEW
+ NM_LISTVIEW *nmLV = (NM_LISTVIEW *)nmhdr;
+
+ // this is true for almost all events
+ event.m_item.m_data = nmLV->lParam;
+
switch ( nmhdr->code )
{
case LVN_BEGINRDRAG:
eventType = wxEVT_COMMAND_LIST_BEGIN_DRAG;
}
- {
- NM_LISTVIEW *hdr = (NM_LISTVIEW *)lParam;
- event.m_itemIndex = hdr->iItem;
- event.m_pointDrag.x = hdr->ptAction.x;
- event.m_pointDrag.y = hdr->ptAction.y;
- }
+ event.m_itemIndex = nmLV->iItem;
+ event.m_pointDrag.x = nmLV->ptAction.x;
+ event.m_pointDrag.y = nmLV->ptAction.y;
break;
case LVN_BEGINLABELEDIT:
eventType = wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT;
LV_DISPINFO *info = (LV_DISPINFO *)lParam;
wxConvertFromMSWListItem(this, event.m_item, info->item, GetHwnd());
- break;
}
+ break;
case LVN_COLUMNCLICK:
- {
- eventType = wxEVT_COMMAND_LIST_COL_CLICK;
- NM_LISTVIEW* hdr = (NM_LISTVIEW*)lParam;
- event.m_itemIndex = -1;
- event.m_col = hdr->iSubItem;
- break;
- }
+ eventType = wxEVT_COMMAND_LIST_COL_CLICK;
+ event.m_itemIndex = -1;
+ event.m_col = nmLV->iSubItem;
+ break;
case LVN_DELETEALLITEMS:
- // what's the sense of generating a wxWin event for this when
- // it's absolutely not portable?
-#if 0
eventType = wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS;
event.m_itemIndex = -1;
-#endif // 0
- // return TRUE to suppress all additional LVN_DELETEITEM
- // notifications - this makes deleting all items from a list ctrl
- // much faster
- *result = TRUE;
+ FreeAllAttrs();
- return TRUE;
+ break;
case LVN_DELETEITEM:
- {
- eventType = wxEVT_COMMAND_LIST_DELETE_ITEM;
- NM_LISTVIEW* hdr = (NM_LISTVIEW*)lParam;
- event.m_itemIndex = hdr->iItem;
+ eventType = wxEVT_COMMAND_LIST_DELETE_ITEM;
+ event.m_itemIndex = nmLV->iItem;
- if ( m_hasAnyAttr )
- {
- delete (wxListItemAttr *)m_attrs.Delete(hdr->iItem);
- }
+ if ( m_hasAnyAttr )
+ {
+ delete (wxListItemAttr *)m_attrs.Delete(nmLV->iItem);
}
break;
case LVN_INSERTITEM:
- {
- eventType = wxEVT_COMMAND_LIST_INSERT_ITEM;
- NM_LISTVIEW* hdr = (NM_LISTVIEW*)lParam;
- event.m_itemIndex = hdr->iItem;
- break;
- }
+ eventType = wxEVT_COMMAND_LIST_INSERT_ITEM;
+ event.m_itemIndex = nmLV->iItem;
+ break;
case LVN_ITEMCHANGED:
+ // This needs to be sent to wxListCtrl as a rather more concrete
+ // event. For now, just detect a selection or deselection.
+ if ( (nmLV->uNewState & LVIS_SELECTED) && !(nmLV->uOldState & LVIS_SELECTED) )
{
- // This needs to be sent to wxListCtrl as a rather more
- // concrete event. For now, just detect a selection
- // or deselection.
- NM_LISTVIEW* hdr = (NM_LISTVIEW*)lParam;
- if ( (hdr->uNewState & LVIS_SELECTED) && !(hdr->uOldState & LVIS_SELECTED) )
- {
- eventType = wxEVT_COMMAND_LIST_ITEM_SELECTED;
- event.m_itemIndex = hdr->iItem;
- }
- else if ( !(hdr->uNewState & LVIS_SELECTED) && (hdr->uOldState & LVIS_SELECTED) )
- {
- eventType = wxEVT_COMMAND_LIST_ITEM_DESELECTED;
- event.m_itemIndex = hdr->iItem;
- }
- else
- return FALSE;
- break;
+ eventType = wxEVT_COMMAND_LIST_ITEM_SELECTED;
+ event.m_itemIndex = nmLV->iItem;
}
+ else if ( !(nmLV->uNewState & LVIS_SELECTED) && (nmLV->uOldState & LVIS_SELECTED) )
+ {
+ eventType = wxEVT_COMMAND_LIST_ITEM_DESELECTED;
+ event.m_itemIndex = nmLV->iItem;
+ }
+ else
+ {
+ return FALSE;
+ }
+ break;
case LVN_KEYDOWN:
{
eventType = wxEVT_COMMAND_LIST_KEY_DOWN;
event.m_code = wxCharCodeMSWToWX(wVKey);
}
- break;
+
+ if ( lItem != -1 )
+ {
+ // fill the other fields too
+ event.m_item.m_text = GetItemText(lItem);
+ event.m_item.m_data = GetItemData(lItem);
+ }
}
+ break;
case NM_DBLCLK:
// if the user processes it in wxEVT_COMMAND_LEFT_CLICK(), don't do
}
// else translate it into wxEVT_COMMAND_LIST_ITEM_ACTIVATED event
+ // if it happened on an item (and not on empty place)
+ if ( nmLV->iItem == -1 )
{
- eventType = wxEVT_COMMAND_LIST_ITEM_ACTIVATED;
- NM_LISTVIEW* hdr = (NM_LISTVIEW*)lParam;
- event.m_itemIndex = hdr->iItem;
+ // not on item
+ return FALSE;
}
+
+ eventType = wxEVT_COMMAND_LIST_ITEM_ACTIVATED;
+ event.m_itemIndex = nmLV->iItem;
+ event.m_item.m_text = GetItemText(nmLV->iItem);
+ event.m_item.m_data = GetItemData(nmLV->iItem);
break;
case NM_RCLICK:
- /* TECH NOTE: NM_RCLICK isn't really good enough here. We want to
- subclass and check for the actual WM_RBUTTONDOWN message, because
- NM_RCLICK waits for the WM_RBUTTONUP message as well before firing off.
- We want to have notify events for both down -and- up. */
- {
- // if the user processes it in wxEVT_COMMAND_RIGHT_CLICK(), don't do
- // anything else
- if ( wxControl::MSWOnNotify(idCtrl, lParam, result) ) {
- return TRUE;
- }
+ /* TECH NOTE: NM_RCLICK isn't really good enough here. We want to
+ subclass and check for the actual WM_RBUTTONDOWN message,
+ because NM_RCLICK waits for the WM_RBUTTONUP message as well
+ before firing off. We want to have notify events for both down
+ -and- up. */
+ {
+ // if the user processes it in wxEVT_COMMAND_RIGHT_CLICK(),
+ // don't do anything else
+ if ( wxControl::MSWOnNotify(idCtrl, lParam, result) )
+ {
+ return TRUE;
+ }
- // else translate it into wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK event
- LV_HITTESTINFO lvhti;
- wxZeroMemory(lvhti);
+ // else translate it into wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK event
+ LV_HITTESTINFO lvhti;
+ wxZeroMemory(lvhti);
- ::GetCursorPos(&(lvhti.pt));
- ::ScreenToClient(GetHwnd(),&(lvhti.pt));
- if ( ListView_HitTest(GetHwnd(),&lvhti) != -1 )
- {
- if ( lvhti.flags & LVHT_ONITEM )
+ ::GetCursorPos(&(lvhti.pt));
+ ::ScreenToClient(GetHwnd(),&(lvhti.pt));
+ if ( ListView_HitTest(GetHwnd(),&lvhti) != -1 )
{
- eventType = wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK;
- event.m_itemIndex = lvhti.iItem;
+ if ( lvhti.flags & LVHT_ONITEM )
+ {
+ eventType = wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK;
+ event.m_itemIndex = lvhti.iItem;
+ }
}
}
- }
break;
#if 0
// post processing
// ---------------
- switch ( (int)nmhdr->code )
+ switch ( nmhdr->code )
{
+ case LVN_DELETEALLITEMS:
+ // always return TRUE to suppress all additional LVN_DELETEITEM
+ // notifications - this makes deleting all items from a list ctrl
+ // much faster
+ *result = TRUE;
+
+ return TRUE;
+
case LVN_GETDISPINFO:
{
LV_DISPINFO *info = (LV_DISPINFO *)lParam;
*result = event.IsAllowed();
return TRUE;
}
- default:
- break;
}
*result = !event.IsAllowed();