listview.hpp (5225B)
1 /* ReaPack: Package manager for REAPER 2 * Copyright (C) 2015-2025 Christian Fillion 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #ifndef REAPACK_LISTVIEW_HPP 19 #define REAPACK_LISTVIEW_HPP 20 21 #include "control.hpp" 22 23 #include "event.hpp" 24 #include "filter.hpp" 25 #include "serializer.hpp" 26 27 #include <functional> 28 #include <optional> 29 #include <vector> 30 31 class Menu; 32 33 class ListView : public Control { 34 public: 35 enum SortOrder { AscendingOrder, DescendingOrder }; 36 37 enum ColumnFlag { 38 NoLabelFlag = 1<<0, 39 CollapseFlag = 1<<1, 40 FilterFlag = 1<<2, 41 }; 42 43 enum ColumnDataType { 44 UserType, 45 VersionType, 46 TimeType, 47 }; 48 49 struct Cell { 50 Cell() : userData(nullptr) {} 51 Cell(const Cell &) = delete; 52 53 std::string value; 54 void *userData; 55 }; 56 57 class Row { 58 public: 59 Row(void *data, ListView *); 60 Row(const Row &) = delete; 61 ~Row() { delete[] m_cells; } 62 63 void *userData; 64 65 int index() const { return userIndex; } 66 67 const Cell &cell(const int i) const { return m_cells[i]; } 68 void setCell(const int i, const std::string &, void *data = nullptr); 69 void setChecked(bool check = true); 70 71 std::vector<std::string> filterValues() const; 72 73 protected: 74 friend ListView; 75 int viewIndex; 76 int userIndex; 77 78 private: 79 ListView *m_list; 80 Cell *m_cells; 81 }; 82 83 struct Column { 84 std::string label; 85 int width; 86 int flags; 87 ColumnDataType dataType; 88 89 bool test(ColumnFlag f) const { return (flags & f) != 0; } 90 int compare(const Cell &, const Cell &) const; 91 }; 92 93 // Use before modifying the list's content. It will re-sort and/or re-filter the 94 // list automatically when destructed and, on Windows, also prevents flickering. 95 class BeginEdit { 96 public: 97 BeginEdit(ListView *lv) : m_list(lv), m_inhibit(lv) {} 98 ~BeginEdit() { m_list->endEdit(); } 99 100 private: 101 ListView *m_list; 102 InhibitControl m_inhibit; 103 }; 104 105 typedef std::vector<Column> Columns; 106 107 ListView(HWND handle, const Columns & = {}); 108 109 void reserveRows(size_t count) { m_rows.reserve(count); } 110 Row *createRow(void *data = nullptr); 111 Row *row(size_t index) const { return m_rows[index].get(); } 112 void removeRow(int index); 113 int rowCount() const { return static_cast<int>(m_rows.size()); } 114 int visibleRowCount() const; 115 bool empty() const { return m_rows.empty(); } 116 117 void clear(); 118 void reset(); 119 void autoSizeHeader(); 120 void enableIcons(); 121 122 int currentIndex() const; 123 bool headerHitTest(int x, int y) const; 124 int itemUnder(int x, int y, bool *overIcon = nullptr) const; 125 int itemUnderMouse(bool *overIcon = nullptr) const; 126 127 int scroll() const; 128 void setScroll(int); 129 130 void setSelected(int index, bool select); 131 void select(int index) { setSelected(index, true); } 132 void unselect(int index) { setSelected(index, false); } 133 void selectAll(); 134 void unselectAll(); 135 int selectionSize() const; 136 bool hasSelection() const { return selectionSize() > 0; } 137 std::vector<int> selection(bool sort = true) const; 138 139 int addColumn(const Column &); 140 const Column &column(int index) const { return m_cols[index]; } 141 void resizeColumn(int index, int width); 142 int columnWidth(int index) const; 143 int columnCount() const; 144 145 void sortByColumn(int index, SortOrder order = AscendingOrder, bool user = false); 146 void setFilter(const std::string &); 147 void endEdit(); 148 149 void restoreState(Serializer::Data &); 150 void saveState(Serializer::Data &) const; 151 void resetColumns(); 152 153 Event<void()> onSelect; 154 Event<void()> onIconClick; 155 Event<void()> onActivate; 156 Event<bool(Menu &, int index)> onFillContextMenu; 157 158 protected: 159 friend Row; 160 161 void updateCell(int row, int cell); 162 void setRowIcon(int row, int icon); 163 164 private: 165 struct Sort { 166 int column = -1; 167 SortOrder order = AscendingOrder; 168 }; 169 170 enum DirtyFlag { 171 NeedSortFlag = 1<<0, 172 NeedReindexFlag = 1<<1, 173 NeedFilterFlag = 1<<2, 174 }; 175 176 void onNotify(LPNMHDR, LPARAM) override; 177 bool onContextMenu(HWND, int, int) override; 178 179 void setExStyle(int style, bool enable = true); 180 void setSortArrow(bool); 181 void onItemChanged(LPARAM lpnmlistview); 182 void onClick(bool dbclick); 183 void onColumnClick(LPARAM lpnmlistview); 184 int translate(int userIndex) const; 185 int translateBack(int internalIndex) const; 186 void headerMenu(int x, int y); 187 void insertItem(int viewIndex, int rowIndex); 188 void sort(); 189 void reindexVisible(); 190 void filter(); 191 192 int m_dirty; 193 Filter m_filter; 194 195 bool m_customizable; 196 std::vector<Column> m_cols; 197 std::vector<std::unique_ptr<Row>> m_rows; 198 std::optional<Sort> m_sort; 199 std::optional<Sort> m_defaultSort; 200 }; 201 202 #endif