page-set.mkiv / last modification: 2019-11-14 17:16
%D \module
%D   [       file=page-set,
%D        version=2000.10.20,
%D          title=\CONTEXT\ Page Macros,
%D       subtitle=Column Sets,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

% not yet mkiv! probably namespace issues with localframed (only one left)
%
% getnoflines vs getrawnoflines
%
% can have some vpack and hpack

% This is a rather old mechanism and we can best keep it as it is. If it gets
% replaced by a more modern solution, it will be an extra mechanism. So, we
% only do some basic cleanup.

\writestatus{loading}{ConTeXt Page 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

\newif\ifforcecolumnsetgrid      \forcecolumnsetgridtrue
\newif\ifcollectingsetcontent    % never set
\newif\ifcarryoverfootnotes      %\carryoverfootnotestrue
\newif\iflastcolumnfootnotes     % never set \lastcolumnfootnotestrue
\newif\ifintermediatefootnotes

\newbox        \b_page_set_preceding
\newbox        \b_page_set_trailing

\newdimen      \d_page_set_local_hsize
\newconditional\c_page_set_width_set

\installcorenamespace{columnsetgrid}

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

\def\page_set_cell    #1#2{\csname              \??columnsetgrid:\number#1:\number#2\endcsname}
\def\page_set_cell_get#1#2{\box\csname          \??columnsetgrid:\number#1:\number#2\endcsname}
\def\page_set_cell_set#1#2{\global\setbox\csname\??columnsetgrid:\number#1:\number#2\endcsname}

\def\page_set_cell_doifelse#1#2%
  {\relax
   \ifvoid\csname\??columnsetgrid:\number#1:\number#2\endcsname
     \expandafter\secondoftwoarguments
   \else
     \expandafter\firstoftwoarguments
   \fi}

\def\page_set_cell_erase_grid  % maybe dedicated loops ... make another loop when max's have changed
  {\bgroup
   \increment\columnmaxcells\relax
   \ifodd\realpageno \else
     \columnspreadfalse
   \fi
   \ifcolumnspread
     \page_set_cell_erase_grid_spread
   \else
     \page_set_cell_erase_grid_page
   \fi
   \page_set_cell_erase_grid_top
   \global\columnfirstcell\zerocount
   \global\columnlastcell \columnfirstcell
   \global\columnfreecells\columnfirstcell
   \egroup}

\let\m_page_column_l\relax
\let\m_page_column_r\relax

\def\page_set_cell_erase_grid_spread
  {\dorecurse\nofcolumns
     {\let \m_page_column_l\recurselevel
      \edef\m_page_column_r{\the\numexpr\recurselevel+\lofcolumns}%
      \dostepwiserecurse \zerocount \columnmaxcells \plusone
        {\ifcsname\??columnsetgrid:\m_page_column_l:\recurselevel\endcsname
           \global\setbox\csname\??columnsetgrid:\m_page_column_l:\recurselevel\endcsname
           \ifcsname\??columnsetgrid:\m_page_column_r:\recurselevel\endcsname
             \box\csname\??columnsetgrid:\m_page_column_r:\recurselevel\endcsname
           \else
             \emptyhbox
             \expandafter\newbox\csname\??columnsetgrid:\m_page_column_r:\recurselevel\endcsname
           \fi
         \else
           \expandafter\newbox\csname\??columnsetgrid:\m_page_column_l:\recurselevel\endcsname
           \ifcsname\??columnsetgrid:\m_page_column_r:\recurselevel\endcsname
             \global\setbox\csname\??columnsetgrid:\m_page_column_l:\recurselevel\endcsname\box\csname\??columnsetgrid:\m_page_column_r:\recurselevel\endcsname
           \else
             \expandafter\newbox\csname\??columnsetgrid:\m_page_column_r:\recurselevel\endcsname
           \fi
         \fi}}}

\def\page_set_cell_erase_grid_page
  {\dorecurse \tofcolumns
     {\let\m_page_column_l\recurselevel
      \dostepwiserecurse \zerocount \columnmaxcells \plusone
        {\ifcsname\??columnsetgrid:\m_page_column_l:\recurselevel\endcsname
           \global\setbox\csname\??columnsetgrid:\m_page_column_l:\recurselevel\endcsname\emptybox
         \else
           \expandafter\newbox\csname\??columnsetgrid:\m_page_column_l:\recurselevel\endcsname
         \fi}}}

\def\page_set_cell_erase_grid_top
  {\dorecurse\tofcolumns
     {\global\setbox\csname\??columnsetgrid:\recurselevel:\columnmaxcells\endcsname\copy\placeholderboxa}}

% % % %

\def\OTRSETmakeupwidth{\innermakeupwidth}

\unexpanded\def\page_set_command_flush_side_floats
  {\page_sides_forget_floats}

\unexpanded\def\page_set_command_synchronize_side_floats
  {\page_sides_forget_floats}

% 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

%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 \expandafter
   \expandafter\egroup\expandafter\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 \expandafter
   \expandafter\egroup\expandafter\scratchdimen\the\!!dimena\relax}

\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
        {\page_set_cell_set\!!countf\recurselevel#1}}%
   \dostepwiserecurse{#3}\!!counte\plusone
     {\wd\page_set_cell{#2}\recurselevel\hsize}%
   \page_set_cell_set{#2}\!!counte#6}

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

\def\OTRSETerasegridcells#1#2#3#4%
  {\doOTRSETsetgridcells{\emptybox}{#1}{#2}{#3}{#4}{\emptybox}}

\unexpanded\def\setupcolumnsetlines{\doquintupleempty\dosetupcolumnsettrick[l]}
\unexpanded\def\setupcolumnsetstart{\doquintupleempty\dosetupcolumnsettrick[s]}

\installcorenamespace{columnsettag} % temp hack

\def\dosetupcolumnsettrick[#1][#2][#3][#4][#5]% tag id page col value
  {\iffifthargument
     \setevalue{\??columnsettag:#1:#2:\number#3:\number#4}{\number#5}%
   \else
     \setevalue{\??columnsettag:#1:#2:\number#3:0}{\number#4}%
   \fi}

\def\currentcolumnmaxcellstag #1{\??columnsettag:l:\OTRSETidentifier:\columnsetpage:\number#1}
\def\currentcolumnstartcelltag#1{\??columnsettag: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\relax
     \fi
   \else\ifcsname#10\endcsname
     \ifnum\csname#10\endcsname=\zerocount
       #2%
     \else
       \number\numexpr\ifnum\csname#10\endcsname<\zerocount
         \columnmaxcells+\fi\csname#10\endcsname\relax
     \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
   \ifnum\scratchcounter<\columnmaxcells\relax
     \edef\columnmaxcells{\the\scratchcounter}% added 2013.04.19
   \fi
   \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
          \page_set_cell_doifelse{#1}\columnfirstcell
            {\global\advance\columnfirstcell\plusone}\exitloop
        \fi}%
     \global\columnlastcell\columnfirstcell
     \doloop
       {\ifnum\columnlastcell>\columnmaxcells\relax
          \exitloop
        \else
          \page_set_cell_doifelse{#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\numexpr\columnlastcell-\columnfirstcell+\plusone\relax
       \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
     {\page_set_cell_doifelse{#1}\recurselevel
        {\ifnum\columnmaxfreecells<\scratchcounter
           \edef\columnmaxfreecells{\the\scratchcounter}%
           \let\columnfrmfreecells\recurselevel
         \fi
         \scratchcounter\zerocount}
        {\advance\scratchcounter\plusone}}%
   \popmacro\columnmaxcells}

\def\OTRSETrecurseRL#1%
  {\dostepwiserecurse\nofcolumns\plusone\minusone
     {#1\hskip\namedcolumnsetparameter{\currentcolumnset:\recurselevel}\c!distance}}

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

\def\OTRSETmakeupwidth{\makeupwidth} % temporary indirectness

\def\page_set_make_background_box
  {\begingroup
   \mofcolumns\recurselevel % used to signal mp
   \d_page_set_local_hsize\OTRSETlocalwidth\recurselevel
   \scratchdistance\namedcolumnsetparameter{\currentcolumnset:\recurselevel}\c!distance\relax
   \edef\currentcolumnset{\currentcolumnset:\recurselevel}%
   \letcolumnsetparameter\c!width \d_page_set_local_hsize
   \letcolumnsetparameter\c!height\!!heighta
   \letcolumnsetparameter\c!lines \empty
   \letcolumnsetparameter\c!region\currentcolumnset
   \setbox\scratchbox\hpack\inheritedcolumnsetframed{}% maybe \fastlocalframed
   \wd\scratchbox\d_page_set_local_hsize
   \ht\scratchbox\!!heighta
   \ifcase\columndirection
     \hskip\scratchdistance
     \box\scratchbox
   \else
     \box\scratchbox
     \hskip\scratchdistance
   \fi
   \endgroup}

\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}\page_set_make_background_box}%
   \hskip-\OTRSETmakeupwidth
   % main text
   \hbox to \OTRSETmakeupwidth
     {\dostepwiserecurse{#1}{#2}{#3}
        {\mofcolumns\recurselevel
         \d_page_set_local_hsize\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{\page_set_cell_get\mofcolumns\recurselevel}%
               \ht\scratchbox\strutht
               \dp\scratchbox\strutdp
               \ifcase\columndirection
                 \box\scratchbox
               \else
                 \hbox to \d_page_set_local_hsize
                   {\hskip\d_page_set_local_hsize\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\d_page_set_local_hsize % \textwidth
         \page_marks_synchronize_column{#1}{#2}\recurselevel\scratchbox
         \ifcase\columndirection
           \hskip\namedcolumnsetparameter{\currentcolumnset:\recurselevel}\c!distance\box\scratchbox
         \else
           \box\scratchbox\hskip\namedcolumnsetparameter{\currentcolumnset:\recurselevel}\c!distance
         \fi}}%
   \egroup}

\let\OTRSETbalht\zeropoint

\def\OTRSETreducegridbox % for the moment no difference between methods
  {\glet\OTRSETbalht\zeropoint
   \ifcase\OTRSETbalancemethod
     % no balancing
   \else
     \bgroup
     \!!counta\columnmaxcells
     \donetrue
     \doloop
       {\dorecurse\nofcolumns{\page_set_cell_doifelse\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{\page_set_cell_get\nofcolumns\lastcolumnlastcell}%
          \box\scratchbox}%
       \ht\scratchbox\strutht
       \dp\scratchbox\strutdp
       \page_set_cell_set\nofcolumns\lastcolumnlastcell\box\scratchbox
     \fi
     \global\lastcolumnlastcell\zerocount
   \fi}

\def\OTRSETdoflush
  {\ifcollectingsetcontent
     \global\mofcolumns\plusone
   \else
     \OTRSETdofinalflush
     \OTRSETdofinaloutput
     \ifnum\columnsetpage>\zerocount
       \dorecurse\nofcolumns{\doresetcolumnsetlines\recurselevel}%
     \fi
     \doglobal\increment\columnsetpage
     \OTRSETinitializecolumns
     \OTRSETstartnextpage
     \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=\textheight
     \bgroup
     \ifcase\OTRSETbalancemethod
       \page_otr_construct_and_shipout\box\OTRfinalpagebox\zerocount % three arguments
     \else\ifdim\OTRSETbalht>\zeropoint
       % catch a bordercase
       \scratchdimen\OTRSETbalht
       \advance\scratchdimen\lineheight\relax
       \ifdim\scratchdimen>\textheight
         % full page
         \page_otr_construct_and_shipout\box\OTRfinalpagebox\zerocount % three arguments
       \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
       \page_otr_construct_and_shipout\box\OTRfinalpagebox\zerocount % three arguments
     \fi \fi
     \glet\OTRSETbalht\zeropoint
     \egroup
   \fi}

\definesystemconstant {colset}

\definetwopasslist\s!colset

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

\def\OTRSETskipstart
  {\doifelsenothing{\columnsetparameter\c!start}
     {\scratchcounter\zerocount}%
     {\scratchcounter\columnsetparameter\c!start}%
   \relax % needed !
   \ifcase\scratchcounter\else
     \advance\scratchcounter\plusone
     \doOTRSETsetgridcells
       {\copy\placeholderboxe}
       \plusone\plusone\nofcolumns\scratchcounter
       \emptybox
   \fi}

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

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

\unexpanded\def\page_set_command_synchronize_hsize
  {\ifconditional\c_page_set_width_set
     \bgroup
     \scratchdimen\OTRSETlocalwidth\mofcolumns
     \ifdim\scratchdimen=\textwidth
       \egroup
     \else
       % only if change in width and \column/\break
       \egroup
       \page_set_command_set_hsize
     \fi
   \fi}

\def\OTRSETcheckfreelines
  {\page_set_command_set_vsize}

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

\let\OTRSETcolumnseparator\relax

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

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

\installcolumnbreakmethod \s!columnset \v!local
  {\OTRSETcolumnhbreak
   \page_set_command_flush_all_floats
   \page_otr_eject_page
   % no \page_set_command_set_hsize, can be mid smaller (like tabulate)
   % also, this one should be executed at the outer level
   % (setting hsize inside otr does not work)
   \page_set_command_synchronize_hsize}

% 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).

\installcolumnbreakmethod \s!columnset \v!yes
  {\OTRSETcolumnhbreak
   \edef\savedmofcolumns{\the\mofcolumns}%
   \edef\savedrealpageno{\the\realpageno}%
   \page_otr_flush_all_floats
   \page_otr_eject_page
   \doloop
     {\ifnum\savedmofcolumns=\mofcolumns
        \ifnum\savedrealpageno=\realpageno
          \OTRSETdummycolumn
        \else
          \exitloop
        \fi
      \else
        \exitloop
      \fi}%
   \page_set_command_synchronize_hsize}

\installcolumnbreakmethod \s!columnset \s!unknown
  {\expanded{\OTRSETgotocolumn[\@@columnspecification]}}

\installcolumnbreakmethod \s!columnset \v!page
  {\page_otr_fill_and_eject_page}

\newtoks\OTRSETeverystartofcolumn

\newbox\OTRSETsavedfootnotes

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

\newconstant\OTRSETflushtextmode % will be replaced

\def\OTRSETflushtextsofar % needs renaming
  {\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

\installoutputroutine\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\hpack
         {\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
     \page_set_command_set_vsize
   \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
     {\page_areas_registered_box1\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
   \page_set_command_synchronize_hsize
   \page_set_command_set_vsize}

\def\OTRSETfindnextgap
  {\OTRSETsetfreecells\mofcolumns\columnlastcell
   \ifsomefreecolumncells
     % okay
   \else
     \global\advance\mofcolumns \plusone
     \ifnum\mofcolumns>\nofcolumns
       \OTRSETdoflush
       \global\columnlastcell\plusone
       \global\columnfirstcell\zerocount
       \page_set_command_flush_floats
     \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
       {\page_set_cell_doifelse{#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
                   {\page_set_cell_set{#1}\recurselevel\copy\placeholderboxc}%
                %\message{[gap]}%
               \fi
             \fi
           \fi
           \donefalse}
          {\ifdone \else
             \donetrue
             \!!counta\recurselevel
           \fi}}%
   \fi}

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

\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
       {\hpack{\copy#1}}%
     \page_set_command_set_vsize
   \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 % -)
     \page_set_command_set_vsize
   \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 \namedcolumnsetparameter{\currentcolumnset:\number\scratchcounter}\c!distance
        \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\page_set_cell\recurselevel\scratchcounter>\zeropoint
%       \let\columnspacetopoffset\plusone
%     \else\ifdim\dp\page_set_cell\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\page_set_cell\recurselevel\scratchcounter>\zeropoint
%       \let\columnspacebotoffset\plusone
%     \else\ifdim\dp\page_set_cell\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
               \page_set_cell_doifelse\!!countf\recurselevel
                 {\enoughcolumncellsfalse}{}%
             \fi}%
        \fi}%
   \fi}

\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
   \page_set_cell_doifelse\pofcolumns\plusone
     {\OTRSETprepareforcolumnslot2}{\OTRSETprepareforcolumnslot1}{#1}% % 1/2 dependent of place, todo
   \OTRSETflushtextsofar
   \OTRSETstoreincolumnslotindeed
     \pofcolumns \pofcolumns +\currenthcell
     \floatrow\columnmaxcells+\currentvcell{#1}}

\def\OTRSETstoreincolumnslotFXBT#1% fixed column
  {\OTRSETcheckprefered
   \page_set_cell_doifelse\pofcolumns\columnmaxcells
     {\OTRSETprepareforcolumnslot2}{\OTRSETprepareforcolumnslot3}{#1}% % 3/2 dependent of place, todo
   \OTRSETflushtextsofar
   \OTRSETstoreincolumnslotindeed
     \pofcolumns    \pofcolumns+\currenthcell
     \columnmaxcells\floatrow  -\currentvcell{#1}}

\newconstant\OTRSETforcefixedfloats

\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[\number\columnslotspacing*\v!line]%
       \snaptogrid\hpack to \hsize{\hss\box#1\hss}% strange, why the centering
       \blank[\number\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}%
   \page_set_command_set_vsize}

\def\OTRSETcheckprefered
  {\ifx\floatcolumn\empty
     \let\pofcolumns\nofcolumns
   \else\ifnum\floatcolumn<\mofcolumns
     \let\pofcolumns\mofcolumns
   \else
     \let\pofcolumns\floatcolumn
   \fi\fi
   \ifx\floatrow\empty
     \let\pofcolumns\plusone
   \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
     \page_set_command_set_vsize
    %\message{[fnt]}% float
   \else
    %\message{[rej]}% save box
     \OTRSETsavebox{#9}%
   \fi}

\setnewconstant\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{\csstring\OTRSETstoreincolumnslot#1}
%     {\getvalue{\csstring\OTRSETstoreincolumnslot#1}{#2}}
%     {\OTRSETstoreincolumnslotUNKNOWN{#2}}}
   \executeifdefined{\csstring\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
     \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}

\unexpanded\def\page_set_command_check_if_float_fits
  {\global\ifconditional\c_page_floats_not_permitted\setfalse\c_page_floats_room\else\settrue\c_page_floats_room\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}

% for the moment resave is still needed here

\def\OTRSETsavebox#1% clean up the skips
  {\OTRSETunpreparebox{#1}%
   \page_floats_save\s!text}

\def\OTRSETresavebox#1% clean up the skips
  {\OTRSETunpreparebox{#1}%
   \page_floats_resave\s!text}

\unexpanded\def\page_set_command_flush_float_box
  {\box\floatbox}

\unexpanded\def\page_set_command_flush_floats
  {\bgroup
   \def\OTRSETsavebox##1{\!!doneafalse}%
   \doloop
     {\ifconditional\c_page_floats_some_waiting
        \OTRSETskipstart
        \page_floats_get_info\s!text
        \ifdim\floatwidth>\zeropoint
          \!!doneatrue
          \page_floats_flush\s!text\plusone
%
% a quick hack ... will be redone
%
\ifdim\wd\floatbox<\floatwidth \ifhbox\floatbox
    \global\setbox\floatbox\hpack{\unhbox\floatbox}%
\fi \fi
%
          \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\page_set_cell\currenthcell\currentvcell>\zeropoint
                 \centergridcellonlyfalse
               \else\ifdim\dp\page_set_cell\currenthcell\currentvcell>\zeropoint
                 \centergridcellonlyfalse
               \fi\fi}%
          \fi
        \fi
        \currenthcell\recurselevel
        \dorecurse\columnmaxcells
          {\currentvcell\recurselevel\relax
           \ifdim\ht\page_set_cell\currenthcell\currentvcell>\zeropoint
           \ifdim\dp\page_set_cell\currenthcell\currentvcell=\zeropoint
             \bgroup
             \setbox\scratchbox\page_set_cell_get\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\page_set_cell\xrecurselevel\recurselevel>\zeropoint
                       \!!donebfalse
                     \else\ifdim\wd\page_set_cell\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 \namedcolumnsetparameter{\currentcolumnset:\recurselevel}\c!distance}%
             \ifdim\totalcolumnspace>\wd\scratchbox
               \setbox\scratchbox\hpack to \totalcolumnspace{\hss\box\scratchbox\hss}%
             \fi
             \page_set_cell_set\currenthcell\currentvcell\box\scratchbox
           \egroup
           \fi
           \fi}}%
   \fi}

\def\OTRSETinitializecolumns% once per page
  {\columnspreadtrue % todo
   \ifcolumnspread
     \global\rofcolumns\columnsetparameter\c!nright
     \global\lofcolumns\columnsetparameter\c!nleft
     \global\tofcolumns\rofcolumns \relax
     \ifodd\realpageno\relax
       \global\nofcolumns\rofcolumns
     \else
       \global\advance\tofcolumns\lofcolumns
       \global\nofcolumns\lofcolumns
     \fi
   \else
     \global\nofcolumns\columnsetparameter\c!n
     \global\rofcolumns\nofcolumns
     \global\lofcolumns\nofcolumns
     \global\tofcolumns\nofcolumns
   \fi
   \OTRSETassignwidths
   \global\mofcolumns\plusone
   \page_set_cell_erase_grid}

% this is a first step in upgrading

\installcorenamespace{columnset}

\installframedcommandhandler \??columnset {columnset} \??columnset

\setupcolumnset % todo, use the rather basic backgroundframed
  [\c!direction=\v!right,
   \c!balance=\v!no,
   \c!distance=1.5\bodyfontsize,
   \c!n=2,
   \c!nleft=\columnsetparameter\c!n,
   \c!nright=\columnsetparameter\c!n,
   \c!width=\v!fit,
   \c!lines=0,
   \c!start=0,
   \c!frame=\v!off,
   \c!offset=\v!overlay,
   \c!frame=\v!off,
   \c!align=]

\let\page_set_setup_saved\setupcolumnset

\newconditional\c_page_set_defining

\appendtoks
    \ifconditional\c_page_set_defining \else
      \settrue\c_page_set_defining
      \dorecurse{\columnsetparameter\c!nleft}
        {\normalexpanded{\definecolumnset[\currentcolumnset:\recurselevel][\currentcolumnset]}}%
      \dorecurse{\columnsetparameter\c!nright}
        {\normalexpanded{\definecolumnset[\currentcolumnset:\recurselevel][\currentcolumnset]}}%
      \normalexpanded{\page_set_setup_saved[\currentcolumnset:1][\c!distance=\zeropoint]}%
      \setfalse\c_page_set_defining
    \fi
\to \everydefinecolumnset

\unexpanded\def\setupcolumnset
  {\dotripleargument\page_set_setup}

\def\page_set_setup[#1][#2][#3]%
  {\ifthirdargument
     \unexpanded\def\page_set_setup_step##1%
       {\doifelse{##1}\v!each
          {\dorecurse{\namedcolumnsetparameter{#1}\c!n}{\page_set_setup_step\recurselevel}}
          {\normalexpanded{\page_set_setup_saved[#1:##1]}[#3]}}%
     \processcommalist[#2]\page_set_setup_step
   \else
     \page_set_setup_saved[#1][#2]%
   \fi}

\definecolumnset
  [\s!default]

\unexpanded\def\page_set_command_next_page
  {\page_otr_fill_and_eject_page
   \relax\ifnum\mofcolumns>\plusone
     \OTRSETgotocolumn[\v!last]%
     \ifnum\mofcolumns>\plusone
       \OTRSETgotocolumn[\v!force]%
     \fi
   \fi}

\let\page_set_command_next_page_and_inserts\page_set_command_next_page

\def\OTRSETgotocolumn
  {\dosingleempty\doOTRSETgotocolumn}

\def\doOTRSETgotoCOLROW#1% <number>|<number>*<number>
  {\bgroup % really needed
   \splitatasterisk{#1}\column\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
     \page_otr_fill_and_eject_page
     \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
       {\page_set_cell_doifelse\mofcolumns\recurselevel\donothing
          {\advance\scratchcounter\plusone}}
     \getnoflines\pagetotal
     \advance\scratchcounter-\noflines
     \ifnum\scratchcounter>\zerocount
       \dorecurse\scratchcounter{\line{\strut}}%
     \fi
   \fi
   \page_set_command_set_vsize}

\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
%          {\page_set_cell_doifelse\mofcolumns\recurselevel\donothing
%             {\advance\scratchcounter\plusone}}
%        \getnoflines\pagetotal
%        \advance\scratchcounter-\noflines
%        \ifnum\scratchcounter>\zerocount
%          \dorecurse\scratchcounter{\line{\strut}}%
%        \fi
%      \fi
%    \fi
%    \page_set_command_set_vsize}

\def\OTRSETgotocell#1#2% obsolete: now \column[#1*#2]
  {\endgraf
   \doOTRSETgotoCOLUMN{#1}%
   \doOTRSETgotoROW   {#2}}

\def\OTRSETdummycolumn
  {\verticalstrut
   \vskip-\struttotal
   \page_otr_fill_and_eject_page}

\newcounter\columnsetlevel
\let\currentcolumnset\empty

\newconditional\OTRSETfinish % never checked

\unexpanded\def\startcolumnset
  {\dodoubleempty\dostartcolumnset}

\def\dostartcolumnset[#1][#2]%
  {\increment\columnsetlevel\relax
   \glet\localcolumnmaxcells\!!zerocount
   \global\setfalse\OTRSETfinish
   \ifnum\columnsetlevel=\plusone
     \bgroup
     \saveinterlinespace
     \glet\columnsetpage\!!plusone
     \def\currentcolumnset{#2}%
     \insidecolumnstrue % will be different flag in addition
     \setupoutputroutine[\s!columnset]%
     \doifelsenothing{#1}
       {\glet\OTRSETlist\s!default}
       {\xdef\OTRSETlist{#1}}%
     \OTRSETstartnextpage
     \OTRSETassignwidths
     \page_set_command_set_hsize
   \else
     \bgroup
   \fi
   \begingroup} % extra grouping needed ... else weird issue with ungrouped font switch (e.g. \ss)

% \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
  {\page_set_cell_doifelse\plusone\plusone
     {\bgroup
      \OTRSETcentergridcells
      \OTRSETbalancemethod\plusone
      \OTRSETreducegridbox
      \global\setbox\OTRfinalpagebox\OTRSETmakegridbox
      \ht\OTRfinalpagebox\textheight % signals output that there is content
      \OTRSETdofinaloutput
      \glet\OTRSETbalht\zeropoint
      \egroup}
     {}}

\unexpanded\def\stopcolumnset
  {\endgraf
   \endgroup % ends extra grouping
   \ifnum\columnsetlevel=\plusone
     \endgraf % needed, else wrong vsize in one par case
     \global\settrue\OTRSETfinish
     % no, extra page \pagebreak % (test on pascal toc)
     \dostopcolumnset
     \egroup
     \global\notelimittrue % brrr, untested and fuzzy
     \page_otr_command_set_vsize
     \page_otr_command_set_hsize
     \ifvoid\OTRfinalpagebox\else
       % probably balanced
       \ifdim\ht\OTRfinalpagebox<\textheight
         \snaptogrid[\v!page]\hpack{\box\OTRfinalpagebox}%
       \else
         \box\OTRfinalpagebox
       \fi
     \fi
     \global\setfalse\OTRSETfinish
     \ifconditional\c_page_floats_some_waiting
       \page_otr_command_set_vsize
       \pagebreak
       \page_otr_command_set_vsize
     \fi
     \OTRSETflushleftovers
   \else
     \egroup
   \fi
   \decrement\columnsetlevel\relax}

\newconstant\OTRSETbalancemethod

\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

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

\unexpanded\def\definecolumnsetarea   {\definecolumntextarea}
\unexpanded\def\setupcolumnsetarea    {\setupcolumntextarea}
\unexpanded\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\page_otr_fill_and_eject_page}%
   \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
       \page_otr_fill_and_eject_page
       % 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]%
      \glet\OTRSETidentifier\commalistelement
      \xdef\currentcolumnset{\commalistelement}%
      \checkcolumnsetparent
      \let\newcommalistelement\empty
      \doglobal\replaceincommalist\OTRSETlist1%
      \OTRSETrestart}}

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

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

\unexpanded\def\page_set_command_routine
  {\dontcomplain % new, get rid of overfull message (to be sorted out)
   \doloop
     {\OTRSETnaturalflush
     %\OTRSETstartnextpage %  no
      \page_set_command_flush_floats
      \OTRSETcheckfreelines
      \ifsomefreecolumncells
        \exitloop
      \else
        % flush page and get rid of more floats if present
      \fi}%
   \OTRSETchecksidefloat}

\def\OTRSETsetcolumnmaxcells
  {\getrawnoflines\textheight\xdef\columnmaxcells{\the\noflines}}

\def\OTRSETinitializefeatures
  {% number of lines
   % new: raw
   \OTRSETsetcolumnmaxcells
   % direction
   \doifelse{\columnsetparameter\c!direction}\v!right
     {\columndirection\zerocount}
     {\columndirection\plusone}%
   % balancing
   \OTRSETbalancemethod\zerocount
   \processaction
     [\columnsetparameter\c!balance]
     [    \v!yes=>\OTRSETbalancemethod\plusone,
          \v!top=>\OTRSETbalancemethod\plustwo,
       \v!bottom=>\OTRSETbalancemethod\plusthree]}

% test:
%
% \definecolumnset[test-1]  %[balance=yes]
% \definecolumnset[test-2]  %[balance=yes]
%
% \setupcolumnsetlines[test-1][1][1] [4]
% \setupcolumnsetlines[test-1][1][2][10]
%
% \startcolumnset [test-1] \dorecurse {1}{\input tufte \par} \stopcolumnset
% \startcolumnset [test-2] \dorecurse {2}{\input ward  \par} \stopcolumnset

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

\installoutputroutine\OTRSETflushpreposttext
  {\global\setbox\b_page_set_preceding\vbox
     {\unvbox\normalpagebox
      \global\lastskipinotr\lastskip}%
   \ifdim\lastskipinotr>\zeropoint
     \global\setbox\b_page_set_preceding\hpack
       {\lower\strutdepth\box\b_page_set_preceding}%
   \fi
   \dp\b_page_set_preceding\strutdepth
   \ifcarryoverfootnotes \else
     \global\setbox\b_page_set_trailing\vbox{\placebottomnotes}%
   \fi}

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

\def\OTRSEThandlepreposttext
  {\ifdim\ht\b_page_set_preceding>\zeropoint % new
     \getnoflines{\ht\b_page_set_preceding}%
     \edef\precolumnlines{\the\noflines}%
     \doOTRSETsetgridcells
       {\copy\placeholderboxe}
       \plusone\plusone\nofcolumns\noflines
     % normal version (single column set)
     % {\box\b_page_set_preceding}%
     % compensated for bodyfont change
       {\hbox
          {\OTRSETsetcorrectcellht
           \raise\scratchdimen\box\b_page_set_preceding}}%
   \else
     \let\precolumnlines\!!zerocount
   \fi
   \ifdim\ht\b_page_set_trailing>\zeropoint % new, otherwise empty bottom line
     \getnoflines{\ht\b_page_set_trailing}%
     \edef\postcolumnlines{\the\noflines}%
     \advance\columnfreecells -\noflines
     \advance\columnfreecells \plusone
     \doOTRSETsetgridcells
       {\copy\placeholderboxe}
       \plusone\columnfreecells\nofcolumns\noflines
       {\box\b_page_set_trailing}%
   \else
     \let\postcolumnlines\!!zerocount
   \fi}

\def\OTRSETchecksidefloat
  {} % {\sidefloatoutput}

\unexpanded\def\page_set_command_side_float_output
  {} % nothing, reset anyway

\def\OTRSETcheckgrid
  {\topskip1\topskip
   \ifforcecolumnsetgrid
     \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}

% undocumented goodie

\def\definecolumnsethsize#1#2#3#4% will be improved/speed up
  {\bgroup
   \def\OTRSETidentifier{#1}%
   \ifcase\columnsetlevel\relax
     \mofcolumns\plusone
     \OTRSETinitializecolumns
     \OTRSETassignwidths % already done
     \page_set_command_set_hsize
   \fi
   \!!counta#2\!!countb#3\docalculatecolumnsetspan
   \expandafter\egroup\expandafter\edef\expandafter#4\expandafter{\the\!!widtha}}

% interface to footnotes

\installcorenamespace{columnsetwidth}

\def\OTRSETassignwidths
  {%\scratchdimen\makeupwidth
   \freezetextwidth \scratchdimen\textwidth
   %
   \scratchcounter\zerocount
   \dorecurse\nofcolumns
     {\doifelse{\namedcolumnsetparameter{\currentcolumnset:\recurselevel}\c!width}\v!fit
        {\advance\scratchcounter \plusone}
        {\advance\scratchdimen -\namedcolumnsetparameter{\currentcolumnset:\recurselevel}\c!width}%
      \advance\scratchdimen -\namedcolumnsetparameter{\currentcolumnset:\recurselevel}\c!distance}%
   \ifcase\scratchcounter\else
     \divide\scratchdimen \scratchcounter
   \fi
   \global\setfalse\c_page_set_width_set
   \dorecurse\nofcolumns
     {\doifelse{\namedcolumnsetparameter{\currentcolumnset:\recurselevel}\c!width}\v!fit
        {\dimen0=\scratchdimen}
        {\global\settrue\c_page_set_width_set
         \dimen0=\namedcolumnsetparameter{\currentcolumnset:\recurselevel}\c!width}%
      \setxvalue{\??columnsetwidth\recurselevel}{\the\dimen0}}}

\def\OTRSETlocalwidth#1%
  {\getvalue{\??columnsetwidth\number#1}}

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

\def\columnplaceholder#1#2%
  {\hbox
     {\setbox\scratchbox\hpack to \hsize
        {\iftracecolumnset
           \hskip-.5ex%
           \startcolor[columnset:#2]\vrule\s!width\exheight\s!height.5\exheight\s!depth.5\exheight\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{\tt\tfxx
     \startcolor[blue](\the\vsize->\number\columnfirstcell\#\number\columnfreecells)\stopcolor
     \hskip\leftskip}}

\installtextracer{OTRSET} % low level

\def\enabletextracerOTRSET {\tracecolumnsettrue \let\OTRSETshowstatus\doOTRSETshowstatus}
\def\disabletextracerOTRSET{\tracecolumnsetfalse\let\OTRSETshowstatus\relax}

\disabletextracerOTRSET

% \appendtoks \OTRSETshowstatus \to \everypar

% page contents

% \def\OTRSETdopagecontents#1#2% takes two args: \box<n> \unvbox<n>
\unexpanded\def\page_set_command_package_contents#1#2% \box<n> \unvbox<n> % this one will be redone (checked)
  {\vbox to \textheight{\forgetall#1#2}}

\def\page_set_place_float_page  {\def\floatmethod{PAGE}\page_set_place_float_slot} % check
\def\page_set_place_float_here  {\def\floatmethod{HERE}\page_set_place_float_slot} % check
\def\page_set_place_float_else  {\def\floatmethod{HERE}\page_set_place_float_slot} % check / not used
\def\page_set_place_float_force {\def\floatmethod{FIXD}\page_set_place_float_slot} % check
\def\page_set_place_float_top   {\def\floatmethod{TOPS}\page_set_place_float_slot} % check
\def\page_set_place_float_bottom{\def\floatmethod{BOTS}\page_set_place_float_slot} % check

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

\def\page_set_place_float_slot
  {\setbox\floatbox\vbox{\page_otr_command_flush_float_box}%
   \dp\floatbox\strutdp
   \expandafter\uppercasestring\floatmethod\to\floatmethod
   \OTRSETstoreincolumnslot\floatmethod\floatbox
   \page_floats_report_total}

% kind of new, looks much like OTRONE, but not entirely

\newconditional\c_page_set_top_of_insert

\unexpanded\def\page_set_command_set_top_insertions
  {\bgroup
   \ifconditional\c_page_floats_some_waiting
     \noffloatinserts\zerocount
     \let\totaltopinserted\!!zeropoint
     \OTRSETdodosettopinserts
     \ifnum\rootfloatparameter\c!nbottom=\zerocount
       \ifnum\rootfloatparameter\c!nlines>\zerocount
         \ifdim\totaltopinserted>\zeropoint\relax
           \scratchdimen\dimexpr\rootfloatparameter\c!nlines\lineheight+\totaltopinserted\relax
           \ifdim\scratchdimen>\textheight % \vsize  %%%%%%%%% \textheight
             \showmessage\m!floatblocks8{\rootfloatparameter\c!nlines}%
             \page_otr_fill_and_eject_page % was triple: vfilll
           \fi
         \fi
       \fi
     \fi
   \fi
   \egroup}

\def\OTRSETdodosettopinserts
  {\ifnum\noffloatinserts<\c_page_floats_n_of_top
     \page_floats_get
     \ifdim\d_page_floats_inserted_top=\zeropoint\relax
       \settrue\c_page_set_top_of_insert
     \else
       \setfalse\c_page_set_top_of_insert
     \fi
     \setbox\scratchbox\vbox % kan beter !
       {\forgetall
        \ifconditional\c_page_set_top_of_insert
         %\ifdim\OTRSETtopoffset=\zeropoint
         %  \moveongrid[\v!top]
         %\fi
        \else
          \betweenfloatblanko % inserts can't look back
        \fi
        \page_otr_command_flush_float_box
        \blank[\rootfloatparameter\c!spaceafter]}%
     \global\advance\d_page_floats_inserted_top \ht\scratchbox\relax
     \ifdim\d_page_floats_inserted_top>\vsize % was \textheight\relax
       \OTRSETresavebox\scratchbox
       \noffloatinserts\c_page_floats_n_of_top\relax
       \global\advance\d_page_floats_inserted_top -\ht\scratchbox
       \let\OTRSETdodosettopinserts\relax % to be tested
     \else
       \xdef\totaltopinserted{\the\d_page_floats_inserted_top}%
       \insert\namedinsertionnumber\s!topfloat\bgroup
         \forgetall
         \box\scratchbox
       \egroup
       \ifconditional\c_page_floats_some_waiting
         \advance\noffloatinserts \plusone
       \else
         \noffloatinserts\c_page_floats_n_of_top\relax
       \fi
       \page_floats_report_flushed
     \fi
   \else
     \ifconditional\c_page_floats_some_waiting
       \showmessage\m!floatblocks6{\the\c_page_floats_n_of_top}%
     \fi
     \let\OTRSETdodosettopinserts\relax
   \fi
   \OTRSETdodosettopinserts}

\unexpanded\def\page_set_command_set_bottom_insertions
  {\bgroup
   \ifconditional\c_page_floats_some_waiting
     \noffloatinserts\zerocount
     \OTRSETdodosetbotinserts
   \fi
   \egroup}

\def\OTRSETdodosetbotinserts
  {\ifnum\noffloatinserts<\c_page_floats_n_of_bottom\relax
     \page_floats_get
     \global\advance\d_page_floats_inserted_bottom\dimexpr\ht\floatbox+\dp\floatbox+\d_strc_floats_top\relax
     \ifdim\d_page_floats_inserted_bottom<\pagegoal\relax
       \insert\namedinsertionnumber\s!bottomfloat\bgroup
         \forgetall
         \blank[\rootfloatparameter\c!spacebefore]%
         \page_otr_command_flush_float_box
       \egroup
       \ifconditional\c_page_floats_some_waiting
         \advance\noffloatinserts \plusone
       \else
         \noffloatinserts\c_page_floats_n_of_bottom
       \fi
       \page_floats_report_flushed
     \else
       \OTRSETresavebox\floatbox
       \noffloatinserts\c_page_floats_n_of_bottom\relax
     \fi
     \global\settrue\c_page_floats_not_permitted % vgl topfloats s!
   \else
     \ifconditional\c_page_floats_some_waiting
       \showmessage\m!floatblocks7{\the\c_page_floats_n_of_bottom}%
     \fi
     \let\OTRSETdodosetbotinserts\relax
   \fi
   \OTRSETdodosetbotinserts}

\unexpanded\def\page_set_command_flush_top_insertions
  {\ifvoid\namedinsertionnumber\s!topfloat\else
     \ifvoid\columntopbox\mofcolumns
       \columnsettopbox\mofcolumns\box\namedinsertionnumber\s!topfloat
     \else
       \columnsettopbox\mofcolumns\vbox % temp, must be better
         {\forgetall
          \offinterlineskip
          \box\columntopbox\mofcolumns
          \box\namedinsertionnumber\s!topfloat}
     \fi
   \fi
   \global\d_page_floats_inserted_top\zeropoint\relax} % goes away

\unexpanded\def\page_set_command_flush_bottom_insertions
  {\ifvoid\namedinsertionnumber\s!bottomfloat \else
     \columnsetbotbox\mofcolumns\box\namedinsertionnumber\s!bottomfloat
%   \else
%     \columnsetbotbox\mofcolumns\vbox % temp, must be better
%       {\forgetall
%        \offinterlineskip
%        \box\namedinsertionnumber\s!bottomfloat
%        \box\columnbotbox\mofcolumns}
   \fi
   \global\d_page_floats_inserted_bottom\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

\installcorenamespace{columnsetarea}

\unexpanded\def\definecolumntextarea
  {\dotripleempty\dodefinecolumntextarea}

\def\dodefinecolumntextarea[#1][#2][#3]% y=0 is mogelijke en handig !
  {\ifthirdargument
     \doifelseinset{#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
          {\doifelseoddpage
             {\definecolumntextarea[#1][\v!right][\c!type=#2,#3]}
             {\definecolumntextarea[#1][\v!left ][\c!type=#2,#3]}}
          {\presetlocalframed
             [\??columnsetarea#1#2]%
           \processaction[#2] % \doglobal voorkomt stack build up
             [ \v!left=>\doglobal\addtocommalist{#1}\columnleftareas,
              \v!right=>\doglobal\addtocommalist{#1}\columnrightareas]%
           \getparameters[\??columnsetarea#1#2]
             [\c!x=1,\c!y=1,\c!nx=1,\c!ny=1,\c!clipoffset=2\lineheight,
              \c!leftoffset=\zeropoint,\c!rightoffset=\zeropoint,
              \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}

\unexpanded\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
          {\doifelseoddpage
             {\setupcolumntextarea[#1][\v!right][#3]}
             {\setupcolumntextarea[#1][\v!left][#3]}}
          {\getparameters[\??columnsetarea#1#2][#3]}}%
   \else
     \setupcolumntextarea[#1][\v!next][#2]%
   \fi}

\def\docheckcolumnsetareapage#1#2%
  {\ifnum\getvalue{\??columnsetarea#1\c!page}>\plusone
     \doifelsevalue{\??columnsetarea#1\c!type}\v!fixed
       {\ifnum\columnsetpage=\getvalue{\??columnsetarea#1\c!page}\relax
          \donetrue\else\donefalse
        \fi}
       {\ifnum\columnsetpage<\getvalue{\??columnsetarea#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{\??columnsetarea##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{\??columnsetarea#1#2\c!x }}{\getvalue{\??columnsetarea#1#2\c!y }}
     {\getvalue{\??columnsetarea#1#2\c!nx}}{\getvalue{\??columnsetarea#1#2\c!ny}}
     {\copy\placeholderboxd}}

\unexpanded\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{\??columnsetarea##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}

% \page[left]
% \definecolumntextarea[intro][left][x=1,y=1,nx=4,ny=20,state=start,background=introlayer]
% \setupcolumntextareatext[intro][left][\setups{intro}]
% \flushcolumntextareas

\def\flushcolumntextareas
  {\initializecolumntextareas
   \page_otr_command_set_vsize} % set ?

\def\columntextlastbackspace{\backspace}

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

\def\columntextareaparameter#1%
  {\csname\??columnsetarea\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
        [\??columnsetarea\currentcolumntestarea]
        [\c!location=,% new (*)
            \c!width=\!!widtha,\c!height=\!!heighta,\c!lines=]
        {\columntextareaparameter\empty{}}}% messy
   \!!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\hpack{\lower\strutdepth\box\scratchbox}%
      \dp\scratchbox\zeropoint
      \ht\scratchbox\!!heighta}%
   %
   \setbox0\hpack
     {\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=\columntextareaparameter\c!rightoffset,%
                   \c!width=\!!widthb,%
                  \c!height=\!!heighta]%
          {\copy\scratchbox}%
      \fi}%
   \page_set_cell_set\!!counta\!!countb\box0
   \ifcase\!!countc\else
     \advance\!!counta \columntextareaparameter\c!nx
     \advance\!!counta -\!!countc
     \advance\!!widtha -\!!widthb
     \setbox0\hpack
%        {\hskip-\namedlayoutparameter\v!odd\c!backspace
       {\hskip-\layoutparameter\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=\columntextareaparameter\c!leftoffset,%
                   \c!width=\!!widtha,%
                  \c!height=\!!heighta,%
                 \c!hoffset=\!!widthb]%
          {\copy\scratchbox}}%
     \page_set_cell_set\!!counta\!!countb\box0%
   \fi}

\unexpanded\def\setupcolumntextareatext
  {\dotripleempty\dosetupcolumntextareatext}

\def\dosetupcolumntextareatext[#1][#2][#3]%
  {\ifthirdargument
     \doifelse{#2}\v!both
       {\setvalue{\??columnsetarea#1\v!left }{#3}%
        \setvalue{\??columnsetarea#1\v!right}{#3}}
       {\doifelse{#2}\v!next
          {\doifelseoddpage
             {\setvalue{\??columnsetarea#1\v!right}{#3}}%
             {\setvalue{\??columnsetarea#1\v!left }{#3}}}%
          {\setvalue{\??columnsetarea#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\namedcolumnsetparameter{\currentcolumnset:\recurselevel}\c!distance}%
   \!!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
       \advance\!!widtha \layoutparameter\c!backspace
       \advance\!!widtha \layoutparameter\c!backspace
       \advance\!!widthb \layoutparameter\c!backspace
       \dorecurse\!!countc
         {\advance\!!widtha\namedcolumnsetparameter{\currentcolumnset:\recurselevel}\c!distance}%
     \fi
   \fi}

\def\columnsetspanhsize{\textwidth}

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

\unexpanded\def\page_set_command_set_float_hsize % this helper has to be moved to strc-flt
  {\hsize                % maybe checking optional
     \ifdim\d_strc_float_temp_width>\makeupwidth
       \makeupwidth
     \else
       \d_strc_float_temp_width
     \fi}

\installcorenamespace{columnsetspan}

\unexpanded\def\definecolumnsetspan
  {\dodoubleempty\dodefinecolumnsetspan}

\def\dodefinecolumnsetspan[#1][#2]%
  {%\ifsecondargument
     \defineframedtext % we can have a parent
       [\??columnsetspan#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]

\unexpanded\def\setupcolumnsetspan
  {\dodoubleempty\dosetupcolumnsetspan}

\def\dosetupcolumnsetspan[#1][#2]%
  {\ifsecondargument
     \setupframedtexts[\??columnsetspan#1][#2]%
   \else
     \setupcolumnsetspan[\s!default][#1]%
   \fi}

\unexpanded\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[\??columnsetspan#1]
     [\c!width=\columnsetspanhsize,
      \c!linecorrection=\v!off,
      \c!depthcorrection=\v!off,
      #2]%
   % determine widths
   \!!countc\namedframedtextparameter{\??columnsetspan#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{\namedframedtextparameter{\??columnsetspan#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
     \pack_framed_text_start{\??columnsetspan#1}[\v!none]% geen nils placement
     % spoils spacing : \vskip-\struttotal\par\verticalstrut\par
     \ifnum\columnsetlevel>\zerocount
       \namedframedtextparameter{\??columnsetspan#1}\c!before
     \fi
     \unexpanded\def\stopcolumnsetspan{\dostopcolumnsetspan{#1}}}

\def\dostopcolumnsetspan#1%
  {\par
   \verticalstrut
   \kern-2\struttotal
   \verticalstrut
   \ifnum\columnsetlevel>\zerocount
     \doifsomething{\namedframedtextparameter{\??columnsetspan#1}\c!after}
       {\namedframedtextparameter{\??columnsetspan#1}\c!after
        \kern\zeropoint}% otherwise blanks disappear, better be a switch
   \else
     \endgraf
   \fi
   \pack_framed_text_stop
   \egroup
   \setbox\scratchbox\frozenhbox to \hsize
     {\dontcomplain
      \alignedline{\namedframedtextparameter{\??columnsetspan#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
%    \alignstrutmode\zerocount
%    \alignedline{\namedframedtextparameter{\??columnsetspan#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)
     \columnslotspacing\namedframedtextparameter{\??columnsetspan#1}\c!nlines\relax
     % todo: nboven/onder
     %\OTRSETstoreincolumnslotHERE\scratchbox
     \edef\floatmethod{\namedframedtextparameter{\??columnsetspan#1}\c!default}%
     \expandafter\uppercasestring\floatmethod\to\floatmethod
     % todo : \v!here -> here enzovoorts
     \OTRSETstoreincolumnslot\floatmethod\scratchbox
     \checknextindentation[\namedframedtextparameter{\??columnsetspan#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
     \namedframedtextparameter{\??columnsetspan#1}\c!before
     \snaptogrid\vbox{\box\scratchbox}%
     \namedframedtextparameter{\??columnsetspan#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

\unexpanded\def\page_set_command_flush_saved_floats % rather similar to _one_ ut this might change
  {\global\d_page_floats_inserted_top\zeropoint
   \global\d_page_floats_inserted_bottom\zeropoint
   \ifconditional\c_page_floats_flushing \else
     \page_set_command_set_top_insertions
     \page_set_command_set_bottom_insertions
     \ifconditional\c_page_floats_some_waiting
        \doif{\rootfloatparameter\c!cache}\v!no\page_set_command_flush_floats % could be _otr_
     \fi
   \fi}

\unexpanded\def\page_set_command_flush_all_floats
  {\page_one_command_flush_all_floats}

\defineoutputroutine
  [\s!columnset]
  [\s!page_otr_command_routine                  =\page_set_command_routine,
   \s!page_otr_command_package_contents         =\page_set_command_package_contents,
   \s!page_otr_command_set_vsize                =\page_set_command_set_vsize,
 % \s!page_otr_command_set_hsize                =\page_one_command_set_hsize, % tricky, goes wrong
   \s!page_otr_command_synchronize_hsize        =\page_set_command_synchronize_hsize,
   \s!page_otr_command_next_page                =\page_set_command_next_page,
   \s!page_otr_command_next_page_and_inserts    =\page_set_command_next_page_and_inserts,
   \s!page_otr_command_set_top_insertions       =\page_set_command_set_top_insertions,
   \s!page_otr_command_set_bottom_insertions    =\page_set_command_set_bottom_insertions,
   \s!page_otr_command_flush_top_insertions     =\page_set_command_flush_top_insertions,
   \s!page_otr_command_flush_bottom_insertions  =\page_set_command_flush_bottom_insertions,
   \s!page_otr_command_check_if_float_fits      =\page_set_command_check_if_float_fits,
   \s!page_otr_command_set_float_hsize          =\page_set_command_set_float_hsize,
   \s!page_otr_command_flush_float_box          =\page_set_command_flush_float_box,
   \s!page_otr_command_side_float_output        =\page_set_command_side_float_output,
   \s!page_otr_command_synchronize_side_floats  =\page_set_command_synchronize_side_floats,
   \s!page_otr_command_flush_floats             =\page_set_command_flush_floats,
   \s!page_otr_command_flush_side_floats        =\page_set_command_flush_side_floats,
   \s!page_otr_command_flush_saved_floats       =\page_set_command_flush_saved_floats,
   \s!page_otr_command_flush_all_floats         =\page_set_command_flush_all_floats,
 % \s!page_otr_command_flush_margin_blocks      =\page_set_command_flush_margin_blocks, % not used
  ]

\installfloatmethod \s!columnset \v!here   \page_set_place_float_here
\installfloatmethod \s!columnset \v!force  \page_set_place_float_force
\installfloatmethod \s!columnset \v!top    \page_set_place_float_top
\installfloatmethod \s!columnset \v!bottom \page_set_place_float_bottom
\installfloatmethod \s!columnset \v!page   \page_set_place_float_page
\installfloatmethod \s!columnset \s!tblr   \page_set_place_float_slot
\installfloatmethod \s!columnset \s!lrtb   \page_set_place_float_slot
\installfloatmethod \s!columnset \s!tbrl   \page_set_place_float_slot
\installfloatmethod \s!columnset \s!rltb   \page_set_place_float_slot
\installfloatmethod \s!columnset \s!fxtb   \page_set_place_float_slot
\installfloatmethod \s!columnset \s!btlr   \page_set_place_float_slot
\installfloatmethod \s!columnset \s!lrbt   \page_set_place_float_slot
\installfloatmethod \s!columnset \s!btrl   \page_set_place_float_slot
\installfloatmethod \s!columnset \s!rlbt   \page_set_place_float_slot
\installfloatmethod \s!columnset \s!fxbt   \page_set_place_float_slot
\installfloatmethod \s!columnset \s!fixd   \page_set_place_float_force

\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

% only in columnsets

% \def\cornerfigure
%   {\dotripleempty\docornerfigure}
%
% \def\docornerfigure[#1][#2][#3]% [layer] [location] [settings]
%   {\bgroup
%    \dowithnextbox
%      {\!!doneafalse
%       \!!donebfalse
%       \processallactionsinset
%         [\v!left,\v!bottom,#2]
%         [ \v!left=>\!!doneatrue ,
%          \v!right=>\!!doneafalse,
%           \v!top=>\!!donebtrue ,
%           \v!bottom=>\!!donebfalse]%
%       \!!widtha\nextboxwd
%       \if!!donea
%         % unchecked
%         \advance\!!widtha-\backspace
%       \else
%         % unchecked
%         \advance\!!widtha-\backspace
%       \fi
%       \!!widtha\textwidth % could be an option
%       \!!heighta\nextboxht
%       % zou een macro moeten zijn \getnoflayoutlines
%       \ifnum\layoutparameter\c!lines=\zerocount
%         \getnoflines\textheight
%       \else
%         \noflines\layoutparameter\c!lines
%       \fi
%       %
%       \advance\noflines \plusone % wordt default, instelbaar
%       \!!heightb\noflines\lineheight\relax
%       \if!!doneb % boven
%         % unchecked
%         \advance\!!heighta-\topspace
%         \advance\!!heighta-\headerheight
%         \advance\!!heighta-\headerdistance
%       \else % onder
%         % checked
%         \advance\!!heighta-\paperheight
%         \advance\!!heighta+\!!heightb
%         \advance\!!heighta+\topspace
%         \advance\!!heighta+\headerheight
%         \advance\!!heighta+\headerdistance
%         \advance\!!heighta-\footerdistance
%         \advance\!!heighta-\footerheight
%       \fi
%       \getnoflines\!!heighta
%       \!!heighta\noflines\lineheight\relax
%       \def\docornerfigure[####1]%
%         {\expanded{\plaatsfiguur[####1,\v!none]{}
%            {\noexpand\phantombox[\c!width=\the\!!widtha,\c!height=\the\!!heighta]}}}%
%       \if!!donea
%         \if!!doneb % links  boven / rb
%           \setlayer[#1]
%             [\c!corner={\v!left,\v!top},\c!location=rb,#3]
%             {\flushnextbox}%
%           \docornerfigure[tblr]%
%         \else      % links  onder / rt
%           \setlayer[#1]
%             [\c!corner={\v!left,\v!bottom},\c!location=rt,#3]
%             {\flushnextbox}%
%           \docornerfigure[btlr]%
%         \fi
%       \else
%         \if!!doneb % rechts boven / lt
%           \setlayer[#1]
%             [\c!corner={\v!right,\v!top},\c!location=lb,#3]
%             {\flushnextbox}%
%           \docornerfigure[tbrl]%
%         \else      % rechts onder / lb
%           \setlayer[#1]
%             [\c!corner={\v!right,\v!bottom},\c!location=lt,#3]
%             {\flushnextbox}%
%           \docornerfigure[btrl]%
%         \fi
%       \fi
%       \egroup}
%    \vbox}