diff --git a/src/fenigma/app.py b/src/fenigma/app.py index d13db6c..cc2b97f 100644 --- a/src/fenigma/app.py +++ b/src/fenigma/app.py @@ -692,14 +692,21 @@ class MainWindow(Adw.ApplicationWindow): self.cursor_label.set_label("") return coord = solver.point_to_coord(point_km) - coord_text = coord.label() if coord is not None else "off map" + if coord is None: + # Off the map entirely, AZ/dist are still mathematically + # defined for any raw km point (nothing stops that math from + # running on a negative or >20/>10 coordinate), showing them + # anyway would read as a real reading for a position that + # isn't actually on the map. + self.cursor_label.set_label("off map") + return nest = self.board.nest if nest.coord is not None: az = ballistics.bearing_deg_point(nest.coord.as_fraction(), point_km) dist = ballistics.distance_km_point(nest.coord.as_fraction(), point_km) - self.cursor_label.set_label(f"AZ {az:05.1f}° {dist:5.2f}km {coord_text}") + self.cursor_label.set_label(f"AZ {az:05.1f}° {dist:5.2f}km {coord.label()}") else: - self.cursor_label.set_label(coord_text) + self.cursor_label.set_label(coord.label()) # -- Nest ----------------------------------------------------------------- def _build_nest_popover(self, rebuild) -> Gtk.Widget: diff --git a/src/fenigma/grid_widget.py b/src/fenigma/grid_widget.py index e6493c0..b2d2a3a 100644 --- a/src/fenigma/grid_widget.py +++ b/src/fenigma/grid_widget.py @@ -7,6 +7,7 @@ stay in sync with the map (see app.py).""" from __future__ import annotations import math +from collections import namedtuple import gi @@ -29,6 +30,22 @@ LABEL_PAD = 8 # gap between a marker and its name label HOVER_RADIUS_PX = 12 OVERLAY_RAY_LENGTH_KM = 30.0 # long enough to cross the 20x10 map from any origin +MIN_ZOOM = 1.0 # the whole 20x10 map fits, the default +MAX_ZOOM = 10.0 +ZOOM_STEP = 1.15 # per scroll-wheel notch + +# Everything needed to convert between km-space (the 20x10 grid) and +# widget pixels for one frame, bundled so every draw/hit-test method +# takes one argument instead of threading cell_w/cell_h/grid_h/pan +# separately through a dozen call sites. cell_w/cell_h differ only when +# square_cells is off (the default): the map then stretches to fill the +# widget exactly, cell_w == cell_h only when the widget's own aspect +# ratio happens to match the grid's. pad_x/pad_y are the letterboxing +# margin added on whichever axis has leftover space when square_cells +# is on. ox/oy are the visible viewport's origin in km-space (0,0 +# unless zoomed in and panned). +_View = namedtuple("_View", "cell_w cell_h grid_w grid_h pad_x pad_y ox oy") + CATEGORY_COLOR = { "nest": (0.35, 0.60, 0.95), "spotter": (0.35, 0.78, 0.40),