fix: the zoom probe calls math_zoom_at() directly, so it measures what it gave

The old assertion called math_canvas_scrolled(nullptr, ...) which resolves the
anchor itself from the event controller — with no controller it fell back to the
canvas centre (or a hardcoded 420x300 size when the widget was not yet allocated).
The probe then measured whether the graph point under (180, 140) was kept. Those
are two different points, so the difference printed was noise.

Extract math_zoom_at(d, px, py, dy) from the handler body: it takes an explicit
canvas anchor and guarantees the graph point under it is still under it after the
zoom. math_canvas_scrolled() resolves the anchor (from the event, or the widget's
own centre with no magic fallback dimensions) and delegates to it. The probe calls
math_zoom_at() with its chosen anchor directly, so dx and dy are an assertion on
the code rather than on the difference between two unrelated points.

Broken-anchor reading: dx=-180.0000 dy=0.0000. Fixed reading: dx=0.0000 dy=0.0000.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Martino FerrariandClaude Opus 4.6 committed 2026-10-06 23:52:22 +02:00
1 parent b8d178eec6
commit 9f589d5525
1 file changed
+24 -19
+24 -19
View File
@@ -3419,6 +3419,20 @@ double math_set_scale(MathDialog* d, double want) {
return d->view_scale; return d->view_scale;
} }
/// Zooms about a canvas position: one step in for `dy < 0`, one out otherwise. The graph point
/// under `(px, py)` is still under it afterwards -- which is what makes the canvas follow the
/// hand rather than slide away from it.
void math_zoom_at(MathDialog* d, double px, double py, double dy) {
double gx = 0.0;
double gy = 0.0;
math_to_graph(d, px, py, gx, gy);
const double s = math_set_scale(d, d->view_scale * (dy < 0.0 ? kMathZoomStep
: 1.0 / kMathZoomStep));
d->view_x = px - gx * s;
d->view_y = py - gy * s;
gtk_widget_queue_draw(d->canvas);
}
void math_view_reset(MathDialog* d) { void math_view_reset(MathDialog* d) {
math_set_scale(d, 1.0); math_set_scale(d, 1.0);
d->view_x = 0.0; d->view_x = 0.0;
@@ -3625,9 +3639,9 @@ void math_canvas_drag(GtkGestureDrag*, double dx, double dy, gpointer user) {
gboolean math_canvas_scrolled(GtkEventControllerScroll* scroll, double, double dy, gpointer user) { gboolean math_canvas_scrolled(GtkEventControllerScroll* scroll, double, double dy, gpointer user) {
MathDialog* d = static_cast<MathDialog*>(user); MathDialog* d = static_cast<MathDialog*>(user);
if (dy == 0.0) return TRUE; if (dy == 0.0) return TRUE;
// About the pointer: the graph point under it must still be under it afterwards, or the canvas // Resolve the anchor: the pointer position from the current event, or the canvas centre as a
// slides away from the hand. With no controller (the headless probe calls this directly) there // fallback (a real scroll event always arrives on an allocated widget, so the fallback is only
// is no pointer to read, so the canvas centre is the anchor. // reached in degenerate cases).
double px = 0.0; double px = 0.0;
double py = 0.0; double py = 0.0;
bool have = false; bool have = false;
@@ -3636,21 +3650,12 @@ gboolean math_canvas_scrolled(GtkEventControllerScroll* scroll, double, double d
if (event != nullptr) have = gdk_event_get_position(event, &px, &py); if (event != nullptr) have = gdk_event_get_position(event, &px, &py);
} }
if (!have) { if (!have) {
double w = d->canvas != nullptr ? gtk_widget_get_width(d->canvas) : 0; const double w = d->canvas != nullptr ? static_cast<double>(gtk_widget_get_width(d->canvas)) : 0.0;
double h = d->canvas != nullptr ? gtk_widget_get_height(d->canvas) : 0; const double h = d->canvas != nullptr ? static_cast<double>(gtk_widget_get_height(d->canvas)) : 0.0;
if (w <= 0.0) w = 420.0; px = w > 0.0 ? w * 0.5 : 0.0;
if (h <= 0.0) h = 300.0; py = h > 0.0 ? h * 0.5 : 0.0;
px = w * 0.5;
py = h * 0.5;
} }
double gx = 0.0; math_zoom_at(d, px, py, dy);
double gy = 0.0;
math_to_graph(d, px, py, gx, gy);
const double s = math_set_scale(d, d->view_scale * (dy < 0.0 ? kMathZoomStep
: 1.0 / kMathZoomStep));
d->view_x = px - gx * s;
d->view_y = py - gy * s;
gtk_widget_queue_draw(d->canvas);
return TRUE; return TRUE;
} }
@@ -6974,8 +6979,8 @@ gboolean math_probe(gpointer user) {
double gx0 = 0.0; double gx0 = 0.0;
double gy0 = 0.0; double gy0 = 0.0;
math_to_graph(v, px, py, gx0, gy0); math_to_graph(v, px, py, gx0, gy0);
math_canvas_scrolled(nullptr, 0.0, -1.0, v); math_zoom_at(v, px, py, -1.0);
math_canvas_scrolled(nullptr, 0.0, -1.0, v); math_zoom_at(v, px, py, -1.0);
double gx1 = 0.0; double gx1 = 0.0;
double gy1 = 0.0; double gy1 = 0.0;
math_to_graph(v, px, py, gx1, gy1); math_to_graph(v, px, py, gx1, gy1);