splitpane

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package splitpane is a two-pane split with a draggable divider: two layout.Nodes side by side (Columns) or stacked (Rows), separated by a one-cell divider that the user moves with the keyboard or the mouse. The panes never shrink below their minimum sizes.

The Model owns only the divider position. The panes are layout.Nodes the app supplies (any widget's LayoutNode), drawn by the split's own LayoutNode, which also draws into a cell grid (layout.CellNode). For the mouse, tell the Model where it is drawn with Bounds (see layout.RectOf) and turn Mouse on.

Example

Two panes in 21 columns, the divider moved one cell by the keyboard.

package main

import (
	"fmt"

	"github.com/ows4444/tui"
	"github.com/ows4444/tui/input"
	"github.com/ows4444/tui/layout"
	"github.com/ows4444/tui/splitpane"
)

func main() {
	m := splitpane.New(layout.Block("files"), layout.Block("preview"))
	m.SetTotal(21)
	m.Min1, m.Min2 = 4, 4
	m, _ = m.Update(tui.Key{Type: tui.KeyRight, Mod: input.ModCtrl})
	first, second := m.Sizes()
	fmt.Println(first, second)
}
Output:
11 9

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ChangedMsg

type ChangedMsg struct{ Pos int }

ChangedMsg is delivered (via the Cmd Update returns) when the divider moves. Pos is the new size of the first pane.

type Direction

type Direction int

Direction is how the two panes are arranged.

const (
	// Columns puts the panes side by side with a vertical divider; Pos is
	// the first pane's width. It is the zero value.
	Columns Direction = iota
	// Rows stacks the panes with a horizontal divider; Pos is the first
	// pane's height.
	Rows
)

type KeyMap

type KeyMap struct {
	// Shrink moves the divider toward the first pane (left or up).
	Shrink keymap.Binding
	// Grow moves the divider toward the second pane (right or down).
	Grow keymap.Binding
	// Reset puts the divider back in the middle.
	Reset keymap.Binding
}

KeyMap is the set of keys Update reacts to.

func DefaultKeyMap

func DefaultKeyMap() KeyMap

DefaultKeyMap returns the default bindings: ctrl+left or ctrl+up shrinks the first pane, ctrl+right or ctrl+down grows it, ctrl+e centres the divider.

type Model

type Model struct {
	// First and Second are the panes: left/top and right/bottom.
	First, Second layout.Node
	// Direction is Columns (the zero value) or Rows.
	Direction Direction
	// Min1 and Min2 are the smallest sizes of the first and second pane
	// along the split axis, in cells.
	Min1, Min2 int
	// Step is the cells one Grow or Shrink key moves the divider; 0 means 1.
	Step int
	// Total is the size along the split axis, divider included, used when
	// Bounds is empty. LayoutNode ignores it and uses the Size it is given.
	Total int
	Theme theme.Theme

	// KeyMap holds the key bindings Update obeys. New fills it with
	// DefaultKeyMap; a Model built as a literal with no bindings set behaves
	// as if it held DefaultKeyMap.
	KeyMap KeyMap

	// Mouse, when true, makes Update handle tui.MouseEvent: pressing the
	// divider and dragging moves it. Off (the default) ignores the mouse.
	Mouse bool
	// Bounds is the screen rectangle where the app draws the split; the
	// divider is hit-tested within it, and its extent along the split axis
	// is the Total.
	Bounds hittest.Rect
	// contains filtered or unexported fields
}

Model is a split pane. Pos, the size of the first pane, is kept clamped so that the first pane is at least Min1 and the second at least Min2 cells along the split axis (when both cannot fit, Min1 wins).

func New

func New(first, second layout.Node) Model

New builds a split of first and second, side by side, with the divider in the middle.

func (Model) Bindings

func (m Model) Bindings() []keymap.Binding

Bindings returns the active bindings, for help text.

func (Model) DividerRect

func (m Model) DividerRect() hittest.Rect

DividerRect is the screen rectangle of the divider (one cell wide or tall) within Bounds, or the zero Rect when Bounds is empty.

func (Model) Dragging

func (m Model) Dragging() bool

Dragging reports whether the divider is being dragged.

func (Model) LayoutNode

func (m Model) LayoutNode() layout.Node

LayoutNode adapts the split to a layout.Node (also a layout.CellNode). Measure asks both panes under the constraints and reports the larger cross-axis size and the panes plus divider along the axis; Render and DrawCells fit the allotted Size, clamping the divider to the minimums at that size (Bounds and Total are ignored there). The Model is not changed.

func (Model) Linearize

func (m Model) Linearize() string

Linearize describes the split as plain text for accessible output (see tui.Linearizer): its arrangement and divider position, then each pane's own linear text when it has one, e.g. "Split pane, 2 columns, divider at 30 of 80" followed by "Pane 1:" and "Pane 2:" sections.

func (Model) Pos

func (m Model) Pos() int

Pos returns the first pane's size in cells, clamped to the minimums.

func (*Model) SetPos

func (m *Model) SetPos(p int)

SetPos puts the divider at p cells from the start, clamped to the minimums.

func (Model) SetTheme

func (m Model) SetTheme(t theme.Theme) Model

SetTheme returns m with t applied. It makes Model a tui.ThemeSetter, so a root model can forward the Program's theme (see tui.WithTheme).

func (*Model) SetTotal

func (m *Model) SetTotal(n int)

SetTotal sets Total and re-clamps the divider to it.

func (Model) Sizes

func (m Model) Sizes() (first, second int)

Sizes returns the first and second pane sizes along the split axis; with the one-cell divider they add up to the total.

func (Model) Tokens

func (m Model) Tokens() theme.Tokens

Tokens returns the colour tokens the widget renders with: its theme's roles, overridden by any theme.WithTokens(theme.ComponentSplitPane, ...) and then by WithTokens.

func (Model) Update

func (m Model) Update(msg tui.Msg) (Model, tui.Cmd)

Update moves the divider by Step on the Shrink and Grow bindings and centres it on Reset. With Mouse on, pressing the divider with the left button and dragging moves it; releasing drops it. The divider always stays within the minimums. It returns a Cmd delivering ChangedMsg when the position changed. Any other Msg is a no-op.

func (Model) View

func (m Model) View() string

View renders the split at Bounds' size (or Total by the Bounds' other extent when Bounds is empty, one cell across). Use LayoutNode to place it in a layout.

func (Model) WithTokens

func (m Model) WithTokens(tok theme.Tokens) Model

WithTokens returns m with tok as its per-instance colour override. Nil fields inherit from the theme, so only the roles tok names change; the theme and every other widget are untouched. A second call replaces the first.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL