File Coverage

blib/lib/UI/Various/Listbox.pm
Criterion Covered Total %
statement 90 93 96.7
branch 35 38 92.1
condition 3 3 100.0
subroutine 21 21 100.0
pod 8 8 100.0
total 157 163 96.3


line stmt bran cond sub pod time code
1             package UI::Various::Listbox;
2              
3             # Author, Copyright and License: see end of file
4              
5             =head1 NAME
6              
7             UI::Various::Listbox - general listbox widget of L
8              
9             =head1 SYNOPSIS
10              
11             use UI::Various;
12             my $main = UI::Various::main();
13             my $variable = 0;
14             $main->window(...
15             UI::Various::Listbox->new(height => 5,
16             selection => 2,
17             texts => \@variable),
18             ...);
19             $main->mainloop();
20              
21             =head1 ABSTRACT
22              
23             This module defines the general listbox widget of an application using
24             L.
25              
26             =head1 DESCRIPTION
27              
28             Besides the common attributes inherited from C the
29             C widget knows the following additional attributes:
30              
31             =head2 Attributes
32              
33             =over
34              
35             =cut
36              
37             #########################################################################
38              
39 8     8   102 use v5.14;
  8         24  
40 8     8   40 use strictures;
  8         17  
  8         51  
41 8     8   1393 no indirect 'fatal';
  8         15  
  8         42  
42 8     8   421 no multidimensional;
  8         16  
  8         46  
43 8     8   244 use warnings 'once';
  8         17  
  8         424  
44              
45             our $VERSION = '0.22';
46              
47 8     8   46 use UI::Various::core;
  8         13  
  8         55  
48 8     8   46 use UI::Various::widget;
  8         17  
  8         535  
49 8     8   42 BEGIN { require 'UI/Various/' . UI::Various::core::using() . '/Listbox.pm'; }
50              
51             require Exporter;
52             our @ISA = qw(UI::Various::widget);
53             our @EXPORT_OK = qw();
54              
55             #########################################################################
56              
57             =item height [rw]
58              
59             the height of the listbox is the maximum number of elements shown
60              
61             Other then in other UI elements it is a mandatory parameter. Note the the
62             C<*Term> UIs use one additional line for the position information at the top
63             of the listbox.
64              
65             =cut
66              
67             sub height($;$)
68             {
69             return access('height',
70             sub{
71 10 100 100 10   79 unless (m/^\d+$/ and $_ > 0)
72             {
73 2         5 error('parameter__1_must_be_a_positive_integer',
74             'height');
75 2         10 $_ = 5;
76             }
77             },
78 27     27 1 142 @_);
79             }
80              
81             =item selection [rw, recommended]
82              
83             the selection type of the listbox, a number between 0 and 2, defaults to 2:
84              
85             =over
86              
87             =item 0 - the elements are not selectable
88              
89             =item 1 - only single selection
90              
91             =item 2 - multiple selection is possible
92              
93             =back
94              
95             =cut
96              
97             sub selection($;$)
98             {
99             return access('selection',
100             sub{
101 5 100   5   24 unless (m/^[012]$/)
102             {
103 1         4 error('parameter__1_must_be_in__2__3',
104             'selection', 0, 2);
105 1         5 $_ = 2;
106             }
107             },
108 23     23 1 82 @_);
109             }
110              
111             =item texts [ro, recommended]
112              
113             the texts of the elements of the listbox as strings
114              
115             The default is an empty list.
116              
117             Note that the content of the list may only be modified with the methods
118             provided by C (C> and
119             C>). The only exception is when the
120             listbox did not yet contain any element.
121              
122             =cut
123              
124             sub texts($\@)
125             {
126             return
127             access
128             ('texts',
129             sub{
130 6 100   6   18 unless (ref($_) eq 'ARRAY')
131             {
132 1         3 error('_1_attribute_must_be_a_2_reference', 'texts', 'ARRAY');
133 1         12 return undef;
134             }
135 5         9 my ($self) = @_;
136 5 100       13 if ($self->{_initialised})
137             {
138 1         6 error('_1_may_not_be_modified_directly_after_initialisation',
139             'texts');
140 1         12 return undef;
141             }
142 4         6 my $entries = @$_;
143 4 100       8 if ($entries > 0)
144             {
145 3         5 local $_ = 0;
146 3         15 $self->{_selected} = [ (' ') x $entries ];
147 3         10 $self->{_initialised} = 1;
148 3         13 $self->{first} = 0;
149             }
150             else
151 1         4 { $self->{first} = -1; }
152             },
153 40     40 1 795 @_);
154             }
155              
156             =item first [ro]
157              
158             the index of the first element to be shown
159              
160             The last element shown will have the index C + C - 1, if
161             C is long enough.
162              
163             =cut
164              
165             sub first($)
166             {
167 28     28 1 730 return get('first', $_[0]);
168             }
169              
170             #########################################################################
171             #
172             # internal constants and data:
173              
174 8         887 use constant ALLOWED_PARAMETERS =>
175 8     8   62 (UI::Various::widget::COMMON_PARAMETERS, qw(first selection texts));
  8         20  
176 8     8   55 use constant DEFAULT_ATTRIBUTES => (first => -1, selection => 2, texts => []);
  8         14  
  8         7010  
177              
178             #########################################################################
179             #########################################################################
180              
181             =back
182              
183             =head1 METHODS
184              
185             Besides the accessors (attributes) described above and by
186             L and the methods
187             inherited from L only the
188             constructor is provided by the C class itself:
189              
190             =cut
191              
192             #########################################################################
193              
194             =head2 B - constructor
195              
196             see L
197             constructor for UI elements>
198              
199             =cut
200              
201             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
202              
203             sub new($;\[@$])
204             {
205 9     9 1 2834 debug(3, __PACKAGE__, '::new');
206 9         77 local $_ = construct({ DEFAULT_ATTRIBUTES },
207             '^(?:' . join('|', ALLOWED_PARAMETERS) . ')$',
208             @_);
209 9 100       37 unless (defined $_->{height})
210             {
211 1         4 error('mandatory_parameter__1_is_missing', 'height');
212 1         10 return undef;
213             }
214 8         29 return $_;
215             }
216              
217             #########################################################################
218              
219             =head2 B - add new element
220              
221             $listbox->add($text, ...);
222              
223             =head3 example:
224              
225             $self->add('one more');
226             $self->add('one more', 'still one more');
227              
228             =head3 parameters:
229              
230             $text another text to be added to the end of the listbox
231              
232             =head3 description:
233              
234             This method adds one or more new elements at the end of the listbox.
235              
236             =cut
237              
238             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
239             sub add($@)
240             {
241 5     5 1 1858 my $self = shift;
242              
243             # sanity checks:
244 5 100       28 $self->isa(__PACKAGE__)
245             or fatal('invalid_object__1_in_call_to__2__3',
246             ref($self), __PACKAGE__, 'add');
247              
248 4         5 push @{$self->{texts}}, @_;
  4         20  
249 4         6 push @{$self->{_selected}}, (' ') x scalar(@_);
  4         15  
250             # call UI-specific implementation, if applicable:
251 4 50       24 if ($self->can('_add'))
252 0         0 { $self->_add(@_); }
253             }
254              
255             #########################################################################
256              
257             =head2 B - remove element
258              
259             $listbox->remove($index);
260              
261             =head3 example:
262              
263             $self->remove(2);
264              
265             =head3 parameters:
266              
267             $index the index of the element to be removed from the listbox
268              
269             =head3 description:
270              
271             This method removes an element from the listbox. The element to be removed
272             is identified by its index. Indices start with 0.
273              
274             =cut
275              
276             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
277             sub remove($$)
278             {
279 18     18 1 5443 my ($self, $index) = (@_);
280              
281             # sanity checks:
282 18 100       58 $self->isa(__PACKAGE__)
283             or fatal('invalid_object__1_in_call_to__2__3',
284             ref($self), __PACKAGE__, 'remove');
285 17 100       91 unless ($index =~ m/^\d+$/)
286             {
287 1         5 error('parameter__1_must_be_a_positive_integer_in_call_to__2__3',
288             'index', __PACKAGE__, 'remove');
289 1         5 return;
290             }
291 16 100       22 if ($index <= $#{$self->{texts}})
  16         36  
292             {
293 15         18 splice @{$self->{texts}}, $index, 1;
  15         25  
294 15         20 splice @{$self->{_selected}}, $index, 1;
  15         20  
295 15         33 $self->first <= $#{$self->{texts}} or
296 15 100       28 $self->{first} = 0 < @{$self->{texts}} ? 0 : -1;
  3 100       8  
297             }
298             # call UI-specific implementation, if applicable:
299 16 50       95 if ($self->can('_remove'))
300 0         0 { $self->_remove($index); }
301             }
302              
303             #########################################################################
304              
305             =head2 B - get current selection of listbox
306              
307             $selection = $listbox->selected(); # C 1>
308             @selection = $listbox->selected(); # C 2>
309              
310             =head3 description:
311              
312             This method returns the sorted indices of the currently selected element(s)
313             of the listbox. Indices start with 0. If there is nothing selected at all,
314             the method returns C for C 1> and an empty list for
315             C 2>.
316              
317             =head3 returns:
318              
319             selected element(s) (or C for C 0>)
320              
321             =cut
322              
323             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
324              
325             sub selected($)
326             {
327 10     10 1 4103 my ($self) = @_;
328 10 100       26 unless ($self->{selection})
329             {
330 1         4 error('invalid_call_to__1__2', __PACKAGE__, 'selected');
331 1         5 return undef;
332             }
333 9         12 my @selected = ();
334 9 50       39 if ($self->can('_selected'))
335             {
336 0         0 @selected = $self->_selected; # call UI-specific implementation
337             }
338             else
339             {
340 9         14 local $_ = 0;
341 9         12 foreach (0..$#{$self->texts})
  9         17  
342             {
343 74 100       128 $self->{_selected}[$_] ne ' ' and push @selected, $_;
344             }
345             }
346             return
347 9 100       17 $self->selection > 1 ? @selected :
    100          
348             0 < @selected ? $selected[0] : undef;
349             }
350              
351             1;
352              
353             #########################################################################
354             #########################################################################
355              
356             =head1 SEE ALSO
357              
358             L
359              
360             =head1 LICENSE
361              
362             Copyright (C) Thomas Dorner.
363              
364             This library is free software; you can redistribute it and/or modify it
365             under the same terms as Perl itself. See LICENSE file for more details.
366              
367             =head1 AUTHOR
368              
369             Thomas Dorner Edorner (at) cpan (dot) orgE
370              
371             =cut