%D \module %D [ file=core-pos, %D version=1999.08.01, %D title=\CONTEXT\ Core Macros, %D subtitle=Positioning Support, %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. % needs a cleanup, things may change % shorter tags, ..:achtergrond:.. etc in pos actions % dubbele text- * pos's eruit % class pos -> als gelijk aan vorige, dan niet niet definieren % en erven, maw: % % 1 -> opslaan % 2 -> undef, dus == prev % 3 -> undef, dus == prev % 4 -> opslaan \writestatus{loading}{Context Positioning Support} % todo: topskip als optie voor eerste regel achtergrond % todo: build pos layers on top of layers % todo: positionlayer pos van text-1 etc delen %D Although \TEX\ has a rather powerful channel to the outside %D world, called \type {\special}, real communication with %D other programs is complicated by the fact that no positional %D information is available. Mid 1999, I discussed this with %D \THANH, the author of \PDFTEX, and after some experiments, %D \PDFTEX\ was extended with a simple but effective mechanism, %D that provided positional information. The interesting %D thought is that, although \TEX\ is frozen, similar %D functionality could have been achieved with \type %D {\specials} and an additional \DVI\ postprocessor. %D %D Since we want to be as compatible as can be, \CONTEXT\ will %D support both methods, although the development is primarily %D driven by the \PDFTEX\ way of doing things. Since the %D mechanism is basically not limited to one application, for %D the moment we stick to building the functionality around one %D \CONTEXT\ special command, but at the same time we keep our %D eyes open for extensions in other directions. %D %D A question that may arise when one reads this module, is to %D what extend these macros are generic, in the sense that they %D could be collected in a support module instead of a core %D module. Since the mechanism described here will closely %D cooperate with the \METAPOST\ support built in \CONTEXT, %D which in turn will be tightly integrated with the \CONTEXT\ %D overlay mechanisms, I decided to write a core module instead %D of a support one. This makes even more sense, when one takes %D into account that this kind of support depends on special %D drivers. \unprotect %D The first application of positional information was embedded %D graphics. Since we are interacting with text, it made sense %D to take the current line height and depth into account too. %D This is why we have two basic position macros: one for %D simple positions, and one for boxes. %D %D We could have sticked to one special, and actually did so in %D earlier experiments, but for convenience, as well for %D clearness, we now have two alternatives. This approach will %D save us quite some bytes when storing large quantities of %D positional information. We save as less information as %D needed, that is, we save no dimensions, in a \METAPOST\ %D friendly way. %D %D The three specials involved are: %D %D \starttyping %D \dosetposition {identifier} %D \dosetpositionwhd {identifier} {width} {height} {depth} %D \dosetpositionplus {identifier} {width} {height} {depth} {list} %D \dosetpositionpapersize {width} {height} %D \stoptyping %D %D Either directly, when using \PDFTEX, or by means of a %D postprocessor, when using \DVI\ output, these end up in the %D utility file as: %D %D \starttyping %D \pospxy {identifier} {page} {x} {y} %D \pospxywhd {identifier} {page} {x} {y} {w} {h} {d} %D \pospxylist {identifier} {page} {x} {y} {w} {h} {d} {list} %D \stoptyping %D %D This means that we have to provide both a utility set and %D reset macro for positions. \def\POSprefix{POS::} \def\pxypos {\pospxy} % obsolete \def\pxyposwhd {\pospxywhd} % obsolete \def\pxyposplus{\pospxyplus} % obsolete \def\resetpositions {\let\pospxy \gobblefourarguments \let\pospxywhd \gobblesevenarguments \let\pospxyplus\gobbleeightarguments} \def\setpositions {\let\pospxy \setpospxy \let\pospxywhd \setpospxywhd \let\pospxyplus\setpospxyplus} \addutilityreset{positions} %D This is real tricky! The page anchor is applied to the %D page box and therefore flushed first. So, when present, it %D is applied to all positions except itself. \chardef\positionanchormode=0 % don't relocate page origin \chardef\positionanchormode=1 % relocate page origin once \def\pageanchor{page:0} % todo: change with each page size change \def\registerpageposition#1% this one is flushed first ! {\ifpositioning\ifcase\realpageno\or \ifdim\printpaperheight=\paperheight\else \ifdim\printpaperwidth=\paperwidth\else \setbox#1\hbox{\hpos\pageanchor{\box#1}}% \fi \fi \fi\fi} \def\setpospxy#1#2#3#4% {\dosetpositionnm\@@posp{#2}% \dosetpositionxy\@@posx{#3}\MPx \dosetpositionxy\@@posy{#4}\MPy \@EA\xdef\csname\POSprefix#1\endcsname{\@@posp,\@@posx,\@@posy}} \def\setpospxywhd#1#2#3#4#5#6#7% {\dosetpositionnm\@@posp{#2}% \dosetpositionxy\@@posx{#3}\MPx \dosetpositionxy\@@posy{#4}\MPy \dosetpositionpt\@@posw{#5}% \dosetpositionpt\@@posh{#6}% \dosetpositionpt\@@posd{#7}% \@EA\xdef\csname\POSprefix#1\endcsname{\@@posp,\@@posx,\@@posy,\@@posw,\@@posh,\@@posd}} \def\setpospxyplus#1#2#3#4#5#6#7#8% {\dosetpositionnm\@@posp{#2}% \dosetpositionxy\@@posx{#3}\MPx \dosetpositionxy\@@posy{#4}\MPy \dosetpositionpt\@@posw{#5}% \dosetpositionpt\@@posh{#6}% \dosetpositionpt\@@posd{#7}% \@EA\xdef\csname\POSprefix#1\endcsname{\@@posp,\@@posx,\@@posy,\@@posw,\@@posh,\@@posd,#8}} %D Sometimes we want to trick the position handler a bit: \def\replacepospxywhd#1#2#3#4#5#6#7% {\begingroup \nosetpositionnm\@@posp{#2}% \nosetpositionpt\@@posx{#3}% \nosetpositionpt\@@posy{#4}% \nosetpositionpt\@@posw{#5}% \nosetpositionpt\@@posh{#6}% \nosetpositionpt\@@posd{#7}% \@EA\xdef\csname\POSprefix#1\endcsname{\@@posp,\@@posx,\@@posy,\@@posw,\@@posh,\@@posd}% \endgroup} % slower, as many tokens, etc: % % \def\replacepospxywhd#1#2#3#4#5#6#7% % {\begingroup % \let\dosetpositionnm\nosetpositionnm % \let\dosetpositionpt\nosetpositionpt % \let\dosetpositionxy\nosetpositionpt % \setpospxywhd{#1}{#2}{#3}{#4}{#5}{#6}{#7}% % \endgroup} %D We need to initialize. \resetpositions %D For postprocessing purposes, we save the number of %D positions. \newcounter\currentpositions % current number of positions \newcounter\totalnofpositions % total from previous run \appendtoks \savecurrentvalue\totalnofpositions\currentpositions \to \everybye %D The next switch can be used to communicate a special %D situation. Positioning and associated actions can be %D executed any time. However, in for instance backgrounds %D they can be collected in a layer, for instance the text %D layer (especially the hidden text layer). In the case of %D floats, we run into problems, since the page information is %D not applicable when the content floats indeed. In such %D situations one can treat positions and graphics local. \newif\iflocalpositioning %D Watch out: sometimes a pagebreak occurs inside a float %D placement, so there we need to disable local mode. \appendtoks \localpositioningtrue \to \everyinsidefloat \appendtoks \localpositioningfalse \to \everypagebody %D We save positionional information without dimensions, which %D saves some bytes. The conversion too saves some bytes, but %D is primarily needed because we want to pass those values to %D \METAPOST\ too. \def\dosetpositionpt#1#2% {\scratchdimen\number#2\scaledpoint \xdef#1{\withoutpt\the\scratchdimen}} \def\dosetpositionnm#1#2% {\xdef#1{\number#2}} \def\dosetpositionxy#1#2#3% todo: scaled points {\scratchdimen\number#2\scaledpoint \ifcase\positionanchormode\or \advance\scratchdimen-#3\pageanchor \fi \xdef#1{\withoutpt\the\scratchdimen}} \def\nosetpositionnm#1#2{\xdef#1{\number#2}} \def\nosetpositionpt#1#2{\scratchdimen#2\xdef#1{\withoutpt\the\scratchdimen}} \beginETEX \dimexpr \def\dosetpositionpt#1#2{\xdef#1{\withoutpt\the\dimexpr(\number#2\scaledpoint)}} \def\nosetpositionpt#1#2{\xdef#1{\withoutpt\the\dimexpr(#2)}} \endETEX \def\checkpositions {\startnointerference \protectlabels \doutilities{positions}\jobname\empty\relax\relax \global\let\checkpositions\relax \stopnointerference} %D Since the positional values are to be fully expandable, we %D need to preload them as soon as possible, which is why we %D load the data when we start a text. \appendtoks \checkpositions \to \everystarttext %D Positions are either generated at a delayed write time %D (in \PDFTEX), or derived from the dvi file. The actual %D method is implemented in a special driver. If needed, the %D driver can fall back on the following macros. \def\dolazysaveposition#1#2#3#4% tag page x y {\expanded{\writeutilitycommand{\noexpand\pospxy {#1}{#2}{#3}{#4}}}} \def\dolazysavepositionwhd#1#2#3#4#5#6#7% tag page x y w h d {\expanded{\writeutilitycommand{\noexpand\pospxywhd {#1}{#2}{#3}{#4}{#5}{#6}{#7}}}} \def\dolazysavepositionplus#1#2#3#4#5#6#7#8% tag page x y w h d list {\expanded{\writeutilitycommand{\noexpand\pospxyplus {#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}}}} \def\dosaveposition#1#2#3#4% tag page x y {\expanded{\immediatewriteutilitycommand{\noexpand\pospxy {#1}{#2}{#3}{#4}}}} \def\dosavepositionwhd#1#2#3#4#5#6#7% tag page x y w h d {\expanded{\immediatewriteutilitycommand{\noexpand\pospxywhd {#1}{#2}{#3}{#4}{#5}{#6}{#7}}}} \def\dosavepositionplus#1#2#3#4#5#6#7#8% tag page x y w h d list {\expanded{\immediatewriteutilitycommand{\noexpand\pospxyplus {#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}}}} %D \macros %D {MPp, MPx, MPy, MPw, MPh, MPd, %D MPxy, MPll, MPlr, MPur, MPul, MPpos} %D %D Access to the positional information is provided by macros %D with short names that are clearly meant for \METAPOST. \def\MPp {\doMPxyhdwlr\doMPp } \def\MPx {\doMPxyhdwlr\doMPx } \def\MPy {\doMPxyhdwlr\doMPy } \def\MPw {\doMPxyhdwlr\doMPw } \def\MPh {\doMPxyhdwlr\doMPh } \def\MPd {\doMPxyhdwlr\doMPd } \def\MPxy {\doMPxyhdwlr\doMPxy } \def\MPll {\doMPxyhdwlr\doMPll } \def\MPlr {\doMPxyhdwlr\doMPlr } \def\MPur {\doMPxyhdwlr\doMPur } \def\MPul {\doMPxyhdwlr\doMPul } \def\MPpos{\doMPxyhdwlr\doMPpos} %D So \type {\MPx{identifier}} returns a position, specified %D in points. When unknown, \type {0pt} is returned. From the %D next definitions, we can see that some positions are %D expressions. \def\doMPp #1,#2,#3,#4,#5,#6,#7\relax{#1} \def\doMPx #1,#2,#3,#4,#5,#6,#7\relax{#2\s!pt} \def\doMPy #1,#2,#3,#4,#5,#6,#7\relax{#3\s!pt} \def\doMPw #1,#2,#3,#4,#5,#6,#7\relax{#4\s!pt} \def\doMPh #1,#2,#3,#4,#5,#6,#7\relax{#5\s!pt} \def\doMPd #1,#2,#3,#4,#5,#6,#7\relax{#6\s!pt} \def\doMPxy #1,#2,#3,#4,#5,#6,#7\relax{(#2\s!pt,#3\s!pt)} \def\doMPll #1,#2,#3,#4,#5,#6,#7\relax{(#2\s!pt,#3\s!pt-#6\s!pt)} \def\doMPlr #1,#2,#3,#4,#5,#6,#7\relax{(#2\s!pt+#4\s!pt,#3\s!pt-#6\s!pt)} \def\doMPur #1,#2,#3,#4,#5,#6,#7\relax{(#2\s!pt+#4\s!pt,#3\s!pt+#5\s!pt)} \def\doMPul #1,#2,#3,#4,#5,#6,#7\relax{(#2\s!pt,#3\s!pt+#5\s!pt)} \def\doMPpos#1,#2,#3,#4,#5,#6,#7\relax{#1,#2\s!pt,#3\s!pt,#4\s!pt,#5\s!pt,#6\s!pt} %D As said, we will default to zero (dimensions) when a %D position is unknown. \def\doMPxyhdwlr#1#2% {\ifundefined{\POSprefix#2}% #10,0,0,0,0,0,0\relax \else \@EA\@EA\@EA#1\csname\POSprefix#2\endcsname,0,0,0,0\relax \fi} \beginETEX \def\doMPxyhdwlr#1#2% evt kan \s!unknown leeg zijn {\@EA\@EA\@EA#1\csname\POSprefix \ifcsname\POSprefix#2\endcsname#2\else\s!unknown\fi\endcsname ,0,0,0,0\relax} \setvalue{\POSprefix\s!unknown}{0,0,0} \endETEX %D \macros %D {MPplus, MPrest, MPv, MPvv} %D %D Since we will probably keep on extending, we provide a %D general extension macro. The plus alternative takes an %D extra argument, denoting what additional parameter to pick %D up. So, the third extra is fetched with, %D %D \starttyping %D \MPplus{identifier}{3}{default} %D \stoptyping %D %D All extras (comma separated) are fetched with: %D %D \starttyping %D \MPrest{identifier} %D \stoptyping %D %D The extra parameters are not treated. \def\MPplus {\MPdoplus\doMPplus} \let\MPv \MPplus \def\MPrest#1{\MPdoplus\doMPrest{#1}{}} \let\MPvv\MPrest \def\MPdoplus#1#2#3#4% {\ifundefined{\POSprefix#2}#4\else \@EA\@EA\@EA#1\csname\POSprefix#2\endcsname,,,,,,,,,\relax{#3}% \fi} % \beginETEX % % \def\MPdoplus#1#2#3#4% % {\ifcsname\POSprefix#2\endcsname % \@EA\@EA\@EA#1\csname\POSprefix#2\endcsname,,,,,,,,,\relax{#3}% % \else % #4% % \fi} % % \endETEX \def\doMPplus#1,#2,#3,#4,#5,#6,% {\dodoMPplus} \def\dodoMPplus#1,#2,#3,#4,#5,#6,#7,#8\relax#9% {\ifcase#9\or#1\or#2\or#3\or#4\or#5\or#6\or#7\else \dododoMPplus#8\relax{#9}\fi} \def\dododoMPplus#1,#2,#3,#4,#5,#6,#7,#8\relax#9% {\ifcase#9\or \or \or \or \or \or \or \or #1\or#2\or#3\or#4\or#5\or#6\or#7\fi} \def\doMPrest#1,#2,#3,#4,#5,#6,#7,,#8\relax#9% {#7} % We can now remap the normal whd onto this. %D \macros %D {MPanchor} %D %D For readability we define a few synonyms: \let\MPanchor\MPpos %D \macros %D {POSp, POSx, POSy, POSh, POSd, POSw} %D %D and: \let\POSp\MPp \let\POSx\MPx \let\POSy\MPy \let\POSh\MPh \let\POSd\MPd \let\POSw\MPw \newbox\positionbox \newif\ifpositioning %D There are two low level positioning macros. Both store the %D position as well as execute an action associated with that %D position. \def\initializenextposition {\ifpositioning \else \global\positioningtrue \dosetpositionpapersize {\number\printpaperwidth}% {\number\printpaperheight }% \fi \doglobal\increment\currentpositions} % \def\setposition#1% % {\initializenextposition % \dosetposition{#1}% % \dopositionaction{#1}} % % \def\setpositionbox#1% % {\dowithnextbox % {\hbox to \nextboxwd % {\initializenextposition % \def\currentposition{#1}% % \dosetpositionwhd \currentposition % {\number\nextboxwd}% % {\number\nextboxht}% % {\number\nextboxdp}% % \traceposstring\llap\green{\currentposition>}% % \setbox\positionbox\flushnextbox % \dopositionaction\currentposition % \box\positionbox % \hss}}} % % \def\setpositionplus#1#2% % {\dowithnextbox % {\hbox to \nextboxwd % {\initializenextposition % \def\currentposition{#1}% % \dosetpositionplus \currentposition % {\number\nextboxwd}% % {\number\nextboxht}% % {\number\nextboxdp}% % {#2}% % \traceposstring\rlap\magenta{<\currentposition}% % \setbox\positionbox\flushnextbox % \dopositionaction\currentposition % \box\positionbox % \hss}}} \def\setpositiononly#1% {\iftrialtypesetting % nothing \else \initializenextposition \def\currentposition{#1}% \dosetposition\currentposition \fi} \def\setposition#1% {\iftrialtypesetting % nothing \else \initializenextposition \def\currentposition{#1}% \dosetposition\currentposition \traceposstring\llap\green{\currentposition>}% \dopositionaction\currentposition \fi} \def\setpositiondata#1#2#3#4% {\iftrialtypesetting \else \initializenextposition \hbox {\def\currentposition{#1}% \dosetpositionwhd\currentposition {\number#2}% {\number#3}% {\number#4}% \traceposstring\llap\green{\currentposition>}% \dopositionaction\currentposition \hss}% \fi} \def\setpositionbox#1% {\dowithnextbox {\iftrialtypesetting \flushnextbox \else \initializenextposition \hbox to \nextboxwd {\edef\currentposition{#1}% \dosetpositionwhd\currentposition {\number\nextboxwd}% {\number\nextboxht}% {\number\nextboxdp}% \traceposstring\llap\green{\currentposition>}% \setbox\positionbox\flushnextbox \dopositionaction\currentposition \box\positionbox \hss}% \fi}} \def\setpositiondataplus#1#2#3#4#5% {\iftrialtypesetting \else \initializenextposition \hbox to \nextboxwd {\edef\currentposition{#1}% \dosetpositionplus\currentposition {\number#2}% {\number#3}% {\number#4}% {#5}% \traceposstring\rlap\magenta{<\currentposition}% \dopositionaction\currentposition \hss}% \fi} \def\setpositionplus#1#2% {\dowithnextbox {\iftrialtypesetting \flushnextbox \else \initializenextposition \hbox to \nextboxwd {\edef\currentposition{#1}% \dosetpositionplus\currentposition {\number\nextboxwd}% {\number\nextboxht}% {\number\nextboxdp}% {#2}% \traceposstring\rlap\magenta{<\currentposition}% \setbox\positionbox\flushnextbox \dopositionaction\currentposition \box\positionbox \hss}% \fi}} \let\currentposition\s!unknown %D A few more low level macros take care of defining and %D recalling actions. We could save this information in the %D position containers themselves, this would save hash %D entries, but at the cost of much more time consuming %D expansion. Actions are saved globally! \newtoks\everypositionaction \let\POSactionprefix\POSprefix \def\dosetpositionaction#1% {\setgvalue{\POSactionprefix#1::}} %D The lists can become quite long (also because there can %D be lots of parameters passed on) so we provide a hook %D to clean up the list afterwards. \let\cleanuppositionaction\gobbleoneargument %D The next one will be overloaded later. %D %D \starttyping %D \def\dopositionaction#1% test saves hash entry in etex %D {\ifundefined{\POSactionprefix#1::}\else %D \ifnum\MPp{#1}>\zerocount % new %D \setbox\scratchbox\hbox \bgroup %D \traceposstring\clap\red{<#1>}% %D \the\everyinsertpositionaction %D \the\everypositionaction %D \ifcollectMPpositiongraphics %D % can save a lot of run time %D \pushMPdrawing %D \MPshiftdrawingtrue %D \resetMPdrawing %D \getvalue{\POSactionprefix#1::}% %D \ifMPdrawingdone %D \getMPdrawing %D \fi %D \resetMPdrawing %D \popMPdrawing %D \else %D \getvalue{\POSactionprefix#1::}% %D \fi %D \cleanuppositionaction{#1}% %D \egroup %D \smashedbox\scratchbox %D \else %D % shouldn't happen too often %D \traceposstring\clap\cyan{<#1>}% %D \fi %D \fi} %D \stoptyping \def\doifpositionaction#1% {\ifundefined{\POSactionprefix#1::}% \@EA\gobbleoneargument \else \@EA\firstofoneargument \fi} \def\doifpositionactionelse#1% {\ifundefined{\POSactionprefix#1::}% \@EA\secondoftwoarguments \else \@EA\firstoftwoarguments \fi} %D We can copy a position with: %D %D \starttyping %D \copyposition {to} {from} %D \stoptyping %D %D Again, this is a global action. \def\copyposition#1#2% {\bgroup %\edef\to {\POSprefix#1}% \edef\from{\POSprefix#2}% \ifundefined\from\else % \global\@EA\@EA\@EA\let\@EA\csname\@EA\to\@EA\endcsname\csname\from\endcsname \global\@EA\let\csname\POSprefix#1\@EA\endcsname\csname\from\endcsname \fi \egroup} %D The fact that handling positions is a two pass operation, is %D one of the reasons why we need to be able to test for %D existence, using: %D %D \starttyping %D \doifpositionelse {identifier} {found action} {not found action} %D \stoptyping % \def\doifpositionelse#1% % {\doifdefinedelse{\POSprefix#1}} \def\doifpositionelse#1% {\ifundefined{\POSprefix#1}% \expandafter\secondoftwoarguments \else \expandafter\firstoftwoarguments \fi} %D We have now arrived at a few macros that would make sense as %D support macros, but ended up in the core. %D \macros %D {xypos} %D %D We have several macros available to save positions. Later %D we will see applications. %D %D \starttabulate[|l|l||] %D \NC \type {\xypos} \NC \NC simple position with no dimensions \NC \NR %D \NC \type {\hpos} \NC \NC position and characteristics of a \type {\hbox} \NC \NR %D \NC \type {\vpos} \NC \NC position and characteristics of a \type {\vbox} \NC \NR %D \NC \type {\bpos} \NC b: \NC begin point in a line \NC \NR %D \NC \type {\epos} \NC e: \NC end point in a line \NC \NR %D \NC \type {\fpos} \NC f: \NC begin point in a paragraph \NC \NR %D \NC \type {\tpos} \NC t: \NC end point in a paragraph \NC \NR %D \stoptabulate %D %D Each macro takes an identifier as argument, and the \type %D {\hpos} and \type {\vpos} also expect box content. % \def\xypos{\initializenextposition\dosetposition} \let\xypos\setpositiononly \def\hpos#1{\dontleavehmode\setpositionbox{#1}\hbox} \def\vpos#1{\setpositionbox{#1}\vbox} \def\bpos#1{\hpos{b:#1}{\strut}\ignorespaces} \def\epos#1{\removelastspace\hpos{e:#1}{\strut}} \def\fpos#1% {\setpositionplus{b:#1}\parposcounter\horizontalstrut \ignorespaces} \def\tpos#1% {\removelastspace \setpositionplus{e:#1}\parposcounter\horizontalstrut} \def\ffpos#1% {\setpositionplus{b:#1}\parposcounter\horizontalstrut\wpos{#1}% \ignorespaces} \def\ttpos#1% {\removelastspace \setpositionplus{e:#1}\parposcounter\horizontalstrut} \def\wpos#1% {\dontleavehmode\vadjust % may disappear if buried {\setbox0\hbox{\raise\strutdp\hbox{\rawwpos{#1}}}% \rlap{\smashedbox0}}} \def\wwpos#1% \hsmashed{\llap{\rawwpos{#1}}} {\rlap {\setbox0\hbox{\rawwpos{#1}}% \smashedbox0}} \def\rawwpos#1% {\hpos{w:#1} {\strut \hskip-\leftskip \hskip\hsize \hskip-\rightskip}} % the next macro disables par positions (in inner boxes) and % only registers the width \def\setinnerparpositions {\let\fpos\ffpos \let\tpos\ttpos \let\wpos\wwpos} % example of usage: (see for application "techniek") % % \appendtoks % \setinnerparpositions % \to \everytabulate %D When we want to calculate more complex backgrounds, we %D need to know what the current indentation scheme is. At %D the cost of many positions and memory, we can keep track %D of them. This mechanism is activated automatically %D based on information collected in the previous pass. \newcounter\parposcounter \newif\ifpositioningpar \def\efficientdimen#1% {\the#1} % \ifdim#1=\zeropoint\string\!!zeropoint\else\the#1\fi} % we can check for used entries, and if not, then not add one \def\registerparoptions {\ifpositioningpar \ifpositioning \iftrialtypesetting \else \ifinpagebody \else \ifmmode \else \ifinformula \else \ifprocessingverbatim \iflinepar \doregisterparoptions \fi \else \doregisterparoptions \fi \fi \fi \fi \fi \fi \fi} \chardef\parposstrut=1 % 0 => no strut data, so fall backs used \def\doregisterparoptions {\doglobal\increment\parposcounter \begingroup \leftskip 1\leftskip \rightskip1\rightskip \setpositiondataplus {p:\parposcounter}% % identifier {\zeropoint}% {\strutht}% {\strutdp}% {\efficientdimen\hsize ,% 1 \efficientdimen\leftskip ,% 2 \efficientdimen\rightskip ,% 3 \efficientdimen\hangindent,% 4 \the\hangafter ,% 5 \efficientdimen\parindent }% 6 %\normalhbox{\registerparsymbol}% \registerparsymbol \endgroup} \newif\iftracepositions \def\traceposstring#1#2#3% {\iftracepositions\smashedhbox{#1{\infofont#2#3}}\fi} \def\registerparsymbol {\iftracepositions \smashedhbox to \zeropoint {\hss \blue \llap{\infofont\number\parposcounter}% \scratchdimen\onepoint \vrule \!!width 4\scratchdimen \!!height2\scratchdimen \!!depth 2\scratchdimen \hss}% \fi} % \appendtoks \registerparoptions \to \everypar %D \macros %D {doifoverlappingelse} %D %D A first application of positional information, is to %D determine if two boxes do overlap: %D %D \starttyping %D \doifoverlappingelse{point a}{point b} %D {action when overlapping} %D {action when not overlapping} %D \stoptyping % \def\doifoverlappingelse#1#2#3#4% % {\relax\ifnum\MPp{#1}=\MPp{#2}\relax % \bgroup % \donefalse % \def\check##1##2% % {\ifdone\else % \ifdim\dimen1##1<\dimen0 \else \ifdim\dimen1##1>\dimen2 \else % \ifdim\dimen1##2<\dimen4 \else \ifdim\dimen1##2>\dimen6 \else % \donetrue % \fi\fi % \fi\fi % \fi}% % \dimen 0=\MPx{#1}% % \dimen 2=\MPx{#1}\advance\dimen 2 \MPw{#1}% % \dimen 4=\MPy{#1}\advance\dimen 4 -\MPd{#1}% % \dimen 6=\MPy{#1}\advance\dimen 6 \MPh{#1}% % \dimen10=\MPx{#2}% % \dimen12=\MPx{#2}\advance\dimen12 \MPw{#2}% % \dimen14=\MPy{#2}\advance\dimen14 -\MPd{#2}% % \dimen16=\MPy{#2}\advance\dimen16 \MPh{#2}% % %\message{\the\dimen 0-\the\dimen 2,\the\dimen 4-\the\dimen 6}\wait % %\message{\the\dimen10-\the\dimen12,\the\dimen14-\the\dimen16}\wait % \check04\check24\check26\check06\ifdone\egroup#3\else\egroup#4\fi % \else % #4% % \fi} % \newdimen\overlappingmargin \overlappingmargin\zeropoint % % \overlappingmargin-2sp % better \def\overlappingmargin{-2\scaledpoint} \def\doifoverlappingelse#1#2% {\begingroup \donefalse \edef\!!stringa{#1}\edef\!!stringb{#2}% \ifnum\MPp\!!stringa=\MPp\!!stringb\relax \!!dimena\MPx\!!stringa \!!dimenb\MPx\!!stringa\advance\!!dimenb \MPw\!!stringa \!!dimenc\MPy\!!stringa\advance\!!dimenc-\MPd\!!stringa \!!dimend\MPy\!!stringa\advance\!!dimend \MPh\!!stringa \!!dimene\MPx\!!stringb \!!dimenf\MPx\!!stringb\advance\!!dimenf \MPw\!!stringb \!!dimeng\MPy\!!stringb\advance\!!dimeng-\MPd\!!stringb \!!dimenh\MPy\!!stringb\advance\!!dimenh \MPh\!!stringb \ifdim\overlappingmargin=\zeropoint\else \advance\!!dimena-\overlappingmargin \advance\!!dimenb+\overlappingmargin \advance\!!dimenc-\overlappingmargin \advance\!!dimend+\overlappingmargin \advance\!!dimene-\overlappingmargin \advance\!!dimenf+\overlappingmargin \advance\!!dimeng-\overlappingmargin \advance\!!dimenh+\overlappingmargin \fi % more often eh fb eg fg \def\checkone##1##2% {\ifdim##1<\!!dimena \else \ifdim##1>\!!dimenb \else \ifdim##2<\!!dimenc \else \ifdim##2>\!!dimend \else \donetrue \fi\fi \fi\fi}% \def\checktwo##1##2% {\ifdim##1<\!!dimene \else \ifdim##1>\!!dimenf \else \ifdim##2<\!!dimeng \else \ifdim##2>\!!dimenh \else \donetrue \fi\fi \fi\fi}% \checkone\!!dimene\!!dimeng \ifdone \else \checkone\!!dimene\!!dimenh \ifdone \else \checkone\!!dimenf\!!dimeng \ifdone \else \checkone\!!dimenf\!!dimenh \ifdone \else \checktwo\!!dimena\!!dimenc \ifdone \else \checktwo\!!dimena\!!dimend \ifdone \else \checktwo\!!dimenb\!!dimene \ifdone \else \checktwo\!!dimenb\!!dimenc \fi \fi \fi \fi \fi \fi \fi \fi \ifdone \endgroup\expandafter\firstoftwoarguments \else \endgroup\expandafter\secondoftwoarguments \fi} %D \macros %D {doifpositionsonsamepageelse, %D doifpositionsonthispageelse} %D %D Instead of letting the user handle fuzzy expansion, we %D provide a simple test on positione being on the same page. %D %D \starttyping %D \doifpositionsonsamepageelse{point a}{point b} %D {action when on same page} %D {action when not on same page} %D \doifpositionsonthispageelse{point a}{point b} %D {action when on this page} %D {action when not on this page} %D \stoptyping \def\dodoifpositionsonsamepageelse#1#2#3#4% {\bgroup \scratchcounter#1\donefalse \def\docommando##1% {\ifcase\scratchcounter \scratchcounter\MPp{##1}\donetrue \else \ifnum\scratchcounter=\MPp{##1}\relax\else\donefalse\fi \fi}% \rawprocesscommalist[#2]\docommando \ifdone\egroup#3\else\egroup#4\fi} \def\doifpositionsonsamepageelse% {\dodoifpositionsonsamepageelse{0}} \def\doifpositionsonthispageelse#1#2#3% {\dodoifpositionsonsamepageelse\realfolio} %D Before we come to graphics support, we have to make sure of %D the reference point on the page. The next macro does so and %D is hooked into the page building routine. % in the future, the depth of tail will reflect page depth \def\textanchor{text:\realfolio} % \def\placepositionanchors % todo : depth pagebox % {\ifpositioning % \setbox\scratchbox\vbox to \teksthoogte % {\topskipcorrection % \hbox{\strut\dopositionaction\headanchor}% % \vfill % \hbox{\strut\dopositionaction\tailanchor}}% % \dp\scratchbox\zeropoint % \wd\scratchbox\zetbreedte % not \zeropoint, else wrong text backgrounds % \hpos\textanchor{\box\scratchbox}% % \else % \vskip\teksthoogte % \fi} \def\placepositionanchors % todo : depth pagebox {\ifpositioning \setbox\scratchbox\vbox to \textheight {\simpletopskipcorrection \hbox{\strut\dopositionaction\headanchor}% \vfill \hbox{\strut\dopositionaction\tailanchor}}% \dp\scratchbox\zeropoint \wd\scratchbox\makeupwidth % not \zeropoint, else wrong text backgrounds \hpos\textanchor{\box\scratchbox}% \else \vskip\textheight \fi} %D The first version of this module implemented head and tail %D anchors. Currently we stick to just one anchor and derive %D the head and tail anchors from this one. \def\headanchor{head:\realfolio} % virtual position \def\tailanchor{tail:\realfolio} % virtual position \def\presetpositionanchors% compatibility hack (still needed?) {\ifpositioning \dopresetpositionanchors \fi} % \def\dopresetpositionanchors % {\bgroup % \dimen0=\ifdim\topskip>\strutht\topskip\else\strutht\fi % \dimen2=\MPy\textanchor % \dimen4=\dimen2 % \advance\dimen2 \MPh\textanchor % space is essential % \advance\dimen2 -\dimen0 % \advance\dimen4 \strutdp % \dimen6=\MPx\textanchor % \dimen8=\MPw\textanchor % \setxvalue{\POSprefix\headanchor}% % {\realfolio,\withoutpt\the\dimen6,\withoutpt\the\dimen2,% % \withoutpt\the\dimen8,\withoutpt\the\dimen0,\withoutpt\the\strutdp}% % \setxvalue{\POSprefix\tailanchor}% % {\realfolio,\withoutpt\the\dimen6,\withoutpt\the\dimen4,% % \withoutpt\the\dimen8,\withoutpt\the\strutht,\withoutpt\the\strutdp}% % %\showanchor\textanchor\showanchor\headanchor\showanchor\tailanchor\wait % \egroup} \def\dopresetpositionanchors {\bgroup \!!dimena\ifdim\topskip>\strutht\topskip\else\strutht\fi \!!dimenb\MPy\textanchor \!!dimenc\!!dimenb \advance\!!dimenb \MPh\textanchor % space is essential \advance\!!dimenb -\!!dimena \advance\!!dimenc \strutdp \!!dimend\MPx\textanchor \!!dimene\MPw\textanchor \setxvalue{\POSprefix\headanchor}% {\realfolio,\withoutpt\the\!!dimend,\withoutpt\the\!!dimenb,% \withoutpt\the\!!dimene,\withoutpt\the\!!dimena,\withoutpt\the\strutdp}% \setxvalue{\POSprefix\tailanchor}% {\realfolio,\withoutpt\the\!!dimend,\withoutpt\the\!!dimenc,% \withoutpt\the\!!dimene,\withoutpt\the\strutht,\withoutpt\the\strutdp}% %\showanchor\textanchor\showanchor\headanchor\showanchor\tailanchor\wait \egroup} \def\showanchor#1% {\expanded{\writestatus{#1} {\MPp{#1}\string|\MPx{#1}\string|\MPy{#1}\string|% \MPw{#1}\string|\MPh{#1}\string|\MPd{#1}}}} %D We set these anchors before and after each page. \appendtoks \presetpositionanchors \to \beforeeverypage \appendtoks \presetpositionanchors \to \aftereverypage %D \macros %D {positionoverlay,startpositionoverlay} %D %D As long as we're dealing with graphics it makes much sense %D to use the available overlay mechanism. For this purpose, we %D define some dedicated overlay extensions. %D %D \startbuffer[sample] %D \defineoverlay [sample] [\positionoverlay{sample}] %D %D \startpositionoverlay{sample} %D \setMPpositiongraphic{A-1}{connectcenter}{from=A-1,to=A-2} %D \stoppositionoverlay %D \stopbuffer %D %D \typebuffer[sample] %D %D \startbuffer[graphic] %D \startMPpositiongraphic{connectcenter} %D path pa, pb ; pair ca, cb ; %D initialize_box(\MPpos{\MPvar{from}}) ; pa := pxy ; ca := cxy ; %D initialize_box(\MPpos{\MPvar{to}}) ; pb := pxy ; cb := cxy ; %D draw pa withcolor red ; %D draw pb withcolor red ; %D draw ca -- cb withcolor blue ; %D anchor_box(\MPanchor{\MPvar{from}}) ; %D \stopMPpositiongraphic %D \stopbuffer %D %D We can best demonstrate this in an example, say: %D %D \startbuffer[text] %D \framed %D [backgroundachtergrond=sample,align=middle,width=7cm] %D {We want to connect \hpos {A-1} {this} word with its %D grammatical cousin \hpos {A-2} {that}.} %D \stopbuffer %D %D \typebuffer[text] %D %D \startlinecorrection %D %\getbuffer[graphic,sample,text] %D \stoplinecorrection %D %D The graphic is defined in the following way, using some %D macros defined in an auxiliary \METAPOST\ module that is %D preloaded. %D %D \typebuffer[graphic] \def\MPanchoridentifier{mpa} % {mp-anchor} \def\MPoverlayposprefix{MO::} % obsolete and wrong anyway % % \long\def\defineMPpositiongraphic#1% % {\long\setvalue{\MPoverlayposprefix#1}} %D The rest of the definitions concerning such overlays may %D look complicated, \let\currentpositionoverlay\empty %D Position actions are automatically executed when a position %D is set. % \def\positionoverlay#1% % {\ifpositioning % \vbox to \overlayheight % {\edef\MPanchor##1{\MPpos{#1::\MPanchoridentifier:\realfolio}}% % \the\everyinsertpositionaction % \copyposition{#1::\MPanchoridentifier}{#1::\MPanchoridentifier:\realfolio}% % \hpos % {#1::\MPanchoridentifier:\realfolio} % {\hbox to \overlaywidth{\dopositionaction{#1::\MPanchoridentifier}\hss}}% % \vfill}% % \fi} \let\MPanchornumber\realfolio % \def\positionoverlay#1% % {\ifpositioning % \vbox to \overlayheight % {\edef\MPanchorid{#1::\MPanchoridentifier:\MPanchornumber}% % \edef\MPanchor##1{\MPpos{\MPanchorid}}% % \the\everyinsertpositionaction % \copyposition{#1::\MPanchoridentifier}{#1::\MPanchoridentifier:\MPanchornumber}% % \hpos % {#1::\MPanchoridentifier:\MPanchornumber} % {\hbox to \overlaywidth{\dopositionaction{#1::\MPanchoridentifier}\hss}}% % \vfill}% % \fi} % \def\positionoverlay#1% the test prevents too many redundant positions % {\ifpositioning % in (not used) text* position layers % \vbox to \overlayheight % {\doifpositionactionelse{#1::\MPanchoridentifier}% % {\edef\MPanchorid{#1::\MPanchoridentifier:\MPanchornumber}% % \edef\MPanchor##1{\MPpos{\MPanchorid}}% % \the\everyinsertpositionaction % \copyposition{#1::\MPanchoridentifier}{#1::\MPanchoridentifier:\MPanchornumber}% % \hpos % {#1::\MPanchoridentifier:\MPanchornumber}% % {\hbox to \overlaywidth{\dopositionaction{#1::\MPanchoridentifier}\hss}}}% % {\hbox to \overlaywidth{\hss}}% % \vfill}% % \fi} \def\positionoverlay#1% the test prevents too many redundant positions {\ifpositioning % in (not used) text* position layers \vbox to \overlayheight {\doifpositionactionelse{#1::\MPanchoridentifier}% {\edef\MPanchorid{#1::\MPanchoridentifier:\MPanchornumber}% \edef\MPanchor##1{\MPpos{\MPanchorid}}% \the\everyinsertpositionaction \copyposition{#1::\MPanchoridentifier}{#1::\MPanchoridentifier:\MPanchornumber}% \hpos {#1::\MPanchoridentifier:\MPanchornumber}% % this is ok %{\hbox to \overlaywidth{\dopositionaction{#1::\MPanchoridentifier}\hss}}}% % but this one prevents cyclic runs due to % rounding errors {\setbox\scratchbox\hbox to \overlaywidth {\dopositionaction{#1::\MPanchoridentifier}\hss}% \ht\scratchbox\overlayheight \dp\scratchbox\zeropoint \box\scratchbox}}% {\hbox to \overlaywidth{\hss}}% \vfill}% \fi} \def\startpositionoverlay#1% {\iftrialtypesetting % we don't want redundant entries in the list \@EA\gobbleuntil\@EA\stoppositionoverlay \else \def\currentpositionoverlay{#1}% \fi} \def\stoppositionoverlay {\let\currentpositionoverlay\empty} \def\resetpositionoverlay#1% {\dosetpositionaction{#1::\MPanchoridentifier::}{}} %D Here the complication has to do with collecting actions %D for later execution. This collection is especially handy %D when we want to move actions to a specific layer. %D Such series of actions are stored in a macro (the one %D with the funny \type {++}) which is cleaned up after each %D invocation. \newtoks\everycleanpositionaction \newtoks\everyinsertpositionaction %\def\cleanuppositionaction#1% % {\doifdefined{\POSactionprefix#1++} % {\the\everycleanpositionaction % \setxvalue{\POSactionprefix#1++}{\getvalue{\POSactionprefix#1++}}}} %\def\cleanuppositionaction#1% % {\ifundefined{\POSactionprefix#1++}\else % \the\everycleanpositionaction % \setxvalue{\POSactionprefix#1++}{\getvalue{\POSactionprefix#1++}}% % \fi} \def\cleanuppositionaction#1% not in trialtypesetting {\ifundefined{\POSactionprefix#1++}\else \the\everycleanpositionaction \iflocalpositioning \letgvalue{\POSactionprefix#1++}\empty \else \setxvalue{\POSactionprefix#1++}{\getvalue{\POSactionprefix#1++}}% \fi \fi} \def\handlepositionaction#1\with#2\on#3% {\bgroup \ifx\currentpositionoverlay\empty \edef\!!stringa{#3}% no layer, just pos itself as anchor \else \edef\!!stringa{\currentpositionoverlay::\MPanchoridentifier}% \fi \edef\!!stringc{\POSactionprefix\!!stringa++}% \expanded{\dosetpositionaction{\!!stringa}{\noexpand\getvalue{\!!stringc}}}% \global\let#1\relax \edef\!!stringb{\executeifdefined\!!stringc\empty}% \setxvalue\!!stringc{\!!stringb#1#2}% \egroup} %D The indirectness enables us redefine macros for special %D purposes, like a cleanup. \def\handlepositionboxes#1#2#3% {\handlepositionaction\dohandlepositionboxes\with{#1}{#2}{#3}\on{#2}} \def\doinsertpositionboxes#1#2#3% pos tag setups {\ifnum\MPp{#1}=\realpageno\relax % \doifdefined{\MPoverlayposprefix#1} % {\getvalue{\MPoverlayposprefix#1}{#1}{#2}{#3}}% \executeifdefined{\MPoverlayposprefix#1}% \gobblethreearguments{#1}{#2}{#3}% \fi} \appendtoks \let\dohandlepositionboxes\doinsertpositionboxes % was handle ? \to \everyinsertpositionaction \def\docleanpositionboxes#1#2#3% pos tag setups {\ifnum\MPp{#1}<\realpageno \else \noexpand \dohandlepositionboxes{#1}{#2}{#3}% reinsert \fi} \appendtoks \let\dohandlepositionboxes\docleanpositionboxes \to \everycleanpositionaction %D A position graphic is a normal (non||reused) \METAPOST\ %D graphic, used immediately, with zero dimensions, so that a %D sequence of them does not harm. \newbox\positiongraphicbox \def\startMPpositiongraphic % id setups {\dodoublegroupempty\dostartMPpositiongraphic} \long\def\dostartMPpositiongraphic#1#2#3\stopMPpositiongraphic {\long\setgvalue{MPG:#1}% tag list mpcode {\useMPpositiongraphic{#1}{#2}{#3}}} %\def\prepareMPpositionvariables % {\doifundefined{\@@meta self}{\setvalue{\@@meta self}{\currentposition}}% % \doifundefined{\@@meta from}{\setvalue{\@@meta from}{\currentposition}}} \def\prepareMPpositionvariables {\ifundefined{\@@meta self}\setvalue{\@@meta self}{\currentposition}\fi \ifundefined{\@@meta from}\setvalue{\@@meta from}{\currentposition}\fi} % \long\def\useMPpositiongraphic#1#2#3% % {\bgroup % \prepareMPvariables{#2}% % \prepareMPpositionvariables % \enableincludeMPgraphics % \startMPgraphic#3\stopMPgraphic % \loadMPgraphic{\MPgraphicfile.\the\currentMPgraphic}{}% % \deallocateMPslot\currentMPgraphic % \placeMPgraphic % \egroup} \newif\ifcollectMPpositiongraphics \collectMPpositiongraphicstrue \long\def\useMPpositiongraphic#1#2#3% {\bgroup \prepareMPvariables{#2}% \prepareMPpositionvariables \enableincludeMPgraphics \ifcollectMPpositiongraphics \expanded{\startMPdrawing#3\noexpand\stopMPdrawing}% \global\MPdrawingdonetrue \else \startMPgraphic#3\stopMPgraphic \loadMPgraphic{\MPgraphicfile.\the\currentMPgraphic}{}% \deallocateMPslot\currentMPgraphic \placeMPgraphic \fi \egroup} % Now we need a adapted action handler: % \def\dopositionaction#1% test saves hash entry in etex % {\ifundefined{\POSactionprefix#1::}\else % \ifnum\MPp{#1}>\zerocount % new % \bgroup % \traceposstring\clap\red{<#1>}% % \the\everyinsertpositionaction % \the\everypositionaction % \ifcollectMPpositiongraphics % % can save a lot of run time % \pushMPdrawing % \MPshiftdrawingtrue % \resetMPdrawing % \getvalue{\POSactionprefix#1::}% % \ifMPdrawingdone % \getMPdrawing % \fi % \resetMPdrawing % \popMPdrawing % \else % \getvalue{\POSactionprefix#1::}% % \fi % \cleanuppositionaction{#1}% % \egroup % \else % % shouldn't happen too often % \traceposstring\clap\cyan{<#1>}% % \fi % \fi} \def\dopositionaction#1% test saves hash entry in etex {\ifundefined{\POSactionprefix#1::}\else \ifnum\MPp{#1}>\zerocount % new \bgroup \setbox\scratchbox\hbox \bgroup \traceposstring\clap\red{<#1>}% \the\everyinsertpositionaction \the\everypositionaction \ifcollectMPpositiongraphics % can save a lot of run time \pushMPdrawing \MPshiftdrawingtrue \resetMPdrawing \getvalue{\POSactionprefix#1::}% \ifMPdrawingdone \getMPdrawing \fi \resetMPdrawing \popMPdrawing \else \getvalue{\POSactionprefix#1::}% \fi \cleanuppositionaction{#1}% \egroup % smashed is really needed else \smashedbox\scratchbox % we get problems with too big \egroup % overlays (s-pre-0x.tex) \else % shouldn't happen too often \traceposstring\clap\cyan{<#1>}% \fi \fi} \def\MPpositiongraphic {\dodoublegroupempty\doMPpositiongraphic} % \def\doMPpositiongraphic#1#2% tag setups % {\bgroup % \def\@@meta{#1:}% % \setupMPvariables[#2]% % \prepareMPpositionvariables % \MPshiftdrawingtrue % \def\doMPpositiongraphic##1##2{\getvalue{MPG:##1}}% temp hack % \setbox\positiongraphicbox\hbox % {\ignorespaces % \executeifdefined{MPM:#1}{\executeifdefined{MPG:#1}\donothing}% % \removelastspace}% % \smashbox\positiongraphicbox % \box\positiongraphicbox % \egroup} \def\doMPpositiongraphic#1#2% tag setups {\bgroup \def\@@meta{#1:}% \setupMPvariables[#2]% \prepareMPpositionvariables \MPshiftdrawingtrue \def\doMPpositiongraphic##1##2% {{% new, see (techniek) \def\@@meta{##1:}% \setupMPvariables[#2,##2]% \prepareMPpositionvariables % and needed \getvalue{MPG:##1}}}% temp hack \setbox\positiongraphicbox\hbox {\ignorespaces \executeifdefined{MPM:#1}{\executeifdefined{MPG:#1}\donothing}% \removelastspace}% \smashbox\positiongraphicbox \box\positiongraphicbox \egroup} \long\def\startMPpositionmethod#1#2\stopMPpositionmethod {\long\setgvalue{MPM:#1}{#2}} % todo: var list here %D Simple one position graphics. \def\setMPpositiongraphic {\dotriplegroupempty\dosetMPpositiongraphic} \def\dosetMPpositiongraphic#1#2#3% pos tag vars {\ifx\currentpositionoverlay\empty \dosetpositionaction{#1}{\MPpositiongraphic{#2}{#3}}% \else % silly can be one \handlepositiongraphics{#1}{#2}{#3}% \fi} \def\handlepositiongraphics#1#2#3% combine with boxes {\handlepositionaction\dohandleMPpositiongraphic\with{#1}{#2}{#3}\on{#2}} \def\doinsertMPpositiongraphic#1#2#3% pos tag setups {\ifnum\MPp{#1}=\realpageno\relax % extra saveguard \def\currentposition{#1}\MPpositiongraphic{#2}{#3}% \fi} \appendtoks \let\dohandleMPpositiongraphic\doinsertMPpositiongraphic \to \everyinsertpositionaction \def\docleanMPpositiongraphic#1#2#3% pos tag setups {\ifnum\MPp{#1}<\realpageno \else \noexpand \dohandleMPpositiongraphic{#1}{#2}{#3}% \fi} \appendtoks \let\dohandleMPpositiongraphic\docleanMPpositiongraphic \to \everycleanpositionaction %D Graphics that span two positions. \def\setMPpositiongraphicrange {\doquadruplegroupempty\dosetMPpositiongraphicrange} \def\dosetMPpositiongraphicrange#1#2#3#4% bpos epos tag vars {\ifx\currentpositionoverlay\empty \dosetpositionaction{#1}{\MPpositiongraphic{#3}{#4}}% \else \handlepositiongraphicsrange{#1}{#2}{#3}{#4}% \fi} \def\handlepositiongraphicsrange#1#2#3#4% {\handlepositionaction\dohandleMPpositiongraphicrange\with{#1}{#2}{#3}{#4}\on{#2}} % \def\doinsertMPpositiongraphicrange#1#2#3#4% pos pos tag setups % {\donefalse % \ifnum\MPp{#1}=\realpageno\relax \donetrue % \else\ifnum\MPp{#2}=\realpageno\relax \donetrue % \else\ifnum\MPp{#1}<\realpageno\relax\ifnum\MPp{#2}>\realpageno\donetrue % \fi\fi\fi\fi \ifdone % \def\currentposition{#1}\MPpositiongraphic{#3}{#4}% % \fi} \def\doinsertMPpositiongraphicrange#1#2#3#4% pos pos tag setups {\ifnum\MPp{#1}\MPp{#2}>\zerocount \iflocalpositioning \donetrue \else \donefalse \ifnum\MPp{#1}=\realpageno \donetrue \else\ifnum\MPp{#2}=\realpageno \donetrue \else\ifnum\MPp{#1}<\realpageno\relax\ifnum\MPp{#2}>\realpageno \donetrue \fi\fi\fi\fi \fi \ifdone \def\currentposition{#1}\MPpositiongraphic{#3}{#4}% \fi \fi} \appendtoks \let\dohandleMPpositiongraphicrange\doinsertMPpositiongraphicrange \to \everyinsertpositionaction \def\docleanMPpositiongraphicrange#1#2#3#4% pos tag setups {\ifnum\MPp{#2}<\realpageno \else \noexpand \dohandleMPpositiongraphicrange{#1}{#2}{#3}{#4}% \fi} \appendtoks \let\dohandleMPpositiongraphicrange\docleanMPpositiongraphicrange \to \everycleanpositionaction % will be overloaded, and/or code below moved to core-box \defineoverlay[\v!text-2][\positionoverlay{\v!text-2}] \defineoverlay[\v!text-1][\positionoverlay{\v!text-1}] \defineoverlay[\v!text+1][\positionoverlay{\v!text+1}] \defineoverlay[\v!text+2][\positionoverlay{\v!text+2}] %D The auxiliary \METAPOST\ macros are defined by default, %D by saying: \appendtoks if unknown context_core : input mp-core.mp ; fi ; \to \MPextensions %D Some of these macros are pretty clever but too complicated %D to be nice. When things are kind of stable I'll clean up %D this mess. %D THIS NEEDS A CLEANUP \setupMPvariables [mpos:box] [linecolor=blue, linewidth=\linewidth, fillcolor=lightgray, filloffset=\!!zeropoint] \startMPpositiongraphic{mpos:box}{fillcolor,linecolor,linewidth} initialize_box(\MPpos{\MPvar{self}}) ; boxfillcolor := \MPvar{fillcolor} ; boxlinecolor := \MPvar{linecolor} ; boxlinewidth := \MPvar{linewidth} ; boxfilloffset := \MPvar{filloffset} ; draw_box ; anchor_box(\MPanchor{\MPvar{self}}) ; \stopMPpositiongraphic \setupMPvariables [mpos:area] [linecolor=blue, linewidth=\linewidth, fillcolor=lightgray, filloffset=\!!zeropoint] \startMPpositiongraphic{mpos:area}{fillcolor,linecolor,linewidth} initialize_area(\MPpos{b:\MPvar{self}},\MPpos{e:\MPvar{self}}) ; boxfillcolor := \MPvar{fillcolor} ; boxlinecolor := \MPvar{linecolor} ; boxlinewidth := \MPvar{linewidth} ; boxfilloffset := \MPvar{filloffset} ; draw_area ; anchor_area(\MPanchor{b:\MPvar{self}}) ; \stopMPpositiongraphic %D This is already cleaned up. % gridtype = 1 => baseline % gridtype = 2 => betweenline \setupMPvariables [mpos:par] [mp=mpos:par:shape, gridtype=0, linetype=1, filltype=1, %snaptops=true, % not that nice: true/false gridcolor=red, linecolor=blue, fillcolor=lightgray, filloffset=\!!zeropoint, linewidth=\linewidth, gridwidth=\linewidth, lineradius=.5\bodyfontsize] \startuseMPgraphic{mpos:par:shape} \iftracepositions show_par \else draw_par \fi ; \stopuseMPgraphic \startuseMPgraphic{mpos:par:setup} boxgridtype := \MPvar{gridtype} ; boxlinetype := \MPvar{linetype} ; boxfilltype := \MPvar{filltype} ; boxgridcolor := \MPvar{gridcolor} ; boxlinecolor := \MPvar{linecolor} ; boxfillcolor := \MPvar{fillcolor} ; boxfilloffset := \MPvar{filloffset} ; boxlinewidth := \MPvar{linewidth} ; boxgridwidth := \MPvar{gridwidth} ; boxlineradius := \MPvar{lineradius} ; %snap_multi_par_tops := \MPvar{snaptops} ; \stopuseMPgraphic \startuseMPgraphic{mpos:par:extra} % user stuff, like: % snap_multi_par_tops := false ; \stopuseMPgraphic % \startMPpositionmethod{mpos:par} % \doifpositionelse{w:\MPvar{self}} % {\startMPpositiongraphic{mpos:par}% % {fillcolor,filloffset,linecolor,gridcolor,linewidth,gridwidth,lineradius} % initialize_area_par(\MPpos{b:\MPvar{self}}, % \MPpos{e:\MPvar{self}}, % \MPpos{w:\MPvar{self}}) ; % \includeMPgraphic{mpos:par:setup} ; % \includeMPgraphic{mpos:par:extra} ; % \includeMPgraphic{\MPvar{mp}} ; % \includeMPgraphic{mpos:par:shape} ; % anchor_par(\MPanchor{b:\MPvar{self}}) ; % \stopMPpositiongraphic} % {\startMPpositiongraphic{mpos:par}% % {fillcolor,filloffset,linecolor,gridcolor,linewidth,gridwidth,lineradius} % initialize_par(\MPpos{b:\MPvar{self}}, % \MPpos{e:\MPvar{self}}, % \MPpos{text:\realfolio}, % \MPpos{p:\MPparcounter}, % \MPvv {p:\MPparcounter}{0,0,0,0,0,0}) ; % \includeMPgraphic{mpos:par:setup} ; % \includeMPgraphic{mpos:par:extra} ; % \includeMPgraphic{\MPvar{mp}} ; % \includeMPgraphic{mpos:par:shape} ; % anchor_par(\MPanchor{b:\MPvar{self}}) ; % \stopMPpositiongraphic}% % \MPpositiongraphic{mpos:par}{}% % \stopMPpositionmethod %D Less readable but shorter. \ifx\MPparcounter\undefined \newcounter\MPparcounter \fi \def\MPself {\MPvar{self}} \def\MPbself {b:\MPself} \def\MPeself {e:\MPself} \def\MPwself {w:\MPself} \def\MPparanchor{p:\MPparcounter} \def\MPl#1{\MPplus{#1}20} \def\MPr#1{\MPplus{#1}30} \startMPpositionmethod{mpos:par} %%%%%%%%%%% will become obsolete \edef\MPparcounter{\MPv\MPbself{1}{0}}% \doifpositionelse\MPwself {\startMPpositiongraphic{mpos:par}% {fillcolor,filloffset,linecolor,gridcolor,linewidth,gridwidth,lineradius} initialize_area_par(\MPpos\MPbself, \MPpos\MPeself, \MPpos\MPwself) ; \includeMPgraphic{mpos:par:setup} ; \includeMPgraphic{mpos:par:extra} ; \includeMPgraphic{\MPvar{mp}} ; anchor_par(\MPanchor\MPbself) ; \stopMPpositiongraphic} {\startMPpositiongraphic{mpos:par}% {fillcolor,filloffset,linecolor,gridcolor,linewidth,gridwidth,lineradius} initialize_par(\MPpos\MPbself, \MPpos\MPeself, \MPpos\textanchor, \MPpos\MPparanchor, \MPvv \MPparanchor{0,0,0,0,0,0}) ; \includeMPgraphic{mpos:par:setup} ; \includeMPgraphic{mpos:par:extra} ; \includeMPgraphic{\MPvar{mp}} ; anchor_par(\MPanchor\MPbself) ; \stopMPpositiongraphic}% \MPpositiongraphic{mpos:par}{}% \stopMPpositionmethod %D The next alternative works in columnsets : % \iftracepositions show\else draw\fi_multi_pars ; \startuseMPgraphic{mpos:par:columnset} \iftracepositions show_multi_pars \else draw_multi_pars \fi ; \stopuseMPgraphic \startMPpositionmethod{mpos:par:columnset} \edef\MPparcounter{\MPv\MPbself{1}{0}}% \startMPpositiongraphic{mpos:par}% {fillcolor,filloffset,linecolor,gridcolor,% linewidth,gridwidth,lineradius} \includeMPgraphic{mpos:par:setup} ; \includeMPgraphic{mpos:par:extra} ; prepare_multi_pars(\MPpos\MPbself,\MPpos\MPeself,\MPpos\MPwself, \MPpos\MPparanchor,\MPvv\MPparanchor{0,0,0,0,0,0}) ; relocate_multipars(-\MPxy\MPanchorid) ; % inside layerpos \includeMPgraphic{\MPvar{mp}} ; \stopMPpositiongraphic \MPpositiongraphic{mpos:par}{}% \stopMPpositionmethod %D \starttyping %D \setupbackground %D [test] %D [mp=mpos:par:columnset, %D methodmethode=mpos:par:columnset] %D \stoptyping %D We need to treat floats in a special way. \appendtoks local_multi_par_area:=\iflocalpositioning true\else false\fi; \to \MPinitializations \def\textbackgroundoverlay#1% {\iflocalpositioning\v!local\else\v!text\fi#1} \newcounter\localpositionnumber \def\MPanchornumber {\iflocalpositioning\localpositionnumber\else\realfolio\fi} %D So far for the trickery. \newcounter\textbackgrounddepth \appendtoks \savecurrentvalue\totalnofparbackgrounds\nofparbackgrounds \to \everybye \appendtoks \initializeparbackgrounds \to \everystarttext \ifx\totalnofparbackgrounds\undefined \newcounter\totalnofparbackgrounds \fi \ifx\nofparbackgrounds \undefined \newcounter\nofparbackgrounds \fi \def\initializeparbackgrounds {\ifcase\totalnofparbackgrounds\else \global\positioningtrue \global\positioningpartrue \fi} \unexpanded\def\starttextbackground {\bgroup \increment\textbackgrounddepth \dodoubleempty\dostarttextbackground} \let\dodostarttextbackground\relax \let\dodostoptextbackground \relax % \def\currentparbackground{background:0} % \def\nextparbackground {background:1} \def\currentparbackground{pbg:0} \def\nextparbackground {pbg:1} \def\btbanchor{b:\currentparbackground} \def\etbanchor{e:\currentparbackground} \def\nextbtbanchor{b:\nextparbackground} \def\nextetbanchor{e:\nextparbackground} \def\backgroundvariable#1% {\csname\??td\currenttextbackground#1\endcsname} % \definetextbackground[more][state=start,backgroundcolor=red] % location=paragraph % \definetextbackground[test][state=start,backgroundcolor=green] % % \page \placefigure[left]{}{} % % \starttextbackground[test] % \readfile{ward}{}{} % \starttextbackground[more] % \readfile{ward}{}{} % \stoptextbackground % \readfile{ward}{}{} % \stoptextbackground % % \page \placefigure[right]{}{} % % \starttextbackground[test] % \readfile{ward}{}{} % \starttextbackground[more] % \readfile{ward}{}{} % \stoptextbackground % \readfile{ward}{}{} % \stoptextbackground \def\dostarttextbackground[#1][#2]% {\checktextbackgrounds \def\currenttextbackground{#1}% \doglobal\increment\nofparbackgrounds %\edef\currentparbackground{background:\nofparbackgrounds}% \edef\currentparbackground{pbg:\nofparbackgrounds}% \bgroup \increment\nofparbackgrounds %\xdef\nextparbackground{background:\nofparbackgrounds}% \xdef\nextparbackground{pbg:\nofparbackgrounds}% \egroup % todo : \synchonizepositionpage{b:\currentparbackground}{s:\currentparbackground}% \setuptextbackground[#1][#2]% \let\dodostarttextbackground\relax \let\dodostoptextbackground \relax \doifvalue{\??td#1\c!state}\v!start {\dopresettextbackground{#1}}% \dodostarttextbackground} % todo \backgroundvariable\c!variant \def\dopresettextbackground#1% todo: \backgroundparameter {\ExpandFirstAfter\processaction % \EFA niet echt nodig [\getvalue{\??td#1\c!location}] [ \v!text=>\let\dodostarttextbackground\dostarttextbackgroundtxt \let\dodostoptextbackground \dostoptextbackgroundtxt, \v!paragraph=>\let\dodostarttextbackground\dostarttextbackgroundpar \let\dodostoptextbackground \dostoptextbackgroundpar, \v!none=>\let\dodostarttextbackground\relax \let\dodostoptextbackground \relax]% \ifx\dodostarttextbackground\dostarttextbackgroundpar % untested \ifnum\textbackgrounddepth>\plusone % new \let\dodostarttextbackground\dostarttextbackgroundtxt \let\dodostoptextbackground \dostoptextbackgroundtxt \fi \fi \doifelsevalue{\??td#1\c!frame}\v!on {\doifelsevalue{\??td#1\c!corner}\v!round {\setvalue{\??td#1\c!frame}{2}} {\setvalue{\??td#1\c!frame}{1}}} {\setvalue{\??td#1\c!frame}{0}}% \doifelsevalue{\??td#1\c!background}\v!color {\setvalue{\??td#1\c!background}{1}} {\setvalue{\??td#1\c!background}{0}}% %\startpositionoverlay{\v!text\getvalue{\??td#1\c!level}}% \startpositionoverlay{\textbackgroundoverlay{\getvalue{\??td#1\c!level}}}% \expanded {\setMPpositiongraphicrange % moet veel efficienter {\btbanchor}% {b:\currentparbackground}% {\etbanchor}% {e:\currentparbackground}% {\getvalue{\??td#1\c!method}}% {self=\currentparbackground, mp=\getvalue{\??td#1\c!mp}, gridtype=\getvalue{\??td#1\c!alternative}, filltype=\getvalue{\??td#1\c!background}, linetype=\getvalue{\??td#1\c!frame}, gridcolor=\getvalue{\??td#1\c!framecolor}, linecolor=\getvalue{\??td#1\c!framecolor}, fillcolor=\getvalue{\??td#1\c!backgroundcolor}, filloffset=\getvalue{\??td#1\c!backgroundoffset}, gridwidth=\getvalue{\??td#1\c!rulethickness}, linewidth=\getvalue{\??td#1\c!rulethickness}, lineradius=\getvalue{\??td#1\c!radius}}}% \stoppositionoverlay} \def\stoptextbackground {\dodostoptextbackground \carryoverpar\egroup} \def\starttextbackgroundmanual {\dostartattributes{\??td\currenttextbackground}\c!style\c!color\empty \fpos\currentparbackground\ignorespaces} \def\stoptextbackgroundmanual {\tpos\currentparbackground \dostopattributes} \def\dostarttextbackgroundtxt {\ifvmode \leavevmode \fi \dostartattributes{\??td\currenttextbackground}\c!style\c!color\empty \fpos\currentparbackground\ignorespaces} \def\dostoptextbackgroundtxt {\tpos\currentparbackground \dostopattributes} % keep this simple one, it's used in prikkels and alike % % \def\dostarttextbackgroundpar % {\endgraf % new % \getvalue{\??td\currenttextbackground\c!before}% % \noindent\fpos\currentparbackground\ignorespaces % \bgroup % \nobreak \vskip-\lineheight \nobreak % \doassignsomeskip\getvalue{\??td\currenttextbackground\c!topoffset}\to\scratchskip % \kern\scratchskip\nobreak % \dosetleftskipadaption{\getvalue{\??td\currenttextbackground\c!leftoffset}}% % \advance\leftskip\leftskipadaption % \dosetleftskipadaption{\getvalue{\??td\currenttextbackground\c!rightoffset}}% % \advance\rightskip\leftskipadaption % \dostartattributes{\??td\currenttextbackground}\c!style\c!color{}% % \nowhitespace % \seteffectivehsize % \par} % % \def\dostoptextbackgroundpar % {\par % \dostopattributes % \doassignsomeskip\getvalue{\??td\currenttextbackground\c!bottomoffset}\to\scratchskip % \kern\scratchskip\nobreak % \nobreak \vskip-\lineheight \nobreak % \nowhitespace % \egroup % \nobreak \noindent \strut \hfill \kern\zeropoint \tpos\currentparbackground % \endgraf % new % \getvalue{\??td\currenttextbackground\c!after}} \def\dostarttextbackgroundpar {\endgraf % new \getvalue{\??td\currenttextbackground\c!before}% \doassignsomeskip\getvalue{\??td\currenttextbackground\c!topoffset}\to\scratchskip \xdef\textbackgroundskip{\the\scratchskip}% \noindent \ifgridsnapping \ifdim\textbackgroundskip>\zeropoint \struttedbox{\hbox{\raise\textbackgroundskip\hbox{\fpos\currentparbackground}}}% \else \fpos\currentparbackground \fi \else \fpos\currentparbackground \fi \bgroup \endgraf % we need a vertical nobreak - 29/06/2004 \nobreak \vskip-\lineheight \nobreak \doassignsomeskip\getvalue{\??td\currenttextbackground\c!topoffset}\to\scratchskip \ifgridsnapping \else \ifdim\textbackgroundskip>\zeropoint \kern\textbackgroundskip\nobreak \fi \fi \dosetleftskipadaption{\getvalue{\??td\currenttextbackground\c!leftoffset}}% \advance\leftskip\leftskipadaption \dosetleftskipadaption{\getvalue{\??td\currenttextbackground\c!rightoffset}}% \advance\rightskip\leftskipadaption % new \dosetraggedcommand{\getvalue{\??td\currenttextbackground\c!align}}% \raggedcommand % \dostartattributes{\??td\currenttextbackground}\c!style\c!color\empty \nowhitespace \seteffectivehsize \doinhibitblank % \blank[\v!disable]% new \par} \def\dostoptextbackgroundpar {\par \removelastskip % new \dostopattributes \doassignsomeskip\getvalue{\??td\currenttextbackground\c!bottomoffset}\to\scratchskip \ifdim\lastskip>\zeropoint \advance\scratchskip-\lastskip \fi \xdef\textbackgroundskip{\the\scratchskip}% \ifgridsnapping \else \ifdim\textbackgroundskip>\zeropoint \kern\scratchskip\nobreak \fi \fi \nobreak \vskip-\lineheight \nobreak \nowhitespace \egroup \bgroup \forgeteverypar % NOT REALLY NEEDED, SAVES HASH/MEM \nobreak \noindent \strut \hfill \kern\zeropoint \ifgridsnapping % experimental, pascal (todo: topoffset in same way) \ifdim\textbackgroundskip>\zeropoint \struttedbox{\hbox{\lower\textbackgroundskip\hbox{\tpos\currentparbackground}}}% \else \tpos\currentparbackground \fi \else \tpos\currentparbackground \fi \egroup \endgraf % new \getvalue{\??td\currenttextbackground\c!after}} \let\textparpages \!!zeropoint \let\textparheight\!!zeropoint \let\textparwidth \!!zeropoint \def\calculatetextpardimensions {\docalculatetextpardimensions\btbanchor \etbanchor \MPparanchor} \def\calculatenexttextpardimensions {\docalculatetextpardimensions\nextbtbanchor\nextetbanchor\relax} \def\docalculatetextpardimensions#1#2#3% {\scratchcounter\MPp#2%\etbanchor \advance\scratchcounter-\MPp#1%\btanchor \edef\textparpages{\the\scratchcounter}% \ifcase\scratchcounter % one page \scratchdimen \MPy#1%\btanchor \advance\scratchdimen-\MPy#2%\etbanchor \else % two or more pages \scratchdimen \MPy#1%\btanchor \advance\scratchdimen-\MPy#2%\etbanchor \advance\scratchdimen-\MPy\textanchor \advance\scratchdimen \MPy\textanchor \advance\scratchdimen \MPh\textanchor\relax \ifcase\scratchcounter>2 \ifnum\scratchcounter<5 % more pages \scratchdimen\textheight \advance\scratchcounter \minusone \multiply\scratchdimen \scratchcounter \else % keep'm small \scratchdimen5\textheight \fi \fi \fi \edef\textparheight{\the\scratchdimen}% \ifcase\scratchcounter % one page \scratchdimen \MPx#2%\etbanchor \advance\scratchdimen-\MPx#1%\btanchor \else % two or more pages / maybe also hang \ifx#3\relax \scratchdimen\makeupwidth % \textwidth \else \scratchdimen\MPw\MPparanchor \advance\scratchdimen-\MPl\MPparanchor \advance\scratchdimen-\MPr\MPparanchor \fi \fi \edef\textparwidth{\the\scratchdimen}} \def\mintextparheight{4\lineheight} \def\dontsplitnexttextbackground % dangerous but useful {\ifdim\pagetotal>\textheight \else \ifdim\pagegoal=\maxdimen \else \calculatenexttextpardimensions % too tricky % \scratchdimen=\textparheight % \advance\scratchdimen\pagetotal\relax % \ifdim\scratchdimen>\pagegoal % \page % \fi \ifdim\textparheight>\zeropoint \ifdim\textparheight>\mintextparheight\else \page % option \fi \fi \fi \fi} \def\definetextbackground {\dodoubleempty\dodefinetextbackground} \def\dodefinetextbackground[#1][#2]% {\ifsecondargument % why ? \copyparameters[\??td#1][\??td] [\c!state,\c!location,\c!alternative,\c!mp,\c!method, \c!background,\c!backgroundcolor,\c!corner,\c!level, \c!backgroundoffset,\c!before,\c!after,\c!align, \c!radius,\c!frame,\c!framecolor,\c!rulethickness, \c!leftoffset,\c!rightoffset,\c!topoffset,\c!bottomoffset]% \getparameters[\??td#1][#2]% \doifvalue{\??td#1\c!state}\v!start\checktextbackgrounds \unexpanded\setvalue{#1}% {\groupedcommand{\starttextbackground[#1]}{\stoptextbackground}}% \setvalue{\e!start#1}{\starttextbackground[#1]}% \setvalue{\e!stop #1}{\stoptextbackground}% \fi} \def\setuptextbackground {\dodoubleargument\dosetuptextbackground} \def\dosetuptextbackground[#1][#2]% {\ifsecondargument \doifelsenothing{#1} {\dodosetuptextbackground{#2}\empty} {\processcommalist[#1]{\dodosetuptextbackground{#2}}}% \else \dodosetuptextbackground{#1}\empty \fi} \def\dodosetuptextbackground#1#2% {\getparameters[\??td#2][#1]% \def\currenttextbackground{#2}% \doifvalue{\??td#2\c!state}\v!start\checktextbackgrounds} \let\currenttextbackground\empty \def\checktextbackgrounds {\ifproductionrun \enabletextarearegistration \enablehiddenbackground \fi} \setuptextbackground [\c!mp=mpos:par:columnset, % buggy: mpos:par:shape \c!method=mpos:par:columnset, % \c!state=\v!start, \c!location=\v!text, \c!leftoffset=\!!zeropoint, % 1em, \c!rightoffset=\getvalue{\??td\currenttextbackground\c!leftoffset}, \c!topoffset=\!!zeropoint, % \v!medium, \c!bottomoffset=\getvalue{\??td\currenttextbackground\c!topoffset}, \c!level=-1, \c!alternative=0, \c!align=, \c!background=\v!color, \c!backgroundcolor=lightgray, \c!backgroundoffset=\!!zeropoint, \c!corner=\v!rectangular, \c!radius=.5\bodyfontsize, \c!frame=\v!on, \c!framecolor=blue, \c!rulethickness=\linewidth] %D As an example we define a grid background: \definetextbackground [\v!grid] [\c!state=\v!stop, \c!location=\v!paragraph, \c!frame=\v!off, \c!framecolor=red, \c!background=, \c!alternative=1] \ifx\basegrid\undefined \else \letvalue\v!grid=\basegrid \fi % lelijk, aanpassen, opties \setupMPvariables [mpos:connect] [linecolor=red, linewidth=1pt] \setupMPvariables [mpos:encircle] [fillcolor=lightgray, filloffset=\!!zeropoint, linecolor=blue, linewidth=1pt] \startuseMPgraphic{mpos:common:ec} path pa ; pair ca ; color lc ; numeric lw ; lw := \MPvar{linewidth} ; lc := \MPvar{linecolor} ; initialize_box(\MPpos{\MPvar{self}}) ; pa := pxy ; ca := cxy ; pa := boundingbox pa enlarged 2lw ; pa := llcorner pa...lrcorner pa...urcorner pa...ulcorner pa...cycle ; drawoptions (withpen pencircle scaled lw withcolor lc) ; \stopuseMPgraphic \startMPpositiongraphic{mpos:encircle}{linecolor,fillcolor,linewidth} \includeMPgraphic{mpos:common:ec} fill pa withcolor \MPvar{fillcolor} ; draw pa ; anchor_box(\MPanchor{\MPvar{self}}) ; \stopMPpositiongraphic \startMPpositiongraphic{mpos:connect}{linecolor,linewidth} path pb, pc ; pair cb, cc ; \includeMPgraphic{mpos:common:ec} initialize_box(\MPpos{\MPvar{to}}) ; pb := pxy ; cb := cxy ; pb := boundingbox pb enlarged 2lw ; pb := llcorner pb...lrcorner pb...urcorner pb...ulcorner pb...cycle ; pc := ca {up} .. {down} cb ; cc := (pc intersection_point pa) ; if intersection_found : pc := pc cutbefore cc ; cc := (pc intersection_point pb) ; if intersection_found : pc := pc cutafter cc ; drawarrow pc ; drawarrow reverse pc ; fi ; fi ; anchor_box(\MPanchor{\MPvar{self}}) ; \stopMPpositiongraphic %D \macros %D {stackposdown, stackposup, stackposleft,stackposright} %D %D A non graphic example of the use of positioning, is to stack %D text in for instance the margin. %D %D \stackposdown \inleft {some text}The text \type {some text} %D goes into the left margin, and \stackposdown \inleft {some %D more}\type {some more} as well. When they overlap, they %D will not touch. %D %D Here we said \type {\stackposdown \inleft{some text}}. Instead %D of \stackposleft \inleft {one}stacking \stackposleft \inleft %D {two}vertically, one can stack horizontally by \stackposleft %D \inleft {three}using \type {\stackposleft}. %D %D We can go in all four directions, using \type {\stackposdown}, %D \type {\stackposup}, \type {\stackposleft} and \type %D {\stackposright}. \def\stackposdistance{.5em} \newcounter\currentautopos \def\POSstackprefix{stack:} \def\dostackposbox#1#2% {\dowithnextbox {#2{\let\previousautopos\currentautopos \doglobal\increment\currentautopos \hpos{\POSstackprefix\currentautopos} {\doifoverlappingelse{\POSstackprefix\currentautopos}{\POSstackprefix\previousautopos} {#1} {\flushnextbox}}}}% \hbox} \def\stackposup {\dostackposbox{\raise\lineheight\flushnextbox}} \def\stackposdown {\dostackposbox{\lower\lineheight\flushnextbox}} \def\stackposleft {\dostackposbox{\copy\nextbox\hskip\nextboxwd\hskip\stackposdistance}} \def\stackposright{\dostackposbox{\hskip\stackposdistance\hskip\nextboxwd\flushnextbox}} %D \macros %D {stackeddown} %D %D However, a better implementation is possible with the %D following macro. We now have an extra key \type {stack} for %D margin settings. When set to \type {yes}, this macro comes %D into action. % \def\stackeddown % {\dowithnextbox % {\doglobal\increment\currentautopos % \hpos{\POSstackprefix\currentautopos} % {\edef\next % {\nextboxht\the\nextboxht % \nextboxdp\the\nextboxdp % \nextboxwd\the\nextboxwd}% % \let\previousautopos\currentautopos % \scratchdimen\zeropoint % \doloop % {\decrement\previousautopos % \doifoverlappingelse{\POSstackprefix\currentautopos}{\POSstackprefix\previousautopos} % {\advance\scratchdimen\MPh{\POSstackprefix\previousautopos}% % \advance\scratchdimen\MPd{\POSstackprefix\previousautopos}}% % \exitloop % \ifnum\previousautopos<\zerocount\exitloop\fi}% % % \ifdim\scratchdimen>\zeropoint % \setbox\nextbox\iftracepositions\@EA\ruledhbox\else\@EA\hbox\fi % {\lower\scratchdimen\flushnextbox}% % \next % % \fi % \flushnextbox}}} % Because there can be many stacked items in a line and successive lines, we % play dirty and adapt the position and height of the current node so that % this becomes visible to a next pass. % % \startbuffer % \inleft {test 1} test 1 \inleft {test 2} test 2 \endgraf % \inleft {test 3} test 3 % \stopbuffer % \getbuffer \typebuffer \flushstatus \page % % \startbuffer % \inleft {test 1} test 1 \inleft {test 2} test 2 \inleft {test 3} test 3 \endgraf % \inleft {test 4} test 4 % \stopbuffer % \getbuffer \typebuffer \flushstatus \page % % \startbuffer % \inleft {test 1} test 1 \endgraf % \inleft {test 2} test 2 \endgraf % \inleft {test 3} test 3 % \stopbuffer % \getbuffer \typebuffer \flushstatus \page % % \startbuffer % \inleft {test 1\\test 1} test 1 \inleft {test 2} test 2 \endgraf % \inleft {test 3} test 3 % \stopbuffer % \getbuffer \typebuffer \flushstatus \page % % \startbuffer % \inleft {test 1\\test 1\\test 1\\test 1\\test 1} test 1 \endgraf % test 2 \endgraf % \inleft {test 3} test 3 % \stopbuffer % \getbuffer \typebuffer \flushstatus \page % % \startbuffer % \inleft{test 1} test \inleft{test 2} test \inleft{test 3\\test 3} test % \stopbuffer % \getbuffer \typebuffer \flushstatus \page % % \startbuffer % \inleft{test 1\\test 1\\test 1} test \inleft{test 2\\test 2} test \inleft{test 3\\test 3\\test 3} test \endgraf % \inleft{test 1\\test 1\\test 1} test \inleft{test 2\\test 2} test \inleft{test 3\\test 3\\test 3} test % \stopbuffer % \getbuffer \typebuffer \flushstatus \page \newdimen\laststackvmove \def\stackeddown {\bgroup % this macro assumes a few things and is meant to work for margin notes \dowithnextbox {\doglobal\increment\currentautopos \global\laststackvmove\zeropoint \hpos{\POSstackprefix\currentautopos} {\edef\next {\nextboxht\the\nextboxht \nextboxdp\the\nextboxdp \nextboxwd\the\nextboxwd}% \let\previousautopos\currentautopos \scratchdimen\zeropoint \scratchcounter\zerocount \doloop {\decrement\previousautopos\relax \edef\currentposition {\POSstackprefix\currentautopos}% \edef\previousposition{\POSstackprefix\previousautopos}% \ifnum\MPp\currentposition=\MPp\previousposition\relax %\registerstatus{doing \currentautopos/\previousautopos}% \doifoverlappingelse\currentposition\previousposition {\scratchskip \MPy\currentposition \advance\scratchskip-\MPy\previousposition \advance\scratchskip-\MPd\currentposition % untested \advance\scratchskip \MPd\previousposition % untested \advance\scratchskip \MPh\currentposition % todo: also take depth into account \relax \ifdim\scratchskip<\scratchdimen %\registerstatus{no \the\scratchskip}% \else %\registerstatus{yes \the\scratchskip}% \scratchdimen\scratchskip \fi}% \donothing % {\registerstatus{next}}% \ifnum\previousautopos<\zerocount\exitloop\fi \else \exitloop \fi}% \ifdim\scratchdimen=\zeropoint \else \bgroup \edef\currentposition{\POSstackprefix\currentautopos}% \scratchskip\scratchdimen \advance\scratchskip\MPh\currentposition \scratchdimen-\scratchdimen \advance\scratchdimen\MPy\currentposition %\registerstatus{old \currentautopos: \MPy\currentposition/\MPh\currentposition}% \expanded{\replacepospxywhd {\currentposition}{\MPp\currentposition}{\MPx\currentposition}{\the\scratchdimen}% {\MPw\currentposition}{\the\scratchskip}{\MPd\currentposition}}% %\registerstatus{new \currentautopos: \MPy\currentposition/\MPh\currentposition}% \egroup \global\laststackvmove\scratchdimen % new \setbox\nextbox\iftracepositions\@EA\ruledhbox\else\@EA\hbox\fi {\lower\scratchdimen\flushnextbox}% \next %\registerstatus{\strut}% \fi \flushnextbox}% \egroup}} %D The next hack make sure that margin texts near faulty %D strutted lines are handled ok. \newif\ifrepositionmarginbox % \repositionmarginboxtrue \newcounter\currentmarginpos % \def\dopositionmarginbox#1% % {\bgroup % \ifrepositionmarginbox % \doglobal\increment\currentmarginpos % \setposition{\s!margin:\currentmarginpos}% % \scratchdimen=\MPy{\s!margin:\currentmarginpos}% % \doglobal\increment\currentmarginpos % \advance\scratchdimen by -\MPy{\s!margin:\currentmarginpos}% % \advance\scratchdimen by -\strutdp % \setbox#1=\hbox % {\setposition{\s!margin:\currentmarginpos}\raise\scratchdimen\box#1}% % \dp#1=\!!zeropoint % \ht#1=\!!zeropoint % \fi % \vadjust{\box#1}% % \egroup} \def\dopositionmarginbox#1% how about page boundaries ! {\bgroup \ifrepositionmarginbox \doglobal\increment\currentmarginpos \setposition{\s!margin:\currentmarginpos}% \scratchdimen\MPy{\s!margin:\currentmarginpos}% \doglobal\increment\currentmarginpos \advance\scratchdimen -\MPy{\s!margin:\currentmarginpos}% \advance\scratchdimen -\strutdp % new \setbox#1\hbox {\hskip-\MPx{\s!margin:\currentmarginpos}% \hskip\MPx{head:\realfolio}% \box#1}% % so far \setbox#1\hbox {\setposition{\s!margin:\currentmarginpos}% \raise\scratchdimen\box#1}% \dp#1\zeropoint \ht#1\zeropoint \fi \graphicvadjust{\box#1}% \egroup} %D For a right menu, a sequence of calls to \type %D {right_menu_button} is generated. %D %D \starttyping %D right_menu_button (n, p, s=0/1/2, x, y, w, h, d) ; %D \stoptyping %D %D Here, n is the number of the button, s a status variable, %D while the rest is positional info. The status variable is %D 0, 1 or~2: not found, found and found but current page. % 0=not found 1=found 2=current page % geen leeg \newtoks\MPmenutoks \def\MPmenubuttons#1{\the\MPmenutoks} \appendtoks \global\MPmenutoks\emptytoks \to \everyshipout % 0=notfound 1=found 2=currentpage \def\do@@amposition#1#2#3% {\doifelsevalue{\??am#1\c!position}\v!yes {\doglobal\increment\currentamposition \doifnumberelse{#2} {\docheckrealreferencepage{#2}% \global\chardef\currentamrealpage\ifrealreferencepage2\else1\fi} {\doifreferencefoundelse{#2} {\global\chardef\currentamrealpage\ifrealreferencepage2\else1\fi} {\global\chardef\currentamrealpage0}}% % not found \expanded {\doglobal\noexpand\appendtoks #1_menu_button(\currentamposition,\the\currentamrealpage,\noexpand\MPpos{#1:\currentamposition}) ; \to \MPmenutoks}% \hpos{#1:\currentamposition}{#3}} {#3}} \def\do@@ammenuposition#1% {\ifnum\currentamposition>0 \dowithnextbox{\hpos{menu:#1:\realfolio}{\flushnextbox}}\hbox \fi} %D \macros %D {GFC, GTC, GSC} %D %D The next macros extend tables and tabulation with %D backgrounds and position related features. Areas are %D specified with symbolic names, and symbolic references to %D the graphics involved. Each table has its own namespace. \newcounter\noftabpositions \newtoks \posXCtoks \def\tbPOSprefix {tbp:\noftabpositions:} \def\tablepos {\scratchtoks\posXCtoks \global\posXCtoks\emptytoks \the\scratchtoks} \let\tabulatepos\tablepos \def\dodododoGSC[#1:#2]% {\remappositionframed{#2}{\tbPOSprefix#1}% \bpos{\tbPOSprefix#1}% \doglobal\appendtoks\@EA\epos\@EA{\tbPOSprefix#1}\to\posXCtoks} \def\dododoGSC[#1:#2:#3]% {\doglobal\appendtoks\dodododoGSC[#1:#2]\to\posXCtoks\NC} \def\dodoGSC[#1]% {\def\docommando##1{\dododoGSC[##1:##1]}% \processcommalist[#1]\docommando} \def\dodododoGFC[#1:#2:#3]% {\remappositionframed{#2}{\tbPOSprefix#1}% \bpos{\tbPOSprefix#1}} \def\dododoGFC[#1]% {\def\docommando##1{\dodododoGFC[##1:##1]}% \processcommalist[#1]\docommando} \def\dodoGFC[#1]% {\doglobal\appendtoks\dododoGFC[#1]\to\posXCtoks\NC} \def\dododododoGTC[#1:#2]% {\epos{\tbPOSprefix#1}} \def\dodododoGTC[#1]% {\def\docommando##1{\dododododoGTC[##1:##1]}% \processcommalist[#1]\docommando} \def\dododoGTC[#1]% {\doglobal\appendtoks\dodododoGTC[#1]\to\posXCtoks} \def\dodoGTC[#1]% {\doglobal\appendtoks\dododoGTC[#1]\to\posXCtoks\NC} \def\dodododoXC[#1#2]% {\if#1>\dodoGFC [#2:#2]\else \if#1+\dodoGFC [#2:#2]\else \if#1<\dodoGTC [#2:#2]\else \if#1-\dodoGTC [#2:#2]\else \if#1=\dodoGSC [#2:#2]\else \dodoGSC[#1#2:#1#2]\fi\fi\fi\fi\fi} \def\dododoXC#1% {\dodododoXC[#1]} \def\dodoXC[#1]% {{\let\NC\relax\processcommalist[#1]\dododoXC}} \def\doGSC[#1]{\iffirstargument\dodoGSC[#1]\else\expandafter\NC\fi} \def\doGFC[#1]{\iffirstargument\dodoGFC[#1]\else\expandafter\NC\fi} \def\doGTC[#1]{\iffirstargument\dodoGTC[#1]\else\expandafter\NC\fi} \def\doXC [#1]{\iffirstargument\dodoXC [#1]\else\expandafter\fi\NC} \def\tbGSC{\dosingleempty\doGSC} \def\tbGFC{\dosingleempty\doGFC} \def\tbGTC{\dosingleempty\doGTC} \def\tbXC {\dosingleempty\doXC } %D The amount of code to support tables and tabulation is %D rather minimalistic. \let\tabulatepos\tablepos \def\tabulatenormalpos {\hss\tabulatepos\hss} \def\tabulateequalpos {\setbox\scratchbox\hbox{\tabulateEQ}% \hbox to \wd\scratchbox{\hss\kern\zeropoint\tabulatepos\hss}% \hskip-\wd\scratchbox \box\scratchbox} \def\tabulatenormalcolumn#1% overloaded {&\iftabulateequal\tabulateequalpos\else\tabulatenormalpos\fi &\global\chardef\tabulatetype#1&} \def\tabulateequalcolumn#1% overloaded {&\tabulateequalpos &\global\chardef\tabulatetype#1&} \appendtoks \doglobal\increment\noftabpositions \to \everytabulate %D In order to prevent potential clashes with abbreviations, %D postpone the mapping. \appendtoks \let\GSC\tbGSC \let\GFC\tbGFC \let\GTC\tbGTC \let\XC\tbXC \to \everytabulate %D \macros %D {definepositionframed} %D %D The next example show how to provide backgrounds to table %D cells. First we define some framed backgrounds. %D %D \startbuffer %D \definepositionframed[x][background=color,backgroundcolor=red] %D \definepositionframed[y][background=color,backgroundcolor=green] %D \definepositionframed[z][background=color,backgroundcolor=blue] %D \stopbuffer %D %D \typebuffer %D %D % \getbuffer %D %D \startbuffer %D \starttabulate[|c|c|c|] %D \GFC[f:x] this is a small \NC table \NC in which we \NC \FR %D \NC will demonstrate \GFC[g:z] that this \GTC[g] positioning \NC \MR %D \GSC[e:y] mechanism also \GTC[f] works quite well \NC in tables \NC \LR %D \stoptabulate %D \stopbuffer %D %D The table itself defines three areas (a, b and~c) using %D these frames. %D %D \typebuffer %D % \getbuffer %D %D Tables (based on \TABLE) are supported by: \def\normalTABLEsimplebar {\unskip\!ttRightGlue&\tablepos&} % | \def\normalTABLEcomplexbar{\unskip\!ttRightGlue&\omit\tablepos\!ttAlternateVrule} % \| \def\normalTABLEquote {\unskip\!ttRightGlue&\omit\tablepos&} % " \appendtoks \doglobal\increment\noftabpositions \to \everytable %D Since we don't want nameclashes: \appendtoks \let\GSC\tbGSC \let\GFC\tbGFC \let\GTC\tbGTC \let\XC\tbXC \to \everytable %D In the previous example, we could have provided an overlay to %D the framed definition. A more direct approach is demonstrated %D below: %D %D \startbuffer %D \def\cw#1{\color[white]{#1}} %D %D \startMPpositiongraphic{tableshade} %D initialize_area(\MPpos{\MPvar{from}},\MPpos{\MPvar{to}}) ; %D color c ; c := \MPvar{color} ; %D linear_shade(pxy,0,.4c,.9c) ; %D anchor_area(\MPanchor{\MPvar{from}}) ; %D \stopMPpositiongraphic %D %D \setMPpositiongraphic{b:x}{tableshade}{from=b:x,to=e:x,color=red} %D \setMPpositiongraphic{b:y}{tableshade}{from=b:y,to=e:y,color=green} %D \setMPpositiongraphic{b:z}{tableshade}{from=b:z,to=e:z,color=blue} %D \stopbuffer %D %D \typebuffer \getbuffer %D %D The definition of the table looks about the same as the %D previous one: %D %D \startbuffer %D \starttable[|c|c|c|] %D \GFC[b:z] \cw{this is a small} \NC \cw{table} \NC in which we \NC \FR %D \NC \cw{will demonstrate} \GFC[c:y] \cw{that this} \GTC[c] \cw{positioning} \NC \MR %D \GSC[a:x] \cw{mechanism also} \GTC[b] \cw{works quite well} \NC in tables \NC \LR %D \stoptable %D \stopbuffer %D %D \typebuffer %D %D \getbuffer % \definepositionframed[w][background=color,backgroundcolor=yellow] % \definepositionframed[x][background=color,backgroundcolor=red] % \definepositionframed[y][background=color,backgroundcolor=green] % \definepositionframed[z][background=color,backgroundcolor=blue] % % \starttabulate[|c|c|c|] % \NC this is a small \NC table \NC in which we \NC \FR % \NC will demonstrate \NC that this \NC positioning \NC \MR % \NC mechanism also \NC works quite well \NC in tables \NC \LR % \stoptabulate % % \starttabulate[|c|c|c|] % \GFC[f:x] this is a small \GTC table \NC in which we \NC \FR % \NC will demonstrate \GFC[g:z] that this \GTC[g] positioning \NC \MR % \GSC[e:y] mechanism also \GTC[f] works quite well \NC in tables \NC \LR % \stoptabulate % % \starttabulate[|c|c|c|] % \GFC[f:x,d:w] this is a small \GTC[d] table \NC in which we \NC \FR % \NC will demonstrate \GFC[g:z] that this \GTC[g] positioning \NC \MR % \GSC[e:y] mechanism also \GTC[f] works quite well \NC in tables \NC \LR % \stoptabulate % % \starttabulate[|c|c|c|] % \XC[+f:x] this is a small \XC table \NC in which we \NC \FR % \NC will demonstrate \XC[+g:z] that this \XC[-g] positioning \NC \MR % \XC[=e:y] mechanism also \XC[-f] works quite well \NC in tables \NC \LR % \stoptabulate % % \starttabulate[|c|c|c|] % \XC[+f:x,+d:w] this is a small \XC[-d] table \NC in which we \NC \FR % \NC will demonstrate \XC[+g:z] that this \XC[-g] positioning \NC \MR % \XC[=e:y] mechanism also \XC[-f] works quite well \NC in tables \NC \LR % \stoptabulate % evt [b:x] % % \definepositionframed[x][background=color,fillcolor=red] % \definepositionframed[y][background=color,fillcolor=green] % \definepositionframed[z][background=color,fillcolor=blue] \def\remappositionframed#1#2% from to {\copyposition{b:#1}{b:#2}% \copyposition{e:#1}{e:#2}% \dosetpositionaction{b:#2}{\dopositionaction{b:#1}}} \def\definepositionframed {\dodoubleargument\dodefinepositionframed} \def\dodefinepositionframed[#1][#2]% {\dosetpositionaction{b:#1}{\dopositionframed[#1][#2]}} \def\positionframed {\dodoubleempty\dopositionframed} \def\dopositionframed[#1][#2]% {\bgroup \setbox\scratchbox\hbox {\dimen0=\MPx{e:#1}% \advance\dimen0 -\MPx{b:#1}% \dimen2=\MPy{b:#1}% \advance\dimen2 -\MPy{e:#1}% \advance\dimen2 \MPd{e:#1}% \lower\dimen2\hbox {\advance\dimen2 \MPh{b:#1}% \framed [\c!width=\dimen0,\c!height=\dimen2, \c!offset=\v!overlay,#2]{}}}% \smashedbox\scratchbox \egroup} % \def\sethdistances#1% % {\hbox{\lpos{ml:#1}\hpos{mh:#1}{\strut}\rpos{mr:#1}}} % % \def\gethdistances#1% % {\scratchdimen\MPx{mh:#1}% % \advance\scratchdimen -\MPx{ml#1}% % \edef\lefthdistance{\the\scratchdimen}% % \scratchdimen\MPx{mr:#1}% % \advance\scratchdimen -\MPx{mh:#1}% % \edef\righthdistance{\the\scratchdimen}} \protect \endinput % todo 1: shift down option \startuseMPgraphic{mpos:par:columnset} \iftracepositions show_multi_pars \else draw_multi_pars \fi ; path p ; p := boundingbox currentpicture ; currentpicture := currentpicture shifted (0,-StrutDepth/2) ; setbounds currentpicture to p ; \stopuseMPgraphic \setupcolors[state=start] \definetextbackground[underline][location=text,alternative=1,background=,frame=off,distance=2pt] \definestartstop [underline] [before={\starttextbackground[underline]}, after=\stoptextbackground]