comparison foosdk/sdk/libPPUI/listview_helper.cpp @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
comparison
equal deleted inserted replaced
0:e9bb126753e7 1:20d02a178406
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 }