Skip to content

Commit 63b9382

Browse files
authored
Merge pull request #1088 from Alex-Jordan/nicetables-percent
let width specifications in niceTables be numbers from (0,1]
2 parents 6b85f52 + b07ef6c commit 63b9382

File tree

1 file changed

+116
-102
lines changed

1 file changed

+116
-102
lines changed

macros/ui/niceTables.pl

Lines changed: 116 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ =head3 All output formats
8888
8989
C<r> for right-aligned column
9090
91-
C<p{width}> for a column with left-aligned paragraphs of fixed width.
92-
The width needs to be absolute to work in all output formats.
91+
C<p{width}> for a column with left-aligned paragraphs of the given width.
92+
The width can be an absolute width or (unlike in LaTeX) a positive decimal number at most 1.
93+
If it is a decimal, it will be interpreted as a portion of the available width.
9394
9495
C<X> for a column that expands to fill (see C<Xratio> below),
9596
and will have left-aligned paragraphs
@@ -536,7 +537,8 @@ sub TableEnvironment {
536537
if ($main::displayMode eq 'TeX') {
537538
my $tabulartype = $hasX ? 'tabularx' : 'tabular';
538539
my $tabularwidth = $hasX ? "$tableOpts->{Xratio}\\linewidth" : '';
539-
$rows = latexEnvironment($rows, $tabulartype, [ $tabularwidth, '[t]', $tableOpts->{texalignment} ], ' ');
540+
my $texalignment = $tableOpts->{texalignment} =~ s/p\{0*(0(\.\d*)?|1(\.0*)?)\}/p\{$1\\linewidth\}/gr;
541+
$rows = latexEnvironment($rows, $tabulartype, [ $tabularwidth, '[t]', $texalignment ], ' ');
540542
$rows = prefix($rows, '\centering%') if $tableOpts->{center};
541543
$rows = prefix($rows, '\renewcommand{\arraystretch}{' . ($tableOpts->{padding}[0] + 1) . '}', '');
542544
$rows = prefix($rows, '\setlength{\tabcolsep}{' . ($tableOpts->{padding}[1] * 10) . 'pt}', '');
@@ -566,16 +568,15 @@ sub TableEnvironment {
566568
$ptxmargins = "${leftmargin}% ${rightmargin}%";
567569
$ptxwidth .= '%';
568570
} elsif (!$tableOpts->{center}) {
569-
$ptxwidth = '100%';
570571
$ptxmargins = '0% 0%';
571572
}
572573
if ($tableOpts->{LaYoUt}) {
573574
$rows = tag(
574575
$rows,
575576
'sbsgroup',
576577
{
577-
width => $ptxwidth,
578578
margins => $ptxmargins,
579+
widths => $cols
579580
}
580581
);
581582
} elsif (!$tableOpts->{LaYoUt}) {
@@ -584,13 +585,12 @@ sub TableEnvironment {
584585
$rows,
585586
'tabular',
586587
{
587-
valign => ($tableOpts->{valign} ne 'middle') ? $tableOpts->{valign} : '',
588-
bottom => $tableOpts->{horizontalrules} ? 'minor' : '',
589-
rowheaders => $tableOpts->{rowheaders} ? 'yes' : '',
590-
margins => $ptxmargins,
591-
width => $ptxwidth,
592-
left => $ptxleft,
593-
top => $ptxtop,
588+
valign => ($tableOpts->{valign} ne 'middle') ? $tableOpts->{valign} : '',
589+
bottom => $tableOpts->{horizontalrules} ? 'minor' : '',
590+
'row-headers' => $tableOpts->{rowheaders} ? 'yes' : '',
591+
width => $ptxwidth,
592+
left => $ptxleft,
593+
top => $ptxtop,
594594
}
595595
);
596596
}
@@ -674,49 +674,87 @@ sub Cols {
674674
}
675675

676676
if ($main::displayMode eq 'PTX') {
677-
my $ptxhalign = '';
678-
$ptxhalign = 'center' if ($align->{halign} eq 'c');
679-
$ptxhalign = 'right' if ($align->{halign} eq 'r');
680-
my $ptxright = '';
681-
$ptxright = getPTXthickness($align->{right});
682-
my $ptxtop = '';
683-
$ptxtop = getPTXthickness($top);
684-
my $ptxwidth = '';
685-
$ptxwidth = getWidthPercent($align->{width}) if $align->{width};
686-
$ptxwidth = ($tableOpts->{Xratio} / $#$alignment * 100) . '%'
687-
if ($align->{halign} eq 'X');
688-
$ptxwidth = getWidthPercent($width) if $width;
689-
push(
690-
@cols,
691-
tag(
692-
'', 'col',
693-
{
694-
halign => $ptxhalign,
695-
right => $ptxright,
696-
top => $ptxtop,
697-
width => $ptxwidth
698-
}
699-
)
700-
);
677+
if ($tableOpts->{LaYoUt}) {
678+
push @cols, ($align->{width} ? getWidthPercent($align->{width}) : '%');
679+
} else {
680+
my $ptxhalign = '';
681+
$ptxhalign = 'center' if ($align->{halign} eq 'c');
682+
$ptxhalign = 'right' if ($align->{halign} eq 'r');
683+
my $ptxright = '';
684+
$ptxright = getPTXthickness($align->{right});
685+
my $ptxtop = '';
686+
$ptxtop = getPTXthickness($top);
687+
my $ptxwidth = '';
688+
$ptxwidth = getWidthPercent($align->{width}) if $align->{width};
689+
$ptxwidth = ($tableOpts->{Xratio} / $#$alignment * 100) . '%'
690+
if ($align->{halign} eq 'X');
691+
$ptxwidth = getWidthPercent($width) if $width;
692+
push(
693+
@cols,
694+
tag(
695+
'', 'col',
696+
{
697+
halign => $ptxhalign,
698+
right => $ptxright,
699+
top => $ptxtop,
700+
width => $ptxwidth
701+
}
702+
)
703+
);
704+
}
701705
} else {
702706
my $htmlright = '';
703707
$htmlright .= css('border-right', 'solid 2px')
704708
if ($i == 1 && $tableOpts->{rowheaders} && $tableOpts->{headerrules});
705709
$htmlright .= css('border-right', getRuleCSS($align->{right}));
706710
my $htmltop = '';
707711
$htmltop .= css('border-top', getRuleCSS($top));
712+
my $htmlwidth = '';
713+
if ($align->{width}) {
714+
$htmlwidth = css('width', $align->{width});
715+
$htmlwidth = css('width', getWidthPercent($align->{width}))
716+
if ($align->{width} =~ /^0*(0(\.\d*)?|1(\.0*)?)$/);
717+
}
708718

709719
# $i starts at 1, but columncss indexing starts at 0
710720
my $htmlcolcss = css($columnscss->[ $i - 1 ]);
711721
if ($align->{tex} =~ /\\columncolor(\[HTML\])?\{(.*?)[}!]/) {
712722
$htmlcolcss .= css('background-color', ($1 ? '#' : '') . $2);
713723
}
714724

715-
push(@cols, tag('', 'col', { style => "${htmlright}${htmltop}${htmlcolcss}" }));
725+
push(@cols, tag('', 'col', { style => "${htmlright}${htmltop}${htmlcolcss}${htmlwidth}" }));
716726
}
717727

718728
}
719729

730+
if ($main::displayMode eq 'PTX' && $tableOpts->{LaYoUt}) {
731+
my @decimalcols = map { substr $_, 0, -1 } @cols;
732+
my $total = 0;
733+
my $count = 0;
734+
for (@decimalcols) {
735+
if ($_ eq '') {
736+
$count++;
737+
} else {
738+
$total += $_;
739+
}
740+
}
741+
# determine if somewhere in the alignment there are X columns
742+
my $hasX = 0;
743+
for my $align (@$alignment) {
744+
if ($align->{halign} eq 'X') {
745+
$hasX = 1;
746+
last;
747+
}
748+
}
749+
my $width = ($hasX ? $tableOpts->{Xratio} * 100 : 100);
750+
my $fill = ($count != 0) ? int(($width - $total) / $count * 10**4) / 10**4 : 0;
751+
for (@decimalcols) {
752+
$_ = $fill if ($_ eq '');
753+
}
754+
@cols = map { $_ . '%' } @decimalcols;
755+
return join(' ', @cols);
756+
}
757+
720758
return join("\n", @cols);
721759

722760
}
@@ -805,52 +843,11 @@ sub Rows {
805843
if (!$ptxleft && $rowArray->[0]{halign} && $alignment->[0]{left});
806844

807845
if ($tableOpts->{LaYoUt}) {
808-
my $ptxwidthsum = 0;
809-
my $ptxautocols = $#alignment;
810-
for my $j (1 .. $#alignment) {
811-
if ($rowArray->[ $j - 1 ]{width}) {
812-
$ptxwidthsum +=
813-
substr getWidthPercent($tableArray->[ $j - 1 ]{width}),
814-
0, -1;
815-
$ptxautocols -= 1;
816-
} elsif ($alignment->[$j]{width}) {
817-
$ptxwidthsum += substr getWidthPercent($alignment->[$j]{width}), 0, -1;
818-
$ptxautocols -= 1;
819-
}
820-
}
821-
822-
# determine if somewhere in the overall alignment, there are X columns
823-
my $hasX = 0;
824-
for my $align (@$alignment) {
825-
if ($align->{halign} eq 'X') {
826-
$hasX = 1;
827-
last;
828-
}
829-
}
830-
my $leftoverspace =
831-
(($hasX) ? $tableOpts->{Xratio} * 100 : 100) - $ptxwidthsum;
832-
my $divvyuptherest = 0;
833-
$divvyuptherest = int($leftoverspace / $ptxautocols * 10000) / 10000
834-
unless ($ptxautocols == 0);
835-
my @ptxwidths;
836-
for my $j (1 .. $#alignment) {
837-
if ($rowOpts->[ $j - 1 ]{width}) {
838-
push(@ptxwidths, getWidthPercent($rowOpts->[ $j - 1 ]{width}));
839-
} elsif ($alignment->[$j]{width}) {
840-
push(@ptxwidths, getWidthPercent($alignment->[$j]{width}));
841-
} else {
842-
push(@ptxwidths, $divvyuptherest . '%');
843-
}
844-
}
845-
846-
my $ptxwidths = join(" ", @ptxwidths);
847846
$row = tag(
848847
$row,
849848
'sidebyside',
850849
{
851-
valign => ($valign) ? $valign : $tableOpts->{valign},
852-
margins => '0% 0%',
853-
widths => $ptxwidths,
850+
valign => ($valign) ? $valign : $tableOpts->{valign},
854851
}
855852
);
856853
} else {
@@ -954,6 +951,7 @@ sub Row {
954951
|| ($tableOpts->{rowheaders} && $tableOpts->{headerrules} && $i == 0))
955952
{
956953
my $columntype = $cellOpts->{halign};
954+
$columntype = $columntype =~ s/p\{0*(0(\.\d*)?|1(\.0*)?)\}/p\{$1\\linewidth\}/gr;
957955
$columntype = $cellAlign->{halign} // 'l' unless $columntype;
958956
$columntype = 'p{' . $tableOpts->{Xratio} / ($#$rowArray + 1) . "\\linewidth}"
959957
if ($columntype eq 'X');
@@ -1038,8 +1036,11 @@ sub Row {
10381036
if ($cellAlign->{halign} eq 'c');
10391037
$css .= css('text-align', 'right')
10401038
if ($cellAlign->{halign} eq 'r');
1041-
$css .= css('width', $cellAlign->{width})
1042-
if ($cellAlign->{width});
1039+
if ($cellAlign->{width} =~ /^0*(0(\.\d*)?|1(\.0*)?)$/) {
1040+
$css .= css('width', getWidthPercent($1));
1041+
} elsif ($cellAlign->{width}) {
1042+
$css .= css('width', $cellAlign->{width});
1043+
}
10431044
$css .= css('font-weight', 'bold')
10441045
if ($cellAlign->{tex} =~ /\\bfseries/);
10451046
$css .= css('font-style', 'italic')
@@ -1075,8 +1076,11 @@ sub Row {
10751076
if ($cellOpts->{halign} =~ /^c/);
10761077
$css .= css('text-align', 'right') if ($cellOpts->{halign} =~ /^r/);
10771078
$css .= css('text-align', 'left') if ($cellOpts->{halign} =~ /^p/);
1078-
$css .= css('width', $1)
1079-
if ($cellOpts->{halign} =~ /^p\{([^}]*?)}/);
1079+
if ($cellOpts->{halign} =~ /^p\{0*(0(\.\d*)?|1(\.0*)?)}/) {
1080+
$css .= css('width', getWidthPercent($1));
1081+
} elsif ($cellOpts->{halign} =~ /^p\{([^}]*?)}/) {
1082+
$css .= css('width', $1);
1083+
}
10801084
$css .= css('font-weight', 'bold')
10811085
if ($cellOpts->{tex} =~ /\\bfseries/);
10821086
$css .= css('font-style', 'italic')
@@ -1581,29 +1585,39 @@ sub getPTXthickness {
15811585
}
15821586

15831587
sub getWidthPercent {
1584-
my $absWidth = shift;
1585-
my $x = 0;
1586-
my $unit = 'cm';
1587-
if ($absWidth =~ /^(\.\d+|\d+\.?\d*)\s*(\w+)/) {
1588+
my $width = shift;
1589+
return $width if (substr($width, -1) eq '%');
1590+
return $width * 100 . '%' if ($width =~ /^0*(0(\.\d*)?|1(\.0*)?)$/);
1591+
my $x = 0;
1592+
my $unit = 'cm';
1593+
if ($width =~ /^(\.\d+|\d+\.?\d*)\s*(\w+)$/) {
15881594
$x = $1;
15891595
$unit = $2;
15901596
}
1591-
my %convert_to_cm = (
1592-
'pt' => 1 / 864 * 249 / 250 * 12 * 2.54,
1593-
'mm' => 1 / 10,
1594-
'cm' => 1,
1595-
'in' => 2.54,
1596-
'ex' => 0.15132,
1597-
'em' => 0.35146,
1598-
'mu' => 0.35146 / 8,
1599-
'sp' => 1 / 864 * 249 / 250 * 12 * 2.54 / 65536,
1600-
'bp' => 2.54 / 72,
1601-
'dd' => 1 / 864 * 249 / 250 * 12 * 2.54 * 1238 / 1157,
1602-
'pc' => 1 / 864 * 249 / 250 * 12 * 2.54 * 12,
1603-
'cc' => 1 / 864 * 249 / 250 * 12 * 2.54 * 1238 / 1157 * 12,
1604-
'px' => 2.54 / 72,
1597+
my %convert_to_pt = (
1598+
# units with related absolute defintions
1599+
# the following are as TeX defines them
1600+
pt => 1,
1601+
pc => 12,
1602+
in => 72.27,
1603+
mm => 72.27 / 25.4,
1604+
cm => 72.27 / 2.54,
1605+
sp => 1 / 65536,
1606+
dd => 1238 / 1157,
1607+
cc => 12 * 1238 / 1157,
1608+
bp => 72.27 / 72,
1609+
# CSS defines 1 px to be 1/96 of an inch
1610+
# note that px is not a legal unit in TeX
1611+
px => 72 / 96,
1612+
# units relative to font
1613+
# the following are based on TeX default font
1614+
# (10pt Computer Modern)
1615+
em => 10.00002,
1616+
ex => 4.30554,
16051617
);
1606-
return (int($x * $convert_to_cm{$unit} / (6.25 * 2.54) * 10000) / 100) . '%';
1618+
# This is only used for PTX output, and a PTX document's default width is 340pt.
1619+
# We offer a percent with up to six significant digits
1620+
return (int($x * $convert_to_pt{$unit} / 340 * 10**6) / 10**4) . '%';
16071621
}
16081622

16091623
sub hrule {

0 commit comments

Comments
 (0)