%D \module
%D   [       file=page-lyr,
%D        version=2000.10.20,
%D          title=\CONTEXT\ Page Macros,
%D       subtitle=Layers, 
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

\writestatus{loading}{Context Page Macros / Layers} 

\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
%D the output routine, but future extensions may depend on a
%D more close cooperation. 

%D First we overload a macro from \type {core-rul}. From now on
%D we accept a (optional) argument: the specific layer it
%D will go in. This means that we can move an overlay from one
%D background to the other using the dimensions of the parent.

\ifx\undefined\defineoverlay \message{loaded to early} \wait \fi 

\def\defineoverlay
  {\dotripleempty\dodefineoverlay}

\def\dodefineoverlay[#1][#2][#3]% overlay [layer] content 
  {\ifthirdargument
     \writestatus{BEWARE}{This (overlay definition) has changed!}% temp
     \def\docommando##1%
       {\setvalue{\??ov##1}####1####2####3####4####5####6####7%
          {\setlayer[#2]{\executedefinedoverlay
             ##1\\#3\\{####1}{####2}{####3}{####4}{####5}{####6}{####7}}}}%
   \else
     \def\docommando##1%
       {\setvalue{\??ov##1}{\executedefinedoverlay
          ##1\\#2\\}}%
   \fi
   \processcommalist[#1]\docommando}

%D When tracing is turned on, a couple of boxes will 
%D show up as well as the reference point. 

\newif\iftracelayers % \tracelayerstrue

%D This handy constant saved some string memory. 

\def\@@layerbox{@@layerbox}

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

% todo : links/rechts 

\def\definelayer
  {\dodoubleargument\dodefinelayer}

\def\dodefinelayer[#1][#2]%
  {\setuplayer
     [#1]
     [\c!dubbelzijdig=,\c!preset=,
      \c!status=\v!start,\c!richting=\v!normaal,\c!optie=,
      \c!x=\!!zeropoint,\c!y=\!!zeropoint,\c!positie=\v!nee,
      \c!regel=0,\c!kolom=0,
      \c!breedte=\nextboxwd,\c!hoogte=\nextboxht,
      \c!offset=\!!zeropoint,\c!rotatie=, % geen 0 ! 
      \c!hoffset=\!!zeropoint,\c!voffset=\!!zeropoint,
      \c!plaats=rb,\c!positie=\v!nee,\c!pagina=,
      \c!methode=\v!overlay,
      \c!sx=1,\c!sy=1,\c!hoek=,#2]%
   \doifvalue{\??ll#1\c!dubbelzijdig}\v!ja
     {\dopresetlayerbox{\v!links #1}%
      \dopresetlayerbox{\v!rechts#1}}%
   \dopresetlayerbox{#1}%
   \defineoverlay[#1][\composedlayer{#1}]}

\def\dopresetlayerbox#1%
  {\ifundefined{\@@layerbox#1}%
     \expandafter\newbox\csname\@@layerbox#1\endcsname
   \else
     \resetlayer[#1]%
   \fi}

%D \macros 
%D   {setuplayer}
%D
%D After a layer is defined, you can change its 
%D characteristics. 

\def\setuplayer
  {\dodoubleargument\dosetuplayer}

\def\dosetuplayer[#1][#2]%
  {\def\docommando##1{\getparameters[\??ll##1][#2]}%
   \processcommalist[#1]\docommando}

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

\def\currentlayerdata{0}

\def\setlayer
  {\dotripleempty\dosetlayer}

\def\dosetlayer[#1][#2][#3]%
  {\ifthirdargument
     \doifnotvalue{\??ll#1\c!status}\v!stop{\dodosetlayer[#1][#2][#3]}%
   \else
     \doifnotvalue{\??ll#1\c!status}\v!stop{\dodosetlayer[#1][][#2]}%
   \fi}

\def\dodosetlayer[#1][#2][#3]% #2 = links/rechts
  {\bgroup
   \recalculatebackgrounds
   \recalculatelogos
   \doglobal\increment\currentlayerdata
   \forgetall
   \dontcomplain
   \doifvalue{\??ll#1\c!optie}\v!test\tracelayerstrue
   \iftracelayers\traceboxplacementtrue\fi
   \dowithnextbox % sneller als aparte macro
     {\ifundefined{\@@layerbox#1}%
        \writestatus{layer}{unknown layer #1}%
      \else
        \dododosetlayer[#1][#2][#3]%
      \fi
      \egroup}
     \hbox}

\newbox\layerbox

\newdimen\@@layerxsiz \newdimen\@@layerxoff \newdimen\@@layerxpos
\newdimen\@@layerysiz \newdimen\@@layeryoff \newdimen\@@layerypos

\let\lastlayerxpos\!!zeropoint
\let\lastlayerypos\!!zeropoint

% todo left/right 

\def\setlastlayerpos#1%
  {\edef\layerpage{\MPp{lyr:\currentlayerdata}}%
   \scratchdimen\MPx{lyr:#1:\layerpage}%
   \scratchdimen-\scratchdimen
   \advance\scratchdimen\MPx{lyr:\currentlayerdata}%
   \xdef\lastlayerxpos{\the\scratchdimen}%
   \scratchdimen\MPy{lyr:#1:\layerpage}%
   \advance\scratchdimen-\MPy{lyr:\currentlayerdata}%
   \xdef\lastlayerypos{\the\scratchdimen}}

\def\definelayerpreset
 {\dodoubleargument\dodefinelayerpreset}

\def\dodefinelayerpreset[#1][#2]%
  {\setvalue{\??ll\??ll#1}{\dopresetlayer{#2}}}

\def\dopresetlayer#1#2#3% #1=list #2=tag #3=list  
  {\getparameters[\??ll#2][#1,#3]}

\letempty\currentlayer

\def\layerparameter#1{\csname\??ll\currentlayer#1\endcsname}

\def\dododosetlayer[#1][#2][#3]% will be sped up
  {% we use the global width, never change this 
   \def\currentlayer{#1}%
   \@@layerxsiz\layerparameter\c!breedte
   \@@layerysiz\layerparameter\c!hoogte
   % preroll 
   \getparameters[\??ll#1][#3]%
   % presets and real roll  
   \doifdefined{\??ll\??ll\layerparameter\c!preset}
     {\getvalue{\??ll\??ll\layerparameter\c!preset}{#1}{#3}}%
   % that was real slow 
   \doifvalue{\??ll#1\c!positie}\v!overlay  % slow
     {\getparameters[\??ll#1]
        [\c!breedte=\zeropoint,
         \c!hoogte=\zeropoint,
         \c!positie=\v!ja]}%
   \doifvaluesomething{\??ll#1\c!rotatie}
     {\setbox\nextbox\hbox
        {\rotate
           [\c!plaats=\v!hoog,
            \c!rotatie=\layerparameter\c!rotatie]
           {\flushnextbox}}}%
   % no, not local 
   % \@@layerxsiz\layerparameter\c!breedte
   % \@@layerysiz\layerparameter\c!hoogte 
   % never change that 
   \@@layerxpos\layerparameter\c!x
   \@@layerypos\layerparameter\c!y
   \doifelsevalue{\??ll#1\c!hoffset}\v!max
     {\@@layerxoff\@@layerxsiz}    
     {\@@layerxoff\layerparameter\c!hoffset}%
   \doifelsevalue{\??ll#1\c!voffset}\v!max
     {\@@layeryoff\@@layerysiz}
     {\@@layeryoff\layerparameter\c!voffset}%
   \advance\@@layerxoff\layerparameter\c!offset
   \advance\@@layeryoff\layerparameter\c!offset
   \@@layerxpos\layerparameter\c!sx\@@layerxpos
   \@@layerypos\layerparameter\c!sy\@@layerypos
   \@@layerxoff\layerparameter\c!sx\@@layerxoff
   \@@layeryoff\layerparameter\c!sy\@@layeryoff
   \doifelsevalue{\??ll#1\c!positie}\v!ja   % combine ^
     {\setlastlayerpos{#2#1}% todo l/r %%%%%%%%%%%%
      \@@layerxpos\lastlayerxpos
      \@@layerypos\lastlayerypos
      \letgvalue{\??ll#1\layerpage\c!positie}\v!ja
      \letgvalue{\??ll#1\c!status}\v!start % needed ?
      \setbox\layerbox\vbox to \@@layerysiz
        {\hbox to \@@layerxsiz{\xypos{lyr:\currentlayerdata}\hss}\vss}}
     {\setbox\layerbox\emptybox
      \globallet\lastlayerxpos\!!zeropoint
      \globallet\lastlayerypos\!!zeropoint
      \ExpandBothAfter\doifinset\v!onder{\layerparameter\c!hoek}
        {\ifnum\layerparameter\c!regel=\zerocount\else % can be < 0
           \scratchcounter\layerparameter\c!regel
           \scratchcounter-\scratchcounter
           \advance\scratchcounter\layoutlines
           \advance\scratchcounter\plusone
           \setevalue{\??ll#1\c!regel}{\the\scratchcounter}%
         \fi 
         \ifdim\@@layerysiz>\zeropoint
           \advance\@@layerypos-\@@layerysiz
           \@@layerypos-\@@layerypos
           \@@layeryoff-\@@layeryoff
         \fi}%
      \ExpandBothAfter\doifinset\v!rechts{\layerparameter\c!hoek}
        {\ifnum\layerparameter\c!kolom=\zerocount\else % can be < 0
           \scratchcounter\layerparameter\c!kolom
           \scratchcounter-\scratchcounter
           \advance\scratchcounter \layoutcolumns
           \advance\scratchcounter \plusone
           \setevalue{\??ll#1\c!kolom}{\the\scratchcounter}%
         \fi 
         \ifdim\@@layerxsiz>\zeropoint
           \advance\@@layerxpos-\@@layerxsiz
           \@@layerxpos-\@@layerxpos
           \@@layerxoff-\@@layerxoff
         \fi}%
      \ExpandBothAfter\doif\v!midden{\layerparameter\c!hoek}
        {\ifdim\@@layerxsiz>\zeropoint
           \advance\@@layerxpos.5\@@layerxsiz
         \fi
         \ifdim\@@layerysiz>\zeropoint
           \advance\@@layerypos.5\@@layerysiz
         \fi}%
      \edef\layerpage{\layerparameter\c!pagina}}%
   \doifsomething\layerpage
     {\edef\layerpage{:\layerpage}%
      \doifundefined{\@@layerbox#2#1\layerpage}
        {\global\expandafter\newbox\csname\@@layerbox#2#1\layerpage\endcsname}}%
   \dontcomplain % more comfortable  
   \global\setbox\csname\@@layerbox#2#1\layerpage\endcsname\vbox
         to \layerparameter\c!hoogte % new, otherwise no negative y possible 
     {\offinterlineskip
      \hsize\layerparameter\c!breedte % new, keep box small 
      \ifvoid\csname\@@layerbox#1\layerpage\endcsname\else
        \ht\csname\@@layerbox#2#1\layerpage\endcsname\zeropoint
        \dp\csname\@@layerbox#2#1\layerpage\endcsname\zeropoint
        \wd\csname\@@layerbox#2#1\layerpage\endcsname\zeropoint
        \doifnotvalue{\layerparameter\c!richting}\v!omgekeerd
          {\box\csname\@@layerbox#2#1\layerpage\endcsname}%
      \fi
\doifelsevalue{\??ll#1\c!plaats}\v!grid\donetrue\donefalse
\ifdone
   \nextboxht\strutheight
   \nextboxdp\strutdepth
\else
   \setbox\nextbox\hbox
     {\alignedbox[\layerparameter\c!plaats]\vbox{\flushnextbox}}%
\fi
   \ifnum\layerparameter\c!regel=\zerocount\else % no \ifcase, can be negative 
     \advance\@@layerypos \layerparameter\c!regel\lineheight
     \advance\@@layerypos \topskip 
     \advance\@@layerypos-\lineheight
     \advance\@@layerypos-\nextboxht
   \fi
   \ifnum\layerparameter\c!kolom=\zerocount\else % no \ifcase, can be negative 
     \advance\@@layerxpos \layoutcolumnoffset{\layerparameter\c!kolom}%
   \fi
\ifdone
  \setbox\nextbox\hbox
    {\alignedbox[rb]\vbox{\flushnextbox}}%
\fi
      \smashbox\nextbox
      \vskip\@@layerypos
      \vskip\@@layeryoff
      \hskip\@@layerxpos
      \hskip\@@layerxoff
      \flushnextbox
      \ifvoid\csname\@@layerbox#2#1\layerpage\endcsname
        % already flushed
      \else
        % the reverse case % check !
        \vskip-\@@layerypos
        \vskip-\@@layeryoff
        \box\csname\@@layerbox#2#1\layerpage\endcsname
      \fi}%
   \ifvoid\layerbox\else\box\layerbox\fi}

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

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

% \unexpanded\def\flushlayer[#1]%
%   {\doifnotvalue{\??ll#1\c!status}{\v!stop}
%      {\startoverlay
%         {\doflushlayer1{#1}{#1}}
%         {\doflushlayer0{#1}{#1:\realfolio}}
%       \stopoverlay}}
% 
% \def\doflushlayer#1#2#3%
%   {\ifundefined{\@@layerbox#3}%
%      \ifcase#1\else\writestatus{layer}{unknown layer #3}\fi
%    \else
%      \doifvalue{\??ll#2\c!optie}{\v!test}    
%        {\traceboxplacementtrue\tracelayerstrue}%
%      \iftracelayers \ruledvbox \else \vbox \fi to \overlayheight
%        {\forgetall
%         \hbox to \overlaywidth
%           {\doifvalue{\??ll#3\realfolio\c!positie}{\v!ja}
%              {\xypos{lyr:#3:\realfolio}}%
%            \let\next\box
%            \ifcase#1\else
%              \doifnotvalue{\??ll#2\c!positie}{\v!ja}
%                {\doifvalue{\??ll#2\c!status}{\v!herhaal}
%                   {\let\next\copy}}%
%            \fi                   
%            \next\csname\@@layerbox#3\endcsname
%            \hss}%
%         \vss}%
%    \fi}

\unexpanded\def\flushlayer[#1]%
  {\doifelsevalue{\??ll#1\c!dubbelzijdig}\v!ja
     {\doifundefinedelse{\@@layerbox#1}%
        {\dodoflushlayerA[#1]} 
        {\doifbothsidesoverruled
           \dodoflushlayerB[#1][\v!links]%  left
         \orsideone
           \dodoflushlayerB[#1][\v!rechts]% right 
         \orsidetwo
           \dodoflushlayerB[#1][\v!links]%  left
         \od}}
     {\dodoflushlayerA[#1]}} 

\def\dodoflushlayerA[#1]%
  {\doifnotvalue{\??ll#1\c!status}\v!stop
     {\startoverlay
        {\dodoflushlayer1{#1}{#1}}
        {\dodoflushlayer0{#1}{#1:\realfolio}}
      \stopoverlay}}

\def\dodoflushlayerB[#1][#2]%
  {\doifnotvalue{\??ll#1\c!status}\v!stop
     {\startoverlay
        {\dodoflushlayer1{#1}{#1}}
        {\dodoflushlayer0{#1}{#1:\realfolio}}
        {\dodoflushlayer1{#1}{#2#1}}
        {\dodoflushlayer0{#1}{#2#1:\realfolio}}
      \stopoverlay}}

\def\dodoflushlayer#1#2#3% 
  {\ifundefined{\@@layerbox#3}%
     \ifcase#1\else\writestatus{layer}{unknown layer #3}\fi
   \else
     \doifvalue{\??ll#2\c!optie}\v!test\tracelayerstrue
     \iftracelayers\traceboxplacementtrue\fi
     \doifelsevalue{\??ll#2\c!methode}\v!tekst\donetrue\donefalse
     \iftracelayers \ruledvbox \else \vbox \fi \ifdone \else to \overlayheight \fi
       {\forgetall
        \hbox \ifdone \else to \overlaywidth \fi 
          {% klopt dit? #3 en niet #2 ? 
           \doifvalue{\??ll#3\realfolio\c!positie}\v!ja
             {\xypos{lyr:#3:\realfolio}}%
           \let\next\box
           \ifcase#1\else
             \doifnotvalue{\??ll#2\c!positie}\v!ja
               {\doifvalue{\??ll#2\c!status}\v!herhaal
                  {\let\next\copy}}%
           \fi                   
           \next\csname\@@layerbox#3\endcsname
           \hss}%
        \vss}%
   \fi}

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

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

\let\placelayer\flushlayer

%D \macros
%D  {resetlayer} 
%D
%D This macro hardly needs an explanation (and is seldom 
%D needed as well). 

\def\doresetlayer#1%
  {\ifundefined{\@@layerbox#1}\else 
     \global\setbox\csname\@@layerbox#1\endcsname\emptybox
   \fi}

\def\resetlayer[#1]%
  {\doresetlayer{#1}%
   \doifvalue{\??ll#1\c!dubbelzijdig}\v!ja % kind of redundant test
     {\doresetlayer{\v!links #1}%          
      \doresetlayer{\v!rechts#1}}%         
   \doresetlayer{#1:\realfolio}}  

%D \macros
%D  {setMPlayer}
%D 
%D The following layer macro uses the positions that are 
%D registered by \METAPOST. 
%D
%D \starttypen
%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 \getMLlayer[test]{\useMPgraphic{oeps}}
%D \stoptypen
%D 
%D The last line is equivalent to 
%D
%D \starttypen
%D \framed
%D   [background={foreground,test},offset=overlay]
%D   {\useMPgraphic{oeps}}
%D \stoptypen

\def\setMPlayer
  {\dotripleempty\dosetMPlayer}

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

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

\def\getMPlayer
  {\dodoubleempty\dogetMPlayer}

\def\dogetMPlayer[#1][#2]%
  {\framed
     [\c!achtergrond={\v!voorgrond,#1},
      \c!kader=\v!uit,
      \c!offset=\v!overlay,#2]}

% Some day this (old) mechanism will be combined/integrated 
% in overlays 

\newskip\xposition  \newskip\yposition
\newskip\xdimension \newskip\ydimension
\newskip\xoffset    \newskip\yoffset

\newbox\positionbox

\def\startpositioning
  {\bgroup
   \xposition \zeropoint     \yposition \zeropoint
   \xdimension\zeropoint     \ydimension\zeropoint
   \xoffset   \zeropoint     \yoffset   \zeropoint
   \hfuzz     \papierbreedte \vfuzz     \papierhoogte
   \setbox\positionbox\hbox\bgroup}

\def\stoppositioning
  {\doifnot\@@psoffset\v!ja
     {\global\xoffset\zeropoint
      \global\yoffset\zeropoint}%
   \global\advance\xdimension \xoffset
   \global\advance\ydimension \yoffset
   \egroup
   \vbox to \ydimension
     {\vskip\yoffset
      \hbox to \xdimension
        {\hskip\xoffset
         \box\positionbox
         \hfill}
      \vfill}%
   \egroup}

\def\resetpositioning%
  {\getparameters[\??ps]
     [\c!status=\v!start,
      \c!eenheid=\s!cm,
      \c!factor=1,
      \c!schaal=1,
      \c!xfactor=\@@psfactor,
      \c!yfactor=\@@psfactor,
      \c!xschaal=\@@psschaal,
      \c!yschaal=\@@psschaal,
      \c!xstap=\v!absoluut,
      \c!ystap=\v!absoluut,
      \c!xoffset=\!!zeropoint,
      \c!yoffset=\!!zeropoint]}

\def\setuppositioning%
  {\resetpositioning
   \dodoubleargument\getparameters[\??ps]}

\def\calculateposition#1#2#3#4#5#6#7#8#9%
  {\setdimensionwithunit\scratchskip{#1}\@@pseenheid 
   \scratchskip#8\scratchskip
   \scratchskip#9\scratchskip
   \advance\scratchskip #4\relax
   \doif{#2}\v!relatief
     {\advance\scratchskip #3%
      \let#4\!!zeropoint}%
   #3\scratchskip\relax
   \doifnot\@@psstatus\v!overlay
     {\scratchskip#5\relax
      \advance\scratchskip #3\relax
      \ifdim#3<-#7\relax          \global#7-#3\relax          \fi
      \ifdim\scratchskip>#6\relax \global#6\scratchskip\relax \fi}}

\def\position
  {\dosingleempty\doposition}

\def\doposition[#1]#2(#3,#4)%
  {\dowithnextbox
     {\bgroup
      \getparameters[\??ps][#1]%
      \dontcomplain
      \calculateposition{#3}\@@psxstap\xposition
        \@@psxoffset{\nextboxwd}\xdimension\xoffset
        \@@psxschaal\@@psxfactor
      \scratchdimen\nextboxht \advance\scratchdimen \nextboxdp
      \calculateposition{#4}\@@psystap\yposition
        \@@psyoffset\scratchdimen\ydimension\yoffset
        \@@psyschaal\@@psyfactor
      \vbox to \zeropoint % kan beter. 
        {\vskip\yposition
         \hbox to \zeropoint
           {\hskip\xposition
            \flushnextbox
            \hss}
         \vss}%
      \xdef\dopoppositioning%
        {\xposition\the\xposition
         \yposition\the\yposition
         \noexpand\def\noexpand\@@psxoffset{\@@psxoffset}%
         \noexpand\def\noexpand\@@psyoffset{\@@psyoffset}}%
      \egroup
      \dopoppositioning
      \ignorespaces}
   \hbox}

\resetpositioning

\setuppositioning 
  [\c!eenheid=\s!cm,
   \c!factor=1,
   \c!schaal=1,
   \c!xstap=\v!absoluut,
   \c!ystap=\v!absoluut,
   \c!offset=\v!ja,
   \c!xoffset=\!!zeropoint,
   \c!yoffset=\!!zeropoint]

\protect \endinput 
