% \iffalse meta-comment % % Copyright (C) 2016-2020 by Richard Grewe % ------------------------------------------------------- % % Thie file may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % https://www.latex-project.org/lppl.txt % and version 1.3c or later is part of all distributions of LaTeX % version 2008 or later. % % This file has the LPPL maintenance status "maintained". % % \fi % % \iffalse %<*driver> \ProvidesFile{keyvaltable.dtx} % %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{keyvaltable} %<*package> [2020/08/09 v2.3 Package for filling tables using key-value lists] % % %<*driver> \documentclass[svgnames]{ltxdoc} \usepackage{rgltxdoc}[2019/12/21 v1.3] \usepackage{etoc} \usepackage{amssymb}% \checkmark \EnableCrossrefs \CodelineIndex \RecordChanges \usepackage{xspace} \newcommand\thispackage{\pkgname{keyvaltable}\xspace} % the following packages are additional for the examples \usepackage{xintexpr} \usepackage{makecell,cellspace} \usepackage{gensymb}% for \degree \usepackage{tabularx,longtable,xltabular,tabu} \usepackage{filecontents} \usepackage{keyvaltable} \usepackage{datatool,csvsimple} \NewKeyValTable[ showhead=false,headformat={\bfseries\footnotesize}, rowbg=black!7!white..black!3!white, showrules=false, backend=tabu]{GoalApproach}{ id: align=r, default=(\alph{kvtRow}), head=\#; goal: align=X[l]; approach: align={X[2,l]}; } \newcommand\RecipePreset{% \NewKeyValTable{Recipe}{amount:align=r;ingredient:align=l;step:align=X}} % \usepackage{fontawesome} \makeatletter \newenvironment{NiceText}[2]{% \medskip\par\noindent \rgltxdoc@inmargin{\smash{\textcolor{#1}{\large#2}}}{\quad}% \ignorespaces}{\medskip\par\noindent} \newenvironment{NiceNote}{\NiceText{DarkBlue}{\faInfoCircle}}{\endNiceText} \newenvironment{NiceTipp}{\NiceText{DarkBlue}{\faLightbulbO}}{\endNiceText} \newenvironment{NiceWarn}{\NiceText{DarkBlue}{\faWarning}}{\endNiceText} % \end{macrocode} \makeatother % \begin{filecontents*}{recipes.csv} id,amount,ingredient,step snowman,3,balls of snow,staple all 3 balls snowman,1,carrot,stick into top ball snowman,2,coffee beans,put diagonally above carrot cherries,150g,ice cream,put into bowl cherries,50g,cherries,heat up and add to bowl \end{filecontents*} % \begin{document} \DocInput{keyvaltable.dtx} \PrintChanges \PrintIndex \end{document} % % \fi % % \CheckSum{0} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % \changes{v0.1}{2016/03/13}{Initial version} % \changes{v0.3b}{2018/11/01}{Package author's name change} % % \GetFileInfo{keyvaltable.dtx} % % \DoNotIndex{\newcommand,\newenvironment,\def,\gdef,\edef} % % % \title{The \thispackage package\thanks{This document % corresponds to \thispackage~\fileversion, dated \filedate. % The package is available online at % \url{http://www.ctan.org/pkg/keyvaltable} and % \url{https://github.com/Ri-Ga/keyvaltable}.}} % \author{Richard Grewe \\ \texttt{r-g+tex@posteo.net}} % % \maketitle % % \begin{abstract}\noindent % The \thispackage package's main goal is to facilitate % typesetting tables\ldots\medskip\\ % \begin{KeyValTable}{GoalApproach} % \Row{ % goal={\ldots easily and yet still looking rather nicely}, % approach={through horizontal rules and alternating row background % colors by default;}} % \Row{ % goal={\ldots in a way that separates content from presentation}, % approach={by table rows that are specified as lists of key-value % pairs, where the keys are column names and the corresponding % values are the content of the cell in this row in the respective % column;}} % \Row{ % goal={\ldots with re-usable layout for tables of the same type}, % approach={through named table types, of which each has a list of % columns as well as further properties such as the background % colors of rows; each column, in turn, has a name as well as % further properties such as the heading of the column and the % alignment of the column's content.}} % \end{KeyValTable} % \end{abstract} % % \etocsetnexttocdepth{1} % \etocmulticol[2]{\section*{Contents}} % \clearpage % % \section{Basic Usage}\label{sec:basic} % % We start with a basic usage example. An explanation of the involved % macros follows afterwards.\medskip % % \begin{LTXexample}[morekeywords={NewKeyValTable,Row,KeyValTable}] % \NewKeyValTable{Recipe}{ % amount: align=r; % ingredient: align=l; % step: align=X; % } % \begin{KeyValTable}{Recipe} % \Row{amount=150g, ingredient=ice cream, % step=put into bowl} % \Row{amount= 50g, ingredient=cherries, % step=heat up and add to bowl} % \end{KeyValTable} % \end{LTXexample} % The example code first defines a new table type, |Recipe|, along with % the columns that belong to this type. There are three columns % (|amount|, |ingredient|, and |step|), whose specifications are separated % with semicolons. After the separating |:|, for each column, the macro % configures the column alignment using the |align| key. The alignments % |r| (right) and |l| (left) are the standard |tabular| alignments; the % |X| alignment is provided by the \pkgname{tabularx} package (see the % documentation there). % % After defining the table type, the example creates a table of % the newly defined type. For this, the example uses the |KeyValTable| % environment and the |\Row| macro, once for each row. The parameter % |Recipe| of the |KeyValTable| identifies the type of the table. % In the parameter of the |\Row| macro, the content of the individual % cells can be specified by key-value pairs such as |amount=150g|, which % puts ``150g'' into the |amount| column of the respective row. % % The example above already shows that producing a rather nice-looking % table -- including alternating row colors as well as horizontal rules % -- without further ado. How the \thispackage package can be % used in the general case and how its visual appearance can be % customized is subject of the remainder of this documentation. % % \begin{NiceTipp} % To quickly sketch a table type, one can even omit properties % of columns and just list their names, separated by semicolons, as the % following example shows. All columns then get the default alignment: % |l|. % \end{NiceTipp} % \begin{LTXexample} % \NewKeyValTable{Recipe}{amount;ingredient;step} % \begin{KeyValTable}{Recipe} % \Row{amount=150g, ingredient=ice cream, % step=put into bowl} % \Row{amount= 50g, ingredient=cherries, % step=heat up and add to bowl} % \end{KeyValTable} % \end{LTXexample} % % % \section{Defining Table Types} % % As the example in \cref{sec:basic} shows, % |\NewKeyValTable| defines a table type. % % \NiceDescribeMacro{\NewKeyValTable}{\oarg{options}\marg{tname}\marg{colspecs}\oarg{layout}} % The macro defines a table type with name \meta{tname} whose columns % are specified by \meta{colspecs}. % The \meta{colspecs} parameter must be a semicolon-separated list. % Each column specification is of the form % \begin{center} % \meta{colname}|:| \meta{property}|=|\meta{value}|,| % \meta{property}|=|\meta{value}|,|\ldots % \end{center} % In such a specification, \meta{colname} represents the name of the % column. The \meta{property}|=|\meta{value} pairs configure certain % properties of the column. The \meta{property} can be one of the % following: % % \NiceDescribeKey{align}{vals={l,c,r,p,X,\ldots}, init=l} % This property specifies the alignment of content in the % column. The \meta{value} can be set to any column alignment % understood by table environments.\footnote{More complex values, for % instance using the notation of the \pkgname{array} package for % inserting material before or after a column, are permitted but not % further tested. Use at your own risk.} % % \NiceDescribeKey{default}{vals=\vmeta{content}, init=\vmeta{empty}} % This property specifies the default \meta{content} of a cell in this % column, i.e., in case that a \cmd{\Row} does not provide content for % the cell. Initially (i.e., if unset for a column), this is an % empty string. % % \NiceDescribeKey{format}{vals=\vmeta{single argument macro}, init=\vmeta{"identity"}} % This property specifies a formatting macro for content of the cell. % The macro can take one argument and is provided with the content of % the cell as its argument. Initially, the format is defined to take % the content as is.\footnote{Prior to version~2.3 of \thispackage, % the initial format setting was to put \cmd{\strut} before and after % the content to yield a better vertical row spacing in some % situations. See also \cref{sec:VertSpacing}.} % % \NiceDescribeKey{head}{vals=\vmeta{content}, init=\vmeta{colname}} % This property specifies the \meta{content} of the column's header % row. The initial value for this property is the name of the column. % % \NiceDescribeKey{hidden}{vals={true,false}, init=false, def=true} % This property specifies whether a table column shall be displayed or % not. The \meta{value} for this property can be |true| (to hide the % cell) or |false| (to display the cell). Using |hidden| without % \meta{value} is equivalent to specifying |hidden=true|. % % The following example shows all of the above column properties in % action. % % \begin{LTXexample}[morekeywords={align,default,format,head,hidden}] % \NewKeyValTable{ShoppingList}{ % what: head=article, format=\textbf; % amount: align=r, default=1; % why: hidden; % } % \begin{KeyValTable}{ShoppingList} % \Row{what=melon} % \Row{what=apples, amount=6} % \Row{what=bicycle, why=Bob's birthday} % \end{KeyValTable} % \end{LTXexample} % % The \meta{options} and \meta{layout} parameters of |\NewKeyValTable| % are described in \cref{sec:TableAppearance} and, respectively, % \cref{sec:CustomHeaders} of this documentation. % % % \section{Typesetting Tables}\label{sec:typesetting-tables} % % The \thispackage package offers three possibilities for typesetting % tables. % The first is in the traditional \hologo{LaTeX} form, in which there is % an environment that encloses the individual row specifications. % The second possibility is to specify rows throughout the document, bind % them to a name, and finally typeset a table from all rows bound to % the particular name. % The third possibility is to source the row specifications from a % file. % % \subsection{Specifying Rows in a Table Environment} % % The first possibility for typesetting a table using the % \thispackage package, is via the |KeyValTable| environment. % \cref{sec:basic} presents an example of this possibility. % % \NiceDescribeEnv{KeyValTable}{\oarg{options}\marg{tname}} % The |KeyValTable| environment creates a table of type \meta{tname}. % The type \meta{tname} must have been created using |\NewKeyValTable| % before. The environment itself already produces a table with the % columns specified for the table type, produces a header row and some % horizontal lines, and sets up background colors of rows. % The \meta{options} are described in \cref{sec:TableAppearance}. % % \NiceDescribeMacro{\Row}{\oarg{options}\marg{content}} % A table row is produced by the |\Row| macro. The % \meta{content} must be a comma-separated list of % \meta{cname}|=|\meta{text} pairs. The \meta{cname} identifies a column % that was registered for the table type \meta{tname}. The \meta{text} % specifies the content of the cell in the respective column. Each % column for which no \meta{text} is provided in \meta{content}, will % result in a cell that is filled with the column's default value. % The \meta{options} argument customizes row properties and is further % explained in \cref{sec:RowOptions}. % % % \subsection{Tables of Collected Rows}\label{sec:collected} % % The content of a table's rows might logically belong to locations that % are scattered throughout a document, e.g., to individual sections of % the document. In this situation, it can be convenient to have the rows % specified close to the locations their contents belong to, instead of % specified in the table environment. % % The following example illustrates the use of this feature for taking % and collecting notes in a document: % \begin{LTXexample}[width=0.475\hsize,morekeywords={NewCollectedTable,CollectRow,ShowCollectedTable}] % \NewKeyValTable{Notes}{type; text} % \NewCollectedTable{notes}{Notes} % % \subsection*{Notes} % \ShowCollectedTable{notes} % % \section{Introduction} % \CollectRow{notes}{type=remark, text=intro too long} % Lorem ipsum dolor sit amet, \ldots % % \section{Analysis} % \CollectRow{notes}{type=task, text=proofread Analysis} % Lorem ipsum dolor sit amet, \ldots % \end{LTXexample} % See \cref{sec:referencing} on how to (automatically) include % references to, e.g., section or page numbers in tables. % The key macros (highlighted in bold font) used in the example are the % following three. % % \NiceDescribeMacro{\NewCollectedTable}{\marg{cname}\marg{tname}} % This macro defines the name \meta{cname} for a new collection of % rows. The collection is associated with the table type \meta{tname}. % This macro must be used before |\CollectRow| for a \meta{cname}. % % \NiceDescribeMacro{\CollectRow}{\oarg{options}\marg{cname}\marg{content}} % This macro adds the row content \meta{content} and row options % \meta{options} to the row collection \meta{cname}. % % \NiceDescribeMacro{\ShowCollectedTable}{\oarg{options}\marg{cname}} % This macro typesets a table of the row collection \meta{cname}, with % the table options \meta{options}. % The table includes rows that are collected only afterwards in the % document. For this, \hologo{LaTeX} must be run at least two times. % % % \subsection{Sourcing Rows From a File} % % Rather than specifying the rows of a table inside a |KeyValTable| % environment, the rows can also be sourced from a file. % More concretely, this file must consist of the |\Row| macros that % specify the content of the rows. % For information on how to source rows from CSV files, see % \cref{sec:CSV}. % % \NiceDescribeMacro{\ShowKeyValTableFile}{\oarg{options}\marg{tname}\marg{filename}} % This macro produces a |KeyValTable| environment of type \meta{tname} % whose content is taken from the file \meta{filename}. % The \meta{options} specify the table options, which are directly % passed to the options argument of the |KeyValTable| environment. % % \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={ShowKeyValTableFile}] % \begin{filecontents}{snowman.kvt} % \Row{amount=3, ingredient=balls of snow, % step=staple all 3 balls} % \Row{amount=1, ingredient=carrot, % step=stick into top ball} % \Row{amount=2, ingredient=coffee beans, % step=put diagonally above carrot} % \end{filecontents} % \ShowKeyValTableFile{Recipe}{snowman.kvt} % \end{LTXexample} % % % \subsection{Tables of Collected Rows (Legacy Interface)} % % This section documents legacy functionality of \thispackage, that is % now superseded by the functionality described in \cref{sec:collected}. % The legacy functionality compares to the new functionality as follows: % \begin{itemize}[noitemsep] % \item Rows must be collected \emph{before} the place in the document % where they are displayed in a table. % \item For each table type, there can be only one collection of rows. % After the collection has been typeset in a table the collection is % emptied again. % \item Row content is not written into the aux file. This might be % relevant for very large tables. % \end{itemize} % The following macros and environments implement the functionality. % % \NiceDescribeMacro{\AddKeyValRow}{\marg{tname}\oarg{options}\marg{content}} % A table row is produced by the % |\AddKeyValRow| macro. The \meta{tname} % identifies the table type and the \meta{content} provides the content % of the cells in the row. The format of the \meta{content} is the same % as for the |\Row| macro described in % Section~\ref{sec:typesetting-tables}. % % \NiceDescribeMacro{\ShowKeyValTable}{\oarg{options}\marg{tname}} % A table of all the rows defined via |\AddKeyValRow| can be displayed % by the |\ShowKeyValTable| macro. The % parameters have the same meaning as for the |KeyValTable| environment. % This macro resets the list of rows for the specified table type. % % \NiceDescribeEnv{KeyValTableContent}{\marg{tname}} % For simplifying the addition of rows, the % |KeyValTableContent| environment can be used. In this % environment, the |\Row| macro can be used just like in the % |KeyValTable| environment. The only difference is that the % |KeyValTableContent| environment does not cause the table to be % displayed. For displaying the content collected in % |KeyValTableContent| environments, the |\ShowKeyValTable| macro can be % used. % % The following example demonstrates the use, based on the previously % defined |Recipe| table type. % \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={AddKeyValRow,KeyValTableContent,ShowKeyValTable}] % \AddKeyValRow{Recipe}{amount=3, % ingredient=balls of snow, % step=staple all 3 balls} % \begin{KeyValTableContent}{Recipe} % \Row{amount=1, ingredient=carrot, % step=stick into top ball} % \Row{amount=2, ingredient=coffee beans, % step=put diagonally above carrot} % \end{KeyValTableContent} % \ShowKeyValTable{Recipe} % \end{LTXexample} % % % \section{Row Numbering\,\&\,Labeling}\label{sec:row-numbering} % % The mechanism of default column values enables a simple means for % automatic row numbering, labeling, and referencing document entities. % % \subsection{Row Numbering} % % For row numbering, one can use one of three row counters provided by % the \thispackage package: |kvtRow|, |kvtTypeRow|, and |kvtTotalRow|. % The counters are explained after the following example, which % demonstrates the use for the case of the |kvtRow| counter. % % \begin{LTXexample}[morekeywords={thekvtRow,thekvtTypeRow}] % \NewKeyValTable[headformat=\textbf]{Numbered}{ % line: align=r, head=\#, % format=\textbf, % default=\thekvtRow; % text: align=l, head=Text} % \begin{KeyValTable}{Numbered} % \Row{text=First row} % \Row{text=Second row} % \end{KeyValTable} % \end{LTXexample} % % \NiceDescribeCounter{kvtRow}{} % The |kvtRow| counter counts the row in the \emph{current} table. The % row number excludes the header row of the table. If the table spans % multiple pages, the row number also excludes the repeated headings on % subsequent pages. % % \NiceDescribeCounter{kvtTypeRow}{} % The |kvtTypeRow| counter counts the rows in the current table and % includes the number of rows of all previous tables of the same type. % % \NiceDescribeCounter{kvtTotalRow}{} % The |kvtTotalRow| counter counts the rows in the current table and % includes the number of rows of all previous tables produced using the % \thispackage package. % % By default, all rows are counted by the aforementioned counters. % However, this default can be changed. % % \NiceDescribeKey{uncounted}{vals={true,false}, init=false, def=true} % This row option specifies whether the row shall not be counted % (|true|) or shall be counted (|false|). % If only |uncounted| is used without a value, this is equivalent to % |uncounted=true|. % The following example illustrates the option. % % \begin{LTXexample}[morekeywords={uncounted}, % morepreset={\NewKeyValTable[headformat=\textbf]{Numbered}{ % line: align=r,head=\#,format=\textbf,default=\thekvtRow; % text: align=l,head=Text}}] % \begin{KeyValTable}{Numbered} % \Row{text=First row} % \Row[uncounted]{line={--}, text=interlude} % \Row{text=Second row} % \end{KeyValTable} % \end{LTXexample} % % By default, all counters start at value $1$. Through the following % possibilities, this behavior can be changed. % % \NiceDescribeKey{resume}{vals={true,false}, init=false, def=true}\label{opt:resume} % This option is available in |KeyValTable| environments. When this % option is set to |true|, the value of the |kvtRow| counter is resumed % from the previous |KeyValTable| environment. The other two counters % are not affected by this option. % % \subsection{Row Labeling} % % Row numbering can easily be combined with row labeling. % The following example shows how the |format| column property can be % used for this purpose. % \begin{LTXexample}[morekeywords={kvtLabel}] % \NewKeyValTable{Labeled}{ % label: align=r, head=\textbf{\#}, % format=\kvtLabel{kvtRow}; % text: align=l, head=\textbf{Text}} % \begin{KeyValTable}{Labeled} % \Row{text=First row, label=first} % \Row{text=After row \ref{first}} % \end{KeyValTable} % \end{LTXexample} % % \NiceDescribeMacro{\kvtLabel}{\oarg{labelopts}\marg{counter}\marg{label}} % The |\kvtLabel| macro shows the current value of the \meta{counter} -- % in particular |kvtRow|, |kvtTypeRow|, and |kvtTotalRow| -- and sets % the \meta{label} to the value of \meta{counter}. When using the macro % with the |format| property, only the first argument (\meta{counter}) % must be provided, as the above example shows. The second argument % (\meta{label}) is provided by the respective cell content. % % The |\kvtLabel| macro should work well with packages that change the % referencing, like \pkgname{cleveref} or \pkgname{varioref}. When using a % package that adds an optional argument to the |\label| command (like % \pkgname{cleveref} does), the \meta{labelopts} can be used to pass an % optional argument to |\label|. This feature is demonstrated in % \cref{sec:package-cleveref}. % % \subsection{Referencing in Collected Rows}\label{sec:referencing} % % The previous sections show examples of referencing row numbers. % In tables of collected rows, it may be desirable to reference the % point in the document at which a row was collected. % The example in \cref{sec:collected} illustrates such a situation. % In the following, we augment that example by references to section and % page numbers. % % \begin{LTXexample}[width=0.5\hsize,morekeywords={NewCollectedTable,CollectRow,ShowCollectedTable}] % \NewKeyValTable{Notes2}{ % id: default=\thekvtRow.; % type; text; % where: default={\S\thesection\ (p.\@\thepage)};} % \NewCollectedTable{notes2}{Notes2} % % \subsection*{Notes} % \ShowCollectedTable{notes2} % % \section{Introduction} % \CollectRow{notes2}{type=remark, text=intro too long} % Lorem ipsum dolor sit amet, \ldots % % \section{Analysis} % \CollectRow{notes2}{type=task, text=proofread!} % Lorem ipsum dolor sit amet, \ldots % \end{LTXexample} % % The above example demonstrates that the correct section number is % referenced. Since the whole example is contained on a single page, the % example does not demonstrate that the page number (|\thepage|) in the % "where" column actually references the page in the document on which % the |\CollectRow| takes place. Note that the correct page will be % produced even when the |\CollectRow| is placed in a float, such as a % figure or table. % \begin{NiceWarn} % \hologo{LaTeX} internally implements a special treatment of % |\thepage| to make page references possible. For this reason, using % something like |\arabic{page}| to produce the page number will % presumably not work correctly. % \end{NiceWarn} % % The \thispackage package % \begin{itemize}[nosep] % \item takes the values of row counters (like |\thekvtRow|) from the % position of \emph{the row in the table} % but % \item takes the values of other counters such as the page counter and % the section counter from the \emph{point in the document where % \cmd{\CollectRow} is used}. % \end{itemize} % This takes into account that counter values can be obtained via % \cmd{\the\meta{ctrname}} (like |\thekvtRow| or |\thepage|) as well as % via macros like |\arabic|, |\roman| etc. % The following macros allow for declaring additional counters and % formatting macros to be taken into account by \thispackage. % % \NiceDescribeMacros{2} % {\kvtDeclareTableMacros}{\marg{macro-list}} % {\kvtDeclareTableCounters}{\marg{counter-list}} % These macros take a comma-separated list of macros (respectively % counters) and declares these as "table macros" ("table counters"). % A macro or counter declared this way is expanded only inside the table % environment and not at the point where |\CollectRow| is used. % The \thispackage already declares |\thekvtRow|, |\thekvtTypeRow|, and % |\thekvtTotalRow| as table macros and declares |kvtRow|, |kvtTypeRow|, % and |kvtTotalRow| as table counters. % % \NiceDescribeMacro{\kvtDeclareCtrFormatters}{\marg{macro-list}} % This macro takes a comma-separated list of macros and declares them as % macros for formatting counter values. Examples for such macros are % |\arabic|, |\alph|, |\Alph|, |\roman|, |\Roman|, |\fnsymbol|, which % \thispackage already declares. % When other counter-formatting macros shall be used in the |default| % value of a column, such as |\ordinal| of the \pkgname{fmtcount} % package, they have to be passed to |\kvtDeclareCtrFormatters| first. % % % \section{Changing the Appearance} % % The appearance (e.g., colors, rules) of a table can be changed at % the level of the overall table as well as for individual rows, % columns, and cells. % % \subsection{Table Appearance}\label{sec:TableAppearance} % % The appearance of a table can be configured through the \meta{options} % parameters of % \begin{itemize}[nosep] % \item |KeyValTable|, |\ShowKeyValTable|, and |\ShowKeyValTableFile| % (affecting the particular table), % \item |\NewKeyValTable| (affecting all tables of the table type), and % \item |\kvtSet| (affecting all tables). % \end{itemize} % In this list, the former take precedence over the latter. That is, % table options override table type options and table type options % override global options for all tables. % % In each case, \meta{options} must be specified as a comma-separated % list of \meta{property}|=|\meta{value} pairs. % The following \meta{property} keys can be configured. % % \NiceDescribeKeys{2} % {backend}{vals={tabular,tabularx,longtable,xltabular,tabu,longtabu}} % {shape}{vals={multipage,onepage}, init=multipage} % The |backend| property specifies the table environment to be used for % producing the table. A set of six environments is currently supported, % including environments that can span multiple pages and environments % whose columns can stretch/shrink to fill the available space ("|X|" % columns). % The |shape| property abstracts from the concrete environments. % In case of |multipage|, the table may span multiple pages and % depending on whether |X|-columns are used or not, an appropriate % environment is selected. In case of |onepage|, the table does not % split into multiple pages. % See \cref{sec:AltTabEnv} for more details on the available shapes and % backends. % Only one of |shape| and |backend| can be specified. If both are % specified, the property that is specified last wins. % % \NiceDescribeKey{width}{vals=\vmeta{dimension}, init=\cmd\linewidth} % This property specifies the width of the table, if the selected % |shape|/|backend| supports it (see \cref{sec:AltTabEnv}). % % \NiceDescribeKeys{2} % {valign}{vals={t,c,b}, init=\vmeta{empty}} % {halign}{vals={l,c,r}, init=\vmeta{empty}} % These two properties specify the vertical and, respectively, horizontal % alignment of the table, if the selected |shape|/|backend| supports it (see % \cref{sec:AltTabEnv}). % % \NiceDescribeKey{showhead}{vals={true,false}, init=true} % This property specifies whether the header row shall be shown. The % \meta{value} must be a Boolean (i.e., |true| or |false|), where |true| % specifies that the header row is shown and |false| specifies that the % header row is not shown. % % \NiceDescribeKeys{2} % {showrules}{vals={true,false}, init=true} % {norules}{vals={true,false}, init=false, def=true} % The |showrules| property specifies whether top and bottom rules as % well as a rule below the header row are drawn (|true|) or not % (|false|). The |norules| property serves the same purpose, but the % value |true| hides the rules and the value |false| causes the rules to % be drawn. % Note that both properties only affect the rules that \thispackage % produces automatically; rules manually added, e.g., via |\hline|, % |\midrule|, or |\MidRule| (see Section~\ref{sec:rules}) are not % affected by the properties. % % \NiceDescribeKey{headalign}{vals={\vmeta{empty} or \vmeta{coltype}}, init=\vmeta{empty}} % This property specifies the alignment for header cells. If left % empty, each header cell receives the same alignment as the respective % column. % % \NiceDescribeKey{headbg}{vals=\vmeta{color}, init={black!14}} % This property specifies the background color of the header rows. The % \meta{color} must be a single color specification that is understood % by the \pkgname{xcolor} package. The \meta{color} is passed directly % to the \cs{rowcolor} macro. If \meta{color} is empty, then no % background color is produced for the header row. % % \NiceDescribeKey{headformat}{vals=\vmeta{single argument macro}, init=\vmeta{"identity"}} % This property specifies a format to be applied to all header cells. % The value specified for the |headformat| key is used to format each % header. The value can be a macro that takes once argument, through % which it is provided the header (as specified in the column's |head| % property). Initially, an "identity" macro is used, meaning that each % |head| is taken without change. % % \NiceDescribeKey{rowbg}{vals=\vmeta{color}, init={white..black!10}} % This property specifies the background colors of content rows. The % \meta{value} for this property must be of the format % \meta{oddcolor}|..|\meta{evencolor}. The first row after the header is % colored with \meta{oddcolor}, the second row with \meta{evencolor}, % and so forth. Both colors must be understood by the \pkgname{xcolor} % package. If \meta{color} is empty, then no background color is % produced for content rows. % % \NiceDescribeKeys{2} % {norowbg}{vals={true,false}, init=false, def=true} % {nobg}{vals={true,false}, init=false, def=true} % These properties are shorthands for |rowbg={}| (turning off % background colors for content rows) and, respectively, for % |rowbg={},headbg={}| (turning off background colors for header rows % and for content rows). Using these options without a value is % equivalent to using |true| for the value. For instance, |nobg| is % equivalent to |nobg=true|. % % \vref{fig:TableOptionExamples} demonstrates the \meta{options} in % examples. % \begin{figure} % \begin{LTXexample}[morekeywords={showhead,rowbg}] % \kvtSet{format=\texttt} % \NewKeyValTable[showhead=false, % rowbg=blue!10..blue!15, % ]{TabOptions}{opt; val} % \begin{KeyValTable}{TabOptions} % \Row{opt=showhead, val=false} % \Row{opt=rowbg, val=blue!10..blue!15} % \end{KeyValTable} % \end{LTXexample} % \begin{LTXexample}[morepreset={\kvtSet{format=\texttt}},morekeywords={showrules,headbg,headalign,headformat,halign,norowbg}] % \NewKeyValTable[showrules=false,headbg=blue!25, % headalign=c,headformat=\textbf,norowbg, % halign=r, % ]{TabOptions2}{opt; val} % \begin{KeyValTable}{TabOptions2} % \Row{opt=showrules, val=false} % \Row{opt=headbg, val=blue!25} % \Row{opt=headalign, val=c} % \Row{opt=headformat, val=\string\textbf} % \Row{opt=norowbg, val=true} % \Row{opt=halign, val=r} % \end{KeyValTable} % \end{LTXexample} % \begin{LTXexample}[morepreset={\kvtSet{format=\texttt}},morekeywords={nobg,norules,valign,shape,width}] % \NewKeyValTable[valign=t,nobg,norules, % shape=onepage,width=3cm,headformat=\textbf, % ]{TabOptions3}{opt: align=X;} % \begin{KeyValTable}{TabOptions3} % \Row{opt=nobg} % \Row{opt=norules} % \end{KeyValTable} % \begin{KeyValTable}{TabOptions3} % \Row{opt={shape=onepage}} % \Row{opt={valign=t}} % \Row{opt={width=3cm}} % \end{KeyValTable} % \end{LTXexample} % \caption{Examples for table options} % \label{fig:TableOptionExamples} % \end{figure} % % \subsubsection{Table Styles and Resumable Options} % % Rather than specifying properties for individual tables or table % types, \thispackage also supports named \emph{table styles}. % % \NiceDescribeKey{style}{vals=\vmeta{list of style names}, init=\vmeta{empty}} % Through this property of tables or table types, a list of styles can % be applied to a single table or, respectively, a table type. Each % style must have been defined with |\kvtNewTableStyle| before. % % \NiceDescribeMacro{\kvtNewTableStyle}{\marg{name}\marg{options}} % This macro declares a new table style with the given \meta{name} and % defines it to be equivalent to using the given \meta{options}. % The \meta{name} must not already be defined. % % \NiceDescribeMacro{\kvtRenewTableStyle}{\marg{name}\marg{options}} % This macro re-defines an existing table style \meta{name} with new % \meta{options}. % % The following example demonstrates table styles for an individual % table. % % \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={style,kvtNewTableStyle}] % \kvtNewTableStyle{plain}{ % norules,nobg,headformat=\textbf} % \begin{KeyValTable}[style=plain]{Recipe} % \Row{amount=150g, ingredient=ice cream, % step=put into bowl} % \Row{amount= 50g, ingredient=cherries, % step=heat up and add to bowl} % \end{KeyValTable} % \end{LTXexample} % % \begin{NiceNote} % The \meta{options} in |\kvtNewTableStyle| can be left % empty. In this case, the table style does not have any effect on the % appearance of tables. However, the style can already be used for % "tagging" tables and table types, while the final options for the % style can be configured at a later point in time. % \end{NiceNote} % % Even without table styles, the appearance of the previous % |KeyValTable| can be used again through the following option. % \NiceDescribeKey{resume*}{vals={true,false}, init=false, def=true} % When set to |true|, this option makes the table use the options from % the previous |KeyValTable| environment. This option also implies the % |resume| option (see \vref{opt:resume}). % If the previous environment also used |resume*|, then the options of % its predecessor environment are used, and so forth. % Note that this means that table options are not accumulated over % subsequent uses of |resume*|. % This behavior is the same as in the \pkgname{enumitem} package. % % % \subsection{Column Appearance} % % Column appearance is configured through the parameters |align|, % |head|, |format|, and |default| of columns in |\NewKeyValTable|. % % % \subsection{Row Appearance}\label{sec:RowOptions} % % Through the \meta{options} argument of the % |\Row| % and the % |\KeyValRow| % macros, the appearance of rows can be configured. % As with other option arguments of the \thispackage package, the % options must be a comma-separated list of key-value pairs. % The following options are supported. % % \NiceDescribeKey{hidden}{vals={true,false}, init=false, def=true} % This property specifies whether the row shall be hidden (|true|) or % not (|false|). If only |hidden| is used without a value, this is % equivalent to |hidden=true|. % % \NiceDescribeKey{align}{vals={\vmeta{empty} or \vmeta{coltype}}, init=\vmeta{empty}} % This property specifies the alignment of the cells in the row. % If this property is not specified, the respective columns' alignment % is used. The alignment applies to normal cells as well as to cells % in column groups.\footnote{Note that the alignment does not override % the alignment specified in any \cs{multicolumn} if it is assigned to % a cell in the row.} % % \NiceDescribeKey{bg}{vals=\vmeta{color}, init=\vmeta{empty}} % This property specifies the background color for the particular row. % If this option is not specified (or set to an empty value % explicitly), the background color is determined by the |rowbg| % option of the table. % % \NiceDescribeKeys{3} % {format}{vals=\vmeta{single argument macro}, init=\vmeta{"identity"}} % {format*}{vals=\vmeta{single argument macro}, init=\vmeta{"identity"}} % {format!}{vals=\vmeta{single argument macro}, init=\vmeta{none}} % These properties specify formatting for all cells of the particular % row. The difference between the three properties is how they % interact with the column formats of the respective cells in the row. % The |format| property is applied to the cell content \emph{before} % the column format, and the |format*| property is applied % \emph{after} the column format. % The |format!| property overrides any column formats in the % respective row and also renders the |format| and |format*| % properties ineffective. % % \NiceDescribeKey{headlike}{vals={true,false}, init=false, def=true} % This property, when used without a value or with value |true|, % specifies that the row shall be formatted like a header row. % Concretely, the alignment, background color, and format of the row's % cells is then set to the values of the table's |headalign|, % |headbg|, and |headformat| properties. % % \begin{NiceNote} % Initial values for all row options can be set with % |\kvtSet{Row/|\meta{option}|=|\meta{value}|}| (see also % \cref{sec:kvtSet}). % \end{NiceNote} % % The following example demonstrates some of the options. % \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={hidden,above,bg,format}] % \begin{KeyValTable}{Recipe} % \Row{amount=150g, ingredient=ice cream, % step=put into bowl} % \Row{amount= 50g, ingredient=cherries, % step=heat up and add to bowl} % \Row[hidden]{amount=25g, ingredient=cream, % step=decorate on top} % \Row[above=1ex,bg=Gold,format=\textit]{ % step=serve with a smile} % \end{KeyValTable} % \end{LTXexample} % % % \subsubsection{Vertical Row Size \& Spacing}\label{sec:VertSpacing} % % When rows are narrow or appear to be narrow, extra spacing above and % below can be configured. There are (at least) three options for this. % % The first option is to use the following |\Row| options. % \NiceDescribeKeys{3} % {above}{vals=\vmeta{dimension}, init=\vmeta{empty}} % {below}{vals=\vmeta{dimension}, init=\vmeta{empty}} % {around}{vals=\vmeta{dimension}, init=\vmeta{empty}} % These properties specify extra vertical space above and, % respectively, below the row. The |around| property is a short-hand % for setting both, |above| and |below|, to the same value. % Note that the vertical space is currently not colored with the % row's background color but with the page's background color. % The argument, if provided, is directly passed to |\vspace|. % % The second option is to use the row |format| or a column's |format| % property to insert |\strut| macros around cell content. % For the |format|, the following macro exists. % % \NiceDescribeMacro{\kvtStrutted}{\oarg{inner}\marg{arg}} % This macro places a |\strut| before \meta{arg} and a |\strut| after % \meta{arg}. This has the effect that the first and last row of % \meta{arg} obtain a "natural" height and depth even if their content % is smaller. % The second |\strut| is omitted when it would cause a new line to be % produced. % See \cref{sec:row-numbering} for an example. % % The third option is using the \pkgname{cellspace} package and its % column alignments (e.g., |Sl| instead of |l|) along with the configurable dimensions |\cellspacetoplimit| and |\cellspacebottomlimit|. % The following example shows the second and the third option. % % \begin{LTXexample}[morekeywords={cellspace,kvtStrutted,cellspacetoplimit}] % \usepackage{cellspace} % \setlength{\cellspacetoplimit}{3pt} % \NewKeyValTable{VertSpacing}{ % normal; % struts: format=\kvtStrutted; % cellspace: align=Sl; % } % \begin{KeyValTable}{VertSpacing} % \Row{normal=normal size} % \Row{normal=\large Large} % \Row{struts=\large Large} % \Row{cellspace=\large Large} % \end{KeyValTable} % \end{LTXexample} % % % \subsubsection{Row Styles} % % Rather than specifying properties for individual rows, \thispackage % also supports named \emph{row styles}. % % \NiceDescribeKey{style}{vals=\vmeta{list of style names}, init=\vmeta{empty}} % Through this property of rows, a list of styles can be applied to the % row. Each style must have been defined with |\kvtNewRowStyle| before. % % \NiceDescribeMacro{\kvtNewRowStyle}{\marg{name}\marg{row-options}} % This macro declares a new row style with the given \meta{name} and % defines it to be equivalent to using the given \meta{row-options}. % The \meta{name} must not already be defined. % % \NiceDescribeMacro{\kvtRenewRowStyle}{\marg{name}\marg{row-options}} % This macro re-defines an existing row style \meta{name} with new % \meta{row-options}. % % The following example produces the same output as the previous % example, but uses row styles. % % \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={style,kvtNewRowStyle}] % \kvtNewRowStyle{optional}{hidden} % \kvtNewRowStyle{highlight}{above=1ex,bg=Gold} % \begin{KeyValTable}{Recipe} % \Row{amount=150g, ingredient=ice cream, % step=put into bowl} % \Row{amount= 50g, ingredient=cherries, % step=heat up and add to bowl} % \Row[style=optional]{amount=25g, % ingredient=cream, step=decorate on top} % \Row[style=highlight]{step=serve with a smile} % \end{KeyValTable} % \end{LTXexample} % % \begin{NiceNote} % The \meta{row-options} in |\kvtNewRowStyle| can be left empty. % In this case, the row style does not have any effect on the appearance % of rows. However, the style can already be used for "tagging" rows and % the final options for the style can be configured at a later point in % time. % \end{NiceNote} % % % \subsubsection{Rules Between Rows}\label{sec:rules} % % For placing additional horizontal rules between rows, the % \thispackage package provides the following two macros that are % available in |KeyValTable| environments. % % \NiceDescribeMacro{\MidRule}{\oarg{width}} % This macro puts a horizontal rule over the full width of the table, % with line width \meta{width}. The macro puts the same vertical % spacing above and below the rule, just like |\midrule| of the % \pkgname{booktabs} package. The difference to |\midrule| is that row % colors (as specified by the |rowbg| property) are respected. % The following example demonstrates the use of |\MidRule|. % % \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={MidRule}] % \begin{KeyValTable}{Recipe} % \Row{amount=150g, ingredient=ice cream, % step=put into bowl} % \Row{amount= 50g, ingredient=cherries, % step=heat up and add to bowl} % \MidRule % \Row{step=serve with a smile} % \end{KeyValTable} % \end{LTXexample} % % \NiceDescribeMacro{\CMidRule}{\oarg{width}\marg{columns}} % This macro puts horizontal rules below each of the columns in the % comma-separated list \meta{columns}. This comma-separated list can % also contain names of column groups. The rules all have line width % \meta{width}. The outcome is similar to what a set of |\cmidrule|'s % would produce, except that row colors are respected and that column % indexes need not be counted. % The following example demonstrates the use of |\CMidRule|. % % \begin{LTXexample}[morekeywords={CMidRule}] % \NewKeyValTable[headformat=\textbf]{Prices}{ % part; min: align=r; max: align=r}[ % headers={min+max: head=price}, % colgroups={price: span=min+max}] % \begin{KeyValTable}{Prices} % \Row{part=engine, min=2500\$, max=3000\$} % \Row{part=tires, min=500\$, max=700\$} % \CMidRule[2pt]{price} % \Row{part=$\Sigma$, min=3000\$, max=3700\$} % \end{KeyValTable} % \end{LTXexample} % % The following macros are provided for general use, in % normal table environments. % \newcommand\kvtparg[1]{\texttt{(}\meta{#1}\texttt{)}}% % \NiceDescribeMacros{4} % {\kvtRuleTop}{\oarg{width}\marg{color2}} % {\kvtRuleBottom}{\oarg{width}\marg{color1}} % {\kvtRuleMid}{\oarg{width}\marg{color1}\marg{color2}} % {\kvtRuleCMid}{\oarg{width}\kvtparg{trim}\marg{a-b}\marg{color1}\marg{color2}} % These macros are replacements for the macros |\toprule|, % |\bottomrule|, |\midrule|, and |\cmidrule| of the \pkgname{booktabs} % package, which do not integrate well with background colors of rows. % The arguments \meta{color1} and \meta{color2} take the background % color above and, respectively, below the rule. % % Note that while multiple |\cmidrule|s can follow each other and % produce rules at the same horizontal position, this is not possible % with |\kvtRuleCMid|. Instead, if multiple |\kvtRuleCMid|s are desired, % one can use the following macro: % \NiceDescribeMacro{\kvtRulesCMid}{\oarg{width}\marg{rlist}\marg{color1}\marg{color2}} % In this macro, \meta{rlist} is a comma-separated list of % "\kvtparg{trim}\marg{a-b}" pairs, where each \meta{trim} is optional. % Consider the \pkgname{booktabs} documentation for more information % about \meta{trim}. % % % \subsection{Cell Appearance} % % Individual cells can be formatted by using the respective % \hologo{LaTeX} code directly in the value of the cell. % One can disable the column's configured |format| for the cell by % using the starred column name in |\Row|. % The following example demonstrates starred column names. % % \begin{LTXexample} % \usepackage{url}\urlstyle{sf} % \NewKeyValTable{Links}{ % service; % url: format=\url } % \begin{KeyValTable}{Links} % \Row{service=CTAN, % url=ctan.org/pkg/keyvaltable} % \Row{service=github, % url=github.com/Ri-Ga/keyvaltable} % \Row{service=Google Play, url*=none} % \end{KeyValTable} % \end{LTXexample} % % \subsection{Setting Global Defaults}\label{sec:kvtSet} % % \NiceDescribeMacro{\kvtSet}{\marg{options}} % The \thispackage package allows changing the default values % globally for the parameters of tables and columns. This can be done by % using the |\kvtSet| macro. % % \begin{LTXexample}[morekeywords={kvtSet}] % \kvtSet{headbg=red,default=?,align=r} % \NewKeyValTable{Defaults}{x; y} % \begin{KeyValTable}{Defaults} % \Row{x=1} % \Row{y=4} % \end{KeyValTable} % \end{LTXexample} % % % \section{Customizing the Layout} % % The \thispackage package provides some means for altering tables % beyond those described in the previous sections. % Those means are described in the following. % % \subsection{Custom Table Headers}\label{sec:CustomHeaders} % % By default, a table type defined by |\NewKeyValTable| includes a % single header row and each column of the table type has a header cell % in this row. % Through the optional \meta{layout} parameter of |\NewKeyValTable|, % one can define multiple header rows and can define header cells that % span multiple columns. % % The following two examples illustrate how the |headers| key in the % \meta{layout} parameter can be used for specifying custom % headers.\footnote{In \thispackage v1.0, the \meta{layout} % parameter specified \emph{only} the headers and did not use a % \texttt{headers} key for this. For compatibility, this can be enabled % with the \texttt{compat=1.0} package option.} % The first example produces a single header row in which two columns % are grouped with a single header, one column has a normal header, and % in which one column is not provided with a header. % \begin{LTXexample} % \NewKeyValTable{Headers1}{ % id: align=r, default=\thekvtRow.; % amount: align=r; ingredient: align=l; % step: align=X; % }[headers={ % amount+ingredient: head=\textbf{ingredient}; % step: head=\textbf{step}, align=l; % } % ] % \begin{KeyValTable}{Headers1} % \Row{amount=150g, ingredient=ice cream, % step=put into bowl} % \Row{amount= 50g, ingredient=cherries, % step=heat up and add to bowl} % \end{KeyValTable} % \end{LTXexample} % % The second example shows how multiple header rows can be specified % and, particularly, how the normal column headers can be displayed % through the use of "|::|". % \begin{LTXexample}[width=0.5\hsize] % \NewKeyValTable[headformat=\textbf,headalign=c] % {Headers2}{ % date: align=r, head=date; % Berlin/min: align=r, head=min; % Berlin/max: align=r, head=max; % Paris/min: align=r, head=min; % Paris/max: align=r, head=max; % }[headers={ % Berlin/min+Berlin/max+Paris/min+Paris/max: % head=temperature\\ % Paris/min+Paris/max: head=Paris, underline; % Berlin/min+Berlin/max: head=Berlin, underline\\ % ::}] % \begin{KeyValTable}{Headers2} % \Row{date=01.01.1970, % Berlin/min=0\degree C, Berlin/max=...} % \end{KeyValTable} % \end{LTXexample} % % The syntax for a \meta{value} of the |headers| key in the % \meta{layout} parameter is as follows: % \begin{itemize}[noitemsep] % \item \meta{value} is a list, separated by "|\\|", where each % element in the list specifies the columns of a single header % \meta{row}. % \item Each \meta{row}, in turn, is also a % list. The elements of this list are separated by "|;|" (as in the % columns specification of |\NewKeyValTable|) and each element % specifies a header \meta{cell}. % \item Each \meta{cell} is of the form % \begin{center} % \meta{col}|+|\ldots|+|\meta{col}|:| \meta{property}|=|\meta{value}|,| % \meta{property}|=|\meta{value}|,|\ldots % \end{center} % where each \meta{col} is the name of a column. % The specified header cell then spans each of the listed columns. % The columns must be displayed consecutively, though not necessarily % in the same order in which they are specified in \meta{cell}. % \end{itemize} % The \meta{property}|=|\meta{value} pairs configure properties of the % header cell. Supported \meta{property} keys are the following. % % \NiceDescribeKey{align}{vals={\vmeta{alignment-letter},\vmeta{empty}}, init=c} % This property specifies the alignment of content in the header cell. % The \meta{value} can be set to any column alignment understood by % the underlying table environment used (see \cref{sec:AltTabEnv}). % This particularly includes |l|, |c|, |r|, and |p|, as well as |X| % for some of the table environments. % The initial value can be modified with % |\kvtSet{HeadCell/align=...}|. % % \NiceDescribeKey{head}{vals=\vmeta{text}, init=\vmeta{colspec}} % This property specifies the content of the header cell. % The initial value for this property is the column specification, % i.e., "\meta{col}|+|\ldots|+|\meta{col}". % % \NiceDescribeKey{underline}{vals={true,false}, init=false, def=true} % This property specifies whether the header cell shall be underlined, % to visually indicate that the columns in the header cell form a % logical group. % % % \subsection{Column Spanning} % % The \thispackage package supports column spanning via "column % groups". A column group is a collection of adjacent columns, has % its own name, and can be assigned a value just like "normal" columns % can be. % The following example demonstrates how column groups can be defined % and be used. % % \begin{LTXexample}[morekeywords={colgroups}] % \NewKeyValTable{AltRecipe}{ % amount: align=r, format=\textbf; % ingredient: align=l; % step: align=X; % }[colgroups={ % all: span=step+amount+ingredient % }] % \begin{KeyValTable}{AltRecipe} % \Row{amount=150g, ingredient=ice cream, % step=put into bowl} % \Row{amount= 50g, ingredient=cherries, % step=heat up and add to bowl} % \MidRule % \Row{all=serve with a smile} % \end{KeyValTable} % \end{LTXexample} % % As the example shows, column groups are defined through the % |colgroups| key of the second optional argument of |\NewKeyValTable|. % This key expects a semicolon-separated list of individual column % groups definitions. % Each such definition takes the same shape as a normal column % definition -- that is, first the name of the column group, then a % colon, and then a comma-separated list of column properties. % The properties that can be set are the following. % % \NiceDescribeKey{span}{vals=\vmeta{plus-separated columns}} % This property specifies which columns the column group shall span, as % a plus-separated list of column names. Some or all of the columns can % be hidden. All the displayed columns must be adjacent in the table, % though. % % \NiceDescribeKeys{2} % {align}{vals={\vmeta{alignment-letter},\vmeta{empty}}, init=c} % {format}{vals=\vmeta{single argument macro}, init=\vmeta{"identity"}} % These properties are analogous to the respective properties of normal % columns. The only difference is that the initial column alignment of % column groups is "|c|" while the alignment of normal columns is "|l|". % % \begin{NiceNote} % Initial values for all the |align| and |format| options can be % set with |\kvtSet|, via the |ColGroup/align| and, respectively % |ColGroup/format| keys (see also \cref{sec:kvtSet}). % \end{NiceNote} % % % \subsubsection{Manual Column Spanning} % % The |\multicolumn| macro can be used for the content of a cell. % The effect of this is that a number of subsequent cells are spanned % over with the content of the cell. The following example demonstrates % the use. % \begin{LTXexample}[width=0.475\hsize,morekeywords={multicolumn}] % \NewKeyValTable{MultiCol}{ % col1: align=l; % col2: align=l; % col3: align=l;} % \begin{KeyValTable}{MultiCol} % \Row{col1=1, col2=\multicolumn{1}{r}{2}, col3=3} % \Row{col1=1, col2=\multicolumn{2}{c}{2+3}} % \Row{col1=\multicolumn{2}{c}{1+2}, col3=3} % \Row{col1=\multicolumn{3}{c}{1+2+3}} % \end{KeyValTable} % \end{LTXexample} % A word of warning: % The |\multicolumn| macro implicitly constrains the ordering of % columns. For instance, in the above example, switching columns 2 and 3 % would lead to an error in the second row (because |col2| is the % rightmost column and therefore cannot span two columns) and also in % the third row (because |col1| spans two columns but the second, |col3| % is not empty). Thus, column spanning via |\multicolumn| should be used % with care. % % % \subsection{Captions} % % There are two ways to add captions to \pkgname{keyvaltable} tables: % The first way is to enclose the table in a |table| environment. This % is particularly suit for tables that do not span multiple pages, such % as those produced through the |onepage| shape or the backends % |tabular|, |tabularx|, and |tabu| (see \cref{sec:AltTabEnv}). % % \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={caption,label,ref}] % \begin{table} % \begin{KeyValTable}[shape=onepage]{Recipe} % \Row{amount=150g, ingredient=ice cream, % step=put into bowl} % \Row{amount= 50g, ingredient=cherries, % step=heat up and add to bowl} % \end{KeyValTable} % \caption{Cherries++} % \label{Cherries} % \end{table} % Table~\ref{Cherries} shows the recipe. % \end{LTXexample} % % The second way to add captions is through the |caption| option of % \pkgname{keyvaltable} tables. This option is available for the % "multipage" shape and, respectively, the table backends |longtable|, % |xltabular|, and |longtabu| (see \cref{sec:AltTabEnv}). % % \NiceDescribeKeys{4} % {caption}{vals=\vmeta{text}, init=\vmeta{none}} % {caption/lot}{vals=\vmeta{text}, init=\vmeta{none}} % {caption/alt}{vals=\vmeta{text}, init=\vmeta{none}} % {label}{vals=\vmeta{name}, init=\vmeta{none}} % These options set the caption and, respectively, label of a table. % Through the option |caption/lot|, the caption to be put into the list % of tables can be specified; if omitted, |caption| is used. % Through the option |caption/alt|, the alternative caption to be % displayed on those pages of multipage tables where the main caption is % not shown; if omitted, no caption is displayed on these pages. % % The position of the caption is determined by the following option. % % \NiceDescribeKey{captionpos}{vals={t,b}, init=b} % This option specifies the position of table captions. Value "|t|" % specifies that captions are at the top of (above) their tables; value % "|b|" specifies that captions are at the bottom of (below) their % tables. % Moreover, in case of "|t|" the main caption is on top of the % \emph{first} page of a table while in case of "|b|" the main caption % is at the bottom of the \emph{last} page of a table. % % The following example shows the options in action. % % \begin{LTXexample}[morepreset=\RecipePreset\setcounter{table}{0},morekeywords={caption,label,ref}] % \begin{KeyValTable}[captionpos=t, % caption=Cherries++, label=Cherries2]{Recipe} % \Row{amount=150g, ingredient=ice cream, % step=put into bowl} % \Row{amount= 50g, ingredient=cherries, % step=heat up and add to bowl} % \end{KeyValTable} % Table~\ref{Cherries2} shows the recipe. % \end{LTXexample} % % % \subsection{Alternative Table Environments} % \label{sec:AltTabEnv} % The \thispackage package internally uses traditional table % environments, such as |tabular|, for typesetting the actual tables. % Through the |shape| and |backend| properties of a table or table type, % the table environment used by for the table or, respectively, table % type can be changed. % \Vref{tab:TabEnv} compares the possible shapes/environments with % regards to % \begin{itemize}[nosep] % \item whether they support tables that span multiple pages, % \item whether they support |caption| and |label| options, % \item whether they support |X|-type (variable-width) columns, % \item whether their width can be specified (through the |width| % option), and % \item whether they support a vertical or horizontal alignment of the % table to be specified. % \end{itemize} % Finally, the table also lists the names of the packages that provide % the respective environments. The packages for the shapes |onepage| and % |multipage| are loaded automatically. All other packages must be % loaded via |\usepackage| when the respective shape or backend shall be % used. % \begin{table}\centering % \newcommand\RHead[1]{\rotatebox{90}{\small\varwidth{\linewidth}#1\endvarwidth}}% % \newcommand\YesNo[1]{\ifstrequal{#1}{yes}{\checkmark}{}}% % \NewKeyValTable[backend=tabular,headformat=\sffamily\textbf]{ShapeProps}{ % shape: format=\small\texttt; % env: format=\small\texttt, head=backend; % multipage: align=c, head=\RHead{multipage}, format=\YesNo; % caption: align=c, head=\RHead{caption}, format=\YesNo; % Xcols: align=c, head=\RHead{\texttt{X} columns}, format=\YesNo; % width: align=c, head=\RHead{width}, format=\YesNo; % align: align=c, head=\RHead{align}, format=\textsf; % packages: align=l, format=\pkgnames}% % \begin{KeyValTable}{ShapeProps} % \Row{shape=onepage, env=tabular/tabularx, multipage=no, caption=no, Xcols=yes, width=yes, align=v, packages=tabularx} % \Row{shape=multipage, env=longtable/xltabular, multipage=yes, caption=yes, Xcols=yes, width=yes, align=h, packages={longtable, xltabular}} % \MidRule % \noalign{\footnotesize with package option |compat=1.0|:} % \Row{shape=onepage, env=tabu, multipage=no, caption=no, Xcols=yes, width=yes, align=v, packages=tabu} % \Row{shape=multipage, env=longtabu, multipage=yes, caption=yes, Xcols=yes, width=yes, align=h, packages={tabu, longtable}} % \MidRule % \Row{ env=tabular, multipage=no, caption=no, Xcols=no, width=no, align=v} % \Row{ env=tabularx, multipage=no, caption=no, Xcols=yes, width=yes, align=v, packages={tabularx}} % \Row{ env=longtable, multipage=yes, caption=yes, Xcols=no, width=no, align=h, packages={longtable}} % \Row{ env=xltabular, multipage=yes, caption=yes, Xcols=yes, width=yes, align=h, packages={xltabular}} % \Row{ env=tabu, multipage=no, caption=no, Xcols=yes, width=yes, align=v, packages={tabu}} % \Row{ env=longtabu, multipage=yes, caption=yes, Xcols=yes, width=yes, align=h, packages={tabu,longtable}} % \end{KeyValTable} % \caption{Comparison of table shapes and backends} % \label{tab:TabEnv} % \end{table} % % Examples can be found in \vref{fig:TableTypes}. % \begin{figure}[p] % \begin{LTXexample}[width=0.475\hsize, % morekeywords={tabular,longtable}] % \NewKeyValTable[showrules=false]{ShapeNoX}{ % id: align=l, default=\thekvtTypeRow; % l: align=l; c: align=c; r: align=r;}[headers={ % l+c+r: head=\textbf{\kvtTableOpt{shape} shape}\\ ::}] % % \begin{KeyValTable}[backend=tabular]{ShapeNoX} % \Row{l=left, c=center, r=right} % \Row{l=left-2, c=2-center-2, r=2-right} % \end{KeyValTable}\\ % \begin{KeyValTable}[backend=longtable]{ShapeNoX} % \Row{l=left, c=center, r=right} % \Row{l=left-2, c=2-center-2, r=2-right} % \end{KeyValTable} % \end{LTXexample} % % \begin{LTXexample}[width=0.475\hsize, % morekeywords={tabularx,xltabular,tabu,longtabu}] % \NewKeyValTable[showrules=false]{ShapeWithX}{ % id: align=l, default=\thekvtTypeRow; % l: align=l; X: align=X; r: align=r;}[headers={ % l+X+r: head=\textbf{\kvtTableOpt{shape} shape}\\ ::}] % % \begin{KeyValTable}[backend=tabularx]{ShapeWithX} % \Row{l=left, X=expandable, r=right} % \Row{l=left-2, X=expandable-2, r=2-right} % \end{KeyValTable}\medskip\\ % \begin{KeyValTable}[backend=xltabular]{ShapeWithX} % \Row{l=left, X=expandable, r=right} % \Row{l=left-2, X=expandable-2, r=2-right} % \end{KeyValTable} % \begin{KeyValTable}[backend=tabu]{ShapeWithX} % \Row{l=left, X=expandable, r=right} % \Row{l=left-2, X=expandable-2, r=2-right} % \end{KeyValTable} % \begin{KeyValTable}[backend=longtabu]{ShapeWithX} % \Row{l=left, X=expandable, r=right} % \Row{l=left-2, X=expandable-2, r=2-right} % \end{KeyValTable} % \end{LTXexample} % \caption{Examples for the backend option} % \label{fig:TableTypes} % \end{figure} % % ^^M The following \clearpage is a hack! It fixes the page breaking % ^^M that is messed up because of the longtable/xltabular/longtabu % ^^M in fig:TableTypes. % \clearpage % \section{Use with Other Packages} % % \subsection{Named References (\pkgname{cleveref})}\label{sec:package-cleveref} % % The |\kvtLabel| feature of the \thispackage package can be % used together with named references, as provided by the % \pkgname{cleveref} package. A name to a row label can be given by using % the optional first argument to the |\kvtLabel| formatting macro and % specifying the name to use using |\crefname|. The following example % uses ``row'' for the optional argument and ``line'' for the displayed % name of the reference. % \begin{LTXexample} % \usepackage{cleveref} % \crefname{row}{line}{lines} % \NewKeyValTable[headformat=\textbf]{NamedRef}{ % label: align=r, head=Line, % format=\kvtLabel[row]{kvtRow}; % text: align=l, head=Text} % \begin{KeyValTable}{NamedRef} % \Row{text=First row, label=one} % \Row{text=After \cref{one}} % \end{KeyValTable} % \end{LTXexample} % % % \subsection{Tables from CSV Files (\pkgname{datatool} and \pkgname{csvsimple})}\label{sec:CSV} % % The \thispackage package itself does not offer its own functionality % for generating tables from CSV files. However, together with existing % CSV packages, table content can be sourced from CSV files. % The remainder of this section shows how this can be achieved by % example. The following CSV file serves as the data file in the % examples. We use the same |Recipe| table type as previously. % % \lstinputlisting[caption=recipes.csv]{recipes.csv} % % \paragraph{\pkgname{datatool}} % The package provides a variety of macros for loading and also % displaying CSV database content. The following shows how the macros % |\DTLloaddb| and |\DTLforeach*| can be used, together with % |\AddKeyValRow| and |\ShowKeyValTable|. % The example also shows how a simple filter can be applied to the rows % via |\DTLforeach*|. % % \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={DTLloaddb,DTLforeach,expandonce}] % \usepackage{datatool} % \DTLloaddb{recipes}{recipes.csv} % \DTLforeach*[\equal{\Id}{snowman}]{recipes} % {\Id=id, % \Amount=amount,\Ingr=ingredient,\Step=step} % {\AddKeyValRow{Recipe}[expandonce]{ % amount=\Amount,ingredient=\Ingr,step=\Step}} % \ShowKeyValTable{Recipe} % \end{LTXexample} % % Two aspects shall be noted. % Firstly, we use |\AddKeyValRow| rather than |KeyValTable|, % because |\DTLforeach*| interferes with how |KeyValTable| constructs % its rows and yields "misplaced |\noalign|" errors. We do not use % |\CollectRow| here, because it requires two runs and we do not need % the feature to show the table before the rows are specified. % Secondly, we use the row option |expandonce| to ensure that the macros % |\Amount|, |\Ingr|, and |\Step| are expanded (i.e., replaced by their % values). Without this option, all rows would only carry the three % macros and display the value that these macros have at the time of the % |\ShowKeyValTable|. % % \NiceDescribeKeys{2} % {expandonce}{vals={true,false}, init=false, def=true} % {expand}{vals={true,false}, init=false, def=true} % These row options can be used when programmatically constructing the % rows of a table, particularly with |KeyValTableContent| and % |\CollectRow|. % The |expandonce| option expands all the cell values % given to a row (default values not included) exactly once before % including it in the respective row. % The |expand| option fully expands the cell values, in |protect|'ed % mode (i.e., robust commands are not expanded). % % % \paragraph{\pkgname{csvsimple}} % For the sake of our example, using this package is very similar to % using \pkgname{datatool}. % % \begin{LTXexample}[morepreset=\RecipePreset,morekeywords={csvreader,expand}] % \usepackage{csvsimple} % \csvreader[head to column names, % filter equal={\id}{cherries}]{recipes.csv}{} % {\AddKeyValRow{Recipe}[expand]{ % amount=\amount,ingredient=\ingredient, % step=\step}} % \ShowKeyValTable{Recipe} % \end{LTXexample} % % Two differences are noteworthy here: % First, we can avoid specifying macro names for the columns through the % |head to column names|, which uses the column names as macro names. % Second, we have to use the |expand| option rather than |expandonce| % here, because \pkgname{csvsimple} apparently does not directly store % the column value in the respective macro. % % % \subsection{Computational Cells (\pkgname{xint})} % % The mechanism of cell formatting macros enables a simple means for % automatically computing formulas contained in a column. This can be % done, for instance using the \pkgname{xint} package and defining a % custom format macro (here |\Math|) that takes over the computation. % \begin{LTXexample} % \usepackage{xintexpr} % \newcommand\Math[1]{% % \xinttheexpr trunc(#1, 1)\relax} % \NewKeyValTable{Calculating}{ % type; value: align=r,format=\Math} % \begin{KeyValTable}{Calculating} % \Row{type=simple, value=10+5.5} % \Row{type=advanced, value=0.2*(9+2^8)} % \end{KeyValTable} % \end{LTXexample} % % % \subsection{Cell Formatting (\pkgname{makecell})} % % The \thispackage package can be used together with the % \pkgname{makecell} package in at least two ways: % \begin{enumerate}[noitemsep] % \item formatting header cells using the |head| property of columns; % \item formatting content cells using the |format| property of columns. % \end{enumerate} % The following example gives an impression. % \begin{LTXexample} % \usepackage{makecell} % \renewcommand\theadfont{\bfseries} % \renewcommand\theadalign{lt} % \NewKeyValTable{Header}{ % first: head=\thead{short}; % second: head=\thead{two\\ lines};} % \begin{KeyValTable}{Header} % \Row{first=just a, second=test} % \end{KeyValTable} % \end{LTXexample} % % % \clearpage % \section{Related Packages} % % I'm not aware of any \LaTeX{} packages that pursue similar goals or % provide similar functionality. The following \LaTeX{} packages provide % loosely related functionalities to the \thispackage package. % % \begin{description} % \item[\pkgname{tablestyles}:] % This package simplifies typesetting tables with common and/or more % appealing appearances than default \hologo{LaTeX} tables. % This corresponds to what \thispackage supports with the various % coloring and formatting options to |\kvtSet|, |\NewKeyValTable|, and % individual tables. % The \pkgname{tablestyles} package builds on the default % \hologo{LaTeX} environments and syntax for typesetting tables (with % column alignments specified in an argument to the table environment, % and columns separated by |&| in the body of the environment). % \item[\pkgname{ctable}:] % This package focuses on typesetting tables with captions and notes. % With this package, the specification of table content is quite % close to normal |tabular| environments, except that the package's % table creation is done via a macro, |\ctable|. % \item[\pkgname{easytable}:] % This package provides an environment |TAB| which simplifies the % creation of tables with particular horizontal and vertical cell % alignments, rules around cells, and cell width distributions. In % that sense, the package aims at simpler table creation, like % \thispackage. However, the package does not pursue % separation of content from presentation or re-use of table layouts. % \item[\pkgname{tabularkv}:] % Despite the similarity in the name, this package pursues a different % purpose. Namely, this package provides means for specifying table % options such as width and height through an optional key-value % argument to the |tabularkv| environment. This package does not use % a key-value like specification for the content of tables. % \end{description} % % \section{Future Work} % % \begin{itemize} % \item support for different headers on the first page vs.\@ on % subsequent pages of a multipage table; support configurable spacing % between and above/below header rows % \item support for more flexibility with regards to specifying % distinct captions on first/middle/last page of the table. % \item improved row coloring that makes sure that the alternation % re-starts on continued pages of a table that spans several pages % \item rerun detection for recorded rows (possibly via % \pkgname{rerunfilecheck}) % \item nesting of |KeyValTable| environments (this is so far not tested % by the package author and might not work or work only to a limited % extent) % \end{itemize} % % \clearpage % % \StopEventually{} %\iffalse %<*package> %\fi % % \section{Implementation} % \etocsetnexttocdepth{2} % \etoclocalmulticol[2]{\subsection*{Content}} % % \subsection{Package Dependencies} % % We use \pkgname{etoolbox} for some convenience macros that make the % code more easily maintainable and use \pkgname{xkeyval} for options % in key--value form. The \pkgname{trimspaces} package is used once for % trimming spaces before a string comparison. % \begin{macrocode} \RequirePackage{etoolbox} \RequirePackage{xkeyval} \RequirePackage{trimspaces} % \end{macrocode} % We use \pkgname{booktabs} for nice horizontal lines, % \pkgname{colortbl} for row coloring, and \pkgname{xcolor} for color % names. To avoid package option clashes with \pkgname{xcolor}, we % load it at the end of the preamble.. % \changes{v2.3}{2020/06/13}{Delayed loading of \pkgname{xcolor}} % \begin{macrocode} \RequirePackage{colortbl} \AtBeginDocument{\@ifpackageloaded{xcolor}{}{\RequirePackage{xcolor}}} \RequirePackage{booktabs} % \end{macrocode} % % \subsection{Auxiliary Code} % % \subsubsection{List Parsing} % % \begin{macro}{\kvt@DeclareTrimListParser} % The |\kvt@DeclareTrimListParser|(|*|)\marg{command}\marg{separator} % macro is equivalent to \pkgname{etoolbox}'s |\DeclareListParser|, % except that the \meta{command} is defined such that it will remove % trailing spaces from list elements before passing the list elements to % the processing macro (i.e., to |\do| or the user-provided macro). % Note: With |\DeclareListParser|, \meta{command} is defined to only % remove leading spaces but not trailing ones. % This implementation relies on the internals of % \pkgname{etoolbox} and works with v2.4 of the package, at least. % \begin{macrocode} \newcommand\kvt@DeclareTrimListParser{% \@ifstar{\kvt@DeclareTrimListParser@i{*}} {\kvt@DeclareTrimListParser@i{}}} \newcommand\kvt@DeclareTrimListParser@i[3]{% \DeclareListParser#1{#2}{#3}\expandafter \patchcmd\csname etb@lst@\expandafter\@gobble\string#2\endcsname {\etb@listitem}{\kvt@etb@listitem}{} {\kvt@warn{Failed to patch a command defined by the etoolbox package, possibly because etoolbox internals have changed. You might encounter superfluous spaces.}}} % \end{macrocode} % The cascade of |\expandafter| below ensures that first the trimming % macro is expanded and afterwards the outer |\unexpanded| of the % timming macro's expansion is expanded, which by definition of the % "noexp" trimming macro fully expands the macro's logic. % The auxiliary macro below is only for switching the two arguments such % that the expansion control can be applied to the second argument. % \begin{macrocode} \newcommand\kvt@etb@listitem[2]{% \expandafter\expandafter\expandafter\kvt@etb@listitem@i \expandafter\expandafter\expandafter{\trim@post@space@noexp{#2}}{#1}} \newcommand\kvt@etb@listitem@i[2]{\etb@listitem{#2}{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@dossvlist} % The |\kvt@dossvlist|\marg{list} macro parses a semicolon-separated % list and runs |\do|\meta{item} for every element of the list. % \begin{macrocode} \DeclareListParser{\kvt@dossvlist}{;} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@forpsvlist} % The |\kvt@forpsvlist|\marg{handler}\marg{list} parses a `+'-separated list. % \begin{macrocode} \kvt@DeclareTrimListParser*{\kvt@forpsvlist}{+} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@dobrklist} % The |\kvt@dobrklist|\marg{list} parses a `|\\|'-separated list. % \begin{macrocode} \kvt@DeclareTrimListParser{\kvt@dobrklist}{\\} % \end{macrocode} % \end{macro} % % \subsubsection{Errors and Warnings} % % \begin{macro}{\kvt@error} % \begin{macro}{\kvt@warn} % These macros produce error and warning messages. % \begin{macrocode} \newcommand\kvt@error[2]{\PackageError{keyvaltable}{#1}{#2}} \newcommand\kvt@warn[1]{\PackageWarning{keyvaltable}{#1}} % \end{macrocode} % \end{macro} % \end{macro} % % \subsubsection{Setting Keys} % % \begin{macro}{\kvt@setkeys} % \begin{macro}{\kvt@setcmdkeys} % \begin{macro}{\kvt@setcskeys} % The |\kvt@setkeys|\marg{keys}\marg{fam} macro abbreviates % |\setkeys[kvt]|\meta{fam}\meta{keys} (note the reverse order of % arguments). % The |\kvt@setcmdkeys|\marg{keycmd}\marg{fam} and % |\kvt@setcskeys|\marg{keycs}\marg{fam} abbreviate the cases where % \meta{keys} are stored in macro \meta{keycmd} or, respectively, % stored in a macro with name \meta{keycs}. % \begin{macrocode} \newcommand\kvt@setkeys[2]{\setkeys[kvt]{#2}{#1}} \newcommand\kvt@setcmdkeys[2]{% \expandafter\kvt@setkeys\expandafter{#1}{#2}} \newcommand\kvt@setcskeys[2]{% \expandafter\kvt@setcmdkeys\expandafter{\csname #1\endcsname}{#2}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\kvt@setkeys@nopresets} % The % |\kvt@setkeys@nopresets|\marg{keys}\marg{family} macro % expands to a |\kvt@setkeys| in which no presets are active. % \begin{macrocode} \newcommand\kvt@setkeys@nopresets[2]{% \kvt@xkv@disablepreset[kvt]{#2}{\kvt@setkeys{#1}{#2}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@colsetkeys} % \begin{macro}{\kvt@colsetcmdkeys} % \begin{macro}{\kvt@colsetcskeys} % The |\kvt@colsetkeys|\marg{fam}\marg{keys} macro abbreviates % |\setkeys[KeyValTable]| with the same arguments. % The |\kvt@colsetcmdkeys|\marg{famcmd}\marg{keys} and % |\kvt@colsetcskeys|\marg{famcs}\marg{keys} abbreviate the cases where % \meta{fam} is stored in macro \meta{famcmd} or, respectively, % stored in a macro with name \meta{famcs}. % \begin{macrocode} \newcommand\kvt@colsetkeys[2]{\setkeys[KeyValTable]{#1}{#2}} \newcommand\kvt@colsetcmdkeys[2]{% \expandafter\kvt@colsetkeys\expandafter{#1}{#2}} \newcommand\kvt@colsetcskeys[2]{% \expandafter\kvt@colsetcmdkeys\expandafter{\csname #1\endcsname}{#2}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\kvtStrutted} % The |\kvtStrutted|\oarg{inner}\marg{arg} macro prefixes and suffixes % the argument \meta{arg} with a |\strut|. When used for formatting % cell content, this makes sure that there is some vertical space % between the content of a cell and the top and bottom of the row. % The optional \oarg{inner} argument, if provided, should be a macro % that takes one argument. In this case, instead of \meta{arg}, % \meta{inner}|{|\meta{arg}|}| is prefixed and sufficed with |\strut|. % \changes{v0.3}{2016/06/06}{Fix for cells with vertical material} % \changes{v2.0}{2019/03/22}{Added optional argument} % \begin{macrocode} \newcommand\kvtStrutted[2][\@firstofone]{% \strut#1{#2}\ifhmode\expandafter\strut\fi} % \end{macrocode} % \end{macro} % % % \subsection{Setting Options} % % \begin{macro}{\kvtSet} % The |\kvtSet|\marg{options} set the default options, which apply % to all tables typeset with the package. % \begin{macrocode} \newcommand\kvtSet[1]{% \kvt@setkeys{#1}{global,Table,Column}% \ifdefvoid\kvt@@presetqueue{} {\kvt@@presetqueue\undef\kvt@@presetqueue}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@lazypreset} % The |\kvt@@lazypreset|\marg{family}\marg{head keys} macro collects a % request for pre-setting \meta{head keys} in family % key \meta{family}. Using this macro, one can avoid causing problems % with using \pkgname{xkeyval}'s |\presetkeys| inside the \meta{function} % defined for a key (e.g., via |\define@key|). The collected requests % can be performed by expanding the |\kvt@@presetqueue| macro. % \begin{macrocode} \newcommand\kvt@lazypreset[2]{% \appto\kvt@@presetqueue{\presetkeys[kvt]{#1}{#2}{}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@keysetter} % The % |\kvt@keysetter|\marg{macro}\marg{fam}\marg{key}\marg{value}\marg{func} % macro is an auxiliary macro that can be used inside the "func" % argument of |\define@...key| macros. % If \meta{macro} is not defined, |\kvt@keysetter| expands to an % instance of |\kvt@lazypreset| in order to set a global default. % Otherwise, |\kvt@keysetter| expands to \meta{func}, which is supposed % to set a key for the specific context referenced by \meta{macro}. % \begin{macrocode} \newcommand\kvt@keysetter[5]{% \ifdefvoid{#1} {\kvt@lazypreset{#2}{#3=#4}} {#5}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvtTableOpt} % The |\kvtTableOpt|\marg{optname} macro, inside a |KeyValTable| % environment, expands to the value of the table option \meta{optname}. % \begin{macrocode} \newcommand\kvtTableOpt[1]{\csname cmdkvt@Table@#1\endcsname} % \end{macrocode} % \end{macro} % % \subsubsection{Table Options} % % The following code defines the possible table options. % % \changes{v0.2}{2016/05/21}{Added ``shape'' table option} % \changes{v2.0}{2019/05/11}{Added table options "caption" and "label"} % \changes{v2.1}{2020/01/18}{Added ``valign'' and ``halign'' table options} % \changes{v2.2}{2020/02/24}{Added ``style'' table option} % \changes{v2.2}{2020/02/27}{added option "backend"} % \changes{v2.2}{2020/03/08}{added option "captionpos"} % \begin{macrocode} \define@cmdkey[kvt]{Table}{rowbg}{} \define@cmdkey[kvt]{Table}{headbg}{} \define@cmdkey[kvt]{Table}{headalign}{} \define@cmdkey[kvt]{Table}{headformat}{} \define@cmdkey[kvt]{Table}{width}{} \define@boolkey[kvt]{Table}{showhead}{} \define@boolkey[kvt]{Table}{showrules}{} \define@choicekey[kvt]{Table}{captionpos}{t,b} {\csdef{cmdkvt@Table@captionpos}{#1}} \define@choicekey[kvt]{Table}{valign}{t,c,b} {\csdef{cmdkvt@Table@valign}{#1}} \define@choicekey[kvt]{Table}{halign}{l,c,r} {\csdef{cmdkvt@Table@halign}{#1}} \define@key[kvt]{Table}{style}{\kvt@UseTableStyles{#1}} % \end{macrocode} % The following options only abbreviate options defined above. % \changes{v2.1}{2020/01/14}{added abbreviation option "norules"} % \begin{macrocode} \define@boolkey[kvt]{Table}{norowbg}[true]{% \kvt@setkeys{rowbg={}}{Table}} \define@boolkey[kvt]{Table}{nobg}[true]{% \kvt@setkeys{rowbg={},headbg={}}{Table}} \define@boolkey[kvt]{Table}{norules}[true]{% \ifbool{#1} {\kvt@setkeys{showrules=false}{Table}} {\kvt@setkeys{showrules=true}{Table}}} \define@key[kvt]{Table}{backend}{\ifinlist{#1}{\kvt@@tablebackends} {\csdef{cmdkvt@Table@shape}{#1}} {\kvt@error{Table backend '#1' not known} {Check for misspellings in '#1'}}} \define@key[kvt]{Table}{shape}{\ifinlist{#1}{\kvt@@tableshapes} {\csdef{cmdkvt@Table@shape}{#1}} {\ifinlist{#1}{\kvt@@tablebackends} {\kvt@warn{Using a backend ('#1') as shape is deprecated. Use the 'backend' option instead.}% \csdef{cmdkvt@Table@shape}{#1}} {\kvt@error{Table shape '#1' not known} {Check for misspellings in '#1'}}}} % \end{macrocode} % % The following table options only apply to individual |KeyValTable| % environments and cannot be set with |\NewKeyValTable| or |\kvtSet|. % \changes{v2.2}{2020/02/23}{added table options "resume" and "resume*"} % \changes{v2.2}{2020/03/12}{added options "caption/lot" and "caption/alt"} % \begin{macrocode} \define@cmdkey[kvt]{TableEnv}{caption}{} \define@cmdkey[kvt]{TableEnv}{caption/lot}{} \define@cmdkey[kvt]{TableEnv}{caption/alt}{} \define@cmdkey[kvt]{TableEnv}{label}{} \define@boolkey[kvt]{TableEnv}{resume}[true]{% \ifbool{#1}{\ifundef\kvt@@rowcountlast {\kvt@error{No previous table whose counter could be resumed.} {Check whether the "resume" is intentional and whether a previously existing predecessor table has disappeared.}}{}}{}} \define@boolkey[kvt]{TableEnv}{resume*}[true]{% \ifbool{#1} % \end{macrocode} % The |\kvt@@lastenvopt| macro holds the previous |KeyValTable|'s % options. Beyond these options, |resume*| automatically also sets % |resume|. % \begin{macrocode} {\ifundef\kvt@@lastenvopt {\kvt@error{No previous table whose options could be resume*'d.} {Check whether the "resume*" is intentional and whether a previously existing predecessor table has disappeared.}}{}% \kvt@setcmdkeys\kvt@@lastenvopt{Table}% \kvt@setkeys{resume}{TableEnv}} {}} % \end{macrocode} % % % \subsubsection{Column Options} % % The following code defines the possible column options. % % \changes{v1.0}{2018/12/30}{Enabled default ``true'' for ``hidden''} % \begin{macrocode} \define@key[kvt]{Column}{default}{\kvt@colkeysetter{default}{#1}} \define@key[kvt]{Column}{format}{\kvt@colkeysetter{format}{#1}} \define@key[kvt]{Column}{align}{\kvt@colkeysetter{align}{#1}} \define@key[kvt]{Column}{head}{\kvt@colkeysetter{head}{#1}} \define@boolkey[kvt]{Column}{hidden}[true]{% \kvt@colkeysetter{hidden}{#1}} % \end{macrocode} % % \begin{macro}{\kvt@colkeysetter} % The |\kvt@colkeysetter|\marg{key}\marg{value} specializes % |\kvt@keysetter| for column options. % \begin{macrocode} \newcommand\kvt@colkeysetter[2]{% \kvt@keysetter{\kvt@@column}{Column}{#1}{#2}{% \csdef{kvt@col@#1@\kvt@@column}{#2}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@def@globalopt} % \begin{macro}{\kvt@def@globalopts} % The |\kvt@def@globalopt|\marg{family}{key} macro creates the option key % "\meta{family}/\meta{key}". When used in |\kvtSet|, this key sets the preset % value for the \meta{key} in \meta{family}. % The |\kvt@def@globalopts|\marg{family}{keys} macro extends the former % macro to comma-separated lists of \meta{keys} within a single % \meta{family}. % \begin{macrocode} \newcommand\kvt@def@globalopt[2]{% \define@key[kvt]{global}{#1/#2}{\kvt@lazypreset{#1}{#2={##1}}}} \newcommand\kvt@def@globalopts[2]{% \forcsvlist{\kvt@def@globalopt{#1}}{#2}} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macrocode} \define@cmdkey[kvt]{ColGroup}{span}{% \csgdef{kvt@colgrp@span@\kvt@@tname @\kvt@@colgrp}{#1}} \define@cmdkey[kvt]{ColGroup}{align}{% \csgdef{kvt@colgrp@align@\kvt@@tname @\kvt@@colgrp}{#1}} \define@cmdkey[kvt]{ColGroup}{format}{% \csgdef{kvt@colgrp@format@\kvt@@tname @\kvt@@colgrp}{#1}} \kvt@def@globalopts{ColGroup}{align, format} % \end{macrocode} % % % \subsubsection{Layout Customization Options} % % The following defines the option keys for the second optional argument % to |\NewKeyValTable|. These options intentionally do not support % setting global defaults via |\kvtSet|. % \begin{macrocode} \define@cmdkey[kvt]{Layout}{headers}{% \expandafter\kvt@parseheadrows\expandafter{\kvt@@tname}{#1}} \define@cmdkey[kvt]{Layout}{colgroups}{% \expandafter\kvt@parsecolgroups\expandafter{\kvt@@tname}{#1}} % \end{macrocode} % % The following defines the options for header cells. % \begin{macrocode} \define@key[kvt]{HeadCell}{head}{% \csdef{kvt@@hdcell@head@\kvt@@hdcell}{#1}} \define@key[kvt]{HeadCell}{align}{% \csdef{kvt@@hdcell@align@\kvt@@hdcell}{#1}} \define@boolkey[kvt]{HeadCell}{underline}[true]{% \csdef{kvt@@hdcell@underline@\kvt@@hdcell}{#1}} \kvt@def@globalopts{HeadCell}{align} % \end{macrocode} % % % \subsubsection{Row Options} % % The following block declares the known row options. % Note that these are not enabled for |\kvtSet|. % \changes{v2.0}{2019/05/11}{added row options "expand" and "expandonce"} % \changes{v2.0}{2019/05/11}{added row options "nobg" and "norowbg"} % \changes{v2.0}{2019/05/11}{added row option "style"} % \changes{v2.0}{2019/05/11}{added row option "uncounted"} % \changes{v2.1}{2020/02/15}{added row options "format", "format*", % "format!", "align", and "headlike"} % \begin{macrocode} \define@cmdkey[kvt]{Row}{bg}{} \define@cmdkey[kvt]{Row}{format}{} \define@cmdkey[kvt]{Row}{format*}{} \define@cmdkey[kvt]{Row}{format!}{} \define@cmdkey[kvt]{Row}{align}{} \define@boolkey[kvt]{Row}{headlike}[true]{% \ifbool{#1}{% \edef\kvt@@opts{% bg={\expandonce\cmdkvt@Table@headbg},% format!={\expandonce\cmdkvt@Table@headformat},% align={\expandonce\cmdkvt@Table@headalign}}% \expandafter\kvt@setkeys@nopresets\expandafter{\kvt@@opts}{Row}% }{}} \define@boolkey[kvt]{Row}{hidden}[true]{} \define@cmdkey[kvt]{Row}{below}{} \define@cmdkey[kvt]{Row}{above}{} \define@key[kvt]{Row}{around}{% \kvt@setkeys@nopresets{below={#1},above={#1}}{Row}} \define@key[kvt]{Row}{style}{\kvt@UseRowStyles{#1}} \define@boolkey[kvt]{Row}{uncounted}[true]{} \define@boolkey[kvt]{Row}{expand}[true]{} \define@boolkey[kvt]{Row}{expandonce}[true]{} % \end{macrocode} % The following specifies which row options can be specified globally, % i.e. via a |Row/option| key. Not contained in the list are the % |format| options and the |headlike| option, as setting these globally % appears strange. % \begin{macrocode} \kvt@def@globalopts{Row}{ bg,hidden,below,above,around,style,uncounted, expand,expandonce} % \end{macrocode} % % % \subsubsection{Option Defaults} % % The following sets the default values for the options. This is done % only after the package is otherwise completely processed, to ensure % that all features are already defined/registered at that point. % \changes{v2.3}{2020/07/30}{Removed \cmd{\kvtStrutted} from default format} % \begin{macrocode} \AtEndOfPackage{\kvtSet{% rowbg=white..black!10, headbg=black!14, showhead=true, showrules=true, headformat=\@firstofone, headalign=, shape=multipage, width=\linewidth, captionpos=b, % \end{macrocode} % Column options % \begin{macrocode} default=, format=\@firstofone, align=l, head=, hidden=false, Row/bg={}, Row/hidden=false, Row/above={}, Row/below={}, Row/uncounted=false, Row/expand=false, Row/expandonce=false, ColGroup/align=c, ColGroup/format=\@firstofone, HeadCell/align=c, }} % \end{macrocode} % % % \subsection{Declaring Key-Value Tables} % % \begin{macro}{\NewKeyValTable} % The % |\NewKeyValTable|\oarg{options}\marg{tname}\marg{colspecs}\oarg{layout} % declares a new key-value table type, identified by the given % \meta{tname}. The columns of the table type are specified by % \meta{colspecs}. The optional \meta{options}, if given, override the % default table options for tables of type \meta{tname}. % \changes{v0.2}{2016/05/21}{Added table-type options} % \changes{v1.0}{2019/02/03}{Added optional headers argument} % \changes{v2.0}{2019/04/28}{Changed headers argument to layout argument} % \begin{macrocode} \newcommand\NewKeyValTable[3][]{% \@ifnextchar[%] {\kvt@NewKeyValTable{#1}{#2}{#3}}% {\kvt@NewKeyValTable{#1}{#2}{#3}[]}} % \end{macrocode} % The % |\kvt@NewKeyValTable|\marg{options}\marg{tname}\marg{colspecs}\oarg{layout} % macro is an auxiliary macro used for parsing the fourth, optional % argument of |\NewKeyValTable|. % \begin{macrocode} \def\kvt@NewKeyValTable#1#2#3[#4]{% % \end{macrocode} % Before doing anything, check whether \meta{tname} has already been % defined. % \begin{macrocode} \ifinlist{#2}{\kvt@alltables} {\kvt@error{Table type with name '#2' already defined} {Check '#2' for typos and check other uses of \string\NewKeyValTable}}{}% % \end{macrocode} % First initialize the ``variables''. % \begin{macrocode} \csdef{kvt@options@#2}{#1}% \csdef{kvt@headings@#2}{}% % \end{macrocode} % The following adds a zero-width column to the left of every table. % This column serves the purpose of "holding" the code that % \thispackage uses for formatting a row (e.g., parsing |\Row| % arguments). This code is partly not expandable. % The reason for not putting this code into the first actual colum of % tables is that this code would prevent |\multicolumn| to be used in % the first column. % \changes{v1.0}{2019/02/03}{Added zero-width column for \cs{multicolumn}} % \changes{v2.1}{2020/02/16}{Removed zero-width column again} % \begin{macrocode} \csdef{kvt@alignments@#2}{}% \csdef{kvt@allcolumns@#2}{}% \csdef{kvt@displaycols@#2}{}% \csdef{kvt@ndisplaycols@#2}{0}% \csdef{kvt@rowcount@#2}{0}% \csdef{kvt@rows@#2}{}% \csdef{kvt@headings@#2}{\kvt@defaultheader}% \listadd\kvt@alltables{#2}% % \end{macrocode} % Now parse \meta{colspecs}, a semicolon-separated list of individual % column specifications, and add the columns to the table. Each % |\do|\marg{colspec} takes the specification for a single column. % \begin{macrocode} \def\do##1{% \kvt@parsecolspec{#2}##1::\@undefined}% \kvt@dossvlist{#3}% % \end{macrocode} % By default, a single header row is constructed. % \begin{macrocode} \csdef{kvt@headrowcount@#2}{1}% % \end{macrocode} % The following terminates the argument list of |\kvt@defaultheader|. % \begin{macrocode} \csappto{kvt@headings@#2}{{\@nil}}% % \end{macrocode} % Finally, parse \meta{layout}. % \begin{macrocode} \kvt@parselayout{#4}{#2}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@parsecolspec} % The % |\kvt@parsecolspec|\marg{tname}\meta{cname}|:|\meta{config}|:|\meta{empty}|\@undefined| % takes a configuration \meta{config} for a column \meta{cname} in table % \meta{tname} and adds the column with the configuration to the table. % \begin{macrocode} \def\kvt@parsecolspec#1#2:#3:#4\@undefined{% % \end{macrocode} % Catch syntax errors first. % \begin{macrocode} \kvt@checkcolspecempty{#4}{column}{#2}% \def\kvt@@column{#2}% \trim@spaces@in\kvt@@column \expandafter\kvt@parsecolspec@i\expandafter{\kvt@@column}{#1}{#3}} \newcommand\kvt@parsecolspec@i[3]{\kvt@parsecolspec@ii{#2}{#1}{#3}} \newcommand\kvt@parsecolspec@ii[3]{% \def\kvt@@column{#1@#2}% % \end{macrocode} % Check and record the column name first. % \begin{macrocode} \ifinlistcs{#2}{kvt@allcolumns@#1} {\kvt@error{Column name '#2' declared more than once in table type '#1'}{Check '#2' for typos; column names declared so far:% \forlistcsloop{ }{kvt@allcolumns@#1}}}{}% \listcsadd{kvt@allcolumns@#1}{#2}% \kvt@setkeys{#3}{Column}% % \end{macrocode} % The following stores the column's properties. The column is only added % if the |hidden| option is not set to |true|. % \begin{macrocode} \ifcsstring{kvt@col@hidden@#1@#2}{true}{}{% \cseappto{kvt@alignments@#1}{\csexpandonce{kvt@col@align@#1@#2}}% % \end{macrocode} % Append the column heading to \cs{kvt@headings@\meta{tname}}, which % collects arguments to |\kvt@defaultheader|. Hence, the appended tokens % are enclosed in curly braces. If no |head| is specified for the % column, \meta{cname} is used for the column header. Otherwise, the % |head| value is used. % \begin{macrocode} \ifcsvoid{kvt@col@head@#1@#2}% {\csappto{kvt@headings@#1}{{#2}}}% {\cseappto{kvt@headings@#1}{{\csexpandonce{kvt@col@head@#1@#2}}}}% \listcsadd{kvt@displaycols@#1}{#2}% \csedef{kvt@ndisplaycols@#1}{% \the\numexpr\csuse{kvt@ndisplaycols@#1}+1\relax}% }% % \end{macrocode} % The following creates the column key that can be used by the row % macros to set the content of the column's content in that row. % The starred variant of the key disables the column's |format| for the % cell. % \begin{macrocode} \define@cmdkey[KeyValTable]{#1}{#2}[]{}% \define@key[KeyValTable]{#1}{#2*}{% \csdef{cmdKeyValTable@#1@#2}{##1}% \csdef{kvt@@noformat@#1@#2}{1}}% \presetkeys[KeyValTable]{#1}{#2}{}% % \end{macrocode} % The |\kvt@parsecolspec| macro is not necessarily enclosed in a group. % To avoid leaking a local |\kvt@@column| value to the outer (global) % scope, we explicitly undefine it. % \begin{macrocode} \undef\kvt@@column} % \end{macrocode} % \end{macro} % % % \begin{macro}{\kvt@defaultheader} % The |\kvt@defaultheader|\marg{head1}\ldots\marg{headn}|\@nil| macro, % takes $n$ header cell titles, \meta{head1} to \meta{headn} and formats % them based on the |headformat| and |headalign| options. % More precisely, when fully expanded, |\kvt@defaultheader| yields % "\meta{rowcolor}\meta{fmthead1}| & |\ldots| & |\meta{fmtheadn}|\tabularnewline|". % In the above, \meta{rowcolor}=|\rowcolor{|\meta{headbg}|}|. % \begin{macrocode} \newcommand\kvt@defaultheader{% \noexpand\kvt@rowcolorornot{\cmdkvt@Table@headbg}% \kvt@defaultheader@i{}} \newcommand\kvt@defaultheader@i[2]{% \kvt@ifnil{#2}{\noexpand\tabularnewline}{% \unexpanded{#1}% \ifdefvoid\cmdkvt@Table@headalign {\expandonce\cmdkvt@Table@headformat{\unexpanded{#2}}} {\noexpand\multicolumn{1}{\expandonce\cmdkvt@Table@headalign} {\expandonce\cmdkvt@Table@headformat{\unexpanded{#2}}}}% \kvt@defaultheader@i{&}}} % \end{macrocode} % \begin{macro}{\kvt@ifnil} % The |\kvt@ifnil|\marg{val}\marg{iftrue}\marg{iffalse} macro expands to % \meta{iftrue} if \meta{val} is |\@nil|, and expands to \meta{iffalse} % otherwise. % Fixme: The |\relax| in the following is not fully ideal as it is not % swallowed by the |\ifx| and therefore remains in the macro's % expansion. % \begin{macrocode} \newcommand\kvt@ifnil[1]{% \ifx\@nil#1\relax \expandafter\@firstoftwo\else \expandafter\@secondoftwo\fi} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\kvt@alltables} % The |\kvt@alltables| is an \pkgname{etoolbox} list containing the names % of all tables declared by |\NewKeyValTable|. % \begin{macrocode} \newcommand\kvt@alltables{} % \end{macrocode} % \end{macro} % % % \subsection{Custom Layout Parameters} % % \begin{macro}{\kvt@parselayout} % The |\kvt@parselayout|\marg{layout-opts}\marg{tname} macro parses the % layout options, \meta{layout-opts}, for table type \meta{tname}, % \begin{macrocode} \newcommand\kvt@parselayout[2]{% \def\kvt@@tname{#2}% % \end{macrocode} % Now parse the \meta{layout-opts}. The keys are defined such that their % handlers already do the parsing. % \begin{macrocode} \kvt@setkeys{#1}{Layout}% \undef\kvt@@tname} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@parsecolgroups} % The |\kvt@parsecolgroups|\marg{tname}\marg{spec} macro parses the % specification, \meta{spec}, of column groups for table type % \meta{tname}. % \begin{macrocode} \newcommand\kvt@parsecolgroups[2]{% \begingroup % \end{macrocode} % |\kvt@@result| collects the parsing outcome code that shall escape the % group started above. % \begin{macrocode} \def\kvt@@result{}% \def\do##1{\kvt@parsecolgroup{#1}##1::\@undefined}% \kvt@dossvlist{#2}% \expandafter\endgroup\kvt@@result} % \end{macrocode} % The % |\kvt@parsecolgroup|\marg{tname}\marg{cgname}\marg{cgopts}\marg{empty} % macro parses a single column group, \meta{cgname} with options % \meta{cgopts}. % \begin{macrocode} \def\kvt@parsecolgroup#1#2:#3:#4\@undefined{% % \end{macrocode} % Catch syntax errors first. % \begin{macrocode} \kvt@checkcolspecempty{#4}{column group}{#2}% % \end{macrocode} % Next, check for a valid \meta{cgname}. % \begin{macrocode} \ifinlistcs{#2}{kvt@allcolumns@#1}{\kvt@error {Name `#2' cannot be used for a column group in table type `#1', as it is already used for a column} {Check the \string\NewKeyValTable{#1} for the names of known columns and check `#2' for a typo.}}{}% \ifinlistcs{#2}{kvt@grpcolkeys@#1}{\kvt@error {Name `#2' is used twice in table type `#1'} {Check the \string\NewKeyValTable{#1} for typos in the names of columns groups.}}{}% \def\kvt@@colgrp{#2}% \kvt@setkeys{#3}{ColGroup}% \kvt@checkcolgroupcs{kvt@colgrp@span@#1@#2}{#1}{#2}% % \end{macrocode} % Store the result of |\kvt@checkcolgroupcs| for later use. % \begin{macrocode} \csxdef{kvt@colgrp@first@#1@#2}{\kvt@@colgrp@first}% \csxdef{kvt@colgrp@count@#1@#2}{\kvt@@colgrp@n}% % \end{macrocode} % The following defines the |\Row| key for \meta{cgname}, as an % abbreviation for setting the value of the first displayed column of % \meta{cgname} (|\kvt@@colgrp@first| to a |\multicolumn| that spans the % "right" number of columns). % \begin{macrocode} \eappto\kvt@@result{% \noexpand\define@cmdkey[KeyValTable]{#1}{#2}{% % \end{macrocode} % The following |\ifdefvoid| check ensures that if \meta{cgname} is a % hidden column group (i.e., a column group of which all spanned columns % are hidden), then setting \meta{cgname} to a value has no effect. % \begin{macrocode} \ifdefvoid\kvt@@colgrp@first{}{% % \end{macrocode} % The "abbreviation" is implemented via |\setkeys|. The letter normally % employs the defined |\presetkeys|, but we disable this through % |\kvt@xkv@disablepreset| to avoid that column keys that are set before % a colgroup key are overwritten by their preset values. % \begin{macrocode} \noexpand\kvt@xkv@disablepreset[KeyValTable]{#1}{% \noexpand\setkeys[KeyValTable]{#1}{% % \end{macrocode} % Notice the "*" after |\kvt@@colgrp@first|, % which disables the first column's default formatting to replace it by % the formatting of \meta{cgname}. % \begin{macrocode} \expandonce\kvt@@colgrp@first=\noexpand\kvt@@@colgroup {\unexpanded{#2}}% {\expandonce\kvt@@colgrp@n}% {\csexpandonce{kvt@colgrp@align@#1@#2}}% {\unexpanded{##1}}}}% }% }}% \listcsadd{kvt@grpcolkeys@#1}{#2}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@checkcolspecempty} % The |\kvt@checkcolspecempty|\marg{empty}\marg{type}\marg{name} % macro checks the \meta{empty} parameter of a parsing macro for a % colon-separated key-value pair. % If \meta{empty} is empty, this corresponds to the valid case that only % the name of a column group was provided and no properties. If % \meta{empty} equals ":", then a name and properties were provided. In % all other cases, superfluous colons were found. % \begin{macrocode} \newcommand\kvt@checkcolspecempty[3]{% \ifstrempty{#1}{}{\ifstrequal{#1}{:}{}{\kvt@error {Too many ':' in definition of #2 '#3'} {Check whether there is an accidental ':' that should actually be a ',' or ';'.}}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@checkcolgroup} % The |\kvt@checkcolgroup|\marg{span-psv}\marg{tname}\marg{cgname} macro % performs some checks on \meta{span-psv} as a specification of which % columns shall be spanned by a group column of name \meta{cgname}. % The checks are % \begin{itemize} % \item whether all column names are indeed columns of \meta{tname}, % \item whether each column appears at most once in the column group, % and % \item whether the (displayed) columns from \meta{span-psv} appear % consecutively in \meta{tname}. % \end{itemize} % The macro returns the number of spanned (displayed!) columns in % |\kvt@@colgrp@n| and the name of the first column in % |\kvt@@colgrp@first|. % % Fixme: There can probably be some code sharing with % |\kvt@parseheadrow| and |\kvt@parsecolgroup|. % \begin{macrocode} \newcommand\kvt@checkcolgroup[3]{% % \end{macrocode} % First, check individual colums in \meta{span-psv} and transfer them % into a "map", |kvt@@incolgrp@| that simply records which column names % occur in \meta{span-psv}. % \begin{macrocode} \def\kvt@@psvdo##1{% \ifinlistcs{##1}{kvt@allcolumns@#2}{}{\kvt@error {Column `##1' referenced in column group `#3' not known in table type `#2'} {Check the \string\NewKeyValTable{#2} for the names of known columns and check `##1' for a typo.}}% \ifcsvoid{kvt@@incolgrp@##1}{}{\kvt@error {Column `##1' used more than once in column group `#3' of table type `#2'} {Check `##1' for a typo.}}% \csdef{kvt@@incolgrp@##1}{#2}% }\kvt@forpsvlist{\kvt@@psvdo}{#1}% % \end{macrocode} % The following two macros are the "return values". % \begin{macrocode} \def\kvt@@colgrp@n{0}% \let\kvt@@colgrp@first\relax % \end{macrocode} % Second, iterate over the displayed columns of \meta{tname} to check % whether the columns in \meta{span-psv} are consecutive. % For this, use |\kvt@@status| to track % whether no column of \meta{span-psv} has yet been visited (value 0, % the initial value), % whether the current column is part of \meta{span-psv} (value 1), and % whether columns of \meta{span-psv} have been visited but the current % column is not part of \meta{span-psv} (value 2). % \begin{macrocode} \def\kvt@@status{0}% % \end{macrocode} % |\kvt@@coldo|\marg{column} is applied to each displayed column, in % order. % \begin{macrocode} \def\kvt@@coldo##1{% \ifcsvoid{kvt@@incolgrp@##1} % \end{macrocode} % If \meta{column} is \emph{not} in \meta{span-psv}, then change % |\kvt@@status| from 1 to 2, but do not change it when it is 0 or 2. % \begin{macrocode} {\expandafter\ifcase\kvt@@status \or \def\kvt@@status{2}\fi}% % \end{macrocode} % If \meta{column} is in \meta{span-psv}, then change |\kvt@@status| % from 0 to 1 and record \meta{column} as |\kvt@@colgrp@first|; if % |\kvt@@status| is previously 2, then the columns in \meta{span-psv} % would not be consecutively displayed and, hence, an error is raised. % \begin{macrocode} {\expandafter\ifcase\kvt@@status \def\kvt@@status{1}\def\kvt@@colgrp@first{##1}% \or\or \kvt@error{Column group `\kvt@@colgrp' must consist of only consecutive columns, but it is not}% {Compare `\string\kvt@@curgrp' to the column ordering as specified in `\string\NewKeyValTable{#1}'}% \fi \edef\kvt@@colgrp@n{\the\numexpr\kvt@@colgrp@n+1\relax}% % \end{macrocode} % Since this macro is not encapsulated in a group (in order to return % |\kvt@@colgrp@n| and |\kvt@@colgrp@first|), we finally prevent the % local \cs{kvt@@incolgrp@\meta{column}} from leaking outside this % macro. % \begin{macrocode} \csundef{kvt@@incolgrp@##1}}% }\forlistcsloop{\kvt@@coldo}{kvt@displaycols@#2}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@checkcolgroupcs} % The |\kvt@checkcolgroupcs|\marg{span-psv-cs}\marg{tname}\marg{cgname} % macro is the same as |\kvt@checkcolgroup| except that it takes a % control sequence name as its first argument rather than a % plus-separated list directly. % \begin{macrocode} \newcommand\kvt@checkcolgroupcs[3]{% \expandafter\expandafter\expandafter \kvt@checkcolgroup \expandafter\expandafter\expandafter{\csname #1\endcsname}{#2}{#3}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@parseheadrows} % The |\kvt@parseheadrows|\marg{tname}\marg{headers} % macro parses the values of the |headers| key in the \meta{layout} % argument of |\NewKeyValTable|. The values are |\\|-separated lists of % header rows, and the rows are semicolon-separated lists of header % cells. Each header cell can span zero, one, or more visible columns. % If the |headers| key is not set (or empty), then the default header % (based on the column specification alone) is used, as set by % |\kvt@NewKeyValTable|. % \begin{macrocode} \newcommand\kvt@parseheadrows[2]{% \ifstrempty{#2}{}{\kvt@parseheadrows@i{#2}{#1}}} \newcommand\kvt@parseheadrows@i[2]{% \csdef{kvt@@custheadrows@#2}{}% \csdef{kvt@headrowcount@#2}{0}% \begingroup \def\kvt@@parseheadrows{}% % \end{macrocode} % Now loop over \meta{headers} to split \meta{headers} by |\\|. % Append each item, which specifies a single header row, to % |\kvt@@parseheadrows| for subsequent parsing by |\kvt@parseheadrow|. % If an item equals the special sequence "|::|", then the original % header for the columns is added as header row. % \begin{macrocode} \def\do##1{% \ifstrequal{##1}{::} {\appto\kvt@@parseheadrows{% \cseappto{kvt@@custheadrows@#2}{% \csexpandonce{kvt@headings@#2}}}} {\appto\kvt@@parseheadrows{\kvt@parseheadrow{#2}{##1}}}% % \end{macrocode} % Increment the header row counter for each |\\|-separated item of % \meta{headers}. % \begin{macrocode} \appto\kvt@@parseheadrows{\csedef{kvt@headrowcount@#2}{% \the\numexpr\csuse{kvt@headrowcount@#2}+1\relax}}% }\kvt@dobrklist{#1}% % \end{macrocode} % Finally, escape the inner group and overwrite the headings % with the result of the parsing. % \begin{macrocode} \expandafter\endgroup\kvt@@parseheadrows \csletcs{kvt@headings@#2}{kvt@@custheadrows@#2}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@parseheadrow} % The |\kvt@parseheadrow|\marg{tname}\marg{colspec} macro parses a % single header row and appends the resulting table code to % \cs{kvt@@custheadrows@\meta{tname}}. % \begin{macrocode} \newcommand\kvt@parseheadrow[2]{% \begingroup % \end{macrocode} % First parse \meta{colspec}, populating the % \cs{kvt@@hdcellof@\meta{colname}} macros that associate each column % with the header cell to which the column belongs (in this row). % \begin{macrocode} \def\do##1{\kvt@parsehdcolspec{#1}##1::\@undefined}% \kvt@dossvlist{#2}% % \end{macrocode} % Initialize variables for the subsequent loop. % The |\kvt@@tmpgrphd| macro collects the code for the cells of the % current header row. % The |\kvt@@tmpunderline| macro collects the rules (|\cmidrule|-like) % from header cells, in an \pkgname{etoolbox} list. % The |\kvt@@span| counter specifies how many columns the current cell % shall span. % Finally, |\kvt@@curhd| and |\kvt@@lasthd| hold the name of the % header cell in which the current column and, respectively, previous % column are in. Each of the two macros is undefined if there is no % such header cell. % \begin{macrocode} \let\kvt@@tmpgrphd\@empty \let\kvt@@tmpunderlines\@empty \letcs\kvt@@tmpncols{kvt@ndisplaycols@#1}% \kvt@@span\z@ \kvt@@coln\@ne \undef\kvt@@curhd \undef\kvt@@lasthd \kvt@def@atseconduse\kvt@@switchcol{\appto\kvt@@tmpgrphd{&}}% % \end{macrocode} % Next, loop over all displayed columns, stored in % \cs{kvt@displaycols@\meta{tname}}. The following |\do|\marg{colname} % macro collects (spanned) columns as specified in \meta{colspec}, in the % ordering in which the table's columns are displayed. The spanned % columns are stored in |\kvt@@tmpgrphd|. % \begin{macrocode} \def\do##1{\letcs\kvt@@curhd{kvt@@hdcellof@##1}% \ifdefequal\kvt@@curhd\kvt@@lasthd % \end{macrocode} % If the header cell has not changed, simply increase the spanning % counter. % \begin{macrocode} {\advance\kvt@@span\@ne}% % \end{macrocode} % Otherwise, i.e., if the header cell has changed, then conclude the % previous column (if there was one) and reset the span to 1 (to count % for the column in |\kvt@@curhd|) and set |\kvt@@lasthd| to the % current one. % \begin{macrocode} {\ifnum\kvt@@span>\z@ \expandafter\kvt@concludehdcolumn\fi \ifdefvoid\kvt@@curhd{}{\ifcsdef{kvt@@hdcelldone@\kvt@@curhd}{% \kvt@error{Header cell `\kvt@@curhd' must consist of only consecutive columns, but it is not}% {Compare `\string\kvt@@curhd' to the column ordering as specified in `\string\NewKeyValTable{#1}'}}{}}% \advance\kvt@@coln\kvt@@span\relax \kvt@@span\@ne \let\kvt@@lasthd\kvt@@curhd}% }\dolistcsloop{kvt@displaycols@#1}% \kvt@concludehdcolumn % \end{macrocode} % Finally, conclude the whole header row and append the row to the % overall list of rows, stored in \cs{kvt@@custheadrows@\meta{tname}}, % while ending the current \hologo{TeX} group. % \begin{macrocode} \appto\kvt@@tmpgrphd{\tabularnewline}% \ifdefempty\kvt@@tmpunderlines{}{% \eappto\kvt@@tmpgrphd{% \noexpand\kvtRule@cmid{\noexpand\cmidrulewidth} {\expandonce\kvt@@tmpunderlines} {\expandonce\cmdkvt@Table@headbg} {\expandonce\cmdkvt@Table@headbg}}}% \edef\do{\noexpand\csappto{kvt@@custheadrows@#1}{% \unexpanded{\noexpand\kvt@rowcolorornot{\cmdkvt@Table@headbg}}% \noexpand\unexpanded{\expandonce{\kvt@@tmpgrphd}}}}% \expandafter\endgroup\do} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@rowcolorornot} % The |\kvt@rowcolorornot|\marg{color} expands to % |\rowcolor|\marg{color} if \meta{color} is nonempty and does have no % effect if \meta{color} is empty. % \begin{macro}{\kvt@rowcolorcmdornot} % The |\kvt@rowcolorcmdornot|\marg{cmd} expands to % |\rowcolor|\marg{color}, where \meta{color} is the (one-time) % expansion of \meta{cmd}, if \meta{cmd} is a defined macro whose % expansion is nonempty; its expansion is empty otherwise. % \begin{macrocode} \newcommand\kvt@rowcolorornot[1]{\ifstrempty{#1}{}{\rowcolor{#1}}} \newcommand\kvt@rowcolorcmdornot[1]{\ifdefvoid{#1}{}{% \expandafter\rowcolor\expandafter{#1}}} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\kvt@@bodyrow} % The counter |\kvt@@bodyrow| is used internally in |KeyValTable| % environments for keeping track of rows for the background-coloring. % The difference between this counter and |\kvtRow| is that the former % also counts |uncounted| rows and is unaffected by the |resume| option. % The counter only counts rows produced by |\Row| and its corresponding % collecting counterparts. Header rows as well as manually inserted % rows, including those produced by macros like |\midrule| in a % |longtable| environment, are not counted (as opposed by the internal % counter of |\rowcolors|). % \begin{macrocode} \newcount\kvt@@bodyrow % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@@span} % The counter |\kvt@@span| is used temporarily in macros for counting % how many columns are spanned by column groups. % The counter |\kvt@@coln| is used temporarily in macros for counting % column indexes. % \begin{macrocode} \newcount\kvt@@span \newcount\kvt@@coln % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@concludehdcolumn} % The |\kvt@concludehdcolumn| macro appends a cell, potentially spanning % multiple columns, to the row under construction (which is in % |\kvt@@tmpgrphd|). % \begin{macrocode} \newcommand\kvt@concludehdcolumn{% \kvt@@switchcol \ifdefvoid\kvt@@lasthd{}{% \eappto\kvt@@tmpgrphd{\noexpand\multicolumn {\the\kvt@@span} {\csexpandonce{kvt@@hdcell@align@\kvt@@lasthd}} {\noexpand\cmdkvt@Table@headformat {\csexpandonce{kvt@@hdcell@head@\kvt@@lasthd}}}}% % \end{macrocode} % The following adds a pair of trim and spanned columns to % |\kvt@@tmpunderlines| for later drawing all the horizontal rules that % underline column groups. % A rule is trimmed left if it's not the first column and % a rule is trimmed right if it's not the last column. % \begin{macrocode} \ifcsstring{kvt@@hdcell@underline@\kvt@@lasthd}{true} {\listeadd\kvt@@tmpunderlines{% {\ifnumgreater{\kvt@@coln}{1}{l}{}% \ifnumless{\kvt@@coln+\kvt@@span-1}{\kvt@@tmpncols}{r}{}}% {\the\kvt@@coln-\the\numexpr\kvt@@coln+\kvt@@span-1\relax}}}{}% % \end{macrocode} % Mark the header cell as already used and concluded, such that another % use of the same header cell can be detected and raise an error. % \begin{macrocode} \cslet{kvt@@hdcelldone@\kvt@@lasthd}{\@ne}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@parsehdcolspec} % The |\kvt@parsehdcolspec|\marg{tname}\meta{cname}|:|\meta{config}|:|\meta{empty}|\@undefined| % macro parses a single header cell (resp. column group), \meta{cname}. % For a header cell, \meta{cname} can consist of multiple, % "+"-separated column names. % \begin{macrocode} \def\kvt@parsehdcolspec#1#2:#3:#4\@undefined{% % \end{macrocode} % Catch syntax errors first. % \begin{macrocode} \kvt@checkcolspecempty{#4}{header cell}{#2}% % \end{macrocode} % Next, link the individual columns of a header cell to the cell. % In this, ensure that no column is contained in more than one header % cell. % \begin{macrocode} \def\kvt@@colreg##1{% \ifinlistcs{##1}{kvt@allcolumns@#1}{} {\kvt@error{Column `##1', referenced in header cell `#2', not known in table type `#1'}{Check the \string\NewKeyValTable{#1} for the names of known columns and check `##1' for a typo.}}% \ifcsmacro{kvt@@hdcellof@##1} {\kvt@error{Column `##1' used in more than one header cell} {Check the fourth, optional argument of \string\NewKeyValTable and eliminate multiple occurrences of column `##1'.}} {\csdef{kvt@@hdcellof@##1}{#2}}% }\kvt@forpsvlist{\kvt@@colreg}{#2}% % \end{macrocode} % Now parse the \meta{config} of the header cell. % \begin{macrocode} \def\kvt@@hdcell{#2}% \kvt@setkeys{#3}{HeadCell}} % \end{macrocode} % \end{macro} % % % \subsection{Row Numbering and Labeling} % % The following counters simplify row numbering in key-value tables. % One can use a table-local counter (|kvtRow|), a table-type local % counter (|kvtTypeRow|), and a global counter (|kvtTotalRow|). % % \begin{macro}{kvtRow} % The |kvtRow| counter can be used by cells to get the current row % number. This row number (in contrast to |taburow|) does not count % table headers. That is, |kvtRow| provides the current \emph{content} % row number, even in tables that are spread over multiple pages. % \begin{macrocode} \newcounter{kvtRow} % \end{macrocode} % \end{macro} % \begin{macro}{kvtTypeRow} % The |kvtTypeRow| counter can be used by cells to get the current row % number, including all previous rows of tables of the same type. This % counter works together with the \cs{kvt@rowcount@\meta{tname}} macro, % which keeps track of the individual row counts of the \meta{tname} % type. % \begin{macrocode} \newcounter{kvtTypeRow} % \end{macrocode} % \end{macro} % \begin{macro}{kvtTotalRow} % The |kvtTotalRow| counter can be used by cells to get the current row % number, including all previous |KeyValTable| tables. % \begin{macrocode} \newcounter{kvtTotalRow} \setcounter{kvtTotalRow}{0} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvtLabel} % The |\kvtLabel|\oarg{labelopts}\marg{counter}\marg{label} macro sets % a label, named \meta{label}, for the current value of the \LaTeX{} % counter named \meta{counter}. % \changes{v0.2}{2016/05/22}{Added macro for row labeling} % \changes{v0.3}{2016/06/09}{Robustified for use with, e.g., \pkgname{cleveref}} % \begin{macrocode} \newcommand\kvtLabel[3][]{% % \end{macrocode} % The following imitates a |\refstepcounter| in the sense of setting the % current label, but it does not touch the \meta{counter} (in case % someone added some custom hooks to them). % \begin{macrocode} \setcounter{kvt@LabelCtr}{\value{#2}}% \addtocounter{kvt@LabelCtr}{-1}% \refstepcounter{kvt@LabelCtr}% % \end{macrocode} % Next, define the \meta{label} (if provided) and show the value of % \meta{counter}. % \begin{macrocode} \ifstrempty{#3}{}{% \ifstrempty{#1}{\label{#3}}{\label[#1]{#3}}}% \csuse{the#2}} % \end{macrocode} % \end{macro} % \begin{macro}{kvt@LabelCtr} % The |kvt@LabelCtr| counter is an auxiliary counter for setting labels, % used by |\kvtLabel|. % \begin{macrocode} \newcounter{kvt@LabelCtr} % \end{macrocode} % \end{macro} % % % \subsection{Rules} % % This section exists because drawing rules with proper spacing and % proper consideration of row background colors requires some effort. % \changes{v2.3}{2020/08/09}{Made rules aware of row background colors} % % \begin{macro}{\kvt@RuleTop} % The |\kvt@RuleTop| macro produces a |\kvtRuleTop| rule that fits with % the header background color or, if no headers are shown, the % alternating row background colors. % \begin{macrocode} \newcommand\kvt@RuleTop{\noalign{% \edef\kvt@@do{\noexpand\kvtRuleTop{\ifbool{kvt@Table@showhead} {\expandonce\cmdkvt@Table@headbg}{\expandonce\kvt@@bgcolor@odd}}}% \expandafter}\kvt@@do} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@RuleBottom} % The |\kvt@RuleBottom| macro produces a |\kvtRuleBottom| rule that fits % with the alternating row background colors. % \begin{macrocode} \newcommand\kvt@RuleBottom{\noalign{% \edef\kvt@@do{\noexpand\kvtRuleBottom{\ifnumodd{\the\kvt@@bodyrow} {\expandonce\kvt@@bgcolor@odd}{\expandonce\kvt@@bgcolor@even}}}% \expandafter}\kvt@@do} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@RuleMid} % The |\kvt@RuleMid|\oarg{wd} macro produces a |\kvtRuleMid| rule that % fits with the alternating row background colors. % \begin{macrocode} \newcommand\kvt@RuleMid{\noalign{\ifnum0=`}\fi \@ifnextchar[{\kvt@RuleMid@i}{\kvt@RuleMid@i[\lightrulewidth]}} \long\def\kvt@RuleMid@i[#1]{% \edef\kvt@@do{\unexpanded{\ifnum0=`{\fi}\kvtRuleMid[{#1}]}% \ifnumodd{\the\kvt@@bodyrow} {{\expandonce\kvt@@bgcolor@odd}{\expandonce\kvt@@bgcolor@even}} {{\expandonce\kvt@@bgcolor@even}{\expandonce\kvt@@bgcolor@odd}}}% \kvt@@do} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@RuleSubHead} % The |\kvt@RuleSubHead| macro is very similar to |\kvt@RuleMid|. % The latter is to be placed between body rows of a table. % The former is to be placed between the header row(s) and the body % rows. % \begin{macrocode} \newcommand\kvt@RuleSubHead{\noalign{% \edef\kvt@@do{\noexpand\kvtRuleMid {\expandonce\cmdkvt@Table@headbg}{\expandonce\kvt@@bgcolor@odd}}% \expandafter}\kvt@@do} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@RuleCMid} % The |\kvt@RuleCMid|\marg{tname}\oarg{wd}\marg{cglist} macro draws a % set of horizontal rules for a given comma-separated list of names of % columns and/or column groups, \meta{cglist}. % \begin{macrocode} \newcommand\kvt@RuleCMid[1]{\noalign{\ifnum0=`}\fi \@ifnextchar[{\kvt@RuleCMid@i{#1}} {\kvt@RuleCMid@i{#1}[\cmidrulewidth]}} \long\def\kvt@RuleCMid@i#1[#2]#3{% \let\kvt@@rules\@empty \def\kvt@@do##1{% \ifcsdef{kvt@colgrp@first@#1@##1} {\kvt@RuleCMid@cg{#1}{##1}} {\kvt@RuleCMid@cc{#1}{##1}{1}}}% \forcsvlist\kvt@@do{#3}% % \end{macrocode} % The above collected the second argument of |\kvtRule@cmid| in % |\kvt@@rules|. The remaining lines now add the remaining arguments. % \begin{macrocode} \edef\kvt@@rules{\unexpanded{\ifnum0=`{\fi}\kvtRule@cmid}% {\unexpanded{#2}}% {\expandonce\kvt@@rules} \ifnumodd{\the\kvt@@bodyrow} {{\expandonce\kvt@@bgcolor@odd}{\expandonce\kvt@@bgcolor@even}} {{\expandonce\kvt@@bgcolor@even}{\expandonce\kvt@@bgcolor@odd}}}% \kvt@@rules} % \end{macrocode} % The |\kvt@RuleCMid@cg|\marg{tname}\marg{colgrp} macro % takes the first column of \meta{colgrp} and column count of this % column group and passes them on to |\kvt@RuleCMid@c|. % \begin{macrocode} \newcommand\kvt@RuleCMid@cg[2]{\bgroup% \edef\kvt@@do{\egroup \unexpanded{\kvt@RuleCMid@c{#1}}% {\csuse{kvt@colgrp@first@#1@#2}} {\csuse{kvt@colgrp@count@#1@#2}}}% \kvt@@do} % \end{macrocode} % The |\kvt@RuleCMid@c|\marg{tname}\marg{cname}\marg{count} % macro determines the index $a$ of column \meta{cname} and adds a rule % from this column to $a+\meta{count}-1$. % The |\kvt@RuleCMid@cc| macro takes the same arguments but additionally % checks whether \meta{cname} is a valid column name. % \begin{macrocode} \newcommand\kvt@RuleCMid@cc[3]{% \ifinlistcs{#2}{kvt@allcolumns@#1} {\ifinlistcs{#2}{kvt@displaycols@#1} {\kvt@RuleCMid@c{#1}{#2}{#3}} % \end{macrocode} % Rules below known but hidden columns are silently skipped by the below % line. % \begin{macrocode} {}} {\kvt@error {Column or column group `#2' for `\string\CMidRule' not known in table type `#1'} {Check the \string\NewKeyValTable{#1} for the names of known columns and check `#2' for a typo.}}} \newcommand\kvt@RuleCMid@c[3]{% % \end{macrocode} % Find index of column \meta{cname} and store it in |\@tempcnta|. % Fixme: Column indexes could also be precomputed. % \begin{macrocode} \@tempcnta\z@ \def\do##1{\advance\@tempcnta\@ne \ifstrequal{#2}{##1}{\listbreak}{}}% \dolistcsloop{kvt@displaycols@#1}% % \end{macrocode} % Now add new rule pair (trim and columns) to the list stored in % |\kvt@@rules|. % \begin{macrocode} \listeadd\kvt@@rules{% {\ifnumgreater{\@tempcnta}{1}{l}{}% \ifnumless{\@tempcnta+#3-1}{\csuse{kvt@ndisplaycols@#1}}{r}{}}% {\the\@tempcnta-\the\numexpr\@tempcnta+#3-1\relax}}} % \end{macrocode} % \end{macro} % % \paragraph{Candidate for separate package.} % The following macros are independent of the remaining \thispackage % macros and could be factored out into their own small macro package % (|kvtrule|?) as a solution to reoccurring questions about row colors % with \pkgname{booktabs} (e.g., % \url{https://tex.stackexchange.com/questions/177202/booktabs-and-row-color}). % % The macros below act as alternatives to rule macros of the % \pkgname{booktabs} package. % The \pkgname{booktabs} rule macros draw horizontal rules with some % spacing above and below the rule. Their spacing does not take into % account row colors. % The replacement macro allow specifying the row color above % (\meta{c-above}) and below (\meta{c-below}) of rule. % % \begin{macro}{\kvtRuleTop} % The |\kvtRuleTop|\oarg{wd}\marg{c-below} macro acts as a replacement % macro for \pkgname{booktabs}'s |\toprule|\oarg{wd} macro. % \begin{macrocode} \newcommand\kvtRuleTop{\noalign{\ifnum0=`}\fi \@ifnextchar[{\kvtRuleTop@i}{\kvtRuleTop@i[\heavyrulewidth]}} \long\def\kvtRuleTop@i[#1]#2{\ifnum0=`{\fi}% \specialrule{#1}{\abovetopsep}{0pt}% \kvtRule@ColorRule{#2}{2\belowrulesep}{0pt}{-\belowrulesep}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvtRuleBottom} % The |\kvtRuleBottom|\oarg{wd}\marg{c-above} macro acts as a % replacement for \pkgname{booktabs}'s |\bottomrule|\oarg{wd} macro. % \begin{macrocode} \newcommand\kvtRuleBottom{\noalign{\ifnum0=`}\fi \@ifnextchar[{\kvtRuleBottom@i}{\kvtRuleBottom@i[\heavyrulewidth]}} \long\def\kvtRuleBottom@i[#1]#2{\ifnum0=`{\fi}% \kvtRule@ColorRule{#2}{\aboverulesep}{0pt}{0pt}% \specialrule{#1}{0pt}{\belowbottomsep}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvtRuleMid} % The |\kvtRuleMid|\oarg{wd}\marg{c-above}\marg{c-below} macro acts as a % replacement for \pkgname{booktabs}'s |\midrule|\oarg{wd} macro. % \begin{macrocode} \newcommand\kvtRuleMid{\noalign{\ifnum0=`}\fi \@ifnextchar[{\kvtRuleMid@i}{\kvtRuleMid@i[\lightrulewidth]}} \long\def\kvtRuleMid@i[#1]#2#3{\ifnum0=`{\fi}% \kvtRule@ColorRule{#2}{\aboverulesep}{0pt}{0pt}% \specialrule{#1}{0pt}{0pt}% % \end{macrocode} % For some reason, without the doubling of |\belowrulesep| below, % there is a white space below the |\specialrule|. (Fixme?) % \begin{macrocode} \kvtRule@ColorRule{#3}{2\belowrulesep}{0pt}{-\belowrulesep}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvtRuleCMid} % The % |\kvtRuleCMid|\oarg{wd}|(|\meta{trim}|)|\marg{a-b}\marg{c-above}\marg{c-below} % macro acts as a replacement for \pkgname{booktabs}'s % |\cmidrule|\oarg{wd}|(|\meta{trim}|)|\marg{a-b} macro. % \begin{macrocode} \newcommand\kvtRuleCMid{\noalign{\ifnum0=`}\fi \@ifnextchar[{\kvtRuleCMid@i}{\kvtRuleCMid@i[\cmidrulewidth]}} \long\def\kvtRuleCMid@i[#1]{% \@ifnextchar({\kvtRuleCMid@ii{#1}}{\kvtRuleCMid@ii{#1}()}} \long\def\kvtRuleCMid@ii#1(#2)#3{\ifnum0=`{\fi}% \kvtRule@cmid{#1}{{#2}{#3}}} % \end{macrocode} % The % |\kvtRule@cmid|\marg{wd}\marg{r-list}\marg{c-above}\marg{c-below} % macro does the actual work. % The \meta{r-list} parameter is a \pkgname{etoolbox} list of pairs % "\marg{trim}\marg{a-b}". % \begin{macrocode} \newcommand\kvtRule@cmid[4]{% % \end{macrocode} % The "\meta{wd}/2" (i.e., |#1/2|) occurring twice below "splits" the % later rule vertically into the upper half (on \meta{c-above} % background) and the lower half (on \meta{c-below} background). % \begin{macrocode} \kvtRule@ColorRule{#3} {\the\dimexpr\aboverulesep+#1/2\relax} {0pt} {\the\dimexpr-#1/2\relax}% % \end{macrocode} % Draw the "below" color already here such that the rule can be drawn in % the middle on top of the "above" and "below" color. % \begin{macrocode} \kvtRule@ColorRule{#4} {\the\dimexpr\belowrulesep+#1/2\relax}{0pt} {\the\dimexpr-\belowrulesep-#1\relax}% % \end{macrocode} % Now collect the rules to be drawn in a single macro |\kvt@@rules|. % \begin{macrocode} \noalign{% \let\kvt@@rules\@empty% \def\kvt@@do##1{\appto\kvt@@rules{\kvtRule@cmid@i{#1}##1}}% \forlistloop\kvt@@do{#2}% \expandafter}% \kvt@@rules % \end{macrocode} % In the spacing below, cancel out the negative spacing from % |\kvtRule@cmid@i|. % \begin{macrocode} \noalign{\vskip\dimexpr\belowrulesep+#1\relax}} % \end{macrocode} % % The |\kvtRule@cmid@i|\marg{wd}\marg{trim}\marg{a-b} macro produces a % single |\cmidrule|-like rule from a set of such rules. The arguments % are the same as for |\cmidrule|. % \begin{macrocode} \newcommand\kvtRule@cmid@i[3]{% % \end{macrocode} % The following three lines locally inject zero |\aboverulesep| into % |\cmidrule|. Due to grouping within |\@cmidrule|, this is not possible % for |\belowrulesep|; hence, we have to fix |\belowrulesep| in the % |\vskip| later in this macro. % Note that the |\noalign| started below is ended within |\@cmidrule|. % \begin{macrocode} \noalign{\ifnum0=`}\fi \aboverulesep=0pt\relax \@cmidrule[#1](#2){#3}% % \end{macrocode} % The imitates the code from |\xcmidrule| for when further |\cmidrule|s % follow. It additionally cancels out the superfluous |\belowrulesep| as % described before. % \begin{macrocode} \noalign{% \vskip-\dimexpr #1+\belowrulesep\relax \global\@lastruleclass\@ne}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvtRulesCMid} % The |\kvtRulesCMid|\oarg{width}\marg{r-list}\marg{color1}\marg{color2} % macro is the user interface for |\kvtRule@cmid| with multiple rules. % Here, \meta{r-list} is a comma-separated list of optional trim (in % parentheses) and column range -- and the code below essentially just % transforms this syntax into the syntax expected by |\kvtRule@cmid|. % \begin{macrocode} \newcommand\kvtRulesCMid{\noalign{\ifnum0=`}\fi \@ifnextchar[{\kvtRulesCMid@i}{\kvtRulesCMid@i[\cmidrulewidth]}} \long\def\kvtRulesCMid@i[#1]#2#3#4{% \let\kvt@@rules\@empty \forcsvlist\kvtRulesCMid@ii{#2}% \ifnum0=`{\fi\expandafter}\expandafter \kvtRulesCMid@v\expandafter{\kvt@@rules}{#1}{#3}{#4}} \newcommand\kvtRulesCMid@ii[1]{\kvtRulesCMid@iii#1\@undefined} \newcommand\kvtRulesCMid@iii{% \@ifnextchar({\kvtRulesCMid@iv}{\kvtRulesCMid@iv()}} \long\def\kvtRulesCMid@iv(#1)#2\@undefined{% \listadd\kvt@@rules{{#1}{#2}}} \newcommand\kvtRulesCMid@v[4]{\kvtRule@cmid{#2}{#1}{#3}{#4}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvtRule@ColorRule} % The |\kvtRule@ColorRule|\marg{color}\marg{wd}\marg{above}\marg{below} % macro draws a full-width horizontal table rule of width \meta{wd} in % color \meta{color} and spacing \meta{above} above and \meta{below} % below the rule. % If \meta{color} is empty, the current background color is used. % \begin{macrocode} \newcommand\kvtRule@ColorRule[4]{% \ifstrempty{#1} {\noalign{\expandafter\vskip\the\dimexpr #2+#3+#4\relax}} {\kvtRule@SaveRuleColor \arrayrulecolor{#1}% \specialrule{#2}{#3}{#4}% \kvtRule@RestoreRuleColor}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvtRule@SaveRuleColor} % \begin{macro}{\kvtRule@RestoreRuleColor} % These macros save and, respectively, restore the current rule color, % as provided by the \pkgname{colortbl} package in |\CT@arc@|. % \begin{macrocode} \newcommand\kvtRule@SaveRuleColor{% \noalign{\global\let\kvt@@ctarc\CT@arc@}} \newcommand\kvtRule@RestoreRuleColor{% \noalign{\global\let\CT@arc@\kvt@@ctarc}} % \end{macrocode} % \end{macro} % \end{macro} % % % \subsection{Key-Value Table Content} % % \begin{environment}{KeyValTable} % The |KeyValTable|\oarg{options}\marg{tname} environment encloses a new % table whose type is identified by the given \meta{tname}. Table options % can be overridden by providing \meta{options}. % \begin{macrocode} \newenvironment{KeyValTable}[2][]{% % \end{macrocode} % \begin{macro}{\Row} % The |\Row|\oarg{options}\marg{content} macro is made available locally % in the |KeyValTable| environment. % \begin{macrocode} \def\Row{\kvt@AddKeyValRow {\noalign\bgroup}{\expandafter\egroup\kvt@@row}{#2}}% \def\MidRule{\kvt@RuleMid}% \def\CMidRule{\kvt@RuleCMid{#2}}% % \end{macrocode} % \end{macro} % \begin{macrocode} \kvt@SetOptions{#2}{#1}% % \end{macrocode} % Save \meta{options} globally for a potential "|resume*|" option in the % immediately following |KeyValTable| environment. % If |resume*| is specified for the current environment, then the % previous options are not replaced. That is, |resume*| resumes the % options from the previous non-resuming environment. % \begin{macrocode} \ifbool{kvt@TableEnv@resume*}{} {\gdef\kvt@@lastenvopt{#1}}% \csuse{kvt@StartTable@\cmdkvt@Table@shape}{#2}% }{% \csuse{kvt@EndTable@\cmdkvt@Table@shape}} % \end{macrocode} % \end{environment} % % \begin{macro}{\kvt@SetOptions} % The |\kvt@SetOptions|\marg{tname}\marg{options} macro sets the % specific table options in the current environment, based on the % options for table type \meta{tname} and the specific \meta{options}. % \begin{macrocode} \newcommand\kvt@SetOptions[2]{\expandafter \kvt@SetOptions@i\expandafter{\csname kvt@options@#1\endcsname}{#2}} % \end{macrocode} % The auxiliary macro |\kvt@SetOptions@i|\marg{optcmd}\marg{options} % first sets the options in the expansion of \meta{optcmd} and then the % \meta{options}. % \begin{macrocode} \newcommand\kvt@SetOptions@i[2]{\expandafter \kvt@setkeys\expandafter{#1,#2}{Table,TableEnv}} % \end{macrocode} % \end{macro} % % % \subsubsection{Table Environment Properties} % % The following code maintains properties about known table % environments. This code does not depend on other code of the % \thispackage package but is only used by \thispackage. % % The following properties can be maintained about table environments. % \begin{macrocode} \define@boolkey[metatbl]{EnvProp}{isLong}{\metatbl@boolprop{isLong}{#1}} \define@boolkey[metatbl]{EnvProp}{isTabu}{\metatbl@boolprop{isTabu}{#1}} \define@boolkey[metatbl]{EnvProp}{hasWidth}{% \metatbl@boolprop{hasWidth}{#1}} \define@boolkey[metatbl]{EnvProp}{hasCaption}{% \metatbl@boolprop{hasCaption}{#1}} \define@boolkey[metatbl]{EnvProp}{canVAlign}{% \metatbl@boolprop{canVAlign}{#1}} \define@boolkey[metatbl]{EnvProp}{canHAlign}{% \metatbl@boolprop{canHAlign}{#1}} \define@cmdkey[metatbl]{EnvProp}{packages}{\metatbl@setprop{pkg}{#1}} % \end{macrocode} % The |atEnd| property shall be set to \hologo{TeX} code with one % argument (i.e., using the positional argument |#1|) that adds its % argument to the end of the active table environment's final content. % Finding such code is not obvious for table environments that collect % the content of the environment, like |tabularx| does, for instance. % \begin{macrocode} \define@key[metatbl]{EnvProp}{atEnd}{\metatbl@setprop[1]{atEnd}{#1}} % \end{macrocode} % % \begin{macro}{\metatblRegisterEnv} % The |\metatblRegisterEnv|\marg{env-name}\marg{properties} macro % registers a table environment with name \meta{env-name} and sets its % properties according to \meta{properties}, a comma-separated key-value % list. % \begin{macrocode} \newrobustcmd\metatblRegisterEnv[2]{% \edef\metatbl@@envname{#1}% \csdef{metatbl@@registered@#1}{true}% \setkeys[metatbl]{EnvProp}{#2}} % \end{macrocode} % \end{macro} % % \begin{macro}{\metatbl@setprop} % The |\metatbl@setprop|\oarg{n}\marg{key}\marg{value} % macro defines a macro with \meta{n} arguments ($0$ by default) for the % environment stored in |\metatbl@@envname| and the given % \meta{key}. This macro then expands to \meta{value}. % \begin{macrocode} \newcommand\metatbl@setprop[3][0]{% \expandafter\newcommand \csname metatbl@EnvProp@#2@\metatbl@@envname\endcsname[#1]{#3}} % \end{macrocode} % \end{macro} % % \begin{macro}{\metatbl@boolprop} % The |\metatbl@boolprop|\marg{prop}\marg{value} macro stores the % Boolean value \meta{value} in a property \meta{prop} for the % environment stored in |\metatbl@@envname|. % \begin{macrocode} \newcommand\metatbl@boolprop[2]{% \providebool{metatbl@EnvProp@#1@\metatbl@@envname}% \setbool{metatbl@EnvProp@#1@\metatbl@@envname}{#2}} % \end{macrocode} % \end{macro} % % \begin{macro}{\metatblRegistered} % \begin{macro}{\metatblIsLong} % \begin{macro}{\metatblIsTabu} % \begin{macro}{\metatblHasWidth} % \begin{macro}{\metatblHasCaption} % \begin{macro}{\metatblCanVAlign} % \begin{macro}{\metatblCanHAlign} % The following macros all expect the three arguments % \marg{env-name}\marg{iftrue}\marg{iffalse}. % The macro % |\metatblRegistered| % expands to \meta{iftrue} if \meta{env-name} has been registered via % |\metatblRegisterEnv| and expands to \meta{iffalse} otherwise. % The remaining macros expand to \meta{iftrue}, if the respective % property has been set to |true| in when \meta{env-name} was registered % via |\metatblRegisterEnv|, and expand to \meta{iffalse} otherwise. % \begin{macrocode} \newcommand\metatblRegistered[1]{\ifcsdef{metatbl@@registered@#1}} \newcommand\metatblIsLong[1]{\ifbool{metatbl@EnvProp@isLong@#1}} \newcommand\metatblIsTabu[1]{\ifbool{metatbl@EnvProp@isTabu@#1}} \newcommand\metatblHasWidth[1]{\ifbool{metatbl@EnvProp@hasWidth@#1}} \newcommand\metatblHasCaption[1]{\ifbool{metatbl@EnvProp@hasCaption@#1}} \newcommand\metatblCanVAlign[1]{\ifbool{metatbl@EnvProp@canVAlign@#1}} \newcommand\metatblCanHAlign[1]{\ifbool{metatbl@EnvProp@canHAlign@#1}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\metatblUsePackage} % \begin{macro}{\metatblRequire} % Macros |\metatblUsePackage|\marg{env-names} and % |\metatblRequire|\marg{env-names} load the packages required % for typesetting |KeyValTable| tables based on the table environments % listed in \meta{env-names}. % The former aims more at normal document use, the second at use by % package developers. % \begin{macrocode} \newcommand\metatblUsePackage[1]{% \def\do##1{% \metatbl@csnamearg\usepackage{metatbl@EnvProp@pkg@##1}}% \docsvlist{#1}} \newcommand\metatblRequire[1]{% \def\do##1{% \metatbl@csnamearg\RequirePackage{metatbl@EnvProp@pkg@##1}}% \docsvlist{#1}} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\metatblAtEnd} % The |\metatblAtEnd|\marg{env-name}\marg{code} macro registers % \meta{code} for addition at the end of tables based on the % \meta{env-name} environment. % \begin{macrocode} \newcommand\metatblAtEnd[2]{% \csname metatbl@EnvProp@atEnd@#1\endcsname{#2}} % \end{macrocode} % \end{macro} % % \begin{macro}{\metatbl@csnamearg} % The auxiliary macro % |\metatbl@csnamearg|\marg{command}\marg{csname} % passes the expansion of the macro with name \meta{csname} as the first % argument to \meta{command}. % \begin{macrocode} \newcommand\metatbl@csnamearg[2]{% \expandafter\expandafter\expandafter#1% \expandafter\expandafter\expandafter{\csname#2\endcsname}} % \end{macrocode} % \end{macro} % % The following are the properties of some basic table environments. % \begin{macrocode} \metatblRegisterEnv{tabular}{% isLong=false, hasWidth=false, isTabu=false, hasCaption=false, canVAlign=true, canHAlign=false, packages={}, atEnd={\preto\endtabular{#1}}, } \metatblRegisterEnv{tabularx}{% isLong=false, hasWidth=true, isTabu=false, hasCaption=false, canVAlign=true, canHAlign=false, packages=tabularx, atEnd={% % \end{macrocode} % Of the following two lines, the latter is for the case that the % \pkgname{xltabular} package is loaded, and the former is for the case % that the package is not loaded. % \begin{macrocode} \preto\TX@endtabularx{\toks@\expandafter{\the\toks@#1}}% \preto\XLT@i@TX@endtabularx{\toks@\expandafter{\the\toks@#1}}}, } \metatblRegisterEnv{longtable}{% isLong=true, hasWidth=false, isTabu=false, hasCaption=true, canVAlign=false, canHAlign=true, packages={longtable}, atEnd={\preto\endlongtable{#1}}, } \metatblRegisterEnv{xltabular}{% isLong=true, hasWidth=true, isTabu=false, hasCaption=true, canVAlign=false, canHAlign=true, packages=xltabular, atEnd={\preto\XLT@ii@TX@endtabularx{\toks@\expandafter{\the\toks@#1}}}, } \metatblRegisterEnv{tabu}{% isLong=false, hasWidth=true, isTabu=true, hasCaption=false, canVAlign=true, canHAlign=false, packages={tabu}, % \end{macrocode} % The following is not a mistake: |tabu| does % |\def\endtabu{\endtabular}| at the beginning of a |tabu| environment. % \begin{macrocode} atEnd={\preto\endtabular{#1}}, } \metatblRegisterEnv{longtabu}{% isLong=true, hasWidth=true, isTabu=true, hasCaption=true, canVAlign=false, canHAlign=true, packages={tabu,longtable}, % \end{macrocode} % The following is not a mistake: |tabu| does % |\def\endlongtabu{\endlongtable}| at the beginning of a |longtabu| % environment. % \begin{macrocode} atEnd={\preto\endlongtable{#1}}, } % \end{macrocode} % % \begin{macro}{\metatbl@ifhasXcolumns} % The |\metatbl@ifhasXcolumns|\marg{preamble}\marg{iftrue}\marg{iffalse} % takes a \meta{preamble} (the argument of a |tabular| environment that % specifies the columns of the table) and checks, whether this preamble % contains an "|X|" column. If such a column is contained, the macro % expands to \meta{iftrue}. Otherwise, it expands to \meta{iffalse}. % \begin{macrocode} \newrobustcmd\metatbl@ifhasXcolumns[1]{% \begingroup % \end{macrocode} % The |\metatbl@@branch| macro is used at the end of the macro to select % \meta{iftrue} or \meta{iffalse} for expansion. Initially, the macro is % defined to select \meta{iffalse}. % \begin{macrocode} \def\metatbl@@branch{\@secondoftwo}% % \end{macrocode} % The code uses the |\@mkpream| macro of the \pkgname{array} package to % create an |\halign| preamble from the |tabular| \meta{preamble}. % The result of |\@mkpream| is in |\@preamble| afterwards, but this % result is not used, but rather discarded at the |\endgroup| below. % Rather, we hook into |\@mkpream| via |\NC@rewrite@X|, which is used % when an |X| column was encountered in \meta{preamble}.\footnote{This % hooking into \cmd{\@mkpream} is inspired by how |tabularx| replaces |X| % columns by |p| columns as part of its measuring.} % When an |X| column is encountered, |\metatbl@@branch| is redefined to % expand to \meta{iftrue} in the end. % \begin{macrocode} \def\NC@rewrite@X{\def\metatbl@@branch{\@firstoftwo}\NC@find l}% \@mkpream{#1}% \expandafter\endgroup\metatbl@@branch} % \end{macrocode} % \end{macro} % % % \subsubsection{Table Environment Code} % % \begin{macro}{\kvt@StartTabularlike} % The % |\kvt@StartTabularlike|\marg{env}\marg{tname} % macro begins a table environment for the given table type \meta{tname}. % The \meta{env} parameter specifies the concrete environment name. % \begin{macrocode} \newcommand\kvt@StartTabularlike[2]{% % \end{macrocode} % \changes{v1.0}{2019/02/18}{Implemented \texttt{showrules} option} % \begin{macrocode} \metatblAtEnd{#1}{\kvt@@endhook}% \let\kvt@@endhook\@empty \let\kvt@@prehook\@empty \ifbool{kvt@Table@showrules} {\def\kvt@@rule##1{\csuse{kvt@Rule##1}}} {\def\kvt@@rule##1{}}% \appto\kvt@@prehook{\kvt@@rule{Top}}% \appto\kvt@@endhook{\kvt@@rule{Bottom}}% % \end{macrocode} % The following saves the row counter value for the table type globally, % such that subsequent tables of the same \meta{tname} can start counting % from there. Moreover, it save the local row counter for the case that % the next table uses the "|resume|" option. % \begin{macrocode} \appto\kvt@@endhook{\noalign{% \csxdef{kvt@rowcount@#2}{\thekvtTypeRow}% \csxdef{kvt@@rowcountlast}{\thekvtRow}}}% % \end{macrocode} % Adding caption and label. % \begin{macrocode} \ifdefvoid\cmdkvt@TableEnv@caption {\let\kvt@@caption@main\@empty \let\kvt@@caption@alt\@empty} {\metatblHasCaption{#1} {\edef\kvt@@caption@main{% \csexpandonce{kvt@caption@\cmdkvt@Table@captionpos}% \ifcsvoid{cmdkvt@TableEnv@caption/lot}{} {[{\csexpandonce{cmdkvt@TableEnv@caption/lot}}]}% {\expandonce\cmdkvt@TableEnv@caption \ifdefvoid\cmdkvt@TableEnv@label{}{% \noexpand\label{\expandonce\cmdkvt@TableEnv@label}}}% \noexpand\\}% \ifcsvoid{cmdkvt@TableEnv@caption/alt} {\def\kvt@@caption@alt{}} {\edef\kvt@@caption@alt{% \csexpandonce{kvt@caption@\cmdkvt@Table@captionpos}[]% {\csexpandonce{cmdkvt@TableEnv@caption/alt}}% \noexpand\\}}% }{\kvt@error {Caption lost, table backend '#1' does not support captions} {Consider placing the KeyValTable environment inside a 'table' environment and use the \string\caption\space macro inside.}}}% \ifdefstring{\cmdkvt@Table@captionpos}{t} {\let\kvt@@caption@headmain\kvt@@caption@main \let\kvt@@caption@footmain\@empty \let\kvt@@caption@headalt\kvt@@caption@alt \let\kvt@@caption@footalt\@empty} {\let\kvt@@caption@footmain\kvt@@caption@main \let\kvt@@caption@headmain\@empty \let\kvt@@caption@footalt\kvt@@caption@alt \let\kvt@@caption@headalt\@empty}% \ifbool{kvt@Table@showhead} {\eappto\kvt@@prehook{\csuse{kvt@headings@#2}% \noexpand\kvt@@rule{SubHead}}} {}% % \end{macrocode} % The following lines perform some checks before the table environment % is started. % \begin{macrocode} \ifdefvoid{\cmdkvt@Table@valign}{}{\metatblCanVAlign{#1}{} {\undef{\cmdkvt@Table@valign}% \kvt@warn{Table environment '#1' of table '#2' does not support the vertical alignment option (valign). Ignoring the option}}}% \ifdefvoid{\cmdkvt@Table@halign}{}{\metatblCanHAlign{#1}{} {\undef{\cmdkvt@Table@halign}% \kvt@warn{Table environment '#1' of table '#2' does not support the horizontal alignment option (halign). Ignoring the option}}}% % \end{macrocode} % Initializing the row counters. The global counter |kvtTotalRow| needs % no local initialization. % \begin{macrocode} \global\kvt@@bodyrow=0\relax \ifbool{kvt@TableEnv@resume} {\setcounter{kvtRow}{\csuse{kvt@@rowcountlast}}} {\setcounter{kvtRow}{0}}% \setcounter{kvtTypeRow}{\csuse{kvt@rowcount@#2}}% % \end{macrocode} % Initialize the background colors for the body rows. % \begin{macrocode} \expandafter\kvt@setrowcolors\expandafter{\cmdkvt@Table@rowbg}% % \end{macrocode} % In |\kvt@@do|, the start code for the environment, including the % header rows, is gathered, with expansion to fill in all the table % settings and options. % \changes{v0.3}{2016/06/05}{Added \texttt{showhead} option} % \changes{v1.0}{2019/03/09}{Added \texttt{width} option} % \changes{v2.1}{2020/01/19}{Added \texttt{valign} and \texttt{halign} options} % \begin{macrocode} \begingroup\edef\kvt@@do{\endgroup \expandafter\noexpand\csname #1\endcsname % \end{macrocode} % As background on the positions of the parameters below, here is the % syntax for beginning the supported environments: % \begin{itemize}[nosep] % \item|\begin{tabular}|\oarg{valign}\marg{preamble} % \item|\begin{tabularx}|\marg{width}\oarg{valign}\marg{preamble} % \item|\begin{longtable}|\oarg{halign}\marg{preamble} % \item|\begin{xltabular}|\oarg{halign}\marg{width}\marg{preamble} % \item|\begin{tabu}| to \meta{width}\oarg{valign}\marg{preamble} % \item|\begin{longtabu}| to \meta{width}\oarg{halign}\marg{preamble} % \end{itemize} % The above cases are covered in the following lines. % \begin{macrocode} \ifdefvoid{\cmdkvt@Table@halign}{} {\metatblIsTabu{#1}{}{[\cmdkvt@Table@halign]}}% \metatblHasWidth{#1} {\metatblIsTabu{#1} {to \expandonce\cmdkvt@Table@width} {{\expandonce\cmdkvt@Table@width}}} {}% \ifdefvoid{\cmdkvt@Table@valign}{}{[\cmdkvt@Table@valign]}% \ifdefvoid{\cmdkvt@Table@halign}{} {\metatblIsTabu{#1}{[\cmdkvt@Table@halign]}{}}% {\csexpandonce{kvt@alignments@#2}}% % \end{macrocode} % The remainder below already starts the content of the table % environment. It also sets the header and footer for multipage tables. % \begin{macrocode} \expandonce\kvt@@caption@headmain \expandonce\kvt@@prehook \metatblIsLong{#1}{% \noexpand\endfirsthead \expandonce\kvt@@caption@headalt \expandonce\kvt@@prehook \noexpand\endhead}{}% \expandonce\kvt@@caption@footmain \metatblIsLong{#1}{% \noexpand\endlastfoot \expandonce\kvt@@caption@footalt \noexpand\endfoot}{}% }\kvt@@do} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@caption@b} % \begin{macro}{\kvt@caption@t} % The |\kvt@caption@b| and |\kvt@caption@t| macros behave like % |\caption| but add extra behavior depending on whether the caption is % displayed above (|\kvt@caption@t|) or below (|\kvt@caption@b|) the % table. Currently, |\kvt@caption@b| only fixes the spacing between the % table and the caption. % \begin{macrocode} \newcommand\kvt@caption@t{\caption} \newcommand\kvt@caption@b{% % \end{macrocode} % Fixme: The following |\baselineskip| before the caption compensates % that \pkgname{longtable} adds a |\baselineskip| below the caption (in % its macro |\LT@makecaption|) but not above. The \pkgname{ltcaption} % package replaces the hard-coded |\baselineskip| by |\LTcapskip| but % also only puts it below the caption. The code below could at least be % improved to use |\LTcapskip| if it is available. % \begin{macrocode} \noalign{\parbox{0pt}{\vskip\baselineskip}}% \caption} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\kvt@setrowcolors} % The |\kvt@setrowcolors|\marg{colors} sets up row % colors using the |\rowcolors| macro of \pkgname{xcolor}. % The \marg{colors} parameter expects arguments of the form % "\meta{color1}|..|\meta{color2}" (the syntax used for the |rowbg| % option. The row colors then alternate between \meta{color1} and % \meta{color2}, starting with \meta{color1} in the first row. % If \meta{colors} is empty, then no row colors are setup. % \begin{macrocode} \newcommand\kvt@setrowcolors[1]{% \ifstrempty{#1}{\kvt@setrowcolors@ii{}{}} {\kvt@setrowcolors@i#1\@nil}} \def\kvt@setrowcolors@i#1..#2\@nil{% \kvt@setrowcolors@ii{#1}{#2}} \newcommand\kvt@setrowcolors@ii[2]{% \def\kvt@@bgcolor@odd{#1}% \def\kvt@@bgcolor@even{#2}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@userowcolors} % The |\kvt@userowcolors| macro macro expands to % |\rowcolor|\marg{color}, where \meta{color} is the background color % set via |\kvt@setrowcolors| for odd, respectively even rows, based on % |\kvt@@bodyrow|. % \begin{macrocode} \newcommand\kvt@userowcolors{\ifnumodd{\the\kvt@@bodyrow} {\kvt@rowcolorcmdornot{\kvt@@bgcolor@odd}} {\kvt@rowcolorcmdornot{\kvt@@bgcolor@even}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@RegisterBackend} % \begin{macro}{\kvt@RegisterShape} % The |\kvt@RegisterBackend|\marg{env} macro registers the table % environment \meta{env} as a table backend for use by \thispackage. % The |\kvt@RegisterShape|\marg{name}\marg{nonX-env}\marg{X-env} % registers a shape with the given \meta{name} and associates it with % the environment \meta{nonX-env} when the shape is used for a table % without |X| columns and with environment \meta{X-env} otherwise. % \begin{macrocode} \newcommand\kvt@RegisterBackend[1]{% \ifinlist{#1}{\kvt@@tablebackends} {\kvt@error{Backend '#1' already registered} {Internal error. Check use of \string\kvt@RegisterBackend.}} {\kvt@CheckMetatblEnv{#1}% \listadd{\kvt@@tablebackends}{#1}% \kvt@DefineStdTabEnv{#1}{#1}}} \newcommand\kvt@RegisterShape[3]{% \ifinlist{#1}{\kvt@@tableshapes} {\kvt@error{Shape '#1' already registered} {Internal error. Check use of \string\kvt@RegisterShape.}} {\kvt@CheckMetatblEnv{#2}\kvt@CheckMetatblEnv{#3}% \listadd{\kvt@@tableshapes}{#1}% \ifstrequal{#2}{#3} {\kvt@DefineStdTabEnv{#1}{#2}} {\kvt@DefineDualTabEnv{#1}{#2}{#3}}}} \newcommand\kvt@CheckMetatblEnv[1]{\metatblRegistered{#1}{} {\kvt@error{Environment '#1' not supported by keyvaltable} {Check \string\metatblRegisterEnv\space for how to make it supported.}}} % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\kvt@RegisterBackend} % \begin{macro}{\kvt@RegisterShape} % The macros |\kvt@@tablebackends| and |\kvt@@tableshapes| hold % \pkgname{etoolbox} lists of registered names of table backends and % table shapes. % \begin{macrocode} \newcommand\kvt@@tablebackends{} \newcommand\kvt@@tableshapes{} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\kvt@DefineStdTabEnv} % The |\kvt@DefineStdTabEnv|\marg{shape}\marg{env} % macro defines the macros needed for the given \meta{shape} value. % If \meta{shape} is omitted, \meta{env} (the name of the environment to % use for the shape) is used as \meta{shape} value. % \begin{macrocode} \newcommand\kvt@DefineStdTabEnv[2]{% \csdef{kvt@StartTable@#1}##1{% \kvt@StartTabularlike{#2}{##1}}% \csedef{kvt@EndTable@#1}{% \expandafter\noexpand\csname end#2\endcsname}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@DefineDualTabEnv} % The |\kvt@DefineDualTabEnv|\marg{shape}\marg{nonX-env}\marg{X-env} % macro defines the macros for the given \meta{shape} name. % The macros are defined in a way such that the table environment % \meta{nonX-env} is used for typesetting tables that do not use |X| % columns and that table environment \meta{X-env} is used for % typesetting tables that do use |X| columns. % \begin{macrocode} \newcommand\kvt@DefineDualTabEnv[3]{% \expandafter\newcommand\csname kvt@StartTable@#1\endcsname[1]{% \kvt@ifhasXcolumns{##1} {\csedef{kvt@EndTable@#1}{% \expandafter\noexpand\csname end#3\endcsname}% \kvt@StartTabularlike{#3}{##1}% }{\csedef{kvt@EndTable@#1}{% \expandafter\noexpand\csname end#2\endcsname}% \kvt@StartTabularlike{#2}{##1}}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@ifhasXcolumns} % The |\kvt@ifhasXcolumns|\marg{tname}\marg{iftrue}\marg{iffalse} % takes a table type \meta{tname} and checks whether the table type % contains an "|X|" column. If such a column is contained, the macro % expands to \meta{iftrue}. Otherwise, it expands to \meta{iffalse}. % \begin{macrocode} \newcommand\kvt@ifhasXcolumns[1]{% \expandafter\expandafter\expandafter\metatbl@ifhasXcolumns \expandafter\expandafter\expandafter{% \csname kvt@alignments@#1\endcsname}} % \end{macrocode} % \end{macro} % % The following lines define the macros for the various table % environments. % \begin{macrocode} \kvt@RegisterBackend{tabular} \kvt@RegisterBackend{longtable} \kvt@RegisterBackend{tabularx} \kvt@RegisterBackend{xltabular} \kvt@RegisterBackend{tabu} \kvt@RegisterBackend{longtabu} % \end{macrocode} % % % \subsubsection{Environment-Independent Parts} % % \begin{macro}{\kvt@AddKeyValRow} % The % |\kvt@AddKeyValRow|\marg{pre}\marg{post}\marg{tname}\oarg{options}\marg{content} % macro composes a row for the table of type \meta{tname} from the given % \meta{content} and \meta{options}. The \meta{content} is a % key-value list that specifies the content of the individual cells in % the row. The result is returned in macro |\kvt@@row|. % The arguments \meta{pre} and \meta{post} are expanded at the very % beginning, resp.\@ end of the macro. % They allow to control grouping (|\begingroup| and |\endgroup|) as well % as table placement via |\noalign|. % \changes{v1.0}{2019/03/17}{Added \oarg{options}} % \begin{macrocode} \newcommand\kvt@AddKeyValRow[3]{% #1% % \end{macrocode} % It's essential that \meta{pre} above comes even before |\@ifnextchar| % and, therefore, cannot be moved into |\kvt@AddKeyValRow@i|: % The |\@ifnextchar| is not fully expandable and therefore any % |\noalign| (in \meta{pre}) following |\@ifnextchar| would lead to % "misplaced |\noalign|" errors. % \begin{macrocode} \@ifnextchar[%] {\kvt@AddKeyValRow@i{#2}{#3}} {\kvt@AddKeyValRow@i{#2}{#3}[]}} % \end{macrocode} % \end{macro} % \begin{macro}{\kvt@AddKeyValRow@i} % The % |\kvt@AddKeyValRow@i|\marg{post}\marg{tname}\oarg{options}\marg{content} % macro parses \meta{options} and evaluates the |hidden| option. % \begin{macrocode} \def\kvt@AddKeyValRow@i#1#2[#3]#4{% \kvt@setkeys{#3}{Row}% \ifbool{kvt@Row@hidden} {\let\kvt@@row\@empty #1} {\kvt@AddKeyValRow@ii{#1}{#2}{#4}}} % \end{macrocode} % \end{macro} % \begin{macro}{\kvt@AddKeyValRow@ii} % The % |\kvt@AddKeyValRow@ii|\marg{post}\marg{tname}\marg{content} % macro mainly processes \meta{content} as well as \meta{options} % that have already been parsed by |\kvt@AddKeyValRow@i|. % \begin{macrocode} \def\kvt@AddKeyValRow@ii#1#2#3{% \setkeys[KeyValTable]{#2}{#3}% % \end{macrocode} % Initialize and first add the |\noalign| material to the row. % \begin{macrocode} \def\kvt@@row{}% \ifdefvoid\cmdkvt@Row@above{}{% \eappto\kvt@@row{\noexpand\noalign{\noexpand\vspace{% \expandonce\cmdkvt@Row@above}}}}% \appto\kvt@@row{\noalign{\global\advance\kvt@@bodyrow\@ne}}% \ifbool{kvt@Row@uncounted}{}{% \appto\kvt@@row{\noalign{\kvt@stepcounters}}}% \ifdefvoid\cmdkvt@Row@bg {\appto\kvt@@row{\kvt@userowcolors}} {\eappto\kvt@@row{\noexpand\rowcolor{\expandonce\cmdkvt@Row@bg}}}% % \end{macrocode} % If a row alignment is specified, a default |\multicolumn| display is % enabled for the row's cells. % \begin{macrocode} \ifdefvoid\cmdkvt@Row@align {\def\kvt@@rowmkmulticolumn{\kvt@unicolumn}} {\edef\kvt@@rowmkmulticolumn{% \noexpand\kvt@multicolumn{1}{\expandonce\cmdkvt@Row@align}}}% % \end{macrocode} % The following defines a macro % |\kvt@@cellfmtbuilder|\marg{cmd}\marg{csname}. % This macro defines the macro \meta{cmd}\marg{cell} to format the cell % content, \meta{cell}, based on the column format \meta{csname} and the % row formatting options. % Through this "builder" macro, the row format options need only be % considered once and the column format options can then be included % when the displayed columns are iterated over. % \begin{macrocode} \ifcsvoid{cmdkvt@Row@format!} {\edef\kvt@@cellfmtbuilder##1##2{% \noexpand\edef##1####1{% \noexpand\kvt@expandonce@onearg\noexpand\kvt@@mkmulticolumn {\ifcsvoid{cmdkvt@Row@format*}{\@firstofone} {\noexpand\unexpanded{\csexpandonce{cmdkvt@Row@format*}}}% {\noexpand\csexpandonce{##2}{% \ifdefvoid\cmdkvt@Row@format{\@firstofone} {\noexpand\unexpanded{\expandonce\cmdkvt@Row@format}}% {####1}}}}}}}% {\edef\kvt@@cellfmtbuilder##1##2{% \noexpand\edef##1####1{% \noexpand\kvt@expandonce@onearg\noexpand\kvt@@mkmulticolumn{% \noexpand\unexpanded{\csexpandonce{cmdkvt@Row@format!}}% {####1}}}}}% % \end{macrocode} % The following loop uses |\do|\marg{cname} to append the content of % all displayed columns (in the given format and using the given default % value), where each column value is in % \cs{cmdKeyValTable@\meta{tname}@\meta{cname}}. % Note that currently the default value is formatted using the given % format macro -- a design decision. % \changes{v1.0}{2019/02/03}{Added \cs{multicolumn} support} % \begin{macrocode} \kvt@@span=0\relax \kvt@def@atseconduse\kvt@@switchcol{\appto\kvt@@row{&}}% \def\do##1{% % \end{macrocode} % First, check whether a column-spanning cell is active % ($\cs{kvt@@span}>0$). If this is the case, ensure that if the raw cell % content in the current column is empty, then the column is simply % ignored and otherwise an error is produced. % \begin{macrocode} \ifnumgreater\kvt@@span{0} {\advance\kvt@@span\m@ne \ifcsvoid{cmdKeyValTable@#2@##1}{} {\ifdefvoid\kvt@@curcgname {\kvt@error{Column '##1' nonempty inside a \string\multicolumn}{}} {\kvt@error{Column '##1' nonempty inside column group '\kvt@@curcgname'}{}}}} {\kvt@@switchcol % \end{macrocode} % Initialize the multicolumn display to the row's default. % \begin{macrocode} \let\kvt@@mkmulticolumn\kvt@@rowmkmulticolumn \letcs\kvt@@curcolformat{kvt@col@format@#2@##1}% % \end{macrocode} % First recover the cell content (either the specified value for the row % or, if no value is specified for the row, the cell's default value) % without formatting. % \begin{macrocode} \ifcsvoid{cmdKeyValTable@#2@##1} {\letcs\kvt@@cell{kvt@col@default@#2@##1}} {\letcs\kvt@@cell{cmdKeyValTable@#2@##1}% % \end{macrocode} % Unless the default cell value is used, first check for a multicolumn % value. Default cell values should not need this. The check is done % before the expansion code afterwards, in order for applying the % expansion to the code in the cell value rather than to the multicolumn % code. % \begin{macrocode} \expandafter\kvt@CheckMulticolumn\expandafter{\kvt@@cell}{#2}% % \end{macrocode} % Apply expansion control options, but only to manually supplied cell % values, not to default values. % \begin{macrocode} \ifbool{kvt@Row@expandonce} {\expandafter\let\expandafter\kvt@@cell\kvt@@cell}{}% \ifbool{kvt@Row@expand} {\protected@edef\kvt@@cell{\kvt@@cell}}{}}% % \end{macrocode} % Separately also already create the content -- with formatting unless % the user explicitly requested no cell formatting. % \begin{macrocode} \ifcsvoid{kvt@@noformat@#2@##1} {\kvt@@cellfmtbuilder\kvt@@formatter{kvt@@curcolformat}}% {\let\kvt@@formatter\kvt@unicolumn}% \csundef{kvt@@noformat@#2@##1}% \edef\kvt@@fmtcell{\expandafter\expandonce\expandafter{% \expandafter\kvt@@formatter\expandafter{% \kvt@@cell}}}% % \end{macrocode} % Finally, append the cell to the row. % \begin{macrocode} \expandafter\appto\expandafter\kvt@@row\expandafter{% \kvt@@fmtcell}}% }\dolistcsloop{kvt@displaycols@#2}% \undef\kvt@@cellfmtbuilder % \end{macrocode} % Finally, add the concluding newline for the row as well as % the vertical space after the row, if requested. % \begin{macrocode} \appto\kvt@@row{\tabularnewline}% \ifdefvoid\cmdkvt@Row@below{}{% \eappto\kvt@@row{\noexpand\noalign{\noexpand\vspace{% \expandonce\cmdkvt@Row@below}}}}% % \end{macrocode} % At the very end of the expansion text, put \meta{post}. % \begin{macrocode} #1} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@def@atseconduse} % The |\kvt@def@atseconduse|\marg{cmd}\marg{code} defines the macro % \meta{cmd} to expand to \meta{code} but only from its second use % onwards. At its first use, \meta{cmd} only redefines itself to % \meta{code} but does not do anything else. % \begin{macrocode} \newcommand\kvt@def@atseconduse[2]{\def#1{\def#1{#2}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@expandonce@onearg} % The |\kvt@expandonce@onearg|\marg{cmd}\marg{arg} macro expands to % \meta{arg} if \meta{cmd} is empty and expands to an |\expandonce| on % \meta{cmd} with \meta{arg} as argument otherwise. % This macro is for an |\edef| context in which an empty \meta{cmd} % should not leave any parentheses around the \meta{arg}. % \begin{macrocode} \newcommand\kvt@expandonce@onearg[2]{% \ifdefequal{#1}{\@empty}{#2}{\expandonce{#1}{#2}}} % \end{macrocode} % Note that the alternative of avoiding the conditional (|\ifdefequal|) % in the above code and using |\@firstofone| instead of |\@empty| for a % noop in \meta{cmd} does not work: % \begin{itemize}[nosep] % \item Using `|\expandonce|\marg{cmd}\marg{arg}' would, by definition % of |\expandonce|, expand to % `|\unexpanded\expandafter{\@firstofone}|' and produces the error % `Argument of |\@firstofone| has an extra |}|'. % \item Using `|\expandonce{|\meta{cmd}\marg{arg}|}|' would expand to % `|\unexpanded|\marg{arg}' and, thus, prevent expansion of % \meta{arg}. % \end{itemize} % \end{macro} % % \begin{macro}{\kvt@stepcounters} % The |\kvt@stepcounters|\oarg{delta} macro increments all row counters % by \meta{delta}. If \meta{delta} is omitted, \meta{delta}=1. % \begin{macrocode} \newcommand\kvt@stepcounters[1][1]{% \addtocounter{kvtRow}{#1}% \addtocounter{kvtTypeRow}{#1}% \addtocounter{kvtTotalRow}{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@CheckMulticolumn} % The % |\kvt@CheckMulticolumn|\marg{content}\marg{tname} macro % checks whether a cell's \meta{content} in a table of type \meta{tname} % spans multiple columns in one of two ways: % \begin{enumerate}[nosep] % \item \meta{content} = |\multicolumn|\marg{n}\marg{align}\marg{content} or % \item \meta{content} = |\kvt@@@colgroup|\marg{cgname}\marg{n}\marg{align}\marg{content} % \end{enumerate} % The first way corresponds to the case that a user of the package % explicitly assigns a |\multicolumn| expression to a cell in a row. % The second way is generated by the package when a user assigns a % normal cell value to a column group key. % \begin{macrocode} \newcommand\kvt@CheckMulticolumn[2]{% % \end{macrocode} % For parsing \meta{content}, the macro uses |\kvt@CheckMulticolumn@i| % and adds 5 |\relax| after \meta{content} for the case that % \meta{content} is empty or too short. % \begin{macrocode} \kvt@CheckMulticolumn@i{#2}#1% \relax\relax\relax\relax\relax\kvt@@undefined} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@CheckMulticolumn@i} % The % |\kvt@CheckMulticolumn@i|\marg{tname}\marg{c1}$\cdots$\marg{c5}\marg{ign}|\@undefined| % macro checks \meta{content} when split into \meta{c1}$\cdots$\meta{c5} % for one of the two multicolumn cases listed in the description of % |\kvt@CheckMulticolumn|. % \begin{macrocode} \def\kvt@CheckMulticolumn@i#1#2#3#4#5#6#7\kvt@@undefined{% \ifdefmacro{#2}{% % \end{macrocode} % First case: \meta{c1}=|\multicolumn|. In this case, we have % \meta{c2}=\meta{n}, \meta{c3}=\meta{align}, and % \meta{c4}=\meta{content}. % \begin{macrocode} \ifx#2\multicolumn \kvt@SetMulticolumn{#4}{#3}{#5}% \let\kvt@@curcgname\@empty % \end{macrocode} % Second case: \meta{c1}=|\kvt@@@colgroup|. In this case, we have % \meta{c3}=\meta{n}, \meta{c4}=\meta{align}, and % \meta{c5}=\meta{content}. Moreover, \meta{c2} holds \meta{cgname}. % \begin{macrocode} \else\ifx#2\kvt@@@colgroup \letcs\kvt@@curcolformat{kvt@colgrp@format@#1@#3}% \def\kvt@@curcgname{#3}% % \end{macrocode} % If a row alignment is defined, it overrides the alignment of the % column group: % \begin{macrocode} \ifdefvoid\cmdkvt@Row@align {\kvt@SetMulticolumn{#5}{#4}{#6}} {\expandafter \kvt@SetMulticolumn\expandafter{\cmdkvt@Row@align}{#4}{#6}}% \fi\fi}{}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@@@colgroup} % The |\kvt@@@colgroup| macro is not used as an actual macro but only as % an identifier for |\kvt@CheckMulticolumn@i|. % \begin{macrocode} \newcommand\kvt@@@colgroup{kvt@@@colgroup} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@SetMulticolumn} % The |\kvt@SetMulticolumn|\marg{align}\marg{n}\marg{content} records % that \meta{n} cells, starting from the current cell, belong to a % multicolumn cell with alignment \meta{align} and the given % \meta{content}. % \begin{macrocode} \newcommand\kvt@SetMulticolumn[3]{% % \end{macrocode} % First, record \meta{n} in |\kvt@@span|. The subtraction of $-1$ is % already in preparation for the next column, in which one spanning has % already been reduced. % \begin{macrocode} \kvt@@span=#2\relax \advance\kvt@@span\m@ne % \end{macrocode} % Next, unwrap the cell's \meta{content} to |\kvt@@cell| and record the % |\kvt@@mkmulticolumn| for re-wrapping the content later, after all % cell formatting has been applied. % \begin{macrocode} \def\kvt@@cell{#3}% \def\kvt@@mkmulticolumn{\kvt@multicolumn{#2}{#1}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@unicolumn} % \begin{macro}{\kvt@multicolumn} % The |\kvt@unicolumn|\marg{content} macro is the central macro for % creating a "normal" (non-multicolumn) cell holding the given % \meta{content}. % Analogously, the macro % |\kvt@multicolumn|\marg{align}\marg{n}\marg{content} % is the central macro for creating a multi-column cell with % \meta{content}. % The two macros are only meant to improve code legibility and to % simplify certain future modifications. % \begin{macrocode} \newcommand\kvt@unicolumn[1]{#1} \newcommand\kvt@multicolumn[3]{\multicolumn{#1}{#2}{#3}} % \end{macrocode} % \end{macro} % \end{macro} % % \subsubsection{Table and Row Styles} % % The following are the user macros. % % \begin{macro}{\kvtNewRowStyle} % \changes{v2.0}{2019/03/25}{Added the macro} % \begin{macro}{\kvtRenewRowStyle} % \changes{v2.0}{2019/03/25}{Added the macro} % The |\kvtNewRowStyle|\marg{name}\marg{row-options} macro declares % \meta{name} as a row style and defines it to be equivalent to % specifying \meta{row-options} directly in the optional argument of % |\Row|. The macro fails if \meta{name} is already declared as a row % style. % \begin{macrocode} \newcommand\kvtNewRowStyle{\kvt@NewStyle{row}{\kvtRenewRowStyle}} % \end{macrocode} % The |\kvtRenewRowStyle|\marg{name}\marg{row-options} macro re-defines % an already existing row style with new \meta{row-options}. % \begin{macrocode} \newcommand\kvtRenewRowStyle{\kvt@RenewStyle{row}{\kvtNewRowStyle}} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\kvtNewTableStyle} % \changes{v2.2}{2020/02/24}{Added the macro} % \begin{macro}{\kvtRenewTableStyle} % \changes{v2.2}{2020/02/24}{Added the macro} % The |\kvtNewTableStyle|\marg{name}\marg{options} macro declares % \meta{name} as a table style and defines it to be equivalent to % specifying \meta{options} directly in the optional argument of % a |KeyValTable| environment or of a |\NewKeyValTable|. The macro fails % if \meta{name} is already declared as a table style. % \begin{macrocode} \newcommand\kvtNewTableStyle{\kvt@NewStyle{table}{\kvtRenewTableStyle}} % \end{macrocode} % The |\kvtRenewTableStyle|\marg{name}\marg{options} macro re-defines % an already existing table style with new \meta{options}. % \begin{macrocode} \newcommand\kvtRenewTableStyle{\kvt@RenewStyle{table}{\kvtNewTableStyle}} % \end{macrocode} % \end{macro} % \end{macro} % % The following are the internal macros that the style code shares. % % \begin{macro}{\kvt@NewStyle} % \begin{macro}{\kvt@RenewStyle} % The |\kvt@NewStyle|\marg{type}\marg{renewcmd}\marg{name}\marg{options} % macro defines a new style, \meta{name}, for \meta{type} (|table| or % |row|) to correspond to \meta{options}. % Analogously, % |\kvt@RenewStyle|\marg{type}\marg{newcmd}\marg{name}\marg{options} % macro re-defines a style. % \begin{macrocode} \newcommand\kvt@NewStyle[4]{% \ifcsundef{kvt@@#1style@#3} {\csdef{kvt@@#1style@#3}{#4}} {\kvt@error{The #1 style '#3' is already defined}{Use \string#2\space to change an existing style.}}} \newcommand\kvt@RenewStyle[4]{% \ifcsundef{kvt@@#1style@#3} {\kvt@error{A #1 style '#3' is not defined} {Use \string#2\space to define a new #1 style.}} {\csdef{kvt@@#1style@#3}{#4}}} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\kvt@UseRowStyles} % \begin{macro}{\kvt@UseTableStyles} % \changes{v2.2}{2020/02/24}{Added the macro} % The |\kvt@UseRowStyles|\marg{styles} and % |\kvt@UseTableStyles|\marg{styles} macros set the keys for the given, % comma-separated list of \meta{styles}. % \begin{macrocode} \newcommand\kvt@UseRowStyles[1]{% \kvt@UseStyles{row}{Row}{\kvt@NewRowStyle}{#1}} \newcommand\kvt@UseTableStyles[1]{% \kvt@UseStyles{table}{Table}{\kvt@NewTableStyle}{#1}} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\kvt@UseStyle} % The |\kvt@UseStyle|\marg{type}\marg{fam}\marg{newcmd}\marg{style} % macro sets the keys for type \meta{type} based on the \meta{options} % stored for the given \meta{style}. % The \meta{fam} identifies the % \pkgname{xkeyval} family for \meta{type} and \meta{newcmd} is the % macro for defining new \meta{type} styles. % \begin{macrocode} \newcommand\kvt@UseStyle[4]{% \ifcsundef{kvt@@#1style@#4} {\kvt@error{A #1 style '#4' is not defined} {Use \string#3\space to define a new #1 style.}} {\kvt@setcskeys{kvt@@#1style@#4}{#2}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@UseStyles} % The |\kvt@UseStyles|\marg{type}\marg{fam}\marg{newcmd}\marg{styles} % macro sets the \meta{type} keys based on the \meta{options} for all % styles in the comma-separated list \meta{styles}. % The \meta{fam} identifies the % \pkgname{xkeyval} family for \meta{type} and \meta{newcmd} is the % macro for defining new \meta{type} styles. % \begin{macrocode} \newcommand\kvt@UseStyles[4]{% % \end{macrocode} % We use |\kvt@xkv@disablepreset| to eliminate undesired effects that % would otherwise be caused by preset values for keys. % For an example of such side-effect, consider a style "|vis|" that is % defined as "|hidden=false|". Then, % |\Row[bg=red,style=vis]{...}| % causes a % |\setkeys[kvt]{Row}{hidden=false}| % to be processed inside the |\setkeys[kvt]{Row}{bg=red,style=vis}|, % after the |bg=red| is processed. % The former % |\setkeys| would then again employ the presets for |Row| (e.g., from a % |\kvtSet{Row/bg=blue}|) and undesirably overwrite the |bg=red|. % \begin{macrocode} \kvt@xkv@disablepreset[kvt]{#2}{% \forcsvlist{\kvt@UseStyle{#1}{#2}{#3}}{#4}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@xkv@disablepreset} % The |\kvt@xkv@disablepreset|\oarg{prefix}\marg{family}\marg{code} % disables head presets and tail presets for \meta{family} during the % expansion of \meta{code}. % \begin{macrocode} \newcommand\kvt@xkv@disablepreset[3][KV]{% \ifnumgreater{\XKV@depth}{1} {#3} {\kvt@xkv@savepreset{#1}{#2}{h}% \kvt@xkv@savepreset{#1}{#2}{t}% #3% \kvt@xkv@restorepreset{#1}{#2}{h}% \kvt@xkv@restorepreset{#1}{#2}{t}}} % \end{macrocode} % \end{macro} % \begin{macro}{\kvt@xkv@savepreset} % \begin{macro}{\kvt@xkv@restorepreset} % The auxiliary macro % |\kvt@xkv@savepreset|\marg{prefix}\marg{family}\marg{h/t} % saves and unsets the preset keys (head keys for \meta{h/t}=h and tail % keys otherwise) for \meta{family}. The macro % |\kvt@xkv@restorepreset|\marg{prefix}\marg{family}\marg{h/t} % restores the preset keys saved via |\kvt@xkv@savepreset|. % \begin{macrocode} \newcommand\kvt@xkv@savepreset[3]{% \csletcs{kvt@@saved@preset#3}{XKV@#1@#2@preset#3}% \csundef{XKV@#1@#2@preset#3}} \newcommand\kvt@xkv@restorepreset[3]{% \csletcs{XKV@#1@#2@preset#3}{kvt@@saved@preset#3}} % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Collecting Key-Value Table Content} % % \begin{macro}{\NewCollectedTable} % The |\NewCollectedTable|\marg{cname}\marg{tname} macro registers a new % table for recorded rows under name \meta{cname} for table type % \meta{tname}. The macro can only be used when % \meta{cname} is not already defined. It's function is not more than % memorizing \meta{tname} for \meta{cname}. % \changes{v2.0}{2019/04/10}{Added the macro} % \begin{macrocode} \newcommand\NewCollectedTable[2]{% \ifcsvoid{kvt@@tnameof@#1} {\csgdef{kvt@@tnameof@#1}{#2}} {\kvt@error{Name '#1' for a row collection is already defined} {Check for other \string\NewCollectedTable{#1}.}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\CollectRow} % The |\CollectRow|\oarg{options}\marg{cname}\marg{content} writes a % |\kvt@RecordedRow| entry to the aux file, protecting fragile parts of % \meta{content} through |\protected@write|. % \changes{v2.0}{2019/04/09}{Added the macro} % \begin{macrocode} \newcommand\CollectRow[3][]{% \ifcsvoid{kvt@@tnameof@#2} {\kvt@error{No row collection with name '#2' defined} {Use \string\NewCollectedTable in the preamble to define it.}} {% % \end{macrocode} % First check in a local group whether the passed \meta{content} and % \meta{options} are of a proper syntax. % \begin{macrocode} \begingroup \kvt@setkeys{#1}{Row}% \kvt@colsetcskeys{kvt@@tnameof@#2}{#3}% \endgroup % \end{macrocode} % Next, write to |\@auxout|. % \begin{macrocode} \kvt@protected@write\@auxout{\string\kvt@RecordedRow{#1}{#2}{% % \end{macrocode} % In the following, the columns' default values are explicitly added to % the row. This ensures that defaults are expanded (via the |\write|) at % the point at which a row is recorded rather than when the row is % displayed. This allows using |\thepage| as the default value for a % column with the intuitively expected outcome. % \begin{macrocode} \kvt@coldefaults{#2}% #3}}% }} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@protected@write} % The |\kvt@protected@write|\marg{file}\marg{content} macro writes % \meta{content} to \meta{file}. The write ensures that \meta{content} % is written in a particularly protected form that % \begin{enumerate}[noitemsep] % \item protects ordinarily |\protect|'ed parts via |\protected@write|; % \begin{macrocode} \newcommand\kvt@protected@write[2]{\protected@write{#1} % \end{macrocode} % \item protects table macros -- like |\thekvtRow| --, which are stored % in the \pkgname{etoolbox} list |\kvt@@writeprotected@cmds|, by % defining them to expand to their own name -- delaying the actual % expansion until when the file's contents is expanded; % \begin{macrocode} {\def\do##1{\def##1{\string##1}}% \dolistloop{\kvt@@writeprotected@cmds}% % \end{macrocode} % \item protects table counters like |kvtRow| by adapting the % counter-formatting macros to treat table counters differently from % other counters. % \begin{macrocode} \forlistloop{\kvt@writeprotect@fmt}{\kvt@@numberformatters}} {#2}} % \end{macrocode} % \end{enumerate} % \end{macro} % % \begin{macro}{\kvt@writeprotect@fmt} % The |\kvt@writeprotect@fmt|\marg{fmt-csname} macro takes the name of a % counter-formatting macro (e.g., the name "arabic" for the macro|\arabic|) % and redefines it such that counters declared via % |\kvtDeclareTableCounters| are not expanded while all other counters % are treated normally. % \begin{macrocode} \newcommand\kvt@writeprotect@fmt[1]{% % \end{macrocode} % First, save a copy of \meta{fmt-csname} and then redefine % \meta{fmt-csname}. % \begin{macrocode} \csletcs{kvt@@fmt@#1}{#1}% \csdef{#1}##1{% % \end{macrocode} % The |kvt@@c@##1| in the following condition is a csname that is % defined by |\kvtDeclareTableCounters| if |##1| (the counter to be % formatted) has been declared as a table counter. If the macro is % defined, then \meta{fmt-csname} expands to its name with its argument. % Otherwise, the saved copy of \meta{fmt-csname} is expanded, producing % the actual counter value. % \begin{macrocode} \ifcsdef{kvt@@c@##1} {\expandafter\string\csname#1\endcsname{##1}} {\csname kvt@@fmt@#1\endcsname{##1}}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvtDeclareTableMacros} % The |\kvtDeclareTableMacros|\marg{macro-list} macro declares all % the macros in \meta{macro-list} to be "table macros", i.e., % macros that should be expanded inside the |KeyValTable| environment % rather than in a |\CollectRow|. % The macro records the \meta{macro-list} by appending its elements to % |\kvt@@writeprotected@cmds|. The actual expansion control is performed % by |\kvt@protected@write|. % \begin{macrocode} \newcommand\kvtDeclareTableMacros[1]{% \forcsvlist{\listadd\kvt@@writeprotected@cmds}{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{\kvt@@writeprotected@cmds} % Initially empty \pkgname{etoolbox} list of table macros. % \begin{macrocode} \newcommand\kvt@@writeprotected@cmds{} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvtDeclareTableCounters} % The |\kvtDeclareTableCounters|\marg{counter-list} macro declares all % the counters in \meta{counter-list} to be "table counters", i.e., % counters that should be expanded inside the |KeyValTable| environment % rather than in a |\CollectRow|. % The macro only marks the counters by defining % \cs{kvt@@c@\meta{counter}}. The actual expansion control is performed % by |\kvt@writeprotect@fmt|. % \begin{macrocode} \newcommand\kvtDeclareTableCounters[1]{% \def\do##1{\cslet{kvt@@c@##1}\@ne}% \docsvlist{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvtDeclareCtrFormatters} % The |\kvtDeclareCtrFormatters|\marg{macro-list} macro declares all the % macros in \meta{macro-list} to be counter-formatting macros, i.e., % macros that take a \hologo{LaTeX} counter as their argument and format % the counter's value, e.g., arabic, alphabetic, or as a roman number. % The macro records the \meta{macro-list} by appending the csnames of % its elements to |\kvt@@numberformatters|. The actual expansion % control for the macros in \meta{macro-list} is performed by % |\kvt@writeprotect@fmt|. % \begin{macrocode} \newcommand\kvtDeclareCtrFormatters[1]{% \def\do##1{\listeadd\kvt@@numberformatters{% \expandafter\@gobble\string##1}}% \docsvlist{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{\kvt@@writeprotected@cmds} % Initially empty \pkgname{etoolbox} list of counter-formatting macros. % \begin{macrocode} \newcommand\kvt@@numberformatters{} % \end{macrocode} % \end{macro} % % The following registers the row counter macros as well as the row % counters themselves as macros/counters that shall only be expanded % inside the respective table. % \begin{macrocode} \kvtDeclareTableMacros{\thekvtRow,\thekvtTypeRow,\thekvtTotalRow} \kvtDeclareTableCounters{kvtRow,kvtTypeRow,kvtTotalRow} % \end{macrocode} % The following registers macros that format counter values. This % registering is necessary such that |\kvt@writeprotect@fmt| can protect % table counters from expansion. % \begin{macrocode} \kvtDeclareCtrFormatters{\arabic,\alph,\Alph,\roman,\Roman,\fnsymbol} % \end{macrocode} % % \begin{macro}{\kvt@coldefault} % \begin{macro}{\kvt@coldefaults} % \begin{macro}{\kvt@coldefaults@i} % The |\kvt@coldefault|\marg{tname}\marg{cname} macro expands to % "\meta{cname}|={|\meta{default}|},|", where \meta{default} is the % default value of column \meta{cname} in table type \meta{tname}. If % \meta{default} is empty, then the macro expands to the empty string. % The |\kvt@coldefaults@i|\marg{tname} macro expands to the % comma-separated list of the |\kvt@coldefault| for all \emph{displayed} % columns of table type \meta{tname}. % Finally, the |\kvt@coldefaults|\marg{cname} macro expands to % |\kvt@coldefaults| for the table type assigned to \meta{cname} via % |\NewCollectedTable|. % \begin{macrocode} \newcommand\kvt@coldefaults[1]{% \kvt@coldefaults@i{\csuse{kvt@@tnameof@#1}}} \newcommand\kvt@coldefaults@i[1]{% \forlistcsloop{\kvt@coldefault{#1}}{kvt@displaycols@#1}} \newcommand\kvt@coldefault[2]{\ifcsvoid{kvt@col@default@#1@#2}{}{% #2={\csuse{kvt@col@default@#1@#2}},}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\kvt@RecordedRow} % The |\kvt@RecordedRow|\marg{options}\marg{cname}\marg{content} % appends a |\Row| with \meta{options} and \meta{content} to a global % macro for \meta{cname}. % \begin{macrocode} \newcommand\kvt@RecordedRow[3]{% \csgappto{kvt@@rowsof@#2}{\Row[{#1}]{#3}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\ShowCollectedTable} % The |\ShowCollectedTable|\oarg{options}\marg{cname} % produces a |KeyValTable| table for the rows stored under the given % \meta{cname}, table options \meta{options}. % \changes{v2.0}{2019/04/09}{Added the macro} % \begin{macrocode} \newcommand\ShowCollectedTable[2][]{% \ifcsvoid{kvt@@tnameof@#2} {\kvt@error{No row collection with name '#2' defined} {Use \string\NewCollectedTable in the preamble to define it.}} {\ifcsvoid{kvt@@rowsof@#2} {\kvt@warn{No row data available for name '#2'. A LaTeX rerun might be needed^^M for the row data to be available}% \kvt@tableofcname{#2}{#1}{???\tabularnewline}}% {\kvt@tableofcname{#2}{#1}{\csuse{kvt@@rowsof@#2}}}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\kvt@tableof} % \begin{macro}{\kvt@tableofcname} % \begin{macro}{\kvt@tableofcname@i} % The |\kvt@tableof|\marg{tname}\marg{options}\marg{content} expands to % a |KeyValTable| environment for table type \meta{tname} with % \meta{options} and environment body \meta{content}. % The |\kvt@tableofcname|\marg{cname}\marg{options}\marg{content} % expands to a |\kvt@tableof| where \meta{tname} is the table type % assigned to \meta{cname}. % Finally, |\kvt@tableofcname@i| is an auxiliary macro for expansion % control. % \begin{macrocode} \newcommand\kvt@tableof[3]{% \begin{KeyValTable}[{#2}]{#1}% #3% \end{KeyValTable}} \newcommand\kvt@tableofcname[1]{\expandafter \kvt@tableofcname@i\expandafter{\csname kvt@@tnameof@#1\endcsname}} \newcommand\kvt@tableofcname@i[1]{\expandafter \kvt@tableof\expandafter{#1}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsubsection{Table Content from Files} % % \begin{macro}{\ShowKeyValTableFile} % The |\ShowKeyValTableFile|\oarg{options}\marg{tname}\marg{filename} % loads the content of the file with name \meta{filename} and places it % inside the body of a |KeyValTable| environment of type \meta{tname} with % the given \meta{options}. That is, the filename should contain the rows % of the table. % \changes{v2.0}{2019/03/25}{Added the macro} % \begin{macrocode} \newcommand\ShowKeyValTableFile[3][]{% \IfFileExists{#3} {\begin{KeyValTable}[{#1}]{#2}\@@input#3 \end{KeyValTable}}% {\kvt@error{No KeyValTable file '#3'} {Check whether the file really exists or whether there is a typo in the argument '#3'}}} % \end{macrocode} % \end{macro} % % \subsubsection{Legacy Variant} % % \begin{macro}{\ShowKeyValTable} % The |\ShowKeyValTable|\oarg{options}\marg{tname} macro shows a table % of type \meta{tname} with given \meta{options}. The rows must have % been collected using |\Row| in |KeyValTableContent| environments or % using |\AddKeyValRow|. % \begin{macrocode} \newcommand\ShowKeyValTable[2][]{% \begin{KeyValTable}[#1]{#2}% \csuse{kvt@rows@#2}% \end{KeyValTable}% \csdef{kvt@rows@#2}{}} % \end{macrocode} % \end{macro} % % \begin{macro}{\AddKeyValRow} % The |\AddKeyValRow|\marg{tname}\oarg{options}\marg{content} adds a row % with a given \meta{content} to the existing content for the next table % of type \meta{tname} that is displayed with |\ShowKeyValTable|. The % \meta{content} and \meta{options} parameters are the same as with % |\kvt@AddKeyValRow|. % The resulting row (|\kvt@@row|) is globally appended to % \cs{kvt@rows@\meta{tname}}. % \begin{macrocode} \newcommand\AddKeyValRow[1]{% \kvt@AddKeyValRow {\begingroup} {\csxappto{kvt@rows@#1}{\expandonce{\kvt@@row}}\endgroup} {#1}} % \end{macrocode} % \end{macro} % % \begin{environment}{KeyValTableContent} % The |KeyValTableContent|\marg{tname} environment acts as a container % in which rows can be specified without automatically being displayed. % In this environment, rows can be specified via the % |\Row|\marg{content} macro, which is supposedly shorter than using % |\AddKeyValRow|\meta{tname}\meta{content}. % \begin{macrocode} \newenvironment{KeyValTableContent}[1]{% \def\Row{\AddKeyValRow{#1}}}{}% % \end{macrocode} % \end{environment} % % % \subsection{Package Options} % % The following option allows specifying a version for (hopefully) % compatibility with the respective old version. % \changes{v2.0}{2019/05/11}{added package option "compat"} % \begin{macrocode} \define@cmdkey[kvt]{PackageOptions}[kvt@@pkg@]{compat}{} % \end{macrocode} % % Next, set default package options and process them. % \begin{macrocode} \ExecuteOptionsX[kvt]{% compat=2.0, } \ProcessOptionsX[kvt]\relax % \end{macrocode} % % % \subsection{Compatibility} % % \begin{macro}{\kvt@NewCompat} % The % |\kvt@IfVersion|\marg{relation}\marg{version}\marg{iftrue}\marg{iffalse} % macro expands to \meta{iftrue} if the requested package version is in % the given \meta{relation} ($<$, $<$, or $=$) to \meta{version}. % Otherwise, the macro expands to \meta{iffalse}. % Package versions are requested via the |compat| package option. If no % version is explicitly requested, the newest version is implicitly % assumed to be requested. % \meta{code} as % \begin{macrocode} \newcommand\kvt@IfVersion[2]{% \ifdimcomp{\kvt@@pkg@compat pt}{#1}{#2pt}} % \end{macrocode} % \end{macro} % % Before v2.0, \pkgname{tabu} was the default table environment. % \begin{macrocode} \kvt@IfVersion{<}{2.0}{% \metatblRequire{tabu,longtabu} \kvt@RegisterShape{onepage}{tabu}{tabu} \kvt@RegisterShape{multipage}{longtabu}{longtabu} }{% \metatblRequire{tabularx,longtable,xltabular} \kvt@RegisterShape{onepage}{tabular}{tabularx} \kvt@RegisterShape{multipage}{longtable}{xltabular} } % \end{macrocode} % % Before v2.0, the second optional argument of |\NewKeyValTable| % specified the header rows only. Only afterwards, that argument % received a key-value syntax. % \begin{macrocode} \kvt@IfVersion{<}{2.0}{% \renewcommand\kvt@parselayout[2]{\kvt@parseheadrows{#2}{#1}}% }{} % \end{macrocode} % %\iffalse % %\fi % \Finale \endinput