Let the map brightness reach the map, and put the options in groups
The map brightness setting could not make the map visible on a vector theme, which is the one place it was needed. Those themes want the ground well out of the way -- a tinted photograph of a county behind the vectors is the one thing that stops a vector display looking like one -- and that was done by multiplying the setting by about a quarter. A multiplier is a ceiling: turned the whole way up, the setting still gave a map at a tenth the brightness the default theme gives, which is to say invisible, and no amount of turning it up did anything about that. It is a curve now rather than a ceiling. The theme raises the setting to a power, so the middle of the range is still quiet -- seventy per cent lands where the old quarter did, which is the look these themes are for -- and the top of the range is a full-brightness map on every theme there is. On the green phosphor the setting now spans a luminance of six to seventy where it used to stop at twenty-one. And the options are in six groups rather than one list: receiver, listening, aircraft, animation, the map, labels. Thirty-three of them on one screen is a wall rather than a menu. A number opens a group and a number inside it changes an option, with the numbers still being each option's place in the whole list so that the same number means the same option wherever it is typed -- which meant reordering the list so that every group is contiguous, and there is a test that says so. A group menu makes a known option harder to reach than a flat list did, so the name works too: typing "map brightness" at the top goes straight to it, and part of a name lists everything it could mean. A name that matches exactly wins outright, so "speed" reaches the setting called speed rather than that one and every other whose description happens to mention the word. One thing to know: a bare number at the top of the menu now opens a group where it used to edit the option of that number. The tests that drove the menu that way would have gone on silently editing whatever option shared the number, so they ask by name now, and one of them checks that a group number changes nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016PsWPTweCT6pwxKngvVxcg
This commit is contained in:
parent
2da1d1f245
commit
6d2436cde1
10 changed files with 540 additions and 250 deletions
|
|
@ -54,6 +54,17 @@ def number(key: str) -> str:
|
|||
return str(air.OPTIONS.index(air.by_key(key)) + 1)
|
||||
|
||||
|
||||
def reach(key: str) -> str:
|
||||
"""What to type at the top of the aircraft menu to edit one option.
|
||||
|
||||
Its name: the options live in groups now, so a bare number there opens
|
||||
a group. A name that matches one exactly goes straight to it, which is
|
||||
how somebody who knows what they are looking for gets at it without
|
||||
hunting through the groups first.
|
||||
"""
|
||||
return key
|
||||
|
||||
|
||||
def run(monkeypatch, console, answers, cfg):
|
||||
drive(monkeypatch, answers)
|
||||
try:
|
||||
|
|
@ -207,12 +218,12 @@ def test_a_broken_options_file_falls_back_to_the_defaults(settings_dir):
|
|||
def _listen_and_draw(monkeypatch, console, tmp_path, picture="png"):
|
||||
cfg = ScanConfig(output_dir=str(tmp_path))
|
||||
run(monkeypatch, console,
|
||||
[number("simulate"), "yes", # invent a sky
|
||||
number("seconds"), "3", # listen for three seconds
|
||||
number("picture"), picture, # what to draw
|
||||
number("lookup"), "no", # no lookups: no network in a test
|
||||
number("basemap"), "no", # nor a tile server
|
||||
number("airports"), "no", # nor the map data
|
||||
[reach("simulate"), "yes", # invent a sky
|
||||
reach("seconds"), "3", # listen for three seconds
|
||||
reach("picture"), picture, # what to draw
|
||||
reach("lookup"), "no", # no lookups: no network in a test
|
||||
reach("basemap"), "no", # nor a tile server
|
||||
reach("airports"), "no", # nor the map data
|
||||
"l", # listen now
|
||||
"m", "1", # draw the newest log
|
||||
"b"], cfg)
|
||||
|
|
@ -265,10 +276,10 @@ def test_listening_can_draw_as_soon_as_it_stops(monkeypatch, console,
|
|||
"""One key, from nothing to a picture."""
|
||||
cfg = ScanConfig(output_dir=str(tmp_path))
|
||||
run(monkeypatch, console,
|
||||
[number("simulate"), "yes", number("seconds"), "3",
|
||||
number("lookup"), "no", number("basemap"), "no",
|
||||
number("airports"), "no", number("draw_after"), "yes",
|
||||
number("picture"), "png", "l", "b"], cfg)
|
||||
[reach("simulate"), "yes", reach("seconds"), "3",
|
||||
reach("lookup"), "no", reach("basemap"), "no",
|
||||
reach("airports"), "no", reach("draw_after"), "yes",
|
||||
reach("picture"), "png", "l", "b"], cfg)
|
||||
assert list(tmp_path.glob("adsb_*.png"))
|
||||
|
||||
|
||||
|
|
@ -430,3 +441,89 @@ def test_leaving_it_off_changes_nothing(capsys):
|
|||
same = air.checked(loud, air.AircraftOptions(recheck=False), [track])
|
||||
assert same[0] is track
|
||||
assert capsys.readouterr().out.strip() == ""
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# The options, in groups
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_no_group_is_long_enough_to_need_scrolling():
|
||||
"""Thirty-three options on one screen is a wall. The point of the
|
||||
groups is that each of them fits in front of you at once."""
|
||||
for group in air.OPTION_GROUPS:
|
||||
items = air.in_group(group)
|
||||
assert 1 <= len(items) <= 10, (group, len(items))
|
||||
|
||||
|
||||
def test_every_option_is_in_exactly_one_group():
|
||||
seen = [o for group in air.OPTION_GROUPS for o in air.in_group(group)]
|
||||
assert len(seen) == len(air.OPTIONS)
|
||||
assert {o.key for o in seen} == {o.key for o in air.OPTIONS}
|
||||
|
||||
|
||||
def test_each_group_sits_together_in_the_numbering():
|
||||
"""The number beside an option is its place in the whole list, so that
|
||||
the same number means the same option wherever it is typed. That only
|
||||
reads sensibly if a group's options are next to each other."""
|
||||
for group in air.OPTION_GROUPS:
|
||||
places = [air.OPTIONS.index(o) for o in air.in_group(group)]
|
||||
assert places == list(range(places[0], places[0] + len(places))), group
|
||||
|
||||
|
||||
def test_a_name_typed_in_full_goes_straight_to_that_option():
|
||||
"""Typing "seconds" should reach the setting called seconds, not that
|
||||
one and every other whose description mentions the word."""
|
||||
for key in ("seconds", "picture", "simulate", "speed", "width", "rings"):
|
||||
found = tui._find_options(key)
|
||||
assert [o.key for o in found] == [key], (key, [o.key for o in found])
|
||||
|
||||
|
||||
def test_a_part_of_a_name_finds_everything_it_could_mean():
|
||||
found = [o.key for o in tui._find_options("ring")]
|
||||
assert "rings" in found and "window_rings" in found
|
||||
|
||||
|
||||
def test_a_name_nobody_has_finds_nothing():
|
||||
assert tui._find_options("zzz") == []
|
||||
assert tui._find_options("") == []
|
||||
|
||||
|
||||
def test_opening_a_group_shows_its_options_and_nothing_else(monkeypatch,
|
||||
console, capsys,
|
||||
settings_dir):
|
||||
from rich.console import Console
|
||||
|
||||
loud = Console(width=100, force_terminal=False, no_color=True)
|
||||
where = air.OPTION_GROUPS.index("The map") + 1
|
||||
run(monkeypatch, loud, [str(where), "b", "b"], ScanConfig())
|
||||
printed = capsys.readouterr().out
|
||||
for option in air.in_group("The map"):
|
||||
assert option.label.split()[0] in printed, option.key
|
||||
# An option from another group is not on that screen.
|
||||
after = printed.split("the map", 2)[-1]
|
||||
assert "Tuner gain" not in after and "Listen for" not in after
|
||||
|
||||
|
||||
def test_typing_an_option_name_at_the_top_opens_that_option(monkeypatch,
|
||||
console,
|
||||
settings_dir):
|
||||
"""The way in for somebody who knows what they are looking for and does
|
||||
not want to hunt through the groups for it."""
|
||||
held = air.AircraftOptions()
|
||||
monkeypatch.setattr(air, "load_options", lambda *a, **kw: held)
|
||||
run(monkeypatch, console, ["map brightness", "45", "b"], ScanConfig())
|
||||
assert held.map_brightness == 45
|
||||
|
||||
|
||||
def test_a_group_number_at_the_top_does_not_edit_the_option_of_that_number(
|
||||
monkeypatch, console, settings_dir):
|
||||
"""A bare number at the top of the menu opens a group. It used to edit
|
||||
the option with that number, and the two would otherwise disagree."""
|
||||
held = air.AircraftOptions()
|
||||
was = held.seconds
|
||||
monkeypatch.setattr(air, "load_options", lambda *a, **kw: held)
|
||||
# Option 1 is the receiver; group 1 is the receiver group. Typing 1
|
||||
# and then going back must leave everything alone.
|
||||
run(monkeypatch, console, ["1", "b", "b"], ScanConfig())
|
||||
assert held.seconds == was
|
||||
assert held.device == air.AircraftOptions().device
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue