supp-box.mkxl /size: 87 Kb    last modification: 2021-10-28 13:51
1%D \module
2%D   [       file=supp-box,
3%D        version=1995.10.10,
4%D          title=\CONTEXT\ Support Macros,
5%D       subtitle=Boxes,
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 Support Macros / Boxes}
15
16\unprotect
17
18\registerctxluafile{supp-box}{autosuffix,optimize}
19
20%D And some dimensions:
21
22\newdimen\givenwidth
23\newdimen\givenheight
24\newdimen\givendepth
25
26% \fixupboxesmode\plusone % gone: is now the default
27
28%D This module implements some box manipulation macros. Some are quite simple, some
29%D are more advanced and when understood well, all can be of use.
30%D
31%D \macros
32%D   {strutdp,strutht,strutwd}
33%D
34%D The next shortcuts save memory and keying. The width is normally zero points (if
35%D not, you're in trouble). These shortcuts can be used like a dimension, opposite
36%D to the core macros \type {\strutdepth} and alike, which are values.
37
38                    \def\strutdp  {\dp\strutbox} % overloaded in spac-ver
39                    \def\strutht  {\ht\strutbox} % overloaded in spac-ver
40\permanent\protected\def\strutwd  {\wd\strutbox}
41\permanent\protected\def\struthtdp{\dimexpr\strutht+\strutdp\relax}
42\permanent\protected\def\strutgap {\dimexpr\strutht-\strutdp\relax}
43
44%D \macros
45%D   {voidbox,nextbox}
46%D
47%D Let's start with an easy one. The next macro hides the ugly \type {@} in \type
48%D {\voidb@x}.
49
50\ifdefined\voidbox \else \newbox\voidbox \fi
51\ifdefined\nextbox \else \newbox\nextbox \fi
52
53%D \macros
54%D   {nextdepth}
55%D
56%D Let's start with a rather simple declaration. Sometimes we need to save the \TEX\
57%D \DIMENSION\ \type{\prevdepth} and append it later on. The name \type {\nextdepth}
58%D suits this purpose well.
59
60\newdimen\nextdepth
61
62%D \macros
63%D   {smashbox, smashboxed, smashedbox}
64%D
65%D Smashing is introduced in \PLAIN\ \TEX, and stands for reducing the dimensions of
66%D a box to zero. The most resolute one is presented first.
67
68% \permanent\protected\def\smashbox#1%
69%   {\wd#1\zeropoint
70%    \ht#1\zeropoint
71%    \dp#1\zeropoint}
72%
73% \permanent\protected\def\smashboxed#1%
74%   {\wd#1\zeropoint
75%    \ht#1\zeropoint
76%    \dp#1\zeropoint
77%    \box#1\relax}
78
79%D \macros
80%D   {hsmashbox,vsmashbox}
81%D
82%D Smashing can be used for overlaying boxes. Depending on the mode, horizontal or
83%D vertical, one can use:
84
85% \permanent\protected\def\hsmashbox#1%
86%   {\wd#1\zeropoint}
87%
88% \permanent\protected\def\vsmashbox#1%
89%   {\ht#1\zeropoint
90%    \dp#1\zeropoint}
91
92%D The next implementation is less sensitive for spurious spaces.
93
94\newcount\c_boxes_register
95
96\permanent\protected\def\smashbox
97  {\afterassignment\syst_boxes_smash_boxes_register\c_boxes_register}
98
99\def\syst_boxes_smash_boxes_register
100  {\wd\c_boxes_register\zeropoint
101   \ht\c_boxes_register\zeropoint
102   \dp\c_boxes_register\zeropoint}
103
104\permanent\protected\def\hsmashbox
105  {\afterassignment\syst_boxes_hsmashed_boxes_register\c_boxes_register}
106
107\def\syst_boxes_hsmashed_boxes_register
108  {\wd\c_boxes_register\zeropoint}
109
110\permanent\protected\def\vsmashbox
111  {\afterassignment\syst_boxes_vsmashed_boxes_register\c_boxes_register}
112
113\def\syst_boxes_vsmashed_boxes_register
114  {\ht\c_boxes_register\zeropoint
115   \dp\c_boxes_register\zeropoint}
116
117\permanent\protected\def\smashedbox
118  {\afterassignment\syst_boxes_smashed_boxes_register\c_boxes_register}
119
120\protected\def\syst_boxes_smashed_boxes_register
121  {\wd\c_boxes_register\zeropoint
122   \ht\c_boxes_register\zeropoint
123   \dp\c_boxes_register\zeropoint
124   \box\c_boxes_register}
125
126\aliased\let\smashboxed\smashedbox
127
128%D \macros
129%D   {hsmash,vsmash,
130%D    hsmashed,vsmashed}
131%D
132%D While the previous macros expected a \BOX, the next act on a content. They are
133%D some subtle differences betreen the smash and smashed alternatives. The later
134%D ones reduce all dimensions to zero.
135
136\permanent\protected\def\hsmash  {\bgroup\dowithnextboxcs\syst_boxes_hsmashed_nextbox\hbox}
137\permanent\protected\def\vsmash  {\bgroup\dowithnextboxcs\syst_boxes_vsmashed_nextbox\vbox}
138\permanent\protected\def\hsmashed{\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox \hbox}
139\permanent\protected\def\vsmashed{\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox \vbox}
140
141\protected\def\syst_boxes_hsmashed_nextbox
142  {\wd\nextbox\zeropoint
143   \box\nextbox
144   \egroup}
145
146\protected\def\syst_boxes_vsmashed_nextbox
147  {\ht\nextbox\zeropoint
148   \dp\nextbox\zeropoint
149   \box\nextbox
150   \egroup}
151
152\protected\def\syst_boxes_smashed_nextbox
153  {\ht\nextbox\zeropoint
154   \dp\nextbox\zeropoint
155   \wd\nextbox\zeropoint
156   \box\nextbox
157   \egroup}
158
159%D \macros
160%D   {smashedhbox,smashedvbox}
161%D
162%D Also handy (all dimensions zeroed):
163%D
164%D \starttyping
165%D \smashedhbox to ... {...}
166%D \smashedvbox to ... {...}
167%D \stoptyping
168
169\permanent\protected\def\smashedhbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox\hbox}
170\permanent\protected\def\smashedvbox{\vpack\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox\vbox}
171
172%D First we define a helper. We use a \LUATEX\ feature in order to avoid
173%D mathpalettes.
174
175\newcount\c_boxes_math_style
176
177\protected\def\syst_boxes_math_set_nextbox#1%
178  {\c_boxes_math_style\normalmathstyle
179   \setbox\nextbox\hbox{\normalstartimath\mathsurround\zeropoint\triggermathstyle\c_boxes_math_style{#1}\normalstopimath}}
180
181%D \macros
182%D   {smash}
183%D
184%D This smash alternative takes an optional arg [whdtb] as well as is potentially
185%D catcode safer. It is needed by the math module (although the \type {\leavevmode}
186%D is not added here).
187
188\permanent\protected\def\smash
189  {\begingroup
190   \futureexpandis[\syst_boxes_smash_yes\syst_boxes_smash_nop}
191
192\def\syst_boxes_smash_nop
193  {\edef\m_boxes_smash_options{hd}%
194   \futurelet\nexttoken\syst_boxes_smash_indeed}
195
196\def\syst_boxes_smash_yes[#1]%
197  {\edef\m_boxes_smash_options{#1}%
198   \futurelet\nexttoken\syst_boxes_smash_indeed}
199
200\def\syst_boxes_smash_indeed
201  {\ifmmode
202     \expandafter\syst_boxes_smash_math
203   \orelse\ifx\nexttoken\bgroup
204     \expandafter\syst_boxes_smash_hbox
205   \else
206     \expandafter\syst_boxes_smash_text
207   \fi}
208
209\def\syst_boxes_smash_math#1%
210  {\syst_boxes_math_set_nextbox{#1}%
211   \syst_boxes_smash_process}
212
213\def\syst_boxes_smash_hbox
214  {\dowithnextboxcs\syst_boxes_smash_process\hbox}
215
216\def\syst_boxes_smash_text#1%
217  {\setbox\nextbox\hbox{#1}%
218   \syst_boxes_smash_process}
219
220\def\syst_boxes_smash_process
221  {\expandafter\syst_boxes_smash_process_option\m_boxes_smash_options\relax
222   \box\nextbox
223   \endgroup}
224
225\installcorenamespace {smashoptions}
226
227\defcsname\??smashoptions   w\endcsname{\wd\nextbox\zeropoint}
228\defcsname\??smashoptions   h\endcsname{\ht\nextbox\zeropoint}
229\defcsname\??smashoptions   d\endcsname{\dp\nextbox\zeropoint}
230\defcsname\??smashoptions   t\endcsname{\ht\nextbox\zeropoint}
231\defcsname\??smashoptions   b\endcsname{\dp\nextbox\zeropoint}
232\defcsname\??smashoptions  hd\endcsname{\ht\nextbox\zeropoint\dp\nextbox\zeropoint}
233\defcsname\??smashoptions whd\endcsname{\wd\nextbox\zeropoint\ht\nextbox\zeropoint\dp\nextbox\zeropoint}
234
235\def\syst_boxes_smash_process_option#1%
236  {\ifx#1\relax\else
237     \begincsname\??smashoptions#1\endcsname
238     \expandafter\syst_boxes_smash_process_option
239   \fi}
240
241\def\syst_boxes_lower_nextbox_dp
242  {\setbox\nextbox\hpack{\lower\dp\nextbox\box\nextbox}}
243
244%D \starttabulate[|l|l|]
245%D \NC w   \NC \ruledhbox{\smash  [w]{This is some great smashing, isn't it?}} \NC \NR
246%D \NC h   \NC \ruledhbox{\smash  [h]{This is some great smashing, isn't it?}} \NC \NR
247%D \NC d   \NC \ruledhbox{\smash  [d]{This is some great smashing, isn't it?}} \NC \NR
248%D \NC tb  \NC \ruledhbox{\smash [tb]{This is some great smashing, isn't it?}} \NC \NR
249%D \NC whd \NC \ruledhbox{\smash[whd]{This is some great smashing, isn't it?}} \NC \NR
250%D \stoptabulate
251
252%D \macros
253%D   {phantom, hphantom, vphantom, mathstrut}
254%D
255%D The next implementation of \type {\phantom} cum suis does not grab an argument in
256%D the non||math case, which is better.
257%D
258%D Due to a complicated call to \type {\mathpallete} and thereby \type
259%D {\mathchoice}, the next macro looks ugly. We also take care of non||braced
260%D arguments.
261
262\permanent\protected\def\phantom {\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed  }
263\permanent\protected\def\vphantom{\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed_v}
264\permanent\protected\def\hphantom{\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed_h}
265
266\def\syst_boxes_phantom_math  #1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make  }
267\def\syst_boxes_phantom_math_v#1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make_v}
268\def\syst_boxes_phantom_math_h#1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make_h}
269
270\def\syst_boxes_phantom_hbox  {\dowithnextboxcs\syst_boxes_phantom_make  \hbox} % always hbox
271\def\syst_boxes_phantom_hbox_v{\dowithnextboxcs\syst_boxes_phantom_make_v\hbox} % always hbox
272\def\syst_boxes_phantom_hbox_h{\dowithnextboxcs\syst_boxes_phantom_make_h\hbox} % always hbox
273
274\def\syst_boxes_phantom_text  #1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make  } % always hbox
275\def\syst_boxes_phantom_text_v#1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make_v} % always hbox
276\def\syst_boxes_phantom_text_h#1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make_h} % always hbox
277
278\def\syst_boxes_phantom_indeed
279  {\ifmmode
280     \expandafter\syst_boxes_phantom_math
281   \orelse\ifx\nexttoken\bgroup
282     \expandafter\syst_boxes_phantom_hbox
283   \else
284     \expandafter\syst_boxes_phantom_text
285   \fi}
286
287\def\syst_boxes_phantom_indeed_v
288  {\ifmmode
289     \expandafter\syst_boxes_phantom_math_v
290   \orelse\ifx\nexttoken\bgroup
291     \expandafter\syst_boxes_phantom_hbox_v
292   \else
293     \expandafter\syst_boxes_phantom_text_v
294   \fi}
295
296\def\syst_boxes_phantom_indeed_h
297  {\ifmmode
298     \expandafter\syst_boxes_phantom_math_h
299   \orelse\ifx\nexttoken\bgroup
300     \expandafter\syst_boxes_phantom_hbox_h
301   \else
302     \expandafter\syst_boxes_phantom_text_h
303   \fi}
304
305\def\syst_boxes_phantom_make
306  {\setbox\scratchbox\emptyhbox
307   \ht\scratchbox\ht\nextbox
308   \dp\scratchbox\dp\nextbox
309   \wd\scratchbox\wd\nextbox
310   \box\scratchbox
311   \endgroup}
312
313\def\syst_boxes_phantom_make_v
314  {\setbox\scratchbox\emptyhbox
315   \ht\scratchbox\ht\nextbox
316   \dp\scratchbox\dp\nextbox
317   \box\scratchbox
318   \endgroup}
319
320\def\syst_boxes_phantom_make_h
321  {\setbox\scratchbox\emptyhbox
322   \wd\scratchbox\wd\nextbox
323   \box\scratchbox
324   \endgroup}
325
326%D We also define plain's \type {\mathstrut}.
327
328\permanent\protected\def\mathstrut{\vphantom(} % can be made faster by inlining
329
330%D \macros
331%D   {getboxheight}
332%D
333%D Although often needed, \TEX\ does not support arithmics like:
334%D
335%D \starttyping
336%D \dimen0 = \ht0 + \dp0
337%D \stoptyping
338%D
339%D so we implemented:
340%D
341%D \starttyping
342%D \getboxheight ... \of \box...
343%D \stoptyping
344%D
345%D For instance,
346%D
347%D \starttyping
348%D \getboxheight \dimen0 \of \box0
349%D \getboxheight \someheight \of \box \tempbox
350%D \stoptyping
351%D
352%D The implementation is rather stupid:
353%D
354%D \starttyping
355%D \def\getboxheight#1\of#2\box#3%
356%D   {#1\ht#3\advance#1\dp#3\relax}
357%D \stoptyping
358%D
359%D The next alternative is slightly more clever, since it accepts \type {{12}} as
360%D well as \type {12} as box number.
361
362\permanent\protected\def\getboxheight#1\of#2\box#3%
363  {\def\next{#1\htdp\c_boxes_register}%
364   \afterassignment\next\c_boxes_register=#3}
365
366%D For a long time the following three macros were part of the grid snapping core
367%D module, but it makes more sense to have them here so that users can see them.
368%D
369%D \macros
370%D   {getnoflines, getroundednoflines, getrawnoflines}
371%D
372%D Het commando \type {\getnoflines} converteert een hoogte (dimensie) in een aantal
373%D regels en kent dit toe aan \type {\noflines}.
374%D
375%D \starttyping
376%D \getnoflines{dimensie}
377%D \stoptyping
378%D
379%D Er wordt gedeeld door \type {\openlineheight} en een hoogte van~0pt komt overeen
380%D met 0~regels. The raw alternative does not round. See the \MKII\ and \MKIV\ files
381%D for historic variants.
382
383\ifdefined\roundingeps \else \newdimen\roundingeps \roundingeps=10sp \fi
384
385\newcount\noflines
386\newdimen\noflinesheight
387
388\permanent\protected\def\getnoflines#1%
389  {\noflinesheight#1\relax
390   \ifzeropt\noflinesheight
391     \noflines\zerocount
392   \orelse\ifdim\noflinesheight>\zeropoint
393     \advance\noflinesheight-\roundingeps
394     \divide\noflinesheight\openlineheight
395     \noflines\noflinesheight
396     \advance\noflines\plusone
397   \else
398     \advance\noflinesheight\roundingeps
399     \divide\noflinesheight\openlineheight
400     \noflines\noflinesheight
401     \advance\noflines\minusone
402   \fi}
403
404\permanent\protected\def\getroundednoflines#1%
405  {\noflinesheight#1\relax
406   \ifzeropt\noflinesheight
407     \noflines\zerocount
408   \orelse\ifdim\noflinesheight>\zeropoint
409     \advance\noflinesheight\roundingeps
410     \divide\noflinesheight\openlineheight
411     \noflines\noflinesheight
412   \else
413     \advance\noflinesheight-\roundingeps
414     \divide\noflinesheight\openlineheight
415     \noflines\noflinesheight
416   \fi}
417
418\permanent\protected\def\getrawnoflines#1%
419  {\noflinesheight#1\relax
420   \ifzeropt\noflinesheight
421     \noflines\zerocount
422   \orelse\ifdim\noflinesheight>\zeropoint
423     \advance\noflinesheight\roundingeps
424     \advance\noflinesheight.5\openlineheight
425     \divide\noflinesheight\openlineheight
426     \noflines\noflinesheight
427   \else
428     \advance\noflinesheight-\roundingeps
429     \advance\noflinesheight-.5\openlineheight
430     \divide\noflinesheight\openlineheight
431     \noflines\noflinesheight
432   \fi}
433
434%D Let's proof that it works:
435%D
436%D \startbuffer
437%D \scratchdimen\dimexpr(3pt)               \getnoflines\scratchdimen  1=\the\noflines \endgraf
438%D \scratchdimen\dimexpr(10\lineheight)     \getnoflines\scratchdimen 10=\the\noflines \endgraf
439%D \scratchdimen\dimexpr(10.1\lineheight)   \getnoflines\scratchdimen 11=\the\noflines \endgraf
440%D \scratchdimen\dimexpr(10.5\lineheight)   \getnoflines\scratchdimen 11=\the\noflines \endgraf
441%D \scratchdimen\dimexpr(10.9\lineheight)   \getnoflines\scratchdimen 11=\the\noflines \endgraf
442%D \scratchdimen\dimexpr(10\lineheight+3pt) \getnoflines\scratchdimen 11=\the\noflines \endgraf
443%D \scratchdimen\dimexpr(10\lineheight+3sp) \getnoflines\scratchdimen 10=\the\noflines \endgraf
444%D \scratchdimen\dimexpr(10\lineheight-3sp) \getnoflines\scratchdimen 10=\the\noflines \endgraf
445%D
446%D \scratchdimen\dimexpr(3pt)               \getrawnoflines\scratchdimen  0=\the\noflines \endgraf
447%D \scratchdimen\dimexpr(10\lineheight)     \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
448%D \scratchdimen\dimexpr(10.1\lineheight)   \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
449%D \scratchdimen\dimexpr(10.5\lineheight)   \getrawnoflines\scratchdimen 11=\the\noflines \endgraf
450%D \scratchdimen\dimexpr(10.9\lineheight)   \getrawnoflines\scratchdimen 11=\the\noflines \endgraf
451%D \scratchdimen\dimexpr(10\lineheight+3pt) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
452%D \scratchdimen\dimexpr(10\lineheight+3sp) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
453%D \scratchdimen\dimexpr(10\lineheight-3sp) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf
454%D \stopbuffer
455%D
456%D \typebuffer \getbuffer
457
458%D \macros
459%D   {determinenoflines}
460%D
461%D The next macro determines the number of lines and returns it it \type
462%D {\noflines}. The macro works reasonable well as long as the content can be
463%D unboxed.
464%D
465%D \starttyping
466%D \determinenoflines{test\\test}
467%D \determinenoflines{\bfd test\\test}
468%D \determinenoflines{\definedfont[Sans at 40pt]test\\test}
469%D \stoptyping
470
471% \def\syst_boxes_determine_noflines % can be mkiv'd
472%   {\beginofshapebox
473%      \unvbox\nextbox
474%    \endofshapebox
475%    \globalscratchcounter\zerocount
476%    \reshapebox{\global\advance\globalscratchcounter\plusone}%
477%    \expandafter\egroup\expandafter\noflines\the\globalscratchcounter\relax}
478
479\def\syst_boxes_determine_noflines
480  {\expandafter\egroup\expandafter\noflines\noflinesinbox\nextbox\relax}
481
482\permanent\protected\def\determinenoflines
483  {\bgroup
484   \forgetall
485   \enforced\let\crlf\endgraf
486   \enforced\let\\\endgraf
487   \dowithnextboxcs\syst_boxes_determine_noflines\vbox}
488
489\def\determinednoflines#1%
490  {\localcontrolled{\determinenoflines{#1}}\noflines}
491
492%D \macros
493%D   {doiftextelse, doiftext}
494%D
495%D When \type {\doifelse} cum suis hopelessly fail, for instance because we pass
496%D data, we can fall back on the next macro:
497%D
498%D \starttyping
499%D \doiftextelse {data} {then branch} {else branch}
500%D \doiftext     {data} {then branch}
501%D \stoptyping
502
503\permanent\protected\def\doifelsetext#1%
504  {\begingroup
505   \setbox\scratchbox\hbox % no \hpack because we can have fallbacks
506     {\settrialtypesetting
507      \ignorespaces#1\removeunwantedspaces}%
508   \ifzeropt\wd\scratchbox
509     \endgroup\expandafter\secondoftwoarguments
510   \else
511     \endgroup\expandafter\firstoftwoarguments
512   \fi}
513
514\permanent\protected\def\doiftext#1%
515  {\begingroup
516   \setbox\scratchbox\hbox % no \hpack because we can have fallbacks
517     {\settrialtypesetting
518      \ignorespaces#1\removeunwantedspaces}%
519   \ifzeropt\wd\scratchbox
520     \endgroup\expandafter\gobbleoneargument
521   \else
522     \endgroup\expandafter\firstofoneargument
523   \fi}
524
525% more efficient but maybe fragile:
526%
527%       \nospacing#1}%
528
529\aliased\let\doiftextelse\doifelsetext
530
531%D \macros
532%D   {dowithnextbox,nextbox}
533%D
534%D Sometimes we want a macro to grab a box and do something on the content. One
535%D could pass an argument to a box, but this can violate the specific \CATCODES\ of
536%D its content and leads to unexpected results. The next macro treats the following
537%D braced text as the content of a box and manipulates it afterwards in a predefined
538%D way.
539%D
540%D The first argument specifies what to do with the content. This content is
541%D available in \type {\nextbox}. The second argument is one of \type {\hbox}, \type
542%D {\vbox} or \type {\vtop}. The third argument must be grouped with \type {\bgroup}
543%D and \type {\egroup}, \type {{...}} or can be a \type {\box} specification.
544%D
545%D In \CONTEXT\ this macro is used for picking up a box and treating it according to
546%D earlier specifications. We use for instance something like:
547%D
548%D \starttyping
549%D \def\getfloat%
550%D   {\def\handlefloat{...\box\nextbox...}
551%D    \dowithnextboxcs\handlefloat\vbox}
552%D \stoptyping
553%D
554%D instead of:
555%D
556%D \starttyping
557%D \def\getfloat#1%
558%D   {...#1...}
559%D \stoptyping
560%D
561%D In this implementation the \type {\aftergroup} construction is needed because
562%D \type {\afterassignment} is executed inside the box.
563
564\let\syst_boxes_with_next_box\relax
565
566\permanent\protected\def\dowithnextbox#1%
567  {\def\syst_boxes_with_next_box{#1}%
568   \afterassignment\syst_boxes_with_next_box_indeed
569   \setbox\nextbox}
570
571\def\syst_boxes_with_next_box_indeed
572  {\aftergroup\syst_boxes_with_next_box}
573
574\permanent\protected\def\dowithnextboxcs#1%
575  {\let\syst_boxes_with_next_box#1%
576   \afterassignment\syst_boxes_with_next_box_indeed
577   \setbox\nextbox}
578
579%D So in fact we get:
580%D
581%D \starttyping
582%D \setbox\nextbox { \aftergroup\syst_boxes_with_next_box ... }
583%D \stoptyping
584%D
585%D or
586%D
587%D \starttyping
588%D \setbox\nextbox { ... } \syst_boxes_with_next_box
589%D \stoptyping
590%D
591%D A slower but more versatile implementation is:
592%D
593%D \starttyping
594%D \protected\def\dowithnextbox#1#2%
595%D   {\def\syst_boxes_with_next_box{#1}%
596%D    \ifx#2\hbox
597%D      \afterassignment\syst_boxes_with_next_box_indeed
598%D    \orelse\ifx#2\vbox
599%D      \afterassignment\syst_boxes_with_next_box_indeed
600%D    \orelse\ifx#2\vtop
601%D      \afterassignment\syst_boxes_with_next_box_indeed
602%D    \orelse\ifx#2\normalvcenter
603%D      \afterassignment\syst_boxes_with_next_box_indeed
604%D    \else
605%D      \afterassignment\syst_boxes_with_next_box
606%D    \fi
607%D    \setbox\nextbox#2}
608%D \stoptyping
609%D
610%D This alternative also accepts \type {\box0} and alike, but we don't really need
611%D this functionality now.
612
613%D \macros
614%D   {nextboxht,nextboxwd,nextboxdp,flushnextbox}
615%D
616%D The next couple of shortcuts saves us memory as well as \type {{}}'s in passing
617%D parameters.
618
619\permanent\def\nextboxht  {\ht\nextbox}
620\permanent\def\nextboxwd  {\wd\nextbox}
621\permanent\def\nextboxdp  {\dp\nextbox}
622\permanent\def\nextboxhtdp{\htdp\nextbox}
623
624\permanent\protected\def\flushnextbox{\box\nextbox}
625
626%D \macros
627%D   {dowithnextboxcontent}
628%D
629%D But, occasionally we do need to pass some local settings without wanting to use
630%D additional grouping. Therefore we provide:
631%D
632%D \starttyping
633%D \dowithnextboxcontent{inside}{after}{box content}
634%D \stoptyping
635%D
636%D {\em todo: Search source for potential usage!}
637
638% \protected\def\dowithnextboxcontent#1#2% inside, after
639%   {\def\syst_boxes_with_next_box_one{#2}%
640%    \def\syst_boxes_with_next_box_two{#1}%
641%    \afterassignment\syst_boxes_with_next_box_content_indeed
642%    \setbox\nextbox}
643%
644% \protected\def\dowithnextboxcontentcs#1#2% inside, after
645%   {\let\syst_boxes_with_next_box_one#2%
646%    \let\syst_boxes_with_next_box_two#1%
647%    \afterassignment\syst_boxes_with_next_box_content_indeed
648%    \setbox\nextbox}
649%
650% \def\syst_boxes_with_next_box_content_indeed
651%   {\syst_boxes_with_next_box_two\aftergroup\syst_boxes_with_next_box_one}
652
653\permanent\protected\def\dowithnextboxcontent#1#2% inside, after
654  {\afterassigned{#1\aftergrouped{#2}}%
655   \setbox\nextbox}
656
657\permanent\protected\def\dowithnextboxcontentcs#1#2% inside, after
658  {\afterassigned{#1\aftergroup#2}%
659   \setbox\nextbox}
660
661%D \macros
662%D   {llap, rlap, tlap, blap, clap}
663%D
664%D Some well known friends, but we implement them our own way. We want the macros to
665%D work in both math and text mode.
666
667\def\syst_boxes_do_rlap{\hpack to \zeropoint{\box\nextbox\hss}\endgroup}
668\def\syst_boxes_do_llap{\hpack to \zeropoint{\hss\box\nextbox}\endgroup}
669\def\syst_boxes_do_clap{\hpack to \zeropoint{\hss\box\nextbox\hss}\endgroup}
670\def\syst_boxes_do_tlap{\vpack to \zeropoint{\vss\box\nextbox}\endgroup}
671\def\syst_boxes_do_blap{\vpack to \zeropoint{\box\nextbox\vss}\endgroup}
672
673\def\syst_boxes_rlap     {\begingroup\dowithnextboxcs\syst_boxes_do_rlap\hbox}
674\def\syst_boxes_llap     {\begingroup\dowithnextboxcs\syst_boxes_do_llap\hbox}
675\def\syst_boxes_clap     {\begingroup\dowithnextboxcs\syst_boxes_do_clap\hbox}
676\def\syst_boxes_math_clap{\mathpalette\syst_boxes_do_math_clap}
677\def\syst_boxes_math_llap{\mathpalette\syst_boxes_do_math_llap}
678\def\syst_boxes_math_rlap{\mathpalette\syst_boxes_do_math_rlap}
679
680\def\syst_boxes_do_math_clap#1#2{\syst_boxes_clap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}}
681\def\syst_boxes_do_math_llap#1#2{\syst_boxes_llap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}}
682\def\syst_boxes_do_math_rlap#1#2{\syst_boxes_rlap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}}
683
684\permanent\protected\def\rlap{\mathortext\syst_boxes_math_rlap\syst_boxes_rlap}
685\permanent\protected\def\llap{\mathortext\syst_boxes_math_llap\syst_boxes_llap}
686\permanent\protected\def\clap{\mathortext\syst_boxes_math_clap\syst_boxes_clap}
687\permanent\protected\def\tlap{\begingroup\dowithnextboxcs\syst_boxes_do_tlap\vbox}
688\permanent\protected\def\blap{\begingroup\dowithnextboxcs\syst_boxes_do_blap\vbox}
689
690%D in \LMTX\ this mechanism is obsolete! Use boxlines instead!
691
692%D \macros
693%D   {beginofshapebox,
694%D    reshapebox, doreshapebox,
695%D    flushshapebox,
696%D    innerflushshapebox,
697%D    shapebox,
698%D    ifreshapingbox}
699%D
700%D The next utility macro originates from some linenumbering mechanism. Due to
701%D \TEX's advanced way of typesetting paragraphs, it's not easy to do things on a
702%D line||by||line basis. This macro is able to reprocess a given box and can act
703%D upon its vertical boxed components, such as lines. The unwinding sequence in this
704%D macro is inspired by a \NTG\ workshop of David Salomon in June 1992.
705%D
706%D First we have to grab the piece of text we want to act upon. This is done by
707%D means of the duo macros:
708%D
709%D \starttyping
710%D \beginofshapebox
711%D a piece of text
712%D \endofshapebox
713%D \stoptyping
714%D
715%D When all texts is collected, we can call \type {\reshapebox} and do something
716%D with it's vertical components. We can make as much passes as needed. When we're
717%D done, the box can be unloaded with \type {\flushshapebox}. The only condition in
718%D this scheme is that \type {\reshapebox} must somehow unload the \BOX\ \type
719%D {\shapebox}.
720%D
721%D An important aspect is that the content is unrolled bottom||up. The next example
722%D illustrates this maybe unexpected characteristic.
723%D
724%D \startbuffer
725%D \beginofshapebox
726%D \em \input tufte
727%D \endofshapebox
728%D
729%D \newcounter\LineNumber
730%D
731%D \reshapebox
732%D   {\doglobal\increment\LineNumber
733%D    \hbox{\llap{\LineNumber\hskip2em}\box\shapebox}}
734%D
735%D \flushshapebox
736%D \stopbuffer
737%D
738%D \typebuffer
739%D
740%D \getbuffer
741%D
742%D As we can see, when some kind of numbering is done, we have to add a second pass.
743%D
744%D \startbuffer
745%D \newcounter\LineNumber
746%D \newcounter\NumberOfLines
747%D
748%D \reshapebox
749%D   {\doglobal\increment\NumberOfLines
750%D    \box\shapebox}
751%D
752%D \reshapebox
753%D   {\doglobal\increment\LineNumber
754%D    \hbox
755%D      {\llap{\LineNumber\ (\NumberOfLines)\hskip2em}%
756%D       \box\shapebox}%
757%D    \doglobal\decrement\NumberOfLines}
758%D
759%D \flushshapebox
760%D \stopbuffer
761%D
762%D \typebuffer
763%D
764%D \getbuffer
765%D
766%D This example shows that the content of the box is still available after flushing.
767%D Another feature is that only the last reshaping counts. Multiple reshaping can be
768%D done by:
769%D
770%D \startbuffer
771%D \beginofshapebox
772%D \flushshapebox
773%D \endofshapebox
774%D
775%D \reshapebox
776%D   {\doglobal\increment\LineNumber
777%D    \hbox{\llap{$\star$\hskip1em}\box\shapebox}%
778%D    \doglobal\decrement\NumberOfLines}
779%D
780%D \flushshapebox
781%D \stopbuffer
782%D
783%D \typebuffer
784%D
785%D \getbuffer
786%D
787%D The macros are surprisingly easy to follow and in fact introduce no new concepts.
788%D Nearly all books on \TEX\ show similar solutions for unwinding \BOXES.
789%D
790%D Some macros, like footnote ones, can be sensitive for reshaping, which can result
791%D in an endless loop. We therefore offer:
792%D
793%D \starttyping
794%D \ifreshapingbox
795%D \stoptyping
796%D
797%D Some \CONTEXT\ commands are protected this way. Anyhow, reshaping is aborted
798%D after 100 dead cycles.
799%D
800%D By the way, changing the height and depth of \BOX\ \type {\shapebox} results in
801%D bad spacing. This means that for instance linenumbers etc. should be given zero
802%D height and depth before being lapped into the margin. The previous examples
803%D ignore this side effect, but beware!
804%D
805%D This is ancient stuff and proably not used any more but we keep it around or
806%D maybe turn it into a module some day. It shows the kind of struggling that we
807%D needed before \LUATEX\ came around.
808
809\newif    \ifsomeshapeleft
810\newif    \ifreshapingbox
811\newif    \ifreshapingfailed % may save redundant runs
812
813\newbox   \shapebox
814\newcount \shapepenalty
815\newdimen \shapekern
816\newskip  \shapeskip
817
818\newbox   \newshapebox
819\newbox   \oldshapebox
820\newbox   \tmpshapebox
821
822\newcount \shapecounter
823
824\newevery \everyshapebox \relax
825
826\permanent\dimensiondef\shapesignal.12345678pt % or 12345sp
827
828\permanent\protected\def\reshapebox#1%
829  {\doreshapebox
830     {#1}%
831     {\penalty\shapepenalty}%
832     {\kern   \shapekern   }%
833     {\vskip  \shapeskip   }}
834
835\permanent\protected\def\doreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip
836  {\global\reshapingfailedfalse
837   \ifzeropt\ht\oldshapebox
838     \setbox\newshapebox\emptyvbox
839   \else
840     \setbox\newshapebox\vbox % can be \vpack
841       {\unvcopy\oldshapebox
842        \setbox\newshapebox\emptybox
843        \shapecounter\zerocount
844        \doloop{\dodoreshapebox{#1}{#2}{#3}{#4}}}%
845     \setbox\newshapebox\box\tmpshapebox
846   \fi}
847
848% We will turn this into a \MKIV\ variant (we can use \type {\vpack} too).
849
850\permanent\protected\def\insertshapesignal
851  {\hpack to \shapesignal{\strut\hss}% plus \strut
852   \prevdepth\strutdp} % never \nointerlineskip
853
854\permanent\protected\def\restoreshapebox % compensates for the signal
855  {\global\setbox\tmpshapebox\vbox{\vskip-\lineheight\unvcopy\oldshapebox}}
856
857\permanent\def\dodoreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip
858  {\ifnum\lastnodetype=\gluenodecode
859     \shapeskip\lastskip
860     \global\setbox\tmpshapebox\vbox{#4\unvbox\tmpshapebox}%
861     \unskip
862   \orelse\ifnum\lastnodetype=\kernnodecode
863     \shapekern\lastkern
864     \global\setbox\tmpshapebox\vbox{#3\unvbox\tmpshapebox}%
865     \unkern
866   \orelse\ifnum\lastnodetype=\penaltynodecode
867     \shapepenalty\lastpenalty
868     \global\setbox\tmpshapebox\vbox{#2\unvbox\tmpshapebox}%
869     \unpenalty
870   \orelse\ifnum\lastnodetype<\zeropoint
871     \exitloop
872   \else
873     \setbox\shapebox\lastbox
874     \ifvoid\shapebox
875     \orelse\ifdim\wd\shapebox=\shapesignal\relax
876       \exitloop
877     \else
878       \shapecounter\zerocount
879       \global\setbox\tmpshapebox\vbox{#1\unvbox\tmpshapebox}%
880     \fi
881   \fi
882   \ifnum\shapecounter>100 % can be less
883     \global\reshapingfailedtrue
884     \message{!!forced exit from shapebox \the\lastnodetype !!}%
885     \restoreshapebox
886     \exitloop
887   \else
888     \advance\shapecounter \plusone
889   \fi}
890
891\permanent\protected\def\beginofshapebox
892  {\setbox\oldshapebox\vbox
893     \bgroup
894     \reshapingboxtrue
895     \the\everyshapebox
896     \insertshapesignal}
897
898\permanent\protected\def\endofshapebox
899  {\endgraf
900   \egroup}
901
902\aliased\let\beginshapebox\beginofshapebox
903\aliased\let\endshapebox  \endofshapebox
904
905\permanent\protected\def\flushshapebox
906  {\bgroup
907   \ifzeropt\ht\newshapebox
908   \else
909     % make \prevdepth legal
910     % \par before the next \vskip gives far worse results
911     \ifdim\parskip>\zeropoint\vskip\parskip\else\par\fi
912     % and take a look
913     \ifdim\prevdepth=-\thousandpoint
914       \prevdepth\zeropoint
915     \fi
916     \ifdim\prevdepth<\zeropoint\relax
917       % something like a line or a signal or ...
918       \donetrue
919     \orelse\ifinner
920       % not watertight and not ok
921       \donefalse
922     \orelse\ifdim\pagegoal=\maxdimen
923       \donetrue
924     \else
925       % give the previous line a normal depth
926       \donetrue
927       {\forgeteverypar\verticalstrut}\nobreak
928       \kern-\struttotal % geen \vskip
929       \kern-\parskip
930     % \vskip-\strutdp
931     \fi
932     \scratchdimen\dp\newshapebox
933     \unvbox\newshapebox
934     % \prevdepth=0pt and \dp\newshapebox depend on last line
935     \kern-\scratchdimen % ??
936     % now \prevdepth=0pt
937     \ifdone
938       \kern\strutdp
939       \prevdepth\strutdp
940     \fi
941   \fi
942   \egroup}
943
944%D In real inner situations we can use:
945%D
946%D \starttyping
947%D \flushinnershapebox
948%D \stoptyping
949%D
950%D This one is used in \type{\framed}.
951
952% The kern fails on for instance:
953%
954% \omlijnd[offset=0pt,hoogte=8mm,uitlijnen={rechts,laho}]{\bfa test}
955
956\permanent\protected\def\innerflushshapebox
957  {\ifzeropt\ht\newshapebox \else
958     \unvcopy\newshapebox\relax % unvcopy ! else spacing problem
959   % \kern-\dp\newshapebox\relax
960   \fi}
961
962%D For absolute control, one can use \type {\doreshapebox} directly. This macro
963%D takes four arguments, that take care of:
964%D
965%D \startitemize[n,packed]
966%D \item \type{\shapebox}
967%D \item \type{\shapepenalty}
968%D \item \type{\shapekern}
969%D \item \type{\shapeskip}
970%D \stopitemize
971
972%D \macros
973%D   {shapedhbox}
974%D
975%D When constructing a new box, using the content of \type {\shapebox}, one can best
976%D use \type {\shapedhbox} instead of \type {\hbox}, since it manages the height and
977%D depth of the line.
978
979\permanent\protected\def\shapedhbox % lines with non strutted dimensions have
980  {\expanded{\dowithnextbox         % interlineskip so if we want the original
981     {\ht\nextbox\the\ht\shapebox   % spacing, we need to preserve the original
982      \dp\nextbox\the\dp\shapebox   % height and depth which is definitely
983      \box\nextbox}}                % needed if we apply struts to the 'new'
984   \hbox}                           % box or do something that changed ist size
985
986%D Till here obsolete.
987
988%D \macros
989%D   {hyphenatedword,
990%D    hyphenatedpar,
991%D    hyphenatedfile,
992%D    dohyphenateword}
993%D
994%D We no longer use the pure \TEX\ variant. In due time we will report some more
995%D advanced statistics.
996%D
997%D \starttyping
998%D \showhyphens{dohyphenatedword}
999%D \stoptyping
1000
1001\permanent\protected\def\doshowhyphenatednextbox
1002  {\clf_showhyphenatedinlist\nextbox}
1003
1004\permanent\protected\def\showhyphens % hpack: so no processing (we hyphenate in lua)
1005  {\dowithnextboxcs\doshowhyphenatednextbox\hpack}
1006
1007%D The following macros are seldom used but handy for tracing.
1008%D
1009%D \starttyping
1010%D \hyphenatedword{dohyphenatedword}
1011%D \hyphenatedpar {\dorecurse{10}{dohyphenatedword }}
1012%D \hyphenatedfile{tufte}
1013%D \stoptyping
1014
1015\def\syst_boxes_hyphenatednextbox     {\clf_hyphenatedlist\nextbox false\relax\unhbox\nextbox}
1016\def\syst_boxes_hyphenatednextboxcolor{\clf_hyphenatedlist\nextbox true \relax\unhbox\nextbox}
1017
1018\permanent\protected\def\hyphenatedword       {\dowithnextboxcs\syst_boxes_hyphenatednextbox\hbox}
1019\permanent\protected\def\hyphenatedpar        {\dowithnextboxcs\syst_boxes_hyphenatednextbox\hbox}
1020\permanent\protected\def\hyphenatedfile     #1{\dowithnextboxcs\syst_boxes_hyphenatednextbox\hbox{\readfile{#1}\donothing\donothing}}
1021\permanent\protected\def\hyphenatedcoloredword{\dowithnextboxcs\syst_boxes_hyphenatednextboxcolor\hbox}
1022
1023%D \macros
1024%D   {processtokens}
1025%D
1026%D We fully agree with (most) typographers that inter||letter spacing is only
1027%D permitted in fancy titles, we provide a macro that can be used to do so. Because
1028%D this is (definitely and fortunately) no feature of \TEX, we have to step through
1029%D the token list ourselves.
1030%D
1031%D \starttyping
1032%D \processtokens {before} {between} {after} {space} {tokens}
1033%D \stoptyping
1034%D
1035%D An example of a call is:
1036%D
1037%D \startbuffer
1038%D \processtokens {[} {+} {]} {\space} {hello world}
1039%D \stopbuffer
1040%D
1041%D \typebuffer
1042%D
1043%D This results in:
1044%D
1045%D \getbuffer
1046%D
1047%D The list of tokens may contain spaces, while \type {\\}, \type {{}} and \type {\
1048%D } are handled as space too.
1049
1050%D This can be done in a more modern way but for nostalgic reasons we keep it.
1051
1052\mutable\let\nextprocessedtoken\empty
1053
1054\mutable\let\before \relax % for now mutable
1055%mutable\let\between\relax % is a math character
1056\mutable\let\after  \relax % for now mutable
1057\mutable\let\white  \relax % for now mutable
1058
1059\permanent\protected\def\processtokens#1#2#3#4#5%
1060  {\begingroup
1061   \enforced\permanent\def\space{ }%
1062   \enforced\let\\\space
1063   \enforced\def\before {#1}%
1064   \enforced\def\between{#2}%
1065   \enforced\def\after  {#3}%
1066   \enforced\def\white  {#4}%
1067   \enforced\let\m_syst_boxes_before\before
1068   \syst_boxes_processtokens#5\s!e_o_t_token
1069   \endgroup}
1070
1071\def\syst_boxes_processtokens% the space after = is essential
1072  {\afterassignment\syst_boxes_do_processtokens\let\nextprocessedtoken= }
1073
1074\def\syst_boxes_redo_processedtoken
1075  {\dowithnextbox
1076     {\before{\copy\nextbox}% \before can use nextbox several times
1077      \enforced\let\before\between
1078      \syst_boxes_processtokens}
1079      \hbox\bgroup}
1080
1081\def\syst_boxes_do_processtokens
1082  {\ifx\nextprocessedtoken\s!e_o_t_token
1083     \after
1084   \orelse\ifx\nextprocessedtoken\bgroup
1085     \expandafter\syst_boxes_redo_processedtoken
1086   \else
1087     \expandafter\if\space\nextprocessedtoken
1088       \after\white
1089       \enforced\let\before\m_syst_boxes_before
1090     \else
1091       \before\nextprocessedtoken
1092       \enforced\let\before\between
1093     \fi
1094     \expandafter\syst_boxes_processtokens
1095   \fi}
1096
1097%D \macros
1098%D   {doboundtext}
1099%D
1100%D Sometimes there is not enough room to show the complete (line of) text. In such a
1101%D situation we can strip of some characters by using \type {\doboundtext}. When the
1102%D text is wider than the given width, it's split and the third argument is
1103%D appended. When the text to be checked is packed in a command, we'll have to use
1104%D \type {\expandafter}.
1105%D
1106%D \starttyping
1107%D \doboundtext{a very, probably to long, text}{3cm}{...}
1108%D \stoptyping
1109%D
1110%D When calculating the room needed, we take the width of the third argument into
1111%D account, which leads to a bit more complex macro than needed at first sight.
1112%D
1113%D Sort of obsolete I guess:
1114
1115\def\syst_boxes_boundtext#1%
1116  {\setbox\scratchboxone\hbox{#1}%
1117   \advance\scratchdimen -\wd\scratchboxone
1118   \ifdim\scratchdimen>\zeropoint\relax#1\fi}
1119
1120\permanent\protected\def\doboundtext#1#2#3% still used?
1121  {\hbox
1122     {\setbox\scratchbox\hbox{#1}%
1123      \scratchdimen#2\relax
1124      \ifdim\wd\scratchbox>\scratchdimen
1125        \setbox\scratchbox\hbox{#3}%
1126        \advance\scratchdimen -\wd\scratchbox
1127        \handletokens#1\with\syst_boxes_boundtext
1128      \fi
1129      \box\scratchbox}}
1130
1131%D \macros
1132%D   {limitatetext}
1133%D
1134%D A bit more beautiful alternative for the previous command is the next one. This
1135%D command is more robust because we let \TEX\ do most of the job. The previous
1136%D command works better on text that cannot be hyphenated.
1137%D
1138%D \starttyping
1139%D \limitatetext {text}  {width} {sentinel}
1140%D \limitatetext {text} {-width} {prelude}
1141%D \stoptyping
1142%D
1143%D When no width is given, the whole text comes available. The sentinel is optional.
1144%D This is about the third version.
1145
1146\ifdefined\fakecompoundhyphen\else \let\fakecompoundhyphen\relax      \fi
1147\ifdefined\veryraggedright   \else \def\veryraggedright{\raggedright} \fi
1148
1149%D See \MKIV\ file for the older implementation.
1150
1151\let\m_syst_boxes_left \empty
1152\let\m_syst_boxes_right\empty
1153
1154\permanent\protected\def\limitatetext#1#2#3%
1155  {% we could also split in \LUA
1156   \splitatcomma{#2}\m_syst_boxes_left\m_syst_boxes_right
1157   \limitated
1158  \ifempty\m_syst_boxes_left\else
1159      left     \m_syst_boxes_left
1160  \fi
1161  \ifempty\m_syst_boxes_right\else
1162      right    \m_syst_boxes_right
1163  \fi
1164      strip    true
1165      sentinel {#3}
1166      text     {#1}
1167   \relax}
1168
1169%D Undocumented bonus (see wiki):
1170%D
1171%D \starttyping
1172%D \limitatefirstline{\input tufte\relax}{10cm}{\unknown}
1173%D \stoptyping
1174
1175\permanent\protected\def\limitatefirstline#1#2#3%
1176  {\hbox\bgroup\strut % \hpack
1177   \setbox\scratchbox\hbox{\begstrut#1\endstrut}%
1178   \ifdim\wd\scratchbox>#2\relax
1179     \setbox\scratchbox\hbox{#3}%
1180     \hsize#2\relax
1181     \advance\hsize-\wd\scratchbox
1182     \setbox\scratchbox\vbox{\forgetall\veryraggedright#1}%
1183     \setbox\scratchbox\vsplit\scratchbox to \lineheight
1184     \vbox
1185       {\unvbox\scratchbox
1186        \global\setbox\plusone\lastbox
1187        \global\setbox\plusone\hbox{\strut\unhbox\plusone}%
1188        \hbox % to #2 % \hpack
1189          {\unless\ifdefined\clip
1190             \box\plusone
1191           \orelse\ifdim\wd\plusone>\hsize
1192             \lower\strutdepth\hpack{\clip[\c!width=\hsize,\c!height=\lineheight]{\hpack{\raise\strutdepth\box\plusone}}}%
1193           \else
1194             \box\plusone
1195           \fi
1196           \removeunwantedspaces#3}}% \removeunwantedspaces\hss#3}}%
1197   \else
1198     #1%
1199   \fi
1200   \egroup}
1201
1202%D \macros
1203%D   {processisolatedwords,processisolatedchars}
1204%D
1205%D \startbuffer
1206%D \processisolatedchars{some more words}           \ruledhbox \par
1207%D \processisolatedchars{and some $x + y = z$ math} \ruledhbox \par
1208%D \processisolatedchars{and a \hbox{$x + y = z$}}  \ruledhbox \par
1209%D \processisolatedwords{some more words}           \ruledhbox \par
1210%D \processisolatedwords{and some $x + y = z$ math} \ruledhbox \par
1211%D \processisolatedwords{and a \hbox{$x + y = z$}}  \ruledhbox \par
1212%D \stopbuffer
1213%D
1214%D \typebuffer \blank \getbuffer \blank
1215
1216% todo: provide variant with #1 picked up as box
1217
1218\permanent\protected\def\processisolatedchars#1#2%
1219  {\dontleavehmode
1220   \begingroup
1221   \setbox\scratchbox\hbox{\settrialtypesetting#2{\savecurrentattributes{pic}}}%
1222   \setbox\scratchbox\hbox{\restorecurrentattributes{pic}#1}%
1223   \clf_applytobox
1224     method  {char}%
1225     box     \scratchbox
1226     command {\csstring#2}%
1227     nested  true%
1228   \relax
1229   \endgroup}
1230
1231\permanent\protected\def\processisolatedwords#1#2%
1232  {\dontleavehmode
1233   \begingroup
1234   \setbox\scratchbox\hbox{\settrialtypesetting#2{\savecurrentattributes{pic}}}%
1235   \setbox\scratchbox\hbox{\restorecurrentattributes{pic}#1}%
1236   \clf_applytobox
1237     method  {word}%
1238     box     \scratchbox
1239     command {\csstring#2}%
1240     nested  true%
1241   \relax
1242   \endgroup}
1243
1244%D A variant:
1245
1246\permanent\protected\def\applytocharacters#1%
1247  {\dontleavehmode
1248   \dowithnextbox{\clf_applytobox
1249     method  {char}%
1250     box     \nextbox
1251     command {\csstring#1}%
1252     nested  true%
1253   \relax}%
1254   \hbox}
1255
1256\permanent\protected\def\applytowords#1%
1257  {\dontleavehmode
1258   \dowithnextbox{\clf_applytobox
1259     method  {word}%
1260     box     \nextbox
1261     command {\csstring#1}%
1262     nested  true%
1263   \relax}%
1264   \hbox}
1265
1266%D The old call:
1267
1268\permanent\protected\def\processwords#1%
1269  {\processisolatedwords{#1}\processword}
1270
1271\mutable\let\processword\relax
1272
1273\permanent\protected\def\applytosplitstringchar#1#2%
1274  {\dontleavehmode\clf_processsplit
1275     data    {#2}%
1276     command {\csstring#1}%
1277     method  {char}%
1278   \relax}
1279
1280\permanent\protected\def\applytosplitstringword#1#2%
1281  {\dontleavehmode\clf_processsplit
1282     data    {#2}%
1283     command {\csstring#1}%
1284     method  {word}%
1285   \relax}
1286
1287\permanent\protected\def\applytosplitstringline#1#2%
1288  {\dontleavehmode\clf_processsplit
1289     data    {#2}%
1290     command {\csstring#1}%
1291     method  {line}%
1292   \relax}
1293
1294\permanent\protected\def\applytosplitstringcharspaced#1#2%
1295  {\dontleavehmode\clf_processsplit
1296     data    {#2}%
1297     command {\csstring#1}%
1298     method  {char}%
1299     spaced  true%
1300   \relax}
1301
1302\permanent\protected\def\applytosplitstringwordspaced#1#2%
1303  {\dontleavehmode\clf_processsplit
1304     data    {#2}%
1305     command {\csstring#1}%
1306     method  {word}%
1307     spaced  true%
1308   \relax}
1309
1310\permanent\protected\def\applytosplitstringlinespaced#1#2%
1311  {\dontleavehmode\clf_processsplit
1312     data    {#2}%
1313     command {\csstring#1}%
1314     method  {line}%
1315     spaced  true%
1316   \relax}
1317
1318%D \macros
1319%D   {sbox}
1320%D
1321%D This is a rather strange command. It grabs some box content and and limits the
1322%D size to the height and depth of a \type {\strut}. The resulting bottom||alligned
1323%D box can be used aside other ones, without disturbing the normal baseline
1324%D distance.
1325%D
1326%D \startbuffer
1327%D \ruledhbox to .5\hsize{\sbox{eerste\par tweede \par derde}}
1328%D \stopbuffer
1329%D
1330%D \typebuffer
1331%D
1332%D Shows up as:
1333%D
1334%D \startexample
1335%D \vskip3\baselineskip
1336%D \getbuffer
1337%D \stopexample
1338%D
1339%D Before displaying the result we added some skip, otherwise the first two lines
1340%D would have ended up in the text. This macro can be useful when building
1341%D complicated menus, headers and footers and|/|or margin material.
1342
1343\permanent\protected\def\sbox
1344  {\vpack\bgroup
1345   \dowithnextboxcs\syst_boxes_sbox_finish\vbox}
1346
1347\def\syst_boxes_sbox_finish
1348  {\boxyoffset\nextbox-\strutdp
1349   \dp\nextbox\strutdp
1350   \ht\nextbox\strutht
1351   \box\nextbox
1352   \egroup}
1353
1354%D A variant on this:
1355%D
1356%D \starttyping
1357%D xx \ruledhbox{\inlinedbox{\tfd test}} xx
1358%D \stoptyping
1359
1360\permanent\protected\def\inlinedbox
1361  {\bgroup
1362   \dowithnextboxcs\syst_boxes_inlined_finish\hbox}
1363
1364\def\syst_boxes_inlined_finish
1365  {\boxyoffset\nextbox-\dimexpr(\htdp\nextbox-\lineheight)/\plustwo+\strutdp\relax
1366   \ht\nextbox\strutht
1367   \dp\nextbox\strutdp
1368   \box\nextbox
1369   \egroup}
1370
1371%D \macros
1372%D   {struttedbox}
1373%D
1374%D This boxing macro limits the height and depth to those of a strut.
1375
1376\permanent\protected\def\struttedbox
1377  {\hpack\bgroup
1378   \dowithnextboxcs\syst_boxes_struttedbox_finish\hbox}
1379
1380\def\syst_boxes_struttedbox_finish
1381  {\dp\nextbox\strutdepth
1382   \ht\nextbox\strutheight
1383   \box\nextbox
1384   \egroup}
1385
1386%D \macros
1387%D   {topskippedbox}
1388%D
1389%D This macro compensates the difference between the topskip and strutheight. Watch
1390%D how we preserve the depth when it equals strutdepth.
1391
1392\permanent\protected\def\topskippedbox
1393  {\hpack\bgroup\dowithnextboxcs\syst_boxes_topskippedbox_finish\hbox}
1394
1395\def\syst_boxes_topskippedbox_finish
1396  {\edef\m_boxes_tmp{\ifdim\strutdepth=\dp\nextbox\dp\nextbox\the\dp\nextbox\fi}%
1397   \lower\topskip\hpack{\raise\strutheight\box\nextbox}%
1398   \m_boxes_tmp
1399   \egroup}
1400
1401%D \macros
1402%D   {centeredbox, centerednextbox}
1403%D
1404%D Here is another strange one. This one offers a sort of overlay with positive or
1405%D negative offsets. This command can be used in well defined areas where no offset
1406%D options are available. We first used it when building a button inside the margin
1407%D footer, where the button should have a horizontal offset and should be centered
1408%D with respect to the surrounding box. The last of the three examples we show below
1409%D says:
1410%D
1411%D \starttyping
1412%D \vsize=3cm
1413%D \hsize=3cm
1414%D \ruledvbox to \vsize
1415%D   {\centeredbox height .5cm width -1cm
1416%D      {\vrule width \hsize height \vsize}}}
1417%D \stoptyping
1418%D
1419%D Here the \type {\ruledvbox} just shows the surrounding box and \type {\vrule} is
1420%D used to show the centered box.
1421%D
1422%D \def\AnExample#1#2%
1423%D   {\vsize=3cm
1424%D    \hsize=3cm
1425%D    \ruledvbox to \vsize
1426%D      {\centeredbox height #1 width #2
1427%D         {\color[green]{\vrule width \hsize height \vsize}}}}
1428%D
1429%D \startlinecorrection
1430%D \startcombination[3*1]
1431%D   {\AnExample {-1cm}  {.5cm}} {}
1432%D   {\AnExample {.5cm}  {-1cm}} {}
1433%D   {\AnExample {-1cm} {-.5cm}} {}
1434%D \stopcombination
1435%D \stoplinecorrection
1436%D
1437%D This command takes two optional arguments: \type {width} and \type {height}.
1438%D Observing readers can see that we use \TEX's own scanner for grabbing these
1439%D arguments: \type {#1#} reads everyting till the next brace and passes it to both
1440%D rules. The setting of the box dimensions at the end is needed for special cases.
1441%D The dimensions of the surrounding box are kept intact. This commands handles
1442%D positive and negative dimensions (which is why we need two boxes with rules).
1443
1444\permanent\protected\def\centeredbox#1#%   height +/-dimen width +/-dimen
1445  {\bgroup
1446   \dontcomplain
1447   \forgetall
1448   \scangivendimensions#1\relax
1449   \advance\vsize\givenheight
1450   \advance\hsize\givenwidth
1451   \dowithnextboxcs\syst_boxes_centered_finish
1452   \hbox}
1453
1454\def\syst_boxes_centered_finish
1455  {\boxxoffset\nextbox.5\dimexpr
1456      \hsize
1457     -\wd\nextbox
1458     -\givenwidth
1459   \relax
1460   \boxyoffset\nextbox.5\dimexpr
1461      \vsize
1462     -\ht\nextbox
1463     +\dp\nextbox
1464     -\givenheight
1465   \relax
1466   \wd\nextbox\dimexpr\hsize-\givenwidth \relax
1467   \ht\nextbox\dimexpr\vsize-\givenheight\relax
1468   \dp\nextbox\zeropoint
1469   \box\nextbox
1470   \egroup}
1471
1472%D For those who don't want to deal with \type {\hsize} and \type {\vsize}, we have:
1473%D
1474%D \starttyping
1475%D \centerednextbox width 2bp height 2bp
1476%D   {\framed[width=100bp,height=100bp]{}}
1477%D \stoptyping
1478%D
1479%D Do you see why we call this one \type {next}?
1480
1481\permanent\protected\def\centerednextbox#1#%
1482  {\bgroup
1483   \dowithnextbox
1484     {\hsize\wd\nextbox
1485      \vsize\ht\nextbox
1486      \centeredbox#1{\box\nextbox}%
1487      \egroup}
1488   \hbox}
1489
1490%D \macros
1491%D   {centerbox}
1492%D
1493%D Centering on the available space is done by:
1494%D
1495%D \starttyping
1496%D \centerbox <optional specs> {content}
1497%D \stoptyping
1498%D
1499%D When omitted, the current \type {\hsize} and \type {\vsize} are used. Local
1500%D dimensions are supported.
1501
1502\permanent\protected\def\centerbox#1#%   optional height +/-dimen width +/-dimen
1503  {\bgroup
1504   \dowithnextbox
1505     {\setlocalhsize
1506      \setbox\scratchbox\hpack{\vrule\s!width \zeropoint#1}%
1507      \ifzeropt\wd\scratchbox\else\hsize\wd\scratchbox\fi
1508      \setbox\scratchbox\vpack{\hrule\s!height\zeropoint#1}%
1509      \ifzeropt\ht\scratchbox\else\vsize\ht\scratchbox\fi
1510      \vpack to \vsize{\vss\hpack to \hsize{\hss\box\nextbox\hss}\vss}%
1511      \egroup}%
1512     \hbox}
1513
1514%D \macros
1515%D   {setrigidcolumnhsize,rigidcolumnbalance,rigidcolumnlines}
1516%D
1517%D These macros are copied from the \TEX book, page~397, and extended by a macro
1518%D that sets the \type {\hsize}.
1519%D
1520%D \starttyping
1521%D \setrigidcolumnhsize {total width} {distance} {n}
1522%D \rigidcolumnbalance  {box}
1523%D \stoptyping
1524%D
1525%D Both these macros are for instance used in typesetting footnotes. The following
1526%D flags influence the process.
1527
1528\newif\ifalignrigidcolumns
1529\newif\ifstretchrigidcolumns
1530\newif\iftightrigidcolumns    % if true: just a vbox, no depth/noflines/gridsnap corrrections
1531
1532\mutable\let\rigidcolumnlines\!!zerocount
1533
1534\newbox  \rigidcolumnbox
1535\newdimen\rigidhsize
1536\newcount\rigidcolumns
1537
1538\permanent\protected\def\setrigidcolumnhsize#1#2#3% todo: \dimexpr
1539  {\global\rigidhsize\hsize
1540   \global\rigidcolumns#3\relax
1541   \hsize#1\relax
1542   \scratchdimen -#2\relax
1543   \multiply\scratchdimen #3\relax
1544   \advance\scratchdimen  #2\relax
1545   \advance\hsize \scratchdimen
1546   \divide\hsize #3\relax}
1547
1548% ==
1549%
1550% \def\setrigidcolumnhsize#1#2#3%
1551%   {\global\rigidhsize\hsize
1552%    \rigidcolumns#3\relax
1553%    \hsize\dimexpr(#1-\numexpr#3-1\relax\dimexpr#2\relax)/#3\relax}
1554
1555\permanent\protected\def\rigidcolumnbalance#1%
1556  {\ifnum\rigidcolumns=1 % tzt ook h/d correctie
1557     \ifinner\ifhmode\box\else\unvbox\fi\else\unvbox\fi#1\relax
1558   \else
1559     \vbox % \vpack
1560       {\forgetall
1561        \nopenalties
1562        \dontcomplain
1563        \setbox\rigidcolumnbox\vbox
1564          {\line{}\goodbreak\unvbox#1\removebottomthings}%
1565        \splittopskip\openstrutheight
1566        \setbox\scratchbox\vsplit\rigidcolumnbox to \zeropoint
1567        \ifcase\rigidcolumnlines\relax
1568          % \iffalse
1569          %  % maybe some day an option
1570          %  \scratchskip\ht\rigidcolumnbox
1571          %  \advance\scratchskip\dp\rigidcolumnbox
1572          %  \getnoflines\scratchskip
1573          %  \ifodd\noflines
1574          %    \advance\noflines\plusone
1575          %  \fi
1576          %  \divide\noflines\rigidcolumns
1577          %\else
1578            \scratchdimen\ht\rigidcolumnbox
1579            \divide\scratchdimen \rigidcolumns
1580            \getnoflines\scratchdimen
1581          %\fi
1582        \else
1583          \noflines\rigidcolumnlines % to be sure
1584        \fi
1585        \scratchdimen\noflines\lineheight
1586        % new: we now loop so that we don't loose content
1587        % since in practice we also use this macro for
1588        % funny lineheights and border cases
1589        \setbox0=\box\rigidcolumnbox
1590        \doloop
1591          {\setbox\rigidcolumnbox=\copy0
1592           \setbox\scratchbox\hpack to \rigidhsize
1593             {\dorecurse\rigidcolumns
1594                {\setbox\scratchbox\vsplit\rigidcolumnbox to \scratchdimen
1595                   \dp\scratchbox\openstrutdepth
1596                   \setbox\scratchbox\vtop
1597                     \ifalignrigidcolumns to
1598                       \ifstretchrigidcolumns\vsize\else\scratchdimen\fi
1599                     \fi
1600                     {\unvbox\scratchbox}%
1601                 \wd\scratchbox\hsize
1602                 \box\scratchbox
1603                 \hfill}%
1604              \hfillneg}%
1605          \ifvoid\rigidcolumnbox\exitloop\else\advance\scratchdimen\lineheight\fi}%
1606       \iftightrigidcolumns
1607         \setbox\scratchbox\hpack{\raise\dp\scratchbox\box\scratchbox}%
1608       \else
1609         \advance\scratchdimen -\openstrutdepth
1610         \setbox\scratchbox\hpack{\raise\scratchdimen\box\scratchbox}%
1611         \dp\scratchbox\openstrutdepth
1612         \ht\scratchbox\scratchdimen
1613       \fi
1614       \box\scratchbox}%
1615   \fi}
1616
1617%D \macros
1618%D   {startvboxtohbox,stopvboxtohbox,convertvboxtohbox}
1619%D
1620%D Here is another of Knuth's dirty tricks, as presented on pages 398 and 399 of the
1621%D \TEX book. These macros can be used like:
1622%D
1623%D \starttyping
1624%D \vbox
1625%D   \bgroup
1626%D     \startvboxtohbox ... \stopvboxtohbox
1627%D     \startvboxtohbox ... \stopvboxtohbox
1628%D     \startvboxtohbox ... \stopvboxtohbox
1629%D   \egroup
1630%D
1631%D \vbox
1632%D   \bgroup
1633%D     \convertvboxtohbox
1634%D   \egroup
1635%D \stoptyping
1636%D
1637%D These macros are used in reformatting footnotes, so they do what they're meant
1638%D for.
1639
1640\newdimen\vboxtohboxslack
1641\newdimen\hboxestohboxslack
1642
1643%D Create line and fake height of paragraph by messign with heights: a nice hack by
1644%D DEK himself.
1645
1646%\protected\def\setvboxtohbox
1647%  {\bgroup
1648%   \ifdim\baselineskip<16pt \relax
1649%     \scratchdimen\baselineskip
1650%     \multiply\scratchdimen 1024
1651%   \else
1652%     \message{cropping \baselineskip to 16pt}%
1653%     \scratchdimen\maxdimen
1654%   \fi
1655%   \divide\scratchdimen \hsize
1656%   \multiply\scratchdimen 64
1657%   \xdef\vboxtohboxfactor{\withoutpt\the\scratchdimen}%
1658%   \egroup}
1659%
1660% \protected\def\startvboxtohbox
1661%  {\bgroup
1662%   \setvboxtohbox
1663%   \setbox\scratchbox\hbox\bgroup}
1664%
1665% \protected\def\stopvboxtohbox
1666%   {\ifcase\vboxtohboxslack\else\hskip\zeropoint\s!minus\vboxtohboxslack\fi
1667%    \egroup
1668%    \dp\scratchbox\zeropoint
1669%    \ht\scratchbox\vboxtohboxfactor\wd\scratchbox
1670%    \box\scratchbox
1671%    \egroup}
1672
1673% More modern:
1674
1675% \definesystemattribute[vboxtohboxseparator][public]
1676
1677%newbox\d_syst_boxes_vboxtohbox
1678\newbox\d_syst_boxes_separator
1679
1680\permanent\protected\def\startvboxtohboxseparator
1681  {\setbox\d_syst_boxes_separator\hbox attr \vboxtohboxseparatorattribute\plusone\bgroup}
1682
1683\permanent\protected\def\stopvboxtohboxseparator
1684  {\egroup}
1685
1686\permanent\protected\def\startvboxtohbox
1687  {\begingroup
1688   \setbox\scratchbox\hbox\bgroup}
1689
1690\permanent\protected\def\stopvboxtohbox
1691  {\ifvoid\d_syst_boxes_separator
1692     \hskip\zeropoint\ifcase\vboxtohboxslack\else\s!minus\vboxtohboxslack\fi % we really need a skip
1693   \else
1694     \box\d_syst_boxes_separator
1695   \fi
1696   \egroup
1697   \clf_hboxtovbox\scratchbox
1698   \box\scratchbox
1699   \endgroup}
1700
1701% A possible reconstruction:
1702
1703\permanent\protected\def\convertvboxtohbox
1704  {\makehboxofhboxes
1705   \setbox\scratchboxone\hpack{\unhbox\scratchboxone\removehboxes}% \hpack
1706   \noindent\unhbox\scratchboxone\par}
1707
1708\permanent\protected\def\makehboxofhboxes
1709  {\setbox\scratchboxone\emptyhbox
1710   \loop % \doloop { .. \exitloop .. }
1711     \setbox\scratchboxtwo\lastbox
1712     \ifhbox\scratchboxtwo
1713       \setbox\scratchboxone\hpack{\box\scratchboxtwo\unhbox\scratchboxone}%
1714   \repeat}
1715
1716\permanent\protected\def\removehboxes
1717  {\setbox\scratchboxone\lastbox
1718   \ifhbox\scratchboxone
1719     {\removehboxes}\unhbox\scratchboxone
1720   \fi}
1721
1722% And one special for notes:
1723
1724\permanent\protected\def\starthboxestohbox
1725  {\bgroup
1726   \setbox\scratchbox\vbox\bgroup}
1727
1728\permanent\protected\def\stophboxestohbox
1729  {\egroup
1730   \clf_vboxlisttohbox\scratchbox\nextbox\dimexpr\hboxestohboxslack\relax
1731   \dontleavehmode
1732   \unhbox\nextbox
1733   \removeunwantedspaces
1734   \par
1735   \egroup}
1736
1737%D \macros
1738%D   {unhhbox}
1739%D
1740%D The next macro is used in typesetting inline headings. Let's first look at the
1741%D macro and then show an example.
1742
1743\newbox   \unhhedbox
1744\newbox   \hhbox
1745\newdimen \lasthhboxwidth
1746\newskip  \hhboxindent
1747
1748\permanent\protected\def\unhhbox#1\with#2%
1749  {\bgroup
1750   \nopenalties
1751   \dontcomplain
1752   \forgetall
1753   \setbox\unhhedbox\vbox{\hskip\hhboxindent\strut\unhbox#1}% => \hsize
1754   \doloop
1755     {\setbox\hhbox\vsplit\unhhedbox to \lineheight
1756      \ifvoid\unhhedbox
1757        \setbox\hhbox\hbox{\strut\hboxofvbox\hhbox}% \hpack
1758      \fi
1759      \ht\hhbox\strutht
1760      \dp\hhbox\strutdp
1761      \ifzeropt\hhboxindent\else
1762        \setbox\hhbox\hpack{\kern-\hhboxindent\box\hhbox}%
1763        \hhboxindent\zeropoint
1764      \fi
1765      \global\lasthhboxwidth\wd\hhbox
1766      #2\relax
1767      \ifvoid\unhhedbox
1768        \exitloop
1769      \else
1770        \hskip\zeropoint \s!plus \zeropoint
1771      \fi}%
1772   \egroup}
1773
1774\def\syst_boxes_hboxofvbox
1775  {\setbox0\vpack{\unvbox\scratchcounter\global\setbox1\lastbox}%
1776   \unhbox1
1777   \egroup}
1778
1779\permanent\protected\def\hboxofvbox
1780  {\bgroup
1781   \afterassignment\syst_boxes_hboxofvbox
1782   \scratchcounter=}
1783
1784%D This macro can be used to break a paragraph apart and treat each line seperately,
1785%D for instance, making it clickable. The main complication is that we want to be
1786%D able to continue the paragraph, something that's needed in the in line section
1787%D headers.
1788%D
1789%D \startbuffer
1790%D \setbox0=\hbox{\input tufte \relax}
1791%D \setbox2=\hbox{\input knuth \relax}
1792%D \unhhbox0\with{\ruledhbox{\box\hhbox}}
1793%D \hskip1em plus 1em minus 1em
1794%D \hhboxindent=\lasthhboxwidth
1795%D \advance\hhboxindent by \lastskip
1796%D \unhhbox2\with{\ruledhbox{\box\hhbox}}
1797%D \stopbuffer
1798%D
1799%D \getbuffer
1800%D
1801%D This piece of text was typeset by saying:
1802%D
1803%D \typebuffer
1804%D
1805%D Not that nice a definition, but effective. Note the stretch we've build in the
1806%D line that connects the two paragraphs.
1807
1808%D \macros
1809%D   {doifcontent}
1810%D
1811%D When processing depends on the availability of content, one can give the next
1812%D macro a try.
1813%D
1814%D \starttyping
1815%D \doifcontent{pre content}{post content}{no content}\somebox
1816%D \stoptyping
1817%D
1818%D Where \type {\somebox} is either a \type {\hbox} or \type {\vbox}. If the
1819%D dimension of this box suggest some content, the resulting box is unboxed and
1820%D surrounded by the first two arguments, else the third arguments is executed.
1821
1822\permanent\protected\def\doifcontent#1#2#3%
1823  {\dowithnextbox
1824     {\ifhbox\nextbox
1825        \ifdim\wd\nextbox>\zeropoint
1826          #1\unhbox\nextbox#2\relax
1827        \else
1828          #3\relax
1829        \fi
1830      \else
1831        \ifdim\ht\nextbox>\zeropoint
1832          #1\unvbox\nextbox#2\relax
1833        \else
1834          #3\relax
1835        \fi
1836      \fi}}
1837
1838%D So when we say:
1839%D
1840%D \startbuffer
1841%D \doifcontent{[}{]}{}\hbox{content sensitive typesetting}
1842%D
1843%D \doifcontent{}{\page}{}\vbox{content sensitive typesetting}
1844%D
1845%D \doifcontent{}{}{\message{Didn't you forget something?}}\hbox{}
1846%D \stopbuffer
1847%D
1848%D \typebuffer
1849%D
1850%D We get:
1851%D
1852%D \getbuffer
1853%D
1854%D Where the last call of course does not show up in this document, but definitely
1855%D generates a confusing message.
1856
1857%D \macros
1858%D   {processboxes}
1859%D
1860%D The next macro gobble boxes and is for instance used for overlays. First we show
1861%D the general handler.
1862
1863\newbox\processbox % public : this is the one where \nextbox's end up in
1864
1865\let\syst_boxes_process_indeed\relax
1866
1867\permanent\protected\def\processboxes#1%
1868  {\bgroup
1869   \def\syst_boxes_process_indeed{#1}% #1 can be redefined halfway
1870   \setbox\processbox\emptybox
1871   \doifelsenextbgroup\syst_boxes_process_yes\syst_boxes_process_nop}
1872
1873\def\syst_boxes_process_yes
1874  {\dowithnextboxcs\syst_boxes_process_content\hbox}
1875
1876\def\syst_boxes_process_content
1877  {\removeunwantedspaces
1878   \syst_boxes_process_indeed % takes \nextbox makes \processbox
1879   \doifelsenextbgroup\syst_boxes_process_yes\syst_boxes_process_nop}
1880
1881\protected\def\syst_boxes_process_nop
1882  {\removeunwantedspaces
1883   \box\processbox
1884   \egroup}
1885
1886%D \macros
1887%D   {startoverlay}
1888%D
1889%D We can overlay boxes by saying:
1890%D
1891%D \startbuffer
1892%D \startoverlay
1893%D   {\framed{hans}}
1894%D   {\framed[width=3cm]{ton}}
1895%D   {\framed[height=2cm]{oeps}}
1896%D \stopoverlay
1897%D \stopbuffer
1898%D
1899%D \typebuffer
1900%D
1901%D shows up as:
1902%D
1903%D \leavevmode\getbuffer
1904
1905\permanent\def\boxisempty#1%
1906  {\ifdim\wd#1=\zeropoint
1907     \ifdim\ht#1=\zeropoint
1908       \ifdim\dp#1=\zeropoint
1909         \zerocount
1910       \else
1911         \plusone
1912       \fi
1913     \else
1914       \plusone
1915     \fi
1916   \else
1917     \plusone
1918   \fi}
1919
1920\def\syst_boxes_overlay_process
1921  {\ifcase\boxisempty\nextbox\else
1922     \syst_boxes_overlay_process_indeed
1923   \fi}
1924
1925\def\syst_boxes_overlay_process_indeed
1926  {%\removeunwantedspaces % already done
1927   \scratchdepth\dp\ifdim\dp\nextbox>\dp\processbox\nextbox\else\processbox\fi
1928   \ifdim\ht\nextbox>\ht\processbox
1929     \setbox\processbox\vpack to \ht\nextbox   {\dp\processbox\zeropoint\vss\box\processbox\vss}%
1930   \else
1931     \setbox\nextbox   \vpack to \ht\processbox{\dp\nextbox   \zeropoint\vss\box\nextbox   \vss}%
1932   \fi
1933   \dp\nextbox   \scratchdepth
1934   \dp\processbox\scratchdepth
1935   \scratchwidth\wd\ifdim\wd\nextbox>\wd\processbox\nextbox\else\processbox\fi
1936   \setbox\processbox\hpack to \scratchwidth
1937     {\hpack to \scratchwidth{\hss\box\processbox\hss}%
1938      \kern-\scratchwidth
1939      \hpack to \scratchwidth{\hss\box\nextbox   \hss}}}
1940
1941\permanent\protected\def\startoverlay
1942  {\bgroup
1943   \enforced\aliased\let\stopoverlay\egroup
1944   \processboxes\syst_boxes_overlay_process}
1945
1946\permanent\protected\lettonothing\stopoverlay
1947
1948%D \macros
1949%D   {fakebox}
1950%D
1951%D The next macro is a rather silly one, but saves space.
1952%D
1953%D \starttyping
1954%D \hbox{\fakebox0}
1955%D \stoptyping
1956%D
1957%D returns an empty box with the dimensions of the box specified, here being zero.
1958
1959\permanent\protected\def\fakebox
1960  {\bgroup
1961   \afterassignment\syst_boxes_fakebox_finish\scratchcounter}
1962
1963\def\syst_boxes_fakebox_finish
1964  {\setbox\scratchbox\ifhbox\scratchcounter\emptyhbox\else\emptyvbox\fi
1965   \wd\scratchbox\wd\scratchcounter
1966   \ht\scratchbox\ht\scratchcounter
1967   \dp\scratchbox\dp\scratchcounter
1968   \box\scratchbox
1969   \egroup}
1970
1971%D \macros
1972%D   {lbox,rbox,cbox,tbox,bbox}
1973%D
1974%D Here are some convenient alternative box types:
1975%D
1976%D \starttyping
1977%D \lbox{text ...}
1978%D \cbox{text ...}
1979%D \rbox{text ...}
1980%D \stoptyping
1981%D
1982%D Are similar to \type {\vbox}, which means that they also accept something like
1983%D \type {to 3cm}, but align to the left, middle and right. These box types can be
1984%D used to typeset paragraphs.
1985
1986\def\syst_boxes_lrc_process#1%
1987  {\bgroup
1988   \forgetall
1989   \enforced\let\\\endgraf
1990   #1%
1991   \let\nexttoken}
1992
1993\permanent\protected\def\lbox#1#{\vbox#1\syst_boxes_lrc_process\raggedleft  }
1994\permanent\protected\def\cbox#1#{\vbox#1\syst_boxes_lrc_process\raggedcenter}
1995\permanent\protected\def\rbox#1#{\vbox#1\syst_boxes_lrc_process\raggedright }
1996
1997\permanent\protected\def\ltop#1#{\vtop#1\syst_boxes_lrc_process\raggedleft  }
1998\permanent\protected\def\ctop#1#{\vtop#1\syst_boxes_lrc_process\raggedcenter}
1999\permanent\protected\def\rtop#1#{\vtop#1\syst_boxes_lrc_process\raggedright }
2000
2001%D The alternatives \type {\tbox} and \type {\bbox} can be used to properly align
2002%D boxes, like in:
2003%D
2004%D \setupexternalfigures[directory={../sample}]
2005%D \startbuffer
2006%D \starttable[|||]
2007%D \HL
2008%D \VL \tbox{\externalfigure[cow][height=3cm,frame=on]} \VL top aligned    \VL\SR
2009%D \HL
2010%D \VL \bbox{\externalfigure[cow][height=3cm,frame=on]} \VL bottom aligned \VL\SR
2011%D \HL
2012%D \stoptable
2013%D \stopbuffer
2014%D
2015%D \typebuffer
2016%D
2017%D The positioning depends on the strut settings:
2018%D
2019%D \getbuffer
2020
2021\permanent\protected\def\tbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_tbox_finish\hbox}
2022\permanent\protected\def\bbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_bbox_finish\hbox}
2023
2024\def\syst_boxes_tbox_finish
2025  {\scratchheight\ht\strutbox
2026   \scratchdepth\dimexpr\htdp\nextbox-\scratchheight\relax
2027   \ht\nextbox\scratchheight
2028   \dp\nextbox\scratchdepth
2029   \boxyoffset\nextbox-\scratchdepth
2030   \box\nextbox
2031   \egroup}
2032
2033\def\syst_boxes_bbox_finish
2034  {\scratchdepth\dp\strutbox
2035   \scratchheight\dimexpr\htdp\nextbox-\scratchdepth\relax
2036   \dp\nextbox\scratchdepth
2037   \ht\nextbox\scratchheight
2038   \boxyoffset\nextbox-\scratchdepth
2039   \box\nextbox
2040   \egroup}
2041
2042%D \macros
2043%D   {lhbox,mhbox,rhbox}
2044%D
2045%D A few more boxes.
2046
2047\def\syst_boxes_lhbox{\hpack to \hsize{\box\nextbox\hss    }}
2048\def\syst_boxes_mhbox{\hpack to \hsize{\hss\box\nextbox\hss}}
2049\def\syst_boxes_rhbox{\hpack to \hsize{\hss\box\nextbox    }}
2050
2051\permanent\protected\def\lhbox{\dowithnextboxcs\syst_boxes_lhbox\hbox}
2052\permanent\protected\def\mhbox{\dowithnextboxcs\syst_boxes_mhbox\hbox}
2053\permanent\protected\def\rhbox{\dowithnextboxcs\syst_boxes_rhbox\hbox}
2054
2055\aliased\let\lefthbox \lhbox
2056\aliased\let\midhbox  \mhbox
2057\aliased\let\righthbox\rhbox
2058
2059%D \macros
2060%D   {boxofsize}
2061%D
2062%D Sometimes we need to construct a box with a height or width made up of several
2063%D dimensions. Instead of cumbersome additions, we can use:
2064%D
2065%D \starttyping
2066%D \boxofsize \vbox 10cm 3cm -5cm {the text to be typeset}
2067%D \stoptyping
2068%D
2069%D This example demonstrates that one can use positive and negative values.
2070%D Dimension registers are also accepted.
2071
2072\newdimen\sizeofbox
2073
2074\permanent\protected\def\boxofsize#1%
2075  {\bgroup
2076   \sizeofbox\zeropoint
2077   \scratchdimen\zeropoint
2078   \def\docommand
2079     {\advance\sizeofbox\scratchdimen
2080      \futurelet\nexttoken\dodocommand}%
2081   \def\dodocommand
2082     {\ifx\nexttoken\bgroup
2083        \expanded{\egroup#1 to \the\sizeofbox}%
2084      \else
2085        \expandafter\afterassignment\expandafter\docommand\expandafter\scratchdimen
2086      \fi}%
2087   \docommand}
2088
2089%D Some new, still undocumented features:
2090
2091% limitatetext -> beter {text} als laatste !!
2092%
2093% \limitvbox
2094% \limithbox
2095
2096\permanent\protected\def\limitatelines#1#2% size sentinel
2097  {\dowithnextbox
2098     {\scratchdimen#1\hsize
2099      \ifdim\wd\nextbox>\scratchdimen
2100        \setbox\nextbox\hbox
2101          {\advance\scratchdimen -.1\hsize
2102           \limitatetext{\unhbox\nextbox}{\scratchdimen}{\nobreak#2}}%
2103      \fi
2104      \unhbox\nextbox}
2105     \hbox}
2106
2107\permanent\protected\def\fittoptobaselinegrid % weg hier
2108  {\dowithnextbox
2109     {\bgroup
2110      \par
2111      \scratchdimen\ht\nextbox
2112      \ht\nextbox\strutht
2113      \dp\nextbox\strutdp
2114      \hpack{\box\nextbox}
2115      \prevdepth\strutdp
2116      \doloop
2117        {\advance\scratchdimen -\lineheight
2118         \ifdim\scratchdimen<\zeropoint
2119           \exitloop
2120         \else
2121           \nobreak
2122           \hpack{\strut}
2123         \fi}
2124      \egroup}
2125     \vbox}
2126
2127%D Some more undocumented macros (used in m-chart).
2128
2129\newif\iftraceboxplacement % \traceboxplacementtrue
2130
2131\newbox\fakedboxcursor
2132
2133\setbox\fakedboxcursor\hpack
2134  {\vrule\s!width\zeropoint\s!height\zeropoint\s!depth\zeropoint}
2135
2136\permanent\protected\def\boxcursor % overloaded in core-vis
2137  {\iftraceboxplacement
2138     \bgroup
2139     \scratchdimen2\onepoint
2140     \setbox\scratchbox\hpack to \zeropoint
2141       {\hss
2142        \vrule
2143          \s!width \scratchdimen
2144          \s!height\scratchdimen
2145          \s!depth \scratchdimen
2146        \hss}%
2147     \smashedbox\scratchbox
2148     \egroup
2149   \else
2150     \copy\fakedboxcursor
2151   \fi}
2152
2153\permanent\protected\def\placedbox
2154  {\iftraceboxplacement\ruledhbox\else\hbox\fi}
2155
2156\newdimen\boxoffset
2157\newdimen\boxhdisplacement
2158\newdimen\boxvdisplacement
2159
2160\permanent\protected\def\rightbox      {\hpack\bgroup\dowithnextboxcs\syst_boxes_rightbox_finish      \placedbox}
2161\permanent\protected\def\leftbox       {\hpack\bgroup\dowithnextboxcs\syst_boxes_leftbox_finish       \placedbox}
2162\permanent\protected\def\topbox        {\hpack\bgroup\dowithnextboxcs\syst_boxes_topbox_finish        \placedbox}
2163\permanent\protected\def\bottombox     {\hpack\bgroup\dowithnextboxcs\syst_boxes_bottombox_finish     \placedbox}
2164\permanent\protected\def\lefttopbox    {\hpack\bgroup\dowithnextboxcs\syst_boxes_lefttopbox_finish    \placedbox}
2165\permanent\protected\def\righttopbox   {\hpack\bgroup\dowithnextboxcs\syst_boxes_righttopbox_finish   \placedbox}
2166\permanent\protected\def\leftbottombox {\hpack\bgroup\dowithnextboxcs\syst_boxes_leftbottombox_finish \placedbox}
2167\permanent\protected\def\rightbottombox{\hpack\bgroup\dowithnextboxcs\syst_boxes_rightbottombox_finish\placedbox}
2168
2169\aliased\let\topleftbox    \lefttopbox
2170\aliased\let\toprightbox   \righttopbox
2171\aliased\let\bottomleftbox \leftbottombox
2172\aliased\let\bottomrightbox\rightbottombox
2173
2174\def\syst_boxes_rightbox_finish
2175  {\global\boxhdisplacement\boxoffset
2176   \global\boxvdisplacement.5\dimexpr\ht\nextbox-\dp\nextbox\relax
2177   \boxcursor
2178   \boxxmove\nextbox \boxhdisplacement
2179   \boxymove\nextbox-\boxvdisplacement
2180   \box\nextbox
2181   \egroup}
2182
2183\def\syst_boxes_leftbox_finish
2184  {\global\boxhdisplacement\dimexpr-\wd\nextbox-\boxoffset\relax
2185   \global\boxvdisplacement.5\dimexpr\ht\nextbox-\dp\nextbox\relax
2186   \boxcursor
2187   \boxxmove\nextbox \boxhdisplacement
2188   \boxymove\nextbox-\boxvdisplacement
2189   \box\nextbox
2190   \egroup}
2191
2192\def\syst_boxes_topbox_finish
2193  {\global\boxhdisplacement-.5\wd\nextbox
2194   \global\boxvdisplacement\dimexpr-\dp\nextbox-\boxoffset\relax
2195   \boxcursor
2196   \boxxmove\nextbox \boxhdisplacement
2197   \boxymove\nextbox-\boxvdisplacement
2198   \box\nextbox
2199   \egroup}
2200
2201\def\syst_boxes_bottombox_finish
2202  {\global\boxhdisplacement-.5\wd\nextbox
2203   \global\boxvdisplacement\dimexpr\ht\nextbox+\boxoffset\relax
2204   \boxcursor
2205   \boxxmove\nextbox \boxhdisplacement
2206   \boxymove\nextbox-\boxvdisplacement
2207   \box\nextbox
2208   \egroup}
2209
2210\def\syst_boxes_lefttopbox_finish
2211  {\global\boxhdisplacement\dimexpr-\wd\nextbox-\boxoffset\relax
2212   \global\boxvdisplacement\dimexpr-\dp\nextbox-\boxoffset\relax
2213   \boxcursor
2214   \boxxmove\nextbox \boxhdisplacement
2215   \boxymove\nextbox-\boxvdisplacement
2216   \box\nextbox
2217   \egroup}
2218
2219\def\syst_boxes_righttopbox_finish
2220  {\global\boxhdisplacement\boxoffset
2221   \global\boxvdisplacement\dimexpr-\dp\nextbox-\boxoffset\relax
2222   \boxcursor
2223   \boxxmove\nextbox \boxhdisplacement
2224   \boxymove\nextbox-\boxvdisplacement
2225   \box\nextbox
2226   \egroup}
2227
2228\def\syst_boxes_leftbottombox_finish
2229  {\global\boxhdisplacement\dimexpr-\wd\nextbox-\boxoffset\relax
2230   \global\boxvdisplacement\dimexpr\ht\nextbox+\boxoffset\relax
2231   \boxcursor
2232   \boxxmove\nextbox \boxhdisplacement
2233   \boxymove\nextbox-\boxvdisplacement
2234   \box\nextbox
2235   \egroup}
2236
2237\def\syst_boxes_rightbottombox_finish
2238  {\global\boxhdisplacement\boxoffset
2239   \global\boxvdisplacement\dimexpr\ht\nextbox+\boxoffset\relax
2240   \boxcursor
2241   \boxxmove\nextbox \boxhdisplacement
2242   \boxymove\nextbox-\boxvdisplacement
2243   \box\nextbox
2244   \egroup}
2245
2246\permanent\protected\def\middlebox        {\hpack\bgroup\dowithnextboxcs\syst_boxes_middlebox_finish        \placedbox}
2247\permanent\protected\def\baselinemiddlebox{\hpack\bgroup\dowithnextboxcs\syst_boxes_baselinemiddlebox_finish\placedbox}
2248\permanent\protected\def\baselineleftbox  {\hpack\bgroup\dowithnextboxcs\syst_boxes_baselineleftbox_finish  \placedbox}
2249\permanent\protected\def\baselinerightbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_baselinerightbox_finish \placedbox}
2250
2251\def\syst_boxes_middlebox_finish
2252  {\global\boxhdisplacement-.5\wd\nextbox
2253   \global\boxvdisplacement.5\dimexpr\ht\nextbox-\dp\nextbox\relax
2254   \boxcursor
2255   \boxxmove\nextbox \boxhdisplacement
2256   \boxymove\nextbox-\boxvdisplacement
2257   \box\nextbox
2258   \egroup}
2259
2260\def\syst_boxes_baselinemiddlebox_finish
2261  {\global\boxhdisplacement\dimexpr-.5\wd\nextbox-\boxoffset\relax
2262   \global\boxvdisplacement-\boxoffset
2263   \boxcursor
2264   \boxxmove\nextbox \boxhdisplacement
2265   \boxymove\nextbox-\boxvdisplacement
2266   \box\nextbox
2267   \egroup}
2268
2269\def\syst_boxes_baselineleftbox_finish
2270  {\global\boxhdisplacement\dimexpr-\wd\nextbox-\boxoffset\relax
2271   \global\boxvdisplacement-\boxoffset
2272   \boxcursor
2273   \boxxmove\nextbox \boxhdisplacement
2274   \boxymove\nextbox-\boxvdisplacement
2275   \box\nextbox
2276   \egroup}
2277
2278\def\syst_boxes_baselinerightbox_finish
2279  {\global\boxhdisplacement\boxoffset
2280   \global\boxvdisplacement-\boxoffset
2281   \boxcursor
2282   \boxxmove\nextbox \boxhdisplacement
2283   \boxymove\nextbox-\boxvdisplacement
2284   \box\nextbox
2285   \egroup}
2286
2287%D \macros
2288%D   {obox}
2289%D
2290%D Experimental, not yet frozen:
2291
2292\permanent\protected\def\lrtbbox#1#2#3#4% l r t b
2293  {\bgroup
2294   \dowithnextboxcontent
2295     {\advance\hsize-#1\advance\hsize-#2\relax
2296      \advance\vsize-#3\advance\vsize-#4\relax}
2297     {\forgetall\vpack to \vsize{\vskip#3\hpack to \hsize{\hskip#1\box\nextbox\hss}\vss}\egroup}
2298     \vbox}
2299
2300%D \macros
2301%D   {toplinebox}
2302%D
2303%D See core-tbl.tex for an example of its usage:
2304
2305\permanent\protected\def\toplinebox
2306  {\dowithnextboxcs\syst_boxes_toplinebox_finish\tbox}
2307
2308\def\syst_boxes_toplinebox_finish
2309  {\ifdim\dp\nextbox>\strutdepth
2310     \scratchdimen\dp\nextbox
2311     \advance\scratchdimen-\strutdepth
2312     \getnoflines\scratchdimen
2313     \struttedbox{\box\nextbox}%
2314     \dorecurse\noflines\verticalstrut
2315   \else
2316     \box\nextbox
2317   \fi}
2318
2319%D \macros
2320%D   {initializeboxstack,savebox,foundbox}
2321%D
2322%D At the cost of some memory, but saving box registers, we have implemented a box
2323%D repository.
2324%D
2325%D \starttyping
2326%D \initializeboxstack{one}
2327%D
2328%D \savebox{one}{a}{test a}
2329%D \savebox{one}{p}{test p}
2330%D \savebox{one}{q}{test q}
2331%D
2332%D \hbox{a:\foundbox{one}{a}} \par
2333%D \hbox{q:\foundbox{one}{q}} \par
2334%D \hbox{p:\foundbox{one}{p}} \par
2335%D \hbox{x:\foundbox{one}{x}} \par
2336%D \hbox{y:\foundbox{two}{a}} \par
2337%D \stoptyping
2338
2339%D Kind of obsolete:
2340
2341\installcorenamespace {stackbox}
2342\installcorenamespace {stacklst}
2343
2344\permanent\protected\def\setstackbox#1#2%
2345  {\ifcsname\??stackbox#1:#2\endcsname\else
2346     \expandafter\newbox\csname\??stackbox#1:#2\endcsname
2347   \fi
2348   \global\setbox\csname\??stackbox#1:#2\endcsname\vbox}
2349
2350\permanent\protected\def\initializeboxstack#1%
2351  {\def\docommand##1{\setstackbox{#1}{##1}{}}%
2352   \ifcsname\??stacklst#1\endcsname
2353     \expandafter\processcommacommand\expandafter[\lastnamedcs]\docommand
2354   \fi
2355   \gletcsname\??stacklst#1\endcsname\empty}
2356
2357\permanent\protected\def\savebox#1#2% stack name
2358  {% beware, \setxvalue defines the cs beforehand so we cannot use the test inside the { }
2359   \ifcsname\??stacklst#1\endcsname
2360     \xdefcsname\??stacklst#1\expandafter\endcsname\expandafter{\lastnamedcs,#2}%
2361   \else
2362     \xdefcsname\??stacklst#1\endcsname{#2}%
2363   \fi
2364   \setstackbox{#1}{#2}}
2365
2366\permanent\protected\def\flushbox#1#2% unwrapped
2367  {\ifcsname\??stackbox#1:#2\endcsname
2368     \box\lastnamedcs
2369   \else
2370     \emptybox
2371   \fi}
2372
2373\permanent\protected\def\restorebox#1#2% unwrapped
2374  {\ifcsname\??stackbox#1:#2\endcsname
2375     \copy\lastnamedcs
2376   \else
2377     \emptybox
2378   \fi}
2379
2380\permanent\protected\def\foundbox#1#2% wrapped
2381  {\vpack
2382     {\ifcsname\??stackbox#1:#2\endcsname
2383        \copy\lastnamedcs
2384      \fi}}
2385
2386\permanent\protected\def\doifelsebox#1#2%
2387  {\unless\ifcsname\??stackbox#1:#2\endcsname
2388     \expandafter\secondoftwoarguments
2389   \orelse\ifvoid\lastnamedcs
2390     \expandafter\secondoftwoarguments
2391   \else
2392     \expandafter\firstoftwoarguments
2393   \fi}
2394
2395\aliased\let\doifboxelse\doifelsebox
2396
2397%D This one is cheaper (the above is no longer used that much):
2398
2399\installcorenamespace {boxstack}
2400
2401\newcount\c_syst_boxes_stack
2402
2403\mutable\let\b_syst_boxes_stack\relax
2404
2405\protected\def\syst_boxes_stack_allocate
2406  {\newbox\b_syst_boxes_stack
2407   \letcsname\??boxstack\number\c_syst_boxes_stack\endcsname\b_syst_boxes_stack}
2408
2409\protected\def\syst_boxes_push#1#2%
2410  {\global\advance\c_syst_boxes_stack\plusone
2411   \expandafter\let\expandafter\b_syst_boxes_stack\csname\??boxstack\number\c_syst_boxes_stack\endcsname
2412   \ifrelax\b_syst_boxes_stack % cheaper then csname check as in most cases it's defined
2413      \syst_boxes_stack_allocate
2414   \fi
2415   #1\setbox\b_syst_boxes_stack\box#2\relax}
2416
2417\protected\def\syst_boxes_pop#1#2%
2418  {#1\setbox#2\box\csname\??boxstack\number\c_syst_boxes_stack\endcsname
2419   \global\advance\c_syst_boxes_stack\minusone}
2420
2421\permanent\protected\def\localpushbox {\syst_boxes_push\relax}
2422\permanent\protected\def\localpopbox  {\syst_boxes_pop \relax}
2423
2424\permanent\protected\def\globalpushbox{\syst_boxes_push\global}
2425\permanent\protected\def\globalpopbox {\syst_boxes_pop \global}
2426
2427%D And here is a more modern one (not yet in i-*):
2428%D
2429%D \starttyping
2430%D \dorecurse {100} {
2431%D     \setbox\zerocount\hbox{test \recurselevel}
2432%D     \putboxincache{foo}{\recurselevel}\zerocount
2433%D     \copyboxfromcache{foo}{\recurselevel}\zerocount
2434%D     \iftrue
2435%D         \setbox\zerocount\hbox{\directboxfromcache{foo}{\recurselevel}}%
2436%D     \else
2437%D         \getboxfromcache{foo}{\recurselevel}\zerocount
2438%D     \fi
2439%D }
2440%D % \startMPcode draw rawtexbox("category","name") ; \stopMPcode
2441%D \resetboxesincache{foo}
2442%D \stoptyping
2443
2444% \putboxincache          % {category} {name} number
2445% \getboxfromcache        % {category} {name} number
2446% \doifelseboxincache     % {category} {name}
2447% \copyboxfromcache       % {category} {name} number
2448% \directboxfromcache     % {category} {name}
2449% \directcopyboxfromcache % {category} {name}
2450% \resetboxesincache      % {category}
2451% \putnextboxincache      % {category} {name} box
2452% \getboxwdfromcache      % {category} {name}
2453% \getboxhtfromcache      % {category} {name}
2454% \getboxdpfromcache      % {category} {name}
2455
2456%D \macros
2457%D   {removedepth, obeydepth}
2458%D
2459%D While \type {\removedepth} removes the preceding depth, \type {\obeydepth} makes
2460%D sure we have depth. Both macros leave the \type {\prevdepth} untouched.
2461
2462\permanent\protected\def\removedepth
2463  {\ifvmode
2464     \ifdim\prevdepth>\zeropoint
2465       \kern-\prevdepth
2466     \fi
2467   \fi}
2468
2469\permanent\protected\def\obeydepth
2470  {\par % watch out for changes in math formulas
2471   \ifvmode\ifdim\prevdepth<\zeropoint\orelse\ifdim\prevdepth<\strutdp
2472     \kern\dimexpr\strutdp-\prevdepth\relax
2473     \prevdepth\strutdp
2474   \fi\fi}
2475
2476\permanent\protected\def\undepthed
2477  {\dowithnextbox{\dp\nextbox\zeropoint\box\nextbox}\hbox}
2478
2479%D \macros
2480%D   {removebottomthings, removelastskip}
2481%D
2482%D A funny (but rather stupid) one, plus a redefinition.
2483
2484\permanent\protected\def\removebottomthings
2485  {\dorecurse\plusfive{\unskip\unkern\unpenalty}}
2486
2487\permanent\protected\def\removelastskip % \ifvmode the plain tex one \fi, overloaded to \permanent in spac-ver
2488  {\ifvmode\ifzeropt\lastskip\else\vskip-\lastskip\fi\fi}
2489
2490%D \macros
2491%D   {makestrutofbox}
2492%D
2493%D This macro sets the dimensions of a box to those of a strut. Sort of obsolete so
2494%D it will go away.
2495
2496\permanent\protected\def\makestrutofbox % not used
2497  {\afterassignment\syst_boxes_makestrutofbox\c_boxes_register}
2498
2499\def\syst_boxes_makestrutofbox
2500  {\ht\c_boxes_register\strutht
2501   \dp\c_boxes_register\strutdp
2502   \wd\c_boxes_register\zeropoint}
2503
2504%D \macros
2505%D   {raisebox,lowerbox}
2506%D
2507%D Some more box stuff, related to positioning (under construction). Nice stuff for
2508%D a tips and tricks maps article.
2509%D
2510%D \starttyping
2511%D \raisebox{100pt}\hbox{test}
2512%D \hsmash{\raisebox{100pt}\hbox{test}}
2513%D \stoptyping
2514
2515\permanent\protected\def\raisebox#1{\bgroup\afterassignment\syst_boxes_raise_indeed\scratchdimen#1} % so both 10pt and {10pt} is accepted
2516\permanent\protected\def\lowerbox#1{\bgroup\afterassignment\syst_boxes_lower_indeed\scratchdimen#1} % so both 10pt and {10pt} is accepted
2517
2518\def\syst_boxes_raise_indeed{\dowithnextboxcs\syst_boxes_raise_finish}
2519\def\syst_boxes_lower_indeed{\dowithnextboxcs\syst_boxes_lower_finish}
2520
2521\def\syst_boxes_raise_finish
2522  {\boxyoffset\nextbox\scratchdimen
2523   \ht\nextbox\strutht
2524   \dp\nextbox\strutdp
2525   \box\nextbox
2526   \egroup}
2527
2528\def\syst_boxes_lower_finish
2529  {\boxyoffset\nextbox-\scratchdimen
2530   \ht\nextbox\strutht
2531   \dp\nextbox\strutdp
2532   \box\nextbox
2533   \egroup}
2534
2535% vcenter in text, we kunnen vcenter overloaden
2536
2537\permanent\protected\def\halfwaybox
2538  {\hpack\bgroup
2539   \dowithnextboxcs\syst_boxes_halfwaybox_finish\hbox}
2540
2541\def\syst_boxes_halfwaybox_finish
2542  {\dp\nextbox\zeropoint
2543   \lower.5\ht\nextbox\box\nextbox
2544   \egroup}
2545
2546\permanent\protected\def\depthonlybox
2547  {\tpack\bgroup
2548   \dowithnextboxcs\syst_boxes_depthonlybox_finish\vbox}
2549
2550\def\syst_boxes_depthonlybox_finish
2551  {\hsize\wd\nextbox
2552   \kern\zeropoint\box\nextbox
2553   \egroup}
2554
2555%D New:
2556
2557\permanent\def\setdimentoatleast#1#2{\ifdim#1>\zeropoint\else#1=#2\fi}
2558\permanent\def\setdimentoatmost #1#2{\ifdim#1>#2\relax  \else#1=#2\fi}
2559
2560%D And even rawer:
2561
2562\aliased\let\naturalvcenter\normalvtop % will go away
2563
2564% \appendtoks \let\vcenter\normalvcenter \to \everymathematics
2565
2566%D \macros
2567%D   {frozenhbox}
2568%D
2569%D A not so well unhboxable box can be made with:
2570
2571\permanent\protected\def\frozenhbox
2572  {\hpack\bgroup
2573   \dowithnextboxcs\syst_boxes_frozenhbox_finish\hbox}
2574
2575\def\syst_boxes_frozenhbox_finish
2576  {\hpack{\hpack{\box\nextbox}}%
2577   \egroup}
2578
2579%D \macros
2580%D   {setboxllx,setboxlly,gsetboxllx,gsetboxlly,getboxllx,getboxlly}
2581%D
2582%D A prelude to an extended \TEX\ feature:
2583
2584\installcorenamespace {box_x}
2585\installcorenamespace {box_y}
2586
2587\permanent\protected\def\setboxllx #1#2{\edefcsname\??box_x\number#1\endcsname{\the\dimexpr#2\relax}}
2588\permanent\protected\def\setboxlly #1#2{\edefcsname\??box_y\number#1\endcsname{\the\dimexpr#2\relax}}
2589
2590\permanent\protected\def\gsetboxllx#1#2{\xdefcsname\??box_x\number#1\endcsname{\the\dimexpr#2\relax}}
2591\permanent\protected\def\gsetboxlly#1#2{\xdefcsname\??box_y\number#1\endcsname{\the\dimexpr#2\relax}}
2592
2593\permanent\def\getboxllx#1{\ifcsname\??box_x\number#1\endcsname\lastnamedcs\else\zeropoint\fi}
2594\permanent\def\getboxlly#1{\ifcsname\??box_y\number#1\endcsname\lastnamedcs\else\zeropoint\fi}
2595
2596\permanent\def\directgetboxllx#1{\csname\??box_x\number#1\endcsname} % use when sure existence
2597\permanent\def\directgetboxlly#1{\csname\??box_y\number#1\endcsname} % use when sure existence
2598
2599%D \macros
2600%D   {shownextbox}
2601%D
2602%D Handy for tracing
2603%D
2604%D \starttyping
2605%D \shownextbox\vbox{test}
2606%D \shownextbox\vbox{test\endgraf}
2607%D \shownextbox\vbox{test\endgraf\strut\endgraf}
2608%D \shownextbox\vbox{test\endgraf\thinrule}
2609%D \shownextbox\vbox{\setupwhitespace[big]test\endgraf\thinrule}
2610%D \stoptyping
2611
2612\permanent\protected\def\shownextbox % seldom used
2613  {\dowithnextbox
2614     {\bgroup
2615      \showboxbreadth\maxcount
2616      \showboxdepth  \maxcount
2617      \scratchcounter\interactionmode
2618      \batchmode
2619      \showbox\nextbox
2620      \box\nextbox
2621      \interactionmode\scratchcounter
2622      \egroup}}
2623
2624\permanent\protected\def\spreadhbox#1% rebuilds \hbox{<box><hss><box><hss><box>}
2625  {\bgroup
2626   \ifhbox#1\relax
2627     \setbox\scratchboxtwo\emptybox
2628     \unhbox#1%
2629     \doloop
2630       {\unpenalty\unskip\unpenalty\unskip\unpenalty\unskip
2631        \setbox\scratchboxone\lastbox
2632        \ifvoid\scratchboxone
2633          \exitloop
2634        \else
2635          \setbox\scratchboxtwo\hbox
2636            {\ifhbox\scratchboxone \spreadhbox\scratchboxone\else\box\scratchboxone\fi
2637             \ifvoid\scratchboxtwo \else\hss\unhbox\scratchboxtwo\fi}%
2638        \fi}%
2639     \ifvoid\scratchboxtwo\else\unhbox\scratchboxtwo\fi
2640   \else
2641     \box#1%
2642   \fi
2643   \egroup}
2644
2645% \showboxbreadth\plusthousand
2646% \showboxdepth  \plusthousand
2647
2648%D Moved from cont-new:
2649%D
2650%D \starttyping
2651%D \minimalhbox 100pt {test}
2652%D \stoptyping
2653
2654\permanent\protected\def\minimalhbox#1#%
2655  {\dowithnextbox
2656     {\bgroup
2657      \setbox\scratchbox\hpack#1{\hss}%
2658      \ifdim\wd\nextbox<\wd\scratchbox\wd\nextbox\wd\scratchbox\fi
2659      \box\nextbox
2660      \egroup}
2661     \hbox}
2662
2663%D A bit dirty:
2664
2665% \permanent\protected\def\nodestostring#1#2% more tolerant for #2=\cs
2666%   {\begingroup
2667%    \setbox\nextbox\hbox{#2}%
2668%    \normalexpanded{\endgroup\edef\noexpand#1{\boxtostring\nextbox}}}
2669%
2670% \permanent\def\tostring
2671%   {\beginlocalcontrol
2672%    \dowithnextbox{\endlocalcontrol\boxtostring\nextbox}\hbox}
2673%
2674% \permanent\def\tostring
2675%   {\beginlocalcontrol\begingroup
2676%    \dowithnextbox{\normalexpanded{\endgroup\endlocalcontrol\boxtostring\nextbox}}\hbox}
2677
2678\def\syst_boxes_contenttostring
2679  {\normalexpanded{\endgroup\endlocalcontrol\boxtostring\nextbox}}
2680
2681\permanent\def\contenttostring
2682  {\beginlocalcontrol\begingroup
2683   \dowithnextboxcs\syst_boxes_contenttostring\hbox}
2684
2685\newtoks \everypreroll
2686\newif   \ifprerolling
2687
2688\appendtoks
2689    \prerollingtrue
2690\to \everypreroll
2691
2692\let\prerolltostring\firstofoneargument % we need to bypass initializations
2693
2694\appendtoks
2695    \permanent\def\prerolltostring
2696      {\beginlocalcontrol\begingroup
2697       \the\everypreroll
2698       \dowithnextboxcs\syst_boxes_contenttostring\hbox}
2699\to \everydump
2700
2701% depricated:
2702
2703\permanent\protected\def\nodestostring#1#2% more tolerant for #2=\cs
2704  {\edef#2{\contenttostring{#1}}}
2705
2706%D Even more dirty:
2707
2708\aliased\let\hyphenatedhbox\hbox % was a macro in mkii
2709
2710%D We can do this:
2711%D
2712%D \starttyping
2713%D \setbox0\hbox to 10cm{foo} \setbox2\hbox{\unhbox0} \the\wd2
2714%D \stoptyping
2715%D
2716%D But this saves a copy (and hpack pass):
2717%D
2718%D \starttyping
2719%D \setbox0\hbox to 10cm{foo} \the\naturalwd0
2720%D \stoptyping
2721
2722\newdimen\lastnaturalboxwd
2723\newdimen\lastnaturalboxht
2724\newdimen\lastnaturalboxdp
2725
2726%D We can define these public in lua:
2727
2728\aliased\let\getnaturaldimensions\clf_getnaturaldimensions % sets three dimensions
2729\aliased\let\naturalwd           \clf_naturalwd            % calculates and returns wd
2730
2731\aliased\let\getnaturalwd\clf_getnaturalwd % no intermediate
2732\aliased\let\setnaturalwd\clf_setnaturalwd % no intermediate
2733
2734\permanent\protected\def\doifelserighttoleftinbox{\clf_doifelserighttoleftinbox}
2735
2736\aliased\let\doifrighttoleftinboxelse\doifelserighttoleftinbox
2737
2738%D New, used in high/low:
2739
2740\definesystemattribute [runningtext] [public]
2741
2742\permanent\protected\def\runninghbox{\hbox attr \runningtextattribute \fontid\font} % not yet in i-*
2743
2744%D To complement lua (yet undocumented):
2745
2746\permanent\protected\def\beginhbox{\hbox\bgroup}  \aliased\let\endhbox\egroup
2747\permanent\protected\def\beginvbox{\vbox\bgroup}  \aliased\let\endvbox\egroup
2748\permanent\protected\def\beginvtop{\vtop\bgroup}  \aliased\let\endvtop\egroup
2749
2750\permanent\protected\def\sethboxregister#1{\setbox#1\hbox}
2751\permanent\protected\def\setvboxregister#1{\setbox#1\vbox}
2752\permanent\protected\def\setvtopregister#1{\setbox#1\vtop}
2753
2754\permanent\protected\def\flushboxregister#1{\box\numexpr#1\relax}
2755
2756\permanent\protected\def\starthboxregister#1{\setbox#1\hbox\bgroup}  \aliased\let\stophboxregister\egroup
2757\permanent\protected\def\startvboxregister#1{\setbox#1\vbox\bgroup}  \aliased\let\stopvboxregister\egroup
2758\permanent\protected\def\startvtopregister#1{\setbox#1\vtop\bgroup}  \aliased\let\stopvtopregister\egroup
2759
2760% %D For whatever third party package needs it:
2761% %D
2762% %D \starttyping
2763% %D \newlocalbox\BoxOne
2764% %D \newlocalbox\BoxTwo
2765% %D
2766% %D \setbox\BoxOne\hbox{Box One}
2767% %D \setbox\BoxTwo\hbox{Box Two}
2768% %D
2769% %D [\box\BoxTwo] [\box\BoxOne]
2770% %D \stoptyping
2771%
2772% \installcorenamespace{localbox}
2773%
2774% \permanent\protected\def\newlocalbox#1%
2775%   {\expandafter\let\expandafter#1\csname\??localbox\string#1\endcsname
2776%    \ifrelax#1%
2777%      \syst_aux_new_localbox#1%
2778%    \fi}
2779%
2780% \def\syst_aux_new_localbox#1%
2781%   {\expandafter\newbox\csname\??localbox\string#1\endcsname
2782%    \newlocalbox#1}
2783
2784%D Who knows when this comes in handy:
2785
2786\permanent\protected\def\lastlinewidth{\dimexpr\clf_lastlinewidth\scaledpoint\relax}
2787
2788%D Keep as reference:
2789
2790% \protected\def\tightvbox{\dowithnextbox{\dp\nextbox\zeropoint\box\nextbox}\vbox}
2791% \protected\def\tightvtop{\dowithnextbox{\ht\nextbox\zeropoint\box\nextbox}\vtop}
2792
2793%D This one keeps dimensions and sets the shift field (and so it's more for testing
2794%D than for real usage):
2795
2796\permanent\protected\def\shiftbox  {\clf_shiftbox}
2797\permanent\protected\def\vpackbox  {\clf_vpackbox}
2798\permanent\protected\def\hpackbox  {\clf_hpackbox}
2799\permanent\protected\def\vpackedbox{\clf_vpackedbox}
2800\permanent\protected\def\hpackedbox{\clf_hpackedbox}
2801
2802%D This one has been moved from a 2 decade old file. It makes something boxed
2803%D sit on the baseline.
2804
2805\permanent\protected\def\linebox
2806  {\hpack\bgroup\dowithnextbox
2807     {\scratchdimen\dimexpr\dimexpr\htdp\nextbox-\lineheight\relax/2+\dp\strutbox\relax
2808      \setbox\nextbox\hpack{\lower\scratchdimen\box\nextbox}%
2809      \ht\nextbox\ht\strutbox
2810      \dp\nextbox\dp\strutbox
2811      \box\nextbox
2812      \egroup}
2813     \hbox}
2814
2815%D \macros
2816%D   {widthuptohere}
2817%D
2818%D Implemented at the \LUA\ end:
2819%D
2820%D \startbuffer
2821%D widthuptohere:\the\widthuptohere\crlf
2822%D widthuptohere : \the\widthuptohere (space without stretch or shrink!)
2823%D \stopbuffer
2824%D
2825%D \typebuffer \blank \getbuffer \blank
2826%D
2827%D Implemented elsewhere:
2828%D
2829%D \starttyping
2830%D \boxlines    <box>
2831%D \boxline     <box> <line>
2832%D \copyboxline <box> <line>
2833%D \setboxline  <box> <line>
2834%D \boxlineht   <box> <line> [<dimen>]
2835%D \boxlinedp   <box> <line> [<dimen>]
2836%D \boxlinewd   <box> <line> [<dimen>]
2837%D \boxlinels   <box> <line>
2838%D \boxliners   <box> <line>
2839%D \boxlinelh   <box> <line>
2840%D \boxlinerh   <box> <line>
2841%D \boxlinelp   <box> <line>
2842%D \boxlinerp   <box> <line>
2843%D \boxlinein   <box> <line>
2844%D \boxrangeht  <box> <first line> <last line>
2845%D \boxrangedp  <box> <first line> <last line>
2846%D \boxrangewd  <box> <first line> <last line>
2847%D \stoptyping
2848
2849% To be discussed with ws.
2850%
2851% \installcorenamespace{namedboxes}
2852%
2853% \protected\def\newnamedbox#1%
2854%   {\ifcsname\??namedboxes#1\endcsname\else
2855%      \expandafter\newbox\csname\??namedboxes#1\endcsname
2856%    \fi}
2857%
2858% \protected\def\namedbox#1{\csname\??namedboxes#1\endcsname}
2859
2860%D Implemented elsewhere:
2861%D
2862%D \startbuffer
2863%D \setbox0\hbox{test \footnote{test}} (\prelistbox0) (\postlistbox0)
2864%D \setprelistbox0\hbox{BEFORE} \setpostlistbox0\hbox{AFTER}
2865%D \box0
2866%D \stopbuffer
2867%D
2868%D \typebuffer \blank \getbuffer \blank
2869%D
2870%D \starttyping
2871%D \prelistbox     <box>
2872%D \postlistbox    <box>
2873%D \prelistcopy    <box>
2874%D \postlistcopy   <box>
2875%D \setprelistbox  <box> <hbox|vbox|vtop|somebox>
2876%D \setpostlistbox <box> <hbox|vbox|vtop|somebox>
2877%D \stoptyping
2878
2879%D Defined in lua:
2880%D
2881%D setsplitlisthtdp\scratchbox\struthp\strutdp
2882
2883%D Handy but I'll probably forget it:
2884%D
2885%D \starttyping
2886%D \setbox0\hbox{!!!!!}
2887%D \showbox     0
2888%D \showboxhere 0 % always on console, less clutter
2889%D \stoptyping
2890
2891\untraced\permanent\protected\def\showboxhere{\showbox nolevels content online }
2892
2893\protect \endinput
2894
2895% a bit of test code:
2896
2897% \hbox \bgroup
2898%     \ruledvbox                {\hbox{\strut gans}}
2899%     \ruledvbox to \lineheight {\hbox{\strut gans}}
2900%     \ruledvbox to \lineheight {\hbox       {gans}}
2901%     \ruledvbox to \strutheight{\hbox       {gans}}
2902%     \ruledvbox to \strutheight{\hbox{\strut gans}}
2903%     \ruledvbox to \strutheight{\vss\hbox{gans}}
2904% \egroup
2905
2906% to be considered
2907
2908% \startluacode
2909%
2910%     local spacer = lpeg.patterns.spacer
2911%
2912%     function commands.withwords(command,str)
2913%         if str then
2914%             command = command or "ruledhbox"
2915%             local done = false
2916%             local function apply(s)
2917%                 if done then
2918%                     context.space()
2919%                     done = true
2920%                 else
2921%                     context.dontleavehmode()
2922%                 end
2923%                 context[command](s)
2924%             end
2925%             lpeg.match(lpeg.splitter(spacer,apply),str)
2926%         end
2927%
2928%     end
2929%
2930% \stopluacode
2931%
2932% \unprotect
2933%
2934% \protected\def\withwordsinstring#1#2% command str
2935%   {\ctxcommand{withwords(\!!bs#1\!!es,\!!bs#2\!!es)}}
2936%
2937% \protected\def\withwordsinfile#1#2% command name
2938%   {\ctxcommand{withwords(\!!bs#1\!!es,io.loaddata(resolvers.findfile("#2")))}}
2939%
2940% \protect
2941%
2942% \starttext
2943%
2944%     \defineframed[colored][foregroundcolor=red,foregroundstyle=\bfc\underbar,location=low]
2945%
2946%     \withwordsinstring{colored}{bla bla}
2947%     \withwordsinfile{colored}{ward.tex}
2948%
2949% \stoptext
2950