signals: label plots by row and cell, drop onto a cell
This commit is contained in:
1 parent
645cb6f4fa
commit
9f3e3597af
4 files changed
+83
-7
No files matched your search
+3
-3
@@ -2908,11 +2908,11 @@ void on_remove_clicked(GtkButton* button, gpointer user) {
|
||||
++removed;
|
||||
}
|
||||
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 {
|
||||
const std::string name = r.name[static_cast<std::size_t>(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;
|
||||
@@ -2990,7 +2990,7 @@ void row_menu_fill(RowMenuState& st) {
|
||||
|
||||
if (st.view == RowMenuView::Main) {
|
||||
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_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);
|
||||
|
||||
@@ -4259,8 +4259,73 @@ gboolean split_probe_step(gpointer user) {
|
||||
cell_plus_sensitive, row_plus_sensitive, rs.row_count());
|
||||
// Close editor.
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(a->layout_toggle), false);
|
||||
split_probe_next(*a);
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
||||
+13
-2
@@ -265,7 +265,9 @@ void fill(App& app, const std::string& name, GtkWidget* page) {
|
||||
GtkWidget* rows_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
|
||||
gtk_widget_set_name(rows_box, "udpscope-plot-on"); // the probe counts its buttons
|
||||
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);
|
||||
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.
|
||||
@@ -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;
|
||||
}
|
||||
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) {
|
||||
outlive_the_rebuild(GTK_WIDGET(b));
|
||||
assign_signal_to_row(*static_cast<App*>(user), tagged(b),
|
||||
|
||||
+2
-2
@@ -554,7 +554,7 @@ bool assign_signal_to_row(App& app, std::size_t signal, int row) {
|
||||
if (slot < 0) {
|
||||
// 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.
|
||||
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 "
|
||||
"editor (L)");
|
||||
return false;
|
||||
@@ -567,7 +567,7 @@ bool assign_signal_to_row(App& app, std::size_t signal, int row) {
|
||||
schedule_layout_save(app);
|
||||
app.relayout_pending = true;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user