line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Text::Table::More; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
86075
|
use 5.010001; |
|
1
|
|
|
|
|
12
|
|
4
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
17
|
|
5
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
169
|
|
6
|
|
|
|
|
|
|
#use utf8; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY |
9
|
|
|
|
|
|
|
our $DATE = '2022-01-27'; # DATE |
10
|
|
|
|
|
|
|
our $DIST = 'Text-Table-More'; # DIST |
11
|
|
|
|
|
|
|
our $VERSION = '0.022'; # VERSION |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# see Module::Features for more details on this |
14
|
|
|
|
|
|
|
our %FEATURES = ( |
15
|
|
|
|
|
|
|
set_v => { |
16
|
|
|
|
|
|
|
TextTable => 1, |
17
|
|
|
|
|
|
|
}, |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
features => { |
20
|
|
|
|
|
|
|
PerlTrove => { |
21
|
|
|
|
|
|
|
"Development Status" => "4 - Beta", |
22
|
|
|
|
|
|
|
"Environment" => "Console", |
23
|
|
|
|
|
|
|
# Framework |
24
|
|
|
|
|
|
|
"Intended Audience" => ["Developers"], |
25
|
|
|
|
|
|
|
"License" => "OSI Approved :: Artistic License", |
26
|
|
|
|
|
|
|
# Natural Language |
27
|
|
|
|
|
|
|
# Operating System |
28
|
|
|
|
|
|
|
"Programming Language" => "Perl", |
29
|
|
|
|
|
|
|
"Topic" => ["Software Development :: Libraries :: Perl Modules", "Utilities"], |
30
|
|
|
|
|
|
|
# Typing |
31
|
|
|
|
|
|
|
}, |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
TextTable => { |
34
|
|
|
|
|
|
|
can_align_cell_containing_wide_character => 1, |
35
|
|
|
|
|
|
|
can_align_cell_containing_color_code => 1, |
36
|
|
|
|
|
|
|
can_align_cell_containing_newline => 1, |
37
|
|
|
|
|
|
|
can_use_box_character => 1, |
38
|
|
|
|
|
|
|
can_customize_border => 1, |
39
|
|
|
|
|
|
|
can_halign => 1, |
40
|
|
|
|
|
|
|
can_halign_individual_row => 1, |
41
|
|
|
|
|
|
|
can_halign_individual_column => 1, |
42
|
|
|
|
|
|
|
can_halign_individual_cell => 1, |
43
|
|
|
|
|
|
|
can_valign => 1, |
44
|
|
|
|
|
|
|
can_valign_individual_row => 1, |
45
|
|
|
|
|
|
|
can_valign_individual_column => 1, |
46
|
|
|
|
|
|
|
can_valign_individual_cell => 1, |
47
|
|
|
|
|
|
|
can_rowspan => 1, |
48
|
|
|
|
|
|
|
can_colspan => 1, |
49
|
|
|
|
|
|
|
can_color => 0, |
50
|
|
|
|
|
|
|
can_color_theme => 0, |
51
|
|
|
|
|
|
|
can_set_cell_height => 0, |
52
|
|
|
|
|
|
|
can_set_cell_height_of_individual_row => 0, |
53
|
|
|
|
|
|
|
can_set_cell_width => 0, |
54
|
|
|
|
|
|
|
can_set_cell_width_of_individual_column => 0, |
55
|
|
|
|
|
|
|
speed => 'slow', |
56
|
|
|
|
|
|
|
can_hpad => 0, |
57
|
|
|
|
|
|
|
can_hpad_individual_row => 0, |
58
|
|
|
|
|
|
|
can_hpad_individual_column => 0, |
59
|
|
|
|
|
|
|
can_hpad_individual_cell => 0, |
60
|
|
|
|
|
|
|
can_vpad => 0, |
61
|
|
|
|
|
|
|
can_vpad_individual_row => 0, |
62
|
|
|
|
|
|
|
can_vpad_individual_column => 0, |
63
|
|
|
|
|
|
|
can_vpad_individual_cell => 0, |
64
|
|
|
|
|
|
|
}, |
65
|
|
|
|
|
|
|
}, |
66
|
|
|
|
|
|
|
); |
67
|
|
|
|
|
|
|
|
68
|
1
|
|
|
1
|
|
1887
|
use List::AllUtils qw(first firstidx max); |
|
1
|
|
|
|
|
16671
|
|
|
1
|
|
|
|
|
80
|
|
69
|
|
|
|
|
|
|
|
70
|
1
|
|
|
1
|
|
6
|
use Exporter qw(import); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
3552
|
|
71
|
|
|
|
|
|
|
our @EXPORT_OK = qw/ generate_table /; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
our $_split_lines_func; |
74
|
|
|
|
|
|
|
our $_pad_func; |
75
|
|
|
|
|
|
|
our $_length_height_func; |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# consts |
78
|
|
|
|
|
|
|
sub IDX_EXPTABLE_CELL_ROWSPAN() {0} # number of rowspan, only defined for the rowspan head |
79
|
|
|
|
|
|
|
sub IDX_EXPTABLE_CELL_COLSPAN() {1} # number of colspan, only defined for the colspan head |
80
|
|
|
|
|
|
|
sub IDX_EXPTABLE_CELL_WIDTH() {2} # visual width. this does not include the cell padding. |
81
|
|
|
|
|
|
|
sub IDX_EXPTABLE_CELL_HEIGHT() {3} # visual height. this does not include row separator. |
82
|
|
|
|
|
|
|
sub IDX_EXPTABLE_CELL_ORIG() {4} # str/hash |
83
|
|
|
|
|
|
|
sub IDX_EXPTABLE_CELL_IS_ROWSPAN_TAIL() {5} # whether this cell is tail of a rowspan |
84
|
|
|
|
|
|
|
sub IDX_EXPTABLE_CELL_IS_COLSPAN_TAIL() {6} # whether this cell is tail of a colspan |
85
|
|
|
|
|
|
|
sub IDX_EXPTABLE_CELL_ORIG_ROWNUM() {7} # |
86
|
|
|
|
|
|
|
sub IDX_EXPTABLE_CELL_ORIG_COLNUM() {8} # |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# whether an exptable cell is the head (1st cell) or tail (the rest) of a |
89
|
|
|
|
|
|
|
# rowspan/colspan. these should be macros if possible, for speed. |
90
|
135
|
50
|
|
135
|
|
331
|
sub _exptable_cell_is_rowspan_tail { defined($_[0]) && $_[0][IDX_EXPTABLE_CELL_IS_ROWSPAN_TAIL] } |
91
|
125
|
50
|
|
125
|
|
296
|
sub _exptable_cell_is_colspan_tail { defined($_[0]) && $_[0][IDX_EXPTABLE_CELL_IS_COLSPAN_TAIL] } |
92
|
133
|
50
|
66
|
133
|
|
369
|
sub _exptable_cell_is_tail { defined($_[0]) && ($_[0][IDX_EXPTABLE_CELL_IS_ROWSPAN_TAIL] || $_[0][IDX_EXPTABLE_CELL_IS_COLSPAN_TAIL]) } |
93
|
82
|
50
|
|
82
|
|
234
|
sub _exptable_cell_is_rowspan_head { defined($_[0]) && !$_[0][IDX_EXPTABLE_CELL_IS_ROWSPAN_TAIL] } |
94
|
0
|
0
|
|
0
|
|
0
|
sub _exptable_cell_is_colspan_head { defined($_[0]) && !$_[0][IDX_EXPTABLE_CELL_IS_COLSPAN_TAIL] } |
95
|
156
|
50
|
|
156
|
|
514
|
sub _exptable_cell_is_head { defined($_[0]) && defined $_[0][IDX_EXPTABLE_CELL_ORIG] } |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
sub _divide_int_to_n_ints { |
98
|
218
|
|
|
218
|
|
303
|
my ($int, $n) = @_; |
99
|
218
|
|
|
|
|
220
|
my $subtot = 0; |
100
|
218
|
|
|
|
|
211
|
my $int_subtot = 0; |
101
|
218
|
|
|
|
|
206
|
my $prev_int_subtot = 0; |
102
|
218
|
|
|
|
|
217
|
my @ints; |
103
|
218
|
|
|
|
|
279
|
for (1..$n) { |
104
|
237
|
|
|
|
|
285
|
$subtot += $int/$n; |
105
|
237
|
|
|
|
|
398
|
$int_subtot = sprintf "%.0f", $subtot; |
106
|
237
|
|
|
|
|
281
|
push @ints, $int_subtot - $prev_int_subtot; |
107
|
237
|
|
|
|
|
295
|
$prev_int_subtot = $int_subtot; |
108
|
|
|
|
|
|
|
} |
109
|
218
|
|
|
|
|
326
|
@ints; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub _vpad { |
113
|
109
|
|
|
109
|
|
168
|
my ($lines, $num_lines, $width, $which) = @_; |
114
|
109
|
100
|
|
|
|
275
|
return $lines if @$lines >= $num_lines; # we don't do truncate |
115
|
14
|
|
|
|
|
15
|
my @vpadded_lines; |
116
|
14
|
|
|
|
|
21
|
my $pad_line = " " x $width; |
117
|
14
|
100
|
|
|
|
44
|
if ($which =~ /^b/) { # bottom padding |
|
|
100
|
|
|
|
|
|
118
|
11
|
|
|
|
|
23
|
push @vpadded_lines, @$lines; |
119
|
11
|
|
|
|
|
31
|
push @vpadded_lines, $pad_line for @$lines+1 .. $num_lines; |
120
|
|
|
|
|
|
|
} elsif ($which =~ /^t/) { # top padding |
121
|
1
|
|
|
|
|
6
|
push @vpadded_lines, $pad_line for @$lines+1 .. $num_lines; |
122
|
1
|
|
|
|
|
2
|
push @vpadded_lines, @$lines; |
123
|
|
|
|
|
|
|
} else { # center padding |
124
|
2
|
|
|
|
|
4
|
my $p = $num_lines - @$lines; |
125
|
2
|
|
|
|
|
5
|
my $p1 = int($p/2); |
126
|
2
|
|
|
|
|
3
|
my $p2 = $p - $p1; |
127
|
2
|
|
|
|
|
7
|
push @vpadded_lines, $pad_line for 1..$p1; |
128
|
2
|
|
|
|
|
3
|
push @vpadded_lines, @$lines; |
129
|
2
|
|
|
|
|
8
|
push @vpadded_lines, $pad_line for 1..$p2; |
130
|
|
|
|
|
|
|
} |
131
|
14
|
|
|
|
|
37
|
\@vpadded_lines; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub _get_attr { |
135
|
566
|
|
|
566
|
|
764
|
my ($attr_name, $y, $x, $cell_value, $table_args) = @_; |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
CELL_ATTRS_FROM_CELL_VALUE: { |
138
|
566
|
100
|
|
|
|
583
|
last unless ref $cell_value eq 'HASH'; |
|
566
|
|
|
|
|
821
|
|
139
|
74
|
|
|
|
|
93
|
my $attr_val = $cell_value->{$attr_name}; |
140
|
74
|
100
|
|
|
|
117
|
return $attr_val if defined $attr_val; |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
CELL_ATTRS_FROM_CELL_ATTRS_ARG: |
144
|
|
|
|
|
|
|
{ |
145
|
563
|
100
|
66
|
|
|
570
|
last unless defined $x && defined $y; |
|
563
|
|
|
|
|
1089
|
|
146
|
389
|
|
|
|
|
445
|
my $cell_attrs = $table_args->{cell_attrs}; |
147
|
389
|
100
|
|
|
|
577
|
last unless $cell_attrs; |
148
|
93
|
|
|
|
|
128
|
for my $entry (@$cell_attrs) { |
149
|
93
|
100
|
100
|
|
|
193
|
next unless $entry->[0] == $y && $entry->[1] == $x; |
150
|
14
|
|
|
|
|
18
|
my $attr_val = $entry->[2]{$attr_name}; |
151
|
14
|
100
|
|
|
|
26
|
return $attr_val if defined $attr_val; |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
COL_ATTRS: |
156
|
|
|
|
|
|
|
{ |
157
|
560
|
100
|
|
|
|
549
|
last unless defined $x; |
|
560
|
|
|
|
|
747
|
|
158
|
386
|
|
|
|
|
434
|
my $col_attrs = $table_args->{col_attrs}; |
159
|
386
|
100
|
|
|
|
524
|
last unless $col_attrs; |
160
|
90
|
|
|
|
|
108
|
for my $entry (@$col_attrs) { |
161
|
90
|
100
|
|
|
|
152
|
next unless $entry->[0] == $x; |
162
|
18
|
|
|
|
|
25
|
my $attr_val = $entry->[1]{$attr_name}; |
163
|
18
|
100
|
|
|
|
42
|
return $attr_val if defined $attr_val; |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
ROW_ATTRS: |
168
|
|
|
|
|
|
|
{ |
169
|
551
|
50
|
|
|
|
571
|
last unless defined $y; |
|
551
|
|
|
|
|
743
|
|
170
|
551
|
|
|
|
|
586
|
my $row_attrs = $table_args->{row_attrs}; |
171
|
551
|
100
|
|
|
|
753
|
last unless $row_attrs; |
172
|
163
|
|
|
|
|
211
|
for my $entry (@$row_attrs) { |
173
|
163
|
100
|
|
|
|
246
|
next unless $entry->[0] == $y; |
174
|
62
|
|
|
|
|
77
|
my $attr_val = $entry->[1]{$attr_name}; |
175
|
62
|
100
|
|
|
|
105
|
return $attr_val if defined $attr_val; |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
TABLE_ARGS: |
180
|
|
|
|
|
|
|
{ |
181
|
542
|
|
|
|
|
534
|
my $attr_val = $table_args->{$attr_name}; |
|
542
|
|
|
|
|
590
|
|
182
|
542
|
100
|
|
|
|
765
|
return $attr_val if defined $attr_val; |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
535
|
|
|
|
|
856
|
undef; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
sub _get_exptable_cell_lines { |
189
|
109
|
|
|
109
|
|
176
|
my ($table_args, $exptable, $row_heights, $column_widths, |
190
|
|
|
|
|
|
|
$bottom_borders, $intercol_width, $y, $x) = @_; |
191
|
|
|
|
|
|
|
|
192
|
109
|
|
|
|
|
133
|
my $exptable_cell = $exptable->[$y][$x]; |
193
|
109
|
|
|
|
|
151
|
my $cell = $exptable_cell->[IDX_EXPTABLE_CELL_ORIG]; |
194
|
109
|
100
|
|
|
|
161
|
my $text = ref $cell eq 'HASH' ? $cell->{text} : $cell; |
195
|
109
|
|
100
|
|
|
194
|
my $align = _get_attr('align', $y, $x, $cell, $table_args) // 'left'; |
196
|
109
|
|
100
|
|
|
163
|
my $valign = _get_attr('valign', $y, $x, $cell, $table_args) // 'top'; |
197
|
109
|
100
|
|
|
|
184
|
my $pad = $align eq 'left' ? 'r' : $align eq 'right' ? 'l' : 'c'; |
|
|
100
|
|
|
|
|
|
198
|
109
|
100
|
|
|
|
137
|
my $vpad = $valign eq 'top' ? 'b' : $valign eq 'bottom' ? 't' : 'c'; |
|
|
100
|
|
|
|
|
|
199
|
109
|
|
|
|
|
120
|
my $height = 0; |
200
|
109
|
|
|
|
|
139
|
my $width = 0; |
201
|
109
|
|
|
|
|
170
|
for my $ic (1..$exptable_cell->[IDX_EXPTABLE_CELL_COLSPAN]) { |
202
|
118
|
|
|
|
|
157
|
$width += $column_widths->[$x+$ic-1]; |
203
|
118
|
100
|
|
|
|
222
|
$width += $intercol_width if $ic > 1; |
204
|
|
|
|
|
|
|
} |
205
|
109
|
|
|
|
|
133
|
for my $ir (1..$exptable_cell->[IDX_EXPTABLE_CELL_ROWSPAN]) { |
206
|
119
|
|
|
|
|
145
|
$height += $row_heights->[$y+$ir-1]; |
207
|
119
|
100
|
100
|
|
|
293
|
$height++ if $bottom_borders->[$y+$ir-2] && $ir > 1; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
109
|
|
|
|
|
165
|
my @datalines = map { $_pad_func->($_, $width, $pad, ' ', 'truncate') } |
|
130
|
|
|
|
|
895
|
|
211
|
|
|
|
|
|
|
($_split_lines_func->($text)); |
212
|
109
|
|
|
|
|
2196
|
_vpad(\@datalines, $height, $width, $vpad); |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
sub generate_table { |
216
|
18
|
|
|
18
|
1
|
110058
|
require Module::Load::Util; |
217
|
18
|
|
|
|
|
3121
|
require Text::NonWideChar::Util; |
218
|
|
|
|
|
|
|
|
219
|
18
|
|
|
|
|
278
|
my %args = @_; |
220
|
18
|
50
|
|
|
|
50
|
my $rows = $args{rows} or die "Please specify rows"; |
221
|
18
|
|
50
|
|
|
59
|
my $bs_name = $args{border_style} // 'ASCII::SingleLineDoubleAfterHeader'; |
222
|
18
|
|
100
|
|
|
44
|
my $cell_attrs = $args{cell_attrs} // []; |
223
|
|
|
|
|
|
|
|
224
|
18
|
|
|
|
|
70
|
my $bs_obj = Module::Load::Util::instantiate_class_with_optional_args({ns_prefix=>"BorderStyle"}, $bs_name); |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
DETERMINE_CODES: { |
227
|
18
|
|
|
|
|
5660
|
my $color = $args{color}; |
|
18
|
|
|
|
|
24
|
|
228
|
18
|
|
|
|
|
24
|
my $wide_char = $args{wide_char}; |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
# split_lines |
231
|
18
|
100
|
|
|
|
34
|
if ($color) { |
232
|
1
|
|
|
|
|
5
|
require Text::ANSI::Util; |
233
|
1
|
|
|
9
|
|
7
|
$_split_lines_func = sub { Text::ANSI::Util::ta_add_color_resets(split /\R/, $_[0]) }; |
|
9
|
|
|
|
|
38
|
|
234
|
|
|
|
|
|
|
} else { |
235
|
17
|
|
|
100
|
|
84
|
$_split_lines_func = sub { split /\R/, $_[0] }; |
|
100
|
|
|
|
|
295
|
|
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
# pad & length_height |
239
|
18
|
100
|
|
|
|
34
|
if ($color) { |
240
|
1
|
50
|
|
|
|
3
|
if ($wide_char) { |
241
|
1
|
|
|
|
|
426
|
require Text::ANSI::WideUtil; |
242
|
1
|
|
|
|
|
349
|
$_pad_func = \&Text::ANSI::WideUtil::ta_mbpad; |
243
|
1
|
|
|
|
|
3
|
$_length_height_func = \&Text::ANSI::WideUtil::ta_mbswidth_height; |
244
|
|
|
|
|
|
|
} else { |
245
|
0
|
|
|
|
|
0
|
require Text::ANSI::Util; |
246
|
0
|
|
|
|
|
0
|
$_pad_func = \&Text::ANSI::Util::ta_pad; |
247
|
0
|
|
|
|
|
0
|
$_length_height_func = \&Text::ANSI::Util::ta_length_height; |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
} else { |
250
|
17
|
50
|
|
|
|
26
|
if ($wide_char) { |
251
|
0
|
|
|
|
|
0
|
require Text::WideChar::Util; |
252
|
0
|
|
|
|
|
0
|
$_pad_func = \&Text::WideChar::Util::mbpad; |
253
|
0
|
|
|
|
|
0
|
$_length_height_func = \&Text::WideChar::Util::mbswidth_height; |
254
|
|
|
|
|
|
|
} else { |
255
|
17
|
|
|
|
|
1109
|
require String::Pad; |
256
|
17
|
|
|
|
|
548
|
require Text::NonWideChar::Util; |
257
|
17
|
|
|
|
|
28
|
$_pad_func = \&String::Pad::pad; |
258
|
17
|
|
|
|
|
25
|
$_length_height_func = \&Text::NonWideChar::Util::length_height; |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
# XXX when we allow cell attrs right_border and left_border, this will |
264
|
|
|
|
|
|
|
# become array too like $exptable_bottom_borders. |
265
|
18
|
|
|
|
|
54
|
my $intercol_width = length(" " . $bs_obj->get_border_char(3, 1) . " "); |
266
|
|
|
|
|
|
|
|
267
|
18
|
|
|
|
|
396
|
my $exptable = []; # [ [[$orig_rowidx,$orig_colidx,$rowspan,$colspan,...], ...], [[...], ...], ... ] |
268
|
18
|
|
|
|
|
31
|
my $exptable_bottom_borders = []; # idx=exptable rownum, val=bool |
269
|
18
|
|
|
|
|
19
|
my $M = 0; # number of rows in the exptable |
270
|
18
|
|
|
|
|
22
|
my $N = 0; # number of columns in the exptable |
271
|
|
|
|
|
|
|
CONSTRUCT_EXPTABLE: { |
272
|
|
|
|
|
|
|
# 1. the first step is to construct a 2D array we call "exptable" (short |
273
|
|
|
|
|
|
|
# for expanded table), which is like the original table but with all the |
274
|
|
|
|
|
|
|
# spanning rows/columns split into the smaller boxes so it's easier to |
275
|
|
|
|
|
|
|
# draw later. for example, a table cell with colspan=2 will become 2 |
276
|
|
|
|
|
|
|
# exptable cells. an m-row x n-column table will become M-row x N-column |
277
|
|
|
|
|
|
|
# exptable, where M>=m, N>=n. |
278
|
|
|
|
|
|
|
|
279
|
18
|
|
|
|
|
19
|
my $rownum; |
|
18
|
|
|
|
|
19
|
|
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# 1a. first substep: construct exptable and calculate everything except |
282
|
|
|
|
|
|
|
# each exptable cell's width and height, because this will require |
283
|
|
|
|
|
|
|
# information from the previous substeps. |
284
|
|
|
|
|
|
|
|
285
|
18
|
|
|
|
|
21
|
$rownum = -1; |
286
|
18
|
|
|
|
|
32
|
for my $row (@$rows) { |
287
|
53
|
|
|
|
|
56
|
$rownum++; |
288
|
53
|
|
|
|
|
55
|
my $colnum = -1; |
289
|
53
|
|
|
|
|
53
|
my $separator_type = do { |
290
|
53
|
|
100
|
|
|
106
|
my $cmp = ($args{header_row}//0)-1 <=> $rownum; |
291
|
|
|
|
|
|
|
# 0=none, 2=separator between header/data, 4=separator between |
292
|
|
|
|
|
|
|
# data rows, 8=separator between header rows. this is from |
293
|
|
|
|
|
|
|
# BorderStyle standard. |
294
|
53
|
100
|
|
|
|
102
|
$cmp==0 ? 2 : $cmp==1 ? 8 : 4; |
|
|
100
|
|
|
|
|
|
295
|
|
|
|
|
|
|
}; |
296
|
53
|
|
100
|
|
|
185
|
$exptable->[$rownum] //= []; |
297
|
53
|
|
|
|
|
89
|
push @{ $exptable->[$rownum] }, undef |
298
|
53
|
50
|
66
|
|
|
56
|
if (@{ $exptable->[$rownum] } == 0 || |
|
53
|
|
|
|
|
125
|
|
299
|
|
|
|
|
|
|
defined($exptable->[$rownum][-1])); |
300
|
|
|
|
|
|
|
#use DDC; say "D:exptable->[$rownum] = ", DDC::dump($exptable->[$rownum]); |
301
|
53
|
|
|
58
|
|
130
|
my $exptable_colnum = firstidx {!defined} @{ $exptable->[$rownum] }; |
|
58
|
|
|
|
|
94
|
|
|
53
|
|
|
|
|
127
|
|
302
|
|
|
|
|
|
|
#say "D:rownum=$rownum, exptable_colnum=$exptable_colnum"; |
303
|
53
|
50
|
|
|
|
140
|
if ($exptable_colnum == -1) { $exptable_colnum = 0 } |
|
0
|
|
|
|
|
0
|
|
304
|
53
|
100
|
66
|
|
|
182
|
$exptable_bottom_borders->[$rownum] //= $args{separate_rows} ? $separator_type : 0; |
305
|
|
|
|
|
|
|
|
306
|
53
|
|
|
|
|
78
|
for my $cell (@$row) { |
307
|
109
|
|
|
|
|
131
|
$colnum++; |
308
|
109
|
|
|
|
|
109
|
my $text; |
309
|
|
|
|
|
|
|
|
310
|
109
|
|
|
|
|
115
|
my $rowspan = 1; |
311
|
109
|
|
|
|
|
127
|
my $colspan = 1; |
312
|
109
|
100
|
|
|
|
191
|
if (ref $cell eq 'HASH') { |
313
|
17
|
|
|
|
|
27
|
$text = $cell->{text}; |
314
|
17
|
100
|
|
|
|
37
|
$rowspan = $cell->{rowspan} if $cell->{rowspan}; |
315
|
17
|
100
|
|
|
|
28
|
$colspan = $cell->{colspan} if $cell->{colspan}; |
316
|
|
|
|
|
|
|
} else { |
317
|
92
|
|
|
|
|
125
|
$text = $cell; |
318
|
92
|
|
|
|
|
87
|
my $el; |
319
|
92
|
100
|
100
|
21
|
|
306
|
$el = first {$_->[0] == $rownum && $_->[1] == $colnum && $_->[2]{rowspan}} @$cell_attrs; |
|
21
|
|
|
|
|
60
|
|
320
|
92
|
50
|
|
|
|
227
|
$rowspan = $el->[2]{rowspan} if $el; |
321
|
92
|
100
|
100
|
21
|
|
230
|
$el = first {$_->[0] == $rownum && $_->[1] == $colnum && $_->[2]{colspan}} @$cell_attrs; |
|
21
|
|
|
|
|
55
|
|
322
|
92
|
50
|
|
|
|
190
|
$colspan = $el->[2]{colspan} if $el; |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
|
325
|
109
|
|
|
|
|
123
|
my @widths; |
326
|
|
|
|
|
|
|
my @heights; |
327
|
|
|
|
|
|
|
ROW: |
328
|
109
|
|
|
|
|
166
|
for my $ir (1..$rowspan) { |
329
|
119
|
|
|
|
|
142
|
for my $ic (1..$colspan) { |
330
|
133
|
|
|
|
|
133
|
my $exptable_cell; |
331
|
133
|
|
|
|
|
209
|
$exptable->[$rownum+$ir-1][$exptable_colnum+$ic-1] = $exptable_cell = []; |
332
|
|
|
|
|
|
|
|
333
|
133
|
|
|
|
|
186
|
$exptable_cell->[IDX_EXPTABLE_CELL_ORIG_ROWNUM] = $rownum; |
334
|
133
|
|
|
|
|
184
|
$exptable_cell->[IDX_EXPTABLE_CELL_ORIG_COLNUM] = $colnum; |
335
|
|
|
|
|
|
|
|
336
|
133
|
100
|
100
|
|
|
304
|
if ($ir == 1 && $ic == 1) { |
337
|
109
|
|
|
|
|
138
|
$exptable_cell->[IDX_EXPTABLE_CELL_ROWSPAN] = $rowspan; |
338
|
109
|
|
|
|
|
116
|
$exptable_cell->[IDX_EXPTABLE_CELL_COLSPAN] = $colspan; |
339
|
109
|
|
|
|
|
167
|
$exptable_cell->[IDX_EXPTABLE_CELL_ORIG] = $cell; |
340
|
|
|
|
|
|
|
} else { |
341
|
24
|
100
|
|
|
|
43
|
$exptable_cell->[IDX_EXPTABLE_CELL_IS_ROWSPAN_TAIL] = 1 if $ir > 1; |
342
|
24
|
100
|
|
|
|
45
|
$exptable_cell->[IDX_EXPTABLE_CELL_IS_COLSPAN_TAIL] = 1 if $ic > 1; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
#use DDC; dd $exptable; say ''; # debug |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
# determine whether we should draw bottom border of each row |
348
|
119
|
100
|
100
|
|
|
262
|
if ($rownum+$ir-1 == 0 && ($args{header_row}//0) > 0) { |
|
|
|
100
|
|
|
|
|
349
|
32
|
|
|
|
|
39
|
$exptable_bottom_borders->[0] = $separator_type; |
350
|
|
|
|
|
|
|
} else { |
351
|
87
|
|
|
|
|
87
|
my $val; |
352
|
87
|
100
|
|
|
|
150
|
$val = _get_attr('bottom_border', $rownum+$ir-1, 0, $cell, \%args); $exptable_bottom_borders->[$rownum+$ir-1] = $separator_type if $val; |
|
87
|
|
|
|
|
144
|
|
353
|
87
|
50
|
|
|
|
129
|
$val = _get_attr('top_border' , $rownum+$ir-1, 0, $cell, \%args); $exptable_bottom_borders->[$rownum+$ir-2] = $separator_type if $val; |
|
87
|
|
|
|
|
124
|
|
354
|
87
|
100
|
|
|
|
134
|
$val = _get_attr('bottom_border', $rownum+$ir-1, undef, undef, \%args); $exptable_bottom_borders->[$rownum+$ir-1] = $separator_type if $val; |
|
87
|
|
|
|
|
118
|
|
355
|
87
|
50
|
|
|
|
126
|
$val = _get_attr('top_border' , $rownum+$ir-1, undef, undef, \%args); $exptable_bottom_borders->[$rownum+$ir-2] = $separator_type if $val; |
|
87
|
|
|
|
|
133
|
|
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
119
|
100
|
|
|
|
209
|
$M = $rownum+$ir if $M < $rownum+$ir; |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
|
361
|
109
|
|
|
|
|
111
|
$exptable_colnum += $colspan; |
362
|
109
|
|
|
|
|
218
|
$exptable_colnum++ while defined $exptable->[$rownum][$exptable_colnum]; |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
} # for a row |
365
|
53
|
100
|
|
|
|
100
|
$N = $exptable_colnum if $N < $exptable_colnum; |
366
|
|
|
|
|
|
|
} # for rows |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
# 1b. calculate the heigth and width of each exptable cell (as required |
369
|
|
|
|
|
|
|
# by the text, or specified width/height when we allow cell attrs width, |
370
|
|
|
|
|
|
|
# height) |
371
|
|
|
|
|
|
|
|
372
|
18
|
|
|
|
|
32
|
for my $exptable_rownum (0..$M-1) { |
373
|
53
|
|
|
|
|
68
|
for my $exptable_colnum (0..$N-1) { |
374
|
133
|
|
|
|
|
155
|
my $exptable_cell = $exptable->[$exptable_rownum][$exptable_colnum]; |
375
|
133
|
100
|
|
|
|
184
|
next if _exptable_cell_is_tail($exptable_cell); |
376
|
109
|
|
|
|
|
148
|
my $rowspan = $exptable_cell->[IDX_EXPTABLE_CELL_ROWSPAN]; |
377
|
109
|
|
|
|
|
124
|
my $colspan = $exptable_cell->[IDX_EXPTABLE_CELL_COLSPAN]; |
378
|
109
|
|
|
|
|
119
|
my $cell = $exptable_cell->[IDX_EXPTABLE_CELL_ORIG]; |
379
|
109
|
100
|
|
|
|
170
|
my $text = ref $cell eq 'HASH' ? $cell->{text} : $cell; |
380
|
109
|
|
|
|
|
169
|
my $lh = $_length_height_func->($text); |
381
|
|
|
|
|
|
|
#use DDC; say "D:length_height[$exptable_rownum,$exptable_colnum] = (".DDC::dump($text)."): ".DDC::dump($lh); |
382
|
109
|
|
|
|
|
1720
|
my $tot_intercol_widths = ($colspan-1) * $intercol_width; |
383
|
109
|
50
|
|
|
|
128
|
my $tot_interrow_heights = 0; for (1..$rowspan-1) { $tot_interrow_heights++ if $exptable_bottom_borders->[$exptable_rownum+$_-1] } |
|
109
|
|
|
|
|
159
|
|
|
10
|
|
|
|
|
22
|
|
384
|
|
|
|
|
|
|
#say "D:interrow_heights=$tot_interrow_heights"; |
385
|
109
|
|
|
|
|
212
|
my @heights = _divide_int_to_n_ints(max(0, $lh->[1] - $tot_interrow_heights), $rowspan); |
386
|
109
|
|
|
|
|
207
|
my @widths = _divide_int_to_n_ints(max(0, $lh->[0] - $tot_intercol_widths ), $colspan); |
387
|
109
|
|
|
|
|
152
|
for my $ir (1..$rowspan) { |
388
|
119
|
|
|
|
|
136
|
for my $ic (1..$colspan) { |
389
|
133
|
|
|
|
|
210
|
$exptable->[$exptable_rownum+$ir-1][$exptable_colnum+$ic-1][IDX_EXPTABLE_CELL_HEIGHT] = $heights[$ir-1]; |
390
|
133
|
|
|
|
|
300
|
$exptable->[$exptable_rownum+$ir-1][$exptable_colnum+$ic-1][IDX_EXPTABLE_CELL_WIDTH] = $widths [$ic-1]; |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
} # for rows |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
} # CONSTRUCT_EXPTABLE |
397
|
|
|
|
|
|
|
#use DDC; dd $exptable; # debug |
398
|
|
|
|
|
|
|
#print "D: exptable size: $M x $N (HxW)\n"; # debug |
399
|
|
|
|
|
|
|
#use DDC; print "bottom borders: "; dd $exptable_bottom_borders; # debug |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
OPTIMIZE_EXPTABLE: { |
402
|
|
|
|
|
|
|
# TODO |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
# 2. we reduce extraneous columns and rows if there are colspan that are |
405
|
|
|
|
|
|
|
# too many. for example, if all exptable cells in column 1 has colspan=2 |
406
|
|
|
|
|
|
|
# (or one row has colspan=2 and another row has colspan=3), we might as |
407
|
|
|
|
|
|
|
# remove 1 column because the extra column span doesn't have any |
408
|
|
|
|
|
|
|
# content. same case for extraneous row spans. |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
# 2a. remove extra undefs. skip this. doesn't make a difference. |
411
|
|
|
|
|
|
|
#for my $exptable_row (@{ $exptable }) { |
412
|
|
|
|
|
|
|
# splice @$exptable_row, $N if @$exptable_row > $N; |
413
|
|
|
|
|
|
|
#} |
414
|
|
|
|
|
|
|
|
415
|
18
|
|
|
|
|
19
|
1; |
|
18
|
|
|
|
|
19
|
|
416
|
|
|
|
|
|
|
} # OPTIMIZE_EXPTABLE |
417
|
|
|
|
|
|
|
#use DDC; dd $exptable; # debug |
418
|
|
|
|
|
|
|
|
419
|
18
|
|
|
|
|
25
|
my $exptable_column_widths = []; # idx=exptable colnum |
420
|
18
|
|
|
|
|
21
|
my $exptable_row_heights = []; # idx=exptable rownum |
421
|
|
|
|
|
|
|
DETERMINE_SIZE_OF_EACH_EXPTABLE_COLUMN_AND_ROW: { |
422
|
|
|
|
|
|
|
# 3. before we draw the exptable, we need to determine the width and |
423
|
|
|
|
|
|
|
# height of each exptable column and row. |
424
|
|
|
|
|
|
|
#use DDC; |
425
|
18
|
|
|
|
|
21
|
for my $ir (0..$M-1) { |
|
18
|
|
|
|
|
21
|
|
426
|
53
|
|
|
|
|
67
|
my $exptable_row = $exptable->[$ir]; |
427
|
|
|
|
|
|
|
$exptable_row_heights->[$ir] = max( |
428
|
53
|
|
100
|
|
|
69
|
1, map {$_->[IDX_EXPTABLE_CELL_HEIGHT] // 0} @$exptable_row); |
|
139
|
|
|
|
|
288
|
|
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
|
431
|
18
|
|
|
|
|
29
|
for my $ic (0..$N-1) { |
432
|
|
|
|
|
|
|
$exptable_column_widths->[$ic] = max( |
433
|
40
|
50
|
|
|
|
55
|
1, map {$exptable->[$_][$ic] ? $exptable->[$_][$ic][IDX_EXPTABLE_CELL_WIDTH] : 0} 0..$M-1); |
|
133
|
|
|
|
|
247
|
|
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
} # DETERMINE_SIZE_OF_EACH_EXPTABLE_COLUMN_AND_ROW |
436
|
|
|
|
|
|
|
#use DDC; print "column widths: "; dd $exptable_column_widths; # debug |
437
|
|
|
|
|
|
|
#use DDC; print "row heights: "; dd $exptable_row_heights; # debug |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
# each elem is an arrayref containing characters to render a line of the |
440
|
|
|
|
|
|
|
# table, e.g. for element [0] the row is all borders. for element [1]: |
441
|
|
|
|
|
|
|
# [$left_border_str, $exptable_cell_content1, $border_between_col, |
442
|
|
|
|
|
|
|
# $exptable_cell_content2, ...]. all will be joined together with "\n" to |
443
|
|
|
|
|
|
|
# form the final rendered table. |
444
|
18
|
|
|
|
|
21
|
my @buf; |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
DRAW_EXPTABLE: { |
447
|
|
|
|
|
|
|
# 4. finally we draw the (exp)table. |
448
|
|
|
|
|
|
|
|
449
|
18
|
|
|
|
|
20
|
my $y = 0; |
|
18
|
|
|
|
|
21
|
|
450
|
|
|
|
|
|
|
|
451
|
18
|
|
|
|
|
26
|
for my $ir (0..$M-1) { |
452
|
|
|
|
|
|
|
DRAW_TOP_BORDER: |
453
|
|
|
|
|
|
|
{ |
454
|
53
|
100
|
|
|
|
75
|
last unless $ir == 0; |
455
|
17
|
100
|
100
|
|
|
41
|
my $b_y = ($args{header_row}//0) > 0 ? 0 : 6; |
456
|
17
|
|
|
|
|
44
|
my $b_topleft = $bs_obj->get_border_char($b_y, 0); |
457
|
17
|
|
|
|
|
361
|
my $b_topline = $bs_obj->get_border_char($b_y, 1); |
458
|
17
|
|
|
|
|
325
|
my $b_topbetwcol = $bs_obj->get_border_char($b_y, 2); |
459
|
17
|
|
|
|
|
291
|
my $b_topright = $bs_obj->get_border_char($b_y, 3); |
460
|
17
|
0
|
33
|
|
|
295
|
last unless length $b_topleft || length $b_topline || length $b_topbetwcol || length $b_topright; |
|
|
|
33
|
|
|
|
|
|
|
|
0
|
|
|
|
|
461
|
17
|
|
|
|
|
35
|
$buf[$y][0] = $b_topleft; |
462
|
17
|
|
|
|
|
28
|
for my $ic (0..$N-1) { |
463
|
40
|
100
|
|
|
|
70
|
my $cell_right = $ic < $N-1 ? $exptable->[$ir][$ic+1] : undef; |
464
|
40
|
|
100
|
|
|
77
|
my $cell_right_has_content = defined $cell_right && _exptable_cell_is_head($cell_right); |
465
|
40
|
|
|
|
|
77
|
$buf[$y][$ic*4+2] = $bs_obj->get_border_char($b_y, 1, $exptable_column_widths->[$ic]+2); # +1, +2, +3 |
466
|
40
|
100
|
|
|
|
789
|
$buf[$y][$ic*4+4] = $ic == $N-1 ? $b_topright : ($cell_right_has_content ? $b_topbetwcol : $b_topline); |
|
|
100
|
|
|
|
|
|
467
|
|
|
|
|
|
|
} |
468
|
17
|
|
|
|
|
25
|
$y++; |
469
|
|
|
|
|
|
|
} # DRAW_TOP_BORDER |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
# DRAW_DATA_OR_HEADER_ROW |
472
|
|
|
|
|
|
|
{ |
473
|
|
|
|
|
|
|
# draw leftmost border, which we always do. |
474
|
53
|
100
|
100
|
|
|
56
|
my $b_y = $ir == 0 && $args{header_row} ? 1 : 3; |
|
53
|
|
|
|
|
55
|
|
|
53
|
|
|
|
|
117
|
|
475
|
53
|
|
|
|
|
93
|
for my $i (1 .. $exptable_row_heights->[$ir]) { |
476
|
62
|
|
|
|
|
254
|
$buf[$y+$i-1][0] = $bs_obj->get_border_char($b_y, 0); |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
|
479
|
53
|
|
|
|
|
947
|
my $lines; |
480
|
53
|
|
|
|
|
79
|
for my $ic (0..$N-1) { |
481
|
133
|
|
|
|
|
155
|
my $cell = $exptable->[$ir][$ic]; |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
# draw cell content. also possibly draw border between |
484
|
|
|
|
|
|
|
# cells. we don't draw border inside a row/colspan. |
485
|
133
|
100
|
|
|
|
209
|
if (_exptable_cell_is_head($cell)) { |
486
|
109
|
|
|
|
|
172
|
$lines = _get_exptable_cell_lines( |
487
|
|
|
|
|
|
|
\%args, $exptable, $exptable_row_heights, $exptable_column_widths, |
488
|
|
|
|
|
|
|
$exptable_bottom_borders, $intercol_width, $ir, $ic); |
489
|
109
|
|
|
|
|
156
|
for my $i (0..$#{$lines}) { |
|
109
|
|
|
|
|
182
|
|
490
|
153
|
|
|
|
|
283
|
$buf[$y+$i][$ic*4+0] = $bs_obj->get_border_char($b_y, 1); |
491
|
153
|
|
|
|
|
2813
|
$buf[$y+$i][$ic*4+1] = " "; |
492
|
153
|
|
|
|
|
244
|
$buf[$y+$i][$ic*4+2] = $lines->[$i]; |
493
|
153
|
|
|
|
|
266
|
$buf[$y+$i][$ic*4+3] = " "; |
494
|
|
|
|
|
|
|
} |
495
|
|
|
|
|
|
|
#use DDC; say "D: Drawing exptable_cell($ir,$ic): ", DDC::dump($lines); |
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
# draw rightmost border, which we always do. |
499
|
133
|
100
|
|
|
|
280
|
if ($ic == $N-1) { |
500
|
53
|
100
|
100
|
|
|
128
|
my $b_y = $ir == 0 && $args{header_row} ? 1 : 3; |
501
|
53
|
|
|
|
|
84
|
for my $i (1 .. $exptable_row_heights->[$ir]) { |
502
|
62
|
|
|
|
|
266
|
$buf[$y+$i-1][$ic*4+4] = $bs_obj->get_border_char($b_y, 2); |
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
} |
507
|
|
|
|
|
|
|
} # DRAW_DATA_OR_HEADER_ROW |
508
|
53
|
|
|
|
|
974
|
$y += $exptable_row_heights->[$ir]; |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
DRAW_ROW_SEPARATOR: |
511
|
|
|
|
|
|
|
{ |
512
|
53
|
100
|
|
|
|
60
|
last unless $ir < $M-1; |
|
53
|
|
|
|
|
104
|
|
513
|
36
|
100
|
|
|
|
60
|
last unless $exptable_bottom_borders->[$ir]; |
514
|
31
|
|
|
|
|
46
|
my $b_y = $exptable_bottom_borders->[$ir]; |
515
|
31
|
|
|
|
|
47
|
my $b_betwrowleft = $bs_obj->get_border_char($b_y, 0); |
516
|
31
|
|
|
|
|
524
|
my $b_betwrowline = $bs_obj->get_border_char($b_y, 1); |
517
|
31
|
|
|
|
|
504
|
my $b_betwrowbetwcol = $bs_obj->get_border_char($b_y, 2); |
518
|
31
|
|
|
|
|
502
|
my $b_betwrowright = $bs_obj->get_border_char($b_y, 3); |
519
|
31
|
0
|
33
|
|
|
515
|
last unless length $b_betwrowleft || length $b_betwrowline || length $b_betwrowbetwcol || length $b_betwrowright; |
|
|
|
33
|
|
|
|
|
|
|
|
0
|
|
|
|
|
520
|
31
|
|
|
|
|
47
|
my $b_betwrowbetwcol_notop = $bs_obj->get_border_char($b_y, 4); |
521
|
31
|
|
|
|
|
514
|
my $b_betwrowbetwcol_nobot = $bs_obj->get_border_char($b_y, 5); |
522
|
31
|
|
|
|
|
503
|
my $b_betwrowbetwcol_noleft = $bs_obj->get_border_char($b_y, 6); |
523
|
31
|
|
|
|
|
499
|
my $b_betwrowbetwcol_noright = $bs_obj->get_border_char($b_y, 7); |
524
|
31
|
100
|
|
|
|
519
|
my $b_ydataorheader = $args{header_row} == $ir+1 ? 2 : $args{header_row} < $ir+1 ? 3 : 1; |
|
|
100
|
|
|
|
|
|
525
|
31
|
|
|
|
|
52
|
my $b_dataorheaderrowleft = $bs_obj->get_border_char($b_ydataorheader, 0, 1); |
526
|
31
|
|
|
|
|
501
|
my $b_dataorheaderrowbetwcol = $bs_obj->get_border_char($b_ydataorheader, 1, 1); |
527
|
31
|
|
|
|
|
523
|
my $b_dataorheaderrowright = $bs_obj->get_border_char($b_ydataorheader, 2, 1); |
528
|
31
|
|
|
|
|
504
|
for my $ic (0..$N-1) { |
529
|
82
|
100
|
|
|
|
147
|
my $cell_right = $ic < $N-1 ? $exptable->[$ir][$ic+1] : undef; |
530
|
82
|
50
|
|
|
|
144
|
my $cell_bottom = $ir < $M-1 ? $exptable->[$ir+1][$ic] : undef; |
531
|
82
|
100
|
66
|
|
|
252
|
my $cell_rightbottom = $ir < $M-1 && $ic < $N-1 ? $exptable->[$ir+1][$ic+1] : undef; |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
# leftmost border |
534
|
82
|
100
|
|
|
|
127
|
if ($ic == 0) { |
535
|
31
|
100
|
|
|
|
52
|
$buf[$y][0] = _exptable_cell_is_rowspan_tail($cell_bottom) ? $b_dataorheaderrowleft : $b_betwrowleft; |
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
# along the width of cell content |
539
|
82
|
100
|
|
|
|
118
|
if (_exptable_cell_is_rowspan_head($cell_bottom)) { |
540
|
67
|
|
|
|
|
132
|
$buf[$y][$ic*4+2] = $bs_obj->get_border_char($b_y, 1, $exptable_column_widths->[$ic]+2); |
541
|
|
|
|
|
|
|
} |
542
|
|
|
|
|
|
|
|
543
|
82
|
|
|
|
|
1225
|
my $char; |
544
|
82
|
100
|
|
|
|
123
|
if ($ic == $N-1) { |
545
|
|
|
|
|
|
|
# rightmost |
546
|
31
|
100
|
|
|
|
44
|
if (_exptable_cell_is_rowspan_tail($cell_bottom)) { |
547
|
6
|
|
|
|
|
8
|
$char = $b_dataorheaderrowright; |
548
|
|
|
|
|
|
|
} else { |
549
|
25
|
|
|
|
|
36
|
$char = $b_betwrowright; |
550
|
|
|
|
|
|
|
} |
551
|
|
|
|
|
|
|
} else { |
552
|
|
|
|
|
|
|
# between cells |
553
|
51
|
100
|
|
|
|
72
|
if (_exptable_cell_is_colspan_tail($cell_right)) { |
554
|
10
|
100
|
|
|
|
12
|
if (_exptable_cell_is_colspan_tail($cell_rightbottom)) { |
555
|
5
|
50
|
|
|
|
7
|
if (_exptable_cell_is_rowspan_tail($cell_bottom)) { |
556
|
5
|
|
|
|
|
7
|
$char = ""; |
557
|
|
|
|
|
|
|
} else { |
558
|
0
|
|
|
|
|
0
|
$char = $b_betwrowline; |
559
|
|
|
|
|
|
|
} |
560
|
|
|
|
|
|
|
} else { |
561
|
5
|
|
|
|
|
7
|
$char = $b_betwrowbetwcol_notop; |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
} else { |
564
|
41
|
100
|
|
|
|
60
|
if (_exptable_cell_is_colspan_tail($cell_rightbottom)) { |
565
|
7
|
|
|
|
|
11
|
$char = $b_betwrowbetwcol_nobot; |
566
|
|
|
|
|
|
|
} else { |
567
|
34
|
100
|
|
|
|
46
|
if (_exptable_cell_is_rowspan_tail($cell_bottom)) { |
|
|
100
|
|
|
|
|
|
568
|
4
|
50
|
|
|
|
6
|
if (_exptable_cell_is_rowspan_tail($cell_rightbottom)) { |
569
|
0
|
|
|
|
|
0
|
$char = $b_dataorheaderrowbetwcol; |
570
|
|
|
|
|
|
|
} else { |
571
|
4
|
|
|
|
|
5
|
$char = $b_betwrowbetwcol_noleft; |
572
|
|
|
|
|
|
|
} |
573
|
|
|
|
|
|
|
} elsif (_exptable_cell_is_rowspan_tail($cell_rightbottom)) { |
574
|
6
|
|
|
|
|
7
|
$char = $b_betwrowbetwcol_noright; |
575
|
|
|
|
|
|
|
} else { |
576
|
24
|
|
|
|
|
35
|
$char = $b_betwrowbetwcol; |
577
|
|
|
|
|
|
|
} |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
} |
581
|
82
|
|
|
|
|
188
|
$buf[$y][$ic*4+4] = $char; |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
} |
584
|
31
|
|
|
|
|
43
|
$y++; |
585
|
|
|
|
|
|
|
} # DRAW_ROW_SEPARATOR |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
DRAW_BOTTOM_BORDER: |
588
|
|
|
|
|
|
|
{ |
589
|
53
|
100
|
|
|
|
54
|
last unless $ir == $M-1; |
|
53
|
|
|
|
|
98
|
|
590
|
17
|
50
|
66
|
|
|
39
|
my $b_y = $ir == 0 && $args{header_row} ? 7 : 5; |
591
|
17
|
|
|
|
|
32
|
my $b_botleft = $bs_obj->get_border_char($b_y, 0); |
592
|
17
|
|
|
|
|
286
|
my $b_botline = $bs_obj->get_border_char($b_y, 1); |
593
|
17
|
|
|
|
|
278
|
my $b_botbetwcol = $bs_obj->get_border_char($b_y, 2); |
594
|
17
|
|
|
|
|
275
|
my $b_botright = $bs_obj->get_border_char($b_y, 3); |
595
|
17
|
0
|
33
|
|
|
280
|
last unless length $b_botleft || length $b_botline || length $b_botbetwcol || length $b_botright; |
|
|
|
33
|
|
|
|
|
|
|
|
0
|
|
|
|
|
596
|
17
|
|
|
|
|
34
|
$buf[$y][0] = $b_botleft; |
597
|
17
|
|
|
|
|
42
|
for my $ic (0..$N-1) { |
598
|
40
|
100
|
|
|
|
72
|
my $cell_right = $ic < $N-1 ? $exptable->[$ir][$ic+1] : undef; |
599
|
40
|
|
|
|
|
78
|
$buf[$y][$ic*4+2] = $bs_obj->get_border_char($b_y, 1, $exptable_column_widths->[$ic]+2); |
600
|
40
|
100
|
|
|
|
732
|
$buf[$y][$ic*4+4] = $ic == $N-1 ? $b_botright : (_exptable_cell_is_colspan_tail($cell_right) ? $b_botline : $b_botbetwcol); |
|
|
100
|
|
|
|
|
|
601
|
|
|
|
|
|
|
} |
602
|
17
|
|
|
|
|
35
|
$y++; |
603
|
|
|
|
|
|
|
} # DRAW_BOTTOM_BORDER |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
} |
606
|
|
|
|
|
|
|
} # DRAW_EXPTABLE |
607
|
|
|
|
|
|
|
|
608
|
18
|
100
|
|
|
|
24
|
for my $row (@buf) { for (@$row) { $_ = "" if !defined($_) } } # debug. remove undef to "" to save dump width |
|
127
|
|
|
|
|
148
|
|
|
1411
|
|
|
|
|
2156
|
|
609
|
|
|
|
|
|
|
#use DDC; dd \@buf; |
610
|
18
|
|
|
|
|
32
|
join "", (map { my $linebuf = $_; join("", grep {defined} @$linebuf)."\n" } @buf); |
|
127
|
|
|
|
|
133
|
|
|
127
|
|
|
|
|
147
|
|
|
1411
|
|
|
|
|
2031
|
|
611
|
|
|
|
|
|
|
} |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
# Back-compat: 'table' is an alias for 'generate_table', but isn't exported |
614
|
|
|
|
|
|
|
{ |
615
|
1
|
|
|
1
|
|
7
|
no warnings 'once'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
60
|
|
616
|
|
|
|
|
|
|
*table = \&generate_table; |
617
|
|
|
|
|
|
|
} |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
1; |
620
|
|
|
|
|
|
|
# ABSTRACT: Generate text table with simple interface and many options |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
__END__ |