Selkie--Container

NAME

Selkie::Container - Role for widgets that hold child widgets

SYNOPSIS

A minimal custom container that stacks its children vertically with a one-row gap between them:

use Selkie::Widget;
use Selkie::Container;
use Selkie::Sizing;

unit class My::GapBox does Selkie::Container;

method render() {
    my $y = 0;
    for self.children -> $child {
        if $child.plane {
            $child.reposition($y, 0);
            $child.resize($child.sizing.value, self.cols);
        } else {
            $child.init-plane(
                self.plane,
                y => $y, x => 0,
                rows => $child.sizing.value,
                cols => self.cols,
            );
        }
        $child.render;
        $y += $child.sizing.value + 1;   # leave a 1-row gap
    }
    self.clear-dirty;
}

DESCRIPTION

Selkie::Container layers on top of Selkie::Widget (also does Selkie::Widget). Compose it for any widget that owns child widgets — layouts (VBox, HBox, Split), decorators (Border, Modal), scrollers (ScrollView).

The role provides:

  • A children list, manipulated via add, remove, clear

  • Automatic store propagation to added children

  • Recursive destruction and subscription cleanup on remove / clear

  • A focusable-descendants walker so Selkie::App can build the Tab cycle

  • A !render-children helper that cascades dirty flags for correct subtree redraws

Your container's job is to implement render, which positions and sizes each child before rendering it. For typical layouts, lean on VBox/HBox/Split instead of building your own container from scratch.

EXAMPLES

Adding and removing children

my $vbox = Selkie::Layout::VBox.new(sizing => Sizing.flex);
my $header = Selkie::Widget::Text.new(text => 'Hi', sizing => Sizing.fixed(1));
$vbox.add($header);

# Later — remove cleans up the widget's plane, subscriptions, and children
$vbox.remove($header);

Rebuilding from scratch

$vbox.clear;                            # destroys all children
$vbox.add($new-a);
$vbox.add($new-b);

Writing your own container

If the built-in layouts don't fit, compose Selkie::Container directly and implement render. Use !render-children (inherited) to cascade dirty flags and render each child — this ensures subtree correctness when the container is dirty:

method render() {
    self!layout-children;      # your own positioning logic
    self!render-children;      # handles dirty cascade + per-child render
    self.clear-dirty;
}

SEE ALSO

method children

method children() returns List

The current list of children, in insertion order. Immutable list — to modify, use add, remove, or clear.

method add

method add(
    Selkie::Widget $child
) returns Selkie::Widget

Add a child widget. The child's parent is set, the store is propagated to it (and its subtree), and the container is marked dirty. Returns the added child for chaining.

method remove

method remove(
    Selkie::Widget $child
) returns Mu

Remove and destroy a specific child. Unsubscribes the child and its entire subtree from the store before destroying. No-op if the given widget isn't actually a child.

method clear

method clear() returns Mu

Remove and destroy every child. Useful before rebuilding the container's contents from scratch (e.g. in a subscription callback that regenerates a list).

method render-children

method render-children() returns Mu

Render each child, cascading dirty to the whole subtree if the container itself is dirty. This is the rendering helper you almost always want in a custom container's render method — it handles the "parent dirty ⇒ children also need redrawing" rule correctly. Private so composed classes can call it as self!render-children.

method park

method park() returns Mu

Park self plus every child/content recursively. Container override of Widget.park — without this, swapping a container off-screen only moves the container's own plane; descendants whose visibility isn't tied to their parent's plane position (e.g. Image's sprixel, Modal's bg-plane) keep showing on terminal.

method focusable-descendants

method focusable-descendants() returns Seq

Depth-first sequence of focusable descendants. Used by Selkie::App to build the Tab/Shift-Tab cycle. Walks children recursively, yielding any whose focusable is True. Override if your container needs a non-standard traversal order.

method destroy

method destroy() returns Mu

Destroy the container and every child recursively. Called automatically when the widget goes out of scope or its parent calls remove.

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.