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

val layer: fn(
  ?#width: &Constraint,
  ?#height: &Constraint,
  ?#size: &[Size, null],
  child: Tui
) -> Layer;

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
  • 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;
use tui::block::{self, *};
use tui::input_handler::{self, *};
use tui::overlay::{self, *};
use tui::paragraph::{self, *};

let open = false;

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

let handle_modal = |e: Event| -> [`Stop, `Continue] select e {
  `Key(k) => select k.kind {
    `Press => select k.code {
      c@ `Esc => {
        open <- c ~ false;
        `Stop
      },
      _ => `Continue
    },
    _ => `Continue
  },
  _ => `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<overlay::Layer> = select open {
  true => [modal],
  false => []
};

overlay(#layers: &layers, base)