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