page-pcl.mkiv / last modification: 2020-01-30 14:16
%D \module
%D   [       file=page-pcl,
%D        version=2017.11.08,
%D          title=\CONTEXT\ Page Macros,
%D       subtitle=Page Columns,
%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.

\writestatus{loading}{ConTeXt Page Macros / Page Columns}

%D This is very experimental code! We took a bit from the mixed columns and single
%D column page code. This one works acceptable with floats and is for whole double
%D column documents. We don't balance (yet). Footnotes are per column. One can have
%D side floats too. No balancing and other fancy features.
%D
%D Don't use this in production! Although the main approach will stay there might be
%D changes in the way floats are dealt with. Not much testing has been done but as
%D we stay close to the single column mode we expect most to just work. Only floats
%D are the (usual) pain. Backgrounds, line numbering, etc.\ not tested either.

\unprotect

\definemeasure[onecolumn]   [\columnwidth]
\definemeasure[twocolumns]  [\dimexpr\plustwo  \columnwidth+          \columndistance\relax]
\definemeasure[threecolumns][\dimexpr\plusthree\columnwidth+\plustwo  \columndistance\relax]
\definemeasure[fourcolumns] [\dimexpr\plusfour \columnwidth+\plusthree\columndistance\relax]

\newcount      \c_page_col_n_of_columns \c_page_col_n_of_columns\plusone
\newcount      \c_page_col_current      \c_page_col_current     \plusone
\newdimen      \d_page_col_distance
\newdimen      \d_page_col_max_height
\newdimen      \d_page_col_max_width
%newdimen      \d_page_col_balance_step
\newdimen      \d_page_col_column_width
\newdimen      \d_page_col_top_height
\newdimen      \d_page_col_top_width
\newdimen      \d_page_col_available
\newdimen      \d_page_col_sofar
\newconditional\c_page_col_page

%D We need to step over empty columns.

\unexpanded\def\page_col_command_next_page
  {\page_col_eject_page}

\unexpanded\def\page_col_column
  {\page_otr_eject_page}

\unexpanded\def\page_col_eject_page
  {\begingroup
   \scratchcountertwo  \realpageno
   \page_otr_eject_page
   \scratchcounterone  \c_page_col_current
   \scratchcounterthree\zerocount
   \doloop{%
     \ifnum\scratchcounterthree>\plushundred
       % too many attempts
       \exitloop
     \else\ifnum\realpageno>\scratchcountertwo
       % we advanced at least one page so we're done
       \exitloop
     \else
       \ifnum\scratchcounterone=\c_page_col_current
          \dontleavehmode\null
       \fi
       \page_otr_eject_page
       \scratchcounterone\c_page_col_current
       \advance\scratchcounterthree\plusone
     \fi\fi
   }%
   \endgroup}

%D \unknown

\unexpanded\def\page_col_command_next_page_and_inserts
  {\page_otr_eject_page_and_flush_inserts}

%D \unknown

\unexpanded\def\page_col_command_set_hsize
  {\global\hsize\d_page_col_column_width\relax
   \global\d_page_col_available\dimexpr
      \numexpr\c_page_col_n_of_columns-\c_page_col_current+\plusone\relax\d_page_col_column_width
    + \numexpr\c_page_col_n_of_columns-\c_page_col_current         \relax\d_page_col_distance
   \relax
   \global\d_page_col_sofar
   \ifnum\c_page_col_n_of_columns=\plusone
     \zeropoint
   \else
     \numexpr\c_page_col_n_of_columns-\plusone\relax
     \dimexpr\d_page_col_column_width+\d_page_col_distance\relax
   \fi
   % consistent with mixed:
   \textwidth\d_page_col_column_width}

%D \unknown

\unexpanded\def\page_col_command_set_vsize % \page_one_command_set_vsize minus the pagegoal setting
  {\ifgridsnapping
     \ifcase\layoutlines
       \getrawnoflines\textheight
     \else
       \noflines\layoutlines
     \fi
     \global\vsize\noflines\openlineheight
   \else
     \global\vsize\textheight
   \fi}

%D \unknown

\def\page_col_registered_text_area_b#1%
  {\begingroup
   \makeupwidth\d_page_col_column_width
   \page_one_registered_text_area_b{#1}%
   \endgroup}

\unexpanded\def\page_col_command_package_contents#1#2% \box<n> \unvbox<n> % this one will be redone (checked)
  {\bgroup
   \setbox\b_page_one_contents\vbox to \textheight
     {\page_one_registered_text_area_a#1#2}%
   \page_one_command_package_show_state
   \ht\b_page_one_contents\textheight
   \page_col_registered_text_area_b
     {\box\b_page_one_contents}%
   \egroup}

\unexpanded\def\page_col_command_package_contents_one#1#2% \box<n> \unvbox<n> % this one will be redone (checked)
  {\bgroup
     \forgetall
     % see one for comments as it is similar
     \strc_notes_check_if_bottom_present
     \d_page_one_natural_depth\dp#2\relax
     \setbox\b_page_one_contents\vbox to \textheight
       {\page_col_command_flush_top_insertions
        \page_one_registered_text_area_a#1#2%
        \hsize\d_page_col_column_width
        \ifgridsnapping
          \vskip\dimexpr\openstrutdepth-\d_page_one_natural_depth\relax
          \prevdepth\openstrutdepth
          \page_col_command_flush_bottom_insertions
          \vfil
        \else\ifcase\bottomraggednessmode
          % ragged (default)
          \vskip\dimexpr\openstrutdepth-\d_page_one_natural_depth\relax
          \prevdepth\openstrutdepth
          \page_col_command_flush_bottom_insertions
          \vfil
        \or
          % align (normal)
          \page_col_command_flush_bottom_insertions
        \or
          % baseline
          \kern\dimexpr\maxdepth-\d_page_one_natural_depth\relax
          \page_col_command_flush_bottom_insertions
        \fi\fi
        \fakepagenotes}%
     \page_one_command_package_show_state
     \ifconditional\c_notes_bottom_present
       \ifgridsnapping
         \ifcase\layoutlines
           \getrawnoflines\textheight
         \else
           \noflines\layoutlines
         \fi
         \scratchoffset\dimexpr\numexpr\noflines-\plusone\relax\lineheight+\topskip\relax
       \else
         \scratchoffset\ht\b_page_one_contents
       \fi
       \setbox\b_page_one_bottom_notes\hpack
         {\checksinglecolumnfootnotes % ?
          \hsize\d_page_col_column_width
          \setupnotes[\c!width=\textwidth]%
          \lower\scratchoffset\vbox{\placebottomnotes\par\kern\zeropoint}}%
      \ht\b_page_one_contents    \zeropoint
      \wd\b_page_one_contents    \zeropoint
      \ht\b_page_one_bottom_notes\zeropoint
      \wd\b_page_one_bottom_notes\zeropoint
      \wd\b_page_one_bottom_notes\d_page_col_column_width
       \page_col_registered_text_area_b
         {\vpack to \textheight
            {\hpack{\box\b_page_one_contents\box\b_page_one_bottom_notes}}}%
     \else
       \ht\b_page_one_contents\textheight
       \wd\b_page_one_contents\d_page_col_column_width
       \page_col_registered_text_area_b
         {\box\b_page_one_contents}%
     \fi
   \egroup}

%D \unknown

\unexpanded\def\page_col_command_side_float_output
  {% % %
   \ifvoid\namedinsertionnumber\s!topfloat\else
     \scratchwidth\wd\namedinsertionnumber\s!topfloat
     \ifdim\scratchwidth>\d_page_col_top_width
       \global\d_page_col_top_width \scratchwidth
     \fi
     \global\d_page_col_top_height\ht\namedinsertionnumber\s!topfloat
   \fi
   % % %
   \setbox\scratchbox\vbox\bgroup
      \page_col_command_package_contents_one\unvbox\normalpagebox
   \egroup
   \putboxincache\s!pagecolumn{\number\c_page_col_current}\scratchbox
   \ifnum\c_page_col_current=\c_page_col_n_of_columns
     \page_col_routine_package
     \page_otr_construct_and_shipout\box\normalpagebox\plusone
     \global\c_page_col_current\plusone
     \global\d_page_col_top_height\zeropoint
     \global\d_page_col_top_width\zeropoint
   % \page_col_command_flush_top_insertions
   % \page_col_command_flush_floats
   \else
     \ifdim\d_page_col_top_width>\zeropoint
       \ifdim\dimexpr\d_page_col_top_width>\d_page_col_sofar\relax
         \begingroup
         \floatingpenalty\zerocount
         \insert\namedinsertionnumber\s!topfloat\bgroup
           \vbox to \d_page_col_top_height{\vss}
             % can be an option
             \page_col_command_flush_top_insertions
             \page_col_command_flush_floats
             % so far till option
           \egroup
         \endgroup
       \fi
     \fi
     \global\advance\c_page_col_current\plusone
   \fi
   %
   \page_col_command_set_vsize
   \page_col_command_set_hsize}

% use \currentmixedcolumns instead of \recurselevel

\def\page_col_routine_package_step
  {% needs packaging anyway
   \getboxfromcache{\s!pagecolumn}{\number\recurselevel}\scratchbox
   \page_lines_add_numbers_to_box\scratchbox\recurselevel\c_page_col_n_of_columns\plusone % new
   \page_marks_synchronize_column\plusone\c_page_col_n_of_columns\recurselevel\scratchbox
   % backgrounds
   \anch_mark_column_box\scratchbox\recurselevel
   \mixedcolumnseparatorheight\ht\scratchbox
   \mixedcolumnseparatordepth \dp\scratchbox
   \inheritedpagecolumnsframedbox\recurselevel\scratchbox}

\def\page_col_routine_package
  {\global\setbox\normalpagebox\hbox to \makeupwidth\bgroup
     \edef\p_separator{\pagecolumnsparameter\c!separator}%
     \pagecolumnseparatorwidth\d_page_col_distance
     \edef\p_direction{\pagecolumnsparameter\c!direction}%
     \ifx\p_direction\v!reverse
       \dostepwiserecurse\c_page_col_n_of_columns\plusone\minusone
         {\page_col_routine_package_step
          \ifnum\recurselevel>\plusone
            \page_col_routine_package_separate
          \fi}%
     \else
       \dorecurse\c_page_col_n_of_columns
         {\page_col_routine_package_step
          \ifnum\recurselevel<\c_page_col_n_of_columns
            \page_col_routine_package_separate
          \fi}%
     \fi
   \egroup
   \resetboxesincache{\s!pagecolumn}}

%D \unknown

% \unexpanded\def\page_col_command_check_if_float_fits
%   {\ifconditional\c_page_floats_not_permitted
%      \global\setfalse\c_page_floats_room
%   %\else\ifabsdim\dimexpr\d_page_col_available-\naturalfloatwd\relax<\onepoint
%    \else\ifdim\dimexpr\d_page_col_available-\naturalfloatwd\relax>-\onepoint
%      \global\settrue\c_page_floats_room
%    \else
%      \global\setfalse\c_page_floats_room
%    \fi\fi
%    \ifconditional\c_page_floats_room
%      \begingroup
%      \scratchdimen\dimexpr\pagetotal+\lineheight\relax
%      \ifdim\scratchdimen>\pagegoal
%        \goodbreak
%        \ifdim\dimexpr\d_page_col_available-\naturalfloatwd\relax>\onepoint
%          \global\setfalse\c_page_floats_room
%        \else
%          \global\settrue\c_page_floats_room
%        \fi
%      \fi
%      \endgroup
%    \fi
%    \ifconditional\c_page_floats_room
%      \ifdim\pagetotal>\zeropoint
%        \scratchdimenone\dimexpr\pagetotal+\floatheight+\d_strc_floats_top-\pageshrink\relax
%        \scratchdimentwo\pagegoal
%        \relax % needed
%        \ifcase\c_page_one_float_method
%          % method 0 : raw
%        \or
%          % method 1 : safe
%          \advance\scratchdimentwo -\strutdp
%        \or
%          % method 2 : tight
%          \advance\scratchdimenone -\onepoint
%        \fi
%        \relax % really needed ! ! ! !
%        \ifdim\scratchdimenone>\scratchdimentwo
%          \global\setfalse\c_page_floats_room
%        \fi
%      \fi
%      \ifconditional\c_page_floats_room
%        \global\setbox\floatbox\hpack to \d_page_col_available{\hss\box\floatbox\hss}%
%      \fi
%    \fi}

\unexpanded\def\page_col_command_check_if_float_fits
  {\ifconditional\c_page_floats_not_permitted
     % forget about it anyway
     \global\setfalse\c_page_floats_room
   \else
     % first we check the current column
%      \ifdim\dimexpr\d_page_col_width-\naturalfloatwd\relax>-\onepoint
     \ifdim\dimexpr\hsize-\naturalfloatwd\relax>-\onepoint
       \global\settrue\c_page_floats_room
     \else
       \global\setfalse\c_page_floats_room
     \fi
     \ifconditional\c_page_floats_room
       % we fit in the column but do we have room
       \ifdim\dimexpr\pagetotal+\lineheight\relax>\pagegoal
         % try again later
         \goodbreak
       \fi
       \ifdim\pagetotal>\zeropoint
         \scratchdimenone\dimexpr\pagetotal+\floatheight+\d_strc_floats_top-\pageshrink\relax
         \scratchdimentwo\pagegoal
         \relax % needed
         \ifcase\c_page_one_float_method
           % method 0 : raw
         \or
           % method 1 : safe
           \advance\scratchdimentwo -\strutdp
         \or
           % method 2 : tight
           \advance\scratchdimenone -\onepoint
         \fi
         \relax % really needed ! ! ! !
         \ifdim\scratchdimenone>\scratchdimentwo
           % there is no room, give up
           \global\setfalse\c_page_floats_room
           % now we can decide on a top float
%          \fi
         \else
%            \ifconditional\c_page_floats_room
%              \global\setbox\floatbox\hpack to \d_page_col_float_available{\hss\box\floatbox\hss}%
%            \fi
         \fi
       \fi
     \fi
   \fi}

%D \unknown

\def\page_col_set_float_pack_hsize
  {\ifnum\c_page_col_current=\c_page_col_n_of_columns
     \c_page_col_current\plusone
   \else
     \advance\c_page_col_current\plusone
   \fi
   \page_col_command_set_hsize
   \hsize\d_page_col_available}

\unexpanded\def\page_col_command_flush_floats
  {\global\settrue\c_page_floats_flushing
   \ifconditional\c_page_floats_some_waiting
     \par
     \page_col_set_float_pack_hsize
     \page_col_command_flush_floats_indeed
   \fi
   \global\savednoffloats\zerocount
   \global\setfalse\c_page_floats_some_waiting
   \global\setfalse\c_page_floats_flushing}

\def\page_floats_show_pack_state_indeed#1%
  {\llap{\smash{\backgroundline[black]{\strut\smallinfofont\white#1\space\the\nofcollectedfloats\space of\space\the\savednoffloats:\the\hsize}}\hskip.25\emwidth}}

\installtextracker
  {floats.collecting}
  {\let\page_floats_show_pack_state\page_floats_show_pack_state_indeed}
  {\let\page_floats_show_pack_state\gobbleoneargument}

\let\page_floats_show_pack_state\gobbleoneargument

\def\page_col_command_flush_floats_indeed % much in common with OTRSET
  {\ifconditional\c_page_floats_some_waiting
     \ifconditional\c_page_floats_compress_flushed
       \setfalse\c_page_floats_center_box % not needed as we do call directly
       \page_floats_collect\s!text\hsize\d_page_floats_compress_distance
       %
       \ifnum\nofcollectedfloats=\plusone
         \ifdim\naturalfloatwd>\hsize
           \nofcollectedfloats\zerocount
         \fi
       \fi
       \ifnum\nofcollectedfloats>\zerocount
         \global\setbox\floatbox\hpack to \hsize
           {\page_floats_show_pack_state F%
            \hfil
            \dorecurse\nofcollectedfloats
              {\ifcase\columndirection % nog document wide
                 \page_floats_flush\s!text\plusone
               \else
                 \page_floats_flush\s!text{\the\numexpr\nofcollectedfloats-\recurselevel+1\relax}%
               \fi
               % this could happen at the lua end instead
               \scratchdimen\dimexpr\wd\floatbox-\naturalfloatwd\relax
               \ifdim\scratchdimen<\zeropoint
                 \global\setbox\floatbox\hpack spread -\scratchdimen{\hss\box\floatbox\hss}%
               \fi
               %
               \ifdim\wd\floatbox>\textwidth % \hsize
                 \hpack to \textwidth{\hss\box\floatbox\hss}% \textwidth
               \else
                 \box\floatbox
               \fi
               \ifnum\recurselevel<\nofcollectedfloats
                 \hfil
               \fi}%
            \hfil}%
           \doplacefloatbox
         % \page_one_insert_top_float
           \doubleexpandafter\page_col_command_flush_floats_indeed
       \else
         % todo
       \fi
     \else
       \page_floats_get
     % \page_one_insert_top_float
       \doplacefloatbox
       \doubleexpandafter\page_col_command_flush_floats_indeed
     \fi
   \fi}

\unexpanded\def\page_col_command_flush_saved_floats % like one
  {\global\d_page_floats_inserted_top\zeropoint
   \global\d_page_floats_inserted_bottom\zeropoint
   \ifconditional\c_page_floats_flushing \else
     \page_col_command_set_top_insertions
     \page_col_command_set_bottom_insertions
     \ifconditional\c_page_floats_some_waiting
        \doif{\rootfloatparameter\c!cache}\v!no\page_col_command_flush_floats % could be _otr_
     \else\ifconditional\c_page_margin_blocks_present
       \page_col_command_flush_floats
     \fi\fi
   \fi}

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

\def\d_page_col_collected_top_float_height % pseudo
  {\dimexpr
     \d_page_floats_inserted_top +
     \maxcollectedfloatstotal +
     \ifdim\d_strc_floats_top>\d_strc_floats_bottom
       \d_strc_floats_top
     \else
       \d_strc_floats_bottom
     \fi
   \relax}

\def\page_col_command_set_top_insertions_indeed
  {\ifnum\noffloatinserts<\c_page_floats_n_of_top
     \ifcase\savednoffloats
       \let\page_col_command_set_top_insertions_indeed\relax
     \else
       \page_floats_collect\s!text\hsize\emwidth
       \ifdim\d_page_col_collected_top_float_height<\textheight
         \global\setbox\floatbox\hpack to \hsize
           {\page_floats_show_pack_state T%
            \hfil
            \dorecurse\nofcollectedfloats
              {\ifcase\columndirection % nog document wide
                 \page_floats_flush\s!text\plusone
               \else
                 \page_floats_flush\s!text{\the\numexpr\nofcollectedfloats-\recurselevel+1\relax}%
               \fi
               % this could happen at the lua end instead
               \scratchdimen\dimexpr\wd\floatbox-\naturalfloatwd\relax
               \ifdim\scratchdimen<\zeropoint
                   \global\setbox\floatbox\hpack spread -\scratchdimen{\hss\box\floatbox\hss}%
               \fi
               %
               \ifdim\wd\floatbox>\makeupwidth % \hsize
                 \hpack to \makeupwidth{\hss\box\floatbox\hss}%
               \else
                 \box\floatbox
               \fi
               \ifnum\recurselevel<\nofcollectedfloats
                 \hfil
               \fi}%
            \hfil}%
         \page_one_prepare_top_float
         \xdef\totaltopinserted{\the\d_page_floats_inserted_top}%
         \page_one_insert_top_float
         \ifconditional\c_page_floats_some_waiting
           \advance\noffloatinserts \plusone
         \else
           \noffloatinserts\c_page_floats_n_of_top\relax
         \fi
         \page_floats_report_flushed
      \else
         \let\page_col_command_set_top_insertions_indeed\relax
       \fi
     \fi
   \else
     \ifconditional\c_page_floats_some_waiting
       \showmessage\m!floatblocks6{\the\c_page_floats_n_of_top}%
     \fi
     \let\page_col_command_set_top_insertions_indeed\relax
   \fi
   \page_col_command_set_top_insertions_indeed}

\let\page_col_command_flush_top_insertions   \page_one_command_flush_top_insertions
\let\page_col_command_flush_bottom_insertions\page_one_command_flush_bottom_insertions

%let\page_col_command_set_top_insertions            \page_one_command_set_top_insertions
\let\page_col_command_set_bottom_insertions         \page_one_command_set_bottom_insertions

%let\page_col_command_set_top_insertions_indeed     \page_one_command_set_top_insertions
\let\page_col_command_set_bottom_insertions_indeed  \page_one_command_set_botttom_insertions

\let\page_col_command_flush_float_box               \page_one_command_flush_float_box
\let\page_col_command_synchronize_side_floats       \page_one_command_synchronize_side_floats
\let\page_col_command_flush_side_floats             \page_one_command_flush_side_floats
\let\page_col_command_flush_margin_blocks           \page_one_command_flush_margin_blocks
\let\page_col_command_test_page                     \page_one_command_test_page

%D The separator code is more or less the same as mixed columns but we need
%D to compensate for the top floats so we comment a bit for now.

\newdimen\pagecolumnseparatorheight
\newdimen\pagecolumnseparatordepth
\newdimen\pagecolumnseparatorwidth

% \installcorenamespace{pagecolumnsseparator}
%
% \unexpanded\def\installpagecolumnseparator#1#2%
%   {\setvalue{\??pagecolumnsseparator#1}{#2}}
%
% \installpagecolumnseparator\v!rule
%   {\vrule
%      \s!width \pagecolumnsparameter\c!rulethickness
%      \s!height\pagecolumnseparatorheight
%      \s!depth \pagecolumnseparatordepth
%    \relax}
%
% \def\page_col_routine_package_separate
%   {\ifcsname\??pagecolumnsseparator\p_separator\endcsname
%      \page_col_command_inject_separator
%    \else
%      \hss
%    \fi}
%
% \unexpanded\def\page_col_command_inject_separator
%   {\begingroup
%    \setbox\scratchbox\hbox to \zeropoint \bgroup
%      \hss
%      \starttextproperties
%      \usepagecolumnscolorparameter\c!rulecolor
%      \begincsname\??pagecolumnsseparator\p_separator\endcsname % was \c!rule
%      \stoptextproperties
%      \hss
%    \egroup
%    \ht\scratchbox\zeropoint
%    \dp\scratchbox\zeropoint
%    \hss
%    \box\scratchbox
%    \hss
%    \endgroup}

\def\page_col_routine_package_separate
  {\hss}

%D \unknown

\unexpanded\def\page_col_command_routine
  {\page_sides_output_routine}

% % not:
%
% \unexpanded\def\page_col_command_routine
%   {\ifconditional\c_page_sides_short
%      \page_sides_output_routine_yes_column
%    \else
%      \page_sides_output_routine_nop_column
%    \fi}
%
% \let\page_sides_output_routine_nop_column\page_sides_output_routine
%
% \def\page_sides_output_routine_yes_column % this might become the main one too
%   {\unvbox\normalpagebox % bah, and the discards?
%   %\page_col_column
%    \column % \page
%    % why was this \global\holdinginserts\zerocount
%    \global\setfalse\c_page_sides_short}

\let\page_col_command_flush_all_floats\relax

%D \unknown

\defineoutputroutine
  [\s!pagecolumn]
  [\s!page_otr_command_routine                =\page_col_command_routine,
   \s!page_otr_command_package_contents       =\page_col_command_package_contents,
   \s!page_otr_command_set_vsize              =\page_col_command_set_vsize,
   \s!page_otr_command_set_hsize              =\page_col_command_set_hsize,
 % \s!page_otr_command_synchronize_hsize      =\page_col_command_synchronize_hsize, % not done
   \s!page_otr_command_next_page              =\page_col_command_next_page,
   \s!page_otr_command_next_page_and_inserts  =\page_col_command_next_page_and_inserts,
   \s!page_otr_command_set_top_insertions     =\page_col_command_set_top_insertions,
   \s!page_otr_command_set_bottom_insertions  =\page_col_command_set_bottom_insertions,
   \s!page_otr_command_flush_top_insertions   =\page_col_command_flush_top_insertions,
   \s!page_otr_command_flush_bottom_insertions=\page_col_command_flush_bottom_insertions,
   \s!page_otr_command_check_if_float_fits    =\page_col_command_check_if_float_fits,
 % \s!page_otr_command_set_float_hsize        =\page_col_command_set_float_hsize,   % not done
   \s!page_otr_command_flush_float_box        =\page_col_command_flush_float_box,
   \s!page_otr_command_side_float_output      =\page_col_command_side_float_output,
   \s!page_otr_command_synchronize_side_floats=\page_col_command_synchronize_side_floats,
   \s!page_otr_command_flush_floats           =\page_col_command_flush_floats,
   \s!page_otr_command_flush_side_floats      =\page_col_command_flush_side_floats,
   \s!page_otr_command_flush_saved_floats     =\page_col_command_flush_saved_floats,
   \s!page_otr_command_flush_all_floats       =\page_col_command_flush_all_floats,
   \s!page_otr_command_flush_margin_blocks    =\page_col_command_flush_margin_blocks,
   \s!page_otr_command_test_column            =\page_col_command_test_page
  ]

%D \unknown

\installfloatmethod \s!pagecolumn \v!here        \page_one_place_float_here
\installfloatmethod \s!pagecolumn \v!force       \page_one_place_float_force
\installfloatmethod \s!pagecolumn \v!left        \page_one_place_float_left
\installfloatmethod \s!pagecolumn \v!right       \page_one_place_float_right
\installfloatmethod \s!pagecolumn \v!text        \page_one_place_float_text
\installfloatmethod \s!pagecolumn \v!top         \page_one_place_float_top
\installfloatmethod \s!pagecolumn \v!bottom      \page_one_place_float_bottom
\installfloatmethod \s!pagecolumn \v!auto        \page_one_place_float_auto
\installfloatmethod \s!pagecolumn \v!margin      \page_one_place_float_margin
\installfloatmethod \s!pagecolumn \v!opposite    \page_one_place_float_face
\installfloatmethod \s!pagecolumn \v!page        \page_one_place_float_page
\installfloatmethod \s!pagecolumn \v!leftpage    \page_one_place_float_leftpage
\installfloatmethod \s!pagecolumn \v!rightpage   \page_one_place_float_rightpage
\installfloatmethod \s!pagecolumn \v!inmargin    \page_one_place_float_inmargin
\installfloatmethod \s!pagecolumn \v!inleft      \page_one_place_float_leftmargin
\installfloatmethod \s!pagecolumn \v!inright     \page_one_place_float_rightmargin
\installfloatmethod \s!pagecolumn \v!leftmargin  \page_one_place_float_leftmargin
\installfloatmethod \s!pagecolumn \v!rightmargin \page_one_place_float_rightmargin
\installfloatmethod \s!pagecolumn \v!leftedge    \page_one_place_float_leftedge
\installfloatmethod \s!pagecolumn \v!rightedge   \page_one_place_float_rightedge
\installfloatmethod \s!pagecolumn \v!somewhere   \page_one_place_float_somewhere
\installfloatmethod \s!pagecolumn \v!backspace   \page_one_place_float_backspace
\installfloatmethod \s!pagecolumn \v!cutspace    \page_one_place_float_cutspace
%installfloatmethod \s!pagecolumn \s!tblr        \page_one_place_float_top
%installfloatmethod \s!pagecolumn \s!lrtb        \page_one_place_float_top
%installfloatmethod \s!pagecolumn \s!tbrl        \page_one_place_float_top
%installfloatmethod \s!pagecolumn \s!fxtb        \page_one_place_float_top
%installfloatmethod \s!pagecolumn \s!rltb        \page_one_place_float_top
%installfloatmethod \s!pagecolumn \s!btlr        \page_one_place_float_bottom
%installfloatmethod \s!pagecolumn \s!lrbt        \page_one_place_float_bottom
%installfloatmethod \s!pagecolumn \s!btrl        \page_one_place_float_bottom
%installfloatmethod \s!pagecolumn \s!rlbt        \page_one_place_float_bottom
%installfloatmethod \s!pagecolumn \s!fxbt        \page_one_place_float_bottom
%installfloatmethod \s!pagecolumn \s!fixd        \page_one_place_float_force

\installfloatmethod \s!pagecolumn \v!local       \somelocalfloat

%D The main interface:

\installcorenamespace{pagecolumns}

\installframedcommandhandler \??pagecolumns {pagecolumns} \??pagecolumns

\setuppagecolumns
  [\c!distance=1.5\bodyfontsize,
   \c!n=\plustwo,
   \c!page=\v!yes,
  %\c!align=, % inherit (also replaces tolerance)
  %\c!before=,
  %\c!after=,
  %\c!separator=\v!none,
  %\c!setups=,
  %\c!balance=\v!no,
  %\c!blank={\v!line,\v!fixed}, yes or no
   \c!frame=\v!off,
   \c!strut=\v!no,
   \c!offset=\v!overlay,
  %\c!maxheight=\textheight,
   \c!maxwidth=\makeupwidth,
  %\c!grid=\v!tolerant,
  %\c!internalgrid=\v!line,
   \c!direction=\v!normal]

\let\startpagecolumns\relax % defined later
\let\stoppagecolumns \relax % defined later

\appendtoks % could become an option
    \setuevalue{\e!start\currentpagecolumns}{\startpagecolumns[\currentpagecolumns]}%
    \setuevalue{\e!stop \currentpagecolumns}{\stoppagecolumns}%
\to \everydefinepagecolumns

\def\page_col_pickup_preceding
  {\begingroup
   \setupoutputroutine[\s!mixedcolumn]%
   \c_page_mix_routine\c_page_mix_routine_intercept
   \page_otr_trigger_output_routine
   \ifvoid\b_page_mix_preceding \else
     % moved here, before the packaging
     \page_postprocessors_linenumbers_deepbox\b_page_mix_preceding
     % we need to avoid unvboxing with successive balanced on one page
     \global\setbox\b_page_mix_preceding\vbox\bgroup
       % yes or no: \forcestrutdepth
       \unvbox\b_page_mix_preceding
       \forcestrutdepth
     \egroup
     \wd\b_page_mix_preceding\makeupwidth
     \global\d_page_mix_preceding_height\ht\b_page_mix_preceding
   \fi
   \endgroup}

\def\page_col_flush_preceding
  {\ifvoid\b_page_mix_preceding \else
     % this is just one method but ok for now
     \begingroup
     % we might need more but for now this is ok
     \setupfloat[\c!spacebefore=,\c!spaceafter=]%
     \startplacefigure[\c!location={\v!top,\v!none}]%
       \box\b_page_mix_preceding
     \stopplacefigure
     \endgroup
   \fi}

\unexpanded\def\startpagecolumns
  {\begingroup
   \begingroup
   \dosingleempty\page_col_start}

\unexpanded\def\page_col_start[#1]%
  {\doifelseassignment{#1}%
     {\let\currentpagecolumns\empty
      \setuppagecolumns[#1]}%
     {\edef\currentpagecolumns{#1}}%
   \edef\p_page{\pagecolumnsparameter\c!page}%
   \ifx\p_page\empty
     \setfalse\c_page_col_page
   \else\ifx\p_page\v!no
     \setfalse\c_page_col_page
   \else
     \settrue\c_page_col_page
     \page[\p_page]%
   \fi\fi
   \c_page_col_n_of_columns\pagecolumnsparameter\c!n\relax
   \ifnum\c_page_col_n_of_columns>\plusone
     \expandafter\page_col_start_yes
   \else
     \expandafter\page_col_start_nop
   \fi} % public

\unexpanded\def\page_col_start_yes
  {\d_page_col_distance     \pagecolumnsparameter\c!distance\relax
 % \d_page_col_max_height   \pagecolumnsparameter\c!maxheight
   \d_page_col_max_width    \pagecolumnsparameter\c!maxwidth
 % \d_page_col_balance_step \pagecolumnsparameter\c!step
   \c_page_col_current  \plusone
   %
   \d_page_col_column_width\dimexpr(\d_page_col_max_width-\d_page_col_distance*\numexpr(\c_page_col_n_of_columns-\plusone)\relax)/\c_page_col_n_of_columns\relax
   %
   \columnwidth    \d_page_col_column_width
   \columndistance \d_page_col_distance
   \nofcolumns     \c_page_col_n_of_columns
   \textwidth      \columnwidth % kind of redundant
   %
   \nopenalties
   %
   % \insidecolumnstrue % NO!
   %
   \let\column\page_col_column
   %
   \def\page_floats_get_used_hsize{\makeupwidth} % a bit of a hack
   %
   \usealignparameter  \pagecolumnsparameter
   \useblankparameter  \pagecolumnsparameter
 % \useprofileparameter\pagecolumnsparameter
   %
   \usepagecolumnscolorparameter\c!color
   %
   \setupnotes[\c!width=\textwidth]%
   %
   \usesetupsparameter\pagecolumnsparameter
   %
   % This will become a method but for now it's good enough
   %
   \ifconditional\c_page_col_page\else
     \page_col_pickup_preceding
   \fi
   \setupoutputroutine[\s!pagecolumn]%
   \ifconditional\c_page_col_page\else
     \page_col_flush_preceding
   \fi
   %
   \setupfloats[\c!ntop=\plusthousand]%
 % \setupfloats[\c!nbottom=\plusthousand]%
   %
   \page_col_command_set_vsize
   \page_col_command_set_hsize
   %
   \unexpanded\def\page_col_start[##1]%
     {\page_col_start_nop}%
   %
   \let\stoppagecolumns\page_col_stop_yes}

\unexpanded\def\page_col_start_nop
  {\nofcolumns\c_page_mix_n_of_columns
   \let\stoppagecolumns\page_col_stop_nop}

\unexpanded\def\page_col_stop_yes
  {\column % \page_otr_eject_page
   \page
   \endgroup
 % \setupoutputroutine[\s!singlecolumn]%
   \page_otr_command_set_vsize
   \page_otr_command_set_hsize
   \page
   \endgroup}

\unexpanded\def\page_col_stop_nop
  {\page
   \endgroup
   \endgroup}

\protect \endinput