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
Selkie::Layout::VBox, Selkie::Layout::HBox ā N-child stacked layouts
Selkie::Theme ā
dividerslot controls divider appearance
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::WidgetInstall 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::WidgetInstall 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 MuRe-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 HashPure-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 ListExpose 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 SeqFocusable 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 MuDestroy both panes, the divider plane, and the split's own plane.