File Coverage

blib/lib/UI/Various/widget.pm
Criterion Covered Total %
statement 57 57 100.0
branch 12 12 100.0
condition 3 3 100.0
subroutine 17 17 100.0
pod 5 5 100.0
total 94 94 100.0


line stmt bran cond sub pod time code
1             package UI::Various::widget;
2              
3             # Author, Copyright and License: see end of file
4              
5             =head1 NAME
6              
7             UI::Various::widget - abstract base class for UI elements
8              
9             =head1 SYNOPSIS
10              
11             # This module should never be used directly!
12             # It is used indirectly via the following:
13             use UI::Various;
14              
15             =head1 ABSTRACT
16              
17             This module is the common abstract base class for all kinds of objects in
18             the L package aka UI elements or widgets.
19              
20             =head1 DESCRIPTION
21              
22             All C modules are classes with the following common
23             attributes (inherited from C):
24              
25             =head2 Attributes
26              
27             (sorted alphabetically)
28              
29             B attributes can be read and modified. The later may have some
30             restrictions. (See documentation of specific attribute).
31              
32             B attributes can only be read and not modified.
33              
34             B attributes may be empty or C.
35              
36             B attributes may be empty or C, but it is advisable to
37             give them a proper value.
38              
39             B attributes may be undefined, but if they are read, a possible
40             value will be searched for all the hierarchy up to either the L
41             Manager"|UI::Various::Main> object or the top-level
42             L or L objects.
43             They may still be undefined everywhere, though.
44              
45             =over
46              
47             =cut
48              
49             #########################################################################
50              
51 23     23   656 use v5.14;
  23         64  
52 23     23   95 use strictures;
  23         36  
  23         95  
53 23     23   3998 no indirect 'fatal';
  23         38  
  23         133  
54 23     23   1206 no multidimensional;
  23         31  
  23         95  
55 23     23   766 use warnings 'once';
  23         36  
  23         1090  
56              
57             our $VERSION = '0.23';
58              
59 23     23   104 use UI::Various::core;
  23         43  
  23         131  
60              
61             require Exporter;
62             our @ISA = qw(Exporter);
63             our @EXPORT_OK = qw();
64              
65             #########################################################################
66              
67             =item height [rw, inherited]
68              
69             preferred (maximum) height of a UI element in (approximately) characters,
70             should not exceed L
71             |UI::Various::Main/max_height ro>
72              
73             Be careful with small height values as this could lead to undisplayed or
74             even discarded UI elements in some of the possible UIs. If this is the main
75             window, the application could be immediately exited!
76              
77             =cut
78              
79             sub height($;$)
80             {
81 14     14 1 781 return _inherited_access('height', undef, @_);
82             }
83              
84             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
85              
86             =item B [rw, optional]
87              
88             a reference to the parent of the current UI element, usually C for
89             the C> object and defined for everything else
90              
91             Note that usually this should only be manipulated by methods of
92             C>.
93              
94             =cut
95              
96             sub parent($;$)
97             {
98             return
99             access('parent',
100             sub{
101 132 100   132   243 if (defined $_)
102             {
103 131 100       505 $_->isa('UI::Various::container') or
104             fatal('invalid_parent__1_not_a_ui_various_container',
105             ref($_));
106             }
107             },
108 2429     2429 1 12277 @_);
109             }
110              
111             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
112              
113             =item width [rw, inherited]
114              
115             preferred (maximum) width of a UI element in (approximately) characters,
116             should not exceed L
117             |UI::Various::Main/max_width ro>
118              
119             =cut
120              
121             sub width($;$)
122             {
123 496     496 1 2265 return _inherited_access('width', undef, @_);
124             }
125              
126             # TODO: fg, bg, x, y, align (1-9, default 5, 1 is sw)
127              
128             #########################################################################
129             #
130             # internal constants and data:
131              
132 23     23   150 use constant COMMON_PARAMETERS => qw(height width);
  23         40  
  23         1784  
133 23     23   111 use constant ALLOWED_PARAMETERS => qw(parent);
  23         36  
  23         1197  
134 23     23   114 use constant DEFAULT_ATTRIBUTES => (parent => undef);
  23         32  
  23         11509  
135              
136             #########################################################################
137             #########################################################################
138              
139             =back
140              
141             =head1 METHODS
142              
143             Besides the accessors described above the following methods are available in
144             all C classes:
145              
146             =cut
147              
148             #########################################################################
149              
150             =head2 B - constructor
151              
152             see L
153             constructor for UI elements>
154              
155             =cut
156              
157             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
158              
159             sub new($;\[@$])
160             {
161 9     9 1 2879 return construct({ DEFAULT_ATTRIBUTES },
162             '^(?:' . join('|', ALLOWED_PARAMETERS) . ')$',
163             @_);
164             }
165              
166             #########################################################################
167              
168             =head2 B - determine top UI element of hierarchy
169              
170             $top = $ui_element->top;
171              
172             =head3 example:
173              
174             $top = $ui_element->top;
175             if ($top) { ... }
176              
177             =head3 description:
178              
179             This method follows the C relationship until it reaches the top UI
180             element of the hierarchy and returns it. If the C relationship has
181             a cycle, an C
182             / warning / info message>> is created and the method returns C.
183              
184             =head3 returns:
185              
186             top UI element
187              
188             =cut
189              
190             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
191              
192             sub top($)
193             {
194 582     582 1 1722 my ($self) = @_;
195             # sanity checks:
196 582 100       1132 $self->isa(__PACKAGE__)
197             or fatal('invalid_object__1_in_call_to__2__3',
198             ref($self), __PACKAGE__, 'top');
199              
200 581         682 my %seen = ();
201 581         548 my $n = 0;
202 581         556 local $_;
203              
204             # unrolled recursion with variable $self:
205 581         1105 while (not defined $seen{$self})
206             {
207 1410         1992 $_ = $self->parent;
208 1410 100       3981 return $self unless $_;
209 830         1425 $seen{$self} = $n++;
210 830         1378 $self = $_;
211             }
212             return error('cyclic_parent_relationship_detected__1_levels_above',
213 1         3 $seen{$self});
214             }
215              
216              
217             #########################################################################
218              
219             =head2 B<_inherited_access> - accessor for common inherited attributes
220              
221             If a read access can't find a value for the object, it tries getting a value
222             from all ancestors up to the L
223             object. Otherwise see L
224             common accessor for UI elements>
225              
226             =cut
227              
228             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
229              
230             sub _inherited_access($$@)
231             {
232 518     518   710 my $attribute = shift;
233 518         545 my $sub_set = shift; # only needed in setter!
234 518         543 my $self = shift;
235              
236             # write access (setter):
237 518 100       898 exists $_[0] and return access($attribute, $sub_set, $self, @_);
238              
239             # read access:
240 497         600 local $_;
241 497         844 while ($self)
242             {
243 1115         1786 $_ = access($attribute, undef, $self);
244 1113 100       2405 defined $_ and return $_;
245 625         813 $self = $self->parent;
246             }
247 7         18 return undef;
248             }
249              
250             #########################################################################
251              
252             =head2 B<_toplevel> - return visible toplevel UI element
253              
254             $ui_element->_toplevel;
255              
256             =head3 description:
257              
258             Return the toplevel parent UI element of any UI container. While above
259             C> usually returns the
260             L element this call usually returns a
261             L or L. In addition it does not
262             have sanity checks.
263              
264             =cut
265              
266             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
267              
268             sub _toplevel($)
269             {
270 22     22   47 local ($_) = @_;
271 22   100     186 while (defined $_ and not $_->isa('UI::Various::toplevel'))
272             {
273 38         73 $_ = $_->parent;
274             }
275 22         73 return $_;
276             }
277              
278             # TODO: Debug?, terminal_color
279              
280             1;
281              
282             #########################################################################
283             #########################################################################
284              
285             =head1 SEE ALSO
286              
287             L
288              
289             =head1 LICENSE
290              
291             Copyright (C) Thomas Dorner.
292              
293             This library is free software; you can redistribute it and/or modify it
294             under the same terms as Perl itself. See LICENSE file for more details.
295              
296             =head1 AUTHOR
297              
298             Thomas Dorner Edorner (at) cpan (dot) orgE
299              
300             =cut