add edit step + do recipe in main view, added carousel for recipe selection
This commit is contained in:
67
frontend/views/list_select/carousel.py
Normal file
67
frontend/views/list_select/carousel.py
Normal 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')
|
||||
Reference in New Issue
Block a user