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             (Usually attributes are 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 only be modified before using the widget. (Note
35             that this is mostly not enforced.)
36              
37             B attributes can only be initialised and not modified or read later.
38              
39             B attributes may be empty or C.
40              
41             B attributes may be empty or C, but it is advisable to
42             give them a proper value.
43              
44             B attributes may be undefined, but if they are read, a possible
45             value will be searched for all the hierarchy up to either the L
46             Manager"|UI::Various::Main> object or the top-level
47             L or L objects.
48             They may still be undefined everywhere, though.
49              
50             =over
51              
52             =cut
53              
54             #########################################################################
55              
56 24     24   609 use v5.14;
  24         72  
57 24     24   110 use strictures;
  24         35  
  24         109  
58 24     24   3306 no indirect 'fatal';
  24         42  
  24         130  
59 24     24   1231 no multidimensional;
  24         39  
  24         96  
60 24     24   786 use warnings 'once';
  24         47  
  24         1199  
61              
62             our $VERSION = '0.24';
63              
64 24     24   130 use UI::Various::core;
  24         40  
  24         167  
65              
66             require Exporter;
67             our @ISA = qw(Exporter);
68             our @EXPORT_OK = qw();
69              
70             #########################################################################
71              
72             =item height [rw, fixed, inherited]
73              
74             preferred (maximum) height of a UI element in (approximately) characters,
75             should not exceed L
76             |UI::Various::Main/max_height ro>
77              
78             Be careful with small height values as this could lead to undisplayed or
79             even discarded UI elements in some of the possible UIs. If this is the main
80             window, the application could be immediately exited!
81              
82             =cut
83              
84             sub height($;$)
85             {
86 14     14 1 559 return _inherited_access('height', undef, @_);
87             }
88              
89             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
90              
91             =item B [rw, optional]
92              
93             a reference to the parent of the current UI element, usually C for
94             the C> object and defined for everything else
95              
96             Note that usually this should only be manipulated by methods of
97             C>.
98              
99             =cut
100              
101             sub parent($;$)
102             {
103             return
104             access('parent',
105             sub{
106 134 100   134   269 if (defined $_)
107             {
108 133 100       579 $_->isa('UI::Various::container') or
109             fatal('invalid_parent__1_not_a_ui_various_container',
110             ref($_));
111             }
112             },
113 2490     2490 1 14017 @_);
114             }
115              
116             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
117              
118             =item width [rw, fixed, inherited]
119              
120             preferred (maximum) width of a UI element in (approximately) characters,
121             should not exceed L
122             |UI::Various::Main/max_width ro>
123              
124             =cut
125              
126             sub width($;$)
127             {
128 516     516 1 2439 return _inherited_access('width', undef, @_);
129             }
130              
131             # TODO: fg, bg, x, y, align (1-9, default 5, 1 is sw)
132              
133             #########################################################################
134             #
135             # internal constants and data:
136              
137 24     24   148 use constant COMMON_PARAMETERS => qw(height width);
  24         41  
  24         1610  
138 24     24   135 use constant ALLOWED_PARAMETERS => qw(parent);
  24         57  
  24         1332  
139 24     24   134 use constant DEFAULT_ATTRIBUTES => (parent => undef);
  24         68  
  24         12422  
140              
141             #########################################################################
142             #########################################################################
143              
144             =back
145              
146             =head1 METHODS
147              
148             Besides the accessors described above the following methods are available in
149             all C classes:
150              
151             =cut
152              
153             #########################################################################
154              
155             =head2 B - constructor
156              
157             see L
158             constructor for UI elements>
159              
160             =cut
161              
162             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
163              
164             sub new($;\[@$])
165             {
166 9     9 1 3373 return construct({ DEFAULT_ATTRIBUTES },
167             '^(?:' . join('|', ALLOWED_PARAMETERS) . ')$',
168             @_);
169             }
170              
171             #########################################################################
172              
173             =head2 B - determine top UI element of hierarchy
174              
175             $top = $ui_element->top;
176              
177             =head3 example:
178              
179             $top = $ui_element->top;
180             if ($top) { ... }
181              
182             =head3 description:
183              
184             This method follows the C relationship until it reaches the top UI
185             element of the hierarchy and returns it. If the C relationship has
186             a cycle, an C
187             / warning / info message>> is created and the method returns C.
188              
189             =head3 returns:
190              
191             top UI element
192              
193             =cut
194              
195             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
196              
197             sub top($)
198             {
199 601     601 1 1891 my ($self) = @_;
200             # sanity checks:
201 601 100       1344 $self->isa(__PACKAGE__)
202             or fatal('invalid_object__1_in_call_to__2__3',
203             ref($self), __PACKAGE__, 'top');
204              
205 600         734 my %seen = ();
206 600         642 my $n = 0;
207 600         651 local $_;
208              
209             # unrolled recursion with variable $self:
210 600         1287 while (not defined $seen{$self})
211             {
212 1448         2208 $_ = $self->parent;
213 1448 100       4638 return $self unless $_;
214 849         1542 $seen{$self} = $n++;
215 849         1644 $self = $_;
216             }
217             return error('cyclic_parent_relationship_detected__1_levels_above',
218 1         4 $seen{$self});
219             }
220              
221              
222             #########################################################################
223              
224             =head2 B<_inherited_access> - accessor for common inherited attributes
225              
226             If a read access can't find a value for the object, it tries getting a value
227             from all ancestors up to the L
228             object. Otherwise see L
229             common accessor for UI elements>
230              
231             =cut
232              
233             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
234              
235             sub _inherited_access($$@)
236             {
237 538     538   814 my $attribute = shift;
238 538         912 my $sub_set = shift; # only needed in setter!
239 538         698 my $self = shift;
240              
241             # write access (setter):
242 538 100       1028 exists $_[0] and return access($attribute, $sub_set, $self, @_);
243              
244             # read access:
245 516         639 local $_;
246 516         1024 while ($self)
247             {
248 1153         2145 $_ = access($attribute, undef, $self);
249 1151 100       2764 defined $_ and return $_;
250 644         1024 $self = $self->parent;
251             }
252 7         24 return undef;
253             }
254              
255             #########################################################################
256              
257             =head2 B<_toplevel> - return visible toplevel UI element
258              
259             $ui_element->_toplevel;
260              
261             =head3 description:
262              
263             Return the toplevel parent UI element of any UI container. While above
264             C> usually returns the
265             L element this call usually returns a
266             L or L. In addition it does not
267             have sanity checks.
268              
269             =cut
270              
271             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
272              
273             sub _toplevel($)
274             {
275 22     22   53 local ($_) = @_;
276 22   100     205 while (defined $_ and not $_->isa('UI::Various::toplevel'))
277             {
278 38         80 $_ = $_->parent;
279             }
280 22         72 return $_;
281             }
282              
283             # TODO: Debug?, terminal_color
284              
285             1;
286              
287             #########################################################################
288             #########################################################################
289              
290             =head1 SEE ALSO
291              
292             L
293              
294             =head1 LICENSE
295              
296             Copyright (C) Thomas Dorner.
297              
298             This library is free software; you can redistribute it and/or modify it
299             under the same terms as Perl itself. See LICENSE file for more details.
300              
301             =head1 AUTHOR
302              
303             Thomas Dorner Edorner (at) cpan (dot) orgE
304              
305             =cut