Skip to content
Jakub Sobon edited this page Mar 3, 2019 · 22 revisions

Container API

Doc Status

The container package is used to establish and mutate the layout of the terminal. An instance of the container object is required to start the Termdash application, see the Termdash API for details.

The container splits the raw terminal into smaller portions (sub-containers). The developer decides how the splits are organized. Design of the container object is heavily inspired by the i3 window manager, specifically by how the i3 wm organizes the layout of application windows on the screen.

Developers can also use the container to customize the look of the Termdash application.

Apart from organising the terminal layout, the Termdash infrastructure uses the container to call the Draw method on all placed widgets and to map virtual canvases given to widgets onto the raw terminal. The container is also responsible for distributing events to individual widgets.

Terminal layout

Layout of the terminal is organized in a binary tree structure. Each container is a node in this tree. Unless the node was created empty, it contains one of the following:

  • two sub-containers; OR
  • a widget.

Given a container, developers can create sub-containers by splitting the container. There are two kinds of splits:

  • horizontal split, which creates top and bottom sub-containers.
  • vertical split, which creates left and right sub-containers.

This property is recursive, meaning developers can further split the sub-containers using the same rules. The following diagram demonstrates how splits are utilized to create a layout.

The container.New function is used to constract a container. The API of this function uses a recursive builder patters, the complete layout of all the containers in the tree is established in a single call.

To create the terminal layout indicated in the diagram above, the developer can use the following call:

tb, err := termbox.New()
if err != nil {
  return fmt.Errorf("termbox.New => %v", err)
}

if _, err := container.New(
    tb,
    container.SplitVertical(
        container.Left(),                     // Container is empty.
        container.Right(
            container.SplitHorizontal(
                container.Top()               // Container is empty.
                container.Bottom(
                    container.SplitVertical(
                        container.Left(),     // Container is empty.
                        container.Right(),    // Container is empty.
                    ),
                ),
            ),
        ),
    ),
); err != nil {
    panic(err)
}

Splitting a container

A container can either be split vertically or horizontally.

The container.SplitHorizontal option splits the current container into two sub-containers:

The container.SplitVertical option splits the current container into two sub-containers:

The container.SplitPercent option is used to specify at what percentage to perform the split. I.e. the percentage of the containers width (when splitting vertically) or height (when splitting horizontally).

The default value of the split is defined as a package constant.

Clone this wiki locally