EchoMap 2026-07-25 6d3977c
An experimental cross-platform digital signal processing application for sound-source localisation.
Loading...
Searching...
No Matches
ChannelMappingPanel.cpp
1//
2// Created by owd on 07/07/2026.
3//
4
5#include "ChannelMappingPanel.hpp"
6
7#include "../EchoMap.hpp"
9#include "../objects/Project.hpp"
10#include "../objects/Sensor.hpp"
11#include "../objects/Signal.hpp"
12
13namespace echomap
14{
15
17 EchoMap* app,
18 const Project* const initial_project
19) :
20 panel_name(std::string("Channel Mapping") + get_imgui_stable_name()),
21 app(app),
22 active_project(initial_project)
23{
24}
25
26const char* ChannelMappingPanel::get_imgui_name() const noexcept
27{
28 return panel_name.c_str();
29}
30
32{
33 if (ImGui::Begin(panel_name.c_str())) {
34 if (active_project == nullptr)
35 ImGui::Text("No project is loaded.");
36 else {
37 ImGui::SeparatorText("Create Channel Mapping");
38 draw_new_channel_mapping();
39
40 // If a new mapping has been fully described, add it and prompt for another.
41 if (new_entry_cache.signal != nullptr && new_entry_cache.sensor != nullptr) {
43 active_project->get_id(),
44 new_entry_cache.signal->get_id(),
45 new_entry_cache.sensor->get_id()
46 ));
47
48 new_entry_cache.signal = nullptr;
49 new_entry_cache.sensor = nullptr;
50 }
51
52 ImGui::SeparatorText("Existing Channel Mapping");
53 draw_existing_channel_mapping();
54 }
55 }
56
57 ImGui::End();
58}
59
61 const Project* const new_project
62)
63{
64 active_project = new_project;
65}
66
67const char* ChannelMappingPanel::get_imgui_stable_name() noexcept
68{
69 return "###ChannelMappingPanel";
70}
71
72void ChannelMappingPanel::draw_new_channel_mapping() noexcept
73{
74 // TODO refactor monster.
75
76 if (ImGui::BeginTable("##NewChannelMapping", 2, table_flags)) {
77 ImGui::TableSetupColumn("Signal", ImGuiTableColumnFlags_WidthStretch);
78 ImGui::TableSetupColumn("Sensor", ImGuiTableColumnFlags_WidthStretch);
79 ImGui::TableHeadersRow();
80 ImGui::TableNextRow();
81 ImGui::TableNextColumn();
82
83 bool need_to_force = false;
84
85 // Prompt for the associated signal.
86 ImGui::SetNextItemWidth(-std::numeric_limits<float>::min());
87 if (ImGui::BeginCombo(
88 "##NewAssociationSignal",
89 new_entry_cache.signal == nullptr ? "Select signal..." : new_entry_cache.signal->get_imgui_name(),
90 0
91 )) {
92 for (const auto& signal : active_project->observe_signals()) {
93 const bool is_selected = new_entry_cache.signal == nullptr ? false : signal == *new_entry_cache.signal;
94
95 // Checks if something has changed (thus current value needs updating).
96 if (ImGui::Selectable(signal.get_imgui_name(), is_selected))
97 new_entry_cache.signal = &signal;
98
99 // Checks if the current item is selected.
100 if (is_selected)
101 ImGui::SetItemDefaultFocus();
102 }
103
104 ImGui::EndCombo();
105 need_to_force = true;
106 }
107
108 ImGui::TableNextColumn();
109
110 // Prompt for the associated sensor.
111 ImGui::SetNextItemWidth(-std::numeric_limits<float>::min());
112 if (ImGui::BeginCombo(
113 "##NewAssociationSensor",
114 new_entry_cache.sensor == nullptr ? "Select sensor..." : new_entry_cache.sensor->get_imgui_name(),
115 0
116 )) {
117 for (const auto& sensor : active_project->observe_sensors()) {
118 const bool is_selected = new_entry_cache.sensor == nullptr ? false : sensor == *new_entry_cache.sensor;
119
120 if (ImGui::Selectable(sensor.get_imgui_name(), is_selected))
121 new_entry_cache.sensor = &sensor;
122
123 if (is_selected)
124 ImGui::SetItemDefaultFocus();
125 }
126
127 ImGui::EndCombo();
128 need_to_force = true;
129 }
130
131 ImGui::EndTable();
132
133 if (need_to_force)
134 app->increment_forced_frames();
135 }
136}
137
138void ChannelMappingPanel::draw_existing_channel_mapping() const noexcept
139{
140 if (ImGui::BeginTable("##ExistingChannelMapping", 2, table_flags)) {
141 ImGui::TableSetupColumn("Signal", ImGuiTableColumnFlags_WidthStretch);
142 ImGui::TableSetupColumn("Sensor", ImGuiTableColumnFlags_WidthStretch);
143 ImGui::TableHeadersRow();
144
145 // Display existing associations.
146 for (const auto& [signal, sensor] : active_project->observe_associations()) {
147 ImGui::TableNextRow();
148 ImGui::TableNextColumn();
149 ImGui::SetNextItemWidth(-std::numeric_limits<float>::min());
150 ImGui::TextUnformatted(signal.get_imgui_name());
151 ImGui::TableNextColumn();
152 ImGui::SetNextItemWidth(-std::numeric_limits<float>::min());
153 ImGui::TextUnformatted(sensor.get_imgui_name());
154 }
155
156 ImGui::EndTable();
157 }
158}
159
160} // namespace echomap
AllNotifications specification.
EchoMap class specification.
Audio signal class specification.
const char * get_imgui_name() const noexcept override
Retrieves the name of the IPanel for Dear ImGui API functions.
void draw() noexcept override
Draw the panel to the active rendering context.
void change_active_project(const Project *new_project) override
Updates the active Project being described by the IPanel.
ChannelMappingPanel(EchoMap *app, const Project *initial_project=nullptr)
Create a new ChannelMappingPanel to describe and configure Signal-Sensor mappings.
The EchoMap maintains state for the application including WebGPU and Dear ImGui context,...
Definition EchoMap.hpp:35
auto observe_signals() const noexcept
Provides a transformed view for stored Signal objects in the Project.
Definition Project.hpp:97
T min(T... args)
The main EchoMap outermost namespace for all non-exported symbols.
STL namespace.
T signal(T... args)
A notification indicating that a new channel mapping should be established.