%D \module %D [ file=tabl-ltb, %D version=2002.10.31, %D title=\CONTEXT\ Table Macros, %D subtitle=Line Tables, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA / Hans Hagen \& Ton Otten}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. % testfile: tfmetrics.tex % todo: als nx>1, dan in geval van rek tussenruimte berekenen en optellen % bij breedte, dus: nx nog niet gebruiken in combinatie met rek ! ! ! ! ! % This module is experimental, undocumented, and currently only set up % eTeX. It provides a mechanism for typesetting very large tables, % spanning many pages horizontally and vertically, with repeated % header lines and (entry) columns, tab tracking, color, etc. In does % two passes over a table, which is why the table goes into a % buffer or file. As said, tables can be real huge. % \BH \BC .. \EC \BC .. \EC \EH % append % \BR \BC .. \EC \BC .. \EC \ER % % or % % \NC .. \NC .. \NC \NR (todo: optional last \NC) % alternative: % % (1) direct run, save content in macro, but only if needed % % todo % % (2) buffered table content % % \startbuffer % \startlinetablehead % \stoplinetablehead % \startlinetablebody % \stoplinetablebody % \stopbuffer % % \processlinetablebuffer[buffer] % % in buffer : head and body % % (3) unbuffered run, multipass % % - run with starting width zero / prev run % - clip on prev run % - flush real widths \writestatus{loading}{ConTeXt Table Macros / Line Tables} \unprotect \newconstant\linetablesplitstate \newconstant\linetableheadstate \newconstant\linetablemode \edef\??ler{\??le:r:} \edef\??lec{\??le:c:} \edef\??lew{\??le:w:} \edef\??leh{\??le:h:} \edef\??led{\??le:d:} \newif\iflinetablepreroll \newif\ifinlinetable \newcount\linetablecolumn \newcount\linetablesubcol \newdimen\linetablewidth \newdimen\linetableheight \newbox \linetablecell \let\noflinetablecolumns\!!zerocount \let\noflinetablerows \!!zerocount \let\noflinetablelines \!!zerocount \let\noflinetableparts \!!zerocount \let\linetablepart \!!plusone \let\linetablestep \!!plusone \let\linetableline \!!zerocount \let\linetablerow \!!zerocount \let\linetablerows \!!zerocount \initializetablebox \zerocount % holds repeater \newconstant\linetablehmode \newconstant\linetablepage \newconstant\linetablerepeat \unexpanded\def\setuplinetable {\dotripleempty\dosetuplinetable} \def\dosetuplinetable[#1][#2][#3]% {\ifthirdargument \getparameters[\??le:#1:#2][#3]% \else\ifsecondargument \getparameters[\??lec#1][#2]% \else \getparameters[\??le][#1]% \fi\fi} \setuplinetable [\c!n=\!!maxcard, \c!lines=\!!maxcard, \c!nx=\plusone, \c!nleft=0, \c!repeat=\v!yes, % when \c!nleft>0, repeat on both pages \c!before=, \c!after=, \c!inbetween=\page, \c!distance=\zeropoint, \c!stretch=\v!no, \c!align=\c!right, \c!leftoffset=.25ex, \c!rightoffset=\linetableparameter\c!leftoffset, \c!maxwidth=\zeropoint, \c!width=5em, \c!height=\v!fit, % \v!line = faster \c!background=, \c!backgroundcolor=] \def\linetableparameter#1% {\csname\??le#1\endcsname} \def\doifelselinetablecparameter#1% {\ifcsname\??lec\number\linetablecolumn#1\endcsname \expandafter\firstoftwoarguments \else \expandafter\secondoftwoarguments \fi} \def\linetablecparameter#1% {\csname \ifcsname\??lec\number\linetablecolumn#1\endcsname \??lec\number\linetablecolumn \else \??le \fi #1\endcsname} \def\linetablerparameter#1% faster, leaner and meaner {\csname \ifnum\linetablerow=\zerocount % geen ifcase \ifcsname\??ler\v!header#1\endcsname \??ler\v!header#1% \else\ifcsname\??ler0#1\endcsname \??ler0#1% \else \s!empty \fi\fi \else \ifcsname\??ler\number\linetablerow#1\endcsname \??ler\number\linetablerow#1% \else\ifcsname\??ler\v!oddeven\linetablerow#1\endcsname \??ler\v!oddeven\linetablerow#1% \else \s!empty \fi\fi \fi \endcsname} \def\setnoftableslines {\doifelse{\linetableparameter\c!lines}\v!fit {% whitespace already added by vertical strut \ifdim\pagegoal<\maxdimen \scratchdimen\pagegoal \advance\scratchdimen -\pagetotal \else \scratchdimen\textheight \fi \getrawnoflines\scratchdimen \xdef\noflinetablelines{\the\noflines} \iflinetablepreroll \else \ifnum\noflinetablelines<\plustwo \page \setnoftableslines \fi \fi } {\xdef\noflinetablelines{\linetableparameter\c!lines}}} \unexpanded\def\startlinetablecell {\dosingleempty\dostartlinetablecell} \def\dostartlinetablecell[#1]% {\global\setbox\linetablecell\hbox\bgroup \iffirstargument \getparameters[\??lec\number\linetablecolumn][#1]% \fi \xdef\linetablestep{\linetablecparameter\c!nx}% \ifcase\linetablestep\or \scratchdimen\linetablecparameter\c!width \scratchskip \linetablecparameter\c!distance \else \scratchdimen \zeropoint \scratchskip \zeropoint \scratchcounter\linetablecolumn \dorecurse\linetablestep {\advance\scratchdimen\linetablecparameter\c!width %\advance\scratchskip \linetablecparameter\c!distance \global\advance \linetablecolumn\plusone \advance\scratchskip \linetablecparameter\c!distance }% \global\linetablecolumn\scratchcounter \fi \linetablemode \iflinetablepreroll \ifdim\scratchdimen>\zeropoint \zerocount \else \plustwo \fi \else \zerocount \fi \ifcase\linetablemode \ifcase\linetablehmode % nothing \or % fit, keep it simple \or \linetablemode\plusone % line \else % some already calculated height \fi \fi \setbox\scratchbox\hbox \bgroup \dontcomplain \hskip\linetablecparameter\c!leftoffset\relax % 0 = width, unknown height % 1 = width, fixed height % 2 = no width, auto hsize \ifnum\linetablemode<\plustwo \advance\scratchdimen-\linetablecparameter\c!leftoffset \advance\scratchdimen-\linetablecparameter\c!rightoffset \fi \ifcase\linetablemode \dosetraggedcommand{\linetablecparameter\c!align}% \vtop \ifdim\linetableheight>\zeropoint to\linetableheight \fi \bgroup \hsize\scratchdimen \raggedcommand \else \setalignmentswitch{\linetablecparameter\c!align}% \hbox \ifcase\linetablemode \or to\scratchdimen \fi \bgroup \ifcase\alignmentswitch\hss\or\hss\fi \fi \dostartattributes{\??lec\number\linetablecolumn}\c!style\c!color\empty \begstrut \ignorespaces} % \unexpanded\def\stoplinetablecell % {\unskip \endstrut % \dostopattributes % \ifcase\linetablemode % \endgraf % \else % \ifcase\alignmentswitch\else\hss\fi % \fi % \egroup % \hskip\linetablecparameter\c!rightoffset % \egroup % \iflinetablepreroll % \box\scratchbox % \else % \doif{\linetablecparameter\c!background}\v!color % {\backgroundline[\linetablecparameter\c!backgroundcolor]}% % {\box\scratchbox}% % \fi % \egroup} \newconditional\linetableautoheight \settrue\linetableautoheight \unexpanded\def\stoplinetablecell {\unskip \endstrut \dostopattributes \ifcase\linetablemode \endgraf \else \ifcase\alignmentswitch\else\hss\fi \fi \egroup \hskip\linetablecparameter\c!rightoffset \egroup \iflinetablepreroll \box\scratchbox \else \doifelse{\linetablecparameter\c!background}\v!color {\ifconditional\linetableautoheight \hbox{\blackrule [ \c!color=\linetablecparameter\c!backgroundcolor, \c!height=\linetablerparameter{x\c!height}, \c!depth=\linetablerparameter{x\c!depth}, \c!width=\wd\scratchbox]% \hskip-\wd\scratchbox\box\scratchbox}% \else \backgroundline[\linetablecparameter\c!backgroundcolor]{\box\scratchbox}% \fi}% {\box\scratchbox}% \fi \egroup} % \unexpanded\def\stoplinetablecell % {\unskip \endstrut % \dostopattributes % \ifcase\linetablemode % \endgraf % \else % \ifcase\alignmentswitch\else\hss\fi % \fi % \egroup % \hskip\linetablecparameter\c!rightoffset % \egroup % \iflinetablepreroll % \box\scratchbox % \else % \doifelse{\linetablecparameter\c!background}\v!color % {\ifconditional\linetableautoheight % % \hbox{\blackrule % % [ \c!color=\linetablecparameter\c!backgroundcolor, % % \c!height=\linetablerparameter{x\c!height}, % % \c!depth=\linetablerparameter{x\c!depth}, % % \c!width=\wd\scratchbox]% % % \hskip-\wd\scratchbox\box\scratchbox}% % \dp\scratchbox\linetablerparameter{x\c!depth}% % \ht\scratchbox\linetablerparameter{x\c!height}% % \framed % [\c!offset=\v!overlay, % \c!frameoffset=.5\linewidth, % \c!leftframe=\v!off,\c!rightframe=\v!off, % \c!background=\v!color, % \c!backgroundcolor=\linetablecparameter\c!backgroundcolor% % ]{\box\scratchbox}% % \else % \backgroundline[\linetablecparameter\c!backgroundcolor]{\box\scratchbox}% % \fi}% % {\box\scratchbox}% % \fi % \egroup} \def\savelinetablepart {\global\setbox\tablebox\linetablepart \ifnum\linetablepart=\zerocount \box\scratchbox % just storing \else \vbox {\ifvoid\tablebox\linetablepart\else\unvbox\tablebox\linetablepart\fi \doif{\linetablerparameter\c!background}\v!color {\backgroundline[\linetablerparameter\c!backgroundcolor]}% {\box\scratchbox}% is also arg to \backgroundline \endgraf \linetablerparameter\c!after}% \fi} \def\flushlinetableparts {\doglobal\increment\linetableline \ifnum\linetableline<\noflinetablelines % keep collecting \else \iflinetablepreroll % forget about them \else \dorecurse\noflinetableparts {\let\linetablepart\recurselevel \dp\tablebox\linetablepart\strutdepth % noindent en endgraf needed else whitespace mess-up! \whitespace % here not after verticalstrut \ifdim\topskipgap=\zeropoint\else \verticalstrut\nobreak\kern-\struttotal\kern-\parskip\nobreak\nointerlineskip % fix topskip \fi \noindent\strut\hbox to \hsize{\box\tablebox\linetablepart\hss}\endgraf \ifnum\linetablepart<\noflinetableparts\relax \linetableparameter\c!inbetween \fi}% \ifnum\linetablerows<\noflinetablerows\relax \linetableparameter\c!inbetween \else % after, later \fi \linetableheadstate\plusthree \global\setbox\tablebox\zerocount\emptybox % here \fi % reset \linetablerow will be an option, currently % starts at zero after split \globallet\linetablerow\!!zerocount \globallet\linetableline\!!zerocount \global\linetablepage\zerocount \global\linetablewidth\zeropoint \setnoftableslines \fi} \unexpanded\def\startlinetablepart {\global\linetablesubcol\zerocount \setbox\scratchbox\hbox\bgroup \doconvertfont{\linetablerparameter\c!style}% \startcolor[\linetablerparameter\c!color]% \ignorespaces} \unexpanded\def\stoplinetablepart {\ifnum\linetablepart>\zerocount \unskip \unskip % remove last intercolumn skip (distance+fill) \fi \stopcolor \egroup \iflinetablepreroll \else \ifcase\linetablepart % we're collecting the repeater \else \scratchdimen\hsize \advance\scratchdimen-\wd\scratchbox\relax \ifdim\scratchdimen>\linetableparameter\c!stretch\else \setbox\scratchbox\hbox to \hsize{\unhbox\scratchbox}% \fi \fi \fi} \def\checklinetablepart {\global\advance\linetablewidth\wd\linetablecell \global\advance\linetablecolumn\linetablestep \global\advance\linetablesubcol\linetablestep \relax %\message{\the\linetablecolumn,\the\linetablesubcol}\wait % from now on the column counter is already incremented \ifcase\linetablesplitstate \iflinetablepreroll \else \box\linetablecell % the columncounter is one ahead ! % \hskip\linetablecparameter\c!afstand \hskip\scratchskip \fi %%% \donefalse \ifcase\linetablerepeat\else % van te voren berekenen \scratchcounter\linetablecolumn\advance\scratchcounter-\plustwo \ifnum\linetablerepeat=\scratchcounter \donetrue % collecting repeater \fi \fi %%%% \ifdone % collecting repeater \else \ifnum\linetablecolumn>\getvalue{\??le::\linetablepart}\relax \donetrue \fi \fi \ifdone \stoplinetablepart \iflinetablepreroll \else \savelinetablepart \fi \ifcase\linetablepage \or \global\linetablepage \plustwo \else \global\linetablepage \plusone \fi \doglobal\increment\linetablepart \global\linetablewidth\wd\tablebox\zerocount \startlinetablepart \fi \else \donefalse \!!doneafalse \ifcase\linetablerepeat\else % van te voren berekenen \scratchcounter\linetablecolumn \advance\scratchcounter-\plustwo \ifnum\linetablerepeat=\scratchcounter \donetrue % collecting repeater \fi \fi \ifdone \!!doneatrue % collecting repeater \else\ifdim\linetablewidth>\hsize \donetrue \else % \global\advance\linetablewidth\linetablecparameter\c!afstand\relax \global\advance\linetablewidth\scratchskip \ifdim\linetablewidth>\hsize % ? \donetrue \fi \fi\fi \ifdone \stoplinetablepart \savelinetablepart \ifcase\linetablepage \or \global\linetablepage \plustwo \else \global\linetablepage \plusone \fi \doglobal\increment\linetablepart \ifnum\linetablepart>\noflinetableparts \globallet\noflinetableparts\linetablepart \initializetablebox\linetablepart \fi \global\linetablewidth\wd\linetablecell \startlinetablepart \if!!doneb \else \ifcase\linetablerepeat \else % check for left/right page \ifcase\linetablepage\donetrue\or\donetrue\or\donefalse\fi\ifdone % insert repeater \global\advance\linetablewidth\wd\tablebox\zerocount \iflinetablepreroll\kern\wd\else\unhcopy\fi\tablebox\zerocount \fi \fi \fi \fi \iflinetablepreroll \else \box\linetablecell % the columncounter is one ahead ! % \hskip\linetablecparameter\c!afstand % \hskip\scratchskip \dorecurse\linetablestep{\strut\hfil}% \hskip\scratchskip \fi \fi} % \linetableparameter\c!var -> \@@levar (when no classes) \unexpanded\def\startlinetablerun % to do: quit when nested {\bgroup \inlinetabletrue % autowidth \doif{\linetableparameter\c!maxwidth}\v!fit {\setuplinetable[\c!maxwidth=\zeropoint]}% \processaction [\linetableparameter\c!stretch] [ \v!no=>{\setuplinetable[\c!stretch=\maxdimen]},% no stretch \v!yes=>{\setuplinetable[\c!stretch=\zeropoint]}]% max stretch \linetablerepeat\linetableparameter\c!nleft \linetablesplitstate % = \ifdim\linetableparameter\c!maxwidth>\zeropoint \zerocount \else \plusone \fi % optional prevdepth correction \iflinetablepreroll \globallet\noflinetablerows\!!zerocount \else \linetableparameter\c!before \fi \globallet\linetablerows\!!zerocount \globallet\noflinetablecolumns\!!zerocount \globallet\noflinetableparts\!!zerocount \!!counta\zerocount \def\docommand##1% {\doglobal\increment\noflinetableparts \advance\!!counta##1% \setxvalue{\??le::\noflinetableparts}{\the\!!counta}}% \processcommacommand[\linetableparameter\c!n]\docommand \initializetableboxes\noflinetableparts \ifcase\linetablerepeat \globallet\linetablepart\!!plusone \else \globallet\linetablepart\!!zerocount % repeater \fi \globallet\linetablestep\!!plusone \globallet\linetableline\!!zerocount \globallet\linetablerow \!!zerocount \global\linetablecolumn \zerocount \global\linetablesubcol \zerocount \global\linetablewidth \zeropoint \iflinetablepreroll \else \ifdim\pagetotal>\zeropoint \verticalstrut\kern-\struttotal \fi \fi \setnoftableslines \checklinetablepage \let\BR\linetableBR \let\ER\linetableER \let\BH\linetableBR \let\EH\linetableER \let\BC\linetableBC \let\EC\linetableEC \let\NC\linetableNC \let\NR\linetableNR \flushlinetablehead} \unexpanded\def\stoplinetablerun {\globallet\linetableline\!!maxcard \linetableheadstate\zerocount % blocked \flushlinetableparts \iflinetablepreroll \else \linetableparameter\c!after \fi \globallet\linetablepart \!!zerocount \globallet\noflinetableparts\!!zerocount \egroup} \def\checklinecolumndimension#1#2#3% {\expandafter\xdef\csname#1\number#3\endcsname {\expandafter\ifx\csname#1\number#3\endcsname\relax \the#2\linetablecell \else\ifdim\csname#1\number#3\endcsname<#2\linetablecell \the#2\linetablecell \else \csname#1\number#3\endcsname \fi\fi}} \def\checklinecolumnwidth {\checklinecolumndimension\??lew\wd\linetablecolumn} \def\checklinecolumnheight{\checklinecolumndimension\??leh\ht\linetablerow} \def\checklinecolumndepth {\checklinecolumndimension\??led\dp\linetablerow} \def\linetableBR {\dosingleempty\dolinetableBR} \def\dolinetableBR[#1]% #1 not yet implemented {\ifnum\linetableheadstate=1\else \doglobal\increment\linetablerow \doglobal\increment\linetablerows \fi \global\linetablecolumn\plusone \global\linetablesubcol\plusone % \linetableheight\linetablerparameter\c!height % % \ifx\linetableheight\empty % % nothing % \else\ifx\linetableheight\v!fit % % keep it simple % \else\ifx\linetableheight\v!line % \linetablemode\plusone % \else % \!!heighta\linetableheight % \advance\!!heighta-\strutdepth % \fi\fi\fi % \linetableheight\zeropoint \edef\!!stringa{\linetablerparameter\c!height}% \ifx\!!stringa\empty \linetablehmode\zerocount \else\ifx\!!stringa\v!fit \linetablehmode\plusone \else\ifx\!!stringa\v!line \linetablehmode\plustwo \else \linetableheight\!!stringa \advance\linetableheight-\strutdepth \fi\fi\fi % \startlinetablepart} \def\linetableBC {\startlinetablecell} \def\linetableEC {\stoplinetablecell \iflinetablepreroll \checklinecolumnwidth \checklinecolumnheight \checklinecolumndepth \fi \checklinetablepart} \def\linetableER {% \stoplinetablecell % no \box\linetablecell, i.e. dummy columnn, last \NC \NR \stoplinetablepart \savelinetablepart \advance\linetablecolumn \minusone \ifnum\linetablecolumn>\noflinetablecolumns \xdef\noflinetablecolumns{\number\linetablecolumn}% \fi \flushlinetableparts \global\linetablecolumn\zerocount \global\linetablewidth \zeropoint \ifcase\linetablerepeat \globallet\linetablepart\!!plusone \else \globallet\linetablepart\!!zerocount % repeater \fi \checklinetablepage \flushlinetablehead} \def\checklinetablepage {\global\linetablepage\zerocount \ifcase\linetablerepeat \else \ifcase\linetablepage \doif{\linetableparameter\c!repeat}\v!no {\global\linetablepage\doifoddpageelse\plusone\plustwo}% \fi \fi} \def\flushlinetablehead {\ifcase\linetableheadstate % 0 blocked \or % 1 doing head \or % 2 head done \or % 3 trigger flush \linetableheadstate\plusone \the\@@linetablehead\relax \linetableheadstate\plustwo \fi} \def\linetableNC % first time special treatment {\relax \ifcase\linetablecolumn \linetableBR \else \linetableEC \fi \linetableBC} % beware, this will result in BR BC EC BC NR \def\linetableNR {\stoplinetablecell % dummy \linetableER} \unexpanded\def\startlinetable {\startlinetablerun} \unexpanded\def\stoplinetable {\stoplinetablerun} \unexpanded\def\startlinetableanalysis {\bgroup \linetableprerolltrue \settrialtypesetting \startlinetablerun} \unexpanded\def\stoplinetableanalysis {\stoplinetablerun \egroup \globallet\noflinetablerows\linetablerows \dorecurse\noflinetablerows % global, from last run {\linetableparameter\c!n} {%\writestatus{linetable}{\recurselevel->\getvalue{\??lew\recurselevel}}% \setevalue{\??ler\recurselevel x\c!height}{\getvalue{\??leh\recurselevel}}% \setevalue{\??ler\recurselevel x\c!depth }{\getvalue{\??led\recurselevel}}% \letgvalue{\??leh\recurselevel}\!!zeropoint \letgvalue{\??led\recurselevel}\!!zeropoint} \dorecurse\noflinetablecolumns % global, from last run {\linetableparameter\c!n} {%\writestatus{linetable}{\recurselevel->\getvalue{\??lew\recurselevel}}% \setevalue{\??lec\recurselevel\c!width}{\getvalue{\??lew\recurselevel}}% \letgvalue{\??lew\recurselevel}\!!zeropoint}} % init next table % todo: store in box instead of macro \newtoks \@@linetablehead \long\unexpanded\def\startlinetablehead#1\stoplinetablehead {\ifinlinetable \@@linetablehead\emptytoks \fi \linetableheadstate\plusthree % full \@@linetablehead{#1}% \ifinlinetable \flushlinetablehead \fi} \def\linetableBH {\ifx\EC\relax % signal, grabbing lines \else \@@linetablehead\emptytoks \fi \pushmacro\BC \pushmacro\EC \def\BC##1\EC{\appendtoks##1\to\@@linetablehead}% \let\EC\relax} % signal \def\linetableEH {\popmacro\EC \popmacro\BC \@EA\startlinetablehead\the\@@linetablehead\stoplinetablehead} \let\startlinetablebody\donothing \let\stoplinetablebody \donothing \def\processlinetablebuffer {\dosingleempty\doprocesslinetablebuffer} \def\doprocesslinetablebuffer[#1]% {\bgroup \let\startlinetable\donothing \let\stoplinetable \donothing \startlinetableanalysis\getbuffer[#1]\stoplinetableanalysis \startlinetablerun \getbuffer[#1]\stoplinetablerun \egroup} \def\processlinetablefile#1% {\bgroup \let\startlinetable\donothing \let\stoplinetable \donothing \startlinetableanalysis\readfile{#1}\donothing\donothing\stoplinetableanalysis \startlinetablerun \readfile{#1}\donothing\donothing\stoplinetablerun \egroup} \protect \endinput \doifnotmode{demo}{\endinput} \setuplinetable[n=6,m={2,2,2},lines=25] % m ? \setuplinetable[c][1] [width=2cm,background=color,backgroundcolor=red] \setuplinetable[c][4] [width=3cm,background=color,backgroundcolor=yellow] \setuplinetable[c][6] [width=3cm,background=color,backgroundcolor=magenta] \setuplinetable[r][odd] [background=color,backgroundcolor=gray] \setuplinetable[r][even][background=color,backgroundcolor=green] \starttext \showframe \showstruts \setupcolors[state=start] \setuppagenumbering[alternative=doublesided]\page[left] \startlinetable \NC aaa\crlf aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR \dorecurse{100}{\NC aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR} \stoplinetable \startlinetable \NC[style=slanted,color=green,background=color,backgroundcolor=darkred,nx=2,uitlijnen=middle] xxx \NC yy \NC ddddd \NC eeee \NC ff \NC \NR \dorecurse{100}{\NC aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR} \stoplinetable % \startbuffer[lt] % \NC aaa\crlf aaa \NC bb \NC c \NC ddddd \NC ee \NC ff \NC \NR % \NC aaa\crlf aaa \NC b \NC cc \NC ddd \NC eeee \NC f \NC \NR % \stopbuffer % % \processlinetablebuffer[lt] \stoptext