add edit step + do recipe in main view, added carousel for recipe selection

This commit is contained in:
2026-03-12 22:57:15 +01:00
parent 90257a62a0
commit d5dacb8fc4
21 changed files with 1052 additions and 279 deletions

View File

@@ -0,0 +1,67 @@
from __future__ import annotations
from PIL import ImageDraw
from .base import SelectableList
class CarouselView(SelectableList):
"""Single-item display shows the selected item centred and larger.
Position indicator dots at the bottom communicate how many items
exist and which one is currently selected. Uses
:pymethod:`ListItem.render_large` so callers can optionally provide
a more detailed rendering for carousel mode.
``large_font_size`` controls the font size passed to
:pymethod:`ListItem.render_large` (default 30, roughly 3× PIL default).
``center_x`` sets the horizontal centre used when drawing the item text
(default 84, the midpoint of a 168 px wide display). PIL's ``anchor='mm'``
is forwarded so the text is centred on that x coordinate.
``render_height`` is the total vertical space (in pixels) allocated to the
carousel; dots are placed at the very bottom of this region. Defaults to
``max_visible * item_height``.
"""
def __init__(self, *args,
large_font_size: int = 30,
center_x: int = 84,
render_height: int | None = None,
**kwargs):
super().__init__(*args, **kwargs)
self.large_font_size = large_font_size
self.center_x = center_x
self.render_height = render_height
def render(self, draw: ImageDraw.ImageDraw, y_start: int) -> None:
if not self._items:
return
item = self._items[self.selected_index]
height = self.render_height or (self.max_visible * self.item_height)
y_center = y_start + height // 2
# Render selected item centred (large variant, no highlight)
item.render_large(
draw,
(self.center_x, y_center),
fill='black',
font_size=self.large_font_size,
anchor='mm',
)
total = len(self._items)
# Position indicator dots at the top of the allocated area
if total > 1:
indicator_y = y_start
dot_spacing = min(8, max(4, 80 // max(total - 1, 1)))
total_width = (total - 1) * dot_spacing
start_x = self.center_x - total_width // 2
for i in range(total):
x = start_x + i * dot_spacing
r = 2 if i == self.selected_index else 1
draw.circle((x, indicator_y), r, fill='black')