1 /////////////////////////////////////////////////////////////////////////////
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"
56 (LVHT_ONITEMICON | LVHT_ONITEMLABEL | LVHT_ONITEMSTATEICON)
59 #ifndef LVM_SETEXTENDEDLISTVIEWSTYLE
60 #define LVM_SETEXTENDEDLISTVIEWSTYLE (0x1000 + 54)
63 #ifndef LVS_EX_FULLROWSELECT
64 #define LVS_EX_FULLROWSELECT 0x00000020
68 #define LVS_OWNERDATA 0x1000
71 // mingw32/cygwin don't have declarations for comctl32.dll 4.70+ stuff
73 typedef struct tagNMLVCACHEHINT
80 #define NM_CACHEHINT NMLVCACHEHINT
83 #ifndef LVN_ODCACHEHINT
84 #define LVN_ODCACHEHINT (-113)
87 #ifndef ListView_GetHeader
88 #define ListView_GetHeader(w) (HWND)SendMessage((w),LVM_GETHEADER,0,0)
92 #define LVM_GETHEADER (LVM_FIRST+31)
95 #ifndef Header_GetItemRect
96 #define Header_GetItemRect(w,i,r) \
97 (BOOL)SendMessage((w),HDM_GETITEMRECT,(WPARAM)(i),(LPARAM)(r))
100 #ifndef HDM_GETITEMRECT
101 #define HDM_GETITEMRECT (HDM_FIRST+7)
104 // ----------------------------------------------------------------------------
106 // ----------------------------------------------------------------------------
108 // convert our state and mask flags to LV_ITEM constants
109 static void wxConvertToMSWFlags(long state
, long mask
, LV_ITEM
& lvItem
);
111 // convert wxListItem to LV_ITEM
112 static void wxConvertToMSWListItem(const wxListCtrl
*ctrl
,
113 const wxListItem
& info
, LV_ITEM
& lvItem
);
115 // convert LV_ITEM to wxListItem
116 static void wxConvertFromMSWListItem(HWND hwndListCtrl
,
118 /* const */ LV_ITEM
& lvItem
);
120 // ----------------------------------------------------------------------------
122 // ----------------------------------------------------------------------------
124 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG
)
125 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG
)
126 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
)
127 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT
)
128 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM
)
129 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
)
130 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO
)
131 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO
)
132 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED
)
133 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED
)
134 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN
)
135 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM
)
136 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK
)
137 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
)
138 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
)
139 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING
)
140 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG
)
141 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
)
142 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
)
143 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED
)
144 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT
)
146 IMPLEMENT_DYNAMIC_CLASS(wxListCtrl
, wxControl
)
147 IMPLEMENT_DYNAMIC_CLASS(wxListView
, wxListCtrl
)
148 IMPLEMENT_DYNAMIC_CLASS(wxListItem
, wxObject
)
150 BEGIN_EVENT_TABLE(wxListCtrl
, wxControl
)
151 EVT_PAINT(wxListCtrl::OnPaint
)
154 // ============================================================================
156 // ============================================================================
158 // ----------------------------------------------------------------------------
160 // ----------------------------------------------------------------------------
162 void wxListEvent::CopyObject(wxObject
& object_dest
) const
164 wxListEvent
*obj
= (wxListEvent
*)&object_dest
;
166 wxNotifyEvent::CopyObject(object_dest
);
168 obj
->m_code
= m_code
;
169 obj
->m_itemIndex
= m_itemIndex
;
170 obj
->m_oldItemIndex
= m_oldItemIndex
;
172 obj
->m_cancelled
= m_cancelled
;
173 obj
->m_pointDrag
= m_pointDrag
;
174 obj
->m_item
.m_mask
= m_item
.m_mask
;
175 obj
->m_item
.m_itemId
= m_item
.m_itemId
;
176 obj
->m_item
.m_col
= m_item
.m_col
;
177 obj
->m_item
.m_state
= m_item
.m_state
;
178 obj
->m_item
.m_stateMask
= m_item
.m_stateMask
;
179 obj
->m_item
.m_text
= m_item
.m_text
;
180 obj
->m_item
.m_image
= m_item
.m_image
;
181 obj
->m_item
.m_data
= m_item
.m_data
;
182 obj
->m_item
.m_format
= m_item
.m_format
;
183 obj
->m_item
.m_width
= m_item
.m_width
;
185 if ( m_item
.HasAttributes() )
187 obj
->m_item
.SetTextColour(m_item
.GetTextColour());
188 obj
->m_item
.SetBackgroundColour(m_item
.GetBackgroundColour());
189 obj
->m_item
.SetFont(m_item
.GetFont());
193 // ----------------------------------------------------------------------------
194 // wxListCtrl construction
195 // ----------------------------------------------------------------------------
197 void wxListCtrl::Init()
199 m_imageListNormal
= NULL
;
200 m_imageListSmall
= NULL
;
201 m_imageListState
= NULL
;
202 m_ownsImageListNormal
= m_ownsImageListSmall
= m_ownsImageListState
= FALSE
;
206 m_hasAnyAttr
= FALSE
;
209 bool wxListCtrl::Create(wxWindow
*parent
,
214 const wxValidator
& validator
,
215 const wxString
& name
)
218 SetValidator(validator
);
219 #endif // wxUSE_VALIDATORS
228 m_windowStyle
= style
;
241 m_windowId
= (id
== -1) ? NewControlId() : id
;
243 DWORD wstyle
= WS_VISIBLE
| WS_CHILD
| WS_TABSTOP
|
244 LVS_SHAREIMAGELISTS
| LVS_SHOWSELALWAYS
;
246 if ( m_windowStyle
& wxCLIP_SIBLINGS
)
247 wstyle
|= WS_CLIPSIBLINGS
;
249 if ( wxStyleHasBorder(m_windowStyle
) )
251 m_baseStyle
= wstyle
;
253 if ( !DoCreateControl(x
, y
, width
, height
) )
257 parent
->AddChild(this);
262 bool wxListCtrl::DoCreateControl(int x
, int y
, int w
, int h
)
264 DWORD wstyle
= m_baseStyle
;
267 WXDWORD exStyle
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
);
269 // Even with extended styles, need to combine with WS_BORDER
270 // for them to look right.
274 long oldStyle
= 0; // Dummy
275 wstyle
|= ConvertToMSWStyle(oldStyle
, m_windowStyle
);
277 // Create the ListView control.
278 m_hWnd
= (WXHWND
)CreateWindowEx(exStyle
,
283 GetWinHwnd(GetParent()),
290 wxLogError(_("Can't create list control window, check that comctl32.dll is installed."));
295 // for comctl32.dll v 4.70+ we want to have this attribute because it's
296 // prettier (and also because wxGTK does it like this)
297 if ( (wstyle
& LVS_REPORT
) && wxTheApp
->GetComCtl32Version() >= 470 )
299 ::SendMessage(GetHwnd(), LVM_SETEXTENDEDLISTVIEWSTYLE
,
300 0, LVS_EX_FULLROWSELECT
);
303 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW
));
304 SetForegroundColour(GetParent()->GetForegroundColour());
311 void wxListCtrl::UpdateStyle()
315 // The new window view style
317 DWORD dwStyleNew
= ConvertToMSWStyle(dummy
, m_windowStyle
);
318 dwStyleNew
|= m_baseStyle
;
320 // Get the current window style.
321 DWORD dwStyleOld
= ::GetWindowLong(GetHwnd(), GWL_STYLE
);
323 // Only set the window style if the view bits have changed.
324 if ( dwStyleOld
!= dwStyleNew
)
326 ::SetWindowLong(GetHwnd(), GWL_STYLE
, dwStyleNew
);
331 void wxListCtrl::FreeAllAttrs(bool dontRecreate
)
335 for ( wxNode
*node
= m_attrs
.Next(); node
; node
= m_attrs
.Next() )
337 delete (wxListItemAttr
*)node
->Data();
343 m_attrs
.Create(wxKEY_INTEGER
, 1000); // just as def ctor
346 m_hasAnyAttr
= FALSE
;
350 wxListCtrl::~wxListCtrl()
352 FreeAllAttrs(TRUE
/* no need to recreate hash any more */);
356 m_textCtrl
->SetHWND(0);
357 m_textCtrl
->UnsubclassWin();
362 if (m_ownsImageListNormal
) delete m_imageListNormal
;
363 if (m_ownsImageListSmall
) delete m_imageListSmall
;
364 if (m_ownsImageListState
) delete m_imageListState
;
367 // ----------------------------------------------------------------------------
368 // set/get/change style
369 // ----------------------------------------------------------------------------
371 // Add or remove a single window style
372 void wxListCtrl::SetSingleStyle(long style
, bool add
)
374 long flag
= GetWindowStyleFlag();
376 // Get rid of conflicting styles
379 if ( style
& wxLC_MASK_TYPE
)
380 flag
= flag
& ~wxLC_MASK_TYPE
;
381 if ( style
& wxLC_MASK_ALIGN
)
382 flag
= flag
& ~wxLC_MASK_ALIGN
;
383 if ( style
& wxLC_MASK_SORT
)
384 flag
= flag
& ~wxLC_MASK_SORT
;
400 m_windowStyle
= flag
;
405 // Set the whole window style
406 void wxListCtrl::SetWindowStyleFlag(long flag
)
408 m_windowStyle
= flag
;
413 // Can be just a single style, or a bitlist
414 long wxListCtrl::ConvertToMSWStyle(long& oldStyle
, long style
) const
417 if ( style
& wxLC_ICON
)
419 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_SMALLICON
)
420 oldStyle
-= LVS_SMALLICON
;
421 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_REPORT
)
422 oldStyle
-= LVS_REPORT
;
423 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_LIST
)
424 oldStyle
-= LVS_LIST
;
428 if ( style
& wxLC_SMALL_ICON
)
430 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_ICON
)
431 oldStyle
-= LVS_ICON
;
432 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_REPORT
)
433 oldStyle
-= LVS_REPORT
;
434 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_LIST
)
435 oldStyle
-= LVS_LIST
;
436 wstyle
|= LVS_SMALLICON
;
439 if ( style
& wxLC_LIST
)
441 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_ICON
)
442 oldStyle
-= LVS_ICON
;
443 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_REPORT
)
444 oldStyle
-= LVS_REPORT
;
445 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_SMALLICON
)
446 oldStyle
-= LVS_SMALLICON
;
450 if ( style
& wxLC_REPORT
)
452 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_ICON
)
453 oldStyle
-= LVS_ICON
;
454 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_LIST
)
455 oldStyle
-= LVS_LIST
;
456 if ( (oldStyle
& LVS_TYPEMASK
) == LVS_SMALLICON
)
457 oldStyle
-= LVS_SMALLICON
;
459 wstyle
|= LVS_REPORT
;
462 if ( style
& wxLC_ALIGN_LEFT
)
464 if ( oldStyle
& LVS_ALIGNTOP
)
465 oldStyle
-= LVS_ALIGNTOP
;
466 wstyle
|= LVS_ALIGNLEFT
;
469 if ( style
& wxLC_ALIGN_TOP
)
471 if ( oldStyle
& LVS_ALIGNLEFT
)
472 oldStyle
-= LVS_ALIGNLEFT
;
473 wstyle
|= LVS_ALIGNTOP
;
476 if ( style
& wxLC_AUTOARRANGE
)
477 wstyle
|= LVS_AUTOARRANGE
;
479 if ( style
& wxLC_NO_SORT_HEADER
)
480 wstyle
|= LVS_NOSORTHEADER
;
482 if ( style
& wxLC_NO_HEADER
)
483 wstyle
|= LVS_NOCOLUMNHEADER
;
485 if ( style
& wxLC_EDIT_LABELS
)
486 wstyle
|= LVS_EDITLABELS
;
488 if ( style
& wxLC_SINGLE_SEL
)
489 wstyle
|= LVS_SINGLESEL
;
491 if ( style
& wxLC_SORT_ASCENDING
)
493 if ( oldStyle
& LVS_SORTDESCENDING
)
494 oldStyle
-= LVS_SORTDESCENDING
;
495 wstyle
|= LVS_SORTASCENDING
;
498 if ( style
& wxLC_SORT_DESCENDING
)
500 if ( oldStyle
& LVS_SORTASCENDING
)
501 oldStyle
-= LVS_SORTASCENDING
;
502 wstyle
|= LVS_SORTDESCENDING
;
505 #if !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) )
506 if ( style
& wxLC_VIRTUAL
)
508 int ver
= wxTheApp
->GetComCtl32Version();
511 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."),
512 ver
/ 100, ver
% 100);
515 wstyle
|= LVS_OWNERDATA
;
522 // ----------------------------------------------------------------------------
524 // ----------------------------------------------------------------------------
526 // Sets the foreground, i.e. text, colour
527 bool wxListCtrl::SetForegroundColour(const wxColour
& col
)
529 if ( !wxWindow::SetForegroundColour(col
) )
532 ListView_SetTextColor(GetHwnd(), wxColourToRGB(col
));
537 // Sets the background colour
538 bool wxListCtrl::SetBackgroundColour(const wxColour
& col
)
540 if ( !wxWindow::SetBackgroundColour(col
) )
543 // we set the same colour for both the "empty" background and the items
545 COLORREF color
= wxColourToRGB(col
);
546 ListView_SetBkColor(GetHwnd(), color
);
547 ListView_SetTextBkColor(GetHwnd(), color
);
552 // Gets information about this column
553 bool wxListCtrl::GetColumn(int col
, wxListItem
& item
) const
558 lvCol
.pszText
= NULL
;
560 if ( item
.m_mask
& wxLIST_MASK_TEXT
)
562 lvCol
.mask
|= LVCF_TEXT
;
563 lvCol
.pszText
= new wxChar
[513];
564 lvCol
.cchTextMax
= 512;
567 bool success
= (ListView_GetColumn(GetHwnd(), col
, & lvCol
) != 0);
569 // item.m_subItem = lvCol.iSubItem;
570 item
.m_width
= lvCol
.cx
;
572 if ( (item
.m_mask
& wxLIST_MASK_TEXT
) && lvCol
.pszText
)
574 item
.m_text
= lvCol
.pszText
;
575 delete[] lvCol
.pszText
;
578 if ( item
.m_mask
& wxLIST_MASK_FORMAT
)
580 if (lvCol
.fmt
== LVCFMT_LEFT
)
581 item
.m_format
= wxLIST_FORMAT_LEFT
;
582 else if (lvCol
.fmt
== LVCFMT_RIGHT
)
583 item
.m_format
= wxLIST_FORMAT_RIGHT
;
584 else if (lvCol
.fmt
== LVCFMT_CENTER
)
585 item
.m_format
= wxLIST_FORMAT_CENTRE
;
591 // Sets information about this column
592 bool wxListCtrl::SetColumn(int col
, wxListItem
& item
)
597 lvCol
.pszText
= NULL
;
599 if ( item
.m_mask
& wxLIST_MASK_TEXT
)
601 lvCol
.mask
|= LVCF_TEXT
;
602 lvCol
.pszText
= WXSTRINGCAST item
.m_text
;
603 lvCol
.cchTextMax
= 0; // Ignored
605 if ( item
.m_mask
& wxLIST_MASK_FORMAT
)
607 lvCol
.mask
|= LVCF_FMT
;
609 if ( item
.m_format
== wxLIST_FORMAT_LEFT
)
610 lvCol
.fmt
= LVCFMT_LEFT
;
611 if ( item
.m_format
== wxLIST_FORMAT_RIGHT
)
612 lvCol
.fmt
= LVCFMT_RIGHT
;
613 if ( item
.m_format
== wxLIST_FORMAT_CENTRE
)
614 lvCol
.fmt
= LVCFMT_CENTER
;
617 if ( item
.m_mask
& wxLIST_MASK_WIDTH
)
619 lvCol
.mask
|= LVCF_WIDTH
;
620 lvCol
.cx
= item
.m_width
;
622 if ( lvCol
.cx
== wxLIST_AUTOSIZE
)
623 lvCol
.cx
= LVSCW_AUTOSIZE
;
624 else if ( lvCol
.cx
== wxLIST_AUTOSIZE_USEHEADER
)
625 lvCol
.cx
= LVSCW_AUTOSIZE_USEHEADER
;
627 lvCol
.mask
|= LVCF_SUBITEM
;
628 lvCol
.iSubItem
= col
;
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
);
727 if ( !ListView_SetItem(GetHwnd(), &item
) )
729 wxLogDebug(_T("ListView_SetItem() failed"));
734 // we need to update the item immediately to show the new image
735 bool updateNow
= (info
.m_mask
& wxLIST_MASK_IMAGE
) != 0;
737 // check whether it has any custom attributes
738 if ( info
.HasAttributes() )
740 wxListItemAttr
*attr
= (wxListItemAttr
*)m_attrs
.Get(item
.iItem
);
743 m_attrs
.Put(item
.iItem
, (wxObject
*)new wxListItemAttr(*info
.GetAttributes()));
745 *attr
= *info
.GetAttributes();
749 // if the colour has changed, we must redraw the item
755 // we need this to make the change visible right now
756 ListView_Update(GetHwnd(), item
.iItem
);
762 long wxListCtrl::SetItem(long index
, int col
, const wxString
& label
, int imageId
)
766 info
.m_mask
= wxLIST_MASK_TEXT
;
767 info
.m_itemId
= index
;
771 info
.m_image
= imageId
;
772 info
.m_mask
|= wxLIST_MASK_IMAGE
;
774 return SetItem(info
);
778 // Gets the item state
779 int wxListCtrl::GetItemState(long item
, long stateMask
) const
783 info
.m_mask
= wxLIST_MASK_STATE
;
784 info
.m_stateMask
= stateMask
;
785 info
.m_itemId
= item
;
793 // Sets the item state
794 bool wxListCtrl::SetItemState(long item
, long state
, long stateMask
)
796 // NB: don't use SetItem() here as it doesn't work with the virtual list
799 wxZeroMemory(lvItem
);
801 wxConvertToMSWFlags(state
, stateMask
, lvItem
);
803 if ( !::SendMessage(GetHwnd(), LVM_SETITEMSTATE
,
804 (WPARAM
)item
, (LPARAM
)&lvItem
) )
806 wxLogLastError(_T("ListView_SetItemState"));
814 // Sets the item image
815 bool wxListCtrl::SetItemImage(long item
, int image
, int WXUNUSED(selImage
))
819 info
.m_mask
= wxLIST_MASK_IMAGE
;
820 info
.m_image
= image
;
821 info
.m_itemId
= item
;
823 return SetItem(info
);
826 // Gets the item text
827 wxString
wxListCtrl::GetItemText(long item
) const
831 info
.m_mask
= wxLIST_MASK_TEXT
;
832 info
.m_itemId
= item
;
839 // Sets the item text
840 void wxListCtrl::SetItemText(long item
, const wxString
& str
)
844 info
.m_mask
= wxLIST_MASK_TEXT
;
845 info
.m_itemId
= item
;
851 // Gets the item data
852 long wxListCtrl::GetItemData(long item
) const
856 info
.m_mask
= wxLIST_MASK_DATA
;
857 info
.m_itemId
= item
;
864 // Sets the item data
865 bool wxListCtrl::SetItemData(long item
, long data
)
869 info
.m_mask
= wxLIST_MASK_DATA
;
870 info
.m_itemId
= item
;
873 return SetItem(info
);
876 // Gets the item rectangle
877 bool wxListCtrl::GetItemRect(long item
, wxRect
& rect
, int code
) const
881 int code2
= LVIR_BOUNDS
;
882 if ( code
== wxLIST_RECT_BOUNDS
)
884 else if ( code
== wxLIST_RECT_ICON
)
886 else if ( code
== wxLIST_RECT_LABEL
)
890 bool success
= (ListView_GetItemRect(GetHwnd(), (int) item
, &rect2
) != 0);
892 bool success
= (ListView_GetItemRect(GetHwnd(), (int) item
, &rect2
, code2
) != 0);
897 rect
.width
= rect2
.right
- rect2
.left
;
898 rect
.height
= rect2
.bottom
- rect2
.top
;
902 // Gets the item position
903 bool wxListCtrl::GetItemPosition(long item
, wxPoint
& pos
) const
907 bool success
= (ListView_GetItemPosition(GetHwnd(), (int) item
, &pt
) != 0);
909 pos
.x
= pt
.x
; pos
.y
= pt
.y
;
913 // Sets the item position.
914 bool wxListCtrl::SetItemPosition(long item
, const wxPoint
& pos
)
916 return (ListView_SetItemPosition(GetHwnd(), (int) item
, pos
.x
, pos
.y
) != 0);
919 // Gets the number of items in the list control
920 int wxListCtrl::GetItemCount() const
922 return ListView_GetItemCount(GetHwnd());
925 // Retrieves the spacing between icons in pixels.
926 // If small is TRUE, gets the spacing for the small icon
927 // view, otherwise the large icon view.
928 int wxListCtrl::GetItemSpacing(bool isSmall
) const
930 return ListView_GetItemSpacing(GetHwnd(), (BOOL
) isSmall
);
933 // Gets the number of selected items in the list control
934 int wxListCtrl::GetSelectedItemCount() const
936 return ListView_GetSelectedCount(GetHwnd());
939 // Gets the text colour of the listview
940 wxColour
wxListCtrl::GetTextColour() const
942 COLORREF ref
= ListView_GetTextColor(GetHwnd());
943 wxColour
col(GetRValue(ref
), GetGValue(ref
), GetBValue(ref
));
947 // Sets the text colour of the listview
948 void wxListCtrl::SetTextColour(const wxColour
& col
)
950 ListView_SetTextColor(GetHwnd(), PALETTERGB(col
.Red(), col
.Green(), col
.Blue()));
953 // Gets the index of the topmost visible item when in
954 // list or report view
955 long wxListCtrl::GetTopItem() const
957 return (long) ListView_GetTopIndex(GetHwnd());
960 // Searches for an item, starting from 'item'.
961 // 'geometry' is one of
962 // wxLIST_NEXT_ABOVE/ALL/BELOW/LEFT/RIGHT.
963 // 'state' is a state bit flag, one or more of
964 // wxLIST_STATE_DROPHILITED/FOCUSED/SELECTED/CUT.
965 // item can be -1 to find the first item that matches the
967 // Returns the item or -1 if unsuccessful.
968 long wxListCtrl::GetNextItem(long item
, int geom
, int state
) const
972 if ( geom
== wxLIST_NEXT_ABOVE
)
974 if ( geom
== wxLIST_NEXT_ALL
)
976 if ( geom
== wxLIST_NEXT_BELOW
)
978 if ( geom
== wxLIST_NEXT_LEFT
)
979 flags
|= LVNI_TOLEFT
;
980 if ( geom
== wxLIST_NEXT_RIGHT
)
981 flags
|= LVNI_TORIGHT
;
983 if ( state
& wxLIST_STATE_CUT
)
985 if ( state
& wxLIST_STATE_DROPHILITED
)
986 flags
|= LVNI_DROPHILITED
;
987 if ( state
& wxLIST_STATE_FOCUSED
)
988 flags
|= LVNI_FOCUSED
;
989 if ( state
& wxLIST_STATE_SELECTED
)
990 flags
|= LVNI_SELECTED
;
992 return (long) ListView_GetNextItem(GetHwnd(), item
, flags
);
996 wxImageList
*wxListCtrl::GetImageList(int which
) const
998 if ( which
== wxIMAGE_LIST_NORMAL
)
1000 return m_imageListNormal
;
1002 else if ( which
== wxIMAGE_LIST_SMALL
)
1004 return m_imageListSmall
;
1006 else if ( which
== wxIMAGE_LIST_STATE
)
1008 return m_imageListState
;
1013 void wxListCtrl::SetImageList(wxImageList
*imageList
, int which
)
1016 if ( which
== wxIMAGE_LIST_NORMAL
)
1018 flags
= LVSIL_NORMAL
;
1019 if (m_ownsImageListNormal
) delete m_imageListNormal
;
1020 m_imageListNormal
= imageList
;
1021 m_ownsImageListNormal
= FALSE
;
1023 else if ( which
== wxIMAGE_LIST_SMALL
)
1025 flags
= LVSIL_SMALL
;
1026 if (m_ownsImageListSmall
) delete m_imageListSmall
;
1027 m_imageListSmall
= imageList
;
1028 m_ownsImageListSmall
= FALSE
;
1030 else if ( which
== wxIMAGE_LIST_STATE
)
1032 flags
= LVSIL_STATE
;
1033 if (m_ownsImageListState
) delete m_imageListState
;
1034 m_imageListState
= imageList
;
1035 m_ownsImageListState
= FALSE
;
1037 ListView_SetImageList(GetHwnd(), (HIMAGELIST
) imageList
? imageList
->GetHIMAGELIST() : 0, flags
);
1040 void wxListCtrl::AssignImageList(wxImageList
*imageList
, int which
)
1042 SetImageList(imageList
, which
);
1043 if ( which
== wxIMAGE_LIST_NORMAL
)
1044 m_ownsImageListNormal
= TRUE
;
1045 else if ( which
== wxIMAGE_LIST_SMALL
)
1046 m_ownsImageListSmall
= TRUE
;
1047 else if ( which
== wxIMAGE_LIST_STATE
)
1048 m_ownsImageListState
= TRUE
;
1051 // ----------------------------------------------------------------------------
1053 // ----------------------------------------------------------------------------
1055 // Arranges the items
1056 bool wxListCtrl::Arrange(int flag
)
1059 if ( flag
== wxLIST_ALIGN_LEFT
)
1060 code
= LVA_ALIGNLEFT
;
1061 else if ( flag
== wxLIST_ALIGN_TOP
)
1062 code
= LVA_ALIGNTOP
;
1063 else if ( flag
== wxLIST_ALIGN_DEFAULT
)
1065 else if ( flag
== wxLIST_ALIGN_SNAP_TO_GRID
)
1066 code
= LVA_SNAPTOGRID
;
1068 return (ListView_Arrange(GetHwnd(), code
) != 0);
1072 bool wxListCtrl::DeleteItem(long item
)
1074 return (ListView_DeleteItem(GetHwnd(), (int) item
) != 0);
1077 // Deletes all items
1078 bool wxListCtrl::DeleteAllItems()
1080 return (ListView_DeleteAllItems(GetHwnd()) != 0);
1083 // Deletes all items
1084 bool wxListCtrl::DeleteAllColumns()
1086 while ( m_colCount
> 0 )
1088 if ( ListView_DeleteColumn(GetHwnd(), 0) == 0 )
1090 wxLogLastError(wxT("ListView_DeleteColumn"));
1098 wxASSERT_MSG( m_colCount
== 0, wxT("no columns should be left") );
1104 bool wxListCtrl::DeleteColumn(int col
)
1106 bool success
= (ListView_DeleteColumn(GetHwnd(), col
) != 0);
1108 if ( success
&& (m_colCount
> 0) )
1113 // Clears items, and columns if there are any.
1114 void wxListCtrl::ClearAll()
1117 if ( m_colCount
> 0 )
1121 wxTextCtrl
* wxListCtrl::EditLabel(long item
, wxClassInfo
* textControlClass
)
1123 wxASSERT( (textControlClass
->IsKindOf(CLASSINFO(wxTextCtrl
))) );
1125 // VS: ListView_EditLabel requires that the list has focus.
1127 HWND hWnd
= (HWND
) ListView_EditLabel(GetHwnd(), item
);
1131 m_textCtrl
->SetHWND(0);
1132 m_textCtrl
->UnsubclassWin();
1137 m_textCtrl
= (wxTextCtrl
*) textControlClass
->CreateObject();
1138 m_textCtrl
->SetHWND((WXHWND
) hWnd
);
1139 m_textCtrl
->SubclassWin((WXHWND
) hWnd
);
1144 // End label editing, optionally cancelling the edit
1145 bool wxListCtrl::EndEditLabel(bool WXUNUSED(cancel
))
1147 wxFAIL_MSG( _T("not implemented") );
1152 // Ensures this item is visible
1153 bool wxListCtrl::EnsureVisible(long item
)
1155 return ListView_EnsureVisible(GetHwnd(), (int) item
, FALSE
) != 0;
1158 // Find an item whose label matches this string, starting from the item after 'start'
1159 // or the beginning if 'start' is -1.
1160 long wxListCtrl::FindItem(long start
, const wxString
& str
, bool partial
)
1162 LV_FINDINFO findInfo
;
1164 findInfo
.flags
= LVFI_STRING
;
1166 findInfo
.flags
|= LVFI_PARTIAL
;
1169 // ListView_FindItem() excludes the first item from search and to look
1170 // through all the items you need to start from -1 which is unnatural and
1171 // inconsistent with the generic version - so we adjust the index
1174 return ListView_FindItem(GetHwnd(), (int) start
, &findInfo
);
1177 // Find an item whose data matches this data, starting from the item after 'start'
1178 // or the beginning if 'start' is -1.
1179 long wxListCtrl::FindItem(long start
, long data
)
1181 LV_FINDINFO findInfo
;
1183 findInfo
.flags
= LVFI_PARAM
;
1184 findInfo
.lParam
= data
;
1186 return ListView_FindItem(GetHwnd(), (int) start
, & findInfo
);
1189 // Find an item nearest this position in the specified direction, starting from
1190 // the item after 'start' or the beginning if 'start' is -1.
1191 long wxListCtrl::FindItem(long start
, const wxPoint
& pt
, int direction
)
1193 LV_FINDINFO findInfo
;
1195 findInfo
.flags
= LVFI_NEARESTXY
;
1196 findInfo
.pt
.x
= pt
.x
;
1197 findInfo
.pt
.y
= pt
.y
;
1198 findInfo
.vkDirection
= VK_RIGHT
;
1200 if ( direction
== wxLIST_FIND_UP
)
1201 findInfo
.vkDirection
= VK_UP
;
1202 else if ( direction
== wxLIST_FIND_DOWN
)
1203 findInfo
.vkDirection
= VK_DOWN
;
1204 else if ( direction
== wxLIST_FIND_LEFT
)
1205 findInfo
.vkDirection
= VK_LEFT
;
1206 else if ( direction
== wxLIST_FIND_RIGHT
)
1207 findInfo
.vkDirection
= VK_RIGHT
;
1209 return ListView_FindItem(GetHwnd(), (int) start
, & findInfo
);
1212 // Determines which item (if any) is at the specified point,
1213 // giving details in 'flags' (see wxLIST_HITTEST_... flags above)
1214 long wxListCtrl::HitTest(const wxPoint
& point
, int& flags
)
1216 LV_HITTESTINFO hitTestInfo
;
1217 hitTestInfo
.pt
.x
= (int) point
.x
;
1218 hitTestInfo
.pt
.y
= (int) point
.y
;
1220 ListView_HitTest(GetHwnd(), & hitTestInfo
);
1223 if ( hitTestInfo
.flags
& LVHT_ABOVE
)
1224 flags
|= wxLIST_HITTEST_ABOVE
;
1225 if ( hitTestInfo
.flags
& LVHT_BELOW
)
1226 flags
|= wxLIST_HITTEST_BELOW
;
1227 if ( hitTestInfo
.flags
& LVHT_NOWHERE
)
1228 flags
|= wxLIST_HITTEST_NOWHERE
;
1229 if ( hitTestInfo
.flags
& LVHT_ONITEMICON
)
1230 flags
|= wxLIST_HITTEST_ONITEMICON
;
1231 if ( hitTestInfo
.flags
& LVHT_ONITEMLABEL
)
1232 flags
|= wxLIST_HITTEST_ONITEMLABEL
;
1233 if ( hitTestInfo
.flags
& LVHT_ONITEMSTATEICON
)
1234 flags
|= wxLIST_HITTEST_ONITEMSTATEICON
;
1235 if ( hitTestInfo
.flags
& LVHT_TOLEFT
)
1236 flags
|= wxLIST_HITTEST_TOLEFT
;
1237 if ( hitTestInfo
.flags
& LVHT_TORIGHT
)
1238 flags
|= wxLIST_HITTEST_TORIGHT
;
1240 return (long) hitTestInfo
.iItem
;
1243 // Inserts an item, returning the index of the new item if successful,
1245 long wxListCtrl::InsertItem(wxListItem
& info
)
1247 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual controls") );
1250 wxConvertToMSWListItem(this, info
, item
);
1252 // check whether it has any custom attributes
1253 if ( info
.HasAttributes() )
1256 wxListItemAttr
*attr
;
1257 attr
= (wxListItemAttr
*) m_attrs
.Get(item
.iItem
);
1261 m_attrs
.Put(item
.iItem
, (wxObject
*)new wxListItemAttr(*info
.GetAttributes()));
1263 else *attr
= *info
.GetAttributes();
1265 m_hasAnyAttr
= TRUE
;
1268 return (long) ListView_InsertItem(GetHwnd(), & item
);
1271 long wxListCtrl::InsertItem(long index
, const wxString
& label
)
1274 info
.m_text
= label
;
1275 info
.m_mask
= wxLIST_MASK_TEXT
;
1276 info
.m_itemId
= index
;
1277 return InsertItem(info
);
1280 // Inserts an image item
1281 long wxListCtrl::InsertItem(long index
, int imageIndex
)
1284 info
.m_image
= imageIndex
;
1285 info
.m_mask
= wxLIST_MASK_IMAGE
;
1286 info
.m_itemId
= index
;
1287 return InsertItem(info
);
1290 // Inserts an image/string item
1291 long wxListCtrl::InsertItem(long index
, const wxString
& label
, int imageIndex
)
1294 info
.m_image
= imageIndex
;
1295 info
.m_text
= label
;
1296 info
.m_mask
= wxLIST_MASK_IMAGE
| wxLIST_MASK_TEXT
;
1297 info
.m_itemId
= index
;
1298 return InsertItem(info
);
1301 // For list view mode (only), inserts a column.
1302 long wxListCtrl::InsertColumn(long col
, wxListItem
& item
)
1307 lvCol
.pszText
= NULL
;
1309 if ( item
.m_mask
& wxLIST_MASK_TEXT
)
1311 lvCol
.mask
|= LVCF_TEXT
;
1312 lvCol
.pszText
= WXSTRINGCAST item
.m_text
;
1313 lvCol
.cchTextMax
= 0; // Ignored
1315 if ( item
.m_mask
& wxLIST_MASK_FORMAT
)
1317 lvCol
.mask
|= LVCF_FMT
;
1319 if ( item
.m_format
== wxLIST_FORMAT_LEFT
)
1320 lvCol
.fmt
= LVCFMT_LEFT
;
1321 if ( item
.m_format
== wxLIST_FORMAT_RIGHT
)
1322 lvCol
.fmt
= LVCFMT_RIGHT
;
1323 if ( item
.m_format
== wxLIST_FORMAT_CENTRE
)
1324 lvCol
.fmt
= LVCFMT_CENTER
;
1327 lvCol
.mask
|= LVCF_WIDTH
;
1328 if ( item
.m_mask
& wxLIST_MASK_WIDTH
)
1330 if ( item
.m_width
== wxLIST_AUTOSIZE
)
1331 lvCol
.cx
= LVSCW_AUTOSIZE
;
1332 else if ( item
.m_width
== wxLIST_AUTOSIZE_USEHEADER
)
1333 lvCol
.cx
= LVSCW_AUTOSIZE_USEHEADER
;
1335 lvCol
.cx
= item
.m_width
;
1339 // always give some width to the new column: this one is compatible
1344 lvCol
.mask
|= LVCF_SUBITEM
;
1345 lvCol
.iSubItem
= col
;
1347 bool success
= ListView_InsertColumn(GetHwnd(), col
, & lvCol
) != -1;
1354 wxLogDebug(wxT("Failed to insert the column '%s' into listview!"),
1361 long wxListCtrl::InsertColumn(long col
,
1362 const wxString
& heading
,
1367 item
.m_mask
= wxLIST_MASK_TEXT
| wxLIST_MASK_FORMAT
;
1368 item
.m_text
= heading
;
1371 item
.m_mask
|= wxLIST_MASK_WIDTH
;
1372 item
.m_width
= width
;
1374 item
.m_format
= format
;
1376 return InsertColumn(col
, item
);
1379 // Scrolls the list control. If in icon, small icon or report view mode,
1380 // x specifies the number of pixels to scroll. If in list view mode, x
1381 // specifies the number of columns to scroll.
1382 // If in icon, small icon or list view mode, y specifies the number of pixels
1383 // to scroll. If in report view mode, y specifies the number of lines to scroll.
1384 bool wxListCtrl::ScrollList(int dx
, int dy
)
1386 return (ListView_Scroll(GetHwnd(), dx
, dy
) != 0);
1391 // fn is a function which takes 3 long arguments: item1, item2, data.
1392 // item1 is the long data associated with a first item (NOT the index).
1393 // item2 is the long data associated with a second item (NOT the index).
1394 // data is the same value as passed to SortItems.
1395 // The return value is a negative number if the first item should precede the second
1396 // item, a positive number of the second item should precede the first,
1397 // or zero if the two items are equivalent.
1399 // data is arbitrary data to be passed to the sort function.
1401 // FIXME: this is horrible and MT-unsafe and everything else but I don't have
1402 // time for anything better right now (VZ)
1403 static long gs_sortData
= 0;
1404 static wxListCtrl
*gs_sortCtrl
= NULL
;
1405 static wxListCtrlCompare gs_sortFunction
= NULL
;
1407 int wxCMPFUNC_CONV
wxListCtrlCompareFn(const void *arg1
, const void *arg2
)
1409 int n1
= *(const int *)arg1
,
1410 n2
= *(const int *)arg2
;
1412 return gs_sortFunction(gs_sortCtrl
->GetItemData(n1
),
1413 gs_sortCtrl
->GetItemData(n2
),
1417 bool wxListCtrl::SortItems(wxListCtrlCompare fn
, long data
)
1419 // sort the attributes too
1423 count
= GetItemCount();
1424 int *aItems
= new int[count
];
1425 for ( n
= 0; n
< count
; n
++ )
1432 gs_sortFunction
= fn
;
1434 qsort(aItems
, count
, sizeof(int), wxListCtrlCompareFn
);
1438 gs_sortFunction
= NULL
;
1440 wxHashTable
attrsNew(wxKEY_INTEGER
, 1000);
1441 for ( n
= 0; n
< count
; n
++ )
1443 wxObject
*attr
= m_attrs
.Delete(aItems
[n
]);
1446 attrsNew
.Put(n
, attr
);
1456 if ( !ListView_SortItems(GetHwnd(), (PFNLVCOMPARE
)fn
, data
) )
1458 wxLogDebug(_T("ListView_SortItems() failed"));
1468 // ----------------------------------------------------------------------------
1469 // message processing
1470 // ----------------------------------------------------------------------------
1472 bool wxListCtrl::MSWCommand(WXUINT cmd
, WXWORD id
)
1474 if (cmd
== EN_UPDATE
)
1476 wxCommandEvent
event(wxEVT_COMMAND_TEXT_UPDATED
, id
);
1477 event
.SetEventObject( this );
1478 ProcessCommand(event
);
1481 else if (cmd
== EN_KILLFOCUS
)
1483 wxCommandEvent
event(wxEVT_KILL_FOCUS
, id
);
1484 event
.SetEventObject( this );
1485 ProcessCommand(event
);
1492 bool wxListCtrl::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
*result
)
1494 // prepare the event
1495 // -----------------
1497 wxListEvent
event(wxEVT_NULL
, m_windowId
);
1498 wxEventType eventType
= wxEVT_NULL
;
1500 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
1502 // check for messages from the header (in report view)
1503 HWND hwndHdr
= ListView_GetHeader(GetHwnd());
1505 // is it a message from the header?
1506 if ( nmhdr
->hwndFrom
== hwndHdr
)
1508 NMHEADER
*nmHDR
= (NMHEADER
*)nmhdr
;
1509 event
.m_itemIndex
= -1;
1511 switch ( nmhdr
->code
)
1513 // yet another comctl32.dll bug: under NT/W2K it sends Unicode
1514 // TRACK messages even to ANSI programs: on my system I get
1515 // HDN_BEGINTRACKW and HDN_ENDTRACKA and no HDN_TRACK at all!
1517 // work around is to simply catch both versions and hope that it
1518 // works (why should this message exist in ANSI and Unicode is
1519 // beyond me as it doesn't deal with strings at all...)
1520 case HDN_BEGINTRACKA
:
1521 case HDN_BEGINTRACKW
:
1522 eventType
= wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
;
1527 if ( eventType
== wxEVT_NULL
)
1528 eventType
= wxEVT_COMMAND_LIST_COL_DRAGGING
;
1533 if ( eventType
== wxEVT_NULL
)
1534 eventType
= wxEVT_COMMAND_LIST_COL_END_DRAG
;
1535 event
.m_col
= nmHDR
->iItem
;
1540 eventType
= wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
;
1543 // find the column clicked: we have to search for it
1544 // ourselves as the notification message doesn't provide
1547 // where did the click occur?
1549 if ( !::GetCursorPos(&ptClick
) )
1551 wxLogLastError(_T("GetCursorPos"));
1554 if ( !::ScreenToClient(hwndHdr
, &ptClick
) )
1556 wxLogLastError(_T("ScreenToClient(listctrl header)"));
1559 event
.m_pointDrag
.x
= ptClick
.x
;
1560 event
.m_pointDrag
.y
= ptClick
.y
;
1562 int colCount
= Header_GetItemCount(hwndHdr
);
1565 for ( int col
= 0; col
< colCount
; col
++ )
1567 if ( Header_GetItemRect(hwndHdr
, col
, &rect
) )
1569 if ( ::PtInRect(&rect
, ptClick
) )
1580 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
1583 else if ( nmhdr
->hwndFrom
== GetHwnd() )
1585 // almost all messages use NM_LISTVIEW
1586 NM_LISTVIEW
*nmLV
= (NM_LISTVIEW
*)nmhdr
;
1588 // this is true for almost all events
1589 event
.m_item
.m_data
= nmLV
->lParam
;
1591 switch ( nmhdr
->code
)
1593 case LVN_BEGINRDRAG
:
1594 eventType
= wxEVT_COMMAND_LIST_BEGIN_RDRAG
;
1598 if ( eventType
== wxEVT_NULL
)
1600 eventType
= wxEVT_COMMAND_LIST_BEGIN_DRAG
;
1603 event
.m_itemIndex
= nmLV
->iItem
;
1604 event
.m_pointDrag
.x
= nmLV
->ptAction
.x
;
1605 event
.m_pointDrag
.y
= nmLV
->ptAction
.y
;
1608 case LVN_BEGINLABELEDIT
:
1610 eventType
= wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
;
1611 LV_DISPINFO
*info
= (LV_DISPINFO
*)lParam
;
1612 wxConvertFromMSWListItem(GetHwnd(), event
.m_item
, info
->item
);
1613 event
.m_itemIndex
= event
.m_item
.m_itemId
;
1617 case LVN_COLUMNCLICK
:
1618 eventType
= wxEVT_COMMAND_LIST_COL_CLICK
;
1619 event
.m_itemIndex
= -1;
1620 event
.m_col
= nmLV
->iSubItem
;
1623 case LVN_DELETEALLITEMS
:
1624 eventType
= wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
;
1625 event
.m_itemIndex
= -1;
1631 case LVN_DELETEITEM
:
1632 eventType
= wxEVT_COMMAND_LIST_DELETE_ITEM
;
1633 event
.m_itemIndex
= nmLV
->iItem
;
1637 delete (wxListItemAttr
*)m_attrs
.Delete(nmLV
->iItem
);
1641 case LVN_ENDLABELEDIT
:
1643 eventType
= wxEVT_COMMAND_LIST_END_LABEL_EDIT
;
1644 LV_DISPINFO
*info
= (LV_DISPINFO
*)lParam
;
1645 wxConvertFromMSWListItem(GetHwnd(), event
.m_item
, info
->item
);
1646 if ( info
->item
.pszText
== NULL
|| info
->item
.iItem
== -1 )
1649 event
.m_itemIndex
= event
.m_item
.m_itemId
;
1653 case LVN_SETDISPINFO
:
1655 eventType
= wxEVT_COMMAND_LIST_SET_INFO
;
1656 LV_DISPINFO
*info
= (LV_DISPINFO
*)lParam
;
1657 wxConvertFromMSWListItem(GetHwnd(), event
.m_item
, info
->item
);
1661 case LVN_INSERTITEM
:
1662 eventType
= wxEVT_COMMAND_LIST_INSERT_ITEM
;
1663 event
.m_itemIndex
= nmLV
->iItem
;
1666 case LVN_ITEMCHANGED
:
1667 // This needs to be sent to wxListCtrl as a rather more concrete
1668 // event. For now, just detect a selection or deselection.
1669 if ( (nmLV
->uNewState
& LVIS_SELECTED
) && !(nmLV
->uOldState
& LVIS_SELECTED
) )
1671 eventType
= wxEVT_COMMAND_LIST_ITEM_SELECTED
;
1672 event
.m_itemIndex
= nmLV
->iItem
;
1674 else if ( !(nmLV
->uNewState
& LVIS_SELECTED
) && (nmLV
->uOldState
& LVIS_SELECTED
) )
1676 eventType
= wxEVT_COMMAND_LIST_ITEM_DESELECTED
;
1677 event
.m_itemIndex
= nmLV
->iItem
;
1687 LV_KEYDOWN
*info
= (LV_KEYDOWN
*)lParam
;
1688 WORD wVKey
= info
->wVKey
;
1690 // get the current selection
1691 long lItem
= GetNextItem(-1,
1693 wxLIST_STATE_SELECTED
);
1695 // <Enter> or <Space> activate the selected item if any (but
1696 // not with Shift and/or Ctrl as then they have a predefined
1697 // meaning for the list view)
1699 (wVKey
== VK_RETURN
|| wVKey
== VK_SPACE
) &&
1700 !(wxIsShiftDown() || wxIsCtrlDown()) )
1702 eventType
= wxEVT_COMMAND_LIST_ITEM_ACTIVATED
;
1706 eventType
= wxEVT_COMMAND_LIST_KEY_DOWN
;
1707 event
.m_code
= wxCharCodeMSWToWX(wVKey
);
1711 event
.m_item
.m_itemId
= lItem
;
1715 // fill the other fields too
1716 event
.m_item
.m_text
= GetItemText(lItem
);
1717 event
.m_item
.m_data
= GetItemData(lItem
);
1723 // if the user processes it in wxEVT_COMMAND_LEFT_CLICK(), don't do
1725 if ( wxControl::MSWOnNotify(idCtrl
, lParam
, result
) )
1730 // else translate it into wxEVT_COMMAND_LIST_ITEM_ACTIVATED event
1731 // if it happened on an item (and not on empty place)
1732 if ( nmLV
->iItem
== -1 )
1738 eventType
= wxEVT_COMMAND_LIST_ITEM_ACTIVATED
;
1739 event
.m_itemIndex
= nmLV
->iItem
;
1740 event
.m_item
.m_text
= GetItemText(nmLV
->iItem
);
1741 event
.m_item
.m_data
= GetItemData(nmLV
->iItem
);
1745 // if the user processes it in wxEVT_COMMAND_RIGHT_CLICK(),
1746 // don't do anything else
1747 if ( wxControl::MSWOnNotify(idCtrl
, lParam
, result
) )
1752 // else translate it into wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK event
1753 LV_HITTESTINFO lvhti
;
1754 wxZeroMemory(lvhti
);
1756 ::GetCursorPos(&(lvhti
.pt
));
1757 ::ScreenToClient(GetHwnd(),&(lvhti
.pt
));
1758 if ( ListView_HitTest(GetHwnd(),&lvhti
) != -1 )
1760 if ( lvhti
.flags
& LVHT_ONITEM
)
1762 eventType
= wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
;
1763 event
.m_itemIndex
= lvhti
.iItem
;
1764 event
.m_pointDrag
.x
= lvhti
.pt
.x
;
1765 event
.m_pointDrag
.y
= lvhti
.pt
.y
;
1770 #if defined(_WIN32_IE) && _WIN32_IE >= 0x300 \
1771 && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) )
1773 *result
= OnCustomDraw(lParam
);
1776 #endif // _WIN32_IE >= 0x300
1778 case LVN_ODCACHEHINT
:
1780 const NM_CACHEHINT
*cacheHint
= (NM_CACHEHINT
*)lParam
;
1782 eventType
= wxEVT_COMMAND_LIST_CACHE_HINT
;
1784 // we get some really stupid cache hints like ones for items in
1785 // range 0..0 for an empty control or, after deleting an item,
1786 // for items in invalid range - filter this garbage out
1787 if ( cacheHint
->iFrom
< cacheHint
->iTo
)
1789 event
.m_oldItemIndex
= cacheHint
->iFrom
;
1791 long iMax
= GetItemCount();
1792 event
.m_itemIndex
= cacheHint
->iTo
< iMax
? cacheHint
->iTo
1802 case LVN_GETDISPINFO
:
1805 LV_DISPINFO
*info
= (LV_DISPINFO
*)lParam
;
1807 LV_ITEM
& lvi
= info
->item
;
1808 long item
= lvi
.iItem
;
1810 if ( lvi
.mask
& LVIF_TEXT
)
1812 wxString text
= OnGetItemText(item
, lvi
.iSubItem
);
1813 wxStrncpy(lvi
.pszText
, text
, lvi
.cchTextMax
);
1816 if ( lvi
.mask
& LVIF_IMAGE
)
1818 lvi
.iImage
= OnGetItemImage(item
);
1821 // a little dose of healthy paranoia: as we never use
1822 // LVM_SETCALLBACKMASK we're not supposed to get these ones
1823 wxASSERT_MSG( !(lvi
.mask
& LVIF_STATE
),
1824 _T("we don't support state callbacks yet!") );
1831 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
1836 // where did this one come from?
1840 // process the event
1841 // -----------------
1843 event
.SetEventObject( this );
1844 event
.SetEventType(eventType
);
1846 if ( !GetEventHandler()->ProcessEvent(event
) )
1852 switch ( nmhdr
->code
)
1854 case LVN_DELETEALLITEMS
:
1855 // always return TRUE to suppress all additional LVN_DELETEITEM
1856 // notifications - this makes deleting all items from a list ctrl
1862 case LVN_ENDLABELEDIT
:
1863 // logic here is inversed compared to all the other messages
1864 *result
= event
.IsAllowed();
1869 *result
= !event
.IsAllowed();
1874 #if defined(_WIN32_IE) && _WIN32_IE >= 0x300
1876 WXLPARAM
wxListCtrl::OnCustomDraw(WXLPARAM lParam
)
1878 LPNMLVCUSTOMDRAW lplvcd
= (LPNMLVCUSTOMDRAW
)lParam
;
1879 NMCUSTOMDRAW
& nmcd
= lplvcd
->nmcd
;
1880 switch ( nmcd
.dwDrawStage
)
1883 // if we've got any items with non standard attributes,
1884 // notify us before painting each item
1886 // for virtual controls, always suppose that we have attributes as
1887 // there is no way to check for this
1888 return IsVirtual() || m_hasAnyAttr
? CDRF_NOTIFYITEMDRAW
1891 case CDDS_ITEMPREPAINT
:
1893 size_t item
= (size_t)nmcd
.dwItemSpec
;
1894 if ( item
>= (size_t)GetItemCount() )
1896 // we get this message with item == 0 for an empty control,
1897 // we must ignore it as calling OnGetItemAttr() would be
1899 return CDRF_DODEFAULT
;
1902 wxListItemAttr
*attr
=
1903 IsVirtual() ? OnGetItemAttr(item
)
1904 : (wxListItemAttr
*)m_attrs
.Get(item
);
1908 // nothing to do for this item
1909 return CDRF_DODEFAULT
;
1913 wxColour colText
, colBack
;
1914 if ( attr
->HasFont() )
1916 wxFont font
= attr
->GetFont();
1917 hFont
= (HFONT
)font
.GetResourceHandle();
1924 if ( attr
->HasTextColour() )
1926 colText
= attr
->GetTextColour();
1930 colText
= GetTextColour();
1933 if ( attr
->HasBackgroundColour() )
1935 colBack
= attr
->GetBackgroundColour();
1939 colBack
= GetBackgroundColour();
1942 lplvcd
->clrText
= wxColourToRGB(colText
);
1943 lplvcd
->clrTextBk
= wxColourToRGB(colBack
);
1945 // note that if we wanted to set colours for
1946 // individual columns (subitems), we would have
1947 // returned CDRF_NOTIFYSUBITEMREDRAW from here
1950 ::SelectObject(nmcd
.hdc
, hFont
);
1952 return CDRF_NEWFONT
;
1955 // fall through to return CDRF_DODEFAULT
1958 return CDRF_DODEFAULT
;
1962 #endif // NM_CUSTOMDRAW supported
1964 // Necessary for drawing hrules and vrules, if specified
1965 void wxListCtrl::OnPaint(wxPaintEvent
& event
)
1969 wxControl::OnPaint(event
);
1971 // Reset the device origin since it may have been set
1972 dc
.SetDeviceOrigin(0, 0);
1974 bool drawHRules
= ((GetWindowStyle() & wxLC_HRULES
) != 0);
1975 bool drawVRules
= ((GetWindowStyle() & wxLC_VRULES
) != 0);
1977 if (!drawHRules
&& !drawVRules
)
1979 if ((GetWindowStyle() & wxLC_REPORT
) == 0)
1982 wxPen
pen(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT
), 1, wxSOLID
);
1984 dc
.SetBrush(* wxTRANSPARENT_BRUSH
);
1986 wxSize clientSize
= GetClientSize();
1990 int itemCount
= GetItemCount();
1994 long top
= GetTopItem();
1995 for (i
= top
; i
< top
+ GetCountPerPage() + 1; i
++)
1997 if (GetItemRect(i
, itemRect
))
1999 cy
= itemRect
.GetTop();
2000 if (i
!= 0) // Don't draw the first one
2002 dc
.DrawLine(0, cy
, clientSize
.x
, cy
);
2005 if (i
== itemCount
- 1)
2007 cy
= itemRect
.GetBottom();
2008 dc
.DrawLine(0, cy
, clientSize
.x
, cy
);
2014 if (drawVRules
&& (i
> -1))
2016 wxRect firstItemRect
;
2017 GetItemRect(0, firstItemRect
);
2019 if (GetItemRect(i
, itemRect
))
2022 int x
= itemRect
.GetX();
2023 for (col
= 0; col
< GetColumnCount(); col
++)
2025 int colWidth
= GetColumnWidth(col
);
2027 dc
.DrawLine(x
, firstItemRect
.GetY() - 2, x
, itemRect
.GetBottom());
2033 // ----------------------------------------------------------------------------
2034 // virtual list controls
2035 // ----------------------------------------------------------------------------
2037 wxString
wxListCtrl::OnGetItemText(long WXUNUSED(item
), long WXUNUSED(col
)) const
2039 // this is a pure virtual function, in fact - which is not really pure
2040 // because the controls which are not virtual don't need to implement it
2041 wxFAIL_MSG( _T("not supposed to be called") );
2043 return wxEmptyString
;
2046 int wxListCtrl::OnGetItemImage(long WXUNUSED(item
)) const
2049 wxFAIL_MSG( _T("not supposed to be called") );
2054 wxListItemAttr
*wxListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item
)) const
2056 wxASSERT_MSG( item
>= 0 && item
< GetItemCount(),
2057 _T("invalid item index in OnGetItemAttr()") );
2059 // no attributes by default
2063 void wxListCtrl::SetItemCount(long count
)
2065 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
2067 if ( !::SendMessage(GetHwnd(), LVM_SETITEMCOUNT
, (WPARAM
)count
, 0) )
2069 wxLogLastError(_T("ListView_SetItemCount"));
2073 void wxListCtrl::RefreshItem(long item
)
2075 if ( !ListView_Update(GetHwnd(), item
) )
2077 wxLogLastError(_T("ListView_Update"));
2081 void wxListCtrl::RefreshItems(long itemFrom
, long itemTo
)
2083 wxRect rect1
, rect2
;
2084 GetItemRect(itemFrom
, rect1
);
2085 GetItemRect(itemTo
, rect2
);
2087 wxRect rect
= rect1
;
2088 rect
.height
= rect2
.GetBottom() - rect1
.GetTop();
2093 // ----------------------------------------------------------------------------
2095 // ----------------------------------------------------------------------------
2097 // List item structure
2098 wxListItem::wxListItem()
2108 m_format
= wxLIST_FORMAT_CENTRE
;
2114 void wxListItem::Clear()
2123 m_format
= wxLIST_FORMAT_CENTRE
;
2125 m_text
= wxEmptyString
;
2127 if (m_attr
) delete m_attr
;
2131 void wxListItem::ClearAttributes()
2133 if (m_attr
) delete m_attr
;
2137 static void wxConvertFromMSWListItem(HWND hwndListCtrl
,
2141 info
.m_data
= lvItem
.lParam
;
2144 info
.m_stateMask
= 0;
2145 info
.m_itemId
= lvItem
.iItem
;
2147 long oldMask
= lvItem
.mask
;
2149 bool needText
= FALSE
;
2150 if (hwndListCtrl
!= 0)
2152 if ( lvItem
.mask
& LVIF_TEXT
)
2159 lvItem
.pszText
= new wxChar
[513];
2160 lvItem
.cchTextMax
= 512;
2162 lvItem
.mask
|= LVIF_TEXT
| LVIF_IMAGE
| LVIF_PARAM
;
2163 ::SendMessage(hwndListCtrl
, LVM_GETITEM
, 0, (LPARAM
)& lvItem
);
2166 if ( lvItem
.mask
& LVIF_STATE
)
2168 info
.m_mask
|= wxLIST_MASK_STATE
;
2170 if ( lvItem
.stateMask
& LVIS_CUT
)
2172 info
.m_stateMask
|= wxLIST_STATE_CUT
;
2173 if ( lvItem
.state
& LVIS_CUT
)
2174 info
.m_state
|= wxLIST_STATE_CUT
;
2176 if ( lvItem
.stateMask
& LVIS_DROPHILITED
)
2178 info
.m_stateMask
|= wxLIST_STATE_DROPHILITED
;
2179 if ( lvItem
.state
& LVIS_DROPHILITED
)
2180 info
.m_state
|= wxLIST_STATE_DROPHILITED
;
2182 if ( lvItem
.stateMask
& LVIS_FOCUSED
)
2184 info
.m_stateMask
|= wxLIST_STATE_FOCUSED
;
2185 if ( lvItem
.state
& LVIS_FOCUSED
)
2186 info
.m_state
|= wxLIST_STATE_FOCUSED
;
2188 if ( lvItem
.stateMask
& LVIS_SELECTED
)
2190 info
.m_stateMask
|= wxLIST_STATE_SELECTED
;
2191 if ( lvItem
.state
& LVIS_SELECTED
)
2192 info
.m_state
|= wxLIST_STATE_SELECTED
;
2196 if ( lvItem
.mask
& LVIF_TEXT
)
2198 info
.m_mask
|= wxLIST_MASK_TEXT
;
2199 info
.m_text
= lvItem
.pszText
;
2201 if ( lvItem
.mask
& LVIF_IMAGE
)
2203 info
.m_mask
|= wxLIST_MASK_IMAGE
;
2204 info
.m_image
= lvItem
.iImage
;
2206 if ( lvItem
.mask
& LVIF_PARAM
)
2207 info
.m_mask
|= wxLIST_MASK_DATA
;
2208 if ( lvItem
.mask
& LVIF_DI_SETITEM
)
2209 info
.m_mask
|= wxLIST_SET_ITEM
;
2210 info
.m_col
= lvItem
.iSubItem
;
2215 delete[] lvItem
.pszText
;
2217 lvItem
.mask
= oldMask
;
2220 static void wxConvertToMSWFlags(long state
, long stateMask
, LV_ITEM
& lvItem
)
2222 if (stateMask
& wxLIST_STATE_CUT
)
2224 lvItem
.stateMask
|= LVIS_CUT
;
2225 if (state
& wxLIST_STATE_CUT
)
2226 lvItem
.state
|= LVIS_CUT
;
2228 if (stateMask
& wxLIST_STATE_DROPHILITED
)
2230 lvItem
.stateMask
|= LVIS_DROPHILITED
;
2231 if (state
& wxLIST_STATE_DROPHILITED
)
2232 lvItem
.state
|= LVIS_DROPHILITED
;
2234 if (stateMask
& wxLIST_STATE_FOCUSED
)
2236 lvItem
.stateMask
|= LVIS_FOCUSED
;
2237 if (state
& wxLIST_STATE_FOCUSED
)
2238 lvItem
.state
|= LVIS_FOCUSED
;
2240 if (stateMask
& wxLIST_STATE_SELECTED
)
2242 lvItem
.stateMask
|= LVIS_SELECTED
;
2243 if (state
& wxLIST_STATE_SELECTED
)
2244 lvItem
.state
|= LVIS_SELECTED
;
2248 static void wxConvertToMSWListItem(const wxListCtrl
*ctrl
,
2249 const wxListItem
& info
,
2252 lvItem
.iItem
= (int) info
.m_itemId
;
2254 lvItem
.iImage
= info
.m_image
;
2255 lvItem
.lParam
= info
.m_data
;
2256 lvItem
.stateMask
= 0;
2259 lvItem
.iSubItem
= info
.m_col
;
2261 if (info
.m_mask
& wxLIST_MASK_STATE
)
2263 lvItem
.mask
|= LVIF_STATE
;
2265 wxConvertToMSWFlags(info
.m_state
, info
.m_stateMask
, lvItem
);
2268 if (info
.m_mask
& wxLIST_MASK_TEXT
)
2270 lvItem
.mask
|= LVIF_TEXT
;
2271 if ( ctrl
->GetWindowStyleFlag() & wxLC_USER_TEXT
)
2273 lvItem
.pszText
= LPSTR_TEXTCALLBACK
;
2277 // pszText is not const, hence the cast
2278 lvItem
.pszText
= (wxChar
*)info
.m_text
.c_str();
2279 if ( lvItem
.pszText
)
2280 lvItem
.cchTextMax
= info
.m_text
.Length();
2282 lvItem
.cchTextMax
= 0;
2285 if (info
.m_mask
& wxLIST_MASK_IMAGE
)
2286 lvItem
.mask
|= LVIF_IMAGE
;
2287 if (info
.m_mask
& wxLIST_MASK_DATA
)
2288 lvItem
.mask
|= LVIF_PARAM
;
2291 // ----------------------------------------------------------------------------
2293 // ----------------------------------------------------------------------------
2295 IMPLEMENT_DYNAMIC_CLASS(wxListEvent
, wxNotifyEvent
)
2297 wxListEvent::wxListEvent(wxEventType commandType
, int id
)
2298 : wxNotifyEvent(commandType
, id
)
2304 m_cancelled
= FALSE
;
2307 #endif // wxUSE_LISTCTRL