1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/listctrl.cpp
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "listctrl.h"
22 #pragma implementation "listctrlbase.h"
25 // For compilers that support precompilation, includes "wx.h".
26 #include "wx/wxprec.h"
32 #if wxUSE_LISTCTRL && defined(__WIN95__)
38 #include "wx/settings.h"
41 #include "wx/textctrl.h"
42 #include "wx/imaglist.h"
43 #include "wx/listctrl.h"
44 #include "wx/dcclient.h"
46 #include "wx/msw/private.h"
48 #if ((defined(__GNUWIN32_OLD__) || defined(__TWIN32__)) && !defined(__CYGWIN10__))
49 #include "wx/msw/gnuwin32/extra.h"
54 #include "wx/msw/missing.h"
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 // convert our state and mask flags to LV_ITEM constants
61 static void wxConvertToMSWFlags(long state
, long mask
, LV_ITEM
& lvItem
);
63 // convert wxListItem to LV_ITEM
64 static void wxConvertToMSWListItem(const wxListCtrl
*ctrl
,
65 const wxListItem
& info
, LV_ITEM
& lvItem
);
67 // convert LV_ITEM to wxListItem
68 static void wxConvertFromMSWListItem(HWND hwndListCtrl
,
70 /* const */ LV_ITEM
& lvItem
);
72 // convert our wxListItem to LV_COLUMN
73 static void wxConvertToMSWListCol(int col
, const wxListItem
& item
,
76 // ----------------------------------------------------------------------------
77 // private helper classes
78 // ----------------------------------------------------------------------------
80 // We have to handle both fooW and fooA notifications in several cases
81 // because of broken commctl.dll and/or unicows.dll. This class is used to
82 // convert LV_ITEMA and LV_ITEMW to LV_ITEM (which is either LV_ITEMA or
83 // LV_ITEMW depending on wxUSE_UNICODE setting), so that it can be processed
84 // by wxConvertToMSWListItem().
88 ~wxLV_ITEM() { delete m_buf
; }
89 operator LV_ITEM
&() const { return *m_item
; }
92 wxLV_ITEM(LV_ITEMW
&item
) : m_buf(NULL
), m_item(&item
) {}
93 wxLV_ITEM(LV_ITEMA
&item
)
95 m_item
= new LV_ITEM((LV_ITEM
&)item
);
96 if ( (item
.mask
& LVIF_TEXT
) && item
.pszText
)
98 m_buf
= new wxMB2WXbuf(wxConvLocal
.cMB2WX(item
.pszText
));
99 m_item
->pszText
= (wxChar
*)m_buf
->data();
108 wxLV_ITEM(LV_ITEMW
&item
)
110 m_item
= new LV_ITEM((LV_ITEM
&)item
);
111 if ( (item
.mask
& LVIF_TEXT
) && item
.pszText
)
113 m_buf
= new wxWC2WXbuf(wxConvLocal
.cWC2WX(item
.pszText
));
114 m_item
->pszText
= (wxChar
*)m_buf
->data();
119 wxLV_ITEM(LV_ITEMA
&item
) : m_buf(NULL
), m_item(&item
) {}
127 ///////////////////////////////////////////////////////
129 // The MSW version had problems with SetTextColour() et
130 // al as the wxListItemAttr's were stored keyed on the
131 // item index. If a item was inserted anywhere but the end
132 // of the list the the text attributes (colour etc) for
133 // the following items were out of sync.
136 // Under MSW the only way to associate data with a List
137 // item independant of its position in the list is to
138 // store a pointer to it in its lParam attribute. However
139 // user programs are already using this (via the
140 // SetItemData() GetItemData() calls).
142 // However what we can do is store a pointer to a
143 // structure which contains the attributes we want *and*
144 // a lParam for the users data, e.g.
146 // class wxListItemInternalData
149 // wxListItemAttr *attr;
150 // long lParam; // user data
153 // To conserve memory, a wxListItemInternalData is
154 // only allocated for a LV_ITEM if text attributes or
155 // user data(lparam) are being set.
158 // class wxListItemInternalData
159 class wxListItemInternalData
162 wxListItemAttr
*attr
;
163 LPARAM lParam
; // user data
165 wxListItemInternalData() : attr(NULL
), lParam(0) {}
166 ~wxListItemInternalData()
173 // Get the internal data structure
174 static wxListItemInternalData
*GetInternalData(HWND hwnd
, long itemId
);
175 static wxListItemInternalData
*GetInternalData(wxListCtrl
*ctl
, long itemId
);
176 static wxListItemAttr
*GetInternalDataAttr(wxListCtrl
*ctl
, long itemId
);
179 // ----------------------------------------------------------------------------
181 // ----------------------------------------------------------------------------
183 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG
)
184 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG
)
185 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
)
186 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT
)
187 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM
)
188 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
)
189 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO
)
190 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO
)
191 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED
)
192 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED
)
193 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN
)
194 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM
)
195 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK
)
196 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
)
197 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
)
198 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING
)
199 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG
)
200 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
)
201 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
)
202 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED
)
203 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED
)
204 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT
)
206 IMPLEMENT_DYNAMIC_CLASS(wxListCtrl
, wxControl
)
207 IMPLEMENT_DYNAMIC_CLASS(wxListView
, wxListCtrl
)
208 IMPLEMENT_DYNAMIC_CLASS(wxListItem
, wxObject
)
210 IMPLEMENT_DYNAMIC_CLASS(wxListEvent
, wxNotifyEvent
)
212 BEGIN_EVENT_TABLE(wxListCtrl
, wxControl
)
213 EVT_PAINT(wxListCtrl::OnPaint
)
216 // ============================================================================
218 // ============================================================================
220 // ----------------------------------------------------------------------------
221 // wxListCtrl construction
222 // ----------------------------------------------------------------------------
224 void wxListCtrl::Init()
226 m_imageListNormal
= NULL
;
227 m_imageListSmall
= NULL
;
228 m_imageListState
= NULL
;
229 m_ownsImageListNormal
= m_ownsImageListSmall
= m_ownsImageListState
= FALSE
;
233 m_AnyInternalData
= FALSE
;
234 m_hasAnyAttr
= FALSE
;
237 bool wxListCtrl::Create(wxWindow
*parent
,
242 const wxValidator
& validator
,
243 const wxString
& name
)
246 SetValidator(validator
);
247 #endif // wxUSE_VALIDATORS
256 m_windowStyle
= style
;
269 m_windowId
= (id
== -1) ? NewControlId() : id
;
271 DWORD wstyle
= WS_VISIBLE
| WS_CHILD
| WS_TABSTOP
|
272 LVS_SHAREIMAGELISTS
| LVS_SHOWSELALWAYS
;
274 if ( m_windowStyle
& wxCLIP_SIBLINGS
)
275 wstyle
|= WS_CLIPSIBLINGS
;
277 if ( wxStyleHasBorder(m_windowStyle
) )
279 m_baseStyle
= wstyle
;
281 if ( !DoCreateControl(x
, y
, width
, height
) )
285 parent
->AddChild(this);
290 bool wxListCtrl::DoCreateControl(int x
, int y
, int w
, int h
)
292 DWORD wstyle
= m_baseStyle
;
295 WXDWORD exStyle
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
);
297 // Even with extended styles, need to combine with WS_BORDER
298 // for them to look right.
302 long oldStyle
= 0; // Dummy
303 wstyle
|= ConvertToMSWStyle(oldStyle
, m_windowStyle
);
305 // Create the ListView control.
306 m_hWnd
= (WXHWND
)CreateWindowEx(exStyle
,
311 GetWinHwnd(GetParent()),
318 wxLogError(_("Can't create list control window, check that comctl32.dll is installed."));
323 // for comctl32.dll v 4.70+ we want to have this attribute because it's
324 // prettier (and also because wxGTK does it like this)
325 if ( (wstyle
& LVS_REPORT
) && wxTheApp
->GetComCtl32Version() >= 470 )
327 ::SendMessage(GetHwnd(), LVM_SETEXTENDEDLISTVIEWSTYLE
,
328 0, LVS_EX_FULLROWSELECT
);
331 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
332 SetForegroundColour(GetParent()->GetForegroundColour());
339 void wxListCtrl::UpdateStyle()
343 // The new window view style
345 DWORD dwStyleNew
= ConvertToMSWStyle(dummy
, m_windowStyle
);
346 dwStyleNew
|= m_baseStyle
;
348 // Get the current window style.
349 DWORD dwStyleOld
= ::GetWindowLong(GetHwnd(), GWL_STYLE
);
351 // Only set the window style if the view bits have changed.
352 if ( dwStyleOld
!= dwStyleNew
)
354 ::SetWindowLong(GetHwnd(), GWL_STYLE
, dwStyleNew
);
359 void wxListCtrl::FreeAllInternalData()
361 if (m_AnyInternalData
)
363 int n
= GetItemCount();
366 for (i
= 0; i
< n
; i
++)
368 wxListItemInternalData
*data
= GetInternalData(this, i
);
373 memset(&item
, 0, sizeof(item
));
375 item
.mask
= LVIF_PARAM
;
376 item
.lParam
= (LPARAM
) 0;
377 BOOL result
= ListView_SetItem(GetHwnd(), &item
);
380 m_AnyInternalData
= FALSE
;
384 wxListCtrl::~wxListCtrl()
386 FreeAllInternalData();
390 m_textCtrl
->SetHWND(0);
391 m_textCtrl
->UnsubclassWin();
396 if (m_ownsImageListNormal
) delete m_imageListNormal
;
397 if (m_ownsImageListSmall
) delete m_imageListSmall
;
398 if (m_ownsImageListState
) delete m_imageListState
;
401 // ----------------------------------------------------------------------------
402 // set/get/change style
403 // ----------------------------------------------------------------------------
405 // Add or remove a single window style
406 void wxListCtrl::SetSingleStyle(long style
, bool add
)
408 long flag
= GetWindowStyleFlag();
410 // Get rid of conflicting styles
413 if ( style
& wxLC_MASK_TYPE
)
414 flag
= flag
& ~wxLC_MASK_TYPE
;
415 if ( style
& wxLC_MASK_ALIGN
)
416 flag
= flag
& ~wxLC_MASK_ALIGN
;
417 if ( style
& wxLC_MASK_SORT
)
418 flag
= flag
& ~wxLC_MASK_SORT
;
434 m_windowStyle
= flag
;
439 // Set the whole window style
440 void wxListCtrl::SetWindowStyleFlag(long flag
)
442 m_windowStyle
= flag
;
447 // Can be just a single style, or a bitlist
448 long wxListCtrl::ConvertToMSWStyle(long& oldStyle
, long style
) const
451 if ( style
& wxLC_ICON
)
453 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_SMALLICON
)
454 oldStyle
-= LVS_SMALLICON
;
455 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_REPORT
)
456 oldStyle
-= LVS_REPORT
;
457 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_LIST
)
458 oldStyle
-= LVS_LIST
;
462 if ( style
& wxLC_SMALL_ICON
)
464 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_ICON
)
465 oldStyle
-= LVS_ICON
;
466 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_REPORT
)
467 oldStyle
-= LVS_REPORT
;
468 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_LIST
)
469 oldStyle
-= LVS_LIST
;
470 wstyle
|= LVS_SMALLICON
;
473 if ( style
& wxLC_LIST
)
475 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_ICON
)
476 oldStyle
-= LVS_ICON
;
477 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_REPORT
)
478 oldStyle
-= LVS_REPORT
;
479 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_SMALLICON
)
480 oldStyle
-= LVS_SMALLICON
;
484 if ( style
& wxLC_REPORT
)
486 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_ICON
)
487 oldStyle
-= LVS_ICON
;
488 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_LIST
)
489 oldStyle
-= LVS_LIST
;
490 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_SMALLICON
)
491 oldStyle
-= LVS_SMALLICON
;
493 wstyle
|= LVS_REPORT
;
496 if ( style
& wxLC_ALIGN_LEFT
)
498 if ( oldStyle
& LVS_ALIGNTOP
)
499 oldStyle
-= LVS_ALIGNTOP
;
500 wstyle
|= LVS_ALIGNLEFT
;
503 if ( style
& wxLC_ALIGN_TOP
)
505 if ( oldStyle
& LVS_ALIGNLEFT
)
506 oldStyle
-= LVS_ALIGNLEFT
;
507 wstyle
|= LVS_ALIGNTOP
;
510 if ( style
& wxLC_AUTOARRANGE
)
511 wstyle
|= LVS_AUTOARRANGE
;
513 if ( style
& wxLC_NO_SORT_HEADER
)
514 wstyle
|= LVS_NOSORTHEADER
;
516 if ( style
& wxLC_NO_HEADER
)
517 wstyle
|= LVS_NOCOLUMNHEADER
;
519 if ( style
& wxLC_EDIT_LABELS
)
520 wstyle
|= LVS_EDITLABELS
;
522 if ( style
& wxLC_SINGLE_SEL
)
523 wstyle
|= LVS_SINGLESEL
;
525 if ( style
& wxLC_SORT_ASCENDING
)
527 if ( oldStyle
& LVS_SORTDESCENDING
)
528 oldStyle
-= LVS_SORTDESCENDING
;
529 wstyle
|= LVS_SORTASCENDING
;
532 if ( style
& wxLC_SORT_DESCENDING
)
534 if ( oldStyle
& LVS_SORTASCENDING
)
535 oldStyle
-= LVS_SORTASCENDING
;
536 wstyle
|= LVS_SORTDESCENDING
;
539 #if !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) )
540 if ( style
& wxLC_VIRTUAL
)
542 int ver
= wxTheApp
->GetComCtl32Version();
545 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."),
546 ver
/ 100, ver
% 100);
549 wstyle
|= LVS_OWNERDATA
;
556 // ----------------------------------------------------------------------------
558 // ----------------------------------------------------------------------------
560 // Sets the foreground, i.e. text, colour
561 bool wxListCtrl::SetForegroundColour(const wxColour
& col
)
563 if ( !wxWindow::SetForegroundColour(col
) )
566 ListView_SetTextColor(GetHwnd(), wxColourToRGB(col
));
571 // Sets the background colour
572 bool wxListCtrl::SetBackgroundColour(const wxColour
& col
)
574 if ( !wxWindow::SetBackgroundColour(col
) )
577 // we set the same colour for both the "empty" background and the items
579 COLORREF color
= wxColourToRGB(col
);
580 ListView_SetBkColor(GetHwnd(), color
);
581 ListView_SetTextBkColor(GetHwnd(), color
);
586 // Gets information about this column
587 bool wxListCtrl::GetColumn(int col
, wxListItem
& item
) const
592 if ( item
.m_mask
& wxLIST_MASK_TEXT
)
594 lvCol
.mask
|= LVCF_TEXT
;
595 lvCol
.pszText
= new wxChar
[513];
596 lvCol
.cchTextMax
= 512;
599 bool success
= ListView_GetColumn(GetHwnd(), col
, & lvCol
) != 0;
601 // item.m_subItem = lvCol.iSubItem;
602 item
.m_width
= lvCol
.cx
;
604 if ( (item
.m_mask
& wxLIST_MASK_TEXT
) && lvCol
.pszText
)
606 item
.m_text
= lvCol
.pszText
;
607 delete[] lvCol
.pszText
;
610 if ( item
.m_mask
& wxLIST_MASK_FORMAT
)
612 if (lvCol
.fmt
== LVCFMT_LEFT
)
613 item
.m_format
= wxLIST_FORMAT_LEFT
;
614 else if (lvCol
.fmt
== LVCFMT_RIGHT
)
615 item
.m_format
= wxLIST_FORMAT_RIGHT
;
616 else if (lvCol
.fmt
== LVCFMT_CENTER
)
617 item
.m_format
= wxLIST_FORMAT_CENTRE
;
623 // Sets information about this column
624 bool wxListCtrl::SetColumn(int col
, wxListItem
& item
)
627 wxConvertToMSWListCol(col
, item
, lvCol
);
629 return ListView_SetColumn(GetHwnd(), col
, &lvCol
) != 0;
632 // Gets the column width
633 int wxListCtrl::GetColumnWidth(int col
) const
635 return ListView_GetColumnWidth(GetHwnd(), col
);
638 // Sets the column width
639 bool wxListCtrl::SetColumnWidth(int col
, int width
)
642 if ( m_windowStyle
& wxLC_LIST
)
646 if ( width2
== wxLIST_AUTOSIZE
)
647 width2
= LVSCW_AUTOSIZE
;
648 else if ( width2
== wxLIST_AUTOSIZE_USEHEADER
)
649 width2
= LVSCW_AUTOSIZE_USEHEADER
;
651 return ListView_SetColumnWidth(GetHwnd(), col2
, width2
) != 0;
654 // Gets the number of items that can fit vertically in the
655 // visible area of the list control (list or report view)
656 // or the total number of items in the list control (icon
657 // or small icon view)
658 int wxListCtrl::GetCountPerPage() const
660 return ListView_GetCountPerPage(GetHwnd());
663 // Gets the edit control for editing labels.
664 wxTextCtrl
* wxListCtrl::GetEditControl() const
669 // Gets information about the item
670 bool wxListCtrl::GetItem(wxListItem
& info
) const
673 wxZeroMemory(lvItem
);
675 lvItem
.iItem
= info
.m_itemId
;
676 lvItem
.iSubItem
= info
.m_col
;
678 if ( info
.m_mask
& wxLIST_MASK_TEXT
)
680 lvItem
.mask
|= LVIF_TEXT
;
681 lvItem
.pszText
= new wxChar
[513];
682 lvItem
.cchTextMax
= 512;
686 lvItem
.pszText
= NULL
;
689 if (info
.m_mask
& wxLIST_MASK_DATA
)
690 lvItem
.mask
|= LVIF_PARAM
;
692 if (info
.m_mask
& wxLIST_MASK_IMAGE
)
693 lvItem
.mask
|= LVIF_IMAGE
;
695 if ( info
.m_mask
& wxLIST_MASK_STATE
)
697 lvItem
.mask
|= LVIF_STATE
;
698 // the other bits are hardly interesting anyhow
699 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_FOCUSED
;
702 bool success
= ListView_GetItem((HWND
)GetHWND(), &lvItem
) != 0;
705 wxLogError(_("Couldn't retrieve information about list control item %d."),
710 // give NULL as hwnd as we already have everything we need
711 wxConvertFromMSWListItem(NULL
, info
, lvItem
);
715 delete[] lvItem
.pszText
;
720 // Sets information about the item
721 bool wxListCtrl::SetItem(wxListItem
& info
)
724 wxConvertToMSWListItem(this, info
, item
);
726 // we never update the lParam if it contains our pointer
727 // to the wxListItemInternalData structure
728 item
.mask
&= ~LVIF_PARAM
;
730 // check if setting attributes or lParam
731 if (info
.HasAttributes() || (info
.m_mask
& wxLIST_MASK_DATA
))
733 // get internal item data
734 // perhaps a cache here ?
735 wxListItemInternalData
*data
= GetInternalData(this, info
.m_itemId
);
740 m_AnyInternalData
= TRUE
;
741 data
= new wxListItemInternalData();
742 item
.lParam
= (LPARAM
) data
;
743 item
.mask
|= LVIF_PARAM
;
748 if (info
.m_mask
& wxLIST_MASK_DATA
)
749 data
->lParam
= info
.m_data
;
752 if (info
.HasAttributes())
755 *data
->attr
= *info
.GetAttributes();
757 data
->attr
= new wxListItemAttr(*info
.GetAttributes());
762 // we could be changing only the attribute in which case we don't need to
763 // call ListView_SetItem() at all
767 if ( !ListView_SetItem(GetHwnd(), &item
) )
769 wxLogDebug(_T("ListView_SetItem() failed"));
775 // we need to update the item immediately to show the new image
776 bool updateNow
= (info
.m_mask
& wxLIST_MASK_IMAGE
) != 0;
778 // check whether it has any custom attributes
779 if ( info
.HasAttributes() )
783 // if the colour has changed, we must redraw the item
789 // we need this to make the change visible right now
790 RefreshItem(item
.iItem
);
796 long wxListCtrl::SetItem(long index
, int col
, const wxString
& label
, int imageId
)
800 info
.m_mask
= wxLIST_MASK_TEXT
;
801 info
.m_itemId
= index
;
805 info
.m_image
= imageId
;
806 info
.m_mask
|= wxLIST_MASK_IMAGE
;
808 return SetItem(info
);
812 // Gets the item state
813 int wxListCtrl::GetItemState(long item
, long stateMask
) const
817 info
.m_mask
= wxLIST_MASK_STATE
;
818 info
.m_stateMask
= stateMask
;
819 info
.m_itemId
= item
;
827 // Sets the item state
828 bool wxListCtrl::SetItemState(long item
, long state
, long stateMask
)
830 // NB: don't use SetItem() here as it doesn't work with the virtual list
833 wxZeroMemory(lvItem
);
835 wxConvertToMSWFlags(state
, stateMask
, lvItem
);
837 // for the virtual list controls we need to refresh the previously focused
838 // item manually when changing focus without changing selection
839 // programmatically because otherwise it keeps its focus rectangle until
840 // next repaint (yet another comctl32 bug)
843 (stateMask
& wxLIST_STATE_FOCUSED
) &&
844 (state
& wxLIST_STATE_FOCUSED
) )
846 focusOld
= GetNextItem(-1, wxLIST_NEXT_ALL
, wxLIST_STATE_FOCUSED
);
853 if ( !::SendMessage(GetHwnd(), LVM_SETITEMSTATE
,
854 (WPARAM
)item
, (LPARAM
)&lvItem
) )
856 wxLogLastError(_T("ListView_SetItemState"));
861 if ( focusOld
!= -1 )
863 // no need to refresh the item if it was previously selected, it would
864 // only result in annoying flicker
865 if ( !(GetItemState(focusOld
,
866 wxLIST_STATE_SELECTED
) & wxLIST_STATE_SELECTED
) )
868 RefreshItem(focusOld
);
875 // Sets the item image
876 bool wxListCtrl::SetItemImage(long item
, int image
, int WXUNUSED(selImage
))
880 info
.m_mask
= wxLIST_MASK_IMAGE
;
881 info
.m_image
= image
;
882 info
.m_itemId
= item
;
884 return SetItem(info
);
887 // Gets the item text
888 wxString
wxListCtrl::GetItemText(long item
) const
892 info
.m_mask
= wxLIST_MASK_TEXT
;
893 info
.m_itemId
= item
;
900 // Sets the item text
901 void wxListCtrl::SetItemText(long item
, const wxString
& str
)
905 info
.m_mask
= wxLIST_MASK_TEXT
;
906 info
.m_itemId
= item
;
912 // Gets the item data
913 long wxListCtrl::GetItemData(long item
) const
917 info
.m_mask
= wxLIST_MASK_DATA
;
918 info
.m_itemId
= item
;
925 // Sets the item data
926 bool wxListCtrl::SetItemData(long item
, long data
)
930 info
.m_mask
= wxLIST_MASK_DATA
;
931 info
.m_itemId
= item
;
934 return SetItem(info
);
937 // Gets the item rectangle
938 bool wxListCtrl::GetItemRect(long item
, wxRect
& rect
, int code
) const
943 if ( code
== wxLIST_RECT_BOUNDS
)
944 codeWin
= LVIR_BOUNDS
;
945 else if ( code
== wxLIST_RECT_ICON
)
947 else if ( code
== wxLIST_RECT_LABEL
)
948 codeWin
= LVIR_LABEL
;
951 wxFAIL_MSG( _T("incorrect code in GetItemRect()") );
953 codeWin
= LVIR_BOUNDS
;
957 bool success
= ListView_GetItemRect(GetHwnd(), (int) item
, &rectWin
) != 0;
959 bool success
= ListView_GetItemRect(GetHwnd(), (int) item
, &rectWin
, codeWin
) != 0;
962 rect
.x
= rectWin
.left
;
963 rect
.y
= rectWin
.top
;
964 rect
.width
= rectWin
.right
- rectWin
.left
;
965 rect
.height
= rectWin
.bottom
- rectWin
.top
;
970 // Gets the item position
971 bool wxListCtrl::GetItemPosition(long item
, wxPoint
& pos
) const
975 bool success
= (ListView_GetItemPosition(GetHwnd(), (int) item
, &pt
) != 0);
977 pos
.x
= pt
.x
; pos
.y
= pt
.y
;
981 // Sets the item position.
982 bool wxListCtrl::SetItemPosition(long item
, const wxPoint
& pos
)
984 return (ListView_SetItemPosition(GetHwnd(), (int) item
, pos
.x
, pos
.y
) != 0);
987 // Gets the number of items in the list control
988 int wxListCtrl::GetItemCount() const
990 return ListView_GetItemCount(GetHwnd());
993 // Retrieves the spacing between icons in pixels.
994 // If small is TRUE, gets the spacing for the small icon
995 // view, otherwise the large icon view.
996 int wxListCtrl::GetItemSpacing(bool isSmall
) const
998 return ListView_GetItemSpacing(GetHwnd(), (BOOL
) isSmall
);
1001 void wxListCtrl::SetItemTextColour( long item
, const wxColour
&col
)
1004 info
.m_itemId
= item
;
1005 info
.SetTextColour( col
);
1009 wxColour
wxListCtrl::GetItemTextColour( long item
) const
1012 info
.m_itemId
= item
;
1014 return info
.GetTextColour();
1017 void wxListCtrl::SetItemBackgroundColour( long item
, const wxColour
&col
)
1020 info
.m_itemId
= item
;
1021 info
.SetBackgroundColour( col
);
1025 wxColour
wxListCtrl::GetItemBackgroundColour( long item
) const
1028 info
.m_itemId
= item
;
1030 return info
.GetBackgroundColour();
1033 // Gets the number of selected items in the list control
1034 int wxListCtrl::GetSelectedItemCount() const
1036 return ListView_GetSelectedCount(GetHwnd());
1039 // Gets the text colour of the listview
1040 wxColour
wxListCtrl::GetTextColour() const
1042 COLORREF ref
= ListView_GetTextColor(GetHwnd());
1043 wxColour
col(GetRValue(ref
), GetGValue(ref
), GetBValue(ref
));
1047 // Sets the text colour of the listview
1048 void wxListCtrl::SetTextColour(const wxColour
& col
)
1050 ListView_SetTextColor(GetHwnd(), PALETTERGB(col
.Red(), col
.Green(), col
.Blue()));
1053 // Gets the index of the topmost visible item when in
1054 // list or report view
1055 long wxListCtrl::GetTopItem() const
1057 return (long) ListView_GetTopIndex(GetHwnd());
1060 // Searches for an item, starting from 'item'.
1061 // 'geometry' is one of
1062 // wxLIST_NEXT_ABOVE/ALL/BELOW/LEFT/RIGHT.
1063 // 'state' is a state bit flag, one or more of
1064 // wxLIST_STATE_DROPHILITED/FOCUSED/SELECTED/CUT.
1065 // item can be -1 to find the first item that matches the
1067 // Returns the item or -1 if unsuccessful.
1068 long wxListCtrl::GetNextItem(long item
, int geom
, int state
) const
1072 if ( geom
== wxLIST_NEXT_ABOVE
)
1073 flags
|= LVNI_ABOVE
;
1074 if ( geom
== wxLIST_NEXT_ALL
)
1076 if ( geom
== wxLIST_NEXT_BELOW
)
1077 flags
|= LVNI_BELOW
;
1078 if ( geom
== wxLIST_NEXT_LEFT
)
1079 flags
|= LVNI_TOLEFT
;
1080 if ( geom
== wxLIST_NEXT_RIGHT
)
1081 flags
|= LVNI_TORIGHT
;
1083 if ( state
& wxLIST_STATE_CUT
)
1085 if ( state
& wxLIST_STATE_DROPHILITED
)
1086 flags
|= LVNI_DROPHILITED
;
1087 if ( state
& wxLIST_STATE_FOCUSED
)
1088 flags
|= LVNI_FOCUSED
;
1089 if ( state
& wxLIST_STATE_SELECTED
)
1090 flags
|= LVNI_SELECTED
;
1092 return (long) ListView_GetNextItem(GetHwnd(), item
, flags
);
1096 wxImageList
*wxListCtrl::GetImageList(int which
) const
1098 if ( which
== wxIMAGE_LIST_NORMAL
)
1100 return m_imageListNormal
;
1102 else if ( which
== wxIMAGE_LIST_SMALL
)
1104 return m_imageListSmall
;
1106 else if ( which
== wxIMAGE_LIST_STATE
)
1108 return m_imageListState
;
1113 void wxListCtrl::SetImageList(wxImageList
*imageList
, int which
)
1116 if ( which
== wxIMAGE_LIST_NORMAL
)
1118 flags
= LVSIL_NORMAL
;
1119 if (m_ownsImageListNormal
) delete m_imageListNormal
;
1120 m_imageListNormal
= imageList
;
1121 m_ownsImageListNormal
= FALSE
;
1123 else if ( which
== wxIMAGE_LIST_SMALL
)
1125 flags
= LVSIL_SMALL
;
1126 if (m_ownsImageListSmall
) delete m_imageListSmall
;
1127 m_imageListSmall
= imageList
;
1128 m_ownsImageListSmall
= FALSE
;
1130 else if ( which
== wxIMAGE_LIST_STATE
)
1132 flags
= LVSIL_STATE
;
1133 if (m_ownsImageListState
) delete m_imageListState
;
1134 m_imageListState
= imageList
;
1135 m_ownsImageListState
= FALSE
;
1137 ListView_SetImageList(GetHwnd(), (HIMAGELIST
) imageList
? imageList
->GetHIMAGELIST() : 0, flags
);
1140 void wxListCtrl::AssignImageList(wxImageList
*imageList
, int which
)
1142 SetImageList(imageList
, which
);
1143 if ( which
== wxIMAGE_LIST_NORMAL
)
1144 m_ownsImageListNormal
= TRUE
;
1145 else if ( which
== wxIMAGE_LIST_SMALL
)
1146 m_ownsImageListSmall
= TRUE
;
1147 else if ( which
== wxIMAGE_LIST_STATE
)
1148 m_ownsImageListState
= TRUE
;
1151 // ----------------------------------------------------------------------------
1153 // ----------------------------------------------------------------------------
1155 // Arranges the items
1156 bool wxListCtrl::Arrange(int flag
)
1159 if ( flag
== wxLIST_ALIGN_LEFT
)
1160 code
= LVA_ALIGNLEFT
;
1161 else if ( flag
== wxLIST_ALIGN_TOP
)
1162 code
= LVA_ALIGNTOP
;
1163 else if ( flag
== wxLIST_ALIGN_DEFAULT
)
1165 else if ( flag
== wxLIST_ALIGN_SNAP_TO_GRID
)
1166 code
= LVA_SNAPTOGRID
;
1168 return (ListView_Arrange(GetHwnd(), code
) != 0);
1172 bool wxListCtrl::DeleteItem(long item
)
1174 if ( !ListView_DeleteItem(GetHwnd(), (int) item
) )
1176 wxLogLastError(_T("ListView_DeleteItem"));
1180 // the virtual list control doesn't refresh itself correctly, help it
1183 // we need to refresh all the lines below the one which was deleted
1185 if ( item
> 0 && GetItemCount() )
1187 GetItemRect(item
- 1, rectItem
);
1192 rectItem
.height
= 0;
1195 wxRect rectWin
= GetRect();
1196 rectWin
.height
= rectWin
.GetBottom() - rectItem
.GetBottom();
1197 rectWin
.y
= rectItem
.GetBottom();
1199 RefreshRect(rectWin
);
1205 // Deletes all items
1206 bool wxListCtrl::DeleteAllItems()
1208 FreeAllInternalData();
1209 return ListView_DeleteAllItems(GetHwnd()) != 0;
1212 // Deletes all items
1213 bool wxListCtrl::DeleteAllColumns()
1215 while ( m_colCount
> 0 )
1217 if ( ListView_DeleteColumn(GetHwnd(), 0) == 0 )
1219 wxLogLastError(wxT("ListView_DeleteColumn"));
1227 wxASSERT_MSG( m_colCount
== 0, wxT("no columns should be left") );
1233 bool wxListCtrl::DeleteColumn(int col
)
1235 bool success
= (ListView_DeleteColumn(GetHwnd(), col
) != 0);
1237 if ( success
&& (m_colCount
> 0) )
1242 // Clears items, and columns if there are any.
1243 void wxListCtrl::ClearAll()
1246 if ( m_colCount
> 0 )
1250 wxTextCtrl
* wxListCtrl::EditLabel(long item
, wxClassInfo
* textControlClass
)
1252 wxASSERT( (textControlClass
->IsKindOf(CLASSINFO(wxTextCtrl
))) );
1254 // ListView_EditLabel requires that the list has focus.
1256 WXHWND hWnd
= (WXHWND
) ListView_EditLabel(GetHwnd(), item
);
1260 m_textCtrl
->SetHWND(0);
1261 m_textCtrl
->UnsubclassWin();
1265 m_textCtrl
= (wxTextCtrl
*) textControlClass
->CreateObject();
1266 m_textCtrl
->SetHWND(hWnd
);
1267 m_textCtrl
->SubclassWin(hWnd
);
1268 m_textCtrl
->SetParent(this);
1273 // End label editing, optionally cancelling the edit
1274 bool wxListCtrl::EndEditLabel(bool WXUNUSED(cancel
))
1276 wxFAIL_MSG( _T("not implemented") );
1281 // Ensures this item is visible
1282 bool wxListCtrl::EnsureVisible(long item
)
1284 return ListView_EnsureVisible(GetHwnd(), (int) item
, FALSE
) != 0;
1287 // Find an item whose label matches this string, starting from the item after 'start'
1288 // or the beginning if 'start' is -1.
1289 long wxListCtrl::FindItem(long start
, const wxString
& str
, bool partial
)
1291 LV_FINDINFO findInfo
;
1293 findInfo
.flags
= LVFI_STRING
;
1295 findInfo
.flags
|= LVFI_PARTIAL
;
1298 // ListView_FindItem() excludes the first item from search and to look
1299 // through all the items you need to start from -1 which is unnatural and
1300 // inconsistent with the generic version - so we adjust the index
1303 return ListView_FindItem(GetHwnd(), (int) start
, &findInfo
);
1306 // Find an item whose data matches this data, starting from the item after 'start'
1307 // or the beginning if 'start' is -1.
1308 long wxListCtrl::FindItem(long start
, long data
)
1310 LV_FINDINFO findInfo
;
1312 findInfo
.flags
= LVFI_PARAM
;
1313 findInfo
.lParam
= data
;
1315 return ListView_FindItem(GetHwnd(), (int) start
, & findInfo
);
1318 // Find an item nearest this position in the specified direction, starting from
1319 // the item after 'start' or the beginning if 'start' is -1.
1320 long wxListCtrl::FindItem(long start
, const wxPoint
& pt
, int direction
)
1322 LV_FINDINFO findInfo
;
1324 findInfo
.flags
= LVFI_NEARESTXY
;
1325 findInfo
.pt
.x
= pt
.x
;
1326 findInfo
.pt
.y
= pt
.y
;
1327 findInfo
.vkDirection
= VK_RIGHT
;
1329 if ( direction
== wxLIST_FIND_UP
)
1330 findInfo
.vkDirection
= VK_UP
;
1331 else if ( direction
== wxLIST_FIND_DOWN
)
1332 findInfo
.vkDirection
= VK_DOWN
;
1333 else if ( direction
== wxLIST_FIND_LEFT
)
1334 findInfo
.vkDirection
= VK_LEFT
;
1335 else if ( direction
== wxLIST_FIND_RIGHT
)
1336 findInfo
.vkDirection
= VK_RIGHT
;
1338 return ListView_FindItem(GetHwnd(), (int) start
, & findInfo
);
1341 // Determines which item (if any) is at the specified point,
1342 // giving details in 'flags' (see wxLIST_HITTEST_... flags above)
1343 long wxListCtrl::HitTest(const wxPoint
& point
, int& flags
)
1345 LV_HITTESTINFO hitTestInfo
;
1346 hitTestInfo
.pt
.x
= (int) point
.x
;
1347 hitTestInfo
.pt
.y
= (int) point
.y
;
1349 ListView_HitTest(GetHwnd(), & hitTestInfo
);
1352 if ( hitTestInfo
.flags
& LVHT_ABOVE
)
1353 flags
|= wxLIST_HITTEST_ABOVE
;
1354 if ( hitTestInfo
.flags
& LVHT_BELOW
)
1355 flags
|= wxLIST_HITTEST_BELOW
;
1356 if ( hitTestInfo
.flags
& LVHT_NOWHERE
)
1357 flags
|= wxLIST_HITTEST_NOWHERE
;
1358 if ( hitTestInfo
.flags
& LVHT_ONITEMICON
)
1359 flags
|= wxLIST_HITTEST_ONITEMICON
;
1360 if ( hitTestInfo
.flags
& LVHT_ONITEMLABEL
)
1361 flags
|= wxLIST_HITTEST_ONITEMLABEL
;
1362 if ( hitTestInfo
.flags
& LVHT_ONITEMSTATEICON
)
1363 flags
|= wxLIST_HITTEST_ONITEMSTATEICON
;
1364 if ( hitTestInfo
.flags
& LVHT_TOLEFT
)
1365 flags
|= wxLIST_HITTEST_TOLEFT
;
1366 if ( hitTestInfo
.flags
& LVHT_TORIGHT
)
1367 flags
|= wxLIST_HITTEST_TORIGHT
;
1369 return (long) hitTestInfo
.iItem
;
1372 // Inserts an item, returning the index of the new item if successful,
1374 long wxListCtrl::InsertItem(wxListItem
& info
)
1376 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual controls") );
1379 wxConvertToMSWListItem(this, info
, item
);
1380 item
.mask
&= ~LVIF_PARAM
;
1382 // check wether we need to allocate our internal data
1383 bool needInternalData
= ((info
.m_mask
& wxLIST_MASK_DATA
) || info
.HasAttributes());
1384 if (needInternalData
)
1386 m_AnyInternalData
= TRUE
;
1387 item
.mask
|= LVIF_PARAM
;
1389 // internal stucture that manages data
1390 wxListItemInternalData
*data
= new wxListItemInternalData();
1391 item
.lParam
= (LPARAM
) data
;
1393 if (info
.m_mask
& wxLIST_MASK_DATA
)
1394 data
->lParam
= info
.m_data
;
1396 // check whether it has any custom attributes
1397 if ( info
.HasAttributes() )
1399 // take copy of attributes
1400 data
->attr
= new wxListItemAttr(*info
.GetAttributes());
1405 return (long) ListView_InsertItem(GetHwnd(), & item
);
1408 long wxListCtrl::InsertItem(long index
, const wxString
& label
)
1411 info
.m_text
= label
;
1412 info
.m_mask
= wxLIST_MASK_TEXT
;
1413 info
.m_itemId
= index
;
1414 return InsertItem(info
);
1417 // Inserts an image item
1418 long wxListCtrl::InsertItem(long index
, int imageIndex
)
1421 info
.m_image
= imageIndex
;
1422 info
.m_mask
= wxLIST_MASK_IMAGE
;
1423 info
.m_itemId
= index
;
1424 return InsertItem(info
);
1427 // Inserts an image/string item
1428 long wxListCtrl::InsertItem(long index
, const wxString
& label
, int imageIndex
)
1431 info
.m_image
= imageIndex
;
1432 info
.m_text
= label
;
1433 info
.m_mask
= wxLIST_MASK_IMAGE
| wxLIST_MASK_TEXT
;
1434 info
.m_itemId
= index
;
1435 return InsertItem(info
);
1438 // For list view mode (only), inserts a column.
1439 long wxListCtrl::InsertColumn(long col
, wxListItem
& item
)
1442 wxConvertToMSWListCol(col
, item
, lvCol
);
1444 if ( !(lvCol
.mask
& LVCF_WIDTH
) )
1446 // always give some width to the new column: this one is compatible
1447 // with the generic version
1448 lvCol
.mask
|= LVCF_WIDTH
;
1452 // when we insert a column which can contain an image, we must specify this
1453 // flag right now as doing it later in SetColumn() has no effect
1455 // we use LVCFMT_BITMAP_ON_RIGHT by default because without it there is no
1456 // way to dynamically set/clear the bitmap as the column without a bitmap
1457 // on the left looks ugly (there is a hole)
1459 // unfortunately with my version of comctl32.dll (5.80), the left column
1460 // image is always on the left and it seems that it's a "feature" - I
1461 // didn't find any way to work around it in any case
1462 if ( lvCol
.mask
& LVCF_IMAGE
)
1464 lvCol
.mask
|= LVCF_FMT
;
1465 lvCol
.fmt
|= LVCFMT_BITMAP_ON_RIGHT
;
1468 bool success
= ListView_InsertColumn(GetHwnd(), col
, &lvCol
) != -1;
1475 wxLogDebug(wxT("Failed to insert the column '%s' into listview!"),
1482 long wxListCtrl::InsertColumn(long col
,
1483 const wxString
& heading
,
1488 item
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_FORMAT
;
1489 item
.m_text
= heading
;
1492 item
.m_mask
|= wxLIST_MASK_WIDTH
;
1493 item
.m_width
= width
;
1495 item
.m_format
= format
;
1497 return InsertColumn(col
, item
);
1500 // Scrolls the list control. If in icon, small icon or report view mode,
1501 // x specifies the number of pixels to scroll. If in list view mode, x
1502 // specifies the number of columns to scroll.
1503 // If in icon, small icon or list view mode, y specifies the number of pixels
1504 // to scroll. If in report view mode, y specifies the number of lines to scroll.
1505 bool wxListCtrl::ScrollList(int dx
, int dy
)
1507 return (ListView_Scroll(GetHwnd(), dx
, dy
) != 0);
1512 // fn is a function which takes 3 long arguments: item1, item2, data.
1513 // item1 is the long data associated with a first item (NOT the index).
1514 // item2 is the long data associated with a second item (NOT the index).
1515 // data is the same value as passed to SortItems.
1516 // The return value is a negative number if the first item should precede the second
1517 // item, a positive number of the second item should precede the first,
1518 // or zero if the two items are equivalent.
1520 // data is arbitrary data to be passed to the sort function.
1522 // Internal structures for proxying the user compare function
1523 // so that we can pass it the *real* user data
1525 // translate lParam data and call user func
1526 struct wxInternalDataSort
1528 wxListCtrlCompare user_fn
;
1532 int CALLBACK
wxInternalDataCompareFunc(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
1534 struct wxInternalDataSort
*internalData
= (struct wxInternalDataSort
*) lParamSort
;
1536 wxListItemInternalData
*data1
= (wxListItemInternalData
*) lParam1
;
1537 wxListItemInternalData
*data2
= (wxListItemInternalData
*) lParam2
;
1539 long d1
= (data1
== NULL
? 0 : data1
->lParam
);
1540 long d2
= (data2
== NULL
? 0 : data2
->lParam
);
1542 return internalData
->user_fn(d1
, d2
, internalData
->data
);
1546 bool wxListCtrl::SortItems(wxListCtrlCompare fn
, long data
)
1548 struct wxInternalDataSort internalData
;
1549 internalData
.user_fn
= fn
;
1550 internalData
.data
= data
;
1552 // WPARAM cast is needed for mingw/cygwin
1553 if ( !ListView_SortItems(GetHwnd(),
1554 wxInternalDataCompareFunc
,
1555 (WPARAM
) &internalData
) )
1557 wxLogDebug(_T("ListView_SortItems() failed"));
1567 // ----------------------------------------------------------------------------
1568 // message processing
1569 // ----------------------------------------------------------------------------
1571 bool wxListCtrl::MSWCommand(WXUINT cmd
, WXWORD id
)
1573 if (cmd
== EN_UPDATE
)
1575 wxCommandEvent
event(wxEVT_COMMAND_TEXT_UPDATED
, id
);
1576 event
.SetEventObject( this );
1577 ProcessCommand(event
);
1580 else if (cmd
== EN_KILLFOCUS
)
1582 wxCommandEvent
event(wxEVT_KILL_FOCUS
, id
);
1583 event
.SetEventObject( this );
1584 ProcessCommand(event
);
1591 bool wxListCtrl::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
*result
)
1593 // prepare the event
1594 // -----------------
1596 wxListEvent
event(wxEVT_NULL
, m_windowId
);
1597 event
.SetEventObject(this);
1599 wxEventType eventType
= wxEVT_NULL
;
1601 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
1603 // if your compiler is as broken as this, you should really change it: this
1604 // code is needed for normal operation! #ifdef below is only useful for
1605 // automatic rebuilds which are done with a very old compiler version
1606 #ifdef HDN_BEGINTRACKA
1608 // check for messages from the header (in report view)
1609 HWND hwndHdr
= ListView_GetHeader(GetHwnd());
1611 // is it a message from the header?
1612 if ( nmhdr
->hwndFrom
== hwndHdr
)
1614 HD_NOTIFY
*nmHDR
= (HD_NOTIFY
*)nmhdr
;
1616 event
.m_itemIndex
= -1;
1618 switch ( nmhdr
->code
)
1620 // yet another comctl32.dll bug: under NT/W2K it sends Unicode
1621 // TRACK messages even to ANSI programs: on my system I get
1622 // HDN_BEGINTRACKW and HDN_ENDTRACKA and no HDN_TRACK at all!
1624 // work around is to simply catch both versions and hope that it
1625 // works (why should this message exist in ANSI and Unicode is
1626 // beyond me as it doesn't deal with strings at all...)
1627 case HDN_BEGINTRACKA
:
1628 case HDN_BEGINTRACKW
:
1629 eventType
= wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
;
1634 if ( eventType
== wxEVT_NULL
)
1635 eventType
= wxEVT_COMMAND_LIST_COL_DRAGGING
;
1640 if ( eventType
== wxEVT_NULL
)
1641 eventType
= wxEVT_COMMAND_LIST_COL_END_DRAG
;
1642 event
.m_col
= nmHDR
->iItem
;
1647 eventType
= wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
;
1650 // find the column clicked: we have to search for it
1651 // ourselves as the notification message doesn't provide
1654 // where did the click occur?
1656 if ( !::GetCursorPos(&ptClick
) )
1658 wxLogLastError(_T("GetCursorPos"));
1661 if ( !::ScreenToClient(hwndHdr
, &ptClick
) )
1663 wxLogLastError(_T("ScreenToClient(listctrl header)"));
1666 event
.m_pointDrag
.x
= ptClick
.x
;
1667 event
.m_pointDrag
.y
= ptClick
.y
;
1669 int colCount
= Header_GetItemCount(hwndHdr
);
1672 for ( int col
= 0; col
< colCount
; col
++ )
1674 if ( Header_GetItemRect(hwndHdr
, col
, &rect
) )
1676 if ( ::PtInRect(&rect
, ptClick
) )
1687 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
1691 #endif // defined(HDN_BEGINTRACKA)
1692 if ( nmhdr
->hwndFrom
== GetHwnd() )
1694 // almost all messages use NM_LISTVIEW
1695 NM_LISTVIEW
*nmLV
= (NM_LISTVIEW
*)nmhdr
;
1697 // this is true for almost all events
1698 event
.m_item
.m_data
= nmLV
->lParam
;
1700 switch ( nmhdr
->code
)
1702 case LVN_BEGINRDRAG
:
1703 eventType
= wxEVT_COMMAND_LIST_BEGIN_RDRAG
;
1707 if ( eventType
== wxEVT_NULL
)
1709 eventType
= wxEVT_COMMAND_LIST_BEGIN_DRAG
;
1712 event
.m_itemIndex
= nmLV
->iItem
;
1713 event
.m_pointDrag
.x
= nmLV
->ptAction
.x
;
1714 event
.m_pointDrag
.y
= nmLV
->ptAction
.y
;
1717 // NB: we have to handle both *A and *W versions here because some
1718 // versions of comctl32.dll send ANSI message to an Unicode app
1719 case LVN_BEGINLABELEDITA
:
1721 eventType
= wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
;
1722 wxLV_ITEM
item(((LV_DISPINFOA
*)lParam
)->item
);
1723 wxConvertFromMSWListItem(GetHwnd(), event
.m_item
, item
);
1724 event
.m_itemIndex
= event
.m_item
.m_itemId
;
1727 case LVN_BEGINLABELEDITW
:
1729 eventType
= wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
;
1730 wxLV_ITEM
item(((LV_DISPINFOW
*)lParam
)->item
);
1731 wxConvertFromMSWListItem(GetHwnd(), event
.m_item
, item
);
1732 event
.m_itemIndex
= event
.m_item
.m_itemId
;
1736 case LVN_ENDLABELEDITA
:
1738 eventType
= wxEVT_COMMAND_LIST_END_LABEL_EDIT
;
1739 wxLV_ITEM
item(((LV_DISPINFOA
*)lParam
)->item
);
1740 wxConvertFromMSWListItem(NULL
, event
.m_item
, item
);
1741 if ( ((LV_ITEM
)item
).pszText
== NULL
||
1742 ((LV_ITEM
)item
).iItem
== -1 )
1745 event
.m_itemIndex
= event
.m_item
.m_itemId
;
1748 case LVN_ENDLABELEDITW
:
1750 eventType
= wxEVT_COMMAND_LIST_END_LABEL_EDIT
;
1751 wxLV_ITEM
item(((LV_DISPINFOW
*)lParam
)->item
);
1752 wxConvertFromMSWListItem(NULL
, event
.m_item
, item
);
1753 if ( ((LV_ITEM
)item
).pszText
== NULL
||
1754 ((LV_ITEM
)item
).iItem
== -1 )
1757 event
.m_itemIndex
= event
.m_item
.m_itemId
;
1761 case LVN_COLUMNCLICK
:
1762 eventType
= wxEVT_COMMAND_LIST_COL_CLICK
;
1763 event
.m_itemIndex
= -1;
1764 event
.m_col
= nmLV
->iSubItem
;
1767 case LVN_DELETEALLITEMS
:
1768 eventType
= wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
;
1769 event
.m_itemIndex
= -1;
1772 case LVN_DELETEITEM
:
1773 eventType
= wxEVT_COMMAND_LIST_DELETE_ITEM
;
1774 event
.m_itemIndex
= nmLV
->iItem
;
1776 // delete the assoicated internal data
1778 wxListItemInternalData
*data
=
1779 GetInternalData(this, nmLV
->iItem
);
1785 case LVN_SETDISPINFO
:
1787 eventType
= wxEVT_COMMAND_LIST_SET_INFO
;
1788 LV_DISPINFO
*info
= (LV_DISPINFO
*)lParam
;
1789 wxConvertFromMSWListItem(GetHwnd(), event
.m_item
, info
->item
);
1793 case LVN_INSERTITEM
:
1794 eventType
= wxEVT_COMMAND_LIST_INSERT_ITEM
;
1795 event
.m_itemIndex
= nmLV
->iItem
;
1798 case LVN_ITEMCHANGED
:
1799 // we translate this catch all message into more interesting
1800 // (and more easy to process) wxWindows events
1802 // first of all, we deal with the state change events only
1803 if ( nmLV
->uChanged
& LVIF_STATE
)
1805 // temp vars for readability
1806 const UINT stOld
= nmLV
->uOldState
;
1807 const UINT stNew
= nmLV
->uNewState
;
1809 // has the focus changed?
1810 if ( !(stOld
& LVIS_FOCUSED
) && (stNew
& LVIS_FOCUSED
) )
1812 eventType
= wxEVT_COMMAND_LIST_ITEM_FOCUSED
;
1813 event
.m_itemIndex
= nmLV
->iItem
;
1816 if ( (stNew
& LVIS_SELECTED
) != (stOld
& LVIS_SELECTED
) )
1818 if ( eventType
!= wxEVT_NULL
)
1820 // focus and selection have both changed: send the
1821 // focus event from here and the selection one
1823 event
.SetEventType(eventType
);
1824 (void)GetEventHandler()->ProcessEvent(event
);
1826 else // no focus event to send
1828 // then need to set m_itemIndex as it wasn't done
1830 event
.m_itemIndex
= nmLV
->iItem
;
1833 eventType
= stNew
& LVIS_SELECTED
1834 ? wxEVT_COMMAND_LIST_ITEM_SELECTED
1835 : wxEVT_COMMAND_LIST_ITEM_DESELECTED
;
1839 if ( eventType
== wxEVT_NULL
)
1841 // not an interesting event for us
1849 LV_KEYDOWN
*info
= (LV_KEYDOWN
*)lParam
;
1850 WORD wVKey
= info
->wVKey
;
1852 // get the current selection
1853 long lItem
= GetNextItem(-1,
1855 wxLIST_STATE_SELECTED
);
1857 // <Enter> or <Space> activate the selected item if any (but
1858 // not with Shift and/or Ctrl as then they have a predefined
1859 // meaning for the list view)
1861 (wVKey
== VK_RETURN
|| wVKey
== VK_SPACE
) &&
1862 !(wxIsShiftDown() || wxIsCtrlDown()) )
1864 eventType
= wxEVT_COMMAND_LIST_ITEM_ACTIVATED
;
1868 eventType
= wxEVT_COMMAND_LIST_KEY_DOWN
;
1870 // wxCharCodeMSWToWX() returns 0 if the key is an ASCII
1871 // value which should be used as is
1872 int code
= wxCharCodeMSWToWX(wVKey
);
1873 event
.m_code
= code
? code
: wVKey
;
1877 event
.m_item
.m_itemId
= lItem
;
1881 // fill the other fields too
1882 event
.m_item
.m_text
= GetItemText(lItem
);
1883 event
.m_item
.m_data
= GetItemData(lItem
);
1889 // if the user processes it in wxEVT_COMMAND_LEFT_CLICK(), don't do
1891 if ( wxControl::MSWOnNotify(idCtrl
, lParam
, result
) )
1896 // else translate it into wxEVT_COMMAND_LIST_ITEM_ACTIVATED event
1897 // if it happened on an item (and not on empty place)
1898 if ( nmLV
->iItem
== -1 )
1904 eventType
= wxEVT_COMMAND_LIST_ITEM_ACTIVATED
;
1905 event
.m_itemIndex
= nmLV
->iItem
;
1906 event
.m_item
.m_text
= GetItemText(nmLV
->iItem
);
1907 event
.m_item
.m_data
= GetItemData(nmLV
->iItem
);
1911 // if the user processes it in wxEVT_COMMAND_RIGHT_CLICK(),
1912 // don't do anything else
1913 if ( wxControl::MSWOnNotify(idCtrl
, lParam
, result
) )
1918 // else translate it into wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK event
1919 LV_HITTESTINFO lvhti
;
1920 wxZeroMemory(lvhti
);
1922 ::GetCursorPos(&(lvhti
.pt
));
1923 ::ScreenToClient(GetHwnd(),&(lvhti
.pt
));
1924 if ( ListView_HitTest(GetHwnd(),&lvhti
) != -1 )
1926 if ( lvhti
.flags
& LVHT_ONITEM
)
1928 eventType
= wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
;
1929 event
.m_itemIndex
= lvhti
.iItem
;
1930 event
.m_pointDrag
.x
= lvhti
.pt
.x
;
1931 event
.m_pointDrag
.y
= lvhti
.pt
.y
;
1936 #if defined(_WIN32_IE) && _WIN32_IE >= 0x300 \
1937 && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) )
1939 *result
= OnCustomDraw(lParam
);
1942 #endif // _WIN32_IE >= 0x300
1944 case LVN_ODCACHEHINT
:
1946 const NM_CACHEHINT
*cacheHint
= (NM_CACHEHINT
*)lParam
;
1948 eventType
= wxEVT_COMMAND_LIST_CACHE_HINT
;
1950 // we get some really stupid cache hints like ones for items in
1951 // range 0..0 for an empty control or, after deleting an item,
1952 // for items in invalid range - filter this garbage out
1953 if ( cacheHint
->iFrom
< cacheHint
->iTo
)
1955 event
.m_oldItemIndex
= cacheHint
->iFrom
;
1957 long iMax
= GetItemCount();
1958 event
.m_itemIndex
= cacheHint
->iTo
< iMax
? cacheHint
->iTo
1968 case LVN_GETDISPINFO
:
1971 LV_DISPINFO
*info
= (LV_DISPINFO
*)lParam
;
1973 LV_ITEM
& lvi
= info
->item
;
1974 long item
= lvi
.iItem
;
1976 if ( lvi
.mask
& LVIF_TEXT
)
1978 wxString text
= OnGetItemText(item
, lvi
.iSubItem
);
1979 wxStrncpy(lvi
.pszText
, text
, lvi
.cchTextMax
);
1982 #if defined(_WIN32_IE) && _WIN32_IE >= 0x300 \
1983 && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 1 ) )
1984 if ( lvi
.mask
& LVIF_IMAGE
)
1986 lvi
.iImage
= OnGetItemImage(item
);
1990 // a little dose of healthy paranoia: as we never use
1991 // LVM_SETCALLBACKMASK we're not supposed to get these ones
1992 wxASSERT_MSG( !(lvi
.mask
& LVIF_STATE
),
1993 _T("we don't support state callbacks yet!") );
2000 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
2005 // where did this one come from?
2009 // process the event
2010 // -----------------
2012 event
.SetEventType(eventType
);
2014 if ( !GetEventHandler()->ProcessEvent(event
) )
2020 switch ( nmhdr
->code
)
2022 case LVN_DELETEALLITEMS
:
2023 // always return TRUE to suppress all additional LVN_DELETEITEM
2024 // notifications - this makes deleting all items from a list ctrl
2030 case LVN_ENDLABELEDITA
:
2031 case LVN_ENDLABELEDITW
:
2032 // logic here is inversed compared to all the other messages
2033 *result
= event
.IsAllowed();
2038 *result
= !event
.IsAllowed();
2043 #if defined(_WIN32_IE) && _WIN32_IE >= 0x300
2045 WXLPARAM
wxListCtrl::OnCustomDraw(WXLPARAM lParam
)
2047 LPNMLVCUSTOMDRAW lplvcd
= (LPNMLVCUSTOMDRAW
)lParam
;
2048 NMCUSTOMDRAW
& nmcd
= lplvcd
->nmcd
;
2049 switch ( nmcd
.dwDrawStage
)
2052 // if we've got any items with non standard attributes,
2053 // notify us before painting each item
2055 // for virtual controls, always suppose that we have attributes as
2056 // there is no way to check for this
2057 return IsVirtual() || m_hasAnyAttr
? CDRF_NOTIFYITEMDRAW
2060 case CDDS_ITEMPREPAINT
:
2062 size_t item
= (size_t)nmcd
.dwItemSpec
;
2063 if ( item
>= (size_t)GetItemCount() )
2065 // we get this message with item == 0 for an empty control,
2066 // we must ignore it as calling OnGetItemAttr() would be
2068 return CDRF_DODEFAULT
;
2071 wxListItemAttr
*attr
=
2072 IsVirtual() ? OnGetItemAttr(item
)
2073 : GetInternalDataAttr(this, item
);
2077 // nothing to do for this item
2078 return CDRF_DODEFAULT
;
2082 wxColour colText
, colBack
;
2083 if ( attr
->HasFont() )
2085 wxFont font
= attr
->GetFont();
2086 hFont
= (HFONT
)font
.GetResourceHandle();
2093 if ( attr
->HasTextColour() )
2095 colText
= attr
->GetTextColour();
2099 colText
= GetTextColour();
2102 if ( attr
->HasBackgroundColour() )
2104 colBack
= attr
->GetBackgroundColour();
2108 colBack
= GetBackgroundColour();
2111 lplvcd
->clrText
= wxColourToRGB(colText
);
2112 lplvcd
->clrTextBk
= wxColourToRGB(colBack
);
2114 // note that if we wanted to set colours for
2115 // individual columns (subitems), we would have
2116 // returned CDRF_NOTIFYSUBITEMREDRAW from here
2119 ::SelectObject(nmcd
.hdc
, hFont
);
2121 return CDRF_NEWFONT
;
2124 // fall through to return CDRF_DODEFAULT
2127 return CDRF_DODEFAULT
;
2131 #endif // NM_CUSTOMDRAW supported
2133 // Necessary for drawing hrules and vrules, if specified
2134 void wxListCtrl::OnPaint(wxPaintEvent
& event
)
2138 wxControl::OnPaint(event
);
2140 // Reset the device origin since it may have been set
2141 dc
.SetDeviceOrigin(0, 0);
2143 bool drawHRules
= ((GetWindowStyle() & wxLC_HRULES
) != 0);
2144 bool drawVRules
= ((GetWindowStyle() & wxLC_VRULES
) != 0);
2146 if (!drawHRules
&& !drawVRules
)
2148 if ((GetWindowStyle() & wxLC_REPORT
) == 0)
2151 wxPen
pen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
);
2153 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
2155 wxSize clientSize
= GetClientSize();
2159 int itemCount
= GetItemCount();
2163 long top
= GetTopItem();
2164 for (i
= top
; i
< top
+ GetCountPerPage() + 1; i
++)
2166 if (GetItemRect(i
, itemRect
))
2168 cy
= itemRect
.GetTop();
2169 if (i
!= 0) // Don't draw the first one
2171 dc
.DrawLine(0, cy
, clientSize
.x
, cy
);
2174 if (i
== itemCount
- 1)
2176 cy
= itemRect
.GetBottom();
2177 dc
.DrawLine(0, cy
, clientSize
.x
, cy
);
2183 if (drawVRules
&& (i
> -1))
2185 wxRect firstItemRect
;
2186 GetItemRect(0, firstItemRect
);
2188 if (GetItemRect(i
, itemRect
))
2191 int x
= itemRect
.GetX();
2192 for (col
= 0; col
< GetColumnCount(); col
++)
2194 int colWidth
= GetColumnWidth(col
);
2196 dc
.DrawLine(x
, firstItemRect
.GetY() - 2, x
, itemRect
.GetBottom());
2202 // ----------------------------------------------------------------------------
2203 // virtual list controls
2204 // ----------------------------------------------------------------------------
2206 wxString
wxListCtrl::OnGetItemText(long WXUNUSED(item
), long WXUNUSED(col
)) const
2208 // this is a pure virtual function, in fact - which is not really pure
2209 // because the controls which are not virtual don't need to implement it
2210 wxFAIL_MSG( _T("not supposed to be called") );
2212 return wxEmptyString
;
2215 int wxListCtrl::OnGetItemImage(long WXUNUSED(item
)) const
2218 wxFAIL_MSG( _T("not supposed to be called") );
2223 wxListItemAttr
*wxListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item
)) const
2225 wxASSERT_MSG( item
>= 0 && item
< GetItemCount(),
2226 _T("invalid item index in OnGetItemAttr()") );
2228 // no attributes by default
2232 void wxListCtrl::SetItemCount(long count
)
2234 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
2236 if ( !::SendMessage(GetHwnd(), LVM_SETITEMCOUNT
, (WPARAM
)count
, 0) )
2238 wxLogLastError(_T("ListView_SetItemCount"));
2242 void wxListCtrl::RefreshItem(long item
)
2244 // strangely enough, ListView_Update() results in much more flicker here
2245 // than a dumb Refresh() -- why?
2247 if ( !ListView_Update(GetHwnd(), item
) )
2249 wxLogLastError(_T("ListView_Update"));
2253 GetItemRect(item
, rect
);
2258 void wxListCtrl::RefreshItems(long itemFrom
, long itemTo
)
2260 wxRect rect1
, rect2
;
2261 GetItemRect(itemFrom
, rect1
);
2262 GetItemRect(itemTo
, rect2
);
2264 wxRect rect
= rect1
;
2265 rect
.height
= rect2
.GetBottom() - rect1
.GetTop();
2270 static wxListItemInternalData
*GetInternalData(HWND hwnd
, long itemId
)
2273 it
.mask
= LVIF_PARAM
;
2276 bool success
= ListView_GetItem(hwnd
, &it
) != 0;
2278 return (wxListItemInternalData
*) it
.lParam
;
2283 static wxListItemInternalData
*GetInternalData(wxListCtrl
*ctl
, long itemId
)
2285 return GetInternalData((HWND
) ctl
->GetHWND(), itemId
);
2288 static wxListItemAttr
*GetInternalDataAttr(wxListCtrl
*ctl
, long itemId
)
2290 wxListItemInternalData
*data
= GetInternalData(ctl
, itemId
);
2298 static void wxConvertFromMSWListItem(HWND hwndListCtrl
,
2302 wxListItemInternalData
*internaldata
=
2303 (wxListItemInternalData
*) lvItem
.lParam
;
2306 info
.m_data
= internaldata
->lParam
;
2310 info
.m_stateMask
= 0;
2311 info
.m_itemId
= lvItem
.iItem
;
2313 long oldMask
= lvItem
.mask
;
2315 bool needText
= FALSE
;
2316 if (hwndListCtrl
!= 0)
2318 if ( lvItem
.mask
& LVIF_TEXT
)
2325 lvItem
.pszText
= new wxChar
[513];
2326 lvItem
.cchTextMax
= 512;
2328 lvItem
.mask
|= LVIF_TEXT
| LVIF_IMAGE
| LVIF_PARAM
;
2329 ::SendMessage(hwndListCtrl
, LVM_GETITEM
, 0, (LPARAM
)& lvItem
);
2332 if ( lvItem
.mask
& LVIF_STATE
)
2334 info
.m_mask
|= wxLIST_MASK_STATE
;
2336 if ( lvItem
.stateMask
& LVIS_CUT
)
2338 info
.m_stateMask
|= wxLIST_STATE_CUT
;
2339 if ( lvItem
.state
& LVIS_CUT
)
2340 info
.m_state
|= wxLIST_STATE_CUT
;
2342 if ( lvItem
.stateMask
& LVIS_DROPHILITED
)
2344 info
.m_stateMask
|= wxLIST_STATE_DROPHILITED
;
2345 if ( lvItem
.state
& LVIS_DROPHILITED
)
2346 info
.m_state
|= wxLIST_STATE_DROPHILITED
;
2348 if ( lvItem
.stateMask
& LVIS_FOCUSED
)
2350 info
.m_stateMask
|= wxLIST_STATE_FOCUSED
;
2351 if ( lvItem
.state
& LVIS_FOCUSED
)
2352 info
.m_state
|= wxLIST_STATE_FOCUSED
;
2354 if ( lvItem
.stateMask
& LVIS_SELECTED
)
2356 info
.m_stateMask
|= wxLIST_STATE_SELECTED
;
2357 if ( lvItem
.state
& LVIS_SELECTED
)
2358 info
.m_state
|= wxLIST_STATE_SELECTED
;
2362 if ( lvItem
.mask
& LVIF_TEXT
)
2364 info
.m_mask
|= wxLIST_MASK_TEXT
;
2365 info
.m_text
= lvItem
.pszText
;
2367 if ( lvItem
.mask
& LVIF_IMAGE
)
2369 info
.m_mask
|= wxLIST_MASK_IMAGE
;
2370 info
.m_image
= lvItem
.iImage
;
2372 if ( lvItem
.mask
& LVIF_PARAM
)
2373 info
.m_mask
|= wxLIST_MASK_DATA
;
2374 if ( lvItem
.mask
& LVIF_DI_SETITEM
)
2375 info
.m_mask
|= wxLIST_SET_ITEM
;
2376 info
.m_col
= lvItem
.iSubItem
;
2381 delete[] lvItem
.pszText
;
2383 lvItem
.mask
= oldMask
;
2386 static void wxConvertToMSWFlags(long state
, long stateMask
, LV_ITEM
& lvItem
)
2388 if (stateMask
& wxLIST_STATE_CUT
)
2390 lvItem
.stateMask
|= LVIS_CUT
;
2391 if (state
& wxLIST_STATE_CUT
)
2392 lvItem
.state
|= LVIS_CUT
;
2394 if (stateMask
& wxLIST_STATE_DROPHILITED
)
2396 lvItem
.stateMask
|= LVIS_DROPHILITED
;
2397 if (state
& wxLIST_STATE_DROPHILITED
)
2398 lvItem
.state
|= LVIS_DROPHILITED
;
2400 if (stateMask
& wxLIST_STATE_FOCUSED
)
2402 lvItem
.stateMask
|= LVIS_FOCUSED
;
2403 if (state
& wxLIST_STATE_FOCUSED
)
2404 lvItem
.state
|= LVIS_FOCUSED
;
2406 if (stateMask
& wxLIST_STATE_SELECTED
)
2408 lvItem
.stateMask
|= LVIS_SELECTED
;
2409 if (state
& wxLIST_STATE_SELECTED
)
2410 lvItem
.state
|= LVIS_SELECTED
;
2414 static void wxConvertToMSWListItem(const wxListCtrl
*ctrl
,
2415 const wxListItem
& info
,
2418 lvItem
.iItem
= (int) info
.m_itemId
;
2420 lvItem
.iImage
= info
.m_image
;
2421 lvItem
.stateMask
= 0;
2424 lvItem
.iSubItem
= info
.m_col
;
2426 if (info
.m_mask
& wxLIST_MASK_STATE
)
2428 lvItem
.mask
|= LVIF_STATE
;
2430 wxConvertToMSWFlags(info
.m_state
, info
.m_stateMask
, lvItem
);
2433 if (info
.m_mask
& wxLIST_MASK_TEXT
)
2435 lvItem
.mask
|= LVIF_TEXT
;
2436 if ( ctrl
->GetWindowStyleFlag() & wxLC_USER_TEXT
)
2438 lvItem
.pszText
= LPSTR_TEXTCALLBACK
;
2442 // pszText is not const, hence the cast
2443 lvItem
.pszText
= (wxChar
*)info
.m_text
.c_str();
2444 if ( lvItem
.pszText
)
2445 lvItem
.cchTextMax
= info
.m_text
.Length();
2447 lvItem
.cchTextMax
= 0;
2450 if (info
.m_mask
& wxLIST_MASK_IMAGE
)
2451 lvItem
.mask
|= LVIF_IMAGE
;
2454 static void wxConvertToMSWListCol(int WXUNUSED(col
), const wxListItem
& item
,
2457 wxZeroMemory(lvCol
);
2459 if ( item
.m_mask
& wxLIST_MASK_TEXT
)
2461 lvCol
.mask
|= LVCF_TEXT
;
2462 lvCol
.pszText
= (wxChar
*)item
.m_text
.c_str(); // cast is safe
2465 if ( item
.m_mask
& wxLIST_MASK_FORMAT
)
2467 lvCol
.mask
|= LVCF_FMT
;
2469 if ( item
.m_format
== wxLIST_FORMAT_LEFT
)
2470 lvCol
.fmt
= LVCFMT_LEFT
;
2471 else if ( item
.m_format
== wxLIST_FORMAT_RIGHT
)
2472 lvCol
.fmt
= LVCFMT_RIGHT
;
2473 else if ( item
.m_format
== wxLIST_FORMAT_CENTRE
)
2474 lvCol
.fmt
= LVCFMT_CENTER
;
2477 if ( item
.m_mask
& wxLIST_MASK_WIDTH
)
2479 lvCol
.mask
|= LVCF_WIDTH
;
2480 if ( item
.m_width
== wxLIST_AUTOSIZE
)
2481 lvCol
.cx
= LVSCW_AUTOSIZE
;
2482 else if ( item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
2483 lvCol
.cx
= LVSCW_AUTOSIZE_USEHEADER
;
2485 lvCol
.cx
= item
.m_width
;
2488 #if defined(_WIN32_IE) && _WIN32_IE >= 0x300 \
2489 && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 1 ) )
2490 if ( item
.m_mask
& wxLIST_MASK_IMAGE
)
2492 if ( wxTheApp
->GetComCtl32Version() >= 470 )
2494 lvCol
.mask
|= LVCF_IMAGE
;
2495 lvCol
.iImage
= item
.m_image
;
2497 //else: it doesn't support item images anyhow
2502 #endif // wxUSE_LISTCTRL