tabularray icon indicating copy to clipboard operation
tabularray copied to clipboard

Nested tblr breaks vertical alignment

Open nihil-admirari opened this issue 2 years ago • 9 comments

In the following, both columns should be header-aligned

\documentclass[paper=b5]{scrartcl}
\usepackage{tabularray}

\newsavebox\SomeNumbers
\sbox\SomeNumbers{\begin{tblr}{hlines, vlines}1 & 2 & 3\end{tblr}}

\begin{document}
  \begin{tblr}{colspec={X[l, h]X[l, h]} , hlines, vlines}
    {Fill \\ some \\ boxes} & \begin{tblr}{hlines, vlines}1 & 2 & 3\end{tblr} \\
    {Fill \\ some \\ more \\ boxes} & \usebox\SomeNumbers
  \end{tblr}
\end{document}

but they aren't

test

Footer-alignment suffers from the same problem. As a workaround, saving nested tblr is a box restores the proper alignment, as the example shows, but nonetheless.

nihil-admirari avatar May 04 '23 19:05 nihil-admirari

I can confirm this is a bug. In this case, you could use t alignment as another workaround.

  \begin{tblr}{colspec={X[l, t]X[l, t]} , hlines, vlines}
    {Fill \\ some \\ boxes} & \begin{tblr}{hlines, vlines}1 & 2 & 3\end{tblr} \\
    {Fill \\ some \\ more \\ boxes} & \usebox\SomeNumbers
  \end{tblr}

lvjr avatar May 06 '23 02:05 lvjr

\g__tblr_cell_valign_tl is altered by (the last cell of) nested tblr env.

Looks like \g__tblr_cell_valign_tl (at least as well as \g__tblr_cell_halign_tl and \g__tblr_cell_middle_tl) should be stored in a per nesting-level basis, for example in \cs{g__tblr_cell_ \int_use:N \g_tblr_level_int _prop}, and set locally.

muzimuzhi avatar May 06 '23 10:05 muzimuzhi

Just a workaround: resetting cell alignments each time after a cell text is retrieved.

I still think it's better to set \g__tblr_cell_(halign|valign|middle)_tl locally (and rename them to \l__tblr_cell_...).

diff --git a/tabularray.sty b/tabularray.sty
index 15f9dd8..7f21a13 100644
--- a/tabularray.sty
+++ b/tabularray.sty
@@ -3629,7 +3629,10 @@
         \dim_gzero:N \g__tblr_cell_head_dim
         \dim_gzero:N \g__tblr_cell_foot_dim
       }
-      { \__tblr_get_cell_text_real:nn { #1 } { #2 } }
+      {
+        \__tblr_get_cell_text_real:nn { #1 } { #2 }
+        \__tblr_get_cell_alignments:nn { #1 } { #2 }
+      }
   }

 \tl_new:N \l__tblr_cell_fg_tl

image

Full example

\documentclass{article}
\usepackage[landscape]{geometry}
\usepackage{tabularray}

\SetTblrOuter{baseline=t}
\SetTblrInner{hlines, vlines}

\newsavebox\SomeNumbers
\sbox\SomeNumbers{\begin{tblr}{}1 & 2 & 3\end{tblr}}

\begin{document}
\def\test#1{
  \begin{tblr}{#1}
    \SetCell[c=2]{c} \texttt{\detokenize{#1}} \\
    {Fill \\ some \\ boxes} &
      \begin{tblr}{} 1 & 2 & 3\end{tblr} \\
    {Fill \\ some \\ boxes} & \usebox\SomeNumbers
  \end{tblr}
}

\def\tests{\par
  \test{colspec={Q[t] Q[t]}}\quad
  \test{colspec={Q[m] Q[m]}}\quad
  \test{colspec={Q[b] Q[b]}}\quad
  \test{colspec={Q[h] Q[h]}}\quad
  \test{colspec={Q[f] Q[f]}}
}

\subsection*{Before}
\tests

\ExplSyntaxOn
\cs_gset_protected:Npn \__tblr_get_cell_text:nn #1 #2
  {
    \int_compare:nNnTF { \__tblr_data_item:neen { cell } {#1} {#2} { omit } } > {0}
      {
        \dim_gzero:N \g__tblr_cell_wd_dim
        \dim_gzero:N \g__tblr_cell_ht_dim
        \dim_gzero:N \g__tblr_cell_head_dim
        \dim_gzero:N \g__tblr_cell_foot_dim
      }
      {
        \__tblr_get_cell_text_real:nn { #1 } { #2 }
        \__tblr_get_cell_alignments:nn { #1 } { #2 } % <<< added
      }
  }
\ExplSyntaxOff

\subsection*{After}
\tests
\end{document}

muzimuzhi avatar May 06 '23 12:05 muzimuzhi

I don't remember why these variables were made global. They should be local because in the future we will need to make them public for hook usages.

lvjr avatar May 06 '23 12:05 lvjr

They were changed from local to global in commit 839749e (global variables for cell alignments, 2021-04-30), prior to the first public release (2021H).

muzimuzhi avatar May 06 '23 12:05 muzimuzhi

image

The alignment in the result image seems wrong. I think it could be better to compare subtable cells with normal text cells.

lvjr avatar May 06 '23 13:05 lvjr

The alignment in the result image seems wrong.

If you meant the effect of colspec={Q[b] Q[b]} in both Before and After, it's probably caused by the global \SetTblrOuter{baseline=t}. Removing it and adding outer style baseline=t to the level 1 tblr env, and adding a row of normal text cells, image

Full example, v2

\documentclass{article}
\usepackage[landscape]{geometry}
\usepackage{tabularray}

\SetTblrInner{hlines, vlines}
%\SetTblrOuter{baseline=t}

\newsavebox\SomeNumbers
\sbox\SomeNumbers{\begin{tblr}{}1 & 2 & 3\end{tblr}}

\begin{document}
\def\test#1{
  \begin{tblr}[baseline=t]{colspec={Q[#1] Q[#1]}}
    \SetCell[c=2]{c} \texttt{\detokenize{Q[#1]}} \\
    {Fill \\ some \\ boxes} & text \\
    {Fill \\ some \\ boxes} & \begin{tblr}{} 1 & 2 & 3\end{tblr} \\
    {Fill \\ some \\ boxes} & \usebox\SomeNumbers
  \end{tblr}
}

\def\tests{\par
  \test{t}\quad
  \test{m}\quad
  \test{b}\quad
  \test{h}\quad
  \test{f}
}

\subsection*{Before}
\tests

\ExplSyntaxOn
\cs_gset_protected:Npn \__tblr_get_cell_text:nn #1 #2
  {
    \int_compare:nNnTF { \__tblr_data_item:neen { cell } {#1} {#2} { omit } } > {0}
      {
        \dim_gzero:N \g__tblr_cell_wd_dim
        \dim_gzero:N \g__tblr_cell_ht_dim
        \dim_gzero:N \g__tblr_cell_head_dim
        \dim_gzero:N \g__tblr_cell_foot_dim
      }
      {
        \__tblr_get_cell_text_real:nn { #1 } { #2 }
        \__tblr_get_cell_alignments:nn { #1 } { #2 } % <<< added
      }
  }
\ExplSyntaxOff

\subsection*{After}
\tests
\end{document}

muzimuzhi avatar May 06 '23 13:05 muzimuzhi

Just a workaround: resetting cell alignments each time after a cell text is retrieved.

[...]

diff --git a/tabularray.sty b/tabularray.sty
index 15f9dd8..7f21a13 100644
--- a/tabularray.sty
+++ b/tabularray.sty
@@ -3629,7 +3629,10 @@
         \dim_gzero:N \g__tblr_cell_head_dim
         \dim_gzero:N \g__tblr_cell_foot_dim
       }
-      { \__tblr_get_cell_text_real:nn { #1 } { #2 } }
+      {
+        \__tblr_get_cell_text_real:nn { #1 } { #2 }
+        \__tblr_get_cell_alignments:nn { #1 } { #2 }
+      }
   }

 \tl_new:N \l__tblr_cell_fg_tl

The patch above may be a bit confusing because I wanted to minimize the size of patch.

This v2 patch is easier to understand: set cell alignments again just after something like \hbox_set:Nn \l_tmpa_box { \__tblr_get_cell_text:nn {#1} {#2} }. If a cell contains a nested tblr table, then storing it in a temp box may change \g__tblr_cell_(halign|valign|middle)_tl (globally) whose values will be used for current cell later. Thus a resetting is needed and helpful.

v2 patch, generated with git diff -U11 to show more context

diff --git a/tabularray.sty b/tabularray.sty
index 15f9dd8..a4e996d 100644
--- a/tabularray.sty
+++ b/tabularray.sty
@@ -3606,22 +3606,23 @@
     \dim_set:Nn \rightsep
       { \__tblr_data_item:nen { column } { \int_use:N \c@colnum } { rightsep } }
   }
 
 %% Measure and update natural dimensions of the row/column/cell
 %% #1: row number; #2 column number; #3: width dimension;
 %% #4: total height dimension; #5: head dimension; #6: foot dimension
 \cs_new_protected:Npn \__tblr_measure_cell_update_sizes:nnNNNN #1 #2 #3 #4 #5 #6
   {
     \__tblr_get_cell_alignments:nn {#1} {#2}
     \hbox_set:Nn \l_tmpa_box { \__tblr_get_cell_text:nn {#1} {#2} }
+    \__tblr_get_cell_alignments:nn {#1} {#2}
     \__tblr_update_cell_size:nnNNNN {#1} {#2} #3 #4 #5 #6
     \__tblr_update_row_size:nnNNN {#1} {#2} #4 #5 #6
     \__tblr_update_col_size:nN {#2} #3
   }
 
 %% #1: row number, #2: column number
 \cs_new_protected:Npn \__tblr_get_cell_text:nn #1 #2
   {
     \int_compare:nNnTF { \__tblr_data_item:neen { cell } {#1} {#2} { omit } } > {0}
       {
         \dim_gzero:N \g__tblr_cell_wd_dim
@@ -6579,22 +6580,23 @@
     \hbox_set_to_wd:Nnn \l__tblr_a_box { \l__tblr_cell_wd_dim }
       {
         \tl_if_eq:NnTF \g__tblr_cell_halign_tl {j}
           % cell width may be less than column width for j cells
           { \__tblr_get_cell_text:nn {#1} {#2} \hfil }
           {
             \tl_if_eq:NnF \g__tblr_cell_halign_tl {l} { \hfil }
             \__tblr_get_cell_text:nn {#1} {#2}
             \tl_if_eq:NnF \g__tblr_cell_halign_tl {r} { \hfil }
           }
       }
+    \__tblr_get_cell_alignments:nn {#1} {#2}
     \vbox_set_to_ht:Nnn \l__tblr_b_box { \l__tblr_cell_ht_dim }
       {
         \tl_case:Nn \g__tblr_cell_valign_tl
           {
             \c__tblr_valign_m_tl
               {
                 \vfil
                 \int_compare:nNnT { \lTblrCellRowSpanTl } < {2}
                   {
                     \box_set_ht:Nn \l__tblr_a_box
                       { \__tblr_data_item:nen { row } {#1} { @row-upper } }

muzimuzhi avatar May 08 '23 19:05 muzimuzhi

I guest we may need to solve issue #531 first.

lvjr avatar Nov 18 '24 08:11 lvjr