%D \module %D [ file=meta-txt, %D version=2000.07.06, %D title=\METAPOST\ Graphics, %D subtitle=Text Tricks, %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. %D In this library some handy text manipulations are defined. Some can and will be %D improved as soon as the \TEX||\METAPOST\ interface is stable. Some of the %D solutions may look weird, which is entirely my fault, since I implemented them in %D the process of getting grip on this kind of manipulations. Undoubtly better %D \METAPOST\ code is possible, but my way of learning this kind of trickery happens %D to be by \quote {trial and error} and \quote {look and feel} (as well as %D identifying tricks in Hobby's code). % textext ipv btex ... etex % we need a proper prefix here \unprotect \definesystemvariable {sh} % ShapedText .. todo: commandhandler \unexpanded\def\setupshapetexts {\dodoubleempty\getparameters[\??sh]} \setupshapetexts [\c!bodyfont=] \startMPextensions loadmodule "text" ; \stopMPextensions \ifdefined\parwidth \else \newdimen\parwidth \newdimen\parheight \newdimen\parvoffset \newdimen\parhoffset \newcount\parlines \newtoks \partoks \newbox \shapetextbox \newcount\parfirst \fi \unexpanded\def\startshapetext[#1]% {\global\newcounter\currentshapetext \global\setbox\shapetextbox\vbox\bgroup \switchtobodyfont[\@@shbodyfont]% \dontcomplain \hsize\parwidth \setuptolerance[\v!verytolerant,\v!stretch]% \scratchcounter\zerocount \scratchtoks\emptytoks \def\docommand##1% {\setbox\scratchbox\hpack{\useMPgraphic{##1}}% \global\parfirst\zerocount \getMPdata \setshapecharacteristics \advance\scratchcounter by \parlines \expandafter\appendtoks\the\partoks\to\scratchtoks}% \processcommalist[#1]\docommand \xdef\totalparlines{\the\scratchcounter}% \global\partoks\scratchtoks \parshape \the\scratchcounter \the\scratchtoks\relax \setshapecharacteristics % extra dummy \def\par{\endgraf\adaptparshape}% \everypar{\begstrut}} \unexpanded\def\stopshapetext {\endstrut \egroup \global\newcounter\currentshapetext \getshapecharacteristics} \unexpanded\def\adaptparshape {\def\docommand##1% {\ifcase\scratchcounter \expandafter\appendtoks\space##1 \to\scratchtoks \else \advance\scratchcounter\minusone \fi}% \scratchcounter\prevgraf \doglobal\decrement(\totalparlines,\scratchcounter)% \multiply\scratchcounter\plustwo \scratchtoks\emptytoks \expanded{\processseparatedlist[\the\partoks][\space]}\docommand \global\partoks\scratchtoks \parshape\totalparlines\the\partoks\relax} \unexpanded\def\getshapecharacteristics {\doglobal\increment\currentshapetext \doifelsedefined{parlines:\currentshapetext} {\getvalue{parlines:\currentshapetext}} {\global\parlines \plusone \global\parfirst \zerocount \global\parvoffset\zeropoint \global\parhoffset\zeropoint \global\parwidth \hsize \global\parheight \vsize}} \unexpanded\def\setshapecharacteristics {\doglobal\increment\currentshapetext \setxvalue{parlines:\currentshapetext}% {\global\parlines \the\parlines \global\parfirst \the\parfirst \global\parvoffset\the\parvoffset \global\parhoffset\the\parhoffset \global\parwidth \the\parwidth \global\parheight \the\parheight}} \unexpanded\def\getshapetext % option: unvbox {\vbox\bgroup \forgetall \dontcomplain \setbox\scratchbox\vbox to \parheight {\switchtobodyfont[\@@shbodyfont]% \splittopskip\strutheight \vskip\parvoffset \ifcase\parfirst\else\vskip\lineheight\fi \hskip\parhoffset \hbox{\vsplit\shapetextbox to \parlines\lineheight}}% \wd\scratchbox\parwidth \ht\scratchbox\parheight \dp\scratchbox\zeropoint \box\scratchbox \getshapecharacteristics \egroup} \doifundefined{RotFont}{\definefont[RotFont][RegularBold*default]} \unexpanded\def\getfollowtoken#1% {\hbox\bgroup \strut \ctxlua{mp.follow_text(#1)}% \egroup} \definefontfeature[mp:tp][liga=no] \startMPdefinitions def mfun_follow_draw (expr alternative) = if unknown RotPath : path RotPath ; RotPath := origin ; fi ; % if unknown RotColor : color RotColor ; RotColor := black ; fi ; if unknown TraceRot : boolean TraceRot ; TraceRot := false ; fi ; if unknown ExtraRot : numeric ExtraRot ; ExtraRot := 0 ; fi ; picture pic[] ; numeric len[] ; len[0] := 0 ; numeric n ; n := lua.mp.follow_size() ; for i=1 upto n : pic[i] := lua.mp.follow_slot(i) ; pic[i] := pic[i] shifted - llcorner pic[i] ; len[i] := len[i-1] + lua.mp.follow_width(i) ; endfor ; numeric al, at, pl, pc, wid, pos ; pair ap, ad ; al := arclength RotPath ; if al = 0 : al := len[n] + ExtraRot ; RotPath := origin -- (al,0) ; fi ; if al < len[n]: RotPath := RotPath scaled ((len[n]+ExtraRot)/al) ; al := arclength RotPath ; fi ; if alternative = 1 : pl := (al-len[n])/(if n>1 : (n-1) else : 1 fi) ; pc := 0 ; else : % centered / MP pl := 0 ; pc := arclength RotPath/2 - len[n]/2 ; fi ; if TraceRot : draw RotPath withpen pencircle scaled 1pt withcolor blue ; fi ; for i=1 upto n : % wid := abs(xpart urcorner pic[i] - xpart llcorner pic[i]) ; wid := lua.mp.follow_width(i) ; pos := len[i]-wid/2 + (i-1)*pl + pc ; at := arctime pos of RotPath ; ap := point at of RotPath ; ad := direction at of RotPath ; if mfun_trial_run : % skip (ok, somewhat inefficient as we can consider a % dedicated store and textext variant (todo) else : pic[i] := pic[i] shifted (-wid/2,0) rotated(angle(ad)) shifted ap ; draw pic[i] ; % withcolor RotColor ; if TraceRot : draw boundingbox pic[i] withpen pencircle scaled .25pt withcolor red ; draw ap withpen pencircle scaled .50pt withcolor green ; fi ; fi ; endfor ; if TraceRot : draw boundingbox currentpicture withpen pencircle scaled .25pt withcolor blue ; fi ; enddef ; \stopMPdefinitions \startluacode local context = context local nodecodes = nodes.nodecodes local kerncodes = nodes.kerncodes local visible_code = { [nodecodes.glyph] = true, [nodecodes.glue] = true, [nodecodes.hlist] = true, [nodecodes.vlist] = true, [nodecodes.rule] = true, } local kern_code = nodecodes.kern local c_userkern = kerncodes.userkern local a_fontkern = attributes.private("fontkern") local copynode = nodes.copy local freenode = nodes.free local topoints = number.topoints local mpprint = mp.print local n = nil local s = 0 function mp.follow_reset() for i=1,#n do freenode(n[i]) end n = nil s = 0 end function mp.follow_initialize(b) if not n then local head = tex.takebox(b).list if head then n = { } s = 0 head = node.flatten_discretionaries(head) local current = head while current do local id = current.id if visible_code[id] then s = s + 1 head, current, n[s] = nodes.remove(head,current) elseif id == kern_code and current.subtype == c_userkern and not current[a_fontkern] then s = s + 1 head, current, n[s] = nodes.remove(head,current) else current = current.next end end nodes.flush_list(head) end end end function mp.follow_size() mpprint(s) end function mp.follow_slot(i) mpprint('textext("\\getfollowtoken{' .. i .. '}")') end function mp.follow_text(s) context(copynode(n[s])) end function mp.follow_width(i) mpprint(topoints(n[i].width)) end \stopluacode \unexpanded\def\dofollowtokens#1#2% {\vbox\bgroup \forgetall \dontcomplain \setbox\scratchbox\hbox{\addff{mp:tp}#2}% \ctxlua{mp.follow_initialize(\number\scratchbox)}% \startMPcode \includeMPgraphic{followtokens} ; mfun_follow_draw(\number#1) ; \stopMPcode \ctxlua{mp.follow_reset()}% \egroup} \unexpanded\def\followtokens {\dofollowtokens\plusone} \unexpanded\def\followtokenscentered{\dofollowtokens\zerocount} % stretched variant: % % \followtokens % {This is just a dummy text, kerned by T{\kern % -.1667em\lower .5ex\hbox {E}}{\kern -.125emX} and typeset % in a circle using {\setMFPfont M}{\setMFPfont % E}{\setMFPfont T}{\setMFPfont A}{\setMFPfont % P}{\setMFPfont O}{\setMFPfont S}{\setMFPfont T}.\quad} % centered variant: % % \def\followtokengraphicscale#1{%% % \startuseMPgraphic {followtokens} % path RotPath; RotPath := reverse halfcircle scaled #1 ; % draw RotPath ; % setbounds currentpicture to boundingbox fullcircle scaled 12cm ; % \stopuseMPgraphic} % % \startoverlay % {\followtokengraphicscale{12cm}%% % \followtokenscentered{There was question on the list about this kind of graphics.}} % {\followtokengraphicscale{10cm}%% % \followtokenscentered{And Marco patched followingtokens to handle a centered text.}} % {\followtokengraphicscale{8cm}%% % \followtokenscentered{That ended up as variant branch in the main macro.}} % {\followtokengraphicscale{6cm}%% % \followtokenscentered{So now we have two commands.}} % \stopoverlay % \followtokengraphicscale{6cm} % \followtokens{Hans Hagen uses {\darkred\TeX}, {\darkgreen\Lua}, {\darkblue \MetaPost} and friends.} \startuseMPgraphic{fuzzycount} begingroup save height, span, drift, d, cp ; height := 3/ 5 * \baselinedistance ; span := 1/ 3 * height ; drift := 1/10 * height ; pickup pencircle scaled (1/12 * height) ; def d = (uniformdeviate drift) enddef ; for i := 1 upto \MPvar{n} : draw if (i mod 5)=0 : ((-d-4.5span,d)--(+d-0.5span,height-d)) else : ((-d,+d)--(+d,height-d)) fi shifted (span*i,d-drift) ; endfor; picture cp ; cp := currentpicture ; % for readability setbounds currentpicture to (llcorner cp shifted (0,-ypart llcorner cp) -- lrcorner cp shifted (0,-ypart lrcorner cp) -- urcorner cp -- ulcorner cp -- cycle) ; endgroup ; \stopuseMPgraphic \setupMPvariables [fuzzycount] [n=10] \unexpanded\def\fuzzycount#1% {{\tx\useMPgraphic{fuzzycount}{n=#1}}} \defineconversion[fuzzy][\fuzzycount] %%%%%%% \setupMPvariables [EnglishRule] [height=1ex, width=\the\localhsize, % without \the, problems in non e-tex color=darkgray] \defineblank [EnglishRule] [medium] \startuniqueMPgraphic{EnglishRule}{height,width,color} x1 = 0 ; x3 = \MPvar{width} ; x2 = x4 = .5x3 ; y1 = y3 = 0 ; y2 = -y4 = \MPvar{height}/2 ; fill z1..z2..z3 & z3..z4..z1 & cycle withcolor \MPvar{color} ; \stopuniqueMPgraphic \unexpanded\def\EnglishRule {\startlinecorrection[EnglishRule] \setlocalhsize \noindent \reuseMPgraphic{EnglishRule} \stoplinecorrection} %D The following macro returns a tight bound character sequence. %D %D \useMPlibrary[txt] %D %D \startlinecorrection %D \TightText{\ss\bf 123}{0cm}{3cm}{red} %D \stoplinecorrection \unexpanded\def\TightText#1#2#3#4% {\hpack {\startMPcode picture p ; p := image (graphictext "#1" withfillcolor red) ; draw p xsized #2 ysized #3 withcolor \MPcolor{#4} ; \stopMPcode}} \protect \endinput