diff options
author | Karl Berry <karl@freefriends.org> | 2010-10-08 22:55:52 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2010-10-08 22:55:52 +0000 |
commit | 0defb3a486d0ea4acc281201f2fe3dfb1fe58677 (patch) | |
tree | b131bfc838dce3c5248b8cafc79728ca2ea348ee /Master/texmf-dist/source/latex/cals/table.dtx | |
parent | 642d21e6f53417257b6ff173b9216d3862139fe1 (diff) |
new latex pkg cals (8oct01)
git-svn-id: svn://tug.org/texlive/trunk@20025 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/cals/table.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/cals/table.dtx | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/cals/table.dtx b/Master/texmf-dist/source/latex/cals/table.dtx new file mode 100644 index 00000000000..0e55a9378f1 --- /dev/null +++ b/Master/texmf-dist/source/latex/cals/table.dtx @@ -0,0 +1,387 @@ +% \subsection{Row dispatcher} + +% \begin{macro}{\cals@row@dispatch} +% Depending if the current row has a rowspan cell or not, +% the execution is different. +% \begin{macrocode} +\newcommand\cals@row@dispatch{% +\ifx b\cals@current@context + \cals@ifInRspan\iftrue + \cals@row@dispatch@span + \else + \cals@row@dispatch@nospan + \fi +\else + \cals@row@dispatch@nospan +\fi} +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\cals@row@dispatch@nospan} +% After a row is typeset in a box, this macro decides what to do next. +% Usually, it should just add decorations and output the row. +% But if a table break is required, it should put the current row +% to backup, typeset the footer, the break, the header and only then +% the row from the backup. Summary of main parameters: +% \begin{itemize} +% \item rowsep from the last row (|\cals@last@rs|) and the +% last context (|\cals@last@context|) +% \item current row (|\cals@current@row|), its decorations +% (|\cals@current@cs|, |\cals@current@rs@above|, +% |\cals@current@rs@below|) and context (|\cals@current@context|) +% \end{itemize} +% \begin{macrocode} +\newcommand\cals@row@dispatch@nospan{% +% \end{macrocode} +% The header and footer rows are always typeset without further +% considerations. +% \begin{macrocode} +\let\cals@last@context@bak=\cals@last@context +\ifx h\cals@current@context \else +\ifx f\cals@current@context \else +% \end{macrocode} +% In the body, if a break is required: do it. +% \begin{macrocode} +\cals@ifbreak\iftrue + \setbox\cals@backup@row=\box\cals@current@row + \setbox\cals@backup@cs=\box\cals@current@cs + \let\cals@backup@rs@above=\cals@current@rs@above + \let\cals@backup@rs@below=\cals@current@rs@below + \let\cals@backup@context=\cals@current@context + \cals@tfoot@tokens + \lastrule + \cals@issue@break + \cals@thead@tokens + \setbox\cals@current@row=\box\cals@backup@row + \setbox\cals@current@cs=\box\cals@backup@cs + \let\cals@current@rs@above=\cals@backup@rs@above + \let\cals@current@rs@below=\cals@backup@rs@below + \let\cals@current@context=\cals@backup@context +\fi\fi\fi +% \end{macrocode} +% Typeset the row. +% \begin{macrocode} +\cals@issue@row +% \end{macrocode} +% Consider a table such that thead+row1 do not fit to a page +% (see the unit test |regression/test_010_wrongbreak|). +% Without the next code, the following happens: +% thead and row1 are typeset, but the output procedure is not +% executed yet. Therefore, when row2 is ready, we detect that +% a table break is required and create it. Then the output procedure +% moves thead+row1 on the next page. The result: +% thead and row1 on one page, row2 and the rest on the next page +% instead of the whole table on one page. +% Solution: force a run of the output procedure after +% the first row of a table chunk. +% \begin{macrocode} +\ifx b\cals@last@context + \ifx h\cals@last@context@bak \vskip0pt \penalty10000 \fi + \ifx n\cals@last@context@bak \vskip0pt \penalty10000 \fi +\fi +} +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\cals@row@dispatch@span} +% The only specific thing to rowspanned rows is that we should not +% allow breaks between the rows in one group. We put these rows +% to one box, and process this big box as a big row. +% \begin{macrocode} +\newcommand\cals@row@dispatch@span{% +% \end{macrocode} +% Output the row to the backup box. If the row is the first +% row in the span, let its decorations will be the decorations +% for the future big row. Also, reset the values of leftskip +% and rightskip to avoid adding them twice, once in a individual +% row, and once to the common span box. +% \begin{macrocode} +\ifvoid\cals@backup@row + \setbox\cals@backup@row=\vbox{\box\cals@current@row}% + \setbox\cals@backup@cs=\box\cals@current@cs + \let\cals@backup@rs@above=\cals@current@rs@above + \let\cals@backup@context=\cals@last@context + \cals@backup@leftskip=\leftskip + \cals@backup@rightskip=\rightskip + \leftskip=0pt \rightskip=0pt \relax +\else + \setbox\cals@backup@row=\vbox{\unvbox\cals@backup@row + \cals@issue@row}% +\fi +\let\cals@last@rs@below=\cals@current@rs@below +\let\cals@last@context=\cals@current@context +% \end{macrocode} +% If this is the last row of the span, create the fake big row +% and use the normal dispatcher. +% +% \begin{macrocode} +\cals@ifLastRspanRow\iftrue + \setbox\cals@current@row=\box\cals@backup@row + \setbox\cals@current@cs=\box\cals@backup@cs + \let\cals@current@rs@above=\cals@backup@rs@above + \let\cals@last@context=\cals@backup@context + \leftskip=\cals@backup@leftskip + \rightskip=\cals@backup@rightskip + \cals@row@dispatch@nospan +\fi +} +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\cals@backup@row} +% \begin{macro}{\cals@backup@cs} +% Boxes and skips for backup. +% \begin{macrocode} +\newbox\cals@backup@row +\newbox\cals@backup@cs +\newskip\cals@backup@leftskip +\newskip\cals@backup@rightskip +% \end{macrocode} +% \end{macro} +% \end{macro} + +% To decide on table breaks and row separation decorations, +% we need to trace context. + +% \begin{macro}{\cals@current@context} +% The context of the current row. Possible values, +% set as a "|\let|" to a character: +% \begin{itemize} +% \item n: no context, should not happen when the value is required +% \item h: table header +% \item f: table footer +% \item b: table body +% \end{itemize} +% \end{macro} + +% \begin{macro}{\cals@last@context} +% The context of the previous row. Possible values, set as a +% "|\let|" to a character: +% \begin{itemize} +% \item n: there is no previous row (not only the start of a table, +% but also the start of a table chunk) +% \item h, f, b: table header, footer, body +% \item r: a last rule of the table (or its chunk) is just output. +% This status is used to allow multiple calls to |\lastrule|. +% Probably the use of |current| instead of |last| is more logical, +% but using |last| is more safe. Who knows if an user decides to use +% |\lastrule| somewhere in a middle of a table. +% \end{itemize} +% \end{macro} + +% \begin{macro}{\cals@ifbreak} +% Table breaks can be manual or automatic. The first is easy, +% the second is near to impossible if we take into account +% table headers and footer. The following heuristic seems good. +% +% Check if the current row plus the footer fits to the +% rest of the page. If not, a break is required. This approach +% is based on two assumptions: +% \begin{itemize} +% \item the height of the footer is always the same, and +% \item any body row is larger than the footer. +% \end{itemize} +% +% More precise and technical description: |\cals@ifbreak| decides +% if an automatic table break is required and leaves the +% macro |\cals@iftrue| (yes) or |\cals@iffalse| (no) in the input stream. +% If the user sets |\cals@tbreak@tokens| (using |\tbreak|), +% break is forced. Otherwise, no break is allowed: +% \begin{itemize} +% \item In the header +% \item In the footer +% \item Immediately after the header +% \item At the beginning of a chunk of a table. +% \end{itemize} +% Otherwise break is recommended when +% the sum of the height of the current row and of the footer part +% is greater as the rest height of the page. +% The implicit first parameter is used for if-fi balancing, +% see |\cals@iftrue|. +% \begin{macrocode} +\newcommand\cals@ifbreak[1]{} +\def\cals@ifbreak{% +\let\cals@tmp=\cals@iffalse +\let\cals@tmpII=\cals@iftrue +\ifx\relax\cals@tbreak@tokens + \ifx h\cals@current@context \else + \ifx f\cals@current@context \else + \ifx h\cals@last@context \else + \ifx n\cals@last@context \else + \dimen0=\pagetotal\relax + \advance\dimen0 by \ht\cals@current@row\relax + %\showthe\ht\cals@current@row\relax + \ifx \cals@tfoot@tokens\relax \else + %\show\cals@tfoot@height\relax + \advance\dimen0 by \cals@tfoot@height\relax + \fi + %\showthe\dimen0\relax + \ifdim \dimen0>\pagegoal\relax + \let\cals@tmp=\cals@tmpII + \fi + \fi\fi\fi\fi +\else \let\cals@tmp=\cals@tmpII % tbreak@tokens +\fi +\cals@tmp} +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\cals@issue@break} +% By default, force a page break, otherwise use user's tokens +% set by |\tbreak|. +% \begin{macrocode} +\newcommand\cals@issue@break{\ifx \relax\cals@tbreak@tokens \penalty-10000 % +\else \cals@tbreak@tokens \fi +\let\cals@tbreak@tokens=\relax +\let\cals@last@context=n} +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\cals@issue@rowsep@alone} +% Typesets the top (or bottom) frame of a table: +% combines |\cals@current@rs@above| and |\cals@framers@width| +% and outputs the row separator. +% \begin{macrocode} +\newcommand\cals@issue@rowsep@alone{% +\setbox0=\hbox{% + \hskip\leftskip + \cals@rs@sofar@reset + \cals@rs@joinOne\cals@framers@width\cals@current@rs@above + \cals@rs@sofar@end + \hskip\rightskip}% +\ht0=0pt \dp0=0pt \box0 } +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\cals@issue@rowsep} +% Combine row separations |\cals@last@rs@below| and |\cals@current@rs@above|, +% taking into considiration the width of the rule: +% \begin{itemize} +% \item n to h, f, b (the top frame): use |\cals@framers@width| +% and ignore |last@rs@below| because we don't have it +% \item h to h, b to b, f to f (the usual separator): use |\cals@rs@width| +% \item for all other combinations (header to body, body to footer), +% including impossible: use |\cals@bodyrs@width| +% \end{itemize} +% \begin{macrocode} +\newcommand\cals@issue@rowsep{% +\ifx n\cals@last@context \cals@issue@rowsep@alone \else + \ifx \cals@last@context\cals@current@context + \let\cals@tmpIII=\cals@rs@width \else + \let\cals@tmpIII=\cals@bodyrs@width \fi + \setbox0=\hbox{% + \hskip\leftskip + \cals@rs@sofar@reset + \cals@rs@joinTwo\cals@tmpIII\cals@last@rs@below\cals@current@rs@above + \cals@rs@sofar@end + \hskip\rightskip}% + \ht0=0pt \dp0=0pt \box0 % +\fi} +% \end{macrocode} +% \end{macro} + + +% \begin{macro}{\cals@last@row@height} +% For spanning support, we need to remember the height of the last row +% \begin{macrocode} +\newdimen\cals@last@row@height +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\cals@issue@row} +% Typesets the current row and its decorations, then updates +% the last context. Regards |\leftskip| and |\rightskip| +% by putting them inside the row. +% \begin{macrocode} +\newcommand\cals@issue@row{% +% \end{macrocode} +% Decorations: first the column separation, then the row separation. +% \begin{macrocode} +\nointerlineskip +\setbox0=\vtop{\hbox{\hskip\leftskip \box\cals@current@cs \hskip\rightskip}}% + \ht0=0pt \box0 +\nointerlineskip +\cals@issue@rowsep +\nointerlineskip +% \end{macrocode} +% Output the row, update the last context. +% \begin{macrocode} +\hbox{\hskip\leftskip \box\cals@current@row \hskip\rightskip}% +\let\cals@last@rs@below=\cals@current@rs@below +\let\cals@last@context=\cals@current@context} +% \end{macrocode} +% \end{macro} + +% \subsection{Table elements} + +% \begin{environment}{\calstable} +% Setup the parameters and let the row dispatcher to do all the work. +% \begin{macrocode} +\newenvironment{calstable}{% +\let\cals@thead@tokens=\relax +\let\cals@tfoot@tokens=\relax +\let\cals@tbreak@tokens=\relax +\cals@tfoot@height=0pt \relax +\let\cals@last@context=n% +\let\cals@current@context=b% +\parindent=0pt % +\cals@setpadding{Ag}\cals@setcellprevdepth{Al}% +\let\cals@borderL=\relax +\let\cals@borderR=\relax +\let\cals@borderT=\relax +\let\cals@borderB=\relax +}{% End of the table +\cals@tfoot@tokens\lastrule} +% \end{macrocode} +% \end{environment} + +% \begin{macro}{\lastrule} +% Typesets the last rule (bottom frame) of a table chunk. +% Repeatable calls are ignored. +% Useful in the macro |\tfoot|. +% \begin{macrocode} +\newcommand\lastrule{% +\ifx r\cals@last@context \relax \else + \let\cals@last@context=r% + \nointerlineskip + \let\cals@current@rs@above=\cals@last@rs@below\cals@issue@rowsep@alone% +\fi} +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\thead} +% Table: the header. Remember for later use, typeset right now. +% \begin{macrocode} +\newcommand\thead[1]{% +\def\cals@thead@tokens{\let\cals@current@context=h% +#1\let\cals@current@context=b}% +\cals@thead@tokens} +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\tfoot} +% Table: the footer. Remember for later use. Right now, typeset +% to a box to calculate an expected height for the table breaker +% |\cals@ifbreak|. +% \begin{macrocode} +\newcommand\tfoot[1]{% +\def\cals@tfoot@tokens{\let\cals@current@context=f#1}% +\setbox0=\vbox{\cals@tfoot@tokens}% +\cals@tfoot@height=\ht0 \relax} +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\cals@tfoot@height} +% The height of the footer. +% \begin{macrocode} +\newdimen\cals@tfoot@height +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\tbreak} +% Table: force a table break. Argument should contain something +% like |\penalty-10000 |. +% \begin{macrocode} +\newcommand\tbreak[1]{\def\cals@tbreak@tokens{#1}} +% \end{macrocode} +% \end{macro} |