pack-lyr.mkxl /size: 28 Kb    last modification: 2025-02-21 11:03
1%D \module
2%D   [       file=pack-lyr,
3%D        version=2000.10.20,
4%D          title=\CONTEXT\ Packaging Macros,
5%D       subtitle=Layers,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14\writestatus{loading}{ConTeXt Packaging Macros / Layers}
15
16% todo : first / last / next / +... => page key
17%        test on left/right box when no doublesided option given
18%        use \ifcsname instead of doifvalue
19
20\unprotect
21
22% When being backgrounds layers get the background offset displacement. Should be
23% an option, on by default (compatibility).
24
25%D The layering mechanism implemented here is independent of the output routine, but
26%D future extensions may depend on a more close cooperation.
27%D
28%D First we overload a macro from \type {pack-rul}. From now on we accept a
29%D (optional) argument: the specific layer it will go in. This means that we can
30%D move an overlay from one background to the other using the dimensions of the
31%D parent.
32
33\ifdefined\defineoverlay \else \message{loaded to early} \wait \fi
34
35\pushoverloadmode
36
37\permanent\overloaded\tolerant\protected\def\defineoverlay[#1]#*[#S#2]#*[#S#3]% overlay [layer] content
38  {\ifnum\lastarguments=\plusthree
39    %\writestatus{BEWARE}{This (overlay definition) has changed!}% temp
40     \def\pack_framed_define_overlay_indeed##1{\defcsname\??overlay##1\endcsname{\setlayer[#2]{\executedefinedoverlay{##1}{#3}}}}%
41   \else
42     \def\pack_framed_define_overlay_indeed##1{\defcsname\??overlay##1\endcsname{\executedefinedoverlay{##1}{#2}}}%
43   \fi
44   \processcommalist[#1]\pack_framed_define_overlay_indeed}
45
46\popoverloadmode
47
48%D We use the command handler code. The previous, more direct parameter handling was
49%D 25\% faster when no parameters were passed when adding content to a layer.
50%D However, when we pass for instance a preset, the new methos is some 10\% faster
51%D and it happens that in most cases we do pass some parameters. It would be
52%D interesting to see if we can push the preset in between the regular chain but it
53%D could also lead to unwanted side effects when nesting layer placement.
54
55\installcorenamespace{layer}
56\installcorenamespace{layerbox}
57\installcorenamespace{layerpreset}
58\installcorenamespace{layerposition} % brr, unreadable
59
60%D \macros
61%D   {definelayer,setuplayer}
62%D
63%D Each layer gets its own (global) box. This also means that the data that goes
64%D into a layer, is typeset immediately. Each layer automatically gets an associated
65%D overlay, which can be used in any background assignment.
66%D
67%D After a layer is defined, you can change its characteristics.
68
69\installcommandhandler \??layer {layer} \??layer
70
71\setuplayer
72  [\c!state=\v!start,
73  %\c!doublesided=,
74  %\c!preset=,
75  %\c!option=,
76  %\c!corner=,
77  %\c!page=,
78  %\c!rotation=, % geen 0 !
79   \c!direction=\v!normal,
80   \c!position=\v!no,
81   \c!method=\v!overlay,
82   \c!x=\zeropoint,
83   \c!y=\zeropoint,
84   \c!line=0,
85   \c!column=0,
86   \c!width=\wd\nextbox,  % don't change this globally
87   \c!height=\ht\nextbox, % don't change this globally
88   \c!offset=\zeropoint,
89   \c!hoffset=\zeropoint,
90   \c!voffset=\zeropoint,
91   \c!dx=\zeropoint,
92   \c!dy=\zeropoint,
93   \c!location=rb,
94   \c!sx=1,
95   \c!sy=1,
96   \c!region=\layeranchor]
97
98\permanent\def\layeranchor{\currentlayer:\the\realpageno}
99
100\lettonothing\m_pack_layers_anchor
101\lettonothing\m_pack_layers_page
102\lettonothing\m_pack_layers_region
103\lettonothing\m_pack_layers_target
104\lettonothing\p_pack_layers_column
105\lettonothing\p_pack_layers_corner
106\lettonothing\p_pack_layers_dx
107\lettonothing\p_pack_layers_dy
108\lettonothing\p_pack_layers_height
109\lettonothing\p_pack_layers_hoffset
110\lettonothing\p_pack_layers_line
111\lettonothing\p_pack_layers_location
112\lettonothing\p_pack_layers_method
113\lettonothing\p_pack_layers_offset
114\lettonothing\p_pack_layers_option
115\lettonothing\p_pack_layers_position
116\lettonothing\p_pack_layers_preset
117\lettonothing\p_pack_layers_region
118\lettonothing\p_pack_layers_repeat
119\lettonothing\p_pack_layers_rotation
120\lettonothing\p_pack_layers_state
121\lettonothing\p_pack_layers_sx
122\lettonothing\p_pack_layers_sy
123\lettonothing\p_pack_layers_voffset
124\lettonothing\p_pack_layers_width
125\lettonothing\p_pack_layers_x
126\lettonothing\p_pack_layers_y
127
128\newconditional\c_pack_layers_repeated
129\newconditional\c_pack_layers_trace
130\newinteger    \c_pack_layers_current_data
131
132\newbox\b_layers \pushoverloadmode \mutable\let\b_layers\b_layers \popoverloadmode
133
134\newdimension\d_pack_layers_x_size
135\newdimension\d_pack_layers_y_size
136\newdimension\d_pack_layers_x_offset
137\newdimension\d_pack_layers_y_offset
138\newdimension\d_pack_layers_x_position
139\newdimension\d_pack_layers_y_position
140
141\newdimension\layerwidth
142\newdimension\layerheight
143
144\mutable\let\lastlayerxpos\!!zeropoint
145\mutable\let\lastlayerypos\!!zeropoint
146\mutable\let\lastlayerwd  \!!zeropoint
147\mutable\let\lastlayerht  \!!zeropoint
148\mutable\let\lastlayerdp  \!!zeropoint
149
150\appendtoks
151    \ifcstok{\layerparameter\c!doublesided}\v!yes
152        \relateparameterhandlers{layer}{\v!left \currentlayer}{layer}\currentlayer % permits left*
153        \relateparameterhandlers{layer}{\v!right\currentlayer}{layer}\currentlayer % permits right*
154        \pack_layers_preset_box{\v!left \currentlayer}%
155        \pack_layers_preset_box{\v!right\currentlayer}%
156    \fi
157    \pack_layers_preset_box\currentlayer
158    \normalexpanded{\defineoverlay[\currentlayer][\composedlayer{\currentlayer}]}%
159\to \everydefinelayer
160
161\def\pack_layers_preset_box#1%
162  {\ifcsname\??layerbox#1\endcsname
163     \resetlayer[#1]%
164   \else
165     \expandafter\newbox\csname\??layerbox#1\endcsname
166   \fi}
167
168%D \macros
169%D  {resetlayer}
170%D
171%D This macro hardly needs an explanation (but is seldom needed anyway).
172
173\def\pack_layers_reset_box#1%
174  {\ifcsname\??layerbox#1\endcsname
175    %\global\setbox\csname\??layerbox#1\endcsname\emptybox
176     \global\setbox\lastnamedcs\emptybox
177   \fi}
178
179\permanent\protected\def\resetlayer[#1]%
180  {\pack_layers_reset_box{#1}%
181   \pack_layers_reset_box{\v!left #1}%
182   \pack_layers_reset_box{\v!right#1}%
183   \pack_layers_reset_box{#1:\the\realpageno}}
184
185%D \macros
186%D   {setlayer}
187%D
188%D Data is moved into a layer with the following macro. When \type {position} is
189%D set, relative positioning is used, with the current point as reference point.
190%D Otherwise the topleft corner is used as reference point.
191%D
192%D \starttyping
193%D \setlayer [identifier] [optional parameters] {data}
194%D \stoptyping
195
196\mutable\lettonothing\currentlayerwidth
197\mutable\lettonothing\currentlayerheight
198
199\permanent\tolerant\protected\def\setcurrentlayerdimensions[#1]#*[#2]% name left|right
200  {\edef\currentlayerwidth {\thelayerwidth {#2#1}}%
201   \edef\currentlayerheight{\thelayerheight{#2#1}}}
202
203\permanent\def\thelayerwidth #1{\the\ifcsname\??layerbox#1\endcsname\wd\lastnamedcs\else\zeropoint\fi}
204\permanent\def\thelayerheight#1{\the\ifcsname\??layerbox#1\endcsname\ht\lastnamedcs\else\zeropoint\fi}
205
206\permanent\tolerant\protected\def\setlayer[#1]#*[#S#2]#*[#S#3]% #4 == box do \fi is ok
207  {\bgroup
208   \nofarguments\lastarguments
209   \checkpositionoverlays % otherwise funny regions
210   \cdef\currentlayer{#1}%
211   \edef\p_pack_layers_state{\layerparameter\c!state}%
212   \ifx\p_pack_layers_state\v!stop
213     \dowithnextboxcs\egroup\hbox % no pack ?
214   \orelse\ifnum\nofarguments=\plusthree
215     \edef\m_pack_layers_target{#2}%
216     \pack_layers_set_indeed{#3}%
217   \orelse\ifhastok={#2}%
218     \lettonothing\m_pack_layers_target
219     \pack_layers_set_indeed{#2}%
220   \else
221     \edef\m_pack_layers_target{#2}%
222     \pack_layers_set_indeed\empty
223   \fi}
224
225\def\pack_layers_set_indeed#1%
226  {\page_backgrounds_recalculate % brrr
227   \global\advanceby\c_pack_layers_current_data\plusone
228   \forgetall
229   \dontcomplain
230   \edef\p_pack_layers_option{\layerparameter\c!option}%
231   \ifx\p_pack_layers_option\v!test
232     \c_pack_layers_trace\conditionaltrue
233     \traceboxplacementtrue
234   \fi
235   \dowithnextbox{\pack_layers_set_finish{#1}}\hbox}
236
237\def\pack_layers_set_finish#1%
238  {\ifcsname\??layerbox\currentlayer\endcsname % can move up
239     \ifx\m_pack_layers_target\v!even
240       \ifodd\realpageno
241         % discard nextbox
242       \else
243         \let\m_pack_layers_target\v!left
244         \pack_layers_set_content{#1}%
245       \fi
246     \orelse\ifx\m_pack_layers_target\v!odd
247       \ifodd\realpageno
248         \let\m_pack_layers_target\v!right
249         \pack_layers_set_content{#1}%
250       \else
251         % discard nextbox
252       \fi
253     \else
254       \pack_layers_set_content{#1}%
255     \fi
256   \else
257     \writestatus{layer}{unknown layer \currentlayer}%
258   \fi
259   \egroup}
260
261% todo: left/right
262% todo: get position data in one go
263
264\def\pack_layers_set_last_position_yes % target: left|right
265  {% this will become one call
266   \edef\m_pack_layers_anchor{\??layerposition\the\c_pack_layers_current_data}%
267   \edef\m_pack_layers_page  {\MPp\m_pack_layers_anchor}%
268   %edef\m_pack_layers_region{\MPr\m_pack_layers_anchor}% wrong one
269   \edef\m_pack_layers_region{\layerparameter\c!region}%
270   \d_pack_layers_x_position{-\jobposx\m_pack_layers_region+\jobposx\m_pack_layers_anchor}%
271   \d_pack_layers_y_position{ \jobposy\m_pack_layers_region-\jobposy\m_pack_layers_anchor+\jobposh\m_pack_layers_region}%
272   \xdef\lastlayerxpos{\the\d_pack_layers_x_position}%
273   \xdef\lastlayerypos{\the\d_pack_layers_y_position}%
274 % \writestatus{layering}{region: \m_pack_layers_region=>\MPxywhd\m_pack_layers_region}%
275 % \writestatus        {}{anchor: \m_pack_layers_anchor=>\MPxywhd\m_pack_layers_anchor}%
276 % \writestatus        {}{offset: \c!dx,\c!dy          =>\lastlayerxpos,\lastlayerypos}%
277   \global\letlayerparameter\c!state\v!start % needed ?
278   \setbox\b_layers\vpack to \d_pack_layers_y_size
279     {\hpack to \d_pack_layers_x_size
280        {\xypos\m_pack_layers_anchor\hss}%
281      \vss}}
282
283\def\pack_layers_set_last_position_nop
284  {\setbox\b_layers\emptybox
285   \d_pack_layers_x_position\p_pack_layers_sx \dimexpr\p_pack_layers_x\relax % multiplied
286   \d_pack_layers_y_position\p_pack_layers_sy \dimexpr\p_pack_layers_y\relax % multiplied
287   \glet\lastlayerxpos\!!zeropoint
288   \glet\lastlayerypos\!!zeropoint
289   \ifinset\v!bottom\p_pack_layers_corner\pack_layers_set_bottom_positions\fi
290   \ifinset\v!right \p_pack_layers_corner\pack_layers_set_right_positions \fi
291   \ifinset\v!middle\p_pack_layers_corner\pack_layers_set_middle_positions\fi
292   \edef\m_pack_layers_page{\layerparameter\c!page}}
293
294\permanent\tolerant\protected\def\definelayerpreset[#1]#*[#S#2]%
295  {\ifarguments\or
296     \letcsname\??layerpreset#1\endcsname\empty
297   \orelse\ifhastok={#2}%
298     \defcsname\??layerpreset#1\endcsname{\setupcurrentlayer[#2]}%
299   \else
300     \defcsname\??layerpreset#1\endcsname{\csname\??layerpreset#2\endcsname}%
301   \fi}
302
303\mutable\integerdef\b_layers_page\zerocount
304
305\def\pack_layers_set_content#1%
306  {\resetstacking % for Aditya to test and document
307   \layerwidth {\layerparameter\c!width }% global (local later)
308   \layerheight{\layerparameter\c!height}% global (local later)
309   \d_pack_layers_x_size\layerwidth
310   \d_pack_layers_y_size\layerheight
311   %
312   \setupcurrentlayer[#1]% preroll
313   %
314   \edef\p_pack_layers_preset   {\layerparameter\c!preset  }%
315   %
316   \ifcsname\??layerpreset\p_pack_layers_preset\endcsname
317     \lastnamedcs
318     \setupcurrentlayer[#1]% postroll
319   \fi
320   %
321   \edef\p_pack_layers_rotation {\layerparameter\c!rotation }%
322   \edef\p_pack_layers_position {\layerparameter\c!position }%
323   \edef\p_pack_layers_hoffset  {\layerparameter\c!hoffset  }%
324   \edef\p_pack_layers_voffset  {\layerparameter\c!voffset  }%
325   \edef\p_pack_layers_offset   {\layerparameter\c!offset   }%
326   \edef\p_pack_layers_dx       {\layerparameter\c!dx       }%
327   \edef\p_pack_layers_dy       {\layerparameter\c!dy       }%
328   \edef\p_pack_layers_sx       {\layerparameter\c!sx       }%
329   \edef\p_pack_layers_sy       {\layerparameter\c!sy       }%
330   \edef\p_pack_layers_x        {\layerparameter\c!x        }% can be moved inline
331   \edef\p_pack_layers_y        {\layerparameter\c!y        }% can be moved inline
332   \edef\p_pack_layers_corner   {\layerparameter\c!corner   }%
333   \edef\p_pack_layers_location {\layerparameter\c!location }%
334   \edef\p_pack_layers_line     {\layerparameter\c!line     }%
335   \edef\p_pack_layers_column   {\layerparameter\c!column   }%
336   \edef\p_pack_layers_width    {\layerparameter\c!width    }% local ones
337   \edef\p_pack_layers_height   {\layerparameter\c!height   }% local ones
338   %
339   \ifx\p_pack_layers_position\v!overlay
340     \let\p_pack_layers_width   \zeropoint
341     \let\p_pack_layers_height  \zeropoint
342     \let\p_pack_layers_position\v!yes
343   \fi
344   \ifempty\p_pack_layers_rotation \else
345     % use direct call
346     \setbox\nextbox\hpack
347       {\rotate[\c!location=\v!high,\c!rotation=\layerparameter\c!rotation]{\box\nextbox}}%
348   \fi
349   \d_pack_layers_x_offset \p_pack_layers_sx \dimexpr % multiplied
350     \ifx\p_pack_layers_hoffset\v!max
351       \d_pack_layers_x_size
352     \else
353       \p_pack_layers_hoffset
354     \fi
355    +\p_pack_layers_offset
356    +\p_pack_layers_dx
357   \relax
358   \d_pack_layers_y_offset \p_pack_layers_sy \dimexpr % multiplied
359     \ifx\p_pack_layers_voffset\v!max
360       \d_pack_layers_y_size
361     \else
362       \p_pack_layers_voffset
363     \fi
364    +\p_pack_layers_offset
365    +\p_pack_layers_dy
366   \relax
367   \ifx\p_pack_layers_position\v!yes
368     \pack_layers_set_last_position_yes
369   \else
370     \pack_layers_set_last_position_nop
371   \fi
372   %
373   \ifempty\m_pack_layers_page \else % is expanded
374     \edef\m_pack_layers_page{:\m_pack_layers_page}%
375     \ifcsname\??layerbox\m_pack_layers_target\currentlayer\m_pack_layers_page\endcsname \else
376       \expandafter\newbox\csname\??layerbox\m_pack_layers_target\currentlayer\m_pack_layers_page\endcsname
377     \fi
378   \fi
379   \integerdef\b_layers_page\csname\??layerbox\m_pack_layers_target\currentlayer\m_pack_layers_page\endcsname
380   \ifvoid\b_layers_page
381     \gsetboxllx\b_layers_page\zeropoint
382     \gsetboxlly\b_layers_page\zeropoint
383   \fi
384   \global\setbox\b_layers_page\vpack %to \layerparameter\c!height % new, otherwise no negative y possible
385     {\offinterlineskip
386      \ifvoid\b_layers_page
387        \scratchwidth \zeropoint
388        \scratchheight\zeropoint
389      \else
390        \scratchwidth \wd\b_layers_page
391        \scratchheight\ht\b_layers_page
392        \ht\b_layers_page\zeropoint
393        \dp\b_layers_page\zeropoint
394        \wd\b_layers_page\zeropoint
395        \ifcstok{\layerparameter\c!direction}\v!reverse\else
396          \box\b_layers_page
397        \fi
398      \fi
399      % don't move
400      \xdef\lastlayerwd{\the\wd\nextbox}%
401      \xdef\lastlayerht{\the\ht\nextbox}% % not entirely ok when grid !
402      \xdef\lastlayerdp{\the\dp\nextbox}% % not entirely ok when grid !
403      % this code
404      \ifx\p_pack_layers_location\v!grid
405        \ht\nextbox\strutheight
406        \dp\nextbox\strutdepth
407      \else
408        \setbox\nextbox\hpack
409          {\alignedbox[\p_pack_layers_location]\vpack{\box\nextbox}}%
410      \fi
411      \ifnum\p_pack_layers_line=\zerocount\else % no \ifcase, can be negative
412    % \ifzero\p_pack_layers_line\else % todo: test this
413        \advanceby\d_pack_layers_y_position{\p_pack_layers_line\lineheight+\topskip-\lineheight-\ht\nextbox}%
414      \fi
415      \ifnum\p_pack_layers_column=\zerocount\else % no \ifcase, can be negative
416    % \ifzero\p_pack_layers_column\else % todo: test this
417        \advanceby\d_pack_layers_x_position{\layoutcolumnoffset\p_pack_layers_column}%
418      \fi
419      \ifx\p_pack_layers_location\v!grid
420        \setbox\nextbox\hpack
421          {\alignedbox[rb]\vpack{\box\nextbox}}%
422      \fi
423      % ll registration
424      \scratchdimen{\d_pack_layers_x_position+\d_pack_layers_x_offset}%
425      \ifdim\scratchdimen<\getboxllx\b_layers_page
426        \gsetboxllx\b_layers_page\scratchdimen
427      \fi
428      \advanceby\scratchdimen\wd\nextbox
429      \wd\nextbox\ifdim\scratchdimen>\scratchwidth \scratchdimen \else \scratchwidth \fi
430      \scratchdimen{\d_pack_layers_y_position+\d_pack_layers_y_offset}%
431      \ifdim\scratchdimen<\getboxlly\b_layers_page
432        \gsetboxlly\b_layers_page\scratchdimen
433      \fi
434      % ll compensation
435      \advanceby\scratchdimen\htdp\nextbox
436      \ht\nextbox\ifdim\scratchdimen>\scratchheight \scratchdimen \else \scratchheight \fi
437      \dp\nextbox\zeropoint
438      % placement
439      \hsize\p_pack_layers_width
440      \vpack to \p_pack_layers_height \bgroup
441        \smashbox\nextbox
442        \vskip{\d_pack_layers_y_position+\d_pack_layers_y_offset}%
443        \hskip{\d_pack_layers_x_position+\d_pack_layers_x_offset}%
444        % or maybe instead of the \vskip
445        % \raise-{\d_pack_layers_y_position+\d_pack_layers_y_offset}%
446        \box\nextbox
447        \ifvoid\b_layers_page
448          % already flushed
449        \else
450          % the reverse case % check !
451          \vskip{-(\d_pack_layers_y_position+\d_pack_layers_y_offset)}%
452          \box\b_layers_page
453        \fi
454      \egroup}%
455   % when position is true, the layerbox holds the compensation and needs
456   % to be placed; never change this !
457   \ifvoid\b_layers \else
458     \box\b_layers
459   \fi}
460
461\def\pack_layers_set_bottom_positions
462  {\ifnum\p_pack_layers_line=\zerocount\else % can be < 0
463% {\ifzero\p_pack_layers_line\else % todo: test this
464     \edef\p_pack_layers_line{\tointeger{-\p_pack_layers_line+\layoutlines+\plusone}}% use counter instead ?
465   \fi
466   \ifdim\d_pack_layers_y_size>\zeropoint
467     \advanceby\d_pack_layers_y_position-\d_pack_layers_y_size
468     \d_pack_layers_y_position-\d_pack_layers_y_position
469     \d_pack_layers_y_offset-\d_pack_layers_y_offset
470   \fi}
471
472\def\pack_layers_set_right_positions
473  {\ifnum\p_pack_layers_column=\zerocount\else % can be < 0
474% {\ifzero\p_pack_layers_column\else % todo: test this
475     \edef\p_pack_layers_column{\tointeger{-\layerparameter\c!column+\layoutcolumns+\plusone}}% use counter instead ?
476   \fi
477   \ifdim\d_pack_layers_x_size>\zeropoint
478     \advanceby\d_pack_layers_x_position-\d_pack_layers_x_size
479     \d_pack_layers_x_position-\d_pack_layers_x_position
480     \d_pack_layers_x_offset-\d_pack_layers_x_offset
481   \fi}
482
483\def\pack_layers_set_middle_positions
484  {\ifdim\d_pack_layers_x_size>\zeropoint \advanceby\d_pack_layers_x_position.5\d_pack_layers_x_size \fi
485   \ifdim\d_pack_layers_y_size>\zeropoint \advanceby\d_pack_layers_y_position.5\d_pack_layers_y_size \fi}
486
487%D Given the task to be accomplished, the previous macro is not even that
488%D complicated. It mainly comes down to skipping to the right place and placing a
489%D box on top of or below the existing content. In the case of position tracking,
490%D another reference point is chosen.
491
492%D \macros
493%D  {doifelselayerdata}
494
495\permanent\def\doifelselayerdata#1%
496  {\ifcsname\??layerbox#1\endcsname
497    %\ifvoid\csname\??layerbox#1\endcsname
498     \ifvoid\lastnamedcs
499       \doubleexpandafter\secondoftwoarguments
500     \else
501       \doubleexpandafter\firstoftwoarguments
502     \fi
503   \else
504     \expandafter\secondoftwoarguments
505   \fi}
506
507\aliased\let\doiflayerdataelse\doifelselayerdata
508
509%D \macros
510%D  {flushlayer}
511%D
512%D When we flush a layer, we flush both the main one and the page dependent one
513%D (when defined). This feature is more efficient in \ETEX\ since there testing for
514%D an undefined macro does not takes hash space.
515
516% todo: setups before flush, handy hook
517
518\permanent\protected\def\flushlayer[#1]% quite core, so optimized (todo: check for void)
519  {\begingroup
520   \forgetall
521   \cdef\currentlayer{#1}%
522   \edef\p_pack_layers_state{\layerparameter\c!state}%
523   \ifx\p_pack_layers_state\v!stop
524     % nothing
525   \orelse\ifx\p_pack_layers_state\v!next
526     \global\letlayerparameter\c!state\v!start  % dangerous, stack-built-up
527   \orelse\ifx\p_pack_layers_state\v!continue
528     \global\letlayerparameter\c!state\v!repeat % dangerous, stack-built-up
529   \orelse\ifcstok{\layerparameter\c!doublesided}\v!yes
530     \ifcsname\??layerbox#1\endcsname
531       % we can make a dedicated one for this
532       \doifbothsidesoverruled
533         {\pack_layers_flush_double\v!left }%
534         {\pack_layers_flush_double\v!right}%
535         {\pack_layers_flush_double\v!left }%
536     \else
537       \pack_layers_flush_single
538     \fi
539   \else
540     \pack_layers_flush_single
541   \fi
542   \endgroup}
543
544% optimized
545
546\mutable\integerdef\b_layer_one\zerocount
547\mutable\integerdef\b_layer_two\zerocount
548
549\def\pack_layers_flush_single
550  {\ifcsname\??layerbox\currentlayer\endcsname
551     \ifvoid\lastnamedcs
552       \ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
553         \ifvoid\lastnamedcs\else
554           \chardef\b_layer_two\lastnamedcs
555           \pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two
556         \fi
557       \fi
558     \else
559       \chardef\b_layer_one\lastnamedcs % will be \integerdef
560       \ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
561         \ifvoid\lastnamedcs\else
562           \chardef\b_layer_two\lastnamedcs % will be \integerdef
563           \startoverlay
564             {\pack_layers_flush_indeed\plusone   \currentlayer                 \b_layer_one}%
565             {\pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two}%
566           \stopoverlay
567         \fi
568       \else
569         \pack_layers_flush_indeed\plusone\currentlayer\b_layer_one
570       \fi
571     \fi
572   \orelse\ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
573     \ifvoid\lastnamedcs
574        % nothing
575     \else
576       \chardef\b_layer_two\lastnamedcs
577       \pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two
578     \fi
579   \fi}
580
581% less optimized:
582
583\def\pack_layers_flush_double#1%
584  {\startoverlay
585     {\ifcsname\??layerbox\currentlayer\endcsname
586        \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
587          \pack_layers_flush_indeed\plusone\currentlayer\b_layer_two
588        \fi
589      \fi}%
590     {\ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
591        \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
592          \pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two
593        \fi
594      \fi}%
595     {\ifcsname\??layerbox#1\currentlayer\endcsname
596        \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
597          \pack_layers_flush_indeed\plusone{#1\currentlayer}\b_layer_two
598        \fi
599      \fi}%
600     {\ifcsname\??layerbox#1\currentlayer:\the\realpageno\endcsname
601        \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
602          \pack_layers_flush_indeed\zerocount{#1\currentlayer:\the\realpageno}\b_layer_two
603        \fi
604      \fi}%
605   \stopoverlay}
606
607\let\pack_layers_top_fill   \relax
608\let\pack_layers_bottom_fill\vss
609
610\def\pack_layers_flush_indeed#1#2#3%
611  {\begingroup % already grouped
612   \offinterlineskip
613   \edef\p_pack_layers_preset{\layerparameter\c!preset}%
614   \ifcsname\??layerpreset\p_pack_layers_preset\endcsname
615     \lastnamedcs
616   \fi
617   \edef\p_pack_layers_method{\layerparameter\c!method}%
618   \edef\p_pack_layers_option{\layerparameter\c!option}%
619   \ifx\p_pack_layers_option\v!test
620     \c_pack_layers_trace\conditionaltrue
621     \traceboxplacementtrue
622   \fi
623   \ifcase#1\relax
624     \c_pack_layers_repeated\conditionalfalse
625   \else
626     \edef\p_pack_layers_position{\layerparameter\c!position}%
627     \ifx\p_pack_layers_position\v!yes
628       \c_pack_layers_repeated\conditionalfalse
629     \else
630       \edef\p_pack_layers_repeat{\layerparameter\c!repeat}%
631       \ifx\p_pack_layers_repeat\v!yes
632         \c_pack_layers_repeated\conditionaltrue
633       \orelse\ifx\p_pack_layers_state\v!repeat
634         \c_pack_layers_repeated\conditionaltrue
635       \else
636         \c_pack_layers_repeated\conditionalfalse
637       \fi
638     \fi
639   \fi
640   %chardef\b_layers\csname\??layerbox#2\endcsname % trick
641   \let\b_layers#3%
642   % we need to copy in order to retain the negative offsets for a next
643   % stage of additions, i.e. llx/lly accumulate in repeat mode and the
644   % compensation may differ each flush depending on added content
645   \setbox\nextbox
646     \ifx\p_pack_layers_method\v!fit
647       \pack_layers_positioned_box_yes
648     \else
649       \pack_layers_positioned_box_nop
650     \fi
651   % todo: method=offset => overlayoffset right/down (handy for backgrounds with offset)
652   \doifelseoverlay{#2}%
653     {\setlayoutcomponentattribute{\v!layer:#2}}%
654     \resetlayoutcomponentattribute
655   % we have conflicting demands: some mechanisms want ll anchoring .. I need to figure this out
656   % and maybe we will have 'origin=bottom' or so
657   \setbox\nextbox
658   \ifx\p_pack_layers_option\v!test \ruledvbox \else \vpack \fi \ifx\p_pack_layers_method\v!overlay to \d_overlay_height \fi \layoutcomponentboxattribute
659     {\pack_layers_top_fill
660%
661%       \hpack \ifx\p_pack_layers_method\v!overlay to \d_overlay_width \fi
662%         {\box\nextbox
663%          \hss}%
664%
665      \ifx\p_pack_layers_method\v!overlay \wd\nextbox\d_overlay_width\fi
666      \box\nextbox
667%
668      \pack_layers_bottom_fill}%
669 % \cdef\currentlayer{#2}% :\the\realpageno}% local .. check \anchor
670   \edef\p_pack_layers_position{\layerparameter\c!position}% local
671   \ifx\p_pack_layers_position\v!yes
672     \edef\p_pack_layers_region{\layerparameter\c!region}%
673     \ifempty\p_pack_layers_region\else
674       \anch_mark_tagged_box\nextbox\p_pack_layers_region\zerocount % was \layeranchor
675     \fi
676   \fi
677   \box\nextbox
678   %
679   \ifconditional\c_pack_layers_repeated\else
680     \gsetboxllx\b_layers\zeropoint
681     \gsetboxlly\b_layers\zeropoint
682   \fi
683   \endgroup}
684
685\def\pack_layers_positioned_box_yes
686  {\vpack
687     {\vskip-\getboxlly\b_layers
688      \hskip-\getboxllx\b_layers
689      \hsize{\wd\b_layers-\getboxllx\b_layers}%
690      \ifconditional\c_pack_layers_repeated\copy\else\box\fi\b_layers}}
691
692\def\pack_layers_positioned_box_nop
693  {\ifconditional\c_pack_layers_repeated\copy\else\box\fi\b_layers}
694
695% \definelayer[test][method=fit] \setupcolors[state=start,option=test]
696%
697% \framed[framecolor=red,offset=overlay]{\setlayer[test]{aa}\setlayer[test][x=10pt]{g}\flushlayer[test]}
698% \framed[framecolor=red,offset=overlay]{\setlayer[test]{aa}\setlayer[test][x=-10pt]{bb}\flushlayer[test]}
699% \framed[framecolor=red,offset=overlay]{\setlayer[test][x=-20pt]{cccccc}\flushlayer[test]}
700% \framed[framecolor=red,offset=overlay]{\setlayer[test]{dd}\setlayer[test][x=-20pt,y=-3pt]{eeeeee}\flushlayer[test]}
701
702%D \macros
703%D  {composedlayer,placelayer,tightlayer}
704%D
705%D This is a handy shortcut, which saves a couple of braces when we use it as
706%D parameter. This name also suits better to other layering commands.
707
708\permanent\protected\def\composedlayer#1{\flushlayer[#1]}
709
710\permanent\protected\def\tightlayer[#1]%
711  {\hpack
712     {\cdef\currentlayer{#1}% todo: left/right
713      \setbox\nextbox\emptybox
714      \d_overlay_width {\layerparameter\c!width}%
715      \d_overlay_height{\layerparameter\c!height}%
716      \composedlayer{#1}}}
717
718\aliased\let\placelayer\flushlayer
719
720%D \macros
721%D  {setMPlayer}
722%D
723%D The following layer macro uses the positions that are registered by \METAPOST.
724%D
725%D \starttyping
726%D \definelayer[test]
727%D
728%D \setMPlayer [test] [somepos-1] {Whatever we want here!}
729%D \setMPlayer [test] [somepos-2] {Whatever we need there!}
730%D \setMPlayer [test] [somepos-3] {\externalfigure[cow.mps][width=2cm]}
731%D
732%D \startuseMPgraphic{oeps}
733%D   draw fullcircle scaled 10cm withcolor red ;
734%D   register ("somepos-1",2cm,3cm,center currentpicture) ;
735%D   register ("somepos-2",8cm,5cm,(-1cm,-2cm)) ;
736%D   register ("somepos-3",0cm,0cm,(-2cm,2cm)) ;
737%D \stopuseMPgraphic
738%D
739%D \getMPlayer[test]{\useMPgraphic{oeps}}
740%D \stoptyping
741%D
742%D The last line is equivalent to
743%D
744%D \starttyping
745%D \framed
746%D   [background={foreground,test},offset=overlay]
747%D   {\useMPgraphic{oeps}}
748%D \stoptyping
749
750\mutable\def\MPlayerwidth {\hsize}
751\mutable\def\MPlayerheight{\vsize}
752
753\permanent\tolerant\protected\def\setMPlayer[#1]#*[#2]#*[S#3]%
754  {\edef\MPlayerwidth {\MPw{#2}}%
755   \edef\MPlayerheight{\MPh{#2}}%
756   \setlayer[#1][\c!x=\MPx{#2},\c!y=\MPy{#2},\c!position=\v!no,#3]}
757
758\permanent\tolerant\protected\def\getMPlayer[#1]#*[#S#2]%
759  {\framed[\c!background={\v!foreground,#1},\c!frame=\v!off,\c!offset=\v!overlay,#2]} % takes argument
760
761%D Watch out, a redefinition:
762
763\ifdefined\settextpagecontent \else
764    \writestatus\m!system{error in page-lyr.tex} \wait
765\fi
766
767\definelayer
768  [OTRTEXT]
769
770\setuplayer
771  [OTRTEXT]
772  [\c!width=\innermakeupwidth,
773   \c!height=\textheight]
774
775\aliased\let\normalsettextpagecontent\settextpagecontent % will be overloaded in page-spr
776
777\overloaded\aliased\let\normalsettextpagecontent\settextpagecontent % will be overloaded in page-spr
778
779\permanent\overloaded\protected\def\settextpagecontent#1#2#3% #2 and #3 will disappear
780  {\doifelselayerdata{OTRTEXT}
781     {\setbox#1\hpack to \makeupwidth
782        {\startoverlay
783           {\tightlayer[OTRTEXT]} % first, otherwise problems with toc
784           {\normalsettextpagecontent{#1}{#2}{#3}\box#1}
785         \stopoverlay}%
786      \dp#1\zeropoint}%
787     {\normalsettextpagecontent{#1}{#2}{#3}}}
788
789\protect \endinput
790