fix(screens): wrap step subtitles to column width
Long step subtitles ("This will connect your phone to the WeVisto" /
"This will open the WeVisto setup page") overflowed the left column
and crossed the centre divider on both panels. Added a greedy word-
wrap helper and bumped step_pitch (13.3: 92→112, 7.3: 32→50) so the
wrapped second line has room below the first.
Regenerated both panels' setup_bg/ap_bg/ap_bg_retry assets.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -137,6 +137,23 @@ def draw_logo_placeholder(img):
|
||||
"PLACEHOLDER", font=f_hint, fill=BK)
|
||||
|
||||
|
||||
def wrap_to_width(draw, text, font, max_w):
|
||||
"""Greedy word-wrap so each rendered line stays within max_w pixels."""
|
||||
lines, current = [], ""
|
||||
for word in text.split():
|
||||
candidate = (current + " " + word) if current else word
|
||||
bb = draw.textbbox((0, 0), candidate, font=font)
|
||||
if bb[2] - bb[0] <= max_w:
|
||||
current = candidate
|
||||
else:
|
||||
if current:
|
||||
lines.append(current)
|
||||
current = word
|
||||
if current:
|
||||
lines.append(current)
|
||||
return lines
|
||||
|
||||
|
||||
def text_center(draw, cx, y, text, font, fill):
|
||||
bb = draw.textbbox((0,0), text, font=font)
|
||||
tw = bb[2]-bb[0]
|
||||
@@ -256,14 +273,17 @@ def gen_ap(accent=YL, header="SETUP MODE — STEP 1 OF 2", qr_label="SCAN TO C
|
||||
("Scan QR 2", "This will open the WeVisto setup page"),
|
||||
]
|
||||
sy = BODY_Y + 95
|
||||
step_pitch = 32
|
||||
step_pitch = 50
|
||||
text_max_w = DIV1_X - 62 - 6
|
||||
line_h = 15
|
||||
for i, (l1, l2) in enumerate(steps):
|
||||
bx, by = 28, sy + i*step_pitch
|
||||
draw.rectangle([bx, by, bx+24, by+24], fill=BK)
|
||||
text_center(draw, bx+12, by+6, str(i+1), F_STEPN, accent)
|
||||
draw.text((62, by+3), l1, font=F_STEP, fill=BK)
|
||||
if l2:
|
||||
draw.text((62, by+17), l2, font=F_STEP, fill=BK)
|
||||
for j, line in enumerate(wrap_to_width(draw, l2, F_STEP, text_max_w)):
|
||||
draw.text((62, by+17 + j*line_h), line, font=F_STEP, fill=BK)
|
||||
|
||||
# Manual QR + side label — bottom of left panel.
|
||||
# The manual covers the captive-portal-didn't-open fallback (192.168.4.1)
|
||||
|
||||
@@ -110,6 +110,25 @@ def text_center(draw, cx, y, text, font, fill):
|
||||
draw.text((cx - tw // 2, y), text, font=font, fill=fill)
|
||||
|
||||
|
||||
def wrap_to_width(draw, text, font, max_w):
|
||||
"""Greedy word-wrap so each rendered line stays within max_w pixels.
|
||||
Doesn't split individual words. Returns a list of lines."""
|
||||
lines = []
|
||||
current = ""
|
||||
for word in text.split():
|
||||
candidate = (current + " " + word) if current else word
|
||||
bb = draw.textbbox((0, 0), candidate, font=font)
|
||||
if bb[2] - bb[0] <= max_w:
|
||||
current = candidate
|
||||
else:
|
||||
if current:
|
||||
lines.append(current)
|
||||
current = word
|
||||
if current:
|
||||
lines.append(current)
|
||||
return lines
|
||||
|
||||
|
||||
def leave_qr_white(draw, qr_x, qr_y, qr_px):
|
||||
draw.rectangle([qr_x, qr_y, qr_x + qr_px - 1, qr_y + qr_px - 1], fill=WH)
|
||||
|
||||
@@ -304,16 +323,20 @@ def gen_ap(accent=YL,
|
||||
("Scan QR 2", "This will open the WeVisto setup page"),
|
||||
]
|
||||
step_y0 = head_y + 240
|
||||
step_pitch = 92
|
||||
step_pitch = 112
|
||||
box = 50 # numbered black box size
|
||||
text_x = LEFT_PAD + box + 22
|
||||
text_max_w = DIV_X - text_x - 18 # don't cross the column divider
|
||||
line_h = 34 # ~F_STEP line height
|
||||
for i, (l1, l2) in enumerate(steps):
|
||||
by = step_y0 + i * step_pitch
|
||||
draw.rectangle([LEFT_PAD, by, LEFT_PAD + box, by + box], fill=BK)
|
||||
text_center(draw, LEFT_PAD + box // 2, by + 8,
|
||||
str(i + 1), F_STEPN, accent)
|
||||
draw.text((LEFT_PAD + box + 22, by - 4), l1, font=F_STEP_B, fill=BK)
|
||||
draw.text((text_x, by - 4), l1, font=F_STEP_B, fill=BK)
|
||||
if l2:
|
||||
draw.text((LEFT_PAD + box + 22, by + 32), l2, font=F_STEP, fill=BK)
|
||||
for j, line in enumerate(wrap_to_width(draw, l2, F_STEP, text_max_w)):
|
||||
draw.text((text_x, by + 32 + j * line_h), line, font=F_STEP, fill=BK)
|
||||
|
||||
# Orientation diagrams — tucked between the steps and the manual QR so
|
||||
# the user sees both possible hanging positions before they commit.
|
||||
|
||||