From 3662e7487f30aff9d794dd5ff3a39ef9c3b87442 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 4 Jun 2026 20:06:40 -0700 Subject: [PATCH] Make the focus strip resolution-flexible (fix 176x176 layout) The focus-quality (HFD) strip was added in #449 before the resolution-flexible UI work in #453. #453 converted the camera preview's image resize and star selectors to derive from the display resolution but never touched draw_focus_strip(), which kept 128-only literals: strip_top = 90 # bottom-band top plot_top = +9 # V-curve top clearance plot_bottom = -10 # V-curve bottom clearance bottom label = -9 On the 176x176 SSD1333 panel strip_top=90 lands mid-screen (~51% down) instead of as a bottom band, stranding the exposure/matched-star labels high up with a large empty gap above the readout, and the bottom detected-star label clips at the screen edge. Derive the geometry instead (ADR 0009): - strip_top: a fixed fraction of screen height (res_y - res_y*38/128), so the band stays ~30% of the screen on any panel. - label-row clearances: from self.fonts.small.height, so the rows track the (larger) small font on the 176 panel and never collide with the V-curve. The 128 small font is 9 px, so strip_top+9 == strip_top+small_h, res_y-10 == res_y-small_h-1, and res_y-9 == res_y-small_h: the 128 layout is reproduced pixel-for-pixel (zero regression), while the 176 layout becomes a correct proportional bottom band. Verified headless on both DisplayHeadless (128) and DisplayHeadless176 (176). Docs: update the CONTEXT.md focus-strip glossary entry, which described a fixed "~38 px" band, to note it scales with the display. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/ax/ui/CONTEXT.md | 2 +- python/PiFinder/ui/preview.py | 29 +++++++++++++++++++++-------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/docs/ax/ui/CONTEXT.md b/docs/ax/ui/CONTEXT.md index d36c8afe..3729444a 100644 --- a/docs/ax/ui/CONTEXT.md +++ b/docs/ax/ui/CONTEXT.md @@ -141,7 +141,7 @@ The **median** HFD over the few brightest detected stars in the current frame _Avoid_: best HFD (that's the marker), single-star HFD. **Focus strip**: -The bottom-of-screen overlay (~38 px) that renders the focus indicator over the live image: a large right-justified **focus HFD** readout (filling the strip height), and in the freed left region the V-curve, best-focus marker, exposure, detected-star count, and the (kept) matched-star count. On by default; `square` hides the whole strip. Persists across all zoom levels (HFD is zoom-independent). +The bottom-of-screen overlay (a fixed fraction of the screen height — ~38 px on the 128 panel, proportionally taller on a larger panel; see ADR 0009) that renders the focus indicator over the live image: a large right-justified **focus HFD** readout (filling the strip height), and in the freed left region the V-curve, best-focus marker, exposure, detected-star count, and the (kept) matched-star count. On by default; `square` hides the whole strip. Persists across all zoom levels (HFD is zoom-independent). _Avoid_: HUD (loosely the same overlay; "focus strip" is the canonical name), info overlay (the prior exposure+matched-count overlay this replaces). **V-curve** (focus trend graph): diff --git a/python/PiFinder/ui/preview.py b/python/PiFinder/ui/preview.py index 69ba8477..d22deb5d 100644 --- a/python/PiFinder/ui/preview.py +++ b/python/PiFinder/ui/preview.py @@ -250,14 +250,24 @@ def _hfd_to_y(self, hfd, plot_top, plot_bottom): def draw_focus_strip(self): """Render the focus strip: big HFD readout, V-curve, marker, and HUD. - ~38 px bottom band, on by default; square hides it. Persists across all - zoom levels (HFD is zoom-independent). Layout: a large right-justified - HFD number (the hero readout) fills the strip height; the V-curve and - small labels sit in the freed left region. + Bottom band, on by default; square hides it. Persists across all zoom + levels (HFD is zoom-independent). Layout: a large right-justified HFD + number (the hero readout) fills the strip height; the V-curve and small + labels sit in the freed left region. + + Geometry is resolution-flexible (ADR 0009): the band is a fixed fraction + of the screen height (~38 px on the 128 panel, proportionally taller on + a larger panel) and the label clearances derive from the small-font + height, so the rows never collide with the V-curve as the font grows. """ - strip_top = 90 res_x = self.display_class.resX res_y = self.display_class.resY + # Bottom band height scales with the screen (38 px / 128 px on the + # 128 panel); strip_top was a 128-only literal (90) before #453. + strip_top = res_y - round(res_y * 38 / 128) + # Small-font height drives the label-row clearances (9 px on the 128 + # panel); deriving them keeps the rows clear of the V-curve at 176. + small_h = self.fonts.small.height # Dim band so the overlay stays legible over a bright image. self.draw.rectangle([0, strip_top, res_x, res_y], fill=(0, 0, 0, 150)) @@ -304,10 +314,13 @@ def draw_focus_strip(self): ) # --- Left region: V-curve framed by small labels --- + # plot_top clears the top label row; plot_bottom sits just above the + # bottom label row -- both derived from the small-font height so they + # track the font across resolutions (9 / 10 px on the 128 panel). plot_left = 2 plot_right = num_left - 3 - plot_top = strip_top + 9 - plot_bottom = res_y - 10 + plot_top = strip_top + small_h + plot_bottom = res_y - small_h - 1 # Top labels: exposure (left), matched-star count (right of the graph). # The matched 0 -> N jump still signals "sharp enough to solve". @@ -336,7 +349,7 @@ def draw_focus_strip(self): # Bottom label: detected-star count (the self-contained detector). outline_text( self.draw, - (plot_left, res_y - 9), + (plot_left, res_y - small_h), _("det {n}").format(n=detected), align="left", font=self.fonts.small,