%D \module
%D   [       file=page-set,
%D        version=2000.10.20,
%D          title=\CONTEXT\ OTR Macros,
%D       subtitle=Column Sets,
%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.

% getnoflines vs getrawnoflines

% some day: cleanup 

\writestatus{loading}{Context OTR Macros / Column Sets}

% todo : last longer than previous
% todo : block span over last column if footnotes
% todo : diagnosis balancing run
% todo : separate footnote placement
% todo : go on on same page with colset
% todo : test page areas per page

\unprotect

\newcount\tofcolumns % total
\newcount\lofcolumns % left
\newcount\rofcolumns % right

\newcount\columnfirstcell \columnfirstcell=1
\newcount\columnlastcell
\newcount\columnfreecells
\newcount\currenthcell
\newcount\currentvcell
\newcount\columnhcells
\newcount\columnvcells

\newif\ifenoughcolumncells
\newif\ifsomefreecolumncells
\newif\ifcolumnspread
\newif\iftracecolumnset    %   \tracecolumnsettrue

\def\columnmaxcells    {75} % runtime
\def\columnmaxfreecells {0} % runtime
\def\columngaplimit     {0} % {5}

\def\@otr@{otr}

\def\OTRSETgridcell#1#2%
  {\csname\@otr@:\number#1:\number#2\endcsname}

\def\OTRSETgetgridcell#1#2%
  {\box\csname\@otr@:\number#1:\number#2\endcsname}

\def\OTRSETsetgridcell#1#2%
  {\global\setbox\csname\@otr@:\number#1:\number#2\endcsname}

\long\def\OTRSETdoifcellelse#1#2#3#4%
  {\relax\ifvoid\csname\@otr@:\number#1:\number#2\endcsname#4\else#3\fi}

\beginETEX \ifcsname

\def\columnerasegridboxes
  {\bgroup
   \increment\columnmaxcells\relax
   \ifodd\realpageno
   \else % we are on the other page
     \columnspreadfalse
   \fi
   \ifcolumnspread
     \dorecurse\nofcolumns
       {\let\!!stringa\recurselevel
        \scratchcounter\recurselevel \advance\scratchcounter\lofcolumns
        \edef\!!stringb{\the\scratchcounter}%
        \dostepwiserecurse \zerocount \columnmaxcells \plusone
          {\ifcsname\@otr@:\!!stringa:\recurselevel\endcsname
             \global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\box
             \ifcsname\@otr@:\!!stringb:\recurselevel\endcsname
               \csname\@otr@:\!!stringb:\recurselevel\endcsname
              %\global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\box\csname\@otr@:\!!stringb:\recurselevel\endcsname
             \else
               \voidb@x
              %\global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\box\voidb@x
               \expandafter\newbox\csname\@otr@:\!!stringb:\recurselevel\endcsname
             \fi
           \else
             \expandafter\newbox\csname\@otr@:\!!stringa:\recurselevel\endcsname
             \ifcsname\@otr@:\!!stringb:\recurselevel\endcsname
               \global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\box\csname\@otr@:\!!stringb:\recurselevel\endcsname
             \else
               \expandafter\newbox\csname\@otr@:\!!stringb:\recurselevel\endcsname
             \fi
           \fi}}%
   \else
     \dorecurse \tofcolumns
       {\let\!!stringa\recurselevel
        \dostepwiserecurse \zerocount \columnmaxcells \plusone
          {\ifcsname\@otr@:\!!stringa:\recurselevel\endcsname
             \global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\box\voidb@x
           \else
             \expandafter\newbox\csname\@otr@:\!!stringa:\recurselevel\endcsname
           \fi}}%
   \fi
   \dorecurse\tofcolumns
     {\global\setbox\csname\@otr@:\recurselevel:\columnmaxcells\endcsname\copy\placeholderboxa}%
   \global\columnfirstcell\zerocount
   \global\columnlastcell\columnfirstcell
   \global\columnfreecells\columnfirstcell
   \egroup}

\endETEX

\beginTEX

\def\columnerasegridboxes
  {\bgroup
   \increment\columnmaxcells\relax
   \ifodd\realpageno \else % we are on the other page
     \columnspreadfalse
   \fi
   \ifcolumnspread
     \dorecurse\nofcolumns
       {\let\!!stringa\recurselevel
        \scratchcounter\recurselevel \advance\scratchcounter\lofcolumns
        \edef\!!stringb{\the\scratchcounter}%
        \dostepwiserecurse \zerocount \columnmaxcells \plusone
          {\expandafter\ifx\csname\@otr@:\!!stringa:\recurselevel\endcsname\relax
             \expandafter\newbox\csname\@otr@:\!!stringa:\recurselevel\endcsname
             \expandafter\ifx\csname\@otr@:\!!stringb:\recurselevel\endcsname\relax
               \expandafter\newbox\csname\@otr@:\!!stringb:\recurselevel\endcsname
             \else
               \global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\box\csname\@otr@:\!!stringb:\recurselevel\endcsname
             \fi
           \else
             \global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\box
             \expandafter\ifx\csname\@otr@:\!!stringb:\recurselevel\endcsname\relax
               \voidb@x
              %\global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\box\voidb@x
               \expandafter\newbox\csname\@otr@:\!!stringb:\recurselevel\endcsname
             \else
               \csname\@otr@:\!!stringb:\recurselevel\endcsname
              %\global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\box\csname\@otr@:\!!stringb:\recurselevel\endcsname
             \fi
           \fi}}%
   \else
     \dorecurse\tofcolumns
       {\let\!!stringa\recurselevel
        \dostepwiserecurse \zerocount \columnmaxcells \plusone
          {\expandafter\ifx\csname\@otr@:\!!stringa:\recurselevel\endcsname\relax
             \expandafter\newbox\csname\@otr@:\!!stringa:\recurselevel\endcsname
           \else
             \global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\box\voidb@x
           \fi}}%
   \fi
   \dorecurse\tofcolumns
     {\global\setbox\csname\@otr@:\recurselevel:\columnmaxcells\endcsname\copy\placeholderboxa}%
   \global\columnfirstcell\zerocount
   \global\columnlastcell\columnfirstcell
   \global\columnfreecells\columnfirstcell
   \egroup}

\endTEX

\def\doOTRSETsetgridcells#1#2#3#4#5#6% placeholder col row wid hei {data}
  {\!!countd#2\advance\!!countd#4\advance\!!countd\minusone
   \!!counte#3\advance\!!counte#5\advance\!!counte\minusone
   \dostepwiserecurse{#2}\!!countd\plusone
     {\!!countf\recurselevel
      \dostepwiserecurse{#3}\!!counte\plusone
        {\OTRSETsetgridcell\!!countf\recurselevel#1}}%
   \dostepwiserecurse{#3}\!!counte\plusone
     {\global\wd\OTRSETgridcell{#2}\recurselevel\hsize}%
   \OTRSETsetgridcell{#2}\!!counte#6}

\def\OTRSETsetgridcells
  {\doOTRSETsetgridcells{\copy\placeholderboxb}}

\def\OTRSETerasegridcells#1#2#3#4%
  {\doOTRSETsetgridcells{\box\voidb@x}{#1}{#2}{#3}{#4}{\box\voidb@x}}

\def\OTRSETsetfreecells#1#2% col start
  {\global\columnfirstcell\ifnum#2=0 1\else#2\fi\relax
   \ifnum\columnfirstcell>\columnmaxcells
     \global\columnfreecells\zerocount
     \global\columnfirstcell\plusone
     \global\columnlastcell \zerocount
     \global\somefreecolumncellsfalse
    %\message{no cells a}%
   \else
     \doloop
       {\ifnum\columnfirstcell>\columnmaxcells\relax
          \exitloop
        \else
          \OTRSETdoifcellelse{#1}\columnfirstcell
            {\global\advance\columnfirstcell\plusone}
            {\exitloop}%
        \fi}%
     \global\columnlastcell\columnfirstcell
     \doloop
       {\ifnum\columnlastcell>\columnmaxcells\relax
          \exitloop
        \else
          \OTRSETdoifcellelse{#1}\columnlastcell
            {\global\advance\columnlastcell \minusone \exitloop}
            {\global\advance\columnlastcell \plusone }%
        \fi}%
     \ifnum\columnfirstcell>\columnmaxcells
       \global\columnfreecells\zerocount
       \global\columnfirstcell\plusone
       \global\columnlastcell \zerocount
       \global\somefreecolumncellsfalse
      %\message{no cells b}%
     \else
       \ifnum\columnlastcell>\columnmaxcells
         \global\columnlastcell\columnmaxcells
       \fi
       \global\columnfreecells\columnlastcell
       \global\advance\columnfreecells -\columnfirstcell
       \global\advance\columnfreecells \plusone
       \global\somefreecolumncellstrue
      %\message{\number\columnfirstcell-\number\columnlastcell=\number\columnfreecells}%
     \fi
   \fi}

\def\OTRSETgetmaxfreecells#1#2% col start
  {\scratchcounter\zerocount
   \let\columnmaxfreecells\!!zerocount
   \let\columnfrmfreecells\!!zerocount
   \dostepwiserecurse{#2}\columnmaxcells\plusone
     {\OTRSETdoifcellelse{#1}\recurselevel
        {\ifnum\columnmaxfreecells<\scratchcounter
           \edef\columnmaxfreecells{\the\scratchcounter}%
           \let\columnfrmfreecells\recurselevel
         \fi
         \scratchcounter\zerocount}
        {\advance\scratchcounter\plusone}}}

\long\def\OTRSETrecurseRL#1%
  {\dostepwiserecurse\nofcolumns\plusone\minusone
     {#1\hskip\OTRSETgetparameter\c!afstand\recurselevel}}

\def\OTRSETmakegridbox
  {\ifcase\columndirection
     \OTRSETdomakegridbox\plusone\nofcolumns\plusone
   \else
     \OTRSETdomakegridbox\nofcolumns\plusone\minusone
   \fi}

\def\OTRSETdomakegridbox#1#2#3%
  {\hbox\bgroup
   \dontcomplain
   \forgetall % can go once in \flush
   \OTRSETregisterbalancing
   \ifbalancecolumns
     \ifnum\realpageno=\balancingpageno\relax
       \!!heighta \localcolumnmaxcells\lineheight
       \global\let\localcolumnmaxcells\!!zerocount
     \else
       \!!heighta \teksthoogte
     \fi
   \else
     \!!heighta \teksthoogte
   \fi
   %
   % test first !
   \hbox to \zetbreedte
     {\dostepwiserecurse{#1}{#2}{#3}
        {\mofcolumns\recurselevel
         \localcolumnwidth\OTRSETlocalwidth\mofcolumns
         \setbox\scratchbox\hbox\localframed
           [\??mc\OTRSETidentifier\number\mofcolumns]%
           [\c!breedte=\localcolumnwidth,\c!hoogte=\!!heighta,
            \c!regels=]%
           {}%
         \wd\scratchbox\localcolumnwidth
         \ht\scratchbox\!!heighta
         \ifcase\columndirection
           \hskip\OTRSETgetparameter\c!afstand\recurselevel
           \box\scratchbox
         \else
           \box\scratchbox
           \hskip\OTRSETgetparameter\c!afstand\recurselevel
         \fi}}%
   \hskip-\zetbreedte
   % main text
   \hbox to \zetbreedte
     {\dostepwiserecurse{#1}{#2}{#3}
        {\mofcolumns\recurselevel
         \localcolumnwidth\OTRSETlocalwidth\mofcolumns
         \offinterlineskip
         \setbox\scratchbox\vbox to \!!heighta % \teksthoogte
           {\topskipcorrection
            \dorecurse\columnmaxcells
              {\setbox\scratchbox\hbox{\OTRSETgetgridcell\mofcolumns\recurselevel}%
               \ht\scratchbox\ht\strutbox
               \dp\scratchbox\dp\strutbox
               \ifcase\columndirection
                 \box\scratchbox
               \else
                 \hbox to \localcolumnwidth
                   {\hskip\localcolumnwidth\llap{\box\scratchbox}}%
               \fi
               \par}}%
         \wd\scratchbox\localcolumnwidth % \tekstbreedte
         \ifcase\columndirection
           \hskip\OTRSETgetparameter\c!afstand\recurselevel\box\scratchbox
         \else
           \box\scratchbox\hskip\OTRSETgetparameter\c!afstand\recurselevel
         \fi}}%
   \egroup}

\def\OTRSETreducegridbox
  {\ifnum\localcolumnmaxcells>\zerocount
     \let\columnmaxcells\localcolumnmaxcells
   \fi}

\def\OTRSETflushfinalfootnotes
  {\ifcase\lastcolumnlastcell \else
     \setbox\scratchbox\hbox
       {\placebottomnotes}%
     \ifdim\ht\scratchbox>\zeropoint
       \setbox\scratchbox\hbox
         {\hbox to \zeropoint{\OTRSETgetgridcell\nofcolumns\lastcolumnlastcell}%
          \box\scratchbox}%
       \ht\scratchbox\ht\strutbox
       \dp\scratchbox\dp\strutbox
       \OTRSETsetgridcell\nofcolumns\lastcolumnlastcell\box\scratchbox
     \fi
     \global\lastcolumnlastcell\zerocount
   \fi}

\def\OTRSETdoflush
  {\ifcollectingcontent
     \global\mofcolumns\plusone
   \else
     \OTRSETdofinalflush
     \OTRSETdofinaloutput
     \OTRSETinitializecolumns
    %\OTRSETdoflushfloats
     \OTRSETstartnextpage
     \initializecolumntextareas
   \fi}

%\def\OTRSETdofinalflush % see \OTRSETdoflush
%  {\OTRSETflushfinalfootnotes
%   \placecolumntextareas
%   \OTRSETcentergridcells
%   \setbox\scratchbox=\OTRSETmakegridbox
%   \global\mofcolumns=\nofcolumns % otherwise problems in finaloutput
%   \finaloutput\box\scratchbox}

\newbox\OTRfinalpagebox

\def\OTRSETdofinalflush % see \OTRSETdoflush
  {\OTRSETflushfinalfootnotes
   \placecolumntextareas
   \OTRSETcentergridcells
   \bgroup % we want to keep the reduction local
     \OTRSETreducegridbox
     \global\setbox\OTRfinalpagebox\OTRSETmakegridbox
   \egroup % otherwise we get the wrong number of free cells
  %\gdef\localcolumnmaxcells{0}% here ?
   \global\mofcolumns\nofcolumns} % otherwise problems in finaloutput

\def\OTRSETdofinaloutput
  {\ifdim\ht\OTRfinalpagebox=\teksthoogte
   % \bgroup \let\OTRSETsetvsize\relax % prevents useless search for gap
       \finaloutput\box\OTRfinalpagebox
   % \egroup
   \fi}

\newcounter\OTRSETnofbalanced

\def\OTRSETregisterbalancing
  {\ifcase\OTRSETfinish \or
     \global\chardef\OTRSETfinish\plustwo 
     \doglobal\increment\OTRSETnofbalanced
     \expanded{\writeutilitycommand
       {\noexpand\twopassentry{\s!colset}{\OTRSETnofbalanced}{\noexpand\realfolio}}}%
   \fi}

\def\OTRSETresetbalancing 
  {\doglobal\newcounter\balancingpageno
   \global\chardef\OTRSETfinish\zerocount}

\definesystemvariable {mc}
\definesystemvariable {mt}
\definesystemconstant {colset}

\definetwopasslist\s!colset

\newdimen  \OTRSETtextswidth
\newdimen  \OTRSETtextsheight
\let       \OTRSETidentifier=\empty

\newtoks   \OTRSEToutput

\def\OTRSETgetparameter#1#2{\getvalue{\??mc\OTRSETidentifier\number#2#1}}
\def\OTRSETsetparameter#1#2{\setvalue{\??mc\OTRSETidentifier\number#2#1}}

\def\OTRSETsetvsize % snap per sectie (gap here?)
  {\ifcollectingcontent \else % can be assigndimen
     \OTRSETcheckinsert % added
     \OTRSETsetfreecells\mofcolumns\columnfirstcell
     \ifsomefreecolumncells
       \global\vsize\columnfreecells\lineheight
       \global\pagegoal\vsize % niet nodig, tenzij binnen otr
       \synchronizeoutput % fails on example
      % \allowbreak % hm
     \fi
     \synchronizenotes
   \fi}

\def\OTRSETsethsize
  {%\OTRSETassignwidth\OTRSETidentifier\to\localcolumnwidth
   \localcolumnwidth\OTRSETlocalwidth\mofcolumns
   \tekstbreedte\localcolumnwidth
   \hsize\localcolumnwidth}

%\def\OTRSETsynchronizehsize
%  {\doifnotvalue{\??mc\OTRSETidentifier\the\mofcolumns\c!breedte}\v!passend
%     \OTRSETsethsize} 

\def\OTRSETsynchronizehsize  
  {\ifcase0\getvalue{\??mc\??mc\c!breedte}\else % some width set  
     \bgroup
     \scratchdimen\OTRSETlocalwidth\mofcolumns
     \ifdim\scratchdimen=\tekstbreedte
       \egroup 
     \else
       \egroup \OTRSETsethsize % only if change in width and \column/\break 
     \fi
   \fi } 

\def\OTRSETcheckfreelines
  {\OTRSETsetvsize}

\def\doOTRSETcolumnseparator
  {\hbox to \zeropoint{\hss\red\vl\hss}}

\let\OTRSETcolumnseparator\relax

\def\showbreaks
  {\let\OTRSETcolumnseparator\doOTRSETcolumnseparator}

% \installcolumnbreakhandler {SET} \v!ja
%   {% hmmm:
%    \ifhmode
%      \bgroup
%      \removeunwantedspaces
%      \parfillskip\zeropoint
%      \OTRSETcolumnseparator
%      \par
%      \egroup
%    \fi
%    % brrr:
%    \ejectinsert
%    \ejectpage 
%    \OTRSETsynchronizehsize} % no \OTRSETsethsize, can be mid smaller (like tabulate)
% 
% \installcolumnbreakhandler {SET} \v!forceer
%   {\OTRSETgotocolumn[\v!forceer]}
% \installcolumnbreakhandler {SET} \v!eerste
%   {\OTRSETgotocolumn[\v!eerste]}
% \installcolumnbreakhandler {SET} \v!laatste
%   {\OTRSETgotocolumn[\v!laatste]}
%
% \installcolumnbreakhandler {SET} \v!pagina
%   {\simplepagebreak % \flushnotes \executepagebreakhandler\v!ja
%    \ifnum\mofcolumns>\plusone
%      \OTRSETgotocolumn[\v!laatste,\v!forceer]%
%    \fi}

\def\OTRSETcolumnhbreak
  {\ifhmode 
     \bgroup
     \removeunwantedspaces
     \parfillskip\zeropoint
     \OTRSETcolumnseparator
     \par
     \egroup
   \fi}

\installcolumnbreakhandler {SET} \v!lokaal
  {\OTRSETcolumnhbreak
   \ejectinsert
   \ejectpage % brrr
   \OTRSETsynchronizehsize} % no \OTRSETsethsize, can be mid smaller (like tabulate)

% We need to make sure that we really leave the column; mid 
% column we may end up in an empty gap, and we don;t want to 
% stay there (basically such a gap is a small empty page 
% then).  

\installcolumnbreakhandler {SET} \v!ja
  {\OTRSETcolumnhbreak
   \edef\savedmofcolumns{\the\mofcolumns}%
   \edef\savedrealpageno{\the\realpageno}%
   \ejectinsert
   \ejectpage % brrr
   \doloop
     {\ifnum\savedmofcolumns=\mofcolumns
        \ifnum\savedrealpageno=\realpageno
          \OTRSETdummycolumn
        \else
          \exitloop
        \fi 
      \else      
        \exitloop
      \fi}%
   \OTRSETsynchronizehsize} 

\installcolumnbreakhandler {SET} \s!unknown
  {\expanded{\OTRSETgotocolumn[\@@columnspecification]}}

\installcolumnbreakhandler {SET} \v!pagina
  {\vfill\eject % \doejectpage\eject
   \OTRSETgotonextpage}

\newtoks\OTRSETeverystartofcolumn

\newbox\OTRSETsavedfootnotes

% \installoutput\OTRSETflushtextsofar % spacing goes wrong

%\def\OTRSETflushtextsofar
%  {\ifvoid\normalpagebox \else
%     \setbox\scratchbox\vbox{\unvbox\normalpagebox}%
%     \OTRSETsavenotes
%     \OTRSEThandleflushedtext0
%   \fi}

% The complication is in the fact that when the HERE float 
% is placed, the otr is not invoked when there is not yet 
% enough content; this can lead to a change in order (turning 
% on the tracer with option 0 is very instructive, watch the 
% small numbers in the margin)  
%
% 0 = no flushing, so no interference but user should handle
%     border cases of placement 
% 1 = the normal otr, rather untested 
% 2 = a solution that works ok, is experimental and above 
%     all messy

\chardef\OTRSETflushtextmode=0 

\def\OTRSETflushtextsofar
  {\ifcase\OTRSETflushtextmode
     % don't mess around 
   \or
     % the normal one 
     \ifvoid\normalpagebox\else
       \OTRSETnaturalflush
       \OTRSETcheckfreelines
     \fi
   \or
     % way to complicated, but kind of ok  
     \doOTRSETflushtextsofar
   \fi}

\newskip\lastskipinotr

\installoutput\doOTRSETflushtextsofar % experimental 
  {\ifvoid\normalpagebox\else
     \scratchdimen\dp\normalpagebox
     \setbox\scratchbox\vbox
       {\forgetall
        \unvbox\normalpagebox 
        \global\lastskipinotr\lastskip\relax
        \ifdim\lastskipinotr>\zeropoint\relax
          \removelastskip
        \else
          \kern-\scratchdimen % handle depth 
        \fi}%
     \ifdim\lastskipinotr>\zeropoint
       \scratchskip\ht\scratchbox
       \setbox\scratchbox\hbox
         {\lower\strutdepth\box\scratchbox}%
       \dp\scratchbox\scratchdimen
       \ht\scratchbox\scratchskip
     \fi
     \OTRSETsavenotes
     \OTRSEThandleflushedtext0
     \ifdim\lastskipinotr>\zeropoint
       %\vskip \lastskipinotr % hm, gets lost anyway  
     \else
       % we should not discard skips after here; tricky
     \fi
     \OTRSETsetvsize
   \fi}

\def\OTRSETplacebottomnotes
  {\iflastcolumnfootnotes
     \ifnum\nofcolumns=\mofcolumns
       \ifintermediatefootnotes \placebottomnotes \fi
     \fi
   \else
     \placebottomnotes
   \fi}

\def\OTRSETflushsavednotes
  {\iflastcolumnfootnotes
     \ifnum\nofcolumns=\mofcolumns
       \flushsavednotes
     \fi
   \else
     \flushsavednotes
   \fi}

\def\OTRSETsavenotes
  {\iflastcolumnfootnotes
     \ifnum\nofcolumns=\mofcolumns \else
       \savenotes
     \fi
   \fi}

\appendtoks \OTRSETflushsavednotes \to \OTRSETeverystartofcolumn

% \def\OTRSETnaturalflush
%   {\bgroup
%    \forgetall % new, needed !
%    \setbox0\vbox to \columnfreecells\lineheight
%      {\vskip-\topskip
%       \vskip\lineheight
%       \prevdepth\dp\strutbox
%       \unvbox\normalpagebox
%       \vfill}%
%    \setbox2\hbox
%      {\OTRSETplacebottomnotes}%
%    \setbox\scratchbox\hbox
%      {\wd0\zeropoint\box0\box2}%
%    \dp\scratchbox\dp\strutbox
%    \OTRSEThandleflushedtext1
%    \egroup}

\def\OTRSETnaturalflush
  {\bgroup
   \forgetall % new, needed !
   \setbox0\vbox to \columnfreecells\lineheight
     {\vskip-\topskip
      \vskip\lineheight
      \prevdepth\dp\strutbox
      \unvbox\normalpagebox
      \vfill}%
   \setbox2\hbox
     {\OTRSETplacebottomnotes}%
   \setbox\scratchbox\hbox
     {\wd0\zeropoint\box0\box2}%
   \dp\scratchbox\dp\strutbox
   \donetrue
   \ifbalancecolumns \ifcase\OTRSETfinish \or \or
     % we're in the second balance loop in this column set, 
     % so we have to preserve the previous and discard the rest 
     \donefalse 
   \fi \fi 
   \ifdone
     \OTRSEThandleflushedtext1
   \else
     \writestatus
       {columnset}
       {check balancing values of '\OTRSETidentifier', text discarded!}%
     \wait % better wait than get lost, esp with two balances per page 
   \fi 
   \egroup}

\newcount\lastcolumnlastcell

\def\OTRSEThandleflushedtext#1%
  {\getnoflines{\ht\scratchbox}%
  %\wd\scratchbox\tekstbreedte % geen \hsize kan < zijn in bv split tabulate
   \wd\scratchbox\OTRSETlocalwidth\mofcolumns
   \doOTRSETsetgridcells
     {\copy\placeholderboxf}
     \mofcolumns\columnfirstcell\plusone\noflines
     {\registeredtextarea1\columnfirstcell\scratchbox}% == \hbox
   \global\columnlastcell\columnfirstcell
   \global\advance\columnlastcell \noflines
   \global\lastcolumnlastcell\columnlastcell
   \global\advance\lastcolumnlastcell \minusone
   % find next (acceptable) gap, todo: deadcycle
   \ifcase#1\else
     \OTRSETfillgapsbetweencells\mofcolumns\columnlastcell
   \fi
   \OTRSETfindnextgap
   % \message{\the\mofcolumns,\the\columnfirstcell,\the\columnfreecells}%
   % \wait
   % we cannot adapt the hsize since it may have changed (like 
   % inside a tabulate) so we only change it when there is a
   % reason to do so 
   \OTRSETsynchronizehsize 
   \OTRSETsetvsize}

\def\OTRSETfindnextgap
  {\OTRSETsetfreecells\mofcolumns\columnlastcell
   \ifsomefreecolumncells
     % okay
   \else
     \global\advance\mofcolumns \plusone
     \ifnum\mofcolumns>\nofcolumns
       \OTRSETdoflush
       \global\columnlastcell\plusone
       \global\columnfirstcell\zerocount
       \OTRSETdoflushfloats
     \else
       \the\OTRSETeverystartofcolumn
       \global\columnlastcell\plusone
       \global\columnfirstcell\zerocount
     \fi
   \fi}

\let\OTRSETcheckfreelines\donothing

\def\OTRSETfillgapsbetweencells#1#2% col
  {\ifnum\columngaplimit>\zerocount
     \donefalse
     \dostepwiserecurse{#2}\columnmaxcells\plusone
       {\OTRSETdoifcellelse{#1}\recurselevel
          {\ifdone
             \!!countb\recurselevel \advance\!!countb -\!!counta\relax
             \ifnum\!!countb>\plusone
               \advance\!!countb \minusone
               \ifnum\!!countb<\columngaplimit\relax
                 \!!countb\recurselevel \advance\!!countb \minusone
                 \dostepwiserecurse\!!counta\!!countb\plusone
                   {\OTRSETsetgridcell{#1}\recurselevel\copy\placeholderboxc}%
                %\message{[gap]}%
               \fi
             \fi
           \fi
           \donefalse}
          {\ifdone \else
             \donetrue
             \!!counta\recurselevel
           \fi}}%
   \fi}

\appendtoks
  \OTRSETfillgapsbetweencells\mofcolumns\plusone
\to \OTRSETeverystartofcolumn

%\def\OTRSETfreezeminimumgap#1%
%  {\OTRSETgetmaxfreecells{#1}{1}%
%   \ifnum\columnmaxfreecells>0
%     \!!countb=\columnfrmfreecells
%     \!!counta=\!!counta \advance\!!counta -\columnmaxfreecells
%     \dorecurse{\columnmaxcells}
%       {\ifnum\recurselevel<\!!counta\relax
%          \donetrue
%        \else\ifnum\recurselevel>\!!countb
%          \donetrue
%        \else
%          \donefalse
%        \fi\fi
%        \ifdone
%          \OTRSETdoifcellelse{#1}{\recurselevel}
%            {}{\OTRSETsetgridcell{#1}\recurselevel\copy\placeholderboxc}%
%        \fi}%
%   \fi}
%
%\def\OTRSETfillgaps#1#2#3% col from to
%  {\dostepwiserecurse{#2}{#3}{1}
%     {\OTRSETdoifcellelse{#1}{\recurselevel}
%        {}{\OTRSETsetgridcell{#1}\recurselevel\copy\placeholderboxc}}}
%
%\def\OTRSETfillbotgaps#1#2% col first
%  {\OTRSETfillgaps{#1}{#2}{\columnmaxcells}}
%
%\def\OTRSETfilltopgaps#1#2% col last
%  {\OTRSETfillgaps{#1}{1}{#2}}

\newif\ifspancolumnslots \spancolumnslotstrue
\newif\ifcheckcolumnspan \checkcolumnspantrue

\def\OTRSETcheckwidthgap#1#2% box size
  {\ifcheckcolumnspan
     \bgroup
     \scratchdimen#2%
     \advance\scratchdimen-\wd#1\relax
     \ifdim-10\s!sp>\scratchdimen
       \egroup
     \else\ifdim10\s!sp<\scratchdimen
       \egroup
     \else
       \egroup
       \wd#1=#2%
     \fi\fi
   \fi}

\def\OTRSETcheckcolumnslot#1%
  {\enoughcolumncellstrue
   \ifspancolumnslots\else
     \OTRSETcheckwidthgap#1\hsize
     \ifdim\wd#1>\hsize
       \enoughcolumncellsfalse
     \fi
   \fi
   \ifenoughcolumncells
     \getnoflines\pagetotal
     \scratchcounter\noflines
     \getnoflines{\ht#1}%
     \columnvcells\noflines
     \columnhcells\plusone
     \advance\scratchcounter \columnvcells \relax
     \ifnum\scratchcounter>\columnfreecells
       \enoughcolumncellsfalse
     \fi
   \fi}

\def\OTRSETstoreincolumnslotPAGE#1%
  {\ifenoughcolumncells
     % to do
     \OTRSETsavebox{#1}%
   \else
     \OTRSETsavebox{#1}%
   \fi}

\def\OTRSETstoreincolumnslotTOPS#1%
  {\OTRSETprepareforcolumnslot1{#1}%
   \OTRSETcheckcolumnslot{#1}%
   \ifenoughcolumncells
     \OTRSETcheckcolumnspace\mofcolumns\columnfirstcell{#1}%
   \fi
   \ifenoughcolumncells
     \OTRSETsetgridcells\mofcolumns\columnfirstcell\columnhcells\columnvcells
       {\hbox{\copy#1}}%
     \OTRSETsetvsize
   \else
     \OTRSETsavebox{#1}%
   \fi}

\def\OTRSETstoreincolumnslotBOTS#1%
  {\OTRSETprepareforcolumnslot3{#1}%
   \edef\savedcolumnlastcell{\the\columnlastcell}%
   \OTRSETcheckcolumnslot{#1}%
   \ifenoughcolumncells
     \advance\columnlastcell -\columnvcells \advance\columnlastcell \plusone
%     \OTRSETcheckcolumnspace\mofcolumns\columnfirstcell{#1}%
     \OTRSETcheckcolumnspace\mofcolumns\columnlastcell{#1}%
   \fi
   \ifenoughcolumncells
     \OTRSETsetgridcells\mofcolumns\columnlastcell\columnhcells\columnvcells
       {\copy#1}
     \OTRSETfillgapsbetweencells\mofcolumns\savedcolumnlastcell % -)
     \OTRSETsetvsize
   \else
     \columnlastcell\savedcolumnlastcell
     \OTRSETsavebox{#1}%
   \fi}

\newdimen\totalcolumnspace

\def\columnspacetopoffset{0}
\def\columnspacebotoffset{0}

\def\OTRSETcheckcolumnspace#1#2#3% col row box
  {\columnhcells\plusone
   \totalcolumnspace\zeropoint
   \scratchcounter#1%
   \enoughcolumncellstrue
   \doloop
     {\advance\totalcolumnspace \OTRSETlocalwidth\scratchcounter\relax % needed
\OTRSETcheckwidthgap#3\totalcolumnspace
      \ifnum\wd#3>\totalcolumnspace\relax
        \ifnum\scratchcounter=\nofcolumns
          \enoughcolumncellsfalse
          \exitloop
        \else
          \advance\columnhcells \plusone
          \advance\scratchcounter \plusone
          \advance\totalcolumnspace \OTRSETgetparameter\c!afstand\scratchcounter
        \fi
      \else
        \exitloop
      \fi}%
   \ifenoughcolumncells
     \getnoflines{\ht#3}%
     \columnvcells\noflines
     \OTRSETcheckcolumncells{#1}{#2}\columnhcells\columnvcells
   \fi}

\def\OTRSETcheckcolumncells#1#2#3#4% col row wid hei
  {\!!countd#1\advance\!!countd#3\advance\!!countd\minusone
   \!!counte#2\advance\!!counte#4\advance\!!counte\minusone
   \ifnum\!!counte>\columnmaxcells\relax
     \enoughcolumncellsfalse
   \else
     \enoughcolumncellstrue
%\let\columnspacetopoffset\zerocount
%\scratchcounter#2\advance\scratchcounter\minusone
%\ifnum\scratchcounter>0
%  \dostepwiserecurse{#1}\!!countd\plusone
%    {\ifdim\wd\OTRSETgridcell\recurselevel\scratchcounter>\zeropoint
%       \let\columnspacetopoffset\plusone
%     \else\ifdim\dp\OTRSETgridcell\recurselevel\scratchcounter>\zeropoint
%       \let\columnspacetopoffset\plusone
%     \fi\fi}%
%  \advance\!!counte \columnspacetopoffset \relax
%  \advance\columnvcells \columnspacetopoffset \relax
%\fi
%\let\columnspacebotoffset\zerocount
%\scratchcounter\!!counte
%\advance\scratchcounter \columnvcells \relax
%\ifnum\scratchcounter>\columnmaxcells\else
%  \dostepwiserecurse{#1}\!!countd\plusone
%    {\ifdim\wd\OTRSETgridcell\recurselevel\scratchcounter>\zeropoint
%       \let\columnspacebotoffset\plusone
%     \else\ifdim\dp\OTRSETgridcell\recurselevel\scratchcounter>\zeropoint
%       \let\columnspacebotoffset\plusone
%     \fi\fi}%
%  \advance\!!counte \columnspacebotoffset \relax
%  \advance\columnvcells \columnspacebotoffset \relax
%\fi
     \dostepwiserecurse{#1}\!!countd\plusone % cols
       {\ifenoughcolumncells
          \!!countf\recurselevel\relax
          \dostepwiserecurse{#2}\!!counte\plusone % rows
            {\ifenoughcolumncells
               \OTRSETdoifcellelse\!!countf\recurselevel
                 {\enoughcolumncellsfalse}{}%
             \fi}%
        \fi}%
   \fi}

\def\OTRSETsetpreferedcolumnslot#1#2%
  {\doifsomething{#1}{\edef\preferedcolumn{#1}}%
   \doifsomething{#2}{\edef\preferedrow   {#2}}}

\OTRSETsetpreferedcolumnslot{\nofcolumns}{1} % default ?

\let\pofcolumns\mofcolumns
\let\qofcolumns\mofcolumns

\newif\ifquitincurrentcolumn

\def\OTRSETstoreincolumnslotLRTB#1%
  {\OTRSETprepareforcolumnslot1{#1}%
\OTRSETflushtextsofar 
   \OTRSETstoreincolumnslotindeed
     \mofcolumns\nofcolumns+\currenthcell
     \plusone\columnmaxcells+\currentvcell{#1}}

\def\OTRSETstoreincolumnslotLRBT#1%
  {\OTRSETprepareforcolumnslot3{#1}%
\OTRSETflushtextsofar 
   \OTRSETstoreincolumnslotindeed
     \mofcolumns\nofcolumns+\currenthcell
     \columnmaxcells\plusone-\currentvcell{#1}}

\def\OTRSETstoreincolumnslotRLTB#1%
  {\OTRSETprepareforcolumnslot1{#1}%
\OTRSETflushtextsofar 
   \OTRSETstoreincolumnslotindeed
     \nofcolumns\qofcolumns-\currenthcell
     \plusone\columnmaxcells+\currentvcell{#1}}

\def\OTRSETstoreincolumnslotRLBT#1%
  {\OTRSETprepareforcolumnslot3{#1}%
\OTRSETflushtextsofar 
   \OTRSETstoreincolumnslotindeed
     \nofcolumns\qofcolumns-\currenthcell
     \columnmaxcells\plusone-\currentvcell{#1}}

\def\OTRSETstoreincolumnslotTBLR#1%
  {\OTRSETprepareforcolumnslot1{#1}%
\OTRSETflushtextsofar 
   \OTRSETstoreincolumnslotindeed
     \plusone\columnmaxcells+\currentvcell
     \mofcolumns\nofcolumns+\currenthcell{#1}}

\def\OTRSETstoreincolumnslotTBRL#1%
  {\OTRSETprepareforcolumnslot1{#1}%
\OTRSETflushtextsofar 
   \OTRSETstoreincolumnslotindeed
     \plusone\columnmaxcells+\currentvcell
     \nofcolumns\qofcolumns-\currenthcell{#1}}

\def\OTRSETstoreincolumnslotBTLR#1%
  {\OTRSETprepareforcolumnslot3{#1}%
\OTRSETflushtextsofar 
   \OTRSETstoreincolumnslotindeed
     \columnmaxcells\plusone-\currentvcell
     \mofcolumns\nofcolumns+\currenthcell{#1}}

\def\OTRSETstoreincolumnslotBTRL#1%
  {\OTRSETprepareforcolumnslot3{#1}%
\OTRSETflushtextsofar 
   \OTRSETstoreincolumnslotindeed
     \columnmaxcells\plusone-\currentvcell
     \nofcolumns\qofcolumns-\currenthcell{#1}}

\def\OTRSETstoreincolumnslotFXTB#1% fixed column
  {\OTRSETprepareforcolumnslot2{#1}% % 1/2 dependent of place, todo
\OTRSETflushtextsofar 
   \OTRSETstoreincolumnslotindeed
     \pofcolumns\pofcolumns+\currenthcell
     \preferedrow\columnmaxcells+\currentvcell{#1}}

\def\OTRSETstoreincolumnslotFXBT#1% fixed column
  {\OTRSETprepareforcolumnslot2{#1}% % 3/2 dependent on place, todo
\OTRSETflushtextsofar 
   \OTRSETstoreincolumnslotindeed
     \pofcolumns\pofcolumns+\currenthcell
     \columnmaxcells\preferedrow-\currentvcell{#1}}

% \def\OTRSETstoreincolumnslotHERE#1% fixed column
%   {\OTRSETprepareforcolumnslot2{#1}%
%    \OTRSETflushtextsofar
%    \getnoflines\pagetotal \advance\noflines\columnfirstcell
%    \OTRSETstoreincolumnslotindeed
%      \mofcolumns\mofcolumns+\currenthcell
%      \noflines\columnmaxcells+\currentvcell{#1}%
%    \OTRSETsetvsize}

\chardef\OTRSETforcefixedfloats=0

\def\OTRSETstoreincolumnslotHERE#1% fixed column
  {\ifcase\OTRSETforcefixedfloats
     \OTRSETstoreincolumnslotSOMEWHERE2{#1}%
   \else
     \OTRSETstoreincolumnslotFIXD{#1}% 
   \fi}

\def\OTRSETstoreincolumnslotFIXD#1% fixed column
  {\OTRSETprepareforcolumnslot2{#1}%
   % no flush text sofar here 
   \snaptogrid\vbox{\box#1}}

\def\OTRSETstoreincolumnslotSOMEWHERE#1#2% 
  {\OTRSETprepareforcolumnslot{#1}{#2}%  
   \OTRSETflushtextsofar
   \getnoflines\pagetotal \advance\noflines\columnfirstcell
   \OTRSETstoreincolumnslotindeed
     \mofcolumns\mofcolumns+\currenthcell
     \noflines\columnmaxcells+\currentvcell{#2}%
   \OTRSETsetvsize}

\def\OTRSETstoreincolumnslotindeed#1#2#3#4#5#6#7#8#9%
  {%\OTRSETflushtextsofar
   \ifnum\preferedcolumn<\mofcolumns
     \let\pofcolumns\mofcolumns
   \else
     \let\pofcolumns\preferedcolumn
   \fi
   \ifquitincurrentcolumn
     \ifnum\mofcolumns=\nofcolumns
       \def\qofcolumns{\mofcolumns}%
     \else
       \scratchcounter\mofcolumns
       \advance\scratchcounter \plusone
       \edef\qofcolumns{\the\scratchcounter}%
     \fi
   \else
     \let\qofcolumns\mofcolumns
   \fi
   \enoughcolumncellsfalse
   \donefalse
   \dostepwiserecurse{#1}{#2}{#31}
     {\ifdone
        \exitloop
      \else
        #4=\recurselevel
        \dostepwiserecurse{#5}{#6}{#71}
          {\ifdone
             \exitloop
           \else
             #8=\recurselevel
             \OTRSETcheckcolumnspace\currenthcell\currentvcell{#9}%
             \ifenoughcolumncells \donetrue \fi
           \fi}%
      \fi}%
   \ifdone
     \enoughcolumncellstrue
   \else
     \enoughcolumncellsfalse
   \fi
   \ifenoughcolumncells
%    \ifnum\columnspacetopoffset>0\message{[+++]}\fi
%    \ifnum\columnspacebotoffset>0\message{[---]}\fi
%    \OTRSETsetgridcells\currenthcell\currentvcell\columnhcells\columnvcells
%      {\vbox
%         {\ifcase\columnspacetopoffset\else\ruledvskip\columnspacetopoffset\lineheight\fi
%          \copy#9
%          \ifcase\columnspacebotoffset\else\ruledvskip\columnspacebotoffset\lineheight\fi}}%
     \OTRSETsetgridcells\currenthcell\currentvcell\columnhcells\columnvcells
       {\copy#9}%
     \ifnum\currenthcell=\mofcolumns\relax
       \ifdim\ht\OTRSETsavedfootnotes>\zeropoint
         \OTRSETsetfreecells\mofcolumns\columnfirstcell
         \ifsomefreecolumncells
           \getnoflines{\ht\OTRSETsavedfootnotes}\relax
           \ifnum\columnfreecells<\noflines
             \global\somefreecolumncellsfalse
           \else
            %\message{[flt]}% float
           \fi
         \fi
         \ifsomefreecolumncells
           % ok, enough room for notes
          %\message{[flt]}% float
         \else % ?
           \OTRSETsavebox{#9}%
           \OTRSETerasegridcells\currenthcell\currentvcell\columnhcells\columnvcells
          %\message{[clr]}% save box
         \fi
       \else
        %\message{[flt]}% float
       \fi
     \else
      %\message{[flt]}% float
     \fi
     \OTRSETsetvsize
    %\message{[fnt]}% float
   \else
    %\message{[rej]}% save box
     \OTRSETsavebox{#9}%
   \fi}

\chardef\columnslotspacing \plusone

\def\OTRSETstoreincolumnslot#1% #2 % {method} {box} % alleen last
  {% no messing around here
   % \dp#2=\zeropoint
   % \ifcase\columnslotspacing\else
   %   \setbox#2=\vbox spread \columnslotspacing\lineheight
   %     {\vss\box#2\vss}%
   % \fi
   % and don't change this any more 
%   \doifdefinedelse{\strippedcsname\OTRSETstoreincolumnslot#1}
%     {\getvalue{\strippedcsname\OTRSETstoreincolumnslot#1}{#2}}
%     {\OTRSETstoreincolumnslotUNKNOWN{#2}}}
   \executeifdefined{\strippedcsname\OTRSETstoreincolumnslot#1}
     \OTRSETstoreincolumnslotUNKNOWN} % {#2}}

\def\OTRSETstoreincolumnslotUNKNOWN#1%
  {\OTRSETprepareforcolumnslot2{#1}\copy#1} % {} ? 

\def\OTRSETprepareforcolumnslot#1#2% 1=hoog 2=midden 3=laag
  {\dp#2\zeropoint
   \ifcase\columnslotspacing\else
     \scratchdimen\columnslotspacing\lineheight
     \ifnum#1=2 \scratchdimen2\scratchdimen \fi
     \setbox#2\vbox spread \scratchdimen
       {\ifnum#1>1\vss\fi\box#2\relax\ifnum#1<3\vss\fi}%
   \fi}

\def\OTRSETdocheckiffloatfits % eigenlijk moet else float anders
  {\global\ifnofloatpermitted\roomforfloatfalse\else\roomforfloattrue\fi}

\def\OTRSETsavebox#1% clean up the skips
  {\ifhbox#1% spans and so
     \global\setbox\floatbox\vbox{\box#1}%
   \else
     \setbox\scratchbox\vbox
       {\unvbox#1\unskip\unskip\unskip
        \global\setbox\floatbox\lastbox}%
   \fi
   \dosavefloat}

\def\OTRSETflushfloatbox % nog verder doorvoeren en meer info in marge
  {\iftestfloatbox\ruledhbox\fi{\box\floatbox}}

\def\OTRSETdoflushfloats
  {\bgroup
   \def\OTRSETsavebox##1{\!!doneafalse}%
   \doloop
     {\ifsomefloatwaiting
        \dogetfloat
        \ifdim\wd\floatbox>\zeropoint
          \!!doneatrue
          \dp\floatbox\zeropoint
          \OTRSETstoreincolumnslot{TBLR}\floatbox
          \if!!donea
           %\message{[flu]}%
          \else
            \doresavefloat
            \exitloop
          \fi
        \else
         %\message{[err]}% happens but why?
        \fi
      \else
        \exitloop
      \fi}
   \egroup}

\newif\ifcentergridcells \centergridcellstrue

\newif\ifcentergridcellonly     \centergridcellonlyfalse
\newif\ifautocentergridcellonly \autocentergridcellonlytrue

\def\OTRSETcentergridcells
  {\ifcentergridcells
     \dorecurse\nofcolumns
       {\currenthcell\recurselevel
        \ifautocentergridcellonly
          % we prevent centering when the next column is empty
          % to be checked ! ! ! !
          \advance\currenthcell \plusone
          \centergridcellonlytrue
          \ifnum\currenthcell>\nofcolumns
            % ok already
          \else
            % only span if there is a next column with content
            \dorecurse\columnmaxcells
              {\ifdim\ht\OTRSETgridcell\currenthcell\currentvcell>\zeropoint
                 \centergridcellonlyfalse
               \else\ifdim\dp\OTRSETgridcell\currenthcell\currentvcell>\zeropoint
                 \centergridcellonlyfalse
               \fi\fi}%
          \fi
        \fi
        \currenthcell\recurselevel
        \dorecurse\columnmaxcells
          {\currentvcell\recurselevel\relax
           \ifdim\ht\OTRSETgridcell\currenthcell\currentvcell>\zeropoint
           \ifdim\dp\OTRSETgridcell\currenthcell\currentvcell=\zeropoint
             \bgroup
             \setbox\scratchbox\OTRSETgetgridcell\currenthcell\currentvcell
             \getnoflines{\ht\scratchbox}%
             \!!counta\currentvcell
             \advance\!!counta -\noflines
             \advance\!!counta \plusone
             % first col always ok
             \!!countb\currenthcell
             \!!countc\currenthcell
             \advance\!!countc \plusone
             \!!donebtrue
             \ifcentergridcellonly
               \!!countc\maxdimen
             \fi
             \dostepwiserecurse\!!countc\nofcolumns\plusone
               {\if!!doneb
                  \let\xrecurselevel\recurselevel
                  \dostepwiserecurse\!!counta\currentvcell\plusone
                    {\ifdim\ht\OTRSETgridcell\xrecurselevel\recurselevel>\zeropoint
                       \!!donebfalse
                     \else\ifdim\wd\OTRSETgridcell\xrecurselevel\recurselevel>\zeropoint
                       \!!donebfalse
                     \fi\fi}%
                  \if!!doneb
                    \!!countb\xrecurselevel
                  \fi
                \fi}%
             \totalcolumnspace\OTRSETlocalwidth\currenthcell
             \dostepwiserecurse\!!countc\!!countb\plusone
               {\advance\totalcolumnspace \OTRSETlocalwidth\recurselevel
                \advance\totalcolumnspace \OTRSETgetparameter\c!afstand\recurselevel}%
             \ifdim\totalcolumnspace>\wd\scratchbox
               \setbox\scratchbox\hbox to \totalcolumnspace{\hss\box\scratchbox\hss}%
             \fi
             \OTRSETsetgridcell\currenthcell\currentvcell\box\scratchbox
           \egroup
           \fi
           \fi}}%
   \fi}

\def\OTRSETinitializecolumns% once per page
  {\columnspreadtrue % todo
   \ifcolumnspread
     \global\rofcolumns\getvalue{\??mc\OTRSETidentifier\c!nrechts}%
     \global\lofcolumns\getvalue{\??mc\OTRSETidentifier\c!nlinks}%
     \global\tofcolumns\rofcolumns \relax
     \ifodd\realpageno\relax
       \global\nofcolumns\rofcolumns
     \else
       \global\advance\tofcolumns\lofcolumns
       \global\nofcolumns\lofcolumns
     \fi
   \else
     \global\nofcolumns\getvalue{\??mc\OTRSETidentifier\c!n}%
     \global\rofcolumns\nofcolumns
     \global\lofcolumns\nofcolumns
     \global\tofcolumns\nofcolumns
   \fi
   \OTRSETassignwidths
   \global\mofcolumns\plusone
   \columnerasegridboxes}

% vanaf hier:

\def\definecolumnset
  {\dodoubleargument\dodefinecolumnset}

\def\dodefinecolumnset[#1][#2]%
  {\getparameters[\??mc#1]
     [\c!richting=\v!rechts,
      \c!n=2,
      \c!breedte=\v!passend,
      \c!balanceren=\v!nee,
      \c!afstand=1.5\bodyfontsize, % controleren
      \c!nlinks=\getvalue{\??mc#1\c!n},
      \c!nrechts=\getvalue{\??mc#1\c!n},
      \c!regels=0,
      #2]%
   \redodefinecolumnset[#1]}

\def\redodefinecolumnset[#1]%
  {\dorecurse{\getvalue{\??mc#1\c!nlinks}} % todo
     {\dododefinecolumnset[#1][\recurselevel]}%
   \dorecurse{\getvalue{\??mc#1\c!nrechts}} % todo
     {\dododefinecolumnset[#1][\recurselevel]}%
   \setupcolumnset[#1][1][\c!afstand=\!!zeropoint]}

\def\dododefinecolumnset[#1][#2]%
  {\presetlocalframed
     [\??mc#1#2]%
   \setupcolumnset
     [#1][#2]
     [\c!offset=\v!overlay,
      \c!kader=\v!uit,
      \c!uitlijnen=,
      \c!regels=0,% really needed since c!regels is now part of framed 
      \c!afstand=\getvalue{\??mc#1\c!afstand}]}

\def\setupcolumnset
  {\dotripleargument\dosetupcolumnset}

\def\dosetupcolumnset[#1][#2][#3]%
  {\ifthirdargument
     \def\docommando##1%
       {\doifelse{##1}\v!elk
          {\dorecurse{\getvalue{\??mc#1\c!n}}{\docommando\recurselevel}}
          {\getparameters[\??mc#1##1][#3]}}%
     \processcommalist[#2]\docommando
   \else
     \getparameters[\??mc#1][#2]%
   \fi}

\definecolumnset[\s!default][\c!n=2] % fallback 

\def\OTRSETgotonextpage
  {\vfill\eject
   \relax\ifnum\mofcolumns>\plusone
     \OTRSETgotocolumn[\v!laatste]%
     \ifnum\mofcolumns>\plusone
       \OTRSETgotocolumn[\v!forceer]%
     \fi
   \fi}

\let\OTRSETgotonextpageX\OTRSETgotonextpage % will become obsolete

\def\OTRSETgotocolumn
  {\dosingleempty\doOTRSETgotocolumn}

% \def\doOTRSETgotocolumn[#1]% first|last|yes|<number>
%   {\doifnumberelse{#1}
%      {\OTRSETdummycolumn
%       \doloop
%         {\ifnum\mofcolumns<#1\relax
%            \OTRSETdummycolumn
%          \else
%            \exitloop
%          \fi}}
%      {\processallactionsinset
%         [#1]
%         [     \v!ja=>\OTRSETdummycolumn,
%          \v!forceer=>\OTRSETdummycolumn,
%           \v!eerste=>{\doOTRSETgotocolumn[1]},
%          \v!laatste=>\expanded{\doOTRSETgotocolumn[\the\nofcolumns]},
%          \s!default=>\OTRSETdummycolumn]}}

\def\doOTRSETgotocolumn[#1]% first|last|yes|<number>
  {\doifnumberelse{#1}
     {\ifnum\mofcolumns<#1\relax
        \vfill\eject % \doejectpage\eject
        \doloop
          {\ifnum\mofcolumns<#1\relax
             \OTRSETdummycolumn \else \exitloop
           \fi}%
      \fi}
     {\processallactionsinset
        [#1]
        [     \v!ja=>\OTRSETdummycolumn,
         \v!forceer=>\OTRSETdummycolumn,
          \v!eerste=>{\doOTRSETgotocolumn[1]},
         \v!laatste=>\expanded{\doOTRSETgotocolumn[\the\nofcolumns]},
         \s!default=>\OTRSETdummycolumn]}}

% to be documented and tested, not yet that robust

\def\OTRSETgotocell#1#2%
  {\endgraf
   \gdef\gotocellcounter{0}%
   \doloop
     {\ifnum\mofcolumns<#1\relax
        \doglobal\increment\gotocellcounter\relax
        \ifnum\gotocellcounter>#1\relax
          \line{\strut}\crlf
          \line{\strut}\crlf
          \column
          \writestatus{columnset}{quitting goto cell}%
          \exitloop
        \else
          \column
        \fi
      \else
        \exitloop
      \fi}%
   \ifnum\mofcolumns=#1\relax
     \ifnum#2>1
       \scratchcounter\zerocount
       \currenthcell\mofcolumns
       \currentvcell#2\advance\currentvcell \minusone
       \dorecurse\currentvcell
         {\OTRSETdoifcellelse\mofcolumns\recurselevel\donothing
            {\advance\scratchcounter\plusone}}
       \getnoflines\pagetotal
       \advance\scratchcounter-\noflines
       \ifnum\scratchcounter>\zerocount
         \dorecurse\scratchcounter{\line{\strut}}%
       \fi
     \fi
   \fi
   \OTRSETsetvsize}

\def\OTRSETdummycolumn
  {\vbox{\strut}
   \vskip-\lineheight
   \vfill
   \eject}

\newcounter\columnsetlevel
\let\currentcolumnset\empty
\chardef\OTRSETfinish\zerocount

\def\startcolumnset
  {\dodoubleempty\dostartcolumnset}

\def\dostartcolumnset[#1][#2]%
  {\increment\columnsetlevel\relax
   \OTRSETresetbalancing 
   \globallet\localcolumnmaxcells\!!zerocount
   \ifnum\columnsetlevel=\plusone
     \bgroup
     \def\currentcolumnset{#2}%
     \binnenkolommentrue % will be different flag
     \activateotr{SET}{ONE}% andere naam, activate or so
     \doifelsenothing{#1}
       {\globallet\OTRSETlist\s!default}
       {\xdef\OTRSETlist{#1}}%
     \OTRSETstartnextpage
     \OTRSETloadbalancing % here
     \OTRSETinitbalancing 
     \OTRSETassignwidths
     \OTRSETsethsize
   \else
     \bgroup
   \fi}

% \def\stopcolumnset
%   {\relax
%    \ifnum\columnsetlevel=\plusone
%      \par
%      \dostopcolumnset
%      \egroup
%      \global\footnotelimittrue
%      \setvsize
%      \sethsize
%      \ifvoid\OTRfinalpagebox\else
%        % probably balanced
%        \ifdim\ht\OTRfinalpagebox<\teksthoogte
%          \snaptogrid[\v!pagina]\hbox{\box\OTRfinalpagebox}
%        \else
%          \box\OTRfinalpagebox
%        \fi
%      \fi
%      \ifsomefloatwaiting \setvsize \pagina \setvsize \fi
%    \else
%      \egroup
%    \fi
%    \decrement\columnsetlevel\relax}

\def\stopcolumnset
  {\relax
   \ifnum\columnsetlevel=\plusone
     \global\chardef\OTRSETfinish\plusone
     \pagebreak
     \dostopcolumnset
     \egroup
     \global\footnotelimittrue
     \setvsize
     \sethsize
     \ifvoid\OTRfinalpagebox\else
       % probably balanced
       \ifdim\ht\OTRfinalpagebox<\teksthoogte
         \snaptogrid[\v!pagina]\hbox{\box\OTRfinalpagebox}%
       \else
         \box\OTRfinalpagebox
       \fi
     \fi
     \global\chardef\OTRSETfinish\zerocount
     \ifsomefloatwaiting \setvsize \pagina \setvsize \fi
   \else
     \egroup
   \fi
   \decrement\columnsetlevel\relax}

\def\dostopcolumnset
  {%\OTRSETdofinalflushfloats % yes/no
   \ifbalancecolumns
     \OTRSETdobalance
   \else
     \OTRSETnobalance
   \fi}

\def\OTRSETdobalance
  {\OTRSETnobalance}

\def\localcolumnmaxcells{0}

% currently line represents real line, i.e. on the grid, and
% not something noflines (also, watch out for switching from
% 2-3 columns on one page with both sets balanced: the 
% second set does not see the first set 

\chardef\OTRSETbottombalance\zerocount

% \def\OTRSETinitbalancing
%   {\ifbalancecolumns
%      \let\savedcolumnmaxcells\columnmaxcells
%      \ifnum\realpageno=\balancingpageno\relax
%        \ifnum\mofcolumns=\plusone
%          \dorecurse\nofcolumns
%            {\!!counta\recurselevel\relax
%             \!!countb\getvalue{\??mc\OTRSETidentifier\number\!!counta\c!regels}\relax
%             \ifcase\!!countb
%               \!!countb\getvalue{\??mc\OTRSETidentifier\c!regels}\relax
%             \fi 
%             \ifcase\!!countb
%               \!!countb \savedcolumnmaxcells\relax
%             \fi
%             % can be an option: absolute versus relative
%             \advance\!!countb\precolumnlines
%             \ifnum\!!countb>\localcolumnmaxcells\relax
%               \xdef\localcolumnmaxcells{\the\!!countb}%
%             \fi
%             \advance\!!countb \plusone
%             \dostepwiserecurse\!!countb\columnmaxcells\plusone
%               {\ifvoid\OTRSETgridcell\!!counta\recurselevel
%                  \OTRSETsetgridcell\!!counta\recurselevel\copy\placeholderboxe
%                \fi}}%
%          \OTRSETsetvsize % ! ! ! 
%        \fi
%      \fi
%    \fi}

\def\OTRSETinitbalancing
  {\ifbalancecolumns
     \let\savedcolumnmaxcells\columnmaxcells
     \ifnum\realpageno=\balancingpageno\relax
       \ifnum\mofcolumns=\plusone
         \dorecurse\nofcolumns
           {\!!counta\recurselevel\relax
            \!!countb\getvalue{\??mc\OTRSETidentifier\number\!!counta\c!regels}\relax
            \ifcase\!!countb
              \!!countb\getvalue{\??mc\OTRSETidentifier\c!regels}\relax
            \fi 
            \ifcase\!!countb
              \!!countb \savedcolumnmaxcells\relax
            \fi
            % can be an option: absolute versus relative
            \ifcase\OTRSETbottombalance
              \advance\!!countb\precolumnlines
              \ifnum\!!countb>\localcolumnmaxcells\relax
                \xdef\localcolumnmaxcells{\the\!!countb}%
              \fi
              \advance\!!countb \plusone
              \dostepwiserecurse\!!countb\columnmaxcells\plusone
                {\ifvoid\OTRSETgridcell\!!counta\recurselevel
                   \OTRSETsetgridcell\!!counta\recurselevel\copy\placeholderboxe
                 \fi}%
            \else
              \globallet\localcolumnmaxcells\columnmaxcells
              \advance\!!countb-\columnmaxcells 
              \!!countb-\!!countb
              \advance\!!countb \minusone
              \ifnum\!!countb>\zerocount
                \dostepwiserecurse\plusone\!!countb\plusone
                  {\ifvoid\OTRSETgridcell\!!counta\recurselevel
                     \OTRSETsetgridcell\!!counta\recurselevel\copy\placeholderboxe
                   \fi}%
              \fi
            \fi}%
         \OTRSETsetvsize % ! ! ! 
       \fi
     \fi
   \fi}

\def\OTRSETpresetbalancing
  {\doifvaluesomething{\??mc\OTRSETidentifier\c!regels}%
     {\getcommacommandsize[\csname\??mc\OTRSETidentifier\c!regels\endcsname]%
      \ifnum\commalistsize>\plusone
        \scratchcounter\zerocount
        \def\docommando##1%
          {\advance\scratchcounter\plusone
           \setvalue{\??mc\OTRSETidentifier\the\scratchcounter\c!regels}{##1}}%
        \processcommacommand
          [\csname\??mc\OTRSETidentifier\c!regels\endcsname]\docommando
        \setvalue{\??mc\OTRSETidentifier\c!regels}{0}%
      \fi}}

\def\OTRSETloadbalancing
  {\gettwopassdata\s!colset
   \iftwopassdatafound
     \OTRSETpresetbalancing
     \global\let\balancingpageno\twopassdata
   \else
     \doglobal\newcounter\balancingpageno
   \fi
   \global\balancingcolumnsfalse} % not really used yet 

%\def\OTRSETnobalance
%  {\iflastcolumnfootnotes % testen ! optie
%     % inhibit flush of floats !
%     \dostepwiserecurse{\mofcolumns}{\nofcolumns}{1}
%       {\vskip-\lineheight\vbox{\strut}\vfill\eject}%
%   \else
%     \ifdim\pagetotal>\zeropoint
%       \vfill \eject \OTRSETdofinalflush
%     \fi
%   \fi}

\def\OTRSETnobalance
  {\iflastcolumnfootnotes % testen ! optie
     % inhibit flush of floats !
     \dostepwiserecurse\mofcolumns\nofcolumns\plusone
       {\vskip-\lineheight\vbox{\strut}\vfill\eject}%
   \else
     \ifdim\pagetotal>\zeropoint
       \ifnum\mofcolumns=\nofcolumns
         \OTRSETflushfinalfootnotes
         \vfill \eject
       \else
         \vfill \eject
         \OTRSETdofinalflush
         \OTRSETdofinaloutput
       \fi
     \fi
   \fi}

\def\OTRSETstartnextpage
  {\doifsomething\OTRSETlist
     {\getfromcommacommand[\OTRSETlist][1]%
      \global\let\OTRSETidentifier\commalistelement
      \doifundefined{\??mc\OTRSETidentifier\c!n}
        {\globallet\OTRSETidentifier\s!default}%
      \let\newcommalistelement\empty
      \doglobal\replaceincommalist\OTRSETlist1%
      \OTRSETrestart}}

\def\OTRSETrestart % weed
  {\OTRSETinitializefeatures
   \OTRSETflushpreposttext
   \OTRSETinitializecolumns
   \OTRSETcheckinsert
   \OTRSETcheckgrid
   \OTRSETsetvsize
   \OTRSETsethsize % or local ? 
   \OTRSETsetplaceholders
   \OTRSEThandlepreposttext
   \initializecolumntextareas % name !
   \OTRSETsetvsize}

\OTRSEToutput
  {\OTRSETnaturalflush
  %\OTRSETstartnextpage
   \OTRSETdoflushfloats % zou eigenlijk in \flushsavedfloats moeten (gaat fout)
   \OTRSETcheckfreelines
   \OTRSETchecksidefloat}

\def\OTRSETinitializefeatures
  {% number of lines
   % new: raw
   \getrawnoflines\teksthoogte\xdef\columnmaxcells{\the\noflines}%
   % direction
   \doifelsevalue{\??mc\OTRSETidentifier\c!richting}\v!rechts
     {\chardef\columndirection\zerocount}
     {\chardef\columndirection\plusone}%
   % balancing
   \balancecolumnsfalse
   \chardef\OTRSETbottombalance\zerocount
   \processaction
     [\getvalue{\??mc\OTRSETidentifier\c!balanceren}]
     [    \v!ja=>\balancecolumnstrue,
       \v!onder=>\chardef\OTRSETbottombalance\plusone
                 \balancecolumnstrue,
       \v!boven=>%chardef\OTRSETbottombalance\zerocount
                 \balancecolumnstrue]}

% keep 'm for a while 
%
% \installoutput\OTRSETflushpreposttext
%  {\global\setbox\precolumnbox\vbox{\unvbox\normalpagebox}%
%   \ifcarryoverfootnotes \else
%     \global\setbox\postcolumnbox\vbox{\placebottomnotes}%
%   \fi}
%
% to be tested on 'boekinhoud' in 'pascal/demo-bbi'
%
% junk ! ! ! ! !
%
%\installoutput\OTRSETflushpreposttext
%  {\global\setbox\precolumnbox\vbox
%     {\unvbox\normalpagebox
%      \strut\vskip-2\lineheight\strut}% we want a proper depth
%   \ifcarryoverfootnotes \else
%     \global\setbox\postcolumnbox\vbox{\placebottomnotes}%
%   \fi}
%
% \starttext
%   \definecolumnset[two][n=2]
%   \startcolumnset[two] \dorecurse{4}{\input tufte } \stopcolumnset
%   \input tufte
%   \startcolumnset[two] \input tufte \stopcolumnset
% \stoptext
% 
% \installoutput\OTRSETflushpreposttext
%   {\global\setbox\precolumnbox\vbox{\unvbox\normalpagebox}%
%    \global\dp\precolumnbox\strutdepth
%    \ifcarryoverfootnotes \else
%      \global\setbox\postcolumnbox\vbox{\placebottomnotes}%
%    \fi}

% test: 
%
% \definecolumnset[two]  [n=2,balance=yes]
% \definecolumnset[three][n=3,balance=yes]
% \setupcolumnset [two]  [1] [lines=10]
% \setupcolumnset [two]  [2] [lines=10]
% 
% \startcolumnset[two]   \dorecurse{14}{\input tufte \par} \stopcolumnset
% \startcolumnset[three] \dorecurse{12}{\input tufte \par} \stopcolumnset
%
% with: 
% 
% \installoutput\OTRSETflushpreposttext
%   {%\ifvoid\normalpagebox
%    %  \global\setbox\precolumnbox\vbox{}%
%    %\else
%      \global\setbox\precolumnbox\vbox
%        {\unvcopy\normalpagebox}%
%      \global\setbox\precolumnbox\vbox to \ht\precolumnbox
%        {\box\normalpagebox}%
%    %\fi
%    \global\dp\precolumnbox\strutdepth
%    \ifcarryoverfootnotes \else
%      \global\setbox\postcolumnbox\vbox{\placebottomnotes}%
%    \fi}

% testcase : pascal demo-bbi, paragraaf/aanduiding koppen 

\ifx\lastskipinotr\undefined \newskip\lastskipinotr \fi 

\installoutput\OTRSETflushpreposttext
  {\global\setbox\precolumnbox\vbox
     {\unvbox\normalpagebox
      \global\lastskipinotr\lastskip}%
   \ifdim\lastskipinotr>\zeropoint
     \global\setbox\precolumnbox\hbox
       {\lower\strutdepth\box\precolumnbox}%
   \fi 
   \global\dp\precolumnbox\strutdepth
   \ifcarryoverfootnotes \else
     \global\setbox\postcolumnbox\vbox{\placebottomnotes}%
   \fi}

\let\precolumnlines \!!zerocount
\let\postcolumnlines\!!zerocount

\def\OTRSEThandlepreposttext
  {\ifdim\ht\precolumnbox>\zeropoint % new
     \getnoflines{\ht\precolumnbox}%
     \edef\precolumnlines{\the\noflines}%
     \doOTRSETsetgridcells
       {\copy\placeholderboxe}
       \plusone\plusone\nofcolumns\noflines
       {\box\precolumnbox}%
   \else
     \let\precolumnlines\!!zerocount
   \fi
   \ifdim\ht\postcolumnbox>\zeropoint % new, otherwise empty bottom line
     \getnoflines{\ht\postcolumnbox}%
     \edef\postcolumnlines{\the\noflines}%
     \advance\columnfreecells -\noflines
     \advance\columnfreecells \plusone
     \doOTRSETsetgridcells
       {\copy\placeholderboxe}
       \plusone\columnfreecells\nofcolumns\noflines
       {\box\postcolumnbox}%
   \else
     \let\postcolumnlines\!!zerocount
   \fi}

\def\OTRSETchecksidefloat
  {} % {\sidefloatoutput}

\def\OTRSETfinalsidefloatoutput
  {}

\def\OTRSETcheckgrid
  {\topskip1\topskip
   \ifforcecolumngrid
     \widowpenalty\zerocount
     \clubpenalty\zerocount
     \brokenpenalty\zerocount
   \fi}

\def\OTRSETcheckinsert%
  {\iflastcolumnfootnotes
     \ifnum\nofcolumns=\mofcolumns
       \OTRSETforceinserts
     \else
       \OTRSETinhibitinserts
     \fi
   \else
     \OTRSETforceinserts
   \fi}

\def\OTRSETforceinserts
  {\enablenotes}

\def\OTRSETinhibitinserts
  {\disablenotes}

% interface to footnotes

%\def\OTRSETassignwidth#1\to#2%
%  {\doifelsevalue{\??mc#1\c!breedte}{\v!passend}
%     {#2=\zetbreedte
%      \scratchcounter=\getvalue{\??mc#1\c!nlinks}\relax
%\ifnum\getvalue{\??mc#1\c!nrechts}>\scratchcounter
%      \scratchcounter=\getvalue{\??mc#1\c!nrechts}%
%\fi
%      \dorecurse{\scratchcounter}
%        {\advance#2 -\getvalue{\??mc#1\recurselevel\c!afstand}}%
%      \divide#2 \scratchcounter}
%     {#2=\getvalue{\??mc#1\c!breedte}}}

%\def\OTRSETassignwidth#1\to#2% assumes mofcolumns
%  {\doifelsevalue{\??mc#1\number\mofcolumns\c!breedte}{\v!passend}
%     {#2=\zetbreedte
%      \scratchcounter=0
%      \dorecurse{\getvalue{\??mc#1\c!n}}
%        {\doifelsevalue{\??mc#1\number\recurselevel\c!breedte}{\v!passend}
%           {\advance\scratchcounter by 1 }
%           {\advance#2 by -\getvalue{\??mc#1\recurselevel\c!breedte}}%
%         \advance#2 by -\getvalue{\??mc#1\recurselevel\c!afstand}}%
%      \divide#2 by \scratchcounter}
%     {#2=\getvalue{\??mc#1\number\mofcolumns\c!breedte}}}
%
% replaced by
%
%\def\OTRSETassignwidth#1\to#2% assumes mofcolumns
%  {#2=\OTRSETlocalwidth\mofcolumns}

\def\OTRSETassignwidths
  {%\scratchdimen\zetbreedte
   \freezetextwidth \scratchdimen\tekstbreedte
   %
   \scratchcounter\zerocount
   \dorecurse\nofcolumns
     {\doifelsevalue{\??mc\OTRSETidentifier\recurselevel\c!breedte}\v!passend
        {\advance\scratchcounter \plusone }
        {\advance\scratchdimen -\getvalue{\??mc\OTRSETidentifier\recurselevel\c!breedte}}%
      \advance\scratchdimen -\getvalue{\??mc\OTRSETidentifier\recurselevel\c!afstand}}%
   \ifcase\scratchcounter\else
     \divide\scratchdimen \scratchcounter
   \fi
   \setgvalue{\??mc\??mc\c!breedte}{0}%
   \dorecurse\nofcolumns
     {\doifelsevalue{\??mc\OTRSETidentifier\recurselevel\c!breedte}\v!passend
        {\dimen0=\scratchdimen}
        {\setgvalue{\??mc\??mc\c!breedte}{1}%
         \dimen0=\getvalue{\??mc\OTRSETidentifier\recurselevel\c!breedte}}%
      \setxvalue{\??mc\recurselevel\??mc\c!breedte}{\the\dimen0}}}

\def\OTRSETlocalwidth#1%
  {\getvalue{\??mc\number#1\??mc\c!breedte}}

\newbox\placeholderboxa
\newbox\placeholderboxb
\newbox\placeholderboxc
\newbox\placeholderboxd
\newbox\placeholderboxe
\newbox\placeholderboxf

\def\columnplaceholder#1#2%
  {\hbox
     {\localcolortrue
      \setbox\scratchbox\hbox to \hsize
        {\iftracecolumnset \incolortrue \localcolortrue 
           #2\hskip-.5ex\vrule\!!width1ex\!!height.5ex\!!depth.5ex\hss
         \fi
         \hss}%
      \ifcase#1\relax
        \ht\scratchbox\zeropoint
        \dp\scratchbox\zeropoint
        \wd\scratchbox\zeropoint
      \else
        \wd\scratchbox\hsize
        \ht\scratchbox\ht\strutbox
        \dp\scratchbox\dp\strutbox
      \fi
      \box\scratchbox}}

\def\OTRSETsetplaceholders
  {\global\setbox\placeholderboxa\columnplaceholder0\cyan
   \global\setbox\placeholderboxb\columnplaceholder0\green
   \global\setbox\placeholderboxc\columnplaceholder0\blue
   \global\setbox\placeholderboxd\columnplaceholder0\red
   \global\setbox\placeholderboxe\columnplaceholder0\magenta
   \global\setbox\placeholderboxf\columnplaceholder1\darkgray}

\def\doOTRSETshowstatus
  {\llap{\incolortrue \localcolortrue \tt\tfxx\blue
     (\the\vsize->\number\columnfirstcell\#\number\columnfreecells)%
     \hskip\leftskip}}

\def\OTRSETshowstatus
  {\iftracecolumnset \doOTRSETshowstatus \fi}

\appendtoks \OTRSETshowstatus \to \everypar

% page contents

\def\OTRSETdopagecontents#1#2% takes two args: \box<n> \unvbox<n>
  {\vbox to \teksthoogte{\forgetall#1#2\pushcolor}}

\def\OTRSETsomepagefloat  {\def\floatmethod{PAGE}\OTRSETsomeslotfloat} % check
\def\OTRSETsomeherefloat  {\def\floatmethod{HERE}\OTRSETsomeslotfloat} % check
\def\OTRSETsomeelsefloat  {\def\floatmethod{HERE}\OTRSETsomeslotfloat} % check
\def\OTRSETsomefixdfloat  {\def\floatmethod{FIXD}\OTRSETsomeslotfloat} % check
\def\OTRSETsometopfloat   {\def\floatmethod{TOPS}\OTRSETsomeslotfloat} % check
\def\OTRSETsomebottomfloat{\def\floatmethod{BOTS}\OTRSETsomeslotfloat} % check

% \def\OTRSETsomeslotfloat {\let\floatmethod\v!hier\OTRONEsomeelsefloat}

\def\OTRSETflushfloatbox% nog verder doorvoeren en meer info in marge
  {\iftestfloatbox\ruledhbox\fi{\box\floatbox}}

\def\OTRSETsomeslotfloat[#1]%
  {\setbox\floatbox\vbox{\flushfloatbox}%
   \dp\floatbox\dp\strutbox
   \@EA\uppercasestring\floatmethod\to\floatmethod
   \OTRSETstoreincolumnslot\floatmethod\floatbox
   \doinsertfloatinfo}

% kind of new, looks much like OTRONE, but not entirely

\def\OTRSETdosettopinserts
  {\bgroup
   \ifsomefloatwaiting
     \noffloatinserts\zerocount
     \let\totaltopinserted\!!zeropoint
     \OTRSETdodosettopinserts
     \ifnum\@@bknonder=\zerocount
       \ifnum\@@bknregels>\zerocount
         \ifdim\totaltopinserted>\zeropoint\relax
           \dimen0\lineheight
           \dimen0=\@@bknregels\dimen0
           \advance\dimen0 \totaltopinserted\relax
           \ifdim\dimen0>\teksthoogte % \vsize  %%%%%%%%% \teksthoogte
             \showmessage\m!floatblocks8{\@@bknregels}%
             \vfilll\eject
           \fi
         \fi
       \fi
     \fi
   \fi
   \egroup}

\def\OTRSETdodosettopinserts
  {\ifnum\noffloatinserts<\noftopfloats
     \dogetfloat
     \ifdim\topinserted=\zeropoint\relax
       \topofinserttrue
     \else
       \topofinsertfalse
     \fi
     \setbox\scratchbox\vbox % kan beter !
       {\forgetall
        \iftopofinsert
          \ifdim\OTRSETtopoffset=\zeropoint
            \verplaatsopgrid[\v!boven]
          \fi
        \else
          \betweenfloatblanko % inserts can't look back
        \fi
        \flushfloatbox
        \blanko[\@@bknawit]}%
     \global\advance\topinserted \ht\scratchbox\relax
     \ifdim\topinserted>\vsize % was \teksthoogte\relax
       \doresavefloat
       \noffloatinserts\noftopfloats\relax
       \global\advance\topinserted -\ht\scratchbox
       \let\OTRSETdodosettopinserts\relax % to be tested
     \else
       \xdef\totaltopinserted{\the\topinserted}%
       \insert\topins{\forgetall\box\scratchbox}% interlineskip ?
       \ifsomefloatwaiting
         \advance\noffloatinserts \plusone
       \else
         \noffloatinserts\noftopfloats\relax
       \fi
       \dofloatflushedinfo
     \fi
   \else
     \ifsomefloatwaiting
       \showmessage\m!floatblocks6{\the\noftopfloats}%
     \fi
     \let\OTRSETdodosettopinserts\relax
   \fi
   \OTRSETdodosettopinserts}

\def\OTRSETdosetbotinserts
  {\bgroup
   \ifsomefloatwaiting
     \noffloatinserts\zerocount
     \OTRSETdodosetbotinserts
   \fi
   \egroup}

\def\OTRSETdodosetbotinserts
  {\ifnum\noffloatinserts<\nofbotfloats\relax
     \dogetfloat
     \global\advance\botinserted \ht\floatbox\relax
     \global\advance\botinserted \dp\floatbox\relax
     \global\advance\botinserted \floattopskip\relax
     \ifdim\botinserted<\pagegoal\relax
       \insert\botins
         {\forgetall
          \blanko[\@@bkvoorwit]%
          \flushfloatbox}%
       \ifsomefloatwaiting
         \advance\noffloatinserts \plusone
       \else
         \noffloatinserts\nofbotfloats
       \fi
       \dofloatflushedinfo
     \else
       \doresavefloat
       \noffloatinserts\nofbotfloats\relax
     \fi
     \global\nofloatpermittedtrue % vgl topfloats s!
   \else
     \ifsomefloatwaiting
       \showmessage\m!floatblocks7{\the\nofbotfloats}%
     \fi
     \let\OTRSETdodosetbotinserts\relax
   \fi
   \OTRSETdodosetbotinserts}

\let\OTRSETdosetbothinserts\relax

\def\OTRSETdotopinsertions
  {\ifvoid\topins\else
     \ifvoid\columntopbox\mofcolumns
       \columnsettopbox\mofcolumns\box\topins
     \else
       \columnsettopbox\mofcolumns\vbox % temp, must be better
         {\forgetall
          \offinterlineskip
          \box\columntopbox\mofcolumns
          \box\topins}
     \fi
   \fi
   \global\topinserted\zeropoint\relax} % goes away

\def\OTRSETdobotinsertions
  {\ifvoid\botins \else
     \columnsetbotbox\mofcolumns\box\botins
%   \else
%     \columnsetbotbox\mofcolumns\vbox % temp, must be better
%       {\forgetall
%        \offinterlineskip
%        \box\botins
%        \box\columnbotbox\mofcolumns}
   \fi
   \global\botinserted\zeropoint\relax} % goes away

% set ipv text

% left right 1 2 3 +1 +2 +3

\let\columnleftareas \empty
\let\columnrightareas\empty

% links rechts => odd, even, n, named

\def\definecolumntextarea
  {\dotripleempty\dodefinecolumntextarea}

\def\dodefinecolumntextarea[#1][#2][#3]% y=0 is mogelijke en handig !
  {\ifthirdargument
     \doifelse{#2}\v!beide
       {\definecolumntextarea[#1][\v!links ][#3]%
        \definecolumntextarea[#1][\v!rechts][#3]}
       {\doifelse{#2}\v!volgende
          {\doifoddpageelse
             {\definecolumntextarea[#1][\v!rechts][#3]}
             {\definecolumntextarea[#1][\v!links][#3]}}
          {\presetlocalframed
             [\??mt#1#2]%
           \processaction[#2] % \doglobal voorkomt stack build up
             [ \v!links=>\doglobal\addtocommalist{#1}\columnleftareas,
              \v!rechts=>\doglobal\addtocommalist{#1}\columnrightareas]%
           \getparameters[\??mt#1#2]
             [\c!x=1,\c!y=1,\c!nx=1,\c!ny=1,\c!clipoffset=2\lineheight,
              \c!offset=\v!overlay,\c!strut=\v!nee,\c!kader=\v!uit,
              \c!status=\v!stop,#3]}}%
   \else
     \definecolumntextarea[#1][\v!volgende][#2]%
   \fi}

\def\setupcolumntextarea
  {\dotripleempty\dosetupcolumntextarea}

\def\dosetupcolumntextarea[#1][#2][#3]%
  {\ifthirdargument
     \doifelse{#2}\v!beide
       {\setupcolumntextarea[#1][\v!links ][#3]%
        \setupcolumntextarea[#1][\v!rechts][#3]}
       {\doifelse{#2}\v!volgende
          {\doifoddpageelse
             {\setupcolumntextarea[#1][\v!rechts][#3]}
             {\setupcolumntextarea[#1][\v!links][#3]}}
          {\getparameters[\??mt#1#2][#3]}}%
   \else
     \setupcolumntextarea[#1][\v!volgende][#2]%
   \fi}

\def\initializecolumntextareas
  {\ifodd\realpageno
     \doinitializecolumntextareas\columnrightareas\v!rechts
   \else
     \doinitializecolumntextareas\columnleftareas\v!links
   \fi}

\def\doinitializecolumntextareas#1#2%
  {\def\docommando##1%
     {\doifelsevalue{\??mt##1#2\c!status}\v!start
        {\dodoinitializecolumntextareas{##1}{#2}}
        {\doifvalue{\??mt##1#2\c!status}\v!herhaal
           {\dodoinitializecolumntextareas{##1}{#2}}}}%
   \processcommacommand[#1]\docommando}

\def\dodoinitializecolumntextareas#1#2%
  {\doOTRSETsetgridcells
     {\copy\placeholderboxd}
     {\getvalue{\??mt#1#2\c!x }}{\getvalue{\??mt#1#2\c!y }}
     {\getvalue{\??mt#1#2\c!nx}}{\getvalue{\??mt#1#2\c!ny}}
     {\copy\placeholderboxd}}

\def\placecolumntextareas
  {\ifodd\realpageno
     \doplacecolumntextareas\columnrightareas\v!rechts
   \else
     \doplacecolumntextareas\columnleftareas\v!links
   \fi}

\def\doplacecolumntextareas#1#2% global ?
  {\bgroup
   \forgetall
   \def\docommando##1%
     {\doifelsevalue{\??mt##1#2\c!status}\v!start
        {\doglobal\removefromcommalist{##1}#1%
         \dodoplacecolumntextareas{##1}{#2}}
        {\doifvalue{\??mt##1#2\c!status}\v!herhaal
           {\dodoplacecolumntextareas{##1}{#2}}}}%
   \processcommacommand[#1]\docommando
   \egroup}

\def\columntextlastbackspace{\rugwit}

% \def\dodoplacecolumntextareas#1#2%
%   {\!!counta\getvalue{\??mt#1#2\c!x}%
%    \!!countb\getvalue{\??mt#1#2\c!nx}%
%    \docalculatecolumnsetspan
%    \!!heighta\getvalue{\??mt#1#2\c!ny}\lineheight
%    % to do: met/zonder ht/dp
%    \ifnum\getvalue{\??mt#1#2\c!y}=\zerocount
%      \advance\!!heighta -\lineheight
%      \advance\!!heighta \topskip
%    \fi
%    \advance\!!heighta -\lineheight % option
%    \setbox\scratchbox\vbox
%      {\donetrue\localframed
%         [\??mt#1#2]
%         [\c!breedte=\!!widtha,\c!hoogte=\!!heighta,\c!regels=]
%         {\getvalue{\??mt#1#2}}}%
%    \!!counta\getvalue{\??mt#1#2\c!x}%
%    \!!countb\getvalue{\??mt#1#2\c!y}%
%    \advance\!!countb \getvalue{\??mt#1#2\c!ny}%
%    \advance\!!countb \minusone
%    \OTRSETsetgridcell
%      \!!counta\!!countb
%      \hbox{\clip
%        [\c!breedte=\!!widthb,\c!hoogte=\!!heighta]%
%        {\copy\scratchbox}}%
%    \ifcase\!!countc\else
%      \advance\!!counta \getvalue{\??mt#1#2\c!nx}%
%      \advance\!!counta -\!!countc
%      \advance\!!widtha -\!!widthb
%      \OTRSETsetgridcell
%        \!!counta\!!countb
%        \hbox
%          {\hskip-\namedlayoutparameter\v!oneven\c!rugwit
%           \clip
%             [\c!breedte=\!!widtha,\c!hoogte=\!!heighta,
%              \c!hoffset=\!!widthb]
%             {\copy\scratchbox}}%
%    \fi}

% beware, we have clipping offsets of 2\lineheight by default 

\def\columntextareaparameter#1%
  {\csname\??mt\currentcolumntestarea#1\endcsname}

\def\dodoplacecolumntextareas#1#2%
  {\def\currentcolumntestarea{#1#2}%
   \!!counta\columntextareaparameter\c!x
   \!!countb\columntextareaparameter\c!nx
   \docalculatecolumnsetspan
   \!!heighta\columntextareaparameter\c!ny\lineheight
   % to do: met/zonder ht/dp
   \ifnum\columntextareaparameter\c!y=\zerocount
     \advance\!!heighta -\lineheight
     \advance\!!heighta \topskip
   \fi
   \advance\!!heighta -\lineheight % option
   \setbox\scratchbox\vbox
     {\donetrue\localframed
        [\??mt\currentcolumntestarea] 
        [\c!breedte=\!!widtha,\c!hoogte=\!!heighta,\c!regels=]
        {\columntextareaparameter\empty}}%
   \!!counta\columntextareaparameter\c!x
   \!!countb\columntextareaparameter\c!y
   \advance\!!countb \columntextareaparameter\c!ny
   \advance\!!countb \minusone
   \OTRSETsetgridcell
     \!!counta\!!countb
     \hbox{\clip
       [\c!bovenoffset=\columntextareaparameter\c!clipoffset,%
        \c!onderoffset=\columntextareaparameter\c!clipoffset,%
        \c!linkeroffset=\columntextareaparameter\c!clipoffset,%
        \c!breedte=\!!widthb,%
        \c!hoogte=\!!heighta]%
       {\copy\scratchbox}}%
   \ifcase\!!countc\else
     \advance\!!counta \columntextareaparameter\c!nx
     \advance\!!counta -\!!countc
     \advance\!!widtha -\!!widthb
     \OTRSETsetgridcell
       \!!counta\!!countb
       \hbox
         {\hskip-\namedlayoutparameter\v!oneven\c!rugwit
          \clip
            [\c!bovenoffset=\columntextareaparameter\c!clipoffset,%
             \c!onderoffset=\columntextareaparameter\c!clipoffset,%
             \c!rechteroffset=\columntextareaparameter\c!clipoffset,%
             \c!breedte=\!!widtha,%
             \c!hoogte=\!!heighta,%
             \c!hoffset=\!!widthb]%
            {\copy\scratchbox}}%
   \fi}

\def\setupcolumntextareatext
  {\dotripleempty\dosetupcolumntextareatext}

\long\def\dosetupcolumntextareatext[#1][#2][#3]%
  {\ifthirdargument
     \doifelse{#2}\v!beide
       {\setvalue{\??mt#1\v!links }{#3}%
        \setvalue{\??mt#1\v!rechts}{#3}}
       {\doifelse{#2}\v!volgende
          {\doifoddpageelse
             {\setvalue{\??mt#1\v!rechts}{#3}}%
             {\setvalue{\??mt#1\v!links }{#3}}}%
          {\setvalue{\??mt#1#2}{#3}}}%
   \else
     \setupcolumntextareatext[#1][\v!volgende][{#2}]%
   \fi}

\def\docalculatecolumnsetspan
  {% \!!counta <= x
   % \!!countb <= nx
   % \!!widtha => total width
   % \!!widthb => left width
   % \!!countc => left cols
   \!!widtha\!!countb\tekstbreedte % we assume equal widths 
   \advance\!!countb \!!counta
   \advance\!!countb \minusone
   \ifnum\!!countb>\nofcolumns
     \!!countc\!!countb
     \advance\!!countc -\nofcolumns
     \!!countb\nofcolumns
   \else
     \!!countc\zerocount
   \fi
   \advance\!!counta \plusone
   \dostepwiserecurse\!!counta\!!countb\plusone
     {\advance\!!widtha\OTRSETgetparameter\c!afstand\recurselevel}%
   \!!widthb\!!widtha
   \advance\!!widthb -\!!countc\tekstbreedte
   \ifodd\realpageno \else % tricky, assumes that we keep there 
     \ifcase\!!countc\else
       % nog niet ok voor enkel/dubbelzijdig
       \advance\!!widtha \namedlayoutparameter\v!even  \c!rugwit
       \advance\!!widtha \namedlayoutparameter\v!oneven\c!rugwit
       \advance\!!widthb \namedlayoutparameter\v!even  \c!rugwit
       \dorecurse\!!countc
         {\advance\!!widtha\OTRSETgetparameter\c!afstand\recurselevel}%
     \fi
   \fi}

\def\columnsetspanhsize{\tekstbreedte}

\def\setcolumnsetspanhsize#1#2% x nx / uses counta/b
  {\!!counta#1\!!countb#2\docalculatecolumnsetspan
   \edef\columnsetspanhsize{\the\!!widtha}}

\def\definecolumnsetspan
  {\dodoubleempty\dodefinecolumnsetspan}

\def\dodefinecolumnsetspan[#1][#2]%
  {%\ifsecondargument
     \defineframedtext
       [cs:#1]
       [\c!kader=\v!uit,
        \c!voor=,
        \c!na=,
        \c!offset=\v!overlay,
        \c!plaats=\v!links,
        \c!regelcorrectie=\v!uit,
        \c!dieptecorrectie=\v!uit,
        \c!n=2,
        \c!nregels=0,
        \c!springvolgendein=\v!ja,
        \c!default=HERE,
        \c!variant=\v!a,
        #2]%
   %\else
   %  \definecolumnspan[][#1]%
  }%\fi}

\def\setupcolumnsetspan
  {\dodoubleempty\dosetupcolumnsetspan}

\def\dosetupcolumnsetspan[#1][#2]%
  {%\ifsecondargument
     \setupframedtexts[cs:#1][#2]%
   %\else
   %  \setupcolumnsetspan[][#1]%
  }%\fi}

\def\startcolumnsetspan
  {\dotripleempty\dostartcolumnsetspan}

%%%%%%%%%%%%%%%% TODO

\def\dostartcolumnsetspan[#1][#2][#3]% [#3] gobbles space
  {\endgraf % else rubish output if forgotten
   \vskip \zeropoint % make sure otr is done, otherwise last line problems 
   \bgroup
\forgetall
   \setupframedtexts[cs:#1]
     [\c!breedte=\columnsetspanhsize,
      \c!regelcorrectie=\v!uit,
      \c!dieptecorrectie=\v!uit,
      #2]%
   % determine widths 
   \!!countc\framedtextparameter{cs:#1}\c!n
    % \!!countd\numexpr(\nofcolumns-\mofcolumns+\plusone)%
   \!!countd\nofcolumns
   % n <= n of columns 
   \ifnum\!!countc>\!!countd \!!countc\!!countd \fi   
   \advance\!!countd -\mofcolumns
   \advance\!!countd \plusone
   % n <= n of available columns (alternative a)
   \doif{\framedtextparameter{cs:#1}\c!variant}\v!a
     {\ifnum\!!countc>\!!countd \!!countc\!!countd \fi}%
   % here it all starts 
   \setcolumnsetspanhsize\mofcolumns\!!countc % a/b used
   \hsize\columnsetspanhsize
   \setbox\scratchbox\vbox\bgroup
     \dostartframedtext[cs:#1][\v!geen]% geen nils placement 
     \vskip-\lineheight\par\strut\par
     \framedtextparameter{cs:#1}\c!voor
     \def\stopcolumnsetspan{\dostopcolumnsetspan{#1}}}

% \chardef\columnslotlocation2

% \def\dostopcolumnsetspan#1%
%   {\par
%    \vbox{\strut}
%    \kern-2\lineheight 
%    \vbox{\strut}
%    \doifsomething{\framedtextparameter{cs:#1}\c!na}
%      {\framedtextparameter{cs:#1}\c!na
%       \kern\zeropoint}% otherwise blanks disappear, better be a switch
%    \dostopframedtext 
%    \egroup
%    \setbox\scratchbox\frozenhbox % keeps grid snapping okay 
%      {\lower\strutdepth\box\scratchbox}%
%    %todo: nboven/onder\chardef\columnslotlocation2
%    %\OTRSETstoreincolumnslotSOMEWHERE\columnslotlocation\scratchbox
%    \chardef\columnslotspacing\framedtextparameter{cs:#1}\c!nregels\relax
%    \OTRSETstoreincolumnslotSOMEWHERE2\scratchbox
%    \doif{\framedtextparameter{cs:#1}\c!springvolgendein}\v!nee
%      \noindentation
%    \egroup
%    \endgraf}

\def\dostopcolumnsetspan#1%
  {\par
   \vbox{\strut}
   \kern-2\lineheight 
   \vbox{\strut}
   \doifsomething{\framedtextparameter{cs:#1}\c!na}
     {\framedtextparameter{cs:#1}\c!na
      \kern\zeropoint}% otherwise blanks disappear, better be a switch
   \dostopframedtext 
   \egroup
   % frozen keeps grid snapping okay 
   \setbox\scratchbox\frozenhbox to \hsize
     {\dontcomplain
      \doregelplaats{\framedtextparameter{cs:#1}\c!plaats}%
        {\lower\strutdepth\box\scratchbox}}%
   \dp\scratchbox\zeropoint % else wrong snap insidefloat 
   \ifinsidefloat 
     \box\scratchbox
   \else
     % we only set \columnsetspacing when asked for, else bottom problems 
     % don't change this any more (test naw) 
     \chardef\columnslotspacing\framedtextparameter{cs:#1}\c!nregels\relax
     % todo: nboven/onder & \chardef\columnslotlocation2
     %\OTRSETstoreincolumnslotHERE\scratchbox
     \edef\floatmethod{\framedtextparameter{cs:#1}\c!default}%
     \@EA\uppercasestring\floatmethod\to\floatmethod
     % todo : \v!hier -> here enzovoorts 
     \OTRSETstoreincolumnslot\floatmethod\scratchbox
     \doif{\framedtextparameter{cs:#1}\c!springvolgendein}\v!nee
       \noindentation
   \fi
   \egroup
   \endgraf}

% \startcolumnset[two]
%   \input tufte
%   \startcolumnsetspan[two][width=20cm,location=middle] \input tufte \stopcolumnsetspan
%   \startcolumnsetspan[two][default=btlr] \input tufte \stopcolumnsetspan
%   \input tufte \par
%   \input tufte \par
%   \startcolumnsetspan[two] \emptylines[5] \stopcolumnsetspan
%   \startcolumnsetspan[two] \input tufte   \stopcolumnsetspan
% \stopcolumnset

\protect \endinput
