tabl-ltb.mkiv / last modification: 2019-12-06 19:53
%D \module
%D   [       file=tabl-ltb,
%D        version=2002.10.31, % updated 2016.01.08
%D          title=\CONTEXT\ Table Macros,
%D       subtitle=Line Tables,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

%D This module was made for some special project where we needed to typeset tables
%D spanning spanning many pages horizontally and vertically, with repeated header
%D lines and (entry) columns, tab tracking, color, etc. We do two passes over a
%D table, which is why the table can go into a buffer or file. As said, tables can
%D be real huge but performance is still quite okay (there is room for some speed
%D up). The code has been adapted to \MKIV\ but the functionality is the same as in
%D \MKII.

% \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

\installcorenamespace{linetable}
\installcorenamespace{linetablepart}
\installcorenamespace{linetablewidth}
\installcorenamespace{linetableheight}
\installcorenamespace{linetabledepth}

\newconditional \c_tabl_lines_preroll
\newconditional \c_tabl_lines_in_table

\newdimen       \d_tabl_lines_width
\newdimen       \d_tabl_lines_height
%newdimen       \d_tabl_lines_depth

\newbox         \b_tabl_lines_cell

\newcount       \c_tabl_lines_n_of_columns
\newcount       \c_tabl_lines_n_of_rows
\newcount       \c_tabl_lines_n_of_lines
\newcount       \c_tabl_lines_n_of_parts
\newcount       \c_tabl_lines_part           \c_tabl_lines_part\plusone
\newcount       \c_tabl_lines_step           \c_tabl_lines_step\plusone
\newcount       \c_tabl_lines_line
\newcount       \c_tabl_lines_row
\newcount       \c_tabl_lines_rows
\newcount       \c_tabl_lines_column
\newcount       \c_tabl_lines_subcol

\newconstant    \c_tabl_lines_hmode
\newconstant    \c_tabl_lines_page
\newconstant    \c_tabl_lines_repeat
\newconstant    \c_tabl_lines_split_state
\newconstant    \c_tabl_lines_head_state
\newconstant    \c_tabl_lines_mode

\newtoks        \t_tabl_lines_head

\newconditional \linetableautoheight  \settrue\linetableautoheight

\initializetablebox\zerocount % holds repeater

\unexpanded\def\setuplinetable
  {\dotripleempty\tabl_lines_setup}

\def\tabl_lines_setup[#1][#2][#3]%
  {\ifthirdargument
     \getparameters[\??linetable#1:#2][#3]%
   \else\ifsecondargument
     \getparameters[\??linetable#1:][#2]%
   \else
     \getparameters[\??linetable][#1]%
   \fi\fi}

\setuplinetable
  [\c!n=\maxcard,
   \c!lines=\maxcard,
   \c!nx=\plusone,
   \c!nleft=\zerocount,
   \c!repeat=\v!yes, % when 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=.25\exheight,
   \c!rightoffset=\linetableparameter\c!leftoffset,
   \c!maxwidth=\zeropoint,
   \c!width=5\emwidth,
   \c!height=\v!fit, % \v!line = faster
   \c!background=,
   \c!backgroundcolor=,
   \c!rulethickness=\linewidth]

\def\linetableparameter#1%
  {\begincsname\??linetable#1\endcsname}

\unexpanded\def\doifelselinetablecparameter#1%
  {\ifcsname\??linetable c:\number\c_tabl_lines_column#1\endcsname
     \expandafter\firstoftwoarguments
   \else\ifcsname\??linetable c:#1\endcsname
     \doubleexpandafter\firstoftwoarguments
   \else
     \doubleexpandafter\secondoftwoarguments
   \fi\fi}

\let\doiflinetablecparameterelse\doifelselinetablecparameter

\def\linetablecparameter#1%
  {\begincsname
     \??linetable
     \ifcsname\??linetable c:\number\c_tabl_lines_column#1\endcsname
       c:\number\c_tabl_lines_column
     \else\ifcsname\??linetable c:#1\endcsname
       c:%
     \fi\fi
     #1%
   \endcsname}

\def\linetablerparameter#1% faster, leaner and meaner
  {\begincsname
     \??linetable
     \ifnum\c_tabl_lines_row=\zerocount % geen ifcase
       \ifcsname\??linetable r:\v!header#1\endcsname
         r:\v!header
       \else\ifcsname\??linetable r:0#1\endcsname
         r:0%
       \fi\fi
     \else
       \ifcsname\??linetable r:\number\c_tabl_lines_row#1\endcsname
         r:\number\c_tabl_lines_row
       \else\ifcsname\??linetable r:\v!oddeven\c_tabl_lines_row#1\endcsname
         r:\v!oddeven\c_tabl_lines_row
       \fi\fi
     \fi
     #1%
   \endcsname}

\unexpanded\def\tabl_lines_set
  {\edef\p_lines{\linetableparameter\c!lines}%
   \ifx\p_lines\v!fit
     \tabl_lines_set_indeed
   \else
     \global\c_tabl_lines_n_of_lines\p_lines
   \fi}

\unexpanded\def\tabl_lines_set_indeed
  {% whitespace already added by vertical strut
  %\triggerpagebuilder
   \scratchdimen
     \ifdim\pagegoal<\maxdimen
       \dimexpr\pagegoal-\pagetotal\relax
     \else
       \textheight
     \fi
   \getrawnoflines\scratchdimen
   \global\c_tabl_lines_n_of_lines\noflines
   \ifconditional\c_tabl_lines_preroll \else \ifnum\c_tabl_lines_n_of_lines<\plustwo
     \page
     \tabl_lines_set
   \fi \fi}

\unexpanded\def\startlinetablecell
  {\dosingleempty\tabl_lines_start_cell}

\def\tabl_lines_step_cell
  {\advance\scratchdimen\linetablecparameter\c!width
   \global\advance      \c_tabl_lines_column\plusone
   \advance\scratchskip \linetablecparameter\c!distance}

\def\tabl_lines_start_cell[#1]%
  {\global\setbox\b_tabl_lines_cell\hbox\bgroup
   \iffirstargument
     \getparameters[\??linetable c:\number\c_tabl_lines_column][#1]%
   \fi
   \global\c_tabl_lines_step\linetablecparameter\c!nx\relax
   \ifcase\c_tabl_lines_step\or
     \scratchdimen\linetablecparameter\c!width
     \scratchskip \linetablecparameter\c!distance
   \else
     \scratchdimen  \zeropoint
     \scratchskip   \zeropoint
     \scratchcounter\c_tabl_lines_column
     \dorecurse\c_tabl_lines_step\tabl_lines_step_cell
     \global\c_tabl_lines_column\scratchcounter
   \fi
   \c_tabl_lines_mode
     \ifconditional\c_tabl_lines_preroll
       \ifdim\scratchdimen>\zeropoint \zerocount \else \plustwo \fi
     \else
       \zerocount
     \fi
   \ifcase\c_tabl_lines_mode
     \ifcase\c_tabl_lines_hmode
       % nothing
     \or
       % fit, keep it simple
     \or
       \c_tabl_lines_mode\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\c_tabl_lines_mode<\plustwo
       \advance\scratchdimen-\linetablecparameter\c!leftoffset
       \advance\scratchdimen-\linetablecparameter\c!rightoffset
     \fi
     \ifcase\c_tabl_lines_mode
       \dosetraggedcommand{\linetablecparameter\c!align}%
       \vtop \ifdim\d_tabl_lines_height>\zeropoint to\d_tabl_lines_height \fi \bgroup
         \hsize\scratchdimen
         \raggedcommand
     \else
       \setalignmentswitch{\linetablecparameter\c!align}%
       \hbox \ifcase\c_tabl_lines_mode \or to\scratchdimen \fi \bgroup
         \ifcase\alignmentswitch\hss\or\hss\fi
     \fi
     \dousestyleparameter{\linetablecparameter\c!style}%
     \dousecolorparameter{\linetablecparameter\c!color}%
     \begstrut \ignorespaces}

\unexpanded\def\stoplinetablecell
  {\unskip \endstrut
   \ifcase\c_tabl_lines_mode
     \endgraf
   \else
     \ifcase\alignmentswitch\else\hss\fi
   \fi
   \egroup
   \hskip\linetablecparameter\c!rightoffset
   \egroup
   \ifconditional\c_tabl_lines_preroll
     \box\scratchbox
   \else
     \tabl_lines_wrap_up
   \fi
   \egroup}

\def\tabl_lines_wrap_up
  {\edef\p_background{\linetablecparameter\c!background}%
   \ifx\p_background\v!color
     \ifconditional\linetableautoheight
       \tabl_lines_wrap_up_auto
     \else
       \tabl_lines_wrap_up_line
      \fi
   \else
     \box\scratchbox
   \fi}

% \startuseMPgraphic{one}
%     path p, q ;
%     numeric r ;
%     r := RuleThickness ;
%     p := unitsquare xysized(RuleWidth,RuleHeight+RuleDepth) ;
%     q := p topenlarged -r bottomenlarged -r ;
%     draw q ;
%     setbounds currentpicture to p;
% \stopuseMPgraphic
%
% \setuplinetable[r][odd] [type=mp,mp=one,backgroundcolor=gray,rulethickness=1pt]
% \setuplinetable[r][even][type=mp,mp=one,backgroundcolor=green,rulethickness=1pt]
%
% \startlinetable
%     \dorecurse{10}{\NC aaa \NC bb \NC c \NC ddddd \NC eeee \NC ff \NC \NR}
% \stoplinetable

\def\tabl_lines_wrap_up_auto
  {\edef\p_height{\linetablerparameter{x\c!height}}%
   \edef\p_depth {\linetablerparameter{x\c!depth }}%
   \hpack
     {\blackrule
        [ \c!color=\linetablecparameter\c!backgroundcolor,
           \c!type=\linetablecparameter\c!type,
             \c!mp=\linetablecparameter\c!mp,
  \c!rulethickness=\linetablecparameter\c!rulethickness,
         \c!height=\ifx\p_height\empty\ht\scratchbox\else\p_height\fi,
          \c!depth=\ifx\p_depth \empty\dp\scratchbox\else\p_depth \fi,
          \c!width=\wd\scratchbox]%
      \hskip-\wd\scratchbox\box\scratchbox}}

\def\tabl_lines_wrap_up_auto_r
  {\hpack
     {\blackrule
        [ \c!color=\linetablerparameter\c!backgroundcolor,
           \c!type=\linetablerparameter\c!type,
             \c!mp=\linetablerparameter\c!mp,
  \c!rulethickness=\linetablerparameter\c!rulethickness,
         \c!height=\ht\scratchbox,
          \c!depth=\dp\scratchbox,
          \c!width=\wd\scratchbox]%
      \hskip-\wd\scratchbox\box\scratchbox}}

\def\tabl_lines_wrap_up_line
  {\backgroundline[\linetablecparameter\c!backgroundcolor]{\box\scratchbox}}

\def\tabl_lines_save_part
  {\global\setbox\tablebox\c_tabl_lines_part
   \ifcase\c_tabl_lines_part\relax
     \box\scratchbox % just storing
   \else
     \vbox
       {\ifvoid\tablebox\c_tabl_lines_part\else\unvbox\tablebox\c_tabl_lines_part\fi
        \edef\p_background{\linetablerparameter\c!background}%
        \ifx\p_background\v!color
          \backgroundline[\linetablerparameter\c!backgroundcolor]{\box\scratchbox}%
        \else
          \edef\p_type{\linetablerparameter\c!type}%
          \ifx\p_type\empty
            \box\scratchbox
          \else
            \tabl_lines_wrap_up_auto_r
          \fi
        \fi
        \endgraf
        \linetablerparameter\c!after}%
   \fi}

\def\tabl_lines_flush_parts
  {\global\advance\c_tabl_lines_line\plusone
   \ifnum\c_tabl_lines_line<\c_tabl_lines_n_of_lines
     % keep collecting
   \else
     \ifconditional\c_tabl_lines_preroll
       % forget about them
     \else
       \dorecurse\c_tabl_lines_n_of_parts
         {\c_tabl_lines_part\recurselevel
          \dp\tablebox\c_tabl_lines_part\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
          \hpack to \hsize{\box\tablebox\c_tabl_lines_part\hss}%
          \endgraf
          \ifnum\c_tabl_lines_part<\c_tabl_lines_n_of_parts\relax
            \linetableparameter\c!inbetween
          \fi}%
       \ifnum\c_tabl_lines_rows<\c_tabl_lines_n_of_rows
         \linetableparameter\c!inbetween
       \else
         % after, later
       \fi
       \c_tabl_lines_head_state\plusthree
       \global\setbox\tablebox\zerocount\emptybox % here
     \fi
     % reset \c_tabl_lines_row will be an option, currently
     % starts at zero after split
     \global\c_tabl_lines_row\zerocount
     \global\c_tabl_lines_line\zerocount
     \global\c_tabl_lines_page\zerocount
     \global\d_tabl_lines_width\zeropoint
     \tabl_lines_set
   \fi}

\def\tabl_lines_start_part
  {\global\c_tabl_lines_subcol\zerocount
   \setbox\scratchbox\hbox\bgroup
   \dousestyleparameter{\linetablerparameter\c!style}%
   \dousecolorparameter{\linetablerparameter\c!color}%
   \ignorespaces}

\def\tabl_lines_stop_part
  {\ifnum\c_tabl_lines_part>\zerocount
     \unskip \unskip % remove last intercolumn skip (distance+fill)
   \fi
   \egroup
   \ifconditional\c_tabl_lines_preroll \else
     \ifcase\c_tabl_lines_part
       % we're collecting the repeater
     \else
       \ifdim\dimexpr\hsize-\wd\scratchbox\relax>\linetableparameter\c!stretch\else
         \setbox\scratchbox\hpack to \hsize{\unhbox\scratchbox}%
       \fi
     \fi
   \fi}

\def\tabl_lines_check_part
  {\global\advance\d_tabl_lines_width\wd\b_tabl_lines_cell
   \global\advance\c_tabl_lines_column\c_tabl_lines_step
   \global\advance\c_tabl_lines_subcol\c_tabl_lines_step
   \relax
   %\message{\the\c_tabl_lines_column,\the\c_tabl_lines_subcol}\wait
   % from now on the column counter is already incremented
   \ifcase\c_tabl_lines_split_state
     \ifconditional\c_tabl_lines_preroll \else
       \box\b_tabl_lines_cell
       % the columncounter is one ahead !
       \hskip\scratchskip
     \fi
     %%%
     \donefalse
     \ifcase\c_tabl_lines_repeat\else
       % calculate ahead
       \ifnum\c_tabl_lines_repeat=\numexpr\c_tabl_lines_column-\plustwo\relax
         \donetrue % collecting repeater
       \fi
     \fi
     %%%%
     \ifdone
       % collecting repeater
     \else
       \ifnum\c_tabl_lines_column>\csname\??linetablepart\number\c_tabl_lines_part\endcsname\relax
         \donetrue
       \fi
     \fi
     \ifdone
       \tabl_lines_stop_part
       \ifconditional\c_tabl_lines_preroll \else
         \tabl_lines_save_part
       \fi
       \ifcase\c_tabl_lines_page \or
         \global\c_tabl_lines_page \plustwo
       \else
         \global\c_tabl_lines_page \plusone
       \fi
       \global\advance\c_tabl_lines_part\plusone
       \global\d_tabl_lines_width\wd\tablebox\zerocount
       \tabl_lines_start_part
     \fi
   \else
     \donefalse
     \!!doneafalse
     \ifcase\c_tabl_lines_repeat\else
       % calculate ahead
       \ifnum\c_tabl_lines_repeat=\numexpr\c_tabl_lines_column-\plustwo\relax
         \donetrue % collecting repeater
       \fi
     \fi
     \ifdone
       \!!doneatrue
       % collecting repeater
     \else\ifdim\d_tabl_lines_width>\hsize
       \donetrue
     \else
       \global\advance\d_tabl_lines_width\scratchskip
       \ifdim\d_tabl_lines_width>\hsize % ?
         \donetrue
       \fi
     \fi\fi
     \ifdone
       \tabl_lines_stop_part
       \tabl_lines_save_part
       \ifcase\c_tabl_lines_page \or
         \global\c_tabl_lines_page \plustwo
       \else
         \global\c_tabl_lines_page \plusone
       \fi
       \global\advance\c_tabl_lines_part\plusone
       \ifnum\c_tabl_lines_part>\c_tabl_lines_n_of_parts
         \global\c_tabl_lines_n_of_parts\c_tabl_lines_part
         \initializetablebox\c_tabl_lines_part
       \fi
       \global\d_tabl_lines_width\wd\b_tabl_lines_cell
       \tabl_lines_start_part
       \if!!doneb \else \ifcase\c_tabl_lines_repeat \else
         % check for left/right page
         \ifcase\c_tabl_lines_page\donetrue\or\donetrue\or\donefalse\fi\ifdone
           % insert repeater
           \global\advance\d_tabl_lines_width\wd\tablebox\zerocount
           \ifconditional\c_tabl_lines_preroll\kern\wd\else\unhcopy\fi\tablebox\zerocount
         \fi
       \fi \fi
     \fi
     \ifconditional\c_tabl_lines_preroll \else
       \box\b_tabl_lines_cell
       % the columncounter is one ahead !
%        \dorecurse\c_tabl_lines_step{\strut\hfil}%
\strut
       \hskip\scratchskip
     \fi
   \fi}

\unexpanded\def\startlinetablerun % to do: quit when nested
  {\bgroup
   \settrue\c_tabl_lines_in_table
   % 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
   \c_tabl_lines_repeat\linetableparameter\c!nleft
   \c_tabl_lines_split_state % =
     \ifdim\linetableparameter\c!maxwidth>\zeropoint
       \zerocount \else \plusone
     \fi
   % optional prevdepth correction
   \ifconditional\c_tabl_lines_preroll
     \global\c_tabl_lines_n_of_rows\zerocount
   \else
     \linetableparameter\c!before
   \fi
   \global\c_tabl_lines_rows\zerocount
   \global\c_tabl_lines_n_of_columns\zerocount
   \global\c_tabl_lines_n_of_parts\zerocount
   \scratchcounter\zerocount
   \def\docommand##1%
     {\global\advance\c_tabl_lines_n_of_parts\plusone
      \advance\scratchcounter##1%
      \setxvalue{\??linetablepart\number\c_tabl_lines_n_of_parts}{\the\scratchcounter}}%
   \processcommacommand[\linetableparameter\c!n]\docommand
   \initializetableboxes\c_tabl_lines_n_of_parts
   \global\c_tabl_lines_part\ifcase\c_tabl_lines_repeat\plusone\else\zerocount\fi % repeater
   \global\c_tabl_lines_step\plusone
   \global\c_tabl_lines_line\zerocount
   \global\c_tabl_lines_row \zerocount
   \global\c_tabl_lines_column\zerocount
   \global\c_tabl_lines_subcol\zerocount
   \global\d_tabl_lines_width\zeropoint
   \ifconditional\c_tabl_lines_preroll \else \ifdim\pagetotal>\zeropoint
     \verticalstrut\kern-\struttotal
   \fi \fi
   \tabl_lines_set
   \tabl_lines_check_page
   \let\BR\tabl_lines_BR
   \let\ER\tabl_lines_ER
   \let\BH\tabl_lines_BR
   \let\EH\tabl_lines_ER
   \let\BC\tabl_lines_BC
   \let\EC\tabl_lines_EC
   \let\NC\tabl_lines_NC
   \let\NR\tabl_lines_NR
   \tabl_lines_flush_head}

\unexpanded\def\stoplinetablerun
  {\global\c_tabl_lines_line\maxcard
   \c_tabl_lines_head_state\zerocount % blocked
   \tabl_lines_flush_parts
   \ifconditional\c_tabl_lines_preroll \else
     \linetableparameter\c!after
   \fi
   \global\c_tabl_lines_part\zerocount
   \global\c_tabl_lines_n_of_parts\zerocount
   \egroup}

\def\checklinecolumndimension#1#2#3%
  {\expandafter\xdef\csname#1\number#3\endcsname
     {\expandafter\ifx\csname#1\number#3\endcsname\relax
        \the#2\b_tabl_lines_cell
      \else\ifdim\csname#1\number#3\endcsname<#2\b_tabl_lines_cell
        \the#2\b_tabl_lines_cell
      \else
        \csname#1\number#3\endcsname
      \fi\fi}}

\def\tabl_lines_check_width {\checklinecolumndimension\??linetablewidth \wd\c_tabl_lines_column}
\def\tabl_lines_check_height{\checklinecolumndimension\??linetableheight\ht\c_tabl_lines_row}
\def\tabl_lines_check_depth {\checklinecolumndimension\??linetabledepth \dp\c_tabl_lines_row}

\unexpanded\def\tabl_lines_BR
  {\dosingleempty\tabl_lines_BR_indeed}

\def\tabl_lines_BR_indeed[#1]% #1 not yet implemented
  {\ifnum\c_tabl_lines_head_state=1\else
     \global\advance\c_tabl_lines_row\plusone
     \global\advance\c_tabl_lines_rows\plusone
   \fi
   \global\c_tabl_lines_column\plusone
   \global\c_tabl_lines_subcol\plusone
   \d_tabl_lines_height\zeropoint
   \edef\p_height{\linetablerparameter\c!height}%
   \ifx\p_height\empty
     \c_tabl_lines_hmode \zerocount
   \else\ifx\p_height\v!fit
     \c_tabl_lines_hmode \plusone
   \else\ifx\p_height\v!line
     \c_tabl_lines_hmode \plustwo
   \else
     \d_tabl_lines_height\dimexpr\p_height-\strutdepth\relax
   \fi\fi\fi
   \tabl_lines_start_part}

\unexpanded\def\tabl_lines_BC
  {\startlinetablecell}

\unexpanded\def\tabl_lines_EC
  {\stoplinetablecell
   \ifconditional\c_tabl_lines_preroll
     \tabl_lines_check_width
     \tabl_lines_check_height
     \tabl_lines_check_depth
   \fi
   \tabl_lines_check_part}

\unexpanded\def\tabl_lines_ER
  {% \stoplinetablecell
   % no \box\b_tabl_lines_cell, i.e. dummy columnn, last \NC \NR
   \tabl_lines_stop_part
   \tabl_lines_save_part
   \advance\c_tabl_lines_column \minusone
   \ifnum\c_tabl_lines_column>\c_tabl_lines_n_of_columns
     \global\c_tabl_lines_n_of_columns\c_tabl_lines_column
   \fi
   \tabl_lines_flush_parts
   \global\c_tabl_lines_column\zerocount
   \global\d_tabl_lines_width \zeropoint
   \ifcase\c_tabl_lines_repeat
     \global\c_tabl_lines_part\plusone
   \else
     \global\c_tabl_lines_part\zerocount % repeater
   \fi
   \tabl_lines_check_page
   \tabl_lines_flush_head}

\def\tabl_lines_check_page
  {\global\c_tabl_lines_page\zerocount
   \ifcase\c_tabl_lines_repeat \else \ifcase\c_tabl_lines_page
     \doif{\linetableparameter\c!repeat}\v!no
       {\global\c_tabl_lines_page\doifelseoddpage\plusone\plustwo}%
   \fi \fi}

\def\tabl_lines_flush_head
  {\ifcase\c_tabl_lines_head_state
     % 0 blocked
   \or
     % 1 doing head
   \or
     % 2 head done
   \or
     % 3 trigger flush
     \c_tabl_lines_head_state\plusone
     \the\t_tabl_lines_head\relax
     \c_tabl_lines_head_state\plustwo
   \fi}

\unexpanded\def\tabl_lines_NC % first time special treatment
  {\relax
   \ifcase\c_tabl_lines_column
     \tabl_lines_BR
   \else
     \tabl_lines_EC
   \fi
   \tabl_lines_BC} % beware, this will result in BR BC EC BC NR

\unexpanded\def\tabl_lines_NR
  {\stoplinetablecell % dummy
   \tabl_lines_ER}

\unexpanded\def\startlinetable
  {\startlinetablerun}

\unexpanded\def\stoplinetable
  {\stoplinetablerun}

\unexpanded\def\startlinetableanalysis
  {\bgroup
   \settrue\c_tabl_lines_preroll
   \settrialtypesetting
   \startlinetablerun}

% \unexpanded\def\stoplinetableanalysis
%   {\stoplinetablerun
%    \egroup
%    \global\c_tabl_lines_n_of_rows\c_tabl_lines_rows
%    \dorecurse\c_tabl_lines_n_of_rows % global, from last run {\linetableparameter\c!n}
%      {\setevalue{\??linetable r:\recurselevel x\c!height}{\getvalue{\??linetableheight\recurselevel}}%
%       \setevalue{\??linetable r:\recurselevel x\c!depth }{\getvalue{\??linetabledepth \recurselevel}}%
%       \letgvalue{\??linetableheight\recurselevel}\!!zeropoint
%       \letgvalue{\??linetabledepth \recurselevel}\!!zeropoint}
%    \dorecurse\c_tabl_lines_n_of_columns % global, from last run {\linetableparameter\c!n}
%      {\setevalue{\??linetable c:\recurselevel\c!width}{\getvalue{\??linetablewidth\recurselevel}}%
%       \letgvalue{\??linetablewidth\recurselevel}\!!zeropoint}} % init next table

\unexpanded\def\stoplinetableanalysis
  {\stoplinetablerun
   \egroup
   \global\c_tabl_lines_n_of_rows\c_tabl_lines_rows
   \dorecurse\c_tabl_lines_n_of_rows % global, from last run {\linetableparameter\c!n}
     {\setevalue{\??linetable r:##1x\c!height}{\csname\??linetableheight##1\endcsname}%
      \setevalue{\??linetable r:##1x\c!depth }{\csname\??linetabledepth ##1\endcsname}%
      \letgvalue{\??linetableheight##1}\zeropoint
      \letgvalue{\??linetabledepth ##1}\zeropoint}
   \dorecurse\c_tabl_lines_n_of_columns % global, from last run {\linetableparameter\c!n}
     {\setevalue{\??linetable c:##1\c!width}{\csname\??linetablewidth##1\endcsname}%
      \letgvalue{\??linetablewidth##1}\zeropoint}} % init next table

% todo: store in box instead of macro

\let\stoplinetablehead\relax

\unexpanded\def\startlinetablehead#1\stoplinetablehead
  {\ifconditional\c_tabl_lines_in_table
     \t_tabl_lines_head\emptytoks
   \fi
   \c_tabl_lines_head_state\plusthree % full
   \t_tabl_lines_head{#1}%
   \ifconditional\c_tabl_lines_in_table
     \tabl_lines_flush_head
   \fi}

\unexpanded\def\tabl_lines_BH
  {\ifx\EC\relax
     % signal, grabbing lines
   \else
     \t_tabl_lines_head\emptytoks
   \fi
   \push_macro_BC
   \push_macro_EC
   \def\BC##1\EC{\appendtoks##1\to\t_tabl_lines_head}%
   \let\EC\relax} % signal

\unexpanded\def\tabl_lines_EH
  {\pop_macro_EC
   \pop_macro_BC
   \expandafter\startlinetablehead\the\t_tabl_lines_head\stoplinetablehead}

\let\startlinetablebody\relax
\let\stoplinetablebody \relax

\unexpanded\def\processlinetablebuffer
  {\dosingleempty\tabl_lines_process_buffer}

\def\tabl_lines_process_buffer[#1]%
  {\bgroup
   \let\startlinetable\relax
   \let\stoplinetable \relax
   \startlinetableanalysis\getbuffer[#1]\stoplinetableanalysis
   \startlinetablerun     \getbuffer[#1]\stoplinetablerun
   \egroup}

\unexpanded\def\processlinetablefile
  {\dosingleempty\tabl_lines_process_file}

\def\tabl_lines_process_file#1% maybe accept #1 as well as [#1]
  {\bgroup
   \let\startlinetable\relax
   \let\stoplinetable \relax
   \startlinetableanalysis\readfile{#1}\donothing\donothing\stoplinetableanalysis
   \startlinetablerun     \readfile{#1}\donothing\donothing\stoplinetablerun
   \egroup}

\protect

\continueifinputfile{tabl-ltb.mkiv}

\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

\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