From f113e6a784df90cd39ef0914e82143c426df42ef Mon Sep 17 00:00:00 2001 From: Jean-Pierre Martineau Date: Sun, 19 Jul 2026 21:46:51 -0400 Subject: [PATCH] Atlas graph: light the whole route to the selected link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Selecting a link only brightened that one hop's edge; the path that reaches it read no differently from the rest of the fan. Draw the route to the selection — its own edge plus the approach the walk took into the focus (came_from → focus) — at top priority and full strength, shedding the evidence-age fade the other edges keep, so it reads as one lit thread running west through the focus to the selected neighbour east. The age stays legible in the row's age column. Co-Authored-By: Claude Opus 4.8 --- meshterm/ui/atlas_screen.py | 33 +++++++++++++++++--------- tests/test_atlas.py | 47 +++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 11 deletions(-) diff --git a/meshterm/ui/atlas_screen.py b/meshterm/ui/atlas_screen.py index 3781c40..3c85954 100644 --- a/meshterm/ui/atlas_screen.py +++ b/meshterm/ui/atlas_screen.py @@ -536,7 +536,9 @@ class AtlasScreen(Screen): :meth:`_fan_capacity`); the weaker rest collapse into one ``…`` marker at the fan's foot. Highlighting a collapsed row from the list lights that marker white and swaps its label for the highlighted node's name, so the - selection is always somewhere on the picture. + selection is always somewhere on the picture. The edges tracing the *route to + the selected link* — that link plus the approach the walk took into the focus — + draw brightest and undimmed, lighting the whole path that reaches it. """ canvas = MapCanvas(width, canvas_h) fx, fy = self._focus_pos(width, canvas_h) @@ -552,26 +554,35 @@ class AtlasScreen(Screen): shown, hidden = fan, [] placed = self._place_neighbours(width, canvas_h, shown, back, bool(hidden)) - # Edges first (markers and labels overprint them), coloured by SNR and faded - # by evidence age; the highlighted neighbour's edge wins its cells. The - # collapsed marker's edge is slate — unless the selection hides in it, when - # it takes the selected link's colour instead. + # Edges first (markers and labels overprint them), coloured by SNR and faded by + # evidence age. The *route to the selected link* draws brightest and on top: the + # selected neighbour's own edge, plus the approach the walk took into the focus + # (came_from → focus) — so selecting a link lights the whole path that reaches it, + # west through the focus to east, not just the one hop. Route edges shed the age + # fade (drawn full-strength) so they read as one lit thread over the dimmer rest; + # the age is still legible in the row's age column. The collapsed marker's edge is + # slate — unless the selection hides in it, when it joins the route. now = utcnow() + route = {selected} if selected is not None else set() + if selected is not None and back is not None and back != selected: + route.add(back) # the last walked step, drawn as part of the lit route for other, (x, y) in placed.items(): if other == _MORE: if selected in hidden: link = by_other[selected] - color = _scaled( - _snr_rgb(link.median_snr), _freshness(link.last_seen, now) - ) - priority = 3 + color = _scaled(_snr_rgb(link.median_snr), 1.0) + priority = 4 else: color = _scaled(_NO_READING, 0.6) priority = 1 else: link = by_other[other] - color = _scaled(_snr_rgb(link.median_snr), _freshness(link.last_seen, now)) - priority = 3 if other == selected else 2 + if other in route: + color = _scaled(_snr_rgb(link.median_snr), 1.0) + priority = 4 + else: + color = _scaled(_snr_rgb(link.median_snr), _freshness(link.last_seen, now)) + priority = 2 canvas.draw_line([(fx, fy), (x, y)], color, priority) # The focus marker, its label to the LEFT — the walker reads left-to-right, diff --git a/tests/test_atlas.py b/tests/test_atlas.py index 34d81d5..f2198af 100644 --- a/tests/test_atlas.py +++ b/tests/test_atlas.py @@ -145,6 +145,53 @@ def test_atlas_graph_labels_names_in_full_when_the_canvas_has_room() -> None: assert "Repeater-Downtown-01" in canvas # 20 chars, whole +def test_atlas_selected_link_lights_the_route_that_reaches_it() -> None: + """Selecting a link draws its edge *and* the approach into the focus at full strength. + + With every link stale (so an un-highlighted edge fades to half), the selected + neighbour's edge and the came_from → focus approach are drawn undimmed — the lit + route — while an unselected neighbour's edge stays faded. + """ + from meshterm.ui.atlas_screen import _snr_rgb + + stale = utcnow() - timedelta(days=10) # older than a week → _freshness 0.5 + yul = Contact(name="YUL", public_key="3d" * 32, node_type=2) + alice = Contact(name="Alice", public_key="b2" * 32) + bob = Contact(name="Bob", public_key="c4" * 32) + topo = MeshTopology(US, contacts=[yul, alice, bob]) + y = topo.canonical(yul.public_key) + topo.add_walk([topo.self_id, y], snrs=[10.0], when=stale, source="trace") # approach: green + topo.add_walk([y, topo.canonical(alice.public_key)], snrs=[0.0], when=stale, source="trace") # amber + topo.add_walk([y, topo.canonical(bob.public_key)], snrs=[-15.0], when=stale, source="trace") # red + screen = AtlasScreen( + session=_FakeSession(), + topo=topo, + contacts={topo.canonical(c.public_key): c for c in (yul, alice, bob)}, + self_label="Homestead", + ) + screen.note_viewport(24) + screen.render_body(80) + screen.handle("enter") # walk to YUL — now came_from is us, the approach edge + # Land the selection on Alice (a fan neighbour, not the ⌫-back row). + while screen._rows()[screen._index] != topo.canonical(alice.public_key): + screen.handle("down") + + ansi_lines = screen.render_body(80) + legend = next(i for i, l in enumerate(ansi_lines) if "edge = SNR" in _plain([l])) + canvas = "".join(ansi_lines[:legend]) + + def code(rgb: tuple[int, int, int]) -> str: + return f"38;2;{rgb[0]};{rgb[1]};{rgb[2]}m" + + def scaled(rgb: tuple[int, int, int], f: float) -> tuple[int, int, int]: + return tuple(max(0, min(255, round(c * f))) for c in rgb) + + assert code(_snr_rgb(10.0)) in canvas # approach edge, full-strength green + assert code(_snr_rgb(0.0)) in canvas # Alice's edge, full-strength amber + assert code(scaled(_snr_rgb(-15.0), 0.5)) in canvas # Bob's edge stays faded… + assert code(_snr_rgb(-15.0)) not in canvas # …and never reaches full strength + + def test_atlas_empty_graph_renders_guidance() -> None: """With no evidence at all the screen explains how the atlas fills up.""" topo = MeshTopology(US, contacts=[])