pack-lyr.mkiv / last modification: 2019-10-11 15:54
%D \module
%D   [       file=pack-lyr,
%D        version=2000.10.20,
%D          title=\CONTEXT\ Packaging Macros,
%D       subtitle=Layers,
%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 Packaging Macros / Layers}

% todo : first / last / next / +... => page key
%        test on left/right box when no doublesided option given
%        use \ifcsname instead of doifvalue

\unprotect

% When being backgrounds layers get the background offset displacement. Should be
% an option, on by default (compatibility).

%D The layering mechanism implemented here is independent of the output routine, but
%D future extensions may depend on a more close cooperation.
%D
%D First we overload a macro from \type {pack-rul}. From now on we accept a
%D (optional) argument: the specific layer it will go in. This means that we can
%D move an overlay from one background to the other using the dimensions of the
%D parent.

\ifdefined\defineoverlay \else \message{loaded to early} \wait \fi

\unexpanded\def\defineoverlay
  {\dotripleempty\pack_framed_define_overlay}

\def\pack_framed_define_overlay[#1][#2][#3]% overlay [layer] content
  {\ifthirdargument
    %\writestatus{BEWARE}{This (overlay definition) has changed!}% temp
     \def\pack_framed_define_overlay_indeed##1{\setvalue{\??overlay##1}{\setlayer[#2]{\executedefinedoverlay{##1}{#3}}}}%
   \else
     \def\pack_framed_define_overlay_indeed##1{\setvalue{\??overlay##1}{\executedefinedoverlay{##1}{#2}}}%
   \fi
   \processcommalist[#1]\pack_framed_define_overlay_indeed}

%D We use the command handler code. The previous, more direct parameter handling was
%D 25\% faster when no parameters were passed when adding content to a layer.
%D However, when we pass for instance a preset, the new methos is some 10\% faster
%D and it happens that in most cases we do pass some parameters. It would be
%D interesting to see if we can push the preset in between the regular chain but it
%D could also lead to unwanted side effects when nesting layer placement.

\installcorenamespace{layer}
\installcorenamespace{layerbox}
\installcorenamespace{layerpreset}
\installcorenamespace{layerposition} % brr, unreadable

%D \macros
%D   {definelayer,setuplayer}
%D
%D Each layer gets its own (global) box. This also means that the data that goes
%D into a layer, is typeset immediately. Each layer automatically gets an associated
%D overlay, which can be used in any background assignment.
%D
%D After a layer is defined, you can change its characteristics.

\installcommandhandler \??layer {layer} \??layer

\setuplayer
  [\c!state=\v!start,
  %\c!doublesided=,
  %\c!preset=,
  %\c!option=,
  %\c!corner=,
  %\c!page=,
  %\c!rotation=, % geen 0 !
   \c!direction=\v!normal,
   \c!position=\v!no,
   \c!method=\v!overlay,
   \c!x=\zeropoint,
   \c!y=\zeropoint,
   \c!line=0,
   \c!column=0,
   \c!width=\wd\nextbox,  % don't change this globally
   \c!height=\ht\nextbox, % don't change this globally
   \c!offset=\zeropoint,
   \c!hoffset=\zeropoint,
   \c!voffset=\zeropoint,
   \c!dx=\zeropoint,
   \c!dy=\zeropoint,
   \c!location=rb,
   \c!sx=1,
   \c!sy=1,
   \c!region=\layeranchor]

\def\layeranchor{\currentlayer:\the\realpageno}

\let\p_pack_layers_doublesided\empty
\let\p_pack_layers_state      \empty
\let\p_pack_layers_option     \empty
\let\p_pack_layers_method     \empty
\let\p_pack_layers_preset     \empty
\let\p_pack_layers_rotation   \empty
\let\p_pack_layers_position   \empty
\let\p_pack_layers_hoffset    \empty
\let\p_pack_layers_voffset    \empty
\let\p_pack_layers_offset     \empty
\let\p_pack_layers_dx         \empty
\let\p_pack_layers_dy         \empty
\let\p_pack_layers_sx         \empty
\let\p_pack_layers_sy         \empty
\let\p_pack_layers_x          \empty
\let\p_pack_layers_y          \empty
\let\p_pack_layers_corner     \empty
\let\p_pack_layers_location   \empty
\let\p_pack_layers_line       \empty
\let\p_pack_layers_column     \empty
\let\p_pack_layers_width      \empty
\let\p_pack_layers_height     \empty
\let\p_pack_layers_direction  \empty
\let\p_pack_layers_region     \empty

\let\m_pack_layers_page       \empty
\let\m_pack_layers_target     \empty
\let\m_pack_layers_region     \empty
\let\m_pack_layers_anchor     \empty

\newconditional\c_pack_layers_repeated
\newconditional\c_pack_layers_trace
\newcount      \c_pack_layers_current_data

\newbox\b_layers

\newdimen\d_pack_layers_x_size
\newdimen\d_pack_layers_y_size
\newdimen\d_pack_layers_x_offset
\newdimen\d_pack_layers_y_offset
\newdimen\d_pack_layers_x_position
\newdimen\d_pack_layers_y_position

\newdimen\layerwidth
\newdimen\layerheight

\let\lastlayerxpos\!!zeropoint
\let\lastlayerypos\!!zeropoint
\let\lastlayerwd  \!!zeropoint
\let\lastlayerht  \!!zeropoint
\let\lastlayerdp  \!!zeropoint

\appendtoks
    \edef\p_pack_layers_doublesided{\layerparameter\c!doublesided}%
    \ifx\p_pack_layers_doublesided\v!yes
        \relateparameterhandlers{layer}{\v!left \currentlayer}{layer}\currentlayer % permits left*
        \relateparameterhandlers{layer}{\v!right\currentlayer}{layer}\currentlayer % permits right*
        \pack_layers_preset_box{\v!left \currentlayer}%
        \pack_layers_preset_box{\v!right\currentlayer}%
    \fi
    \pack_layers_preset_box\currentlayer
    \normalexpanded{\defineoverlay[\currentlayer][\noexpand\composedlayer{\currentlayer}]}%
\to \everydefinelayer

\def\pack_layers_preset_box#1%
  {\ifcsname\??layerbox#1\endcsname
     \resetlayer[#1]%
   \else
     \expandafter\newbox\csname\??layerbox#1\endcsname
   \fi}

%D \macros
%D  {resetlayer}
%D
%D This macro hardly needs an explanation (but is seldom needed anyway).

\def\pack_layers_reset_box#1%
  {\ifcsname\??layerbox#1\endcsname
    %\global\setbox\csname\??layerbox#1\endcsname\emptybox
     \global\setbox\lastnamedcs\emptybox
   \fi}

\def\resetlayer[#1]%
  {\pack_layers_reset_box{#1}%
   \pack_layers_reset_box{\v!left #1}%
   \pack_layers_reset_box{\v!right#1}%
   \pack_layers_reset_box{#1:\the\realpageno}}

%D \macros
%D   {setlayer}
%D
%D Data is moved into a layer with the following macro. When \type {position} is
%D set, relative positioning is used, with the current point as reference point.
%D Otherwise the topleft corner is used as reference point.
%D
%D \starttyping
%D \setlayer [identifier] [optional parameters] {data}
%D \stoptyping

\def\setcurrentlayerdimensions
  {\dodoubleempty\pack_layers_set_current_dimensions}

\def\pack_layers_set_current_dimensions[#1][#2]% name left|right
  {\edef\currentlayerwidth {\thelayerwidth {#2#1}}%
   \edef\currentlayerheight{\thelayerheight{#2#1}}}

\def\thelayerwidth #1{\the\ifcsname\??layerbox#1\endcsname\wd\lastnamedcs\else\zeropoint\fi}
\def\thelayerheight#1{\the\ifcsname\??layerbox#1\endcsname\ht\lastnamedcs\else\zeropoint\fi}

\unexpanded\def\setlayer
  {\dotripleempty\pack_layers_set}

\def\pack_layers_set[#1][#2][#3]% #4 == box do \fi is ok
  {\bgroup
   \checkpositionoverlays % otherwise funny regions
   \edef\currentlayer{#1}%
   \edef\p_pack_layers_state{\layerparameter\c!state}%
   \ifx\p_pack_layers_state\v!stop
     \dowithnextboxcs\egroup\hbox % no pack ?
   \else\ifthirdargument
     \pack_layers_set_indeed[#1][#2][#3]%
   \else
     \doifelseassignment{#2}
       {\pack_layers_set_indeed[#1][][#2]}%
       {\pack_layers_set_indeed[#1][#2][]}%
   \fi\fi}

\def\pack_layers_set_indeed[#1][#2][#3]% #2 = links/rechts
  {\page_backgrounds_recalculate % brrr
   \global\advance\c_pack_layers_current_data\plusone
   \forgetall
   \dontcomplain
   \edef\p_pack_layers_option{\layerparameter\c!option}%
   \ifx\p_pack_layers_option\v!test
     \settrue\c_pack_layers_trace
     \traceboxplacementtrue
   \fi
   \edef\m_pack_layers_target{#2}%
   \dowithnextbox{\pack_layers_set_finish{#3}}\hbox}

\def\pack_layers_set_finish#1%
  {\ifcsname\??layerbox\currentlayer\endcsname % can move up
     \ifx\m_pack_layers_target\v!even
       \ifodd\realpageno
         % discard nextbox
       \else
         \let\m_pack_layers_target\v!left
         \pack_layers_set_content{#1}%
       \fi
     \else\ifx\m_pack_layers_target\v!odd
       \ifodd\realpageno
         \let\m_pack_layers_target\v!right
         \pack_layers_set_content{#1}%
       \else
         % discard nextbox
       \fi
     \else
       \pack_layers_set_content{#1}%
     \fi\fi
   \else
     \writestatus{layer}{unknown layer \currentlayer}%
   \fi
   \egroup}

% todo: left/right
% todo: get position data in one go

\def\pack_layers_set_last_position_yes % target: left|right
  {% this will become one call
   \edef\m_pack_layers_anchor{\??layerposition\the\c_pack_layers_current_data}%
   \edef\m_pack_layers_page  {\MPp\m_pack_layers_anchor}%
   %edef\m_pack_layers_region{\MPr\m_pack_layers_anchor}% wrong one
   \edef\m_pack_layers_region{\layerparameter\c!region}%
   \d_pack_layers_x_position \dimexpr-\MPx\m_pack_layers_region+\MPx\m_pack_layers_anchor\relax
   \d_pack_layers_y_position \dimexpr \MPy\m_pack_layers_region-\MPy\m_pack_layers_anchor+\MPh\m_pack_layers_region\relax
   \xdef\lastlayerxpos{\the\d_pack_layers_x_position}%
   \xdef\lastlayerypos{\the\d_pack_layers_y_position}%
 % \writestatus{layering}{region: \m_pack_layers_region=>\MPxywhd\m_pack_layers_region}%
 % \writestatus        {}{anchor: \m_pack_layers_anchor=>\MPxywhd\m_pack_layers_anchor}%
 % \writestatus        {}{offset: \c!dx,\c!dy          =>\lastlayerxpos,\lastlayerypos}%
   \global\letlayerparameter\c!state\v!start % needed ?
   \setbox\b_layers\vpack to \d_pack_layers_y_size
     {\hpack to \d_pack_layers_x_size
        {\xypos\m_pack_layers_anchor\hss}%
      \vss}}

\def\pack_layers_set_last_position_nop
  {\setbox\b_layers\emptybox
   \d_pack_layers_x_position\p_pack_layers_sx\dimexpr\p_pack_layers_x\relax
   \d_pack_layers_y_position\p_pack_layers_sy\dimexpr\p_pack_layers_y\relax
   \glet\lastlayerxpos\!!zeropoint
   \glet\lastlayerypos\!!zeropoint
   \doifinset\v!bottom\p_pack_layers_corner\pack_layers_set_bottom_positions
   \doifinset\v!right \p_pack_layers_corner\pack_layers_set_right_positions
   \doifinset\v!middle\p_pack_layers_corner\pack_layers_set_middle_positions
   \edef\m_pack_layers_page{\layerparameter\c!page}}

\unexpanded\def\definelayerpreset
  {\dodoubleargument\pack_layers_define_preset}

\def\pack_layers_define_preset[#1][#2]%
  {\doifelseassignment{#2}
     {\setvalue{\??layerpreset#1}{\setupcurrentlayer[#2]}}
     {\setvalue{\??layerpreset#1}{\csname\??layerpreset#2\endcsname}}}

\def\pack_layers_set_content#1%
  {\layerwidth \layerparameter\c!width  % global (local later)
   \layerheight\layerparameter\c!height % global (local later)
   \d_pack_layers_x_size\layerwidth
   \d_pack_layers_y_size\layerheight
   %
   \setupcurrentlayer[#1]% preroll
   %
   \edef\p_pack_layers_preset   {\layerparameter\c!preset  }%
   %
   \ifcsname\??layerpreset\p_pack_layers_preset\endcsname
     \lastnamedcs
     \setupcurrentlayer[#1]% postroll
   \fi
   %
   \edef\p_pack_layers_rotation {\layerparameter\c!rotation }%
   \edef\p_pack_layers_position {\layerparameter\c!position }%
   \edef\p_pack_layers_hoffset  {\layerparameter\c!hoffset  }%
   \edef\p_pack_layers_voffset  {\layerparameter\c!voffset  }%
   \edef\p_pack_layers_offset   {\layerparameter\c!offset   }%
   \edef\p_pack_layers_dx       {\layerparameter\c!dx       }%
   \edef\p_pack_layers_dy       {\layerparameter\c!dy       }%
   \edef\p_pack_layers_sx       {\layerparameter\c!sx       }%
   \edef\p_pack_layers_sy       {\layerparameter\c!sy       }%
   \edef\p_pack_layers_x        {\layerparameter\c!x        }%
   \edef\p_pack_layers_y        {\layerparameter\c!y        }%
   \edef\p_pack_layers_corner   {\layerparameter\c!corner   }%
   \edef\p_pack_layers_location {\layerparameter\c!location }%
   \edef\p_pack_layers_line     {\layerparameter\c!line     }%
   \edef\p_pack_layers_column   {\layerparameter\c!column   }%
   \edef\p_pack_layers_width    {\layerparameter\c!width    }% local ones
   \edef\p_pack_layers_height   {\layerparameter\c!height   }% local ones
   \edef\p_pack_layers_direction{\layerparameter\c!direction}%
   %
   \ifx\p_pack_layers_position\v!overlay
     \let\p_pack_layers_width   \zeropoint
     \let\p_pack_layers_height  \zeropoint
     \let\p_pack_layers_position\v!yes
   \fi
   \ifx\p_pack_layers_rotation\empty \else
     % use direct call
     \setbox\nextbox\hpack
       {\rotate[\c!location=\v!high,\c!rotation=\layerparameter\c!rotation]{\box\nextbox}}%
   \fi
   \d_pack_layers_x_offset\p_pack_layers_sx\dimexpr
     \ifx\p_pack_layers_hoffset\v!max\d_pack_layers_x_size\else\p_pack_layers_hoffset\fi+\p_pack_layers_offset+\p_pack_layers_dx
   \relax
   \d_pack_layers_y_offset\p_pack_layers_sy\dimexpr
     \ifx\p_pack_layers_voffset\v!max\d_pack_layers_y_size\else\p_pack_layers_voffset\fi+\p_pack_layers_offset+\p_pack_layers_dy
   \relax
   \ifx\p_pack_layers_position\v!yes
     \pack_layers_set_last_position_yes
   \else
     \pack_layers_set_last_position_nop
   \fi
   %
   \ifx\m_pack_layers_page\empty \else % is expanded
     \edef\m_pack_layers_page{:\m_pack_layers_page}%
     \ifcsname\??layerbox\m_pack_layers_target\currentlayer\m_pack_layers_page\endcsname \else
       \expandafter\newbox\csname\??layerbox\m_pack_layers_target\currentlayer\m_pack_layers_page\endcsname
     \fi
   \fi
   \chardef\layerpagebox\csname\??layerbox\m_pack_layers_target\currentlayer\m_pack_layers_page\endcsname
   \ifvoid\layerpagebox
     \gsetboxllx\layerpagebox\zeropoint
     \gsetboxlly\layerpagebox\zeropoint
   \fi
   \global\setbox\layerpagebox\vpack %to \layerparameter\c!height % new, otherwise no negative y possible
     {\offinterlineskip
      \ifvoid\layerpagebox
        \let\lastlayerwidth \zeropoint
        \let\lastlayerheight\zeropoint
      \else
        \edef\lastlayerwidth {\the\wd\layerpagebox}%
        \edef\lastlayerheight{\the\ht\layerpagebox}%
        \ht\layerpagebox\zeropoint
        \dp\layerpagebox\zeropoint
        \wd\layerpagebox\zeropoint
        \ifx\p_pack_layers_direction\v!reverse\else
          \box\layerpagebox
        \fi
      \fi
      % don't move
      \xdef\lastlayerwd{\the\wd\nextbox}%
      \xdef\lastlayerht{\the\ht\nextbox}% % not entirely ok when grid !
      \xdef\lastlayerdp{\the\dp\nextbox}% % not entirely ok when grid !
      % this code
      \ifx\p_pack_layers_location\v!grid
        \ht\nextbox\strutheight
        \dp\nextbox\strutdepth
      \else
        \setbox\nextbox\hpack
          {\alignedbox[\p_pack_layers_location]\vpack{\box\nextbox}}%
      \fi
      \ifnum\p_pack_layers_line=\zerocount\else % no \ifcase, can be negative
        \advance\d_pack_layers_y_position\dimexpr\p_pack_layers_line\lineheight+\topskip-\lineheight-\ht\nextbox\relax
      \fi
      \ifnum\p_pack_layers_column=\zerocount\else % no \ifcase, can be negative
        \advance\d_pack_layers_x_position\layoutcolumnoffset\p_pack_layers_column\relax
      \fi
      \ifx\p_pack_layers_location\v!grid
        \setbox\nextbox\hpack
          {\alignedbox[rb]\vpack{\box\nextbox}}%
      \fi
      % ll registration
      \scratchdimen\dimexpr\d_pack_layers_x_position+\d_pack_layers_x_offset\relax
      \ifdim\scratchdimen<\getboxllx\layerpagebox
        \gsetboxllx\layerpagebox\scratchdimen
      \fi
      \advance\scratchdimen\wd\nextbox
      \wd\nextbox\ifdim\scratchdimen>\lastlayerwidth \scratchdimen \else \lastlayerwidth \fi
      \scratchdimen\dimexpr\d_pack_layers_y_position+\d_pack_layers_y_offset\relax
      \ifdim\scratchdimen<\getboxlly\layerpagebox
        \gsetboxlly\layerpagebox\scratchdimen
      \fi
      % ll compensation
      \advance\scratchdimen\dimexpr\ht\nextbox+\dp\nextbox\relax
      \ht\nextbox\ifdim\scratchdimen>\lastlayerheight \scratchdimen \else \lastlayerheight \fi
      \dp\nextbox\zeropoint
      % placement
      \hsize\p_pack_layers_width
      \vpack to \p_pack_layers_height \bgroup
        \smashbox\nextbox
        \vskip\dimexpr\d_pack_layers_y_position+\d_pack_layers_y_offset\relax
        \hskip\dimexpr\d_pack_layers_x_position+\d_pack_layers_x_offset\relax
        % or maybe instead of the \vskip
        % \raise-\dimexpr\d_pack_layers_y_position+\d_pack_layers_y_offset\relax
        \box\nextbox
        \ifvoid\layerpagebox
          % already flushed
        \else
          % the reverse case % check !
          \vskip-\dimexpr\d_pack_layers_y_position+\d_pack_layers_y_offset\relax
          \box\layerpagebox
        \fi
      \egroup}%
   % when position is true, the layerbox holds the compensation and needs
   % to be placed; never change this !
   \ifvoid\b_layers \else
     \box\b_layers
   \fi}

\def\pack_layers_set_bottom_positions
  {\ifnum\p_pack_layers_line=\zerocount\else % can be < 0
     \edef\p_pack_layers_line{\the\numexpr-\p_pack_layers_line+\layoutlines+\plusone\relax}% use counter instead ?
   \fi
   \ifdim\d_pack_layers_y_size>\zeropoint
     \advance\d_pack_layers_y_position-\d_pack_layers_y_size
     \d_pack_layers_y_position-\d_pack_layers_y_position
     \d_pack_layers_y_offset-\d_pack_layers_y_offset
   \fi}

\def\pack_layers_set_right_positions
  {\ifnum\p_pack_layers_column=\zerocount\else % can be < 0
     \edef\p_pack_layers_column{\the\numexpr-\layerparameter\c!column+\layoutcolumns+\plusone\relax}% use counter instead ?
   \fi
   \ifdim\d_pack_layers_x_size>\zeropoint
     \advance\d_pack_layers_x_position-\d_pack_layers_x_size
     \d_pack_layers_x_position-\d_pack_layers_x_position
     \d_pack_layers_x_offset-\d_pack_layers_x_offset
   \fi}

\def\pack_layers_set_middle_positions
  {\ifdim\d_pack_layers_x_size>\zeropoint \advance\d_pack_layers_x_position.5\d_pack_layers_x_size \fi
   \ifdim\d_pack_layers_y_size>\zeropoint \advance\d_pack_layers_y_position.5\d_pack_layers_y_size \fi}

%D Given the task to be accomplished, the previous macro is not even that
%D complicated. It mainly comes down to skipping to the right place and placing a
%D box on top of or below the existing content. In the case of position tracking,
%D another reference point is chosen.

%D \macros
%D  {doifelselayerdata}

\def\doifelselayerdata#1%
  {\ifcsname\??layerbox#1\endcsname
    %\ifvoid\csname\??layerbox#1\endcsname
     \ifvoid\lastnamedcs
       \doubleexpandafter\secondoftwoarguments
     \else
       \doubleexpandafter\firstoftwoarguments
     \fi
   \else
     \expandafter\secondoftwoarguments
   \fi}

\let\doiflayerdataelse\doifelselayerdata

%D \macros
%D  {flushlayer}
%D
%D When we flush a layer, we flush both the main one and the page dependent one
%D (when defined). This feature is more efficient in \ETEX\ since there testing for
%D an undefined macro does not takes hash space.

% todo: setups before flush, handy hook

\unexpanded\def\flushlayer[#1]% quite core, so optimized (todo: check for void)
  {\begingroup
   \forgetall
   \edef\currentlayer{#1}%
   \edef\p_pack_layers_state{\layerparameter\c!state}%
   \ifx\p_pack_layers_state\v!stop
     % nothing
   \else\ifx\p_pack_layers_state\v!next
     \global\letlayerparameter\c!state\v!start  % dangerous, stack-built-up
   \else\ifx\p_pack_layers_state\v!continue
     \global\letlayerparameter\c!state\v!repeat % dangerous, stack-built-up
   \else
     \edef\p_pack_layers_doublesided{\layerparameter\c!doublesided}%
     \ifx\p_pack_layers_doublesided\v!yes
       \ifcsname\??layerbox#1\endcsname
         % we can make a dedicated one for this
         \doifbothsidesoverruled
           {\pack_layers_flush_double\v!left }%
           {\pack_layers_flush_double\v!right}%
           {\pack_layers_flush_double\v!left }%
       \else
         \pack_layers_flush_single
       \fi
     \else
       \pack_layers_flush_single
     \fi
   \fi\fi\fi
   \endgroup}

%  \ifcase#1\else\writestatus{layer}{unknown layer #3}\fi

% todo: pass the layer with \lastnamedcs

% \def\pack_layers_flush_single
%   {\startoverlay
%      {\ifcsname\??layerbox  \currentlayer                \endcsname\pack_layers_flush_indeed\plusone   \currentlayer                 \fi}%
%      {\ifcsname\??layerbox  \currentlayer:\the\realpageno\endcsname\pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\fi}%
%    \stopoverlay}
%
% \def\pack_layers_flush_double#1%
%   {\startoverlay
%      {\ifcsname\??layerbox  \currentlayer                \endcsname\pack_layers_flush_indeed\plusone     \currentlayer                 \fi}%
%      {\ifcsname\??layerbox  \currentlayer:\the\realpageno\endcsname\pack_layers_flush_indeed\zerocount  {\currentlayer:\the\realpageno}\fi}%
%      {\ifcsname\??layerbox#1\currentlayer                \endcsname\pack_layers_flush_indeed\plusone  {#1\currentlayer                }\fi}%
%      {\ifcsname\??layerbox#1\currentlayer:\the\realpageno\endcsname\pack_layers_flush_indeed\zerocount{#1\currentlayer:\the\realpageno}\fi}%
%    \stopoverlay}

% optimized:

\def\pack_layers_flush_single
  {\ifcsname\??layerbox\currentlayer\endcsname
     \ifvoid\lastnamedcs
       \ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
         \ifvoid\lastnamedcs\else
           \chardef\b_layer_two\lastnamedcs
           \pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two
         \fi
       \fi
     \else
       \chardef\b_layer_one\lastnamedcs
       \ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
         \ifvoid\lastnamedcs\else
           \chardef\b_layer_two\lastnamedcs
           \startoverlay
             {\pack_layers_flush_indeed\plusone   \currentlayer                 \b_layer_one}%
             {\pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two}%
           \stopoverlay
         \fi
       \else
         \pack_layers_flush_indeed\plusone\currentlayer\b_layer_one
       \fi
     \fi
   \else\ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
     \ifvoid\lastnamedcs
        % nothing
     \else
       \chardef\b_layer_two\lastnamedcs
       \pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two
     \fi
   \fi\fi}

% less optimized:

\def\pack_layers_flush_double#1%
  {\startoverlay
     {\ifcsname\??layerbox\currentlayer\endcsname
        \ifvoid\lastnamedcss\else \chardef\b_layer_two\lastnamedcs
          \pack_layers_flush_indeed\plusone\currentlayer\b_layer_two
        \fi
      \fi}%
     {\ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
        \ifvoid\lastnamedcss\else \chardef\b_layer_two\lastnamedcs
          \pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two
        \fi
      \fi}%
     {\ifcsname\??layerbox#1\currentlayer\endcsname
        \ifvoid\lastnamedcss\else \chardef\b_layer_two\lastnamedcs
          \pack_layers_flush_indeed\plusone{#1\currentlayer}\b_layer_two
        \fi
      \fi}%
     {\ifcsname\??layerbox#1\currentlayer:\the\realpageno\endcsname
        \ifvoid\lastnamedcss\else \chardef\b_layer_two\lastnamedcs
          \pack_layers_flush_indeed\zerocount{#1\currentlayer:\the\realpageno}\b_layer_two
        \fi
      \fi}%
   \stopoverlay}

\let\pack_layers_top_fill   \relax
\let\pack_layers_bottom_fill\vss

%def\pack_layers_flush_indeed#1#2%
\def\pack_layers_flush_indeed#1#2#3%
  {\begingroup % already grouped
   \offinterlineskip
   \edef\p_pack_layers_preset{\layerparameter\c!preset}%
   \ifcsname\??layerpreset\p_pack_layers_preset\endcsname
     \lastnamedcs
   \fi
   \edef\p_pack_layers_method{\layerparameter\c!method}%
   \edef\p_pack_layers_option{\layerparameter\c!option}%
   \ifx\p_pack_layers_option\v!test
     \settrue\c_pack_layers_trace
     \traceboxplacementtrue
   \fi
   \ifcase#1\relax
     \setfalse\c_pack_layers_repeated
   \else
     \edef\p_pack_layers_position{\layerparameter\c!position}%
     \ifx\p_pack_layers_position\v!yes
       \setfalse\c_pack_layers_repeated
     \else
       \edef\p_pack_layers_repeat{\layerparameter\c!repeat}%
       \ifx\p_pack_layers_repeat\v!yes
         \settrue\c_pack_layers_repeated
       \else\ifx\p_pack_layers_state\v!repeat
         \settrue\c_pack_layers_repeated
       \else
         \setfalse\c_pack_layers_repeated
       \fi\fi
     \fi
   \fi
   %chardef\b_layers\csname\??layerbox#2\endcsname % trick
   \let\b_layers#3%
   % we need to copy in order to retain the negative offsets for a next
   % stage of additions, i.e. llx/lly accumulate in repeat mode and the
   % compensation may differ each flush depending on added content
   \setbox\nextbox
     \ifx\p_pack_layers_method\v!fit
       \pack_layers_positioned_box_yes
     \else
       \pack_layers_positioned_box_nop
     \fi
   % todo: method=offset => overlayoffset right/down (handy for backgrounds with offset)
   \doifelseoverlay{#2}%
     {\setlayoutcomponentattribute{\v!layer:#2}}%
     \resetlayoutcomponentattribute
   % we have conflicting demands: some mechanisms want ll anchoring .. I need to figure this out
   % and maybe we will have 'origin=bottom' or so
   \setbox\nextbox
   \ifx\p_pack_layers_option\v!test \ruledvbox \else \vpack \fi \ifx\p_pack_layers_method\v!overlay to \d_overlay_height \fi \layoutcomponentboxattribute
     {\pack_layers_top_fill
      \hpack \ifx\p_pack_layers_method\v!overlay to \d_overlay_width \fi
        {\box\nextbox
         \hss}%
      \pack_layers_bottom_fill}%
   % \edef\currentlayer{#2}% :\the\realpageno}% local .. check \anchor
   % \edef\p_pack_layers_position{\layerparameter\c!position}% local
   \ifx\p_pack_layers_position\v!yes
     \edef\p_pack_layers_region{\layerparameter\c!region}%
     \ifx\p_pack_layers_region\empty
     \else
       \anch_mark_tagged_box\nextbox\p_pack_layers_region % was \layeranchor
     \fi
   \fi
   \box\nextbox
   %
   \ifconditional\c_pack_layers_repeated\else
     \gsetboxllx\b_layers\zeropoint
     \gsetboxlly\b_layers\zeropoint
   \fi
   \endgroup}

\def\pack_layers_positioned_box_yes
  {\vpack
     {\vskip-\getboxlly\b_layers
      \hskip-\getboxllx\b_layers
      \hsize-\dimexpr\getboxllx\b_layers-\wd\b_layers\relax
      \ifconditional\c_pack_layers_repeated\copy\else\box\fi\b_layers}}

\def\pack_layers_positioned_box_nop
  {\ifconditional\c_pack_layers_repeated\copy\else\box\fi\b_layers}

% \definelayer[test][method=fit] \setupcolors[state=start,option=test]
%
% \framed[framecolor=red,offset=overlay]{\setlayer[test]{aa}\setlayer[test][x=10pt]{g}\flushlayer[test]}
% \framed[framecolor=red,offset=overlay]{\setlayer[test]{aa}\setlayer[test][x=-10pt]{bb}\flushlayer[test]}
% \framed[framecolor=red,offset=overlay]{\setlayer[test][x=-20pt]{cccccc}\flushlayer[test]}
% \framed[framecolor=red,offset=overlay]{\setlayer[test]{dd}\setlayer[test][x=-20pt,y=-3pt]{eeeeee}\flushlayer[test]}

%D \macros
%D  {composedlayer,placelayer,tightlayer}
%D
%D This is a handy shortcut, which saves a couple of braces when we use it as
%D parameter. This name also suits better to other layering commands.

\unexpanded\def\composedlayer#1{\flushlayer[#1]}

% \unexpanded\def\tightlayer[#1]%
%   {\hbox
%      {\def\currentlayer{#1}% todo: left/right
%       \setbox\nextbox\emptybox
%       \hsize\layerparameter\c!width
%       \vsize\layerparameter\c!height
%       \composedlayer{#1}}}

\unexpanded\def\tightlayer[#1]%
  {\hpack
     {\def\currentlayer{#1}% todo: left/right
      \setbox\nextbox\emptybox
      \d_overlay_width \layerparameter\c!width
      \d_overlay_height\layerparameter\c!height
      \composedlayer{#1}}}

\let\placelayer\flushlayer

%D \macros
%D  {setMPlayer}
%D
%D The following layer macro uses the positions that are registered by \METAPOST.
%D
%D \starttyping
%D \definelayer[test]
%D
%D \setMPlayer [test] [somepos-1] {Whatever we want here!}
%D \setMPlayer [test] [somepos-2] {Whatever we need there!}
%D \setMPlayer [test] [somepos-3] {\externalfigure[cow.mps][width=2cm]}
%D
%D \startuseMPgraphic{oeps}
%D   draw fullcircle scaled 10cm withcolor red ;
%D   register ("somepos-1",2cm,3cm,center currentpicture) ;
%D   register ("somepos-2",8cm,5cm,(-1cm,-2cm)) ;
%D   register ("somepos-3",0cm,0cm,(-2cm,2cm)) ;
%D \stopuseMPgraphic
%D
%D \getMPlayer[test]{\useMPgraphic{oeps}}
%D \stoptyping
%D
%D The last line is equivalent to
%D
%D \starttyping
%D \framed
%D   [background={foreground,test},offset=overlay]
%D   {\useMPgraphic{oeps}}
%D \stoptyping

\unexpanded\def\setMPlayer
  {\dotripleempty\pack_layers_set_MP}

\def\MPlayerwidth {\hsize}
\def\MPlayerheight{\vsize}

\def\pack_layers_set_MP[#1][#2][#3]%
  {\edef\MPlayerwidth {\MPw{#2}}%
   \edef\MPlayerheight{\MPh{#2}}%
   \setlayer[#1][\c!x=\MPx{#2},\c!y=\MPy{#2},\c!position=\v!no,#3]}

\unexpanded\def\getMPlayer
  {\dodoubleempty\pack_layers_get_MP}

\def\pack_layers_get_MP[#1][#2]%
  {\framed[\c!background={\v!foreground,#1},\c!frame=\v!off,\c!offset=\v!overlay,#2]} % takes argument

%D Watch out, a redefinition:

\ifdefined\settextpagecontent \else
    \writestatus\m!system{error in page-lyr.tex} \wait
\fi

\definelayer
  [OTRTEXT]

\setuplayer
  [OTRTEXT]
  [\c!width=\innermakeupwidth,
   \c!height=\textheight]

\let\normalsettextpagecontent\settextpagecontent % will be overloaded in page-spr

\unexpanded\def\settextpagecontent#1#2#3% #2 and #3 will disappear
  {\doifelselayerdata{OTRTEXT}
     {\setbox#1\hpack to \makeupwidth
        {\startoverlay
           {\tightlayer[OTRTEXT]} % first, otherwise problems with toc
           {\normalsettextpagecontent{#1}{#2}{#3}\box#1}
         \stopoverlay}%
      \dp#1\zeropoint}%
     {\normalsettextpagecontent{#1}{#2}{#3}}}

\protect \endinput