Selkie--Widget--Spinner

NAME

Selkie::Widget::Spinner - Tiny animated loading indicator

SYNOPSIS

use Selkie::Widget::Spinner;
use Selkie::Sizing;

my $spinner = Selkie::Widget::Spinner.new(sizing => Sizing.fixed(1));

# Drive animation from the main loop's frame callback
$app.on-frame: { $spinner.tick };

DESCRIPTION

A one-cell widget that cycles through a set of spinner frames, giving a lightweight "something is happening" signal. Use it next to a status message during async work, or anywhere you'd reach for a small activity indicator.

Not focusable (it's display-only). Animation is manually advanced via tick β€” call it from $app.on-frame. Throttling is wall-clock based: tick is safe to call many times per second, and the animation advances at most once per interval seconds (default 0.1 = 10fps). This makes the visible rate independent of how often the event loop iterates, which matters on fast-input scenarios (e.g. mouse events flooding the queue).

Several built-in frame sets are provided as class constants:

  • BRAILLE β€” the default; ⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏. Smooth-looking in most terminals.

  • DOTS β€” ⣾⣽⣻Ⓙ⑿⣟⣯⣷. Chunkier braille variant.

  • LINE β€” |/-\. Classic ASCII.

  • CIRCLE β€” ◐◓◑◒. Half-circles rotating.

  • ARROW β€” β†β†–β†‘β†—β†’β†˜β†“β†™. Pointing arrows.

Or pass your own array of strings via frames.

EXAMPLES

Side-by-side with a status message

my $row = Selkie::Layout::HBox.new(sizing => Sizing.fixed(1));
my $spinner = Selkie::Widget::Spinner.new(sizing => Sizing.fixed(2));
my $status  = Selkie::Widget::Text.new(text => 'Loading...', sizing => Sizing.flex);
$row.add($spinner);
$row.add($status);
$app.on-frame: { $spinner.tick };

Hide when idle

Spinners look confusing when they're still animating in an idle app. Toggle visibility by swapping between the spinner and an empty Text:

$app.store.subscribe-with-callback(
    'job-running',
    -> $s { $s.get-in('job', 'running') // False },
    -> Bool $running {
        # Repoint $row's first child to spinner-or-blank
        ...
    },
    $row,
);

Simpler: just stop calling tick when idle. The spinner freezes on its last frame rather than disappearing β€” fine for many use cases.

Custom frame set

my $custom = Selkie::Widget::Spinner.new(
    frames   => <β£€ ⣄ β£€ ⣦ β£Ά β£· β£Ώ>,
    interval => 0.05,     # 20fps β€” snappy
    sizing   => Sizing.fixed(1),
);

SEE ALSO

has Positional @.frames

Classic braille spinner β€” the default frame set. Chunkier filled-braille set. ASCII vertical bar / slash rotation. Rotating half-circles. Rotating arrow octants. The array of strings to cycle through. Defaults to BRAILLE.

has Real $.interval

Minimum wall-clock interval between frame advances, in seconds. Default 0.1 = 10fps, which looks smooth without being distracting. Higher values give a calmer spinner; lower values a faster one.

has Selkie::Style $.style

Optional style override for the rendered character. If undefined, the theme's text-highlight slot is used.

method new

method new(
    *%args
) returns Selkie::Widget::Spinner

Constructor. Defaults focusable to False (the spinner is display-only). Common attributes: :frames (override the frame set), :interval (advance throttle, default 0.1s), :style.

method tick

method tick() returns Mu

Advance the animation if at least interval seconds have passed since the previous advance. Call from $app.on-frame. Safe to call many times per second β€” the wall-clock check throttles so the animation rate is independent of how often the event loop iterates.

method reset

method reset() returns Mu

Reset to the first frame. Useful when starting a new operation to give a consistent visual cue.

method current-frame

method current-frame() returns Str

The current frame string. Useful if you want to render the spinner yourself somewhere else.

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.