Feature/source plugins #1

Merged
martino merged 130 commits from feature/source-plugins into main 2026-11-04 07:35:21 +01:00
4 changed files with 83 additions and 7 deletions
Showing only changes of commit 9f3e3597af - Show all commits

No files matched your search

+3 -3
View File
@@ -2908,11 +2908,11 @@ void on_remove_clicked(GtkButton* button, gpointer user) {
++removed; ++removed;
} }
what = "removed " + std::to_string(removed) + (removed == 1 ? " trace" : " traces") + what = "removed " + std::to_string(removed) + (removed == 1 ? " trace" : " traces") +
" from plot " + std::to_string(target->row + 1); " from plot " + app.rows->plot_label(target->row);
} else { } else {
const std::string name = r.name[static_cast<std::size_t>(target->slot)]; const std::string name = r.name[static_cast<std::size_t>(target->slot)];
remove_trace(app, target->row, target->slot); remove_trace(app, target->row, target->slot);
what = "removed '" + name + "' from plot " + std::to_string(target->row + 1); what = "removed '" + name + "' from plot " + app.rows->plot_label(target->row);
} }
app.relayout_pending = true; app.relayout_pending = true;
@@ -2990,7 +2990,7 @@ void row_menu_fill(RowMenuState& st) {
if (st.view == RowMenuView::Main) { if (st.view == RowMenuView::Main) {
char markup[64]; char markup[64];
std::snprintf(markup, sizeof(markup), "<b>Plot %d</b>", row + 1); std::snprintf(markup, sizeof(markup), "<b>Plot %s</b>", app.rows->plot_label(row).c_str());
add_heading(markup); add_heading(markup);
add_row("Y axis: auto scale", nullptr, G_CALLBACK(on_y_auto_clicked), &app); add_row("Y axis: auto scale", nullptr, G_CALLBACK(on_y_auto_clicked), &app);
add_row("Y axis: fixed range...", nullptr, G_CALLBACK(on_y_fixed_clicked), &app); add_row("Y axis: fixed range...", nullptr, G_CALLBACK(on_y_fixed_clicked), &app);
+65
View File
@@ -4259,8 +4259,73 @@ gboolean split_probe_step(gpointer user) {
cell_plus_sensitive, row_plus_sensitive, rs.row_count()); cell_plus_sensitive, row_plus_sensitive, rs.row_count());
// Close editor. // Close editor.
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(a->layout_toggle), false); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(a->layout_toggle), false);
split_probe_next(*a);
break; break;
} }
// --- Steps 16..17: signals page and drop onto a cell (task 6) ---
case 16: {
// Two split rows (plots 0,1 on row 1; plots 2,3 on row 2), all empty; the next step reads a frame
// that was laid out with them.
rs.set_cells_per_row({2, 2});
split_probe_clear_all(*a);
split_probe_restructured(*a);
split_probe_next(*a);
break;
}
case 17: {
split_probe_report(*a, "two-split-rows");
// Which plot the pointer resolves to at the centre of every cell, through the app's own wrapper
// (`row_at(app, x, y)`), in the area's logical coordinates: the cell rects are device pixels.
const plot::FigureLayout& fl = rs.figure().layout();
const double scale = (a->area != nullptr && a->area->device_scale() > 0.0f)
? static_cast<double>(a->area->device_scale()) : 1.0;
std::string rowat;
int rowat_ok = fl.cells.size() == static_cast<std::size_t>(rs.row_count()) ? 1 : 0;
for (std::size_t i = 0; i < fl.cells.size() && rowat_ok; ++i) {
const plot::Rect& c = fl.cells[i];
const int got = row_at(*a, (static_cast<double>(c.x) + c.w * 0.5) / scale,
(static_cast<double>(c.y) + c.h * 0.5) / scale);
rowat += (i == 0 ? "" : ",") + rs.plot_label(static_cast<int>(i)) + "=" + std::to_string(got);
if (got != static_cast<int>(i)) rowat_ok = 0;
}
std::fprintf(stderr, "[split-probe] drop-rowat ok=%d rowat=[%s] (label=plot index at each cell's centre)\n",
rowat_ok, rowat.c_str());
// The signals page's "Plot on" buttons for signal 1: label and tooltip of each, read off the widgets.
const std::string sig0 = a->model->signals()[1].name;
signal_page_ensure(*a, sig0);
signal_pages_sync(*a);
std::string buttons;
const auto page_it = a->signal_pages.find(sig0);
GtkWidget* box = page_it == a->signal_pages.end() ? nullptr
: find_named(page_it->second, "udpscope-plot-on");
for (GtkWidget* b = box != nullptr ? gtk_widget_get_first_child(box) : nullptr; b != nullptr;
b = gtk_widget_get_next_sibling(b)) {
const char* tip = gtk_widget_get_tooltip_text(b);
buttons += std::string(buttons.empty() ? "" : "|") + gtk_button_get_label(GTK_BUTTON(b)) + ":" +
(tip != nullptr ? tip : "-");
}
std::fprintf(stderr, "[split-probe] plot-on-buttons [%s]\n", buttons.c_str());
// The "Plot on 1b" path: the button's own function, onto plot 1 (the right cell of row 1).
const bool assigned = assign_signal_to_row(*a, 1, 1);
std::fprintf(stderr, "[split-probe] assign-1b assigned=%d notice='%s'\n", assigned ? 1 : 0,
a->notice.c_str());
// And the drop handler itself, at the centre of cell 3 ("2b"), with signal 2's index as the payload.
GValue payload = G_VALUE_INIT;
g_value_init(&payload, G_TYPE_STRING);
g_value_set_string(&payload, "2");
const plot::Rect& c3 = fl.cells[3];
const gboolean dropped = on_drop_channel(nullptr, &payload, (static_cast<double>(c3.x) + c3.w * 0.5) / scale,
(static_cast<double>(c3.y) + c3.h * 0.5) / scale, a);
g_value_unset(&payload);
std::fprintf(stderr, "[split-probe] drop-2b dropped=%d notice='%s'\n", dropped ? 1 : 0,
a->notice.c_str());
split_probe_restructured(*a);
split_probe_next(*a);
break;
}
case 18:
split_probe_report(*a, "after-assign");
break;
default: default:
break; break;
} }
+13 -2
View File
@@ -265,7 +265,9 @@ void fill(App& app, const std::string& name, GtkWidget* page) {
GtkWidget* rows_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); GtkWidget* rows_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
gtk_widget_set_name(rows_box, "udpscope-plot-on"); // the probe counts its buttons gtk_widget_set_name(rows_box, "udpscope-plot-on"); // the probe counts its buttons
for (int r = 0; r < app.rows->row_count(); ++r) { for (int r = 0; r < app.rows->row_count(); ++r) {
GtkWidget* b = text_button(std::to_string(r + 1).c_str(), rows_box); // The plot's label is its row's number, then a letter when the row is split ("2", "2a"); the tooltip
// of a split row's cell says the same thing in words.
GtkWidget* b = text_button(app.rows->plot_label(r).c_str(), rows_box);
tag(b, index); tag(b, index);
g_object_set_data(G_OBJECT(b), "udpscope-row", GINT_TO_POINTER(r)); g_object_set_data(G_OBJECT(b), "udpscope-row", GINT_TO_POINTER(r));
// A button for a plot the signal is already on would add it to a second slot there. // A button for a plot the signal is already on would add it to a second slot there.
@@ -274,7 +276,16 @@ void fill(App& app, const std::string& name, GtkWidget* page) {
if (app.rows->row(r).signal_name[static_cast<std::size_t>(slot)] == sig.name) on_this_row = true; if (app.rows->row(r).signal_name[static_cast<std::size_t>(slot)] == sig.name) on_this_row = true;
} }
gtk_widget_set_sensitive(b, !on_this_row); gtk_widget_set_sensitive(b, !on_this_row);
gtk_widget_set_tooltip_text(b, on_this_row ? "already on this plot" : "draw this signal on this plot"); const int figure_row = app.rows->figure_row_of(r);
const int in_row = figure_row >= 0 ? app.rows->cells_in_row(figure_row) : 1;
if (in_row > 1) {
char where[64];
std::snprintf(where, sizeof(where), "row %d, cell %d of %d", figure_row + 1,
app.rows->cell_of(r) + 1, in_row);
gtk_widget_set_tooltip_text(b, on_this_row ? "already on this plot" : where);
} else {
gtk_widget_set_tooltip_text(b, on_this_row ? "already on this plot" : "draw this signal on this plot");
}
g_signal_connect(b, "clicked", G_CALLBACK(+[](GtkButton* b, gpointer user) { g_signal_connect(b, "clicked", G_CALLBACK(+[](GtkButton* b, gpointer user) {
outlive_the_rebuild(GTK_WIDGET(b)); outlive_the_rebuild(GTK_WIDGET(b));
assign_signal_to_row(*static_cast<App*>(user), tagged(b), assign_signal_to_row(*static_cast<App*>(user), tagged(b),
+2 -2
View File
@@ -554,7 +554,7 @@ bool assign_signal_to_row(App& app, std::size_t signal, int row) {
if (slot < 0) { if (slot < 0) {
// Say what to do about it. A refusal a reader cannot act on is only half an answer: the two ways // Say what to do about it. A refusal a reader cannot act on is only half an answer: the two ways
// out are another plot or another row. // out are another plot or another row.
notice("plot " + std::to_string(row + 1) + notice("plot " + app.rows->plot_label(row) +
" holds four signals already: drop it on another plot, or add a row with the layout " " holds four signals already: drop it on another plot, or add a row with the layout "
"editor (L)"); "editor (L)");
return false; return false;
@@ -567,7 +567,7 @@ bool assign_signal_to_row(App& app, std::size_t signal, int row) {
schedule_layout_save(app); schedule_layout_save(app);
app.relayout_pending = true; app.relayout_pending = true;
rebuild_signal_panels(app); // the row's colour chip now has a trace to name rebuild_signal_panels(app); // the row's colour chip now has a trace to name
notice("plotting '" + name + "' on plot " + std::to_string(row + 1)); notice("plotting '" + name + "' on plot " + app.rows->plot_label(row));
return true; return true;
} }