| 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__ |