diff --git a/macros/ui/niceTables.pl b/macros/ui/niceTables.pl index 665003861..bca5e26ce 100644 --- a/macros/ui/niceTables.pl +++ b/macros/ui/niceTables.pl @@ -88,8 +88,9 @@ =head3 All output formats C for right-aligned column -C for a column with left-aligned paragraphs of fixed width. -The width needs to be absolute to work in all output formats. +C for a column with left-aligned paragraphs of the given width. +The width can be an absolute width or (unlike in LaTeX) a positive decimal number at most 1. +If it is a decimal, it will be interpreted as a portion of the available width. C for a column that expands to fill (see C below), and will have left-aligned paragraphs @@ -536,7 +537,8 @@ sub TableEnvironment { if ($main::displayMode eq 'TeX') { my $tabulartype = $hasX ? 'tabularx' : 'tabular'; my $tabularwidth = $hasX ? "$tableOpts->{Xratio}\\linewidth" : ''; - $rows = latexEnvironment($rows, $tabulartype, [ $tabularwidth, '[t]', $tableOpts->{texalignment} ], ' '); + my $texalignment = $tableOpts->{texalignment} =~ s/p\{0*(0(\.\d*)?|1(\.0*)?)\}/p\{$1\\linewidth\}/gr; + $rows = latexEnvironment($rows, $tabulartype, [ $tabularwidth, '[t]', $texalignment ], ' '); $rows = prefix($rows, '\centering%') if $tableOpts->{center}; $rows = prefix($rows, '\renewcommand{\arraystretch}{' . ($tableOpts->{padding}[0] + 1) . '}', ''); $rows = prefix($rows, '\setlength{\tabcolsep}{' . ($tableOpts->{padding}[1] * 10) . 'pt}', ''); @@ -566,7 +568,6 @@ sub TableEnvironment { $ptxmargins = "${leftmargin}% ${rightmargin}%"; $ptxwidth .= '%'; } elsif (!$tableOpts->{center}) { - $ptxwidth = '100%'; $ptxmargins = '0% 0%'; } if ($tableOpts->{LaYoUt}) { @@ -574,8 +575,8 @@ sub TableEnvironment { $rows, 'sbsgroup', { - width => $ptxwidth, margins => $ptxmargins, + widths => $cols } ); } elsif (!$tableOpts->{LaYoUt}) { @@ -584,13 +585,12 @@ sub TableEnvironment { $rows, 'tabular', { - valign => ($tableOpts->{valign} ne 'middle') ? $tableOpts->{valign} : '', - bottom => $tableOpts->{horizontalrules} ? 'minor' : '', - rowheaders => $tableOpts->{rowheaders} ? 'yes' : '', - margins => $ptxmargins, - width => $ptxwidth, - left => $ptxleft, - top => $ptxtop, + valign => ($tableOpts->{valign} ne 'middle') ? $tableOpts->{valign} : '', + bottom => $tableOpts->{horizontalrules} ? 'minor' : '', + 'row-headers' => $tableOpts->{rowheaders} ? 'yes' : '', + width => $ptxwidth, + left => $ptxleft, + top => $ptxtop, } ); } @@ -674,30 +674,34 @@ sub Cols { } if ($main::displayMode eq 'PTX') { - my $ptxhalign = ''; - $ptxhalign = 'center' if ($align->{halign} eq 'c'); - $ptxhalign = 'right' if ($align->{halign} eq 'r'); - my $ptxright = ''; - $ptxright = getPTXthickness($align->{right}); - my $ptxtop = ''; - $ptxtop = getPTXthickness($top); - my $ptxwidth = ''; - $ptxwidth = getWidthPercent($align->{width}) if $align->{width}; - $ptxwidth = ($tableOpts->{Xratio} / $#$alignment * 100) . '%' - if ($align->{halign} eq 'X'); - $ptxwidth = getWidthPercent($width) if $width; - push( - @cols, - tag( - '', 'col', - { - halign => $ptxhalign, - right => $ptxright, - top => $ptxtop, - width => $ptxwidth - } - ) - ); + if ($tableOpts->{LaYoUt}) { + push @cols, ($align->{width} ? getWidthPercent($align->{width}) : '%'); + } else { + my $ptxhalign = ''; + $ptxhalign = 'center' if ($align->{halign} eq 'c'); + $ptxhalign = 'right' if ($align->{halign} eq 'r'); + my $ptxright = ''; + $ptxright = getPTXthickness($align->{right}); + my $ptxtop = ''; + $ptxtop = getPTXthickness($top); + my $ptxwidth = ''; + $ptxwidth = getWidthPercent($align->{width}) if $align->{width}; + $ptxwidth = ($tableOpts->{Xratio} / $#$alignment * 100) . '%' + if ($align->{halign} eq 'X'); + $ptxwidth = getWidthPercent($width) if $width; + push( + @cols, + tag( + '', 'col', + { + halign => $ptxhalign, + right => $ptxright, + top => $ptxtop, + width => $ptxwidth + } + ) + ); + } } else { my $htmlright = ''; $htmlright .= css('border-right', 'solid 2px') @@ -705,6 +709,12 @@ sub Cols { $htmlright .= css('border-right', getRuleCSS($align->{right})); my $htmltop = ''; $htmltop .= css('border-top', getRuleCSS($top)); + my $htmlwidth = ''; + if ($align->{width}) { + $htmlwidth = css('width', $align->{width}); + $htmlwidth = css('width', getWidthPercent($align->{width})) + if ($align->{width} =~ /^0*(0(\.\d*)?|1(\.0*)?)$/); + } # $i starts at 1, but columncss indexing starts at 0 my $htmlcolcss = css($columnscss->[ $i - 1 ]); @@ -712,11 +722,39 @@ sub Cols { $htmlcolcss .= css('background-color', ($1 ? '#' : '') . $2); } - push(@cols, tag('', 'col', { style => "${htmlright}${htmltop}${htmlcolcss}" })); + push(@cols, tag('', 'col', { style => "${htmlright}${htmltop}${htmlcolcss}${htmlwidth}" })); } } + if ($main::displayMode eq 'PTX' && $tableOpts->{LaYoUt}) { + my @decimalcols = map { substr $_, 0, -1 } @cols; + my $total = 0; + my $count = 0; + for (@decimalcols) { + if ($_ eq '') { + $count++; + } else { + $total += $_; + } + } + # determine if somewhere in the alignment there are X columns + my $hasX = 0; + for my $align (@$alignment) { + if ($align->{halign} eq 'X') { + $hasX = 1; + last; + } + } + my $width = ($hasX ? $tableOpts->{Xratio} * 100 : 100); + my $fill = ($count != 0) ? int(($width - $total) / $count * 10**4) / 10**4 : 0; + for (@decimalcols) { + $_ = $fill if ($_ eq ''); + } + @cols = map { $_ . '%' } @decimalcols; + return join(' ', @cols); + } + return join("\n", @cols); } @@ -805,52 +843,11 @@ sub Rows { if (!$ptxleft && $rowArray->[0]{halign} && $alignment->[0]{left}); if ($tableOpts->{LaYoUt}) { - my $ptxwidthsum = 0; - my $ptxautocols = $#alignment; - for my $j (1 .. $#alignment) { - if ($rowArray->[ $j - 1 ]{width}) { - $ptxwidthsum += - substr getWidthPercent($tableArray->[ $j - 1 ]{width}), - 0, -1; - $ptxautocols -= 1; - } elsif ($alignment->[$j]{width}) { - $ptxwidthsum += substr getWidthPercent($alignment->[$j]{width}), 0, -1; - $ptxautocols -= 1; - } - } - - # determine if somewhere in the overall alignment, there are X columns - my $hasX = 0; - for my $align (@$alignment) { - if ($align->{halign} eq 'X') { - $hasX = 1; - last; - } - } - my $leftoverspace = - (($hasX) ? $tableOpts->{Xratio} * 100 : 100) - $ptxwidthsum; - my $divvyuptherest = 0; - $divvyuptherest = int($leftoverspace / $ptxautocols * 10000) / 10000 - unless ($ptxautocols == 0); - my @ptxwidths; - for my $j (1 .. $#alignment) { - if ($rowOpts->[ $j - 1 ]{width}) { - push(@ptxwidths, getWidthPercent($rowOpts->[ $j - 1 ]{width})); - } elsif ($alignment->[$j]{width}) { - push(@ptxwidths, getWidthPercent($alignment->[$j]{width})); - } else { - push(@ptxwidths, $divvyuptherest . '%'); - } - } - - my $ptxwidths = join(" ", @ptxwidths); $row = tag( $row, 'sidebyside', { - valign => ($valign) ? $valign : $tableOpts->{valign}, - margins => '0% 0%', - widths => $ptxwidths, + valign => ($valign) ? $valign : $tableOpts->{valign}, } ); } else { @@ -954,6 +951,7 @@ sub Row { || ($tableOpts->{rowheaders} && $tableOpts->{headerrules} && $i == 0)) { my $columntype = $cellOpts->{halign}; + $columntype = $columntype =~ s/p\{0*(0(\.\d*)?|1(\.0*)?)\}/p\{$1\\linewidth\}/gr; $columntype = $cellAlign->{halign} // 'l' unless $columntype; $columntype = 'p{' . $tableOpts->{Xratio} / ($#$rowArray + 1) . "\\linewidth}" if ($columntype eq 'X'); @@ -1038,8 +1036,11 @@ sub Row { if ($cellAlign->{halign} eq 'c'); $css .= css('text-align', 'right') if ($cellAlign->{halign} eq 'r'); - $css .= css('width', $cellAlign->{width}) - if ($cellAlign->{width}); + if ($cellAlign->{width} =~ /^0*(0(\.\d*)?|1(\.0*)?)$/) { + $css .= css('width', getWidthPercent($1)); + } elsif ($cellAlign->{width}) { + $css .= css('width', $cellAlign->{width}); + } $css .= css('font-weight', 'bold') if ($cellAlign->{tex} =~ /\\bfseries/); $css .= css('font-style', 'italic') @@ -1075,8 +1076,11 @@ sub Row { if ($cellOpts->{halign} =~ /^c/); $css .= css('text-align', 'right') if ($cellOpts->{halign} =~ /^r/); $css .= css('text-align', 'left') if ($cellOpts->{halign} =~ /^p/); - $css .= css('width', $1) - if ($cellOpts->{halign} =~ /^p\{([^}]*?)}/); + if ($cellOpts->{halign} =~ /^p\{0*(0(\.\d*)?|1(\.0*)?)}/) { + $css .= css('width', getWidthPercent($1)); + } elsif ($cellOpts->{halign} =~ /^p\{([^}]*?)}/) { + $css .= css('width', $1); + } $css .= css('font-weight', 'bold') if ($cellOpts->{tex} =~ /\\bfseries/); $css .= css('font-style', 'italic') @@ -1581,29 +1585,39 @@ sub getPTXthickness { } sub getWidthPercent { - my $absWidth = shift; - my $x = 0; - my $unit = 'cm'; - if ($absWidth =~ /^(\.\d+|\d+\.?\d*)\s*(\w+)/) { + my $width = shift; + return $width if (substr($width, -1) eq '%'); + return $width * 100 . '%' if ($width =~ /^0*(0(\.\d*)?|1(\.0*)?)$/); + my $x = 0; + my $unit = 'cm'; + if ($width =~ /^(\.\d+|\d+\.?\d*)\s*(\w+)$/) { $x = $1; $unit = $2; } - my %convert_to_cm = ( - 'pt' => 1 / 864 * 249 / 250 * 12 * 2.54, - 'mm' => 1 / 10, - 'cm' => 1, - 'in' => 2.54, - 'ex' => 0.15132, - 'em' => 0.35146, - 'mu' => 0.35146 / 8, - 'sp' => 1 / 864 * 249 / 250 * 12 * 2.54 / 65536, - 'bp' => 2.54 / 72, - 'dd' => 1 / 864 * 249 / 250 * 12 * 2.54 * 1238 / 1157, - 'pc' => 1 / 864 * 249 / 250 * 12 * 2.54 * 12, - 'cc' => 1 / 864 * 249 / 250 * 12 * 2.54 * 1238 / 1157 * 12, - 'px' => 2.54 / 72, + my %convert_to_pt = ( + # units with related absolute defintions + # the following are as TeX defines them + pt => 1, + pc => 12, + in => 72.27, + mm => 72.27 / 25.4, + cm => 72.27 / 2.54, + sp => 1 / 65536, + dd => 1238 / 1157, + cc => 12 * 1238 / 1157, + bp => 72.27 / 72, + # CSS defines 1 px to be 1/96 of an inch + # note that px is not a legal unit in TeX + px => 72 / 96, + # units relative to font + # the following are based on TeX default font + # (10pt Computer Modern) + em => 10.00002, + ex => 4.30554, ); - return (int($x * $convert_to_cm{$unit} / (6.25 * 2.54) * 10000) / 100) . '%'; + # This is only used for PTX output, and a PTX document's default width is 340pt. + # We offer a percent with up to six significant digits + return (int($x * $convert_to_pt{$unit} / 340 * 10**6) / 10**4) . '%'; } sub hrule {