page-set.tex / last modification: 2008-10-13 12:17
%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 and go etex

\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
% todo : leftmargin/rightmargin (better than afstand(1))

% use the OTRSET layer for more purposes, like the footnotes !

\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\OTRSETmakeupwidth{\innermakeupwidth}

\let\OTRSETflushsidefloats      \forgetsidefloats % \relax
\let\OTRSETsynchronizesidefloats\forgetsidefloats % \relax

\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%
  {\relax\ifvoid\csname\@otr@:\number#1:\number#2\endcsname
     \@EA\secondoftwoarguments\else\@EA\firstoftwoarguments
   \fi}

% The following two macros are used to compensate for a switch in body fonts
% as in:
%
% \definecolumnset [two]  [n=2,balancing=yes]
% \definecolumnset [three] [n=3,balancing=yes]
%
% \setupcolumnsetlines[two][1][1][7]
% \setupcolumnsetlines[two][1][2][10]
%
% \setupcolumnsetlines[three][1][1][40]
% \setupcolumnsetlines[three][1][2][40]
% \setupcolumnsetlines[three][1][3][40]
%
% \setupcolumnsetstart[three][1][1][15]
% \setupcolumnsetstart[three][1][2][20]
% \setupcolumnsetstart[three][1][3][20]
%
% \starttext
%   \startcolumnset [two] \dorecurse {1}{\input tufte \par} \stopcolumnset
%   \switchtobodyfont[small]
%   \startcolumnset [three] \dorecurse {1}{\input tufte \par} \stopcolumnset
% \stoptext

%D Marks in columnsets:
%D
%D \starttyping
%D \definemarking[M]
%D \setupheadertexts[\setups{show-M-marks}]
%D \definecolumnset[test][n=3]
%D
%D \startsetups show-M-marks
%D \getmarking[M][1][previous]/\getmarking[M][1][first]/\getmarking[M][1][last]\quad
%D \getmarking[M][2][previous]/\getmarking[M][2][first]/\getmarking[M][2][last]\quad
%D \getmarking[M][3][previous]/\getmarking[M][3][first]/\getmarking[M][3][last]\quad
%D \getmarking[M][1][previous]/\getmarking[M][1][first]/\getmarking[M][last]\quad
%D \getsavedmarking[M][previous]/\getsavedmarking[M][first]/\getsavedmarking[M][last]
%D \stopsetups
%D
%D \startbuffer
%D \section{Knuth} [K1]\marking[M]{k1} [K2]\marking[M]{k2} \input knuth
%D \section{Zapf}  [Z]\marking[M]{z} \input zapf
%D \stopbuffer
%D
%D \startbuffer
%D \section{Ward} [W]\marking[M]{w} \input ward
%D \placefigure[here]{none}{\externalfigure[a][height=2cm]}
%D \section{Davis} [D]\marking[M]{d} \input davis
%D \section{Zapf} [Z]\marking[M]{z} \input zapf
%D \stopbuffer
%D
%D \startbuffer
%D \section{Ward} [W]\marking[M]{w} \input ward
%D \placefigure[here]{none}{\externalfigure[a][height=2cm]}
%D \section{Davis} [D]\marking[M]{d} \input davis
%D \section{Zapf} [Z]\marking[M]{z} \input zapf
%D \section{Douglas} [O]\marking[M]{o} \input douglas
%D \stopbuffer
%D
%D \starttext
%D   \startcolumnset[test]
%D     \dorecurse{5}{\getbuffer}
%D     \placefigure[here]{none}{\externalfigure[a][height=2cm]}
%D     % \column % sometimes needed
%D   \stopcolumnset
%D \stoptext
%D \stoptyping

% not ok yet, for column sets we need a special case: within a column we
% need to bubble-up the marks; the indirectness permits overloading here

\let\saveOTRSETmark  \refreshsavedmark
\let\bubbleOTRSETmark\bubblesavedmark
\let\resetOTRSETmark \resetsavedmark
\let\presetOTRSETmark\presetsavedmark

\def\doregisterOTRSETmarks#1{\saveOTRSETmark  [#1][\number\mofcolumns]}
\def\dobubbleOTRSETmarks  #1{\bubbleOTRSETmark[#1][\number\mofcolumns]}
\def\doresetOTRSETmarks   #1{\resetOTRSETmark [#1][\recurselevel]}
\def\dopresetOTRSETmarks  #1{\presetOTRSETmark[#1][\recurselevel]}

\def\registerOTRSETmarks
  {\processcommacommand[\alldefinedmarks]\doregisterOTRSETmarks}
\def\bubbleOTRSETmarks
  {\processcommacommand[\alldefinedmarks]\dobubbleOTRSETmarks}
\def\resetOTRSETmarks
  {\dorecurse\nofcolumns{\processcommacommand[\alldefinedmarks]\doresetOTRSETmarks}}
\def\presetOTRSETmarks
  {\dorecurse\nofcolumns{\processcommacommand[\alldefinedmarks]\dopresetOTRSETmarks}}

%D test case of Vit Zika (context list):
%D
%D \starttyping
%D \setuplayout[height=middle,width=middle,grid=yes]
%D
%D \starttext
%D   \startcolumnset
%D     \dorecurse{10}
%D       {\input thuan \endgraf
%D        \bgroup
%D        \ss\restoreinterlinespace
%D        \dorecurse{3}{\input hawking \endgraf}
%D        \egroup
%D        \input bryson \endgraf}
%D   \stopcolumnset
%D \stoptext
%D \stoptyping

\def\OTRSETsetcorrectnofcells#1%
  {\bgroup
   \!!counta#1\relax
   \ifdim\globalbodyfontsize=\localbodyfontsize
     \restoreinterlinespace
   \else
     \!!dimena-\!!counta\lineheight
     \restoreglobalbodyfont % slow, we need a fast one
     \advance\!!dimena\!!counta\lineheight
     \getnoflines\!!dimena
     \advance\!!counta\noflines
     \ifnum\!!counta<#1\else
       \!!counta#1\relax
     \fi
   \fi
   \relax % needed ! ! ! ! else lookahead over \fi and \@EA
   \@EA\egroup\@EA\scratchcounter\the\!!counta\relax}

\def\OTRSETsetcorrectcellht
  {\bgroup
   \!!dimena-\strutht\relax
   \ifdim\globalbodyfontsize=\localbodyfontsize
     \restoreinterlinespace
   \else
     \restoreglobalbodyfont
   \fi
   \advance\!!dimena\strutht
   \relax % needed ! ! ! ! else lookahead over \fi and \@EA
   \@EA\egroup\@EA\scratchdimen\the\!!dimena\relax}

\def\columnerasegridboxes % maybe dedicated loops
  {\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}

\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\setupcolumnsetlines{\doquintupleempty\dosetupcolumnsettrick[l]}
\def\setupcolumnsetstart{\doquintupleempty\dosetupcolumnsettrick[s]}

\def\dosetupcolumnsettrick[#1][#2][#3][#4][#5]% tag id page col value
  {% not needed, is already relative
   % \doifinstringelse{+}{#3}{\scratchcounter\realpageno}{\scratchcounter\zerocount}%
   % \advance\scratchcounter#3\relax % \relax needed
   % \setevalue{\??mc:#1:#2:\the\scratchcounter:\number#4}{\number#5}}
   \iffifthargument
     \setevalue{\??mc:#1:#2:\number#3:\number#4}{\number#5}%
   \else
     \setevalue{\??mc:#1:#2:\number#3:0}{\number#4}%
   \fi}

\def\currentcolumnmaxcellstag #1{\??mc:l:\OTRSETidentifier:\columnsetpage:\number#1}
\def\currentcolumnstartcelltag#1{\??mc:s:\OTRSETidentifier:\columnsetpage:\number#1}

\def\doresetcolumnsetlines#1%
  {\ifcsname\currentcolumnmaxcellstag{#1}\endcsname
     \letgvalue{\currentcolumnmaxcellstag{#1}}\zerocount
   \fi
   \ifcsname\currentcolumnmaxcellstag{#1}\endcsname
     \letgvalue{\currentcolumnmaxcellstag{#1}}\zerocount
   \fi}

\def\currentcolumnsomecells#1#2%
  {\ifcsname#1\mofcolumns\endcsname
     \ifnum\csname#1\mofcolumns\endcsname=\zerocount
       #2%
     \else
       \number\numexpr(\ifnum\csname#1\mofcolumns\endcsname<\zerocount
         \columnmaxcells+\fi\csname#1\mofcolumns\endcsname)%
     \fi
   \else\ifcsname#10\endcsname
     \ifnum\csname#10\endcsname=\zerocount
       #2%
     \else
       \number\numexpr(\ifnum\csname#10\endcsname<\zerocount
         \columnmaxcells+\fi\csname#10\endcsname)%
     \fi
   \else
     #2%
   \fi\fi}

\def\currentcolumnmaxcells {\currentcolumnsomecells\currentcolumnmaxcellstag \columnmaxcells}
\def\currentcolumnstartcell{\currentcolumnsomecells\currentcolumnstartcelltag\plusone}

\def\OTRSETsetfreecells#1#2% col start
  {\bgroup
   \global\columnfirstcell\ifnum#2=0 1\else#2\fi\relax
   \OTRSETsetcorrectnofcells\currentcolumnmaxcells % sets \scratchcounter
   \edef\columnmaxcells{\the\scratchcounter}%
   \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
   \egroup}

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

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

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

\def\OTRSETmakeupwidth{\makeupwidth} % temporary indirectness

\def\OTRSETdomakegridbox#1#2#3%
  {\hbox\bgroup
   \dontcomplain
   \forgetall % can go once in \flush
   \!!heighta \textheight
   % test first !
   \hbox to \OTRSETmakeupwidth
     {\dostepwiserecurse{#1}{#2}{#3}
        {\mofcolumns\recurselevel
         \localcolumnwidth\OTRSETlocalwidth\mofcolumns
         \setbox\scratchbox\hbox\localframed
           [\??mc\OTRSETidentifier\number\mofcolumns]%
           [\c!width=\localcolumnwidth,\c!height=\!!heighta,\c!lines=]%
           {}%
         \wd\scratchbox\localcolumnwidth
         \ht\scratchbox\!!heighta
         \ifcase\columndirection
           \hskip\OTRSETgetparameter\c!distance\recurselevel
           \box\scratchbox
         \else
           \box\scratchbox
           \hskip\OTRSETgetparameter\c!distance\recurselevel
         \fi}}%
   \hskip-\OTRSETmakeupwidth
   % main text
   \hbox to \OTRSETmakeupwidth
     {\dostepwiserecurse{#1}{#2}{#3}
        {\mofcolumns\recurselevel
         \localcolumnwidth\OTRSETlocalwidth\mofcolumns
         \offinterlineskip
         \setbox\scratchbox\vbox to \!!heighta
           {\topskipcorrection % not needed
            \ifcase\OTRSETbalancemethod
              % no
            \or
              % yes
              \doifelselayerdata{OTRTEXT}\vfill\relax % temp hack
            \or
              % top
            \or
              % bottom
              \vfill
            \fi
            \dorecurse\columnmaxcells
              {\setbox\scratchbox\hbox{\OTRSETgetgridcell\mofcolumns\recurselevel}%
%               {\setbox\scratchbox\hbox
%                  {\localstarttextcolor
%                   \OTRSETgetgridcell\mofcolumns\recurselevel
%                   \localstoptextcolor}%
               \ht\scratchbox\strutht
               \dp\scratchbox\strutdp
               \ifcase\columndirection
                 \box\scratchbox
               \else
                 \hbox to \localcolumnwidth
                   {\hskip\localcolumnwidth\llap{\box\scratchbox}}%
               \fi
               \par}%
            \ifcase\OTRSETbalancemethod
              % no
            \else
              % yes, top, bottom
              \ifdim\globalbodyfontsize=\localbodyfontsize
                \removedepth
                \restoreglobalbodyfont
                \vskip\strutdepth
              \fi
              \kern\zeropoint
              \vss
            \fi}%
         \wd\scratchbox\localcolumnwidth % \textwidth
         \ifcase\columndirection
           \hskip\OTRSETgetparameter\c!distance\recurselevel\box\scratchbox
         \else
           \box\scratchbox\hskip\OTRSETgetparameter\c!distance\recurselevel
         \fi}}%
   \egroup}

\let\OTRSETbalht\zeropoint

\def\OTRSETreducegridbox % for the moment no difference between methods
  {\globallet\OTRSETbalht\zeropoint
   \ifcase\OTRSETbalancemethod
     % no balancing
   \else
     \bgroup
     \!!counta\columnmaxcells
     \donetrue
     \doloop
       {\dorecurse\nofcolumns{\OTRSETdoifcellelse\recurselevel\!!counta\donefalse\donothing}%
        \ifdone
          \ifnum\!!counta>\plusone\advance\!!counta\minusone\else\exitloop\fi
        \else
          \exitloop
        \fi}%
     \ifnum\!!counta>\plusone
       \!!heighta\lineheight
       \multiply\!!heighta \!!counta
       \advance\!!heighta \topskip
       \advance\!!heighta -\lineheight
     \else
       \!!heighta\zeropoint
     \fi
     \xdef\OTRSETbalht{\the\!!heighta}%
     \egroup
   \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\strutht
       \dp\scratchbox\strutdp
       \OTRSETsetgridcell\nofcolumns\lastcolumnlastcell\box\scratchbox
     \fi
     \global\lastcolumnlastcell\zerocount
   \fi}

\def\OTRSETdoflush
  {\ifcollectingcontent
     \registerOTRSETmarks
     \global\mofcolumns\plusone
   \else
     \OTRSETdofinalflush
     \OTRSETdofinaloutput
     \ifnum\columnsetpage>0
       \dorecurse\nofcolumns{\doresetcolumnsetlines\recurselevel}%
     \fi
     \doglobal\increment\columnsetpage
     \OTRSETinitializecolumns
    %\OTRSETdoflushfloats
     \OTRSETstartnextpage
\presetOTRSETmarks
     \initializecolumntextareas
   \fi}

\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
%      \ifcase\OTRSETbalancemethod
%        \finaloutput\box\OTRfinalpagebox
%      \else\ifdim\OTRSETbalht>\zeropoint
%        \global\setbox\OTRfinalpagebox \iftracecolumnset\ruledvbox\else\vbox\fi to \OTRSETbalht
%          {\box\OTRfinalpagebox}%
%        \global\dp\OTRfinalpagebox\strutdepth
%        \box\OTRfinalpagebox
%      \else
%        \finaloutput\box\OTRfinalpagebox
%      \fi \fi
%      \globallet\OTRSETbalht\zeropoint
%    % \egroup
%    \fi}

\def\OTRSETdofinaloutput
  {\ifdim\ht\OTRfinalpagebox=\textheight
    \bgroup % \let\OTRSETsetvsize\relax % prevents useless search for gap
     \ifcase\OTRSETbalancemethod
       \finaloutput\box\OTRfinalpagebox
     \else\ifdim\OTRSETbalht>\zeropoint
       % catch a bordercase
       \scratchdimen\OTRSETbalht
       \advance\scratchdimen\lineheight\relax
       \ifdim\scratchdimen>\textheight
         % full page
         \finaloutput\box\OTRfinalpagebox
       \else
         % same page
         \global\setbox\OTRfinalpagebox \iftracecolumnset\ruledvbox\else\vbox\fi to \OTRSETbalht
           {\box\OTRfinalpagebox\vss}%
         \setlayer[OTRTEXT]{\box\OTRfinalpagebox}%
         \snaptogrid\vbox{\vskip\OTRSETbalht}% hack
       \fi
     \else
       \finaloutput\box\OTRfinalpagebox
     \fi \fi
     \globallet\OTRSETbalht\zeropoint
    \egroup
   \fi}

\definesystemvariable {mc}
\definesystemvariable {mt}
\definesystemconstant {colset}

\definetwopasslist\s!colset

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

\newtoks   \OTRSEToutput

\def\OTRSETgetparameter#1#2{\csname\??mc\OTRSETidentifier\number#2#1\endcsname}
\def\OTRSETsetparameter#1#2{\setvalue{\??mc\OTRSETidentifier\number#2#1}}

\def\OTRSETskipstart
  {\scratchcounter\executeifdefined{\??mc\OTRSETidentifier\c!start}\zerocount
   \relax % needed !
   \ifcase\scratchcounter\else
     \advance\scratchcounter\plusone
     \doOTRSETsetgridcells
       {\copy\placeholderboxe}
       \plusone\plusone\nofcolumns\scratchcounter
       \null
   \fi}

\def\OTRSETsetvsize % snap per sectie (gap here?)
  {\ifcollectingcontent \else % can be assigndimen
\OTRSETskipstart % not that well tested
     \OTRSETcheckinsert % added
     \OTRSETsetfreecells\mofcolumns\columnfirstcell
     \ifsomefreecolumncells
       \global\vsize\columnfreecells\lineheight
       \ifinotr % else problems with floats, see extreme
         \global\pagegoal\vsize % niet nodig, tenzij binnen otr
       \fi
       \synchronizeoutput % fails on example
      % \allowbreak % hm
     \fi
     \synchronizenotes
   \fi}

\def\OTRSETsethsize % of course this does not migrate outside the otr
  {\localcolumnwidth\OTRSETlocalwidth\mofcolumns
   \textwidth\localcolumnwidth
   \hsize\localcolumnwidth}

\def\OTRSETsynchronizehsize
  {\ifcase0\getvalue{\??mc\??mc\c!width}\else % some width set
     \bgroup
     \scratchdimen\OTRSETlocalwidth\mofcolumns
     \ifdim\scratchdimen=\textwidth
       \egroup
     \else
       % only if change in width and \column/\break
       \egroup \OTRSETsethsize
     \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!local
  {\OTRSETcolumnhbreak
   \ejectinsert
   \ejectpage % brrr
   % no \OTRSETsethsize, can be mid smaller (like tabulate)
   % also, this one should be executed at the outer level
   % (setting hsize inside otr does not work)
   \OTRSETsynchronizehsize}

% 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!yes
  {\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!page
  {\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\e