A custom part¶
A how-to guide: content that is a sequence drawn its own way is a
SequencePart subclass, which flows across as many frames as it takes.
from dataclasses import dataclass
from sextile import Flow, Page, PageLayout, PageRequest, PageRouter, Sextile
from sextile.formatting import RowSequencePart
from sextile.viewdata.canvas import RowWriter
from sextile.viewdata.controls import Colour
router = PageRouter()
_TABLE = [("Arsenal", 63), ("City", 61), ("Liverpool", 58), ("Villa", 54), ("Spurs", 50)]
@dataclass(frozen=True, kw_only=True)
class Standings(RowSequencePart[tuple[str, int]]):
def draw(self, row: RowWriter, entry: tuple[str, int]) -> None:
name, points = entry
row.text(f"{name:<12}", Colour.CYAN).text(f"{points:>3}", Colour.YELLOW)
@router.page("8", name="league", title="League table")
async def league(request: PageRequest) -> Page:
return PageLayout(parts=[Flow(Standings(entries=_TABLE))]).build(request)
app = Sextile(name="Sport", pages=[*router])
LEAGUE TABLE 8a Arsenal 63 City 61 Liverpool 58 Villa 54 Spurs 50 0 index
A RowSequencePart writes each entry along its rows: override draw with a
RowWriter that runs left to right, and set rows_per_entry where an entry wants
a second row (draw_detail writes it). Wrap the part in Flow so the layout
carries the overflow onto further frames. For a picture positioned by cell,
subclass SequencePart and draw the cells yourself; for entries a reader chooses
by digit, subclass NumberedRowSequencePart and override destination. A part of
the frame’s furniture — a header or footer — is a Furnishing instead.
The parts, wrappers and furniture are catalogued in Layout, and why furniture is kept separate from the parts down the middle is in Design decisions. For a placed picture rather than a sequence, see Draw a custom frame and Compose a frame.