// Banner / restart hit-test golden (P7.2): lock the win/lose banner geometry and // the restart-button hit-test that `BoardView.handle_event` relies on. The button // rect is derived from the SAME grid layout the gems use, and a finished level // freezes every board-cell tap, so the button is the only live target — if its // rect drifted from what `render_banner` draws, a tap on the visible button would // miss and the level could never be restarted. This test checks, headlessly: // // * the button is centered over the grid and sits fully inside the panel, // * the button centre hit-tests INTO the button (tap → restart), // * an off-button tap (a board corner) hit-tests OUT (frozen, no restart). // // Imports BoardLayout (no GL/stb), not BoardView, so it links headless — same // shape and rationale as tests/hit_test.sx. Failure is signalled via a non-zero // exit code (the runner checks exit code AND stdout). #import "modules/std.sx"; #import "modules/ui/types.sx"; #import "board.sx"; #import "board_layout.sx"; irect :: (f: Frame) -> string { format("({},{},{},{})", cast(s64) f.origin.x, cast(s64) f.origin.y, cast(s64) f.size.width, cast(s64) f.size.height) } main :: () -> s32 { // 800×600, no safe inset → 600px square grid, cell 75, origin (100,0): the // same layout tests/hit_test.sx pins, so the numbers are checkable by hand. lay : BoardLayout = ---; lay.compute(Frame.make(0.0, 0.0, 800.0, 600.0), EdgeInsets.zero()); grid := lay.grid_frame(); bl := lay.banner(); print("grid {}\n", irect(grid)); print("panel {}\n", irect(bl.panel)); print("title {}\n", irect(bl.title)); print("button {}\n", irect(bl.button)); fails : s64 = 0; // The button is horizontally centered on the grid (centred banner). bcx := bl.button.mid_x(); if cast(s64) bcx != cast(s64) grid.mid_x() { fails += 1; } print("button mid_x {} grid mid_x {}\n", cast(s64) bcx, cast(s64) grid.mid_x()); // The whole button sits inside the panel — its four corners are contained, // so it can never spill outside the drawn card. bx0 := bl.button.origin.x; by0 := bl.button.origin.y; bx1 := bl.button.max_x(); by1 := bl.button.max_y(); corners_in : s64 = 0; if bl.panel.contains(Point.{ x = bx0, y = by0 }) { corners_in += 1; } if bl.panel.contains(Point.{ x = bx1, y = by0 }) { corners_in += 1; } if bl.panel.contains(Point.{ x = bx0, y = by1 }) { corners_in += 1; } if bl.panel.contains(Point.{ x = bx1, y = by1 }) { corners_in += 1; } if corners_in != 4 { fails += 1; } print("button corners inside panel: {}/4\n", corners_in); // A tap on the button centre restarts (hit-test true); the panel itself is // also contained, so the centre is unambiguously on the button. center := Point.{ x = bl.button.mid_x(), y = bl.button.mid_y() }; hit_center := bl.button.contains(center); if !hit_center { fails += 1; } print("button center hit: {}\n", hit_center); // Off-button taps that a finished level must NOT treat as restart: the grid's // top-left corner cell centre, and a point just outside the panel. Neither is // in the button, so each leaves the level frozen. corner_cell := Point.{ x = grid.origin.x + lay.cell_size * 0.5, y = grid.origin.y + lay.cell_size * 0.5 }; outside := Point.{ x = bl.panel.origin.x - 5.0, y = bl.panel.mid_y() }; off_hits : s64 = 0; if bl.button.contains(corner_cell) { off_hits += 1; } if bl.button.contains(outside) { off_hits += 1; } if off_hits != 0 { fails += 1; } print("off-button taps that hit the button: {}\n", off_hits); if fails == 0 { print("ok: restart button hit-test matches the drawn banner\n"); return 0; } print("FAIL: {} banner hit-test checks failed\n", fails); return 1; }