Drafter.Widget.Digits (drafter v0.3.1)

Copy Markdown View Source

Renders text as large characters, drawn with box outlines or with pixels packed into braille, quadrant, or half-block cells.

Covers the digits 09, the full alphabet, and common punctuation. Lower case falls back to the upper-case form, and a character no font can draw renders as blanks of the same width.

The glyphs live in Drafter.Widget.Digits.Font, which also accepts FIGlet fonts loaded at runtime. See the large text guide for the catalogue and how to choose between fonts.

Component tag

Tag :digits, built by Drafter.App as {:digits, value, opts}:

digits(value, opts)

The positional argument is passed through to_string/1 to become :text, so it may be any term implementing String.Chars. All other props come from opts.

Options

  • :text - String.t/0 of characters to render. Default "". Supplied positionally through the digits/2 element, passed through to_string/1. Empty text renders nothing at all
  • :style - map/0 of style properties applied to all characters. Default %{}
  • :align - horizontal alignment within the available width: :left (default), :center, :right
  • :font - a name from Drafter.Widget.Digits.Font.names/0, or a font map. Default nil. Overrides :size when set
  • :size - coarse size when no :font is given: :large (default, the :block font) or :small (the :compact font)
  • :renderer - :text (default) draws cells; any other value transmits an image on a terminal supporting kitty, iTerm2, or sixel, falling back to cells where none is available
  • :bg_data - list of numbers. Default nil. When set, an area-chart fill is drawn behind the digits using per-cell background colours
  • :color - {r, g, b} fill colour for the area chart. Default {0, 150, 255}. Digit glyphs are drawn in an auto-contrasting foreground
  • :bg_min - value mapped to the bottom of the :bg_data area fill. Default 0
  • :bg_max - value mapped to the top of the :bg_data area fill. Default nil, which uses the largest sampled value, or 1 when :bg_data is empty

update/2 merges the props map into the state, so every option is live, and a re-render passes all of them through.

Widget value

Drafter.get_widget_value/1 returns the rendered :text as a String.t/0, because the value extractor reads the :text field.

Data channel

When the widget is declared with a data buffer, apply_data_buffer/3 sets :text to to_string/1 of the last item in the buffer.

Usage

digits("12:34", size: :large, style: %{fg: {0, 200, 100}})
digits("99%", size: :small, align: :center)
digits("CPU 42", font: :braille)
digits("Vellum", font: :slant, renderer: :graphics)
digits("42%", bg_data: history, color: {0, 180, 120}, size: :large, align: :center)

Summary

Functions

Sets :text to to_string/1 of the newest item in the widget's data buffer.

The registry tag for this widget.

Turns the {:digits, value, opts} element into a props map for mount/1.

Ignores every event and returns {:noreply, state}. The widget is not focusable and never consumes input.

Builds the terminal-graphics payload for the text, or nil.

Whether these digits are drawing a transmitted image rather than cells.

Builds the digits state from props. The state is a plain map, not a struct.

The row height of the font opts selects.

Draws the large characters into rect.

Merges props into state, so every option is live-updatable.

Passes every option through to update/2 on a re-render, so nothing about a digits widget is mount-only.

Types

t()

@type t() :: %{
  text: String.t(),
  style: map(),
  align: :left | :center | :right,
  size: :large | :small,
  font: atom() | map() | nil,
  renderer: atom(),
  bg_data: [number()] | nil,
  color: {0..255, 0..255, 0..255},
  bg_min: number(),
  bg_max: number() | nil
}

Functions

apply_data_buffer(state, buffer, rect)

@spec apply_data_buffer(t(), Drafter.RingBuffer.t(), Drafter.Widget.rect()) :: t()

Sets :text to to_string/1 of the newest item in the widget's data buffer.

Everything buffered before the last item is discarded. An empty buffer leaves the state alone.

component_tag()

@spec component_tag() :: :digits

The registry tag for this widget.

iex> Drafter.Widget.Digits.component_tag()
:digits

from_component_opts(value, opts)

@spec from_component_opts(
  term(),
  keyword()
) :: Drafter.Widget.props()

Turns the {:digits, value, opts} element into a props map for mount/1.

value becomes :text through to_string/1, so it may be any term implementing String.Chars.

iex> props = Drafter.Widget.Digits.from_component_opts(42, align: :center)
iex> {props.text, props.align, props.size, props.color, props.bg_min}
{"42", :center, :large, {0, 150, 255}, 0}

handle_event(event, state)

@spec handle_event(Drafter.Event.t(), t()) :: {:noreply, t()}

Ignores every event and returns {:noreply, state}. The widget is not focusable and never consumes input.

image(state, rect, id)

@spec image(t(), Drafter.Widget.rect(), term()) :: {iodata(), iodata(), map()} | nil

Builds the terminal-graphics payload for the text, or nil.

Returns nil when :renderer is :text, when rect has no area, or when no supported graphics protocol is available. Otherwise returns {paint, clear, placement}, where placement is %{dx: 0, dy: 0, cols: rect.width, rows: rect.height}.

image_active?(state)

@spec image_active?(t()) :: boolean()

Whether these digits are drawing a transmitted image rather than cells.

True when :renderer is anything but :text and the terminal has a graphics protocol to draw it with.

mount(props)

@spec mount(Drafter.Widget.props()) :: t()

Builds the digits state from props. The state is a plain map, not a struct.

iex> d = Drafter.Widget.Digits.mount(%{text: "42", size: :small})
iex> {d.text, d.size, d.font, d.align}
{"42", :small, nil, :left}

iex> Drafter.Widget.Digits.mount(%{})
%{text: "", style: %{}, align: :left, size: :large, font: nil, renderer: :text, bg_data: nil, color: {0, 150, 255}, bg_min: 0, bg_max: nil}

preferred_height(args, opts)

@spec preferred_height(
  term(),
  keyword()
) :: pos_integer()

The row height of the font opts selects.

opts[:font] wins; otherwise opts[:size] picks :block for :large (the default) and :compact for :small.

iex> Drafter.Widget.Digits.preferred_height("42", size: :small)
3

iex> Drafter.Widget.Digits.preferred_height("42", [])
5

render(state, rect)

@spec render(t(), Drafter.Widget.rect()) :: [Drafter.Draw.Strip.t()]

Draws the large characters into rect.

Returns [] for empty :text. Otherwise it emits one strip per row of the selected font's height, positioned horizontally according to :align. With :bg_data set, each cell also carries the area-chart background colour for its column.

iex> Drafter.Widget.Digits.render(Drafter.Widget.Digits.mount(%{}), %{x: 0, y: 0, width: 20, height: 7})
[]

update(props, state)

@spec update(Drafter.Widget.props(), t()) :: t()

Merges props into state, so every option is live-updatable.

iex> d = Drafter.Widget.Digits.mount(%{text: "1"})
iex> Drafter.Widget.Digits.update(%{text: "2", align: :center}, d).text
"2"

update_props_from_mount(mount_props, existing_state, opts)

@spec update_props_from_mount(Drafter.Widget.props(), t(), keyword()) ::
  Drafter.Widget.props()

Passes every option through to update/2 on a re-render, so nothing about a digits widget is mount-only.