File Coverage

blib/lib/Term/Form.pm
Criterion Covered Total %
statement 48 769 6.2
branch 3 310 0.9
condition 0 86 0.0
subroutine 15 64 23.4
pod 2 2 100.0
total 68 1231 5.5


line stmt bran cond sub pod time code
1             package Term::Form;
2              
3 3     3   319495 use warnings;
  3         7  
  3         177  
4 3     3   23 use strict;
  3         5  
  3         96  
5 3     3   45 use 5.10.1;
  3         21  
6              
7             our $VERSION = '0.562';
8 3     3   14 use Exporter 'import';
  3         6  
  3         131  
9             our @EXPORT_OK = qw( fill_form );
10              
11 3     3   11 use Carp qw( croak );
  3         15  
  3         172  
12 3     3   14 use List::Util qw( any );
  3         4  
  3         160  
13              
14 3     3   2139 use Term::Choose qw( choose ); ###
  3         362804  
  3         544  
15 3     3   67 use Term::Choose::LineFold qw( line_fold print_columns cut_to_printwidth );
  3         6  
  3         201  
16 3     3   18 use Term::Choose::Constants qw( :all );
  3         6  
  3         869  
17 3     3   18 use Term::Choose::Screen qw( :all );
  3         6  
  3         507  
18 3     3   2465 use Term::Choose::Util qw( unicode_sprintf get_term_size );
  3         178844  
  3         344  
19 3     3   40 use Term::Choose::ValidateOptions qw( validate_options );
  3         4  
  3         369  
20              
21             my $Plugin;
22              
23             BEGIN {
24 3 50   3   22 if ( $^O eq 'MSWin32' ) {
25 0         0 require Term::Choose::Win32;
26 0         0 require Win32::Console::ANSI;
27 0         0 $Plugin = 'Term::Choose::Win32';
28             }
29             else {
30 3         15 require Term::Choose::Linux;
31 3         29751 $Plugin = 'Term::Choose::Linux';
32             }
33             }
34              
35              
36             sub new {
37 1     1 1 223052 my $class = shift;
38 1 50       7 croak "new: called with " . @_ . " arguments - 0 or 1 arguments expected." if @_ > 1;
39 1         3 my ( $opt ) = @_;
40 1         7 my $instance_defaults = _defaults();
41 1 50       4 if ( defined $opt ) {
42 0 0       0 croak "new: The (optional) argument is not a HASH reference." if ref $opt ne 'HASH';
43 0         0 my $caller = 'new';
44 0         0 validate_options( _valid_options( $caller ), $opt, $caller );
45 0         0 for my $key ( keys %$opt ) {
46 0 0       0 $instance_defaults->{$key} = $opt->{$key} if defined $opt->{$key};
47             }
48             }
49 1         4 my $self = bless $instance_defaults, $class;
50 1         12 $self->{backup_instance_defaults} = { %$instance_defaults };
51 1         15 $self->{plugin} = $Plugin->new();
52 1         22 return $self;
53             }
54              
55              
56             sub _valid_options {
57             return {
58 0     0   0 codepage_mapping => '[ 0 1 ]',
59             auto_up => '[ 0 1 2 ]',
60             clear_screen => '[ 0 1 2 ]',
61             color => '[ 0 1 2 ]',
62             hide_cursor => '[ 0 1 2 ]', # hide_cursor == 2 # documentation
63             page => '[ 0 1 2 ]', # undocumented
64             keep => '[ 1-9 ][ 0-9 ]*', # undocumented
65             read_only => 'Array_Int',
66             skip_items => 'Regexp',
67             # only keys are checked, passed values are ignored
68             # it's up to the user to remove the skipped items from the returned array
69             back => 'Str',
70             confirm => 'Str',
71             footer => 'Str', # undocumented
72             info => 'Str',
73             prompt => 'Str',
74             };
75             }
76              
77              
78             sub _defaults {
79             return {
80 1     1   20 auto_up => 0,
81             back => ' BACK',
82             clear_screen => 0,
83             codepage_mapping => 0,
84             color => 0,
85             confirm => 'CONFIRM',
86             footer => '',
87             hide_cursor => 1,
88             info => '',
89             keep => 5,
90             page => 1,
91             prompt => '',
92             read_only => [],
93             skip_items => undef,
94             };
95             }
96              
97              
98             sub __init_term {
99 0     0     my ( $self ) = @_;
100 0           $self->{plugin}->__set_mode( { mode => 'cbreak', hide_cursor => 0 } );
101             }
102              
103              
104             sub __reset_term {
105 0     0     my ( $self, $up ) = @_;
106 0 0         if ( defined $self->{plugin} ) {
107 0           $self->{plugin}->__reset_mode( { hide_cursor => 0 } );
108             }
109 0 0         if ( $up ) {
110 0           print up( $up );
111             }
112 0 0         if ( $self->{clear_screen} == 2 ) { # readline
113 0           print "\r" . clear_to_end_of_line();
114             }
115             else {
116 0           print "\r" . clear_to_end_of_screen();
117             }
118 0 0         if ( $self->{hide_cursor} == 1 ) {
    0          
119 0           print show_cursor();
120             }
121             elsif ( $self->{hide_cursor} == 2 ) {
122 0           print hide_cursor();
123             }
124             }
125              
126              
127             sub __reset {
128 0     0     my ( $self, $up ) = @_;
129 0           $self->__reset_term( $up );
130 0 0         if ( exists $self->{backup_instance_defaults} ) {
131 0           my $instance_defaults = $self->{backup_instance_defaults};
132 0           for my $key ( keys %$self ) {
133 0 0 0       if ( $key eq 'plugin' || $key eq 'backup_instance_defaults' ) {
    0          
134 0           next;
135             }
136             elsif ( exists $instance_defaults->{$key} ) {
137 0           $self->{$key} = $instance_defaults->{$key};
138             }
139             else {
140 0           delete $self->{$key};
141             }
142             }
143             }
144             }
145              
146              
147             sub __get_list {
148 0     0     my ( $self, $orig_list ) = @_;
149 0           my $list;
150 0 0         if ( $self->{color} ) {
151 0           $list = [ @{$self->{i}{pre}} ];
  0            
152 0           my $count = @{$self->{i}{pre}};
  0            
153 0           for my $entry ( @$orig_list ) {
154 0           my ( $key, $value ) = @$entry;
155 0           my @color;
156 0           $key =~ s/${\PH}//g;
  0            
157 0 0         $key =~ s/(${\SGR_ES})/push( @color, $1 ) && ${\PH}/ge;
  0            
  0            
  0            
158 0           $self->{i}{key_colors}[$count++] = [ @color ];
159 0           push @$list, [ $self->__sanitized_string( $key ), $value ];
160             }
161             }
162             else {
163 0           $list = [ @{$self->{i}{pre}}, map { [ $self->__sanitized_string( $_->[0] ), $_->[1] ] } @$orig_list ];
  0            
  0            
164             }
165 0           return $list;
166             }
167              
168              
169             sub __limit_key_w {
170 0     0     my ( $self, $term_w ) = @_;
171 0 0         if ( $self->{i}{max_key_w} > $term_w / 3 ) {
172 0           $self->{i}{max_key_w} = int( $term_w / 3 );
173             }
174             }
175              
176              
177             sub __available_width {
178 0     0     my ( $self, $term_w ) = @_;
179 0           $self->{i}{avail_w} = $term_w - ( $self->{i}{max_key_w} + length( $self->{i}{sep} ) + $self->{i}{arrow_w} );
180             # Subtract $self->{i}{arrow_w} for the '<' before the string.
181             # In each case where no '<'-prefix is required (diff==0) $self->{i}{arrow_w} is added again.
182             # Routins where $self->{i}{arrow_w} is added: __left, __bspace, __home, __ctrl_u, __delete
183             # The required space (1) for the cursor (or the '>') behind the string is already subtracted in get_term_size
184             }
185              
186              
187             sub __threshold_width {
188 0     0     my ( $self ) = @_;
189 0           $self->{i}{th} = int( $self->{i}{avail_w} / 5 );
190 0 0         $self->{i}{th} = 40 if $self->{i}{th} > 40; ##
191             }
192              
193              
194             sub __sanitized_string {
195 0     0     my ( $self, $str ) = @_;
196 0 0         if ( defined $str ) {
197 0           $str =~ s/\t/ /g;
198 0           $str =~ s/\v+/\ \ /g;
199 0           $str =~ s/[\p{Cc}\p{Noncharacter_Code_Point}\p{Cs}]//g;
200             }
201             else {
202 0           $str = '';
203             }
204 0           return $str;
205             }
206              
207              
208             sub __threshold_char_count {
209 0     0     my ( $self, $m ) = @_;
210 0           $m->{th_l} = 0;
211 0           $m->{th_r} = 0;
212 0           my ( $tmp_w, $count ) = ( 0, 0 );
213 0           for ( @{$m->{p_str}} ) {
  0            
214 0           $tmp_w += $_->[1];
215 0           ++$count;
216 0 0         if ( $tmp_w > $self->{i}{th} ) {
217 0           $m->{th_l} = $count;
218 0           last;
219             }
220             }
221 0           ( $tmp_w, $count ) = ( 0, 0 );
222 0           for ( reverse @{$m->{p_str}} ) {
  0            
223 0           $tmp_w += $_->[1];
224 0           ++$count;
225 0 0         if ( $tmp_w > $self->{i}{th} ) {
226 0           $m->{th_r} = $count;
227 0           last;
228             }
229             }
230             }
231              
232              
233             sub __string_and_pos {
234 0     0     my ( $self, $list ) = @_;
235 0           my $default = $list->[$self->{i}{curr_row}][1];
236 0 0         if ( ! defined $default ) {
237 0           $default = '';
238             }
239             my $m = {
240             avail_w => $self->{i}{avail_w},
241 0           th_l => 0,
242             th_r => 0,
243             str => [],
244             str_w => 0,
245             pos => 0,
246             p_str => [],
247             p_str_w => 0,
248             p_pos => 0,
249             diff => 0,
250             };
251 0           for ( $default =~ /\X/g ) {
252 0           my $char_w = print_columns( $_ );
253 0           push @{$m->{str}}, [ $_, $char_w ];
  0            
254 0           $m->{str_w} += $char_w;
255             }
256 0           $m->{pos} = @{$m->{str}};
  0            
257 0           $m->{diff} = $m->{pos};
258 0           _unshift_till_avail_w( $m, [ 0 .. $#{$m->{str}} ] );
  0            
259 0           return $m;
260             }
261              
262              
263             sub __left {
264 0     0     my ( $self, $m ) = @_;
265 0 0         if ( $m->{pos} ) {
266 0           $m->{pos}--;
267             # '<=' and not '==' because th_l could change and fall behind p_pos
268 0   0       while ( $m->{p_pos} <= $m->{th_l} && $m->{diff} ) {
269 0           _unshift_element( $m, $m->{pos} - $m->{p_pos} );
270             }
271 0 0         if ( ! $m->{diff} ) { # no '<'
272 0           $m->{avail_w} = $self->{i}{avail_w} + $self->{i}{arrow_w};
273 0           _push_till_avail_w( $m, [ $#{$m->{p_str}} + 1 .. $#{$m->{str}} ] );
  0            
  0            
274             }
275 0           $m->{p_pos}--;
276             }
277             else {
278 0           $self->{i}{beep} = 1;
279             }
280             }
281              
282              
283             sub __right {
284 0     0     my ( $self, $m ) = @_;
285 0 0         if ( $m->{pos} < $#{$m->{str}} ) {
  0 0          
286 0           $m->{pos}++;
287             # '>=' and not '==' because th_r could change and fall in front of p_pos
288 0   0       while ( $m->{p_pos} >= $#{$m->{p_str}} - $m->{th_r} && $#{$m->{p_str}} + $m->{diff} != $#{$m->{str}} ) {
  0            
  0            
  0            
289 0           _push_element( $m );
290             }
291 0           $m->{p_pos}++;
292             }
293 0           elsif ( $m->{pos} == $#{$m->{str}} ) {
294             #rec w if vw
295 0           $m->{pos}++;
296 0           $m->{p_pos}++;
297             # cursor now behind the string at the end position
298             }
299             else {
300 0           $self->{i}{beep} = 1;
301             }
302             }
303              
304             sub __bspace {
305 0     0     my ( $self, $m ) = @_;
306 0 0         if ( $m->{pos} ) {
307 0           $m->{pos}--;
308             # '<=' and not '==' because th_l could change and fall behind p_pos
309 0   0       while ( $m->{p_pos} <= $m->{th_l} && $m->{diff} ) {
310 0           _unshift_element( $m, $m->{pos} - $m->{p_pos} );
311             }
312 0           $m->{p_pos}--;
313 0 0         if ( ! $m->{diff} ) { # no '<'
314 0           $m->{avail_w} = $self->{i}{avail_w} + $self->{i}{arrow_w};
315             }
316 0           _remove_pos( $m );
317             }
318             else {
319 0           $self->{i}{beep} = 1;
320             }
321             }
322              
323             sub __delete {
324 0     0     my ( $self, $m ) = @_;
325 0 0         if ( $m->{pos} < @{$m->{str}} ) {
  0            
326 0 0         if ( ! $m->{diff} ) { # no '<'
327 0           $m->{avail_w} = $self->{i}{avail_w} + $self->{i}{arrow_w};
328             }
329 0           _remove_pos( $m );
330             }
331             else {
332 0           return;
333             }
334             }
335              
336             sub __ctrl_u {
337 0     0     my ( $self, $m ) = @_;
338 0 0         if ( $m->{pos} ) {
339 0           for my $removed ( splice ( @{$m->{str}}, 0, $m->{pos} ) ) {
  0            
340 0           $m->{str_w} -= $removed->[1];
341             }
342             # diff always 0 # never '<'
343 0           $m->{avail_w} = $self->{i}{avail_w} + $self->{i}{arrow_w};
344 0           _fill_from_begin( $m );
345             }
346             else {
347 0           $self->{i}{beep} = 1;
348             }
349             }
350              
351             sub __ctrl_k {
352 0     0     my ( $self, $m ) = @_;
353 0 0         if ( $m->{pos} < @{$m->{str}} ) {
  0            
354 0           for my $removed ( splice ( @{$m->{str}}, $m->{pos}, @{$m->{str}} - $m->{pos} ) ) {
  0            
  0            
355 0           $m->{str_w} -= $removed->[1];
356             }
357 0           _fill_from_end( $m );
358             }
359             else {
360 0           $self->{i}{beep} = 1;
361             }
362             }
363              
364             sub __home {
365 0     0     my ( $self, $m ) = @_;
366 0 0         if ( $m->{pos} > 0 ) {
367             # diff always 0 # never '<'
368 0           $m->{avail_w} = $self->{i}{avail_w} + $self->{i}{arrow_w};
369 0           _fill_from_begin( $m );
370             }
371             else {
372 0           $self->{i}{beep} = 1;
373             }
374             }
375              
376             sub __end {
377 0     0     my ( $self, $m ) = @_;
378 0 0         if ( $m->{pos} < @{$m->{str}} ) {
  0            
379 0           _fill_from_end( $m );
380             }
381             else {
382 0           $self->{i}{beep} = 1;
383             }
384             }
385              
386             sub __add_char {
387 0     0     my ( $self, $m, $char ) = @_;
388 0           my $char_w = print_columns( $char );
389 0           splice( @{$m->{str}}, $m->{pos}, 0, [ $char, $char_w ] );
  0            
390 0           $m->{pos}++;
391 0           splice( @{$m->{p_str}}, $m->{p_pos}, 0, [ $char, $char_w ] );
  0            
392 0           $m->{p_pos}++;
393 0           $m->{p_str_w} += $char_w;
394 0           $m->{str_w} += $char_w;
395             # no '<' if:
396 0 0 0       if ( ! $m->{diff} && $m->{p_pos} < $self->{i}{avail_w} + $self->{i}{arrow_w} ) {
397 0           $m->{avail_w} = $self->{i}{avail_w} + $self->{i}{arrow_w};
398             }
399 0           while ( $m->{p_pos} < $#{$m->{p_str}} ) {
  0            
400 0 0         if ( $m->{p_str_w} <= $m->{avail_w} ) {
401 0           last;
402             }
403 0           my $tmp = pop @{$m->{p_str}};
  0            
404 0           $m->{p_str_w} -= $tmp->[1];
405             }
406 0           while ( $m->{p_str_w} > $m->{avail_w} ) {
407 0           my $tmp = shift @{$m->{p_str}};
  0            
408 0           $m->{p_str_w} -= $tmp->[1];
409 0           $m->{p_pos}--;
410 0           $m->{diff}++;
411             }
412             }
413              
414             sub _unshift_element {
415 0     0     my ( $m, $pos ) = @_;
416 0           my $tmp = $m->{str}[$pos];
417 0           unshift @{$m->{p_str}}, $tmp;
  0            
418 0           $m->{p_str_w} += $tmp->[1];
419 0           $m->{diff}--;
420 0           $m->{p_pos}++;
421 0           while ( $m->{p_str_w} > $m->{avail_w} ) {
422 0           my $tmp = pop @{$m->{p_str}};
  0            
423 0           $m->{p_str_w} -= $tmp->[1];
424             }
425             }
426              
427             sub _push_element {
428 0     0     my ( $m ) = @_;
429 0           my $tmp = $m->{str}[$#{$m->{p_str}} + $m->{diff} + 1];
  0            
430 0           push @{$m->{p_str}}, $tmp;
  0            
431 0 0         if ( defined $tmp->[1] ) {
432 0           $m->{p_str_w} += $tmp->[1];
433             }
434 0           while ( $m->{p_str_w} > $m->{avail_w} ) {
435 0           my $tmp = shift @{$m->{p_str}};
  0            
436 0           $m->{p_str_w} -= $tmp->[1];
437 0           $m->{diff}++;
438 0           $m->{p_pos}--;
439             }
440             }
441              
442             sub _unshift_till_avail_w {
443 0     0     my ( $m, $idx ) = @_;
444 0           for ( @{$m->{str}}[reverse @$idx] ) {
  0            
445 0 0         if ( $m->{p_str_w} + $_->[1] > $m->{avail_w} ) {
446 0           last;
447             }
448 0           unshift @{$m->{p_str}}, $_;
  0            
449 0           $m->{p_str_w} += $_->[1];
450 0           $m->{p_pos}++; # p_pos stays on the last element of the p_str
451 0           $m->{diff}--; # diff: difference between p_pos and pos; pos is always bigger or equal p_pos
452             }
453             }
454              
455             sub _push_till_avail_w {
456 0     0     my ( $m, $idx ) = @_;
457 0           for ( @{$m->{str}}[@$idx] ) {
  0            
458 0 0         if ( $m->{p_str_w} + $_->[1] > $m->{avail_w} ) {
459 0           last;
460             }
461 0           push @{$m->{p_str}}, $_;
  0            
462 0           $m->{p_str_w} += $_->[1];
463             }
464             }
465              
466             sub _remove_pos {
467 0     0     my ( $m ) = @_;
468 0           splice( @{$m->{str}}, $m->{pos}, 1 );
  0            
469 0           my $tmp = splice( @{$m->{p_str}}, $m->{p_pos}, 1 );
  0            
470 0           $m->{p_str_w} -= $tmp->[1];
471 0           $m->{str_w} -= $tmp->[1];
472 0           _push_till_avail_w( $m, [ ( $#{$m->{p_str}} + $m->{diff} + 1 ) .. $#{$m->{str}} ] );
  0            
  0            
473             }
474              
475             sub _fill_from_end {
476 0     0     my ( $m ) = @_;
477 0           $m->{pos} = @{$m->{str}};
  0            
478 0           $m->{p_str} = [];
479 0           $m->{p_str_w} = 0;
480 0           $m->{diff} = @{$m->{str}};
  0            
481 0           $m->{p_pos} = 0;
482 0           _unshift_till_avail_w( $m, [ 0 .. $#{$m->{str}} ] );
  0            
483             }
484              
485             sub _fill_from_begin {
486 0     0     my ( $m ) = @_;
487 0           $m->{pos} = 0;
488 0           $m->{p_pos} = 0;
489 0           $m->{diff} = 0;
490 0           $m->{p_str} = [];
491 0           $m->{p_str_w} = 0;
492 0           _push_till_avail_w( $m, [ 0 .. $#{$m->{str}} ] );
  0            
493             }
494              
495              
496             sub __print_readline {
497 0     0     my ( $self, $m ) = @_;
498 0           my $i = $self->{i}{curr_row};
499 0           print "\r" . clear_to_end_of_line();
500 0           print $self->{i}{keys}[$i] . $self->{i}{seps}[$i];
501 0 0 0       if ( $self->{no_echo} && $self->{no_echo} == 2 ) {
502 0           return;
503             }
504 0           my $print_str = '';
505             # left arrow:
506 0 0         if ( $m->{diff} ) {
507 0           $print_str .= $self->{i}{arrow_left};
508             }
509             # input text:
510 0 0         if ( $self->{no_echo} ) {
511 0           $print_str .= ( '*' x @{$m->{p_str}} );
  0            
512             }
513             else {
514 0           $print_str .= join( '', map { $_->[0] } @{$m->{p_str}} );
  0            
  0            
515             }
516             # right arrow:
517 0 0         if ( @{$m->{p_str}} + $m->{diff} != @{$m->{str}} ) {
  0            
  0            
518 0           $print_str .= $self->{i}{arrow_right};
519             }
520 0           my $back_to_pos = 0;
521 0           for ( @{$m->{p_str}}[$m->{p_pos} .. $#{$m->{p_str}}] ) {
  0            
  0            
522 0           $back_to_pos += $_->[1];
523             }
524 0 0         if ( $self->{hide_cursor} ) {
525 0           print show_cursor();
526             }
527 0           print $print_str;
528 0 0         if ( $back_to_pos ) {
529 0           print left( $back_to_pos );
530             }
531             }
532              
533              
534             sub __unicode_trim {
535 0     0     my ( $self, $str, $len ) = @_;
536 0 0         return $str if print_columns( $str ) <= $len;
537 0           return cut_to_printwidth( $str, $len - $self->{i}{char_trimmed_w} ) . $self->{i}{char_trimmed};
538             }
539              
540              
541             sub __length_longest_key {
542 0     0     my ( $self, $list ) = @_;
543 0           my $longest = 0;
544 0           for my $i ( 0 .. $#$list ) {
545 0 0         if ( $i < @{$self->{i}{pre}} ) {
  0            
546 0           next;
547             }
548 0 0   0     if ( any { $_ == $i } @{$self->{i}{keys_to_skip}} ) {
  0            
  0            
549 0           next;
550             }
551 0           my $len = print_columns( $list->[$i][0] );
552 0 0         $longest = $len if $len > $longest;
553             }
554 0           $self->{i}{max_key_w} = $longest;
555             }
556              
557              
558             sub __prepare_hight {
559 0     0     my ( $self, $list, $term_w, $term_h ) = @_;
560 0           $self->{i}{avail_h} = $term_h;
561 0 0         if ( length $self->{i}{info_prompt} ) {
562 0           my $info_w = $term_w + EXTRA_W;
563 0           my @info_prompt = line_fold( $self->{i}{info_prompt}, { width => $info_w, color => $self->{color}, join => 0 } );
564 0           $self->{i}{info_prompt_row_count} = @info_prompt;
565 0           $self->{i}{info_prompt} = join "\n", @info_prompt;
566 0           $self->{i}{avail_h} -= $self->{i}{info_prompt_row_count};
567 0           my $min_avail_h = $self->{keep};
568 0 0         if ( $term_h < $min_avail_h ) {
569 0           $min_avail_h = $term_h;
570             }
571 0 0         if ( $self->{i}{avail_h} < $min_avail_h ) {
572 0           $self->{i}{avail_h} = $min_avail_h;
573             }
574             }
575             else {
576 0           $self->{i}{info_prompt_row_count} = 0;
577             }
578 0 0         if ( @$list > $self->{i}{avail_h} ) {
579 0           $self->{i}{page_count} = int @$list / ( $self->{i}{avail_h} - 1 );
580 0 0         if ( @$list % ( $self->{i}{avail_h} - 1 ) ) {
581 0           $self->{i}{page_count}++;
582             }
583             }
584             else {
585 0           $self->{i}{page_count} = 1;
586             }
587 0 0 0       if ( $self->{page} == 2 || ( $self->{page} == 1 && $self->{i}{page_count} > 1) ) {
      0        
588 0           $self->{i}{print_footer} = 1;
589 0           $self->{i}{avail_h}--;
590             }
591             else {
592 0           $self->{i}{print_footer} = 0;
593             }
594 0           return;
595             }
596              
597              
598             sub __print_current_row {
599 0     0     my ( $self, $list, $m ) = @_;
600 0           print "\r" . clear_to_end_of_line();
601 0 0         if ( $self->{i}{curr_row} < @{$self->{i}{pre}} ) {
  0            
602 0           print reverse_video();
603 0           print $list->[$self->{i}{curr_row}][0];
604 0           print normal();
605             }
606             else {
607 0           $self->__print_readline( $m );
608 0 0         $list->[$self->{i}{curr_row}][1] = join( '', map { defined $_->[0] ? $_->[0] : '' } @{$m->{str}} );
  0            
  0            
609             }
610             }
611              
612              
613             sub __prepare_skip_row {
614 0     0     my ( $self, $list, $idx ) = @_;
615 0           my $remainder = '';
616 0           my $val = '';
617 0           ( $self->{i}{keys}[$idx], $remainder ) = cut_to_printwidth( $list->[$idx][0], $self->{i}{max_key_w} );
618 0 0         if ( length $remainder ) {
619 0           ( $self->{i}{seps}[$idx], $remainder ) = cut_to_printwidth( $remainder, 2 );
620 0 0         if ( length $remainder ) {
621 0           $val = cut_to_printwidth( $remainder, $self->{i}{avail_w} );
622             }
623             }
624 0 0         if ( ! length $self->{i}{seps}[$idx] ) {
    0          
625 0           $self->{i}{seps}[$idx] = ' ';
626             }
627             elsif ( length $self->{i}{seps}[$idx] == 1 ) {
628 0           $self->{i}{seps}[$idx] .= ' ';
629             }
630 0           my $row = $self->{i}{keys}[$idx] . $self->{i}{seps}[$idx] . $val;
631 0 0 0       if ( exists $self->{i}{key_colors} && @{$self->{i}{key_colors}[$idx]} ) {
  0            
632 0           my @key_colors = @{$self->{i}{key_colors}[$idx]};
  0            
633 0           $row =~ s/${\PH}/shift @key_colors/ge;
  0            
  0            
634 0           $row .= normal();
635             }
636 0           return $row;
637             }
638              
639              
640             sub __get_row {
641 0     0     my ( $self, $list, $idx ) = @_;
642 0 0         if ( $idx < @{$self->{i}{pre}} ) {
  0            
643 0           return $list->[$idx][0];
644             }
645 0 0   0     if ( any { $_ == $idx } @{$self->{i}{keys_to_skip}} ) {
  0            
  0            
646 0           return $self->__prepare_skip_row( $list, $idx );
647             }
648 0 0         if ( ! defined $self->{i}{keys}[$idx] ) {
649 0           my $key = $list->[$idx][0];
650             $self->{i}{keys}[$idx] = unicode_sprintf(
651             $key, $self->{i}{max_key_w},
652 0           { suffix_on_truncate => [ $self->{i}{char_trimmed}, $self->{i}{char_trimmed_w} ] }
653             );
654             }
655 0 0         if ( ! defined $self->{i}{seps}[$idx] ) {
656 0 0   0     if ( any { $_ == $idx } @{$self->{i}{read_only}} ) {
  0            
  0            
657 0           $self->{i}{seps}[$idx] = $self->{i}{sep_ro};
658             }
659             else {
660 0           $self->{i}{seps}[$idx] = $self->{i}{sep};
661             }
662             }
663 0 0 0       if ( exists $self->{i}{key_colors} && @{$self->{i}{key_colors}[$idx]} ) {
  0            
664 0           my @key_colors = @{$self->{i}{key_colors}[$idx]};
  0            
665 0           $self->{i}{keys}[$idx] =~ s/${\PH}/shift @key_colors/ge;
  0            
  0            
666 0           $self->{i}{keys}[$idx] .= normal();
667             }
668 0 0         if ( defined $list->[$idx][1] ) {
669 0           my $val = $self->__unicode_trim( $list->[$idx][1], $self->{i}{avail_w} );
670 0           return $self->{i}{keys}[$idx] . $self->{i}{seps}[$idx] . $val;
671             }
672             else {
673 0           return $self->{i}{keys}[$idx] . $self->{i}{seps}[$idx];
674             }
675             }
676              
677              
678             sub __write_screen {
679 0     0     my ( $self, $list ) = @_;
680 0           my @rows;
681 0           for my $idx ( $self->{i}{begin_row} .. $self->{i}{end_row} ) {
682 0           push @rows, $self->__get_row( $list, $idx );
683             }
684 0           print join "\n", @rows;
685 0           $self->{i}{curr_page} = int( $self->{i}{end_row} / $self->{i}{avail_h} ) + 1;
686 0           my $up = 0;
687 0 0         if ( $self->{i}{print_footer} ) {
688 0           my $trailing_empty_page_rows = $self->{i}{avail_h} - ( $self->{i}{end_row} - $self->{i}{begin_row} );
689 0 0         if ( $trailing_empty_page_rows > 1 ) {
690 0           print "\n" x ( $trailing_empty_page_rows - 1 );
691             }
692 0           print "\n", sprintf $self->{i}{footer_fmt}, $self->{i}{curr_page};
693 0           $up += $trailing_empty_page_rows;
694             }
695 0           $up += $self->{i}{end_row} - $self->{i}{curr_row};
696 0 0         if ( $up ) {
697 0           print up( $up );
698             }
699             }
700              
701              
702             sub __prepare_footer_fmt {
703 0     0     my ( $self, $term_w ) = @_;
704 0 0         if ( ! $self->{i}{print_footer} ) {
705 0           return;
706             }
707 0           my $width_p_count = length $self->{i}{page_count};
708 0           my $p_count = $self->{i}{page_count};
709 0           my $footer_fmt = '--- %0' . $width_p_count . 'd/' . $p_count . ' ---';
710 0 0         if ( $self->{footer} ) {
711 0           $footer_fmt .= $self->{footer};
712             }
713 0 0         if ( print_columns( sprintf $footer_fmt, $p_count ) > $term_w ) { # color
714 0           $footer_fmt = '%0' . $width_p_count . 'd/' . $p_count;
715 0 0         if ( length( sprintf $footer_fmt, $p_count ) > $term_w ) {
716 0 0         if ( $width_p_count > $term_w ) {
717 0           $width_p_count = $term_w;
718             }
719 0           $footer_fmt = '%0' . $width_p_count . '.' . $width_p_count . 's';
720             }
721             }
722 0           $self->{i}{footer_fmt} = $footer_fmt;
723             }
724              
725              
726             sub __write_first_screen {
727 0     0     my ( $self, $list ) = @_;
728 0 0         $self->{i}{curr_row} = $self->{auto_up} ? 0 : @{$self->{i}{pre}};
  0            
729 0           $self->{i}{begin_row} = 0;
730 0           $self->{i}{end_row} = ( $self->{i}{avail_h} - 1 );
731 0 0         if ( $self->{i}{end_row} > $#$list ) {
732 0           $self->{i}{end_row} = $#$list;
733             }
734 0           $self->{i}{seps} = [];
735 0           $self->{i}{keys} = [];
736 0 0         if ( $self->{clear_screen} == 1 ) {
737 0           print clear_screen();
738             }
739             else {
740 0           print "\r" . clear_to_end_of_screen();
741             }
742 0 0         if ( $self->{hide_cursor} ) {
743 0           print hide_cursor();
744             }
745 0 0         if ( length $self->{i}{info_prompt} ) {
746 0           print $self->{i}{info_prompt} . "\n"; #
747             }
748 0           $self->__write_screen( $list );
749             }
750              
751              
752             sub __prepare_meta_menu_elements {
753 0     0     my ( $self, $term_w ) = @_;
754 0           my @meta_menu_elements = ( 'back', 'confirm' );
755 0           $self->{i}{pre} = [];
756 0           for my $meta_menu_element ( @meta_menu_elements ) {
757 0           my @color;
758 0           my $tmp = $self->{i}{$meta_menu_element . '_orig'};
759 0 0         if ( $self->{color} ) {
760 0           $tmp =~ s/${\PH}//g;
  0            
761 0 0         $tmp =~ s/(${\SGR_ES})/push( @color, $1 ) && ${\PH}/ge;
  0            
  0            
  0            
762             }
763 0           $tmp = $self->__sanitized_string( $tmp );
764 0 0         if ( print_columns( $tmp ) > $term_w ) {
765 0           $tmp = cut_to_printwidth( $tmp, $term_w );
766             }
767 0 0         if ( @color ) {
768 0           $tmp =~ s/${\PH}/shift @color/ge;
  0            
  0            
769 0           $tmp .= normal();
770             }
771 0           $self->{$meta_menu_element} = $tmp;
772 0           push @{$self->{i}{pre}}, [ $self->{$meta_menu_element}, ];
  0            
773             }
774             }
775              
776              
777             sub __modify_fill_form_options {
778 0     0     my ( $self ) = @_;
779 0 0         if ( $self->{clear_screen} == 2 ) {
780 0           $self->{clear_screen} = 0;
781             }
782 0 0 0       if ( length $self->{footer} && $self->{page} != 2 ) {
783 0           $self->{page} = 2;
784             }
785 0 0 0       if ( $self->{page} == 2 && ! $self->{clear_screen} ) {
786 0           $self->{clear_screen} = 1;
787             }
788             }
789              
790              
791             sub fill_form {
792 0 0   0 1   if ( ref $_[0] ne __PACKAGE__ ) {
793 0           my $ob = __PACKAGE__->new();
794 0           delete $ob->{backup_instance_defaults};
795 0           return $ob->fill_form( @_ );
796             }
797 0           my ( $self, $orig_list, $opt ) = @_;
798 0 0         croak "'fill_form' called with no argument." if ! defined $orig_list;
799 0 0         croak "'fill_form' requires an ARRAY reference as its argument." if ref $orig_list ne 'ARRAY';
800 0 0         $opt = {} if ! defined $opt;
801 0 0         croak "'fill_form': the (optional) second argument must be a HASH reference" if ref $opt ne 'HASH';
802 0 0         if ( ! @$orig_list ) { ###
803             # Choose
804 0           my $choice = choose(
805             [ undef, 'Continue' ],
806             { prompt => 'No fields!', undef => 'Back', layout => 2 }
807             );
808 0 0         if ( ! defined $choice ) {
809 0           return;
810             }
811 0           return [];
812             }
813             #return [] if ! @$orig_list;
814 0 0         if ( %$opt ) {
815 0           my $caller = 'fill_form';
816 0           validate_options( _valid_options( $caller ), $opt, $caller );
817 0           for my $key ( keys %$opt ) {
818 0 0         $self->{$key} = $opt->{$key} if defined $opt->{$key};
819             }
820             }
821 0           $self->__modify_fill_form_options();
822 0 0         if ( $^O eq 'MSWin32' ) {
823 0 0         print $self->{codepage_mapping} ? "\e(K" : "\e(U";
824             }
825 0           my @tmp;
826 0 0         if ( length $self->{info} ) {
827 0           push @tmp, $self->{info};
828             }
829 0 0         if ( length $self->{prompt} ) {
830 0           push @tmp, $self->{prompt};
831             }
832 0           $self->{i}{info_prompt} = join "\n", @tmp;
833 0           $self->{i}{sep} = ': ';
834 0           $self->{i}{sep_ro} = '| ';
835 0 0         die if length $self->{i}{sep} != length $self->{i}{sep_ro};
836 0           $self->{i}{char_trimmed} = '~';
837 0           $self->{i}{char_trimmed_w} = length $self->{i}{char_trimmed};
838 0           $self->{i}{arrow_left} = '<';
839 0           $self->{i}{arrow_right} = '>';
840 0           $self->{i}{arrow_w} = 1;
841 0           local $| = 1;
842             local $SIG{INT} = sub {
843 0     0     $self->__reset(); #
844 0           print "^C\n";
845 0           exit;
846 0           };
847 0           $self->__init_term();
848 0           my ( $term_w, $term_h ) = get_term_size();
849 0           $self->{i}{back_orig} = $self->{back};
850 0           $self->{i}{confirm_orig} = $self->{confirm};
851 0           $self->__prepare_meta_menu_elements( $term_w );
852 0           $self->{i}{read_only} = [];
853 0 0         if ( @{$self->{read_only}} ) {
  0            
854 0           $self->{i}{read_only} = [ map { $_ + @{$self->{i}{pre}} } @{$self->{read_only}} ];
  0            
  0            
  0            
855             }
856              
857 0           $self->{i}{keys_to_skip} = [];
858 0 0         if ( defined $self->{skip_items} ) {
859 0           for my $i ( 0 .. $#$orig_list ) {
860 0 0 0       if ( defined $orig_list->[$i][0] && $orig_list->[$i][0] =~ $self->{skip_items} ) {
861 0           push @{$self->{i}{keys_to_skip}}, $i + @{$self->{i}{pre}};
  0            
  0            
862             }
863             else {
864 0           $self->{i}{end_down} = $i;
865             }
866             }
867 0           $self->{i}{end_down} += @{$self->{i}{pre}};
  0            
868             }
869             else {
870 0           $self->{i}{end_down} = $#$orig_list + @{$self->{i}{pre}};
  0            
871             }
872 0           my $list = $self->__get_list( $orig_list );
873 0           $self->__length_longest_key( $list );
874 0           $self->__limit_key_w( $term_w );
875 0           $self->__available_width( $term_w );
876 0           $self->__threshold_width();
877 0           $self->__prepare_hight( $list, $term_w, $term_h );
878 0           $self->__prepare_footer_fmt( $term_w );
879 0           $self->__write_first_screen( $list );
880 0           my $m = $self->__string_and_pos( $list );
881 0           my $k = 0;
882              
883 0           CHAR: while ( 1 ) {
884 0           my $locked = 0;
885 0 0   0     if ( any { $_ == $self->{i}{curr_row} } @{$self->{i}{read_only}} ) {
  0            
  0            
886 0           $locked = 1;
887             }
888 0 0         if ( $self->{i}{beep} ) {
889 0           print bell();
890 0           $self->{i}{beep} = 0;
891             }
892             else {
893 0 0         if ( $self->{hide_cursor} ) {
894 0           print hide_cursor();
895             }
896 0           $self->__print_current_row( $list, $m );
897             }
898 0           my $char;
899 0 0   0     if ( any { $_ == $self->{i}{curr_row} } @{$self->{i}{keys_to_skip}} ) {
  0            
  0            
900 0 0 0       if ( $self->{i}{direction} eq 'up' || $self->{i}{curr_row} >= $self->{i}{end_down} ) {
901 0           $char = VK_UP;
902             }
903             else {
904 0           $char = VK_DOWN;
905             }
906             }
907             else {
908 0           $char = $self->{plugin}->__get_key_OS();
909             }
910 0           $self->{i}{direction} = 'down';
911 0 0         if ( ! defined $char ) {
912 0           $self->__reset();
913 0           warn "EOT: $!";
914 0           return;
915             }
916 0 0         next CHAR if $char == NEXT_get_key;
917 0 0         next CHAR if $char == KEY_TAB;
918 0           my ( $tmp_term_w, $tmp_term_h ) = get_term_size();
919 0 0 0       if ( $tmp_term_w != $term_w || $tmp_term_h != $term_h && $tmp_term_h < ( @$list + 1 ) ) {
      0        
920 0           my $up = $self->{i}{curr_row} + $self->{i}{info_prompt_row_count};
921 0 0         print up( $up ) if $up;
922 0           ( $term_w, $term_h ) = ( $tmp_term_w, $tmp_term_h );
923 0           $self->__prepare_meta_menu_elements( $term_w );
924 0           $self->__length_longest_key( $list );
925 0           $self->__limit_key_w( $term_w );
926 0           $self->__available_width( $term_w );
927 0           $self->__threshold_width();
928 0           $self->__prepare_hight( $list, $term_w, $term_h );
929 0           $self->__prepare_footer_fmt( $term_w );
930 0           $self->__write_first_screen( $list );
931 0           $m = $self->__string_and_pos( $list );
932             }
933             # reset $m->{avail_w} to default:
934 0           $m->{avail_w} = $self->{i}{avail_w};
935 0           $self->__threshold_char_count( $m );
936 0 0 0       if ( $char == KEY_BSPACE || $char == CONTROL_H ) {
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0          
    0          
    0          
    0          
937 0           $k = 1;
938 0 0         if ( $locked ) { # read_only
939 0           $self->{i}{beep} = 1;
940             }
941             else {
942 0           $self->__bspace( $m );
943             }
944             }
945             elsif ( $char == CONTROL_U ) {
946 0           $k = 1;
947 0 0         if ( $locked ) {
948 0           $self->{i}{beep} = 1;
949             }
950             else {
951 0           $self->__ctrl_u( $m );
952             }
953             }
954             elsif ( $char == CONTROL_K ) {
955 0           $k = 1;
956 0 0         if ( $locked ) {
957 0           $self->{i}{beep} = 1;
958             }
959             else {
960 0           $self->__ctrl_k( $m );
961             }
962             }
963             elsif ( $char == VK_DELETE || $char == CONTROL_D ) {
964 0           $k = 1;
965 0           $self->__delete( $m );
966             }
967             elsif ( $char == VK_RIGHT || $char == CONTROL_F ) {
968 0           $k = 1;
969 0           $self->__right( $m );
970             }
971             elsif ( $char == VK_LEFT || $char == CONTROL_B ) {
972 0           $k = 1;
973 0           $self->__left( $m );
974             }
975             elsif ( $char == VK_END || $char == CONTROL_E ) {
976 0           $k = 1;
977 0           $self->__end( $m );
978             }
979             elsif ( $char == VK_HOME || $char == CONTROL_A ) {
980 0           $k = 1;
981 0           $self->__home( $m );
982             }
983             elsif ( $char == VK_UP || $char == CONTROL_S ) {
984 0           $k = 1;
985 0 0         if ( $self->{i}{curr_row} == 0 ) {
986 0           $self->{i}{beep} = 1;
987             }
988             else {
989 0           $self->{i}{curr_row}--;
990 0           $m = $self->__string_and_pos( $list );
991 0 0         if ( $self->{i}{curr_row} >= $self->{i}{begin_row} ) {
992 0           $self->__reset_previous_row( $list, $self->{i}{curr_row} + 1 );
993 0           print up( 1 );
994             }
995             else {
996 0           $self->__print_previous_page( $list );
997             }
998             }
999             }
1000             elsif ( $char == VK_DOWN || $char == CONTROL_T ) {
1001 0           $k = 1;
1002 0 0         if ( $self->{i}{curr_row} == $#$list ) {
1003 0           $self->{i}{beep} = 1;
1004             }
1005             else {
1006 0           $self->{i}{curr_row}++;
1007 0           $m = $self->__string_and_pos( $list );
1008 0 0         if ( $self->{i}{curr_row} <= $self->{i}{end_row} ) {
1009 0           $self->__reset_previous_row( $list, $self->{i}{curr_row} - 1 );
1010 0           print down( 1 );
1011             }
1012             else {
1013 0           print up( $self->{i}{end_row} - $self->{i}{begin_row} );
1014 0           $self->__print_next_page( $list );
1015             }
1016             }
1017             }
1018             elsif ( $char == VK_PAGE_UP || $char == CONTROL_P ) {
1019 0           $k = 1;
1020 0 0         if ( $self->{i}{curr_page} == 1 ) {
1021 0 0         if ( $self->{i}{curr_row} == 0 ) {
1022 0           $self->{i}{beep} = 1;
1023             }
1024             else {
1025 0           $self->__reset_previous_row( $list, $self->{i}{curr_row} );
1026 0           print up( $self->{i}{curr_row} );
1027 0           $self->{i}{curr_row} = 0;
1028 0           $m = $self->__string_and_pos( $list );
1029             }
1030             }
1031             else {
1032 0           my $up = $self->{i}{curr_row} - $self->{i}{begin_row};
1033 0 0         print up( $up ) if $up;
1034 0           $self->{i}{curr_row} = $self->{i}{begin_row} - $self->{i}{avail_h};
1035 0           $m = $self->__string_and_pos( $list );
1036 0           $self->__print_previous_page( $list );
1037             }
1038             }
1039             elsif ( $char == VK_PAGE_DOWN || $char == CONTROL_N ) {
1040 0           $k = 1;
1041 0 0         if ( $self->{i}{curr_page} == $self->{i}{page_count} ) {
1042 0 0         if ( $self->{i}{curr_row} == $#$list ) {
1043 0           $self->{i}{beep} = 1;
1044             }
1045             else {
1046 0           $self->__reset_previous_row( $list, $self->{i}{curr_row} );
1047 0           my $rows = $self->{i}{end_row} - $self->{i}{curr_row};
1048 0           print down( $rows );
1049 0           $self->{i}{curr_row} = $self->{i}{end_row};
1050 0           $m = $self->__string_and_pos( $list );
1051             }
1052             }
1053             else {
1054 0           my $up = $self->{i}{curr_row} - $self->{i}{begin_row};
1055 0 0         print up( $up ) if $up;
1056 0           $self->{i}{curr_row} = $self->{i}{end_row} + 1;
1057 0           $m = $self->__string_and_pos( $list );
1058 0           $self->__print_next_page( $list );
1059             }
1060             }
1061             elsif ( $char == CONTROL_X ) {
1062 0 0         if ( @{$m->{str}} ) {
  0            
1063 0           $list->[$self->{i}{curr_row}][1] = '';
1064 0           $m = $self->__string_and_pos( $list );
1065             }
1066             else {
1067 0           $self->{i}{beep} = 1;
1068             }
1069             }
1070             elsif ( $char == VK_INSERT ) {
1071 0           $self->{i}{beep} = 1;
1072             }
1073             elsif ( $char == LINE_FEED || $char == CARRIAGE_RETURN ) {
1074             # LINE_FEED == CONTROL_J, CARRIAGE_RETURN == CONTROL_M
1075 0           my $up = $self->{i}{curr_row} - $self->{i}{begin_row};
1076 0 0         if ( $self->{i}{info_prompt_row_count} ) {
1077 0           $up += $self->{i}{info_prompt_row_count};
1078             }
1079 0 0         if ( $list->[$self->{i}{curr_row}][0] eq $self->{back} ) {
    0          
1080 0           $self->__reset( $up );
1081 0           return;
1082             }
1083             elsif ( $list->[$self->{i}{curr_row}][0] eq $self->{confirm} ) {
1084 0           splice @$list, 0, @{$self->{i}{pre}};
  0            
1085 0           $self->__reset( $up );
1086 0   0       return [ map { [ $orig_list->[$_][0], $list->[$_][1] // '' ] } 0 .. $#{$list} ];
  0            
  0            
1087             }
1088 0 0 0       if ( $self->{auto_up} == 2 || $self->{i}{curr_row} == $#$list ) {
1089 0           print up( $up );
1090 0           print "\r" . clear_to_end_of_screen();
1091 0           $self->__write_first_screen( $list );
1092 0           $m = $self->__string_and_pos( $list );
1093             }
1094             else {
1095 0           $self->{i}{curr_row}++;
1096 0           $m = $self->__string_and_pos( $list );
1097 0 0         if ( $self->{i}{curr_row} <= $self->{i}{end_row} ) {
1098 0           $self->__reset_previous_row( $list, $self->{i}{curr_row} - 1 );
1099 0           print down( 1 );
1100             }
1101             else {
1102 0           print up( $self->{i}{end_row} - $self->{i}{begin_row} );
1103 0           $self->__print_next_page( $list );
1104             }
1105             }
1106             }
1107             else {
1108 0           $k = 1;
1109 0 0         if ( $locked ) {
1110 0           $self->{i}{beep} = 1;
1111             }
1112             else {
1113 0           $char = chr $char;
1114 0           utf8::upgrade $char;
1115 0           $self->__add_char( $m, $char );
1116             }
1117             }
1118             }
1119             }
1120              
1121              
1122             sub __reset_previous_row {
1123 0     0     my ( $self, $list, $idx ) = @_;
1124 0           print "\r" . clear_to_end_of_line();
1125 0           print $self->__get_row( $list, $idx );
1126 0 0         if ( $self->{i}{curr_row} < $idx ) {
1127 0           $self->{i}{direction} = 'up';
1128             }
1129             }
1130              
1131              
1132             sub __print_next_page {
1133 0     0     my ( $self, $list ) = @_;
1134 0           $self->{i}{begin_row} = $self->{i}{end_row} + 1;
1135 0           $self->{i}{end_row} = $self->{i}{end_row} + $self->{i}{avail_h};
1136 0 0         $self->{i}{end_row} = $#$list if $self->{i}{end_row} > $#$list;
1137 0           print "\r" . clear_to_end_of_screen();
1138 0           $self->__write_screen( $list );
1139 0 0         if ( $self->{i}{curr_row} == $self->{i}{end_row} ) {
1140 0           $self->{i}{direction} = 'up';
1141             }
1142             }
1143              
1144              
1145             sub __print_previous_page {
1146 0     0     my ( $self, $list ) = @_;
1147 0           $self->{i}{end_row} = $self->{i}{begin_row} - 1;
1148 0           $self->{i}{begin_row} = $self->{i}{begin_row} - $self->{i}{avail_h};
1149 0 0         $self->{i}{begin_row} = 0 if $self->{i}{begin_row} < 0;
1150 0           print "\r" . clear_to_end_of_screen();
1151 0           $self->__write_screen( $list );
1152 0 0         if ( $self->{i}{curr_row} > $self->{i}{begin_row} ) {
1153 0           $self->{i}{direction} = 'up';
1154             }
1155             }
1156              
1157              
1158             1;
1159              
1160              
1161             __END__