%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

\pushoverloadmode

\permanent\overloaded\tolerant\protected\def\defineoverlay[#1]#*[#S#2]#*[#S#3]% overlay [layer] content
  {\ifnum\lastarguments=\plusthree
    %\writestatus{BEWARE}{This (overlay definition) has changed!}% temp
     \def\pack_framed_define_overlay_indeed##1{\defcsname\??overlay##1\endcsname{\setlayer[#2]{\executedefinedoverlay{##1}{#3}}}}%
   \else
     \def\pack_framed_define_overlay_indeed##1{\defcsname\??overlay##1\endcsname{\executedefinedoverlay{##1}{#2}}}%
   \fi
   \processcommalist[#1]\pack_framed_define_overlay_indeed}

\popoverloadmode

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

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

\lettonothing\m_pack_layers_anchor
\lettonothing\m_pack_layers_page
\lettonothing\m_pack_layers_region
\lettonothing\m_pack_layers_target

\lettonothing\p_pack_layers_column
\lettonothing\p_pack_layers_corner
\lettonothing\p_pack_layers_dx
\lettonothing\p_pack_layers_dy
\lettonothing\p_pack_layers_height
\lettonothing\p_pack_layers_hoffset
\lettonothing\p_pack_layers_line
\lettonothing\p_pack_layers_location
\lettonothing\p_pack_layers_method
\lettonothing\p_pack_layers_offset
\lettonothing\p_pack_layers_option
\lettonothing\p_pack_layers_position
\lettonothing\p_pack_layers_preset
\lettonothing\p_pack_layers_region
\lettonothing\p_pack_layers_repeat
\lettonothing\p_pack_layers_rotation
\lettonothing\p_pack_layers_state
\lettonothing\p_pack_layers_sx
\lettonothing\p_pack_layers_sy
\lettonothing\p_pack_layers_voffset
\lettonothing\p_pack_layers_width
\lettonothing\p_pack_layers_x
\lettonothing\p_pack_layers_y

\newconditional\c_pack_layers_repeated
\newconditional\c_pack_layers_trace
\newinteger    \c_pack_layers_current_data

\newbox\b_layers \pushoverloadmode \mutable\let\b_layers\b_layers \popoverloadmode

\newdimension\d_pack_layers_x_size
\newdimension\d_pack_layers_y_size
\newdimension\d_pack_layers_x_offset
\newdimension\d_pack_layers_y_offset
\newdimension\d_pack_layers_x_position
\newdimension\d_pack_layers_y_position

\newdimension\layerwidth
\newdimension\layerheight

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

\appendtoks
    \ifcstok{\layerparameter\c!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
    \expanded{\defineoverlay[\currentlayer][\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}

\permanent\protected\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

\mutable\lettonothing\currentlayerwidth
\mutable\lettonothing\currentlayerheight

\permanent\tolerant\protected\def\setcurrentlayerdimensions[#1]#*[#2]% name left|right
  {\edef\currentlayerwidth {\thelayerwidth {#2#1}}%
   \edef\currentlayerheight{\thelayerheight{#2#1}}}

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

\permanent\tolerant\protected\def\setlayer[#1]#*[#S#2]#*[#S#3]% #4 == box do \fi is ok
  {\bgroup
   \nofarguments\lastarguments
   \checkpositionoverlays % otherwise funny regions
   \cdef\currentlayer{#1}%
   \edef\p_pack_layers_state{\layerparameter\c!state}%
   \ifx\p_pack_layers_state\v!stop
     \dowithnextboxcs\egroup\hbox % no pack ?
   \orelse\ifnum\nofarguments=\plusthree
     \edef\m_pack_layers_target{#2}%
     \pack_layers_set_indeed{#3}%
   \orelse\ifhastok={#2}%
     \lettonothing\m_pack_layers_target
     \pack_layers_set_indeed{#2}%
   \else
     \edef\m_pack_layers_target{#2}%
     \pack_layers_set_indeed\empty
   \fi}

\def\pack_layers_set_indeed#1%
  {\page_backgrounds_recalculate % brrr
   \global\advanceby\c_pack_layers_current_data\plusone
   \forgetall
   \dontcomplain
   \edef\p_pack_layers_option{\layerparameter\c!option}%
   \ifx\p_pack_layers_option\v!test
     \c_pack_layers_trace\conditionaltrue
     \traceboxplacementtrue
   \fi
   \dowithnextbox{\pack_layers_set_finish{#1}}\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
     \orelse\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
   \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{-\jobposx\m_pack_layers_region+\jobposx\m_pack_layers_anchor}%
   \d_pack_layers_y_position{ \jobposy\m_pack_layers_region-\jobposy\m_pack_layers_anchor+\jobposh\m_pack_layers_region}%
   \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 % multiplied
   \d_pack_layers_y_position\p_pack_layers_sy \dimexpr\p_pack_layers_y\relax % multiplied
   \glet\lastlayerxpos\!!zeropoint
   \glet\lastlayerypos\!!zeropoint
   \ifinset\v!bottom\p_pack_layers_corner\pack_layers_set_bottom_positions\fi
   \ifinset\v!right \p_pack_layers_corner\pack_layers_set_right_positions \fi
   \ifinset\v!middle\p_pack_layers_corner\pack_layers_set_middle_positions\fi
   \edef\m_pack_layers_page{\layerparameter\c!page}}

\permanent\tolerant\protected\def\definelayerpreset[#1]#*[#S#2]%
  {\ifarguments\or
     \letcsname\??layerpreset#1\endcsname\empty
   \orelse\ifhastok={#2}%
     \defcsname\??layerpreset#1\endcsname{\setupcurrentlayer[#2]}%
   \else
     \defcsname\??layerpreset#1\endcsname{\csname\??layerpreset#2\endcsname}%
   \fi}

\mutable\integerdef\b_layers_page\zerocount

\def\pack_layers_set_content#1%
  {\resetstacking % for Aditya to test and document
   \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        }% can be moved inline
   \edef\p_pack_layers_y        {\layerparameter\c!y        }% can be moved inline
   \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
   %
   \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
   \ifempty\p_pack_layers_rotation \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 % multiplied
     \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 % multiplied
     \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
   %
   \ifempty\m_pack_layers_page \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
   \integerdef\b_layers_page\csname\??layerbox\m_pack_layers_target\currentlayer\m_pack_layers_page\endcsname
   \ifvoid\b_layers_page
     \gsetboxllx\b_layers_page\zeropoint
     \gsetboxlly\b_layers_page\zeropoint
   \fi
   \global\setbox\b_layers_page\vpack %to \layerparameter\c!height % new, otherwise no negative y possible
     {\offinterlineskip
      \ifvoid\b_layers_page
        \scratchwidth \zeropoint
        \scratchheight\zeropoint
      \else
        \scratchwidth \wd\b_layers_page
        \scratchheight\ht\b_layers_page
        \ht\b_layers_page\zeropoint
        \dp\b_layers_page\zeropoint
        \wd\b_layers_page\zeropoint
        \ifcstok{\layerparameter\c!direction}\v!reverse\else
          \box\b_layers_page
        \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
    % \ifzero\p_pack_layers_line\else % todo: test this
        \advanceby\d_pack_layers_y_position{\p_pack_layers_line\lineheight+\topskip-\lineheight-\ht\nextbox}%
      \fi
      \ifnum\p_pack_layers_column=\zerocount\else % no \ifcase, can be negative
    % \ifzero\p_pack_layers_column\else % todo: test this
        \advanceby\d_pack_layers_x_position{\layoutcolumnoffset\p_pack_layers_column}%
      \fi
      \ifx\p_pack_layers_location\v!grid
        \setbox\nextbox\hpack
          {\alignedbox[rb]\vpack{\box\nextbox}}%
      \fi
      % ll registration
      \scratchdimen{\d_pack_layers_x_position+\d_pack_layers_x_offset}%
      \ifdim\scratchdimen<\getboxllx\b_layers_page
        \gsetboxllx\b_layers_page\scratchdimen
      \fi
      \advanceby\scratchdimen\wd\nextbox
      \wd\nextbox\ifdim\scratchdimen>\scratchwidth \scratchdimen \else \scratchwidth \fi
      \scratchdimen{\d_pack_layers_y_position+\d_pack_layers_y_offset}%
      \ifdim\scratchdimen<\getboxlly\b_layers_page
        \gsetboxlly\b_layers_page\scratchdimen
      \fi
      % ll compensation
      \advanceby\scratchdimen\htdp\nextbox
      \ht\nextbox\ifdim\scratchdimen>\scratchheight \scratchdimen \else \scratchheight \fi
      \dp\nextbox\zeropoint
      % placement
      \hsize\p_pack_layers_width
      \vpack to \p_pack_layers_height \bgroup
        \smashbox\nextbox
        \vskip{\d_pack_layers_y_position+\d_pack_layers_y_offset}%
        \hskip{\d_pack_layers_x_position+\d_pack_layers_x_offset}%
        % or maybe instead of the \vskip
        % \raise-{\d_pack_layers_y_position+\d_pack_layers_y_offset}%
        \box\nextbox
        \ifvoid\b_layers_page
          % already flushed
        \else
          % the reverse case % check !
          \vskip{-(\d_pack_layers_y_position+\d_pack_layers_y_offset)}%
          \box\b_layers_page
        \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
% {\ifzero\p_pack_layers_line\else % todo: test this
     \edef\p_pack_layers_line{\tointeger{-\p_pack_layers_line+\layoutlines+\plusone}}% use counter instead ?
   \fi
   \ifdim\d_pack_layers_y_size>\zeropoint
     \advanceby\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
% {\ifzero\p_pack_layers_column\else % todo: test this
     \edef\p_pack_layers_column{\tointeger{-\layerparameter\c!column+\layoutcolumns+\plusone}}% use counter instead ?
   \fi
   \ifdim\d_pack_layers_x_size>\zeropoint
     \advanceby\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 \advanceby\d_pack_layers_x_position.5\d_pack_layers_x_size \fi
   \ifdim\d_pack_layers_y_size>\zeropoint \advanceby\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}

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

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

\permanent\protected\def\flushlayer[#1]% quite core, so optimized (todo: check for void)
  {\begingroup
   \forgetall
   \cdef\currentlayer{#1}%
   \edef\p_pack_layers_state{\layerparameter\c!state}%
   \ifx\p_pack_layers_state\v!stop
     % nothing
   \orelse\ifx\p_pack_layers_state\v!next
     \global\letlayerparameter\c!state\v!start  % dangerous, stack-built-up
   \orelse\ifx\p_pack_layers_state\v!continue
     \global\letlayerparameter\c!state\v!repeat % dangerous, stack-built-up
   \orelse\ifcstok{\layerparameter\c!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
   \endgroup}

% optimized

\mutable\integerdef\b_layer_one\zerocount
\mutable\integerdef\b_layer_two\zerocount

\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 % will be \integerdef
       \ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
         \ifvoid\lastnamedcs\else
           \chardef\b_layer_two\lastnamedcs % will be \integerdef
           \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
   \orelse\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}

% less optimized:

\def\pack_layers_flush_double#1%
  {\startoverlay
     {\ifcsname\??layerbox\currentlayer\endcsname
        \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
          \pack_layers_flush_indeed\plusone\currentlayer\b_layer_two
        \fi
      \fi}%
     {\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}%
     {\ifcsname\??layerbox#1\currentlayer\endcsname
        \ifvoid\lastnamedcs\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\lastnamedcs\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#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
     \c_pack_layers_trace\conditionaltrue
     \traceboxplacementtrue
   \fi
   \ifcase#1\relax
     \c_pack_layers_repeated\conditionalfalse
   \else
     \edef\p_pack_layers_position{\layerparameter\c!position}%
     \ifx\p_pack_layers_position\v!yes
       \c_pack_layers_repeated\conditionalfalse
     \else
       \edef\p_pack_layers_repeat{\layerparameter\c!repeat}%
       \ifx\p_pack_layers_repeat\v!yes
         \c_pack_layers_repeated\conditionaltrue
       \orelse\ifx\p_pack_layers_state\v!repeat
         \c_pack_layers_repeated\conditionaltrue
       \else
         \c_pack_layers_repeated\conditionalfalse
       \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}%
%
      \ifx\p_pack_layers_method\v!overlay \wd\nextbox\d_overlay_width\fi
      \box\nextbox
%
      \pack_layers_bottom_fill}%
 % \cdef\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}%
     \ifempty\p_pack_layers_region\else
       \anch_mark_tagged_box\nextbox\p_pack_layers_region\zerocount % 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{\wd\b_layers-\getboxllx\b_layers}%
      \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.

\permanent\protected\def\composedlayer#1{\flushlayer[#1]}

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

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

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

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

\permanent\tolerant\protected\def\getMPlayer[#1]#*[#S#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]

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

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

\permanent\overloaded\protected\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
