Files
article-tii-scan-heuristic/tabularray.sty
2025-05-27 21:37:54 +08:00

7295 lines
244 KiB
TeX

%%% % -*- coding: utf-8 -*-
%%% ----------------------------------------------------------------------------
%%% Tabularray: Typeset tabulars and arrays with LaTeX3
%%% Copyright : 2021-2023 (c) Jianrui Lyu <tolvjr@163.com>
%%% Repository: https://github.com/lvjr/tabularray
%%% License : The LaTeX Project Public License 1.3c
%%% ----------------------------------------------------------------------------
%%% --------------------------------------------------------
%%> \section{Scratch Variables and Function Variants}
%%% --------------------------------------------------------
%% \DeclareRelease and \DeclareCurrentRelease are added in LaTeX 2018-04-01
\NeedsTeXFormat{LaTeX2e}[2018-04-01]
\providecommand\DeclareRelease[3]{}
\providecommand\DeclareCurrentRelease[2]{}
\DeclareRelease{v2021}{2021-01-01}{tabularray-2021.sty}
\DeclareCurrentRelease{}{2022-01-01}
\RequirePackage{expl3}
\ProvidesExplPackage{tabularray}{2023-03-01}{2023A}
{Typeset tabulars and arrays with LaTeX3}
%% \IfFormatAtLeastTF, xparse and lthooks are added in LaTeX 2020-10-01
%% Note that \@ifl@t@r or \@ifpackagelater means 'this date or later'
\msg_new:nnn { tabularray } { latex-too-old }
{
Your ~ LaTeX ~ release ~ is ~ too ~ old. \\
Please ~ update ~ it ~ to ~ 2020-10-01 ~ first.
}
\@ifl@t@r\fmtversion{2020-10-01}{}{
%% Support TeX Live 2020 on Overleaf
\msg_warning:nn { tabularray } { latex-too-old }
\usepackage{xparse}
}
\AtBeginDocument{
\@ifpackageloaded{xcolor}{\RequirePackage{ninecolors}}{}
\@ifpackageloaded{hyperref}{
\newenvironment{tblrNoHyper}{\NoHyper}{\endNoHyper}
}{
\newenvironment{tblrNoHyper}{}{}
}
}
\NewDocumentCommand \TblrParboxRestore { } { \@parboxrestore }
\NewDocumentCommand \TblrAlignBoth { }
{
\let \\ = \@normalcr
\leftskip = \z@skip
\@rightskip = \z@skip
\rightskip = \@rightskip
\parfillskip = \@flushglue
}
\NewDocumentCommand \TblrAlignLeft { } { \raggedright }
\NewDocumentCommand \TblrAlignCenter { } { \centering }
\NewDocumentCommand \TblrAlignRight { } { \raggedleft }
\cs_set_eq:NN \TblrNewPage \newpage
%% Note that \cs_if_exist:NTF doesn't treat \relax as an existing command.
%% Therefore we define our \__tblr_cs_if_defined:NTF here.
\prg_set_conditional:Npnn \__tblr_cs_if_defined:N #1 { p, T, F, TF }
{
%% \if_cs_exist:N = \ifdefined in eTeX
\if_cs_exist:N #1
\prg_return_true:
\else:
\prg_return_false:
\fi:
}
\prg_set_conditional:Npnn \__tblr_cs_if_defined:c #1 { p, T, F, TF }
{
%% \if_cs_exist:w = \ifcsname in eTeX
\if_cs_exist:w #1 \cs_end:
\prg_return_true:
\else:
\prg_return_false:
\fi:
}
\cs_generate_variant:Nn \msg_error:nnnn { nnVn }
\cs_generate_variant:Nn \prop_item:Nn { Ne, NV }
\cs_generate_variant:Nn \prop_put:Nnn { Nxn, Nxx, NxV }
\cs_generate_variant:Nn \regex_replace_all:NnN { NVN }
\cs_generate_variant:Nn \seq_map_indexed_inline:Nn { cn }
\cs_generate_variant:Nn \tl_const:Nn { ce }
\cs_generate_variant:Nn \tl_log:n { x }
\cs_generate_variant:Nn \tl_gput_right:Nn { Nf }
\cs_generate_variant:Nn \tl_put_left:Nn { Nv }
\prg_generate_conditional_variant:Nnn \clist_if_in:Nn { Nx } { TF }
\prg_generate_conditional_variant:Nnn \prop_if_in:Nn { c } { T }
\prg_generate_conditional_variant:Nnn \regex_match:Nn { NV } { TF }
\prg_generate_conditional_variant:Nnn \str_if_eq:nn { xn } { TF }
\prg_generate_conditional_variant:Nnn \tl_if_eq:nn { en } { T, TF }
\prg_generate_conditional_variant:Nnn \tl_if_head_eq_catcode:nN { VN } { TF }
\prg_generate_conditional_variant:Nnn \tl_if_head_eq_meaning:nN { VN } { T, TF }
\tl_new:N \l__tblr_a_tl
\tl_new:N \l__tblr_b_tl
\tl_new:N \l__tblr_c_tl
\tl_new:N \l__tblr_d_tl
\tl_new:N \l__tblr_e_tl
\tl_new:N \l__tblr_f_tl
\tl_new:N \l__tblr_h_tl
\tl_new:N \l__tblr_i_tl % for row index
\tl_new:N \l__tblr_j_tl % for column index
\tl_new:N \l__tblr_k_tl
\tl_new:N \l__tblr_n_tl
\tl_new:N \l__tblr_o_tl
\tl_new:N \l__tblr_r_tl
\tl_new:N \l__tblr_s_tl
\tl_new:N \l__tblr_t_tl
\tl_new:N \l__tblr_u_tl
\tl_new:N \l__tblr_v_tl
\tl_new:N \l__tblr_w_tl
\tl_new:N \l__tblr_x_tl
\tl_new:N \l__tblr_y_tl
\int_new:N \l__tblr_a_int
\int_new:N \l__tblr_c_int % for column number
\int_new:N \l__tblr_r_int % for row number
\dim_new:N \l__tblr_d_dim % for depth
\dim_new:N \l__tblr_h_dim % for height
\dim_new:N \l__tblr_o_dim
\dim_new:N \l__tblr_p_dim
\dim_new:N \l__tblr_q_dim
\dim_new:N \l__tblr_r_dim
\dim_new:N \l__tblr_s_dim
\dim_new:N \l__tblr_t_dim
\dim_new:N \l__tblr_v_dim
\dim_new:N \l__tblr_w_dim % for width
\box_new:N \l__tblr_a_box
\box_new:N \l__tblr_b_box
\box_new:N \l__tblr_c_box % for cell box
\box_new:N \l__tblr_d_box
%% Total number of tblr tables
\int_new:N \g__tblr_table_count_int
%% Some commands for horizontal alignment
\cs_new_eq:NN \__tblr_halign_command_j: \TblrAlignBoth
\cs_new_eq:NN \__tblr_halign_command_l: \TblrAlignLeft
\cs_new_eq:NN \__tblr_halign_command_c: \TblrAlignCenter
\cs_new_eq:NN \__tblr_halign_command_r: \TblrAlignRight
%% Some counters for row and column numbering.
%% We may need to restore all LaTeX counters in measuring and building cells,
%% so we must not define these counters with \newcounter command.
\int_zero_new:N \c@rownum
\int_zero_new:N \c@colnum
\int_zero_new:N \c@rowcount
\int_zero_new:N \c@colcount
%% Add missing \therownum, \thecolnum, \therowcount, \thecolcount (issue #129)
\ProvideExpandableDocumentCommand \therownum {} { \@arabic \c@rownum }
\ProvideExpandableDocumentCommand \thecolnum {} { \@arabic \c@colnum }
\ProvideExpandableDocumentCommand \therowcount {} { \@arabic \c@rowcount }
\ProvideExpandableDocumentCommand \thecolcount {} { \@arabic \c@colcount }
%% Some dimensions for row and column spacing
\dim_new:N \abovesep
\dim_new:N \belowsep
\dim_new:N \leftsep
\dim_new:N \rightsep
%%% --------------------------------------------------------
%%> \section{Data Structures Based on Property Lists}
%%% --------------------------------------------------------
\int_new:N \g_tblr_level_int % store table nesting level
\cs_new_protected:Npn \__tblr_clear_prop_lists:
{
\prop_gclear_new:c { g__tblr_text_ \int_use:N \g_tblr_level_int _prop }
\prop_gclear_new:c { g__tblr_command_ \int_use:N \g_tblr_level_int _prop }
\prop_gclear_new:c { g__tblr_inner_ \int_use:N \g_tblr_level_int _prop }
\prop_gclear_new:c { g__tblr_note_ \int_use:N \g_tblr_level_int _prop }
\prop_gclear_new:c { g__tblr_remark_ \int_use:N \g_tblr_level_int _prop }
\prop_gclear_new:c { g__tblr_more_ \int_use:N \g_tblr_level_int _prop }
\prop_gclear_new:c { g__tblr_row_ \int_use:N \g_tblr_level_int _prop }
\prop_gclear_new:c { g__tblr_column_ \int_use:N \g_tblr_level_int _prop }
\prop_gclear_new:c { g__tblr_cell_ \int_use:N \g_tblr_level_int _prop }
\prop_gclear_new:c { g__tblr_hline_ \int_use:N \g_tblr_level_int _prop }
\prop_gclear_new:c { g__tblr_vline_ \int_use:N \g_tblr_level_int _prop }
}
\cs_new_protected:Npn \__tblr_prop_gput:nnn #1 #2 #3
{
\prop_gput:cnn
{ g__tblr_#1_ \int_use:N \g_tblr_level_int _prop } { #2 } { #3 }
}
\cs_generate_variant:Nn \__tblr_prop_gput:nnn { nnx, nnV, nxn, nxx, nxV }
\cs_new:Npn \__tblr_prop_item:nn #1 #2
{
\prop_item:cn { g__tblr_#1_ \int_use:N \g_tblr_level_int _prop } { #2 }
}
\cs_generate_variant:Nn \__tblr_prop_item:nn { ne }
\cs_new_protected:Npn \__tblr_prop_if_in:nnT #1
{
\prop_if_in:cnT { g__tblr_#1_ \int_use:N \g_tblr_level_int _prop }
}
\cs_new_protected:Npn \__tblr_prop_if_in:nnF #1
{
\prop_if_in:cnF { g__tblr_#1_ \int_use:N \g_tblr_level_int _prop }
}
\cs_new_protected:Npn \__tblr_prop_if_in:nnTF #1
{
\prop_if_in:cnTF { g__tblr_#1_ \int_use:N \g_tblr_level_int _prop }
}
\prg_generate_conditional_variant:Nnn \__tblr_prop_if_in:nn { nx } { T, F, TF }
\cs_new_protected:Npn \__tblr_prop_log:n #1
{
\prop_log:c { g__tblr_#1_ \int_use:N \g_tblr_level_int _prop }
}
\cs_new_protected:Npn \__tblr_prop_map_inline:nn #1 #2
{
\prop_map_inline:cn { g__tblr_#1_ \int_use:N \g_tblr_level_int _prop } {#2}
}
\cs_new_protected:Npn \__tblr_prop_gput_if_larger:nnn #1 #2 #3
{
\__tblr_gput_if_larger:cnn
{ g__tblr_#1_ \int_use:N \g_tblr_level_int _prop } { #2 } { #3 }
}
\cs_generate_variant:Nn \__tblr_prop_gput_if_larger:nnn { nnx, nnV, nxn, nxx, nxV }
\cs_new_protected:Npn \__tblr_prop_gadd_dimen_value:nnn #1 #2 #3
{
\__tblr_gadd_dimen_value:cnn
{ g__tblr_#1_ \int_use:N \g_tblr_level_int _prop } { #2 } { #3 }
}
\cs_generate_variant:Nn \__tblr_prop_gadd_dimen_value:nnn { nnx, nnV, nxn, nxx }
%% Put the dimension to the prop list only if it's larger than the old one
\tl_new:N \l__tblr_put_if_larger_tl
\cs_new_protected:Npn \__tblr_put_if_larger:Nnn #1 #2 #3
{
\tl_set:Nx \l__tblr_put_if_larger_tl { \prop_item:Nn #1 { #2 } }
\bool_lazy_or:nnT
{ \tl_if_empty_p:N \l__tblr_put_if_larger_tl }
{ \dim_compare_p:nNn { #3 } > { \l__tblr_put_if_larger_tl } }
{ \prop_put:Nnn #1 { #2 } { #3 } }
}
\cs_generate_variant:Nn \__tblr_put_if_larger:Nnn { Nnx, Nxn, Nxx, NnV }
\cs_new_protected:Npn \__tblr_gput_if_larger:Nnn #1 #2 #3
{
\tl_set:Nx \l__tblr_put_if_larger_tl { \prop_item:Nn #1 { #2 } }
\bool_lazy_or:nnT
{ \tl_if_empty_p:N \l__tblr_put_if_larger_tl }
{ \dim_compare_p:nNn { #3 } > { \l__tblr_put_if_larger_tl } }
{ \prop_gput:Nnn #1 { #2 } { #3 } }
}
\cs_generate_variant:Nn \__tblr_gput_if_larger:Nnn { Nnx, Nxn, Nxx, cnn }
%% Add the dimension to some key value of the prop list
%% #1: the prop list, #2: the key, #3: the dimen to add
\cs_new_protected:Npn \__tblr_add_dimen_value:Nnn #1 #2 #3
{
\prop_put:Nnx #1 { #2 } { \dim_eval:n { \prop_item:Nn #1 { #2 } + #3 } }
}
\cs_generate_variant:Nn \__tblr_add_dimen_value:Nnn { cnn }
\cs_new_protected:Npn \__tblr_gadd_dimen_value:Nnn #1 #2 #3
{
\prop_gput:Nnx #1 { #2 } { \dim_eval:n { \prop_item:Nn #1 { #2 } + #3 } }
}
\cs_generate_variant:Nn \__tblr_gadd_dimen_value:Nnn { cnn }
%%% --------------------------------------------------------
%%> \section{Data Structures Based on Token Lists}
%%% --------------------------------------------------------
\cs_new_protected:Npn \__tblr_clear_spec_lists:
{
%\__tblr_clear_one_spec_lists:n { row }
%\__tblr_clear_one_spec_lists:n { column }
%\__tblr_clear_one_spec_lists:n { cell }
\__tblr_clear_one_spec_lists:n { text }
\__tblr_clear_one_spec_lists:n { hline }
\__tblr_clear_one_spec_lists:n { vline }
\__tblr_clear_one_spec_lists:n { outer }
}
\cs_new_protected:Npn \__tblr_clear_one_spec_lists:n #1
{
\clist_if_exist:cTF { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist }
{
\clist_map_inline:cn { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist }
{
\tl_gclear:c { g__tblr_spec_ \int_use:N \g_tblr_level_int _#1_##1_tl }
}
}
{ \clist_new:c { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist } }
}
\cs_new_protected:Npn \__tblr_spec_gput:nnn #1 #2 #3
{
\tl_gset:cn
{ g__tblr_spec_ \int_use:N \g_tblr_level_int _#1_#2_tl } {#3}
\clist_gput_right:cx { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist } {#2}
}
\cs_generate_variant:Nn \__tblr_spec_gput:nnn { nne, nnV, nen, nee, neV }
\cs_new:Npn \__tblr_spec_item:nn #1 #2
{
\tl_if_exist:cT { g__tblr_spec_ \int_use:N \g_tblr_level_int _#1_#2_tl }
{
\exp_args:Nv \exp_not:n
{ g__tblr_spec_ \int_use:N \g_tblr_level_int _#1_#2_tl }
}
}
\cs_generate_variant:Nn \__tblr_spec_item:nn { ne }
\cs_new_protected:Npn \__tblr_spec_gput_if_larger:nnn #1 #2 #3
{
\tl_set:Nx \l__tblr_put_if_larger_tl { \__tblr_spec_item:nn {#1} {#2} }
\bool_lazy_or:nnT
{ \tl_if_empty_p:N \l__tblr_put_if_larger_tl }
{ \dim_compare_p:nNn {#3} > { \l__tblr_put_if_larger_tl } }
{ \__tblr_spec_gput:nnn {#1} {#2} {#3} }
}
\cs_generate_variant:Nn \__tblr_spec_gput_if_larger:nnn { nne, nnV, nen, nee, neV }
\cs_new_protected:Npn \__tblr_spec_gadd_dimen_value:nnn #1 #2 #3
{
\__tblr_spec_gput:nne {#1} {#2}
{ \dim_eval:n { \__tblr_spec_item:ne {#1} {#2} + #3 } }
}
\cs_generate_variant:Nn \__tblr_spec_gadd_dimen_value:nnn { nne, nnV, nen, nee }
\cs_new_protected:Npn \__tblr_spec_log:n #1
{
\clist_gremove_duplicates:c
{ g__tblr_#1_ \int_use:N \g_tblr_level_int _clist }
\tl_log:x
{
The ~ spec ~ list ~ #1 _ \int_use:N \g_tblr_level_int
\space contains ~ the ~ pairs:
}
\clist_map_inline:cn { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist }
{
\tl_log:x
{
\space { ##1 } ~\space=>~\space { \__tblr_spec_item:nn {#1} {##1} }
}
}
}
%%% --------------------------------------------------------
%%> \section{Data Structures Based on Integer Arrays}
%%% --------------------------------------------------------
\msg_new:nnn { tabularray } { intarray-beyond-bound }
{ Position ~ #2 ~ is ~ beyond ~ the ~ bound ~ of ~ intarray ~ #1.}
\cs_new_protected:Npn \__tblr_intarray_gset:Nnn #1 #2 #3
{
\bool_lazy_or:nnTF
{ \int_compare_p:nNn {#2} < {0} }
{ \int_compare_p:nNn {#2} > {\intarray_count:N #1} }
{
\bool_if:NT \g__tblr_tracing_intarray_bool
{ \msg_warning:nnnn { tabularray } { intarray-beyond-bound } {#1} {#2} }
}
{ \intarray_gset:Nnn #1 {#2} {#3} }
}
\cs_generate_variant:Nn \__tblr_intarray_gset:Nnn { cnn }
%% #1: data name; #2: key name; #3: value type
\cs_new_protected:Npn \__tblr_data_new_key:nnn #1 #2 #3
{
\int_gincr:c { g__tblr_data_#1_key_count_int }
\tl_const:ce
{
c__tblr_data_#1_key_name_
\int_use:c { g__tblr_data_#1_key_count_int } _tl
}
{ #2 }
\tl_const:ce { c__tblr_data_#1_key_number_#2_tl }
{ \int_use:c { g__tblr_data_#1_key_count_int } }
\tl_const:cn { c__tblr_data_#1_key_type_#2_tl } {#3}
}
\int_new:N \g__tblr_data_row_key_count_int
\__tblr_data_new_key:nnn { row } { height } { dim }
\__tblr_data_new_key:nnn { row } { coefficient } { dec }
\__tblr_data_new_key:nnn { row } { abovesep } { dim }
\__tblr_data_new_key:nnn { row } { belowsep } { dim }
\__tblr_data_new_key:nnn { row } { @row-height } { dim }
\__tblr_data_new_key:nnn { row } { @row-head } { dim }
\__tblr_data_new_key:nnn { row } { @row-foot } { dim }
\__tblr_data_new_key:nnn { row } { @row-upper } { dim }
\__tblr_data_new_key:nnn { row } { @row-lower } { dim }
\int_new:N \g__tblr_data_column_key_count_int
\__tblr_data_new_key:nnn { column } { width } { dim }
\__tblr_data_new_key:nnn { column } { coefficient } { dec }
\__tblr_data_new_key:nnn { column } { leftsep } { dim }
\__tblr_data_new_key:nnn { column } { rightsep } { dim }
\__tblr_data_new_key:nnn { column } { @col-width } { dim }
\int_new:N \g__tblr_data_cell_key_count_int
\__tblr_data_new_key:nnn { cell } { width } { dim }
\__tblr_data_new_key:nnn { cell } { rowspan } { int }
\__tblr_data_new_key:nnn { cell } { colspan } { int }
\__tblr_data_new_key:nnn { cell } { halign } { str }
\__tblr_data_new_key:nnn { cell } { valign } { str }
\__tblr_data_new_key:nnn { cell } { background } { str }
\__tblr_data_new_key:nnn { cell } { foreground } { str }
\__tblr_data_new_key:nnn { cell } { font } { str }
\__tblr_data_new_key:nnn { cell } { mode } { str }
\__tblr_data_new_key:nnn { cell } { cmd } { str }
\__tblr_data_new_key:nnn { cell } { omit } { int }
\__tblr_data_new_key:nnn { cell } { @cell-width } { dim }
\__tblr_data_new_key:nnn { cell } { @cell-height } { dim }
\__tblr_data_new_key:nnn { cell } { @cell-depth } { dim }
\clist_const:Nn \c__tblr_data_clist { row, column, cell }
\tl_const:Nn \c__tblr_data_row_count_tl { \c@rowcount }
\tl_const:Nn \c__tblr_data_column_count_tl { \c@colcount }
\tl_const:Nn \c__tblr_data_cell_count_tl { \c@rowcount * \c@colcount }
\tl_const:Nn \c__tblr_data_row_index_number_tl {1}
\tl_const:Nn \c__tblr_data_column_index_number_tl {1}
\tl_const:Nn \c__tblr_data_cell_index_number_tl {2}
\int_new:N \g__tblr_array_int
\cs_new_protected:Npn \__tblr_init_table_data:
{
\clist_map_function:NN \c__tblr_data_clist \__tblr_init_one_data:n
}
\cs_new_protected:Npn \__tblr_init_one_data:n #1
{
\int_gincr:N \g__tblr_array_int
\intarray_new:cn { g__tblr_#1_ \int_use:N \g__tblr_array_int _intarray }
{
\int_use:c { g__tblr_data_#1_key_count_int }
* \tl_use:c { c__tblr_data_#1_count_tl }
}
\cs_set_eq:cc { g__tblr_#1_ \int_use:N \g_tblr_level_int _intarray }
{ g__tblr_#1_ \int_use:N \g__tblr_array_int _intarray }
%\intarray_log:c { g__tblr_#1_ \int_use:N \g_tblr_level_int _intarray }
}
%% #1: data name; #2: data index; #3: key name
\cs_new:Npn \__tblr_data_key_to_int:nnn #1 #2 #3
{
( #2 - 1 ) * \int_use:c { g__tblr_data_#1_key_count_int }
+ \tl_use:c { c__tblr_data_#1_key_number_#3_tl }
}
%% #1: data name; #2: data index 1; #3: data index 2; #4: key name
\cs_new:Npn \__tblr_data_key_to_int:nnnn #1 #2 #3 #4
{
( #2 - 1 ) * \c@colcount * \int_use:c { g__tblr_data_#1_key_count_int }
+ ( #3 - 1 ) * \int_use:c { g__tblr_data_#1_key_count_int }
+ \tl_use:c { c__tblr_data_#1_key_number_#4_tl }
}
\int_new:N \l__tblr_key_count_int
\int_new:N \l__tblr_key_quotient_int
\int_new:N \l__tblr_key_quotient_two_int
\int_new:N \l__tblr_key_remainder_int
%% #1: data name; #2: array position;
%% #3: returning tl with index; #4: returning tl with key name
\cs_new:Npn \__tblr_data_int_to_key:nnNN #1 #2 #3 #4
{
\int_set_eq:Nc \l__tblr_key_count_int { g__tblr_data_#1_key_count_int }
\int_set:Nn \l__tblr_key_quotient_int
{
\int_div_truncate:nn
{ #2 + \l__tblr_key_count_int - 1 } { \l__tblr_key_count_int }
}
\int_set:Nn \l__tblr_key_remainder_int
{
#2 + \l__tblr_key_count_int
- \l__tblr_key_quotient_int * \l__tblr_key_count_int
}
\int_compare:nNnT { \l__tblr_key_remainder_int } = { 0 }
{ \int_set_eq:NN \l__tblr_key_remainder_int \l__tblr_key_count_int }
\tl_set:Nx #3 { \int_use:N \l__tblr_key_quotient_int }
\tl_set_eq:Nc #4
{ c__tblr_data_#1_key_name_ \int_use:N \l__tblr_key_remainder_int _tl }
}
%% #1: data name; #2: array position;
%% #3: returning tl with index 1; #4: returning tl with index 2;
%% #5: returning tl with key name
\cs_new:Npn \__tblr_data_int_to_key:nnNNN #1 #2 #3 #4 #5
{
\int_set_eq:Nc \l__tblr_key_count_int { g__tblr_data_#1_key_count_int }
\int_set:Nn \l__tblr_key_quotient_int
{
\int_div_truncate:nn
{ #2 + \l__tblr_key_count_int - 1 } { \l__tblr_key_count_int }
}
\int_set:Nn \l__tblr_key_remainder_int
{
#2 + \l__tblr_key_count_int
- \l__tblr_key_quotient_int * \l__tblr_key_count_int
}
\int_compare:nNnT { \l__tblr_key_remainder_int } = { 0 }
{ \int_set_eq:NN \l__tblr_key_remainder_int \l__tblr_key_count_int }
\tl_set_eq:Nc #5
{ c__tblr_data_#1_key_name_ \int_use:N \l__tblr_key_remainder_int _tl }
\int_set:Nn \l__tblr_key_quotient_two_int
{
\int_div_truncate:nn
{ \l__tblr_key_quotient_int + \c@colcount - 1 } { \c@colcount }
}
\int_set:Nn \l__tblr_key_remainder_int
{
\l__tblr_key_quotient_int + \c@colcount
- \l__tblr_key_quotient_two_int * \c@colcount
}
\int_compare:nNnT { \l__tblr_key_remainder_int } = { 0 }
{ \int_set_eq:NN \l__tblr_key_remainder_int \c@colcount }
\tl_set:Nx #4 { \int_use:N \l__tblr_key_remainder_int }
\tl_set:Nx #3 { \int_use:N \l__tblr_key_quotient_two_int }
}
\tl_new:N \g__tblr_data_int_from_value_tl
%% #1: data name; #2: key name; #3: value
%% The result will be stored in \g__tblr_data_int_from_value_tl
\cs_new_protected:Npn \__tblr_data_int_from_value:nnn #1 #2 #3
{
\cs:w
__tblr_data_int_from_ \tl_use:c { c__tblr_data_#1_key_type_#2_tl } :n
\cs_end:
{#3}
}
%% #1: data name; #2: key name; #3: int
\cs_new:Npn \__tblr_data_int_to_value:nnn #1 #2 #3
{
\cs:w
__tblr_data_int_to_ \tl_use:c { c__tblr_data_#1_key_type_#2_tl } :n
\cs_end:
{#3}
}
\cs_generate_variant:Nn \__tblr_data_int_to_value:nnn { nne, nVe }
\cs_new_protected:Npn \__tblr_data_int_from_int:n #1
{
\tl_gset:Nn \g__tblr_data_int_from_value_tl {#1}
}
\cs_new:Npn \__tblr_data_int_to_int:n #1
{
#1
}
\cs_new_protected:Npn \__tblr_data_int_from_dim:n #1
{
\tl_gset:Nx \g__tblr_data_int_from_value_tl { \dim_to_decimal_in_sp:n {#1} }
}
%% Return a dimension in pt so that it's easier to understand in tracing messages
\cs_new:Npn \__tblr_data_int_to_dim:n #1
{
%#1 sp
%\dim_eval:n { #1 sp }
\dim_to_decimal:n { #1 sp } pt
}
\cs_new_protected:Npn \__tblr_data_int_from_dec:n #1
{
\tl_gset:Nx \g__tblr_data_int_from_value_tl
{ \dim_to_decimal_in_sp:n {#1 pt} }
}
\cs_new:Npn \__tblr_data_int_to_dec:n #1
{
\dim_to_decimal:n {#1 sp}
}
\int_new:N \g__tblr_data_str_value_count_int
\tl_gclear_new:c { g__tblr_data_0_to_str_tl }
\cs_new_protected:Npn \__tblr_data_int_from_str:n #1
{
\tl_if_exist:cTF { g__tblr_data_ \tl_to_str:n {#1} _to_int_tl }
{
\tl_gset_eq:Nc \g__tblr_data_int_from_value_tl
{ g__tblr_data_ \tl_to_str:n {#1} _to_int_tl }
}
{
\int_gincr:N \g__tblr_data_str_value_count_int
\tl_gset:cx { g__tblr_data_ \tl_to_str:n {#1} _to_int_tl }
{ \int_use:N \g__tblr_data_str_value_count_int }
\tl_gset:cn
{ g__tblr_data_ \int_use:N \g__tblr_data_str_value_count_int _to_str_tl }
{ \exp_not:n {#1} }
\tl_gset:Nx \g__tblr_data_int_from_value_tl
{ \int_use:N \g__tblr_data_str_value_count_int }
}
}
\cs_new:Npn \__tblr_data_int_to_str:n #1
{
\tl_use:c { g__tblr_data_#1_to_str_tl }
}
%% #1: data name; #2: data index; #3: key; #4: value
\cs_new_protected:Npn \__tblr_data_gput:nnnn #1 #2 #3 #4
{
\__tblr_data_int_from_value:nnn {#1} {#3} {#4}
\__tblr_intarray_gset:cnn
{ g__tblr_#1_ \int_use:N \g_tblr_level_int _intarray }
{ \__tblr_data_key_to_int:nnn {#1} {#2} {#3} }
{ \g__tblr_data_int_from_value_tl }
}
\cs_generate_variant:Nn \__tblr_data_gput:nnnn
{ nnne, nnnV, nenn, nene, nenV, nVnn }
%% #1: data name; #2: data index 1; #3: data index 2; #4: key; #5: value
\cs_new_protected:Npn \__tblr_data_gput:nnnnn #1 #2 #3 #4 #5
{
\__tblr_data_int_from_value:nnn {#1} {#4} {#5}
\__tblr_intarray_gset:cnn
{ g__tblr_#1_ \int_use:N \g_tblr_level_int _intarray }
{ \__tblr_data_key_to_int:nnnn {#1} {#2} {#3} {#4} }
{ \g__tblr_data_int_from_value_tl }
}
\cs_generate_variant:Nn \__tblr_data_gput:nnnnn
{ nnnne, nnnnV, neenn, neene, neenV, neeen, nVVnn }
%% #1: data name; #2: data index; #3: key
\cs_new:Npn \__tblr_data_item:nnn #1 #2 #3
{
\__tblr_data_int_to_value:nne {#1} {#3}
{
\intarray_item:cn { g__tblr_#1_ \int_use:N \g_tblr_level_int _intarray }
{ \__tblr_data_key_to_int:nnn {#1} {#2} {#3} }
}
}
\cs_generate_variant:Nn \__tblr_data_item:nnn { nen }
%% #1: data name; #2: data index 1; #3: data index 2; #4: key
\cs_new:Npn \__tblr_data_item:nnnn #1 #2 #3 #4
{
\__tblr_data_int_to_value:nne {#1} {#4}
{
\intarray_item:cn { g__tblr_#1_ \int_use:N \g_tblr_level_int _intarray }
{ \__tblr_data_key_to_int:nnnn {#1} {#2} {#3} {#4} }
}
}
\cs_generate_variant:Nn \__tblr_data_item:nnnn { neen }
\tl_new:N \l__tblr_data_key_tl
\tl_new:N \l__tblr_data_index_tl
\tl_new:N \l__tblr_data_index_two_tl
\cs_new_protected:Npn \__tblr_data_log:n #1
{
\use:c { __tblr_data_log_ \use:c { c__tblr_data_#1_index_number_tl } :n } {#1}
\__tblr_prop_log:n {#1}
}
\cs_new_protected:cpn { __tblr_data_log_1:n } #1
{
%\intarray_log:c { g__tblr_#1_ \int_use:N \g_tblr_level_int _intarray }
\tl_set:Nx \l_tmpa_tl { g__tblr_#1_ \int_use:N \g_tblr_level_int _intarray }
\tl_log:n { ----------~----------~----------~----------~---------- }
\int_step_inline:nn
{ \intarray_count:c { \l_tmpa_tl } }
{
\__tblr_data_int_to_key:nnNN {#1} {##1}
\l__tblr_data_index_tl \l__tblr_data_key_tl
\tl_log:x
{
\space
{ #1 [\l__tblr_data_index_tl] / \l__tblr_data_key_tl }
~\space => ~\space
{
\__tblr_data_int_to_value:nVe {#1} \l__tblr_data_key_tl
{ \intarray_item:cn { \l_tmpa_tl } {##1} }
}
}
}
}
\cs_new_protected:cpn { __tblr_data_log_2:n } #1
{
%\intarray_log:c { g__tblr_#1_ \int_use:N \g_tblr_level_int _intarray }
\tl_set:Nx \l_tmpa_tl { g__tblr_#1_ \int_use:N \g_tblr_level_int _intarray }
\tl_log:n { ----------~----------~----------~----------~---------- }
\int_step_inline:nn
{ \intarray_count:c { \l_tmpa_tl } }
{
\__tblr_data_int_to_key:nnNNN {#1} {##1}
\l__tblr_data_index_tl \l__tblr_data_index_two_tl \l__tblr_data_key_tl
\tl_log:x
{
\space
{
#1 [\l__tblr_data_index_tl][\l__tblr_data_index_two_tl]
/ \l__tblr_data_key_tl
}
~\space => ~\space
{
\__tblr_data_int_to_value:nVe {#1} \l__tblr_data_key_tl
{ \intarray_item:cn { \l_tmpa_tl } {##1} }
}
}
}
}
%% #1: data name; #2: row index; #3: key; #4: value
\cs_new_protected:Npn \__tblr_data_gput_if_larger:nnnn #1 #2 #3 #4
{
\__tblr_data_int_from_value:nnn {#1} {#3} {#4}
\__tblr_array_gput_if_larger:cnn
{ g__tblr_#1_ \int_use:N \g_tblr_level_int _intarray }
{ \__tblr_data_key_to_int:nnn {#1} {#2} {#3} }
{ \g__tblr_data_int_from_value_tl }
}
\cs_generate_variant:Nn \__tblr_data_gput_if_larger:nnnn { nnne, nnnV, nene, nenV }
\cs_new_protected:Npn \__tblr_array_gput_if_larger:Nnn #1 #2 #3
{
\int_compare:nNnT {#3} > { \intarray_item:Nn #1 {#2} }
{ \__tblr_intarray_gset:Nnn #1 {#2} {#3} }
}
\cs_generate_variant:Nn \__tblr_array_gput_if_larger:Nnn { cnn }
%% #1: data name; #2: data index; #3: key; #4: value
\cs_new_protected:Npn \__tblr_data_gadd_dimen_value:nnnn #1 #2 #3 #4
{
\__tblr_data_int_from_value:nnn {#1} {#3} {#4}
\__tblr_array_gadd_value:cnn
{ g__tblr_#1_ \int_use:N \g_tblr_level_int _intarray }
{ \__tblr_data_key_to_int:nnn {#1} {#2} {#3} }
{ \g__tblr_data_int_from_value_tl }
}
\cs_generate_variant:Nn \__tblr_data_gadd_dimen_value:nnnn
{ nnne, nnnV, nenn, nene }
\cs_new_protected:Npn \__tblr_array_gadd_value:Nnn #1 #2 #3
{
\__tblr_intarray_gset:Nnn #1 {#2} { \intarray_item:Nn #1 {#2} + #3 }
}
\cs_generate_variant:Nn \__tblr_array_gadd_value:Nnn { cnn }
\bool_new:N \g__tblr_use_intarray_bool
\bool_gset_true:N \g__tblr_use_intarray_bool
\AtBeginDocument
{
\bool_if:NF \g__tblr_use_intarray_bool
{
\cs_set_protected:Npn \__tblr_data_gput:nnnn #1 #2 #3 #4
{
\__tblr_spec_gput:nnn {#1} { [#2] / #3 } {#4}
}
\cs_set_protected:Npn \__tblr_data_gput:nnnnn #1 #2 #3 #4 #5
{
\__tblr_spec_gput:nnn {#1} { [#2][#3] / #4 } {#5}
}
\cs_set:Npn \__tblr_data_item:nnn #1 #2 #3
{
\__tblr_spec_item:nn {#1} { [#2] / #3 }
}
\cs_set:Npn \__tblr_data_item:nnnn #1 #2 #3 #4
{
\__tblr_spec_item:nn {#1} { [#2][#3] / #4 }
}
\cs_set_protected:Npn \__tblr_data_log:n #1
{
\__tblr_spec_log:n {#1}
}
\cs_set_protected:Npn \__tblr_data_gput_if_larger:nnnn #1 #2 #3 #4
{
\__tblr_spec_gput_if_larger:nnn {#1} { [#2] / #3 } {#4}
}
\cs_set_protected:Npn \__tblr_data_gput_if_larger:nnnnn #1 #2 #3 #4 #5
{
\__tblr_spec_gput_if_larger:nnn {#1} { [#2][#3] / #4 } {#5}
}
\cs_set_protected:Npn \__tblr_data_gadd_dimen_value:nnnn #1 #2 #3 #4
{
\__tblr_spec_gadd_dimen_value:nnn {#1} { [#2] / #3 } {#4}
}
\cs_set_protected:Npn \__tblr_data_gadd_dimen_value:nnnnn #1 #2 #3 #4 #5
{
\__tblr_spec_gadd_dimen_value:nnn {#1} { [#2][#3] / #4 } {#5}
}
}
}
%%% --------------------------------------------------------
%%> \section{Child Selectors}
%%% --------------------------------------------------------
\clist_new:N \g_tblr_used_child_selectors_clist
\tl_new:N \l__tblr_childs_arg_spec_tl
\msg_new:nnn { tabularray } { used-child-selector }
{ Child ~ selector ~ name ~ "#1" ~ has ~ been ~ used! }
\NewDocumentCommand \NewChildSelector { m O{0} o m }
{
\__tblr_new_child_selector_aux:xnnn { \tl_trim_spaces:n {#1} } {#2} {#3} {#4}
}
\cs_new_protected:Npn \__tblr_new_child_selector_aux:nnnn #1 #2 #3 #4
{
\clist_if_in:NnTF \g_tblr_used_child_selectors_clist { #1 }
{
\msg_error:nnn { tabularray } { used-child-selector } { #1 }
\clist_log:N \g_tblr_used_child_selectors_clist
}
{
\__tblr_make_xparse_arg_spec:nnN { #2 } { #3 } \l__tblr_childs_arg_spec_tl
\exp_args:NcV \NewDocumentCommand
{ __tblr_child_selector_ #1 :w } \l__tblr_childs_arg_spec_tl { #4 }
\clist_gput_right:Nn \g_tblr_used_child_selectors_clist { #1 }
}
}
\cs_generate_variant:Nn \__tblr_new_child_selector_aux:nnnn { xnnn }
%% #1: argument number, #2: optional argument default, #3: result tl
\cs_new_protected:Npn \__tblr_make_xparse_arg_spec:nnN #1 #2 #3
{
\tl_clear:N #3
\int_compare:nNnT { #1 } > { 0 }
{
\IfValueTF { #2 }
{ \tl_set:Nn #3 { O{#2} } }
{ \tl_set:Nn #3 { m } }
\tl_put_right:Nx #3 { \prg_replicate:nn { #1 - 1 } { m } }
}
}
\clist_new:N \l_tblr_childs_clist
\tl_new:N \l_tblr_childs_total_tl
\NewChildSelector { odd } [1] []
{
\tl_if_blank:nTF {#1}
{
\int_step_inline:nnnn {1} {2} { \l_tblr_childs_total_tl }
{ \clist_put_right:Nn \l_tblr_childs_clist {##1} }
}
{ \__tblr_child_selector_odd_or_even:nn { odd } {#1} }
}
\NewChildSelector { even } [1] []
{
\tl_if_blank:nTF {#1}
{
\int_step_inline:nnnn {2} {2} { \l_tblr_childs_total_tl }
{ \clist_put_right:Nn \l_tblr_childs_clist {##1} }
}
{ \__tblr_child_selector_odd_or_even:nn { even } {#1} }
}
\tl_new:N \l__tblr_child_from_tl
\tl_new:N \l__tblr_child_to_tl
%% #1: odd or even; #2: selector option
\cs_new_protected:Npn \__tblr_child_selector_odd_or_even:nn #1 #2
{
\seq_set_split:Nnn \l_tmpa_seq {-} { #2 - Z }
\tl_set:Nx \l__tblr_child_from_tl { \seq_item:Nn \l_tmpa_seq {1} }
\tl_set:Nx \l__tblr_child_to_tl { \seq_item:Nn \l_tmpa_seq {2} }
\tl_use:c { int_if_ #1 :nF } { \l__tblr_child_from_tl }
{
\tl_set:Nx \l__tblr_child_from_tl
{ \int_eval:n { \l__tblr_child_from_tl + 1 } }
}
\__tblr_child_name_to_index:VN \l__tblr_child_to_tl \l__tblr_child_to_tl
\int_step_inline:nnnn { \l__tblr_child_from_tl } {2} { \l__tblr_child_to_tl }
{ \clist_put_right:Nn \l_tblr_childs_clist {##1} }
}
\regex_const:Nn \c__tblr_split_selector_name_regex { ^ ( [A-Za-z] {2,} ) ( . * ) }
\seq_new:N \l__tblr_childs_split_seq
\seq_new:N \l__tblr_childs_regex_seq
\tl_new:N \l__tblr_childs_selector_tl
%% #1, child specifications; #2, total number.
%% The result will be put into \l_tblr_childs_clist
\cs_new_protected:Npn \__tblr_get_childs:nn #1 #2
{
\clist_clear:N \l_tblr_childs_clist
\tl_set:Nx \l_tblr_childs_total_tl {#2}
\regex_extract_once:NnNTF \c__tblr_split_selector_name_regex {#1}
\l__tblr_childs_regex_seq
{
\tl_set:No \l__tblr_childs_selector_tl
{
\cs:w
__tblr_child_selector_ \seq_item:Nn \l__tblr_childs_regex_seq {2} :w
\cs_end:
}
\exp_last_unbraced:Nx \l__tblr_childs_selector_tl
{ \seq_item:Nn \l__tblr_childs_regex_seq{3} }
}
{
\tl_if_eq:nnTF {#1} {-}
{ \__tblr_get_childs_normal:nn {1-#2} {#2} }
{ \__tblr_get_childs_normal:nn {#1} {#2} }
}
%\clist_log:N \l_tblr_childs_clist
}
\cs_generate_variant:Nn \__tblr_get_childs:nn { nx }
\cs_new_protected:Npn \__tblr_get_childs_normal:nn #1 #2
{
\seq_set_split:Nnn \l__tblr_childs_split_seq {,} {#1}
\seq_map_inline:Nn \l__tblr_childs_split_seq
{
\tl_if_in:nnTF {##1} {-}
{ \__tblr_get_childs_normal_aux:w ##1 \scan_stop }
{ \__tblr_get_childs_normal_aux:w ##1 - ##1 \scan_stop }
}
}
\cs_new_protected_nopar:Npn \__tblr_get_childs_normal_aux:w #1 - #2 \scan_stop
{
\__tblr_child_name_to_index:nN {#1} \l__tblr_child_from_tl
\__tblr_child_name_to_index:nN {#2} \l__tblr_child_to_tl
\int_step_inline:nnn { \l__tblr_child_from_tl } { \l__tblr_child_to_tl }
{ \clist_put_right:Nn \l_tblr_childs_clist {##1} }
}
\regex_const:Nn \c__tblr_child_name_regex { ^ [U-Z] $ }
%% Convert U, V, W, X, Y, Z to the indexes of the last six childs, respectively
\cs_new_protected_nopar:Npn \__tblr_child_name_to_index:nN #1 #2
{
\regex_match:NnTF \c__tblr_child_name_regex {#1}
{
\tl_set:Nx #2
{ \int_eval:n { \l_tblr_childs_total_tl + \int_from_alph:n {#1} - 26 } }
}
{ \tl_set:Nx #2 { #1 } }
}
\cs_generate_variant:Nn \__tblr_child_name_to_index:nN { VN }
%%% --------------------------------------------------------
%%> \section{New Table Commands}
%%% --------------------------------------------------------
%% We need some commands to modify table/row/column/cell specifications.
%% These commands must be defined with \NewTableCommand command,
%% so that we could extract them, execute them once, then disable them.
\clist_new:N \g__tblr_table_commands_clist
\msg_new:nnn { tabularray } { defined-table-command }
{ Table ~ command ~ #1 already ~ defined! }
\NewDocumentCommand \NewTableCommand { m O{0} o m }
{
\clist_if_in:NnTF \g__tblr_table_commands_clist { #1 }
{
\msg_error:nnn { tabularray } { defined-table-command } { #1 }
\clist_log:N \g__tblr_table_commands_clist
}
{
\__tblr_make_xparse_arg_spec:nnN { #2 } { #3 } \l__tblr_a_tl
\exp_args:NcV \NewDocumentCommand
{ __tblr_table_command_ \cs_to_str:N #1 :w } \l__tblr_a_tl { #4 }
%% we can not use \cs_if_exist:NTF here (see issue #328)
\__tblr_cs_if_defined:NTF #1
{
\cs_set_eq:cN { __tblr_table_command_ \cs_to_str:N #1 _saved:w } #1
}
{
\exp_args:NcV \NewDocumentCommand
{ __tblr_table_command_ \cs_to_str:N #1 _saved:w } \l__tblr_a_tl { }
}
\IfValueTF { #3 }
{
\tl_gset:cn { g__tblr_table_cmd_ \cs_to_str:N #1 _arg_numb_tl } {-#2}
}
{
\tl_gset:cn { g__tblr_table_cmd_ \cs_to_str:N #1 _arg_numb_tl } {#2}
}
\clist_gput_right:Nn \g__tblr_table_commands_clist { #1 }
}
}
\cs_new_protected:Npn \__tblr_enable_table_commands:
{
\clist_map_inline:Nn \g__tblr_table_commands_clist
{ \cs_set_eq:Nc ##1 { __tblr_table_command_ \cs_to_str:N ##1 :w } }
}
\cs_new_protected:Npn \__tblr_disable_table_commands:
{
\clist_map_inline:Nn \g__tblr_table_commands_clist
{ \cs_set_eq:Nc ##1 { __tblr_table_command_ \cs_to_str:N ##1 _saved:w } }
}
\cs_new_protected:Npn \__tblr_execute_table_commands:
{
\__tblr_prop_map_inline:nn { command }
{
\__tblr_set_row_col_from_key_name:w ##1
##2
}
\LogTblrTracing { cell }
}
\cs_new_protected:Npn \__tblr_set_row_col_from_key_name:w [#1][#2]
{
\int_set:Nn \c@rownum {#1}
\int_set:Nn \c@colnum {#2}
}
%% Add \empty as a table command so that users can write \\\empty\hline (see #328)
\NewTableCommand\empty{}
%% Table commands are defined only inside tblr environments,
%% but some packages such as csvsimple need to use them outside tblr environments,
%% therefore we define some of them first here.
\ProvideDocumentCommand \SetHlines { o m m } {}
\ProvideDocumentCommand \SetHline { o m m } {}
\ProvideDocumentCommand \SetVlines { o m m } {}
\ProvideDocumentCommand \SetVline { o m m } {}
\ProvideDocumentCommand \SetCells { o m } {}
\ProvideDocumentCommand \SetCell { o m } {}
\ProvideDocumentCommand \SetRows { o m } {}
\ProvideDocumentCommand \SetRow { o m } {}
\ProvideDocumentCommand \SetColumns { o m } {}
\ProvideDocumentCommand \SetColumn { o m } {}
%%% --------------------------------------------------------
%%> \section{New Content Commands}
%%% --------------------------------------------------------
%% We need to emulate or fix some commands such as \diagbox in other packages
%% These commands must be defined with \NewContentCommand command
%% We only enable them inside tblr environment to avoid potential conflict
\clist_new:N \g__tblr_content_commands_clist
\msg_new:nnn { tabularray } { defined-content-command }
{ Content ~ command ~ #1 already ~ defined! }
\NewDocumentCommand \NewContentCommand { m O{0} o m }
{
\clist_if_in:NnTF \g__tblr_content_commands_clist { #1 }
{
\msg_error:nnn { tabularray } { defined-content-command } { #1 }
\clist_log:N \g__tblr_content_commands_clist
}
{
\__tblr_make_xparse_arg_spec:nnN { #2 } { #3 } \l__tblr_a_tl
\exp_args:NcV \NewDocumentCommand
{ __tblr_content_command_ \cs_to_str:N #1 :w } \l__tblr_a_tl { #4 }
\clist_gput_right:Nn \g__tblr_content_commands_clist { #1 }
}
}
\cs_new_protected:Npn \__tblr_enable_content_commands:
{
\clist_map_inline:Nn \g__tblr_content_commands_clist
{ \cs_set_eq:Nc ##1 { __tblr_content_command_ \cs_to_str:N ##1 :w } }
}
%%% --------------------------------------------------------
%%> \section{New Dash Styles}
%%% --------------------------------------------------------
%% \NewDashStyle commands
\dim_zero_new:N \rulewidth
\dim_set:Nn \rulewidth {0.4pt}
\prop_gset_from_keyval:Nn \g__tblr_defined_hdash_styles_prop
{ solid = \hrule height \rulewidth }
\prop_gset_from_keyval:Nn \g__tblr_defined_vdash_styles_prop
{ solid = \vrule width \rulewidth }
\NewDocumentCommand \NewDashStyle { m m }
{
\seq_set_split:Nnn \l_tmpa_seq { ~ } {#2}
\tl_set:Nx \l__tblr_a_tl { \seq_item:Nn \l_tmpa_seq {1} }
\tl_set:Nx \l__tblr_b_tl { \seq_item:Nn \l_tmpa_seq {2} }
\tl_set:Nx \l__tblr_c_tl { \seq_item:Nn \l_tmpa_seq {3} }
\tl_set:Nx \l__tblr_d_tl { \seq_item:Nn \l_tmpa_seq {4} }
\tl_if_eq:NnT \l__tblr_a_tl { on }
{
\tl_if_eq:NnT \l__tblr_c_tl { off }
{
\__tblr_dash_style_make_boxes:nxx {#1}
{ \dim_eval:n {\l__tblr_b_tl} } { \dim_eval:n {\l__tblr_d_tl} }
}
}
}
\cs_new_protected:Npn \__tblr_dash_style_make_boxes:nnn #1 #2 #3
{
\dim_set:Nn \l_tmpa_dim { #2 + #3 }
\tl_set:Nn \l__tblr_h_tl { \hbox_to_wd:nn }
\tl_put_right:Nx \l__tblr_h_tl { { \dim_use:N \l_tmpa_dim } }
\tl_put_right:Nn \l__tblr_h_tl
{
{ \hss \vbox:n { \hbox_to_wd:nn {#2} {} \hrule height \rulewidth } \hss }
}
\prop_gput:NnV \g__tblr_defined_hdash_styles_prop {#1} \l__tblr_h_tl
%\prop_log:N \g__tblr_defined_hdash_styles_prop
\tl_set:Nn \l__tblr_v_tl { \vbox_to_ht:nn }
\tl_put_right:Nx \l__tblr_v_tl { { \dim_use:N \l_tmpa_dim } }
\tl_put_right:Nn \l__tblr_v_tl
{
{ \vss \hbox:n { \vbox_to_ht:nn {#2} {} \vrule width \rulewidth } \vss }
}
\prop_gput:NnV \g__tblr_defined_vdash_styles_prop {#1} \l__tblr_v_tl
%\prop_log:N \g__tblr_defined_vdash_styles_prop
}
\cs_generate_variant:Nn \__tblr_dash_style_make_boxes:nnn { nxx }
\cs_new_protected:Npn \__tblr_get_hline_dash_style:N #1
{
\tl_set:Nx \l_tmpa_tl
{ \prop_item:NV \g__tblr_defined_hdash_styles_prop #1 }
\tl_if_empty:NF \l_tmpa_tl { \tl_set_eq:NN #1 \l_tmpa_tl }
}
\cs_new_protected:Npn \__tblr_get_vline_dash_style:N #1
{
\tl_set:Nx \l_tmpa_tl
{ \prop_item:NV \g__tblr_defined_vdash_styles_prop #1 }
\tl_if_empty:NF \l_tmpa_tl { \tl_set_eq:NN #1 \l_tmpa_tl }
}
\NewDashStyle {dashed} {on ~ 2pt ~ off ~ 2pt}
\NewDashStyle {dotted} {on ~ 0.4pt ~ off ~ 1pt}
%%% --------------------------------------------------------
%%> \section{Set Hlines and Vlines}
%%% --------------------------------------------------------
\tl_const:Nn \@tblr@dash { dash }
\tl_const:Nn \@tblr@text { text }
\regex_const:Nn \c__tblr_is_color_key_regex { ^[A-Za-z] }
%% \SetHlines command for setting every hline in the table
\NewTableCommand \SetHlines [3] [+]
{
\tblr_set_every_hline:nnn {#1} {#2} {#3}
}
%% We put all code inside a group to avoid affecting other table commands
\cs_new_protected:Npn \tblr_set_every_hline:nnn #1 #2 #3
{
\group_begin:
\int_step_inline:nn { \int_eval:n { \c@rowcount + 1 } }
{
\int_set:Nn \c@rownum {##1}
\tblr_set_hline:nnn {#1} {#2} {#3}
}
\group_end:
}
%% Check the number of arguments and call \tblr_set_every_hline in different ways
%% This function is called when parsing table specifications
\cs_new_protected:Npn \__tblr_set_every_hline_aux:n #1
{
\tl_if_head_is_group:nTF {#1}
{
\int_compare:nNnTF { \tl_count:n {#1} } = {3}
{ \tblr_set_every_hline:nnn #1 }
{ \tblr_set_every_hline:nnn {1} #1 }
}
{ \tblr_set_every_hline:nnn {1} {-} {#1} }
}
%% Add \SetHline, \hline and \cline commands
\tl_new:N \l__tblr_hline_count_tl % the count of all hlines
\tl_new:N \l__tblr_hline_num_tl % the index of the hline
\tl_new:N \l__tblr_hline_cols_tl % the columns of the hline
\tl_new:N \l__tblr_hline_dash_tl % dash style
\tl_new:N \l__tblr_hline_fg_tl % dash foreground
\tl_new:N \l__tblr_hline_wd_tl % dash width
\tl_new:N \l__tblr_hline_leftpos_tl % left position
\tl_new:N \l__tblr_hline_rightpos_tl % right position
\bool_new:N \l__tblr_hline_endpos_bool % whether set positions only for both ends
\NewTableCommand \cline [2] [] { \SetHline [=] {#2} {#1} }
\NewTableCommand \hline [1] [] { \SetHline [+] {-} {#1} }
%% #1: the index of the hline (may be + or =)
%% #2: which columns of the hline, separate by commas
%% #3: key=value pairs
\NewTableCommand \SetHline [3] [+]
{
\tblr_set_hline:nnn {#1} {#2} {#3}
}
%% We need to check "text" key first
%% If it does exist and has empty value, then do nothing
\cs_new_protected:Npn \tblr_set_hline:nnn #1 #2 #3
{
\group_begin:
\keys_set_groups:nnn { tblr-hline } { text } {#3}
\tl_if_eq:NnF \l__tblr_hline_dash_tl { \exp_not:N \@tblr@text }
{
\__tblr_set_hline_num:n {#1}
\tl_clear:N \l__tblr_hline_dash_tl
\keys_set:nn { tblr-hline } { dash = solid, #3 }
\__tblr_set_hline_cmd:n {#2}
}
\group_end:
}
\cs_new_protected:Npn \tblr_set_hline:nnnn #1 #2 #3 #4
{
\group_begin:
\__tblr_get_childs:nx {#1} { \int_eval:n { \c@rowcount + 1 } }
\clist_map_inline:Nn \l_tblr_childs_clist
{
\int_set:Nn \c@rownum {##1}
\tblr_set_hline:nnn {#2} {#3} {#4}
}
\group_end:
}
%% Check the number of arguments and call \tblr_set_hline in different ways
%% Note that #1 always includes an outer pair of braces
%% This function is called when parsing table specifications
\cs_new_protected:Npn \__tblr_set_hline_aux:nn #1 #2
{
\tl_if_head_is_group:nTF {#2}
{
\int_compare:nNnTF { \tl_count:n {#2} } = {3}
{ \tblr_set_hline:nnnn #1 #2 }
{ \tblr_set_hline:nnnn #1 {1} #2 }
}
{ \tblr_set_hline:nnnn #1 {1} {-} {#2} }
}
\cs_generate_variant:Nn \__tblr_set_hline_aux:nn { Vn }
%% #1: the index of hline to set (may be + or =)
\cs_new_protected:Npn \__tblr_set_hline_num:n #1
{
\tl_clear:N \l__tblr_hline_num_tl
\tl_set:Nx \l__tblr_hline_count_tl
{ \__tblr_spec_item:ne { hline } { [\int_use:N \c@rownum] / @hline-count } }
%% \l__tblr_hline_count_tl may be empty when rowspec has extra |'s
\int_compare:nNnTF { \l__tblr_hline_count_tl + 0 } = {0}
{
\tl_set:Nx \l__tblr_hline_num_tl { 1 }
\__tblr_spec_gput:nen { hline }
{ [\int_use:N \c@rownum] / @hline-count } { 1 }
}
{
\tl_if_eq:nnTF {#1} {+}
{ \__tblr_set_hline_num_incr: }
{
\tl_if_eq:nnTF {#1} {=}
{ \tl_set_eq:NN \l__tblr_hline_num_tl \l__tblr_hline_count_tl }
{
\int_compare:nNnTF {#1} > { \l__tblr_hline_count_tl }
{ \__tblr_set_hline_num_incr: }
{ \tl_set:Nn \l__tblr_hline_num_tl {#1} }
}
}
}
}
\cs_new_protected:Npn \__tblr_set_hline_num_incr:
{
\tl_set:Nx \l__tblr_hline_count_tl
{ \int_eval:n { \l__tblr_hline_count_tl + 1 } }
\__tblr_spec_gput:nee { hline }
{ [\int_use:N \c@rownum] / @hline-count } { \l__tblr_hline_count_tl }
\tl_set_eq:NN \l__tblr_hline_num_tl \l__tblr_hline_count_tl
}
\keys_define:nn { tblr-hline }
{
dash .code:n = \tl_set:Nn \l__tblr_hline_dash_tl { \exp_not:N \@tblr@dash #1 },
text .code:n = \tl_set:Nn \l__tblr_hline_dash_tl { \exp_not:N \@tblr@text #1 },
text .groups:n = { text },
wd .code:n = \tl_set:Nn \l__tblr_hline_wd_tl { \dim_eval:n {#1} },
fg .code:n = \tl_set:Nn \l__tblr_hline_fg_tl {#1},
leftpos .code:n = \tl_set:Nx \l__tblr_hline_leftpos_tl {#1},
rightpos .code:n = \tl_set:Nx \l__tblr_hline_rightpos_tl {#1},
l .meta:n = { leftpos = #1 },
l .default:n = { -0.8 },
r .meta:n = { rightpos = #1 },
r .default:n = { -0.8 },
lr .meta:n = { leftpos = #1, rightpos = #1 },
lr .default:n = { -0.8 },
endpos .bool_set:N = \l__tblr_hline_endpos_bool,
unknown .code:n = \__tblr_hline_unknown_key:V \l_keys_key_str,
}
\cs_new_protected:Npn \__tblr_hline_unknown_key:n #1
{
\prop_if_in:NnTF \g__tblr_defined_hdash_styles_prop {#1}
{ \tl_set:Nn \l__tblr_hline_dash_tl { \exp_not:N \@tblr@dash #1 } }
{
\regex_match:NnTF \c__tblr_is_color_key_regex {#1}
{ \tl_set:Nn \l__tblr_hline_fg_tl {#1} }
{
\tl_set_rescan:Nnn \l__tblr_v_tl {} {#1}
\tl_set:Nn \l__tblr_hline_wd_tl { \dim_eval:n {\l__tblr_v_tl} }
}
}
}
\cs_generate_variant:Nn \__tblr_hline_unknown_key:n { V }
\cs_new_protected_nopar:Npn \__tblr_set_hline_cmd:n #1
{
\__tblr_get_childs:nx {#1} { \int_use:N \c@colcount }
\clist_map_inline:Nn \l_tblr_childs_clist
{
\__tblr_set_hline_option:nnn { ##1 } { @dash } { \l__tblr_hline_dash_tl }
\tl_if_empty:NF \l__tblr_hline_wd_tl
{
\__tblr_set_hline_option:nnn { ##1 } { wd } { \l__tblr_hline_wd_tl }
}
\tl_if_empty:NF \l__tblr_hline_fg_tl
{
\__tblr_set_hline_option:nnn { ##1 } { fg } { \l__tblr_hline_fg_tl }
}
}
\tl_if_empty:NF \l__tblr_hline_leftpos_tl
{
\bool_if:NTF \l__tblr_hline_endpos_bool
{
\__tblr_set_hline_option:nnn
{ \clist_item:Nn \l_tblr_childs_clist {1} }
{ leftpos }
{ \l__tblr_hline_leftpos_tl }
}
{
\clist_map_inline:Nn \l_tblr_childs_clist
{
\__tblr_set_hline_option:nnn
{ ##1 } { leftpos } { \l__tblr_hline_leftpos_tl }
}
}
}
\tl_if_empty:NF \l__tblr_hline_rightpos_tl
{
\bool_if:NTF \l__tblr_hline_endpos_bool
{
\__tblr_set_hline_option:nnn
{ \clist_item:Nn \l_tblr_childs_clist {-1} }
{ rightpos }
{ \l__tblr_hline_rightpos_tl }
}
{
\clist_map_inline:Nn \l_tblr_childs_clist
{
\__tblr_set_hline_option:nnn
{ ##1 } { rightpos } { \l__tblr_hline_rightpos_tl }
}
}
}
}
%% #1: column; #2: key; #3: value
\cs_new_protected_nopar:Npn \__tblr_set_hline_option:nnn #1 #2 #3
{
\__tblr_spec_gput:nee { hline }
{ [\int_use:N \c@rownum][#1](\l__tblr_hline_num_tl) / #2 } { #3 }
}
\msg_new:nnn { tabularray } { obsolete-firsthline }
{ \firsthline ~ is ~ obsolete; ~ use ~ 'baseline=T' ~ instead. }
\msg_new:nnn { tabularray } { obsolete-lasthline }
{ \lasthline ~ is ~ obsolete; ~ use ~ 'baseline=B' ~ instead. }
\NewTableCommand \firsthline [1] []
{
\msg_error:nn { tabularray } { obsolete-firsthline }
}
\NewTableCommand \lasthline [1] []
{
\msg_error:nn { tabularray } { obsolete-lasthline }
}
%% \SetVlines command for setting every vline in the table
\NewTableCommand \SetVlines [3] [+]
{
\tblr_set_every_vline:nnn {#1} {#2} {#3}
}
%% We put all code inside a group to avoid affecting other table commands
\cs_new_protected:Npn \tblr_set_every_vline:nnn #1 #2 #3
{
\group_begin:
\int_step_inline:nn { \int_eval:n { \c@colcount + 1 } }
{
\int_set:Nn \c@colnum {##1}
\tblr_set_vline:nnn {#1} {#2} {#3}
}
\group_end:
}
%% Check the number of arguments and call \tblr_set_every_vline in different ways
%% This function is called when parsing table specifications
\cs_new_protected:Npn \__tblr_set_every_vline_aux:n #1
{
\tl_if_head_is_group:nTF {#1}
{
\int_compare:nNnTF { \tl_count:n {#1} } = {3}
{ \tblr_set_every_vline:nnn #1 }
{ \tblr_set_every_vline:nnn {1} #1 }
}
{ \tblr_set_every_vline:nnn {1} {-} {#1} }
}
%% Add \SetVline, \vline and \rline commands
\tl_new:N \l__tblr_vline_count_tl % the count of all vlines
\tl_new:N \l__tblr_vline_num_tl % the index of the vline
\tl_new:N \l__tblr_vline_rows_tl % the rows of the vline
\tl_new:N \l__tblr_vline_dash_tl % dash style
\tl_new:N \l__tblr_vline_fg_tl % dash foreground
\tl_new:N \l__tblr_vline_wd_tl % dash width
\tl_new:N \l__tblr_vline_abovepos_tl % above position
\tl_new:N \l__tblr_vline_belowpos_tl % below position
\NewTableCommand \rline [2] [] { \SetVline [=] {#2} {#1} }
\NewTableCommand \vline [1] [] { \SetVline [+] {-} {#1} }
%% #1: the index of the vline (may be + or =)
%% #2: which rows of the vline, separate by commas
%% #3: key=value pairs
\NewTableCommand \SetVline [3] [+]
{
\tblr_set_vline:nnn {#1} {#2} {#3}
}
%% We need to check "text" key first
%% If it does exist and has empty value, then do nothing
\cs_new_protected:Npn \tblr_set_vline:nnn #1 #2 #3
{
\group_begin:
\keys_set_groups:nnn { tblr-vline } { text } {#3}
\tl_if_eq:NnF \l__tblr_vline_dash_tl { \exp_not:N \@tblr@text }
{
\__tblr_set_vline_num:n {#1}
\tl_clear:N \l__tblr_vline_dash_tl
\keys_set:nn { tblr-vline } { dash = solid, #3 }
\__tblr_set_vline_cmd:n {#2}
}
\group_end:
}
\cs_new_protected:Npn \tblr_set_vline:nnnn #1 #2 #3 #4
{
\group_begin:
\__tblr_get_childs:nx {#1} { \int_eval:n { \c@colcount + 1} }
\clist_map_inline:Nn \l_tblr_childs_clist
{
\int_set:Nn \c@colnum {##1}
\tblr_set_vline:nnn {#2} {#3} {#4}
}
\group_end:
}
%% Check the number of arguments and call \tblr_set_vline in different ways
%% Note that #1 always includes an outer pair of braces
%% This function is called when parsing table specifications
\cs_new_protected:Npn \__tblr_set_vline_aux:nn #1 #2
{
\tl_if_head_is_group:nTF {#2}
{
\int_compare:nNnTF { \tl_count:n {#2} } = {3}
{ \tblr_set_vline:nnnn #1 #2 }
{ \tblr_set_vline:nnnn #1 {1} #2 }
}
{ \tblr_set_vline:nnnn #1 {1} {-} {#2} }
}
\cs_generate_variant:Nn \__tblr_set_vline_aux:nn { Vn }
%% #1: the index of vline to set (may be + or =)
\cs_new_protected:Npn \__tblr_set_vline_num:n #1
{
\tl_clear:N \l__tblr_vline_num_tl
\tl_set:Nx \l__tblr_vline_count_tl
{ \__tblr_spec_item:ne { vline } { [\int_use:N \c@colnum] / @vline-count } }
%% \l__tblr_vline_count_tl may be empty when colspec has extra |'s
\int_compare:nNnTF { \l__tblr_vline_count_tl + 0 } = {0}
{
\tl_set:Nx \l__tblr_vline_num_tl { 1 }
\__tblr_spec_gput:nen { vline }
{ [\int_use:N \c@colnum] / @vline-count } { 1 }
}
{
\tl_if_eq:nnTF {#1} {+}
{ \__tblr_set_vline_num_incr: }
{
\tl_if_eq:nnTF {#1} {=}
{ \tl_set_eq:NN \l__tblr_vline_num_tl \l__tblr_vline_count_tl }
{
\int_compare:nNnTF {#1} > { \l__tblr_vline_count_tl }
{ \__tblr_set_vline_num_incr: }
{ \tl_set:Nn \l__tblr_vline_num_tl {#1} }
}
}
}
}
\cs_new_protected:Npn \__tblr_set_vline_num_incr:
{
\tl_set:Nx \l__tblr_vline_count_tl
{ \int_eval:n { \l__tblr_vline_count_tl + 1 } }
\__tblr_spec_gput:nee { vline }
{ [\int_use:N \c@colnum] / @vline-count } { \l__tblr_vline_count_tl }
\tl_set_eq:NN \l__tblr_vline_num_tl \l__tblr_vline_count_tl
}
\keys_define:nn { tblr-vline }
{
dash .code:n = \tl_set:Nn \l__tblr_vline_dash_tl { \exp_not:N \@tblr@dash #1 },
text .code:n = \tl_set:Nn \l__tblr_vline_dash_tl { \exp_not:N \@tblr@text #1 },
text .groups:n = { text },
wd .code:n = \tl_set:Nn \l__tblr_vline_wd_tl { \dim_eval:n {#1} },
fg .code:n = \tl_set:Nn \l__tblr_vline_fg_tl {#1},
abovepos .code:n = \tl_set:Nx \l__tblr_vline_abovepos_tl {#1},
belowpos .code:n = \tl_set:Nx \l__tblr_vline_belowpos_tl {#1},
unknown .code:n = \__tblr_vline_unknown_key:V \l_keys_key_str,
}
\cs_new_protected:Npn \__tblr_vline_unknown_key:n #1
{
\prop_if_in:NnTF \g__tblr_defined_vdash_styles_prop {#1}
{ \tl_set:Nn \l__tblr_vline_dash_tl { \exp_not:N \@tblr@dash #1 } }
{
\regex_match:NnTF \c__tblr_is_color_key_regex {#1}
{ \tl_set:Nn \l__tblr_vline_fg_tl {#1} }
{
\tl_set_rescan:Nnn \l__tblr_v_tl {} {#1}
\tl_set:Nn \l__tblr_vline_wd_tl { \dim_eval:n {\l__tblr_v_tl} }
}
}
}
\cs_generate_variant:Nn \__tblr_vline_unknown_key:n { V }
\cs_new_protected_nopar:Npn \__tblr_set_vline_cmd:n #1
{
\__tblr_get_childs:nx {#1} { \int_use:N \c@rowcount }
\clist_map_inline:Nn \l_tblr_childs_clist
{
\__tblr_spec_gput:nee { vline }
{ [##1][\int_use:N \c@colnum](\l__tblr_vline_num_tl) / @dash }
{ \l__tblr_vline_dash_tl }
\tl_if_empty:NF \l__tblr_vline_wd_tl
{
\__tblr_spec_gput:nee { vline }
{ [##1][\int_use:N \c@colnum](\l__tblr_vline_num_tl) / wd }
{ \l__tblr_vline_wd_tl }
}
\tl_if_empty:NF \l__tblr_vline_fg_tl
{
\__tblr_spec_gput:nee { vline }
{ [##1][\int_use:N \c@colnum](\l__tblr_vline_num_tl) / fg }
{ \l__tblr_vline_fg_tl }
}
\tl_if_empty:NF \l__tblr_vline_abovepos_tl
{
\__tblr_spec_gput:nee { vline }
{ [##1][\int_use:N \c@colnum](\l__tblr_vline_num_tl) / abovepos }
{ \l__tblr_vline_abovepos_tl }
}
\tl_if_empty:NF \l__tblr_vline_belowpos_tl
{
\__tblr_spec_gput:nee { vline }
{ [##1][\int_use:N \c@colnum](\l__tblr_vline_num_tl) / belowpos }
{ \l__tblr_vline_belowpos_tl }
}
}
}
%%% --------------------------------------------------------
%%> \section{Set Hborders and Vborders}
%%% --------------------------------------------------------
%% Hborder holds keys not related to a specified hline
\NewTableCommand \hborder [1] { \tblr_set_hborder:n {#1} }
\cs_new_protected:Npn \tblr_set_hborder:n #1
{
\keys_set:nn { tblr-hborder } {#1}
}
\cs_new_protected:Npn \tblr_set_hborder:nn #1 #2
{
\group_begin:
\__tblr_get_childs:nx {#1} { \int_eval:n { \c@rowcount + 1 } }
\clist_map_inline:Nn \l_tblr_childs_clist
{
\int_set:Nn \c@rownum {##1}
\tblr_set_hborder:n {#2}
}
\group_end:
}
%% This function is called when parsing table specifications
%% Note that #1 always includes an outer pair of braces
\cs_new_protected:Npn \__tblr_set_hborder_aux:nn #1 #2
{
\tblr_set_hborder:nn #1 {#2}
}
\cs_generate_variant:Nn \__tblr_set_hborder_aux:nn { Vn }
\keys_define:nn { tblr-hborder }
{
abovespace .code:n = \__tblr_row_gput_above:ne
{ belowsep } { \dim_eval:n {#1} },
belowspace .code:n = \__tblr_row_gput:ne { abovesep } { \dim_eval:n {#1} },
abovespace+ .code:n = \__tblr_row_gadd_dimen_above:ne
{ belowsep } { \dim_eval:n {#1} },
belowspace+ .code:n = \__tblr_row_gadd_dimen:ne
{ abovesep } { \dim_eval:n {#1} },
pagebreak .code:n = \__tblr_hborder_gput_pagebreak:n {#1},
pagebreak .default:n = yes,
baseline .code:n = \__tblr_outer_gput_spec:ne
{ baseline } { - \int_use:N \c@rownum },
}
\tl_const:Nn \c__tblr_pagebreak_yes_tl { 1 }
\tl_const:Nn \c__tblr_pagebreak_auto_tl { 0 }
\tl_const:Nn \c__tblr_pagebreak_no_tl { -1 }
\cs_new_protected:Npn \__tblr_hborder_gput_pagebreak:n #1
{
\tl_if_exist:cT { c__tblr_pagebreak_ #1 _tl }
{
\__tblr_spec_gput:nee { hline }
{ [\int_use:N \c@rownum] / @pagebreak }
{ \tl_use:c { c__tblr_pagebreak_ #1 _tl } }
}
}
%% Vborder holds keys not related to a specified vline
\NewTableCommand \vborder [1] { \tblr_set_vborder:n {#1} }
\cs_new_protected:Npn \tblr_set_vborder:n #1
{
\keys_set:nn { tblr-vborder } {#1}
}
\cs_new_protected:Npn \tblr_set_vborder:nn #1 #2
{
\group_begin:
\__tblr_get_childs:nx {#1} { \int_eval:n { \c@colcount + 1 } }
\clist_map_inline:Nn \l_tblr_childs_clist
{
\int_set:Nn \c@colnum {##1}
\tblr_set_vborder:n {#2}
}
\group_end:
}
%% This function is called when parsing table specifications
%% Note that #1 always includes an outer pair of braces
\cs_new_protected:Npn \__tblr_set_vborder_aux:nn #1 #2
{
\tblr_set_vborder:nn #1 {#2}
}
\cs_generate_variant:Nn \__tblr_set_vborder_aux:nn { Vn }
\keys_define:nn { tblr-vborder }
{
leftspace .code:n = \__tblr_column_gput_left:ne
{ rightsep } { \dim_eval:n {#1} },
rightspace .code:n = \__tblr_column_gput:ne { leftsep } { \dim_eval:n {#1} },
leftspace+ .code:n = \__tblr_column_gadd_dimen_left:ne
{ rightsep } { \dim_eval:n {#1} },
rightspace+ .code:n = \__tblr_column_gadd_dimen:ne
{ leftsep } { \dim_eval:n {#1} },
}
%%% --------------------------------------------------------
%%> \section{Set Cells}
%%% --------------------------------------------------------
%% \SetCells command for setting every cell in the table
\NewTableCommand \SetCells [2] []
{
\tblr_set_every_cell:nn {#1} {#2}
}
%% We put all code inside a group to avoid affecting other table commands
\cs_new_protected:Npn \tblr_set_every_cell:nn #1 #2
{
\group_begin:
\int_step_inline:nn { \c@rowcount }
{
\int_set:Nn \c@rownum {##1}
\int_step_inline:nn { \c@colcount }
{
\int_set:Nn \c@colnum {####1}
\tblr_set_cell:nn {#1} {#2}
}
}
\group_end:
}
%% Check the number of arguments and call \tblr_set_every_cell in different ways
%% This function is called when parsing table specifications
\cs_new_protected:Npn \__tblr_set_every_cell_aux:n #1
{
\tl_if_head_is_group:nTF {#1}
{ \tblr_set_every_cell:nn #1 }
{ \tblr_set_every_cell:nn {} {#1} }
}
%% \SetCell command for multirow and/or multicolumn cells
\NewTableCommand \SetCell [2] []
{
\tblr_set_cell:nn { #1 } { #2 }
}
\tl_new:N \l__tblr_row_span_num_tl
\tl_new:N \l__tblr_col_span_num_tl
\cs_new_protected:Npn \tblr_set_cell:nn #1 #2
{
\tl_set:Nn \l__tblr_row_span_num_tl { 1 }
\tl_set:Nn \l__tblr_col_span_num_tl { 1 }
\keys_set:nn { tblr-cell-span } { #1 }
\keys_set:nn { tblr-cell-spec } { #2 }
\__tblr_set_span_spec:VV \l__tblr_row_span_num_tl \l__tblr_col_span_num_tl
}
\cs_generate_variant:Nn \tblr_set_cell:nn { nV }
\cs_new_protected:Npn \tblr_set_cell:nnnn #1 #2 #3 #4
{
\group_begin:
\__tblr_get_childs:nx {#1} { \int_use:N \c@rowcount }
\clist_set_eq:NN \l_tmpa_clist \l_tblr_childs_clist
\__tblr_get_childs:nx {#2} { \int_use:N \c@colcount }
\clist_set_eq:NN \l_tmpb_clist \l_tblr_childs_clist
\clist_map_inline:Nn \l_tmpa_clist
{
\int_set:Nn \c@rownum {##1}
\clist_map_inline:Nn \l_tmpb_clist
{
\int_set:Nn \c@colnum {####1}
\tblr_set_cell:nn {#3} {#4}
}
}
\group_end:
}
%% Check the number of arguments and call \tblr_set_cell in different ways
%% Note that #1 is always of the type {<i>}{<j>}
%% This function is called when parsing table specifications
\cs_new_protected:Npn \__tblr_set_cell_aux:nn #1 #2
{
\tl_if_head_is_group:nTF {#2}
{ \tblr_set_cell:nnnn #1 #2 }
{ \tblr_set_cell:nnnn #1 {} {#2} }
}
\cs_generate_variant:Nn \__tblr_set_cell_aux:nn { Vn }
\keys_define:nn { tblr-cell-span }
{
r .tl_set:N = \l__tblr_row_span_num_tl,
c .tl_set:N = \l__tblr_col_span_num_tl,
}
\keys_define:nn { tblr-cell-spec }
{
halign .code:n = \__tblr_cell_gput:nn { halign } {#1},
valign .code:n = \__tblr_cell_gput:nn { valign } {#1},
j .meta:n = { halign = j },
l .meta:n = { halign = l },
c .meta:n = { halign = c },
r .meta:n = { halign = r },
t .meta:n = { valign = t },
p .meta:n = { valign = t },
m .meta:n = { valign = m },
b .meta:n = { valign = b },
h .meta:n = { valign = h },
f .meta:n = { valign = f },
wd .code:n = \__tblr_cell_gput:ne { width } {#1},
bg .code:n = \__tblr_cell_gput:ne { background } {#1},
fg .code:n = \__tblr_cell_gput:ne { foreground } {#1},
font .code:n = \__tblr_cell_gput:nn { font } { #1 \selectfont },
mode .code:n = \__tblr_cell_gput:nn { mode } {#1},
$ .meta:n = { mode = math },
$$ .meta:n = { mode = dmath },
cmd .code:n = \__tblr_cell_gput:nn { cmd } {#1},
preto .code:n = \__tblr_cell_preto_text:n {#1},
appto .code:n = \__tblr_cell_appto_text:n {#1},
unknown .code:n = \__tblr_cell_unknown_key:V \l_keys_key_str,
}
\cs_new_protected:Npn \__tblr_cell_gput:nn #1 #2
{
\__tblr_data_gput:neenn { cell }
{ \int_use:N \c@rownum } { \int_use:N \c@colnum } {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_cell_gput:nn { ne }
\cs_new_protected:Npn \__tblr_cell_gput:nnnn #1 #2 #3 #4
{
\__tblr_data_gput:nnnnn { cell } {#1} {#2} {#3} {#4}
}
\cs_generate_variant:Nn \__tblr_cell_gput:nnnn
{ nenn, ennn, eenn, nene, enne, eene }
\tl_new:N \l__tblr_cell_text_tl
\cs_new_protected:Npn \__tblr_cell_preto_text:n #1
{
\__tblr_cell_preto_text:een
{ \int_use:N \c@rownum } { \int_use:N \c@colnum } {#1}
}
\cs_new_protected:Npn \__tblr_cell_preto_text:nnn #1 #2 #3
{
\tl_set:Nx \l__tblr_cell_text_tl { \__tblr_spec_item:nn { text } { [#1][#2] } }
\tl_put_left:Nn \l__tblr_cell_text_tl {#3}
\__tblr_spec_gput:nnV { text } { [#1][#2] } \l__tblr_cell_text_tl
}
\cs_generate_variant:Nn \__tblr_cell_preto_text:nnn { nen, enn, een }
\cs_new_protected:Npn \__tblr_cell_appto_text:n #1
{
\__tblr_cell_appto_text:een
{ \int_use:N \c@rownum } { \int_use:N \c@colnum } {#1}
}
\cs_new_protected:Npn \__tblr_cell_appto_text:nnn #1 #2 #3
{
\tl_set:Nx \l__tblr_cell_text_tl { \__tblr_spec_item:ne { text } { [#1][#2] } }
\tl_put_right:Nn \l__tblr_cell_text_tl {#3}
\__tblr_spec_gput:neV { text } { [#1][#2] } \l__tblr_cell_text_tl
}
\cs_generate_variant:Nn \__tblr_cell_appto_text:nnn { nen, enn, een }
\cs_new_protected:Npn \__tblr_cell_unknown_key:n #1
{
\regex_match:NnTF \c__tblr_is_color_key_regex {#1}
{
\__tblr_data_gput:neene { cell }
{ \int_use:N \c@rownum } { \int_use:N \c@colnum } { background } {#1}
}
{
\tl_set_rescan:Nnn \l__tblr_v_tl {} {#1}
\__tblr_data_gput:neene { cell }
{ \int_use:N \c@rownum } { \int_use:N \c@colnum } { width }
{ \dim_eval:n { \l__tblr_v_tl } }
}
}
\cs_generate_variant:Nn \__tblr_cell_unknown_key:n { V }
\cs_new_protected:Npn \__tblr_set_span_spec:nn #1 #2
{
\int_compare:nNnT { #1 } > { 1 }
{
\__tblr_prop_gput:nnn { inner } { rowspan } { true }
\__tblr_data_gput:neenn { cell }
{ \int_use:N \c@rownum } { \int_use:N \c@colnum } { rowspan } {#1}
}
\int_compare:nNnT { #2 } > { 1 }
{
\__tblr_prop_gput:nnn { inner } { colspan } { true }
\__tblr_data_gput:neenn { cell }
{ \int_use:N \c@rownum } { \int_use:N \c@colnum } { colspan } {#2}
}
\int_step_variable:nnNn
{ \int_use:N \c@rownum } { \int_eval:n { \c@rownum + #1 - 1 } } \l__tblr_i_tl
{
\int_step_variable:nnNn
{ \int_use:N \c@colnum } { \int_eval:n { \c@colnum + #2 - 1 } }
\l__tblr_j_tl
{
\bool_lazy_and:nnF
{ \int_compare_p:nNn { \l__tblr_i_tl } = { \c@rownum } }
{ \int_compare_p:nNn { \l__tblr_j_tl } = { \c@colnum } }
{
\__tblr_data_gput:neenn { cell }
{ \l__tblr_i_tl } { \l__tblr_j_tl } { omit } {1}
}
\int_compare:nNnF { \l__tblr_i_tl } = { \c@rownum }
{
\__tblr_spec_gput:nen { hline }
{ [\l__tblr_i_tl][\l__tblr_j_tl] / omit } {true}
}
\int_compare:nNnF { \l__tblr_j_tl } = { \c@colnum }
{
\__tblr_spec_gput:nee { vline }
{ [\l__tblr_i_tl][\l__tblr_j_tl] / omit } {true}
}
}
}
%% Make continuous borders for multirow cells
\tl_set:Nx \l__tblr_n_tl
{
\int_max:nn
{
\__tblr_spec_item:ne { vline } { [\int_use:N \c@colnum] / @vline-count }
}
{ 1 }
}
\int_step_variable:nnNn
{ \c@rownum } { \int_eval:n { \c@rownum + #1 - 2 } } \l__tblr_i_tl
{
\__tblr_spec_gput:nee { vline }
{ [\l__tblr_i_tl][\int_use:N \c@colnum](\l__tblr_n_tl) / belowpos } {1}
\__tblr_spec_gput:nee { vline }
{ [\l__tblr_i_tl][\int_eval:n {\c@colnum + #2}](1) / belowpos } {1}
}
}
\cs_generate_variant:Nn \__tblr_set_span_spec:nn { VV }
%% Obsolete \multicolumn and \multirow commands
\msg_new:nnn { tabularray } { obsolete-multicolumn }
{ \multicolumn ~ is ~ obsolete; ~ use ~ \SetCell ~ instead. }
\msg_new:nnn { tabularray } { obsolete-multirow }
{ \multirow ~ is ~ obsolete; ~ use ~ \SetCell ~ instead. }
\NewTableCommand \multicolumn [2]
{
\msg_error:nn { tabularray } { obsolete-multicolumn }
}
\NewTableCommand \multirow [3] [m]
{
\msg_error:nn { tabularray } { obsolete-multirow }
}
%%% --------------------------------------------------------
%%> \section{Set Columns and Rows}
%%% --------------------------------------------------------
%% \SetColumns command for setting every column in the table
\NewTableCommand \SetColumns [2] []
{
\tblr_set_every_column:nn {#1} {#2}
}
%% We put all code inside a group to avoid affecting other table commands
\cs_new_protected:Npn \tblr_set_every_column:nn #1 #2
{
\group_begin:
\int_step_inline:nn { \c@colcount }
{
\int_set:Nn \c@colnum {##1}
\tblr_set_column:nn {#1} {#2}
}
\group_end:
}
%% Check the number of arguments and call \tblr_set_every_column in different ways
%% This function is called when parsing table specifications
\cs_new_protected:Npn \__tblr_set_every_column_aux:n #1
{
\tl_if_head_is_group:nTF {#1}
{ \tblr_set_every_column:nn #1 }
{ \tblr_set_every_column:nn {} {#1} }
}
%% \SetColumn command for current column or each cells in the column
\NewTableCommand \SetColumn [2] []
{
\tblr_set_column:nn {#1} {#2}
}
\cs_new_protected:Npn \tblr_set_column:nn #1 #2
{
\keys_set:nn { tblr-column } {#2}
}
\cs_new_protected:Npn \tblr_set_column:nnn #1 #2 #3
{
\group_begin:
\__tblr_get_childs:nx {#1} { \int_use:N \c@colcount }
\clist_map_inline:Nn \l_tblr_childs_clist
{
\int_set:Nn \c@colnum {##1}
\tblr_set_column:nn {#2} {#3}
}
\group_end:
}
%% Check the number of arguments and call \tblr_set_column in different ways
%% Note that #1 always includes an outer pair of braces
%% This function is called when parsing table specifications
\cs_new_protected:Npn \__tblr_set_column_aux:nn #1 #2
{
\tl_if_head_is_group:nTF {#2}
{ \tblr_set_column:nnn #1 #2 }
{ \tblr_set_column:nnn #1 {} {#2} }
}
\cs_generate_variant:Nn \__tblr_set_column_aux:nn { Vn }
\keys_define:nn { tblr-column }
{
halign .code:n = \__tblr_column_gput_cell:nn { halign } {#1},
valign .code:n = \__tblr_column_gput_cell:nn { valign } {#1},
j .meta:n = { halign = j },
l .meta:n = { halign = l },
c .meta:n = { halign = c },
r .meta:n = { halign = r },
t .meta:n = { valign = t },
p .meta:n = { valign = t },
m .meta:n = { valign = m },
b .meta:n = { valign = b },
h .meta:n = { valign = h },
f .meta:n = { valign = f },
bg .code:n = \__tblr_column_gput_cell:nn { background } {#1},
fg .code:n = \__tblr_column_gput_cell:nn { foreground } {#1},
font .code:n = \__tblr_column_gput_cell:nn { font } { #1 \selectfont },
mode .code:n = \__tblr_column_gput_cell:nn { mode } {#1},
$ .meta:n = { mode = math },
$$ .meta:n = { mode = dmath },
cmd .code:n = \__tblr_column_gput_cell:nn { cmd } {#1},
wd .code:n = \__tblr_column_gput:ne { width } { \dim_eval:n {#1} },
co .code:n = \__tblr_column_gput:ne { coefficient } {#1},
preto .code:n = \__tblr_preto_text_for_every_column_cell:n {#1},
appto .code:n = \__tblr_appto_text_for_every_column_cell:n {#1},
leftsep .code:n = \__tblr_column_gput:ne { leftsep } { \dim_eval:n {#1} },
rightsep .code:n = \__tblr_column_gput:ne { rightsep } { \dim_eval:n {#1} },
colsep .meta:n = { leftsep = #1, rightsep = #1},
leftsep+ .code:n = \__tblr_column_gadd_dimen:ne
{ leftsep } { \dim_eval:n {#1} },
rightsep+ .code:n = \__tblr_column_gadd_dimen:ne
{ rightsep } { \dim_eval:n {#1} },
colsep+ .meta:n = { leftsep+ = #1, rightsep+ = #1},
unknown .code:n = \__tblr_column_unknown_key:V \l_keys_key_str,
}
%% #1: key; #2: value
\cs_new_protected:Npn \__tblr_column_gput:nn #1 #2
{
\__tblr_data_gput:nenn { column } { \int_use:N \c@colnum } {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_column_gput:nn { ne }
\cs_new_protected:Npn \__tblr_column_gput_left:nn #1 #2
{
\__tblr_data_gput:nenn { column } { \int_eval:n { \c@colnum - 1 } } {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_column_gput_left:nn { ne }
\cs_new_protected:Npn \__tblr_column_gadd_dimen:nn #1 #2
{
\__tblr_data_gadd_dimen_value:nenn { column }
{ \int_use:N \c@colnum } {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_column_gadd_dimen:nn { ne }
\cs_new_protected:Npn \__tblr_column_gadd_dimen_left:nn #1 #2
{
\__tblr_data_gadd_dimen_value:nenn { column }
{ \int_eval:n { \c@colnum - 1 } } {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_column_gadd_dimen_left:nn { ne }
%% #1: key; #2: value
\cs_new_protected:Npn \__tblr_column_gput_cell:nn #1 #2
{
\int_step_inline:nn { \c@rowcount }
{
\__tblr_cell_gput:nenn {##1} { \int_use:N \c@colnum } {#1} {#2}
}
}
\cs_generate_variant:Nn \__tblr_column_gput_cell:nn { ne }
\cs_new_protected:Npn \__tblr_preto_text_for_every_column_cell:n #1
{
\int_step_inline:nn { \c@rowcount }
{
\__tblr_cell_preto_text:nen {##1} { \int_use:N \c@colnum } {#1}
}
}
\cs_new_protected:Npn \__tblr_appto_text_for_every_column_cell:n #1
{
\int_step_inline:nn { \c@rowcount }
{
\__tblr_cell_appto_text:nen {##1} { \int_use:N \c@colnum } {#1}
}
}
\regex_const:Nn \c__tblr_is_number_key_regex { ^[\+\-]? (\d+|\d*\.\d+)$ }
\cs_new_protected:Npn \__tblr_column_unknown_key:n #1
{
\regex_match:NnTF \c__tblr_is_number_key_regex {#1}
{ \__tblr_column_gput:ne { coefficient } {#1} }
{
\regex_match:NnTF \c__tblr_is_color_key_regex {#1}
{ \__tblr_column_gput_cell:nn { background } {#1} }
{
\tl_set_rescan:Nnn \l__tblr_v_tl {} {#1}
\__tblr_column_gput:ne { width } { \dim_eval:n { \l__tblr_v_tl } }
}
}
}
\cs_generate_variant:Nn \__tblr_column_unknown_key:n { V }
%% \SetRows command for setting every row in the table
\NewTableCommand \SetRows [2] []
{
\tblr_set_every_row:nn {#1} {#2}
}
%% We put all code inside a group to avoid affecting other table commands
\cs_new_protected:Npn \tblr_set_every_row:nn #1 #2
{
\group_begin:
\int_step_inline:nn { \c@rowcount }
{
\int_set:Nn \c@rownum {##1}
\tblr_set_row:nn {#1} {#2}
}
\group_end:
}
%% Check the number of arguments and call \tblr_set_every_row in different ways
%% This function is called when parsing table specifications
\cs_new_protected:Npn \__tblr_set_every_row_aux:n #1
{
\tl_if_head_is_group:nTF {#1}
{ \tblr_set_every_row:nn #1 }
{ \tblr_set_every_row:nn {} {#1} }
}
%% \SetRow command for current row or each cells in the row
\NewTableCommand \SetRow [2] []
{
\tblr_set_row:nn {#1} {#2}
}
\cs_new_protected:Npn \tblr_set_row:nn #1 #2
{
\keys_set:nn { tblr-row } {#2}
}
\cs_new_protected:Npn \tblr_set_row:nnn #1 #2 #3
{
\group_begin:
\__tblr_get_childs:nx {#1} { \int_use:N \c@rowcount }
\clist_map_inline:Nn \l_tblr_childs_clist
{
\int_set:Nn \c@rownum {##1}
\tblr_set_row:nn {#2} {#3}
}
\group_end:
}
%% Check the number of arguments and call \tblr_set_row in different ways
%% Note that #1 always includes an outer pair of braces
%% This function is called when parsing table specifications
\cs_new_protected:Npn \__tblr_set_row_aux:nn #1 #2
{
\tl_if_head_is_group:nTF {#2}
{ \tblr_set_row:nnn #1 #2 }
{ \tblr_set_row:nnn #1 {} {#2} }
}
\cs_generate_variant:Nn \__tblr_set_row_aux:nn { Vn }
\keys_define:nn { tblr-row }
{
halign .code:n = \__tblr_row_gput_cell:nn { halign } {#1},
valign .code:n = \__tblr_row_gput_cell:nn { valign } {#1},
j .meta:n = { halign = j },
l .meta:n = { halign = l },
c .meta:n = { halign = c },
r .meta:n = { halign = r },
t .meta:n = { valign = t },
p .meta:n = { valign = t },
m .meta:n = { valign = m },
b .meta:n = { valign = b },
h .meta:n = { valign = h },
f .meta:n = { valign = f },
bg .code:n = \__tblr_row_gput_cell:nn { background } {#1},
fg .code:n = \__tblr_row_gput_cell:nn { foreground } {#1},
font .code:n = \__tblr_row_gput_cell:nn { font } { #1 \selectfont },
mode .code:n = \__tblr_row_gput_cell:nn { mode } {#1},
$ .meta:n = { mode = math },
$$ .meta:n = { mode = dmath },
cmd .code:n = \__tblr_row_gput_cell:nn { cmd } {#1},
ht .code:n = \__tblr_row_gput:ne { height } { \dim_eval:n {#1} },
co .code:n = \__tblr_row_gput:ne { coefficient } {#1},
preto .code:n = \__tblr_preto_text_for_every_row_cell:n {#1},
appto .code:n = \__tblr_appto_text_for_every_row_cell:n {#1},
abovesep .code:n = \__tblr_row_gput:ne { abovesep } { \dim_eval:n {#1} },
belowsep .code:n = \__tblr_row_gput:ne { belowsep } { \dim_eval:n {#1} },
rowsep .meta:n = { abovesep = #1, belowsep = #1},
abovesep+ .code:n = \__tblr_row_gadd_dimen:ne { abovesep } { \dim_eval:n {#1} },
belowsep+ .code:n = \__tblr_row_gadd_dimen:ne { belowsep } { \dim_eval:n {#1} },
rowsep+ .meta:n = { abovesep+ = #1, belowsep+ = #1},
baseline .code:n = \__tblr_outer_gput_spec:ne
{ baseline } { \int_use:N \c@rownum },
unknown .code:n = \__tblr_row_unknown_key:V \l_keys_key_str,
}
%% #1: key; #2: value
\cs_new_protected:Npn \__tblr_row_gput:nn #1 #2
{
\__tblr_data_gput:nenn { row } { \int_use:N \c@rownum } {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_row_gput:nn { ne }
\cs_new_protected:Npn \__tblr_row_gput_above:nn #1 #2
{
\__tblr_data_gput:nenn { row } { \int_eval:n { \c@rownum - 1 } } {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_row_gput_above:nn { ne }
\cs_new_protected:Npn \__tblr_row_gadd_dimen:nn #1 #2
{
\__tblr_data_gadd_dimen_value:nenn { row } { \int_use:N \c@rownum } {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_row_gadd_dimen:nn { ne }
\cs_new_protected:Npn \__tblr_row_gadd_dimen_above:nn #1 #2
{
\__tblr_data_gadd_dimen_value:nenn { row }
{ \int_eval:n { \c@rownum - 1 } } {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_row_gadd_dimen_above:nn { ne }
%% #1: key; #2: value
\cs_new_protected:Npn \__tblr_row_gput_cell:nn #1 #2
{
\int_step_inline:nn { \c@colcount }
{
\__tblr_cell_gput:ennn { \int_use:N \c@rownum } {##1} {#1} {#2}
}
}
\cs_generate_variant:Nn \__tblr_row_gput_cell:nn { ne }
\cs_new_protected:Npn \__tblr_preto_text_for_every_row_cell:n #1
{
\int_step_inline:nn { \c@colcount }
{
\__tblr_cell_preto_text:enn { \int_use:N \c@rownum } {##1} {#1}
}
}
\cs_new_protected:Npn \__tblr_appto_text_for_every_row_cell:n #1
{
\int_step_inline:nn { \c@colcount }
{
\__tblr_cell_appto_text:enn { \int_use:N \c@rownum } {##1} {#1}
}
}
\cs_new_protected:Npn \__tblr_row_unknown_key:n #1
{
\regex_match:NnTF \c__tblr_is_number_key_regex {#1}
{
\__tblr_data_gput:nene { row } { \int_use:N \c@rownum }
{ coefficient } {#1}
}
{
\regex_match:NnTF \c__tblr_is_color_key_regex {#1}
{ \__tblr_row_gput_cell:nn { background } {#1} }
{
\tl_set_rescan:Nnn \l__tblr_v_tl {} {#1}
\__tblr_row_gput:ne { height } { \dim_eval:n { \l__tblr_v_tl } }
}
}
}
\cs_generate_variant:Nn \__tblr_row_unknown_key:n { V }
\NewTableCommand \pagebreak [1] [4]
{
\hborder { pagebreak = yes }
}
\NewTableCommand \nopagebreak [1] [4]
{
\hborder { pagebreak = no }
}
%%% --------------------------------------------------------
%%> \section{Column Types and Row Types}
%%% --------------------------------------------------------
%% Some primitive column/row types
\str_const:Nn \c_tblr_primitive_colrow_types_str { Q | < > }
\tl_new:N \g__tblr_expanded_colrow_spec_tl
\exp_args:Nc \NewDocumentCommand { tblr_primitive_column_type_ Q } { O{} }
{
\keys_set:nn { tblr-column } { #1 }
\int_incr:N \c@colnum
\__tblr_execute_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_column_type_ Q } { O{} }
{
\tl_gput_right:Nn \g__tblr_expanded_colrow_spec_tl { Q[#1] }
\__tblr_expand_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_primitive_row_type_ Q } { O{} }
{
\keys_set:nn { tblr-row } { #1 }
\int_incr:N \c@rownum
\__tblr_execute_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_row_type_ Q } { O{} }
{
\tl_gput_right:Nn \g__tblr_expanded_colrow_spec_tl { Q[#1] }
\__tblr_expand_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_primitive_column_type_ | } { O{} }
{
\vline [#1]
\__tblr_execute_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_column_type_ | } { O{} }
{
\tl_gput_right:Nn \g__tblr_expanded_colrow_spec_tl { |[#1] }
\__tblr_expand_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_primitive_row_type_ | } { O{} }
{
\hline [#1]
\__tblr_execute_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_row_type_ | } { O{} }
{
\tl_gput_right:Nn \g__tblr_expanded_colrow_spec_tl { |[#1] }
\__tblr_expand_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_primitive_column_type_ > } { O{} m }
{
\tl_if_blank:nF {#1}
{
\__tblr_data_gput:nene
{ column }
{ \int_use:N \c@colnum } { leftsep }
{ \dim_eval:n {#1} }
}
\tl_if_blank:nF {#2}
{
\__tblr_preto_text_for_every_column_cell:n {#2}
}
\__tblr_execute_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_column_type_ > } { O{} m }
{
\tl_gput_right:Nn \g__tblr_expanded_colrow_spec_tl { >[#1]{#2} }
\__tblr_expand_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_primitive_row_type_ > } { O{} m }
{
\tl_if_blank:nF {#1}
{
\__tblr_data_gput:nene { row } { \int_use:N \c@rownum }
{ abovesep } { \dim_eval:n { #1 } }
}
\tl_if_blank:nF {#2}
{
\__tblr_preto_text_for_every_row_cell:n {#2}
}
\__tblr_execute_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_row_type_ > } { O{} m }
{
\tl_gput_right:Nn \g__tblr_expanded_colrow_spec_tl { >[#1]{#2} }
\__tblr_expand_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_primitive_column_type_ < } { O{} m }
{
\tl_if_blank:nF {#1}
{
\__tblr_data_gput:nene { column }
{ \int_eval:n {\c@colnum - 1} } { rightsep } { \dim_eval:n {#1} }
}
\tl_if_blank:nF {#2}
{
\group_begin:
\int_decr:N \c@colnum
\__tblr_appto_text_for_every_column_cell:n {#2}
\group_end:
}
\__tblr_execute_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_column_type_ < } { O{} m }
{
\tl_gput_right:Nn \g__tblr_expanded_colrow_spec_tl { <[#1]{#2} }
\__tblr_expand_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_primitive_row_type_ < } { O{} m }
{
\tl_if_blank:nF {#1}
{
\__tblr_data_gput:nene { row } { \int_eval:n {\c@rownum - 1} }
{ belowsep } { \dim_eval:n {#1} }
}
\tl_if_blank:nF {#2}
{
\group_begin:
\int_decr:N \c@rownum
\__tblr_appto_text_for_every_row_cell:n {#2}
\group_end:
}
\__tblr_execute_colrow_spec_next:N
}
\exp_args:Nc \NewDocumentCommand { tblr_row_type_ < } { O{} m }
{
\tl_gput_right:Nn \g__tblr_expanded_colrow_spec_tl { <[#1]{#2} }
\__tblr_expand_colrow_spec_next:N
}
%% \NewColumnType/\NewRowType command and predefined column/row types
\str_new:N \g_tblr_used_column_types_str
\str_gset_eq:NN \g_tblr_used_column_types_str \c_tblr_primitive_colrow_types_str
\str_new:N \g_tblr_used_row_types_str
\str_gset_eq:NN \g_tblr_used_row_types_str \c_tblr_primitive_colrow_types_str
\bool_new:N \g__tblr_colrow_spec_expand_stop_bool
\tl_new:N \g__tblr_column_or_row_tl
\msg_new:nnn { tabularray } { used-colrow-type }
{ #1 ~ type ~ name ~ #2 ~ has ~ been ~ used! }
\NewDocumentCommand \NewColumnType { m O{0} o m }
{
\tl_set:Nn \g__tblr_column_or_row_tl { column }
\__tblr_new_column_or_row_type:nnnn {#1} {#2} {#3} {#4}
}
\NewDocumentCommand \NewRowType { m O{0} o m }
{
\tl_set:Nn \g__tblr_column_or_row_tl { row }
\__tblr_new_column_or_row_type:nnnn {#1} {#2} {#3} {#4}
}
\NewDocumentCommand \NewColumnRowType { m O{0} o m }
{
\tl_set:Nn \g__tblr_column_or_row_tl { column }
\__tblr_new_column_or_row_type:nnnn {#1} {#2} {#3} {#4}
\tl_set:Nn \g__tblr_column_or_row_tl { row }
\__tblr_new_column_or_row_type:nnnn {#1} {#2} {#3} {#4}
}
\cs_new_protected:Npn \__tblr_new_column_or_row_type:nnnn #1 #2 #3 #4
{
\str_if_in:cnTF { g_tblr_used_ \g__tblr_column_or_row_tl _types_str } {#1}
{
\tl_if_eq:NnTF \g__tblr_column_or_row_tl { row }
{ \msg_error:nnnn { tabularray } { used-colrow-type } { Row } {#1} }
{ \msg_error:nnnn { tabularray } { used-colrow-type } { Column } {#1} }
\str_log:c { g_tblr_used_ \g__tblr_column_or_row_tl _types_str }
}
{
\__tblr_make_xparse_arg_spec:nnN {#2} {#3} \l__tblr_a_tl
\exp_args:NcV \NewDocumentCommand
{ tblr_ \g__tblr_column_or_row_tl _type_ #1 } \l__tblr_a_tl
{
\bool_gset_false:N \g__tblr_colrow_spec_expand_stop_bool
\tl_gput_right:Nf \g__tblr_expanded_colrow_spec_tl {#4}
\__tblr_expand_colrow_spec_next:N
}
\str_gput_right:cn
{ g_tblr_used_ \g__tblr_column_or_row_tl _types_str } {#1}
}
}
\NewColumnRowType { l } { Q[l] }
\NewColumnRowType { c } { Q[c] }
\NewColumnRowType { r } { Q[r] }
\NewColumnRowType { j } { Q[j] }
\NewColumnType { t } [1] { Q[t,wd=#1] }
\NewColumnType { p } [1] { Q[p,wd=#1] }
\NewColumnType { m } [1] { Q[m,wd=#1] }
\NewColumnType { b } [1] { Q[b,wd=#1] }
\NewColumnType { h } [1] { Q[h,wd=#1] }
\NewColumnType { f } [1] { Q[f,wd=#1] }
\NewRowType { t } [1] { Q[t,ht=#1] }
\NewRowType { p } [1] { Q[p,ht=#1] }
\NewRowType { m } [1] { Q[m,ht=#1] }
\NewRowType { b } [1] { Q[b,ht=#1] }
\NewRowType { h } [1] { Q[h,ht=#1] }
\NewRowType { f } [1] { Q[f,ht=#1] }
\NewColumnRowType { X } [1][] { Q[co=1,#1] }
\NewColumnRowType { ! } [1] { |[text={#1}] }
\NewColumnRowType { @ } [1] { <[0pt]{} |[text={#1}] >[0pt]{} }
\NewColumnRowType { * } [2] { \prg_replicate:nn {#1} {#2} }
\cs_new_protected:Npn \__tblr_parse_colrow_spec:nn #1 #2
{
\tl_gset:Nn \g__tblr_column_or_row_tl {#1}
\tl_gset:Nn \g__tblr_expanded_colrow_spec_tl {#2}
\__tblr_expand_colrow_spec:N \g__tblr_expanded_colrow_spec_tl
\__tblr_execute_colrow_spec:N \g__tblr_expanded_colrow_spec_tl
}
%% Expand defined column/row types
\cs_new_protected:Npn \__tblr_expand_colrow_spec:N #1
{
\bool_do_until:Nn \g__tblr_colrow_spec_expand_stop_bool
{
\LogTblrTracing { colspec, rowspec }
\bool_gset_true:N \g__tblr_colrow_spec_expand_stop_bool
\tl_set_eq:NN \l_tmpa_tl #1
\tl_gclear:N #1
\exp_last_unbraced:NV
\__tblr_expand_colrow_spec_next:N \l_tmpa_tl \scan_stop:
}
}
\msg_new:nnn { tabularray } { unexpandable-colrow-type }
{ Unexpandable ~ command ~ #2 inside ~ #1 ~ type! }
\msg_new:nnn { tabularray } { unknown-colrow-type }
{ Unknown ~ #1 ~ type ~ #2! }
\cs_new_protected:Npn \__tblr_expand_colrow_spec_next:N #1
{
\token_if_eq_catcode:NNTF #1 \scan_stop:
{
\token_if_eq_meaning:NNF #1 \scan_stop:
{
\msg_error:nnVn { tabularray } { unexpandable-colrow-type }
\g__tblr_column_or_row_tl {#1}
}
}
{
\str_if_in:cnTF { g_tblr_used_ \g__tblr_column_or_row_tl _types_str } {#1}
{
%% Note that #1 may be an active character (see issue #58)
\cs:w tblr_ \g__tblr_column_or_row_tl _type_ \token_to_str:N #1 \cs_end:
}
{
\msg_error:nnVn { tabularray } { unknown-colrow-type }
\g__tblr_column_or_row_tl {#1}
\str_log:c { g_tblr_used_ \g__tblr_column_or_row_tl _types_str }
}
}
}
%% Execute primitive column/row types
\cs_new_protected:Npn \__tblr_execute_colrow_spec:N #1
{
\tl_if_eq:NnTF \g__tblr_column_or_row_tl { row }
{ \int_set:Nn \c@rownum {1} }
{ \int_set:Nn \c@colnum {1} }
\exp_last_unbraced:NV \__tblr_execute_colrow_spec_next:N #1 \scan_stop:
}
\cs_new_protected:Npn \__tblr_execute_colrow_spec_next:N #1
{
\token_if_eq_meaning:NNF #1 \scan_stop:
{ \cs:w tblr_primitive_ \g__tblr_column_or_row_tl _type_ #1 \cs_end: }
}
%%% --------------------------------------------------------
%%> \section{Set Environments and New Environments}
%%% --------------------------------------------------------
\tl_new:N \l__tblr_initial_tblr_outer_tl
\tl_set:Nn \l__tblr_initial_tblr_outer_tl
{
halign = c, baseline = m, headsep = 6pt, footsep = 6pt,
presep = 1.5\bigskipamount, postsep = 1.5\bigskipamount,
}
%% #1: env name; #2: specifications
\NewDocumentCommand \SetTblrInner { O{tblr} m }
{
\clist_map_inline:nn {#1}
{ \tl_put_right:cn { l__tblr_default_ ##1 _inner_tl } { , #2 } }
\ignorespaces
}
\cs_new_eq:NN \SetTblrDefault \SetTblrInner
%% #1: env name; #2: specifications
\NewDocumentCommand \SetTblrOuter { O{tblr} m }
{
\clist_map_inline:nn {#1}
{ \tl_put_right:cn { l__tblr_default_ ##1 _outer_tl } { , #2 } }
\ignorespaces
}
%% #1: env name
\NewDocumentCommand \NewTblrEnviron { m }
{
\NewDocumentEnvironment {#1} { O{c} m +b }
{
\__tblr_environ_code:nnnn {#1} {##1} {##2} {##3}
} { }
\tl_new:c { l__tblr_default_ #1 _inner_tl }
\tl_new:c { l__tblr_default_ #1 _outer_tl }
\tl_set_eq:cN { l__tblr_default_ #1 _outer_tl } \l__tblr_initial_tblr_outer_tl
}
%% Create tblr and longtblr environments
\NewTblrEnviron { tblr }
\NewTblrEnviron { longtblr }
\SetTblrOuter [ longtblr ] { long }
\NewTblrEnviron { talltblr }
\SetTblrOuter [ talltblr ] { tall }
\tl_new:N \l__tblr_env_name_tl
\bool_new:N \l__tblr_math_mode_bool
%% Main environment code
%% We need to add \group_align_safe_begin: and \group_align_safe_end:
%% to make tabularray correctly nest in align environment (see issue #143)
\cs_new_protected:Npn \__tblr_environ_code:nnnn #1 #2 #3 #4
{
\group_align_safe_begin:
\int_gincr:N \g__tblr_table_count_int
\tl_set:Nn \l__tblr_env_name_tl {#1}
\mode_if_math:TF
{ \bool_set_true:N \l__tblr_math_mode_bool }
{ \bool_set_false:N \l__tblr_math_mode_bool }
\__tblr_builder:nnn {#2} {#3} {#4}
\group_align_safe_end:
}
\bool_new:N \lTblrMeasuringBool
%% Read, split and build the table
\cs_new_protected:Npn \__tblr_builder:nnn #1 #2 #3
{
\int_gincr:N \g_tblr_level_int
\bool_set_true:N \lTblrMeasuringBool
\__tblr_clear_prop_lists:
\__tblr_clear_spec_lists:
\LogTblrTracing { step = init ~ table ~ outer ~ spec}
\__tblr_init_table_outer_spec:
\LogTblrTracing { step = parse ~ table ~ options }
\__tblr_parse_table_option:n {#1}
\LogTblrTracing { outer }
\LogTblrTracing { option }
\__tblr_enable_table_commands:
\LogTblrTracing { step = split ~ table}
\__tblr_split_table:n {#3}
\LogTblrTracing { command }
\bool_if:NT \g__tblr_use_intarray_bool { \__tblr_init_table_data: }
\LogTblrTracing { step = init ~ table ~ inner ~ spec}
\__tblr_init_table_inner_spec:
\LogTblrTracing { inner }
\LogTblrTracing { step = parse ~ table ~ inner ~ spec}
\__tblr_parse_table_spec:n {#2}
\LogTblrTracing { step = execute ~ table ~ commands}
\__tblr_execute_table_commands:
\__tblr_disable_table_commands:
\__tblr_functional_calculation:
\LogTblrTracing { step = calculate ~ cell ~ and ~ line ~ sizes}
\__tblr_enable_content_commands:
\__tblr_calc_cell_and_line_sizes:
\bool_set_false:N \lTblrMeasuringBool
\LogTblrTracing { step = build ~ the ~ whole ~ table}
\__tblr_build_whole:
\int_gdecr:N \g_tblr_level_int
}
%%% --------------------------------------------------------
%%> \section{Split Table Contents}
%%% --------------------------------------------------------
%% Insert and remove braces for nesting environments inside cells
%% These make line split and cell split workable
%% We need to replace N times for N level nestings
\regex_const:Nn \c__tblr_insert_braces_regex
{
\c{begin} \cB\{ (\c[^BE].*) \cE\} (.*?) \c{end} \cB\{ (\c[^BE].*) \cE\}
}
\tl_const:Nn \c__tblr_insert_braces_tl
{
\c{begin} \cB\{ \cB\{ \1 \cE\} \2 \c{end} \cE\} \cB\{ \3 \cE\}
}
\regex_const:Nn \c__tblr_remove_braces_regex
{
\c{begin} \cB\{ \cB\{ (.*?) \c{end} \cE\}
}
\tl_const:Nn \c__tblr_remove_braces_tl
{
\c{begin} \cB\{ \1 \c{end}
}
\cs_new_protected:Npn \__tblr_insert_braces:N #1
{
\regex_replace_all:NVN \c__tblr_insert_braces_regex \c__tblr_insert_braces_tl #1
\regex_replace_all:NVN \c__tblr_insert_braces_regex \c__tblr_insert_braces_tl #1
}
\cs_new_protected:Npn \__tblr_remove_braces:N #1
{
\regex_replace_all:NVN \c__tblr_remove_braces_regex \c__tblr_remove_braces_tl #1
\regex_replace_all:NVN \c__tblr_remove_braces_regex \c__tblr_remove_braces_tl #1
}
\tl_new:N \l__tblr_body_tl
\seq_new:N \l__tblr_lines_seq
%% Split table content to cells and store them
%% #1: table content
\cs_new_protected:Npn \__tblr_split_table:n #1
{
\tl_set:Nn \l__tblr_body_tl {#1}
\tblr_modify_table_body:
\int_zero:N \c@rowcount
\int_zero:N \c@colcount
\__tblr_split_table_to_lines:NN \l__tblr_body_tl \l__tblr_lines_seq
\__tblr_split_lines_to_cells:N \l__tblr_lines_seq
}
\tl_new:N \l__tblr_expand_tl
\cs_set_eq:NN \__tblr_hook_split_before: \prg_do_nothing:
\cs_new_protected:Npn \tblr_modify_table_body:
{
\__tblr_hook_split_before:
\tl_set:Nx \l__tblr_expand_tl { \__tblr_spec_item:nn { outer } { expand } }
\tl_set:Nx \l__tblr_expand_tl { \tl_head:N \l__tblr_expand_tl }
\tl_if_empty:NF \l__tblr_expand_tl
{
\exp_last_unbraced:NNV
\__tblr_expand_table_body:NN \l__tblr_body_tl \l__tblr_expand_tl
}
}
%% Expand every occurrence of the specified macro once
%% #1: tl with table content; #2: macro to be expanded
\cs_new_protected:Npn \__tblr_expand_table_body:NN #1 #2
{
\tl_set_eq:NN \l_tmpa_tl #1
\tl_clear:N #1
\cs_set_protected:Npn \__tblr_expand_table_body_aux:w ##1 #2
{
\tl_put_right:Nn #1 {##1}
\peek_meaning:NTF \q_stop
{ \use_none:n }
{ \exp_last_unbraced:NV \__tblr_expand_table_body_aux:w #2 }
}
\exp_last_unbraced:NV \__tblr_expand_table_body_aux:w \l_tmpa_tl #2 \q_stop
}
%% Split table content to a sequence of lines
%% #1: tl with table contents, #2: resulting sequence of lines
\cs_new_protected:Npn \__tblr_split_table_to_lines:NN #1 #2
{
\__tblr_insert_braces:N #1
\seq_set_split:NnV \l_tmpa_seq { \\ } #1
\seq_clear:N #2
\seq_map_inline:Nn \l_tmpa_seq
{
\tl_if_head_eq_meaning:nNTF {##1} *
{
\tl_set:Nn \l__tblr_b_tl { \hborder { pagebreak = no } }
\tl_set:Nx \l__tblr_c_tl { \tl_tail:n {##1} }
\tl_trim_spaces:N \l__tblr_c_tl %% Ignore spaces between * and [dimen]
\tl_if_head_eq_meaning:VNT \l__tblr_c_tl [
{
\tl_put_right:Nn \l__tblr_b_tl { \RowBefore@AddBelowSep }
}
\tl_put_right:NV \l__tblr_b_tl \l__tblr_c_tl
\seq_put_right:NV #2 \l__tblr_b_tl
}
{
\tl_if_head_eq_meaning:nNTF { ##1 } [
{ \seq_put_right:Nn #2 { \RowBefore@AddBelowSep ##1 } }
{ \seq_put_right:Nn #2 { ##1 } }
}
}
\int_set:Nn \c@rowcount { \seq_count:N #2 }
}
%% Treat \\[dimen] command
\NewTableCommand \RowBefore@AddBelowSep [1] []
{
\IfValueT { #1 }
{
\__tblr_data_gadd_dimen_value:nene { row }
{ \int_eval:n {\c@rownum - 1} } { belowsep } {#1}
}
}
%% Split table lines to cells and store them
%% #1: sequence of lines
\cs_new_protected:Npn \__tblr_split_lines_to_cells:N #1
{
\seq_map_indexed_function:NN #1 \__tblr_split_one_line:nn
\LogTblrTracing { text }
}
%% Split one line into cells and store them
%% #1: row number, #2 the line text
\cs_new_protected:Npn \__tblr_split_one_line:nn #1 #2
{
\seq_set_split:Nnn \l_tmpa_seq { & } { #2 }
\int_set:Nn \c@rownum {#1}
\int_zero:N \c@colnum
\seq_map_inline:Nn \l_tmpa_seq
{
\tl_set:Nn \l_tmpa_tl { ##1 }
\__tblr_remove_braces:N \l_tmpa_tl
\__tblr_trim_par_space_tokens:N \l_tmpa_tl
\int_incr:N \c@colnum
\__tblr_extract_table_commands:N \l_tmpa_tl
\__tblr_trim_par_space_tokens:N \l_tmpa_tl
\__tblr_spec_gput:neV { text } { [#1][\int_use:N \c@colnum] } \l_tmpa_tl
}
%% Decrease row count by 1 if the last row has only one empty cell text
%% We need to do it here since the > or < column type may add text to cells
\bool_lazy_all:nTF
{
{ \int_compare_p:nNn {#1} = {\c@rowcount} }
{ \int_compare_p:nNn {\c@colnum} = {1} }
{ \tl_if_empty_p:N \l_tmpa_tl }
}
{ \int_decr:N \c@rowcount }
{
\__tblr_prop_gput:nnx
{row} { [#1] / cell-number } { \int_use:N \c@colnum }
\int_compare:nT { \c@colnum > \c@colcount }
{
\int_set_eq:NN \c@colcount \c@colnum
}
}
}
\regex_const:Nn \c__tblr_trim_left_par_space_regex { ^ \c{par} ? \s * }
\regex_const:Nn \c__tblr_trim_right_space_par_regex { \s * \c{par} ? $ }
\cs_new_protected:Npn \__tblr_trim_par_space_tokens:N #1
{
\regex_replace_once:NnN \c__tblr_trim_left_par_space_regex {} #1
\regex_replace_once:NnN \c__tblr_trim_right_space_par_regex {} #1
}
%%% --------------------------------------------------------
%%> \section{Extract Table Commands from Cell Text}
%%% --------------------------------------------------------
%% Extract table commands defined with \NewTableCommand from cell text
\tl_new:N \l__tblr_saved_table_commands_before_cell_text_tl
\tl_new:N \l__tblr_saved_cell_text_after_table_commands_tl
\cs_new_protected:Npn \__tblr_extract_table_commands:N #1
{
\tl_clear:N \l__tblr_saved_table_commands_before_cell_text_tl
\tl_clear:N \l__tblr_saved_cell_text_after_table_commands_tl
\exp_last_unbraced:NV \__tblr_extract_table_commands_next:n #1 \q_stop
\tl_if_empty:NF \l__tblr_saved_table_commands_before_cell_text_tl
{
\__tblr_prop_gput:nxV { command }
{[\int_use:N \c@rownum][\int_use:N \c@colnum]}
\l__tblr_saved_table_commands_before_cell_text_tl
}
\tl_set_eq:NN #1 \l__tblr_saved_cell_text_after_table_commands_tl
}
%% #1 maybe a single token or multiple tokens from a pair of braces
\cs_new_protected:Npn \__tblr_extract_table_commands_next:n #1
{
\tl_if_single_token:nTF {#1}
{
\clist_if_in:NnTF \g__tblr_table_commands_clist { #1 }
{ \__tblr_extract_one_table_command:N #1 }
{
\token_if_eq_meaning:NNF #1 \q_stop
{ \__tblr_save_real_cell_text:w #1 }
}
}
{ \__tblr_save_real_cell_text:w {#1} }
}
\cs_new_protected:Npn \__tblr_extract_one_table_command:N #1
{
\int_set:Nn \l__tblr_a_int
{ \cs:w g__tblr_table_cmd_ \cs_to_str:N #1 _arg_numb_tl \cs_end: }
\tl_put_right:Nn \l__tblr_saved_table_commands_before_cell_text_tl {#1}
\int_compare:nNnTF {\l__tblr_a_int} < {0}
{
\int_set:Nn \l__tblr_a_int { \int_abs:n {\l__tblr_a_int} - 1 }
\peek_charcode:NTF [
{ \__tblr_extract_table_command_arg_o:w }
{ \__tblr_extract_table_command_arg_next: }
}
{ \__tblr_extract_table_command_arg_next: }
}
\cs_new_protected:Npn \__tblr_extract_table_command_arg_o:w [#1]
{
\tl_put_right:Nn \l__tblr_saved_table_commands_before_cell_text_tl { [#1] }
\__tblr_extract_table_command_arg_next:
}
\cs_new_protected:Npn \__tblr_extract_table_command_arg_m:n #1
{
\tl_put_right:Nn \l__tblr_saved_table_commands_before_cell_text_tl { {#1} }
\__tblr_extract_table_command_arg_next:
}
\cs_new_protected:Npn \__tblr_extract_table_command_arg_next:
{
\int_compare:nNnTF {\l__tblr_a_int} > {0}
{
\int_decr:N \l__tblr_a_int
\__tblr_extract_table_command_arg_m:n
}
{ \__tblr_extract_table_commands_next:n }
}
%% The outermost set of braces of cell text #1 will be removed
\cs_new_protected:Npn \__tblr_save_real_cell_text:w #1 \q_stop
{
\tl_set:Nn \l__tblr_saved_cell_text_after_table_commands_tl {#1}
}
%%% --------------------------------------------------------
%%> \section{Initialize Table Inner Specifications}
%%% --------------------------------------------------------
\prop_gset_from_keyval:Nn \g__tblr_initial_table_prop
{
stretch = 1,
rulesep = 2pt,
}
\prop_gset_from_keyval:Nn \g__tblr_initial_rows_prop
{
abovesep = 2pt,
belowsep = 2pt,
@row-height = 0pt,
@row-head = 0pt,
@row-foot = 0pt,
@row-upper = 0pt,
@row-lower = 0pt,
}
\prop_gset_from_keyval:Nn \g__tblr_initial_columns_prop
{
leftsep = 6pt,
rightsep = 6pt,
width = -1pt, % column width unset
coefficient = 0, % column coefficient unset
@col-width = 0pt,
}
\prop_gset_from_keyval:Nn \g__tblr_initial_cells_prop
{
halign = j,
valign = t,
width = -1pt, % cell width unset
rowspan = 1,
colspan = 1,
omit = 0,
}
\prop_gset_from_keyval:Nn \g__tblr_initial_hlines_prop
{
@hline-count = 0,
}
\prop_gset_from_keyval:Nn \g__tblr_initial_vlines_prop
{
@vline-count = 0,
}
\tl_new:N \l__tblr_inner_spec_measure_tl
\tl_new:N \l__tblr_inner_spec_verb_tl
\cs_new_protected:Npn \__tblr_init_table_inner_spec:
{
\prop_map_inline:Nn \g__tblr_initial_table_prop
{
\__tblr_prop_gput:nxn { inner } { ##1 } {##2}
}
\int_step_variable:nNn { \c@rowcount } \l__tblr_i_tl
{
\prop_map_inline:Nn \g__tblr_initial_rows_prop
{
\__tblr_data_gput:nVnn { row } \l__tblr_i_tl {##1} {##2}
}
\prop_map_inline:Nn \g__tblr_initial_hlines_prop
{
\__tblr_spec_gput:nen { hline } { [\l__tblr_i_tl] / ##1 } {##2}
}
\int_step_variable:nNn { \c@colcount } \l__tblr_j_tl
{
\prop_map_inline:Nn \g__tblr_initial_cells_prop
{
\__tblr_data_gput:neeen { cell }
{ \l__tblr_i_tl } { \l__tblr_j_tl } {##1} {##2}
}
}
}
\prop_map_inline:Nn \g__tblr_initial_hlines_prop
{
\__tblr_spec_gput:nen { hline }
{ [\int_eval:n { \c@rowcount + 1}] / ##1 } {##2}
}
\int_step_variable:nNn { \c@colcount } \l__tblr_j_tl
{
\prop_map_inline:Nn \g__tblr_initial_columns_prop
{
\__tblr_data_gput:nenn { column } { \l__tblr_j_tl } {##1} {##2}
}
\prop_map_inline:Nn \g__tblr_initial_vlines_prop
{
\__tblr_spec_gput:nen { vline } { [\l__tblr_j_tl] / ##1 } {##2}
}
}
\prop_map_inline:Nn \g__tblr_initial_vlines_prop
{
\__tblr_spec_gput:nen { vline }
{ [\int_eval:n { \c@colcount + 1}] / ##1 } {##2}
}
\tl_clear:N \l__tblr_inner_spec_measure_tl
\tl_clear:N \l__tblr_inner_spec_verb_tl
\keys_set:nv { tblr } { l__tblr_default_ \l__tblr_env_name_tl _inner_tl }
}
%%% --------------------------------------------------------
%%> \section{Parse Table Inner Specifications}
%%% --------------------------------------------------------
\clist_new:N \g__tblr_table_known_keys_clist
\clist_gset:Nn \g__tblr_table_known_keys_clist
{
colspec, rowspec, column, row, cell, hline, vline, hborder, vborder, width,
rowhead, rowfoot, columns, rows, cells, hlines, vlines, % hborders, vborders,
leftsep, rightsep, colsep, abovesep, belowsep, rowsep, rulesep,
baseline, hspan, vspan, stretch, verb, delimiter
}
\keys_define:nn { tblr }
{
colspec .code:n = \__tblr_parse_colrow_spec:nn { column } {#1},
rowspec .code:n = \__tblr_parse_colrow_spec:nn { row } {#1},
width .code:n = \__tblr_keys_gput:nx { width } { \dim_eval:n {#1} },
hspan .code:n = \__tblr_keys_gput:nn { hspan } {#1},
vspan .code:n = \__tblr_keys_gput:nn { vspan } {#1},
stretch .code:n = \__tblr_keys_gput:nn { stretch } {#1},
verb .tl_set:N = \l__tblr_inner_spec_verb_tl,
verb .default:n = lite,
columns .code:n = \__tblr_set_every_column_aux:n {#1},
rows .code:n = \__tblr_set_every_row_aux:n {#1},
cells .code:n = \__tblr_set_every_cell_aux:n {#1},
hlines .code:n = \__tblr_set_every_hline_aux:n {#1},
vlines .code:n = \__tblr_set_every_vline_aux:n {#1},
leftsep .code:n = \tblr_set_every_column:nn { } { leftsep = #1 },
rightsep .code:n = \tblr_set_every_column:nn { } { rightsep = #1 },
colsep .meta:n = { leftsep = #1, rightsep = #1 },
abovesep .code:n = \tblr_set_every_row:nn { } { abovesep = #1 },
belowsep .code:n = \tblr_set_every_row:nn { } { belowsep = #1 },
rowsep .meta:n = { abovesep = #1, belowsep = #1 },
rulesep .code:n = \__tblr_keys_gput:nn { rulesep } {#1},
rowhead .code:n = \__tblr_keys_gput:nn { rowhead } {#1},
rowfoot .code:n = \__tblr_keys_gput:nn { rowfoot } {#1},
delimiter .code:n = \__tblr_set_delimiter:n {#1},
baseline .code:n = \__tblr_outer_gput_spec:nn { baseline } {#1},
unknown .code:n = \__tblr_table_special_key:Vn \l_keys_key_str {#1},
}
\regex_const:Nn \c__tblr_split_key_name_regex { ^ ( [a-z] + ) ( . * ) }
\cs_new_protected:Npn \__tblr_table_special_key:nn #1 #2
{
\regex_extract_once:NnNT \c__tblr_split_key_name_regex {#1} \l_tmpa_seq
{
\tl_set:Nx \l__tblr_a_tl { \seq_item:Nn \l_tmpa_seq {2} }
\tl_set_rescan:Nnx \l__tblr_b_tl {} { \seq_item:Nn \l_tmpa_seq {3} }
\cs:w __tblr_set_ \l__tblr_a_tl _aux:Vn \cs_end: \l__tblr_b_tl {#2}
}
}
\cs_generate_variant:Nn \__tblr_table_special_key:nn { Vn }
%% If the first key name is known, treat #1 is the table spec;
%% otherwise, treat #1 as colspec.
\regex_const:Nn \c__tblr_first_key_name_regex { ^ \s * ( [A-Za-z\-] + ) }
\cs_new_protected:Npn \__tblr_parse_table_spec:n #1
{
\regex_extract_once:NnNTF \c__tblr_first_key_name_regex {#1} \l_tmpa_seq
{
\clist_if_in:NxTF \g__tblr_table_known_keys_clist
{ \seq_item:Nn \l_tmpa_seq {2} }
{ \keys_set:nn { tblr } {#1} }
{ \__tblr_parse_colrow_spec:nn { column } {#1} }
}
{ \__tblr_parse_colrow_spec:nn { column } {#1} }
}
\cs_new_protected:Npn \__tblr_keys_gput:nn #1 #2
{
\__tblr_prop_gput:nnn { inner } {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_keys_gput:nn { nx }
\keys_define:nn { tblr-delimiter }
{
left .code:n = \__tblr_keys_gput:nn { delim-left } { \left #1 },
right .code:n = \__tblr_keys_gput:nn { delim-right } { \right #1 }
}
\cs_new_protected:Npn \__tblr_set_delimiter:n #1
{
\keys_set:nn { tblr-delimiter } {#1}
}
%%% --------------------------------------------------------
%%> \section{Initialize and Parse Table Outer Specifications}
%%% --------------------------------------------------------
\msg_new:nnn { tabularray } { used-theme-name }
{ theme ~ name ~ #1 ~ has ~ been ~ used! }
%% #1: theme names; #2: template and style commands
\NewDocumentCommand \NewTblrTheme { m +m }
{
\tl_if_exist:cTF { g__tblr_theme_ #1 _code_tl }
{ \msg_error:nnn { tabularray } { used-theme-name } { #1 } }
{
\tl_set:cn { g__tblr_theme_ #1 _code_tl } {#2}
\ignorespaces
}
}
\cs_new_protected:Npn \__tblr_use_theme:n #1
{
\ignorespaces
\tl_use:c { g__tblr_theme_ #1 _code_tl }
}
\cs_new_protected:Npn \__tblr_init_table_outer_spec:
{
\keys_set:nv { tblr-outer } { l__tblr_default_ \l__tblr_env_name_tl _outer_tl }
}
\cs_new_protected:Npn \__tblr_parse_table_option:n #1
{
\keys_set:nn { tblr-outer } {#1}
}
\keys_define:nn { tblr-outer }
{
long .code:n = \__tblr_outer_gput_spec:nn { long } { true },
tall .code:n = \__tblr_outer_gput_spec:nn { tall } { true },
halign .code:n = \__tblr_outer_gput_spec:nn { halign } {#1},
baseline .code:n = \__tblr_outer_gput_spec:nn { baseline } {#1},
l .meta:n = { halign = l },
c .meta:n = { halign = c },
r .meta:n = { halign = r },
t .meta:n = { baseline = t },
T .meta:n = { baseline = T },
m .meta:n = { baseline = m },
M .meta:n = { baseline = M },
b .meta:n = { baseline = b },
B .meta:n = { baseline = B },
valign .meta:n = { baseline = #1 }, % obsolete, will be removed some day
expand .code:n = \__tblr_outer_gput_spec:nn { expand } {#1},
headsep .code:n = \__tblr_outer_gput_spec:nn { headsep } {#1},
footsep .code:n = \__tblr_outer_gput_spec:nn { footsep } {#1},
presep .code:n = \__tblr_outer_gput_spec:nn { presep } {#1},
postsep .code:n = \__tblr_outer_gput_spec:nn { postsep } {#1},
theme .code:n = \__tblr_use_theme:n {#1},
caption .code:n = \__tblr_outer_gput_spec:nn { caption } {#1},
entry .code:n = \__tblr_outer_gput_spec:nn { entry } {#1},
label .code:n = \__tblr_outer_gput_spec:nn { label } {#1},
unknown .code:n = \__tblr_table_option_key:Vn \l_keys_key_str {#1},
}
\cs_new_protected:Npn \__tblr_outer_gput_spec:nn #1 #2
{
\__tblr_spec_gput:nen { outer } {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_outer_gput_spec:nn { ne }
\regex_const:Nn \c__tblr_option_key_name_regex { ^ [A-Za-z\-] + $ }
\msg_new:nnn { tabularray } { unknown-outer-key }
{ Unknown ~ outer ~ key ~ name ~ #1! }
\cs_new_protected:Npn \__tblr_table_option_key:nn #1 #2
{
\regex_match:NnTF \c__tblr_option_key_name_regex {#1}
{ \msg_error:nnn { tabularray } { unknown-outer-key } {#1} }
{
\regex_extract_once:NnNT \c__tblr_split_key_name_regex {#1} \l_tmpa_seq
{
\tl_set:Nx \l__tblr_a_tl { \seq_item:Nn \l_tmpa_seq {2} }
\tl_set_rescan:Nnx \l__tblr_b_tl {} { \seq_item:Nn \l_tmpa_seq {3} }
\tl_set:Nx \l__tblr_c_tl { \tl_head:N \l__tblr_b_tl }
\use:c { __tblr_outer_gput_ \l__tblr_a_tl :Vn } \l__tblr_c_tl {#2}
}
}
}
\cs_generate_variant:Nn \__tblr_table_option_key:nn { Vn }
\cs_new_protected:Npn \__tblr_outer_gput_note:nn #1 #2
{
\__tblr_prop_gput:nnn { note } {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_outer_gput_note:nn { Vn }
\cs_new_protected:Npn \__tblr_outer_gput_remark:nn #1 #2
{
\__tblr_prop_gput:nnn { remark } {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_outer_gput_remark:nn { Vn }
\cs_new_protected:Npn \__tblr_outer_gput_more:nn #1 #2
{
\__tblr_prop_gput:nnn { more } {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_outer_gput_more:nn { Vn }
%%% --------------------------------------------------------
%%> \section{Typeset and Calculate Sizes}
%%% --------------------------------------------------------
%% Calculate the width and height for every cell and border
\cs_new_protected:Npn \__tblr_calc_cell_and_line_sizes:
{
\__tblr_prepare_stretch:
\__tblr_calculate_line_sizes:
\__tblr_calculate_cell_sizes:
\LogTblrTracing { cell, row, column, hline, vline }
\__tblr_compute_extendable_column_width:
\__tblr_adjust_sizes_for_span_cells:
}
%% prepare stretch option of the table
\fp_new:N \l__tblr_stretch_fp
\dim_new:N \l__tblr_strut_dp_dim
\dim_new:N \l__tblr_strut_ht_dim
\cs_new_protected:Npn \__tblr_prepare_stretch:
{
\fp_set:Nn \l__tblr_stretch_fp
{ \__tblr_prop_item:nn { inner } { stretch } }
\fp_compare:nNnTF \l__tblr_stretch_fp > \c_zero_fp
{
\dim_set:Nn \l__tblr_strut_dp_dim
{ \fp_use:N \l__tblr_stretch_fp \box_dp:N \strutbox }
\dim_set:Nn \l__tblr_strut_ht_dim
{ \fp_use:N \l__tblr_stretch_fp \box_ht:N \strutbox }
\cs_set_eq:NN \__tblr_leave_vmode: \mode_leave_vertical:
\cs_set_eq:NN \__tblr_process_stretch: \__tblr_process_stretch_real:
}
{
\cs_set_eq:NN \__tblr_process_stretch: \prg_do_nothing:
\fp_compare:nNnTF \l__tblr_stretch_fp < \c_zero_fp
{ \cs_set_eq:NN \__tblr_leave_vmode: \@setminipage } % for lists (see issue #99)
{ \cs_set_eq:NN \__tblr_leave_vmode: \mode_leave_vertical: }
}
}
\cs_new_eq:NN \__tblr_leave_vmode: \mode_leave_vertical:
\cs_new_protected:Npn \__tblr_process_stretch_real:
{
\dim_compare:nNnT \l__tblr_strut_dp_dim > { \box_dp:N \l_tmpb_box }
{
\box_set_dp:Nn \l_tmpa_box
{
\box_dp:N \l_tmpa_box
- \box_dp:N \l_tmpb_box
+ \l__tblr_strut_dp_dim
}
\box_set_dp:Nn \l_tmpb_box { \l__tblr_strut_dp_dim }
}
\dim_compare:nNnT \l__tblr_strut_ht_dim > { \box_ht:N \l_tmpa_box }
{
\hbox_set:Nn \l_tmpa_box { \box_use:N \l_tmpa_box }
\hbox_set:Nn \l_tmpb_box { \box_use:N \l_tmpb_box }
\box_set_ht:Nn \l_tmpb_box
{
\box_ht:N \l_tmpb_box
- \box_ht:N \l_tmpa_box
+ \l__tblr_strut_ht_dim
}
\box_set_ht:Nn \l_tmpa_box { \l__tblr_strut_ht_dim }
%% return vbox for vertical-align: \c__tblr_middle_m_tl
\vbox_set_top:Nn \l_tmpa_box { \box_use:N \l_tmpa_box }
\vbox_set:Nn \l_tmpb_box { \box_use:N \l_tmpb_box }
}
}
\cs_new_eq:NN \__tblr_process_stretch: \__tblr_process_stretch_real:
%% Calculate the thickness for every hline and vline
\cs_new_protected:Npn \__tblr_calculate_line_sizes:
{
%% We need these two counters in executing hline and vline commands
\int_zero:N \c@rownum
\int_zero:N \c@colnum
\int_step_inline:nn { \c@rowcount + 1 }
{
\int_incr:N \c@rownum
\int_zero:N \c@colnum
\int_step_inline:nn { \c@colcount + 1 }
{
\int_incr:N \c@colnum
\int_compare:nNnT { ##1 } < { \c@rowcount + 1 }
{
\__tblr_measure_and_update_vline_size:nn { ##1 } { ####1 }
}
\int_compare:nNnT { ####1 } < { \c@colcount + 1 }
{
\__tblr_measure_and_update_hline_size:nn { ##1 } { ####1 }
}
}
}
}
%% Measure and update thickness of the vline
%% #1: row number, #2 column number
\cs_new_protected:Npn \__tblr_measure_and_update_vline_size:nn #1 #2
{
\dim_zero:N \l__tblr_w_dim
\tl_set:Nx \l__tblr_n_tl
{ \__tblr_spec_item:ne { vline } { [#2] / @vline-count } }
\int_compare:nNnT { \l__tblr_n_tl } > {0}
{
\tl_set:Nx \l__tblr_s_tl
{ \__tblr_prop_item:ne { inner } { rulesep } }
\int_step_inline:nn { \l__tblr_n_tl }
{
\vbox_set_to_ht:Nnn \l__tblr_b_box {1pt}
{
\__tblr_get_vline_segment_child:nnnnn
{#1} {#2} {##1} {1pt} {1pt}
}
\tl_set:Nx \l__tblr_w_tl { \dim_eval:n { \box_wd:N \l__tblr_b_box } }
\__tblr_spec_gput_if_larger:nee { vline }
{ [#2](##1) / @vline-width } { \l__tblr_w_tl }
\dim_add:Nn \l__tblr_w_dim
{
\__tblr_spec_item:nn { vline } { [#2](##1) / @vline-width }
}
\dim_add:Nn \l__tblr_w_dim { \l__tblr_s_tl }
}
\dim_add:Nn \l__tblr_w_dim { - \l__tblr_s_tl }
}
\__tblr_spec_gput_if_larger:nee { vline }
{ [#2]/ @vline-width } { \dim_use:N \l__tblr_w_dim }
}
%% Get text of a vline segment
%% #1: row number, #2: column number; #3: index number; #4: height; #5: depth
%% We put all code inside a group to avoid conflicts of local variables
\cs_new_protected:Npn \__tblr_get_vline_segment_child:nnnnn #1 #2 #3 #4 #5
{
\group_begin:
\tl_set:Nx \l__tblr_w_tl
{ \__tblr_spec_item:ne { vline } { [#1][#2](#3) / wd } }
\tl_if_empty:NF \l__tblr_w_tl { \dim_set:Nn \rulewidth { \l__tblr_w_tl } }
\tl_set:Nx \l__tblr_d_tl
{ \__tblr_spec_item:ne { vline } { [#1][#2](#3) / @dash } }
\tl_set:Nx \l__tblr_a_tl { \tl_head:N \l__tblr_d_tl }
\tl_set:Nx \l__tblr_b_tl { \tl_tail:N \l__tblr_d_tl }
\exp_args:NV \tl_if_eq:NNTF \l__tblr_a_tl \@tblr@dash
{
\__tblr_get_vline_dash_style:N \l__tblr_b_tl
\xleaders \l__tblr_b_tl \vfil
}
{
%% When using text as vline, we need to omit abovepos and belowpos.
\unskip
\hbox_set:Nn \l__tblr_d_box
{
\bool_if:NTF \l__tblr_math_mode_bool
{ $ \l__tblr_b_tl $ } { \l__tblr_b_tl }
}
\box_set_ht:Nn \l__tblr_d_box {#4}
\box_set_dp:Nn \l__tblr_d_box {#5}
\box_use:N \l__tblr_d_box
\vss
}
\group_end:
}
\cs_generate_variant:Nn \__tblr_get_vline_segment_child:nnnnn { nnnxx }
%% Measure and update thickness of the hline
%% #1: row number, #2 column number
\cs_new_protected:Npn \__tblr_measure_and_update_hline_size:nn #1 #2
{
\dim_zero:N \l__tblr_h_dim
\tl_set:Nx \l__tblr_n_tl
{ \__tblr_spec_item:ne { hline } { [#1] / @hline-count } }
\int_compare:nNnT { \l__tblr_n_tl } > {0}
{
\tl_set:Nx \l__tblr_s_tl
{ \__tblr_prop_item:ne { inner } { rulesep } }
\int_step_inline:nn { \l__tblr_n_tl }
{
\hbox_set_to_wd:Nnn \l__tblr_b_box {1pt}
{ \__tblr_get_hline_segment_child:nnn {#1} {#2} {##1} }
\tl_set:Nx \l__tblr_h_tl
{
\dim_eval:n
{ \box_ht:N \l__tblr_b_box + \box_dp:N \l__tblr_b_box }
}
\__tblr_spec_gput_if_larger:nee { hline }
{ [#1](##1) / @hline-height } { \l__tblr_h_tl }
\dim_add:Nn \l__tblr_h_dim
{
\__tblr_spec_item:nn { hline } { [#1](##1) / @hline-height }
}
\dim_add:Nn \l__tblr_h_dim { \l__tblr_s_tl }
}
\dim_add:Nn \l__tblr_h_dim { - \l__tblr_s_tl }
}
\__tblr_spec_gput_if_larger:nee { hline }
{ [#1] / @hline-height } { \dim_use:N \l__tblr_h_dim }
}
%% Get text of a hline segment
%% #1: row number, #2: column number; #3: index number
\cs_new_protected:Npn \__tblr_get_hline_segment_child:nnn #1 #2 #3
{
\group_begin:
\tl_set:Nx \l__tblr_w_tl
{ \__tblr_spec_item:ne { hline } { [#1][#2](#3) / wd } }
\tl_if_empty:NF \l__tblr_w_tl { \dim_set:Nn \rulewidth { \l__tblr_w_tl } }
\tl_set:Nx \l__tblr_d_tl
{ \__tblr_spec_item:ne { hline } { [#1][#2](#3) / @dash } }
\tl_set:Nx \l__tblr_a_tl { \tl_head:N \l__tblr_d_tl }
\tl_set:Nx \l__tblr_b_tl { \tl_tail:N \l__tblr_d_tl }
\exp_args:NV \tl_if_eq:NNTF \l__tblr_a_tl \@tblr@dash
{
\__tblr_get_hline_dash_style:N \l__tblr_b_tl
\xleaders \l__tblr_b_tl \hfil
}
{
\bool_if:NTF \l__tblr_math_mode_bool
{ $ \l__tblr_b_tl $ } { \l__tblr_b_tl }
\hfil
}
\group_end:
}
%% current cell alignments
\tl_new:N \g__tblr_cell_halign_tl
\tl_new:N \g__tblr_cell_valign_tl
\tl_new:N \g__tblr_cell_middle_tl
\tl_const:Nn \c__tblr_valign_h_tl { h }
\tl_const:Nn \c__tblr_valign_m_tl { m }
\tl_const:Nn \c__tblr_valign_f_tl { f }
\tl_const:Nn \c__tblr_valign_t_tl { t }
\tl_const:Nn \c__tblr_valign_b_tl { b }
\tl_const:Nn \c__tblr_middle_t_tl { t }
\tl_const:Nn \c__tblr_middle_m_tl { m }
\tl_const:Nn \c__tblr_middle_b_tl { b }
%% #1: row number; #2: column number
\cs_new_protected:Npn \__tblr_get_cell_alignments:nn #1 #2
{
\group_begin:
\tl_gset:Nx \g__tblr_cell_halign_tl
{ \__tblr_data_item:neen { cell } {#1} {#2} { halign } }
\tl_set:Nx \l__tblr_v_tl
{ \__tblr_data_item:neen { cell } {#1} {#2} { valign } }
\tl_case:NnF \l__tblr_v_tl
{
\c__tblr_valign_t_tl
{
\tl_gset:Nn \g__tblr_cell_valign_tl {m}
\tl_gset:Nn \g__tblr_cell_middle_tl {t}
}
\c__tblr_valign_m_tl
{
\tl_gset:Nn \g__tblr_cell_valign_tl {m}
\tl_gset:Nn \g__tblr_cell_middle_tl {m}
}
\c__tblr_valign_b_tl
{
\tl_gset:Nn \g__tblr_cell_valign_tl {m}
\tl_gset:Nn \g__tblr_cell_middle_tl {b}
}
}
{
\tl_gset_eq:NN \g__tblr_cell_valign_tl \l__tblr_v_tl
\tl_gclear:N \g__tblr_cell_middle_tl
}
\group_end:
}
%% current cell dimensions
\dim_new:N \g__tblr_cell_wd_dim
\dim_new:N \g__tblr_cell_ht_dim
\dim_new:N \g__tblr_cell_head_dim
\dim_new:N \g__tblr_cell_foot_dim
%% Calculate the width and height for every cell
\cs_new_protected:Npn \__tblr_calculate_cell_sizes:
{
%% You can use these two counters in cell text
\int_zero:N \c@rownum
\int_zero:N \c@colnum
\__tblr_save_counters:n { table }
\int_step_inline:nn { \c@rowcount }
{
\int_incr:N \c@rownum
\int_zero:N \c@colnum
\__tblr_update_rowsep_registers:
\tl_set:Nx \l__tblr_h_tl
{ \__tblr_data_item:nen { row } { \int_use:N \c@rownum } { height } }
%% We didn't initialize row heights with -1pt
\dim_compare:nNnF { \l__tblr_h_tl } = { 0pt }
{
\__tblr_data_gput:nenV { row } { \int_use:N \c@rownum }
{ @row-height } \l__tblr_h_tl
}
\int_step_inline:nn { \c@colcount }
{
\int_incr:N \c@colnum
\__tblr_update_colsep_registers:
\__tblr_measure_cell_update_sizes:nnNNNN
{ \int_use:N \c@rownum }
{ \int_use:N \c@colnum }
\g__tblr_cell_wd_dim
\g__tblr_cell_ht_dim
\g__tblr_cell_head_dim
\g__tblr_cell_foot_dim
}
}
\__tblr_restore_counters:n { table }
\int_step_inline:nn { \c@colcount }
{
\tl_set:Nx \l__tblr_w_tl
{ \__tblr_data_item:nen { column } {##1} { width } }
\dim_compare:nNnF { \l__tblr_w_tl } < { 0pt }
{
\__tblr_data_gput:nenV { column } {##1} { @col-width } \l__tblr_w_tl
}
}
}
\cs_new_protected:Npn \__tblr_update_rowsep_registers:
{
\dim_set:Nn \abovesep
{ \__tblr_data_item:nen { row } { \int_use:N \c@rownum } { abovesep } }
\dim_set:Nn \belowsep
{ \__tblr_data_item:nen { row } { \int_use:N \c@rownum } { belowsep } }
}
\cs_new_protected:Npn \__tblr_update_colsep_registers:
{
\dim_set:Nn \leftsep
{ \__tblr_data_item:nen { column } { \int_use:N \c@colnum } { leftsep } }
\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_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
\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 } }
}
\tl_new:N \l__tblr_cell_fg_tl
\tl_new:N \l__tblr_cell_cmd_tl
\tl_new:N \l__tblr_cell_mode_tl
\bool_new:N \l__tblr_cell_math_mode_bool
\tl_const:Nn \l__tblr_cell_math_style_tl { \relax }
\tl_const:Nn \l__tblr_cell_imath_style_tl { \textstyle }
\tl_const:Nn \l__tblr_cell_dmath_style_tl { \displaystyle }
%% Get cell text, #1: row number, #2: column number
%% If the width of the cell is not set, split it with \\ and compute the width
%% Therefore we always get a vbox for any cell
\cs_new_protected:Npn \__tblr_get_cell_text_real:nn #1 #2
{
\group_begin:
\tl_set:Nx \l__tblr_c_tl { \__tblr_spec_item:ne { text } {[#1][#2]} }
%% when the cell text is guarded by a pair of curly braces,
%% we unbrace it and ignore cmd option of the cell, see issue #90.
\bool_lazy_and:nnTF
{ \tl_if_single_p:N \l__tblr_c_tl }
{ \exp_args:NV \tl_if_head_is_group_p:n \l__tblr_c_tl }
{ \exp_last_unbraced:NNV \tl_set:Nn \l__tblr_c_tl \l__tblr_c_tl }
{
\tl_set:Nx \l__tblr_cell_cmd_tl
{ \__tblr_data_item:neen { cell } {#1} {#2} { cmd } }
\tl_if_empty:NF \l__tblr_cell_cmd_tl
{
\tl_set:Nx \l__tblr_c_tl
{ \exp_not:V \l__tblr_cell_cmd_tl { \exp_not:V \l__tblr_c_tl } }
}
}
\tl_set:Nx \l__tblr_cell_mode_tl
{ \__tblr_data_item:neen { cell } {#1} {#2} { mode } }
\tl_if_empty:NT \l__tblr_cell_mode_tl
{
\bool_if:NTF \l__tblr_math_mode_bool
{ \tl_set:Nn \l__tblr_cell_mode_tl { math } }
{ \tl_set:Nn \l__tblr_cell_mode_tl { text } }
}
\tl_if_eq:NnTF \l__tblr_cell_mode_tl { text }
{ \bool_set_false:N \l__tblr_cell_math_mode_bool }
{
\bool_set_true:N \l__tblr_cell_math_mode_bool
\tl_put_left:Nv \l__tblr_c_tl
{ l__tblr_cell_ \l__tblr_cell_mode_tl _style_tl }
\tl_put_left:Nn \l__tblr_c_tl { $ }
\tl_put_right:Nn \l__tblr_c_tl { $ }
}
\tl_set:Nx \l__tblr_f_tl { \__tblr_data_item:neen { cell } {#1} {#2} { font } }
\tl_set:Nx \l__tblr_w_tl
{ \__tblr_data_item:neen { cell } {#1} {#2} { width } }
\dim_compare:nNnT { \l__tblr_w_tl } < { 0pt } % cell width unset
{
\int_compare:nNnT
{ \__tblr_data_item:neen { cell } {#1} {#2} { colspan } } < {2}
{
\tl_set:Nx \l__tblr_w_tl
{ \__tblr_data_item:nen { column } {#2} { width } }
}
}
\dim_compare:nNnT { \l__tblr_w_tl } < { 0pt } % column width unset
{
\__tblr_save_counters:n { cell }
\bool_if:NTF \l__tblr_cell_math_mode_bool
{
%% Note that font = \boldmath will increase cell width (issue #137)
\hbox_set:Nn \l_tmpa_box { \l__tblr_f_tl \l__tblr_c_tl }
\tl_set:Nx \l__tblr_w_tl { \box_wd:N \l_tmpa_box }
}
{
\__tblr_get_cell_size_with_box:
}
\__tblr_restore_counters:n { cell }
}
\tl_put_left:NV \l__tblr_c_tl \l__tblr_f_tl
\tl_set:Nx \l__tblr_cell_fg_tl
{ \__tblr_data_item:neen { cell } {#1} {#2} { foreground } }
\tl_if_empty:NF \l__tblr_cell_fg_tl
{ \exp_args:NV \color \l__tblr_cell_fg_tl }
\__tblr_get_vcell_and_sizes:NN \l__tblr_c_tl \l__tblr_w_tl
\group_end:
}
\cs_new_protected:Npn \__tblr_get_cell_size_with_box:
{
\tl_if_eq:NnTF \l__tblr_inner_spec_measure_tl { vbox }
{ \__tblr_get_cell_size_with_vbox: }
{ \__tblr_get_cell_size_with_hbox: }
}
%% Varwidth won't work as expected when \color command occurs in it,
%% and we can not fix this problem with \leavevmode command.
%% See https://tex.stackexchange.com/q/460489.
%% But we need to use \color command for fg option,
%% or users may use it in the middle of the cell text,
%% so we have redefine \color command and disable it before measuring cell.
%% In order to correctly measure an enumerate environment,
%% we need to enclose varwidth with NoHyper environment (see issue #196).
\NewDocumentCommand \__tblr_fake_color_command:w { o m } { }
\cs_new_protected:Npn \__tblr_get_cell_size_with_vbox:
{
\hbox_set:Nn \l_tmpa_box
{
\cs_set_eq:NN \color \__tblr_fake_color_command:w
\begin{tblrNoHyper}
\begin{varwidth}{\paperwidth}
\l__tblr_f_tl
\__tblr_rescan_cell_tokens:N \l__tblr_c_tl
\end{varwidth}
\end{tblrNoHyper}
}
\tl_set:Nx \l__tblr_w_tl { \box_wd:N \l_tmpa_box }
}
\cs_new_protected:Npn \__tblr_get_cell_size_with_hbox:
{
\tl_set_eq:NN \l_tmpb_tl \l__tblr_c_tl
\__tblr_insert_braces:N \l_tmpb_tl
\seq_set_split:NnV \l_tmpa_seq { \\ } \l_tmpb_tl
\tl_set:Nn \l__tblr_w_tl { 0pt }
\seq_map_variable:NNn \l_tmpa_seq \l_tmpa_tl
{
\__tblr_remove_braces:N \l_tmpa_tl
\hbox_set:Nn \l_tmpa_box
{
\l__tblr_f_tl
\__tblr_rescan_cell_tokens:N \l_tmpa_tl
}
\tl_set:Nx \l__tblr_w_tl
{ \dim_max:nn { \l__tblr_w_tl } { \box_wd:N \l_tmpa_box } }
}
}
%% #1: cell text; #2: box width
\cs_new_protected:Npn \__tblr_get_vcell_and_sizes:NN #1 #2
{
\group_begin:
\vbox_set:Nn \l_tmpb_box { \__tblr_make_vcell_text:NN #1 #2 }
\vbox_set_top:Nn \l_tmpa_box { \vbox_unpack:N \l_tmpb_box }
\__tblr_process_stretch:
\dim_gset:Nn \g__tblr_cell_wd_dim { \box_wd:N \l_tmpb_box }
\dim_gset:Nn \g__tblr_cell_ht_dim
{ \box_ht:N \l_tmpb_box + \box_dp:N \l_tmpb_box }
\dim_gset:Nn \g__tblr_cell_head_dim { \box_ht:N \l_tmpa_box }
\dim_gset:Nn \g__tblr_cell_foot_dim { \box_dp:N \l_tmpb_box }
\tl_case:Nn \g__tblr_cell_valign_tl
{
\c__tblr_valign_h_tl
{ \box_use:N \l_tmpa_box }
\c__tblr_valign_m_tl
{
\tl_case:Nn \g__tblr_cell_middle_tl
{
\c__tblr_middle_t_tl
{ \box_use:N \l_tmpa_box }
\c__tblr_middle_m_tl
{
\tl_set:Nx \l__tblr_b_tl
{
\dim_eval:n
{
( \g__tblr_cell_ht_dim - \g__tblr_cell_head_dim
- \g__tblr_cell_foot_dim ) / 2
}
}
\box_set_ht:Nn \l_tmpb_box
{ \g__tblr_cell_head_dim + \l__tblr_b_tl }
\box_set_dp:Nn \l_tmpb_box
{ \g__tblr_cell_foot_dim + \l__tblr_b_tl }
\box_use:N \l_tmpb_box
}
\c__tblr_middle_b_tl
{ \box_use:N \l_tmpb_box }
}
}
\c__tblr_valign_f_tl
{ \box_use:N \l_tmpb_box }
}
\group_end:
}
%% #1: cell text; #2: box width
%% All halign commands are defined at the beginning of the file
\cs_new_protected:Npn \__tblr_make_vcell_text:NN #1 #2
{
\dim_set:Nn \tex_hsize:D { #2 }
\TblrParboxRestore
\cs:w __tblr_halign_command_ \g__tblr_cell_halign_tl : \cs_end:
\__tblr_leave_vmode:
\bool_if:NTF \l__tblr_cell_math_mode_bool
{ #1 }
{ \__tblr_rescan_cell_tokens:N #1 }
}
%% When using verb option, there is an end-of-line character at the end.
%% This character causes extra horizontal space at the end when "measure=hbox",
%% or causes extra vertical space at the end with "measure=vbox".
%% Therefore we have to use an \empty to remove it.
%% See https://tex.stackexchange.com/q/213659
\cs_new_protected:Npn \__tblr_rescan_cell_tokens:N #1
{
\tl_if_empty:NTF \l__tblr_inner_spec_verb_tl
{ #1 }
{
%% insert space characters after some control sequences first (issue #112)
\regex_replace_all:nnN { (\c{[A-Za-z]*}) ([A-Za-z]) } { \1 \ \2 } #1
\regex_replace_all:nnN { . } { \c{string} \0 } #1
\tl_set:Nx #1 { #1 \noexpand \empty }
\exp_args:NV \tex_scantokens:D #1
}
}
%% #1: total height dimension; #2: head dimension; #3: foot dimension;
%% #4: tl for resulting upper size; #5: tl for resulting lower size
\tl_new:N \l__tblr_middle_body_tl
\cs_new_protected:Npn \__tblr_get_middle_cell_upper_lower:NNNNN #1 #2 #3 #4 #5
{
\tl_case:Nn \g__tblr_cell_middle_tl
{
\c__tblr_middle_t_tl
{
\tl_set:Nx #4 { \dim_use:N #2 }
\tl_set:Nx #5 { \dim_eval:n { #1 - #2 } }
}
\c__tblr_middle_m_tl
{
\tl_set:Nx \l__tblr_middle_body_tl { \dim_eval:n { #1 - #2 - #3 } }
\tl_set:Nx #4 { \dim_eval:n { #2 + \l__tblr_middle_body_tl / 2 } }
\tl_set:Nx #5 { \dim_eval:n { #3 + \l__tblr_middle_body_tl / 2 } }
}
\c__tblr_middle_b_tl
{
\tl_set:Nx #4 { \dim_eval:n { #1 - #3 } }
\tl_set:Nx #5 { \dim_use:N #3 }
}
}
}
%% Update natural dimensions of the 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_update_cell_size:nnNNNN #1 #2 #3 #4 #5 #6
{
\group_begin:
\tl_set:Nx \l__tblr_c_tl
{ \__tblr_data_item:neen { cell } {#1} {#2} { colspan } }
\int_compare:nNnT { \l__tblr_c_tl } > {1}
{
\__tblr_data_gput:neene { cell } {#1} {#2} { @cell-width } {\dim_use:N #3}
\dim_gzero:N #3 % don't affect column width
}
\tl_set:Nx \l__tblr_r_tl
{ \__tblr_data_item:neen { cell } {#1} {#2} { rowspan } }
\int_compare:nNnT { \l__tblr_r_tl } > {1}
{
\tl_case:Nn \g__tblr_cell_valign_tl
{
\c__tblr_valign_h_tl
{
\tl_set:Nx \l__tblr_u_tl { \dim_use:N #5 }
\tl_set:Nx \l__tblr_v_tl { \dim_eval:n { #4 - #5 } }
%% Update the head size of the first span row here
\__tblr_data_gput_if_larger:nene
{ row } {#1} { @row-head } { \dim_use:N #5 }
}
\c__tblr_valign_f_tl
{
\tl_set:Nx \l__tblr_u_tl { \dim_eval:n { #4 - #6 } }
\tl_set:Nx \l__tblr_v_tl { \dim_use:N #6 }
%% Update the foot size of the last span row here
\__tblr_data_gput_if_larger:nene
{ row }
{ \int_eval:n { #1 + \l__tblr_r_tl - 1 } }
{ @row-foot }
{ \dim_use:N #6 }
}
\c__tblr_valign_m_tl
{
\__tblr_get_middle_cell_upper_lower:NNNNN
#4 #5 #6 \l__tblr_u_tl \l__tblr_v_tl
}
}
\__tblr_data_gput:neenV { cell } {#1} {#2} { @cell-height } \l__tblr_u_tl
\__tblr_data_gput:neenV { cell } {#1} {#2} { @cell-depth } \l__tblr_v_tl
%% Don't affect row sizes
\dim_gzero:N #4
\dim_gzero:N #5
\dim_gzero:N #6
}
\group_end:
}
%% Update size of the row. #1: row number; #2: column number;
%% #3: total height dimension; #4: head dimension; #5: foot dimension
\cs_new_protected:Npn \__tblr_update_row_size:nnNNN #1 #2 #3 #4 #5
{
\group_begin:
%% Note that \l__tblr_h_tl may be empty
\tl_set:Nx \l__tblr_h_tl
{ \__tblr_data_item:nen { row } {#1} { @row-height } }
\tl_if_eq:NNTF \g__tblr_cell_valign_tl \c__tblr_valign_m_tl
{
\tl_set:Nx \l__tblr_a_tl
{ \__tblr_data_item:nen { row } {#1} { @row-upper } }
\tl_set:Nx \l__tblr_b_tl
{ \__tblr_data_item:nen { row } {#1} { @row-lower } }
\__tblr_get_middle_cell_upper_lower:NNNNN
#3 #4 #5 \l__tblr_u_tl \l__tblr_v_tl
\dim_compare:nNnT { \l__tblr_u_tl } > { \l__tblr_a_tl }
{
\tl_set_eq:NN \l__tblr_a_tl \l__tblr_u_tl
\__tblr_data_gput:nenV { row } {#1} { @row-upper } \l__tblr_a_tl
}
\dim_compare:nNnT { \l__tblr_v_tl } > { \l__tblr_b_tl }
{
\tl_set_eq:NN \l__tblr_b_tl \l__tblr_v_tl
\__tblr_data_gput:nenV { row } {#1} { @row-lower } \l__tblr_b_tl
}
\dim_compare:nNnT
{ \l__tblr_a_tl + \l__tblr_b_tl } > { \l__tblr_h_tl + 0pt }
{
\__tblr_data_gput:nene { row } {#1} { @row-height }
{ \dim_eval:n { \l__tblr_a_tl + \l__tblr_b_tl } }
}
}
{
\tl_set:Nx \l__tblr_e_tl
{ \__tblr_data_item:nen { row } {#1} { @row-head } }
\tl_set:Nx \l__tblr_f_tl
{ \__tblr_data_item:nen { row } {#1} { @row-foot } }
\dim_compare:nNnT {#4} > {\l__tblr_e_tl}
{
\__tblr_data_gput:nene { row } {#1} { @row-head } { \dim_use:N #4 }
}
\dim_compare:nNnT {#5} > {\l__tblr_f_tl}
{
\__tblr_data_gput:nene { row } {#1} { @row-foot } { \dim_use:N #5 }
}
\tl_set:Nx \l__tblr_x_tl { \dim_max:nn {#4} { \l__tblr_e_tl } }
\tl_set:Nx \l__tblr_y_tl { \dim_max:nn {#5} { \l__tblr_f_tl } }
\dim_compare:nNnT
{ #3 - #4 - #5 } > { \l__tblr_h_tl - \l__tblr_x_tl - \l__tblr_y_tl }
{
\__tblr_data_gput:nene { row } {#1} { @row-height }
{
\dim_eval:n
{
\l__tblr_x_tl
+ \dim_use:N #3 - \dim_use:N #4 - \dim_use:N #5
+ \l__tblr_y_tl
}
}
}
}
\group_end:
}
%% Update size of the column. #1: column number; #2: width dimension
\cs_new_protected:Npn \__tblr_update_col_size:nN #1 #2
{
\tl_set:Nx \l_tmpb_tl
{ \__tblr_data_item:nen { column } {#1} { @col-width } }
\bool_lazy_or:nnT
{ \tl_if_empty_p:N \l_tmpb_tl }
{ \dim_compare_p:nNn { \dim_use:N #2 } > { \l_tmpb_tl } }
{
\__tblr_data_gput:nene { column } {#1} { @col-width } { \dim_use:N #2 }
}
}
%%% --------------------------------------------------------
%%> \section{Calculate and Adjust Extendable Columns}
%%% --------------------------------------------------------
%% Compute column widths when there are some extendable columns
\dim_new:N \l__column_target_dim
\prop_new:N \l__column_coefficient_prop
\prop_new:N \l__column_natural_width_prop
\prop_new:N \l__column_computed_width_prop
\msg_new:nnn { tabularray } { table-width-too-small }
{ Table ~ width ~ is ~ too ~ small, ~ need ~ #1 ~ more! }
\cs_new_protected:Npn \__tblr_compute_extendable_column_width:
{
\__tblr_collect_extendable_column_width:
\dim_compare:nNnTF { \l__column_target_dim } < { 0pt }
{
\msg_warning:nnx { tabularray } { table-width-too-small }
{ \dim_abs:n { \l__column_target_dim } }
}
{
\prop_if_empty:NF \l__column_coefficient_prop
{ \__tblr_adjust_extendable_column_width: }
}
}
\cs_new_protected:Npn \__tblr_collect_extendable_column_width:
{
\tl_set:Nx \l_tmpa_tl { \__tblr_prop_item:nn { inner } { width } }
\tl_if_empty:NTF \l_tmpa_tl
{ \dim_set_eq:NN \l__column_target_dim \linewidth }
{ \dim_set:Nn \l__column_target_dim { \l_tmpa_tl } }
\prop_clear:N \l__column_coefficient_prop
\prop_clear:N \l__column_natural_width_prop
\prop_clear:N \l__column_computed_width_prop
\int_step_variable:nNn { \c@colcount } \l__tblr_j_tl
{
\tl_set:Nx \l__tblr_a_tl
{ \__tblr_data_item:nen { column } { \l__tblr_j_tl } { width } }
\tl_set:Nx \l__tblr_b_tl
{ \__tblr_data_item:nen { column } { \l__tblr_j_tl } { coefficient } }
\tl_set:Nx \l__tblr_c_tl
{ \__tblr_data_item:nen { column } { \l__tblr_j_tl } { @col-width } }
\dim_compare:nNnTF { \l__tblr_a_tl } < { 0pt } % column width unset
{
\dim_compare:nNnTF { \l__tblr_b_tl pt } = { 0pt }
{ \dim_sub:Nn \l__column_target_dim { \l__tblr_c_tl } }
{
\prop_put:Nxx \l__column_coefficient_prop
{ \l__tblr_j_tl } { \l__tblr_b_tl }
\prop_put:Nxn \l__column_computed_width_prop
{ \l__tblr_j_tl } { 0pt }
\dim_compare:nNnF { \l__tblr_b_tl pt } > { 0pt }
{
\prop_put:Nxx \l__column_natural_width_prop
{ \l__tblr_j_tl } { \l__tblr_c_tl }
}
}
}
{ \dim_sub:Nn \l__column_target_dim { \l__tblr_a_tl } }
\tl_set:Nx \l__tblr_a_tl
{ \__tblr_spec_item:ne { vline } { [\l__tblr_j_tl] / @vline-width } }
\tl_set:Nx \l__tblr_b_tl
{ \__tblr_data_item:nen { column } { \l__tblr_j_tl } { leftsep } }
\tl_set:Nx \l__tblr_c_tl
{ \__tblr_data_item:nen { column } { \l__tblr_j_tl } { rightsep } }
\dim_set:Nn \l__column_target_dim
{ \l__column_target_dim - \l__tblr_a_tl - \l__tblr_b_tl - \l__tblr_c_tl }
}
\tl_set:Nx \l__tblr_a_tl
{
\__tblr_spec_item:ne { vline }
{ [\int_eval:n {\c@colcount + 1}] / @vline-width }
}
\tl_if_empty:NF \l__tblr_a_tl
{ \dim_sub:Nn \l__column_target_dim { \l__tblr_a_tl } }
\LogTblrTracing { target }
}
%% If all columns have negative coefficients and small natural widths,
%% \l__column_coefficient_prop will be empty after one or more rounds.
%% We reset @row-height, etc for \linewidth graphics in X columns (issue #80)
\cs_new_protected:Npn \__tblr_adjust_extendable_column_width:
{
\bool_while_do:nn
{ \dim_compare_p:nNn { \l__column_target_dim } > { \hfuzz } }
{
\prop_if_empty:NTF \l__column_coefficient_prop
{ \__tblr_adjust_extendable_column_width_negative: }
{ \__tblr_adjust_extendable_column_width_once: }
}
\prop_map_inline:Nn \l__column_computed_width_prop
{
\__tblr_data_gput:nnne { column } {##1} { width } {##2}
\__tblr_data_gput:nnnn { column } {##1} { @col-width } { 0pt }
}
\int_step_inline:nn { \c@rowcount }
{
\__tblr_data_gput:nnnn { row } {##1} { @row-height } { 0pt }
\__tblr_data_gput:nnnn { row } {##1} { @row-head } { 0pt }
\__tblr_data_gput:nnnn { row } {##1} { @row-foot } { 0pt }
\__tblr_data_gput:nnnn { row } {##1} { @row-upper } { 0pt }
\__tblr_data_gput:nnnn { row } {##1} { @row-lower } { 0pt }
}
\__tblr_calculate_cell_sizes:
}
%% We use dimen register, since the coefficient may be a decimal number
\cs_new_protected:Npn \__tblr_adjust_extendable_column_width_once:
{
\dim_zero:N \l_tmpa_dim
\prop_map_inline:Nn \l__column_coefficient_prop
{
\dim_add:Nn \l_tmpa_dim { \dim_abs:n { ##2 pt } }
}
\tl_set:Nx \l__tblr_w_tl
{ \dim_ratio:nn { \l__column_target_dim } { \l_tmpa_dim } }
\dim_zero:N \l__column_target_dim
\prop_map_inline:Nn \l__column_coefficient_prop
{
\tl_set:Nx \l__tblr_a_tl
{ \dim_eval:n { \dim_abs:n { ##2 pt } * \l__tblr_w_tl } }
\dim_compare:nNnTF { ##2 pt } > { 0pt }
{
\__tblr_add_dimen_value:Nnn
\l__column_computed_width_prop { ##1 } { \l__tblr_a_tl }
}
{
\tl_set:Nx \l__tblr_b_tl
{ \prop_item:Nn \l__column_natural_width_prop { ##1 } }
\tl_set:Nx \l__tblr_c_tl
{ \prop_item:Nn \l__column_computed_width_prop { ##1 } }
\dim_compare:nNnTF { \l__tblr_a_tl + \l__tblr_c_tl } > { \l__tblr_b_tl }
{
\prop_put:Nnx \l__column_computed_width_prop
{ ##1 } { \l__tblr_b_tl }
\dim_add:Nn \l__column_target_dim
{ \l__tblr_a_tl + \l__tblr_c_tl - \l__tblr_b_tl }
\prop_remove:Nn \l__column_coefficient_prop { ##1 }
}
{
\__tblr_add_dimen_value:Nnn
\l__column_computed_width_prop { ##1 } { \l__tblr_a_tl }
}
}
}
\LogTblrTracing { target }
}
\cs_new_protected:Npn \__tblr_adjust_extendable_column_width_negative:
{
\dim_zero:N \l_tmpa_dim
\prop_map_inline:Nn \l__column_natural_width_prop
{ \dim_add:Nn \l_tmpa_dim { ##2 } }
\tl_set:Nx \l_tmpa_tl
{ \dim_ratio:nn { \l__column_target_dim } { \l_tmpa_dim } }
\dim_zero:N \l__column_target_dim
\prop_map_inline:Nn \l__column_natural_width_prop
{
\tl_set:Nx \l_tmpb_tl { \dim_eval:n { ##2 * \l_tmpa_tl } }
\__tblr_add_dimen_value:Nnn
\l__column_computed_width_prop { ##1 } { \l_tmpb_tl }
}
\LogTblrTracing { target }
}
%%% --------------------------------------------------------
%%> \section{Calculate and Adjust Multispan Cells}
%%% --------------------------------------------------------
%% Compute and adjust widths when there are some span cells.
%% By default, we will compute column widths from span widths;
%% but if we set table option "hspan = minimal",
%% we will compute span widths from column widths.
\cs_new_protected:Npn \__tblr_adjust_sizes_for_span_cells:
{
\__tblr_prop_if_in:nnT { inner } { colspan }
{
\__tblr_collect_column_widths_skips:
\str_if_eq:xnTF
{ \__tblr_prop_item:ne { inner } { hspan } } { minimal }
{
\__tblr_set_span_widths_from_column_widths:
}
{
\__tblr_collect_span_widths:
\__tblr_set_column_widths_from_span_widths:
}
\LogTblrTracing { column }
\__tblr_calculate_cell_sizes:
}
\__tblr_prop_if_in:nnT { inner } { rowspan }
{
\__tblr_collect_row_heights_skips:
\__tblr_collect_span_heights:
\__tblr_set_row_heights_from_span_heights:
\LogTblrTracing { row }
}
}
\prop_new:N \l__tblr_col_item_skip_size_prop
\prop_new:N \l__tblr_col_span_size_prop
\prop_new:N \l__tblr_row_item_skip_size_prop
\prop_new:N \l__tblr_row_span_size_prop
\cs_new_protected:Npn \__tblr_collect_column_widths_skips:
{
\prop_clear:N \l__tblr_col_item_skip_size_prop
\int_step_variable:nNn { \c@colcount } \l__tblr_j_tl
{
\int_compare:nNnTF { \l__tblr_j_tl } > { 1 }
{
\prop_put:Nxx \l__tblr_col_item_skip_size_prop { skip[\l__tblr_j_tl] }
{
\dim_eval:n
{
\__tblr_data_item:nen { column }
{ \int_eval:n { \l__tblr_j_tl - 1 } } { rightsep }
+
\__tblr_spec_item:ne { vline }
{ [\l__tblr_j_tl] / @vline-width }
+
\__tblr_data_item:nen { column } { \l__tblr_j_tl } { leftsep }
}
}
}
{
\prop_put:Nxn \l__tblr_col_item_skip_size_prop { skip[\l__tblr_j_tl] }
{ 0pt }
}
\prop_put:Nxx \l__tblr_col_item_skip_size_prop { item[\l__tblr_j_tl] }
{ \__tblr_data_item:nen { column } { \l__tblr_j_tl } { @col-width } }
}
\__tblr_do_if_tracing:nn { cellspan }
{ \prop_log:N \l__tblr_col_item_skip_size_prop }
}
\cs_new_protected:Npn \__tblr_collect_row_heights_skips:
{
\prop_clear:N \l__tblr_row_item_skip_size_prop
\int_step_variable:nNn { \c@rowcount } \l__tblr_i_tl
{
\int_compare:nNnTF { \l__tblr_i_tl } > { 1 }
{
\prop_put:Nxx \l__tblr_row_item_skip_size_prop { skip[\l__tblr_i_tl] }
{
\dim_eval:n
{
\__tblr_data_item:nen { row }
{ \int_eval:n {\l__tblr_i_tl - 1} } { belowsep }
+
\__tblr_spec_item:ne { hline }
{ [\l__tblr_i_tl] / @hline-height }
+
\__tblr_data_item:nen { row } { \l__tblr_i_tl } { abovesep }
}
}
}
{
\prop_put:Nxn \l__tblr_row_item_skip_size_prop { skip[\l__tblr_i_tl] }
{ 0pt }
}
\__tblr_collect_one_row_height:NN \l__tblr_i_tl \l__tblr_h_tl
\prop_put:Nxx \l__tblr_row_item_skip_size_prop
{ item[\l__tblr_i_tl] } { \l__tblr_h_tl }
}
\__tblr_do_if_tracing:nn { cellspan }
{ \prop_log:N \l__tblr_row_item_skip_size_prop }
}
%% #1: row number; #2: tl with result
\cs_new_protected:Npn \__tblr_collect_one_row_height:NN #1 #2
{
\tl_set:Nx #2 { \__tblr_data_item:nen { row } {#1} { @row-height } }
}
\cs_new_protected:Npn \__tblr_collect_span_widths:
{
\prop_clear:N \l__tblr_col_span_size_prop
\int_step_variable:nNn { \c@colcount } \l__tblr_j_tl
{
\int_step_variable:nNn { \c@rowcount } \l__tblr_i_tl
{
\tl_set:Nx \l__tblr_a_tl
{
\__tblr_data_item:neen { cell }
{ \l__tblr_i_tl } { \l__tblr_j_tl } { colspan }
}
\int_compare:nNnT { \l__tblr_a_tl } > {1}
{
\__tblr_put_if_larger:Nxx \l__tblr_col_span_size_prop
{
( \l__tblr_j_tl -
\int_eval:n {\l__tblr_j_tl + \l__tblr_a_tl - 1} )
}
{
\__tblr_data_item:neen { cell }
{ \l__tblr_i_tl } { \l__tblr_j_tl } { @cell-width }
}
}
}
}
\__tblr_do_if_tracing:nn { cellspan }
{ \prop_log:N \l__tblr_col_span_size_prop }
}
\prop_new:N \l__tblr_row_span_to_row_prop
\cs_new_protected:Npn \__tblr_collect_span_heights:
{
\prop_clear:N \l__tblr_row_span_to_row_prop
\prop_clear:N \l__tblr_row_span_size_prop
\int_step_variable:nNn { \c@rowcount } \l__tblr_i_tl
{
\int_step_variable:nNn { \c@colcount } \l__tblr_j_tl
{
\tl_set:Nx \l__tblr_a_tl
{
\__tblr_data_item:neen { cell }
{ \l__tblr_i_tl } { \l__tblr_j_tl } { rowspan }
}
\int_compare:nNnT { \l__tblr_a_tl } > {1}
{
\tl_set:Nx \l__tblr_v_tl
{
\__tblr_data_item:neen { cell }
{ \l__tblr_i_tl } { \l__tblr_j_tl } { valign }
}
\tl_if_eq:NnT \l__tblr_v_tl { h }
{
\tl_set:Nx \l__tblr_h_tl
{
\__tblr_data_item:nen { row }
{ \l__tblr_i_tl } { @row-head }
}
\__tblr_data_gput:neenV { cell }
{ \l__tblr_i_tl } { \l__tblr_j_tl } { @cell-height }
\l__tblr_h_tl
}
\tl_if_eq:NnT \l__tblr_v_tl { f }
{
\tl_set:Nx \l__tblr_d_tl
{
\__tblr_data_item:nen
{ row }
{ \int_eval:n { \l__tblr_i_tl + \l__tblr_a_tl - 1 } }
{ @row-foot }
}
\__tblr_data_gput:neenV { cell }
{ \l__tblr_i_tl } { \l__tblr_j_tl } { @cell-depth }
\l__tblr_d_tl
}
\__tblr_put_if_larger:Nxx \l__tblr_row_span_size_prop
{
( \l__tblr_i_tl -
\int_eval:n {\l__tblr_i_tl + \l__tblr_a_tl - 1} )
}
{
\dim_eval:n
{
\__tblr_data_item:neen { cell }
{ \l__tblr_i_tl } { \l__tblr_j_tl } { @cell-height }
+
\__tblr_data_item:neen { cell }
{ \l__tblr_i_tl } { \l__tblr_j_tl } { @cell-depth }
}
}
\prop_put:Nxx \l__tblr_row_span_to_row_prop
{ [\l__tblr_i_tl][\l__tblr_j_tl] }
{ \int_eval:n {\l__tblr_i_tl + \l__tblr_a_tl - 1} }
}
}
}
\__tblr_do_if_tracing:nn { cellspan }
{
\prop_log:N \l__tblr_row_span_to_row_prop
\prop_log:N \l__tblr_row_span_size_prop
}
}
%% Compute and set column widths from span widths
\cs_new_protected:Npn \__tblr_set_column_widths_from_span_widths:
{
\str_if_eq:xnTF
{ \__tblr_prop_item:ne { inner } { hspan } }
{ even }
{
\__tblr_distribute_span_sizes_even:xNN
{ \int_use:N \c@colcount }
\l__tblr_col_item_skip_size_prop
\l__tblr_col_span_size_prop
}
{
\__tblr_distribute_span_sizes_default:xNN
{ \int_use:N \c@colcount }
\l__tblr_col_item_skip_size_prop
\l__tblr_col_span_size_prop
}
\__tblr_set_all_column_widths:
}
%% Compute and set row heights from span heights
\cs_new_protected:Npn \__tblr_set_row_heights_from_span_heights:
{
\str_if_eq:xnTF
{ \__tblr_prop_item:ne { inner } { vspan } }
{ even }
{
\__tblr_distribute_span_sizes_even:nNN
{ \int_use:N \c@rowcount }
\l__tblr_row_item_skip_size_prop
\l__tblr_row_span_size_prop
}
{
\__tblr_distribute_span_sizes_default:xNN
{ \int_use:N \c@rowcount }
\l__tblr_row_item_skip_size_prop
\l__tblr_row_span_size_prop
}
\__tblr_set_all_row_heights:
}
%% See page 245 in Chapter 22 of TeXbook
%% #1: total number of items
%% #2: prop list with item sizes and skip sizes; #3: prop list with span sizes
\cs_new_protected:Npn \__tblr_distribute_span_sizes_default:nNN #1 #2 #3
{
\int_step_variable:nNn { #1 } \l__tblr_j_tl
{
\dim_set:Nn \l__tblr_w_dim
{
\prop_item:Ne #2 { item[\l__tblr_j_tl] }
}
\int_step_variable:nNn { \l__tblr_j_tl - 1 } \l__tblr_i_tl
{
\tl_set:Nx \l__tblr_a_tl
{ \prop_item:Ne #3 { (\l__tblr_i_tl-\l__tblr_j_tl) } }
\tl_if_empty:NF \l__tblr_a_tl
{
\int_step_variable:nnNn
{ \l__tblr_i_tl } { \l__tblr_j_tl - 1 } \l__tblr_k_tl
{
\__tblr_do_if_tracing:nn { cellspan }
{
\tl_log:x
{ \l__tblr_j_tl : \l__tblr_i_tl -> \l__tblr_k_tl }
}
\tl_set:Nx \l_tmpa_tl
{
\prop_item:Ne #2 { itemskip[\l__tblr_k_tl] }
}
\tl_set:Nx \l__tblr_a_tl
{ \dim_eval:n { \l__tblr_a_tl - \l_tmpa_tl } }
}
\dim_compare:nNnT { \l__tblr_a_tl } > { \l__tblr_w_dim }
{
\dim_set:Nn \l__tblr_w_dim { \l__tblr_a_tl }
}
}
}
\prop_put:Nxx #2
{ item[\l__tblr_j_tl] } { \dim_use:N \l__tblr_w_dim }
\int_compare:nNnT { \l__tblr_j_tl } < { #1 }
{
\tl_set:Nx \l_tmpb_tl
{
\prop_item:Ne #2
{ skip[\int_eval:n { \l__tblr_j_tl + 1} ] }
}
\dim_add:Nn \l__tblr_w_dim { \l_tmpb_tl }
\prop_put:Nxx #2
{ itemskip[\l__tblr_j_tl] } { \dim_use:N \l__tblr_w_dim }
}
}
\__tblr_do_if_tracing:nn { cellspan } { \prop_log:N #2 }
}
\cs_generate_variant:Nn \__tblr_distribute_span_sizes_default:nNN { x }
%% #1: total number of items
%% #2: prop list with item sizes and skip sizes; #3: prop list with span sizes
\cs_new_protected:Npn \__tblr_distribute_span_sizes_even:nNN #1 #2 #3
{
\prop_clear:N \l_tmpa_prop
\prop_map_inline:Nn #3
{
\__tblr_get_span_from_to:w ##1
\dim_set:Nn \l_tmpa_dim {##2}
\dim_sub:Nn \l_tmpa_dim { \prop_item:Ne #2 { item[\l__tblr_a_tl] } }
\int_step_inline:nnn { \l__tblr_a_tl + 1 } { \l__tblr_b_tl }
{
\dim_sub:Nn \l_tmpa_dim
{
\prop_item:Ne #2 { skip[####1] } + \prop_item:Nn #2 { item[####1] }
}
}
\__tblr_do_if_tracing:nn { cellspan }
{
\tl_log:x { \l__tblr_a_tl -> \l__tblr_b_tl : ~ \dim_use:N \l_tmpa_dim }
}
\dim_compare:nNnT {\l_tmpa_dim} > {0pt}
{
\tl_set:Nx \l_tmpa_tl
{ \dim_eval:n { \l_tmpa_dim / (\l__tblr_b_tl - \l__tblr_a_tl + 1) } }
\int_step_inline:nnn { \l__tblr_a_tl } { \l__tblr_b_tl }
{
\__tblr_put_if_larger:NnV \l_tmpa_prop {####1} \l_tmpa_tl
}
}
}
\__tblr_do_if_tracing:nn { cellspan } { \prop_log:N \l_tmpa_prop }
\prop_map_inline:Nn \l_tmpa_prop
{
\__tblr_add_dimen_value:Nnn #2 {item[##1]} {##2}
}
\__tblr_do_if_tracing:nn { cellspan } { \prop_log:N #2 }
}
\cs_generate_variant:Nn \__tblr_distribute_span_sizes_even:nNN { x }
\cs_new_protected:Npn \__tblr_get_span_from_to:w (#1-#2)
{
\tl_set:Nn \l__tblr_a_tl {#1}
\tl_set:Nn \l__tblr_b_tl {#2}
}
\cs_new_protected:Npn \__tblr_set_all_column_widths:
{
\int_step_variable:nNn { \c@colcount } \l__tblr_j_tl
{
\__tblr_data_gput:nene { column }
{ \l__tblr_j_tl } { width }
{ \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[\l__tblr_j_tl] } }
}
}
\cs_new_protected:Npn \__tblr_set_all_row_heights:
{
\int_step_variable:nNn { \c@rowcount } \l__tblr_i_tl
{
\tl_set:Nx \l__tblr_h_tl
{
\__tblr_data_item:nen { row } { \l__tblr_i_tl } { @row-head }
}
\tl_set:Nx \l__tblr_d_tl
{
\__tblr_data_item:nen { row } { \l__tblr_i_tl } { @row-foot }
}
\tl_set:Nx \l__tblr_a_tl
{
\prop_item:Ne \l__tblr_row_item_skip_size_prop { item[\l__tblr_i_tl] }
}
\__tblr_collect_one_row_height:NN \l__tblr_i_tl \l__tblr_t_tl
\__tblr_data_gput:nene { row }
{ \l__tblr_i_tl } { @row-height } { \l__tblr_a_tl }
}
}
%% Compute and set span widths from column widths
\cs_new_protected:Npn \__tblr_set_span_widths_from_column_widths:
{
\int_step_variable:nNn { \c@colcount } \l__tblr_j_tl
{
\int_step_variable:nNn { \c@rowcount } \l__tblr_i_tl
{
\tl_set:Nx \l__tblr_a_tl
{
\__tblr_data_item:neen { cell }
{ \l__tblr_i_tl } { \l__tblr_j_tl } { colspan }
}
\int_compare:nNnT { \l__tblr_a_tl } > {1}
{
\__tblr_calc_span_widths:xxN
{ \l__tblr_j_tl }
{ \int_eval:n { \l__tblr_j_tl + \l__tblr_a_tl - 1 } }
\l__tblr_w_dim
\__tblr_data_gput:neene { cell }
{ \l__tblr_i_tl } { \l__tblr_j_tl } { width }
{ \dim_use:N \l__tblr_w_dim }
}
}
}
}
%% Cell is spanned from col #1 to col #2, #3 is the return dim
\cs_new_protected:Npn \__tblr_calc_span_widths:nnN #1 #2 #3
{
\dim_set:Nn #3 { \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[#1] } }
\int_step_inline:nnn { #1 + 1 } { #2 }
{
\tl_set:Nx \l_tmpa_tl
{ \prop_item:Ne \l__tblr_col_item_skip_size_prop { skip[##1] } }
\tl_set:Nx \l_tmpb_tl
{ \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[##1] } }
\dim_add:Nn #3 { \dim_eval:n { \l_tmpa_tl + \l_tmpb_tl } }
}
}
\cs_generate_variant:Nn \__tblr_calc_span_widths:nnN { xxN }
%%% --------------------------------------------------------
%%> \section{Header and Footer Styles}
%%% --------------------------------------------------------
\prop_new:N \l__tblr_element_styles_prop
\cs_new_protected:Npn \__tblr_style_put:nn #1 #2
{
\prop_put:Nnn \l__tblr_element_styles_prop {#1} {#2}
}
\cs_generate_variant:Nn \__tblr_style_put:nn { nV, ne, en, eV }
\cs_new:Npn \__tblr_style_item:n #1
{
\prop_item:Nn \l__tblr_element_styles_prop {#1}
}
\cs_new_protected:Npn \__tblr_style_log:
{
\prop_log:N \l__tblr_element_styles_prop
}
\tl_new:N \l__tblr_element_name_tl
\tl_new:N \l__tblr_element_styles_tl
%% #1: list of element names; #2: element styles
\NewDocumentCommand \SetTblrStyle { m +m }
{
\tl_set:Nn \l__tblr_element_styles_tl {#2}
\keys_set:nn { tblr-element } {#1}
\ignorespaces
}
\keys_define:nn { tblr-element }
{
head .meta:n = { firsthead, middlehead, lasthead },
foot .meta:n = { firstfoot, middlefoot, lastfoot },
unknown .code:n = \__tblr_set_element_styles:V \l_keys_key_str,
}
\cs_new_protected:Npn \__tblr_set_element_styles:n #1
{
\tl_set:Nn \l__tblr_element_name_tl {#1}
\keys_set:nV { tblr-style } \l__tblr_element_styles_tl
}
\cs_generate_variant:Nn \__tblr_set_element_styles:n { V }
\keys_define:nn { tblr-style }
{
halign .code:n = \__tblr_element_gput_style:nn { halign } {#1},
l .meta:n = { halign = l },
c .meta:n = { halign = c },
r .meta:n = { halign = r },
j .meta:n = { halign = j },
fg .code:n = \__tblr_element_gput_style:nn { fg } {#1},
font .code:n = \__tblr_element_gput_style:nn { font } {#1},
hang .code:n = \__tblr_element_gput_style:nn { hang } {#1},
indent .code:n = \__tblr_element_gput_style:nn { indent } {#1},
unknown .code:n = \__tblr_element_unknown_key:Vn \l_keys_key_str {#1},
}
\cs_new_protected:Npn \__tblr_element_gput_style:nn #1 #2
{
\__tblr_style_put:en { \l__tblr_element_name_tl / #1 } {#2}
}
\cs_new_protected:Npn \__tblr_element_unknown_key:nn #1 #2
{
\regex_match:NnTF \c__tblr_is_color_key_regex {#1}
{ \__tblr_style_put:en { \l__tblr_element_name_tl / fg } {#1} }
{
%% unknown key name has been changed to string in \l_keys_key_str
\tl_set_rescan:Nnn \l__tblr_f_tl {} {#1}
\tl_if_head_eq_catcode:VNTF \l__tblr_f_tl \scan_stop:
{
\__tblr_style_put:eV { \l__tblr_element_name_tl / font } \l__tblr_f_tl
}
{
\__tblr_style_put:en { \l__tblr_element_name_tl / #1 } {#2}
}
}
}
\cs_generate_variant:Nn \__tblr_element_unknown_key:nn { Vn }
%%% --------------------------------------------------------
%%> \section{Helper Functions for Templates}
%%% --------------------------------------------------------
\tl_new:N \l__tblr_template_name_tl
\tl_new:N \l__tblr_template_code_tl
\keys_define:nn { tblr-def-template }
{
unknown .code:n = \__tblr_def_template:V \l_keys_key_str,
}
%% #1: head/foot element; #2: template name; #3: template code
%% If the template name = default, we enable the template at once
%% Otherwise, we may enable the template by using \SetTblrTemplate command
\NewDocumentCommand \DefTblrTemplate { m m +m }
{
\tl_set:Nn \l__tblr_template_name_tl {#2}
\tl_set:Nn \l__tblr_template_code_tl {#3}
\keys_set:nn { tblr-def-template } {#1}
\ignorespaces
}
\cs_new_eq:NN \DeclareTblrTemplate \DefTblrTemplate
\cs_new_protected:Npn \__tblr_def_template:n #1
{
\tl_set_eq:cN { l__tblr_template_ #1 _ \l__tblr_template_name_tl _tl }
\l__tblr_template_code_tl
}
\cs_generate_variant:Nn \__tblr_def_template:n { V }
\keys_define:nn { tblr-set-template }
{
unknown .code:n = \__tblr_set_template:V \l_keys_key_str,
}
%% #1: head/foot element; #2: template name
\NewDocumentCommand \SetTblrTemplate { m m }
{
\tl_set:Nn \l__tblr_template_name_tl {#2}
\keys_set:nn { tblr-set-template } {#1}
\ignorespaces
}
\cs_new_protected:Npn \__tblr_set_template:n #1
{
\tl_set_eq:cc { l__tblr_template_ #1 _default_tl }
{ l__tblr_template_ #1 _ \l__tblr_template_name_tl _tl }
}
\cs_generate_variant:Nn \__tblr_set_template:n { V }
\NewExpandableDocumentCommand \GetTblrStyle { m m }
{
\__tblr_style_item:n { #1 / #2 }
}
\NewDocumentCommand \UseTblrFont { m }
{
\GetTblrStyle {#1} { font } \selectfont
}
\tl_new:N \l__tblr_use_color_tl
\NewDocumentCommand \UseTblrColor { m }
{
\tl_set:Nx \l__tblr_use_color_tl { \GetTblrStyle {#1} { fg } }
\tl_if_empty:NF \l__tblr_use_color_tl { \color { \l__tblr_use_color_tl } }
}
%% All halign commands are defined at the beginning of the file
\NewDocumentCommand \UseTblrAlign { m }
{
\use:c { __tblr_halign_command_ \GetTblrStyle {#1} { halign } : }
}
\tl_new:N \l__tblr_use_hang_tl
\NewDocumentCommand \UseTblrHang { m }
{
\tl_set:Nx \l__tblr_use_hang_tl { \GetTblrStyle {#1} { hang } }
\tl_if_empty:NF \l__tblr_use_hang_tl
{
\tl_put_left:Nn \l__tblr_use_hang_tl
{ \hangafter = 1 \relax \hangindent = }
\tl_put_right:Nn \l__tblr_use_hang_tl { \relax }
\exp_args:NV \everypar \l__tblr_use_hang_tl
}
}
\tl_new:N \l__tblr_use_indent_tl
\NewDocumentCommand \UseTblrIndent { m }
{
\tl_set:Nx \l__tblr_use_indent_tl { \GetTblrStyle {#1} { indent } }
\tl_if_empty:NF \l__tblr_use_indent_tl
{ \exp_args:NNV \setlength \parindent \l__tblr_use_indent_tl }
}
\AtBeginDocument
{
\@ifpackageloaded{xcolor}{}{\RenewDocumentCommand \UseTblrColor {m} {}}
}
%% #1: head/foot element; #2: template name
\NewExpandableDocumentCommand \ExpTblrTemplate { m m }
{
\tl_use:c { l__tblr_template_ #1 _ #2 _tl }
}
%% #1: head/foot element; #2: template name
\NewDocumentCommand \UseTblrTemplate { m m }
{
\group_begin:
\UseTblrFont {#1}
\UseTblrColor {#1}
\tl_use:c { l__tblr_template_ #1 _ #2 _tl }
\group_end:
}
\NewDocumentCommand \MapTblrNotes { +m }
{
\__tblr_prop_map_inline:nn { note }
{
\tl_set_rescan:Nnn \InsertTblrNoteTag {} {##1}
\tl_set:Nn \InsertTblrNoteText {##2}
#1
}
}
\NewDocumentCommand \MapTblrRemarks { +m }
{
\__tblr_prop_map_inline:nn { remark }
{
\tl_set_rescan:Nnn \InsertTblrRemarkTag {} {##1}
\tl_set:Nn \InsertTblrRemarkText {##2}
#1
}
}
\NewExpandableDocumentCommand \InsertTblrText { m }
{
\__tblr_spec_item:nn { outer } {#1}
}
\NewExpandableDocumentCommand \InsertTblrMore { m }
{
\__tblr_prop_item:nn { more } {#1}
}
%%% --------------------------------------------------------
%%> \section{Table Continuation Templates}
%%% --------------------------------------------------------
\tl_if_exist:NF \tblrcontfootname
{
\tl_set:Nn \tblrcontfootname { Continued ~ on ~ next ~ page }
}
\tl_if_exist:NF \tblrcontheadname
{
\tl_set:Nn \tblrcontheadname { ( Continued ) }
}
\DefTblrTemplate { contfoot-text } { normal } { \tblrcontfootname }
\SetTblrTemplate { contfoot-text } { normal }
\DefTblrTemplate { contfoot } { empty } { }
\DefTblrTemplate { contfoot } { plain }
{
\noindent
\raggedleft
\UseTblrTemplate { contfoot-text } { default }
\par
}
\DefTblrTemplate { contfoot } { normal }
{
%% need to set parindent after alignment
\raggedleft
\UseTblrAlign { contfoot }
\UseTblrIndent { contfoot }
\UseTblrHang { contfoot }
\leavevmode
\UseTblrTemplate { contfoot-text } { default }
\par
}
\SetTblrTemplate { contfoot } { normal }
\DefTblrTemplate { conthead-pre } { empty } { }
\DefTblrTemplate { conthead-pre } { normal } { \space }
\SetTblrTemplate { conthead-pre } { normal }
\DefTblrTemplate { conthead-text } { normal } { \tblrcontheadname }
\SetTblrTemplate { conthead-text } { normal }
\DefTblrTemplate { conthead } { empty } { }
\DefTblrTemplate { conthead } { plain }
{
\noindent
\raggedright
\UseTblrTemplate { conthead-text } { default }
\par
}
\DefTblrTemplate { conthead } { normal }
{
%% need to set parindent after alignment
\raggedright
\UseTblrAlign { conthead }
\UseTblrIndent { conthead }
\UseTblrHang { conthead }
\leavevmode
\UseTblrTemplate { conthead-text } { default }
\par
}
\SetTblrTemplate { conthead } { normal }
%%% --------------------------------------------------------
%%> \section{Table Caption Templates}
%%% --------------------------------------------------------
\tl_new:N \l__tblr_caption_short_tl
\DefTblrTemplate { caption-lot } { empty } { }
\DefTblrTemplate { caption-lot } { normal }
{
\tl_if_empty:NTF \lTblrEntryTl
{ \tl_set_eq:NN \l__tblr_caption_short_tl \lTblrCaptionTl }
{ \tl_set_eq:NN \l__tblr_caption_short_tl \lTblrEntryTl }
\addcontentsline { lot } { table }
{ \protect\numberline { \thetable } { \l__tblr_caption_short_tl } }
}
\SetTblrTemplate { caption-lot } { normal }
%% We need to use \hspace and \enskip, but not ~ or \space,
%% since we want a correct hangindent caption paragraph.
\DefTblrTemplate { caption-tag } { empty } { }
\DefTblrTemplate { caption-tag } { normal } { \tablename\hspace{0.25em}\thetable }
\SetTblrTemplate { caption-tag } { normal }
\DefTblrTemplate { caption-sep } { empty } { }
\DefTblrTemplate { caption-sep } { normal } { : \enskip }
\SetTblrTemplate { caption-sep } { normal }
\DefTblrTemplate { caption-text } { empty } { }
\DefTblrTemplate { caption-text } { normal } { \InsertTblrText { caption } }
\SetTblrTemplate { caption-text } { normal }
\box_new:N \l__tblr_caption_box
\box_new:N \l__tblr_caption_left_box
\DefTblrTemplate { caption } { empty } { }
\DefTblrTemplate { caption } { plain }
{
\hbox_set:Nn \l__tblr_caption_box
{
\UseTblrTemplate { caption-tag } { default }
\UseTblrTemplate { caption-sep } { default }
\UseTblrTemplate { caption-text } { default }
}
\dim_compare:nNnTF { \box_wd:N \l__tblr_caption_box } > { \hsize }
{
\noindent
\hbox_unpack:N \l__tblr_caption_box
\par
}
{
\centering
\makebox [\hsize] [c] { \box_use:N \l__tblr_caption_box }
\par
}
}
\DefTblrTemplate { caption } { normal }
{
\hbox_set:Nn \l__tblr_caption_box
{
\UseTblrTemplate { caption-tag } { default }
\UseTblrTemplate { caption-sep } { default }
\UseTblrTemplate { caption-text } { default }
}
\dim_compare:nNnTF { \box_wd:N \l__tblr_caption_box } > { \hsize }
{
\UseTblrAlign { caption }
\UseTblrIndent { caption }
\hbox_set:Nn \l__tblr_caption_left_box
{
\UseTblrTemplate { caption-tag } { default }
\UseTblrTemplate { caption-sep } { default }
}
\hangindent = \box_wd:N \l__tblr_caption_left_box
\hangafter = 1
\UseTblrHang { caption }
\leavevmode
\hbox_unpack:N \l__tblr_caption_box
\par
}
{
\centering
\makebox [\hsize] [c] { \box_use:N \l__tblr_caption_box }
\par
}
}
\DefTblrTemplate { caption } { simple }
{
\UseTblrAlign { caption }
\UseTblrIndent { caption }
\UseTblrHang { caption }
\leavevmode
\UseTblrTemplate { caption-tag } { default }
\UseTblrTemplate { caption-sep } { default }
\UseTblrTemplate { caption-text } { default }
\par
}
\SetTblrTemplate { caption } { normal }
\DefTblrTemplate { capcont } { empty } { }
\DefTblrTemplate { capcont } { plain }
{
\hbox_set:Nn \l__tblr_caption_box
{
\UseTblrTemplate { caption-tag } { default }
\UseTblrTemplate { caption-sep } { default }
\UseTblrTemplate { caption-text } { default }
\UseTblrTemplate { conthead-pre } { default }
\UseTblrTemplate { conthead-text } { default }
}
\dim_compare:nNnTF { \box_wd:N \l__tblr_caption_box } > { \hsize }
{
\noindent
\hbox_unpack:N \l__tblr_caption_box
\par
}
{
\centering
\makebox [\hsize] [c] { \box_use:N \l__tblr_caption_box }
\par
}
}
\DefTblrTemplate { capcont } { normal }
{
\hbox_set:Nn \l__tblr_caption_box
{
\UseTblrTemplate { caption-tag } { default }
\UseTblrTemplate { caption-sep } { default }
\UseTblrTemplate { caption-text } { default }
\UseTblrTemplate { conthead-pre } { default }
\UseTblrTemplate { conthead-text } { default }
}
\dim_compare:nNnTF { \box_wd:N \l__tblr_caption_box } > { \hsize }
{
\UseTblrAlign { capcont }
\UseTblrIndent { capcont }
\hbox_set:Nn \l__tblr_caption_left_box
{
\UseTblrTemplate { caption-tag } { default }
\UseTblrTemplate { caption-sep } { default }
}
\hangindent = \box_wd:N \l__tblr_caption_left_box
\hangafter = 1
\UseTblrHang { capcont }
\leavevmode
\hbox_unpack:N \l__tblr_caption_box
\par
}
{
\centering
\makebox [\hsize] [c] { \box_use:N \l__tblr_caption_box }
\par
}
}
\DefTblrTemplate { capcont } { simple }
{
\UseTblrAlign { caption }
\UseTblrIndent { caption }
\UseTblrHang { caption }
\leavevmode
\UseTblrTemplate { caption-tag } { default }
\UseTblrTemplate { caption-sep } { default }
\UseTblrTemplate { caption-text } { default }
\UseTblrTemplate { conthead-pre } { default }
\UseTblrTemplate { conthead-text } { default }
\par
}
\SetTblrTemplate { capcont} { normal }
%%% --------------------------------------------------------
%%> \section{Table Notes Templates}
%%% --------------------------------------------------------
%% By default the targets generated by \hypertarget are too low
%% Therefore we need to use \Hy@raisedlink command to fix this problem
%% See https://tex.stackexchange.com/questions/17057
%% We also use \use:c in case the private command \Hy@raisedlink is removed
\cs_new_protected:Npn \__tblr_hyper_target:n #1
{
\cs_if_exist:NT \hypertarget
{
\use:c { Hy@raisedlink }
{
\hypertarget
{ tblr / \int_use:N \g__tblr_table_count_int / \tl_to_str:n {#1} }
{ }
}
}
}
\cs_generate_variant:Nn \__tblr_hyper_target:n { V }
\cs_new_protected:Npn \__tblr_hyper_link:nn #1 #2
{
\cs_if_exist:NTF \hyperlink
{
\hyperlink
{ tblr / \int_use:N \g__tblr_table_count_int / \tl_to_str:n {#1} }
{ #2 }
}
{ #2 }
}
\DefTblrTemplate { note-border } { empty }
{
\hypersetup { pdfborder = { 0 ~ 0 ~ 0 } }
}
\DefTblrTemplate { note-border } { normal }
{
\hypersetup { pdfborder = { 0 ~ 0 ~ 1 } }
}
\SetTblrTemplate { note-border } { empty }
\cs_set_eq:NN \TblrOverlap \rlap
\NewDocumentCommand \TblrNote { m }
{
\cs_if_exist:NT \hypersetup { \ExpTblrTemplate { note-border }{ default } }
\TblrOverlap
{
\__tblr_hyper_link:nn {#1}
{ \textsuperscript { \sffamily \UseTblrFont { note-tag } #1 } }
}
}
\DefTblrTemplate { note-tag } { empty } { }
\DefTblrTemplate { note-tag } { normal }
{
\textsuperscript { \sffamily \UseTblrFont { note-tag } \InsertTblrNoteTag }
}
\SetTblrTemplate { note-tag } { normal }
\DefTblrTemplate { note-target } { normal }
{
\__tblr_hyper_target:V \InsertTblrNoteTag
}
\SetTblrTemplate { note-target } { normal }
\DefTblrTemplate { note-sep } { empty } { }
\DefTblrTemplate { note-sep } { normal } { \space }
\SetTblrTemplate { note-sep } { normal }
\DefTblrTemplate { note-text } { empty } { }
\DefTblrTemplate { note-text } { normal } { \InsertTblrNoteText }
\SetTblrTemplate { note-text } { normal }
\DefTblrTemplate { note } { empty } { }
\DefTblrTemplate { note } { plain }
{
\MapTblrNotes
{
\noindent
\UseTblrTemplate { note-tag } { default }
\UseTblrTemplate { note-target } { default }
\UseTblrTemplate { note-sep } { default }
\UseTblrTemplate { note-text } { default }
\par
}
}
\DefTblrTemplate { note } { normal }
{
\UseTblrAlign { note }
\UseTblrIndent { note }
\MapTblrNotes
{
\hangindent = 0.7em
\hangafter = 1
\UseTblrHang { note }
\leavevmode
\hbox_to_wd:nn { \the\hangindent }
{
\UseTblrTemplate { note-tag } { default }
\UseTblrTemplate { note-target } { default }
\hfil
}
\UseTblrTemplate { note-text } { default }
\par
}
}
\DefTblrTemplate { note } { inline }
{
\UseTblrAlign { note }
\UseTblrIndent { note }
\UseTblrHang { note }
\leavevmode
\MapTblrNotes
{
\UseTblrTemplate { note-tag } { default }
\UseTblrTemplate { note-target } { default }
\UseTblrTemplate { note-sep } { default }
\UseTblrTemplate { note-text } { default }
\quad
}
\par
}
\SetTblrTemplate { note } { normal }
%%% --------------------------------------------------------
%%> \section{Table Remarks Templates}
%%% --------------------------------------------------------
\DefTblrTemplate { remark-tag } { empty } { }
\DefTblrTemplate { remark-tag } { normal }
{
\itshape \UseTblrFont { remark-tag } \InsertTblrRemarkTag
}
\SetTblrTemplate { remark-tag } { normal }
\DefTblrTemplate { remark-sep } { empty } { }
\DefTblrTemplate { remark-sep } { normal } { : \space }
\SetTblrTemplate { remark-sep } { normal }
\DefTblrTemplate { remark-text } { empty } { }
\DefTblrTemplate { remark-text } { normal } { \InsertTblrRemarkText }
\SetTblrTemplate { remark-text } { normal }
\DefTblrTemplate { remark } { empty } { }
\DefTblrTemplate { remark } { plain }
{
\MapTblrRemarks
{
\noindent
\UseTblrTemplate { remark-tag } { default }
\UseTblrTemplate { remark-sep } { default }
\UseTblrTemplate { remark-text } { default }
\par
}
}
\DefTblrTemplate { remark } { normal }
{
\UseTblrAlign { remark }
\UseTblrIndent { remark }
\MapTblrRemarks
{
\hangindent = 0.7em
\hangafter = 1
\UseTblrHang { remark }
\leavevmode
\UseTblrTemplate { remark-tag } { default }
\UseTblrTemplate { remark-sep } { default }
\UseTblrTemplate { remark-text } { default }
\par
}
}
\DefTblrTemplate { remark } { inline }
{
\UseTblrAlign { remark }
\UseTblrIndent { remark }
\UseTblrHang { remark }
\leavevmode
\MapTblrRemarks
{
\UseTblrTemplate { remark-tag } { default }
\UseTblrTemplate { remark-sep } { default }
\UseTblrTemplate { remark-text } { default }
\quad
}
\par
}
\SetTblrTemplate { remark } { normal }
%%% --------------------------------------------------------
%%> \section{Header and Footer Templates}
%%% --------------------------------------------------------
\tl_new:N \g__tblr_template_firsthead_default_tl
\tl_new:N \g__tblr_template_middlehead_default_tl
\tl_new:N \g__tblr_template_lasthead_default_tl
\tl_new:N \g__tblr_template_firstfoot_default_tl
\tl_new:N \g__tblr_template_middlefoot_default_tl
\tl_new:N \g__tblr_template_lastfoot_default_tl
\keys_define:nn { tblr-def-template }
{
head .meta:n = { firsthead, middlehead, lasthead },
foot .meta:n = { firstfoot, middlefoot, lastfoot },
}
\keys_define:nn { tblr-set-template }
{
head .meta:n = { firsthead, middlehead, lasthead },
foot .meta:n = { firstfoot, middlefoot, lastfoot },
}
\DefTblrTemplate { head } { empty } { }
\DefTblrTemplate { foot } { empty } { }
\DefTblrTemplate { firsthead } { normal }
{
\UseTblrTemplate { caption } { default }
}
\DefTblrTemplate { middlehead, lasthead } { normal }
{
\UseTblrTemplate { capcont } { default }
}
\DefTblrTemplate { firstfoot, middlefoot } { normal }
{
\UseTblrTemplate { contfoot } { default }
}
\DefTblrTemplate { lastfoot } { normal }
{
\UseTblrTemplate { note } { default }
\UseTblrTemplate { remark } { default }
}
\SetTblrTemplate { head } { normal }
\SetTblrTemplate { foot } { normal }
%%% --------------------------------------------------------
%%> \section{Build the Whole Table}
%%% --------------------------------------------------------
\cs_new:Npn \__tblr_box_height:N #1
{
\dim_eval:n { \box_ht:N #1 + \box_dp:N #1 }
}
\cs_new_protected:Npn \__tblr_build_head_foot:
{
\__tblr_build_row_head_foot:
\__tblr_build_table_head_foot:
}
\tl_new:N \l__tblr_row_head_tl
\tl_new:N \l__tblr_row_foot_tl
\box_new:N \l__tblr_row_head_box
\box_new:N \l__tblr_row_foot_box
\dim_new:N \l__tblr_row_head_foot_dim
\cs_new_protected:Npn \__tblr_build_row_head_foot:
{
%% \l__tblr_row_head_tl and \l__tblr_row_foot_tl may be empty
\tl_set:Nx \l__tblr_row_head_tl { \__tblr_prop_item:ne { inner } { rowhead } }
\int_compare:nNnTF { \l__tblr_row_head_tl + 0 } > { 0 }
{
\__tblr_build_one_table:nnNN {1} { \l__tblr_row_head_tl }
\c_true_bool \c_true_bool
}
{ \__tblr_build_one_hline:n {1} }
\box_set_eq:NN \l__tblr_row_head_box \l__tblr_table_box
\tl_set:Nx \l__tblr_row_foot_tl { \__tblr_prop_item:ne { inner } { rowfoot } }
\int_compare:nNnTF { \l__tblr_row_foot_tl + 0 } > { 0 }
{
\__tblr_build_one_table:nnNN
{ \c@rowcount - \l__tblr_row_foot_tl + 1 } { \c@rowcount }
\c_true_bool \c_true_bool
}
{ \__tblr_build_one_hline:n { \int_eval:n { \c@rowcount + 1 } } }
\box_set_eq:NN \l__tblr_row_foot_box \l__tblr_table_box
\dim_set:Nn \l__tblr_row_head_foot_dim
{
\__tblr_box_height:N \l__tblr_row_head_box
+ \__tblr_box_height:N \l__tblr_row_foot_box
}
}
\dim_new:N \tablewidth
\cs_new_protected:Npn \__tblr_get_table_width:
{
\dim_zero:N \tablewidth
\int_step_inline:nn { \c@colcount }
{
\dim_add:Nn \tablewidth
{
\__tblr_spec_item:nn { vline } { [##1] / @vline-width }
+
\__tblr_data_item:nnn { column } {##1} { leftsep }
+
\__tblr_data_item:nnn { column } {##1} { @col-width }
+
\__tblr_data_item:nnn { column } {##1} { rightsep }
}
}
\dim_add:Nn \tablewidth
{
\__tblr_spec_item:ne { vline }
{ [\int_eval:n { \c@colcount + 1 }] / @vline-width }
}
}
\box_new:N \l__tblr_table_firsthead_box
\box_new:N \l__tblr_table_middlehead_box
\box_new:N \l__tblr_table_lasthead_box
\box_new:N \l__tblr_table_firstfoot_box
\box_new:N \l__tblr_table_middlefoot_box
\box_new:N \l__tblr_table_lastfoot_box
\cs_new_protected:Npn \__tblr_build_table_head_foot:
{
\__tblr_get_table_width:
% make each of \lTblrCaptionTl, \lTblrEntryTl, \lTblrLabelTl and the
% three corresponding booleans available in all head-foot templates
\__tblr_set_table_label_entry:
\__tblr_build_table_head_aux:Nn \l__tblr_table_firsthead_box
{
\__tblr_build_table_label_entry:
\UseTblrTemplate { firsthead } { default }
}
\__tblr_build_table_head_aux:Nn \l__tblr_table_middlehead_box
{
\UseTblrTemplate { middlehead } { default }
}
\__tblr_build_table_head_aux:Nn \l__tblr_table_lasthead_box
{
\UseTblrTemplate { lasthead } { default }
}
\__tblr_build_table_foot_aux:Nn \l__tblr_table_firstfoot_box
{
\UseTblrTemplate { firstfoot } { default }
}
\__tblr_build_table_foot_aux:Nn \l__tblr_table_middlefoot_box
{
\UseTblrTemplate { middlefoot } { default }
}
\__tblr_build_table_foot_aux:Nn \l__tblr_table_lastfoot_box
{
\UseTblrTemplate { lastfoot } { default }
}
}
\bool_new:N \l__tblr_table_no_title_bool
\bool_new:N \l__tblr_table_no_entry_bool
\bool_new:N \l__tblr_table_no_label_bool
\tl_const:Nn \c_tblr_none_tl { none }
\cs_new_protected:Npn \__tblr_set_table_label_entry:
{
\tl_set:Nx \lTblrCaptionTl { \InsertTblrText { caption } }
\tl_set:Nx \lTblrEntryTl { \InsertTblrText { entry } }
\tl_set:Nx \lTblrLabelTl { \InsertTblrText { label } }
\bool_set:Nn \l__tblr_table_no_title_bool
{ \tl_if_empty_p:N \lTblrCaptionTl }
\bool_set:Nn \l__tblr_table_no_entry_bool
{ \tl_if_eq_p:NN \lTblrEntryTl \c_tblr_none_tl }
\bool_set:Nn \l__tblr_table_no_label_bool
{ \tl_if_eq_p:NN \lTblrLabelTl \c_tblr_none_tl }
\bool_if:NT \l__tblr_table_no_title_bool
{
\SetTblrTemplate { conthead-pre } { empty }
}
\bool_if:NT \l__tblr_table_no_label_bool
{
\SetTblrTemplate { caption-tag }{ empty }
\SetTblrTemplate { caption-sep }{ empty }
}
}
\cs_new_protected:Npn \__tblr_build_tall_table_head_foot:
{
\__tblr_get_table_width:
\__tblr_set_table_label_entry:
\__tblr_build_table_head_aux:Nn \l__tblr_table_firsthead_box
{
\__tblr_build_table_label_entry:
\UseTblrTemplate { firsthead } { default }
}
\__tblr_build_table_foot_aux:Nn
\l__tblr_table_lastfoot_box { \UseTblrTemplate { lastfoot } { default } }
}
\tl_new:N \lTblrCaptionTl
\tl_new:N \lTblrEntryTl
\tl_new:N \lTblrLabelTl
\clist_new:N \lTblrRefMoreClist
\cs_new_protected:Npn \__tblr_build_table_label_entry:
{
\bool_if:NF \l__tblr_table_no_label_bool
{
\refstepcounter { table }
\tl_if_empty:NF \lTblrLabelTl
{
\clist_map_inline:Nn \lTblrRefMoreClist
{ \ExpTblrTemplate { caption-ref } { ##1 } }
\exp_args:NV \label \lTblrLabelTl
}
}
%% We put caption-lot code at last, so that a user can modify \lTblrEntryTl
%% in a caption-label template. For example, a user may want to use
%% short caption in nameref, but at the same time not to add LoT entry.
\bool_if:NF \l__tblr_table_no_entry_bool
{ \UseTblrTemplate { caption-lot } { default } }
}
\cs_new_protected:Npn \__tblr_build_table_head_aux:Nn #1 #2
{
\vbox_set:Nn #1
{
\hsize = \tablewidth
\TblrParboxRestore % it will set \linewidth = \hsize
\vbox_set:Nn \l_tmpa_box {#2}
\box_use:N \l_tmpa_box
\dim_compare:nNnT
{ \box_ht:N \l_tmpa_box + \box_dp:N \l_tmpa_box } > { 0pt }
{ \skip_vertical:n { \__tblr_spec_item:nn { outer } { headsep } } }
}
}
\cs_new_protected:Npn \__tblr_build_table_foot_aux:Nn #1 #2
{
\vbox_set:Nn #1
{
\hsize = \tablewidth
\TblrParboxRestore % it will set \linewidth = \hsize
\vbox_set:Nn \l_tmpb_box {#2}
\dim_compare:nNnT
{ \box_ht:N \l_tmpb_box + \box_dp:N \l_tmpb_box } > { 0pt }
{ \skip_vertical:n { \__tblr_spec_item:nn { outer } { footsep } } }
\box_use:N \l_tmpb_box
}
}
\cs_new_protected:Npn \__tblr_build_whole:
{
\tl_if_eq:enTF { \__tblr_spec_item:nn { outer } { long } } { true }
{ \__tblr_build_long_table:e { \__tblr_spec_item:nn { outer } { halign } } }
{
\tl_if_eq:enTF { \__tblr_spec_item:nn { outer } { tall } } { true }
{
\__tblr_build_tall_table:e
{ \__tblr_spec_item:nn { outer } { baseline } }
}
{
\__tblr_build_short_table:e
{ \__tblr_spec_item:nn { outer } { baseline } }
}
}
}
\dim_new:N \l__tblr_remain_height_dim
\int_new:N \l__tblr_long_from_int
\int_new:N \l__tblr_long_to_int
\int_new:N \l__tblr_curr_i_int
\int_new:N \l__tblr_prev_i_int
\int_new:N \l__tblr_table_page_int
\bool_new:N \l__tblr_page_break_curr_bool
\bool_new:N \l__tblr_page_break_prev_bool
%% #1: table alignment
%% For long table, we need to leave hmode first to get correct \pagetotal
%% Also remove topskip and presep if we are at the beginning of the page
\cs_new_protected:Npn \__tblr_build_long_table:n #1
{
\LogTblrTracing { page }
\par
\skip_zero:N \parskip % see issue #203
\LogTblrTracing { page }
\dim_compare:nNnTF { \pagegoal } = { \maxdimen }
{ \hbox{}\kern-\topskip\nobreak }
{ \skip_vertical:n { \__tblr_spec_item:nn { outer } { presep } } }
\LogTblrTracing { page }
\nointerlineskip
\mode_leave_vertical: % enter horizontal mode to update \pagetotal
\LogTblrTracing { page }
\hrule height ~ 0pt
\nobreak % prevent page break after \hrule (see issue #42)
\LogTblrTracing { page }
\int_set:Nn \l__tblr_table_page_int {1}
\__tblr_build_head_foot:
\dim_set:Nn \l__tblr_remain_height_dim
{ \pagegoal - \pagetotal - \l__tblr_row_head_foot_dim }
\int_set:Nn \l__tblr_long_from_int { \l__tblr_row_head_tl + 1 }
\int_set:Nn \l__tblr_long_to_int { \c@rowcount - ( \l__tblr_row_foot_tl + 0 ) }
\int_set:Nn \l__tblr_curr_i_int { \l__tblr_long_from_int - 1 }
\int_do_while:nNnn { \l__tblr_curr_i_int } < { \l__tblr_long_to_int }
{
\int_set_eq:NN \l__tblr_prev_i_int \l__tblr_curr_i_int
\__tblr_get_next_table_rows:NNNN
\l__tblr_long_to_int \l__tblr_curr_i_int
\l_tmpa_dim \l__tblr_page_break_curr_bool
\__tblr_check_table_page_break:NNN
\l__tblr_remain_height_dim \l_tmpa_dim \l__tblr_page_break_prev_bool
\__tblr_do_if_tracing:nn { page } { \int_log:N \l__tblr_curr_i_int }
\bool_if:NTF \l__tblr_page_break_prev_bool
{
\int_compare:nNnTF
{ \l__tblr_long_from_int } > { \l__tblr_prev_i_int }
{
% See issue #42: if longtblr starts at the bottom of a page,
% \pagetotal maybe exceed \pagegoal after adding presep,
% or after adding rowhead or rowfoot of the table.
% In these cases, we will not typeset table in this page,
% but rather do some negative \vskip and execute \newpage.
\skip_vertical:n { \pagegoal - \pagetotal }
}
{
\__tblr_build_page_table:nnx {#1}
{ \int_use:N \l__tblr_long_from_int }
{ \int_use:N \l__tblr_prev_i_int }
\int_incr:N \l__tblr_table_page_int
\int_set:Nn \l__tblr_long_from_int { \l__tblr_prev_i_int + 1 }
}
\TblrNewPage
\hbox{}\kern-\topskip\nobreak
\noindent
\LogTblrTracing { page }
\dim_set:Nn \l__tblr_remain_height_dim
{ \pagegoal - \pagetotal - \l__tblr_row_head_foot_dim - \l_tmpa_dim }
}
{
\bool_if:NTF \l__tblr_page_break_curr_bool
{
\__tblr_build_page_table:nnx {#1}
{ \int_use:N \l__tblr_long_from_int }
{ \int_use:N \l__tblr_curr_i_int }
\int_incr:N \l__tblr_table_page_int
\TblrNewPage
\hbox{}\kern-\topskip\nobreak
\noindent
\LogTblrTracing { page }
\dim_set:Nn \l__tblr_remain_height_dim
{ \pagegoal - \pagetotal - \l__tblr_row_head_foot_dim }
\int_set:Nn \l__tblr_long_from_int { \l__tblr_curr_i_int + 1 }
}
{ \dim_add:Nn \l__tblr_remain_height_dim { -\l_tmpa_dim } }
}
}
\int_compare:nNnTF { \l__tblr_table_page_int } = {1}
{
\box_set_eq:NN \l__tblr_table_head_box \l__tblr_table_firsthead_box
\box_set_eq:NN \l__tblr_table_foot_box \l__tblr_table_lastfoot_box
}
{
\box_set_eq:NN \l__tblr_table_head_box \l__tblr_table_lasthead_box
\box_set_eq:NN \l__tblr_table_foot_box \l__tblr_table_lastfoot_box
}
\__tblr_build_page_table:nnn {#1}
{ \int_use:N \l__tblr_long_from_int } { \int_use:N \l__tblr_long_to_int }
\skip_vertical:n { \__tblr_spec_item:nn { outer } { postsep } }
% In the past we used "\hrule height ~ 0pt" to get strict postsep,
% but the postsep was not discarded when page breaks, see issue #39.
% Therefore we use \nointerlineskip here.
\nointerlineskip
}
\cs_generate_variant:Nn \__tblr_build_long_table:n { e }
%% #1: int with index of the last row; #2: int with index of current row;
%% #3: row dimension; #4: break page or not.
\cs_new_protected:Npn \__tblr_get_next_table_rows:NNNN #1 #2 #3 #4
{
\bool_set_true:N \l_tmpa_bool
\dim_zero:N #3
\bool_set_false:N #4
\bool_while_do:Nn \l_tmpa_bool
{
\int_incr:N #2
\dim_add:Nn #3
{
\__tblr_data_item:nen { row } { \int_use:N #2 } { abovesep }
+
\__tblr_data_item:nen { row } { \int_use:N #2 } { @row-height }
+
\__tblr_data_item:nen { row } { \int_use:N #2 } { belowsep }
+
\__tblr_spec_item:ne { hline }
{ [ \int_eval:n { #2 + 1 } ] / @hline-height }
}
\int_compare:nNnTF {#2} < {#1}
{
\tl_set:Nx \l__tblr_b_tl
{
\__tblr_spec_item:ne { hline }
{ [ \int_eval:n { #2 + 1 } ] / @pagebreak }
}
% Note that \l__tblr_b_tl may be empty
\int_compare:nNnTF { \l__tblr_b_tl + 0 } < { 0 }
{ \bool_set_true:N \l_tmpa_bool }
{
\bool_set_false:N \l_tmpa_bool
\int_compare:nNnT { \l__tblr_b_tl + 0 } > { 0 }
{ \bool_set_true:N #4 }
}
}
{ \bool_set_false:N \l_tmpa_bool }
}
}
\box_new:N \l__tblr_table_head_box
\box_new:N \l__tblr_table_foot_box
\dim_new:N \l__tblr_table_head_foot_dim
\dim_new:N \l__tblr_table_head_body_foot_dim
%% #1: remain dimension; #2: row dimension; #3: break page or not
\cs_new_protected:Npn \__tblr_check_table_page_break:NNN #1 #2 #3
{
\int_compare:nNnTF { \l__tblr_table_page_int } = {1}
{
\dim_set:Nn \l__tblr_table_head_body_foot_dim
{
\__tblr_box_height:N \l__tblr_table_firsthead_box
+ #2 + \__tblr_box_height:N \l__tblr_table_firstfoot_box
}
\box_set_eq:NN \l__tblr_table_head_box \l__tblr_table_firsthead_box
\dim_compare:nNnTF
{ \l__tblr_table_head_body_foot_dim } > {#1}
{
\bool_set_true:N #3
\box_set_eq:NN \l__tblr_table_foot_box \l__tblr_table_firstfoot_box
}
{ \bool_set_false:N #3 }
}
{
\dim_set:Nn \l__tblr_table_head_body_foot_dim
{
\__tblr_box_height:N \l__tblr_table_middlehead_box
+ #2 + \__tblr_box_height:N \l__tblr_table_middlefoot_box
}
\box_set_eq:NN \l__tblr_table_head_box \l__tblr_table_middlehead_box
\dim_compare:nNnTF
{ \l__tblr_table_head_body_foot_dim } > {#1}
{
\bool_set_true:N #3
\box_set_eq:NN \l__tblr_table_foot_box \l__tblr_table_middlefoot_box
}
{ \bool_set_false:N #3 }
}
}
\box_new:N \l__tblr_table_box
%% #1: table alignment; #2: row from; #3: row to
\cs_new_protected:Npn \__tblr_build_page_table:nnn #1 #2 #3
{
\__tblr_build_one_table:nnNN {#2} {#3} \c_false_bool \c_false_bool
\vbox_set:Nn \l__tblr_table_box
{
\box_use:N \l__tblr_table_head_box
\__tblr_cover_two_vboxes:NN \l__tblr_row_head_box \l__tblr_table_box
\box_use:N \l__tblr_row_foot_box
\hrule height ~ 0pt
\box_use:N \l__tblr_table_foot_box
}
\__tblr_halign_whole:Nn \l__tblr_table_box {#1}
}
\cs_generate_variant:Nn \__tblr_build_page_table:nnn { nnx }
%% To solve the problem of missing hlines of long tables in some PDF readers,
%% We need to draw body rows before head rows (see issue #88).
\cs_new_protected:Npn \__tblr_cover_two_vboxes:NN #1 #2
{
\dim_set:Nn \l_tmpa_dim { \box_ht:N #1 + \box_dp:N #1 }
\dim_set:Nn \l_tmpb_dim { \box_ht:N #2 + \box_dp:N #2 }
\skip_vertical:N \l_tmpa_dim
\hrule height ~ 0pt
\box_use:N #2
\skip_vertical:n { - \l_tmpa_dim - \l_tmpb_dim }
\hrule height ~ 0pt
\box_use:N #1
\skip_vertical:N \l_tmpb_dim
\hrule height ~ 0pt
}
\cs_new_protected:Npn \__tblr_halign_whole:Nn #1 #2
{
\noindent
\hbox_to_wd:nn { \linewidth }
{
\tl_if_eq:nnF {#2} {l} { \hfil }
\box_use:N #1
\tl_if_eq:nnF {#2} {r} { \hfil }
}
}
%% #1: table alignment
%% For tall table, we need to leave vmode first.
%% Since there may be \centering in table environment,
%% We use \raggedright to reset alignement for table head/foot.
\cs_new_protected:Npn \__tblr_build_tall_table:n #1
{
\mode_leave_vertical:
\__tblr_build_tall_table_head_foot:
\__tblr_build_one_table:nnNN {1} {\c@rowcount} \c_true_bool \c_true_bool
\vbox_set:Nn \l__tblr_table_box
{
\box_use:N \l__tblr_table_firsthead_box
\hrule height ~ 0pt
\box_use:N \l__tblr_table_box
\hrule height ~ 0pt
\box_use:N \l__tblr_table_lastfoot_box
}
\__tblr_valign_whole:Nn \l__tblr_table_box {#1}
}
\cs_generate_variant:Nn \__tblr_build_tall_table:n { e }
%% #1: table alignment
%% For short table, we need to leave vmode first
\cs_new_protected:Npn \__tblr_build_short_table:n #1
{
\mode_leave_vertical:
\__tblr_build_one_table:nnNN {1} {\c@rowcount} \c_true_bool \c_true_bool
\__tblr_valign_whole:Nn \l__tblr_table_box {#1}
}
\cs_generate_variant:Nn \__tblr_build_short_table:n { e }
\box_new:N \l__tblr_table_hlines_box
\box_new:N \l__tblr_hline_box
\box_new:N \l__tblr_row_box
%% #1: row from; #2: row to
%% #3: whether build first hline or not; #4: whether build last hline or not
%% To fix disappeared hlines with colorful tables in Adobe Reader (see #76),
%% we collect all hlines and draw them at the end of the table.
\cs_new_protected:Npn \__tblr_build_one_table:nnNN #1 #2 #3 #4
{
\box_clear:N \l__tblr_table_hlines_box
\vbox_set:Nn \l__tblr_table_box
{
\int_step_variable:nnNn {#1} {#2} \l__tblr_i_tl
{
\bool_lazy_or:nnT
{ \int_compare_p:nNn { \l__tblr_i_tl } > {#1} }
{ \bool_if_p:N #3 }
{ \__tblr_put_one_hline:n { \__tblr_build_hline:V \l__tblr_i_tl } }
\hrule height ~ 0pt % remove lineskip between hlines and rows
\__tblr_put_one_row:n { \__tblr_build_row:N \l__tblr_i_tl }
\hrule height ~ 0pt
}
\bool_if:NT #4
{
\__tblr_put_one_hline:n
{ \__tblr_build_hline:n { \int_eval:n {#2 + 1} } }
}
\skip_vertical:n
{
- \box_ht:N \l__tblr_table_hlines_box
- \box_dp:N \l__tblr_table_hlines_box
}
\box_use:N \l__tblr_table_hlines_box
}
}
\cs_new_protected:Npn \__tblr_put_one_hline:n #1
{
\hbox_set:Nn \l__tblr_hline_box {#1}
\skip_vertical:n { \box_ht:N \l__tblr_hline_box + \box_dp:N \l__tblr_hline_box }
\vbox_set:Nn \l__tblr_table_hlines_box
{
\vbox_unpack:N \l__tblr_table_hlines_box
\box_use:N \l__tblr_hline_box
}
}
\cs_new_protected:Npn \__tblr_put_one_row:n #1
{
\hbox_set:Nn \l__tblr_row_box {#1}
\vbox_set:Nn \l__tblr_table_hlines_box
{
\vbox_unpack:N \l__tblr_table_hlines_box
\skip_vertical:n
{ \box_ht:N \l__tblr_row_box + \box_dp:N \l__tblr_row_box }
}
\box_use:N \l__tblr_row_box
}
%% #1: hline number
\cs_new_protected:Npn \__tblr_build_one_hline:n #1
{
\vbox_set:Nn \l__tblr_table_box { \hbox:n { \__tblr_build_hline:n { #1 } } }
}
\tl_new:N \__tblr_vbox_align_tl
\tl_const:Nn \__tblr_vbox_t_tl {t}
\tl_const:Nn \__tblr_vbox_T_tl {T}
\tl_const:Nn \__tblr_vbox_m_tl {m}
\tl_const:Nn \__tblr_vbox_M_tl {M}
\tl_const:Nn \__tblr_vbox_c_tl {c}
\tl_const:Nn \__tblr_vbox_b_tl {b}
\tl_const:Nn \__tblr_vbox_B_tl {B}
\regex_const:Nn \c__tblr_is_positive_integer_regex { ^ \d+ $ }
\regex_const:Nn \c__tblr_is_negative_integer_regex { ^ - \d+ $ }
\tl_new:N \l__tblr_delim_left_tl
\tl_new:N \l__tblr_delim_right_tl
\cs_new_protected:Npn \__tblr_valign_whole:Nn #1 #2
{
\group_begin:
\tl_set:Nx \l__tblr_delim_left_tl
{ \__tblr_prop_item:nn { inner } { delim-left } }
\tl_set:Nx \l__tblr_delim_right_tl
{ \__tblr_prop_item:nn { inner } { delim-right } }
\tl_set:Nn \__tblr_vbox_align_tl {#2}
\dim_set:Nn \l__tblr_t_dim { \box_ht:N #1 + \box_dp:N #1 }
\tl_case:NnF \__tblr_vbox_align_tl
{
\__tblr_vbox_m_tl
{ \__tblr_valign_whole_middle:N #1 }
\__tblr_vbox_c_tl
{ \__tblr_valign_whole_middle:N #1 }
\__tblr_vbox_M_tl
{ \__tblr_valign_whole_middle_row_or_border:N #1 }
\__tblr_vbox_t_tl
{ \__tblr_valign_whole_top:N #1 }
\__tblr_vbox_T_tl
{
\tl_set:Nn \__tblr_vbox_align_tl {1}
\__tblr_valign_whole_at_row_from_above:N #1
}
\__tblr_vbox_b_tl
{ \__tblr_valign_whole_bottom:N #1 }
\__tblr_vbox_B_tl
{
\tl_set:Nx \__tblr_vbox_align_tl { \int_use:N \c@rowcount }
\__tblr_valign_whole_at_row_from_below:N #1
}
}
{
\regex_match:NVTF \c__tblr_is_positive_integer_regex \__tblr_vbox_align_tl
{ \__tblr_valign_whole_at_row:N #1 }
{
\regex_match:NVTF
\c__tblr_is_negative_integer_regex \__tblr_vbox_align_tl
{ \__tblr_valign_whole_at_border:N #1 }
{ \__tblr_valign_whole_middle:N #1 }
}
}
%% we have done the job when valign is m or c
\box_if_empty:NF #1 { \__tblr_add_delimiters_to_box:N #1 }
\group_end:
}
%% We use the idea of delarray package to shift table box
%% when there are delimiters around the table
\cs_new_protected:Npn \__tblr_add_delimiters_to_box:N #1
{
\tl_if_empty:NTF \l__tblr_delim_left_tl
{ \box_use_drop:N #1 }
{
\box_move_down:nn
{
( \box_dp:N #1 - \box_ht:N #1 ) / 2
+ \tex_fontdimen:D 22 \tex_textfont:D 2
}
{ \__tblr_get_vcenter_box:N #1 }
}
}
\cs_new_protected:Npn \__tblr_get_vcenter_box:N #1
{
\hbox:n
{
$ \m@th \l__tblr_delim_left_tl
\tex_vcenter:D { \vbox_unpack_drop:N #1 }
\l__tblr_delim_right_tl $
}
}
\cs_new_protected:Npn \__tblr_valign_whole_middle:N #1
{
\__tblr_get_vcenter_box:N #1
}
\cs_new_protected:Npn \__tblr_valign_whole_top:N #1
{
\dim_set:Nn \l__tblr_h_dim { \__tblr_valign_get_hline_total:n {1} }
\dim_compare:nNnT \l__tblr_h_dim = { 0pt }
{ \dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_row_height:n {1} } }
\box_set_ht:Nn #1 { \l__tblr_h_dim }
\box_set_dp:Nn #1 { \l__tblr_t_dim - \l__tblr_h_dim }
}
\cs_new_protected:Npn \__tblr_valign_whole_bottom:N #1
{
\dim_set:Nn \l__tblr_d_dim
{ \__tblr_valign_get_hline_total:n { \int_eval:n { \c@rowcount + 1 } } }
\dim_compare:nNnTF \l__tblr_d_dim = { 0pt }
{
\dim_set:Nn \l__tblr_d_dim
{ \__tblr_valign_get_row_depth:n { \int_use:N \c@rowcount } }
}
{ \dim_zero:N \l__tblr_d_dim }
\box_set_ht:Nn #1 { \l__tblr_t_dim - \l__tblr_d_dim }
\box_set_dp:Nn #1 { \l__tblr_d_dim }
}
\cs_new_protected:Npn \__tblr_valign_whole_middle_row_or_border:N #1
{
\int_if_odd:nTF { \c@rowcount }
{
\tl_set:Nx \__tblr_vbox_align_tl { \int_eval:n { (\c@rowcount + 1) / 2 } }
\__tblr_valign_whole_at_row_from_above:N #1
}
{
\tl_set:Nx \__tblr_vbox_align_tl { \int_eval:n { \c@rowcount / 2 + 1 } }
\__tblr_valign_whole_at_border_from_above:N #1
}
}
\cs_new_protected:Npn \__tblr_valign_whole_at_row:N #1
{
\int_compare:nNnTF { 2 * \__tblr_vbox_align_tl } > { \c@rowcount }
{ \__tblr_valign_whole_at_row_from_below:N #1 }
{ \__tblr_valign_whole_at_row_from_above:N #1 }
}
\cs_new_protected:Npn \__tblr_valign_whole_at_row_from_above:N #1
{
\dim_set:Nn \l__tblr_h_dim
{ \__tblr_valign_get_hline_total:n { \__tblr_vbox_align_tl } }
\dim_add:Nn \l__tblr_h_dim
{ \__tblr_valign_get_row_height:n { \__tblr_vbox_align_tl } }
\int_step_inline:nn { \__tblr_vbox_align_tl - 1 }
{
\dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_hline_total:n {##1} }
\dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_row_total:n {##1} }
}
\box_set_ht:Nn #1 { \l__tblr_h_dim }
\box_set_dp:Nn #1 { \l__tblr_t_dim - \l__tblr_h_dim }
}
\cs_new_protected:Npn \__tblr_valign_whole_at_row_from_below:N #1
{
\dim_set:Nn \l__tblr_d_dim
{ \__tblr_valign_get_hline_total:n { \int_eval:n {\c@rowcount + 1} } }
\dim_add:Nn \l__tblr_d_dim
{ \__tblr_valign_get_row_depth:n { \__tblr_vbox_align_tl } }
\int_step_inline:nnn { \__tblr_vbox_align_tl + 1 } { \c@rowcount }
{
\dim_add:Nn \l__tblr_d_dim { \__tblr_valign_get_hline_total:n {##1} }
\dim_add:Nn \l__tblr_d_dim { \__tblr_valign_get_row_total:n {##1} }
}
\box_set_dp:Nn #1 { \l__tblr_d_dim }
\box_set_ht:Nn #1 { \l__tblr_t_dim - \l__tblr_d_dim }
}
\cs_new_protected:Npn \__tblr_valign_whole_at_border:N #1
{
\tl_set:Nx \__tblr_vbox_align_tl { \int_eval:n { - \__tblr_vbox_align_tl } }
\int_compare:nNnTF { 2 * \__tblr_vbox_align_tl - 2 } > { \c@rowcount }
{ \__tblr_valign_whole_at_border_from_below:N #1 }
{ \__tblr_valign_whole_at_border_from_above:N #1 }
}
\cs_new_protected:Npn \__tblr_valign_whole_at_border_from_above:N #1
{
\dim_set:Nn \l__tblr_h_dim
{ \__tblr_valign_get_hline_total:n { \__tblr_vbox_align_tl } }
\int_step_inline:nn { \__tblr_vbox_align_tl - 1 }
{
\dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_hline_total:n {##1} }
\dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_row_total:n {##1} }
}
\box_set_ht:Nn #1 { \l__tblr_h_dim }
\box_set_dp:Nn #1 { \l__tblr_t_dim - \l__tblr_h_dim }
}
\cs_new_protected:Npn \__tblr_valign_whole_at_border_from_below:N #1
{
\dim_zero:N \l__tblr_d_dim
\int_step_inline:nnn { \__tblr_vbox_align_tl } { \c@rowcount }
{
\dim_add:Nn \l__tblr_d_dim { \__tblr_valign_get_row_total:n {##1} }
\dim_add:Nn \l__tblr_d_dim
{ \__tblr_valign_get_hline_total:n { \int_eval:n { ##1 + 1 } } }
}
\box_set_dp:Nn #1 { \l__tblr_d_dim }
\box_set_ht:Nn #1 { \l__tblr_t_dim - \l__tblr_d_dim }
}
\cs_new_nopar:Npn \__tblr_valign_get_hline_total:n #1
{
\__tblr_spec_item:ne { hline } { [#1] / @hline-height }
}
\cs_new_nopar:Npn \__tblr_valign_get_row_total:n #1
{
\__tblr_data_item:nnn { row } {#1} { abovesep }
+
\__tblr_data_item:nnn { row } {#1} { @row-height }
+
\__tblr_data_item:nnn { row } {#1} { belowsep }
}
\cs_new_nopar:Npn \__tblr_valign_get_row_height:n #1
{
\__tblr_data_item:nnn { row } {#1} { abovesep }
+
( \__tblr_data_item:nnn { row } {#1} { @row-height }
+
\__tblr_data_item:nnn { row } {#1} { @row-upper }
-
\__tblr_data_item:nnn { row } {#1} { @row-lower }
) / 2
}
\cs_new_nopar:Npn \__tblr_valign_get_row_depth:n #1
{
( \__tblr_data_item:nen { row } {#1} { @row-height }
-
\__tblr_data_item:nen { row } {#1} { @row-upper }
+
\__tblr_data_item:nen { row } {#1} { @row-lower }
) / 2
+
\__tblr_data_item:nnn { row } {#1} { belowsep }
}
%%% --------------------------------------------------------
%%> \section{Build Table Components}
%%% --------------------------------------------------------
\dim_new:N \l__tblr_col_o_wd_dim
\dim_new:N \l__tblr_col_b_wd_dim
%% Build hline. #1: row number
\cs_new_protected:Npn \__tblr_build_hline:n #1
{
\int_step_inline:nn { \c@colcount }
{ \__tblr_build_hline_segment:nn { #1 } { ##1 } }
}
\cs_generate_variant:Nn \__tblr_build_hline:n { x, V }
%% #1: row number, #2: column number
\cs_new_protected:Npn \__tblr_build_hline_segment:nn #1 #2
{
\tl_set:Nx \l__tblr_n_tl
{ \__tblr_spec_item:ne { hline } { [#1] / @hline-count } }
\tl_set:Nx \l__tblr_o_tl
{ \__tblr_spec_item:ne { hline } { [#1][#2] / omit } }
\__tblr_get_col_outer_width_border_width:nNN {#2}
\l__tblr_col_o_wd_dim \l__tblr_col_b_wd_dim
\tl_if_empty:NTF \l__tblr_o_tl
{
\int_compare:nNnT { \l__tblr_n_tl } > {0}
{ \__tblr_build_hline_segment_real:nn {#1} {#2} }
}
{ \__tblr_build_hline_segment_omit:nn {#1} {#2} }
}
%% #1: row number, #2: column number
\cs_new_protected:Npn \__tblr_build_hline_segment_omit:nn #1 #2
{
\skip_horizontal:n { \l__tblr_col_o_wd_dim - \l__tblr_col_b_wd_dim }
}
%% #1: row number, #2: column number
\cs_new_protected:Npn \__tblr_build_hline_segment_real:nn #1 #2
{
\tl_set:Nx \l__tblr_s_tl
{ \__tblr_prop_item:ne { inner } { rulesep } }
\vbox_set:Nn \l__tblr_c_box
{
%% add an empty hbox to support vbox width
\tex_hbox:D to \l__tblr_col_o_wd_dim {}
\int_step_inline:nn { \l__tblr_n_tl }
{
\tl_set:Nx \l__tblr_h_tl
{ \__tblr_spec_item:ne { hline } { [#1](##1) / @hline-height } }
\hrule height ~ 0pt % remove lineskip
\hbox_set_to_wd:Nnn \l__tblr_b_box { \l__tblr_col_o_wd_dim }
{
\__tblr_get_hline_left_right_skips:nnn {#1} {#2} {##1}
\skip_horizontal:N \l__tblr_hline_leftskip_dim
\tl_set:Nx \l__tblr_f_tl
{ \__tblr_spec_item:ne { hline } { [#1][#2](##1) / fg } }
\tl_if_empty:NF \l__tblr_f_tl { \color{\l__tblr_f_tl} }
\__tblr_get_hline_segment_child:nnn {#1} {#2} {##1}
\skip_horizontal:N \l__tblr_hline_rightskip_dim
}
\box_set_ht:Nn \l__tblr_b_box { \l__tblr_h_tl }
\box_set_dp:Nn \l__tblr_b_box { 0pt }
\box_use:N \l__tblr_b_box
\skip_vertical:n { \l__tblr_s_tl }
}
\skip_vertical:n { - \l__tblr_s_tl }
}
\box_use:N \l__tblr_c_box
\skip_horizontal:n { - \l__tblr_col_b_wd_dim }
}
%% Read from table specifications and calculate the widths of row and border
%% column outer width = content width + colsep width + border width
%% #1: the column number, #2: outer width, #3: border width
\cs_new_protected:Npn \__tblr_get_col_outer_width_border_width:nNN #1 #2 #3
{
\dim_set:Nn #3
{ \__tblr_spec_item:ne { vline } { [\int_eval:n {#1 + 1}] / @vline-width } }
\dim_set:Nn #2
{
\__tblr_spec_item:ne { vline } { [#1] / @vline-width }
+
\__tblr_data_item:nen { column } {#1} { leftsep }
+
\__tblr_data_item:nen { column } {#1} { @col-width }
+
\__tblr_data_item:nen { column } {#1} { rightsep }
+
#3
}
}
\dim_new:N \l__tblr_hline_leftskip_dim
\dim_new:N \l__tblr_hline_rightskip_dim
%% Calculate left and right skips from leftpos and rightpos specifications
%% #1: row number; #2: column number; #3: hline index;
\cs_new_protected:Npn \__tblr_get_hline_left_right_skips:nnn #1 #2 #3
{
\tl_set:Nx \l__tblr_hline_leftpos_tl
{ \__tblr_spec_item:ne { hline } { [#1][#2](#3) / leftpos } }
\tl_if_empty:NT \l__tblr_hline_leftpos_tl
{ \tl_set:Nn \l__tblr_hline_leftpos_tl {1} } % default position
\tl_set:Nx \l__tblr_hline_rightpos_tl
{ \__tblr_spec_item:ne { hline } { [#1][#2](#3) / rightpos } }
\tl_if_empty:NT \l__tblr_hline_rightpos_tl
{ \tl_set:Nn \l__tblr_hline_rightpos_tl {1} } % default position
\fp_compare:nNnT { \l__tblr_hline_leftpos_tl } < {1}
{
\dim_set:Nn \l_tmpa_dim
{ \__tblr_spec_item:ne { vline } { [#2] / @vline-width } }
\dim_set:Nn \l_tmpb_dim
{ \__tblr_data_item:nen { column } {#2} { leftsep } }
\fp_compare:nNnTF { \l__tblr_hline_leftpos_tl } < {0}
{
\dim_set:Nn \l__tblr_hline_leftskip_dim
{ \l_tmpa_dim - \l__tblr_hline_leftpos_tl \l_tmpb_dim }
}
{
\dim_set:Nn \l__tblr_hline_leftskip_dim
{ \l_tmpa_dim - \l__tblr_hline_leftpos_tl \l_tmpa_dim }
}
}
\fp_compare:nNnT { \l__tblr_hline_rightpos_tl } < {1}
{
\dim_set:Nn \l_tmpa_dim
{
\__tblr_spec_item:ne { vline }
{ [\int_eval:n { #2 + 1 }] / @vline-width }
}
\dim_set:Nn \l_tmpb_dim
{ \__tblr_data_item:nen { column } {#2} { rightsep } }
\fp_compare:nNnTF { \l__tblr_hline_rightpos_tl } < {0}
{
\dim_set:Nn \l__tblr_hline_rightskip_dim
{ \l_tmpa_dim - \l__tblr_hline_rightpos_tl \l_tmpb_dim }
}
{
\dim_set:Nn \l__tblr_hline_rightskip_dim
{ \l_tmpa_dim - \l__tblr_hline_rightpos_tl \l_tmpa_dim }
}
}
}
\dim_new:N \l__tblr_row_ht_dim
\dim_new:N \l__tblr_row_dp_dim
\dim_new:N \l__tblr_row_abovesep_dim
\dim_new:N \l__tblr_row_belowsep_dim
\box_new:N \l__tblr_row_vlines_box
\box_new:N \l__tblr_vline_box
\box_new:N \l__tblr_cell_box
%% Build current row, #1: row number
%% To fix disappeared vlines with colorful tables in Adobe Reader (see #76),
%% we collect all vlines and draw them at the end of the row.
\cs_new_protected:Npn \__tblr_build_row:N #1
{
\int_set:Nn \c@rownum {#1}
\__tblr_update_rowsep_registers:
\__tblr_get_row_inner_height_depth:VNNNN #1
\l__tblr_row_ht_dim \l__tblr_row_dp_dim
\l__tblr_row_abovesep_dim \l__tblr_row_belowsep_dim
\vrule width ~ 0pt ~ height ~ \l__tblr_row_ht_dim ~ depth ~ \l__tblr_row_dp_dim
\hbox_set:Nn \l__tblr_row_vlines_box
{
\vrule width ~ 0pt ~ height ~ \l__tblr_row_ht_dim
~ depth ~ \l__tblr_row_dp_dim
}
\int_step_variable:nNn { \c@colcount } \l__tblr_j_tl
{
\__tblr_put_one_vline:n
{ \__tblr_build_vline_segment:nn {#1} { \l__tblr_j_tl } }
\__tblr_put_one_cell:n { \__tblr_build_cell:NN #1 \l__tblr_j_tl }
}
\__tblr_put_one_vline:n
{ \__tblr_build_vline_segment:nn {#1} { \int_eval:n {\c@colcount + 1} } }
\skip_horizontal:n { - \box_wd:N \l__tblr_row_vlines_box }
\box_use:N \l__tblr_row_vlines_box
}
%% Read from table specifications and calculate inner height/depth of the row
%% inner height = abovesep + above vspace + row upper
%% inner depth = row lower + below vspace + belowsep
%% #1: the row number; #2: resulting inner height; #3: resulting inner depth;
%% #4: restulting abovesep; #5: restulting belowsep.
\dim_new:N \l__row_upper_dim
\dim_new:N \l__row_lower_dim
\dim_new:N \l__row_vpace_dim
\cs_new_protected:Npn \__tblr_get_row_inner_height_depth:nNNNN #1 #2 #3 #4 #5
{
\dim_set:Nn #4
{ \__tblr_data_item:nen { row } {#1} { abovesep } }
\dim_set:Nn #5
{ \__tblr_data_item:nen { row } {#1} { belowsep } }
\dim_set:Nn \l__row_upper_dim
{ \__tblr_data_item:nen { row } {#1} { @row-upper } }
\dim_set:Nn \l__row_lower_dim
{ \__tblr_data_item:nen { row } {#1} { @row-lower } }
\dim_set:Nn \l__row_vpace_dim
{
( \__tblr_data_item:nen { row } {#1} { @row-height }
- \l__row_upper_dim - \l__row_lower_dim ) / 2
}
\dim_set:Nn #2 { #4 + \l__row_vpace_dim + \l__row_upper_dim }
\dim_set:Nn #3 { \l__row_lower_dim + \l__row_vpace_dim + #5 }
}
\cs_generate_variant:Nn \__tblr_get_row_inner_height_depth:nNNNN { V }
\cs_new_protected:Npn \__tblr_put_one_vline:n #1
{
\hbox_set:Nn \l__tblr_vline_box {#1}
\skip_horizontal:n { \box_wd:N \l__tblr_vline_box }
\hbox_set:Nn \l__tblr_row_vlines_box
{
\hbox_unpack:N \l__tblr_row_vlines_box
\box_use:N \l__tblr_vline_box
}
}
\cs_new_protected:Npn \__tblr_put_one_cell:n #1
{
\hbox_set:Nn \l__tblr_cell_box {#1}
\hbox_set:Nn \l__tblr_row_vlines_box
{
\hbox_unpack:N \l__tblr_row_vlines_box
\skip_horizontal:n { \box_wd:N \l__tblr_cell_box }
}
\box_use:N \l__tblr_cell_box
}
%% #1: row number, #2: column number
\cs_new_protected:Npn \__tblr_build_vline_segment:nn #1 #2
{
\tl_set:Nx \l__tblr_n_tl
{ \__tblr_spec_item:ne { vline } { [#2] / @vline-count } }
\tl_set:Nx \l__tblr_o_tl
{ \__tblr_spec_item:ne { vline } { [#1][#2] / omit } }
\tl_if_empty:NTF \l__tblr_o_tl
{
\int_compare:nNnT { \l__tblr_n_tl } > {0}
{ \__tblr_build_vline_segment_real:nn {#1} {#2} }
}
{ \__tblr_build_vline_segment_omit:nn {#1} {#2} }
}
%% #1: row number, #2: column number
\cs_new_protected:Npn \__tblr_build_vline_segment_omit:nn #1 #2
{
\tl_set:Nx \l__tblr_w_tl
{ \__tblr_spec_item:ne { vline } { [#2] / @vline-width } }
\skip_horizontal:N \l__tblr_w_tl
}
%% #1: row number, #2: column number
%% We make every vline segment intersect with first hline below
%% to remove gaps in vlines around multirow cells
\cs_new_protected:Npn \__tblr_build_vline_segment_real:nn #1 #2
{
\tl_set:Nx \l__tblr_s_tl
{ \__tblr_prop_item:ne { inner } { rulesep } }
\hbox_set:Nn \l__tblr_a_box
{
\int_step_inline:nn { \l__tblr_n_tl }
{
\tl_set:Nx \l__tblr_w_tl
{ \__tblr_spec_item:ne { vline } { [#2](##1) / @vline-width } }
\vbox_set_to_ht:Nnn \l__tblr_b_box
{ \dim_eval:n { \l__tblr_row_ht_dim + \l__tblr_row_dp_dim } }
{
\tl_set:Nx \l__tblr_f_tl
{ \__tblr_spec_item:ne { vline } { [#1][#2](##1) / fg } }
\tl_if_empty:NF \l__tblr_f_tl { \color{\l__tblr_f_tl} }
\__tblr_get_vline_above_below_skips:nnn {#1} {#2} {##1}
\skip_vertical:N \l__tblr_vline_aboveskip_dim
\__tblr_get_vline_segment_child:nnnxx {#1} {#2} {##1}
{ \dim_eval:n { \l__tblr_row_ht_dim } }
{ \dim_eval:n { \l__tblr_row_dp_dim } }
\skip_vertical:N \l__tblr_vline_belowskip_dim
}
\box_set_wd:Nn \l__tblr_b_box { \l__tblr_w_tl }
\box_use:N \l__tblr_b_box
\skip_horizontal:n { \l__tblr_s_tl }
}
\skip_horizontal:n { - \l__tblr_s_tl }
}
\vbox_set:Nn \l__tblr_c_box { \box_use:N \l__tblr_a_box }
\box_set_ht:Nn \l__tblr_c_box { \dim_use:N \l__tblr_row_ht_dim }
\box_set_dp:Nn \l__tblr_c_box { \dim_use:N \l__tblr_row_dp_dim }
\box_use:N \l__tblr_c_box
}
\dim_new:N \l__tblr_vline_aboveskip_dim
\dim_new:N \l__tblr_vline_belowskip_dim
%% Calculate above and below skips from abovepos and belowpos specifications
%% #1: row number; #2: column number; #3: vline index;
\cs_new_protected:Npn \__tblr_get_vline_above_below_skips:nnn #1 #2 #3
{
\tl_set:Nx \l__tblr_vline_abovepos_tl
{ \__tblr_spec_item:ne { vline } { [#1][#2](#3) / abovepos } }
\tl_if_empty:NT \l__tblr_vline_abovepos_tl
{
\tl_set:Nn \l__tblr_vline_abovepos_tl {0} % default position
}
\fp_compare:nNnF { \l__tblr_vline_abovepos_tl } = {0}
{
\dim_set:Nn \l_tmpa_dim
{ \__tblr_spec_item:ne { hline } { [#1] / @hline-height } }
\fp_compare:nNnTF { \l__tblr_vline_abovepos_tl } < {0}
{
\dim_set:Nn \l__tblr_vline_aboveskip_dim
{ - \l__tblr_vline_abovepos_tl \l__tblr_row_abovesep_dim }
}
{
\dim_set:Nn \l__tblr_vline_aboveskip_dim
{ - \l__tblr_vline_abovepos_tl \l_tmpa_dim }
}
}
%% To join two vline segment above and below a cline,
%% we choose to extend every vline downwards a little (#55, #272).
\tl_set:Nx \l__tblr_vline_belowpos_tl
{ \__tblr_spec_item:ne { vline } { [#1][#2](#3) / belowpos } }
\tl_if_empty:NTF \l__tblr_vline_belowpos_tl
{
\dim_set:Nn \l__tblr_vline_belowskip_dim
{
- \__tblr_spec_item:ne { hline }
{ [\int_eval:n { #1 + 1 }](1) / @hline-height }
+ 0pt
}
}
{
\dim_set:Nn \l_tmpa_dim
{
\__tblr_spec_item:ne { hline }
{ [\int_eval:n { #1 + 1 }] / @hline-height }
}
\fp_compare:nNnTF { \l__tblr_vline_belowpos_tl } < {0}
{
\dim_set:Nn \l__tblr_vline_belowskip_dim
{ - \l__tblr_vline_belowpos_tl \l__tblr_row_belowsep_dim }
}
{
\dim_set:Nn \l__tblr_vline_belowskip_dim
{ - \l__tblr_vline_belowpos_tl \l_tmpa_dim }
}
}
}
\tl_new:N \l__tblr_cell_rowspan_tl
\tl_new:N \l__tblr_cell_colspan_tl
\dim_new:N \l__tblr_cell_wd_dim
\dim_new:N \l__tblr_cell_ht_dim
\cs_new_protected:Npn \__tblr_build_cell:NN #1 #2
{
\int_set:Nn \c@colnum {#2}
\__tblr_update_colsep_registers:
\group_begin:
\tl_set:Nx \l__tblr_w_tl
{ \__tblr_data_item:nen { column } {#2} { @col-width } }
\tl_set:Nx \l__tblr_h_tl
{ \__tblr_data_item:nen { row } {#1} { @row-height } }
\tl_set:Nx \l__tblr_x_tl
{ \__tblr_data_item:nen { column } {#2} { leftsep} }
\tl_set:Nx \l__tblr_y_tl
{ \__tblr_data_item:nen { column } {#2} { rightsep } }
\tl_set:Nx \l__tblr_cell_colspan_tl
{ \__tblr_data_item:neen { cell } {#1} {#2} { colspan } }
\int_compare:nNnTF { \l__tblr_cell_colspan_tl } < {2}
{ \dim_set:Nn \l__tblr_cell_wd_dim { \l__tblr_w_tl } }
{
\__tblr_get_span_horizontal_sizes:NNNNN #1 #2
\l__tblr_o_dim \l__tblr_cell_wd_dim \l__tblr_q_dim
}
\tl_set:Nx \l__tblr_cell_rowspan_tl
{ \__tblr_data_item:neen { cell } {#1} {#2} { rowspan } }
\int_compare:nNnTF { \l__tblr_cell_rowspan_tl } < {2}
{ \dim_set:Nn \l__tblr_cell_ht_dim { \l__tblr_h_tl } }
{
\__tblr_get_span_vertical_sizes:NNNNN #1 #2
\l__tblr_r_dim \l__tblr_cell_ht_dim \l__tblr_t_dim
}
\__tblr_get_cell_alignments:nn {#1} {#2}
\__tblr_build_cell_background:NN #1 #2
\__tblr_build_cell_content:NN #1 #2
\group_end:
}
\cs_new_protected:Npn \__tblr_build_cell_content:NN #1 #2
{
\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 }
}
}
\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 { \l__tblr_cell_rowspan_tl } < {2}
{
\box_set_ht:Nn \l__tblr_a_box
{ \__tblr_data_item:nen { row } {#1} { @row-upper } }
\box_set_dp:Nn \l__tblr_a_box
{ \__tblr_data_item:nen { row } {#1} { @row-lower } }
}
\box_use:N \l__tblr_a_box
\vfil
}
\c__tblr_valign_h_tl
{
\box_set_ht:Nn \l__tblr_a_box
{ \__tblr_data_item:nen { row } {#1} { @row-head } }
\box_use:N \l__tblr_a_box
\vfil
}
\c__tblr_valign_f_tl
{
\vfil
\int_compare:nNnTF { \l__tblr_cell_rowspan_tl } < {2}
{
\box_set_dp:Nn \l__tblr_a_box
{ \__tblr_data_item:nen { row } {#1} { @row-foot } }
}
{
\box_set_dp:Nn \l__tblr_a_box
{
\__tblr_data_item:nen
{ row }
{ \int_eval:n { #1 + \l__tblr_cell_rowspan_tl - 1 } }
{ @row-foot }
}
}
\box_use:N \l__tblr_a_box
}
}
\hrule height ~ 0pt %% zero depth
}
\vbox_set_to_ht:Nnn \l__tblr_c_box
{ \l__tblr_row_ht_dim - \l__tblr_row_abovesep_dim }
{
\box_use:N \l__tblr_b_box
\vss
}
\skip_horizontal:n { \l__tblr_x_tl }
\box_use:N \l__tblr_c_box
\skip_horizontal:n { \l__tblr_y_tl - \l__tblr_cell_wd_dim + \l__tblr_w_tl }
}
\cs_new_protected:Npn \__tblr_build_cell_background:NN #1 #2
{
\int_compare:nNnT { \__tblr_data_item:neen { cell } {#1} {#2} { omit } } = {0}
{
\group_begin:
\tl_set:Nx \l__tblr_b_tl
{ \__tblr_data_item:neen { cell } {#1} {#2} { background } }
\tl_if_empty:NF \l__tblr_b_tl
{
\__tblr_get_cell_background_width:NNN #1 #2 \l_tmpa_dim
\__tblr_get_cell_background_depth:NNN #1 #2 \l_tmpb_dim
\__tblr_build_cell_background:nnnn
{ \dim_use:N \l_tmpa_dim }
{ \l__tblr_row_ht_dim }
{ \dim_use:N \l_tmpb_dim }
{ \l__tblr_b_tl }
}
\group_end:
}
}
%% #1: row number; #2: column number; #3 resulting dimension
\cs_new_protected:Npn \__tblr_get_cell_background_width:NNN #1 #2 #3
{
\int_compare:nNnTF { \l__tblr_cell_colspan_tl } < {2}
{ \dim_set:Nn #3 { \l__tblr_x_tl + \l__tblr_w_tl + \l__tblr_y_tl } }
{
\dim_set:Nn #3 { \l__tblr_o_dim + \l__tblr_cell_wd_dim + \l__tblr_q_dim }
}
}
%% #1: row number; #2: column number; #3 resulting dimension
\cs_new_protected:Npn \__tblr_get_cell_background_depth:NNN #1 #2 #3
{
\int_compare:nNnTF { \l__tblr_cell_rowspan_tl } < {2}
{ \dim_set_eq:NN #3 \l__tblr_row_dp_dim }
{
\dim_set:Nn #3
{
\l__tblr_r_dim + \l__tblr_cell_ht_dim
+ \l__tblr_t_dim - \l__tblr_row_ht_dim
}
}
}
%% #1: width, #2: height, #3: depth, #4: color
\cs_new_protected:Npn \__tblr_build_cell_background:nnnn #1 #2 #3 #4
{
\hbox_set:Nn \l__tblr_a_box
{
\color {#4}
\vrule width ~ #1 ~ height ~ #2 ~ depth ~ #3
}
\box_set_dp:Nn \l__tblr_a_box { 0pt }
\box_use:N \l__tblr_a_box
\skip_horizontal:n { - #1 }
}
%% #1: row number; #2: column number; #3: dimen register for rowsep above.
%% #4: dimen register for total height; #5: dimen register for rowsep below.
%% We can use \l__tblr_row_item_skip_size_prop which was made before
%% But when vspan=even, there are no itemskip in the prop list.
%% Therefore we need to calculate them from the sizes of items and skips
\cs_new_protected:Npn \__tblr_get_span_vertical_sizes:NNNNN #1 #2 #3 #4 #5
{
\dim_set:Nn #3
{ \__tblr_data_item:nen { row } {#1} { abovesep } }
\dim_zero:N #4
\dim_add:Nn #4
{ \prop_item:Ne \l__tblr_row_item_skip_size_prop { item[#1] } }
\int_step_inline:nnn { #1 + 1 } { #1 + \l__tblr_cell_rowspan_tl - 1 }
{
\dim_add:Nn #4
{
\prop_item:Ne \l__tblr_row_item_skip_size_prop { skip[##1] }
+
\prop_item:Ne \l__tblr_row_item_skip_size_prop { item[##1] }
}
}
\dim_set:Nn #5
{
\__tblr_data_item:nen { row }
{ \int_eval:n { #1 + \l__tblr_cell_rowspan_tl - 1 } } { belowsep }
}
%\tl_log:x { cell[#1][#2] ~:~ \dim_use:N #3, \dim_use:N #4, \dim_use:N #5 }
}
%% #1: row number; #2: column number; #3: dimen register for colsep left.
%% #4: dimen register for total width; #5: dimen register for colsep right.
%% We can use \l__tblr_col_item_skip_size_prop which was made before
%% But when hspan=even or hspan=minimal, there are no itemskip in the prop list.
%% Therefore we need to calculate them from the sizes of items and skips
\cs_new_protected:Npn \__tblr_get_span_horizontal_sizes:NNNNN #1 #2 #3 #4 #5
{
\dim_set:Nn #3
{ \__tblr_data_item:nen { column } {#2} { leftsep } }
\dim_zero:N #4
\dim_add:Nn #4
{ \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[#2] } }
\int_step_inline:nnn { #2 + 1 } { #2 + \l__tblr_cell_colspan_tl - 1 }
{
\dim_add:Nn #4
{
\prop_item:Ne \l__tblr_col_item_skip_size_prop { skip[##1] }
+
\prop_item:Ne \l__tblr_col_item_skip_size_prop { item[##1] }
}
}
\dim_set:Nn #5
{
\__tblr_data_item:nen { column }
{ \int_eval:n {#2 + \l__tblr_cell_colspan_tl - 1} } { rightsep }
}
%\tl_log:x { cell[#1][#2] ~:~ \dim_use:N #3, \dim_use:N #4, \dim_use:N #5 }
}
%%% --------------------------------------------------------
%%> \section{Tracing Tabularray}
%%% --------------------------------------------------------
\NewDocumentCommand \SetTblrTracing { m }
{
\keys_set:nn { tblr-set-tracing } {#1}
}
\bool_new:N \g__tblr_tracing_text_bool
\bool_new:N \g__tblr_tracing_command_bool
\bool_new:N \g__tblr_tracing_option_bool
\bool_new:N \g__tblr_tracing_theme_bool
\bool_new:N \g__tblr_tracing_outer_bool
\bool_new:N \g__tblr_tracing_inner_bool
\bool_new:N \g__tblr_tracing_column_bool
\bool_new:N \g__tblr_tracing_row_bool
\bool_new:N \g__tblr_tracing_cell_bool
\bool_new:N \g__tblr_tracing_vline_bool
\bool_new:N \g__tblr_tracing_hline_bool
\bool_new:N \g__tblr_tracing_colspec_bool
\bool_new:N \g__tblr_tracing_rowspec_bool
\bool_new:N \g__tblr_tracing_target_bool
\bool_new:N \g__tblr_tracing_cellspan_bool
\bool_new:N \g__tblr_tracing_intarray_bool
\bool_new:N \g__tblr_tracing_page_bool
\bool_new:N \g__tblr_tracing_step_bool
\bool_gset_true:N \g__tblr_tracing_step_bool
\keys_define:nn { tblr-set-tracing }
{
+text .code:n = \bool_gset_true:N \g__tblr_tracing_text_bool,
-text .code:n = \bool_gset_false:N \g__tblr_tracing_text_bool,
+command .code:n = \bool_gset_true:N \g__tblr_tracing_command_bool,
-command .code:n = \bool_gset_false:N \g__tblr_tracing_command_bool,
+option .code:n = \bool_gset_true:N \g__tblr_tracing_option_bool,
-option .code:n = \bool_gset_false:N \g__tblr_tracing_option_bool,
+theme .code:n = \bool_gset_true:N \g__tblr_tracing_theme_bool,
-theme .code:n = \bool_gset_false:N \g__tblr_tracing_theme_bool,
+outer .code:n = \bool_gset_true:N \g__tblr_tracing_outer_bool,
-outer .code:n = \bool_gset_false:N \g__tblr_tracing_outer_bool,
+inner .code:n = \bool_gset_true:N \g__tblr_tracing_inner_bool,
-inner .code:n = \bool_gset_false:N \g__tblr_tracing_inner_bool,
+column .code:n = \bool_gset_true:N \g__tblr_tracing_column_bool,
-column .code:n = \bool_gset_false:N \g__tblr_tracing_column_bool,
+row .code:n = \bool_gset_true:N \g__tblr_tracing_row_bool,
-row .code:n = \bool_gset_false:N \g__tblr_tracing_row_bool,
+cell .code:n = \bool_gset_true:N \g__tblr_tracing_cell_bool,
-cell .code:n = \bool_gset_false:N \g__tblr_tracing_cell_bool,
+vline .code:n = \bool_gset_true:N \g__tblr_tracing_vline_bool,
-vline .code:n = \bool_gset_false:N \g__tblr_tracing_vline_bool,
+hline .code:n = \bool_gset_true:N \g__tblr_tracing_hline_bool,
-hline .code:n = \bool_gset_false:N \g__tblr_tracing_hline_bool,
+colspec .code:n = \bool_gset_true:N \g__tblr_tracing_colspec_bool,
-colspec .code:n = \bool_gset_false:N \g__tblr_tracing_colspec_bool,
+rowspec .code:n = \bool_gset_true:N \g__tblr_tracing_rowspec_bool,
-rowspec .code:n = \bool_gset_false:N \g__tblr_tracing_rowspec_bool,
+target .code:n = \bool_gset_true:N \g__tblr_tracing_target_bool,
-target .code:n = \bool_gset_false:N \g__tblr_tracing_target_bool,
+cellspan .code:n = \bool_gset_true:N \g__tblr_tracing_cellspan_bool,
-cellspan .code:n = \bool_gset_false:N \g__tblr_tracing_cellspan_bool,
+intarray .code:n = \bool_gset_true:N \g__tblr_tracing_intarray_bool,
-intarray .code:n = \bool_gset_false:N \g__tblr_tracing_intarray_bool,
+page .code:n = \bool_gset_true:N \g__tblr_tracing_page_bool,
-page .code:n = \bool_gset_false:N \g__tblr_tracing_page_bool,
+step .code:n = \bool_gset_true:N \g__tblr_tracing_step_bool,
-step .code:n = \bool_gset_false:N \g__tblr_tracing_step_bool,
all .code:n = \__tblr_enable_all_tracings:,
none .code:n = \__tblr_disable_all_tracings:,
}
\cs_new_protected_nopar:Npn \__tblr_enable_all_tracings:
{
\bool_gset_true:N \g__tblr_tracing_text_bool
\bool_gset_true:N \g__tblr_tracing_command_bool
\bool_gset_true:N \g__tblr_tracing_option_bool
\bool_gset_true:N \g__tblr_tracing_theme_bool
\bool_gset_true:N \g__tblr_tracing_outer_bool
\bool_gset_true:N \g__tblr_tracing_inner_bool
\bool_gset_true:N \g__tblr_tracing_column_bool
\bool_gset_true:N \g__tblr_tracing_row_bool
\bool_gset_true:N \g__tblr_tracing_cell_bool
\bool_gset_true:N \g__tblr_tracing_vline_bool
\bool_gset_true:N \g__tblr_tracing_hline_bool
\bool_gset_true:N \g__tblr_tracing_colspec_bool
\bool_gset_true:N \g__tblr_tracing_rowspec_bool
\bool_gset_true:N \g__tblr_tracing_target_bool
\bool_gset_true:N \g__tblr_tracing_cellspan_bool
\bool_gset_true:N \g__tblr_tracing_intarray_bool
\bool_gset_true:N \g__tblr_tracing_page_bool
\bool_gset_true:N \g__tblr_tracing_step_bool
}
\cs_new_protected_nopar:Npn \__tblr_disable_all_tracings:
{
\bool_gset_false:N \g__tblr_tracing_text_bool
\bool_gset_false:N \g__tblr_tracing_command_bool
\bool_gset_false:N \g__tblr_tracing_option_bool
\bool_gset_false:N \g__tblr_tracing_theme_bool
\bool_gset_false:N \g__tblr_tracing_outer_bool
\bool_gset_false:N \g__tblr_tracing_inner_bool
\bool_gset_false:N \g__tblr_tracing_column_bool
\bool_gset_false:N \g__tblr_tracing_row_bool
\bool_gset_false:N \g__tblr_tracing_cell_bool
\bool_gset_false:N \g__tblr_tracing_vline_bool
\bool_gset_false:N \g__tblr_tracing_hline_bool
\bool_gset_false:N \g__tblr_tracing_colspec_bool
\bool_gset_false:N \g__tblr_tracing_rowspec_bool
\bool_gset_false:N \g__tblr_tracing_target_bool
\bool_gset_false:N \g__tblr_tracing_cellspan_bool
\bool_gset_false:N \g__tblr_tracing_intarray_bool
\bool_gset_false:N \g__tblr_tracing_page_bool
\bool_gset_false:N \g__tblr_tracing_step_bool
}
\NewDocumentCommand \LogTblrTracing { m }
{
\keys_set:nn { tblr-log-tracing } {#1}
}
\keys_define:nn { tblr-log-tracing }
{
step .code:n = \__tblr_log_tracing_step:n {#1},
unknown .code:n = \__tblr_log_tracing:N \l_keys_key_str
}
\cs_new_protected:Npn \__tblr_log_tracing:N #1
{
\bool_if:cT { g__tblr_tracing_ #1 _bool }
{ \cs:w __tblr_log_tracing _ #1 : \cs_end: }
}
\cs_new_protected:Npn \__tblr_log_tracing_text:
{
\__tblr_spec_log:n { text }
}
\cs_new_protected:Npn \__tblr_log_tracing_command:
{
\__tblr_prop_log:n { command }
}
\cs_new_protected:Npn \__tblr_log_tracing_option:
{
\__tblr_prop_log:n { note }
\__tblr_prop_log:n { remark }
\__tblr_prop_log:n { more }
}
\cs_new_protected:Npn \__tblr_log_tracing_theme:
{
\__tblr_style_log:
}
\cs_new_protected:Npn \__tblr_log_tracing_outer:
{
\__tblr_spec_log:n { outer }
}
\cs_new_protected:Npn \__tblr_log_tracing_inner:
{
\__tblr_prop_log:n { inner }
}
\cs_new_protected:Npn \__tblr_log_tracing_column:
{
\__tblr_data_log:n { column }
}
\cs_new_protected:Npn \__tblr_log_tracing_row:
{
\__tblr_data_log:n { row }
}
\cs_new_protected:Npn \__tblr_log_tracing_cell:
{
\__tblr_data_log:n { cell }
}
\cs_new_protected:Npn \__tblr_log_tracing_vline:
{
\__tblr_spec_log:n { vline }
}
\cs_new_protected:Npn \__tblr_log_tracing_hline:
{
\__tblr_spec_log:n { hline }
}
\cs_new_protected:Npn \__tblr_log_tracing_colspec:
{
\tl_if_eq:NnT \g__tblr_column_or_row_tl { column }
{ \tl_log:N \g__tblr_expanded_colrow_spec_tl }
}
\cs_new_protected:Npn \__tblr_log_tracing_rowspec:
{
\tl_if_eq:NnT \g__tblr_column_or_row_tl { row }
{ \tl_log:N \g__tblr_expanded_colrow_spec_tl }
}
\cs_new_protected:Npn \__tblr_log_tracing_target:
{
\dim_log:N \l__column_target_dim
\prop_log:N \l__column_coefficient_prop
\prop_log:N \l__column_natural_width_prop
\prop_log:N \l__column_computed_width_prop
}
\cs_new_protected:Npn \__tblr_log_tracing_cellspan:
{
\prop_log:N \l__tblr_col_item_skip_size_prop
\prop_log:N \l__tblr_col_span_size_prop
\prop_log:N \l__tblr_row_item_skip_size_prop
\prop_log:N \l__tblr_row_span_size_prop
\prop_log:N \l__tblr_row_span_to_row_prop
}
\cs_new_protected:Npn \__tblr_log_tracing_page:
{
\dim_log:N \pagegoal
\dim_log:N \pagetotal
}
\cs_new_protected:Npn \__tblr_log_tracing_step:n #1
{
\bool_if:NT \g__tblr_tracing_step_bool { \tl_log:x {Step :~ #1} }
}
\cs_new_protected:Npn \__tblr_do_if_tracing:nn #1 #2
{
\bool_if:cT { g__tblr_tracing_ #1 _bool } {#2}
}
%%% --------------------------------------------------------
%%> \section{Tabularray Libraries}
%%% --------------------------------------------------------
%% \NewTblrLibrary and \UseTblrLibrary commands
\NewDocumentCommand \NewTblrLibrary { m m }
{
\cs_new_protected:cpn { __tblr_use_lib_ #1: } {#2}
}
\NewDocumentCommand \UseTblrLibrary { m }
{
\clist_map_inline:nn {#1} { \use:c { __tblr_use_lib_ ##1: } }
}
%% Library amsmath and environments +array, +matrix, +cases, ...
\NewTblrLibrary { amsmath }
{
\RequirePackage { amsmath }
\NewTblrEnviron { +array }
\SetTblrInner[+array]{colsep = 5pt}
\NewDocumentEnvironment { +matrix } { O{} +b } {
\begin{+array}{
column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt},
cells = {c}, ##1
}
##2
\end{+array}
} { }
\NewDocumentEnvironment { +bmatrix } { O{} +b } {
\begin{+array}{
column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt},
cells = {c}, delimiter = {left = [, right = ]}, ##1
}
##2
\end{+array}
} { }
\NewDocumentEnvironment { +Bmatrix } { O{} +b } {
\begin{+array} {
column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt},
cells = {c}, delimiter = {left = \lbrace, right = \rbrace}, ##1
}
##2
\end{+array}
} { }
\NewDocumentEnvironment { +pmatrix } { O{} +b } {
\begin{+array} {
column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt},
cells = {c}, delimiter = {left = (, right = )}, ##1
}
##2
\end{+array}
} { }
\NewDocumentEnvironment { +vmatrix } { O{} +b } {
\begin{+array} {
column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt},
cells = {c}, delimiter = {left = \lvert, right = \rvert}, ##1
}
##2
\end{+array}
} { }
\NewDocumentEnvironment { +Vmatrix } { O{} +b } {
\begin{+array} {
column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt},
cells = {c}, delimiter = {left = \lVert, right = \rVert}, ##1
}
##2
\end{+array}
} { }
\NewDocumentEnvironment { +cases } { O{} +b } {
\begin{+array} {
column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt},
colspec = {ll}, stretch = 1.2, delimiter = {left=\lbrace, right=.}, ##1
}
##2
\end{+array}
} { }
}
%% Library booktabs and commands \toprule, \midrule, \bottomrule
\NewTblrLibrary { booktabs }
{
% We only use dimensions \aboverulesep and \belowrulesep in booktabs package
\RequirePackage { booktabs }
\newcommand \tblr@booktabs@hline [1] [] { \hline [##1] }
\newcommand \tblr@booktabs@oldhline [1] [] {
\hline [##1]
\hborder { abovespace = \aboverulesep, belowspace = \belowrulesep }
}
\newcommand \tblr@booktabs@cline [2] [] { \cline [##1] {##2} }
\newcommand \tblr@booktabs@oldcline [2] [] {
\cline [##1] {##2}
\hborder { abovespace = \aboverulesep, belowspace = \belowrulesep }
}
\newcommand \tblr@booktabs@cline@more [2] [] { \SetHline [+] {##2} {##1} }
\newcommand \tblr@booktabs@oldcline@more [2] [] {
\SetHline [+] {##2} {##1}
\hborder { abovespace = \aboverulesep, belowspace = \belowrulesep }
}
\NewTableCommand \toprule [1] [] {
\tblr@booktabs@hline [wd=\heavyrulewidth, ##1]
}
\NewTableCommand \midrule [1] [] {
\tblr@booktabs@hline [wd=\lightrulewidth, ##1]
}
\NewTableCommand \bottomrule [1] [] {
\tblr@booktabs@hline [wd=\heavyrulewidth, ##1]
}
\NewTableCommand \cmidrule [2] [] {
\tblr@booktabs@cline [wd=\cmidrulewidth, endpos, ##1] {##2}
}
\NewTableCommand \cmidrulemore [2] [] {
\tblr@booktabs@cline@more [wd=\cmidrulewidth, endpos, ##1] {##2}
}
\newcommand \tblr@booktabs@change@more [1] { \cmidrulemore }
\NewTableCommand \morecmidrules {
\peek_meaning:NTF \cmidrule { \tblr@booktabs@change@more } { \relax }
}
\NewTblrEnviron { booktabs }
\NewTblrEnviron { longtabs }
\NewTblrEnviron { talltabs }
\SetTblrInner [ booktabs ] { rowsep = 0pt }
\SetTblrInner [ longtabs ] { rowsep = 0pt }
\SetTblrInner [ talltabs ] { rowsep = 0pt }
\SetTblrOuter [ longtabs ] { long }
\SetTblrOuter [ talltabs ] { tall }
\RequirePackage { etoolbox }
\newcommand \tblr@booktabs@begin@hook
{
\let \tblr@booktabs@hline = \tblr@booktabs@oldhline
\let \tblr@booktabs@cline = \tblr@booktabs@oldcline
\let \tblr@booktabs@cline@more = \tblr@booktabs@oldcline@more
}
\AtBeginEnvironment { booktabs } { \tblr@booktabs@begin@hook }
\AtBeginEnvironment { longtabs } { \tblr@booktabs@begin@hook }
\AtBeginEnvironment { talltabs } { \tblr@booktabs@begin@hook }
\NewTableCommand \specialrule [3]
{ \hline [##1] \hborder { abovespace = ##2, belowspace = ##3 } }
\NewTableCommand \addrowspace [1] [\defaultaddspace]
{ \hborder { abovespace+ = (##1) / 2, belowspace+ = (##1) / 2 } }
\NewTableCommand \addlinespace [1] [\defaultaddspace]
{ \hborder { abovespace+ = (##1) / 2, belowspace+ = (##1) / 2 } }
}
%% Library counter for resetting all counters
\tl_new:N \__tblr_saved_trial_counters_tl
\tl_new:N \__tblr_saved_cell_counters_tl
\cs_new_protected:Npn \__tblr_save_counters:n #1 { }
\cs_new_protected:Npn \__tblr_restore_counters:n #1 { }
%% We use code from tabularx package for resetting all LaTeX counters,
%% where internal macro \cl@@ckpt looks like the following:
%% \@elt{page} \@elt{equation} \@elt{enumi} \@elt{enumii} \@elt{enumiii} ...
\NewTblrLibrary { counter }
{
\cs_set_protected:Npn \__tblr_save_counters:n ##1
{
\def \@elt ####1 { \global\value{####1} = \the\value{####1} \relax }
\tl_set:cx { __tblr_saved_ ##1 _counters_tl } { \cl@@ckpt }
\let \@elt = \relax
}
\cs_set_protected:Npn \__tblr_restore_counters:n ##1
{
\tl_use:c { __tblr_saved_ ##1 _counters_tl }
}
}
%% Library diagbox and command \diagbox
\NewTblrLibrary { diagbox }
{
\RequirePackage{ diagbox }
\cs_set_eq:NN \__tblr_lib_saved_diagbox:w \diagbox
\NewContentCommand \diagbox [3] []
{
\__tblr_lib_diagbox_fix:n
{
\__tblr_lib_saved_diagbox:w
[ leftsep=\leftsep, rightsep=\rightsep, ##1 ]
{ \__tblr_lib_diagbox_math_or_text:n {##2} }
{ \__tblr_lib_diagbox_math_or_text:n {##3} }
}
}
\NewContentCommand \diagboxthree [4] []
{
\__tblr_lib_diagbox_fix:n
{
\__tblr_lib_saved_diagbox:w
[ leftsep=\leftsep, rightsep=\rightsep, ##1 ]
{ \__tblr_lib_diagbox_math_or_text:n {##2} }
{ \__tblr_lib_diagbox_math_or_text:n {##3} }
{ \__tblr_lib_diagbox_math_or_text:n {##4} }
}
}
}
\cs_new_protected:Npn \__tblr_lib_diagbox_math_or_text:n #1
{
\bool_if:NTF \l__tblr_cell_math_mode_bool {$#1$} {#1}
}
\box_new:N \l__tblr_diag_box
\cs_new_protected:Npn \__tblr_lib_diagbox_fix:n #1
{
\hbox_set:Nn \l__tblr_diag_box {#1}
\box_set_ht:Nn \l__tblr_diag_box { \box_ht:N \l__tblr_diag_box - \abovesep }
\box_set_dp:Nn \l__tblr_diag_box { \box_dp:N \l__tblr_diag_box - \belowsep }
\box_use:N \l__tblr_diag_box
}
%% Library functional with evaluate and process options
\cs_set_eq:NN \__tblr_functional_calculation: \prg_do_nothing:
\NewTblrLibrary { functional }
{
\RequirePackage { functional }
%% Add outer specification "evaluate"
\keys_define:nn { tblr-outer }
{ evaluate .code:n = \__tblr_outer_gput_spec:nn { evaluate } {##1} }
\tl_new:N \l__tblr_evaluate_tl
\cs_set_protected:Npn \__tblr_hook_split_before:
{
\tl_set:Nx \l__tblr_evaluate_tl
{ \__tblr_spec_item:nn { outer } { evaluate } }
\tl_if_empty:NF \l__tblr_evaluate_tl
{
\tl_if_eq:NnTF \l__tblr_evaluate_tl { all }
{
\tlSet \l__tblr_body_tl { \evalWhole {\expValue \l__tblr_body_tl} }
}
{
\exp_last_unbraced:NNV
\__tblr_evaluate_table_body:NN \l__tblr_body_tl \l__tblr_evaluate_tl
}
}
}
%% Evaluate every occurrence of the specified function
%% Note that funtional package runs every return processor inside a group
%% #1: tl with table content; #2: function to be evaluated
\tl_new:N \g__tblr_functional_result_tl
\cs_new_protected:Npn \__tblr_evaluate_table_body:NN ##1 ##2
{
\tl_gclear:N \g__tblr_functional_result_tl
\cs_set_protected:Npn \__tblr_evaluate_table_body_aux:w ####1 ##2
{
\tl_gput_right:Nn \g__tblr_functional_result_tl {####1}
\peek_meaning:NTF \q_stop { \use_none:n } {##2}
}
\fun_run_return_processor:nn
{
\exp_last_unbraced:NV \__tblr_evaluate_table_body_aux:w \gResultTl
}
{
\exp_last_unbraced:NV
\__tblr_evaluate_table_body_aux:w ##1 ##2 \q_stop
}
\tl_set_eq:NN ##1 \g__tblr_functional_result_tl
}
%% Add inner specification "process"
\clist_put_right:Nn \g__tblr_table_known_keys_clist { process }
\keys_define:nn { tblr }
{ process .code:n = \__tblr_keys_gput:nn { process } {##1} }
\cs_set:Npn \__tblr_functional_calculation:
{
\LogTblrTracing { step = do ~ functional ~ calculation }
\__tblr_prop_item:nn { inner } { process }
}
\prgNewFunction \cellGetText { m m }
{
\expWhole { \__tblr_spec_item:nn { text } { [##1][##2] } }
}
\prgNewFunction \cellSetText { m m m }
{
\__tblr_spec_gput:nnn { text } { [##1][##2] } {##3}
}
\prgNewFunction \cellSetStyle { m m m }
{
\tblr_set_cell:nnnn {##1} {##2} {} {##3}
}
\prgNewFunction \rowSetStyle { m m }
{
\tblr_set_row:nnn {##1} {} {##2}
}
\prgNewFunction \columnSetStyle { m m }
{
\tblr_set_column:nnn {##1} {} {##2}
}
}
%% Library nameref and its caption-ref template
\NewTblrLibrary { nameref }
{
\RequirePackage { nameref }
\clist_if_in:NnF \lTblrRefMoreClist { nameref }
{
\clist_put_right:Nn \lTblrRefMoreClist { nameref }
\DefTblrTemplate { caption-ref }{ nameref }
{
\tl_if_eq:NnTF \lTblrEntryTl { none }
{ \exp_args:NV \GetTitleString \lTblrCaptionTl }
{
\tl_if_empty:NTF \lTblrEntryTl
{ \exp_args:NV \GetTitleString \lTblrCaptionTl }
{ \exp_args:NV \GetTitleString \lTblrEntryTl }
}
\tl_set_eq:NN \@currentlabelname \GetTitleStringResult
}
}
}
%% Library siunitx and S columns
\NewTblrLibrary { siunitx }
{
\RequirePackage { siunitx }
\NewColumnType { S } [1] [] { Q[si = {##1}, c] }
\NewColumnType { s } [1] [] { Q[si = {##1}, c, cmd = \TblrUnit] }
\__tblr_data_new_key:nnn { cell } { si } { str }
\keys_define:nn { tblr-column }
{
si .code:n = \__tblr_siunitx_setcolumn:n {##1}
}
\cs_new_protected:Npn \__tblr_siunitx_setcolumn:n ##1
{
\__tblr_column_gput_cell:nn { si } {##1}
\__tblr_column_gput_cell:nn { cmd } { \TblrNum }
}
\NewDocumentCommand \TblrNum { m }
{
\__tblr_siunitx_process:Nn \tablenum {##1}
}
\NewDocumentCommand \TblrUnit { m }
{
\__tblr_siunitx_process:Nn \si {##1}
}
\cs_new_protected:Npn \__tblr_siunitx_process:Nn ##1 ##2
{
\tl_if_head_is_group:nTF {##2}
{ ##2 }
{
\group_begin:
\tl_set:Nx \l_tmpa_tl
{
\__tblr_data_item:neen { cell }
{ \int_use:N \c@rownum } { \int_use:N \c@colnum } { si }
}
\exp_args:NV \sisetup \l_tmpa_tl
##1 {##2}
\group_end:
}
}
\keys_define:nn { tblr-cell-spec } { guard .meta:n = { cmd = } }
\keys_define:nn { tblr-row } { guard .meta:n = { cmd = } }
\keys_define:nn { tblr-column } { guard .meta:n = { cmd = } }
}
%% Library varwidth and measure option
\NewTblrLibrary { varwidth }
{
\RequirePackage { varwidth }
\clist_gput_left:Nn \g__tblr_table_known_keys_clist { measure }
\keys_define:nn { tblr } { measure .tl_set:N = \l__tblr_inner_spec_measure_tl }
}
%% Library zref and its caption-ref template
\NewTblrLibrary { zref }
{
\RequirePackage { zref-user }
\clist_if_in:NnF \lTblrRefMoreClist { zref }
{
\clist_put_right:Nn \lTblrRefMoreClist { zref }
\DefTblrTemplate { caption-ref }{ zref }
{
\exp_args:NV \zlabel \lTblrLabelTl
}
}
}