Atui.Screen (Atui v0.1.0)

Copy Markdown View Source

A fixed-size grid of terminal cells that views draw into.

Every write is clipped to the screen bounds, so a view can never corrupt the frame by drawing past its own edges. Screens compose: a view renders into a screen the size of its rect, and the runtime overlays that onto the frame.

Each cell holds a grapheme and an Atui.Style. Styles stay data until the very last moment — to_iodata/1 emits an escape sequence only where the style changes from the cell before it, and to_text/1 drops them entirely, which is what tests assert against.

Summary

Functions

Draws a box border around rect.

The cell at {x, y} as {grapheme, style}, or nil if out of bounds.

Fills rect with grapheme (a space by default).

A blank screen of the given size.

Copies every cell of other onto base, offset by {x, y}.

Writes a single grapheme, ignoring out-of-bounds coordinates.

Vertically centres lines inside rect, each horizontally centred.

Writes text starting at {x, y}, clipped to the screen.

Writes text horizontally centred on row y within rect.

The full extent of the screen as a rect.

Restyles the cells in rect, keeping whatever graphemes are already there.

Restyles the outline of rect — a focus ring around whatever is drawn there.

Renders the screen as iodata: graphemes, escape sequences, rows separated by CRLF.

The rendered screen as a binary, escape sequences included.

The screen as plain text, one row per line, with every style dropped.

Truncates text to at most width graphemes.

Types

cell()

@type cell() :: {String.t(), Atui.Style.t() | nil}

t()

@type t() :: %Atui.Screen{
  cells: %{required({integer(), integer()}) => cell()},
  height: non_neg_integer(),
  width: non_neg_integer()
}

Functions

box(screen, rect, opts \\ [])

Draws a box border around rect.

Options:

  • :title — centred in the top border, e.g. " Atui v0.1.0 "
  • :chars — border charset: :single (default), :double or :round
  • :style — an Atui.Style for the border and the fill
  • :title_style — an Atui.Style for the title (defaults to :style)
  • :fill — blank the interior first (default true), so a popup hides whatever it is drawn over

cell(screen, x, y)

The cell at {x, y} as {grapheme, style}, or nil if out of bounds.

fill(screen, rect, grapheme \\ " ", style \\ nil)

Fills rect with grapheme (a space by default).

new(width, height)

A blank screen of the given size.

overlay(base, other, x, y)

Copies every cell of other onto base, offset by {x, y}.

put(screen, x, y, grapheme, style \\ nil)

Writes a single grapheme, ignoring out-of-bounds coordinates.

put_lines_centered(screen, rect, lines, style \\ nil)

Vertically centres lines inside rect, each horizontally centred.

put_text(screen, x, y, text, style \\ nil)

Writes text starting at {x, y}, clipped to the screen.

put_text_centered(screen, rect, y, text, style \\ nil)

Writes text horizontally centred on row y within rect.

rect(screen)

The full extent of the screen as a rect.

restyle(screen, rect, style)

Restyles the cells in rect, keeping whatever graphemes are already there.

restyle_border(screen, rect, style)

Restyles the outline of rect — a focus ring around whatever is drawn there.

It recolours cells rather than drawing a border, so a container can mark one of its children without knowing how that child chose to frame itself.

to_iodata(screen)

Renders the screen as iodata: graphemes, escape sequences, rows separated by CRLF.

CRLF (not LF) because the terminal is in raw mode: without the carriage return the cursor stays in whatever column the previous row ended on. Each row ends in the default style, so a coloured background cannot leak into the next.

to_string(screen)

The rendered screen as a binary, escape sequences included.

to_text(screen)

The screen as plain text, one row per line, with every style dropped.

This is the view a person would see, which makes it what assertions want.

truncate(text, width)

Truncates text to at most width graphemes.