Added multi-column sorting to data tables.
This commit is contained in:
parent
9d02d97af3
commit
da8d1589b3
@ -5,6 +5,7 @@
|
|||||||
#define RAID_PUBLIC_RAID_IMRAID_HPP_INCLUDED 1
|
#define RAID_PUBLIC_RAID_IMRAID_HPP_INCLUDED 1
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -73,8 +74,13 @@ inline bool BeginPopupButton(const char* label)
|
|||||||
struct DataTableState
|
struct DataTableState
|
||||||
{
|
{
|
||||||
std::vector<std::size_t> sortedIndices;
|
std::vector<std::size_t> sortedIndices;
|
||||||
std::size_t sortColumn = 0;
|
|
||||||
|
struct SortColumn
|
||||||
|
{
|
||||||
|
std::size_t index;
|
||||||
bool sortDescending = false;
|
bool sortDescending = false;
|
||||||
|
};
|
||||||
|
std::vector<SortColumn> sortColumns;
|
||||||
bool dirty = true;
|
bool dirty = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -97,7 +103,8 @@ template<typename TObject>
|
|||||||
struct DataTableOptions
|
struct DataTableOptions
|
||||||
{
|
{
|
||||||
std::span<const DataTableColumn<TObject>> columns;
|
std::span<const DataTableColumn<TObject>> columns;
|
||||||
ImGuiTableFlags tableFlags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Sortable | ImGuiTableFlags_ScrollY;
|
ImGuiTableFlags tableFlags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Sortable
|
||||||
|
| ImGuiTableFlags_ScrollY | ImGuiTableFlags_SortMulti;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename TObject,typename TData>
|
template<typename TObject,typename TData>
|
||||||
@ -128,10 +135,23 @@ inline void DataTable(const char* strId, const DataTableOptions<TObject>& option
|
|||||||
{
|
{
|
||||||
sortSpecs->SpecsDirty = false;
|
sortSpecs->SpecsDirty = false;
|
||||||
|
|
||||||
const ImGuiTableColumnSortSpecs& specs = *sortSpecs->Specs;
|
if (state.sortColumns.size() != static_cast<std::size_t>(sortSpecs->SpecsCount))
|
||||||
state.dirty |= (specs.ColumnIndex != static_cast<ImS16>(state.sortColumn));
|
{
|
||||||
state.sortColumn = specs.ColumnIndex;
|
state.dirty = true;
|
||||||
state.sortDescending = specs.SortDirection == ImGuiSortDirection_Descending;
|
state.sortColumns.resize(sortSpecs->SpecsCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int idx = 0; idx < sortSpecs->SpecsCount; ++idx)
|
||||||
|
{
|
||||||
|
const ImGuiTableColumnSortSpecs& specs = sortSpecs->Specs[idx];
|
||||||
|
DataTableState::SortColumn& column = state.sortColumns[idx];
|
||||||
|
state.dirty |= (static_cast<std::size_t>(specs.ColumnIndex) != column.index);
|
||||||
|
state.dirty |= column.sortDescending != (specs.SortDirection == ImGuiSortDirection_Descending);
|
||||||
|
column = {
|
||||||
|
.index = static_cast<std::size_t>(specs.ColumnIndex),
|
||||||
|
.sortDescending = (specs.SortDirection == ImGuiSortDirection_Descending)
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.sortedIndices.size() != data.size())
|
if (state.sortedIndices.size() != data.size())
|
||||||
@ -145,16 +165,28 @@ inline void DataTable(const char* strId, const DataTableOptions<TObject>& option
|
|||||||
for (std::size_t idx = 0; idx < data.size(); ++idx) {
|
for (std::size_t idx = 0; idx < data.size(); ++idx) {
|
||||||
state.sortedIndices[idx] = idx;
|
state.sortedIndices[idx] = idx;
|
||||||
}
|
}
|
||||||
std::ranges::sort(state.sortedIndices, [&](std::size_t leftIdx, std::size_t rightIdx) {
|
std::ranges::sort(state.sortedIndices, [&](std::size_t leftIdx, std::size_t rightIdx)
|
||||||
return options.columns[state.sortColumn].comparator(data[leftIdx], data[rightIdx]);
|
{
|
||||||
|
for (const DataTableState::SortColumn& column : state.sortColumns)
|
||||||
|
{
|
||||||
|
const bool less = options.columns[column.index].comparator(data[leftIdx], data[rightIdx]);
|
||||||
|
if (less)
|
||||||
|
{ // left < right
|
||||||
|
return !column.sortDescending;
|
||||||
|
}
|
||||||
|
if (options.columns[column.index].comparator(data[rightIdx], data[leftIdx]))
|
||||||
|
{ // left > right
|
||||||
|
return column.sortDescending;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// left == right
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
state.dirty = false;
|
state.dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::size_t indexIdx = 0; indexIdx < state.sortedIndices.size(); ++indexIdx)
|
for (const std::size_t dataIdx : state.sortedIndices)
|
||||||
{
|
{
|
||||||
const std::size_t dataIdx = state.sortDescending ? state.sortedIndices[state.sortedIndices.size() - indexIdx - 1]
|
|
||||||
: state.sortedIndices[indexIdx];
|
|
||||||
const TObject& object = data[dataIdx];
|
const TObject& object = data[dataIdx];
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user