sextile.formatting¶
Sequences formatted as parts of a page.
A sequence part is a layout.Drawable that lays out a homogeneous sequence: it takes as many entries as the room allows, says which of them can be chosen, and hands back the rest for the next frame. It deals only with the entries; titles, rules and keys are the layout’s.
The shapes ready to use, differing in how many entries a frame holds and how each one is drawn:
Menu numbered, a line of detail beneath each Listing two columns, nothing numbered, for a page that is a reference Figures a label and a figure a row, the figures aligned in one column Lines lines drawn as given, for a page that simply says something Prose running text, wrapped, in as many rows as it takes
A service needing a shape that is not here subclasses SequencePart or RowSequencePart and says how tall an entry is and how to draw one.
Example
Twelve entries, nine on the first frame and three on the second:
PageLayout(
title="LATEST POSTS",
parts=[Menu(entries=posts)],
).build(request)
- class sextile.formatting.Entry(*args, **kwargs)[source]¶
Bases:
ProtocolWhat a sequence part over Entry values requires of them.
A protocol rather than a base class, so that a service with its own richer entry type, carrying whatever it needs, can pass that value directly rather than copy it into a dataclass belonging to the framework.
- property destination: PageAddress | None¶
The address choosing this entry leads to, or None if it is only read.
- class sextile.formatting.Figures(*, entries, empty='', label_width=None, figure_width=None)[source]¶
Bases:
RowSequencePart[Entry]A label and a figure a row, the figures right-aligned in one column.
For a page that reports rather than offers: how many callers, how much is held, how long since. The entry’s text is the label and its detail the figure.
- label_width¶
How wide the labels’ column is, in cells, and figure_width how wide the figures’. Worked out once and carried, as a Listing’s column is.
- figure_width¶
See label_width.
- Parameters:
- class sextile.formatting.SequencePart(*, entries, empty='')[source]¶
-
Abstract base for the sequence parts: a sequence, laid out as a part.
A subclass says how tall an entry is and how to draw one; this class works out how many fit in the room it is given, draws them, and hands back what is left.
The class attributes a subclass overrides to describe its shape:
rows_per_entry: rows one entry occupies.gap: blank rows between one entry and the next, and not after the last.numbered: whether entries take a digit, and so whether the reader can choose them.choose_hint: what the prompt says about choosing, on frames with something to choose. Itskeyis a placeholder: the frame names the digits it actually offered, so a full frame says1-9and a short one1-3.
- entries¶
The values to draw, in the order they are to appear.
- empty¶
Said in place of the entries where there are none. A string is one row; a sequence is its rows as given, an empty string among them a blank one. A service that answers slowly cannot let a frame come up empty and unexplained, because a reader cannot tell that from a fault.
Example
A part three rows tall that draws each entry by cell:
class Pictures(SequencePart[Picture]): rows_per_entry: ClassVar[int] = 3 def draw_entry(self, canvas: Canvas, row: int, entry: Picture) -> None: entry.draw(canvas, row)
- abstractmethod draw_entry(canvas, row, entry)[source]¶
Draw one entry in the rows_per_entry rows beginning at row.
- Parameters:
- Return type:
A numbered part is drawn its digit for it: NumberedRowSequencePart draws the digit column before the entry, so a subclass never sees the digit and every part but a numbered one is spared the parameter.
- class sextile.formatting.Lines(entries=(), *, empty='', colour=Colour.WHITE, align=Align.START)[source]¶
Bases:
SequencePart[str]Lines drawn as given, one to a row, for a page that says something.
Not prose, which wraps running text and puts a blank row between one paragraph and the next. A notice that has arranged its own lines and its own blanks means them where they are, so nothing is wrapped and nothing is moved: a line too long for the row is cut.
- entries¶
The lines, in the order they are to appear, passed first and without a keyword. An empty one leaves a blank row.
- colour¶
What they are drawn in. White for a notice; green for a note beneath a table, set apart from the table above it.
- align¶
Where each line sits across the row, Align.START (the left) by default. Centre a wrapped display string by wrapping it with Breaking.DISPLAY and drawing it Align.CENTRE.
- draw_entry(canvas, row, entry)[source]¶
Draw one entry in the rows_per_entry rows beginning at row.
- Parameters:
- Return type:
A numbered part is drawn its digit for it: NumberedRowSequencePart draws the digit column before the entry, so a subclass never sees the digit and every part but a numbered one is spared the parameter.
- class sextile.formatting.Listing(*, entries, empty='', column=None)[source]¶
Bases:
RowSequencePart[Entry]Two columns, nothing to choose, for a page that is a reference.
What a service is made of, which words it answers to. The left column is set to the width of the widest entry, so that the page reads as a table, and a detail too long for the room left over is carried on to a further row rather than being cut.
- column¶
How wide the left column is. Worked out from the entries when the listing is first made, and carried from frame to frame thereafter – a table that set its column afresh on each frame would shift its columns partway down.
- class sextile.formatting.Menu(*, entries, empty='')[source]¶
Bases:
NumberedRowSequencePart[Entry]Numbered choices, each with a line of detail beneath it.
The shape most viewdata pages take. A reader chooses with a single keypress, so nine entries are the most one frame can offer and the rest go on the frames after it.
- destination(entry)[source]¶
The address choosing entry leads to, or None where it leads nowhere.
Returns None for every entry unless a subclass overrides this.
- Parameters:
entry (
Entry)- Return type:
- class sextile.formatting.MenuItem(text='', detail='', destination=None)[source]¶
Bases:
objectAn Entry for a service that has nothing richer of its own.
- text¶
The text drawn on the entry’s first row.
- detail¶
A second line, a second column, or empty for neither.
- destination¶
The address choosing it leads to, or None if it is only read.
- Parameters:
text (
str)detail (
str)destination (
PageAddress|None)
- class sextile.formatting.NumberedRowSequencePart(*, entries, empty='')[source]¶
Bases:
RowSequencePart,GenericA row sequence part whose entries a reader chooses by a digit.
Only a numbered part takes a digit, so only this one has it in its drawing path: it draws the digit column – a yellow 1 ` before the entry – and `draw writes the entry after it, in the room the digit has left. Menu is the one shape built on it; a service numbering its own entries subclasses this rather than reaching for the digit itself.
Example
Entries a reader chooses by digit, the digit drawn for you:
class Choices(NumberedRowSequencePart[Entry]): def destination(self, entry: Entry) -> PageAddress | None: return entry.destination def draw(self, row: RowWriter, entry: Entry) -> None: row.text(entry.text)
- class sextile.formatting.Prose(*, entries, empty='')[source]¶
Bases:
SequencePart[Row]Running text, wrapped, in as many rows as it takes.
Its entries are rendered Row values rather than Entry values. Laying the text out through viewdata.typesetting gives a notice the same treatment as any long document: quotations in cyan, listings in green, nesting indented, and over-long words broken rather than dropped.
- draw_entry(canvas, row, entry)[source]¶
Draw one entry in the rows_per_entry rows beginning at row.
- Parameters:
- Return type:
A numbered part is drawn its digit for it: NumberedRowSequencePart draws the digit column before the entry, so a subclass never sees the digit and every part but a numbered one is spared the parameter.
- class sextile.formatting.RowSequencePart(*, entries, empty='')[source]¶
Bases:
SequencePart,GenericAbstract base for sequence parts whose entries are written along their rows.
Implements draw_entry by calling draw for an entry’s first row and draw_detail for its second, each with a RowWriter that runs from left to right. A shape positioned by cell, a picture several rows tall among them, should subclass SequencePart and implement draw_entry itself.
Example
A one-row listing that writes each entry as text:
class Names(RowSequencePart[str]): def draw(self, row: RowWriter, entry: str) -> None: row.text(entry)
- draw_entry(canvas, row, entry)[source]¶
Draw one entry in the rows_per_entry rows beginning at row.
- Parameters:
- Return type:
A numbered part is drawn its digit for it: NumberedRowSequencePart draws the digit column before the entry, so a subclass never sees the digit and every part but a numbered one is spared the parameter.