comparison foosdk/sdk/libPPUI/CListControlSimple.h @ 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 #pragma once
2
3 // ================================================================================
4 // CListControlSimple
5 // Simplified CListControl interface; a ready-to-use class that can be instantiated
6 // without subclassing or setting callback objects.
7 // Use when you don't need advanced features such as buttons or editing.
8 // Maintains its own data.
9 // ================================================================================
10
11 #include "CListControlComplete.h"
12
13 #include <functional>
14 #include <vector>
15 #include <map>
16 #include <string>
17 #include <algorithm>
18
19
20 class CListControlSimple : public CListControlReadOnly {
21 public:
22 // Events
23 std::function<void()> onReordered; // if not set, list reordering is disabled
24 std::function<void()> onRemoved; // if not set, list item removal is disabled
25 std::function<void(size_t)> onItemAction; // optional, handle item double click or enter key
26 std::function<void()> onSelChange; // optional, handle selectionchange
27 std::function<void(size_t)> onColumnHeaderClick; // optional, handle column header click, if not set sorting will happen
28
29 size_t GetItemCount() const override {
30 return m_lines.size();
31 }
32 void SetItemCount( size_t count ) {
33 m_lines.resize( count );
34 ReloadData();
35 }
36 void SetItemText(size_t item, size_t subItem, const char * text, bool bRedraw = true) {
37 if ( item < m_lines.size() ) {
38 m_lines[item].text[subItem] = text;
39 if ( bRedraw ) ReloadItem( item );
40 } else {
41 PFC_ASSERT(!"CListControlSimple: item index out of range, call SetItemCount() first");
42 }
43 }
44 bool GetSubItemText(size_t item, size_t subItem, pfc::string_base & out) const override {
45 if ( item < m_lines.size() ) {
46 auto & l = m_lines[item].text;
47 auto iter = l.find( subItem );
48 if ( iter != l.end() ) {
49 out = iter->second.c_str();
50 return true;
51 }
52 }
53 return false;
54 }
55
56 uint32_t QueryDragDropTypes() const override {
57 return (onReordered != nullptr) ? dragDrop_reorder : 0;
58 }
59
60 void RequestReorder( const size_t * order, size_t count) override {
61 if ( onReordered == nullptr ) return;
62 _Reorder(order, count);
63 }
64 void RequestRemoveSelection() override {
65 if (onRemoved == nullptr) return;
66 auto mask = this->GetSelectionMask();
67 size_t oldCount = m_lines.size();
68 pfc::remove_mask_t( m_lines, mask );
69 this->OnItemsRemoved( mask, oldCount );
70 onRemoved();
71 }
72 void ExecuteDefaultAction( size_t idx ) override {
73 if (onItemAction != nullptr) onItemAction(idx);
74 }
75
76 void SetItemUserData( size_t item, size_t user ) {
77 if ( item < m_lines.size() ) {
78 m_lines[item].user = user;
79 }
80 }
81 size_t GetItemUserData( size_t item ) const {
82 size_t ret = 0;
83 if ( item < m_lines.size() ) {
84 ret = m_lines[item].user;
85 }
86 return ret;
87 }
88 void RemoveAllItems() {
89 RemoveItems(pfc::bit_array_true());
90 }
91 void RemoveItems( pfc::bit_array const & mask ) {
92 const auto oldCount = m_lines.size();
93 pfc::remove_mask_t( m_lines, mask );
94 this->OnItemsRemoved( mask, oldCount );
95 }
96 void RemoveItem( size_t which ) {
97 RemoveItems( pfc::bit_array_one( which ) );
98 }
99
100 size_t InsertItem( size_t insertAt, const char * textCol0 = nullptr ) {
101 if ( insertAt > m_lines.size() ) {
102 insertAt = m_lines.size();
103 }
104 {
105 line_t data;
106 if ( textCol0 != nullptr ) data.text[0] = textCol0;
107 m_lines.insert( m_lines.begin() + insertAt, std::move(data) );
108 }
109 this->OnItemsInserted( insertAt, 1, false );
110 return insertAt;
111 }
112 size_t AddItem( const char * textCol0 = nullptr ) {
113 return InsertItem( SIZE_MAX, textCol0 );
114 }
115 size_t InsertItems( size_t insertAt, size_t count ) {
116 if ( insertAt > m_lines.size() ) {
117 insertAt = m_lines.size();
118 }
119
120 {
121 line_t val;
122 m_lines.insert( m_lines.begin() + insertAt, count, val );
123 }
124
125 this->OnItemsInserted( insertAt, count, false );
126 return insertAt;
127 }
128 void SortBy(size_t column, bool descending) {
129 std::vector<size_t> order; order.resize(m_lines.size());
130 for (size_t walk = 0; walk < order.size(); ++walk) order[walk] = walk;
131 auto pred = [column, descending](const line_t& l1, const line_t& l2) {
132 int ret = pfc::winNaturalSortCompare(l1.at(column), l2.at(column));
133 if (!descending) ret = -ret;
134 return ret > 0;
135 };
136 auto pred_order = [&](size_t i1, size_t i2) {
137 return pred(m_lines[i1], m_lines[i2]);
138 };
139 std::sort(order.begin(), order.end(), pred_order);
140 this->_Reorder(order.data(), order.size());
141 this->SetSortIndicator(column, descending);
142 }
143 void SortBy(size_t column) {
144 HDITEM item = { HDI_FORMAT };
145 if (this->GetHeaderCtrl().GetItem((int)column, &item)) {
146 bool bDescending = (item.fmt & HDF_SORTDOWN) != 0;
147 this->SortBy(column, bDescending);
148 }
149 }
150 protected:
151 void OnSelectionChanged(pfc::bit_array const & affected, pfc::bit_array const & status) override {
152 __super::OnSelectionChanged(affected, status);
153 if ( onSelChange ) onSelChange();
154 }
155 void OnColumnHeaderClick(t_size index) {
156 __super::OnColumnHeaderClick(index);
157 if (onColumnHeaderClick) onColumnHeaderClick(index);
158 else this->SortBy(index);
159 }
160 void _Reorder(const size_t* order, size_t count) {
161 pfc::reorder_t(m_lines, order, count);
162 this->OnItemsReordered(order, count);
163 if (onReordered) onReordered();
164 }
165 private:
166 struct line_t {
167 std::map<size_t, std::string> text;
168 size_t user = 0;
169 const char* at(size_t i) const {
170 auto iter = text.find(i);
171 if (iter == text.end()) return "";
172 return iter->second.c_str();
173 }
174 };
175 std::vector<line_t> m_lines;
176 };