The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

use strict;
use 5.10.0;
our $VERSION = '1.769';
use Term::Choose::Constants qw( :all );
sub __key_skipped {
my ( $self ) = @_;
my $pressed_key = $self->{pressed_key};
if ( ! defined $pressed_key ) {
return;
}
elsif ( $pressed_key == VK_DOWN || $pressed_key == KEY_j ) {
my $new_row = $self->Term::Choose::Opt::SkipItems::__next_valid_down();
if ( defined $new_row ) {
if ( $new_row > $self->{last_page_row} ) {
$self->__set_cell( $self->{rc2idx}[$new_row][$self->{pos}[COL]] );
$self->__wr_screen();
}
else {
my $old_row = $self->{pos}[ROW];
$self->{pos}[ROW] = $new_row;
$self->__wr_cell( $old_row, $self->{pos}[COL] );
$self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] );
}
return;
}
else {
return VK_UP;
}
}
elsif ( $pressed_key == VK_UP || $pressed_key == KEY_k ) {
my $new_row = $self->Term::Choose::Opt::SkipItems::__next_valid_up();
if ( defined $new_row ) {
if ( $new_row < $self->{first_page_row} ) {
$self->__set_cell( $self->{rc2idx}[$new_row][$self->{pos}[COL]] );
$self->__wr_screen();
}
else {
my $old_row = $self->{pos}[ROW];
$self->{pos}[ROW] = $new_row;
$self->__wr_cell( $old_row, $self->{pos}[COL] );
$self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] );
}
return;
}
else {
return VK_DOWN;
}
}
elsif ( $pressed_key == VK_RIGHT || $pressed_key == KEY_l ) {
my $new_col = $self->Term::Choose::Opt::SkipItems::__next_valid_right();
if ( defined $new_col ) {
my $old_col = $self->{pos}[COL];
$self->{pos}[COL] = $new_col;
$self->__wr_cell( $self->{pos}[ROW], $old_col );
$self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] );
}
else {
return VK_LEFT;
}
}
elsif ( $pressed_key == VK_LEFT || $pressed_key == KEY_h ) {
my $new_col = $self->Term::Choose::Opt::SkipItems::__next_valid_left();
if ( defined $new_col ) {
my $old_col = $self->{pos}[COL];
$self->{pos}[COL] = $new_col;
$self->__wr_cell( $self->{pos}[ROW], $old_col );
$self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] );
}
else {
return VK_RIGHT;
}
}
elsif ( $pressed_key == KEY_TAB || $pressed_key == CONTROL_I ) {
my ( $new_row, $new_col ) = $self->Term::Choose::Opt::SkipItems::__next_valid_right_down();
if ( defined $new_row && defined $new_col ) {
if ( $new_row > $self->{last_page_row} ) {
$self->__set_cell( $self->{rc2idx}[$new_row][$new_col] );
$self->__wr_screen();
}
else {
my $old_row = $self->{pos}[ROW];
my $old_col = $self->{pos}[COL];
$self->{pos}[ROW] = $new_row;
$self->{pos}[COL] = $new_col;
$self->__wr_cell( $old_row , $old_col );
$self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] );
}
}
else {
return KEY_BSPACE;
}
}
elsif ( $pressed_key == KEY_BSPACE || $pressed_key == CONTROL_H || $pressed_key == KEY_BTAB ) {
my ( $new_row, $new_col ) = $self->Term::Choose::Opt::SkipItems::__next_valid_left_up();
if ( defined $new_row && defined $new_col ) {
if ( $new_row < $self->{first_page_row} ) {
$self->__set_cell( $self->{rc2idx}[$new_row][$new_col] );
$self->__wr_screen();
}
else {
my $old_row = $self->{pos}[ROW];
my $old_col = $self->{pos}[COL];
$self->{pos}[ROW] = $new_row;
$self->{pos}[COL] = $new_col;
$self->__wr_cell( $old_row , $old_col );
$self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] );
}
}
else {
return KEY_TAB;
}
}
elsif ( $pressed_key == VK_PAGE_DOWN || $pressed_key == CONTROL_F ) {
my $id = $self->Term::Choose::Opt::SkipItems::__next_valid_id_up_or_down();
if ( ! defined $id ) {
$id = $self->Term::Choose::Opt::SkipItems::__closest_valid_id_within_page();
}
if ( ! defined $id ) {
$id = $self->Term::Choose::Opt::SkipItems::__next_valid_id_from_next_page_to_end_page();
}
if ( defined $id ) {
$self->__set_cell( $id );
$self->__wr_screen();
return
}
$self->__beep();
return VK_PAGE_UP;
}
elsif ( $pressed_key == VK_PAGE_UP || $pressed_key == CONTROL_B ) {
my $id = $self->Term::Choose::Opt::SkipItems::__next_valid_id_up_or_down();
if ( ! defined $id ) {
$id = $self->Term::Choose::Opt::SkipItems::__closest_valid_id_within_page();
}
if ( ! defined $id ) {
$id = $self->Term::Choose::Opt::SkipItems::__next_valid_id_from_previous_page_to_first_page();
}
if ( defined $id ) {
$self->__set_cell( $id );
$self->__wr_screen();
return
}
$self->__beep();
return VK_PAGE_DOWN;
}
elsif ( $pressed_key == VK_HOME || $pressed_key == CONTROL_A ) {
my $id = $self->Term::Choose::Opt::SkipItems::__first_valid_id();
if ( defined $id ) {
$self->__set_cell( $id );
$self->__wr_screen();
return
}
$self->__beep();
return;
}
elsif ( $pressed_key == VK_END || $pressed_key == CONTROL_E ) {
my $id = $self->Term::Choose::Opt::SkipItems::__last_valid_id();
if ( defined $id ) {
$self->__set_cell( $id );
$self->__wr_screen();
return
}
$self->__beep();
return;
}
return;
}
sub __next_valid_down {
my ( $self ) = @_;
my $last_row = $#{$self->{rc2idx}};
my $row = $self->{pos}[ROW];
my $col = $self->{pos}[COL];
if ( $col > $self->{idx_of_last_col_in_last_row} ) {
$last_row--;
}
while ( ++$row <= $last_row ) {
if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) {
return $row;
}
}
return;
}
sub __next_valid_up {
my ( $self ) = @_;
my $first_row = 0;
my $row = $self->{pos}[ROW];
my $col = $self->{pos}[COL];
while ( --$row >= $first_row ) {
if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) {
return $row;
}
}
return;
}
sub __next_valid_right {
my ( $self ) = @_;
my $last_col = $#{$self->{rc2idx}[$self->{pos}[ROW]]};
my $row = $self->{pos}[ROW];
my $col = $self->{pos}[COL];
while ( ++$col <= $last_col ) {
if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) {
return $col;
}
}
return;
}
sub __next_valid_left {
my ( $self ) = @_;
my $first_col = 0;
my $row = $self->{pos}[ROW];
my $col = $self->{pos}[COL];
while ( --$col >= $first_col ) {
if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) {
return $col;
}
}
return;
}
sub __next_valid_right_down {
my ( $self ) = @_;
my $last_row = $#{$self->{rc2idx}};
my $row = $self->{pos}[ROW];
my $col = $self->{pos}[COL] + 1;
while ( $row <= $last_row ) {
my $last_col = $#{$self->{rc2idx}[$row]};
while ( $col <= $last_col ) {
if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) {
return $row, $col;
}
++$col;
}
++$row;
$col = 0;
}
return;
}
sub __next_valid_left_up {
my ( $self ) = @_;
my $first_row = 0;
my $first_col = 0;
my $row = $self->{pos}[ROW];
my $col = $self->{pos}[COL] - 1;
while ( $row >= $first_row ) {
while ( $col >= $first_col ) {
if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) {
return $row, $col;
}
--$col;
}
--$row;
$col = $#{$self->{rc2idx}[$row]};
}
return;
}
sub __next_valid_id_up_or_down {
my ( $self ) = @_;
my $begin = $self->{first_page_row};
my $end = $self->{last_page_row};
my $row = $self->{pos}[ROW];
my $col = $self->{pos}[COL];
if ( $end == $#{$self->{rc2idx}} && $col > $self->{idx_of_last_col_in_last_row} ) {
$end--;
}
my ( $row_up, $row_down ) = ( $row, $row );
while ( 1 ) {
--$row_up;
++$row_down;
if ( $row_up >= $begin ) {
my $id = $self->{rc2idx}[$row_up][$col];
if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) {
return $id;
}
}
elsif ( $row_down <= $end ) {
my $id = $self->{rc2idx}[$row_down][$col];
if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) {
return $id;
}
}
else {
return;
}
}
}
sub __closest_valid_id_within_page {
my ( $self ) = @_;
return $self->Term::Choose::Opt::SkipItems::__next_valid_id(
$self->{rc2idx}[$self->{first_page_row}][ 0 ],
$self->{rc2idx}[$self->{last_page_row} ][-1 ],
$self->{rc2idx}[$self->{pos}[ROW]] [$self->{pos}[COL]]
);
}
sub __next_valid_id_from_next_page_to_end_page {
my ( $self ) = @_;
for my $row ( $self->{last_page_row} + 1 .. $#{$self->{rc2idx}} ) {
for my $col ( 0 .. $#{$self->{rc2idx}[$row]} ) {
my $id = $self->{rc2idx}[$row][$col];
if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) {
return $id;
}
}
}
return;
}
sub __next_valid_id_from_previous_page_to_first_page {
my ( $self ) = @_;
for my $row ( reverse( 0 .. $self->{first_page_row} - 1 ) ) {
for my $col ( reverse( 0 .. $#{$self->{rc2idx}[$row]} ) ) {
my $id = $self->{rc2idx}[$row][$col];
if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) {
return $id;
}
}
}
return; #
}
sub __first_valid_id {
my ( $self ) = @_;
for my $id ( 0 .. $#{$self->{list}} ) {
if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) {
return $id;
}
}
return;
}
sub __last_valid_id {
my ( $self ) = @_;
for my $id ( reverse( 0 .. $#{$self->{list}} ) ) {
if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) {
return $id;
}
}
return;
}
sub __next_valid_id {
my ( $self, $begin, $end, $id ) = @_;
my ( $id_up, $id_down ) = ( $id, $id );
while ( 1 ) {
--$id_up;
++$id_down;
if ( $id_up >= $begin ) {
return $id_up if $self->{list}[$id_up] !~ /$self->{skip_items}/;
}
elsif ( $id_down <= $end ) {
return $id_down if $self->{list}[$id_down] !~ /$self->{skip_items}/;
}
else {
return;
}
}
}
sub __prepare_default {
my ( $self ) = @_;
if ( $self->{list}[$self->{default} || 0] =~ /$self->{skip_items}/ ) {
$self->{default} = $self->Term::Choose::Opt::SkipItems::__next_valid_id(
0,
$#{$self->{list}},
$self->{default} || 0
);
}
}
sub __unmark_skip_items {
my ( $self ) = @_;
for my $row ( 0 .. $#{$self->{rc2idx}} ) {
for my $col ( 0 .. $#{$self->{rc2idx}[$row]} ) {
if ( $self->{marked}[$row][$col] && $self->{list}[ $self->{rc2idx}[$row][$col] ] =~ /$self->{skip_items}/ ) {
$self->{marked}[$row][$col] = 0;
}
}
}
}
1;
__END__