1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/listctrl.cpp 
   4 // Author:      Julian Smart 
   5 // Modified by: Agron Selimaj 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  29 #include "wx/listctrl.h" 
  32     #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly" 
  36     #include "wx/settings.h" 
  37     #include "wx/dcclient.h" 
  38     #include "wx/textctrl.h" 
  41 #include "wx/imaglist.h" 
  43 #include "wx/msw/private.h" 
  45 #if defined(__WXWINCE__) && !defined(__HANDHELDPC__) 
  53 // Currently gcc and watcom don't define NMLVFINDITEM, and DMC only defines 
  54 // it by its old name NM_FINDTIEM. 
  56 #if defined(__VISUALC__) || defined(__BORLANDC__) || defined(NMLVFINDITEM) 
  57     #define HAVE_NMLVFINDITEM 1 
  58 #elif defined(__DMC__) || defined(NM_FINDITEM) 
  59     #define HAVE_NMLVFINDITEM 1 
  60     #define NMLVFINDITEM NM_FINDITEM 
  63 // ---------------------------------------------------------------------------- 
  65 // ---------------------------------------------------------------------------- 
  67 // convert our state and mask flags to LV_ITEM constants 
  68 static void wxConvertToMSWFlags(long state
, long mask
, LV_ITEM
& lvItem
); 
  70 // convert wxListItem to LV_ITEM 
  71 static void wxConvertToMSWListItem(const wxListCtrl 
*ctrl
, 
  72                                    const wxListItem
& info
, LV_ITEM
& lvItem
); 
  74 // convert LV_ITEM to wxListItem 
  75 static void wxConvertFromMSWListItem(HWND hwndListCtrl
, 
  77                                      /* const */ LV_ITEM
& lvItem
); 
  79 // convert our wxListItem to LV_COLUMN 
  80 static void wxConvertToMSWListCol(HWND hwndList
, 
  82                                   const wxListItem
& item
, 
  85 // ---------------------------------------------------------------------------- 
  86 // private helper classes 
  87 // ---------------------------------------------------------------------------- 
  89 // We have to handle both fooW and fooA notifications in several cases 
  90 // because of broken comctl32.dll and/or unicows.dll. This class is used to 
  91 // convert LV_ITEMA and LV_ITEMW to LV_ITEM (which is either LV_ITEMA or 
  92 // LV_ITEMW depending on wxUSE_UNICODE setting), so that it can be processed 
  93 // by wxConvertToMSWListItem(). 
  95     #define LV_ITEM_NATIVE  LV_ITEMW 
  96     #define LV_ITEM_OTHER   LV_ITEMA 
  98     #define LV_CONV_TO_WX   cMB2WX 
  99     #define LV_CONV_BUF     wxMB2WXbuf 
 101     #define LV_ITEM_NATIVE  LV_ITEMA 
 102     #define LV_ITEM_OTHER   LV_ITEMW 
 104     #define LV_CONV_TO_WX   cWC2WX 
 105     #define LV_CONV_BUF     wxWC2WXbuf 
 106 #endif // Unicode/ANSI 
 111     // default ctor, use Init() later 
 112     wxLV_ITEM() { m_buf 
= NULL
; m_pItem 
= NULL
; } 
 114     // init without conversion 
 115     void Init(LV_ITEM_NATIVE
& item
) 
 117         wxASSERT_MSG( !m_pItem
, _T("Init() called twice?") ); 
 122     // init with conversion 
 123     void Init(const LV_ITEM_OTHER
& item
) 
 125         // avoid unnecessary dynamic memory allocation, jjust make m_pItem 
 126         // point to our own m_item 
 128         // memcpy() can't work if the struct sizes are different 
 129         wxCOMPILE_TIME_ASSERT( sizeof(LV_ITEM_OTHER
) == sizeof(LV_ITEM_NATIVE
), 
 130                                CodeCantWorkIfDiffSizes
); 
 132         memcpy(&m_item
, &item
, sizeof(LV_ITEM_NATIVE
)); 
 134         // convert text from ANSI to Unicod if necessary 
 135         if ( (item
.mask 
& LVIF_TEXT
) && item
.pszText 
) 
 137             m_buf 
= new LV_CONV_BUF(wxConvLocal
.LV_CONV_TO_WX(item
.pszText
)); 
 138             m_item
.pszText 
= (wxChar 
*)m_buf
->data(); 
 142     // ctor without conversion 
 143     wxLV_ITEM(LV_ITEM_NATIVE
& item
) : m_buf(NULL
), m_pItem(&item
) { } 
 145     // ctor with conversion 
 146     wxLV_ITEM(LV_ITEM_OTHER
& item
) : m_buf(NULL
) 
 151     ~wxLV_ITEM() { delete m_buf
; } 
 153     // conversion to the real LV_ITEM 
 154     operator LV_ITEM_NATIVE
&() const { return *m_pItem
; } 
 159     LV_ITEM_NATIVE 
*m_pItem
; 
 160     LV_ITEM_NATIVE m_item
; 
 162     DECLARE_NO_COPY_CLASS(wxLV_ITEM
) 
 165 /////////////////////////////////////////////////////// 
 167 // The MSW version had problems with SetTextColour() et 
 168 // al as the wxListItemAttr's were stored keyed on the 
 169 // item index. If a item was inserted anywhere but the end 
 170 // of the list the the text attributes (colour etc) for 
 171 // the following items were out of sync. 
 174 // Under MSW the only way to associate data with a List 
 175 // item independent of its position in the list is to 
 176 // store a pointer to it in its lParam attribute. However 
 177 // user programs are already using this (via the 
 178 // SetItemData() GetItemData() calls). 
 180 // However what we can do is store a pointer to a 
 181 // structure which contains the attributes we want *and* 
 182 // a lParam for the users data, e.g. 
 184 // class wxListItemInternalData 
 187 //   wxListItemAttr *attr; 
 188 //   long lParam; // user data 
 191 // To conserve memory, a wxListItemInternalData is 
 192 // only allocated for a LV_ITEM if text attributes or 
 193 // user data(lparam) are being set. 
 196 // class wxListItemInternalData 
 197 class wxListItemInternalData
 
 200    wxListItemAttr 
*attr
; 
 201    LPARAM lParam
; // user data 
 203    wxListItemInternalData() : attr(NULL
), lParam(0) {} 
 204    ~wxListItemInternalData() 
 210     DECLARE_NO_COPY_CLASS(wxListItemInternalData
) 
 213 // Get the internal data structure 
 214 static wxListItemInternalData 
*wxGetInternalData(HWND hwnd
, long itemId
); 
 215 static wxListItemInternalData 
*wxGetInternalData(const wxListCtrl 
*ctl
, long itemId
); 
 216 static wxListItemAttr 
*wxGetInternalDataAttr(const wxListCtrl 
*ctl
, long itemId
); 
 217 static void wxDeleteInternalData(wxListCtrl
* ctl
, long itemId
); 
 220 #if wxUSE_EXTENDED_RTTI 
 221 WX_DEFINE_FLAGS( wxListCtrlStyle 
) 
 223 wxBEGIN_FLAGS( wxListCtrlStyle 
) 
 224     // new style border flags, we put them first to 
 225     // use them for streaming out 
 226     wxFLAGS_MEMBER(wxBORDER_SIMPLE
) 
 227     wxFLAGS_MEMBER(wxBORDER_SUNKEN
) 
 228     wxFLAGS_MEMBER(wxBORDER_DOUBLE
) 
 229     wxFLAGS_MEMBER(wxBORDER_RAISED
) 
 230     wxFLAGS_MEMBER(wxBORDER_STATIC
) 
 231     wxFLAGS_MEMBER(wxBORDER_NONE
) 
 233     // old style border flags 
 234     wxFLAGS_MEMBER(wxSIMPLE_BORDER
) 
 235     wxFLAGS_MEMBER(wxSUNKEN_BORDER
) 
 236     wxFLAGS_MEMBER(wxDOUBLE_BORDER
) 
 237     wxFLAGS_MEMBER(wxRAISED_BORDER
) 
 238     wxFLAGS_MEMBER(wxSTATIC_BORDER
) 
 239     wxFLAGS_MEMBER(wxBORDER
) 
 241     // standard window styles 
 242     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
 243     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
 244     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
) 
 245     wxFLAGS_MEMBER(wxWANTS_CHARS
) 
 246     wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
) 
 247     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB 
) 
 248     wxFLAGS_MEMBER(wxVSCROLL
) 
 249     wxFLAGS_MEMBER(wxHSCROLL
) 
 251     wxFLAGS_MEMBER(wxLC_LIST
) 
 252     wxFLAGS_MEMBER(wxLC_REPORT
) 
 253     wxFLAGS_MEMBER(wxLC_ICON
) 
 254     wxFLAGS_MEMBER(wxLC_SMALL_ICON
) 
 255     wxFLAGS_MEMBER(wxLC_ALIGN_TOP
) 
 256     wxFLAGS_MEMBER(wxLC_ALIGN_LEFT
) 
 257     wxFLAGS_MEMBER(wxLC_AUTOARRANGE
) 
 258     wxFLAGS_MEMBER(wxLC_USER_TEXT
) 
 259     wxFLAGS_MEMBER(wxLC_EDIT_LABELS
) 
 260     wxFLAGS_MEMBER(wxLC_NO_HEADER
) 
 261     wxFLAGS_MEMBER(wxLC_SINGLE_SEL
) 
 262     wxFLAGS_MEMBER(wxLC_SORT_ASCENDING
) 
 263     wxFLAGS_MEMBER(wxLC_SORT_DESCENDING
) 
 264     wxFLAGS_MEMBER(wxLC_VIRTUAL
) 
 266 wxEND_FLAGS( wxListCtrlStyle 
) 
 268 IMPLEMENT_DYNAMIC_CLASS_XTI(wxListCtrl
, wxControl
,"wx/listctrl.h") 
 270 wxBEGIN_PROPERTIES_TABLE(wxListCtrl
) 
 271     wxEVENT_PROPERTY( TextUpdated 
, wxEVT_COMMAND_TEXT_UPDATED 
, wxCommandEvent 
) 
 273     wxPROPERTY_FLAGS( WindowStyle 
, wxListCtrlStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
 274 wxEND_PROPERTIES_TABLE() 
 276 wxBEGIN_HANDLERS_TABLE(wxListCtrl
) 
 277 wxEND_HANDLERS_TABLE() 
 279 wxCONSTRUCTOR_5( wxListCtrl 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxPoint 
, Position 
, wxSize 
, Size 
, long , WindowStyle 
) 
 282  TODO : Expose more information of a list's layout etc. via appropriate objects (a la NotebookPageInfo) 
 285 IMPLEMENT_DYNAMIC_CLASS(wxListCtrl
, wxControl
) 
 288 IMPLEMENT_DYNAMIC_CLASS(wxListView
, wxListCtrl
) 
 289 IMPLEMENT_DYNAMIC_CLASS(wxListItem
, wxObject
) 
 291 IMPLEMENT_DYNAMIC_CLASS(wxListEvent
, wxNotifyEvent
) 
 293 BEGIN_EVENT_TABLE(wxListCtrl
, wxControl
) 
 294     EVT_PAINT(wxListCtrl::OnPaint
) 
 297 // ============================================================================ 
 299 // ============================================================================ 
 301 // ---------------------------------------------------------------------------- 
 302 // wxListCtrl construction 
 303 // ---------------------------------------------------------------------------- 
 305 void wxListCtrl::Init() 
 307     m_imageListNormal 
= NULL
; 
 308     m_imageListSmall 
= NULL
; 
 309     m_imageListState 
= NULL
; 
 310     m_ownsImageListNormal 
= m_ownsImageListSmall 
= m_ownsImageListState 
= false; 
 313     m_ignoreChangeMessages 
= false; 
 315     m_AnyInternalData 
= false; 
 316     m_hasAnyAttr 
= false; 
 319 bool wxListCtrl::Create(wxWindow 
*parent
, 
 324                         const wxValidator
& validator
, 
 325                         const wxString
& name
) 
 327     if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) ) 
 330     if ( !MSWCreateControl(WC_LISTVIEW
, wxEmptyString
, pos
, size
) ) 
 333     // explicitly say that we want to use Unicode because otherwise we get ANSI 
 334     // versions of _some_ messages (notably LVN_GETDISPINFOA) in MSLU build 
 335     wxSetCCUnicodeFormat(GetHwnd()); 
 337     // We must set the default text colour to the system/theme color, otherwise 
 338     // GetTextColour will always return black 
 339     SetTextColour(GetDefaultAttributes().colFg
); 
 341     // for comctl32.dll v 4.70+ we want to have some non default extended 
 342     // styles because it's prettier (and also because wxGTK does it like this) 
 343     if ( InReportView() && wxApp::GetComCtl32Version() >= 470 ) 
 347             GetHwnd(), LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, 
 349             LVS_EX_FULLROWSELECT 
| 
 350             LVS_EX_SUBITEMIMAGES 
| 
 351             // normally this should be governed by a style as it's probably not 
 352             // always appropriate, but we don't have any free styles left and 
 353             // it seems better to enable it by default than disable 
 354             LVS_EX_HEADERDRAGDROP
 
 361 WXDWORD 
wxListCtrl::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 363     WXDWORD wstyle 
= wxControl::MSWGetStyle(style
, exstyle
); 
 365     wstyle 
|= LVS_SHAREIMAGELISTS 
| LVS_SHOWSELALWAYS
; 
 370     #define MAP_MODE_STYLE(wx, ms)                                            \ 
 371         if ( style & (wx) ) { wstyle |= (ms); nModes++; } 
 372 #else // !__WXDEBUG__ 
 373     #define MAP_MODE_STYLE(wx, ms)                                            \ 
 374         if ( style & (wx) ) wstyle |= (ms); 
 375 #endif // __WXDEBUG__ 
 377     MAP_MODE_STYLE(wxLC_ICON
, LVS_ICON
) 
 378     MAP_MODE_STYLE(wxLC_SMALL_ICON
, LVS_SMALLICON
) 
 379     MAP_MODE_STYLE(wxLC_LIST
, LVS_LIST
) 
 380     MAP_MODE_STYLE(wxLC_REPORT
, LVS_REPORT
) 
 382     wxASSERT_MSG( nModes 
== 1, 
 383                   _T("wxListCtrl style should have exactly one mode bit set") ); 
 385 #undef MAP_MODE_STYLE 
 387     if ( style 
& wxLC_ALIGN_LEFT 
) 
 388         wstyle 
|= LVS_ALIGNLEFT
; 
 390     if ( style 
& wxLC_ALIGN_TOP 
) 
 391         wstyle 
|= LVS_ALIGNTOP
; 
 393     if ( style 
& wxLC_AUTOARRANGE 
) 
 394         wstyle 
|= LVS_AUTOARRANGE
; 
 396     if ( style 
& wxLC_NO_SORT_HEADER 
) 
 397         wstyle 
|= LVS_NOSORTHEADER
; 
 399     if ( style 
& wxLC_NO_HEADER 
) 
 400         wstyle 
|= LVS_NOCOLUMNHEADER
; 
 402     if ( style 
& wxLC_EDIT_LABELS 
) 
 403         wstyle 
|= LVS_EDITLABELS
; 
 405     if ( style 
& wxLC_SINGLE_SEL 
) 
 406         wstyle 
|= LVS_SINGLESEL
; 
 408     if ( style 
& wxLC_SORT_ASCENDING 
) 
 410         wstyle 
|= LVS_SORTASCENDING
; 
 412         wxASSERT_MSG( !(style 
& wxLC_SORT_DESCENDING
), 
 413                       _T("can't sort in ascending and descending orders at once") ); 
 415     else if ( style 
& wxLC_SORT_DESCENDING 
) 
 416         wstyle 
|= LVS_SORTDESCENDING
; 
 418 #if !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) ) 
 419     if ( style 
& wxLC_VIRTUAL 
) 
 421         int ver 
= wxApp::GetComCtl32Version(); 
 424             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."), 
 425                         ver 
/ 100, ver 
% 100); 
 428         wstyle 
|= LVS_OWNERDATA
; 
 430 #endif // ancient cygwin 
 435 void wxListCtrl::UpdateStyle() 
 439         // The new window view style 
 440         DWORD dwStyleNew 
= MSWGetStyle(m_windowStyle
, NULL
); 
 442         // some styles are not returned by MSWGetStyle() 
 444             dwStyleNew 
|= WS_VISIBLE
; 
 446         // Get the current window style. 
 447         DWORD dwStyleOld 
= ::GetWindowLong(GetHwnd(), GWL_STYLE
); 
 449         // we don't have wxVSCROLL style, but the list control may have it, 
 450         // don't change it then 
 451         dwStyleNew 
|= dwStyleOld 
& (WS_HSCROLL 
| WS_VSCROLL
); 
 453         // Only set the window style if the view bits have changed. 
 454         if ( dwStyleOld 
!= dwStyleNew 
) 
 456             ::SetWindowLong(GetHwnd(), GWL_STYLE
, dwStyleNew
); 
 461 void wxListCtrl::FreeAllInternalData() 
 463     if (m_AnyInternalData
) 
 465         int n 
= GetItemCount(); 
 467         m_ignoreChangeMessages 
= true; 
 468         for (int i 
= 0; i 
< n
; i
++) 
 469             wxDeleteInternalData(this, i
); 
 470         m_ignoreChangeMessages 
= false; 
 472         m_AnyInternalData 
= false; 
 476 wxListCtrl::~wxListCtrl() 
 478     FreeAllInternalData(); 
 482         m_textCtrl
->UnsubclassWin(); 
 483         m_textCtrl
->SetHWND(0); 
 488     if (m_ownsImageListNormal
) 
 489         delete m_imageListNormal
; 
 490     if (m_ownsImageListSmall
) 
 491         delete m_imageListSmall
; 
 492     if (m_ownsImageListState
) 
 493         delete m_imageListState
; 
 496 // ---------------------------------------------------------------------------- 
 497 // set/get/change style 
 498 // ---------------------------------------------------------------------------- 
 500 // Add or remove a single window style 
 501 void wxListCtrl::SetSingleStyle(long style
, bool add
) 
 503     long flag 
= GetWindowStyleFlag(); 
 505     // Get rid of conflicting styles 
 508         if ( style 
& wxLC_MASK_TYPE
) 
 509             flag 
= flag 
& ~wxLC_MASK_TYPE
; 
 510         if ( style 
& wxLC_MASK_ALIGN 
) 
 511             flag 
= flag 
& ~wxLC_MASK_ALIGN
; 
 512         if ( style 
& wxLC_MASK_SORT 
) 
 513             flag 
= flag 
& ~wxLC_MASK_SORT
; 
 521     SetWindowStyleFlag(flag
); 
 524 // Set the whole window style 
 525 void wxListCtrl::SetWindowStyleFlag(long flag
) 
 527     if ( flag 
!= m_windowStyle 
) 
 529         m_windowStyle 
= flag
; 
 537 // ---------------------------------------------------------------------------- 
 539 // ---------------------------------------------------------------------------- 
 541 /* static */ wxVisualAttributes
 
 542 wxListCtrl::GetClassDefaultAttributes(wxWindowVariant variant
) 
 544     wxVisualAttributes attrs 
= GetCompositeControlsDefaultAttributes(variant
); 
 546     // common controls have their own default font 
 547     attrs
.font 
= wxGetCCDefaultFont(); 
 552 // Sets the foreground, i.e. text, colour 
 553 bool wxListCtrl::SetForegroundColour(const wxColour
& col
) 
 555     if ( !wxWindow::SetForegroundColour(col
) ) 
 558     ListView_SetTextColor(GetHwnd(), wxColourToRGB(col
)); 
 563 // Sets the background colour 
 564 bool wxListCtrl::SetBackgroundColour(const wxColour
& col
) 
 566     if ( !wxWindow::SetBackgroundColour(col
) ) 
 569     // we set the same colour for both the "empty" background and the items 
 571     COLORREF color 
= wxColourToRGB(col
); 
 572     ListView_SetBkColor(GetHwnd(), color
); 
 573     ListView_SetTextBkColor(GetHwnd(), color
); 
 578 // Gets information about this column 
 579 bool wxListCtrl::GetColumn(int col
, wxListItem
& item
) const 
 584     lvCol
.mask 
= LVCF_WIDTH
; 
 586     if ( item
.m_mask 
& wxLIST_MASK_TEXT 
) 
 588         lvCol
.mask 
|= LVCF_TEXT
; 
 589         lvCol
.pszText 
= new wxChar
[513]; 
 590         lvCol
.cchTextMax 
= 512; 
 593     if ( item
.m_mask 
& wxLIST_MASK_FORMAT 
) 
 595         lvCol
.mask 
|= LVCF_FMT
; 
 598     if ( item
.m_mask 
& wxLIST_MASK_IMAGE 
) 
 600         lvCol
.mask 
|= LVCF_IMAGE
; 
 603     bool success 
= ListView_GetColumn(GetHwnd(), col
, &lvCol
) != 0; 
 605     //  item.m_subItem = lvCol.iSubItem; 
 606     item
.m_width 
= lvCol
.cx
; 
 608     if ( (item
.m_mask 
& wxLIST_MASK_TEXT
) && lvCol
.pszText 
) 
 610         item
.m_text 
= lvCol
.pszText
; 
 611         delete[] lvCol
.pszText
; 
 614     if ( item
.m_mask 
& wxLIST_MASK_FORMAT 
) 
 616         switch (lvCol
.fmt 
& LVCFMT_JUSTIFYMASK
) { 
 618                 item
.m_format 
= wxLIST_FORMAT_LEFT
; 
 621                 item
.m_format 
= wxLIST_FORMAT_RIGHT
; 
 624                 item
.m_format 
= wxLIST_FORMAT_CENTRE
; 
 627                 item
.m_format 
= -1;  // Unknown? 
 632     // the column images were not supported in older versions but how to check 
 633     // for this? we can't use _WIN32_IE because we always define it to a very 
 634     // high value, so see if another symbol which is only defined starting from 
 635     // comctl32.dll 4.70 is available 
 636 #ifdef NM_CUSTOMDRAW // _WIN32_IE >= 0x0300 
 637     if ( item
.m_mask 
& wxLIST_MASK_IMAGE 
) 
 639         item
.m_image 
= lvCol
.iImage
; 
 641 #endif // LVCOLUMN::iImage exists 
 646 // Sets information about this column 
 647 bool wxListCtrl::SetColumn(int col
, const wxListItem
& item
) 
 650     wxConvertToMSWListCol(GetHwnd(), col
, item
, lvCol
); 
 652     return ListView_SetColumn(GetHwnd(), col
, &lvCol
) != 0; 
 655 // Gets the column width 
 656 int wxListCtrl::GetColumnWidth(int col
) const 
 658     return ListView_GetColumnWidth(GetHwnd(), col
); 
 661 // Sets the column width 
 662 bool wxListCtrl::SetColumnWidth(int col
, int width
) 
 664     if ( m_windowStyle 
& wxLC_LIST 
) 
 667     if ( width 
== wxLIST_AUTOSIZE
) 
 668         width 
= LVSCW_AUTOSIZE
; 
 669     else if ( width 
== wxLIST_AUTOSIZE_USEHEADER
) 
 670         width 
= LVSCW_AUTOSIZE_USEHEADER
; 
 672     return ListView_SetColumnWidth(GetHwnd(), col
, width
) != 0; 
 675 // ---------------------------------------------------------------------------- 
 677 // ---------------------------------------------------------------------------- 
 679 int wxListCtrl::GetColumnOrder(int col
) const 
 681     const int numCols 
= GetColumnCount(); 
 682     wxCHECK_MSG( col 
>= 0 && col 
< numCols
, -1, _T("Col index out of bounds") ); 
 684     wxArrayInt 
indexArray(numCols
); 
 686     if ( !ListView_GetColumnOrderArray(GetHwnd(), numCols
, &indexArray
[0]) ) 
 689     return indexArray
[col
]; 
 692 int wxListCtrl::GetColumnIndexFromOrder(int order
) const 
 694     const int numCols 
= GetColumnCount(); 
 695     wxASSERT_MSG( order 
>= 0 && order 
< numCols
, _T("Col order out of bounds") ); 
 697     wxArrayInt 
indexArray(numCols
); 
 699     if ( !ListView_GetColumnOrderArray(GetHwnd(), numCols
, &indexArray
[0]) ) 
 702     for ( int col 
= 0; col 
< numCols
; col
++ ) 
 704         if ( indexArray
[col
] == order 
) 
 708     wxFAIL_MSG( _T("no column with with given order?") ); 
 713 // Gets the column order for all columns 
 714 wxArrayInt 
wxListCtrl::GetColumnsOrder() const 
 716     const int numCols 
= GetColumnCount(); 
 718     wxArrayInt 
orders(numCols
); 
 719     if ( !ListView_GetColumnOrderArray(GetHwnd(), numCols
, &orders
[0]) ) 
 725 // Sets the column order for all columns 
 726 bool wxListCtrl::SetColumnsOrder(const wxArrayInt
& orders
) 
 728     const int numCols 
= GetColumnCount(); 
 730     wxCHECK_MSG( orders
.size() == (size_t)numCols
, false, 
 731                     _T("wrong number of elements in column orders array") ); 
 733     return ListView_SetColumnOrderArray(GetHwnd(), numCols
, &orders
[0]) != 0; 
 737 // Gets the number of items that can fit vertically in the 
 738 // visible area of the list control (list or report view) 
 739 // or the total number of items in the list control (icon 
 740 // or small icon view) 
 741 int wxListCtrl::GetCountPerPage() const 
 743     return ListView_GetCountPerPage(GetHwnd()); 
 746 // Gets the edit control for editing labels. 
 747 wxTextCtrl
* wxListCtrl::GetEditControl() const 
 752 // Gets information about the item 
 753 bool wxListCtrl::GetItem(wxListItem
& info
) const 
 756     wxZeroMemory(lvItem
); 
 758     lvItem
.iItem 
= info
.m_itemId
; 
 759     lvItem
.iSubItem 
= info
.m_col
; 
 761     if ( info
.m_mask 
& wxLIST_MASK_TEXT 
) 
 763         lvItem
.mask 
|= LVIF_TEXT
; 
 764         lvItem
.pszText 
= new wxChar
[513]; 
 765         lvItem
.cchTextMax 
= 512; 
 769         lvItem
.pszText 
= NULL
; 
 772     if (info
.m_mask 
& wxLIST_MASK_DATA
) 
 773         lvItem
.mask 
|= LVIF_PARAM
; 
 775     if (info
.m_mask 
& wxLIST_MASK_IMAGE
) 
 776         lvItem
.mask 
|= LVIF_IMAGE
; 
 778     if ( info
.m_mask 
& wxLIST_MASK_STATE 
) 
 780         lvItem
.mask 
|= LVIF_STATE
; 
 781         wxConvertToMSWFlags(0, info
.m_stateMask
, lvItem
); 
 784     bool success 
= ListView_GetItem((HWND
)GetHWND(), &lvItem
) != 0; 
 787         wxLogError(_("Couldn't retrieve information about list control item %d."), 
 792         // give NULL as hwnd as we already have everything we need 
 793         wxConvertFromMSWListItem(NULL
, info
, lvItem
); 
 797         delete[] lvItem
.pszText
; 
 802 // Sets information about the item 
 803 bool wxListCtrl::SetItem(wxListItem
& info
) 
 805     const long id 
= info
.GetId(); 
 806     wxCHECK_MSG( id 
>= 0 && id 
< GetItemCount(), false, 
 807                  _T("invalid item index in SetItem") ); 
 810     wxConvertToMSWListItem(this, info
, item
); 
 812     // we never update the lParam if it contains our pointer 
 813     // to the wxListItemInternalData structure 
 814     item
.mask 
&= ~LVIF_PARAM
; 
 816     // check if setting attributes or lParam 
 817     if (info
.HasAttributes() || (info
.m_mask  
& wxLIST_MASK_DATA
)) 
 819         // get internal item data 
 820         // perhaps a cache here ? 
 821         wxListItemInternalData 
*data 
= wxGetInternalData(this, id
); 
 826             m_AnyInternalData 
= true; 
 827             data 
= new wxListItemInternalData(); 
 828             item
.lParam 
= (LPARAM
) data
; 
 829             item
.mask 
|= LVIF_PARAM
; 
 834         if (info
.m_mask  
& wxLIST_MASK_DATA
) 
 835             data
->lParam 
= info
.m_data
; 
 838         if ( info
.HasAttributes() ) 
 840             const wxListItemAttr
& attrNew 
= *info
.GetAttributes(); 
 842             // don't overwrite the already set attributes if we have them 
 844                 data
->attr
->AssignFrom(attrNew
); 
 846                 data
->attr 
= new wxListItemAttr(attrNew
); 
 851     // we could be changing only the attribute in which case we don't need to 
 852     // call ListView_SetItem() at all 
 856         if ( !ListView_SetItem(GetHwnd(), &item
) ) 
 858             wxLogDebug(_T("ListView_SetItem() failed")); 
 864     // we need to update the item immediately to show the new image 
 865     bool updateNow 
= (info
.m_mask 
& wxLIST_MASK_IMAGE
) != 0; 
 867     // check whether it has any custom attributes 
 868     if ( info
.HasAttributes() ) 
 872         // if the colour has changed, we must redraw the item 
 878         // we need this to make the change visible right now 
 879         RefreshItem(item
.iItem
); 
 885 long wxListCtrl::SetItem(long index
, int col
, const wxString
& label
, int imageId
) 
 889     info
.m_mask 
= wxLIST_MASK_TEXT
; 
 890     info
.m_itemId 
= index
; 
 894         info
.m_image 
= imageId
; 
 895         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
 897     return SetItem(info
); 
 901 // Gets the item state 
 902 int wxListCtrl::GetItemState(long item
, long stateMask
) const 
 906     info
.m_mask 
= wxLIST_MASK_STATE
; 
 907     info
.m_stateMask 
= stateMask
; 
 908     info
.m_itemId 
= item
; 
 916 // Sets the item state 
 917 bool wxListCtrl::SetItemState(long item
, long state
, long stateMask
) 
 919     // NB: don't use SetItem() here as it doesn't work with the virtual list 
 922     wxZeroMemory(lvItem
); 
 924     wxConvertToMSWFlags(state
, stateMask
, lvItem
); 
 926     // for the virtual list controls we need to refresh the previously focused 
 927     // item manually when changing focus without changing selection 
 928     // programmatically because otherwise it keeps its focus rectangle until 
 929     // next repaint (yet another comctl32 bug) 
 932          (stateMask 
& wxLIST_STATE_FOCUSED
) && 
 933          (state 
& wxLIST_STATE_FOCUSED
) ) 
 935         focusOld 
= GetNextItem(-1, wxLIST_NEXT_ALL
, wxLIST_STATE_FOCUSED
); 
 942     if ( !::SendMessage(GetHwnd(), LVM_SETITEMSTATE
, 
 943                         (WPARAM
)item
, (LPARAM
)&lvItem
) ) 
 945         wxLogLastError(_T("ListView_SetItemState")); 
 950     if ( focusOld 
!= -1 ) 
 952         // no need to refresh the item if it was previously selected, it would 
 953         // only result in annoying flicker 
 954         if ( !(GetItemState(focusOld
, 
 955                             wxLIST_STATE_SELECTED
) & wxLIST_STATE_SELECTED
) ) 
 957             RefreshItem(focusOld
); 
 964 // Sets the item image 
 965 bool wxListCtrl::SetItemImage(long item
, int image
, int WXUNUSED(selImage
)) 
 967     return SetItemColumnImage(item
, 0, image
); 
 970 // Sets the item image 
 971 bool wxListCtrl::SetItemColumnImage(long item
, long column
, int image
) 
 975     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
 976     info
.m_image 
= image
; 
 977     info
.m_itemId 
= item
; 
 980     return SetItem(info
); 
 983 // Gets the item text 
 984 wxString 
wxListCtrl::GetItemText(long item
) const 
 988     info
.m_mask 
= wxLIST_MASK_TEXT
; 
 989     info
.m_itemId 
= item
; 
 992         return wxEmptyString
; 
 996 // Sets the item text 
 997 void wxListCtrl::SetItemText(long item
, const wxString
& str
) 
1001     info
.m_mask 
= wxLIST_MASK_TEXT
; 
1002     info
.m_itemId 
= item
; 
1008 // Gets the item data 
1009 wxUIntPtr 
wxListCtrl::GetItemData(long item
) const 
1013     info
.m_mask 
= wxLIST_MASK_DATA
; 
1014     info
.m_itemId 
= item
; 
1021 // Sets the item data 
1022 bool wxListCtrl::SetItemPtrData(long item
, wxUIntPtr data
) 
1026     info
.m_mask 
= wxLIST_MASK_DATA
; 
1027     info
.m_itemId 
= item
; 
1030     return SetItem(info
); 
1033 wxRect 
wxListCtrl::GetViewRect() const 
1035     wxASSERT_MSG( !HasFlag(wxLC_REPORT 
| wxLC_LIST
), 
1036                     _T("wxListCtrl::GetViewRect() only works in icon mode") ); 
1039     if ( !ListView_GetViewRect(GetHwnd(), &rc
) ) 
1041         wxLogDebug(_T("ListView_GetViewRect() failed.")); 
1047     wxCopyRECTToRect(rc
, rect
); 
1052 // Gets the item rectangle 
1053 bool wxListCtrl::GetItemRect(long item
, wxRect
& rect
, int code
) const 
1055     return GetSubItemRect( item
, wxLIST_GETSUBITEMRECT_WHOLEITEM
, rect
, code
) ; 
1059  * Retrieve coordinates and size of a specified subitem of a listview control. 
1060  * This function only works if the listview control is in the report mode. 
1062  * @param item : Item number 
1063  * @param subItem : Subitem or column number, use -1 for the whole row including 
1064  *                  all columns or subitems 
1065  * @param rect : A pointer to an allocated wxRect object 
1066  * @param code : Specify the part of the subitem coordinates you need. Choices are 
1067  *               wxLIST_RECT_BOUNDS, wxLIST_RECT_ICON, wxLIST_RECT_LABEL 
1069  * @return bool  : True if successful. 
1071 bool wxListCtrl::GetSubItemRect(long item
, long subItem
, wxRect
& rect
, int code
) const 
1076     if ( code 
== wxLIST_RECT_BOUNDS 
) 
1077         codeWin 
= LVIR_BOUNDS
; 
1078     else if ( code 
== wxLIST_RECT_ICON 
) 
1079         codeWin 
= LVIR_ICON
; 
1080     else if ( code 
== wxLIST_RECT_LABEL 
) 
1081         codeWin 
= LVIR_LABEL
; 
1084         wxFAIL_MSG( _T("incorrect code in GetItemRect() / GetSubItemRect()") ); 
1085         codeWin 
= LVIR_BOUNDS
; 
1089     if( subItem 
== wxLIST_GETSUBITEMRECT_WHOLEITEM
) 
1091       success 
= ListView_GetItemRect(GetHwnd(), (int) item
, &rectWin
, codeWin
) != 0; 
1093     else if( subItem 
>= 0) 
1095       success 
= ListView_GetSubItemRect( GetHwnd(), (int) item
, (int) subItem
, codeWin
, &rectWin
) != 0; 
1099       wxFAIL_MSG( _T("incorrect subItem number in GetSubItemRect()") ); 
1103     rect
.x 
= rectWin
.left
; 
1104     rect
.y 
= rectWin
.top
; 
1105     rect
.width 
= rectWin
.right 
- rectWin
.left
; 
1106     rect
.height 
= rectWin
.bottom 
- rectWin
.top
; 
1114 // Gets the item position 
1115 bool wxListCtrl::GetItemPosition(long item
, wxPoint
& pos
) const 
1119     bool success 
= (ListView_GetItemPosition(GetHwnd(), (int) item
, &pt
) != 0); 
1121     pos
.x 
= pt
.x
; pos
.y 
= pt
.y
; 
1125 // Sets the item position. 
1126 bool wxListCtrl::SetItemPosition(long item
, const wxPoint
& pos
) 
1128     return (ListView_SetItemPosition(GetHwnd(), (int) item
, pos
.x
, pos
.y
) != 0); 
1131 // Gets the number of items in the list control 
1132 int wxListCtrl::GetItemCount() const 
1137 wxSize 
wxListCtrl::GetItemSpacing() const 
1139     const int spacing 
= ListView_GetItemSpacing(GetHwnd(), (BOOL
)HasFlag(wxLC_SMALL_ICON
)); 
1141     return wxSize(LOWORD(spacing
), HIWORD(spacing
)); 
1144 #if WXWIN_COMPATIBILITY_2_6 
1146 int wxListCtrl::GetItemSpacing(bool isSmall
) const 
1148     return ListView_GetItemSpacing(GetHwnd(), (BOOL
) isSmall
); 
1151 #endif // WXWIN_COMPATIBILITY_2_6 
1153 void wxListCtrl::SetItemTextColour( long item
, const wxColour 
&col 
) 
1156     info
.m_itemId 
= item
; 
1157     info
.SetTextColour( col 
); 
1161 wxColour 
wxListCtrl::GetItemTextColour( long item 
) const 
1164     wxListItemInternalData 
*data 
= wxGetInternalData(this, item
); 
1165     if ( data 
&& data
->attr 
) 
1166         col 
= data
->attr
->GetTextColour(); 
1171 void wxListCtrl::SetItemBackgroundColour( long item
, const wxColour 
&col 
) 
1174     info
.m_itemId 
= item
; 
1175     info
.SetBackgroundColour( col 
); 
1179 wxColour 
wxListCtrl::GetItemBackgroundColour( long item 
) const 
1182     wxListItemInternalData 
*data 
= wxGetInternalData(this, item
); 
1183     if ( data 
&& data
->attr 
) 
1184         col 
= data
->attr
->GetBackgroundColour(); 
1189 void wxListCtrl::SetItemFont( long item
, const wxFont 
&f 
) 
1192     info
.m_itemId 
= item
; 
1197 wxFont 
wxListCtrl::GetItemFont( long item 
) const 
1200     wxListItemInternalData 
*data 
= wxGetInternalData(this, item
); 
1201     if ( data 
&& data
->attr 
) 
1202         f 
= data
->attr
->GetFont(); 
1207 // Gets the number of selected items in the list control 
1208 int wxListCtrl::GetSelectedItemCount() const 
1210     return ListView_GetSelectedCount(GetHwnd()); 
1213 // Gets the text colour of the listview 
1214 wxColour 
wxListCtrl::GetTextColour() const 
1216     COLORREF ref 
= ListView_GetTextColor(GetHwnd()); 
1217     wxColour 
col(GetRValue(ref
), GetGValue(ref
), GetBValue(ref
)); 
1221 // Sets the text colour of the listview 
1222 void wxListCtrl::SetTextColour(const wxColour
& col
) 
1224     ListView_SetTextColor(GetHwnd(), PALETTERGB(col
.Red(), col
.Green(), col
.Blue())); 
1227 // Gets the index of the topmost visible item when in 
1228 // list or report view 
1229 long wxListCtrl::GetTopItem() const 
1231     return (long) ListView_GetTopIndex(GetHwnd()); 
1234 // Searches for an item, starting from 'item'. 
1235 // 'geometry' is one of 
1236 // wxLIST_NEXT_ABOVE/ALL/BELOW/LEFT/RIGHT. 
1237 // 'state' is a state bit flag, one or more of 
1238 // wxLIST_STATE_DROPHILITED/FOCUSED/SELECTED/CUT. 
1239 // item can be -1 to find the first item that matches the 
1241 // Returns the item or -1 if unsuccessful. 
1242 long wxListCtrl::GetNextItem(long item
, int geom
, int state
) const 
1246     if ( geom 
== wxLIST_NEXT_ABOVE 
) 
1247         flags 
|= LVNI_ABOVE
; 
1248     if ( geom 
== wxLIST_NEXT_ALL 
) 
1250     if ( geom 
== wxLIST_NEXT_BELOW 
) 
1251         flags 
|= LVNI_BELOW
; 
1252     if ( geom 
== wxLIST_NEXT_LEFT 
) 
1253         flags 
|= LVNI_TOLEFT
; 
1254     if ( geom 
== wxLIST_NEXT_RIGHT 
) 
1255         flags 
|= LVNI_TORIGHT
; 
1257     if ( state 
& wxLIST_STATE_CUT 
) 
1259     if ( state 
& wxLIST_STATE_DROPHILITED 
) 
1260         flags 
|= LVNI_DROPHILITED
; 
1261     if ( state 
& wxLIST_STATE_FOCUSED 
) 
1262         flags 
|= LVNI_FOCUSED
; 
1263     if ( state 
& wxLIST_STATE_SELECTED 
) 
1264         flags 
|= LVNI_SELECTED
; 
1266     return (long) ListView_GetNextItem(GetHwnd(), item
, flags
); 
1270 wxImageList 
*wxListCtrl::GetImageList(int which
) const 
1272     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
1274         return m_imageListNormal
; 
1276     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
1278         return m_imageListSmall
; 
1280     else if ( which 
== wxIMAGE_LIST_STATE 
) 
1282         return m_imageListState
; 
1287 void wxListCtrl::SetImageList(wxImageList 
*imageList
, int which
) 
1290     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
1292         flags 
= LVSIL_NORMAL
; 
1293         if (m_ownsImageListNormal
) delete m_imageListNormal
; 
1294         m_imageListNormal 
= imageList
; 
1295         m_ownsImageListNormal 
= false; 
1297     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
1299         flags 
= LVSIL_SMALL
; 
1300         if (m_ownsImageListSmall
) delete m_imageListSmall
; 
1301         m_imageListSmall 
= imageList
; 
1302         m_ownsImageListSmall 
= false; 
1304     else if ( which 
== wxIMAGE_LIST_STATE 
) 
1306         flags 
= LVSIL_STATE
; 
1307         if (m_ownsImageListState
) delete m_imageListState
; 
1308         m_imageListState 
= imageList
; 
1309         m_ownsImageListState 
= false; 
1311     (void) ListView_SetImageList(GetHwnd(), (HIMAGELIST
) imageList 
? imageList
->GetHIMAGELIST() : 0, flags
); 
1314 void wxListCtrl::AssignImageList(wxImageList 
*imageList
, int which
) 
1316     SetImageList(imageList
, which
); 
1317     if ( which 
== wxIMAGE_LIST_NORMAL 
) 
1318         m_ownsImageListNormal 
= true; 
1319     else if ( which 
== wxIMAGE_LIST_SMALL 
) 
1320         m_ownsImageListSmall 
= true; 
1321     else if ( which 
== wxIMAGE_LIST_STATE 
) 
1322         m_ownsImageListState 
= true; 
1325 // ---------------------------------------------------------------------------- 
1327 // ---------------------------------------------------------------------------- 
1329 // Arranges the items 
1330 bool wxListCtrl::Arrange(int flag
) 
1333     if ( flag 
== wxLIST_ALIGN_LEFT 
) 
1334         code 
= LVA_ALIGNLEFT
; 
1335     else if ( flag 
== wxLIST_ALIGN_TOP 
) 
1336         code 
= LVA_ALIGNTOP
; 
1337     else if ( flag 
== wxLIST_ALIGN_DEFAULT 
) 
1339     else if ( flag 
== wxLIST_ALIGN_SNAP_TO_GRID 
) 
1340         code 
= LVA_SNAPTOGRID
; 
1342     return (ListView_Arrange(GetHwnd(), code
) != 0); 
1346 bool wxListCtrl::DeleteItem(long item
) 
1348     if ( !ListView_DeleteItem(GetHwnd(), (int) item
) ) 
1350         wxLogLastError(_T("ListView_DeleteItem")); 
1355     wxASSERT_MSG( m_count 
== ListView_GetItemCount(GetHwnd()), 
1356                   wxT("m_count should match ListView_GetItemCount")); 
1358     // the virtual list control doesn't refresh itself correctly, help it 
1361         // we need to refresh all the lines below the one which was deleted 
1363         if ( item 
> 0 && GetItemCount() ) 
1365             GetItemRect(item 
- 1, rectItem
); 
1370             rectItem
.height 
= 0; 
1373         wxRect rectWin 
= GetRect(); 
1374         rectWin
.height 
= rectWin
.GetBottom() - rectItem
.GetBottom(); 
1375         rectWin
.y 
= rectItem
.GetBottom(); 
1377         RefreshRect(rectWin
); 
1383 // Deletes all items 
1384 bool wxListCtrl::DeleteAllItems() 
1386     return ListView_DeleteAllItems(GetHwnd()) != 0; 
1389 // Deletes all items 
1390 bool wxListCtrl::DeleteAllColumns() 
1392     while ( m_colCount 
> 0 ) 
1394         if ( ListView_DeleteColumn(GetHwnd(), 0) == 0 ) 
1396             wxLogLastError(wxT("ListView_DeleteColumn")); 
1404     wxASSERT_MSG( m_colCount 
== 0, wxT("no columns should be left") ); 
1410 bool wxListCtrl::DeleteColumn(int col
) 
1412     bool success 
= (ListView_DeleteColumn(GetHwnd(), col
) != 0); 
1414     if ( success 
&& (m_colCount 
> 0) ) 
1419 // Clears items, and columns if there are any. 
1420 void wxListCtrl::ClearAll() 
1423     if ( m_colCount 
> 0 ) 
1427 wxTextCtrl
* wxListCtrl::EditLabel(long item
, wxClassInfo
* textControlClass
) 
1429     wxASSERT( (textControlClass
->IsKindOf(CLASSINFO(wxTextCtrl
))) ); 
1431     // ListView_EditLabel requires that the list has focus. 
1434     WXHWND hWnd 
= (WXHWND
) ListView_EditLabel(GetHwnd(), item
); 
1437         // failed to start editing 
1441     // [re]create the text control wrapping the HWND we got 
1444         m_textCtrl
->UnsubclassWin(); 
1445         m_textCtrl
->SetHWND(0); 
1449     m_textCtrl 
= (wxTextCtrl 
*)textControlClass
->CreateObject(); 
1450     m_textCtrl
->SetHWND(hWnd
); 
1451     m_textCtrl
->SubclassWin(hWnd
); 
1452     m_textCtrl
->SetParent(this); 
1454     // we must disallow TABbing away from the control while the edit contol is 
1455     // shown because this leaves it in some strange state (just try removing 
1456     // this line and then pressing TAB while editing an item in  listctrl 
1458     m_textCtrl
->SetWindowStyle(m_textCtrl
->GetWindowStyle() | wxTE_PROCESS_TAB
); 
1463 // End label editing, optionally cancelling the edit 
1464 bool wxListCtrl::EndEditLabel(bool cancel
) 
1466     // m_textCtrl is not always ready, ie. in EVT_LIST_BEGIN_LABEL_EDIT 
1467     HWND hwnd 
= ListView_GetEditControl(GetHwnd()); 
1472         ::SetWindowText(hwnd
, wxEmptyString
); // dubious but better than nothing 
1474     // we shouldn't destroy the control ourselves according to MSDN, which 
1475     // proposes WM_CANCELMODE to do this, but it doesn't seem to work 
1477     // posting WM_CLOSE to it does seem to work without any side effects 
1478     ::PostMessage(hwnd
, WM_CLOSE
, 0, 0); 
1483 // Ensures this item is visible 
1484 bool wxListCtrl::EnsureVisible(long item
) 
1486     return ListView_EnsureVisible(GetHwnd(), (int) item
, FALSE
) != FALSE
; 
1489 // Find an item whose label matches this string, starting from the item after 'start' 
1490 // or the beginning if 'start' is -1. 
1491 long wxListCtrl::FindItem(long start
, const wxString
& str
, bool partial
) 
1493     LV_FINDINFO findInfo
; 
1495     findInfo
.flags 
= LVFI_STRING
; 
1497         findInfo
.flags 
|= LVFI_PARTIAL
; 
1498     findInfo
.psz 
= str
.wx_str(); 
1500     // ListView_FindItem() excludes the first item from search and to look 
1501     // through all the items you need to start from -1 which is unnatural and 
1502     // inconsistent with the generic version - so we adjust the index 
1505     return ListView_FindItem(GetHwnd(), (int) start
, &findInfo
); 
1508 // Find an item whose data matches this data, starting from the item after 'start' 
1509 // or the beginning if 'start' is -1. 
1510 // NOTE : Lindsay Mathieson - 14-July-2002 
1511 //        No longer use ListView_FindItem as the data attribute is now stored 
1512 //        in a wxListItemInternalData structure refernced by the actual lParam 
1513 long wxListCtrl::FindItem(long start
, wxUIntPtr data
) 
1515     long  idx 
= start 
+ 1; 
1516     long count 
= GetItemCount(); 
1520         if (GetItemData(idx
) == data
) 
1528 // Find an item nearest this position in the specified direction, starting from 
1529 // the item after 'start' or the beginning if 'start' is -1. 
1530 long wxListCtrl::FindItem(long start
, const wxPoint
& pt
, int direction
) 
1532     LV_FINDINFO findInfo
; 
1534     findInfo
.flags 
= LVFI_NEARESTXY
; 
1535     findInfo
.pt
.x 
= pt
.x
; 
1536     findInfo
.pt
.y 
= pt
.y
; 
1537     findInfo
.vkDirection 
= VK_RIGHT
; 
1539     if ( direction 
== wxLIST_FIND_UP 
) 
1540         findInfo
.vkDirection 
= VK_UP
; 
1541     else if ( direction 
== wxLIST_FIND_DOWN 
) 
1542         findInfo
.vkDirection 
= VK_DOWN
; 
1543     else if ( direction 
== wxLIST_FIND_LEFT 
) 
1544         findInfo
.vkDirection 
= VK_LEFT
; 
1545     else if ( direction 
== wxLIST_FIND_RIGHT 
) 
1546         findInfo
.vkDirection 
= VK_RIGHT
; 
1548     return ListView_FindItem(GetHwnd(), (int) start
, & findInfo
); 
1551 // Determines which item (if any) is at the specified point, 
1552 // giving details in 'flags' (see wxLIST_HITTEST_... flags above) 
1554 wxListCtrl::HitTest(const wxPoint
& point
, int& flags
, long *ptrSubItem
) const 
1556     LV_HITTESTINFO hitTestInfo
; 
1557     hitTestInfo
.pt
.x 
= (int) point
.x
; 
1558     hitTestInfo
.pt
.y 
= (int) point
.y
; 
1561 #ifdef LVM_SUBITEMHITTEST 
1562     if ( ptrSubItem 
&& wxApp::GetComCtl32Version() >= 470 ) 
1564         item 
= ListView_SubItemHitTest(GetHwnd(), &hitTestInfo
); 
1565         *ptrSubItem 
= hitTestInfo
.iSubItem
; 
1568 #endif // LVM_SUBITEMHITTEST 
1570         item 
= ListView_HitTest(GetHwnd(), &hitTestInfo
); 
1575     if ( hitTestInfo
.flags 
& LVHT_ABOVE 
) 
1576         flags 
|= wxLIST_HITTEST_ABOVE
; 
1577     if ( hitTestInfo
.flags 
& LVHT_BELOW 
) 
1578         flags 
|= wxLIST_HITTEST_BELOW
; 
1579     if ( hitTestInfo
.flags 
& LVHT_TOLEFT 
) 
1580         flags 
|= wxLIST_HITTEST_TOLEFT
; 
1581     if ( hitTestInfo
.flags 
& LVHT_TORIGHT 
) 
1582         flags 
|= wxLIST_HITTEST_TORIGHT
; 
1584     if ( hitTestInfo
.flags 
& LVHT_NOWHERE 
) 
1585         flags 
|= wxLIST_HITTEST_NOWHERE
; 
1587     // note a bug or at least a very strange feature of comtl32.dll (tested 
1588     // with version 4.0 under Win95 and 6.0 under Win 2003): if you click to 
1589     // the right of the item label, ListView_HitTest() returns a combination of 
1590     // LVHT_ONITEMICON, LVHT_ONITEMLABEL and LVHT_ONITEMSTATEICON -- filter out 
1591     // the bits which don't make sense 
1592     if ( hitTestInfo
.flags 
& LVHT_ONITEMLABEL 
) 
1594         flags 
|= wxLIST_HITTEST_ONITEMLABEL
; 
1596         // do not translate LVHT_ONITEMICON here, as per above 
1600         if ( hitTestInfo
.flags 
& LVHT_ONITEMICON 
) 
1601             flags 
|= wxLIST_HITTEST_ONITEMICON
; 
1602         if ( hitTestInfo
.flags 
& LVHT_ONITEMSTATEICON 
) 
1603             flags 
|= wxLIST_HITTEST_ONITEMSTATEICON
; 
1610 // Inserts an item, returning the index of the new item if successful, 
1612 long wxListCtrl::InsertItem(const wxListItem
& info
) 
1614     wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual controls") ); 
1617     wxConvertToMSWListItem(this, info
, item
); 
1618     item
.mask 
&= ~LVIF_PARAM
; 
1620     // check wether we need to allocate our internal data 
1621     bool needInternalData 
= ((info
.m_mask 
& wxLIST_MASK_DATA
) || info
.HasAttributes()); 
1622     if (needInternalData
) 
1624         m_AnyInternalData 
= true; 
1625         item
.mask 
|= LVIF_PARAM
; 
1627         // internal stucture that manages data 
1628         wxListItemInternalData 
*data 
= new wxListItemInternalData(); 
1629         item
.lParam 
= (LPARAM
) data
; 
1631         if (info
.m_mask 
& wxLIST_MASK_DATA
) 
1632             data
->lParam 
= info
.m_data
; 
1634         // check whether it has any custom attributes 
1635         if ( info
.HasAttributes() ) 
1637             // take copy of attributes 
1638             data
->attr 
= new wxListItemAttr(*info
.GetAttributes()); 
1640             // and remember that we have some now... 
1641             m_hasAnyAttr 
= true; 
1645     long rv 
= ListView_InsertItem(GetHwnd(), & item
); 
1648     wxASSERT_MSG( m_count 
== ListView_GetItemCount(GetHwnd()), 
1649                   wxT("m_count should match ListView_GetItemCount")); 
1654 long wxListCtrl::InsertItem(long index
, const wxString
& label
) 
1657     info
.m_text 
= label
; 
1658     info
.m_mask 
= wxLIST_MASK_TEXT
; 
1659     info
.m_itemId 
= index
; 
1660     return InsertItem(info
); 
1663 // Inserts an image item 
1664 long wxListCtrl::InsertItem(long index
, int imageIndex
) 
1667     info
.m_image 
= imageIndex
; 
1668     info
.m_mask 
= wxLIST_MASK_IMAGE
; 
1669     info
.m_itemId 
= index
; 
1670     return InsertItem(info
); 
1673 // Inserts an image/string item 
1674 long wxListCtrl::InsertItem(long index
, const wxString
& label
, int imageIndex
) 
1677     info
.m_image 
= imageIndex
; 
1678     info
.m_text 
= label
; 
1679     info
.m_mask 
= wxLIST_MASK_IMAGE 
| wxLIST_MASK_TEXT
; 
1680     info
.m_itemId 
= index
; 
1681     return InsertItem(info
); 
1684 // For list view mode (only), inserts a column. 
1685 long wxListCtrl::InsertColumn(long col
, const wxListItem
& item
) 
1688     wxConvertToMSWListCol(GetHwnd(), col
, item
, lvCol
); 
1690     if ( !(lvCol
.mask 
& LVCF_WIDTH
) ) 
1692         // always give some width to the new column: this one is compatible 
1693         // with the generic version 
1694         lvCol
.mask 
|= LVCF_WIDTH
; 
1698     long n 
= ListView_InsertColumn(GetHwnd(), col
, &lvCol
); 
1703     else // failed to insert? 
1705         wxLogDebug(wxT("Failed to insert the column '%s' into listview!"), 
1712 long wxListCtrl::InsertColumn(long col
, 
1713                               const wxString
& heading
, 
1718     item
.m_mask 
= wxLIST_MASK_TEXT 
| wxLIST_MASK_FORMAT
; 
1719     item
.m_text 
= heading
; 
1722         item
.m_mask 
|= wxLIST_MASK_WIDTH
; 
1723         item
.m_width 
= width
; 
1725     item
.m_format 
= format
; 
1727     return InsertColumn(col
, item
); 
1730 // scroll the control by the given number of pixels (exception: in list view, 
1731 // dx is interpreted as number of columns) 
1732 bool wxListCtrl::ScrollList(int dx
, int dy
) 
1734     if ( !ListView_Scroll(GetHwnd(), dx
, dy
) ) 
1736         wxLogDebug(_T("ListView_Scroll(%d, %d) failed"), dx
, dy
); 
1746 // fn is a function which takes 3 long arguments: item1, item2, data. 
1747 // item1 is the long data associated with a first item (NOT the index). 
1748 // item2 is the long data associated with a second item (NOT the index). 
1749 // data is the same value as passed to SortItems. 
1750 // The return value is a negative number if the first item should precede the second 
1751 // item, a positive number of the second item should precede the first, 
1752 // or zero if the two items are equivalent. 
1754 // data is arbitrary data to be passed to the sort function. 
1756 // Internal structures for proxying the user compare function 
1757 // so that we can pass it the *real* user data 
1759 // translate lParam data and call user func 
1760 struct wxInternalDataSort
 
1762     wxListCtrlCompare user_fn
; 
1766 int CALLBACK 
wxInternalDataCompareFunc(LPARAM lParam1
, LPARAM lParam2
,  LPARAM lParamSort
) 
1768     struct wxInternalDataSort 
*internalData 
= (struct wxInternalDataSort 
*) lParamSort
; 
1770     wxListItemInternalData 
*data1 
= (wxListItemInternalData 
*) lParam1
; 
1771     wxListItemInternalData 
*data2 
= (wxListItemInternalData 
*) lParam2
; 
1773     long d1 
= (data1 
== NULL 
? 0 : data1
->lParam
); 
1774     long d2 
= (data2 
== NULL 
? 0 : data2
->lParam
); 
1776     return internalData
->user_fn(d1
, d2
, internalData
->data
); 
1780 bool wxListCtrl::SortItems(wxListCtrlCompare fn
, long data
) 
1782     struct wxInternalDataSort internalData
; 
1783     internalData
.user_fn 
= fn
; 
1784     internalData
.data 
= data
; 
1786     // WPARAM cast is needed for mingw/cygwin 
1787     if ( !ListView_SortItems(GetHwnd(), 
1788                              wxInternalDataCompareFunc
, 
1789                              (WPARAM
) &internalData
) ) 
1791         wxLogDebug(_T("ListView_SortItems() failed")); 
1801 // ---------------------------------------------------------------------------- 
1802 // message processing 
1803 // ---------------------------------------------------------------------------- 
1805 bool wxListCtrl::MSWShouldPreProcessMessage(WXMSG
* msg
) 
1807     if ( msg
->message 
== WM_KEYDOWN 
) 
1809         // Only eat VK_RETURN if not being used by the application in 
1810         // conjunction with modifiers 
1811         if ( msg
->wParam 
== VK_RETURN 
&& !wxIsAnyModifierDown() ) 
1813             // we need VK_RETURN to generate wxEVT_COMMAND_LIST_ITEM_ACTIVATED 
1817     return wxControl::MSWShouldPreProcessMessage(msg
); 
1820 bool wxListCtrl::MSWCommand(WXUINT cmd
, WXWORD id_
) 
1822     const int id 
= (signed short)id_
; 
1823     if (cmd 
== EN_UPDATE
) 
1825         wxCommandEvent 
event(wxEVT_COMMAND_TEXT_UPDATED
, id
); 
1826         event
.SetEventObject( this ); 
1827         ProcessCommand(event
); 
1830     else if (cmd 
== EN_KILLFOCUS
) 
1832         wxCommandEvent 
event(wxEVT_KILL_FOCUS
, id
); 
1833         event
.SetEventObject( this ); 
1834         ProcessCommand(event
); 
1841 // utility used by wxListCtrl::MSWOnNotify and by wxDataViewHeaderWindowMSW::MSWOnNotify 
1842 int WXDLLIMPEXP_CORE 
wxMSWGetColumnClicked(NMHDR 
*nmhdr
, POINT 
*ptClick
) 
1844     wxASSERT(nmhdr 
&& ptClick
); 
1846     // find the column clicked: we have to search for it 
1847     // ourselves as the notification message doesn't provide 
1850     // where did the click occur? 
1851 #if defined(__WXWINCE__) && !defined(__HANDHELDPC__) && _WIN32_WCE < 400 
1852     if (nmhdr
->code 
== GN_CONTEXTMENU
) 
1854         *ptClick 
= ((NMRGINFO
*)nmhdr
)->ptAction
; 
1857 #endif //__WXWINCE__ 
1858     if ( !::GetCursorPos(ptClick
) ) 
1860         wxLogLastError(_T("GetCursorPos")); 
1863     if ( !::ScreenToClient(nmhdr
->hwndFrom
, ptClick
) ) 
1865         wxLogLastError(_T("ScreenToClient(header)")); 
1868     int colCount 
= Header_GetItemCount(nmhdr
->hwndFrom
); 
1871     for ( int col 
= 0; col 
< colCount
; col
++ ) 
1873         if ( Header_GetItemRect(nmhdr
->hwndFrom
, col
, &rect
) ) 
1875             if ( ::PtInRect(&rect
, *ptClick
) ) 
1885 bool wxListCtrl::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM 
*result
) 
1888     // prepare the event 
1889     // ----------------- 
1891     wxListEvent 
event(wxEVT_NULL
, m_windowId
); 
1892     event
.SetEventObject(this); 
1894     wxEventType eventType 
= wxEVT_NULL
; 
1896     NMHDR 
*nmhdr 
= (NMHDR 
*)lParam
; 
1898     // if your compiler is as broken as this, you should really change it: this 
1899     // code is needed for normal operation! #ifdef below is only useful for 
1900     // automatic rebuilds which are done with a very old compiler version 
1901 #ifdef HDN_BEGINTRACKA 
1903     // check for messages from the header (in report view) 
1904     HWND hwndHdr 
= ListView_GetHeader(GetHwnd()); 
1906     // is it a message from the header? 
1907     if ( nmhdr
->hwndFrom 
== hwndHdr 
) 
1909         HD_NOTIFY 
*nmHDR 
= (HD_NOTIFY 
*)nmhdr
; 
1911         event
.m_itemIndex 
= -1; 
1913         switch ( nmhdr
->code 
) 
1915             // yet another comctl32.dll bug: under NT/W2K it sends Unicode 
1916             // TRACK messages even to ANSI programs: on my system I get 
1917             // HDN_BEGINTRACKW and HDN_ENDTRACKA and no HDN_TRACK at all! 
1919             // work around is to simply catch both versions and hope that it 
1920             // works (why should this message exist in ANSI and Unicode is 
1921             // beyond me as it doesn't deal with strings at all...) 
1923             // note that fr HDN_TRACK another possibility could be to use 
1924             // HDN_ITEMCHANGING but it is sent even after HDN_ENDTRACK and when 
1925             // something other than the item width changes so we'd have to 
1926             // filter out the unwanted events then 
1927             case HDN_BEGINTRACKA
: 
1928             case HDN_BEGINTRACKW
: 
1929                 eventType 
= wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
; 
1934                 if ( eventType 
== wxEVT_NULL 
) 
1935                     eventType 
= wxEVT_COMMAND_LIST_COL_DRAGGING
; 
1940                 if ( eventType 
== wxEVT_NULL 
) 
1941                     eventType 
= wxEVT_COMMAND_LIST_COL_END_DRAG
; 
1943                 event
.m_item
.m_width 
= nmHDR
->pitem
->cxy
; 
1944                 event
.m_col 
= nmHDR
->iItem
; 
1947 #if defined(__WXWINCE__) && !defined(__HANDHELDPC__) && _WIN32_WCE < 400 
1948             case GN_CONTEXTMENU
: 
1949 #endif //__WXWINCE__ 
1954                     eventType 
= wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
; 
1955                     event
.m_col 
= wxMSWGetColumnClicked(nmhdr
, &ptClick
); 
1956                     event
.m_pointDrag
.x 
= ptClick
.x
; 
1957                     event
.m_pointDrag
.y 
= ptClick
.y
; 
1961             case HDN_GETDISPINFOW
: 
1962                 // letting Windows XP handle this message results in mysterious 
1963                 // crashes in comctl32.dll seemingly because of bad message 
1966                 // I have no idea what is the real cause of the bug (which is, 
1967                 // just to make things interesting, impossible to reproduce 
1968                 // reliably) but ignoring all these messages does fix it and 
1969                 // doesn't seem to have any negative consequences 
1973                 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
); 
1977 #endif // defined(HDN_BEGINTRACKA) 
1978     if ( nmhdr
->hwndFrom 
== GetHwnd() ) 
1980         // almost all messages use NM_LISTVIEW 
1981         NM_LISTVIEW 
*nmLV 
= (NM_LISTVIEW 
*)nmhdr
; 
1983         const int iItem 
= nmLV
->iItem
; 
1986         // FreeAllInternalData will cause LVN_ITEMCHANG* messages, which can be 
1987         // ignored for efficiency.  It is done here because the internal data is in the 
1988         // process of being deleted so we don't want to try and access it below. 
1989         if ( m_ignoreChangeMessages 
&& 
1990              ( (nmLV
->hdr
.code 
== LVN_ITEMCHANGED
) || 
1991                (nmLV
->hdr
.code 
== LVN_ITEMCHANGING
)) ) 
1997         // If we have a valid item then check if there is a data value 
1998         // associated with it and put it in the event. 
1999         if ( iItem 
>= 0 && iItem 
< GetItemCount() ) 
2001             wxListItemInternalData 
*internaldata 
= 
2002                 wxGetInternalData(GetHwnd(), iItem
); 
2005                 event
.m_item
.m_data 
= internaldata
->lParam
; 
2008         bool processed 
= true; 
2009         switch ( nmhdr
->code 
) 
2011             case LVN_BEGINRDRAG
: 
2012                 eventType 
= wxEVT_COMMAND_LIST_BEGIN_RDRAG
; 
2016                 if ( eventType 
== wxEVT_NULL 
) 
2018                     eventType 
= wxEVT_COMMAND_LIST_BEGIN_DRAG
; 
2021                 event
.m_itemIndex 
= iItem
; 
2022                 event
.m_pointDrag
.x 
= nmLV
->ptAction
.x
; 
2023                 event
.m_pointDrag
.y 
= nmLV
->ptAction
.y
; 
2026             // NB: we have to handle both *A and *W versions here because some 
2027             //     versions of comctl32.dll send ANSI messages even to the 
2029             case LVN_BEGINLABELEDITA
: 
2030             case LVN_BEGINLABELEDITW
: 
2033                     if ( nmhdr
->code 
== LVN_BEGINLABELEDITA 
) 
2035                         item
.Init(((LV_DISPINFOA 
*)lParam
)->item
); 
2037                     else // LVN_BEGINLABELEDITW 
2039                         item
.Init(((LV_DISPINFOW 
*)lParam
)->item
); 
2042                     eventType 
= wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
; 
2043                     wxConvertFromMSWListItem(GetHwnd(), event
.m_item
, item
); 
2044                     event
.m_itemIndex 
= event
.m_item
.m_itemId
; 
2048             case LVN_ENDLABELEDITA
: 
2049             case LVN_ENDLABELEDITW
: 
2052                     if ( nmhdr
->code 
== LVN_ENDLABELEDITA 
) 
2054                         item
.Init(((LV_DISPINFOA 
*)lParam
)->item
); 
2056                     else // LVN_ENDLABELEDITW 
2058                         item
.Init(((LV_DISPINFOW 
*)lParam
)->item
); 
2061                     // was editing cancelled? 
2062                     const LV_ITEM
& lvi 
= (LV_ITEM
)item
; 
2063                     if ( !lvi
.pszText 
|| lvi
.iItem 
== -1 ) 
2065                         // don't keep a stale wxTextCtrl around 
2068                             // EDIT control will be deleted by the list control itself so 
2069                             // prevent us from deleting it as well 
2070                             m_textCtrl
->UnsubclassWin(); 
2071                             m_textCtrl
->SetHWND(0); 
2076                         event
.SetEditCanceled(true); 
2079                     eventType 
= wxEVT_COMMAND_LIST_END_LABEL_EDIT
; 
2080                     wxConvertFromMSWListItem(NULL
, event
.m_item
, item
); 
2081                     event
.m_itemIndex 
= event
.m_item
.m_itemId
; 
2085             case LVN_COLUMNCLICK
: 
2086                 eventType 
= wxEVT_COMMAND_LIST_COL_CLICK
; 
2087                 event
.m_itemIndex 
= -1; 
2088                 event
.m_col 
= nmLV
->iSubItem
; 
2091             case LVN_DELETEALLITEMS
: 
2092                 eventType 
= wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
; 
2093                 event
.m_itemIndex 
= -1; 
2096             case LVN_DELETEITEM
: 
2099                     // this should be prevented by the post-processing code 
2100                     // below, but "just in case" 
2104                 eventType 
= wxEVT_COMMAND_LIST_DELETE_ITEM
; 
2105                 event
.m_itemIndex 
= iItem
; 
2106                 // delete the assoicated internal data 
2107                 wxDeleteInternalData(this, iItem
); 
2110             case LVN_INSERTITEM
: 
2111                 eventType 
= wxEVT_COMMAND_LIST_INSERT_ITEM
; 
2112                 event
.m_itemIndex 
= iItem
; 
2115             case LVN_ITEMCHANGED
: 
2116                 // we translate this catch all message into more interesting 
2117                 // (and more easy to process) wxWidgets events 
2119                 // first of all, we deal with the state change events only and 
2120                 // only for valid items (item == -1 for the virtual list 
2122                 if ( nmLV
->uChanged 
& LVIF_STATE 
&& iItem 
!= -1 ) 
2124                     // temp vars for readability 
2125                     const UINT stOld 
= nmLV
->uOldState
; 
2126                     const UINT stNew 
= nmLV
->uNewState
; 
2128                     event
.m_item
.SetId(iItem
); 
2129                     event
.m_item
.SetMask(wxLIST_MASK_TEXT 
| 
2132                     GetItem(event
.m_item
); 
2134                     // has the focus changed? 
2135                     if ( !(stOld 
& LVIS_FOCUSED
) && (stNew 
& LVIS_FOCUSED
) ) 
2137                         eventType 
= wxEVT_COMMAND_LIST_ITEM_FOCUSED
; 
2138                         event
.m_itemIndex 
= iItem
; 
2141                     if ( (stNew 
& LVIS_SELECTED
) != (stOld 
& LVIS_SELECTED
) ) 
2143                         if ( eventType 
!= wxEVT_NULL 
) 
2145                             // focus and selection have both changed: send the 
2146                             // focus event from here and the selection one 
2148                             event
.SetEventType(eventType
); 
2149                             (void)HandleWindowEvent(event
); 
2151                         else // no focus event to send 
2153                             // then need to set m_itemIndex as it wasn't done 
2155                             event
.m_itemIndex 
= iItem
; 
2158                         eventType 
= stNew 
& LVIS_SELECTED
 
2159                                         ? wxEVT_COMMAND_LIST_ITEM_SELECTED
 
2160                                         : wxEVT_COMMAND_LIST_ITEM_DESELECTED
; 
2164                 if ( eventType 
== wxEVT_NULL 
) 
2166                     // not an interesting event for us 
2174                     LV_KEYDOWN 
*info 
= (LV_KEYDOWN 
*)lParam
; 
2175                     WORD wVKey 
= info
->wVKey
; 
2177                     // get the current selection 
2178                     long lItem 
= GetNextItem(-1, 
2180                                              wxLIST_STATE_SELECTED
); 
2182                     // <Enter> or <Space> activate the selected item if any (but 
2183                     // not with Shift and/or Ctrl as then they have a predefined 
2184                     // meaning for the list view) 
2186                          (wVKey 
== VK_RETURN 
|| wVKey 
== VK_SPACE
) && 
2187                          !(wxIsShiftDown() || wxIsCtrlDown()) ) 
2189                         eventType 
= wxEVT_COMMAND_LIST_ITEM_ACTIVATED
; 
2193                         eventType 
= wxEVT_COMMAND_LIST_KEY_DOWN
; 
2195                         // wxCharCodeMSWToWX() returns 0 if the key is an ASCII 
2196                         // value which should be used as is 
2197                         int code 
= wxCharCodeMSWToWX(wVKey
); 
2198                         event
.m_code 
= code 
? code 
: wVKey
; 
2202                     event
.m_item
.m_itemId 
= lItem
; 
2206                         // fill the other fields too 
2207                         event
.m_item
.m_text 
= GetItemText(lItem
); 
2208                         event
.m_item
.m_data 
= GetItemData(lItem
); 
2214                 // if the user processes it in wxEVT_COMMAND_LEFT_CLICK(), don't do 
2216                 if ( wxControl::MSWOnNotify(idCtrl
, lParam
, result
) ) 
2221                 // else translate it into wxEVT_COMMAND_LIST_ITEM_ACTIVATED event 
2222                 // if it happened on an item (and not on empty place) 
2229                 eventType 
= wxEVT_COMMAND_LIST_ITEM_ACTIVATED
; 
2230                 event
.m_itemIndex 
= iItem
; 
2231                 event
.m_item
.m_text 
= GetItemText(iItem
); 
2232                 event
.m_item
.m_data 
= GetItemData(iItem
); 
2235 #if defined(__WXWINCE__) && !defined(__HANDHELDPC__) && _WIN32_WCE < 400 
2236             case GN_CONTEXTMENU
: 
2237 #endif //__WXWINCE__ 
2239                 // if the user processes it in wxEVT_COMMAND_RIGHT_CLICK(), 
2240                 // don't do anything else 
2241                 if ( wxControl::MSWOnNotify(idCtrl
, lParam
, result
) ) 
2246                 // else translate it into wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK event 
2247                 LV_HITTESTINFO lvhti
; 
2248                 wxZeroMemory(lvhti
); 
2250 #if defined(__WXWINCE__) && !defined(__HANDHELDPC__) && _WIN32_WCE < 400 
2251               if(nmhdr
->code 
== GN_CONTEXTMENU
) { 
2252                   lvhti
.pt 
= ((NMRGINFO
*)nmhdr
)->ptAction
; 
2254 #endif //__WXWINCE__ 
2255                 ::GetCursorPos(&(lvhti
.pt
)); 
2256                 ::ScreenToClient(GetHwnd(),&(lvhti
.pt
)); 
2257                 if ( ListView_HitTest(GetHwnd(),&lvhti
) != -1 ) 
2259                     if ( lvhti
.flags 
& LVHT_ONITEM 
) 
2261                         eventType 
= wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
; 
2262                         event
.m_itemIndex 
= lvhti
.iItem
; 
2263                         event
.m_pointDrag
.x 
= lvhti
.pt
.x
; 
2264                         event
.m_pointDrag
.y 
= lvhti
.pt
.y
; 
2269 #ifdef NM_CUSTOMDRAW 
2271                 *result 
= OnCustomDraw(lParam
); 
2273                 return *result 
!= CDRF_DODEFAULT
; 
2274 #endif // _WIN32_IE >= 0x300 
2276             case LVN_ODCACHEHINT
: 
2278                     const NM_CACHEHINT 
*cacheHint 
= (NM_CACHEHINT 
*)lParam
; 
2280                     eventType 
= wxEVT_COMMAND_LIST_CACHE_HINT
; 
2282                     // we get some really stupid cache hints like ones for 
2283                     // items in range 0..0 for an empty control or, after 
2284                     // deleting an item, for items in invalid range -- filter 
2286                     if ( cacheHint
->iFrom 
> cacheHint
->iTo 
) 
2289                     event
.m_oldItemIndex 
= cacheHint
->iFrom
; 
2291                     const long iMax 
= GetItemCount(); 
2292                     event
.m_itemIndex 
= cacheHint
->iTo 
< iMax 
? cacheHint
->iTo
 
2297 #ifdef HAVE_NMLVFINDITEM 
2298             case LVN_ODFINDITEM
: 
2299                 // this message is only used with the virtual list control but 
2300                 // even there we don't want to always use it: in a control with 
2301                 // sufficiently big number of items (defined as > 1000 here), 
2302                 // accidentally pressing a key could result in hanging an 
2303                 // application waiting while it performs linear search 
2304                 if ( IsVirtual() && GetItemCount() <= 1000 ) 
2306                     NMLVFINDITEM
* pFindInfo 
= (NMLVFINDITEM
*)lParam
; 
2308                     // no match by default 
2311                     // we only handle string-based searches here 
2313                     // TODO: what about LVFI_PARTIAL, should we handle this? 
2314                     if ( !(pFindInfo
->lvfi
.flags 
& LVFI_STRING
) ) 
2319                     const wxChar 
* const searchstr 
= pFindInfo
->lvfi
.psz
; 
2320                     const size_t len 
= wxStrlen(searchstr
); 
2322                     // this is the first item we should examine, search from it 
2323                     // wrapping if necessary 
2324                     const int startPos 
= pFindInfo
->iStart
; 
2325                     const int maxPos 
= GetItemCount(); 
2326                     wxCHECK_MSG( startPos 
<= maxPos
, false, 
2327                                  _T("bad starting position in LVN_ODFINDITEM") ); 
2329                     int currentPos 
= startPos
; 
2332                         // wrap to the beginning if necessary 
2333                         if ( currentPos 
== maxPos 
) 
2335                             // somewhat surprizingly, LVFI_WRAP isn't set in 
2336                             // flags but we still should wrap 
2340                         // does this item begin with searchstr? 
2341                         if ( wxStrnicmp(searchstr
, 
2342                                             GetItemText(currentPos
), len
) == 0 ) 
2344                             *result 
= currentPos
; 
2348                     while ( ++currentPos 
!= startPos 
); 
2350                     if ( *result 
== -1 ) 
2356                     SetItemState(*result
, 
2357                                  wxLIST_STATE_SELECTED 
| wxLIST_STATE_FOCUSED
, 
2358                                  wxLIST_STATE_SELECTED 
| wxLIST_STATE_FOCUSED
); 
2359                     EnsureVisible(*result
); 
2367 #endif // HAVE_NMLVFINDITEM 
2369             case LVN_GETDISPINFO
: 
2372                     LV_DISPINFO 
*info 
= (LV_DISPINFO 
*)lParam
; 
2374                     LV_ITEM
& lvi 
= info
->item
; 
2375                     long item 
= lvi
.iItem
; 
2377                     if ( lvi
.mask 
& LVIF_TEXT 
) 
2379                         wxString text 
= OnGetItemText(item
, lvi
.iSubItem
); 
2380                         wxStrncpy(lvi
.pszText
, text
, lvi
.cchTextMax
); 
2383                     // see comment at the end of wxListCtrl::GetColumn() 
2384 #ifdef NM_CUSTOMDRAW 
2385                     if ( lvi
.mask 
& LVIF_IMAGE 
) 
2387                         lvi
.iImage 
= OnGetItemColumnImage(item
, lvi
.iSubItem
); 
2389 #endif // NM_CUSTOMDRAW 
2391                     // even though we never use LVM_SETCALLBACKMASK, we still 
2392                     // can get messages with LVIF_STATE in lvi.mask under Vista 
2393                     if ( lvi
.mask 
& LVIF_STATE 
) 
2395                         // we don't have anything to return from here... 
2408             return wxControl::MSWOnNotify(idCtrl
, lParam
, result
); 
2412         // where did this one come from? 
2416     // process the event 
2417     // ----------------- 
2419     event
.SetEventType(eventType
); 
2421     bool processed 
= HandleWindowEvent(event
); 
2425     switch ( nmhdr
->code 
) 
2427         case LVN_DELETEALLITEMS
: 
2428             // always return true to suppress all additional LVN_DELETEITEM 
2429             // notifications - this makes deleting all items from a list ctrl 
2433             // also, we may free all user data now (couldn't do it before as 
2434             // the user should have access to it in OnDeleteAllItems() handler) 
2435             FreeAllInternalData(); 
2437             // the control is empty now, synchronize the cached number of items 
2438             // with the real one 
2442         case LVN_ENDLABELEDITA
: 
2443         case LVN_ENDLABELEDITW
: 
2444             // logic here is inverted compared to all the other messages 
2445             *result 
= event
.IsAllowed(); 
2447             // don't keep a stale wxTextCtrl around 
2450                 // EDIT control will be deleted by the list control itself so 
2451                 // prevent us from deleting it as well 
2452                 m_textCtrl
->UnsubclassWin(); 
2453                 m_textCtrl
->SetHWND(0); 
2462         *result 
= !event
.IsAllowed(); 
2467 // ---------------------------------------------------------------------------- 
2468 // custom draw stuff 
2469 // ---------------------------------------------------------------------------- 
2471 // see comment at the end of wxListCtrl::GetColumn() 
2472 #ifdef NM_CUSTOMDRAW // _WIN32_IE >= 0x0300 
2474 static RECT 
GetCustomDrawnItemRect(const NMCUSTOMDRAW
& nmcd
) 
2477     ListView_GetItemRect(nmcd
.hdr
.hwndFrom
, nmcd
.dwItemSpec
, &rc
, LVIR_BOUNDS
); 
2480     ListView_GetItemRect(nmcd
.hdr
.hwndFrom
, nmcd
.dwItemSpec
, &rcIcon
, LVIR_ICON
); 
2482     // exclude the icon part, neither the selection background nor focus rect 
2484     rc
.left 
= rcIcon
.right
; 
2490 bool HandleSubItemPrepaint(LPNMLVCUSTOMDRAW pLVCD
, HFONT hfont
, int colCount
) 
2492     NMCUSTOMDRAW
& nmcd 
= pLVCD
->nmcd
; 
2495     HWND hwndList 
= nmcd
.hdr
.hwndFrom
; 
2496     const int col 
= pLVCD
->iSubItem
; 
2497     const DWORD item 
= nmcd
.dwItemSpec
; 
2499     // the font must be valid, otherwise we wouldn't be painting the item at all 
2500     SelectInHDC 
selFont(hdc
, hfont
); 
2502     // get the rectangle to paint 
2504     ListView_GetSubItemRect(hwndList
, item
, col
, LVIR_BOUNDS
, &rc
); 
2505     if ( !col 
&& colCount 
> 1 ) 
2507         // broken ListView_GetSubItemRect() returns the entire item rect for 
2508         // 0th subitem while we really need just the part for this column 
2510         ListView_GetSubItemRect(hwndList
, item
, 1, LVIR_BOUNDS
, &rc2
); 
2512         rc
.right 
= rc2
.left
; 
2515     else // not first subitem 
2520     // get the image and text to draw 
2524     it
.mask 
= LVIF_TEXT 
| LVIF_IMAGE
; 
2528     it
.cchTextMax 
= WXSIZEOF(text
); 
2529     ListView_GetItem(hwndList
, &it
); 
2531     HIMAGELIST himl 
= ListView_GetImageList(hwndList
, LVSIL_SMALL
); 
2532     if ( himl 
&& ImageList_GetImageCount(himl
) ) 
2534         if ( it
.iImage 
!= -1 ) 
2536             ImageList_Draw(himl
, it
.iImage
, hdc
, rc
.left
, rc
.top
, 
2537                            nmcd
.uItemState 
& CDIS_SELECTED 
? ILD_SELECTED
 
2541         // notice that even if this item doesn't have any image, the list 
2542         // control still leaves space for the image in the first column if the 
2543         // image list is not empty (presumably so that items with and without 
2545         if ( it
.iImage 
!= -1 || it
.iSubItem 
== 0 ) 
2548             ImageList_GetIconSize(himl
, &wImage
, &hImage
); 
2550             rc
.left 
+= wImage 
+ 2; 
2554     ::SetBkMode(hdc
, TRANSPARENT
); 
2556     UINT fmt 
= DT_SINGLELINE 
| 
2559 #endif // __WXWINCE__ 
2564     wxZeroMemory(lvCol
); 
2565     lvCol
.mask 
= LVCF_FMT
; 
2566     if ( ListView_GetColumn(hwndList
, col
, &lvCol
) ) 
2568         switch ( lvCol
.fmt 
& LVCFMT_JUSTIFYMASK 
) 
2583     //else: failed to get alignment, assume it's DT_LEFT (default) 
2585     DrawText(hdc
, text
, -1, &rc
, fmt
); 
2590 static void HandleItemPostpaint(NMCUSTOMDRAW nmcd
) 
2592     if ( nmcd
.uItemState 
& CDIS_FOCUS 
) 
2594         RECT rc 
= GetCustomDrawnItemRect(nmcd
); 
2596         // don't use the provided HDC, it's in some strange state by now 
2597         ::DrawFocusRect(WindowHDC(nmcd
.hdr
.hwndFrom
), &rc
); 
2601 // pLVCD->clrText and clrTextBk should contain the colours to use 
2602 static void HandleItemPaint(LPNMLVCUSTOMDRAW pLVCD
, HFONT hfont
) 
2604     NMCUSTOMDRAW
& nmcd 
= pLVCD
->nmcd
; // just a shortcut 
2606     const HWND hwndList 
= nmcd
.hdr
.hwndFrom
; 
2607     const int item 
= nmcd
.dwItemSpec
; 
2609     // unfortunately we can't trust CDIS_SELECTED, it is often set even when 
2610     // the item is not at all selected for some reason (comctl32 6), but we 
2611     // also can't always trust ListView_GetItem() as it could return the old 
2612     // item status if we're called just after the (de)selection, so remember 
2613     // the last item to gain selection and also check for it here 
2614     for ( int i 
= -1;; ) 
2616         i 
= ListView_GetNextItem(hwndList
, i
, LVNI_SELECTED
); 
2619             nmcd
.uItemState 
&= ~CDIS_SELECTED
; 
2625             nmcd
.uItemState 
|= CDIS_SELECTED
; 
2630     // same thing for CDIS_FOCUS (except simpler as there is only one of them) 
2631     if ( ::GetFocus() == hwndList 
&& 
2632             ListView_GetNextItem(hwndList
, (WPARAM
)-1, LVNI_FOCUSED
) == item 
) 
2634         nmcd
.uItemState 
|= CDIS_FOCUS
; 
2638         nmcd
.uItemState 
&= ~CDIS_FOCUS
; 
2641     if ( nmcd
.uItemState 
& CDIS_SELECTED 
) 
2643         int syscolFg
, syscolBg
; 
2644         if ( ::GetFocus() == hwndList 
) 
2646             syscolFg 
= COLOR_HIGHLIGHTTEXT
; 
2647             syscolBg 
= COLOR_HIGHLIGHT
; 
2649         else // selected but unfocused 
2651             syscolFg 
= COLOR_WINDOWTEXT
; 
2652             syscolBg 
= COLOR_BTNFACE
; 
2654             // don't grey out the icon in this case neither 
2655             nmcd
.uItemState 
&= ~CDIS_SELECTED
; 
2658         pLVCD
->clrText 
= ::GetSysColor(syscolFg
); 
2659         pLVCD
->clrTextBk 
= ::GetSysColor(syscolBg
); 
2661     //else: not selected, use normal colours from pLVCD 
2664     RECT rc 
= GetCustomDrawnItemRect(nmcd
); 
2666     ::SetTextColor(hdc
, pLVCD
->clrText
); 
2667     ::FillRect(hdc
, &rc
, AutoHBRUSH(pLVCD
->clrTextBk
)); 
2669     // we could use CDRF_NOTIFYSUBITEMDRAW here but it results in weird repaint 
2670     // problems so just draw everything except the focus rect from here instead 
2671     const int colCount 
= Header_GetItemCount(ListView_GetHeader(hwndList
)); 
2672     for ( int col 
= 0; col 
< colCount
; col
++ ) 
2674         pLVCD
->iSubItem 
= col
; 
2675         HandleSubItemPrepaint(pLVCD
, hfont
, colCount
); 
2678     HandleItemPostpaint(nmcd
); 
2681 static WXLPARAM 
HandleItemPrepaint(wxListCtrl 
*listctrl
, 
2682                                    LPNMLVCUSTOMDRAW pLVCD
, 
2683                                    wxListItemAttr 
*attr
) 
2687         // nothing to do for this item 
2688         return CDRF_DODEFAULT
; 
2692     // set the colours to use for text drawing 
2693     pLVCD
->clrText 
= attr
->HasTextColour() 
2694                      ? wxColourToRGB(attr
->GetTextColour()) 
2695                      : wxColourToRGB(listctrl
->GetTextColour()); 
2696     pLVCD
->clrTextBk 
= attr
->HasBackgroundColour() 
2697                        ? wxColourToRGB(attr
->GetBackgroundColour()) 
2698                        : wxColourToRGB(listctrl
->GetBackgroundColour()); 
2700     // select the font if non default one is specified 
2701     if ( attr
->HasFont() ) 
2703         wxFont font 
= attr
->GetFont(); 
2704         if ( font
.GetEncoding() != wxFONTENCODING_SYSTEM 
) 
2706             // the standard control ignores the font encoding/charset, at least 
2707             // with recent comctl32.dll versions (5 and 6, it uses to work with 
2708             // 4.something) so we have to draw the item entirely ourselves in 
2710             HandleItemPaint(pLVCD
, GetHfontOf(font
)); 
2711             return CDRF_SKIPDEFAULT
; 
2714         ::SelectObject(pLVCD
->nmcd
.hdc
, GetHfontOf(font
)); 
2716         return CDRF_NEWFONT
; 
2719     return CDRF_DODEFAULT
; 
2722 WXLPARAM 
wxListCtrl::OnCustomDraw(WXLPARAM lParam
) 
2724     LPNMLVCUSTOMDRAW pLVCD 
= (LPNMLVCUSTOMDRAW
)lParam
; 
2725     NMCUSTOMDRAW
& nmcd 
= pLVCD
->nmcd
; 
2726     switch ( nmcd
.dwDrawStage 
) 
2729             // if we've got any items with non standard attributes, 
2730             // notify us before painting each item 
2732             // for virtual controls, always suppose that we have attributes as 
2733             // there is no way to check for this 
2734             if ( IsVirtual() || m_hasAnyAttr 
) 
2735                 return CDRF_NOTIFYITEMDRAW
; 
2738         case CDDS_ITEMPREPAINT
: 
2739             const int item 
= nmcd
.dwItemSpec
; 
2741             // we get this message with item == 0 for an empty control, we 
2742             // must ignore it as calling OnGetItemAttr() would be wrong 
2743             if ( item 
< 0 || item 
>= GetItemCount() ) 
2746             return HandleItemPrepaint(this, pLVCD
, DoGetItemAttr(item
)); 
2749     return CDRF_DODEFAULT
; 
2752 #endif // NM_CUSTOMDRAW supported 
2754 // Necessary for drawing hrules and vrules, if specified 
2755 void wxListCtrl::OnPaint(wxPaintEvent
& event
) 
2757     bool drawHRules 
= HasFlag(wxLC_HRULES
); 
2758     bool drawVRules 
= HasFlag(wxLC_VRULES
); 
2760     if (!InReportView() || !drawHRules 
&& !drawVRules
) 
2768     wxControl::OnPaint(event
); 
2770     // Reset the device origin since it may have been set 
2771     dc
.SetDeviceOrigin(0, 0); 
2773     wxPen 
pen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
); 
2775     dc
.SetBrush(* wxTRANSPARENT_BRUSH
); 
2777     wxSize clientSize 
= GetClientSize(); 
2780     int itemCount 
= GetItemCount(); 
2784         long top 
= GetTopItem(); 
2785         for (i 
= top
; i 
< top 
+ GetCountPerPage() + 1; i
++) 
2787             if (GetItemRect(i
, itemRect
)) 
2789                 int cy 
= itemRect
.GetTop(); 
2790                 if (i 
!= 0) // Don't draw the first one 
2792                     dc
.DrawLine(0, cy
, clientSize
.x
, cy
); 
2795                 if (i 
== itemCount 
- 1) 
2797                     cy 
= itemRect
.GetBottom(); 
2798                     dc
.DrawLine(0, cy
, clientSize
.x
, cy
); 
2804     if (drawVRules 
&& (i 
> -1)) 
2806         wxRect firstItemRect
; 
2807         GetItemRect(0, firstItemRect
); 
2809         if (GetItemRect(i
, itemRect
)) 
2811             // this is a fix for bug 673394: erase the pixels which we would 
2812             // otherwise leave on the screen 
2813             static const int gap 
= 2; 
2814             dc
.SetPen(*wxTRANSPARENT_PEN
); 
2815             dc
.SetBrush(wxBrush(GetBackgroundColour())); 
2816             dc
.DrawRectangle(0, firstItemRect
.GetY() - gap
, 
2817                              clientSize
.GetWidth(), gap
); 
2820             dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
2822             int numCols 
= GetColumnCount(); 
2823             int* indexArray 
= new int[numCols
]; 
2824             if ( !ListView_GetColumnOrderArray( GetHwnd(), numCols
, indexArray
) ) 
2826                 wxFAIL_MSG( _T("invalid column index array in OnPaint()") ); 
2829             int x 
= itemRect
.GetX(); 
2830             for (int col 
= 0; col 
< numCols
; col
++) 
2832                 int colWidth 
= GetColumnWidth(indexArray
[col
]); 
2834                 dc
.DrawLine(x
-1, firstItemRect
.GetY() - gap
, 
2835                             x
-1, itemRect
.GetBottom()); 
2844 wxListCtrl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
2850             // we should bypass our own WM_PRINT handling as we don't handle 
2851             // PRF_CHILDREN flag, so leave it to the native control itself 
2852             return MSWDefWindowProc(nMsg
, wParam
, lParam
); 
2855         case WM_CONTEXTMENU
: 
2856             // because this message is propagated upwards the child-parent 
2857             // chain, we get it for the right clicks on the header window but 
2858             // this is confusing in wx as right clicking there already 
2859             // generates a separate wxEVT_COMMAND_LIST_COL_RIGHT_CLICK event 
2860             // so just ignore them 
2861             if ( (HWND
)wParam 
== ListView_GetHeader(GetHwnd()) ) 
2866     return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
); 
2869 // ---------------------------------------------------------------------------- 
2870 // virtual list controls 
2871 // ---------------------------------------------------------------------------- 
2873 wxString 
wxListCtrl::OnGetItemText(long WXUNUSED(item
), long WXUNUSED(col
)) const 
2875     // this is a pure virtual function, in fact - which is not really pure 
2876     // because the controls which are not virtual don't need to implement it 
2877     wxFAIL_MSG( _T("wxListCtrl::OnGetItemText not supposed to be called") ); 
2879     return wxEmptyString
; 
2882 int wxListCtrl::OnGetItemImage(long WXUNUSED(item
)) const 
2884     wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL
), 
2886                 wxT("List control has an image list, OnGetItemImage or OnGetItemColumnImage should be overridden.")); 
2890 int wxListCtrl::OnGetItemColumnImage(long item
, long column
) const 
2893         return OnGetItemImage(item
); 
2898 wxListItemAttr 
*wxListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item
)) const 
2900     wxASSERT_MSG( item 
>= 0 && item 
< GetItemCount(), 
2901                   _T("invalid item index in OnGetItemAttr()") ); 
2903     // no attributes by default 
2907 wxListItemAttr 
*wxListCtrl::DoGetItemAttr(long item
) const 
2909     return IsVirtual() ? OnGetItemAttr(item
) 
2910                        : wxGetInternalDataAttr(this, item
); 
2913 void wxListCtrl::SetItemCount(long count
) 
2915     wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") ); 
2917     if ( !::SendMessage(GetHwnd(), LVM_SETITEMCOUNT
, (WPARAM
)count
, 
2918                         LVSICF_NOSCROLL 
| LVSICF_NOINVALIDATEALL
) ) 
2920         wxLogLastError(_T("ListView_SetItemCount")); 
2923     wxASSERT_MSG( m_count 
== ListView_GetItemCount(GetHwnd()), 
2924                   wxT("m_count should match ListView_GetItemCount")); 
2927 void wxListCtrl::RefreshItem(long item
) 
2929     RefreshItems(item
, item
); 
2932 void wxListCtrl::RefreshItems(long itemFrom
, long itemTo
) 
2934     ListView_RedrawItems(GetHwnd(), itemFrom
, itemTo
); 
2937 // ---------------------------------------------------------------------------- 
2938 // internal data stuff 
2939 // ---------------------------------------------------------------------------- 
2941 static wxListItemInternalData 
*wxGetInternalData(HWND hwnd
, long itemId
) 
2944     it
.mask 
= LVIF_PARAM
; 
2947     if ( !ListView_GetItem(hwnd
, &it
) ) 
2950     return (wxListItemInternalData 
*) it
.lParam
; 
2954 wxListItemInternalData 
*wxGetInternalData(const wxListCtrl 
*ctl
, long itemId
) 
2956     return wxGetInternalData(GetHwndOf(ctl
), itemId
); 
2960 wxListItemAttr 
*wxGetInternalDataAttr(const wxListCtrl 
*ctl
, long itemId
) 
2962     wxListItemInternalData 
*data 
= wxGetInternalData(ctl
, itemId
); 
2964     return data 
? data
->attr 
: NULL
; 
2967 static void wxDeleteInternalData(wxListCtrl
* ctl
, long itemId
) 
2969     wxListItemInternalData 
*data 
= wxGetInternalData(ctl
, itemId
); 
2973         memset(&item
, 0, sizeof(item
)); 
2974         item
.iItem 
= itemId
; 
2975         item
.mask 
= LVIF_PARAM
; 
2976         item
.lParam 
= (LPARAM
) 0; 
2977         ListView_SetItem((HWND
)ctl
->GetHWND(), &item
); 
2982 // ---------------------------------------------------------------------------- 
2983 // wxWin <-> MSW items conversions 
2984 // ---------------------------------------------------------------------------- 
2986 static void wxConvertFromMSWListItem(HWND hwndListCtrl
, 
2990     wxListItemInternalData 
*internaldata 
= 
2991         (wxListItemInternalData 
*) lvItem
.lParam
; 
2994         info
.m_data 
= internaldata
->lParam
; 
2998     info
.m_stateMask 
= 0; 
2999     info
.m_itemId 
= lvItem
.iItem
; 
3001     long oldMask 
= lvItem
.mask
; 
3003     bool needText 
= false; 
3004     if (hwndListCtrl 
!= 0) 
3006         if ( lvItem
.mask 
& LVIF_TEXT 
) 
3013             lvItem
.pszText 
= new wxChar
[513]; 
3014             lvItem
.cchTextMax 
= 512; 
3016         lvItem
.mask 
|= LVIF_TEXT 
| LVIF_IMAGE 
| LVIF_PARAM
; 
3017         ::SendMessage(hwndListCtrl
, LVM_GETITEM
, 0, (LPARAM
)& lvItem
); 
3020     if ( lvItem
.mask 
& LVIF_STATE 
) 
3022         info
.m_mask 
|= wxLIST_MASK_STATE
; 
3024         if ( lvItem
.stateMask 
& LVIS_CUT
) 
3026             info
.m_stateMask 
|= wxLIST_STATE_CUT
; 
3027             if ( lvItem
.state 
& LVIS_CUT 
) 
3028                 info
.m_state 
|= wxLIST_STATE_CUT
; 
3030         if ( lvItem
.stateMask 
& LVIS_DROPHILITED
) 
3032             info
.m_stateMask 
|= wxLIST_STATE_DROPHILITED
; 
3033             if ( lvItem
.state 
& LVIS_DROPHILITED 
) 
3034                 info
.m_state 
|= wxLIST_STATE_DROPHILITED
; 
3036         if ( lvItem
.stateMask 
& LVIS_FOCUSED
) 
3038             info
.m_stateMask 
|= wxLIST_STATE_FOCUSED
; 
3039             if ( lvItem
.state 
& LVIS_FOCUSED 
) 
3040                 info
.m_state 
|= wxLIST_STATE_FOCUSED
; 
3042         if ( lvItem
.stateMask 
& LVIS_SELECTED
) 
3044             info
.m_stateMask 
|= wxLIST_STATE_SELECTED
; 
3045             if ( lvItem
.state 
& LVIS_SELECTED 
) 
3046                 info
.m_state 
|= wxLIST_STATE_SELECTED
; 
3050     if ( lvItem
.mask 
& LVIF_TEXT 
) 
3052         info
.m_mask 
|= wxLIST_MASK_TEXT
; 
3053         info
.m_text 
= lvItem
.pszText
; 
3055     if ( lvItem
.mask 
& LVIF_IMAGE 
) 
3057         info
.m_mask 
|= wxLIST_MASK_IMAGE
; 
3058         info
.m_image 
= lvItem
.iImage
; 
3060     if ( lvItem
.mask 
& LVIF_PARAM 
) 
3061         info
.m_mask 
|= wxLIST_MASK_DATA
; 
3062     if ( lvItem
.mask 
& LVIF_DI_SETITEM 
) 
3063         info
.m_mask 
|= wxLIST_SET_ITEM
; 
3064     info
.m_col 
= lvItem
.iSubItem
; 
3069             delete[] lvItem
.pszText
; 
3071     lvItem
.mask 
= oldMask
; 
3074 static void wxConvertToMSWFlags(long state
, long stateMask
, LV_ITEM
& lvItem
) 
3076     if (stateMask 
& wxLIST_STATE_CUT
) 
3078         lvItem
.stateMask 
|= LVIS_CUT
; 
3079         if (state 
& wxLIST_STATE_CUT
) 
3080             lvItem
.state 
|= LVIS_CUT
; 
3082     if (stateMask 
& wxLIST_STATE_DROPHILITED
) 
3084         lvItem
.stateMask 
|= LVIS_DROPHILITED
; 
3085         if (state 
& wxLIST_STATE_DROPHILITED
) 
3086             lvItem
.state 
|= LVIS_DROPHILITED
; 
3088     if (stateMask 
& wxLIST_STATE_FOCUSED
) 
3090         lvItem
.stateMask 
|= LVIS_FOCUSED
; 
3091         if (state 
& wxLIST_STATE_FOCUSED
) 
3092             lvItem
.state 
|= LVIS_FOCUSED
; 
3094     if (stateMask 
& wxLIST_STATE_SELECTED
) 
3096         lvItem
.stateMask 
|= LVIS_SELECTED
; 
3097         if (state 
& wxLIST_STATE_SELECTED
) 
3098             lvItem
.state 
|= LVIS_SELECTED
; 
3102 static void wxConvertToMSWListItem(const wxListCtrl 
*ctrl
, 
3103                                    const wxListItem
& info
, 
3106     lvItem
.iItem 
= (int) info
.m_itemId
; 
3108     lvItem
.iImage 
= info
.m_image
; 
3109     lvItem
.stateMask 
= 0; 
3112     lvItem
.iSubItem 
= info
.m_col
; 
3114     if (info
.m_mask 
& wxLIST_MASK_STATE
) 
3116         lvItem
.mask 
|= LVIF_STATE
; 
3118         wxConvertToMSWFlags(info
.m_state
, info
.m_stateMask
, lvItem
); 
3121     if (info
.m_mask 
& wxLIST_MASK_TEXT
) 
3123         lvItem
.mask 
|= LVIF_TEXT
; 
3124         if ( ctrl
->HasFlag(wxLC_USER_TEXT
) ) 
3126             lvItem
.pszText 
= LPSTR_TEXTCALLBACK
; 
3130             // pszText is not const, hence the cast 
3131             lvItem
.pszText 
= (wxChar 
*)info
.m_text
.wx_str(); 
3132             if ( lvItem
.pszText 
) 
3133                 lvItem
.cchTextMax 
= info
.m_text
.length(); 
3135                 lvItem
.cchTextMax 
= 0; 
3138     if (info
.m_mask 
& wxLIST_MASK_IMAGE
) 
3139         lvItem
.mask 
|= LVIF_IMAGE
; 
3142 static void wxConvertToMSWListCol(HWND hwndList
, 
3144                                   const wxListItem
& item
, 
3147     wxZeroMemory(lvCol
); 
3149     if ( item
.m_mask 
& wxLIST_MASK_TEXT 
) 
3151         lvCol
.mask 
|= LVCF_TEXT
; 
3152         lvCol
.pszText 
= (wxChar 
*)item
.m_text
.wx_str(); // cast is safe 
3155     if ( item
.m_mask 
& wxLIST_MASK_FORMAT 
) 
3157         lvCol
.mask 
|= LVCF_FMT
; 
3159         if ( item
.m_format 
== wxLIST_FORMAT_LEFT 
) 
3160             lvCol
.fmt 
= LVCFMT_LEFT
; 
3161         else if ( item
.m_format 
== wxLIST_FORMAT_RIGHT 
) 
3162             lvCol
.fmt 
= LVCFMT_RIGHT
; 
3163         else if ( item
.m_format 
== wxLIST_FORMAT_CENTRE 
) 
3164             lvCol
.fmt 
= LVCFMT_CENTER
; 
3167     if ( item
.m_mask 
& wxLIST_MASK_WIDTH 
) 
3169         lvCol
.mask 
|= LVCF_WIDTH
; 
3170         if ( item
.m_width 
== wxLIST_AUTOSIZE
) 
3171             lvCol
.cx 
= LVSCW_AUTOSIZE
; 
3172         else if ( item
.m_width 
== wxLIST_AUTOSIZE_USEHEADER
) 
3173             lvCol
.cx 
= LVSCW_AUTOSIZE_USEHEADER
; 
3175             lvCol
.cx 
= item
.m_width
; 
3178     // see comment at the end of wxListCtrl::GetColumn() 
3179 #ifdef NM_CUSTOMDRAW // _WIN32_IE >= 0x0300 
3180     if ( item
.m_mask 
& wxLIST_MASK_IMAGE 
) 
3182         if ( wxApp::GetComCtl32Version() >= 470 ) 
3184             lvCol
.mask 
|= LVCF_IMAGE
; 
3186             // we use LVCFMT_BITMAP_ON_RIGHT because the images on the right 
3187             // seem to be generally nicer than on the left and the generic 
3188             // version only draws them on the right (we don't have a flag to 
3189             // specify the image location anyhow) 
3191             // we don't use LVCFMT_COL_HAS_IMAGES because it doesn't seem to 
3192             // make any difference in my tests -- but maybe we should? 
3193             if ( item
.m_image 
!= -1 ) 
3195                 // as we're going to overwrite the format field, get its 
3196                 // current value first -- unless we want to overwrite it anyhow 
3197                 if ( !(lvCol
.mask 
& LVCF_FMT
) ) 
3200                     wxZeroMemory(lvColOld
); 
3201                     lvColOld
.mask 
= LVCF_FMT
; 
3202                     if ( ListView_GetColumn(hwndList
, col
, &lvColOld
) ) 
3204                         lvCol
.fmt 
= lvColOld
.fmt
; 
3207                     lvCol
.mask 
|= LVCF_FMT
; 
3210                 lvCol
.fmt 
|= LVCFMT_BITMAP_ON_RIGHT 
| LVCFMT_IMAGE
; 
3213             lvCol
.iImage 
= item
.m_image
; 
3215         //else: it doesn't support item images anyhow 
3217 #endif // _WIN32_IE >= 0x0300 
3220 #endif // wxUSE_LISTCTRL