diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/supp-box.tex')
-rw-r--r-- | Master/texmf-dist/tex/context/base/supp-box.tex | 2939 |
1 files changed, 2939 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/supp-box.tex b/Master/texmf-dist/tex/context/base/supp-box.tex new file mode 100644 index 00000000000..4b451a6bfab --- /dev/null +++ b/Master/texmf-dist/tex/context/base/supp-box.tex @@ -0,0 +1,2939 @@ +%D \module +%D [ file=supp-box, +%D version=1995.10.10, +%D title=\CONTEXT\ Support Macros, +%D subtitle=Boxes, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA / Hans Hagen \& Ton Otten}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +%D This module implements some box manipulation macros. Some +%D are quite simple, some are more advanced and when understood +%D well, all can be of use. + +\writestatus{loading}{Context Support Macros / Boxes} + +\unprotect + +% watch this: \setbox4\emptybox \wd4\onepoint \the\wd4, no dimensions for void + +%D First a couple of hacks to make this module loadable +%D in plain \TEX. + +\ifx\myalloc@\undefined % seems like we're not in context + \def\newbox{\alloc@4\box\chardef\insc@unt} +\fi + +\ifx \scratchbox\undefined \newbox \scratchbox \fi +\ifx\globalscratchbox\undefined \newbox\globalscratchbox \fi + +\ifx\normalhbox \undefined \let\normalhbox \hbox \fi +\ifx\normalvbox \undefined \let\normalvbox \vbox \fi +\ifx\normalvtop \undefined \let\normalvtop \vtop \fi +\ifx\normalvcenter\undefined \let\normalvcenter\vcenter \fi + +%D \macros +%D {strutdp,strutht,strutwd} +%D +%D The next shortcuts save memory and keying. The width is +%D normally zero points (if not, you're in trouble). These +%D shortcuts can be used like a dimension, opposite to the +%D core macros \type {\strutdepth} and alike, which are +%D values. + +\def\strutdp{\dp\strutbox} +\def\strutht{\ht\strutbox} +\def\strutwd{\wd\strutbox} + +%D \macros +%D {resetbox, emptybox} +%D +%D Let's start with an easy one. The next macro hides the +%D ugly \type {@} in \type {\voidb@x}. + +\def\emptybox {\box\voidb@x} +\def\resetbox#1{\setbox#1\box\voidb@x} + +%D \macros +%D {nextdepth} +%D +%D Let's start with a rather simple declaration. Sometimes we +%D need to save the \TEX\ \DIMENSION\ \type{\prevdepth} and +%D append it later on. The name \type{\nextdepth} suits +%D this purpose well. + +\newdimen\nextdepth + +%D \macros +%D {smashbox, smashedbox} +%D +%D Smashing is introduced in \PLAIN\ \TEX, and stands for +%D reducing the dimensions of a box to zero. The most resolute +%D one is presented first. + +\def\smashbox#1% + {\wd#1\zeropoint + \ht#1\zeropoint + \dp#1\zeropoint} + +\def\smashboxed#1% + {\smashbox{#1}% + \box#1\relax} + +%D \macros +%D {hsmashbox,vsmashbox} +%D +%D Smashing can be used for overlaying boxes. Depending on +%D the mode, horizontal or vertical, one can use: + +\def\hsmashbox#1% + {\wd#1\zeropoint} + +\def\vsmashbox#1% + {\ht#1\zeropoint + \dp#1\zeropoint} + +%D The next implementation is less sensitive for spurious +%D spaces. + +\newcount\registercount + +\def\smashbox + {\afterassignment\dosmashbox\registercount} + +\def\dosmashbox + {\wd\registercount\zeropoint + \ht\registercount\zeropoint + \dp\registercount\zeropoint} + +\def\smashedbox + {\afterassignment\thesmashedbox\registercount} + +\def\thesmashedbox + {\dosmashbox + \box\registercount} + +\def\hsmashbox + {\afterassignment\dohsmashbox\registercount} + +\def\dohsmashbox + {\wd\registercount\zeropoint} + +\def\vsmashbox + {\afterassignment\dovsmashbox\registercount} + +\def\dovsmashbox + {\ht\registercount\zeropoint + \dp\registercount\zeropoint} + +%D \macros +%D {hsmash,vsmash, +%D hsmashed,vsmashed} +%D +%D While the previous macros expected a \BOX, the next act on a +%D content. They are some subtle differences betreen the smash +%D and smashed alternatives. The later ones reduce all +%D dimensions to zero. + +% Ok, but inefficient and/or catcode unsafe: +% +% \def\hsmash #1{\bgroup\setbox0=\normalhbox{#1}\hsmashbox0\box0\egroup} +% \def\vsmash #1{\bgroup\setbox0=\normalvbox{#1}\vsmashbox0\box0\egroup} +% \def\hsmashed#1{\bgroup\setbox0=\normalhbox{#1}\smashbox 0\box0\egroup} +% \def\vsmashed#1{\bgroup\setbox0=\normalvbox{#1}\smashbox 0\box0\egroup} +% +% Better, but a waste of tokens: +% +% \def\hsmash {\bgroup\dowithnextbox{\hsmashbox\nextbox\flushnextbox\egroup}\normalhbox} +% \def\vsmash {\bgroup\dowithnextbox{\vsmashbox\nextbox\flushnextbox\nextbox\egroup}\normalvbox} +% \def\hsmashed{\bgroup\dowithnextbox{\smashbox \nextbox\flushnextbox\nextbox\egroup}\normalhbox} +% \def\vsmashed{\bgroup\dowithnextbox{\smashbox \nextbox\flushnextbox\nextbox\egroup}\normalvbox} +% +% The best: + +\def\dosomesmash#1% (begin|end)group ipv (b|e)group ? + {\bgroup\dowithnextbox{#1\nextbox\flushnextbox\egroup}} + +\def\hsmash {\dosomesmash\hsmashbox\normalhbox} +\def\vsmash {\dosomesmash\vsmashbox\normalvbox} +\def\hsmashed{\dosomesmash\smashbox \normalhbox} +\def\vsmashed{\dosomesmash\smashbox \normalvbox} + +%D \macros +%D {smashedhbox,smashedvbox} +%D +%D Also handy (all dimensions zeroed): +%D +%D \starttyping +%D \smashedhbox to ... {...} +%D \smashedvbox to ... {...} +%D \stoptyping + +\def\dosmashedbox#1% + %{#1\bgroup\dowithnextbox{\smashbox\nextbox\flushnextbox\egroup}#1} + {#1\bgroup\dowithnextbox{\smashedbox\nextbox\egroup}#1} + +\def\smashedhbox{\dosmashedbox\hbox} +\def\smashedvbox{\dosmashedbox\vbox} + +%D \macros +%D {smash} +%D +%D This smash alternative takes an optional arg [whdtb] as +%D well as is potentially catcode safer. It is needed by the +%D math module (although the \type {\leavevmode} is not added +%D here). + +\def\smash + {\futurelet\nexttoken\dosmash} + +\def\dosmash + {\ifx\nexttoken[\@EA\dodosmash\else\@EA\donosmash\fi} + +\def\donosmash + {\dodosmash[hd]} + +\def\dodosmash[#1]% + {\edef\@@smash{#1}\futurelet\nexttoken\dododosmash} + +\def\dododosmash % if needed we can avoid the \next + {\ifmmode + \def\next##1{\mathpalette\mathsm@sh{##1}}% + \else\ifx\nexttoken\bgroup + \let\next\finsm@sh + \else + \def\next##1{\finsm@sh{##1}}% + \fi\fi + \next} + +\def\mathsm@sh#1#2% redefined plain macro + {\finsm@sh{$\m@th#1{#2}$}} + +\def\makesm@sh#1% redefined plain macro (handles t b h d w) + {\if#1w\nextboxwd\zeropoint\else + \if#1h\nextboxht\zeropoint\else + \if#1d\nextboxdp\zeropoint\else + \if#1t\nextboxht\zeropoint\else + \if#1b\nextboxdp\zeropoint\fi\fi\fi\fi\fi} + +\def\finsm@sh % redefined plain macro + {\dowithnextbox + {\@EA\handletokens\@@smash\with\makesm@sh\flushnextbox}\normalhbox} + +%D \starttabulate[|l|l|] +%D \NC w \NC \ruledhbox{\smash [w]{This is some great smashing, isn't it?}} \NC \NR +%D \NC h \NC \ruledhbox{\smash [h]{This is some great smashing, isn't it?}} \NC \NR +%D \NC d \NC \ruledhbox{\smash [d]{This is some great smashing, isn't it?}} \NC \NR +%D \NC tb \NC \ruledhbox{\smash [tb]{This is some great smashing, isn't it?}} \NC \NR +%D \NC whd \NC \ruledhbox{\smash[whd]{This is some great smashing, isn't it?}} \NC \NR +%D \stoptabulate + +%D \macros +%D {phantom, hphantom, vphantom, mathstrut} +%D +%D The next implementation of \type {\phantom} cum suis does +%D not grab an argument in the non||math case, which is better. + +\def\phantom {\ph@nt\nextbox\nextbox\nextbox} +\def\vphantom{\ph@nt\nextbox\nextbox\voidb@x} +\def\hphantom{\ph@nt\voidb@x\voidb@x\nextbox} + +%D Due to a complicated call to \type {\mathpallete} and +%D thereby \type {\mathchoice}, the next macro looks ugly. +%D We also take care of non||braced arguments. + +\def\ph@nt#1#2#3% + {\def\doph@nt + {\ifmmode + \def\mathph@nt####1####2{\makeph@nt#1#2#3{$\m@th####1{####2}$}}% + \def\nextph@nt{\mathpalette\mathph@nt}% + \else\ifx\nextph@nt\bgroup + \def\nextph@nt{\makeph@nt#1#2#3}% + \else + \def\nextph@nt####1{\makeph@nt#1#2#3{####1}}% + \fi\fi + \nextph@nt}% + \futurelet\nextph@nt\doph@nt} + +\def\makeph@nt#1#2#3% + {\begingroup % why no \bgroup + \dowithnextbox + {\setbox\scratchbox\null + \ht\scratchbox\ht#1\dp\scratchbox\dp#2\wd\scratchbox\wd#3% + \box\scratchbox + \endgroup} + \normalhbox} + +% used in table +% +% \let\ifv@\undefined \let\v@true\undefined \let\v@false\undefined +% \let\ifh@\undefined \let\h@true\undefined \let\h@false\undefined + +\let\finph@nt\undefined + +%D We also define plain's \type {\mathstrut}. + +\def\mathstrut{\vphantom{(}} + +%D \macros +%D {getboxheight} +%D +%D Although often needed, \TEX\ does not support arithmics +%D like: +%D +%D \starttyping +%D \dimen0 = \ht0 + \dp0 +%D \stoptyping +%D +%D so we implemented: +%D +%D \starttyping +%D \getboxheight ... \of \box... +%D \stoptyping +%D +%D For instance, +%D +%D \starttyping +%D \getboxheight \dimen0 \of \box0 +%D \getboxheight \someheight \of \box \tempbox +%D \stoptyping +%D +%D The implementation is rather stupid: +%D +%D \starttyping +%D \def\getboxheight#1\of#2\box#3% +%D {#1\ht#3\advance#1\dp#3\relax} +%D \stoptyping +%D +%D The next alternative is slightly more clever, since +%D it accepts \type {{12}} as well as \type {12} as box +%D number. + +\def\getboxheight#1\of#2\box#3% + {\def\next{#1\ht\registercount\advance#1\dp\registercount}% + \afterassignment\next\registercount=#3} + +%D For a long time the following three macros were part of +%D the grid snapping core module, but it makes more sense to +%D have them here so that users can see them. +%D +%D \macros +%D {getnoflines, getroundednoflines, getrawnoflines} +%D +%D Het commando \type{\getnoflines} converteert een hoogte +%D (dimensie) in een aantal regels en kent dit toe aan +%D \type{\noflines}. +%D +%D \starttyping +%D \getnoflines{dimensie} +%D \stoptyping +%D +%D Er wordt gedeeld door \type{\openlineheight} en een hoogte +%D van~0pt komt overeen met 0~regels. The raw alternative +%D does not round. + +%D For a long time we had: +%D +%D \starttyping +%D \newcount\noflines +%D \newdimen\noflinesheight +%D +%D \def\dogetnoflines#1#2% +%D {\noflinesheight#2\relax +%D \ifzeropt\noflinesheight % \ifdim\noflinesheight=\zeropoint +%D \noflines\zerocount +%D \else +%D \divide\noflinesheight \openlineheight +%D \noflines\noflinesheight +%D #1\ifdim\noflines\openlineheight=#2\relax \else +%D \advance\noflines\ifdim#2>\zeropoint\plusone\else\minusone\fi +%D \fi\fi +%D \fi} +%D +%D \def\getnoflines {\dogetnoflines\iftrue } % compensated +%D \def\getrawnoflines{\dogetnoflines\iffalse} % no compensation +%D \stoptyping +%D +%D A more recent variant is: + +\ifx\roundingeps\undefined \newdimen\roundingeps \roundingeps=10sp \fi + +\newcount\noflines +\newdimen\noflinesheight + +\def\getnoflines {\xdogetnoflines\plusone } % compensated +\def\getroundednoflines{\xdogetnoflines\plustwo } % rounded +\def\getrawnoflines {\xdogetnoflines\plusthree} % truncated + +\def\xdogetnoflines#1#2% + {\noflinesheight#2\relax + \ifzeropt\noflinesheight + \noflines\zerocount + \else\ifdim#2>\zeropoint + \ifcase#1\or + \advance\noflinesheight-\roundingeps + \divide\noflinesheight\openlineheight + \noflines\noflinesheight + \advance\noflines\plusone + \or + \advance\noflinesheight\roundingeps + \divide\noflinesheight\openlineheight + \noflines\noflinesheight + \or + \advance\noflinesheight\roundingeps + \advance\noflinesheight.5\openlineheight + \divide\noflinesheight\openlineheight + \noflines\noflinesheight + \fi + \else + \ifcase#1\or + \advance\noflinesheight\roundingeps + \divide\noflinesheight\openlineheight + \noflines\noflinesheight + \advance\noflines\minusone + \or + \advance\noflinesheight-\roundingeps + \divide\noflinesheight\openlineheight + \noflines\noflinesheight + \or + \advance\noflinesheight-\roundingeps + \advance\noflinesheight-.5\openlineheight + \divide\noflinesheight\openlineheight + \noflines\noflinesheight + \fi + \fi\fi} + +%D Let's proof that it works: +%D +%D \startbuffer +%D \scratchdimen\dimexpr(3pt) \getnoflines\scratchdimen 1=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight) \getnoflines\scratchdimen 10=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10.1\lineheight) \getnoflines\scratchdimen 11=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10.5\lineheight) \getnoflines\scratchdimen 11=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10.9\lineheight) \getnoflines\scratchdimen 11=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight+3pt) \getnoflines\scratchdimen 11=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight+3sp) \getnoflines\scratchdimen 10=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight-3sp) \getnoflines\scratchdimen 10=\the\noflines \endgraf +%D +%D \scratchdimen\dimexpr(3pt) \getrawnoflines\scratchdimen 0=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10.1\lineheight) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10.5\lineheight) \getrawnoflines\scratchdimen 11=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10.9\lineheight) \getrawnoflines\scratchdimen 11=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight+3pt) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight+3sp) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight-3sp) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf +%D \stopbuffer +%D +%D \typebuffer \getbuffer + +%D \macros +%D {determinenoflines} +%D +%D The next macro determines the number of lines and +%D returns it it \type {\noflines}. The macro works +%D reasonable well as long as the content can be unboxed. +%D +%D \starttyping +%D \determinenoflines{test\\test} +%D \determinenoflines{\bfd test\\test} +%D \determinenoflines{\definedfont[Sans at 40pt]test\\test} +%D \stoptyping + +\def\determinenoflines + {\bgroup + \forgetall + \let\crlf\endgraf + \let\\\endgraf + \dowithnextbox + {\beginofshapebox + \unvbox\nextbox + \endofshapebox + \global\count1\zerocount + \reshapebox{\global\advance\count1\plusone}% + \egroup\noflines\count1 }% + \vbox} + +%D \macros +%D {doiftextelse, doiftext} +%D +%D When \type {\doifelse} cum suis hopelessly fail, for +%D instance because we pass data, we can fall back on the next +%D macro: +%D +%D \starttyping +%D \doiftextelse {data} {then branch} {else branch} +%D \doiftext {data} {then branch} +%D \stoptyping + +%\def\doiftextelse#1#2#3% +% {\bgroup +% \setbox0=\normalhbox{#1}% +% \ifdim\wd0>\zeropoint +% \egroup#2% +% \else +% \egroup#3% +% \fi} + +% \def\doiftextelse#1% +% {\bgroup +% \setbox0\normalhbox{#1}% +% \ifdim\wd0>\zeropoint +% \egroup\@EA\firstoftwoarguments +% \else +% \egroup\@EA\secondoftwoarguments +% \fi} + +\def\doiftextelse#1% + {\bgroup + \setbox0\normalhbox{\ignorespaces#1\removeunwantedspaces}% + \ifdim\wd0>\zeropoint + \egroup\@EA\firstoftwoarguments + \else + \egroup\@EA\secondoftwoarguments + \fi} + +\def\doiftext#1#2% + {\doiftextelse{#1}{#2}\donothing} + +%D \macros +%D {dowithnextbox,nextbox} +%D +%D Sometimes we want a macro to grab a box and do something +%D on the content. One could pass an argument to a box, but +%D this can violate the specific \CATCODES\ of its content and +%D leads to unexpected results. The next macro treats the +%D following braced text as the content of a box and +%D manipulates it afterwards in a predefined way. +%D +%D The first argument specifies what to do with the content. +%D This content is available in \type{\nextbox}. The second +%D argument is one of \type{\hbox}, \type{\vbox} or +%D \type{\vtop}. The third argument must be grouped with +%D \type{\bgroup} and \type{\egroup}, \type{{...}} or can be +%D a \type{\box} specification. +%D +%D In \CONTEXT\ this macro is used for picking up a box and +%D treating it according to earlier specifications. We use for +%D instance something like: +%D +%D \starttyping +%D \def\getfloat% +%D {\def\handlefloat{...\flushnextbox...} +%D \dowithnextbox\handlefloat\normalvbox} +%D \stoptyping +%D +%D instead of: +%D +%D \starttyping +%D \def\getfloat#1% +%D {...#1...} +%D \stoptyping +%D +%D In this implementation the \type{\aftergroup} construction +%D is needed because \type{\afterassignment} is executed inside +%D the box. + +\newbox\nextbox + +\long\def\dowithnextbox#1% + {\long\def\dodowithnextbox{#1}% + \afterassignment\dododowithnextbox + \setbox\nextbox} + +\def\dododowithnextbox + {\aftergroup\dodowithnextbox} + +%D So in fact we get: +%D +%D \starttyping +%D \setbox\nextbox { \aftergroup\dodowithnextbox ... } +%D \stoptyping +%D +%D or +%D +%D \starttyping +%D \setbox\nextbox { ... } \dodowithnextbox +%D \stoptyping +%D +%D A slower but more versatile implementation is: +%D +%D \starttyping +%D \long\def\dowithnextbox#1#2% +%D {\long\def\dodowithnextbox{#1}% +%D \ifx#2\normalhbox +%D \afterassignment\dododowithnextbox +%D \else\ifx#2\normalvbox +%D \afterassignment\dododowithnextbox +%D \else\ifx#2\normalvtop +%D \afterassignment\dododowithnextbox +%D \else\ifx#2\normalvcenter +%D \afterassignment\dododowithnextbox +%D \else +%D \afterassignment\dodowithnextbox +%D \fi\fi\fi\fi +%D \setbox\nextbox#2} +%D \stoptyping +%D +%D This alternative also accepts \type{\box0} and alike, but +%D we don't really need this functionality now. + +%D \macros +%D {nextboxht,nextboxwd,nextboxdp,flushnextbox} +%D +%D The next couple of shortcuts saves us memory as well as +%D \type {{}}'s in passing parameters. + +\def\nextboxht{\ht\nextbox} +\def\nextboxwd{\wd\nextbox} +\def\nextboxdp{\dp\nextbox} + +\def\flushnextbox{\box\nextbox} + +%D \macros +%D {dowithnextboxcontent} +%D +%D But, occasionally we do need to pass some local settings +%D without wanting to use additional grouping. Therefore we +%D provide: +%D +%D \starttyping +%D \dowithnextboxcontent{inside}{after}{box content} +%D \stoptyping +%D +%D {\em todo: Search source for potential usage!} + +\long\def\dowithnextboxcontent#1#2% inside, after + {\long\def\dodowithnextbox{#2}% + \def\dododowithnextbox{#1\aftergroup\dodowithnextbox}% + \afterassignment\dododowithnextbox + \setbox\nextbox} + +%D Now we can redefine \type {\dowithnextbox} as follows: +%D +%D \starttyping +%D \def\dowithnextbox{\dowithnextboxcontent\empty} +%D \stoptyping +%D +%D But since this macro is used often and since this implementation +%D is slower, we will not use that definition. + +% maybe: +% +% depending on the size of the action, about 10% faster +% +% \newtoks\nextboxtoks +% +% \def\dowithnextbox {\afterassignment\redowithnextbox\nextboxtoks} +% \def\redowithnextbox {\afterassignment\dododowithnextbox\setbox\nextbox} +% \def\dododowithnextbox{\aftergroup\dodowithnextbox} +% \def\dodowithnextbox {\the\nextboxtoks} +% +% \long\def\dowithnextboxcontent#1% #2% inside, after +% {\def\dododowithnextbox{#1\aftergroup\dodowithnextbox}% +% \afterassignment\redowithnextboxcontent\nextboxtoks} +% +% \def\redowithnextboxcontent +% {\afterassignment\dododowithnextbox\setbox\nextbox} + +%D \macros +%D {llap, rlap, tlap, blap, clap} +%D +%D Some well known friends, but we implement them our own +%D way. + +\def\rlap{\begingroup\dowithnextbox{\normalhbox to \zeropoint + {\flushnextbox\normalhss}\endgroup}\normalhbox} + +\def\llap{\begingroup\dowithnextbox{\normalhbox to \zeropoint + {\normalhss\flushnextbox}\endgroup}\normalhbox} + +\def\clap{\begingroup\dowithnextbox{\normalhbox to \zeropoint + {\normalhss\flushnextbox\normalhss}\endgroup}\normalhbox} + +\def\tlap{\begingroup\dowithnextbox{\normalvbox to \zeropoint + {\normalvss\flushnextbox}\endgroup}\normalvbox} + +\def\blap{\begingroup\dowithnextbox{\normalvbox to \zeropoint + {\flushnextbox\normalvss}\endgroup}\normalvbox} + +%D \macros +%D {beginofshapebox, +%D reshapebox, doreshapebox, +%D flushshapebox, +%D innerflushshapebox, +%D shapebox, +%D ifreshapingbox} +%D +%D The next utility macro originates from some linenumbering +%D mechanism. Due to \TEX's advanced way of typesetting +%D paragraphs, it's not easy to do things on a line||by||line +%D basis. This macro is able to reprocess a given box and can +%D act upon its vertical boxed components, such as lines. The +%D unwinding sequence in this macro is inspired by a \NTG\ +%D workshop of David Salomon in June 1992. +%D +%D First we have to grab the piece of text we want to act +%D upon. This is done by means of the duo macros: +%D +%D \starttyping +%D \beginofshapebox +%D a piece of text +%D \endofshapebox +%D \stoptyping +%D +%D When all texts is collected, we can call \type{\reshapebox} +%D and do something with it's vertical components. We can make +%D as much passes as needed. When we're done, the box can be +%D unloaded with \type{\flushshapebox}. The only condition in +%D this scheme is that \type{\reshapebox} must somehow unload +%D the \BOX\ \type{\shapebox}. +%D +%D An important aspect is that the content is unrolled +%D bottom||up. The next example illustrates this maybe +%D unexpected characteristic. +%D +%D \startbuffer +%D \beginofshapebox +%D \em \input tufte +%D \endofshapebox +%D +%D \newcounter\LineNumber +%D +%D \reshapebox +%D {\doglobal\increment\LineNumber +%D \normalhbox{\llap{\LineNumber\hskip2em}\box\shapebox}} +%D +%D \flushshapebox +%D \stopbuffer +%D +%D \typebuffer +%D +%D \getbuffer +%D +%D As we can see, when some kind of numbering is done, we have +%D to add a second pass. +%D +%D \startbuffer +%D \newcounter\LineNumber +%D \newcounter\NumberOfLines +%D +%D \reshapebox +%D {\doglobal\increment\NumberOfLines +%D \box\shapebox} +%D +%D \reshapebox +%D {\doglobal\increment\LineNumber +%D \normalhbox +%D {\llap{\LineNumber\ (\NumberOfLines)\hskip2em}% +%D \box\shapebox}% +%D \doglobal\decrement\NumberOfLines} +%D +%D \flushshapebox +%D \stopbuffer +%D +%D \typebuffer +%D +%D \getbuffer +%D +%D This example shows that the content of the box is still +%D available after flushing. Another feature is that only the +%D last reshaping counts. Multiple reshaping can be done by: +%D +%D \startbuffer +%D \beginofshapebox +%D \flushshapebox +%D \endofshapebox +%D +%D \reshapebox +%D {\doglobal\increment\LineNumber +%D \normalhbox{\llap{$\star$\hskip1em}\box\shapebox}% +%D \doglobal\decrement\NumberOfLines} +%D +%D \flushshapebox +%D \stopbuffer +%D +%D \typebuffer +%D +%D \getbuffer +%D +%D The macros are surprisingly easy to follow and in fact +%D introduce no new concepts. Nearly all books on \TEX\ show +%D similar solutions for unwinding \BOXES. +%D +%D Some macros, like footnote ones, can be sensitive for +%D reshaping, which can result in an endless loop. We +%D therefore offer: +%D +%D \starttyping +%D \ifreshapingbox +%D \stoptyping +%D +%D Some \CONTEXT\ commands are protected this way. Anyhow, +%D reshaping is aborted after 100 dead cycles. +%D +%D By the way, changing the height and depth of \BOX\ +%D \type{\shapebox} results in bad spacing. This means that +%D for instance linenumbers etc. should be given zero height +%D and depth before being lapped into the margin. The +%D previous examples ignore this side effect, but beware! + +\newif \ifsomeshapeleft +\newif \ifreshapingbox + +\newbox \shapebox +\newcount \shapepenalty +\newdimen \shapekern +\newskip \shapeskip + +\newbox \newshapebox +\newbox \oldshapebox + +\newcount \shapecounter + +\newevery \everyshapebox \relax + +\def\shapesignal{.12345678pt} % or 12345sp + +% todo: in etex lastnode + +\def\reshapebox#1% + {\doreshapebox + {#1}% + {\penalty\shapepenalty}% + {\kern \shapekern }% + {\vskip \shapeskip }} + +\newbox\tmpshapebox + +\def\doreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip + {\ifzeropt\ht\oldshapebox % \ifdim\ht\oldshapebox=\zeropoint + \setbox\newshapebox\normalvbox{}% + \else + \setbox\newshapebox\normalvbox + {\unvcopy\oldshapebox + \resetbox\newshapebox + \shapecounter\zerocount + \doloop{\dodoreshapebox{#1}{#2}{#3}{#4}}}% + \setbox\newshapebox\box\tmpshapebox + \fi} + +\def\dodoreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip + {\ifzeropt\lastskip % \ifdim\lastskip=\zeropoint\relax + \ifzeropt\lastkern % \ifdim\lastkern=\zeropoint\relax + \ifcase\lastpenalty % \ifnum\lastpenalty=\zerocount + \setbox\shapebox\lastbox + \ifvoid\shapebox + \unskip\unpenalty\unkern + \else + \ifdim\wd\shapebox=\shapesignal\relax + \exitloop + \else + \shapecounter\zerocount + \global\setbox\tmpshapebox\normalvbox{#1\unvbox\tmpshapebox}% + \fi + \fi + \else + \shapepenalty\lastpenalty + \global\setbox\tmpshapebox\normalvbox{#2\unvbox\tmpshapebox}% + \unpenalty + \fi + \else + \shapekern\lastkern + \global\setbox\tmpshapebox\normalvbox{#3\unvbox\tmpshapebox}% + \unkern + \fi + \else + \shapeskip\lastskip + \global\setbox\tmpshapebox\normalvbox{#4\unvbox\tmpshapebox}% + \unskip + \fi + \ifnum\shapecounter>100 % can be less + \message{<<forced exit from shapebox>>}% + \global\setbox\tmpshapebox\copy\oldshapebox + \exitloop + \else + \advance\shapecounter \plusone + \fi} + +\def\beginofshapebox + {\setbox\oldshapebox\normalvbox + \bgroup + \reshapingboxtrue + \the\everyshapebox + \normalhbox to \shapesignal{\strut\hss}% plus \strut + \prevdepth\strutdp} % never \nointerlineskip + +\def\endofshapebox + {\endgraf + \egroup} + +\let\beginshapebox=\beginofshapebox +\let\endshapebox =\endofshapebox + +\def\flushshapebox + {\bgroup + \ifzeropt\ht\newshapebox % \ifdim\ht\newshapebox=\zeropoint + \else + % make \prevdepth legal + % \par before the next \vskip gives far worse results + \ifdim\parskip>\zeropoint\vskip\parskip\else\par\fi + % and take a look + \ifdim\prevdepth=-\thousandpoint + \prevdepth\zeropoint + \fi + \ifdim\prevdepth<\zeropoint\relax + % something like a line or a signal or ... + \donetrue + \else\ifinner + % not watertight and not ok + \donefalse + \else\ifdim\pagegoal=\maxdimen + \donetrue + \else + % give the previous line a normal depth + \donetrue + {\forgeteverypar\verticalstrut}\nobreak + \kern-\struttotal % geen \vskip + \kern-\parskip + % \vskip-\strutdp + \fi\fi\fi + \scratchdimen\dp\newshapebox + \unvbox\newshapebox + % \prevdepth=0pt and \dp\newshapebox depend on last line + \kern-\scratchdimen % ?? + % now \prevdepth=0pt + \ifdone + \kern\strutdp + \prevdepth\strutdp + \fi + \fi + \egroup} + +%D In real inner situations we can use: +%D +%D \starttyping +%D \flushinnershapebox +%D \stoptyping +%D +%D This one is used in \type{\framed}. + +% The kern fails on for instance: +% +% \omlijnd[offset=0pt,hoogte=8mm,uitlijnen={rechts,laho}]{\bfa test} + +\def\innerflushshapebox + {\ifzeropt\ht\newshapebox \else % \ifdim\ht\newshapebox=\zeropoint\relax \else + \unvcopy\newshapebox\relax + % \kern-\dp\newshapebox\relax + \fi} + +%D For absolute control, one can use \type{\doreshapebox} +%D directly. This macro takes four arguments, that take care +%D of: +%D +%D \startitemize[n,packed] +%D \item \type{\shapebox} +%D \item \type{\shapepenalty} +%D \item \type{\shapekern} +%D \item \type{\shapeskip} +%D \stopitemize + +%D \macros +%D {shapedhbox} +%D +%D When constructing a new box, using the content of \type +%D {\shapebox}, one can best use \type {\shapedhbox} instead +%D of \type {\normalhbox}, since it manages the height and depth of +%D the line. + +% \def\shapedhbox +% {\dowithnextbox +% {\nextboxht\zeropoint +% \nextboxdp\zeropoint +% \flushnextbox} +% \normalhbox} + +\def\shapedhbox % lines with non strutted dimensions have + {\expanded{\dowithnextbox % interlineskip so if we want the original + {\nextboxht\the\ht\shapebox % spacing, we need to preserve the original + \nextboxdp\the\dp\shapebox % height and depth which is definitely + \noexpand\flushnextbox}} % needed if we apply struts to the 'new' + \normalhbox} % box or do something that changed ist size + +%D \macros +%D {hyphenatedword, +%D hyphenatedpar, +%D hyphenatedfile, +%D dohyphenateword} +%D +%D The next one is a tricky one. \PLAIN\ \TEX\ provides +%D \type{\showhyphens} for showing macros on the terminal. When +%D preparing a long list of words we decided to show the +%D hyphens, but had to find out that the \PLAIN\ alternative +%D can hardly be used and|/|or adapted to typesetting. The next +%D two macros do the job and a little more. +%D +%D The simple command \type{\hyphenatedword} accepts one +%D argument and gives the hyphenated word. This macro calls for +%D +%D \starttyping +%D \dohyphenateword {n} {pre} {word} +%D \stoptyping +%D +%D The next examples tell more than lots of words: +%D +%D \startbuffer +%D \dohyphenateword{0} {} {dohyphenatedword} +%D \dohyphenateword{1} {...} {dohyphenatedword} +%D \dohyphenateword{2} {...} {dohyphenatedword} +%D \stopbuffer +%D +%D \typebuffer +%D +%D Here, \type{\hyphenatedword{dohyphenatedword}} is the +%D shorter alternative for the first line. +%D +%D \startvoorbeeld +%D \getbuffer +%D \stopvoorbeeld +%D +%D These macros are slow but effective and not that hard to +%D program at all. + +\ifx\scantokens\undefined \let\scantokens\firstofoneargument \fi + +\def\dohyphenateword#1#2#3% + {\bgroup + \setbox\scratchbox\normalhbox + {\dontcomplain + \nopenalties % \widowpenalty \clubpenalty \brokenpenalty \doublehyphendemerits \finalhyphendemerits \adjdemerits + \hyphenpenalty \zerocount + \exhyphenpenalty\zerocount + \setbox0\normalvbox + {\hsize\zeropoint + \hskip\zeropoint % really needed + \ifnum#1<\zeropoint + \obeyspaces + \obeylines + \def\obeyedspace{\hskip\zeropoint\hbox to \onepoint{}\hskip\zeropoint}% + \let\obeyedline \obeyedspace + \ifcase-#1\or + \def\next{#3}\scantokens\expandafter{\next}% + % also ok: \scantokens{#3}% + \or + \readfile{#3}\donothing\donothing + \else + #3% + \fi + \else + #3% + \fi}% + \ifnum#1>\zerocount + \dorecurse{#1} + {\setbox2\normalhbox + {\splittopskip\openstrutheight + \vsplit0 to \baselineskip}}% + #2% + \fi + \doloop + {\setbox2\normalhbox + {\splittopskip\openstrutheight + \vsplit0 to \baselineskip}% + \setbox2\normalhbox + {\unhbox2 + \setbox2\lastbox + \normalvbox + {\unvbox2 + \setbox2\lastbox + \normalhbox{\unhbox2}}}% + \ifnum#1<\zeropoint\ifdim\wd2=\onepoint\space\else\box2\allowbreak\fi\else\box2\fi + \ifzeropt\ht0 \exitloop\fi}% % \ifdim\ht0=\zeropoint\exitloop\fi}% + \removeunwantedspaces}% + \ifnum#1>\zerocount + \ht\scratchbox\strutht + \dp\scratchbox\strutdp + \box\scratchbox + \else + \unhbox\scratchbox + \fi + \egroup} + +\def\hyphenatedword{\dohyphenateword\zerocount\empty} +\def\hyphenatedpar {\dohyphenateword\minusone \empty} +\def\hyphenatedfile{\dohyphenateword{-2}\empty} + +%D You may want to give the following call a try: +%D +%D \starttyping +%D \hyphenatedpar{\readfile{zapf}{}{}}\endgraf +%D \stoptyping + +%D \macros +%D {doboundtext} +%D +%D Sometimes there is not enough room to show the complete +%D (line of) text. In such a situation we can strip of some +%D characters by using \type{\doboundtext}. When the text is +%D wider than the given width, it's split and the third +%D argument is appended. When the text to be checked is packed +%D in a command, we'll have to use \type{\expandafter}. +%D +%D \starttyping +%D \doboundtext{a very, probably to long, text}{3cm}{...} +%D \stoptyping +%D +%D When calculating the room needed, we take the width of the +%D third argument into account, which leads to a bit more +%D complex macro than needed at first sight. + +% \def\dodoboundtext#1% +% {\setbox0=\normalhbox{\unhcopy0 #1}% +% \ifdim\wd0>\dimen0 +% \let\dodoboundtext=\gobbleoneargument +% \else +% #1\relax +% \fi} +% +% \def\doboundtext#1#2#3% +% {\normalhbox +% {\setbox0=\normalhbox{#1}% +% \dimen0=#2\relax +% \ifdim\wd0>\dimen0 +% \setbox2=\normalhbox{#3}% +% \advance\dimen0 by -\wd2 +% \setbox0=\normalhbox{}% +% \processtokens +% {\dodoboundtext} +% {\dodoboundtext} +% {} +% {\space} +% {#1}% +% \box2 +% \else +% \box0 +% \fi}} + +\def\dodoboundtext#1% + {\setbox0\normalhbox{#1}% + \advance\scratchdimen -\wd0 + \ifdim\scratchdimen>\zeropoint\relax#1\fi}% + +\def\doboundtext#1#2#3% + {\normalhbox + {\setbox\scratchbox\normalhbox{#1}% + \scratchdimen#2\relax + \ifdim\wd\scratchbox>\scratchdimen + \setbox\scratchbox\normalhbox{#3}% + \advance\scratchdimen -\wd\scratchbox + \handletokens#1\with\dodoboundtext + \fi + \box\scratchbox}} + +%D \macros +%D {limitatetext} +%D +%D A bit more beautiful alternative for the previous command is +%D the next one. This command is more robust because we let +%D \TEX\ do most of the job. The previous command works better +%D on text that cannot be hyphenated. +%D +%D \starttyping +%D \limitatetext {text} {width} {sentinel} +%D \limitatetext {text} {-width} {prelude} +%D \stoptyping +%D +%D When no width is given, the whole text comes available. The +%D sentinel is optional. This is about the third version. + +\ifx\fakecompoundhyphen\undefined \let\fakecompoundhyphen\relax \fi + +%D The simple alternative is as follows: +%D +%D \starttyping +%D \unexpanded\def\limitatetext% +%D {\bgroup % evt \setstrut +%D \forgetall +%D \fakecompoundhyphen % dangerous ! ! ! ! ! ! ! ! ! +%D \dowithnextbox\dolimitatetext\normalhbox} +%D +%D \def\dolimitatetext#1#2% +%D {\doifelsenothing{#1} +%D {\unhbox\nextbox} +%D {\widowpenalty=0 +%D \clubpenalty=0 +%D \scratchdimen=#1\relax +%D \ifdim\nextboxwd>\scratchdimen +%D \setbox\scratchbox=\normalhbox{ #2}% +%D \advance\scratchdimen by -\wd\scratchbox +%D \setbox\nextbox=\normalvbox +%D {\hsize=\scratchdimen +%D \hfuzz\maxdimen +%D \veryraggedright +%D \strut\unhcopy\nextbox}% +%D \ifdim\nextboxht>\strutht \else +%D \setbox\scratchbox\null % overfull and not split +%D \fi +%D \setbox\nextbox=\normalvbox % if omitted: missing brace reported +%D {\splittopskip=\openstrutheight +%D \setbox\nextbox=\vsplit\nextbox to \strutht +%D \unvbox\nextbox +%D \setbox\nextbox=\lastbox +%D \global\setbox1=\normalhbox +%D {\unhbox\nextbox\unskip\kern\zeropoint\box\scratchbox\unskip}}% +%D \unhbox1 +%D \else +%D \unhbox\nextbox +%D \fi}% +%D \egroup} +%D \stoptyping +%D +%D The next alternative accepts a negative width. A negative +%D value crops the beginning. The macro thereby becomes less +%D readable, which is why we kept the original here too. + +\unexpanded\def\limitatetext + {\bgroup % evt \setstrut + \forgetall % otherwise indentation and so + %\def\limitatetext##1##2##3{##1}% \def ! + \let\limitatetext\firstofthreearguments + \fakecompoundhyphen % dangerous ! ! ! ! ! ! ! ! ! + \dowithnextbox\dolimitatetext\normalhbox} + +\def\dolimitatetext#1#2% + {\doifelsenothing{#1} + {\unhbox\nextbox} + {\nopenalties + \scratchdimen#1\relax + \ifdim\scratchdimen<\zeropoint\relax % we'll take the last line + \donefalse + \scratchdimen-\scratchdimen + \else + \donetrue + \fi + \ifdim\nextboxwd>\scratchdimen + \setbox\scratchbox\normalhbox{\ifdone\space#2\else#2\space\fi}% + \advance\scratchdimen -\wd\scratchbox + \setbox0\flushnextbox + \setbox\nextbox\normalvbox + {\hsize\scratchdimen + \hfuzz\maxdimen + \veryraggedright + \strut + \ifdone \else + \parfillskip\zeropoint + \rightskip\zeropoint + \hskip\zeropoint \!!plus 1\!!fill % \hsize + \fi + \unhcopy0}% + \ifdim\nextboxht>\strutht + \setbox\nextbox\normalvbox % if omitted: missing brace reported + {\splittopskip\openstrutheight + \ifdone + \setbox\nextbox\vsplit\nextbox to \strutht + \else + \doloop + {\setbox0\vsplit\nextbox to \strutht + \ifdim\nextboxht>\strutht \else \exitloop \fi}% + \fi + \unvbox\nextbox + \setbox\nextbox\lastbox + \global\setbox1\normalhbox + {\ifdone + \unhbox\nextbox\unskip\kern\zeropoint\box\scratchbox + \else + \box\scratchbox\unhbox\nextbox + \fi + \unskip}}% + \unhbox1 + \else + \unhbox0 + \fi + \else + \unhbox\nextbox + \fi}% + \egroup} + +%D We can also limit a text with more control: +%D +%D \startbuffer +%D \limitatetext {\input tufte } {2cm,5mm} {\unknown} +%D \limitatetext {ton en hans} {2cm,5mm} {\unknown} +%D \limitatetext {ton en hans zijn eikels} {2cm,5mm} {\unknown} +%D \limitatetext {ton} {2cm,5mm} {\unknown} +%D \stopbuffer +%D +%D \typebuffer \getbuffer +%D +%D We build this feature on top of the previous macro. + +\let\normallimitatetext\limitatetext + +\def\speciallimitatetext#1#2#3#4% text left right placeholder + {%\dontleavehmode + \bgroup + %\def\speciallimitatetext##1##2##3##4{##1}% \def ! + \let\speciallimitatetext\firstoffourarguments + \setbox0\normalhbox + {\nohyphens + \normallimitatetext{#1}{+#2}{}#4% + \normallimitatetext{#1}{-#3}{}}% + \setbox2\normalhbox + {#1}% + \ifdim\wd2<\wd0 #1\else\unhbox0\fi + \egroup} + +\def\limitatetext#1#2#3% \expanded added 2003/01/16 + {\expanded{\beforesplitstring#2}\at,\to\leftlimit + \expanded{\aftersplitstring #2}\at,\to\rightlimit + \ifx\rightlimit\empty + \normallimitatetext {#1}\leftlimit {#3}% + \else + \speciallimitatetext{#1}\leftlimit\rightlimit{#3}% + \fi} + +%D Undocumented bonus (see wiki): +%D +%D \starttyping +%D \limitatefirstline{\input tufte\relax}{10cm}{\unknown} +%D \stoptyping + +\def\limitatefirstline#1#2#3% + {\hbox\bgroup\strut + \setbox\scratchbox\hbox{\begstrut#1\endstrut}% + \ifdim\wd\scratchbox>#2\relax + \setbox\scratchbox\hbox{#3}% + \hsize#2\relax + \advance\hsize-\wd\scratchbox + \setbox\scratchbox\vbox{\forgetall\veryraggedright#1}% + \setbox\scratchbox\vsplit\scratchbox to \lineheight + \vbox + {\unvbox\scratchbox + \global\setbox\plusone\lastbox + \global\setbox\plusone\hbox{\strut\unhbox\plusone}% + \hbox % to #2 + {\ifx\clip\undefined + \box\plusone + \else\ifdim\wd\plusone>\hsize + \lower\strutdepth\hbox{\clip[\c!width=\hsize,\c!height=\lineheight]{\hbox{\raise\strutdepth\box\plusone}}}% + \else + \box\plusone + \fi\fi + \removeunwantedspaces#3}}% \removeunwantedspaces\hss#3}}% + \else + #1% + \fi + \egroup} + +%D \macros +%D {processisolatedwords, +%D betweenisolatedwords,nothingbetweenisolatedwords} +%D +%D References are often made up of one word or a combination +%D of tightly connected words. The typeset text {\bf +%D chapter~5} is for instance the results of the character +%D sequence: +%D +%D \starttyping +%D The typeset text \in{chapter}[texniques] is for instance +%D \stoptyping +%D +%D When such words are made active in interactive texts, the +%D combination cannot longer be hyphenated. Normally this is no +%D problem, because \TEX\ tries to prevent hyphenation as best +%D as can. +%D +%D Sometimes however we need a few more words to make things +%D clear, like when we want to refer to {\bf \TEX\ by Topic}. +%D The macros that are responsible for typesetting hyperlinks, +%D take care of such sub||sentences by breaking them up in +%D words. Long ago we processed words using the space as a +%D separator, but the more advanced our interactive text became, +%D the more we needed a robust solution. Well, here it is and +%D it called as: +%D +%D \starttyping +%D \processisolatedwords{some words}\someaction +%D \stoptyping +%D +%D The second argument \type{someactions} handles the +%D individual words, like in: +%D +%D \startbuffer +%D \processisolatedwords{some more words} \ruledhbox \par +%D \processisolatedwords{and some $x + y = z$ math} \ruledhbox \par +%D \processisolatedwords{and a \normalhbox{$x + y = z$}} \ruledhbox \par +%D \stopbuffer +%D +%D \typebuffer +%D +%D which let the words turn up as: +%D +%D \startvoorbeeld +%D \getbuffer +%D \stopvoorbeeld +%D +%D The macro has been made a bit more clever than needed at +%D first sight. This is due to the fact that we don't want to +%D generate more overhead in terms of interactive commands than +%D needed. +%D +%D \startbuffer +%D \processisolatedwords{see this \ruledhskip1em} \ruledhbox +%D \processisolatedwords{and \ruledhskip1em this one} \ruledhbox +%D \stopbuffer +%D +%D \typebuffer +%D +%D becomes: +%D +%D \startvoorbeeld +%D \startlines +%D \getbuffer +%D \stoplines +%D \stopvoorbeeld +%D +%D Single word arguments are treated without further +%D processing. This was needed because this command is used in +%D the \type{\goto} command, to which we sometimes pass very +%D strange and|/|or complicated arguments or simply boxes +%D whose dimensions are to be left intact. +%D +%D First we build a \type{\normalhbox}. This enables us to save the +%D last skip. Next we fill a \type{\normalvbox} without hyphenating +%D words. After we've tested if there is more than one word, we +%D start processing the individual lines (words). We need some +%D splitting, packing and unpacking to get the spacing and +%D dimensions right. +%D +%D Normally the isolated words are separated by space, but +%D one can overrule this separator by changing the next macros. +%D +%D When needed, spacing can be suppressed by \type +%D {\nothingbetweenisolatedwords}. + +\newif\ifisolatedwords % public, e.g. used in core-ref + +\def\betweenisolatedwords + {\hskip\currentspaceskip} + +%D In order to prevent problems with nested isolated words, we +%D do process them, but only split at the outermost level. + +\newskip\isolatedlastskip + +\chardef\isolatedwordsmode=0 % no nesting + +\def\processisolatedwords#1#2% todo: vbox ipv hbox ivm afbreken! + {\bgroup % todo: doloop + \fakecompoundhyphen + \dontcomplain + \forgetall + \nopenalties + \ifcase\isolatedwordsmode + \def\processisolatedwords##1##2{##2{##1}}% we split only once + \fi + \global\let\localbetweenisolatedwords\betweenisolatedwords + \setbox0\normalhbox % we default to spaces, but from inside out + {\ignorespaces#1% \localbetweenisolatedwords can be overruled + \global\isolatedlastskip\lastskip}% + \setbox2\normalvbox + {%\hyphenpenalty10000 % this one fails in \url breaking, + \lefthyphenmin\maxcard % but this trick works ok, due to them + \righthyphenmin\maxcard % total>63, when no hyphenation is done + \hsize\zeropoint + \unhcopy0}% == #1 + \ifdim\ht0=\ht2 + \isolatedwordsfalse + #2{\unhbox0}% == #2{#1} % was \unhcopy0 + \else + \isolatedwordstrue + \setbox0\normalhbox + {\ignorespaces + \loop + \setbox4\normalhbox + {\splittopskip\openstrutheight + \vsplit2 to \baselineskip}% + \normalhbox + {\unhbox4\unskip % recently added + \setbox4\lastbox + \normalvbox % outer \normalhbox needed + {\unvbox4 % for nested use + \setbox4\lastbox + \normalhbox{#2{\normalhbox + {\unhbox4 + \unskip\unpenalty % remove end of line stuff + \global\dimen1\lastkern}}}}}% + \ifdim\ht2>\zeropoint\relax + \ifdim\dimen1=\compoundbreakpoint + \allowbreak + \else + \localbetweenisolatedwords + \fi + \repeat + \unskip}% + \unhbox0\unskip + \ifzeropt\isolatedlastskip\else % added % \ifdim\isolatedlastskip=\zeropoint\else % added + \hskip\isolatedlastskip + \fi + \fi + \egroup} + +%D One can use the next macro to change the intersplit +%D material. An example can be found in the \type {\url} +%D macro. The innermost setting is used. In the url case, it +%D means that either very small spaces are used or no spaces +%D at all. So, the innermost settings are used, while the +%D outermost split takes place. + +\def\setbetweenisolatedwords#1% + {\gdef\localbetweenisolatedwords{#1}} + +%D \macros +%D {sbox} +%D +%D This is a rather strange command. It grabs some box content +%D and and limits the size to the height and depth of a +%D \type{\strut}. The resulting bottom||alligned box can be used +%D aside other ones, without disturbing the normal baseline +%D distance. +%D +%D \startbuffer +%D \ruledhbox to .5\hsize{\sbox{eerste\par tweede \par derde}} +%D \stopbuffer +%D +%D \typebuffer +%D +%D Shows up as: +%D +%D \startvoorbeeld +%D \vskip3\baselineskip +%D \getbuffer +%D \stopvoorbeeld +%D +%D Before displaying the result we added some skip, otherwise +%D the first two lines would have ended up in the text. This +%D macro can be useful when building complicated menus, headers +%D and footers and|/|or margin material. + +\def\sbox% in handleiding, voorbeeld \inleft{xx} \extern.. + {\normalvbox\bgroup % new ! ! ! + \dowithnextbox + {\setbox\scratchbox\normalhbox + {\strut + \nextboxdp\zeropoint + \lower\strutdepth\flushnextbox}% + \dp\scratchbox\strutdepth + \ht\scratchbox\strutheight + \box\scratchbox + \egroup}% + \normalvbox} + +%D \macros +%D {struttedbox} +%D +%D This boxing macro limits the height and depth to those of +%D a strut. + +\def\struttedbox + {\normalhbox\bgroup % new ! ! ! + \dowithnextbox + {\nextboxdp\strutdepth + \nextboxht\strutheight + \flushnextbox + \egroup}% + \normalhbox} + +%D \macros +%D {topskippedbox} +%D +%D This macro compensates the difference between the topskip +%D and strutheight. Watch how we preserve the depth when it +%D equals strutdepth. + +\def\topskippedbox + {\normalhbox\bgroup + \dowithnextbox + {\edef\next + {\ifdim\strutdepth=\nextboxdp\nextboxdp\the\nextboxdp\fi}% + \lower\topskip\normalhbox{\raise\strutheight\flushnextbox}% + \next + \egroup}% + \normalhbox} + +%D \macros +%D {centeredbox, centerednextbox} +%D +%D Here is another strange one. This one offers a sort of overlay +%D with positive or negative offsets. This command can be used +%D in well defined areas where no offset options are available. +%D We first used it when building a button inside the margin +%D footer, where the button should have a horizontal offset and +%D should be centered with respect to the surrounding box. The +%D last of the three examples we show below says: +%D +%D \starttyping +%D \vsize=3cm +%D \hsize=3cm +%D \ruledvbox to \vsize +%D {\centeredbox height .5cm width -1cm +%D {\vrule width \hsize height \vsize}}} +%D \stoptyping +%D +%D Here the \type{\ruledvbox} just shows the surrounding box +%D and \type{\vrule} is used to show the centered box. +%D +%D \def\AnExample#1#2% +%D {\vsize=3cm +%D \hsize=3cm +%D \ruledvbox to \vsize +%D {\centeredbox height #1 width #2 +%D {\color[green]{\vrule width \hsize height \vsize}}}} +%D +%D \startlinecorrection +%D \startcombination[3*1] +%D {\AnExample {-1cm} {.5cm}} {} +%D {\AnExample {.5cm} {-1cm}} {} +%D {\AnExample {-1cm} {-.5cm}} {} +%D \stopcombination +%D \stoplinecorrection +%D +%D This command takes two optional arguments: \type{width} and +%D \type{height}. Observing readers can see that we use \TEX's +%D own scanner for grabbing these arguments: \type{#1#} reads +%D everyting till the next brace and passes it to both rules. +%D The setting of the box dimensions at the end is needed for +%D special cases. The dimensions of the surrounding box are kept +%D intact. This commands handles positive and negative +%D dimensions (which is why we need two boxes with rules). + +\def\centeredbox#1#% height +/-dimen width +/-dimen + {\bgroup + \setbox0\normalvbox to \vsize + \bgroup + \dontcomplain + \forgetall + \setbox0\normalhbox{\vrule\!!width \zeropoint#1}% + \setbox2\normalvbox{\hrule\!!height\zeropoint#1}% + \advance\vsize \ht2 + \advance\hsize \wd0 + \normalvbox to \vsize + \bgroup + \vskip-\ht2 + \vss + \normalhbox to \hsize + \bgroup + \dowithnextbox + {\hskip-\wd0 + \hss + \flushnextbox + \hss + \egroup + \vss + \egroup + \egroup + \wd0\hsize + \ht0\vsize + \box0 + \egroup} + \normalhbox} + +%D For those who don't want to deal with \type {\hsize} +%D and \type {\vsize}, we have: +%D +%D \starttyping +%D \centerednextbox width 2bp height 2bp +%D {\framed[width=100bp,height=100bp]{}} +%D \stoptyping +%D +%D Do you see what we call this one \type {next}? + +\def\centerednextbox#1#% + {\bgroup + \dowithnextbox + {\hsize\nextboxwd + \vsize\nextboxht + \centeredbox#1{\flushnextbox}% + \egroup} + \normalhbox} + +%D \macros +%D {centerbox} +%D +%D Centering on the available space is done by: +%D +%D \starttyping +%D \centerbox <optional specs> {content} +%D \stoptyping +%D +%D When omitted, the current \type {\hsize} and \type +%D {\vsize} are used. Local dimensions are supported. + +\long\def\centerbox#1#% optional height +/-dimen width +/-dimen + {\bgroup + \dowithnextbox + {\setlocalhsize + \setbox0\normalhbox{\vrule\!!width \zeropoint#1}% + \setbox2\normalvbox{\hrule\!!height\zeropoint#1}% + \ifzeropt\wd0\else\hsize\wd0\fi % \hsize\ifdim\wd0=\zeropoint\hsize\else\wd0\fi + \ifzeropt\ht2\else\vsize\ht2\fi % \vsize\ifdim\ht2=\zeropoint\vsize\else\ht2\fi + \normalvbox to \vsize{\vss\normalhbox to \hsize{\hss\flushnextbox\hss}\vss}% + \egroup}% + \normalhbox} + +%D \macros +%D {setrigidcolumnhsize,rigidcolumnbalance,rigidcolumnlines} +%D +%D These macros are copied from the \TEX book, page~397, and +%D extended by a macro that sets the \type{\hsize}. +%D +%D \starttyping +%D \setrigidcolumnhsize {total width} {distance} {n} +%D \rigidcolumnbalance {box} +%D \stoptyping +%D +%D Both these macros are for instance used in typesetting +%D footnotes. +%D +%D Men kan het proces van breken enigzins beinvloeden met de +%D volgende twee switches: + +\newif\ifalignrigidcolumns +\newif\ifstretchrigidcolumns +\newif\iftightrigidcolumns % if true: just a vbox, no depth/noflines/gridsnap corrrections + +%D De eerste switch bepaald het uitlijnen, de tweede rekt de +%D individuele kolommen op naar \type{\vsize}. + +\def\setrigidcolumnhsize#1#2#3% + {\xdef\savedrigidhsize{\the\hsize}% + \hsize#1\relax + \global\chardef\rigidcolumns#3\relax + \scratchdimen -#2\relax + \multiply\scratchdimen #3\relax + \advance\scratchdimen #2\relax + \advance\hsize \scratchdimen + \divide\hsize #3\relax} + +\newbox\rigidcolumnbox + +\let\rigidcolumnlines\!!zerocount + +\def\rigidcolumnbalance#1% + {\ifnum\rigidcolumns=1 % tzt ook h/d correctie + \ifinner\ifhmode\box\else\unvbox\fi\else\unvbox\fi#1\relax + \else + \normalvbox + {\forgetall + \nopenalties + \dontcomplain + \setbox\rigidcolumnbox\normalvbox + {\line{}\goodbreak\unvbox#1\removebottomthings}% + \splittopskip\openstrutheight + \setbox\scratchbox\vsplit\rigidcolumnbox to \zeropoint + \ifcase\rigidcolumnlines\relax + % \iffalse + % % maybe some day an option + % \scratchskip\ht\rigidcolumnbox + % \advance\scratchskip\dp\rigidcolumnbox + % \getnoflines\scratchskip + % \ifodd\noflines + % \advance\noflines\plusone + % \fi + % \divide\noflines\rigidcolumns + %\else + \scratchdimen\ht\rigidcolumnbox + \divide\scratchdimen \rigidcolumns + \getnoflines\scratchdimen + %\fi + \else + \noflines\rigidcolumnlines % to be sure + \fi + \scratchdimen\noflines\lineheight + % new: we now loop so that we don't loose content + % since in practice we also use this macro for + % funny lineheights and border cases + \setbox0=\box\rigidcolumnbox + \doloop + {\setbox\rigidcolumnbox=\copy0 + \setbox\scratchbox\normalhbox to \savedrigidhsize + {\dorecurse\rigidcolumns + {\setbox\scratchbox\vsplit\rigidcolumnbox to \scratchdimen + \dp\scratchbox\openstrutdepth + \setbox\scratchbox\normalvtop + \ifalignrigidcolumns to + \ifstretchrigidcolumns\vsize\else\scratchdimen\fi + \fi + {\unvbox\scratchbox}% + \wd\scratchbox\hsize + \box\scratchbox + \hfill}% + \hfillneg}% + \ifvoid\rigidcolumnbox\exitloop\else\advance\scratchdimen\lineheight\fi}% + \iftightrigidcolumns + \setbox\scratchbox\normalhbox{\raise\dp\scratchbox\box\scratchbox}% + \else + \advance\scratchdimen -\openstrutdepth + \setbox\scratchbox\normalhbox{\raise\scratchdimen\box\scratchbox}% + \dp\scratchbox\openstrutdepth + \ht\scratchbox\scratchdimen + \fi + \box\scratchbox}% + \fi} + +%D \macros +%D {startvboxtohbox,stopvboxtohbox,convertvboxtohbox} +%D +%D Here is another of Knuth's dirty tricks, as presented on +%D pages 398 and 399 of the \TEX book. These macros can be used +%D like: +%D +%D \starttyping +%D \normalvbox +%D \bgroup +%D \startvboxtohbox ... \stopvboxtohbox +%D \startvboxtohbox ... \stopvboxtohbox +%D \startvboxtohbox ... \stopvboxtohbox +%D \egroup +%D +%D \normalvbox +%D \bgroup +%D \converthboxtovbox +%D \egroup +%D \stoptyping +%D +%D These macros are used in reformatting footnotes, so they do +%D what they're meant for. + +\def\setvboxtohbox + {\bgroup + \ifdim\baselineskip<16pt \relax + \scratchdimen\baselineskip + \multiply\scratchdimen 1024 + \else + \message{cropping \baselineskip to 16pt}% + \scratchdimen\maxdimen + \fi + \divide\scratchdimen \hsize + \multiply\scratchdimen 64 + \xdef\normalvboxtohboxfactor{\withoutpt\the\scratchdimen}% + \egroup} + +\def\startvboxtohbox + {\bgroup + \setvboxtohbox + \setbox\scratchbox\normalhbox\bgroup} + +\def\stopvboxtohbox + {\egroup + \dp\scratchbox\zeropoint + \ht\scratchbox\normalvboxtohboxfactor\wd\scratchbox + \box\scratchbox + \egroup} + +% % to be done: start halfway a line combined with one line +% % extra to start with (skip) and one line less than counted. +% +% \def\stopvboxtohbox% +% {\egroup +% \setbox2=\normalvbox +% {\forgetall\unhcopy0\par\xdef\globalvhlines{\the\prevgraf}}% +% \setbox2=\normalvbox +% {\unvbox2 +% \setbox2=\lastbox +% \setbox2=\normalhbox{\unhbox2}% +% \xdef\globalvhwidth{\the\wd2}}% +% \decrement\globalvhlines +% \dimen0=\globalvhwidth +% \dimen0=\normalvboxtohboxfactor\dimen0 +% \advance\dimen0 by \globalvhlines\lineheight +% \dp0=\zeropoint +% \ht0=\dimen0 +% %\writestatus{guessed size} +% % {w:\the\wd0\space\space +% % b:\the\baselineskip\space +% % l:\globalvhlines\space +% % e:\globalvhwidth\space +% % h:\the\dimen0}% +% \box0 +% \egroup} + +% todo: \scratchbox + +\def\convertvboxtohbox + {\setvboxtohbox + \makehboxofhboxes + \setbox0\normalhbox{\unhbox0 \removehboxes}% + \noindent\unhbox0\par} + +\def\makehboxofhboxes + {\setbox0\normalhbox{}% + \loop % \doloop { .. \exitloop .. } + \setbox2\lastbox + \ifhbox2 + \setbox0\normalhbox{\box2\unhbox0}% + \repeat} + +\def\removehboxes + {\setbox0\lastbox + \ifhbox0 + {\removehboxes}\unhbox0 + \fi} + +%D \macros +%D {unhhbox} +%D +%D The next macro is used in typesetting inline headings. +%D Let's first look at the macro and then show an example. + +\newbox \unhhedbox +\newbox \hhbox +\newdimen \lasthhboxwidth +\newskip \hhboxindent + +\def\unhhbox#1\with#2% + {\bgroup + \nopenalties + \dontcomplain + \forgetall + \setbox\unhhedbox\normalvbox{\hskip\hhboxindent\strut\unhbox#1}% => \hsize + \doloop + {\setbox\hhbox\vsplit\unhhedbox to \lineheight + \ifvoid\unhhedbox + \setbox\hhbox\normalhbox{\strut\normalhboxofvbox\hhbox}% + \fi + \ht\hhbox\strutht + \dp\hhbox\strutdp + \ifzeropt\hhboxindent\else % \ifdim\hhboxindent=\zeropoint\else + \setbox\hhbox\normalhbox{\hskip-\hhboxindent\box\hhbox}% + \hhboxindent\zeropoint + \fi + \global\lasthhboxwidth\wd\hhbox + #2\relax + \ifvoid\unhhedbox + \exitloop + \else + \hskip\zeropoint \!!plus \zeropoint + \fi}% + \egroup} + +\def\dohboxofvbox + {\setbox0\normalvbox{\unvbox\scratchcounter\global\setbox1\lastbox}% + \unhbox1 + \egroup} + +\def\normalhboxofvbox + {\bgroup + \afterassignment\dohboxofvbox + \scratchcounter=} + +%D This macro can be used to break a paragraph apart and treat +%D each line seperately, for instance, making it clickable. The +%D main complication is that we want to be able to continue the +%D paragraph, something that's needed in the in line section +%D headers. +%D +%D \startbuffer +%D \setbox0=\normalhbox{\input tufte \relax} +%D \setbox2=\normalhbox{\input knuth \relax} +%D \unhhbox0\with{\ruledhbox{\box\hhbox}} +%D \hskip1em plus 1em minus 1em +%D \hhboxindent=\lasthhboxwidth +%D \advance\hhboxindent by \lastskip +%D \unhhbox2\with{\ruledhbox{\box\hhbox}} +%D \stopbuffer +%D +%D \getbuffer +%D +%D This piece of text was typeset by saying: +%D +%D \typebuffer +%D +%D Not that nice a definition, but effective. Note the stretch +%D we've build in the line that connects the two paragraphs. + +%D \macros +%D {doifcontent} +%D +%D When processing depends on the availability of content, one +%D can give the next macro a try. +%D +%D \starttyping +%D \doifcontent{pre content}{post content}{no content}\somebox +%D \stoptyping +%D +%D Where \type{\somebox} is either a \type{\normalhbox} or +%D \type{\normalvbox}. If the dimension of this box suggest some +%D content, the resulting box is unboxed and surrounded by the +%D first two arguments, else the third arguments is executed. + +\unexpanded\def\doifcontent#1#2#3% + {\dowithnextbox + {\ifhbox\nextbox + \ifdim\nextboxwd>\zeropoint + #1\unhbox\nextbox#2\relax + \else + #3\relax + \fi + \else + \ifdim\nextboxht>\zeropoint + #1\unvbox\nextbox#2\relax + \else + #3\relax + \fi + \fi}} + +%D So when we say: +%D +%D \startbuffer +%D \doifcontent{[}{]}{}\normalhbox{content sensitive typesetting} +%D +%D \doifcontent{}{\page}{}\normalvbox{content sensitive typesetting} +%D +%D \doifcontent{}{}{\message{Didn't you forget something?}}\normalhbox{} +%D \stopbuffer +%D +%D \typebuffer +%D +%D We get: +%D +%D \getbuffer +%D +%D Where the last call of course does not show up in this +%D document, but definitely generates a confusing message. + +%D \macros +%D {processboxes} +%D +%D The next macro gobble boxes and is for instance used for +%D overlays. First we show the general handler. + +\newbox\processbox + +\def\processboxes#1% + {\bgroup + \def\doprocessbox{#1}% #1 can be redefined halfway + \resetbox\processbox + \afterassignment\dogetprocessbox\let\next=} + +\def\endprocessboxes + {\ifhmode\unskip\fi + \box\processbox + \next + \egroup} + +\def\dogetprocessbox + {\ifx\next\bgroup + \expandafter\dodogetprocessbox + \else + \expandafter\endprocessboxes + \fi} + +\def\dodogetprocessbox + {\dowithnextbox + {\ifhmode\unskip\fi\doprocessbox % takes \nextbox makes \processbox + \afterassignment\dogetprocessbox\let\next=} + \normalhbox\bgroup} + +%D \macros +%D {startoverlay} +%D +%D We can overlay boxes by saying: +%D +%D \startbuffer +%D \startoverlay +%D {\framed{hans}} +%D {\framed[width=3cm]{ton}} +%D {\framed[height=2cm]{oeps}} +%D \stopoverlay +%D \stopbuffer +%D +%D \typebuffer +%D +%D shows up as: +%D +%D \leavevmode\getbuffer + +% \def\dooverlaybox% +% {\ifhmode\unskip\fi +% \ifdim\nextboxht>\ht\processbox +% \setbox\processbox\normalvbox to \nextboxht +% {\vss\box\processbox\vss}% +% \else +% \setbox\nextbox\normalvbox to \ht\processbox +% {\vss\flushnextbox\vss}% +% \fi +% \scratchdimen=\wd +% \ifdim\nextboxwd>\wd\processbox +% \nextbox +% \else +% \processbox +% \fi +% \setbox\processbox=\normalhbox to \scratchdimen +% {\normalhbox to \scratchdimen{\hss\box\processbox\hss}% +% \hskip-\scratchdimen +% \normalhbox to \scratchdimen{\hss\flushnextbox\hss}}} +% +% \def\startoverlay% +% {\bgroup +% \let\stopoverlay\egroup +% \processboxes\dooverlaybox} + +\def\dooverlaybox + {\ifhmode\unskip\fi + \scratchdimen\dp + \ifdim\nextboxdp>\dp\processbox + \nextbox + \else + \processbox + \fi + \ifdim\nextboxht>\ht\processbox + \setbox\processbox\normalvbox to \nextboxht + {\dp\processbox\zeropoint\vss\box\processbox\vss}% + \else + \setbox\nextbox\normalvbox to \ht\processbox + {\nextboxdp\zeropoint\vss\flushnextbox\vss}% + \fi + \nextboxdp\scratchdimen + \dp\processbox\scratchdimen + \scratchdimen\wd + \ifdim\nextboxwd>\wd\processbox + \nextbox + \else + \processbox + \fi + \setbox\processbox\normalhbox to \scratchdimen + {\normalhbox to \scratchdimen{\hss\box\processbox\hss}% + \hskip-\scratchdimen + \normalhbox to \scratchdimen{\hss\flushnextbox\hss}}} + +\def\startoverlay + {\bgroup + \let\stopoverlay\egroup + \processboxes\dooverlaybox} + +% %D \macros +% %D {starthspread} +% %D +% %D In a similar way we can build a horizontal box, spread +% %D over the available width. +% %D +% %D \startbuffer +% %D \starthspread +% %D {hans} +% %D {ton} +% %D {oeps} +% %D \stophspread +% %D +% %D \stopbuffer +% %D +% %D \typebuffer +% %D +% %D shows up as: +% %D +% %D \leavevmode\getbuffer +% +% \def\dohspread +% {\flushnextbox +% \def\dohspread{\hfil\flushnextbox}} +% +% \def\starthspread +% {\normalhbox to \hsize \bgroup +% \let\stophspread\egroup +% \processboxes\dohspread} + +%D \macros +%D {fakebox} +%D +%D The next macro is a rather silly one, but saves space. +%D +%D \starttyping +%D \normalhbox{\fakebox0} +%D \stoptyping +%D +%D returns an empty box with the dimensions of the box +%D specified, here being zero. + +\def\dofakebox + {\setbox\scratchbox\null + \wd\scratchbox\wd\scratchcounter + \ht\scratchbox\ht\scratchcounter + \dp\scratchbox\dp\scratchcounter + \ifhbox\scratchcounter\normalhbox\else\normalvbox\fi{\box\scratchbox}% + \egroup} + +\def\fakebox + {\bgroup + \afterassignment\dofakebox\scratchcounter} + +%D \macros +%D {lbox,rbox,cbox,tbox,bbox} +%D +%D Here are some convenient alternative box types: +%D +%D \starttyping +%D \lbox{text ...} +%D \cbox{text ...} +%D \rbox{text ...} +%D \stoptyping +%D +%D Are similar to \type {\normalvbox}, which means that they also +%D accept something like \type{to 3cm}, but align to the left, +%D middle and right. These box types can be used to typeset +%D paragraphs. + +\def\lbox{\makelrcbox\normalvbox\raggedleft} +\def\cbox{\makelrcbox\normalvbox\raggedcenter} +\def\rbox{\makelrcbox\normalvbox\raggedright} + +\def\ltop{\makelrcbox\normalvtop\raggedleft} +\def\ctop{\makelrcbox\normalvtop\raggedcenter} +\def\rtop{\makelrcbox\normalvtop\raggedright} + +\def\makelrcbox#1#2#3#% + {#1#3\bgroup \forgetall \let\\=\endgraf #2\let\next=} + +%D The alternatives \type {\tbox} and \type {\bbox} can be used +%D to properly align boxes, like in: +%D +%D \startbuffer +%D \starttable[|||] +%D \HL +%D \VL \tbox{\externalfigure[koe][height=3cm,frame=on]} \VL top aligned \VL\SR +%D \HL +%D \VL \bbox{\externalfigure[koe][height=3cm,frame=on]} \VL bottom aligned \VL\SR +%D \HL +%D \stoptable +%D \stopbuffer +%D +%D \typebuffer +%D +%D The positioning depends on the strut settings: +%D +%D \getbuffer + +\def\tbox{\tbbox\ht\dp} +\def\bbox{\tbbox\dp\ht} + +\def\tbbox#1#2% + {\normalhbox\bgroup + \dowithnextbox + {\scratchdimen\nextboxht + \advance\scratchdimen\nextboxdp + \advance\scratchdimen-#1\strutbox + #1\nextbox#1\strutbox + #2\nextbox\scratchdimen + \setbox\nextbox\normalhbox + {\lower\nextboxdp\flushnextbox}% + #1\nextbox#1\strutbox + #2\nextbox\scratchdimen + \flushnextbox + \egroup} + \normalhbox} + +%D \macros +%D {lhbox,mhbox,rhbox} +%D +%D A few more boxes. + +\def\lhbox{\dowithnextbox{\normalhbox to \hsize{\flushnextbox\hss }}\normalhbox} +\def\mhbox{\dowithnextbox{\normalhbox to \hsize{\hss\flushnextbox\hss}}\normalhbox} +\def\rhbox{\dowithnextbox{\normalhbox to \hsize{\hss\flushnextbox }}\normalhbox} + +\let\lefthbox =\lhbox +\let\midhbox =\mhbox +\let\righthbox=\rhbox + +%D \macros +%D {boxofsize} +%D +%D Sometimes we need to construct a box with a height or +%D width made up of several dimensions. Instead of cumbersome +%D additions, we can use: +%D +%D \starttyping +%D \boxofsize \normalvbox 10cm 3cm -5cm {the text to be typeset} +%D \stoptyping +%D +%D This example demonstrates that one can use positive and +%D negative values. Dimension registers are also accepted. + +\newdimen\sizeofbox + +\def\boxofsize#1% + {\bgroup + \sizeofbox\zeropoint + \scratchdimen\zeropoint + \def\docommando + {\advance\sizeofbox\scratchdimen + \futurelet\next\dodocommando}% + \def\dodocommando + {\ifx\next\bgroup + \expanded{\egroup#1 to \the\sizeofbox}% + \else + \@EA\afterassignment\@EA\docommando\@EA\scratchdimen + \fi}% + \docommando} + +%D Some new, still undocumented features: + +% limitatetext -> beter {text} als laatste !! +% +% \limitvbox +% \limithbox + +\def\limitatelines#1#2% size sentinel + {\dowithnextbox + {\dimen0=#1\hsize + \ifdim\nextboxwd>\dimen0 + \setbox\nextbox\normalhbox + {\advance\dimen0 -.1\hsize + \limitatetext{\unhbox\nextbox}{\dimen0}{\nobreak#2}}% + \fi + \unhbox\nextbox} + \normalhbox} + +\def\fittoptobaselinegrid % weg hier + {\dowithnextbox + {\bgroup + \par + \dimen0\nextboxht + \nextboxht\strutht + \nextboxdp\strutdp + \normalhbox{\flushnextbox} + \prevdepth\strutdp + \doloop + {\advance\dimen0 -\lineheight + \ifdim\dimen0<\zeropoint + \exitloop + \else + \nobreak + \normalhbox{\strut} + \fi} + \egroup} + \normalvbox} + +%D Some more undocumented macros (used in m-chart). + +\newif\iftraceboxplacement % \traceboxplacementtrue + +\newbox\fakedboxcursor + +\setbox\fakedboxcursor\normalhbox + {\vrule\!!width\zeropoint\!!height\zeropoint\!!depth\zeropoint} + +\def\boxcursor % overloaded in core-vis + {\iftraceboxplacement + \bgroup + \scratchdimen2pt + \setbox\scratchbox\normalhbox to \zeropoint + {\hss + \vrule + \!!width \scratchdimen + \!!height\scratchdimen + \!!depth \scratchdimen + \hss}% + \smashedbox\scratchbox + \egroup + \else + \copy\fakedboxcursor + \fi} + +\def\placedbox + {\iftraceboxplacement\ruledhbox\else\normalhbox\fi} + +\newdimen\boxoffset +\newdimen\boxhdisplacement +\newdimen\boxvdisplacement + +%\def\rightbox#1% +% {\normalhbox +% {\setbox0=\placedbox{#1}% +% \dimen0=.5\ht0\advance\dimen0 -.5\dp0 +% \boxcursor\hskip\boxoffset\lower\dimen0\box0}} + +\def\rightbox#1% + {\normalhbox + {\setbox0\placedbox{#1}% + \global\boxhdisplacement\boxoffset + \global\boxvdisplacement.5\ht0 + \global\advance\boxvdisplacement-.5\dp0 + \boxcursor\hskip\boxhdisplacement\lower\boxvdisplacement\box0}} + +%\def\leftbox#1% +% {\normalhbox +% {\setbox0=\placedbox{#1}% +% \dimen0=.5\ht0\advance\dimen0 -.5\dp0 +% \boxcursor\hskip-\wd0\hskip-\boxoffset\lower\dimen0\box0}} + +\def\leftbox#1% + {\normalhbox + {\setbox0\placedbox{#1}% + \global\boxhdisplacement-\wd0 + \global\advance\boxhdisplacement-\boxoffset + \global\boxvdisplacement.5\ht0 + \global\advance\boxvdisplacement-.5\dp0 + \boxcursor\hskip\boxhdisplacement\lower\boxvdisplacement\box0}} + +%\def\topbox#1% +% {\normalhbox +% {\setbox0=\placedbox{#1}% +% \dimen0=\boxoffset\advance\dimen0 \dp0 +% \boxcursor\hskip-.5\wd0\raise\dimen0\box0}} + +\def\topbox#1% + {\normalhbox + {\setbox0\placedbox{#1}% + \global\boxhdisplacement-.5\wd0 + \global\boxvdisplacement-\dp0 + \global\advance\boxvdisplacement-\boxoffset + \boxcursor\hskip\boxhdisplacement\raise-\boxvdisplacement\box0}} + +%\def\bottombox#1% +% {\normalhbox +% {\setbox0=\placedbox{#1}% +% \dimen0=\boxoffset\advance\dimen0 \ht0 +% \boxcursor\hskip-.5\wd0\lower\dimen0\box0}} + +\def\bottombox#1% + {\normalhbox + {\setbox0\placedbox{#1}% + \global\boxhdisplacement-.5\wd0 + \global\boxvdisplacement\ht0 + \global\advance\boxvdisplacement\boxoffset + \boxcursor\hskip\boxhdisplacement\lower\boxvdisplacement\box0}} + +%\def\lefttopbox#1% +% {\normalhbox +% {\setbox0=\placedbox{#1}% +% \dimen0=\boxoffset\advance\dimen0 \dp0 +% \advance\boxoffset\wd0 +% \boxcursor\hskip-\boxoffset\raise\dimen0\box0}} + +\def\lefttopbox#1% + {\normalhbox + {\setbox0\placedbox{#1}% + \global\boxhdisplacement-\wd0 + \global\advance\boxhdisplacement-\boxoffset + \global\boxvdisplacement-\dp0 + \global\advance\boxvdisplacement-\boxoffset + \boxcursor\hskip\boxhdisplacement\raise-\boxvdisplacement\box0}} + +%\def\righttopbox#1% +% {\normalhbox +% {\setbox0=\placedbox{#1}% +% \dimen0=\boxoffset\advance\dimen0 \dp0 +% \boxcursor\hskip\boxoffset\raise\dimen0\box0}} + +\def\righttopbox#1% + {\normalhbox + {\setbox0\placedbox{#1}% + \global\boxhdisplacement\boxoffset + \global\boxvdisplacement-\dp0 + \global\advance\boxvdisplacement-\boxoffset + \boxcursor\hskip\boxhdisplacement\raise-\boxvdisplacement\box0}} + +%\def\leftbottombox#1% +% {\normalhbox +% {\setbox0=\placedbox{#1}% +% \dimen0=\boxoffset\advance\dimen0 \ht0 +% \advance\boxoffset\wd0 +% \boxcursor\hskip-\boxoffset\lower\dimen0\box0}} + +\def\leftbottombox#1% + {\normalhbox + {\setbox0\placedbox{#1}% + \global\boxhdisplacement-\wd0 + \global\advance\boxhdisplacement-\boxoffset + \global\boxvdisplacement\ht0 + \global\advance\boxvdisplacement\boxoffset + \boxcursor\hskip\boxhdisplacement\lower\boxvdisplacement\box0}} + +%\def\rightbottombox#1% +% {\normalhbox +% {\setbox0=\placedbox{#1}% +% \dimen0=\boxoffset\advance\dimen0 \ht0 +% \boxcursor\hskip\boxoffset\lower\dimen0\box0}} + +\def\rightbottombox#1% + {\normalhbox + {\setbox0\placedbox{#1}% + \global\boxhdisplacement\boxoffset + \global\boxvdisplacement\ht0 + \global\advance\boxvdisplacement\boxoffset + \boxcursor\hskip\boxhdisplacement\lower\boxvdisplacement\box0}} + +\let\topleftbox \lefttopbox +\let\toprightbox \righttopbox +\let\bottomleftbox \leftbottombox +\let\bottomrightbox\rightbottombox + +\def\middlebox#1% + {\normalhbox{\setbox0\placedbox{#1}\boxoffset=-.5\wd0\rightbox{\box0}}} + +\def\baselinemiddlebox#1% + {\normalhbox + {\setbox0\placedbox{#1}% + \global\boxhdisplacement-.5\wd0 + \global\advance\boxhdisplacement-\boxoffset + \global\boxvdisplacement-\boxoffset + \boxcursor\hskip\boxhdisplacement\raise-\boxvdisplacement\box0}} + +\def\baselineleftbox#1% + {\normalhbox + {\setbox0\placedbox{#1}% + \global\boxhdisplacement-\wd0 + \global\advance\boxhdisplacement-\boxoffset + \global\boxvdisplacement-\boxoffset + \boxcursor\hskip\boxhdisplacement\raise-\boxvdisplacement\box0}} + +\def\baselinerightbox#1% + {\normalhbox + {\setbox0\placedbox{#1}% + \global\boxhdisplacement\boxoffset + \global\boxvdisplacement-\boxoffset + \boxcursor\hskip\boxhdisplacement\raise-\boxvdisplacement\box0}} + +%D \macros +%D {obox} +%D +%D Experimental, not yet frozen: + +\def\lrtbbox#1#2#3#4% l r t b + {\bgroup + \dowithnextboxcontent + {\advance\hsize-#1\advance\hsize-#2\advance\vsize-#3\advance\vsize-#4\relax} + {\forgetall\vbox to \vsize{\vskip#3\hbox to \hsize{\hskip#1\box\nextbox\hss}\vss}\egroup} + \vbox} + +%D \macros +%D {toplinebox} +%D +%D See core-tbl.tex for an example of its usage: + +\def\toplinebox + {\dowithnextbox + {\ifdim\nextboxdp>\strutdepth + \scratchdimen\nextboxdp + \advance\scratchdimen-\strutdepth + \getnoflines\scratchdimen + \struttedbox{\flushnextbox}% + \dorecurse\noflines\verticalstrut + \else + \flushnextbox + \fi}% + \tbox} + +%D \macros +%D {initializeboxstack,savebox,foundbox} +%D +%D At the cost of some memory, but saving box registers, we +%D have implemented a box repository. +%D +%D \starttyping +%D \initializeboxstack{one} +%D +%D \savebox{one}{a}{test a} +%D \savebox{one}{p}{test p} +%D \savebox{one}{q}{test q} +%D +%D \normalhbox{a:\foundbox{one}{a}} \par +%D \normalhbox{q:\foundbox{one}{q}} \par +%D \normalhbox{p:\foundbox{one}{p}} \par +%D \normalhbox{x:\foundbox{one}{x}} \par +%D \normalhbox{y:\foundbox{two}{a}} \par +%D \stoptyping + +% a first version +% +% \def\@@stackbox{boxstack:b:} +% \def\@@stackmax{boxstack:m:} +% \def\@@stacktag{boxstack:t:} +% +% \def\initializeboxstack#1% +% {\ifundefined{\@@stackbox#1}% +% \@EA\newbox\csname\@@stackbox#1\endcsname +% \else +% \global\setbox\csname\@@stackbox#1\endcsname\normalvbox{}% +% \fi +% % actually we should erase the old values +% \setgvalue{\@@stackmax#1}{0}} +% +% \def\savebox#1#2% stack name +% {\dowithnextbox +% {\doifdefined{\@@stackbox#1} +% {\@EA\doglobal\@EA\increment\csname\@@stackmax#1\endcsname +% \setxvalue{\@@stacktag#2}{\csname\@@stackmax#1\endcsname}% +% \global\setbox\csname\@@stackbox#1\endcsname=\normalvbox +% {\forgetall +% \setbox\scratchbox=\normalvbox{\flushnextbox} +% \ht\scratchbox=\onepoint +% \dp\scratchbox=\zeropoint +% \unvbox\csname\@@stackbox#1\endcsname +% \offinterlineskip +% \allowbreak +% \box\scratchbox}}}% +% \normalvbox} +% +% \def\foundbox#1#2% +% {\normalvbox +% {\doifdefined{\@@stackbox#1} +% {\doifdefined{\@@stacktag#2} +% {\setbox\scratchbox=\normalvbox +% {\splittopskip\zeropoint +% \setbox0=\copy\csname\@@stackbox#1\endcsname +% \dimen0=\getvalue{\@@stacktag#2}pt +% \advance\dimen0 by -\onepoint +% \setbox2=\vsplit0 to \dimen0 +% \ifdim\ht0>\onepoint +% \setbox0=\vsplit0 to \onepoint +% \fi +% \unvbox0\setbox0=\lastbox\unvbox0}% +% \unvbox\scratchbox}}}} + +\beginTEX \newbox + +\def\@@stackbox{boxstack:b:} +\def\@@stackmax{boxstack:m:} +\def\@@stacktag{boxstack:t:} +\def\@@stacklst{boxstack:l:} + +\def\initializeboxstack#1% + {\ifundefined{\@@stackbox#1}% + \@EA\newbox\csname\@@stackbox#1\endcsname + \else + \global\setbox\csname\@@stackbox#1\endcsname\normalvbox{}% + \def\docommando##1{\global\letbeundefined{\@@stacktag#1:##1}}% + \processcommacommand[\getvalue{\@@stacklst#1}]\docommando + \fi + \setgvalue{\@@stacklst#1}{}% + \setgvalue{\@@stackmax#1}{0}} + +\def\savebox#1#2% stack name + {\dowithnextbox + {\doifdefined{\@@stackbox#1} + {\@EA\doglobal\@EA\increment\csname\@@stackmax#1\endcsname + \setxvalue{\@@stacktag#1:#2}{\csname\@@stackmax#1\endcsname}% + \setxvalue{\@@stacklst#1}{\getvalue{\@@stacklst#1},#2}% + \global\setbox\csname\@@stackbox#1\endcsname\normalvbox + {\forgetall + \setbox\scratchbox\normalvbox{\flushnextbox} + \ht\scratchbox\onepoint + \dp\scratchbox\zeropoint + \unvbox\csname\@@stackbox#1\endcsname + \offinterlineskip + \allowbreak + \box\scratchbox}}}% + \normalvbox} + +\def\foundbox#1#2% + {\normalvbox + {\doifdefined{\@@stackbox#1} + {\doifdefined{\@@stacktag#1:#2} + {\setbox\scratchbox\normalvbox + {\splittopskip\zeropoint + \setbox0\copy\csname\@@stackbox#1\endcsname + \dimen0=\getvalue{\@@stacktag#1:#2}\points + \advance\dimen0 -\onepoint + \setbox2\vsplit0 to \dimen0 + \ifdim\ht0>\onepoint + \setbox0\vsplit0 to \onepoint + \fi + \unvbox0\setbox0\lastbox\unvbox0}% + \unvbox\scratchbox}}}} + +\def\doifboxelse#1#2% + {\doifdefinedelse{\@@stacktag#1:#2}} + +\endTEX + +\beginETEX \newbox + +\def\@@stackbox{@box@} +\def\@@stacklst{@xob@} + +\def\setstackbox#1#2% + {\ifcsname\@@stackbox:#1:#2\endcsname\else + \expandafter\newbox\csname\@@stackbox:#1:#2\endcsname + \fi + \global\setbox\csname\@@stackbox:#1:#2\endcsname\normalvbox} + +\def\initializeboxstack#1% + {\def\docommando##1{\setstackbox{#1}{##1}{}}% + \ifcsname\@@stacklst#1\endcsname + \processcommacommand[\getvalue{\@@stacklst#1}]\docommando + \fi + \setgvalue{\@@stacklst#1}{}} + +\def\savebox#1#2% stack name + {\setxvalue{\@@stacklst#1}{\getvalue{\@@stacklst#1},#2}% + \setstackbox{#1}{#2}} + +\def\foundbox#1#2% + {\normalvbox + {\ifcsname\@@stackbox:#1:#2\endcsname + \copy\csname\@@stackbox:#1:#2\endcsname + \fi}} + +\long\def\doifboxelse#1#2#3#4% + {\ifcsname\@@stackbox:#1:#2\endcsname + \ifvoid\csname\@@stackbox:#1:#2\endcsname#4\else#3\fi + \else + #4% + \fi} + +\endETEX + +%D \macros +%D {removedepth, obeydepth} +%D +%D While \type {\removedepth} removes the preceding depth, +%D \type {\obeydepth} makes sure we have depth. Both macros +%D leave the \type {\prevdepth} untouched. + +\def\removedepth + {\ifvmode \ifdim\prevdepth>\zeropoint \kern-\prevdepth \fi \fi} + +\def\obeydepth + {\par \removedepth \ifvmode \kern\strutdp \fi} + +\def\undepthed + {\dowithnextbox{\nextboxdp\zeropoint\flushnextbox}\hbox} + +%D \macros +%D {removebottomthings, removelastskip} +%D +%D A funny (but rather stupid) one, plus a redefinition. + +\def\removebottomthings + {\dorecurse5{\unskip\unkern\unpenalty}} + +\def\removelastskip % \ifvmode the plain tex one \fi +% {\ifvmode\ifdim\lastskip=\zeropoint\else\vskip-\lastskip\fi\fi} + {\ifvmode\ifzeropt\lastskip\else\vskip-\lastskip\fi\fi} + +%D \macros +%D {makestrutofbox} +%D +%D This macro sets the dimensions of a box to those of a +%D strut. + +\def\domakestrutofbox + {\ht\registercount\strutht + \dp\registercount\strutdp + \wd\registercount\zeropoint} + +\def\makestrutofbox + {\afterassignment\domakestrutofbox\registercount} + +%D \macros +%D {raisebox,lowerbox} +%D +%D Some more box stuff, related to positioning (under +%D construction). Nice stuff for a tips and tricks maps +%D article. +%D +%D \starttyping +%D \raisebox{100pt}\normalhbox{test} +%D \raisebox50pt\normalhbox{test} +%D \hsmash{\raisebox{100pt}\normalhbox{test}} +%D \stoptyping + +\def\doraiselowerbox#1#2% a nice trick us used to accept + {\def\next % both direct and {} dimensions + {\dowithnextbox + {\setbox\nextbox\normalhbox{#1\scratchdimen\flushnextbox}% + \nextboxht\strutht + \nextboxdp\strutdp + \flushnextbox}}% + \afterassignment\next\scratchdimen=#2} + +\def\raisebox{\doraiselowerbox\raise} +\def\lowerbox{\doraiselowerbox\raise} + +% maybe some day we need this +% +% \def\appendvbox#1% % uses \box8 +% {\bgroup +% \ifdim\prevdepth<\zeropoint +% \ifdim\pagetotal=\zeropoint +% \setbox8=\normalvtop{\unvcopy#1}% +% \hrule\c!!height\zeropoint +% \kern-\ht8 +% \box#1\relax +% \else +% \box#1\relax +% \fi +% \else +% \dimen0=\prevdepth +% \hrule\c!!height\zeropoint +% \setbox8=\normalvtop{\unvcopy#1}% +% \dimen2=\baselineskip +% \advance\dimen2 by -\dimen0 +% \advance\dimen2 by -\ht8 +% \kern\dimen2 +% \box#1\relax +% \fi +% \egroup} + +% %D Also new: +% %D +% %D \startbuffer +% %D \normbox[1cm][bba]{m} % b(efore) a(fter) v(box) s(trut) f(rame) +% %D \normbox[1cm][bba]{m} +% %D \normbox[1cm][bba]{m} +% %D \stopbuffer +% %D +% %D \typebuffer +% %D \getbuffer +% +% \def\dodonormbox#1#2#3#4#5#6#7% +% {\doifnumberelse{#1} +% {\dimen0=#1}{\setbox0=#3{#1}\dimen0=#50}% +% \doifinstringelse{f}{#2} +% {\let\next#4}{\let\next#3}% +% \next to \dimen0 +% {\counttoken b\in#2\to\!!counta\dorecurse{\!!counta}{#6}#6% +% #7\nextbox +% \counttoken a\in#2\to\!!counta\dorecurse{\!!counta}{#6}#6}} +% +% \def\donormbox[#1][#2]% +% {\bgroup +% \doifinstringelse{v}{#2} +% {\let\next\normalvbox} +% {\let\next\normalhbox}% +% \dowithnextbox +% {\ifvbox\nextbox +% \let\\=\par +% \dodonormbox{#1}{#2}\normalvbox\ruledvbox\ht\vfil\unvbox +% \else +% \let\\=\space +% \dodonormbox{#1}{#2}\normalhbox\ruledhbox\wd\hfil\unhbox +% \fi +% \egroup}% +% \next} +% +% \def\normbox +% {\dodoubleempty\donormbox} + +% vcenter in text, we kunnen vcenter overloaden + +\def\halfwaybox + {\dowithnextbox + {\nextboxdp\zeropoint + \setbox\nextbox\normalhbox{\lower.5\nextboxht\flushnextbox}% + \flushnextbox} + \normalhbox} + +%D New: + +\def\setdimentoatleast#1#2% + {\ifdim#1>\zeropoint\else#1=#2\fi} + +%D We need'm raw. + +\ifx \normalhbox \undefined \let \normalhbox = \hbox \fi +\ifx \normalvbox \undefined \let \normalvbox = \vbox \fi +\ifx \normalvtop \undefined \let \normalvtop = \vtop \fi +\ifx \normalvcenter \undefined \let \normalvcenter = \vcenter \fi + +%D And even rawer: + +\let\naturalhbox \normalhbox +\let\naturalvbox \normalvbox +\let\naturalvtop \normalvtop +\let\naturalvcenter \normalvtop + +\beginOMEGA dir + +\def\naturalhbox{\normalhbox dir TLT} +\def\naturalvbox{\normalvbox dir TLT} +%def\naturalvtop{\normalvtop dir TLT} + +\endOMEGA + +%D \macros +%D {vcenter} +%D +%D Also new: tex mode \type {\vcenter}. + +\let\verynormalvcenter \vcenter % since \vcenter can be visualized + +\def\vcenter + {\normalvbox\bgroup + \dowithnextbox{\normalhbox{$\verynormalvcenter{\flushnextbox}$}\egroup} + \normalvbox} + +% could be \everymathematics + +\prependtoks \let\vcenter\normalvcenter \to \everymath +\prependtoks \let\vcenter\normalvcenter \to \everydisplay + +%D \macros +%D {frozenhbox} +%D +%D A not so well unhboxable bxo can be made with: + +\def\frozenhbox + {\hbox\bgroup\dowithnextbox{\hbox{\hbox{\flushnextbox}}\egroup}\hbox} + +%D \macros +%D {setboxllx,setboxlly,gsetboxllx,gsetboxlly,getboxllx,getboxlly} +%D +%D A prelude to an extended \TEX: + +% it's about time to drop tex in favour of etex / TEX VERSION TO BE TESTED + +\beginTEX + + \def\setboxllx #1#2{\bgroup\scratchdimen#2\expanded{\egroup\noexpand\setevalue{b@@x\number#1}{\the\scratchdimen}}} + \def\setboxlly #1#2{\bgroup\scratchdimen#2\expanded{\egroup\noexpand\setevalue{b@@y\number#1}{\the\scratchdimen}}} + + \def\gsetboxllx#1#2{\bgroup\scratchdimen#2\setxvalue{b@@x\number#1}{\the\scratchdimen}\egroup} + \def\gsetboxlly#1#2{\bgroup\scratchdimen#2\setxvalue{b@@y\number#1}{\the\scratchdimen}\egroup} + +\endTEX + +\beginETEX + + \def\setboxllx#1#2{\setevalue{b@@x\number#1}{\the\dimexpr(#2)}} + \def\setboxlly#1#2{\setevalue{b@@y\number#1}{\the\dimexpr(#2)}} + + \def\gsetboxllx{\global\setboxllx} + \def\gsetboxlly{\global\setboxlly} + +\endETEX + +\def\getboxllx#1{\executeifdefined{b@@x\number#1}\zeropoint} +\def\getboxlly#1{\executeifdefined{b@@y\number#1}\zeropoint} + +%D \macros +%D {shownextbox} +%D +%D Handy for tracing +%D +%D \starttyping +%D \shownextbox\vbox{test} +%D \shownextbox\vbox{test\endgraf} +%D \shownextbox\vbox{test\endgraf\strut\endgraf} +%D \shownextbox\vbox{test\endgraf\thinrule} +%D \shownextbox\vbox{\setupwhitespace[big]test\endgraf\thinrule} +%D \stoptyping + +\def\shownextbox + {\dowithnextbox + {\bgroup + \showboxbreadth\maxdimen + \showboxdepth \maxdimen + \scratchcounter\interactionmode + \batchmode + \showbox\nextbox + \box\nextbox + \interactionmode\scratchcounter + \egroup}} + +\protect \endinput |