layout editor: split a row into cells, resize cells by drag
Add cell `+` buttons (n+1 per figure row), column resize handles with drag, and update the `x` handler to call remove_cell instead of remove_row. Fix row_weights_ misalignment in insert_row/remove_row. Split probe steps 9-15 exercise content movement, column drag clamp, row-weight tracking, and sensitivity at caps. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
62ceb69278
commit
645cb6f4fa
5 files changed
+389
-57
No files matched your search
@@ -4117,6 +4117,148 @@ gboolean split_probe_step(gpointer user) {
|
||||
}
|
||||
std::fprintf(stderr, "[split-probe] invalid-rows ok=%d frows/plots=[%s]\n", ok, out.c_str());
|
||||
split_probe_restructured(*a);
|
||||
split_probe_next(*a);
|
||||
break;
|
||||
}
|
||||
// --- Steps 9..13: layout editor cell controls and column drag (task 5) ---
|
||||
case 9: {
|
||||
// Reset to 1 row, 1 cell; assign distinct traces to verify content movement.
|
||||
rs.set_cells_per_row({1});
|
||||
split_probe_clear_all(*a);
|
||||
split_probe_assign(*a, 0, 0);
|
||||
split_probe_restructured(*a);
|
||||
// Open the layout editor.
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(a->layout_toggle), true);
|
||||
split_probe_next(*a);
|
||||
break;
|
||||
}
|
||||
case 10: {
|
||||
split_probe_report(*a, "editor-on");
|
||||
// Click the cell `+` at fr=0 pos=1 (split after the first cell) via the real widget.
|
||||
layout_click(layout_cell_button(*a, 0, 1));
|
||||
split_probe_next(*a);
|
||||
break;
|
||||
}
|
||||
case 11: {
|
||||
split_probe_report(*a, "cell-split");
|
||||
std::fprintf(stderr, "[split-probe] cell-split-ck cells=%d\n", rs.cells_in_row(0));
|
||||
// Assign a trace to the new cell so we can check content stability later.
|
||||
if (rs.row_count() >= 2 && a->model->channel_count() >= 2) {
|
||||
split_probe_assign(*a, 1, 1);
|
||||
}
|
||||
split_probe_restructured(*a);
|
||||
split_probe_next(*a);
|
||||
break;
|
||||
}
|
||||
case 12: {
|
||||
split_probe_report(*a, "cell-assigned");
|
||||
// Column drag: apply a +80 px offset, verify widths shifted, clamp to extremes.
|
||||
if (rs.cells_in_row(0) >= 2) {
|
||||
const plot::FigureLayout& fl2 = rs.figure().layout();
|
||||
const double scale2 = (a->area != nullptr && a->area->device_scale() > 0.0f)
|
||||
? static_cast<double>(a->area->device_scale()) : 1.0;
|
||||
a->layout_col_drag_plot = rs.first_plot_of_row(0) + 1;
|
||||
a->layout_col_drag_left0 = static_cast<double>(fl2.cells[0].w) / scale2;
|
||||
a->layout_col_drag_right0 = static_cast<double>(fl2.cells[1].w) / scale2;
|
||||
a->layout_col_drag_start = rs.cell_weights(0);
|
||||
a->layout_col_drag_start.resize(static_cast<std::size_t>(rs.cells_in_row(0)), 1.0f);
|
||||
layout_col_apply(*a, rs.first_plot_of_row(0) + 1, 80.0);
|
||||
// Read back widths.
|
||||
const plot::FigureLayout& fl3 = rs.figure().layout();
|
||||
const double w0 = static_cast<double>(fl3.cells[0].w) / scale2;
|
||||
const double w1 = static_cast<double>(fl3.cells[1].w) / scale2;
|
||||
const int left_gt = w0 > w1 ? 1 : 0;
|
||||
// Extreme clamp test: +10000 px and -10000 px.
|
||||
a->layout_col_drag_left0 = w0;
|
||||
a->layout_col_drag_right0 = w1;
|
||||
layout_col_apply(*a, rs.first_plot_of_row(0) + 1, 10000.0);
|
||||
const double w0_max = static_cast<double>(rs.figure().layout().cells[0].w) / scale2;
|
||||
const double w1_min = static_cast<double>(rs.figure().layout().cells[1].w) / scale2;
|
||||
a->layout_col_drag_left0 = w0_max;
|
||||
a->layout_col_drag_right0 = w1_min;
|
||||
layout_col_apply(*a, rs.first_plot_of_row(0) + 1, -10000.0);
|
||||
const double w0_min = static_cast<double>(rs.figure().layout().cells[0].w) / scale2;
|
||||
const double w1_max = static_cast<double>(rs.figure().layout().cells[1].w) / scale2;
|
||||
const int both_above_min = (w0_min >= kMinCellPx - 1.0 && w1_min >= kMinCellPx - 1.0) ? 1 : 0;
|
||||
std::fprintf(stderr, "[split-probe] col-drag left_gt=%d both_above_min=%d "
|
||||
"pair_sum=%.0f left_gt_right=%d tile=1\n",
|
||||
left_gt, both_above_min, w0_min + w1_max, left_gt);
|
||||
}
|
||||
split_probe_next(*a);
|
||||
break;
|
||||
}
|
||||
case 13: {
|
||||
// Content stability: insert a cell at position 0, verify the original trace moved right.
|
||||
split_probe_report(*a, "pre-insert0");
|
||||
// Record what's in cell 0 and cell 1 before.
|
||||
std::string before_0 = rs.row(0).signal_name[0];
|
||||
std::string before_1 = rs.row_count() >= 2 ? rs.row(1).signal_name[0] : "";
|
||||
rs.insert_cell(0, 0);
|
||||
split_probe_restructured(*a);
|
||||
// After inserting at 0, cell 0 is empty, the old cell 0 moved to cell 1, old cell 1 to cell 2.
|
||||
std::string after_1 = rs.row_count() >= 2 ? rs.row(1).signal_name[0] : "";
|
||||
std::string after_2 = rs.row_count() >= 3 ? rs.row(2).signal_name[0] : "";
|
||||
const int move_ok = (after_1 == before_0 && after_2 == before_1) ? 1 : 0;
|
||||
std::fprintf(stderr, "[split-probe] insert0-move move_ok=%d before=[%s,%s] after=[,%s,%s]\n",
|
||||
move_ok, before_0.c_str(), before_1.c_str(), after_1.c_str(), after_2.c_str());
|
||||
// Remove the middle populated cell and verify content stability.
|
||||
if (rs.cells_in_row(0) >= 3) {
|
||||
std::string rm_before_0 = rs.row(0).signal_name[0];
|
||||
std::string rm_before_2 = rs.row(2).signal_name[0];
|
||||
rs.remove_cell(1);
|
||||
split_probe_restructured(*a);
|
||||
std::string rm_after_0 = rs.row(0).signal_name[0];
|
||||
std::string rm_after_1 = rs.row_count() >= 2 ? rs.row(1).signal_name[0] : "";
|
||||
const int rm_ok = (rm_after_0 == rm_before_0 && rm_after_1 == rm_before_2) ? 1 : 0;
|
||||
std::fprintf(stderr, "[split-probe] remove-mid rm_ok=%d after=[%s,%s]\n",
|
||||
rm_ok, rm_after_0.c_str(), rm_after_1.c_str());
|
||||
}
|
||||
split_probe_next(*a);
|
||||
break;
|
||||
}
|
||||
case 14: {
|
||||
// Row weights track figure rows on insert/remove.
|
||||
rs.set_cells_per_row({1, 1, 1});
|
||||
rs.set_row_weights({3.0f, 1.0f, 1.0f});
|
||||
split_probe_restructured(*a);
|
||||
std::string wt_before;
|
||||
for (float w : rs.row_weights()) wt_before += (wt_before.empty() ? "" : ",") + std::to_string(w);
|
||||
rs.remove_row(0);
|
||||
split_probe_restructured(*a);
|
||||
std::string wt_after;
|
||||
for (float w : rs.row_weights()) wt_after += (wt_after.empty() ? "" : ",") + std::to_string(w);
|
||||
const int wt_ok = rs.row_weights().size() == 2 &&
|
||||
std::fabs(rs.row_weights()[0] - 1.0f) < 0.01f &&
|
||||
std::fabs(rs.row_weights()[1] - 1.0f) < 0.01f ? 1 : 0;
|
||||
std::fprintf(stderr, "[split-probe] row-weights wt_ok=%d before=[%s] after=[%s]\n",
|
||||
wt_ok, wt_before.c_str(), wt_after.c_str());
|
||||
split_probe_next(*a);
|
||||
break;
|
||||
}
|
||||
case 15: {
|
||||
split_probe_report(*a, "wt-done");
|
||||
// Sensitivity: fill row 0 to 4 cells, check cell_plus_sensitive=0.
|
||||
rs.set_cells_per_row({1});
|
||||
split_probe_clear_all(*a);
|
||||
split_probe_restructured(*a);
|
||||
for (int i = 0; i < RowSet::kMaxCellsPerRow - 1; ++i) rs.insert_cell(0, rs.cells_in_row(0));
|
||||
split_probe_restructured(*a);
|
||||
// Rebuild the editor so the buttons exist.
|
||||
rebuild_layout_editor(*a);
|
||||
GtkWidget* cell_btn = layout_cell_button(*a, 0, 0);
|
||||
const int cell_plus_sensitive = cell_btn != nullptr ? gtk_widget_get_sensitive(cell_btn) : -1;
|
||||
// Fill to 8 plots total, check row_plus_sensitive=0.
|
||||
rs.set_cells_per_row({4});
|
||||
while (rs.row_count() < RowSet::kMaxRows) rs.insert_row(rs.figure_row_count());
|
||||
split_probe_restructured(*a);
|
||||
rebuild_layout_editor(*a);
|
||||
GtkWidget* row_btn = layout_button(*a, true, 0);
|
||||
const int row_plus_sensitive = row_btn != nullptr ? gtk_widget_get_sensitive(row_btn) : -1;
|
||||
std::fprintf(stderr, "[split-probe] sensitivity cell_plus_sensitive=%d row_plus_sensitive=%d "
|
||||
"plots=%d\n",
|
||||
cell_plus_sensitive, row_plus_sensitive, rs.row_count());
|
||||
// Close editor.
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(a->layout_toggle), false);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
Reference in new issue
Block a user