%D \module %D [ file=m-oldfun, % was: supp-fun %D version=1995.10.10, %D title=\CONTEXT\ Support Macros, %D subtitle=Fun Stuff, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. \ifcase\contextlmtxmode\else\endinput\fi \unprotect %D Beware, these macros wil be replaced and at some point this %D module will not be preloaded any more. %D This module implements some typographics tricks that can %D be fun when designing document layouts. The examples use %D macros that are typical to \CONTEXT, but non \CONTEXT\ %D users can use the drop caps and first line treatment %D macros without problems. This module will be extended %D when the need for more of such tricks arises. \writestatus{loading}{ConTeXt Support Macros / Fun Stuff} %D \macros %D {DroppedCaps, DroppedString, DroppedIndent, DroppedLines} %D %D \startbuffer %D \DroppedCaps %D {\color[green]} {SerifBold} %D {\the\dimexpr2.2\baselineskip} {2pt} {\the\baselineskip} {2} %D Let's start %D \stopbuffer %D %D \getbuffer with dropped caps, those blown up first %D characters of a paragraph. It's hard to implement a general %D mechanism that suits all situations, but dropped caps are so %D seldomly used that we can permit ourselves a rather user %D unfriendly implementation. %D %D \typebuffer %D %D As we will see, there are 7 different settings involved. The %D first argument takes a command that is used to do whatever %D fancy things we want to do, but normally this one will be %D empty. The second argument takes the font. Because we're %D dealing with something very typographic, there is no real %D reason to adopt complicated font switching schemes, a mere %D name will do. Font encodings can bring no harm, because the %D alphanumeric characters are nearly always located at their %D natural position in the encoding vector. %D %D \startbuffer %D \DroppedCaps %D {\color[red]} {SerifBold} %D {\the\baselineskip} {0pt} {0pt} {1} %D This simple %D \stopbuffer %D %D \getbuffer case shows us what happens when we apply minimal %D values. Here we used: %D %D \typebuffer %D %D \startbuffer %D \DroppedCaps %D {\color[red]} {SerifBold} %D {\the\dimexpr2\baselineskip} {0pt} {\the\baselineskip} {2} %D Is this ugly %D \stopbuffer %D %D \getbuffer example the third argument tells %D this macro that we want a dropped capital scaled to the %D baseline distance. The two zero point arguments are the %D horizontal and vertical offsets and the last arguments %D determines the hanging indentation. In this paragraph we %D set the height to two times the baselinedistance and use %D two hanging lines: %D %D \typebuffer %D %D Here, the first character is moved down one baseline. Here %D we also see why the horizontal offset is important. The %D first example (showing the~L) sets this to a few points and %D also used a slightly larger height. %D %D Of course common users (typist) are not supposed to see this %D kind of fuzzy definitions, but fortunately \TEX\ permits us %D to hide them in macros. Using a macro also enables us to %D garantee consistency throughout the document: %D %D \startbuffer %D \def\MyDroppedCaps% %D {\DroppedCaps %D {\color[green]} {SerifBold} %D {\the\dimexpr5\baselineskip} {3pt} {\the\dimexpr3\baselineskip} {4}} %D %D \MyDroppedCaps The implementation %D \stopbuffer %D %D \typebuffer %D %D \getbuffer of the general macro is rather simple and only %D depends on the arguments given and the dimensions of the %D strut box. We explicitly load the font, which is no problem %D because \TEX\ does not load a font twice. We could have %D combined some arguments, like the height, vertical offset %D and the number of lines, but the current implementation %D proved to be the most flexible. One should be aware of the %D fact that the offsets depend on the design of the glyphs %D used. \let\DroppedIndent\!!zeropoint \def\DroppedLines{0} \def\DroppedString{ABCDEFGHIJKLMNOPQRSTUVWXYZ} \let\globaldropcaps\global % will be an option, but on by default \unexpanded\def\localdropcaps{\let\globaldropcaps\relax} \chardef\DroppedStatus = 0 % 0=done 1=starting 2=doing 3=error \chardef\DropMode = 0 % 1 == marginhang \ifx\keeplinestogether\undefined \let\keeplinestogether\gobbleoneargument \fi \unexpanded\def\DroppedCaps#1#2#3#4#5#6#7% does not yet handle accented chars {\defconvertedargument\asciia{#7}% \defconvertedcommand \asciib{\DroppedString}% \doifelseinstring\asciia\asciib {\noindentation \dontleavehmode \checkindentation % redo this one %\ifhmode\hskip-\parindent\fi % sensitive for context mechanism \keeplinestogether{#6}% \setbox0\hbox{\definedfont[#2 at #3]#1{#7}\hskip#4}% \ifdim\dp0>\strutdp % one of those Q's , will be option \setbox2\hbox{\raise\dp0\hbox{\lower\strutdp\copy0}}% \ht2\ht0 \dp0\strutdp \setbox0\box2 \fi \setbox0\hbox {\ifnum\DropMode=\plusone \hskip-\wd0\wd0\zeropoint \fi \lower#5\box0}% \ht0\strutht \dp0\strutdp \ifnum\DropMode=\plusone \globaldropcaps\let\DroppedIndent\!!zeropoint \globaldropcaps\edef\DroppedLines{\number\maxdimen}% \globaldropcaps\chardef\DroppedStatus\plusthree \else \globaldropcaps\edef\DroppedIndent{\the\wd0}% \globaldropcaps\edef\DroppedLines {\number#6}% \globaldropcaps\chardef\DroppedStatus\plustwo \globaldropcaps\hangindent\DroppedIndent \globaldropcaps\hangafter-\DroppedLines % \noindent \noindentation \checkindentation % redo this one \hskip-\DroppedIndent \fi \vbox{\forgetall\box0}% \nobreak \let\next\ignorespaces} % Could be a one character word ! {\globaldropcaps\let\DroppedIndent\!!zeropoint \globaldropcaps\edef\DroppedLines{\number\maxdimen}% \globaldropcaps\chardef\DroppedStatus\plusthree \def\next{#7}}% \let\globaldropcaps\global \next} %D Before we go to the next topic, we summarize this command: %D %D \starttyping %D \DroppedCaps %D {command} {font} %D {height} {hoffset} {voffset} {lines} %D \stoptyping %D %D Sometimes you need to make sure that the global settings are %D kept local, as in: %D % %D \startbuffer % %D \defineparagraphs[SomePar][n=2,rule=on] % %D \setupparagraphs [SomePar][1][width=.5\textwidth] % %D \setupparagraphs [SomePar][2][width=.5\textwidth] %D \startbuffer %D \defineparagraphs[SomePar][n=2,rule=on] %D \setupparagraphs [SomePar][1][width=.5\textwidth] %D \setupparagraphs [SomePar][2][width=.5\textwidth] %D %D \startSomePar %D \localdropcaps\NiceDroppedCaps{}{cmr12}{0pt}{2}Here we need %D to explicitly keep the hanging indentation local, like it or %D not. %D \SomePar %D \localdropcaps\NiceDroppedCaps{}{cmr12}{0pt}{2}Here we need %D to explicitly keep the hanging indentation local, like it or %D not. %D \stopSomePar %D \stopbuffer %D %D \typebuffer \getbuffer %D \macros %D {AutoDroppedCaps, CheckDroppedCaps} %D %D {\em To be documented.} % example usage % % \def\bpar{\ifvmode\CheckDroppedCaps\fi} % \def\epar{\ifhmode\par\fi\CheckDroppedCaps} \newcount\lastprevgraf \newcount\droppedlines \unexpanded\def\CheckDroppedCaps {\global\lastprevgraf\prevgraf} \unexpanded\def\AutoDroppedCaps % will be proper core stuff since it {\globaldropcaps\chardef\DroppedStatus\plusone \global\lastprevgraf\zerocount \global\droppedlines\zerocount \EveryPar{\doAutoDroppedCaps}} \let\AutoDroppedNext\relax \ifx\AutoDroppedCapsCommand\undefined \unexpanded\def\AutoDroppedCapsCommand{\NiceDroppedCaps{}{SerifBold}{.125em}{3}} \fi \unexpanded\def\doAutoDroppedCaps {\ifcase\DroppedStatus % done \let\next\relax \or % starting % \ifnum\lastprevgraf>0 % tricky, probably a wrong par % \globaldropcaps\chardef\DroppedStatus=3 % and inhibits dropped % \let\next\relax % caps after titles and more than once % \else % so let's nill this rubishly code fragment \let\next\AutoDroppedCapsCommand % \fi % and hope for the best \or % doing \global\advance\droppedlines \lastprevgraf \ifnum\droppedlines=\zerocount \globaldropcaps\chardef\DroppedStatus\zerocount \let\next\relax \else\ifnum\droppedlines>\zerocount \ifnum\droppedlines<\DroppedLines\relax \globaldropcaps\hangindent\DroppedIndent \globaldropcaps\hangafter-\DroppedLines \globaldropcaps\advance\hangafter \droppedlines \hskip-\parindent % brrr \let\next\AutoDroppedNext \else \globaldropcaps\chardef\DroppedStatus\zerocount \let\next\relax \fi \else \globaldropcaps\chardef\DroppedStatus\zerocount \let\next\relax \fi\fi \or % error \globaldropcaps\chardef\DroppedStatus\zerocount \let\next\relax \fi \next} %D \macros %D {LineDroppedCaps, NiceDroppedCaps} %D %D To save definitions, we also provide: %D %D \starttyping %D \LineDroppedCaps {command} {font} {hoffset} {lines} %D \NiceDroppedCaps {command} {font} {hoffset} {lines} %D \stoptyping %D %D The first command scales the font to the exact height, while %D the second command scales the font to a nice 2.5 times the %D line height, a value that gives a pleasant grayness. \unexpanded\def\DoLineDroppedCaps#1#2#3#4#5% compensation command font offset lines {\scratchcounter#5% \advance\scratchcounter \minusone \scratchdimen\scratchcounter\baselineskip \advance\scratchdimen #1% \NormalizeFontHeight\DummyFont{W}\scratchdimen{#3}% \DroppedCaps{#2}{#3}\TheNormalizedFontSize{#4} {\scratchcounter\baselineskip}{#5}} \unexpanded\def\LineDroppedCaps% command font offset lines {\DoLineDroppedCaps{\strutht}} \unexpanded\def\NiceDroppedCaps% command font offset lines {\DoLineDroppedCaps{.5\baselineskip}} %D \macros %D {TreatFirstLine} %D %D \startbuffer %D \TreatFirstLine {\sc} {} {} {} %D Instead of limiting its action to one token, the next macro %D treats the whole first line. This paragraph was typeset by %D saying: %D \stopbuffer %D %D \getbuffer %D %D \typebuffer %D %D \startbuffer %D \TreatFirstLine {\startcolor[red]\bf} {\stopcolor} {} {} %D The combined color and font effect is also possible, %D although one must be careful in using macros that accumulate %D grouping, but the commands used here are pretty save in that %D respect. %D \stopbuffer %D %D \getbuffer %D %D \typebuffer %D %D Before we explain the third and fourth argument, we show the %D implementation. Those who know a bit about the way \TEX\ %D treats tokens, will probably see in one glance that this %D alternative works all right for most text||only situations %D in which there is enough text available for the first line, %D but that more complicated things will blow. One has to live %D with that. A workaround is rather trivial but obscures the %D principles used. \unexpanded\def\TreatFirstLine#1#2#3#4% before, after, first, next {\leavevmode \bgroup \forgetall \bgroup #1% \setbox0\emptybox \setbox2\emptybox \def\grabfirstline##1 % {\setbox2\hbox {\ifvoid0 {#3{\ignorespaces##1}}% \else \unhcopy0\ {#4{##1}}% \fi}% \ifdim\wd2=\zeropoint \setbox0\emptybox \setbox2\emptybox \expandafter\grabfirstline \else\ifdim\wd2>\hsize \hbox to \hsize{\strut\unhbox0}#2\egroup \break##1\ \egroup \else \setbox0\box2 \doubleexpandafter\grabfirstline \fi\fi}% \grabfirstline} %D \startbuffer %D \gdef\FunnyCommand %D {\getrandomfloat\FunnyR{0}{1}% %D \getrandomfloat\FunnyG{0}{1}% %D \getrandomfloat\FunnyB{0}{1}% %D \definecolor[FunnyColor][r=\FunnyR,g=\FunnyG,b=\FunnyB]% %D \color[FunnyColor]} %D %D %\TreatFirstLine {\bf} {} {\FunnyCommand} {\FunnyCommand} %D The third and fourth argument can be used to gain special %D effects on the individual words. Of course one needs ... %D \stopbuffer %D %D \getbuffer %D to know a bit more about the macro package used to get real %D nice effects, but this example probably demonstrates the %D principles well. %D %D \typebuffer %D %D Like in dropped caps case, one can hide such treatments in a %D macro, like: %D %D \starttyping %D \def\MyTreatFirstLine% %D {\TreatFirstLine{\bf}{}{\FunnyCommand}{\FunnyCommand}} %D \stoptyping %D \macros %D {reshapebox} %D %D \startbuffer %D \beginofshapebox %D When using \CONTEXT, one can also apply this funny command %D to whole lines by using the reshape mechanism. Describing %D this interesting mechanism falls outside the scope of this %D module, so we only show the trick. This is an example of %D low level \CONTEXT\ functionality: it's all there, and it's %D stable, but not entirely meant for novice users. %D \endofshapebox %D %D \reshapebox{\FunnyCommand{\box\shapebox}} \flushshapebox %D \stopbuffer %D %D \getbuffer %D %D \typebuffer %D %D This mechanism permits hyphenation and therefore gives %D better results than the previously discussed macro %D \type{\TreatFirstLine}. %D \macros %D {TreatFirstCharacter} %D %D \startbuffer %D \TreatFirstCharacter{\bf\color[green]} Just to be %D \stopbuffer %D %D \getbuffer complete we also offer a very simple one %D character alternative, that is not that hard to understand: \unexpanded\def\TreatFirstCharacter#1#2% command, character {{#1{#2}}} %D A previous paragraph started with: %D %D \typebuffer %D \macros %D {StackCharacters} %D %D The next hack deals with vertical stacking. \unexpanded\def\StackCharacters#1#2#3#4% sequence vsize vskip command {\vbox #2 {\forgetall \baselineskip\zeropoint \def\StackCharacter##1{#4{##1}\cr\noalign{#3}}% \halign {\hss##\hss&##\cr \handletokens#1\with\StackCharacter\cr}}} %D \startbuffer %D \StackCharacters{CONTEXT}{}{\vskip.2ex}{\FunnyCommand} %D \stopbuffer %D %D Such a stack looks like: %D %D \startlinecorrection %D \hbox to \hsize %D {$\hss\bfd %D \vcenter{\StackCharacters{TEX} {}{\vskip.2ex}{\FunnyCommand}}% %D \hss %D \vcenter{\StackCharacters{CON} {}{\vskip.2ex}{\FunnyCommand}} %D \hss %D \vcenter{\StackCharacters{TEXT} {}{\vskip.2ex}{\FunnyCommand}} %D \hss %D \vcenter{\StackCharacters{CONTEXT}{}{\vskip.2ex}{\FunnyCommand}} %D \hss$} %D \stoplinecorrection %D %D and is typeset by saying: %D %D \typebuffer %D %D An alternative would have been %D %D \starttyping %D \StackCharacters {CONTEXT} {to 5cm} {\vfill} {\FunnyCommand} %D \stoptyping %D \macros %D {processtokens} %D %D At a lower level horizontal and vertical manipulations are %D already supported by: %D %D \starttyping %D \processtokens {begin} {between} {end} {space} {text} %D \stoptyping %D %D \startbuffer[a] %D \processtokens %D {\hbox to .5\hsize\bgroup} {\hfill} %D {\egroup} {\space} {LET'S HAVE} %D \stopbuffer %D %D \startbuffer[b] %D \processtokens %D {\vbox\bgroup\raggedcenter\hsize1em} %D {\vskip.25ex} {\egroup} {\strut} {FUN} %D \stopbuffer %D %D This macro is able to typeset: %D %D \leavevmode\hbox to \hsize %D {$\hfil\hfil %D \vcenter{\bf\getbuffer[a]}% %D \hfil %D \vcenter{\bfd\getbuffer[b]}% %D \hfil\hfil$} %D %D which was specified as: %D %D \typebuffer[a] %D \typebuffer[b] %D \macros %D {NormalizeFontHeight, NormalizeFontWidth, %D TheNormalizedFontSize} %D %D Next we introduce some font manipulation macros. When we %D want to typeset some text spread in a well defined area, it %D can be considered bad practice to manipulate character and %D word spacing. In such situations the next few macros can be %D of help: %D %D \starttyping %D \NormalizeFontHeight \name {sample text} {height} {font} %D \NormalizeFontWidth \name {sample text} {width} {font} %D \stoptyping %D %D These are implemented using an auxilliary macro: \unexpanded\def\NormalizeFontHeight{\NormalizeFontSize\ht} \unexpanded\def\NormalizeFontWidth {\NormalizeFontSize\wd} \unexpanded\def\NormalizeFontSize#1#2#3#4#5% {\bgroup \dimen0=#4% #4 can be \ht0 or so \setbox0\hbox{\definedfont[#5 at 5pt]#3}% 10pt \ifdim\wd0>\zeropoint \dimen2=#10 % #1 is \wd or \ht \dimen4=\maxdimen % 10000pt \divide\dimen4 \dimen2 \divide\dimen0 1638 % 1000 \dimen0=\number\dimen4\dimen0 \divide \dimen0 \plustwo % ... \xdef\TheNormalizedFontSize{\the\dimen0}% \else \dimen0\bodyfontsize \fi \normalexpanded{\egroup\def\noexpand#2{\definedfont[#5 at \the\dimen0]}}} %D Afterwards, we have access to the calculated size by: \let\TheNormalizedFontSize\!!zeropoint %D Extra: \unexpanded\def\WidthSpanningText#1#2#3% text width font {\hbox{\NormalizeFontWidth\temp{#1}{#2}{#3}\temp\the\everydefinedfont#1}} %D Consider for instance: %D %D \startbuffer %D \NormalizeFontHeight \tmp {X} {2\baselineskip} {cmr10} %D %D {\tmp To Be Or Not To Be} %D \stopbuffer %D %D \typebuffer %D %D This shows up as (we also show the baselines): %D %D {\showbaselines\getbuffer} %D %D The horizontal counterpart is: %D %D \startbuffer %D \NormalizeFontWidth \tmp {This Line Fits} {\hsize} {cmr10} %D %D \hbox{\tmp This Line Fits} %D \stopbuffer %D %D \typebuffer %D %D The calculated font scale is avaliable in the macro %D \type{\NormalizedFontSize}. %D %D \startlinecorrection %D \ruledhbox{\getbuffer} %D \stoplinecorrection %D %D One can of course combine these macros with the ones %D described earlier, like in: %D %D \starttyping %D \NormalizeFontHeight {text} \DroppedFont {2\baselineskip} {cmbx12} %D %D \def\NicelyDroppedCaps %D {\DroppedCaps %D {\color[green]} %D {\DroppedFont} %D {2pt} %D {\baselineskip} %D {2}} %D \stoptyping %D %D It's up to the reader to test this one. \unexpanded\def\FirstNCharacters#1#2% \FirstNCharacters{3}{fr{\"o}beln} {\bgroup \scratchcounter\zerocount \def\docommand##1% {\ifnum\scratchcounter=#1\else ##1\relax % catches ##1 = \"e and alike \advance\scratchcounter\plusone \fi} \handletokens#2\with\docommand \egroup} %D \macros %D {FittingText} %D %D First used in Pascal (demo-bbv): %D %D \startbuffer %D \ruledvbox{\FittingText{3cm}{1cm}{Serif}{24pt}{1pt}{1} %D {\veryraggedright %D \hangindent1em\hangafter1\relax %D \begstrut \dorecurse{8}{Bram Marta }\unskip \endstrut}} %D %D \ruledvbox{\FittingText{3cm}{1cm}{Serif}{24pt}{1pt}{1} %D {\raggedleft\begstrut Bram\\Marta \unskip\endstrut}} %D \stopbuffer %D %D \typebuffer %D %D \startlinecorrection %D \getbuffer %D \stoplinecorrection % #1 width #2 height #3 font #4 size #5 step #6 interlinie #7 text \unexpanded\def\FittingText#1#2#3#4#5#6#7% {\bgroup \forgetall \dontcomplain \setuptolerance[\v!verytolerant]% == \tolerance4500 \hsize#1% \enforced\def\\{\softbreak}% \!!heighta#4% \!!heightb#2% \doloop {\ifdim\!!heighta>\onepoint \expanded{\definefont[\s!dummy][#3 at \the\!!heighta][\c!interlinespace=#6]}% \getvalue\s!dummy \setbox\scratchbox\vbox{#7\endgraf}% \ifdim\ht\scratchbox>\!!heightb \advance\!!heighta-#5% \else \beginshapebox \unvcopy\scratchbox \endshapebox \global\dimen1\hsize \reshapebox {\setbox\shapebox\hbox{\unhbox\shapebox}% \ifdim\wd\shapebox>\dimen1 \global\dimen1\wd\shapebox \fi}% \ifdim\dimen1>\hsize \advance\!!heighta-#5% \else \exitloop \fi \fi \else \exitloop \fi}% %\writestatus{\strippedcsname\FittingText}{height: \the\!!heighta}% \unvbox\scratchbox \egroup} % \font width gap font spec text \unexpanded\def\NormalizeFontWidthSpread#1#2#3#4#5#6% {\global\setfalse\NFSpread \scratchdimen#3% \scratchdimen-.5\scratchdimen \advance\scratchdimen#2\relax \NormalizeFontWidth #1% {\enforced\def\+{\global\settrue\NFSpread\gobbleuntil\relax}% \enforced\def\\{\gobbleuntil\relax}% newline \setupspacing #6\relax}% {\scratchdimen}% {#4}% \ifconditional\NFSpread % de gap valt in de binding \else \definefont[\strippedcsname#1][#4 #5]% \fi} \unexpanded\def\SpreadGapText#1#2% {{\def\+{\kern#1}#2}} \unexpanded\def\GapText#1#2#3#4#5% width distance font spec title {\bgroup \NormalizeFontWidthSpread\DummyFont{#1}{#2}{#3}{#4}{#5}% \DummyFont\setupspacing\SpreadGapText{#2}{#5}\endgraf \egroup} \protect \endinput