Mercurial > foo_out_sdl
comparison foosdk/sdk/foobar2000/foo_sample/listcontrol-ownerdata.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 // Owner-data CListControl use demo | |
| 4 // CListControlOwnerData with callbacks | |
| 5 | |
| 6 #include "stdafx.h" | |
| 7 #include "resource.h" | |
| 8 #include <helpers/atl-misc.h> | |
| 9 #include <libPPUI/CListControlOwnerData.h> | |
| 10 #include <string> | |
| 11 #include <algorithm> | |
| 12 #include <vector> | |
| 13 | |
| 14 #include <helpers/DarkMode.h> | |
| 15 | |
| 16 namespace { | |
| 17 struct listData_t { | |
| 18 std::string m_key, m_value; | |
| 19 }; | |
| 20 static std::vector<listData_t> makeListData() { | |
| 21 std::vector<listData_t> data; | |
| 22 data.resize( 10 ); | |
| 23 for( size_t walk = 0; walk < data.size(); ++ walk ) { | |
| 24 auto & rec = data[walk]; | |
| 25 rec.m_key = (PFC_string_formatter() << "Item #" << (walk+1) ).c_str(); | |
| 26 rec.m_value = "edit me"; | |
| 27 } | |
| 28 return data; | |
| 29 } | |
| 30 | |
| 31 | |
| 32 class CListControlOwnerDataDemoDialog : public CDialogImpl<CListControlOwnerDataDemoDialog>, private IListControlOwnerDataSource { | |
| 33 public: | |
| 34 | |
| 35 // CListControlOwnerData constructor requires ptr to IListControlOwnerDataSource object | |
| 36 CListControlOwnerDataDemoDialog() : m_list(this) {} | |
| 37 | |
| 38 enum { IDD = IDD_LISTCONTROL_DEMO }; | |
| 39 | |
| 40 BEGIN_MSG_MAP_EX(CListControlOwnerDataDemoDialog) | |
| 41 MSG_WM_INITDIALOG(OnInitDialog) | |
| 42 COMMAND_HANDLER_EX(IDCANCEL, BN_CLICKED, OnCancel) | |
| 43 MSG_WM_CONTEXTMENU(OnContextMenu) | |
| 44 END_MSG_MAP() | |
| 45 private: | |
| 46 void OnCancel(UINT, int, CWindow) { | |
| 47 DestroyWindow(); | |
| 48 } | |
| 49 | |
| 50 BOOL OnInitDialog(CWindow, LPARAM) { | |
| 51 | |
| 52 // Create replacing existing windows list control | |
| 53 // automatically initialize position, font, etc | |
| 54 m_list.CreateInDialog( *this, IDC_LIST1 ); | |
| 55 | |
| 56 // Do this AFTER creating CListControl, so dark mode hook talks to new CListControl rather than shortlived IDC_LIST1 placeholder | |
| 57 m_dark.AddDialogWithControls(*this); | |
| 58 | |
| 59 // never hardcode values in pixels, always use screen DPI | |
| 60 auto DPI = m_list.GetDPI(); | |
| 61 m_list.AddColumn( "Name", MulDiv(100, DPI.cx, 96 ) ); | |
| 62 m_list.AddColumn( "Value", MulDiv(150, DPI.cx, 96 ) ); | |
| 63 | |
| 64 ShowWindow(SW_SHOW); | |
| 65 | |
| 66 return TRUE; // system should set focus | |
| 67 } | |
| 68 | |
| 69 // Context menu handler | |
| 70 void OnContextMenu(CWindow wnd, CPoint point) { | |
| 71 // did we get a (-1,-1) point due to context menu key rather than right click? | |
| 72 // GetContextMenuPoint fixes that, returning a proper point at which the menu should be shown | |
| 73 point = m_list.GetContextMenuPoint(point); | |
| 74 | |
| 75 CMenu menu; | |
| 76 // WIN32_OP_D() : debug build only return value check | |
| 77 // Used to check for obscure errors in debug builds, does nothing (ignores errors) in release build | |
| 78 WIN32_OP_D(menu.CreatePopupMenu()); | |
| 79 | |
| 80 enum { ID_TEST1 = 1, ID_TEST2, ID_SELECTALL, ID_SELECTNONE, ID_INVERTSEL }; | |
| 81 menu.AppendMenu(MF_STRING, ID_TEST1, L"Test 1"); | |
| 82 menu.AppendMenu(MF_STRING, ID_TEST2, L"Test 2"); | |
| 83 menu.AppendMenu(MF_SEPARATOR); | |
| 84 // Note: Ctrl+A handled automatically by CListControl, no need for us to catch it | |
| 85 menu.AppendMenu(MF_STRING, ID_SELECTALL, L"Select all\tCtrl+A"); | |
| 86 menu.AppendMenu(MF_STRING, ID_SELECTNONE, L"Select none"); | |
| 87 menu.AppendMenu(MF_STRING, ID_INVERTSEL, L"Invert selection"); | |
| 88 | |
| 89 int cmd; | |
| 90 { | |
| 91 // Callback object to show menu command descriptions in the status bar. | |
| 92 // it's actually a hidden window, needs a parent HWND, where we feed our control's HWND | |
| 93 CMenuDescriptionMap descriptions(m_hWnd); | |
| 94 | |
| 95 // Set descriptions of all our items | |
| 96 descriptions.Set(ID_TEST1, "This is a test item #1"); | |
| 97 descriptions.Set(ID_TEST2, "This is a test item #2"); | |
| 98 | |
| 99 descriptions.Set(ID_SELECTALL, "Selects all items"); | |
| 100 descriptions.Set(ID_SELECTNONE, "Deselects all items"); | |
| 101 descriptions.Set(ID_INVERTSEL, "Invert selection"); | |
| 102 | |
| 103 cmd = menu.TrackPopupMenuEx(TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, point.x, point.y, descriptions, nullptr); | |
| 104 } | |
| 105 switch(cmd) { | |
| 106 case ID_TEST1: | |
| 107 { | |
| 108 pfc::string_formatter msg; | |
| 109 msg << "Test command #1 triggered.\r\n"; | |
| 110 msg << m_list.GetSelectedCount() << " items selected."; | |
| 111 // popup_message : non-blocking MessageBox equivalent | |
| 112 popup_message::g_show(msg, "Information"); | |
| 113 } | |
| 114 break; | |
| 115 case ID_TEST2: | |
| 116 { | |
| 117 pfc::string_formatter msg; | |
| 118 msg << "Test command #1 triggered.\r\n"; | |
| 119 msg << "Selected items:\r\n"; | |
| 120 for( size_t walk = 0; walk < m_list.GetItemCount(); ++ walk) { | |
| 121 if ( m_list.IsItemSelected( walk ) ) { | |
| 122 msg << m_data[walk].m_key.c_str() << "\r\n"; | |
| 123 } | |
| 124 } | |
| 125 msg << "End selected items."; | |
| 126 // popup_message : non-blocking MessageBox equivalent | |
| 127 popup_message::g_show(msg, "Information"); | |
| 128 } | |
| 129 break; | |
| 130 case ID_SELECTALL: | |
| 131 m_list.SelectAll(); // trivial | |
| 132 break; | |
| 133 case ID_SELECTNONE: | |
| 134 m_list.SelectNone(); // trivial | |
| 135 break; | |
| 136 case ID_INVERTSEL: | |
| 137 { | |
| 138 auto mask = m_list.GetSelectionMask(); | |
| 139 m_list.SetSelection( | |
| 140 // Items which we alter - all of them | |
| 141 pfc::bit_array_true(), | |
| 142 // Selection values - NOT'd original selection mask | |
| 143 pfc::bit_array_not(mask) | |
| 144 ); | |
| 145 // Exclusion of footer item from selection handled via CanSelectItem() | |
| 146 } | |
| 147 break; | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 private: | |
| 152 // IListControlOwnerDataSource methods | |
| 153 | |
| 154 size_t listGetItemCount( ctx_t ctx ) override { | |
| 155 PFC_ASSERT( ctx == &m_list ); // ctx is a pointer to the object calling us | |
| 156 return m_data.size(); | |
| 157 } | |
| 158 pfc::string8 listGetSubItemText( ctx_t, size_t item, size_t subItem ) override { | |
| 159 auto & rec = m_data[item]; | |
| 160 switch(subItem) { | |
| 161 case 0: | |
| 162 return rec.m_key.c_str(); | |
| 163 case 1: | |
| 164 return rec.m_value.c_str(); | |
| 165 default: | |
| 166 return ""; | |
| 167 } | |
| 168 | |
| 169 } | |
| 170 bool listCanReorderItems( ctx_t ) override { | |
| 171 return true; | |
| 172 } | |
| 173 bool listReorderItems( ctx_t, const size_t* order, size_t count) override { | |
| 174 PFC_ASSERT( count == m_data.size() ); | |
| 175 pfc::reorder_t( m_data, order, count ); | |
| 176 return true; | |
| 177 } | |
| 178 bool listRemoveItems( ctx_t, pfc::bit_array const & mask) override { | |
| 179 pfc::remove_mask_t( m_data, mask ); | |
| 180 return true; | |
| 181 } | |
| 182 void listItemAction(ctx_t, size_t item) override { | |
| 183 m_list.TableEdit_Start( item, 1 ); | |
| 184 } | |
| 185 void listSubItemClicked( ctx_t, size_t item, size_t subItem) override { | |
| 186 if ( subItem == 1 ) { | |
| 187 m_list.TableEdit_Start( item, subItem ); | |
| 188 } | |
| 189 } | |
| 190 void listSetEditField(ctx_t ctx, size_t item, size_t subItem, const char * val) override { | |
| 191 if ( subItem == 1 ) { | |
| 192 m_data[item].m_value = val; | |
| 193 } | |
| 194 } | |
| 195 bool listIsColumnEditable( ctx_t, size_t subItem ) override { | |
| 196 return subItem == 1; | |
| 197 } | |
| 198 | |
| 199 | |
| 200 std::vector< listData_t > m_data = makeListData(); | |
| 201 | |
| 202 CListControlOwnerData m_list; | |
| 203 | |
| 204 fb2k::CDarkModeHooks m_dark; | |
| 205 }; | |
| 206 } | |
| 207 // Called from mainmenu.cpp | |
| 208 void RunListControlOwnerDataDemo() { | |
| 209 // automatically creates the dialog with object lifetime management and modeless dialog registration | |
| 210 fb2k::newDialog<CListControlOwnerDataDemoDialog>(); | |
| 211 } |
