1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
# (C) Paul Evans, 2013-2023 -- leonerd@leonerd.org.uk
use v5.20;
use warnings;
use Object::Pad 0.807;
package Tickit::Widget::Spinner 0.42;
class Tickit::Widget::Spinner :strict(params);
inherit Tickit::Widget;
use experimental 'postderef';
use Tickit::Style;
use List::Util qw( max );
use Tickit::Utils qw( textwidth );
=head1 NAME
C<Tickit::Widget::Spinner> - a widget displaying a small text animation
=head1 SYNOPSIS
use Tickit;
use Tickit::Widget::Spinner;
my $spinner = Tickit::Widget::Spinner->new(
chars => [ "<X> ", " <X> ", " <X>", "> <X", "X> <" ],
);
Tickit->new( root => $spinner )->run;
=head1 DESCRIPTION
This class provides a widget which displays a simple animation, cycling
through a fixed set of strings with a fixed interval.
=head1 STYLE
The default style pen is used as the widget pen.
=cut
use constant WIDGET_PEN_FROM_STYLE => 1;
=head1 CONSTRUCTOR
=cut
=head2 new
$spinner = Tickit::Widget::Spinner->new( %args );
Constructs a new C<Tickit::Widget::Spinner> object.
Takes the following named arguments:
=over 8
=item chars => ARRAY
Optional. An ARRAY reference containing the text strings to use.
=item interval => NUM
Optional. The time each string is displayed for. Defaults to 0.5.
=back
=cut
field @_chars;
field $_state = 0;
field $_interval :param //= 0.5;
field $_cols;
ADJUST :params (
:$chars = [qw( - \ | / )],
) {
@_chars = $chars->@*;
$_cols = max map { textwidth $_ } @_chars;
}
field $_running;
field $_x;
field $_y;
field $_rect;
=head1 METHODS
=cut
method lines
{
return 1;
}
method cols
{
return $_cols;
}
=head2 start
$spinner->start;
Starts the animation effect.
=cut
method start
{
return if $_running;
$_running = 1;
$self->tick;
}
=head2 stop
$spinner->stop;
Stops the animation effect.
=cut
method stop
{
$_running = 0;
}
method window_gained
{
$self->SUPER::window_gained( @_ );
$self->start;
}
# precache position
method reshape
{
my $win = $self->window or return;
( $_x, $_y ) = map int($_ / 2), $win->cols - $self->cols, $win->lines - $self->lines;
$_rect = Tickit::Rect->new(
top => $_y,
left => $_x,
lines => $self->lines,
cols => $self->cols,
);
}
method tick
{
return unless $_running;
my $state = $_state++;
$_state %= @_chars;
if( my $win = $self->window ) {
$win->tickit->timer( after => $_interval => sub { $self->tick } );
$win->expose( $_rect );
}
}
method render_to_rb
{
my ( $rb, $rect ) = @_;
$rb->eraserect( $rect );
$rb->text_at( $_y, $_x, $_chars[$_state] );
}
=head1 AUTHOR
Paul Evans <leonerd@leonerd.org.uk>
=cut
0x55AA;
|