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

\beginETEX \ifcsname

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

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

\beginTEX

  \def\doresetcolumnsetlines#1%
    {\ifundefined{\currentcolumnmaxcellstag{#1}}\else
       \letgvalue{\currentcolumnmaxcellstag{#1}}\zerocount
     \fi
     \ifundefined{\currentcolumnmaxcellstag{#1}}\else
       \letgvalue{\currentcolumnmaxcellstag{#1}}\zerocount
     \fi}

  \def\currentcolumnsomecells#1#2%
    {\expandafter\ifx\csname#1\mofcolumns\endcsname\relax
       \expandafter\ifx\csname#10\endcsname\relax
         #2%
       \else
         \ifnum\csname#10\endcsname=\zerocount
           #2\else\csname#10\endcsname
         \fi
       \fi
     \else
       \ifnum\csname#1\mofcolumns\endcsname=\zerocount
         #2\else\csname#1\mofcolumns\endcsname
       \fi
     \fi}

\endTEX

\beginETEX \numexpr

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

\endETEX

\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\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
     \OTRSEThandleflushedtext\zerocount
     \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\strutdp
      \unvbox\normalpagebox
      \vfill}%
   \setbox2\hbox
     {\OTRSETplacebottomnotes}%
   \setbox\scratchbox\hbox
     {\wd0\zeropoint\box0\box2}%
   \dp\scratchbox\strutdp
   \OTRSEThandleflushedtext\plusone
   \egroup}

\newcount\lastcolumnlastcell

\def\OTRSEThandleflushedtext#1%
  {\getnoflines{\ht\scratchbox}%
  %\wd\scratchbox\textwidth % geen \hsize kan < zijn in bv split tabulate
   \wd\scratchbox\OTRSETlocalwidth\mofcolumns
   \doOTRSETsetgridcells
     {\copy\placeholderboxf}
     \mofcolumns\columnfirstcell\plusone\noflines
     {\registeredtextarea1\columnfirstcell\scratchbox}% == \hbox / tricky htcorr == \columnfirstcell
   \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
     \bubbleOTRSETmarks % not robust because we reenter
   \else
     \registerOTRSETmarks % not robust because we reenter
     \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\scaledpoint>\scratchdimen
       \egroup
     \else\ifdim10\scaledpoint<\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!distance\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
   \OTRSETcheckprefered
   \OTRSETstoreincolumnslotindeed
     \nofcolumns\qofcolumns-\currenthcell
     \plusone\columnmaxcells+\currentvcell{#1}}

\def\OTRSETstoreincolumnslotRLBT#1%
  {\OTRSETprepareforcolumnslot3{#1}%
   \OTRSETflushtextsofar
   \OTRSETcheckprefered
   \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
   \OTRSETcheckprefered
   \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
   \OTRSETcheckprefered
   \OTRSETstoreincolumnslotindeed
     \columnmaxcells\plusone-\currentvcell
     \nofcolumns\qofcolumns-\currenthcell{#1}}

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

\def\OTRSETstoreincolumnslotFXBT#1% fixed column
  {\OTRSETcheckprefered
   \OTRSETdoifcellelse\pofcolumns\columnmaxcells
     {\OTRSETprepareforcolumnslot2}{\OTRSETprepareforcolumnslot3}{#1}% % 3/2 dependent of 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}

% this one looses too wide graphics
%
% \def\OTRSETstoreincolumnslotFIXD#1% fixed column
%   {\OTRSETprepareforcolumnslot2{#1}%
%    % no flush text sofar here, beware: no width test
%    \snaptogrid\vbox{\box#1}}
%
% still imperfect

\def\OTRSETstoreincolumnslotFIXD#1% fixed column
  {\OTRSETflushtextsofar
   \ifdim\wd#1>\textwidth
     \OTRSETstoreincolumnslotSOMEWHERE2{#1}%
   \else
     % crappy test / needed for o-pbu-f / will be replaced
     \getnoflines{\ht#1}%
     \scratchdimen\noflines\lineheight
     \advance\scratchdimen\lineheight
     \advance\scratchdimen\pagetotal\relax
     \ifdim\scratchdimen<\pagegoal
       %OTRSETprepareforcolumnslot3{#1}%
       %ruledvskip\columnslotspacing\lineheight
       \blank[\columnslotspacing*\v!line]%
       \snaptogrid\hbox to \hsize{\hss\box#1\hss}% strange, why the centering
       \blank[\columnslotspacing*\v!line]%
     \else
       \OTRSETstoreincolumnslotSOMEWHERE2{#1}%
     \fi
   \fi}

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

\def\OTRSETcheckprefered
  {\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}

\def\OTRSETstoreincolumnslotindeed#1#2#3#4#5#6#7#8#9%
  {\OTRSETcheckprefered
   \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\OTRSETprepareforcolumnslot#1#2% 1=hoog 2=midden 3=laag
  {\dp#2\zeropoint
   \ifcase\columnslotspacing\else
     \scratchdimen\columnslotspacing\lineheight
     \ifnum#1=2 \scratchdimen2\scratchdimen \fi
     \begingroup
     \advance\scratchdimen\ht#2\relax
     \ifdim\scratchdimen<\columnmaxcells\lineheight
       \endgroup \setbox#2\vbox spread \scratchdimen \bgroup
     \else
       \endgroup \setbox#2\vbox to \columnmaxcells\lineheight \bgroup
       \vskip\strutdepth
     \fi
     \ifnum#1>1\vss\fi
     \box#2\relax
     \ifnum#1<3\vss\fi
     \egroup
   \fi}

\def\OTRSETdocheckiffloatfits % eigenlijk moet else float anders
  {\global\ifnofloatpermitted\roomforfloatfalse\else\roomforfloattrue\fi}

\def\OTRSETunpreparebox#1%
  {\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}

\def\OTRSETsavebox#1% clean up the skips
  {\OTRSETunpreparebox{#1}%
   \dosavefloat}

\def\OTRSETresavebox#1% clean up the skips
  {\OTRSETunpreparebox{#1}%
   \doresavefloat}

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

\def\OTRSETdoflushfloats
  {\bgroup
   \def\OTRSETsavebox##1{\!!doneafalse}%
   \doloop
     {\ifsomefloatwaiting
\OTRSETskipstart
        \dogetfloat
        \ifdim\wd\floatbox>\zeropoint
          \!!doneatrue
          \dp\floatbox\zeropoint
          \OTRSETstoreincolumnslot{TBLR}\floatbox
          \if!!donea
           %\message{[flu]}%
          \else
            \OTRSETresavebox\floatbox
            \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!distance\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!nright}%
     \global\lofcolumns\getvalue{\??mc\OTRSETidentifier\c!nleft}%
     \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!direction=\v!right,
      \c!balance=\v!no,
      \c!distance=1.5\bodyfontsize, % controleren
      \c!n=2,
      \c!nleft=\getvalue{\??mc#1\c!n},
      \c!nright=\getvalue{\??mc#1\c!n},
      \c!width=\v!fit,
      \c!lines=0,
      \c!start=0,
      #2]%
   \dorecurse{\getvalue{\??mc#1\c!nleft}} % todo
     {\dododefinecolumnset[#1][\recurselevel]}%
   \dorecurse{\getvalue{\??mc#1\c!nright}} % todo
     {\dododefinecolumnset[#1][\recurselevel]}%
   % redo framed settings
   \setupcolumnset[#1][1][\c!distance=\!!zeropoint]}

\def\dododefinecolumnset[#1][#2]%
  {\presetlocalframed
     [\??mc#1#2]%
   \setupcolumnset
     [#1][#2]
     [\c!offset=\v!overlay,
      \c!frame=\v!off,
      \c!align=,
      \c!lines=0,% really needed since c!regels is now part of framed
      \c!width=\getvalue{\??mc#1\c!width},
      \c!distance=\getvalue{\??mc#1\c!distance}]}

\def\setupcolumnset
  {\dotripleargument\dosetupcolumnset}

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

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

\def\doOTRSETgotoCOLROW#1% <number>|<number>*<number>
  {\bgroup % really needed
   \splitstring#1\at*\to\column\and\row
   \bgroup
     \ifx\column\empty\else\expanded{\doOTRSETgotoCOLUMN{\column}}\fi
   \egroup
   \bgroup
     \ifx\row   \empty\else\expanded{\doOTRSETgotoROW   {\row   }}\fi
   \egroup
   \egroup}

\def\doOTRSETgotoCOLUMN#1%
  {\ifnum\mofcolumns=#1\else
     \vfill\eject % \doejectpage\eject
     \doloop
       {\ifnum\mofcolumns=#1\relax
          \exitloop \else \OTRSETdummycolumn
        \fi}%
   \fi}

\def\doOTRSETgotoROW#1%
  {\ifnum#1>1
     \scratchcounter\zerocount
     \currenthcell\mofcolumns
     \currentvcell#1\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
   \OTRSETsetvsize}

\def\doOTRSETgotocolumn[#1]% yes|force|first|last|<number>|<number>*<number>
  {\processallactionsinset
     [#1]
     [    \v!yes=>\OTRSETdummycolumn,
           \v!no=>,% not supported
        \v!force=>\OTRSETdummycolumn,
        \v!first=>\expanded{\doOTRSETgotoCOLUMN{1}},
         \v!last=>\expanded{\doOTRSETgotoCOLUMN{\the\nofcolumns}},
      \s!default=>\OTRSETdummycolumn,
      \s!unknown=>\expanded{\doOTRSETgotoCOLROW{\commalistelement}}]}

% 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\OTRSETgotocell#1#2% obsolete: now \column[#1*#2]
  {\endgraf
   \doOTRSETgotoCOLUMN{#1}%
   \doOTRSETgotoROW   {#2}}

\def\OTRSETdummycolumn
  {\verticalstrut
   \vskip-\struttotal
   \vfill
   \eject}

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

\def\startcolumnset
  {\dodoubleempty\dostartcolumnset}

\def\dostartcolumnset[#1][#2]%
  {\increment\columnsetlevel\relax
   \globallet\localcolumnmaxcells\!!zerocount
   \global\chardef\OTRSETfinish\zerocount
   \resetOTRSETmarks
   \ifnum\columnsetlevel=\plusone
     \bgroup
     \saveinterlinespace
     \globallet\columnsetpage\!!plusone
     \def\currentcolumnset{#2}%
     \insidecolumnstrue % will be different flag in addition
     \activateotr{SET}{ONE}% andere naam, activate or so
     \doifelsenothing{#1}
       {\globallet\OTRSETlist\s!default}
       {\xdef\OTRSETlist{#1}}%
     \OTRSETstartnextpage
     \OTRSETassignwidths
     \OTRSETsethsize
   \else
     \bgroup
   \fi}

% \setuplayout[grid=yes] \definecolumnset[example] \showgrid

% \starttext
%     \startcolumnset[example]
%         \input knuth \endgraf \input knuth
%         \placetable{table}{\framed[width=\makeupwidth,height=4cm]{Hello}}
%         \input knuth \endgraf \input knuth
%     \stopcolumnset
%     \input knuth \endgraf \input knuth
% \stoptext


\def\OTRSETflushleftovers % new per 13/4/2006
  {\OTRSETdoifcellelse{1}{1}
     {\bgroup
      \OTRSETcentergridcells
      \chardef\OTRSETbalancemethod\plusone
      \OTRSETreducegridbox
      \global\setbox\OTRfinalpagebox\OTRSETmakegridbox
      \global\ht\OTRfinalpagebox\textheight % signals output that there is content
      \OTRSETdofinaloutput
      \globallet\OTRSETbalht\zeropoint
      \egroup}
     {}}

\def\stopcolumnset
  {\relax
   \ifnum\columnsetlevel=\plusone
     \endgraf % needed, else wrong vsize in one par case
     \global\chardef\OTRSETfinish\plusone
     % no, extra page \pagebreak % (test on pascal toc)
     \dostopcolumnset
     \egroup
     \global\notelimittrue % brrr, untested and fuzzy
     \setvsize
     \sethsize
     \ifvoid\OTRfinalpagebox\else
       % probably balanced
       \ifdim\ht\OTRfinalpagebox<\textheight
         \snaptogrid[\v!page]\hbox{\box\OTRfinalpagebox}%
       \else
         \box\OTRfinalpagebox
       \fi
     \fi
     \global\chardef\OTRSETfinish\zerocount
     \ifsomefloatwaiting \setvsize \pagebreak \setvsize \fi
     \OTRSETflushleftovers
   \else
     \egroup
   \fi
   \decrement\columnsetlevel\relax}

\chardef\OTRSETbalancemethod\zerocount

\def\dostopcolumnset
  {%\OTRSETdofinalflushfloats % yes/no
   \ifcase\OTRSETbalancemethod
     \OTRSETnobalance
   \else
     \OTRSETdobalance
   \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

% \def\OTRSETinitbalancing
%   {\ifcase\OTRSETbalancemethod\or
%      \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
%             \ifnum\OTRSETbalancemethod=\plusthree
%               \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\docommand##1%
%            {\advance\scratchcounter\plusone
%             \setvalue{\??mc\OTRSETidentifier\the\scratchcounter\c!regels}{##1}}%
%          \processcommacommand
%            [\csname\??mc\OTRSETidentifier\c!regels\endcsname]\docommand
%          \setvalue{\??mc\OTRSETidentifier\c!regels}{0}%
%        \fi}}

% don't loose empty 1page/1column with area (example **)
%
% \definecolumntextarea[title][x=1,y=4,nx=2,ny=7,state=start]
% \setupcolumntextareatext[title][\vtop to 5cm{a\\b\\b\\d}]
%
% \starttext
% \startcolumnset \dorecurse{1}{\input tufte \par} \stopcolumnset
% \stoptext

% better:

\def\definecolumnsetarea   {\definecolumntextarea}
\def\setupcolumnsetarea    {\setupcolumntextarea}
\def\setupcolumnsetareatext{\setupcolumntextareatext}

% so this will be changed

% \def\OTRSETnobalance
%   {\iflastcolumnfootnotes % testen ! optie
%      % inhibit flush of floats !
%      % todo: nothing if no footnotes, else empty page
%      \dostepwiserecurse\mofcolumns\nofcolumns\plusone
%        {\vskip-\struttotal\verticalstrut\vfill\eject}%
%    \else
%      \ifdim\pagetotal>\zeropoint % no, see example **
%        \ifnum\mofcolumns=\nofcolumns
%          \OTRSETflushfinalfootnotes
%        \else
%          % probably todo
%        \fi
%        \vfill
%        \eject
%        % brr, may result in empty page after nicely fit text
%        % or if left, then lost of first column only text
%        \ifnum\mofcolumns>1
%          \OTRSETdofinalflush
%          \OTRSETdofinaloutput
%        \fi
%      \fi
%    \fi}

\def\OTRSETnobalance
  {\iflastcolumnfootnotes % testen ! optie
     % inhibit flush of floats !
     % todo: nothing if no footnotes, else empty page
     \dostepwiserecurse\mofcolumns\nofcolumns\plusone
       {\vskip-\struttotal\verticalstrut\vfill\eject}%
   \else
     \ifnum\mofcolumns>\plusone
       \donetrue
     \else\ifdim\pagetotal>\zeropoint % too dangerous, we loose data
       \donetrue
     \else
       \donefalse
     \fi\fi
     \ifdone
       \ifnum\mofcolumns=\nofcolumns
         \OTRSETflushfinalfootnotes
       \else
         % probably todo
       \fi
       \vfill
       \eject
\registerOTRSETmarks
       % brr, may result in empty page after nicely fit text
       % or if left, then lost of first column only text
       \ifnum\mofcolumns>\plusone
         \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 !
   \OTRSETcheckstartcells
   \OTRSETsetvsize}

% \def\OTRSETcheckstartcells
%   {\dorecurse\nofcolumns
%      {\bgroup
%       \mofcolumns\recurselevel
%       \scratchcounter\currentcolumnstartcell % uses \mofcolumns, returns 1 or more
%       \advance\scratchcounter \minusone
%       \dorecurse\scratchcounter
%         {\OTRSETdoifcellelse\mofcolumns\recurselevel
%            \donothing{\OTRSETsetgridcell\mofcolumns\recurselevel\copy\placeholderboxe}}%
%       \egroup}}

\def\OTRSETcheckstartcells
  {\dorecurse\nofcolumns
     {\bgroup
      \mofcolumns\recurselevel
\OTRSETsetcorrectnofcells\currentcolumnstartcell
\advance\scratchcounter \minusone
      \dorecurse\scratchcounter
        {\OTRSETdoifcellelse\mofcolumns\recurselevel
           \donothing{\OTRSETsetgridcell\mofcolumns\recurselevel\copy\placeholderboxe}}%
      \egroup}}

% \OTRSEToutput
%   {\dontcomplain % new, get rid of overfull message (to be sorted out)
%    \OTRSETnaturalflush
%   %\OTRSETstartnextpage
%    \OTRSETdoflushfloats % actually belongs in \flushsavedfloats (but goes wrong)
%    \OTRSETcheckfreelines
%    \OTRSETchecksidefloat}

\OTRSEToutput
  {\dontcomplain % new, get rid of overfull message (to be sorted out)
   \doloop
     {\OTRSETnaturalflush
     %\OTRSETstartnextpage %  no
      \OTRSETdoflushfloats % actually belongs in \flushsavedfloats (but goes wrong)
      \OTRSETcheckfreelines
      \ifsomefreecolumncells
        \exitloop
      \else
        % flush page and get rid of more floats if present
      \fi}%
   \OTRSETchecksidefloat}

\def\OTRSETinitializefeatures
  {% number of lines
   % new: raw
   \getrawnoflines\textheight\xdef\columnmaxcells{\the\noflines}%
   % direction
   \doifelsevalue{\??mc\OTRSETidentifier\c!direction}\v!right
     {\chardef\columndirection\zerocount}
     {\chardef\columndirection\plusone}%
   % balancing
   \chardef\OTRSETbalancemethod\zerocount
   \processaction
     [\getvalue{\??mc\OTRSETidentifier\c!balance}]
     [    \v!yes=>\chardef\OTRSETbalancemethod\plusone,
          \v!top=>\chardef\OTRSETbalancemethod\plustwo,
       \v!bottom=>\chardef\OTRSETbalancemethod\plusthree]}

% 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\OTRSEThandlepreposttext
  {\ifdim\ht\precolumnbox>\zeropoint % new
     \getnoflines{\ht\precolumnbox}%
     \edef\precolumnlines{\the\noflines}%
     \doOTRSETsetgridcells
       {\copy\placeholderboxe}
       \plusone\plusone\nofcolumns\noflines
     % normal version (single column set)
     % {\box\precolumnbox}%
     % compensated for bodyfont change
       {\hbox
          {\OTRSETsetcorrectcellht
           \raise\scratchdimen\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\OTRSETassignwidths
  {%\scratchdimen\makeupwidth
   \freezetextwidth \scratchdimen\textwidth
   %
   \scratchcounter\zerocount
   \dorecurse\nofcolumns
     {\doifelsevalue{\??mc\OTRSETidentifier\recurselevel\c!width}\v!fit
        {\advance\scratchcounter \plusone }
        {\advance\scratchdimen -\getvalue{\??mc\OTRSETidentifier\recurselevel\c!width}}%
      \advance\scratchdimen -\getvalue{\??mc\OTRSETidentifier\recurselevel\c!distance}}%
   \ifcase\scratchcounter\else
     \divide\scratchdimen \scratchcounter
   \fi
   \setgvalue{\??mc\??mc\c!width}{0}%
   \dorecurse\nofcolumns
     {\doifelsevalue{\??mc\OTRSETidentifier\recurselevel\c!width}\v!fit
        {\dimen0=\scratchdimen}
        {\setgvalue{\??mc\??mc\c!width}{1}%
         \dimen0=\getvalue{\??mc\OTRSETidentifier\recurselevel\c!width}}%
      \setxvalue{\??mc\recurselevel\??mc\c!width}{\the\dimen0}}}

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

\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
           \hskip-.5ex%
           \startcolor[columnset:#2]\vrule\!!width1ex\!!height.5ex\!!depth.5ex\stopcolor
         \fi
         \hss}%
      \ifcase#1\relax
        \ht\scratchbox\zeropoint
        \dp\scratchbox\zeropoint
        \wd\scratchbox\zeropoint
      \else
        \wd\scratchbox\hsize
        \ht\scratchbox\strutht
        \dp\scratchbox\strutdp
      \fi
      \box\scratchbox}}

\definepalet
  [columnset]
  [a=cyan,b=green,c=blue,d=red,e=magenta,f=darkgray]

\def\OTRSETsetplaceholders
  {\global\setbox\placeholderboxa\columnplaceholder0a%
   \global\setbox\placeholderboxb\columnplaceholder0b%
   \global\setbox\placeholderboxc\columnplaceholder0c%
   \global\setbox\placeholderboxd\columnplaceholder0d%
   \global\setbox\placeholderboxe\columnplaceholder0e%
   \global\setbox\placeholderboxf\columnplaceholder1f}

\def\doOTRSETshowstatus
  {\llap{\incolortrue \localcolortrue \tt\tfxx
     \startcolor[blue](\the\vsize->\number\columnfirstcell\#\number\columnfreecells)\stopcolor
     \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 \textheight{\forgetall#1#2\pushproperties}}

\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\OTRSETflushfloatbox % nog verder doorvoeren en meer info in marge
  {\iftestfloatbox\ruledhbox\fi{\box\floatbox}}

\def\OTRSETsomeslotfloat[#1]%
  {\setbox\floatbox\vbox{\flushfloatbox}%
   \dp\floatbox\strutdp
   \@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\@@bknbottom=\zerocount
       \ifnum\@@bknlines>\zerocount
         \ifdim\totaltopinserted>\zeropoint\relax
           \dimen0\lineheight
           \dimen0=\@@bknlines\dimen0
           \advance\dimen0 \totaltopinserted\relax
           \ifdim\dimen0>\textheight % \vsize  %%%%%%%%% \textheight
             \showmessage\m!floatblocks8{\@@bknlines}%
             \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
            \moveongrid[\v!top]
          \fi
        \else
          \betweenfloatblanko % inserts can't look back
        \fi
        \flushfloatbox
        \blank[\@@bkspaceafter]}%
     \global\advance\topinserted \ht\scratchbox\relax
     \ifdim\topinserted>\vsize % was \textheight\relax
       \OTRSETresavebox\floatbox
       \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
          \blank[\@@bkspacebefore]%
          \flushfloatbox}%
       \ifsomefloatwaiting
         \advance\noffloatinserts \plusone
       \else
         \noffloatinserts\nofbotfloats
       \fi
       \dofloatflushedinfo
     \else
       \OTRSETresavebox\floatbox
       \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
     \doifinsetelse{#2}{\v!both,\v!fixed}
       {\definecolumntextarea[#1][\v!left ][\c!type=#2,#3]%
        \definecolumntextarea[#1][\v!right][\c!type=#2,#3]}
       {\doifelse{#2}\v!next
          {\doifoddpageelse
             {\definecolumntextarea[#1][\v!right][\c!type=#2,#3]}
             {\definecolumntextarea[#1][\v!left ][\c!type=#2,#3]}}
          {\presetlocalframed
             [\??mt#1#2]%
           \processaction[#2] % \doglobal voorkomt stack build up
             [ \v!left=>\doglobal\addtocommalist{#1}\columnleftareas,
              \v!right=>\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!no,\c!frame=\v!off,
              \c!type=#2,\c!page=1,\c!state=\v!stop,#3]}}%
   \else
     \definecolumntextarea[#1][\v!next][#2]%
   \fi}

\def\setupcolumntextarea
  {\dotripleempty\dosetupcolumntextarea}

\def\dosetupcolumntextarea[#1][#2][#3]%
  {\ifthirdargument
     \doifelse{#2}\v!both
       {\setupcolumntextarea[#1][\v!left ][#3]%
        \setupcolumntextarea[#1][\v!right][#3]}
       {\doifelse{#2}\v!next
          {\doifoddpageelse
             {\setupcolumntextarea[#1][\v!right][#3]}
             {\setupcolumntextarea[#1][\v!left][#3]}}
          {\getparameters[\??mt#1#2][#3]}}%
   \else
     \setupcolumntextarea[#1][\v!next][#2]%
   \fi}

\def\docheckcolumnsetareapage#1#2%
  {\ifnum\getvalue{\??mt#1\c!page}>\plusone
     \doifelsevalue{\??mt#1\c!type}\v!fixed
       {\ifnum\columnsetpage=\getvalue{\??mt#1\c!page}\relax
          \donetrue\else\donefalse
        \fi}
       {\ifnum\columnsetpage<\getvalue{\??mt#1\c!page}\relax
          \donefalse\else\donetrue
        \fi}%
   \else
     \donetrue
   \fi}

\def\initializecolumntextareas
  {\ifodd\realpageno
     \doinitializecolumntextareas\columnrightareas\v!right
   \else
     \doinitializecolumntextareas\columnleftareas\v!left
   \fi}

\def\doinitializecolumntextareas#1#2%
  {\def\docommand##1%
     {\docheckcolumnsetareapage{##1#2}\plusone
      \ifdone
        \donefalse
        \processaction
          [\getvalue{\??mt##1#2\c!state}]
          [  \v!start=>\donetrue,
            \v!repeat=>\donetrue,
           \s!unknown=>\doperformtest\commalistelement\donetrue\donefalse]%
        \ifdone\dodoinitializecolumntextareas{##1}{#2}\fi
      \fi}%
   \processcommacommand[#1]\docommand}

\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!right
   \else
     \doplacecolumntextareas\columnleftareas\v!left
   \fi}

\def\doplacecolumntextareas#1#2% global ?
  {\bgroup
   \forgetall
   \def\docommand##1%
     {\docheckcolumnsetareapage{##1#2}\zerocount
      \ifdone
        \donefalse
        \processaction
          [\getvalue{\??mt##1#2\c!state}]
          [  \v!start=>\donetrue\doglobal\removefromcommalist{##1}#1,
            \v!repeat=>\donetrue,
           \s!unknown=>\doperformtest\commalistelement\donetrue\donefalse]%
        \ifdone
          \dodoplacecolumntextareas{##1}{#2}%
        \else
          \doglobal\removefromcommalist{##1}#1%
        \fi
      \fi}%
   \processcommacommand[#1]\docommand
   \egroup}

\def\columntextlastbackspace{\backspace}

% 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
   % wrong
   % \ifnum\columntextareaparameter\c!y=\zerocount
   %   \advance\!!heighta -\lineheight
   %   \advance\!!heighta \topskip
   % \fi
   % \advance\!!heighta -\lineheight % option
   \ifnum\columntextareaparameter\c!y=\plusone
     \advance\!!heighta -\lineheight
     \advance\!!heighta \topskip
   \fi
   %
   \setbox\scratchbox\vbox
     {\donetrue\localframed
        [\??mt\currentcolumntestarea]
        [\c!location=,% new (*)
            \c!width=\!!widtha,\c!height=\!!heighta,\c!lines=]
        {\columntextareaparameter\empty}}%
   \!!counta\columntextareaparameter\c!x
   \!!countb\columntextareaparameter\c!y
   \advance\!!countb \columntextareaparameter\c!ny
   \advance\!!countb \minusone
   % new (*)
   \doif{\columntextareaparameter\c!location}\v!depth
     {\setbox\scratchbox\hbox{\lower\strutdepth\box\scratchbox}%
      \dp\scratchbox\zeropoint
      \ht\scratchbox\!!heighta}%
   %
   \setbox0\hbox
     {\ifcase\!!countc
        \copy\scratchbox % \box
      \else
        \clip
          [   %\c!topoffset=\columntextareaparameter\c!clipoffset,%
           %\c!bottomoffset=\columntextareaparameter\c!clipoffset,%
             %\c!leftoffset=\columntextareaparameter\c!clipoffset,%
                  \c!offset=\columntextareaparameter\c!clipoffset,%
             \c!rightoffset=\zeropoint,%
                   \c!width=\!!widthb,%
                  \c!height=\!!heighta]%
          {\copy\scratchbox}%
      \fi}%
   \OTRSETsetgridcell\!!counta\!!countb\box0
   \ifcase\!!countc\else
     \advance\!!counta \columntextareaparameter\c!nx
     \advance\!!counta -\!!countc
     \advance\!!widtha -\!!widthb
     \setbox0\hbox
       {\hskip-\namedlayoutparameter\v!odd\c!backspace
        \clip
          [   %\c!topoffset=\columntextareaparameter\c!clipoffset,%
           %\c!bottomoffset=\columntextareaparameter\c!clipoffset,%
            %\c!rightoffset=\columntextareaparameter\c!clipoffset,%
                  \c!offset=\columntextareaparameter\c!clipoffset,%
              \c!leftoffset=\zeropoint,%
                   \c!width=\!!widtha,%
                  \c!height=\!!heighta,%
                 \c!hoffset=\!!widthb]%
          {\copy\scratchbox}}%
     \OTRSETsetgridcell\!!counta\!!countb\box0%
   \fi}

\def\setupcolumntextareatext
  {\dotripleempty\dosetupcolumntextareatext}

\long\def\dosetupcolumntextareatext[#1][#2][#3]%
  {\ifthirdargument
     \doifelse{#2}\v!both
       {\setvalue{\??mt#1\v!left }{#3}%
        \setvalue{\??mt#1\v!right}{#3}}
       {\doifelse{#2}\v!next
          {\doifoddpageelse
             {\setvalue{\??mt#1\v!right}{#3}}%
             {\setvalue{\??mt#1\v!left }{#3}}}%
          {\setvalue{\??mt#1#2}{#3}}}%
   \else
     \setupcolumntextareatext[#1][\v!next][{#2}]%
   \fi}

\def\docalculatecolumnsetspan
  {% \!!counta <= x
   % \!!countb <= nx
   % \!!widtha => total width
   % \!!widthb => left width
   % \!!countc => left cols
   \!!widtha\!!countb\textwidth % 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!distance\recurselevel}%
   \!!widthb\!!widtha
   \advance\!!widthb -\!!countc\textwidth
   \ifodd\realpageno \else % tricky, assumes that we keep there
     \ifcase\!!countc\else
       % nog niet ok voor enkel/doublesided
       \advance\!!widtha \namedlayoutparameter\v!even\c!backspace
       \advance\!!widtha \namedlayoutparameter\v!odd \c!backspace
       \advance\!!widthb \namedlayoutparameter\v!even\c!backspace
       \dorecurse\!!countc
         {\advance\!!widtha\OTRSETgetparameter\c!distance\recurselevel}%
     \fi
   \fi}

\def\columnsetspanhsize{\textwidth}

\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!frame=\v!off,
        \c!before=,
        \c!after=,
        \c!offset=\v!overlay,
        \c!location=\v!left,
        \c!linecorrection=\v!off,
        \c!depthcorrection=\v!off,
        \c!n=2,
        \c!nlines=0,
        \c!indenting=,
        \c!indentnext=\v!yes,
        \c!default=HERE,
        \c!alternative=\v!a,
        #2]%
   %\else
   %  \definecolumnspan[][#1]%
  }%\fi}

\definecolumnsetspan[\s!default]

\def\setupcolumnsetspan
  {\dodoubleempty\dosetupcolumnsetspan}

\def\dosetupcolumnsetspan[#1][#2]%
  {\ifsecondargument
     \setupframedtexts[cs:#1][#2]%
   \else
     \setupcolumnsetspan[\s!default][#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
   \ifnum\columnsetlevel>\zerocount\else
     % of course we needed a one-column fall back for tm
     \columnsetspanhsize\hsize
     \nofcolumns\plusone
     \mofcolumns\plusone
   \fi
   \setupframedtexts[cs:#1]
     [\c!width=\columnsetspanhsize,
      \c!linecorrection=\v!off,
      \c!depthcorrection=\v!off,
      #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!alternative}\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!none]% geen nils placement
     % spoils spacing : \vskip-\struttotal\par\verticalstrut\par
     \ifnum\columnsetlevel>\zerocount
       \framedtextparameter{cs:#1}\c!before
     \fi
     \def\stopcolumnsetspan{\dostopcolumnsetspan{#1}}}

\def\dostopcolumnsetspan#1%
  {\par
   \verticalstrut
   \kern-2\struttotal
   \verticalstrut
   \ifnum\columnsetlevel>\zerocount
     \doifsomething{\framedtextparameter{cs:#1}\c!after}
       {\framedtextparameter{cs:#1}\c!after
        \kern\zeropoint}% otherwise blanks disappear, better be a switch
   \else
     \endgraf
   \fi
   \dostopframedtext
   \egroup
   \setbox\scratchbox\frozenhbox to \hsize
     {\dontcomplain
      \alignedline{\framedtextparameter{cs:#1}\c!location}\v!middle
        {\lower\strutdepth\box\scratchbox}}%
   \dp\scratchbox\zeropoint % else wrong snap insidefloat
%
% to be tested first (strange in grid mode)
%
% \setbox\scratchbox\frozenhbox to \hsize
%   {\dontcomplain
%    \chardef\alignstrutmode\zerocount
%    \alignedline{\framedtextparameter{cs:#1}\c!plaats}\v!midden
%      {\box\scratchbox}}%
%
   \ifinsidefloat
     \box\scratchbox
   \else\ifnum\columnsetlevel>\zerocount
     % we only set \columnsetspacing when asked for, else bottom problems
     % don't change this any more (test naw)
     \chardef\columnslotspacing\framedtextparameter{cs:#1}\c!nlines\relax
     % todo: nboven/onder & \chardef\columnslotlocation2
     %\OTRSETstoreincolumnslotHERE\scratchbox
     \edef\floatmethod{\framedtextparameter{cs:#1}\c!default}%
     \@EA\uppercasestring\floatmethod\to\floatmethod
     % todo : \v!here -> here enzovoorts
     \OTRSETstoreincolumnslot\floatmethod\scratchbox
     % watch out: no \dochecknextindentation{tag}
     \checknextindentation[\framedtextparameter{cs:#1}\c!indentnext]%
   \else
     % of course we needed a one-column fall back for tm; brrr, the box has now too
     % much height (try \ruledvbox); don't change this without testing techniek
     \scratchdimen\ht\scratchbox
     \advance\scratchdimen-\strutdp
     \ht\scratchbox\scratchdimen
     \framedtextparameter{cs:#1}\c!before
     \snaptogrid\vbox{\box\scratchbox}%
     \framedtextparameter{cs:#1}\c!after
   \fi\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

% extreme examples (1)
%
% \setupfloats[numbering=nocheck]
%
% \definecolumnset [first] [n=2,start=0]
% \definecolumnset [next]  [n=2,start=3]
%
% \setuptexttexts[\vbox to \textheight{\topskipcorrection \hsize\makeupwidth left \hfill right\vfill}]
%
% \setuphead[chapter][text=empty]
%
% \starttext
%
% \startcolumnset[first,next]
%   \placefigure[btrl]{}{}
%   \placefigure[tblr]{}{}
%   \chapter{thuan} \dorecurse{25}{\recurselevel: \input thuan \endgraf}
% \stopcolumnset
%
% \startcolumnset[first,next]
%   \chapter{thuan} \dorecurse{25}{\input thuan \endgraf\placefigure{}{}}
% \stopcolumnset
