Skip to content

Commit

Permalink
Implement signal multi-selection
Browse files Browse the repository at this point in the history
This way they can be added with fewer clicks.
The latest Imgui version is required for this, as multi-selection has
only recently been implemented in imgui:
ocornut/imgui#6518

Fixes #193

While we are at it, this patch also implements clipping of the list with
an ImGuiListClipper.
This is possible, because all rows have the same height in the table.
With this change, scrolling through a large list (100k+ rows) is
significantly smoother.
  • Loading branch information
vimpostor committed Aug 16, 2024
1 parent c39e885 commit d67c1e2
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 24 deletions.
2 changes: 1 addition & 1 deletion src/ui/cmake/Dependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ include(FetchContent)
FetchContent_Declare(
imgui
GIT_REPOSITORY https://github.com/ocornut/imgui.git
GIT_TAG v1.90.8 # latest as of 2024-07-01
GIT_TAG v1.91.0 # latest as of 2024-08-15
SYSTEM
)

Expand Down
76 changes: 53 additions & 23 deletions src/ui/components/SignalSelector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,27 +344,6 @@ class SignalSelector {
}
}

void drawElement(const SignalData& entry, int idx, FlowGraph* fg) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted(entry.device.c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(entry.signalName.c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(entry.quantity.c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(entry.unit.c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(entry.frontend.c_str());
ImGui::TableNextColumn();
ImGui::Text(entry.comment.c_str());
ImGui::TableNextColumn();
if (ImGui::Button(("+##" + std::to_string(idx)).c_str())) {
const auto uri = opencmw::URI<>::UriFactory().scheme(entry.protocol).hostName(entry.hostname).port(static_cast<uint16_t>(entry.port)).path(entry.serviceName).addQueryParameter("channelNameFilter", entry.signalName).build();
fg->addRemoteSource(uri.str());
}
}

void drawSignalSelector(FlowGraph* fg) {
m_querySignalFilters.drawFilters();

Expand Down Expand Up @@ -415,6 +394,12 @@ class SignalSelector {
IMW::Child signals("Signals", ImVec2(0, 0), 0, 0);

if (auto table = DigitizerUi::IMW::Table("Signals", 7, static_cast<ImGuiTableFlags>(ImGuiTableFlags_BordersInnerV), ImVec2(0.0f, 0.0f), 0.0f)) {
// allow multi-selection
static ImGuiSelectionBasicStorage selection;
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_ClearOnClickVoid;
auto* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, m_filteredItems.size());
selection.ApplyRequests(ms_io);

ImGui::TableHeader("SignalsHeader");
ImGui::TableSetupColumn("Device");
ImGui::TableSetupColumn("Name");
Expand All @@ -424,9 +409,54 @@ class SignalSelector {
ImGui::TableSetupColumn("Comment");
ImGui::TableSetupColumn("Add Signal");
ImGui::TableHeadersRow();
{
std::for_each(m_filteredItems.begin(), m_filteredItems.end(), [this, fg, idx = 0](const auto& e) mutable { drawElement(*e, idx++, fg); });

// clip list for better performance
ImGuiListClipper clipper;
clipper.Begin(m_filteredItems.size());
if (ms_io->RangeSrcItem != -1) {
clipper.IncludeItemByIndex(static_cast<int>(ms_io->RangeSrcItem)); // do not clip RangeSrcItem
}

while (clipper.Step()) {
for (auto n = clipper.DisplayStart; n < clipper.DisplayEnd; ++n) {
const auto entry = *m_filteredItems[n];
ImGui::TableNextRow();
ImGui::TableNextColumn();
const bool itemSelected = selection.Contains(static_cast<ImGuiID>(n));
ImGui::SetNextItemSelectionUserData(n);
ImGui::Selectable(entry.device.c_str(), itemSelected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap);
ImGui::TableNextColumn();
ImGui::TextUnformatted(entry.signalName.c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(entry.quantity.c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(entry.unit.c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(entry.frontend.c_str());
ImGui::TableNextColumn();
ImGui::Text(entry.comment.c_str());
ImGui::TableNextColumn();
if (ImGui::Button(("+##" + std::to_string(n)).c_str())) {
std::vector<SignalData> entries = {entry};
if (selection.Size) {
entries.clear();
void* it = nullptr;
ImGuiID id = 0;
while (selection.GetNextSelectedItem(&it, &id)) {
entries.push_back(*m_filteredItems[id]);
}
}

for (const auto& e : entries) {
const auto uri = opencmw::URI<>::UriFactory().scheme(e.protocol).hostName(e.hostname).port(static_cast<uint16_t>(e.port)).path(e.serviceName).addQueryParameter("channelNameFilter", e.signalName).build();
fg->addRemoteSource(uri.str());
}
}
}
}

ms_io = ImGui::EndMultiSelect();
selection.ApplyRequests(ms_io);
}

if (ImGui::Button("Refresh")) {
Expand Down

0 comments on commit d67c1e2

Please sign in to comment.