Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The Overlay Widget

The overlay widget draws a reactive stack of layers over a base widget — the modal and popup primitive. Each layer is centered, sized by its constraints, and cleared before it draws, so the base never bleeds through. While any layer is up, the topmost layer captures all input; when the layers array is empty, the overlay is just its base. Open a modal by pushing a layer, close it by popping it — in practice, by deriving the layers array from your state with select.

Interface

use super::{Constraint, Size, Tui};
/// One stacked layer: a widget drawn over the base in a cleared,
/// centered rectangle sized by its constraints.
type Layer = {
  child: Tui,
  width: &Constraint,
  height: &Constraint,
  size: [&mut Size, null]
};

/// Build a layer. Defaults to 60% of the overlay area in each axis.
/// `#size` observes the rectangle the layer was actually given, like
/// `layout::child`'s.
val layer: fn(
  ?#width: &Constraint,
  ?#height: &Constraint,
  ?#size: [&mut Size, null],
  child: Tui
) -> Layer;

type Overlay = {
  base: Tui,
  layers: &Array<Layer>
};

/// The base widget with a reactive stack of layers drawn over it, in
/// order — the modal/popup primitive. Each layer is centered, sized by
/// its constraints, and cleared before it draws, so the base never
/// bleeds through. Input goes to the TOPMOST layer while any layer is
/// up and to the base otherwise; an empty `layers` array is just the
/// base. Push a layer to open a modal, pop it to close.
val overlay: fn(#layers: &Array<Layer>, base: Tui) -> Tui;

Parameters

layer

  • width - Horizontal size of the layer, as a layout Constraint (default `Percentage(60))
  • height - Vertical size (default `Percentage(60))
  • size - Observes the rectangle the layer was actually given, like layout::child’s; pass &mut size where size: tui::Size
  • child - The widget drawn in the layer

overlay

  • layers - The stack of layers, drawn in order; the last is topmost and captures input
  • base - The widget under the stack

Example

A modal opened with o and closed with Esc. While it is up, its input handler sees every key; the base handler sees none.

use tui::{
  line,
  block::block,
  input_handler::{Event, input_handler, on_press},
  overlay::{Layer, layer, overlay},
  paragraph::paragraph
};

let open = false;

let handle_base = |e: Event| on_press(e, |k| select k.code {
  c@ `Char("o") => {
    open <- c ~ true;
    `Stop
  },
  _ => `Continue
});

let handle_modal = |e: Event| on_press(e, |k| select k.code {
  c@ `Esc => {
    open <- c ~ false;
    `Stop
  },
  _ => `Continue
});

let base = input_handler(
  #handle: &handle_base,
  &block(
    #border: &`All,
    #title: &line("press o to open the modal"),
    &paragraph(&"base content")
  )
);

let modal = layer(
  #width: &`Percentage(50),
  #height: &`Percentage(30),
  input_handler(
    #handle: &handle_modal,
    &block(
      #border: &`All,
      #title: &line("modal, Esc closes"),
      &paragraph(&"while this is up, it captures all input")
    )
  )
);

let layers: Array<Layer> = select open {
  true => [modal],
  false => []
};

overlay(#layers: &layers, base)