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

Selkie v0.16.0

High-level TUI framework built on Notcurses

Authors

  • Matt Doughty

License

Artistic-2.0

Dependencies

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

Test Dependencies

Provides

  • Selkie
  • Selkie::Align
  • Selkie::Alpha
  • Selkie::App
  • Selkie::App::Internal::Animation
  • Selkie::App::Internal::Dispatch
  • Selkie::App::Internal::ErrorLog
  • Selkie::App::Internal::ErrorLogPlatform
  • Selkie::App::Internal::FocusTree
  • Selkie::App::Internal::HitTest
  • Selkie::App::Internal::IdleBudget
  • Selkie::App::Internal::OverlayTree
  • Selkie::App::Internal::PosixFD
  • Selkie::App::Internal::RenderLoop
  • Selkie::App::Internal::ScreenModalLifecycle
  • Selkie::App::Internal::Terminal
  • Selkie::App::Internal::TerminalPlatform
  • Selkie::App::Internal::TerminalReport
  • Selkie::App::Internal::TerminalSequences
  • Selkie::BorderStyle
  • Selkie::Container
  • Selkie::EffectiveBounds
  • Selkie::Event
  • Selkie::Gradient
  • 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::Store::Schema
  • Selkie::Store::Schema::UI
  • Selkie::Style
  • Selkie::Test::Focus
  • Selkie::Test::Keys
  • Selkie::Test::Snapshot
  • Selkie::Test::Snapshot::Harness
  • Selkie::Test::SnapshotPlatform
  • Selkie::Test::Store
  • Selkie::Test::Supply
  • Selkie::Test::Tree
  • Selkie::Theme
  • Selkie::Trace
  • Selkie::Tree
  • Selkie::Tween
  • 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::GradientFill
  • 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
  • X::Selkie::WidgetCycle

Documentation

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

Built with Podlite — the markup and publishing tools behind this site.