// headers
// ----------------------------------------------------------------------------
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
- #pragma implementation "listctrl.h"
- #pragma implementation "listctrlbase.h"
-#endif
-
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#pragma hdrstop
#endif
-#if wxUSE_LISTCTRL && defined(__WIN95__)
+#if wxUSE_LISTCTRL
#ifndef WX_PRECOMP
#include "wx/app.h"
// include <commctrl.h> "properly"
#include "wx/msw/wrapcctl.h"
+// Currently gcc and watcom don't define NMLVFINDITEM, and DMC only defines
+// it by its old name NM_FINDTIEM.
+//
+#if defined(__VISUALC__) || defined(__BORLANDC__) || defined(NMLVFINDITEM)
+ #define HAVE_NMLVFINDITEM 1
+#elif defined(__DMC__) || defined(NM_FINDITEM)
+ #define HAVE_NMLVFINDITEM 1
+ #define NMLVFINDITEM NM_FINDITEM
+#endif
+
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
/* const */ LV_ITEM& lvItem);
// convert our wxListItem to LV_COLUMN
-static void wxConvertToMSWListCol(int col, const wxListItem& item,
+static void wxConvertToMSWListCol(HWND hwndList,
+ int col,
+ const wxListItem& item,
LV_COLUMN& lvCol);
// ----------------------------------------------------------------------------
}
// init with conversion
- void Init(LV_ITEM_OTHER& item)
+ void Init(const LV_ITEM_OTHER& item)
{
// avoid unnecessary dynamic memory allocation, jjust make m_pItem
// point to our own m_item
//
// Solution:
// Under MSW the only way to associate data with a List
-// item independant of its position in the list is to
+// item independent of its position in the list is to
// store a pointer to it in its lParam attribute. However
// user programs are already using this (via the
// SetItemData() GetItemData() calls).
// versions of _some_ messages (notably LVN_GETDISPINFOA) in MSLU build
wxSetCCUnicodeFormat(GetHwnd());
- // for comctl32.dll v 4.70+ we want to have this attribute because it's
- // prettier (and also because wxGTK does it like this)
- if ( InReportView() && wxTheApp->GetComCtl32Version() >= 470 )
+ // We must set the default text colour to the system/theme color, otherwise
+ // GetTextColour will always return black
+ SetTextColour(GetDefaultAttributes().colFg);
+
+ // for comctl32.dll v 4.70+ we want to have some non default extended
+ // styles because it's prettier (and also because wxGTK does it like this)
+ if ( InReportView() && wxApp::GetComCtl32Version() >= 470 )
{
::SendMessage(GetHwnd(), LVM_SETEXTENDEDLISTVIEWSTYLE,
- 0, LVS_EX_FULLROWSELECT);
+ 0, LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES);
}
return true;
#if !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) )
if ( style & wxLC_VIRTUAL )
{
- int ver = wxTheApp->GetComCtl32Version();
+ int ver = wxApp::GetComCtl32Version();
if ( ver < 470 )
{
wxLogWarning(_("Please install a newer version of comctl32.dll\n(at least version 4.70 is required but you have %d.%02d)\nor this program won't operate correctly."),
}
// Sets information about this column
-bool wxListCtrl::SetColumn(int col, wxListItem& item)
+bool wxListCtrl::SetColumn(int col, const wxListItem& item)
{
LV_COLUMN lvCol;
- wxConvertToMSWListCol(col, item, lvCol);
+ wxConvertToMSWListCol(GetHwnd(), col, item, lvCol);
return ListView_SetColumn(GetHwnd(), col, &lvCol) != 0;
}
data->lParam = info.m_data;
// attributes
- if (info.HasAttributes())
+ if ( info.HasAttributes() )
{
- if (data->attr)
- *data->attr = *info.GetAttributes();
+ const wxListItemAttr& attrNew = *info.GetAttributes();
+
+ // don't overwrite the already set attributes if we have them
+ if ( data->attr )
+ data->attr->AssignFrom(attrNew);
else
- data->attr = new wxListItemAttr(*info.GetAttributes());
+ data->attr = new wxListItemAttr(attrNew);
};
};
return col;
}
+void wxListCtrl::SetItemFont( long item, const wxFont &f )
+{
+ wxListItem info;
+ info.m_itemId = item;
+ info.SetFont( f );
+ SetItem( info );
+}
+
+wxFont wxListCtrl::GetItemFont( long item ) const
+{
+ wxFont f;
+ wxListItemInternalData *data = wxGetInternalData(this, item);
+ if ( data && data->attr )
+ f = data->attr->GetFont();
+
+ return f;
+}
+
// Gets the number of selected items in the list control
int wxListCtrl::GetSelectedItemCount() const
{
m_imageListState = imageList;
m_ownsImageListState = false;
}
- ListView_SetImageList(GetHwnd(), (HIMAGELIST) imageList ? imageList->GetHIMAGELIST() : 0, flags);
+ (void) ListView_SetImageList(GetHwnd(), (HIMAGELIST) imageList ? imageList->GetHIMAGELIST() : 0, flags);
}
void wxListCtrl::AssignImageList(wxImageList *imageList, int which)
}
// End label editing, optionally cancelling the edit
-bool wxListCtrl::EndEditLabel(bool WXUNUSED(cancel))
+bool wxListCtrl::EndEditLabel(bool cancel)
{
- wxFAIL_MSG( _T("not implemented") );
-
- return false;
+ // m_textCtrl is not always ready, ie. in EVT_LIST_BEGIN_LABEL_EDIT
+ HWND hwnd = ListView_GetEditControl(GetHwnd());
+ bool b = (hwnd != NULL);
+ if (b)
+ {
+ if (cancel)
+ ::SetWindowText(hwnd, wxEmptyString); // dubious but better than nothing
+ if (m_textCtrl)
+ {
+ m_textCtrl->UnsubclassWin();
+ m_textCtrl->SetHWND(0);
+ delete m_textCtrl;
+ m_textCtrl = NULL;
+ }
+ ::DestroyWindow(hwnd);
+ }
+ return b;
}
// Ensures this item is visible
// Inserts an item, returning the index of the new item if successful,
// -1 otherwise.
-long wxListCtrl::InsertItem(wxListItem& info)
+long wxListCtrl::InsertItem(const wxListItem& info)
{
wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual controls") );
}
// For list view mode (only), inserts a column.
-long wxListCtrl::InsertColumn(long col, wxListItem& item)
+long wxListCtrl::InsertColumn(long col, const wxListItem& item)
{
LV_COLUMN lvCol;
- wxConvertToMSWListCol(col, item, lvCol);
+ wxConvertToMSWListCol(GetHwnd(), col, item, lvCol);
if ( !(lvCol.mask & LVCF_WIDTH) )
{
return internalData->user_fn(d1, d2, internalData->data);
-};
+}
bool wxListCtrl::SortItems(wxListCtrlCompare fn, long data)
{
event.m_item.m_data = internaldata->lParam;
}
-
+ bool processed = true;
switch ( nmhdr->code )
{
case LVN_BEGINRDRAG:
}
break;
+#ifdef HAVE_NMLVFINDITEM
+ case LVN_ODFINDITEM:
+ // this message is only used with the virtual list control but
+ // even there we don't want to always use it: in a control with
+ // sufficiently big number of items (defined as > 1000 here),
+ // accidentally pressing a key could result in hanging an
+ // application waiting while it performs linear search
+ if ( IsVirtual() && GetItemCount() <= 1000 )
+ {
+ NMLVFINDITEM* pFindInfo = (NMLVFINDITEM*)lParam;
+
+ // no match by default
+ *result = -1;
+
+ // we only handle string-based searches here
+ //
+ // TODO: what about LVFI_PARTIAL, should we handle this?
+ if ( !(pFindInfo->lvfi.flags & LVFI_STRING) )
+ {
+ return false;
+ }
+
+ const wxChar * const searchstr = pFindInfo->lvfi.psz;
+ const size_t len = wxStrlen(searchstr);
+
+ // this is the first item we should examine, search from it
+ // wrapping if necessary
+ const int startPos = pFindInfo->iStart;
+ const int maxPos = GetItemCount();
+ wxCHECK_MSG( startPos <= maxPos, false,
+ _T("bad starting position in LVN_ODFINDITEM") );
+
+ int currentPos = startPos;
+ do
+ {
+ // wrap to the beginning if necessary
+ if ( currentPos == maxPos )
+ {
+ // somewhat surprizingly, LVFI_WRAP isn't set in
+ // flags but we still should wrap
+ currentPos = 0;
+ }
+
+ // does this item begin with searchstr?
+ if ( wxStrnicmp(searchstr,
+ GetItemText(currentPos), len) == 0 )
+ {
+ *result = currentPos;
+ break;
+ }
+ }
+ while ( ++currentPos != startPos );
+
+ if ( *result == -1 )
+ {
+ // not found
+ return false;
+ }
+
+ SetItemState(*result,
+ wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
+ wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
+ EnsureVisible(*result);
+ return true;
+ }
+ else
+ {
+ processed = false;
+ }
+ break;
+#endif // HAVE_NMLVFINDITEM
+
case LVN_GETDISPINFO:
if ( IsVirtual() )
{
#ifdef NM_CUSTOMDRAW
if ( lvi.mask & LVIF_IMAGE )
{
- lvi.iImage = OnGetItemImage(item);
+ lvi.iImage = OnGetItemColumnImage(item, lvi.iSubItem);
}
#endif // NM_CUSTOMDRAW
// fall through
default:
- return wxControl::MSWOnNotify(idCtrl, lParam, result);
+ processed = false;
}
+
+ if ( !processed )
+ return wxControl::MSWOnNotify(idCtrl, lParam, result);
}
else
{
case LVN_ENDLABELEDITA:
case LVN_ENDLABELEDITW:
- // logic here is inversed compared to all the other messages
+ // logic here is inverted compared to all the other messages
*result = event.IsAllowed();
// don't keep a stale wxTextCtrl around
if (GetItemRect(i, itemRect))
{
- int col;
+ // this is a fix for bug 673394: erase the pixels which we would
+ // otherwise leave on the screen
+ static const int gap = 2;
+ dc.SetPen(*wxTRANSPARENT_PEN);
+ dc.SetBrush(wxBrush(GetBackgroundColour()));
+ dc.DrawRectangle(0, firstItemRect.GetY() - gap,
+ clientSize.GetWidth(), gap);
+
+ dc.SetPen(pen);
+ dc.SetBrush(*wxTRANSPARENT_BRUSH);
int x = itemRect.GetX();
- for (col = 0; col < GetColumnCount(); col++)
+ for (int col = 0; col < GetColumnCount(); col++)
{
int colWidth = GetColumnWidth(col);
x += colWidth ;
- dc.DrawLine(x-1, firstItemRect.GetY() - 2, x-1, itemRect.GetBottom());
+ dc.DrawLine(x-1, firstItemRect.GetY() - gap,
+ x-1, itemRect.GetBottom());
}
}
}
{
wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL),
-1,
- wxT("List control has an image list, OnGetItemImage should be overridden."));
+ wxT("List control has an image list, OnGetItemImage or OnGetItemColumnImage should be overridden."));
+ return -1;
+}
+
+int wxListCtrl::OnGetItemColumnImage(long item, long column) const
+{
+ if (!column)
+ return OnGetItemImage(item);
+
return -1;
}
return NULL;
return (wxListItemInternalData *) it.lParam;
-};
+}
static
wxListItemInternalData *wxGetInternalData(const wxListCtrl *ctl, long itemId)
{
return wxGetInternalData(GetHwndOf(ctl), itemId);
-};
+}
static wxListItemAttr *wxGetInternalDataAttr(wxListCtrl *ctl, long itemId)
{
wxListItemInternalData *data = wxGetInternalData(ctl, itemId);
return data ? data->attr : NULL;
-};
+}
static void wxDeleteInternalData(wxListCtrl* ctl, long itemId)
{
// pszText is not const, hence the cast
lvItem.pszText = (wxChar *)info.m_text.c_str();
if ( lvItem.pszText )
- lvItem.cchTextMax = info.m_text.Length();
+ lvItem.cchTextMax = info.m_text.length();
else
lvItem.cchTextMax = 0;
}
lvItem.mask |= LVIF_IMAGE;
}
-static void wxConvertToMSWListCol(int WXUNUSED(col), const wxListItem& item,
+static void wxConvertToMSWListCol(HWND hwndList,
+ int col,
+ const wxListItem& item,
LV_COLUMN& lvCol)
{
wxZeroMemory(lvCol);
{
if ( wxTheApp->GetComCtl32Version() >= 470 )
{
- lvCol.mask |= LVCF_IMAGE | LVCF_FMT;
+ lvCol.mask |= LVCF_IMAGE;
- // we use LVCFMT_BITMAP_ON_RIGHT because thei mages on the right
+ // we use LVCFMT_BITMAP_ON_RIGHT because the images on the right
// seem to be generally nicer than on the left and the generic
// version only draws them on the right (we don't have a flag to
// specify the image location anyhow)
//
// we don't use LVCFMT_COL_HAS_IMAGES because it doesn't seem to
// make any difference in my tests -- but maybe we should?
- lvCol.fmt |= LVCFMT_BITMAP_ON_RIGHT | LVCFMT_IMAGE;
+ if ( item.m_image != -1 )
+ {
+ // as we're going to overwrite the format field, get its
+ // current value first -- unless we want to overwrite it anyhow
+ if ( !(lvCol.mask & LVCF_FMT) )
+ {
+ LV_COLUMN lvColOld;
+ wxZeroMemory(lvColOld);
+ lvColOld.mask = LVCF_FMT;
+ if ( ListView_GetColumn(hwndList, col, &lvColOld) )
+ {
+ lvCol.fmt = lvColOld.fmt;
+ }
+
+ lvCol.mask |= LVCF_FMT;
+ }
+
+ lvCol.fmt |= LVCFMT_BITMAP_ON_RIGHT | LVCFMT_IMAGE;
+ }
lvCol.iImage = item.m_image;
}
}
#endif // wxUSE_LISTCTRL
-