|
1
|
1 #include "stdafx.h"
|
|
|
2
|
|
|
3 #include "win32_utility.h"
|
|
|
4 #include "win32_op.h"
|
|
|
5 #include "listview_helper.h"
|
|
|
6 #include "CListViewCtrlEx.h"
|
|
|
7 #include "CHeaderCtrlEx.h"
|
|
|
8
|
|
|
9 namespace listview_helper {
|
|
|
10
|
|
|
11 unsigned insert_item(HWND p_listview,unsigned p_index,const char * p_name,LPARAM p_param)
|
|
|
12 {
|
|
|
13 if (p_index == ~0) p_index = ListView_GetItemCount(p_listview);
|
|
|
14 LVITEM item = {};
|
|
|
15
|
|
|
16 pfc::stringcvt::string_os_from_utf8 os_string_temp(p_name);
|
|
|
17
|
|
|
18 item.mask = LVIF_TEXT | LVIF_PARAM;
|
|
|
19 item.iItem = p_index;
|
|
|
20 item.lParam = p_param;
|
|
|
21 item.pszText = const_cast<TCHAR*>(os_string_temp.get_ptr());
|
|
|
22
|
|
|
23 LRESULT ret = SendMessage(p_listview,LVM_INSERTITEM,0,(LPARAM)&item);
|
|
|
24 PFC_ASSERT(ret >= 0);
|
|
|
25 if (ret < 0) return UINT_MAX;
|
|
|
26 else return (unsigned) ret;
|
|
|
27 }
|
|
|
28
|
|
|
29 unsigned insert_item2(HWND p_listview, unsigned p_index, const char * col0, const char * col1, LPARAM p_param) {
|
|
|
30 unsigned i = insert_item( p_listview, p_index, col0, p_param );
|
|
|
31 if (i != UINT_MAX) {
|
|
|
32 set_item_text( p_listview, i, 1, col1 );
|
|
|
33 }
|
|
|
34 return i;
|
|
|
35 }
|
|
|
36
|
|
|
37 unsigned insert_item3(HWND p_listview, unsigned p_index, const char * col0, const char * col1, const char * col2, LPARAM p_param) {
|
|
|
38 unsigned i = insert_item( p_listview, p_index, col0, p_param );
|
|
|
39 if (i != UINT_MAX) {
|
|
|
40 set_item_text( p_listview, i, 1, col1 );
|
|
|
41 set_item_text( p_listview, i, 2, col2 );
|
|
|
42 }
|
|
|
43 return i;
|
|
|
44 }
|
|
|
45
|
|
|
46 unsigned insert_column(HWND p_listview,unsigned p_index,const char * p_name,unsigned p_width_dlu)
|
|
|
47 {
|
|
|
48 pfc::stringcvt::string_os_from_utf8 os_string_temp(p_name);
|
|
|
49
|
|
|
50 RECT rect = {0,0,(LONG)p_width_dlu,0};
|
|
|
51 MapDialogRect(GetParent(p_listview),&rect);
|
|
|
52
|
|
|
53 LVCOLUMN data = {};
|
|
|
54 data.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT;
|
|
|
55 data.fmt = LVCFMT_LEFT;
|
|
|
56 data.cx = rect.right;
|
|
|
57 data.pszText = const_cast<TCHAR*>(os_string_temp.get_ptr());
|
|
|
58
|
|
|
59 LRESULT ret = SendMessage(p_listview,LVM_INSERTCOLUMN,p_index,(LPARAM)&data);
|
|
|
60 PFC_ASSERT(ret >= 0);
|
|
|
61 if (ret < 0) return UINT_MAX;
|
|
|
62 else return (unsigned) ret;
|
|
|
63 }
|
|
|
64
|
|
|
65 void get_item_text(HWND p_listview,unsigned p_index,unsigned p_column,pfc::string_base & p_out) {
|
|
|
66 enum {buffer_length = 1024*64};
|
|
|
67 pfc::array_t<TCHAR> buffer; buffer.set_size(buffer_length);
|
|
|
68 ListView_GetItemText(p_listview,p_index,p_column,buffer.get_ptr(),buffer_length);
|
|
|
69 p_out = pfc::stringcvt::string_utf8_from_os(buffer.get_ptr(),buffer_length);
|
|
|
70 }
|
|
|
71
|
|
|
72 bool set_item_text(HWND p_listview,unsigned p_index,unsigned p_column,const char * p_name)
|
|
|
73 {
|
|
|
74 LVITEM item = {};
|
|
|
75
|
|
|
76 pfc::stringcvt::string_os_from_utf8 os_string_temp(p_name);
|
|
|
77
|
|
|
78 item.mask = LVIF_TEXT;
|
|
|
79 item.iItem = p_index;
|
|
|
80 item.iSubItem = p_column;
|
|
|
81 item.pszText = const_cast<TCHAR*>(os_string_temp.get_ptr());
|
|
|
82 return SendMessage(p_listview,LVM_SETITEM,0,(LPARAM)&item) ? true : false;
|
|
|
83 }
|
|
|
84
|
|
|
85 bool is_item_selected(HWND p_listview,unsigned p_index)
|
|
|
86 {
|
|
|
87 LVITEM item = {};
|
|
|
88 item.mask = LVIF_STATE;
|
|
|
89 item.iItem = p_index;
|
|
|
90 item.stateMask = LVIS_SELECTED;
|
|
|
91 if (!SendMessage(p_listview,LVM_GETITEM,0,(LPARAM)&item)) return false;
|
|
|
92 return (item.state & LVIS_SELECTED) ? true : false;
|
|
|
93 }
|
|
|
94
|
|
|
95 void set_item_selection(HWND p_listview,unsigned p_index,bool p_state)
|
|
|
96 {
|
|
|
97 PFC_ASSERT( ::IsWindow(p_listview) );
|
|
|
98 LVITEM item = {};
|
|
|
99 item.stateMask = LVIS_SELECTED;
|
|
|
100 item.state = p_state ? LVIS_SELECTED : 0;
|
|
|
101 WIN32_OP_D( SendMessage(p_listview,LVM_SETITEMSTATE,(WPARAM)p_index,(LPARAM)&item) );
|
|
|
102 }
|
|
|
103
|
|
|
104 bool select_single_item(HWND p_listview,unsigned p_index)
|
|
|
105 {
|
|
|
106 LRESULT temp = SendMessage(p_listview,LVM_GETITEMCOUNT,0,0);
|
|
|
107 if (temp < 0) return false;
|
|
|
108 ListView_SetSelectionMark(p_listview,p_index);
|
|
|
109 unsigned n; const unsigned m = pfc::downcast_guarded<unsigned>(temp);
|
|
|
110 for(n=0;n<m;n++) {
|
|
|
111 enum {mask = LVIS_FOCUSED | LVIS_SELECTED};
|
|
|
112 ListView_SetItemState(p_listview,n,n == p_index ? mask : 0, mask);
|
|
|
113 }
|
|
|
114 return ensure_visible(p_listview,p_index);
|
|
|
115 }
|
|
|
116
|
|
|
117 bool ensure_visible(HWND p_listview,unsigned p_index)
|
|
|
118 {
|
|
|
119 return SendMessage(p_listview,LVM_ENSUREVISIBLE,p_index,FALSE) ? true : false;
|
|
|
120 }
|
|
|
121 }
|
|
|
122
|
|
|
123
|
|
|
124 void ListView_GetContextMenuPoint(HWND p_list,LPARAM p_coords,POINT & p_point,int & p_selection) {
|
|
|
125 POINT pt = {(short)LOWORD(p_coords),(short)HIWORD(p_coords)};
|
|
|
126 ListView_GetContextMenuPoint(p_list, pt, p_point, p_selection);
|
|
|
127 }
|
|
|
128
|
|
|
129 void ListView_GetContextMenuPoint(HWND p_list,POINT p_coords,POINT & p_point,int & p_selection) {
|
|
|
130 if (p_coords.x == -1 && p_coords.y == -1) {
|
|
|
131 int firstsel = ListView_GetFirstSelection(p_list);
|
|
|
132 if (firstsel >= 0) {
|
|
|
133 ListView_EnsureVisible(p_list, firstsel, FALSE);
|
|
|
134 RECT rect;
|
|
|
135 WIN32_OP_D( ListView_GetItemRect(p_list,firstsel,&rect,LVIR_BOUNDS) );
|
|
|
136 p_point.x = (rect.left + rect.right) / 2;
|
|
|
137 p_point.y = (rect.top + rect.bottom) / 2;
|
|
|
138 WIN32_OP_D( ClientToScreen(p_list,&p_point) );
|
|
|
139 } else {
|
|
|
140 RECT rect;
|
|
|
141 WIN32_OP_D(GetClientRect(p_list,&rect));
|
|
|
142 p_point.x = (rect.left + rect.right) / 2;
|
|
|
143 p_point.y = (rect.top + rect.bottom) / 2;
|
|
|
144 WIN32_OP_D(ClientToScreen(p_list,&p_point));
|
|
|
145 }
|
|
|
146 p_selection = firstsel;
|
|
|
147 } else {
|
|
|
148 POINT pt = p_coords; // {(short)LOWORD(p_coords),(short)HIWORD(p_coords)};
|
|
|
149 p_point = pt;
|
|
|
150 POINT client = pt;
|
|
|
151 WIN32_OP_D( ScreenToClient(p_list,&client) );
|
|
|
152 LVHITTESTINFO info = {};
|
|
|
153 info.pt = client;
|
|
|
154 p_selection = ListView_HitTest(p_list,&info);
|
|
|
155 }
|
|
|
156 }
|
|
|
157
|
|
|
158 int ListView_GetFirstSelection(HWND p_listview) {
|
|
|
159 return ListView_GetNextItem(p_listview, -1, LVNI_SELECTED);
|
|
|
160 }
|
|
|
161
|
|
|
162 int ListView_GetSingleSelection(HWND p_listview) {
|
|
|
163 if (ListView_GetSelectedCount(p_listview) != 1) return -1;
|
|
|
164 return ListView_GetFirstSelection(p_listview);
|
|
|
165 }
|
|
|
166
|
|
|
167 int ListView_GetFocusItem(HWND p_listview) {
|
|
|
168 return ListView_GetNextItem(p_listview, -1, LVNI_FOCUSED);
|
|
|
169 }
|
|
|
170
|
|
|
171 bool ListView_IsItemSelected(HWND p_listview, int p_index) {
|
|
|
172 return ListView_GetItemState(p_listview, p_index, LVIS_SELECTED) != 0;
|
|
|
173 }
|
|
|
174
|
|
|
175 int ListView_GetColumnCount(HWND listView) {
|
|
|
176 HWND header = ListView_GetHeader(listView);
|
|
|
177 PFC_ASSERT(header != NULL);
|
|
|
178 return Header_GetItemCount(header);
|
|
|
179 }
|
|
|
180
|
|
|
181 void ListView_FixContextMenuPoint(CListViewCtrl list, CPoint & coords) {
|
|
|
182 if (coords == CPoint(-1, -1)) {
|
|
|
183 int selWalk = -1;
|
|
|
184 CRect rcClient; WIN32_OP_D(list.GetClientRect(rcClient));
|
|
|
185 for (;;) {
|
|
|
186 selWalk = list.GetNextItem(selWalk, LVNI_SELECTED);
|
|
|
187 if (selWalk < 0) {
|
|
|
188 CRect rc;
|
|
|
189 WIN32_OP_D(list.GetWindowRect(&rc));
|
|
|
190 coords = rc.CenterPoint();
|
|
|
191 return;
|
|
|
192 }
|
|
|
193 CRect rcItem, rcVisible;
|
|
|
194 WIN32_OP_D(list.GetItemRect(selWalk, &rcItem, LVIR_BOUNDS));
|
|
|
195 if (rcVisible.IntersectRect(rcItem, rcClient)) {
|
|
|
196 coords = rcVisible.CenterPoint();
|
|
|
197 WIN32_OP_D(list.ClientToScreen(&coords));
|
|
|
198 return;
|
|
|
199 }
|
|
|
200 }
|
|
|
201 }
|
|
|
202 }
|
|
|
203
|
|
|
204 unsigned CListViewCtrlEx::GetColunnCount() {
|
|
|
205 return (unsigned) ListView_GetColumnCount( *this );
|
|
|
206 }
|
|
|
207 unsigned CListViewCtrlEx::AddColumnEx(const wchar_t * name, unsigned widthDLU) {
|
|
|
208 return InsertColumnEx( GetColunnCount(), name, widthDLU );
|
|
|
209 }
|
|
|
210 unsigned CListViewCtrlEx::InsertColumnEx(unsigned index, const wchar_t * name, unsigned widthDLU) {
|
|
|
211
|
|
|
212 RECT rect = { 0,0,(LONG)widthDLU,0 };
|
|
|
213 MapDialogRect(GetParent(), &rect);
|
|
|
214
|
|
|
215 LVCOLUMN data = {};
|
|
|
216 data.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_FMT;
|
|
|
217 data.fmt = LVCFMT_LEFT;
|
|
|
218 data.cx = rect.right;
|
|
|
219 data.pszText = const_cast<wchar_t*>(name);
|
|
|
220
|
|
|
221 auto ret = this->InsertColumn(index, & data );
|
|
|
222 if (ret < 0) return UINT_MAX;
|
|
|
223 else return (unsigned)ret;
|
|
|
224 }
|
|
|
225
|
|
|
226 void CListViewCtrlEx::FixContextMenuPoint(CPoint & pt) {
|
|
|
227 ListView_FixContextMenuPoint(*this, pt);
|
|
|
228 }
|
|
|
229
|
|
|
230
|
|
|
231
|
|
|
232 unsigned CListViewCtrlEx::InsertString(unsigned index, const wchar_t * str) {
|
|
|
233 LVITEM item = {};
|
|
|
234
|
|
|
235 item.mask = LVIF_TEXT;
|
|
|
236 item.iItem = index;
|
|
|
237 item.pszText = const_cast<wchar_t*>(str);
|
|
|
238
|
|
|
239 auto ret = InsertItem(&item);
|
|
|
240 if ( ret < 0 ) return UINT_MAX;
|
|
|
241 else return (unsigned) ret;
|
|
|
242 }
|
|
|
243 unsigned CListViewCtrlEx::InsertString8(unsigned index, const char * str) {
|
|
|
244 return InsertString(index, pfc::stringcvt::string_os_from_utf8( str ) );
|
|
|
245 }
|
|
|
246 unsigned CListViewCtrlEx::AddString(const wchar_t * str) {
|
|
|
247 return InsertString(GetItemCount(), str);
|
|
|
248 }
|
|
|
249 unsigned CListViewCtrlEx::AddString8(const char * str) {
|
|
|
250 return AddString(pfc::stringcvt::string_os_from_utf8( str ) );
|
|
|
251 }
|
|
|
252 void CListViewCtrlEx::SetItemText(unsigned iItem, unsigned iSubItem, const wchar_t * str) {
|
|
|
253 LVITEM item = {};
|
|
|
254 item.mask = LVIF_TEXT;
|
|
|
255 item.iItem = iItem;
|
|
|
256 item.iSubItem = iSubItem;
|
|
|
257 item.pszText = const_cast<wchar_t*>(str);
|
|
|
258 SetItem(&item);
|
|
|
259 }
|
|
|
260 void CListViewCtrlEx::SetItemText8(unsigned item, unsigned subItem, const char * str) {
|
|
|
261 SetItemText( item, subItem, pfc::stringcvt::string_os_from_utf8( str ) );
|
|
|
262 }
|
|
|
263
|
|
|
264
|
|
|
265 DWORD CHeaderCtrlEx::GetItemFormat(int iItem) {
|
|
|
266 HDITEM item = {};
|
|
|
267 item.mask = HDI_FORMAT;
|
|
|
268 if (!this->GetItem(iItem, &item)) return 0;
|
|
|
269 return item.fmt;
|
|
|
270 }
|
|
|
271 void CHeaderCtrlEx::SetItemFormat(int iItem, DWORD flags) {
|
|
|
272 HDITEM item = {};
|
|
|
273 item.mask = HDI_FORMAT;
|
|
|
274 item.fmt = flags;
|
|
|
275 SetItem(iItem, &item);
|
|
|
276 }
|
|
|
277
|
|
|
278 void CHeaderCtrlEx::SetItemSort(int iItem, int direction) {
|
|
|
279 DWORD fmtWas = GetItemFormat(iItem);
|
|
|
280 DWORD fmt = fmtWas & ~(HDF_SORTDOWN | HDF_SORTUP);
|
|
|
281 if (direction > 0) fmt |= HDF_SORTDOWN;
|
|
|
282 else if (direction < 0) fmt |= HDF_SORTUP;
|
|
|
283 if (fmt != fmtWas) SetItemFormat(iItem, fmt);
|
|
|
284 }
|
|
|
285
|
|
|
286 void CHeaderCtrlEx::SetSingleItemSort(int iItem, int direction) {
|
|
|
287 const int total = GetItemCount();
|
|
|
288 for (int walk = 0; walk < total; ++walk) {
|
|
|
289 SetItemSort(walk, walk == iItem ? direction : 0);
|
|
|
290 }
|
|
|
291 }
|
|
|
292
|
|
|
293 void CHeaderCtrlEx::ClearSort() {
|
|
|
294 SetSingleItemSort(-1,0);
|
|
|
295 }
|
|
|
296
|
|
|
297 int CListViewCtrlEx::AddGroup(int iGroupID, const wchar_t * header) {
|
|
|
298 LVGROUP g = { sizeof(g) };
|
|
|
299 g.mask = LVGF_HEADER | LVGF_GROUPID;
|
|
|
300 g.pszHeader = const_cast<wchar_t*>( header );
|
|
|
301 g.iGroupId = iGroupID;
|
|
|
302 return __super::AddGroup(&g);
|
|
|
303 }
|