1package Term::Choose::Opt::SkipItems; 2 3use warnings; 4use strict; 5use 5.10.0; 6 7our $VERSION = '1.745'; 8 9use Term::Choose::Constants qw( :all ); 10 11 12sub __key_skipped { 13 my ( $self ) = @_; 14 my $pressed_key = $self->{pressed_key}; 15 if ( ! defined $pressed_key ) { 16 return; 17 } 18 elsif ( $pressed_key == VK_DOWN || $pressed_key == KEY_j ) { 19 my $new_row = $self->Term::Choose::Opt::SkipItems::__next_valid_down(); 20 if ( defined $new_row ) { 21 if ( $new_row > $self->{last_page_row} ) { 22 $self->__set_cell( $self->{rc2idx}[$new_row][$self->{pos}[COL]] ); 23 $self->__wr_screen(); 24 } 25 else { 26 my $old_row = $self->{pos}[ROW]; 27 $self->{pos}[ROW] = $new_row; 28 $self->__wr_cell( $old_row, $self->{pos}[COL] ); 29 $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); 30 } 31 return; 32 } 33 else { 34 return VK_UP; 35 } 36 } 37 elsif ( $pressed_key == VK_UP || $pressed_key == KEY_k ) { 38 my $new_row = $self->Term::Choose::Opt::SkipItems::__next_valid_up(); 39 if ( defined $new_row ) { 40 if ( $new_row < $self->{first_page_row} ) { 41 $self->__set_cell( $self->{rc2idx}[$new_row][$self->{pos}[COL]] ); 42 $self->__wr_screen(); 43 } 44 else { 45 my $old_row = $self->{pos}[ROW]; 46 $self->{pos}[ROW] = $new_row; 47 $self->__wr_cell( $old_row, $self->{pos}[COL] ); 48 $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); 49 } 50 return; 51 } 52 else { 53 return VK_DOWN; 54 } 55 } 56 elsif ( $pressed_key == VK_RIGHT || $pressed_key == KEY_l ) { 57 my $new_col = $self->Term::Choose::Opt::SkipItems::__next_valid_right(); 58 if ( defined $new_col ) { 59 my $old_col = $self->{pos}[COL]; 60 $self->{pos}[COL] = $new_col; 61 $self->__wr_cell( $self->{pos}[ROW], $old_col ); 62 $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); 63 } 64 else { 65 return VK_LEFT; 66 } 67 } 68 elsif ( $pressed_key == VK_LEFT || $pressed_key == KEY_h ) { 69 my $new_col = $self->Term::Choose::Opt::SkipItems::__next_valid_left(); 70 if ( defined $new_col ) { 71 my $old_col = $self->{pos}[COL]; 72 $self->{pos}[COL] = $new_col; 73 $self->__wr_cell( $self->{pos}[ROW], $old_col ); 74 $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); 75 } 76 else { 77 return VK_RIGHT; 78 } 79 } 80 elsif ( $pressed_key == KEY_TAB || $pressed_key == CONTROL_I ) { 81 my ( $new_row, $new_col ) = $self->Term::Choose::Opt::SkipItems::__next_valid_right_down(); 82 if ( defined $new_row && defined $new_col ) { 83 if ( $new_row > $self->{last_page_row} ) { 84 $self->__set_cell( $self->{rc2idx}[$new_row][$new_col] ); 85 $self->__wr_screen(); 86 } 87 else { 88 my $old_row = $self->{pos}[ROW]; 89 my $old_col = $self->{pos}[COL]; 90 $self->{pos}[ROW] = $new_row; 91 $self->{pos}[COL] = $new_col; 92 $self->__wr_cell( $old_row , $old_col ); 93 $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); 94 } 95 } 96 else { 97 return KEY_BSPACE; 98 } 99 } 100 elsif ( $pressed_key == KEY_BSPACE || $pressed_key == CONTROL_H || $pressed_key == KEY_BTAB ) { 101 my ( $new_row, $new_col ) = $self->Term::Choose::Opt::SkipItems::__next_valid_left_up(); 102 if ( defined $new_row && defined $new_col ) { 103 if ( $new_row < $self->{first_page_row} ) { 104 $self->__set_cell( $self->{rc2idx}[$new_row][$new_col] ); 105 $self->__wr_screen(); 106 } 107 else { 108 my $old_row = $self->{pos}[ROW]; 109 my $old_col = $self->{pos}[COL]; 110 $self->{pos}[ROW] = $new_row; 111 $self->{pos}[COL] = $new_col; 112 $self->__wr_cell( $old_row , $old_col ); 113 $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); 114 } 115 } 116 else { 117 return KEY_TAB; 118 } 119 } 120 elsif ( $pressed_key == VK_PAGE_DOWN || $pressed_key == CONTROL_F ) { 121 my $id = $self->Term::Choose::Opt::SkipItems::__next_valid_id_up_or_down(); 122 if ( ! defined $id ) { 123 $id = $self->Term::Choose::Opt::SkipItems::__closest_valid_id_within_page(); 124 } 125 if ( ! defined $id ) { 126 $id = $self->Term::Choose::Opt::SkipItems::__next_valid_id_from_next_page_to_end_page(); 127 } 128 if ( defined $id ) { 129 $self->__set_cell( $id ); 130 $self->__wr_screen(); 131 return 132 } 133 $self->__beep(); 134 return VK_PAGE_UP; 135 } 136 elsif ( $pressed_key == VK_PAGE_UP || $pressed_key == CONTROL_B ) { 137 my $id = $self->Term::Choose::Opt::SkipItems::__next_valid_id_up_or_down(); 138 if ( ! defined $id ) { 139 $id = $self->Term::Choose::Opt::SkipItems::__closest_valid_id_within_page(); 140 } 141 if ( ! defined $id ) { 142 $id = $self->Term::Choose::Opt::SkipItems::__next_valid_id_from_previous_page_to_first_page(); 143 } 144 if ( defined $id ) { 145 $self->__set_cell( $id ); 146 $self->__wr_screen(); 147 return 148 } 149 $self->__beep(); 150 return VK_PAGE_DOWN; 151 } 152 elsif ( $pressed_key == VK_HOME || $pressed_key == CONTROL_A ) { 153 my $id = $self->Term::Choose::Opt::SkipItems::__first_valid_id(); 154 if ( defined $id ) { 155 $self->__set_cell( $id ); 156 $self->__wr_screen(); 157 return 158 } 159 $self->__beep(); 160 return; 161 } 162 elsif ( $pressed_key == VK_END || $pressed_key == CONTROL_E ) { 163 my $id = $self->Term::Choose::Opt::SkipItems::__last_valid_id(); 164 if ( defined $id ) { 165 $self->__set_cell( $id ); 166 $self->__wr_screen(); 167 return 168 } 169 $self->__beep(); 170 return; 171 } 172 return; 173} 174 175 176sub __next_valid_down { 177 my ( $self ) = @_; 178 my $last_row = $#{$self->{rc2idx}}; 179 my $row = $self->{pos}[ROW]; 180 my $col = $self->{pos}[COL]; 181 if ( $col > $self->{idx_of_last_col_in_last_row} ) { 182 $last_row--; 183 } 184 while ( ++$row <= $last_row ) { 185 if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) { 186 return $row; 187 } 188 } 189 return; 190} 191 192 193sub __next_valid_up { 194 my ( $self ) = @_; 195 my $first_row = 0; 196 my $row = $self->{pos}[ROW]; 197 my $col = $self->{pos}[COL]; 198 while ( --$row >= $first_row ) { 199 if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) { 200 return $row; 201 } 202 } 203 return; 204} 205 206 207sub __next_valid_right { 208 my ( $self ) = @_; 209 my $last_col = $#{$self->{rc2idx}[$self->{pos}[ROW]]}; 210 my $row = $self->{pos}[ROW]; 211 my $col = $self->{pos}[COL]; 212 while ( ++$col <= $last_col ) { 213 if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) { 214 return $col; 215 } 216 } 217 return; 218} 219 220 221sub __next_valid_left { 222 my ( $self ) = @_; 223 my $first_col = 0; 224 my $row = $self->{pos}[ROW]; 225 my $col = $self->{pos}[COL]; 226 while ( --$col >= $first_col ) { 227 if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) { 228 return $col; 229 } 230 } 231 return; 232} 233 234 235sub __next_valid_right_down { 236 my ( $self ) = @_; 237 my $last_row = $#{$self->{rc2idx}}; 238 my $row = $self->{pos}[ROW]; 239 my $col = $self->{pos}[COL] + 1; 240 while ( $row <= $last_row ) { 241 my $last_col = $#{$self->{rc2idx}[$row]}; 242 while ( $col <= $last_col ) { 243 if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) { 244 return $row, $col; 245 } 246 ++$col; 247 } 248 ++$row; 249 $col = 0; 250 } 251 return; 252} 253 254 255sub __next_valid_left_up { 256 my ( $self ) = @_; 257 my $first_row = 0; 258 my $first_col = 0; 259 my $row = $self->{pos}[ROW]; 260 my $col = $self->{pos}[COL] - 1; 261 while ( $row >= $first_row ) { 262 while ( $col >= $first_col ) { 263 if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) { 264 return $row, $col; 265 } 266 --$col; 267 } 268 --$row; 269 $col = $#{$self->{rc2idx}[$row]}; 270 } 271 return; 272} 273 274 275sub __next_valid_id_up_or_down { 276 my ( $self ) = @_; 277 my $begin = $self->{first_page_row}; 278 my $end = $self->{last_page_row}; 279 my $row = $self->{pos}[ROW]; 280 my $col = $self->{pos}[COL]; 281 if ( $end == $#{$self->{rc2idx}} && $col > $self->{idx_of_last_col_in_last_row} ) { 282 $end--; 283 } 284 my ( $row_up, $row_down ) = ( $row, $row ); 285 while ( 1 ) { 286 --$row_up; 287 ++$row_down; 288 if ( $row_up >= $begin ) { 289 my $id = $self->{rc2idx}[$row_up][$col]; 290 if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) { 291 return $id; 292 } 293 } 294 elsif ( $row_down <= $end ) { 295 my $id = $self->{rc2idx}[$row_down][$col]; 296 if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) { 297 return $id; 298 } 299 } 300 else { 301 return; 302 } 303 } 304} 305 306 307sub __closest_valid_id_within_page { 308 my ( $self ) = @_; 309 return $self->Term::Choose::Opt::SkipItems::__next_valid_id( 310 $self->{rc2idx}[$self->{first_page_row}][ 0 ], 311 $self->{rc2idx}[$self->{last_page_row} ][-1 ], 312 $self->{rc2idx}[$self->{pos}[ROW]] [$self->{pos}[COL]] 313 ); 314} 315 316 317sub __next_valid_id_from_next_page_to_end_page { 318 my ( $self ) = @_; 319 for my $row ( $self->{last_page_row} + 1 .. $#{$self->{rc2idx}} ) { 320 for my $col ( 0 .. $#{$self->{rc2idx}[$row]} ) { 321 my $id = $self->{rc2idx}[$row][$col]; 322 if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) { 323 return $id; 324 } 325 } 326 } 327 return; 328} 329 330 331sub __next_valid_id_from_previous_page_to_first_page { 332 my ( $self ) = @_; 333 for my $row ( reverse( 0 .. $self->{first_page_row} - 1 ) ) { 334 for my $col ( reverse( 0 .. $#{$self->{rc2idx}[$row]} ) ) { 335 my $id = $self->{rc2idx}[$row][$col]; 336 if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) { 337 return $id; 338 } 339 } 340 } 341 return; # 342} 343 344 345sub __first_valid_id { 346 my ( $self ) = @_; 347 for my $id ( 0 .. $#{$self->{list}} ) { 348 if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) { 349 return $id; 350 } 351 } 352 return; 353} 354 355 356sub __last_valid_id { 357 my ( $self ) = @_; 358 for my $id ( reverse( 0 .. $#{$self->{list}} ) ) { 359 if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) { 360 return $id; 361 } 362 } 363 return; 364} 365 366 367sub __next_valid_id { 368 my ( $self, $begin, $end, $id ) = @_; 369 my ( $id_up, $id_down ) = ( $id, $id ); 370 while ( 1 ) { 371 --$id_up; 372 ++$id_down; 373 if ( $id_up >= $begin ) { 374 return $id_up if $self->{list}[$id_up] !~ /$self->{skip_items}/; 375 } 376 elsif ( $id_down <= $end ) { 377 return $id_down if $self->{list}[$id_down] !~ /$self->{skip_items}/; 378 } 379 else { 380 return; 381 } 382 } 383} 384 385 386sub __prepare_default { 387 my ( $self ) = @_; 388 if ( $self->{list}[$self->{default} || 0] =~ /$self->{skip_items}/ ) { 389 $self->{default} = $self->Term::Choose::Opt::SkipItems::__next_valid_id( 390 0, 391 $#{$self->{list}}, 392 $self->{default} || 0 393 ); 394 } 395} 396 397 398sub __unmark_skip_items { 399 my ( $self ) = @_; 400 for my $row ( 0 .. $#{$self->{rc2idx}} ) { 401 for my $col ( 0 .. $#{$self->{rc2idx}[$row]} ) { 402 if ( $self->{marked}[$row][$col] && $self->{list}[ $self->{rc2idx}[$row][$col] ] =~ /$self->{skip_items}/ ) { 403 $self->{marked}[$row][$col] = 0; 404 } 405 } 406 } 407} 408 409 410 411 4121; 413 414__END__ 415