// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2026 Martino Ferrari #include "source/registry.hpp" #include "ui_app.hpp" #include #include namespace udpscope { namespace ui_impl { void build_source_panels(App& app) { if (app.side_stack == nullptr || app.acq == nullptr || app.acq->source() == nullptr) return; SourceKind* kind = find_kind(app.source_kind); if (kind == nullptr) return; for (const SourcePanel& p : kind->make_panels(*app.acq->source())) { if (p.widget == nullptr || p.id.empty()) { std::fprintf(stderr, "[source] a '%s' panel was skipped: it has %s\n", app.source_kind.c_str(), p.widget == nullptr ? "no widget" : "an empty id"); continue; } // Each page scrolls on its own, like Measure and Signals: panels differ in height. GtkWidget* scroller = gtk_scrolled_window_new(); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroller), p.widget); const std::string name = "source-" + p.id; // The tab is its title: the sidebar's pills are words, not glyphs. adw_view_stack_add_titled(ADW_VIEW_STACK(app.side_stack), scroller, name.c_str(), p.title.c_str()); app.source_panels.push_back({name, p.title, p.widget}); } // Disconnected until the first Connected event says otherwise. apply_source_panels(app, false); } void apply_source_panels(App& app, bool connected) { for (const SourcePanelPage& p : app.source_panels) { if (gtk_widget_get_sensitive(p.content) != (connected ? TRUE : FALSE)) { gtk_widget_set_sensitive(p.content, connected); } } } void sync_source_panels(App& app) { if (app.source_panels.empty() || app.model == nullptr) return; apply_source_panels(app, app.model->stats().connected.load(std::memory_order_relaxed)); } } // namespace ui_impl } // namespace udpscope