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