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