106 lines
3.9 KiB
C++
106 lines
3.9 KiB
C++
/**
|
|
* @file SourcePanel.cpp
|
|
* @brief Source browser sidebar implementation.
|
|
*/
|
|
|
|
#include "SourcePanel.h"
|
|
#include "App.h"
|
|
#include "Protocol.h"
|
|
|
|
#include "imgui.h"
|
|
#include "implot.h"
|
|
#include "Icons.h"
|
|
|
|
#include <cstdio>
|
|
#include <algorithm>
|
|
|
|
namespace StreamHubClient {
|
|
|
|
void RenderSourcePanel(App& app) {
|
|
auto& sources = app.sources();
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4.f, 2.f));
|
|
|
|
if (ImGui::CollapsingHeader("Sources", ImGuiTreeNodeFlags_DefaultOpen)) {
|
|
for (int srcIdx = 0; srcIdx < static_cast<int>(sources.size()); srcIdx++) {
|
|
Source& src = sources[srcIdx];
|
|
|
|
/* State color indicator */
|
|
ImVec4 stateColor = (src.state == "connected")
|
|
? ImVec4(0.1f, 0.9f, 0.3f, 1.f)
|
|
: ImVec4(0.8f, 0.3f, 0.3f, 1.f);
|
|
|
|
ImGui::PushID(srcIdx);
|
|
ImGui::TextColored(stateColor, ICON_FA_CIRCLE);
|
|
ImGui::SameLine();
|
|
|
|
std::string treeLabel = src.label.empty() ? src.id : src.label;
|
|
bool nodeOpen = ImGui::TreeNodeEx(treeLabel.c_str(),
|
|
ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanAvailWidth);
|
|
|
|
/* Per-source context menu: remove */
|
|
if (ImGui::BeginPopupContextItem("##srccmenu")) {
|
|
if (ImGui::MenuItem(ICON_FA_TRASH_CAN " Remove source")) {
|
|
app.ws().sendText(BuildRemoveSource(src.id));
|
|
}
|
|
ImGui::EndPopup();
|
|
}
|
|
|
|
if (nodeOpen) {
|
|
for (int sigIdx = 0; sigIdx < static_cast<int>(src.signals.size()); sigIdx++) {
|
|
Signal& sig = src.signals[sigIdx];
|
|
ImGui::PushID(sigIdx);
|
|
|
|
/* Color swatch */
|
|
ImVec4 col = sig.color;
|
|
if (ImGui::ColorButton("##col", col,
|
|
ImGuiColorEditFlags_NoTooltip |
|
|
ImGuiColorEditFlags_NoBorder,
|
|
ImVec2(12.f, 12.f))) {
|
|
ImGui::OpenPopup("##sigcolor");
|
|
}
|
|
if (ImGui::BeginPopup("##sigcolor")) {
|
|
ImGui::ColorPicker4("Signal Color", reinterpret_cast<float*>(&sig.color),
|
|
ImGuiColorEditFlags_NoAlpha);
|
|
ImGui::EndPopup();
|
|
}
|
|
ImGui::SameLine();
|
|
|
|
/* Unit / type label */
|
|
char label[128];
|
|
if (sig.meta.numElements > 1) {
|
|
snprintf(label, sizeof(label), "%s [%u]",
|
|
sig.meta.name.c_str(), sig.meta.numElements);
|
|
} else {
|
|
snprintf(label, sizeof(label), "%s", sig.meta.name.c_str());
|
|
}
|
|
if (!sig.meta.unit.empty()) {
|
|
strncat(label, " (", sizeof(label) - strlen(label) - 1);
|
|
strncat(label, sig.meta.unit.c_str(), sizeof(label) - strlen(label) - 1);
|
|
strncat(label, ")", sizeof(label) - strlen(label) - 1);
|
|
}
|
|
|
|
ImGui::Selectable(label, false, 0, ImVec2(0, 0));
|
|
|
|
/* Drag-and-drop source: payload = (srcIdx, sigIdx) */
|
|
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) {
|
|
struct DragPayload { int srcIdx; int sigIdx; };
|
|
DragPayload payload{srcIdx, sigIdx};
|
|
ImGui::SetDragDropPayload("SIGNAL_REF", &payload, sizeof(payload));
|
|
ImGui::TextUnformatted(sig.meta.name.c_str());
|
|
ImGui::EndDragDropSource();
|
|
}
|
|
|
|
ImGui::PopID();
|
|
}
|
|
ImGui::TreePop();
|
|
}
|
|
ImGui::PopID();
|
|
}
|
|
}
|
|
|
|
ImGui::PopStyleVar();
|
|
}
|
|
|
|
} /* namespace StreamHubClient */
|