File Coverage

blib/lib/UI/Dialog/Backend/ASCII.pm
Criterion Covered Total %
statement 75 685 10.9
branch 6 290 2.0
condition 25 278 8.9
subroutine 15 35 42.8
pod 13 13 100.0
total 134 1301 10.3


line stmt bran cond sub pod time code
1             package UI::Dialog::Backend::ASCII;
2             ###############################################################################
3             # Copyright (C) 2004-2016 Kevin C. Krinke
4             #
5             # This library is free software; you can redistribute it and/or
6             # modify it under the terms of the GNU Lesser General Public
7             # License as published by the Free Software Foundation; either
8             # version 2.1 of the License, or (at your option) any later version.
9             #
10             # This library is distributed in the hope that it will be useful,
11             # but WITHOUT ANY WARRANTY; without even the implied warranty of
12             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13             # Lesser General Public License for more details.
14             #
15             # You should have received a copy of the GNU Lesser General Public
16             # License along with this library; if not, write to the Free Software
17             # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18             ###############################################################################
19 2     2   13197 use 5.006;
  2         5  
20 2     2   6 use strict;
  2         2  
  2         29  
21 2     2   6 use warnings;
  2         32  
  2         43  
22 2     2   6 use Carp;
  2         2  
  2         97  
23 2     2   417 use UI::Dialog::Backend;
  2         3  
  2         52  
24 2     2   487 use Time::HiRes qw( sleep );
  2         980  
  2         7  
25              
26             BEGIN {
27 2     2   212 use vars qw( $VERSION @ISA );
  2         3  
  2         94  
28 2     2   14 @ISA = qw( UI::Dialog::Backend );
29 2         1854 $VERSION = '1.21';
30             }
31              
32             $| = 1; # turn on autoflush
33              
34             #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
35             #: Constructor Method
36             #:
37              
38             sub new {
39 3     3 1 351 my $proto = shift();
40 3   33     12 my $class = ref($proto) || $proto;
41 3 100       12 my $cfg = ((ref($_[0]) eq "HASH") ? $_[0] : (@_) ? { @_ } : {});
    50          
42 3         4 my $self = {};
43 3         4 bless($self, $class);
44 3         11 $self->{'_state'} = {};
45 3         6 $self->{'_opts'} = {};
46              
47             #: Dynamic path discovery...
48 3         4 my $CFG_PATH = $cfg->{'PATH'};
49 3 50       10 if ($CFG_PATH) {
    50          
50 0 0       0 if (ref($CFG_PATH) eq "ARRAY") {
    0          
    0          
51 0         0 $self->{'PATHS'} = $CFG_PATH;
52             }
53             elsif ($CFG_PATH =~ m!:!) {
54 0         0 $self->{'PATHS'} = [ split(/:/,$CFG_PATH) ];
55             }
56             elsif (-d $CFG_PATH) {
57 0         0 $self->{'PATHS'} = [ $CFG_PATH ];
58             }
59             }
60             elsif ($ENV{'PATH'}) {
61 3         14 $self->{'PATHS'} = [ split(/:/,$ENV{'PATH'}) ];
62             }
63             else {
64 0         0 $self->{'PATHS'} = '';
65             }
66              
67 3   50     14 $self->{'_opts'}->{'callbacks'} = $cfg->{'callbacks'} || undef();
68 3   50     20 $self->{'_opts'}->{'timeout'} = $cfg->{'timeout'} || 0;
69 3   50     12 $self->{'_opts'}->{'wait'} = $cfg->{'wait'} || 0;
70 3   50     12 $self->{'_opts'}->{'debug'} = $cfg->{'debug'} || undef();
71 3   50     11 $self->{'_opts'}->{'title'} = $cfg->{'title'} || undef();
72 3   50     13 $self->{'_opts'}->{'backtitle'} = $cfg->{'backtitle'} || undef();
73 3   50     17 $self->{'_opts'}->{'usestderr'} = $cfg->{'usestderr'} || 0;
74 3   50     13 $self->{'_opts'}->{'extra-button'} = $cfg->{'extra-button'} || 0;
75 3   50     14 $self->{'_opts'}->{'extra-label'} = $cfg->{'extra-label'} || undef();
76 3   50     16 $self->{'_opts'}->{'help-button'} = $cfg->{'help-button'} || 0;
77 3   50     12 $self->{'_opts'}->{'help-label'} = $cfg->{'help-label'} || undef();
78 3   50     11 $self->{'_opts'}->{'nocancel'} = $cfg->{'nocancel'} || 0;
79 3   50     9 $self->{'_opts'}->{'maxinput'} = $cfg->{'maxinput'} || 0;
80 3   50     12 $self->{'_opts'}->{'defaultno'} = $cfg->{'defaultno'} || 0;
81 3   50     9 $self->{'_opts'}->{'autoclear'} = $cfg->{'autoclear'} || 0;
82 3   50     11 $self->{'_opts'}->{'clearbefore'} = $cfg->{'clearbefore'} || 0;
83 3   50     11 $self->{'_opts'}->{'clearafter'} = $cfg->{'clearafter'} || 0;
84 3   50     46 $self->{'_opts'}->{'beepbin'} = $cfg->{'beepbin'} || $self->_find_bin('beep') || '/usr/bin/beep';
85 3   50     14 $self->{'_opts'}->{'beepbefore'} = $cfg->{'beepbefore'} || 0;
86 3   50     10 $self->{'_opts'}->{'beepafter'} = $cfg->{'beepafter'} || 0;
87 3   33     12 $self->{'_opts'}->{'pager'} = ( $cfg->{'pager'} ||
88             $self->_find_bin('pager') ||
89             $self->_find_bin('less') ||
90             $self->_find_bin('more') );
91 3   33     30 $self->{'_opts'}->{'stty'} = $cfg->{'stty'} || $self->_find_bin('stty');
92              
93             $self->{'_opts'}->{'trust-input'} =
94             ( exists $cfg->{'trust-input'}
95 3 50 66     36 && $cfg->{'trust-input'}==1
96             ) ? 1 : 0;
97              
98 3         14 $self->{'_state'} = {'rv'=>0};
99              
100 3         15 return($self);
101             }
102              
103             #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
104             #: Iherited Overrides
105             #:
106              
107             sub _organize_text {
108 0     0     my $self = shift();
109 0   0       my $text = shift() || return();
110 0           my @array;
111 0 0         if (ref($text) eq "ARRAY") {
    0          
112 0           push(@array,@{$text});
  0            
113             }
114             elsif ($text =~ /\\n/) {
115 0           @array = split(/\\n/,$text);
116             }
117             else {
118 0           @array = split(/\n/,$text);
119             }
120 0           $text = undef();
121 0           $text = join("\n",@array);
122 0           return($self->_strip_text($text));
123             }
124             sub _merge_attrs {
125 0     0     my $self = shift();
126 0 0         my $args = (@_ % 2) ? { @_, '_odd' } : { @_ };
127 0           my $defs = $self->{'_opts'};
128 0           foreach my $def (keys(%$defs)) {
129 0 0         $args->{$def} = $defs->{$def} unless $args->{$def};
130             }
131             # alias 'filename' and 'file' to path
132             $args->{'path'} = (($args->{'filename'}) ? $args->{'filename'} :
133             ($args->{'file'}) ? $args->{'file'} :
134 0 0         ($args->{'path'}) ? $args->{'path'} : "");
    0          
    0          
135 0   0       $args->{'clear'} = $args->{'clearbefore'} || $args->{'clearafter'} || $args->{'autoclear'} || 0;
136 0   0       $args->{'beep'} = $args->{'beepbefore'} || $args->{'beepafter'} || $args->{'autobeep'} || 0;
137 0           return($args);
138             }
139              
140             #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
141             #: Private Methods
142             #:
143              
144             #: this is the dynamic 'Colon Command Help'
145             sub _WRITE_HELP_TEXT {
146 0     0     my $self = shift();
147 0           my ($head,$foot);
148 0           my $body = "
149             Colon Commands: [':?' (This help message)], [':pg ' (Go to page 'N')],
150             [':n'|':next' (Go to the next page)], [':p'|':prev' (Go to the previous page)],
151             [':esc'|':escape' (Send the [Esc] signal)].
152             ";
153             # $head .= ("~" x 79);
154 0 0 0       if ($self->{'_opts'}->{'extra-button'} || $self->{'_opts'}->{'extra-label'}) {
155 0           $foot .= "[':e'|':extra' (Send the [Extra] signal)]\n";
156             }
157 0 0         if (!$self->{'_opts'}->{'nocancel'}) {
158 0           $foot .= "[':c'|':cancel' (Send the [Cancel] signal)]\n";
159             }
160 0 0 0       if ($self->{'_opts'}->{'help-button'} || $self->{'_opts'}->{'help-label'}) {
161 0           $foot .= "[':h'|':help' (Send the [Help] signal)]\n";
162             }
163             # $foot .= ("~" x 79)."\n";
164             # $self->msgbox(title=>'Colon Command Help',text=>$head.$body.$foot);
165 0           $self->msgbox(title=>'Colon Command Help',text=>$body.$foot);
166             }
167              
168             #: this returns the labels (or ' ') for the "extra", "help" and
169             #: "cancel" buttons.
170             sub _BUTTONS {
171 0     0     my $self = shift();
172 0           my $cfg = $self->_merge_attrs(@_);
173 0           my ($help,$cancel,$extra) = (' ',' ',' ');
174 0 0         $extra = "Extra" if $cfg->{'extra-button'};
175 0 0         $extra = $cfg->{'extra-label'} if $cfg->{'extra-label'};
176 0 0 0       $extra = "':e'=[".$extra."]" if $extra and $extra ne ' ';
177 0 0         $help = "Help" if $cfg->{'help-button'};
178 0 0         $help = $self->{'help-label'} if $cfg->{'help-label'};
179 0 0 0       $help = "':h'=[".$help."]" if $help and $help ne ' ';
180 0 0         $cancel = "Cancel" unless $cfg->{'nocancel'};
181 0 0         $cancel = $cfg->{'cancellabel'} if $cfg->{'cancellabel'};
182 0 0 0       $cancel = "':c'=[".$cancel."]" if $cancel and $cancel ne ' ';
183 0           return($help,$cancel,$extra);
184             }
185              
186              
187             #: this writes a standard ascii interface to STDOUT. This is intended for use
188             #: with any non-list native ascii mode widgets.
189 0           sub _WRITE_TEXT {
190 0     0     my $self = shift();
191 0           my $cfg = $self->_merge_attrs(@_);
192 0           my $text = "";
193 0 0         if ($cfg->{'literal'}) {
194 0   0       $text = $cfg->{'text'} || '';
195             }
196             else {
197 0   0       $text = $self->_organize_text($cfg->{'text'}) || "";
198             }
199 0           $self->clean_format($cfg->{'trust-input'},\$text);
200 0   0       my $backtitle = $cfg->{'backtitle'} || " ";
201 0   0       my $title = $cfg->{'title'} || " ";
202             format ASCIIPGTXT =
203             +-----------------------------------------------------------------------------+
204             | @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
205             $backtitle
206             +-----------------------------------------------------------------------------+
207             | |
208             | +-------------------------------------------------------------------------+ |
209             | | @|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
210             $title
211             | +-------------------------------------------------------------------------+ |
212             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
213             $text
214             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
215             $text
216             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
217             $text
218             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
219             $text
220             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
221             $text
222             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
223             $text
224             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
225             $text
226             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
227             $text
228             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
229             $text
230             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
231             $text
232             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
233             $text
234             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
235             $text
236             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
237             $text
238             | +-------------------------------------------------------------------------+ |
239             | |
240             +-----------------------------------------------------------------------------+
241             .
242 2     2   10 no strict 'subs';
  2         2  
  2         192  
243 0           my $_fh = select();
244 0 0         select(STDERR) unless not $cfg->{'usestderr'};
245 0           my $LFMT = $~;
246 0           $~ = ASCIIPGTXT;
247 0           write();
248 0           $~= $LFMT;
249 0 0         select($_fh) unless not $cfg->{'usestderr'};
250 2     2   8 use strict 'subs';
  2         2  
  2         708  
251             }
252              
253             #: very much like _WRITE_TEXT() except that this is specifically for
254             #: the menu() widget only.
255 0           sub _WRITE_MENU {
256 0     0     my $self = shift();
257 0           my $cfg = $self->_merge_attrs(@_);
258 0           my $text = "";
259 0 0         if ($cfg->{'literal'}) {
260 0   0       $text = $cfg->{'text'} || '';
261             }
262             else {
263 0   0       $text = $self->_organize_text($cfg->{'text'}) || "";
264             }
265 0           $self->clean_format($cfg->{'trust-input'},\$text);
266 0   0       my $backtitle = $cfg->{'backtitle'} || " ";
267 0   0       my $title = $cfg->{'title'} || " ";
268 0   0       my $menu = $cfg->{'menu'} || [];
269 0           my ($help,$cancel,$extra) = $self->_BUTTONS(@_);
270 0           for (my $i=0;$i<@{$menu};$i++) {
  0            
271 0           $self->clean_format($cfg->{'trust-input'},\$menu->[$i]);
272             }
273             format ASCIIPGMNU =
274             +-----------------------------------------------------------------------------+
275             | @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
276             $backtitle
277             +-----------------------------------------------------------------------------+
278             | |
279             | +-------------------------------------------------------------------------+ |
280             | | @|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
281             $title
282             | +-------------------------------------------------------------------------+ |
283             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
284             $text
285             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
286             $text
287             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
288             $text
289             | +-------------------------------------------------------------------------+ |
290             | @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<< |
291             ($menu->[0]||' '),($menu->[1]||' '),($menu->[2]||' '),($menu->[3]||' '),($menu->[4]||' '),($menu->[5]||' ')
292             | @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<< |
293             ($menu->[6]||' '),($menu->[7]||' '),($menu->[8]||' '),($menu->[9]||' '),($menu->[10]||' '),($menu->[11]||' ')
294             | @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<< |
295             ($menu->[12]||' '),($menu->[13]||' '),($menu->[14]||' '),($menu->[15]||' '),($menu->[16]||' '),($menu->[17]||' ')
296             | @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<< |
297             ($menu->[18]||' '),($menu->[19]||' '),($menu->[20]||' '),($menu->[21]||' '),($menu->[22]||' '),($menu->[23]||' ')
298             | @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<< |
299             ($menu->[24]||' '),($menu->[25]||' '),($menu->[26]||' '),($menu->[27]||' '),($menu->[28]||' '),($menu->[29]||' ')
300             | @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<< |
301             ($menu->[30]||' '),($menu->[31]||' '),($menu->[32]||' '),($menu->[33]||' '),($menu->[34]||' '),($menu->[35]||' ')
302             | @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<< |
303             ($menu->[36]||' '),($menu->[37]||' '),($menu->[38]||' '),($menu->[39]||' '),($menu->[42]||' '),($menu->[43]||' ')
304             | @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<< |
305             ($menu->[42]||' '),($menu->[43]||' '),($menu->[44]||' '),($menu->[45]||' '),($menu->[46]||' '),($menu->[47]||' ')
306             | @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<<< @<<<< @<<<<<<<<<<<<<< |
307             ($menu->[48]||' '),($menu->[49]||' '),($menu->[50]||' '),($menu->[51]||' '),($menu->[52]||' '),($menu->[53]||' ')
308             | @|||||||||||||||||||| @||||||||||||||||||| @||||||||||||||||||| |
309             $extra,$cancel,$help
310             | ':?' = [Colon Command Help] |
311             +-----------------------------------------------------------------------------+
312             .
313 2     2   7 no strict 'subs';
  2         3  
  2         114  
314 0           my $_fh = select();
315 0 0         select(STDERR) unless not $cfg->{'usestderr'};
316 0           my $LFMT = $~;
317 0           $~ = ASCIIPGMNU;
318 0           write();
319 0           $~= $LFMT;
320 0 0         select($_fh) unless not $cfg->{'usestderr'};
321 2     2   6 use strict 'subs';
  2         2  
  2         1139  
322             }
323              
324             #: very much like _WRITE_MENU() except that this is specifically for
325             #: the radiolist() and checklist() widgets only.
326 0           sub _WRITE_LIST {
327 0     0     my $self = shift();
328 0           my $cfg = $self->_merge_attrs(@_);
329 0           my $text = "";
330 0 0         if ($cfg->{'literal'}) {
331 0   0       $text = $cfg->{'text'} || '';
332             }
333             else {
334 0   0       $text = $self->_organize_text($cfg->{'text'}) || "";
335             }
336 0           $self->clean_format($cfg->{'trust-input'},\$text);
337              
338 0   0       my $backtitle = $cfg->{'backtitle'} || " ";
339 0   0       my $title = $cfg->{'title'} || " ";
340 0           my $menu = [];
341 0           push(@{$menu},@{$cfg->{'menu'}});
  0            
  0            
342 0           my ($help,$cancel,$extra) = $self->_BUTTONS(@_);
343 0           my $m = @{$menu};
  0            
344              
345 0 0         if ($cfg->{'wm'}) {
346 0           for (my $i = 2; $i < $m; $i += 3) {
347 0 0 0       if ($menu->[$i] && $menu->[$i] =~ /on/i) {
348 0           $menu->[$i] = '->';
349             }
350             else {
351 0           $menu->[$i] = ' ';
352             }
353             }
354             }
355             else {
356 0           my $mark;
357 0           for (my $i = 2; $i < $m; $i += 3) {
358 0 0 0       if (!$mark && $menu->[$i] && $menu->[$i] =~ /on/i) {
      0        
359 0           $menu->[$i] = '->'; $mark = 1;
  0            
360             }
361             else {
362 0           $menu->[$i] = ' ';
363             }
364             }
365             }
366              
367             format ASCIIPGLST =
368             +-----------------------------------------------------------------------------+
369             | @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
370             $backtitle
371             +-----------------------------------------------------------------------------+
372             | |
373             | +-------------------------------------------------------------------------+ |
374             | | @|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| | |
375             $title
376             | +-------------------------------------------------------------------------+ |
377             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
378             $text
379             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
380             $text
381             | | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |
382             $text
383             | +-------------------------------------------------------------------------+ |
384             |@<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<< |
385             ($menu->[2]||' '),($menu->[0]||' '),($menu->[1]||' '), ($menu->[5]||' '),($menu->[3]||' '),($menu->[4]||' '), ($menu->[8]||' '),($menu->[6]||' '),($menu->[7]||' ')
386             |@<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<< |
387             ($menu->[11]||' '),($menu->[9]||' '),($menu->[10]||' '), ($menu->[14]||' '),($menu->[12]||' '),($menu->[13]||' '), ($menu->[17]||' '),($menu->[15]||' '),($menu->[16]||' ')
388             |@<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<< |
389             ($menu->[20]||' '),($menu->[18]||' '),($menu->[19]||' '), ($menu->[23]||' '),($menu->[21]||' '),($menu->[22]||' '), ($menu->[26]||' '),($menu->[24]||' '),($menu->[25]||' ')
390             |@<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<< |
391             ($menu->[29]||' '),($menu->[27]||' '),($menu->[28]||' '), ($menu->[32]||' '),($menu->[30]||' '),($menu->[31]||' '), ($menu->[35]||' '),($menu->[33]||' '),($menu->[34]||' ')
392             |@<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<< |
393             ($menu->[38]||' '),($menu->[36]||' '),($menu->[37]||' '), ($menu->[41]||' '),($menu->[39]||' '),($menu->[40]||' '), ($menu->[44]||' '),($menu->[42]||' '),($menu->[43]||' ')
394             |@<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<< |
395             ($menu->[47]||' '),($menu->[45]||' '),($menu->[46]||' '), ($menu->[50]||' '),($menu->[48]||' '),($menu->[49]||' '), ($menu->[53]||' '),($menu->[51]||' '),($menu->[52]||' ')
396             |@<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<< |
397             ($menu->[56]||' '),($menu->[54]||' '),($menu->[55]||' '), ($menu->[59]||' '),($menu->[57]||' '),($menu->[58]||' '), ($menu->[62]||' '),($menu->[60]||' '),($menu->[61]||' ')
398             |@<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<< |
399             ($menu->[65]||' '),($menu->[63]||' '),($menu->[64]||' '), ($menu->[68]||' '),($menu->[66]||' '),($menu->[67]||' '), ($menu->[71]||' '),($menu->[69]||' '),($menu->[70]||' ')
400             |@<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<< |
401             ($menu->[74]||' '),($menu->[72]||' '),($menu->[73]||' '), ($menu->[77]||' '),($menu->[75]||' '),($menu->[76]||' '), ($menu->[80]||' '),($menu->[78]||' '),($menu->[79]||' ')
402             |@<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<<< @<<@<<<< @<<<<<<<<<<<<<< |
403             ($menu->[83]||' '),($menu->[81]||' '),($menu->[82]||' '), ($menu->[86]||' '),($menu->[84]||' '),($menu->[85]||' '), ($menu->[89]||' '),($menu->[87]||' '),($menu->[88]||' ')
404             | @|||||||||||||||||||| @||||||||||||||||||| @||||||||||||||||||| |
405             $extra,$cancel,$help
406             | ':?' = [Colon Command Help] |
407             +-----------------------------------------------------------------------------+
408             .
409 2     2   8 no strict 'subs';
  2         3  
  2         113  
410 0           my $_fh = select();
411 0 0         select(STDERR) unless not $cfg->{'usestderr'};
412 0           my $LFMT = $~;
413 0           $~ = ASCIIPGLST;
414 0           write();
415 0           $~= $LFMT;
416 0 0         select($_fh) unless not $cfg->{'usestderr'};
417 2     2   6 use strict 'subs';
  2         2  
  2         7357  
418             }
419              
420             sub _PRINT {
421 0     0     my $self = shift();
422 0           my $stderr = shift();
423 0 0         if ($stderr) {
424 0           print STDERR @_;
425             }
426             else {
427 0           print STDOUT @_;
428             }
429             }
430              
431             #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
432             #: Public Methods
433             #:
434              
435             #:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
436             #: Ask a binary question (Yes/No)
437             sub yesno {
438 0     0 1   my $self = shift();
439 0   0       my $caller = (caller(1))[3] || 'main';
440 0 0 0       $caller = ($caller =~ /^UI\:\:Dialog\:\:Backend\:\:/) ? ((caller(2))[3]||'main') : $caller;
441 0 0 0       if ($_[0] && $_[0] eq 'caller') {
442 0           shift(); $caller = shift();
  0            
443             }
444 0           my $args = $self->_pre($caller,@_);
445 0           my ($YN,$RESP) = ('Yes|no','YES_OR_NO');
446 0 0         $YN = "yes|No" if $self->{'defaultno'};
447 0           while ($RESP !~ /^(y|yes|n|no)$/i) {
448 0           $self->_clear($args->{'clear'});
449 0           $self->_WRITE_TEXT(@_,text=>$args->{'text'});
450 0           $self->_PRINT($args->{'usestderr'},"(".$YN."): ");
451 0           chomp($RESP = );
452 0 0 0       if (!$RESP && $args->{'defaultno'}) {
    0 0        
453 0           $RESP = "no";
454             }
455             elsif (!$RESP && !$args->{'defaultno'}) {
456 0           $RESP = "yes";
457             }
458 0 0         if ($RESP =~ /^(y|yes)$/i) {
459 0           $self->ra("YES");
460 0           $self->rs("YES");
461 0           $self->rv('null');
462             }
463             else {
464 0           $self->ra("NO");
465 0           $self->rs("NO");
466 0           $self->rv(1);
467             }
468             }
469 0           $self->_post($args);
470 0 0         return(1) if $self->state() eq "OK";
471 0           return(0);
472             }
473              
474             #:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
475             #: Text entry
476             sub inputbox {
477 0     0 1   my $self = shift();
478 0   0       my $caller = (caller(1))[3] || 'main';
479 0 0 0       $caller = ($caller =~ /^UI\:\:Dialog\:\:Backend\:\:/) ? ((caller(2))[3]||'main') : $caller;
480 0 0 0       if ($_[0] && $_[0] eq 'caller') {
481 0           shift(); $caller = shift();
  0            
482             }
483 0           my $args = $self->_pre($caller,@_);
484 0           my $length = $args->{'maxinput'} + 1;
485 0           my $text = $args->{'text'};
486 0           my $string;
487 0           chomp($text);
488 0           while ($length > $args->{'maxinput'}) {
489 0           $self->_clear($args->{'clear'});
490 0           $self->_WRITE_TEXT(@_,'text'=>$args->{'text'});
491 0           $self->_PRINT($args->{'usestderr'},"input: ");
492 0           chomp($string = );
493 0 0         if ($args->{'maxinput'}) {
494 0           $length = length($string);
495             }
496             else {
497 0           $length = 0;
498             }
499 0 0         if ($length > $args->{'maxinput'}) {
500             $self->_PRINT($args->{'usestderr'},"error: too many charaters input,".
501 0           " the maximum is: ".$args->{'maxinput'}."\n");
502             }
503             }
504 0           $self->rv('null');
505 0           $self->ra($string);
506 0           $self->rs($string);
507 0           $self->_post($args);
508 0           return($string);
509             }
510              
511             #:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
512             #: Password entry
513             sub password {
514 0     0 1   my $self = shift();
515 0   0       my $caller = (caller(1))[3] || 'main';
516 0 0 0       $caller = ($caller =~ /^UI\:\:Dialog\:\:Backend\:\:/) ? ((caller(2))[3]||'main') : $caller;
517 0 0 0       if ($_[0] && $_[0] eq 'caller') {
518 0           shift(); $caller = shift();
  0            
519             }
520 0           my $args = $self->_pre($caller,@_);
521             croak("The UI::Dialog::Backend::ASCII password widget depends on the stty ".
522             "binary. This was not found or is not executable.")
523 0 0         unless -x $args->{'stty'};
524 0           my ($length,$key) = ($args->{'maxinput'} + 1,'');
525 0           my $string;
526 0           my $text = $args->{'text'};
527 0           chomp($text);
528 0           my $ENV_PATH = $ENV{'PATH'};
529 0           $ENV{'PATH'} = "";
530 0           while ($length > $args->{'maxinput'}) {
531 0           $self->_clear($args->{'clear'});
532 0           $self->_WRITE_TEXT(@_,'text'=>$args->{'text'});
533 0           $self->_PRINT($args->{'usestderr'},"input: ");
534 0 0         if ($self->_is_bsd()) {
535 0           system "$args->{'stty'} cbreak /dev/tty 2>&1";
536             }
537             else {
538 0           system $args->{'stty'}, '-icanon', 'eol', "\001";
539             }
540 0           while ($key = getc(STDIN)) {
541 0 0         last if $key =~ /\n/;
542 0 0         if ($key =~ /^\x1b$/) {
    0          
543             #this could be the DELETE key (not BS or ^H)
544             # ^[[3~ or \x1b\x5b\x33\x7e (aka: ESC + [ + 3 + ~)
545 0           my $key2 = getc(STDIN);
546 0 0         if ($key2 =~ /^\x5b$/) {
547 0           my $key3 = getc(STDIN);
548 0 0         if ($key3 =~ /^\x33$/) {
549 0           my $key4 = getc(STDIN);
550 0 0         if ($key4 =~ /^\x7e$/) {
551 0           chop($string);
552             # go back five spaces and print five spaces (erase ^[[3~)
553             # go back five spaces again (backtrack),
554             # go back one space, print a space and go back (erase *)
555 0 0         if ($args->{'usestderr'}) {
556 0           print STDERR "\b\b\b\b\b"." "."\b\b\b\b\b"."\b \b";
557             }
558             else {
559 0           print STDOUT "\b\b\b\b\b"." "."\b\b\b\b\b"."\b \b";
560             }
561             }
562             else {
563 0           $key = $key.$key2.$key3.$key4;
564             }
565             }
566             else {
567 0           $key = $key.$key2.$key3;
568             }
569             }
570             else {
571 0           $key = $key.$key2;
572             }
573             }
574             elsif ($key =~ /^(?:\x08|\x7f)$/) {
575             # this is either a BS or ^H
576 0           chop($string);
577             # go back two spaces and print two spaces (erase ^H)
578             # go back two spaces again (backtrack),
579             # go back one space, print a space and go back (erase *)
580 0 0         if ($args->{'usestderr'}) {
581 0           print STDERR "\b\b"." "."\b\b"."\b \b";
582             }
583             else {
584 0           print STDOUT "\b\b"." "."\b\b"."\b \b";
585             }
586             }
587             else {
588 0 0         if ($args->{'usestderr'}) {
589 0           print STDERR "\b*";
590             }
591             else {
592 0           print STDOUT "\b*";
593             }
594 0           $string .= $key;
595             }
596             }
597 0 0         if ($self->_is_bsd()) {
598 0           system "$args->{'stty'} -cbreak /dev/tty 2>&1";
599             }
600             else {
601 0           system $args->{'stty'}, 'icanon', 'eol', '^@';
602             }
603 0 0         if ($args->{'maxinput'}) {
604 0           $length = length($string);
605             }
606             else {
607 0           $length = 0;
608             }
609 0 0         if ($length > $args->{'maxinput'}) {
610             $self->_PRINT($args->{'usestderr'},"error: too many charaters input,".
611 0           " the maximum is: ".$args->{'maxinput'}."\n");
612             }
613             }
614 0           $ENV{'PATH'} = $ENV_PATH;
615 0           $self->rv('null');
616 0           $self->ra($string);
617 0           $self->rs($string);
618 0           $self->_post($args);
619 0           return($string);
620             }
621              
622             #:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
623             #: Information box
624             sub infobox {
625 0     0 1   my $self = shift();
626 0   0       my $caller = (caller(1))[3] || 'main';
627 0 0 0       $caller = ($caller =~ /^UI\:\:Dialog\:\:Backend\:\:/) ? ((caller(2))[3]||'main') : $caller;
628 0 0 0       if ($_[0] && $_[0] eq 'caller') {
629 0           shift(); $caller = shift();
  0            
630             }
631 0           my $args = $self->_pre($caller,@_);
632 0           $self->_WRITE_TEXT(@_,'text'=>$args->{'text'});
633 0           $self->_PRINT($args->{'usestderr'});
634             my $s = int(($args->{'wait'}) ? $args->{'wait'} :
635 0 0         ($args->{'timeout'}) ? ($args->{'timeout'} / 1000.0) : 1.0);
    0          
636 0           sleep($s);
637 0           $self->rv('null');
638 0           $self->ra('null');
639 0           $self->rs('null');
640 0           $self->_post($args);
641 0           return(1);
642             }
643              
644             #:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
645             #: Message box
646             sub msgbox {
647 0     0 1   my $self = shift();
648 0   0       my $caller = (caller(1))[3] || 'main';
649 0 0 0       $caller = ($caller =~ /^UI\:\:Dialog\:\:Backend\:\:/) ? ((caller(2))[3]||'main') : $caller;
650 0 0 0       if ($_[0] && $_[0] eq 'caller') {
651 0           shift(); $caller = shift();
  0            
652             }
653 0           my $args = $self->_pre($caller,@_);
654 0           $self->_WRITE_TEXT(@_,'text'=>$args->{'text'});
655 0           $self->_PRINT($args->{'usestderr'},(" " x 25)."[ Press Enter to Continue ]");
656 0           my $junk = ;
657 0           $self->rv('null');
658 0           $self->ra('null');
659 0           $self->rs('null');
660 0           $self->_post($args);
661 0           return(1);
662             }
663              
664              
665             #:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
666             #: Text box
667             sub textbox {
668 0     0 1   my $self = shift();
669 0   0       my $caller = (caller(1))[3] || 'main';
670 0 0 0       $caller = ($caller =~ /^UI\:\:Dialog\:\:Backend\:\:/) ? ((caller(2))[3]||'main') : $caller;
671 0 0 0       if ($_[0] && $_[0] eq 'caller') {
672 0           shift(); $caller = shift();
  0            
673             }
674 0           my $args = $self->_pre($caller,@_);
675 0           my $rv = 0;
676 0 0         if (-r $args->{'path'}) {
677 0           my $ENV_PATH = $ENV{'PATH'};
678 0           $ENV{'PATH'} = "";
679 0 0 0       if ($ENV{'PAGER'} && -x $ENV{'PAGER'}) {
    0          
680 0           system($ENV{'PAGER'}." ".$args->{'path'});
681 0           $rv = $? >> 8;
682             }
683             elsif (-x $args->{'pager'}) {
684 0           system($args->{'pager'}." ".$args->{'path'});
685 0           $rv = $? >> 8;
686             }
687             else {
688 0           open(ATBFILE,"<".$args->{'path'});
689 0           local $/;
690 0           my $data = ;
691 0           close(ATBFILE);
692 0           $self->_PRINT($args->{'usestderr'},$data);
693             }
694 0           $ENV{'PATH'} = $ENV_PATH;
695             }
696             else {
697 0           return($self->msgbox('title'=>'error','text'=>$args->{'path'}.' is not a readable text file.'));
698             }
699 0   0       $self->rv($rv||'null');
700 0           $self->ra('null');
701 0           $self->rs('null');
702 0           $self->_post($args);
703 0           return($rv);
704             }
705              
706             #:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
707             #: A simple menu
708             sub menu {
709 0     0 1   my $self = shift();
710 0   0       my $caller = (caller(1))[3] || 'main';
711 0 0 0       $caller = ($caller =~ /^UI\:\:Dialog\:\:Backend\:\:/) ? ((caller(2))[3]||'main') : $caller;
712 0 0 0       if ($_[0] && $_[0] eq 'caller') {
713 0           shift(); $caller = shift();
  0            
714             }
715 0           my $args = $self->_pre($caller,@_);
716 0 0 0       $args->{'menu'} ||= ref($args->{'list'}) ? $args->{'list'} : [$args->{'list'}];
717 0   0       $args->{'menu'} ||= [];
718 0           my $string;
719 0           my $rs = '';
720 0           my $m = 0;
721 0           $m = @{$args->{'menu'}};
  0            
722 0           my ($valid,$menu,$realm) = ([],[],[]);
723 0 0         push(@{$menu},@{$args->{'menu'}}) if ref($args->{'menu'}) eq "ARRAY";
  0            
  0            
724              
725 0           for (my $i = 0; $i < $m; $i += 2) {
726 0           push(@{$valid},$menu->[$i]);
  0            
727             }
728              
729 0 0         if (@{$menu} >= 60) {
  0            
730 0           my $c = 0;
731 0           while (@{$menu}) {
  0            
732 0           $realm->[$c] = [];
733 0           for (my $i = 0; $i < 60; $i++) {
734 0           push(@{$realm->[$c]},shift(@{$menu}));
  0            
  0            
735             }
736 0           $c++;
737             }
738             }
739             else {
740 0           $realm->[0] = [];
741 0           push(@{$realm->[0]},@{$menu});
  0            
  0            
742             }
743 0           my $pg = 1;
744 0           while (!$rs) {
745 0   0       $self->_WRITE_MENU(@_,'text'=>$args->{'text'},
746             'menu'=>$realm->[($pg - 1||0)]);
747 0           $self->_PRINT($args->{'usestderr'},"(".$pg."/".@{$realm}."): ");
  0            
748 0           chomp($rs = );
749 0 0 0       if ($rs =~ /^:\?$/i) {
    0 0        
    0 0        
    0 0        
    0          
    0          
    0          
    0          
750 0           $self->_clear($args->{'clear'});
751 0           $self->_WRITE_HELP_TEXT();
752 0           undef($rs);
753 0           next;
754             }
755             elsif ($rs =~ /^:(esc|escape)$/i) {
756 0           $self->_clear($args->{'clear'});
757 0           undef($rs);
758 0           $self->rv(255);
759 0           return(0);
760             }
761             elsif (($args->{'extra-button'} || $args->{'extra-label'}) && $rs =~ /^:(e|extra)$/i) {
762 0           $self->rv(3);
763 0           return('EXTRA');
764             }
765             elsif ($args->{'help-button'} && $rs =~ /^:(h|help)$/i) {
766 0           $self->_clear($args->{'clear'});
767 0           undef($rs);
768 0           $self->rv(2);
769 0           return($self->state());
770             }
771             elsif (!$args->{'nocancel'} && $rs =~ /^:(c|cancel)$/i) {
772 0           $self->_clear($args->{'clear'});
773 0           undef($rs);
774 0           $self->rv(1);
775 0           return($self->state());
776             }
777             elsif ($rs =~ /^:pg\s*(\d+)$/i) {
778 0           my $p = $1;
779 0 0 0       if ($p <= @{$realm} && $p > 0) {
  0            
780 0           $pg = $p;
781             }
782 0           undef($rs);
783             }
784             elsif ($rs =~ /^:(n|next)$/i) {
785 0 0         if ($pg < @{$realm}) {
  0            
786 0           $pg++;
787             }
788             else {
789 0           $pg = 1;
790             }
791 0           undef($rs);
792             }
793             elsif ($rs =~ /^:(p|prev)$/i) {
794 0 0         if ($pg > 1) {
795 0           $pg--;
796             }
797             else {
798 0           $pg = @{$realm};
  0            
799             }
800 0           undef($rs);
801             }
802             else {
803 0 0         if (@_ = grep { /^\Q$rs\E$/i } @{$valid}) {
  0            
  0            
804 0           $rs = $_[0];
805             }
806             else {
807 0           undef($rs);
808             }
809             }
810 0           $self->_clear($args->{'clear'});
811             }
812              
813 0           $self->rv('null');
814 0           $self->ra($rs);
815 0           $self->rs($rs);
816 0           $self->_post($args);
817 0           return($rs);
818             }
819              
820             #:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
821             #: A multi-selectable list
822             sub checklist {
823 0     0 1   my $self = shift();
824 0   0       my $caller = (caller(1))[3] || 'main';
825 0 0 0       $caller = ($caller =~ /^UI\:\:Dialog\:\:Backend\:\:/) ? ((caller(2))[3]||'main') : $caller;
826 0 0 0       if ($_[0] && $_[0] eq 'caller') {
827 0           shift(); $caller = shift();
  0            
828             }
829 0           my $args = $self->_pre($caller,@_);
830 0   0       my $menulist = ($args->{'menu'} || $args->{'list'});
831 0           my $menufix = [];
832 0 0         if (ref($menulist) eq "ARRAY") {
833             #: flatten our multidimensional array
834 0           foreach my $item (@$menulist) {
835 0 0         if (ref($item) eq "ARRAY") {
836 0 0         pop(@{$item}) if @$item == 3;
  0            
837 0           push(@$menufix,@{$item});
  0            
838             }
839             else {
840 0           push(@$menufix,$item);
841             }
842             }
843             }
844 0           $args->{'menu'} = $menufix;
845              
846 0           my $ra = [];
847 0           my $rs = '';
848 0           my $m;
849 0 0         $m = @{$args->{'menu'}} if ref($args->{'menu'}) eq "ARRAY";
  0            
850 0           my ($valid,$menu,$realm) = ([],[],[]);
851 0 0         push(@{$menu},@{$args->{'menu'}}) if ref($args->{'menu'}) eq "ARRAY";
  0            
  0            
852              
853 0           for (my $i = 0; $i < $m; $i += 3) {
854 0           push(@{$valid},$menu->[$i]);
  0            
855             }
856              
857 0 0         if (@{$menu} >= 90) {
  0            
858 0           my $c = 0;
859 0           while (@{$menu}) {
  0            
860 0           $realm->[$c] = [];
861 0           for (my $i = 0; $i < 90; $i++) {
862 0           push(@{$realm->[$c]},shift(@{$menu}));
  0            
  0            
863             }
864 0           $c++;
865             }
866             }
867             else {
868 0           $realm->[0] = [];
869 0           push(@{$realm->[0]},@{$menu});
  0            
  0            
870             }
871 0           my $go = "GO";
872 0           my $pg = 1;
873 0           while ($go) {
874 0   0       $self->_WRITE_LIST(@_,'wm'=>'check','text'=>$args->{'text'},'menu'=>$realm->[($pg - 1||0)]);
875 0           $self->_PRINT($args->{'usestderr'},"(".$pg."/".@{$realm}."): ");
  0            
876 0           chomp($rs = );
877 0 0 0       if ($rs =~ /^:\?$/i) {
    0 0        
    0 0        
    0 0        
    0 0        
    0          
    0          
    0          
878 0           $self->_clear($args->{'clear'});
879 0           $self->_WRITE_HELP_TEXT();
880 0           undef($rs);
881 0           next;
882             }
883             elsif ($rs =~ /^:(esc|escape)$/i) {
884 0           $self->_clear($args->{'clear'});
885 0           undef($rs);
886 0           $self->rv(255);
887 0           return($self->state());
888             }
889             elsif (($args->{'extra-button'} || $args->{'extra-label'}) && $rs =~ /^:(e|extra)$/i) {
890 0           $self->_clear($args->{'clear'});
891 0           $self->rv(3);
892 0           return($self->state());
893             }
894             elsif (($args->{'help-button'} || $args->{'help-label'}) && $rs =~ /^:(h|help)$/i) {
895 0           $self->_clear($args->{'clear'});
896 0           undef($rs);
897 0           $self->rv(2);
898 0           return($self->rv());
899             }
900             elsif (!$args->{'nocancel'} && $rs =~ /^:(c|cancel)$/i) {
901 0           $self->_clear($args->{'clear'});
902 0           undef($rs);
903 0           $self->rv(1);
904 0           return($self->state());
905             }
906             elsif ($rs =~ /^:pg\s*(\d+)$/i) {
907 0           my $p = $1;
908 0 0 0       if ($p <= @{$realm} && $p > 0) {
  0            
909 0           $pg = $p;
910             }
911             }
912             elsif ($rs =~ /^:(n|next)$/i) {
913 0 0         if ($pg < @{$realm}) {
  0            
914 0           $pg++;
915             }
916             else {
917 0           $pg = 1;
918             }
919             }
920             elsif ($rs =~ /^:(p|prev)$/i) {
921 0 0         if ($pg > 1) {
922 0           $pg--;
923             }
924             else {
925 0           $pg = @{$realm};
  0            
926             }
927             }
928             else {
929 0           my @opts = split(/\,\s|\,|\s/,$rs);
930 0           my @good;
931 0           foreach my $opt (@opts) {
932 0 0         if (@_ = grep { /^\Q$opt\E$/i } @{$valid}) {
  0            
  0            
933 0           push(@good,$_[0]);
934             }
935             }
936 0 0         if (@opts == @good) {
937 0           undef($go);
938 0           $ra = [];
939 0           push(@{$ra},@good);
  0            
940             }
941             }
942 0           $self->_clear($args->{'clear'});
943 0           undef($rs);
944             }
945              
946 0           $self->rv('null');
947 0           $self->ra($ra);
948 0           $self->rs(join("\n",@$ra));
949 0           $self->_post($args);
950 0           return(@{$ra});
  0            
951             }
952              
953             #:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
954             #: A radio button based list. very much like the menu widget.
955             sub radiolist {
956 0     0 1   my $self = shift();
957 0   0       my $caller = (caller(1))[3] || 'main';
958 0 0 0       $caller = ($caller =~ /^UI\:\:Dialog\:\:Backend\:\:/) ? ((caller(2))[3]||'main') : $caller;
959 0 0 0       if ($_[0] && $_[0] eq 'caller') {
960 0           shift(); $caller = shift();
  0            
961             }
962 0           my $args = $self->_pre($caller,@_);
963 0   0       my $menulist = ($args->{'menu'} || $args->{'list'});
964 0           my $menufix = [];
965 0 0         if (ref($menulist) eq "ARRAY") {
966             #: flatten our multidimensional array
967 0           foreach my $item (@$menulist) {
968 0 0         if (ref($item) eq "ARRAY") {
969 0 0         pop(@{$item}) if @$item == 3;
  0            
970 0           push(@$menufix,@{$item});
  0            
971             }
972             else {
973 0           push(@$menufix,$item);
974             }
975             }
976             }
977 0           $args->{'menu'} = $menufix;
978 0           my $rs = '';
979 0           my $m;
980 0 0         $m = @{$args->{'menu'}} if ref($args->{'menu'}) eq "ARRAY";
  0            
981 0           my ($valid,$menu,$realm) = ([],[],[]);
982 0 0         push(@{$menu},@{$args->{'menu'}}) if ref($args->{'menu'}) eq "ARRAY";
  0            
  0            
983              
984 0           for (my $i = 0; $i < $m; $i += 3) {
985 0           push(@{$valid},$menu->[$i]);
  0            
986             }
987              
988 0 0         if (@{$menu} >= 90) {
  0            
989 0           my $c = 0;
990 0           while (@{$menu}) {
  0            
991 0           $realm->[$c] = [];
992 0           for (my $i = 0; $i < 90; $i++) {
993 0           push(@{$realm->[$c]},shift(@{$menu}));
  0            
  0            
994             }
995 0           $c++;
996             }
997             }
998             else {
999 0           $realm->[0] = [];
1000 0           push(@{$realm->[0]},@{$menu});
  0            
  0            
1001             }
1002 0           my $pg = 1;
1003 0           while (!$rs) {
1004 0   0       $self->_WRITE_LIST(@_,'text'=>$args->{'text'},'menu'=>$realm->[($pg - 1||0)]);
1005 0           $self->_PRINT($args->{'usestderr'},"(".$pg."/".@{$realm}."): ");
  0            
1006 0           chomp($rs = );
1007 0 0 0       if ($rs =~ /^:\?$/i) {
    0 0        
    0 0        
    0 0        
    0 0        
    0          
    0          
    0          
1008 0           $self->_clear($args->{'clear'});
1009 0           $self->_WRITE_HELP_TEXT();
1010 0           undef($rs);
1011 0           next;
1012             }
1013             elsif ($rs =~ /^:(esc|escape)$/i) {
1014 0           $self->_clear($args->{'clear'});
1015 0           undef($rs);
1016 0           $self->rv(255);
1017 0           return($self->rv());
1018             }
1019             elsif (($args->{'extra-button'} || $args->{'extra-label'}) && $rs =~ /^:(e|extra)$/i) {
1020 0           $self->rv(3);
1021 0           return($self->state());
1022             }
1023             elsif (($args->{'help-button'} || $args->{'help-label'}) && $rs =~ /^:(h|help)$/i) {
1024 0           $self->_clear($args->{'clear'});
1025 0           undef($rs);
1026 0           $self->rv(2);
1027 0           return($self->state());
1028             }
1029             elsif (!$args->{'nocancel'} && $rs =~ /^:(c|cancel)$/i) {
1030 0           $self->_clear($args->{'clear'});
1031 0           undef($rs);
1032 0           $self->rv(1);
1033 0           return($self->state());
1034             }
1035             elsif ($rs =~ /^:pg\s*(\d+)$/i) {
1036 0           my $p = $1;
1037 0 0 0       if ($p <= @{$realm} && $p > 0) {
  0            
1038 0           $pg = $p;
1039             }
1040 0           undef($rs);
1041             }
1042             elsif ($rs =~ /^:(n|next)$/i) {
1043 0 0         if ($pg < @{$realm}) {
  0            
1044 0           $pg++;
1045             }
1046             else {
1047 0           $pg = 1;
1048             }
1049 0           undef($rs);
1050             }
1051             elsif ($rs =~ /^:(p|prev)$/i) {
1052 0 0         if ($pg > 1) {
1053 0           $pg--;
1054             }
1055             else {
1056 0           $pg = @{$realm};
  0            
1057             }
1058 0           undef($rs);
1059             }
1060             else {
1061 0 0         if (@_ = grep { /^\Q$rs\E$/i } @{$valid}) {
  0            
  0            
1062 0           $rs = $_[0];
1063             }
1064             else {
1065 0           undef($rs);
1066             }
1067             }
1068 0           $self->_clear($args->{'clear'});
1069             }
1070              
1071 0           $self->rv('null');
1072 0           $self->ra($rs);
1073 0           $self->rs($rs);
1074 0           $self->_post($args);
1075 0           return($rs);
1076             }
1077              
1078              
1079             #:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1080             #: Simple ASCII progress indicator :)
1081             sub spinner {
1082 0     0 1   my $self = shift();
1083 0 0 0       if (!$self->{'__SPIN'} || $self->{'__SPIN'} == 1) {
    0          
    0          
    0          
1084 0           $self->{'__SPIN'} = 2; return("\b|");
  0            
1085             }
1086             elsif ($self->{'__SPIN'} == 2) {
1087 0           $self->{'__SPIN'} = 3; return("\b/");
  0            
1088             }
1089             elsif ($self->{'__SPIN'} == 3) {
1090 0           $self->{'__SPIN'} = 4; return("\b-");
  0            
1091             }
1092             elsif ($self->{'__SPIN'} == 4) {
1093 0           $self->{'__SPIN'} = 1; return("\b\\");
  0            
1094             }
1095             }
1096              
1097             #:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1098             #: Simple ASCII meter bar
1099             # the idea of a "true" dialog like gauge widget with ASCII is not that bad and
1100             # as such, I've named these methods differently so as to keep the namespace
1101             # open for gauge_*() widgets.
1102             sub draw_gauge {
1103 0     0 1   my $self = shift();
1104 0           my $args = $self->_merge_attrs(@_);
1105 0   0       my $length = $args->{'length'} || $args->{'width'} || 74;
1106 0   0       my $bar = ($args->{'bar'} || "-") x $length;
1107 0   0       my $current = $args->{'current'} || 0;
1108 0   0       my $total = $args->{'total'} || 0;
1109             my $percent = (($current && $total) ? int($current / ($total / 100)) :
1110 0 0 0       ($args->{'percent'} || '0'));
      0        
1111 0 0 0       $percent = int(($percent <= 100 && $percent >= 0) ? $percent : 0 );
1112 0           my $perc = int((($length / 100) * $percent));
1113 0   0       substr($bar,($perc||0),1,($args->{'mark'}||"|"));
      0        
1114 0 0         my $text = (($percent =~ /^\d$/) ? " " :
    0          
1115             ($percent =~ /^\d\d$/) ? " " : "").$percent."% ".$bar;
1116 0 0 0       $self->_PRINT($args->{'usestderr'},(($args->{'noCR'} && not $args->{'CR'}) ? "" : "\x0D").$text);
1117 0   0       return($percent||1);
1118             }
1119             sub end_gauge {
1120 0     0 1   my $self = shift();
1121 0           my $args = $self->_merge_attrs(@_);
1122 0           $self->_PRINT($args->{'usestderr'},"\n");
1123             }
1124              
1125             1;