Selkie--Layout--Split

NAME

Selkie::Layout::Split - Two-pane layout with a divider

SYNOPSIS

use Selkie::Layout::Split;
use Selkie::Sizing;

my $split = Selkie::Layout::Split.new(
    orientation => 'horizontal',   # left | right
    ratio       => 0.3,            # 30% | 70%
    sizing      => Sizing.flex,
);
$split.set-first($sidebar);
$split.set-second($main);

DESCRIPTION

Split divides its area into exactly two panes with a one-cell divider between them. The ratio attribute controls the split — 0.3 means the first pane takes 30% of the space, the second gets the rest (minus one cell for the divider).

Two orientations:

  • 'horizontal' — left and right panes, divided by a vertical bar

  • 'vertical' — top and bottom panes, divided by a horizontal bar

Unlike VBox/HBox which take a list of children, Split takes exactly two content widgets via set-first and set-second. Each assignment destroys the previous occupant of that slot — use a container widget (like another VBox) on each side if you need more than one widget per pane.

EXAMPLES

Sidebar + main content

A classic two-pane layout with a 25/75 split:

my $split = Selkie::Layout::Split.new(
    orientation => 'horizontal',
    ratio       => 0.25,
    sizing      => Sizing.flex,
);
$split.set-first($sidebar-list);
$split.set-second($detail-view);

Editor + preview (vertical split)

Top half is the editor, bottom half is the live preview:

my $split = Selkie::Layout::Split.new(
    orientation => 'vertical',
    ratio       => 0.5,
    sizing      => Sizing.flex,
);
$split.set-first($editor);
$split.set-second($preview);

Multiple widgets per pane

Wrap each side in its own layout:

my $left = Selkie::Layout::VBox.new(sizing => Sizing.flex);
$left.add($search-input);     # fixed(1)
$left.add($result-list);      # flex

$split.set-first($left);
$split.set-second($details);

SEE ALSO

has Rat $.ratio

The fraction of space given to the first pane. 0.5 is an even split; 0.3 gives 30% to the first pane, 70% to the second. Can be changed at runtime — just mark the Split dirty and re-layout.

has Str $.orientation

Either 'horizontal' (left+right panes, vertical divider) or 'vertical' (top+bottom panes, horizontal divider).

has Selkie::Widget $.first

The first (left or top) pane's widget. Set via set-first.

has Selkie::Widget $.second

The second (right or bottom) pane's widget. Set via set-second.

method set-first

method set-first(
    Selkie::Widget $w
) returns Selkie::Widget

Install a widget in the first pane. The previous occupant (if any) is destroyed. Returns the new widget for chaining.

method set-second

method set-second(
    Selkie::Widget $w
) returns Selkie::Widget

Install a widget in the second pane. The previous occupant is destroyed. Returns the new widget for chaining.

method handle-resize

method handle-resize(
    Int $rows where { ... },
    Int $cols where { ... }
) returns Mu

Re-layout the two panes and the divider when the parent resizes. The split ratio is honoured exactly — first pane gets floor(total * ratio), the divider takes 1 cell, the second gets the remainder. Idempotent on no-size-change calls.

method compute-split-sizes

method compute-split-sizes(
    Int $total where { ... },
    Rat $ratio
) returns Hash

Pure-math helper that computes the split allocation for a given total length and ratio. Returns a Hash with first, divider, second keys — all UInt, all guaranteed non-negative. Exposed at class scope so the boundary math is unit-testable without needing a notcurses context. Used by !layout-split.

method children

method children() returns List

Expose the panes as children so that Container-level cascade helpers (notably !unsubscribe-tree) reach them. Split stores its panes in $!first / $!second rather than the inherited @!children array, so without this override the cascade walks an empty list and leaks subscriptions / bookkeeping for anything inside a pane.

method focusable-descendants

method focusable-descendants() returns Seq

Focusable descendants in stable left-to-right (or top-to-bottom) order — Tab cycles through everything in the first pane, then everything in the second pane. Omits the divider (which is chrome).

method destroy

method destroy() returns Mu

Destroy both panes, the divider plane, and the split's own plane.

Selkie v0.10.0

High-level TUI framework built on Notcurses

Authors

  • Matt Doughty

License

Artistic-2.0

Dependencies

Notcurses::Native:ver<0.4.0+>:auth<zef:apogee>

Test Dependencies

Provides

  • Selkie
  • Selkie::App
  • Selkie::App::Internal::Dispatch
  • Selkie::App::Internal::ErrorLog
  • Selkie::App::Internal::FocusTree
  • Selkie::App::Internal::HitTest
  • Selkie::App::Internal::IdleBudget
  • Selkie::App::Internal::OverlayTree
  • Selkie::App::Internal::RenderLoop
  • Selkie::App::Internal::ScreenModalLifecycle
  • Selkie::App::Internal::Terminal
  • Selkie::App::Internal::TerminalSequences
  • Selkie::Container
  • Selkie::EffectiveBounds
  • Selkie::Event
  • Selkie::Layout::Allocate
  • Selkie::Layout::HBox
  • Selkie::Layout::Split
  • Selkie::Layout::VBox
  • Selkie::Plot::Palette
  • Selkie::Plot::Scaler
  • Selkie::Plot::Ticks
  • Selkie::ScreenManager
  • Selkie::Sizing
  • Selkie::Store
  • Selkie::Style
  • Selkie::Test::Focus
  • Selkie::Test::Keys
  • Selkie::Test::Snapshot
  • Selkie::Test::Snapshot::Harness
  • Selkie::Test::Store
  • Selkie::Test::Supply
  • Selkie::Test::Tree
  • Selkie::Theme
  • Selkie::Trace
  • Selkie::Tree
  • Selkie::Widget
  • Selkie::Widget::Axis
  • Selkie::Widget::BarChart
  • Selkie::Widget::Border
  • Selkie::Widget::Button
  • Selkie::Widget::CardList
  • Selkie::Widget::Checkbox
  • Selkie::Widget::CommandPalette
  • Selkie::Widget::ConfirmModal
  • Selkie::Widget::FileBrowser
  • Selkie::Widget::FocusableByDefault
  • Selkie::Widget::Heatmap
  • Selkie::Widget::HelpOverlay
  • Selkie::Widget::Histogram
  • Selkie::Widget::Image
  • Selkie::Widget::Legend
  • Selkie::Widget::LineChart
  • Selkie::Widget::ListView
  • Selkie::Widget::Modal
  • Selkie::Widget::MultiLineInput
  • Selkie::Widget::PasswordStrength
  • Selkie::Widget::Plot
  • Selkie::Widget::ProgressBar
  • Selkie::Widget::RadioGroup
  • Selkie::Widget::RichText
  • Selkie::Widget::RichText::Span
  • Selkie::Widget::ScatterPlot
  • Selkie::Widget::ScrollView
  • Selkie::Widget::Select
  • Selkie::Widget::Sparkline
  • Selkie::Widget::Spinner
  • Selkie::Widget::TabBar
  • Selkie::Widget::Table
  • Selkie::Widget::Text
  • Selkie::Widget::TextInput
  • Selkie::Widget::TextInput::HighlightSpan
  • Selkie::Widget::TextStream
  • Selkie::Widget::Toast
  • Selkie::Widget::ViewportedCardList

Documentation

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.