Mercurial > foo_out_sdl
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 } |
