From d3b56d3fd0e52002f38107e29b755324023e92b1 Mon Sep 17 00:00:00 2001
From: Patrick Wuttke
Date: Fri, 19 Sep 2025 13:53:42 +0200
Subject: [PATCH] Added DataTable function.
---
public/raid/imraid.hpp | 107 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 107 insertions(+)
diff --git a/public/raid/imraid.hpp b/public/raid/imraid.hpp
index 179e858..a59edb5 100644
--- a/public/raid/imraid.hpp
+++ b/public/raid/imraid.hpp
@@ -4,7 +4,14 @@
#if !defined(RAID_PUBLIC_RAID_IMRAID_HPP_INCLUDED)
#define RAID_PUBLIC_RAID_IMRAID_HPP_INCLUDED 1
+#include
+#include
+#include
+#include
+#include
+
#include
+#include
namespace ImRaid
{
@@ -47,6 +54,106 @@ inline bool ToggleImageButton(const char* strId, ImTextureID textureId, const Im
}
return clicked;
}
+
+struct DataTableState
+{
+ std::vector sortedIndices;
+ std::size_t sortColumn = 0;
+ bool sortDescending = false;
+ bool dirty = true;
+};
+
+template
+struct DataTableColumn
+{
+ struct CellRendererArgs
+ {
+ const TObject& object;
+ };
+ using renderer_t = std::function;
+ using comparator_t = std::function;
+
+ std::string header;
+ renderer_t renderer;
+ comparator_t comparator;
+};
+
+template
+struct DataTableOptions
+{
+ std::span> columns;
+ ImGuiTableFlags tableFlags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Sortable | ImGuiTableFlags_ScrollY;
+};
+
+template
+inline void DataTable(const char* strId, const DataTableOptions& options, const TData& data, DataTableState& state, ImVec2 outerSize = {})
+{
+ if (outerSize.y <= 0.f) {
+ outerSize.y = ImGui::GetContentRegionAvail().y;
+ }
+
+ if (!ImGui::BeginTable(strId, static_cast(options.columns.size()), options.tableFlags, outerSize)) {
+ return;
+ }
+
+ for (const DataTableColumn& column : options.columns)
+ {
+ ImGuiTableColumnFlags flags = 0;
+ MIJIN_ASSERT(column.renderer, "Missing column renderer.");
+ if (!column.comparator) {
+ flags |= ImGuiTableColumnFlags_NoSort;
+ }
+ ImGui::TableSetupColumn(column.header.c_str(), flags);
+ }
+ ImGui::TableSetupScrollFreeze(0, 1);
+ ImGui::TableHeadersRow();
+
+ ImGuiTableSortSpecs* sortSpecs = ImGui::TableGetSortSpecs();
+ if (sortSpecs != nullptr && sortSpecs->SpecsDirty)
+ {
+ sortSpecs->SpecsDirty = false;
+
+ const ImGuiTableColumnSortSpecs& specs = *sortSpecs->Specs;
+ state.dirty |= (specs.ColumnIndex != state.sortColumn);
+ state.sortColumn = specs.ColumnIndex;
+ state.sortDescending = specs.SortDirection == ImGuiSortDirection_Descending;
+ }
+
+ if (state.sortedIndices.size() != data.size())
+ {
+ state.dirty = true;
+ state.sortedIndices.resize(data.size());
+ }
+
+ if (state.dirty)
+ {
+ for (std::size_t idx = 0; idx < data.size(); ++idx) {
+ state.sortedIndices[idx] = idx;
+ }
+ std::ranges::sort(state.sortedIndices, [&](std::size_t leftIdx, std::size_t rightIdx) {
+ return options.columns[state.sortColumn].comparator(data[leftIdx], data[rightIdx]);
+ });
+ state.dirty = false;
+ }
+
+ for (std::size_t indexIdx = 0; indexIdx < state.sortedIndices.size(); ++indexIdx)
+ {
+ const std::size_t dataIdx = state.sortDescending ? state.sortedIndices[state.sortedIndices.size() - indexIdx - 1]
+ : state.sortedIndices[indexIdx];
+ const TObject& object = data[dataIdx];
+ ImGui::TableNextRow();
+
+ for (const DataTableColumn& column : options.columns)
+ {
+ ImGui::TableNextColumn();
+ column.renderer({
+ .object = object
+ });
+ }
+ }
+
+ ImGui::EndTable();
+}
} // namespace ImRaid
#endif // !defined(RAID_PUBLIC_RAID_IMRAID_HPP_INCLUDED)