pack-lyr.mkxl /size: 28 Kb    last modification: 2023-12-21 09:44
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][\noexpand\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 \dimexpr-\MPx\m_pack_layers_region+\MPx\m_pack_layers_anchor\relax
271   \d_pack_layers_y_position \dimexpr \MPy\m_pack_layers_region-\MPy\m_pack_layers_anchor+\MPh\m_pack_layers_region\relax
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
286   \d_pack_layers_y_position\p_pack_layers_sy\dimexpr\p_pack_layers_y\relax
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  {\layerwidth \layerparameter\c!width  % global (local later)
307   \layerheight\layerparameter\c!height % global (local later)
308   \d_pack_layers_x_size\layerwidth
309   \d_pack_layers_y_size\layerheight
310   %
311   \setupcurrentlayer[#1]% preroll
312   %
313   \edef\p_pack_layers_preset   {\layerparameter\c!preset  }%
314   %
315   \ifcsname\??layerpreset\p_pack_layers_preset\endcsname
316     \lastnamedcs
317     \setupcurrentlayer[#1]% postroll
318   \fi
319   %
320   \edef\p_pack_layers_rotation {\layerparameter\c!rotation }%
321   \edef\p_pack_layers_position {\layerparameter\c!position }%
322   \edef\p_pack_layers_hoffset  {\layerparameter\c!hoffset  }%
323   \edef\p_pack_layers_voffset  {\layerparameter\c!voffset  }%
324   \edef\p_pack_layers_offset   {\layerparameter\c!offset   }%
325   \edef\p_pack_layers_dx       {\layerparameter\c!dx       }%
326   \edef\p_pack_layers_dy       {\layerparameter\c!dy       }%
327   \edef\p_pack_layers_sx       {\layerparameter\c!sx       }%
328   \edef\p_pack_layers_sy       {\layerparameter\c!sy       }%
329   \edef\p_pack_layers_x        {\layerparameter\c!x        }%
330   \edef\p_pack_layers_y        {\layerparameter\c!y        }%
331   \edef\p_pack_layers_corner   {\layerparameter\c!corner   }%
332   \edef\p_pack_layers_location {\layerparameter\c!location }%
333   \edef\p_pack_layers_line     {\layerparameter\c!line     }%
334   \edef\p_pack_layers_column   {\layerparameter\c!column   }%
335   \edef\p_pack_layers_width    {\layerparameter\c!width    }% local ones
336   \edef\p_pack_layers_height   {\layerparameter\c!height   }% local ones
337   %
338   \ifx\p_pack_layers_position\v!overlay
339     \let\p_pack_layers_width   \zeropoint
340     \let\p_pack_layers_height  \zeropoint
341     \let\p_pack_layers_position\v!yes
342   \fi
343   \ifempty\p_pack_layers_rotation \else
344     % use direct call
345     \setbox\nextbox\hpack
346       {\rotate[\c!location=\v!high,\c!rotation=\layerparameter\c!rotation]{\box\nextbox}}%
347   \fi
348   \d_pack_layers_x_offset\p_pack_layers_sx\dimexpr
349     \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
350   \relax
351   \d_pack_layers_y_offset\p_pack_layers_sy\dimexpr
352     \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
353   \relax
354   \ifx\p_pack_layers_position\v!yes
355     \pack_layers_set_last_position_yes
356   \else
357     \pack_layers_set_last_position_nop
358   \fi
359   %
360   \ifempty\m_pack_layers_page \else % is expanded
361     \edef\m_pack_layers_page{:\m_pack_layers_page}%
362     \ifcsname\??layerbox\m_pack_layers_target\currentlayer\m_pack_layers_page\endcsname \else
363       \expandafter\newbox\csname\??layerbox\m_pack_layers_target\currentlayer\m_pack_layers_page\endcsname
364     \fi
365   \fi
366   \integerdef\b_layers_page\csname\??layerbox\m_pack_layers_target\currentlayer\m_pack_layers_page\endcsname
367   \ifvoid\b_layers_page
368     \gsetboxllx\b_layers_page\zeropoint
369     \gsetboxlly\b_layers_page\zeropoint
370   \fi
371   \global\setbox\b_layers_page\vpack %to \layerparameter\c!height % new, otherwise no negative y possible
372     {\offinterlineskip
373      \ifvoid\b_layers_page
374        \scratchwidth \zeropoint
375        \scratchheight\zeropoint
376      \else
377        \scratchwidth \wd\b_layers_page
378        \scratchheight\ht\b_layers_page
379        \ht\b_layers_page\zeropoint
380        \dp\b_layers_page\zeropoint
381        \wd\b_layers_page\zeropoint
382        \ifcstok{\layerparameter\c!direction}\v!reverse\else
383          \box\b_layers_page
384        \fi
385      \fi
386      % don't move
387      \xdef\lastlayerwd{\the\wd\nextbox}%
388      \xdef\lastlayerht{\the\ht\nextbox}% % not entirely ok when grid !
389      \xdef\lastlayerdp{\the\dp\nextbox}% % not entirely ok when grid !
390      % this code
391      \ifx\p_pack_layers_location\v!grid
392        \ht\nextbox\strutheight
393        \dp\nextbox\strutdepth
394      \else
395        \setbox\nextbox\hpack
396          {\alignedbox[\p_pack_layers_location]\vpack{\box\nextbox}}%
397      \fi
398      \ifnum\p_pack_layers_line=\zerocount\else % no \ifcase, can be negative
399    % \ifzero\p_pack_layers_line\else % todo: test this
400        \advanceby\d_pack_layers_y_position\dimexpr\p_pack_layers_line\lineheight+\topskip-\lineheight-\ht\nextbox\relax
401      \fi
402      \ifnum\p_pack_layers_column=\zerocount\else % no \ifcase, can be negative
403    % \ifzero\p_pack_layers_column\else % todo: test this
404        \advanceby\d_pack_layers_x_position\layoutcolumnoffset\p_pack_layers_column\relax
405      \fi
406      \ifx\p_pack_layers_location\v!grid
407        \setbox\nextbox\hpack
408          {\alignedbox[rb]\vpack{\box\nextbox}}%
409      \fi
410      % ll registration
411      \scratchdimen\dimexpr\d_pack_layers_x_position+\d_pack_layers_x_offset\relax
412      \ifdim\scratchdimen<\getboxllx\b_layers_page
413        \gsetboxllx\b_layers_page\scratchdimen
414      \fi
415      \advanceby\scratchdimen\wd\nextbox
416      \wd\nextbox\ifdim\scratchdimen>\scratchwidth \scratchdimen \else \scratchwidth \fi
417      \scratchdimen\dimexpr\d_pack_layers_y_position+\d_pack_layers_y_offset\relax
418      \ifdim\scratchdimen<\getboxlly\b_layers_page
419        \gsetboxlly\b_layers_page\scratchdimen
420      \fi
421      % ll compensation
422      \advanceby\scratchdimen\dimexpr\ht\nextbox+\dp\nextbox\relax
423      \ht\nextbox\ifdim\scratchdimen>\scratchheight \scratchdimen \else \scratchheight \fi
424      \dp\nextbox\zeropoint
425      % placement
426      \hsize\p_pack_layers_width
427      \vpack to \p_pack_layers_height \bgroup
428        \smashbox\nextbox
429        \vskip\dimexpr\d_pack_layers_y_position+\d_pack_layers_y_offset\relax
430        \hskip\dimexpr\d_pack_layers_x_position+\d_pack_layers_x_offset\relax
431        % or maybe instead of the \vskip
432        % \raise-\dimexpr\d_pack_layers_y_position+\d_pack_layers_y_offset\relax
433        \box\nextbox
434        \ifvoid\b_layers_page
435          % already flushed
436        \else
437          % the reverse case % check !
438          \vskip-\dimexpr\d_pack_layers_y_position+\d_pack_layers_y_offset\relax
439          \box\b_layers_page
440        \fi
441      \egroup}%
442   % when position is true, the layerbox holds the compensation and needs
443   % to be placed; never change this !
444   \ifvoid\b_layers \else
445     \box\b_layers
446   \fi}
447
448\def\pack_layers_set_bottom_positions
449  {\ifnum\p_pack_layers_line=\zerocount\else % can be < 0
450% {\ifzero\p_pack_layers_line\else % todo: test this
451     \edef\p_pack_layers_line{\the\numexpr-\p_pack_layers_line+\layoutlines+\plusone\relax}% use counter instead ?
452   \fi
453   \ifdim\d_pack_layers_y_size>\zeropoint
454     \advanceby\d_pack_layers_y_position-\d_pack_layers_y_size
455     \d_pack_layers_y_position-\d_pack_layers_y_position
456     \d_pack_layers_y_offset-\d_pack_layers_y_offset
457   \fi}
458
459\def\pack_layers_set_right_positions
460  {\ifnum\p_pack_layers_column=\zerocount\else % can be < 0
461% {\ifzero\p_pack_layers_column\else % todo: test this
462     \edef\p_pack_layers_column{\the\numexpr-\layerparameter\c!column+\layoutcolumns+\plusone\relax}% use counter instead ?
463   \fi
464   \ifdim\d_pack_layers_x_size>\zeropoint
465     \advanceby\d_pack_layers_x_position-\d_pack_layers_x_size
466     \d_pack_layers_x_position-\d_pack_layers_x_position
467     \d_pack_layers_x_offset-\d_pack_layers_x_offset
468   \fi}
469
470\def\pack_layers_set_middle_positions
471  {\ifdim\d_pack_layers_x_size>\zeropoint \advanceby\d_pack_layers_x_position.5\d_pack_layers_x_size \fi
472   \ifdim\d_pack_layers_y_size>\zeropoint \advanceby\d_pack_layers_y_position.5\d_pack_layers_y_size \fi}
473
474%D Given the task to be accomplished, the previous macro is not even that
475%D complicated. It mainly comes down to skipping to the right place and placing a
476%D box on top of or below the existing content. In the case of position tracking,
477%D another reference point is chosen.
478
479%D \macros
480%D  {doifelselayerdata}
481
482\permanent\def\doifelselayerdata#1%
483  {\ifcsname\??layerbox#1\endcsname
484    %\ifvoid\csname\??layerbox#1\endcsname
485     \ifvoid\lastnamedcs
486       \doubleexpandafter\secondoftwoarguments
487     \else
488       \doubleexpandafter\firstoftwoarguments
489     \fi
490   \else
491     \expandafter\secondoftwoarguments
492   \fi}
493
494\aliased\let\doiflayerdataelse\doifelselayerdata
495
496%D \macros
497%D  {flushlayer}
498%D
499%D When we flush a layer, we flush both the main one and the page dependent one
500%D (when defined). This feature is more efficient in \ETEX\ since there testing for
501%D an undefined macro does not takes hash space.
502
503% todo: setups before flush, handy hook
504
505\permanent\protected\def\flushlayer[#1]% quite core, so optimized (todo: check for void)
506  {\begingroup
507   \forgetall
508   \cdef\currentlayer{#1}%
509   \edef\p_pack_layers_state{\layerparameter\c!state}%
510   \ifx\p_pack_layers_state\v!stop
511     % nothing
512   \orelse\ifx\p_pack_layers_state\v!next
513     \global\letlayerparameter\c!state\v!start  % dangerous, stack-built-up
514   \orelse\ifx\p_pack_layers_state\v!continue
515     \global\letlayerparameter\c!state\v!repeat % dangerous, stack-built-up
516   \orelse\ifcstok{\layerparameter\c!doublesided}\v!yes
517     \ifcsname\??layerbox#1\endcsname
518       % we can make a dedicated one for this
519       \doifbothsidesoverruled
520         {\pack_layers_flush_double\v!left }%
521         {\pack_layers_flush_double\v!right}%
522         {\pack_layers_flush_double\v!left }%
523     \else
524       \pack_layers_flush_single
525     \fi
526   \else
527     \pack_layers_flush_single
528   \fi
529   \endgroup}
530
531% optimized
532
533\mutable\integerdef\b_layer_one\zerocount
534\mutable\integerdef\b_layer_two\zerocount
535
536\def\pack_layers_flush_single
537  {\ifcsname\??layerbox\currentlayer\endcsname
538     \ifvoid\lastnamedcs
539       \ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
540         \ifvoid\lastnamedcs\else
541           \chardef\b_layer_two\lastnamedcs
542           \pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two
543         \fi
544       \fi
545     \else
546       \chardef\b_layer_one\lastnamedcs % will be \integerdef
547       \ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
548         \ifvoid\lastnamedcs\else
549           \chardef\b_layer_two\lastnamedcs % will be \integerdef
550           \startoverlay
551             {\pack_layers_flush_indeed\plusone   \currentlayer                 \b_layer_one}%
552             {\pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two}%
553           \stopoverlay
554         \fi
555       \else
556         \pack_layers_flush_indeed\plusone\currentlayer\b_layer_one
557       \fi
558     \fi
559   \orelse\ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
560     \ifvoid\lastnamedcs
561        % nothing
562     \else
563       \chardef\b_layer_two\lastnamedcs
564       \pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two
565     \fi
566   \fi}
567
568% less optimized:
569
570\def\pack_layers_flush_double#1%
571  {\startoverlay
572     {\ifcsname\??layerbox\currentlayer\endcsname
573        \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
574          \pack_layers_flush_indeed\plusone\currentlayer\b_layer_two
575        \fi
576      \fi}%
577     {\ifcsname\??layerbox\currentlayer:\the\realpageno\endcsname
578        \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
579          \pack_layers_flush_indeed\zerocount{\currentlayer:\the\realpageno}\b_layer_two
580        \fi
581      \fi}%
582     {\ifcsname\??layerbox#1\currentlayer\endcsname
583        \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
584          \pack_layers_flush_indeed\plusone{#1\currentlayer}\b_layer_two
585        \fi
586      \fi}%
587     {\ifcsname\??layerbox#1\currentlayer:\the\realpageno\endcsname
588        \ifvoid\lastnamedcs\else \chardef\b_layer_two\lastnamedcs
589          \pack_layers_flush_indeed\zerocount{#1\currentlayer:\the\realpageno}\b_layer_two
590        \fi
591      \fi}%
592   \stopoverlay}
593
594\let\pack_layers_top_fill   \relax
595\let\pack_layers_bottom_fill\vss
596
597\def\pack_layers_flush_indeed#1#2#3%
598  {\begingroup % already grouped
599   \offinterlineskip
600   \edef\p_pack_layers_preset{\layerparameter\c!preset}%
601   \ifcsname\??layerpreset\p_pack_layers_preset\endcsname
602     \lastnamedcs
603   \fi
604   \edef\p_pack_layers_method{\layerparameter\c!method}%
605   \edef\p_pack_layers_option{\layerparameter\c!option}%
606   \ifx\p_pack_layers_option\v!test
607     \c_pack_layers_trace\conditionaltrue
608     \traceboxplacementtrue
609   \fi
610   \ifcase#1\relax
611     \c_pack_layers_repeated\conditionalfalse
612   \else
613     \edef\p_pack_layers_position{\layerparameter\c!position}%
614     \ifx\p_pack_layers_position\v!yes
615       \c_pack_layers_repeated\conditionalfalse
616     \else
617       \edef\p_pack_layers_repeat{\layerparameter\c!repeat}%
618       \ifx\p_pack_layers_repeat\v!yes
619         \c_pack_layers_repeated\conditionaltrue
620       \orelse\ifx\p_pack_layers_state\v!repeat
621         \c_pack_layers_repeated\conditionaltrue
622       \else
623         \c_pack_layers_repeated\conditionalfalse
624       \fi
625     \fi
626   \fi
627   %chardef\b_layers\csname\??layerbox#2\endcsname % trick
628   \let\b_layers#3%
629   % we need to copy in order to retain the negative offsets for a next
630   % stage of additions, i.e. llx/lly accumulate in repeat mode and the
631   % compensation may differ each flush depending on added content
632   \setbox\nextbox
633     \ifx\p_pack_layers_method\v!fit
634       \pack_layers_positioned_box_yes
635     \else
636       \pack_layers_positioned_box_nop
637     \fi
638   % todo: method=offset => overlayoffset right/down (handy for backgrounds with offset)
639   \doifelseoverlay{#2}%
640     {\setlayoutcomponentattribute{\v!layer:#2}}%
641     \resetlayoutcomponentattribute
642   % we have conflicting demands: some mechanisms want ll anchoring .. I need to figure this out
643   % and maybe we will have 'origin=bottom' or so
644   \setbox\nextbox
645   \ifx\p_pack_layers_option\v!test \ruledvbox \else \vpack \fi \ifx\p_pack_layers_method\v!overlay to \d_overlay_height \fi \layoutcomponentboxattribute
646     {\pack_layers_top_fill
647%
648%       \hpack \ifx\p_pack_layers_method\v!overlay to \d_overlay_width \fi
649%         {\box\nextbox
650%          \hss}%
651%
652      \ifx\p_pack_layers_method\v!overlay \wd\nextbox\d_overlay_width\fi
653      \box\nextbox
654%
655      \pack_layers_bottom_fill}%
656 % \cdef\currentlayer{#2}% :\the\realpageno}% local .. check \anchor
657   \edef\p_pack_layers_position{\layerparameter\c!position}% local
658   \ifx\p_pack_layers_position\v!yes
659     \edef\p_pack_layers_region{\layerparameter\c!region}%
660     \ifempty\p_pack_layers_region\else
661       \anch_mark_tagged_box\nextbox\p_pack_layers_region\zerocount % was \layeranchor
662     \fi
663   \fi
664   \box\nextbox
665   %
666   \ifconditional\c_pack_layers_repeated\else
667     \gsetboxllx\b_layers\zeropoint
668     \gsetboxlly\b_layers\zeropoint
669   \fi
670   \endgroup}
671
672\def\pack_layers_positioned_box_yes
673  {\vpack
674     {\vskip-\getboxlly\b_layers
675      \hskip-\getboxllx\b_layers
676      \hsize-\dimexpr\getboxllx\b_layers-\wd\b_layers\relax
677      \ifconditional\c_pack_layers_repeated\copy\else\box\fi\b_layers}}
678
679\def\pack_layers_positioned_box_nop
680  {\ifconditional\c_pack_layers_repeated\copy\else\box\fi\b_layers}
681
682% \definelayer[test][method=fit] \setupcolors[state=start,option=test]
683%
684% \framed[framecolor=red,offset=overlay]{\setlayer[test]{aa}\setlayer[test][x=10pt]{g}\flushlayer[test]}
685% \framed[framecolor=red,offset=overlay]{\setlayer[test]{aa}\setlayer[test][x=-10pt]{bb}\flushlayer[test]}
686% \framed[framecolor=red,offset=overlay]{\setlayer[test][x=-20pt]{cccccc}\flushlayer[test]}
687% \framed[framecolor=red,offset=overlay]{\setlayer[test]{dd}\setlayer[test][x=-20pt,y=-3pt]{eeeeee}\flushlayer[test]}
688
689%D \macros
690%D  {composedlayer,placelayer,tightlayer}
691%D
692%D This is a handy shortcut, which saves a couple of braces when we use it as
693%D parameter. This name also suits better to other layering commands.
694
695\permanent\protected\def\composedlayer#1{\flushlayer[#1]}
696
697\permanent\protected\def\tightlayer[#1]%
698  {\hpack
699     {\cdef\currentlayer{#1}% todo: left/right
700      \setbox\nextbox\emptybox
701      \d_overlay_width \layerparameter\c!width
702      \d_overlay_height\layerparameter\c!height
703      \composedlayer{#1}}}
704
705\aliased\let\placelayer\flushlayer
706
707%D \macros
708%D  {setMPlayer}
709%D
710%D The following layer macro uses the positions that are registered by \METAPOST.
711%D
712%D \starttyping
713%D \definelayer[test]
714%D
715%D \setMPlayer [test] [somepos-1] {Whatever we want here!}
716%D \setMPlayer [test] [somepos-2] {Whatever we need there!}
717%D \setMPlayer [test] [somepos-3] {\externalfigure[cow.mps][width=2cm]}
718%D
719%D \startuseMPgraphic{oeps}
720%D   draw fullcircle scaled 10cm withcolor red ;
721%D   register ("somepos-1",2cm,3cm,center currentpicture) ;
722%D   register ("somepos-2",8cm,5cm,(-1cm,-2cm)) ;
723%D   register ("somepos-3",0cm,0cm,(-2cm,2cm)) ;
724%D \stopuseMPgraphic
725%D
726%D \getMPlayer[test]{\useMPgraphic{oeps}}
727%D \stoptyping
728%D
729%D The last line is equivalent to
730%D
731%D \starttyping
732%D \framed
733%D   [background={foreground,test},offset=overlay]
734%D   {\useMPgraphic{oeps}}
735%D \stoptyping
736
737\mutable\def\MPlayerwidth {\hsize}
738\mutable\def\MPlayerheight{\vsize}
739
740\permanent\tolerant\protected\def\setMPlayer[#1]#*[#2]#*[S#3]%
741  {\edef\MPlayerwidth {\MPw{#2}}%
742   \edef\MPlayerheight{\MPh{#2}}%
743   \setlayer[#1][\c!x=\MPx{#2},\c!y=\MPy{#2},\c!position=\v!no,#3]}
744
745\permanent\tolerant\protected\def\getMPlayer[#1]#*[#S#2]%
746  {\framed[\c!background={\v!foreground,#1},\c!frame=\v!off,\c!offset=\v!overlay,#2]} % takes argument
747
748%D Watch out, a redefinition:
749
750\ifdefined\settextpagecontent \else
751    \writestatus\m!system{error in page-lyr.tex} \wait
752\fi
753
754\definelayer
755  [OTRTEXT]
756
757\setuplayer
758  [OTRTEXT]
759  [\c!width=\innermakeupwidth,
760   \c!height=\textheight]
761
762\aliased\let\normalsettextpagecontent\settextpagecontent % will be overloaded in page-spr
763
764\overloaded\aliased\let\normalsettextpagecontent\settextpagecontent % will be overloaded in page-spr
765
766\permanent\overloaded\protected\def\settextpagecontent#1#2#3% #2 and #3 will disappear
767  {\doifelselayerdata{OTRTEXT}
768     {\setbox#1\hpack to \makeupwidth
769        {\startoverlay
770           {\tightlayer[OTRTEXT]} % first, otherwise problems with toc
771           {\normalsettextpagecontent{#1}{#2}{#3}\box#1}
772         \stopoverlay}%
773      \dp#1\zeropoint}%
774     {\normalsettextpagecontent{#1}{#2}{#3}}}
775
776\protect \endinput
777