sextile.viewdata.frame

A viewdata frame: a fixed grid of 24 rows by 40 cells.

Each cell holds one byte, exactly as the SAA5050 sees it: a G0 character position in 0x20-0x7F, or a spacing attribute below 0x20 which the display renders as a space in the prevailing background.

The grid is fixed rather than a stream of writes because Commstar wraps from the bottom right cell straight back to the top left instead of scrolling. A serialiser that emitted one cell too many would overwrite the top of the frame it had just drawn. With a fixed grid that cannot happen: the frame always occupies exactly 960 cells.

Attributes cost a byte more on the wire than on screen, since they travel escaped as two bytes but still occupy a single cell. The grid, never the byte count, is the authority on layout.

sextile.viewdata.frame.FOOTER_ROW: Final = 23

The last row, which the session draws on directly. The command line while a request is being keyed goes here, and the countdown before a silent line is released. A page reaches it through its furniture rather than through this.

class sextile.viewdata.frame.Frame[source]

Bases: object

A frame under construction.

cell(row, column)[source]

The byte held at a position.

Parameters:
Return type:

int

is_attribute(row, column)[source]

Whether a position holds a spacing attribute rather than a character.

Parameters:
Return type:

bool

set_attribute(row, column, attribute)[source]

Place a spacing attribute, which occupies the cell and displays as a space.

Parameters:
Return type:

None

set_cell(row, column, code)[source]

Put a displayable code in a cell, as the SAA5050 will read it.

What it draws depends on the character set in force where it lands, which is the caller’s business: the same byte is a letter in alpha and a pattern of blocks in graphics. Canvas tracks that; this does not.

Parameters:
Return type:

None

write(row, column, text)[source]

Place text, transliterating and encoding it into G0 positions.

Parameters:
Return type:

None

text_at(row, column, length)[source]

The characters held in a run of cells, with attributes reading as spaces.

Parameters:
Return type:

str

to_bytes(*, trim=True)[source]

The frame as it travels: clear, home, then the cells that say something.

Trailing blanks are not sent. The frame begins by clearing the screen, so a space at the end of a row overwrites nothing – it exists only to walk the cursor forward, and a carriage return and line feed do that in two bytes rather than up to forty. A row that fills all forty columns gets no terminator, because column 40 wraps of its own accord and a terminator there would skip a row. After the last row with anything on it, nothing is sent at all.

trim=False gives the older form, every cell in turn, so the two can be compared on real hardware.

Parameters:

trim (bool)

Return type:

bytes

row_bytes(row, *, upto=None)[source]

One row’s cells, escaped, with no preamble and no terminator.

For drawing over a row of a screen that is already showing something, which is what the command line does.

upto stops short of the row’s end, and a repaint of several rows must use it. Measured on real Commstar: a row written to all forty columns wraps of its own accord, so the cursor is already on the next row and the carriage return and cursor down that walk to the next row of the block move it down a second one. A three-row block written full width lands on rows 4, 6 and 8 and overruns what is beneath it.

The command line does not need it, its field being deliberately full width and nothing following it.

Parameters:
Return type:

bytes

last_written_row()[source]

The last row with anything on it, or -1 if the frame is blank.

Where the cursor is left once the frame has been sent, trailing blanks not being sent, which is what lets anything drawn afterwards find its way from there.

Return type:

int

used_columns(row)[source]

How much of a row is worth sending: up to its last non-blank cell.

Parameters:

row (int)

Return type:

int

to_grid()[source]

A readable dump as two layers, so golden-frame failures diff legibly.

The character layer shows what the screen shows, with attribute cells appearing as the spaces they are. The attribute layer names those cells by the letter they travel as, and marks every other cell with a dot.

Return type:

tuple[list[str], list[str]]