%D \module %D [ file=anch-pgr, % split off core-pos %D version=1999.08.01, %D title=\CONTEXT\ Anchoring Macros, %D subtitle=Positioning Graphics, %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. \writestatus{loading}{ConTeXt Anchoring Macros / Grapics} %D Before we come to graphics support, we have to make sure of %D the reference point on the page. The next macros do so and %D are hooked into the page building routine. \unprotect %D Here we implement position actions (was a dummy). \unexpanded\def\showanchor#1% {\normalexpanded{\writestatus{#1} {\MPp{#1}\string|\MPx{#1}\string|\MPy{#1}\string|\MPw{#1}\string|\MPh{#1}\string|\MPd{#1}}}} %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! %D %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. \newtoks\everypositionaction \newtoks\everyinsertpositionaction \newtoks\everycleanpositionaction \let\POSactionprefix\POSprefix \unexpanded\def\dosetpositionaction#1% {\setgvalue{\POSactionprefix#1::}} \def\doifpositionaction#1% {\ifcsname\POSactionprefix#1::\endcsname \expandafter\firstofoneargument \else \expandafter\gobbleoneargument \fi} \def\doifpositionactionelse#1% {\ifcsname\POSactionprefix#1::\endcsname \expandafter\firstoftwoarguments \else \expandafter\secondoftwoarguments \fi} \def\dopositionaction#1% test saves hash entry in etex {\ifcsname\POSactionprefix#1::\endcsname \positions_action_indeed{#1}% \fi} \def\positions_action_indeed#1% {\ifcase\MPp{#1}\relax \traceposstring\clap\cyan{<#1>}% shouldn't happen too often \else \begingroup \setbox\scratchbox\hbox {\traceposstring\clap\red{<#1>}% \the\everyinsertpositionaction \the\everypositionaction \csname\POSactionprefix#1::\endcsname \positions_cleanup_action{#1}}% \smashedbox\scratchbox % smashing is really needed else we get problems with too big overlays \endgroup \fi} %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. % this can probably be done better % \def\positions_cleanup_action#1% not in trialtypesetting % {\ifcsname\POSactionprefix#1++\endcsname % \the\everycleanpositionaction % \iflocalpositioning % \letgvalue{\POSactionprefix#1++}\empty % \else % \setxvalue{\POSactionprefix#1++}{\getvalue{\POSactionprefix#1++}}% % \fi % \fi} \def\positions_cleanup_action#1% not in trialtypesetting {\ifcsname\POSactionprefix#1++\endcsname \the\everycleanpositionaction \iflocalpositioning % erase \expandafter\let\csname\POSactionprefix#1++\endcsname\empty \else % globalize \global\expandafter\let\csname\POSactionprefix#1++\expandafter\endcsname\csname\POSactionprefix#1++\endcsname \fi \fi} \def\handlepositionaction#1\with#2\on#3% ugly {\begingroup \edef\!!stringa{\ifx\currentpositionoverlay\empty#3\else\currentpositionoverlay::\MPanchoridentifier\fi}% \edef\!!stringc{\POSactionprefix\!!stringa++}% \normalexpanded{\dosetpositionaction{\!!stringa}{\noexpand\getvalue{\!!stringc}}}% \global\let#1\relax \edef\!!stringb{\ifcsname\!!stringc\endcsname\csname\!!stringc\endcsname\fi}% why ... \setxvalue\!!stringc{\!!stringb#1#2}% \endgroup} %D The next macros do some housekeeping. \def\pageanchor{page:0} % for the moment only one pagesize \def\textanchor{text:\the\realpageno} %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. We set these %D anchors before and after each page. % FOR THE MOMENT DISABLED (was downward compatibity issue) % % \def\headanchor{head:\the\realpageno} % virtual position % \def\tailanchor{tail:\the\realpageno} % virtual position % % \def\presetpositionanchors % is this still needed? % {\ifpositioning % \positions_preset_anchors % \fi} % % \def\positions_preset_anchors % {\begingroup % \!!dimena\ifdim\topskip>\strutht\topskip\else\strutht\fi % \!!dimenb\dimexpr\MPy\textanchor+\MPh\textanchor-\!!dimena\relax % \!!dimenc\dimexpr\MPy\textanchor+\strutdp\relax % \!!dimend\MPx\textanchor % \!!dimene\MPw\textanchor % \replacepospxywhd\headanchor\realfolio\!!dimend\!!dimenb\!!dimene\!!dimena\strutdp % \replacepospxywhd\tailanchor\realfolio\!!dimend\!!dimenc\!!dimene\strutht \strutdp % \endgroup} % % \appendtoks \presetpositionanchors \to \beforeeverypage % \appendtoks \presetpositionanchors \to \aftereverypage % todo: change with each page size change .. can be made more efficient % as some values are the same .. this one can (at some point) be used % to provide correction for imposition \unexpanded\def\positions_register_page#1% this one is flushed first ! ... can't we avoid this one {\ifpositioning\ifcase\realpageno\or \ifdim\printpaperheight=\paperheight \ifdim\printpaperwidth=\paperwidth % not needed, \else \positions_register_page_indeed{#1}% \fi \else \positions_register_page_indeed{#1}% \fi \fi\fi} \def\positions_register_page_indeed#1% {\setbox#1\hbox{\hpos\pageanchor{\box#1}}} \unexpanded\def\positions_place_anchors {\ifpositioning \positions_place_anchors_yes \else \positions_place_anchors_nop \fi} % FOR THE MOMENT DISABLED % % \def\positions_place_anchors_yes % todo : depth pagebox % {\begingroup % \setbox\scratchbox\vbox to \textheight % {\simpletopskipcorrection % \hbox{\strut\dopositionaction\headanchor}% ! actions on a virtual position % \vfill % \hbox{\strut\dopositionaction\tailanchor}}% ! actions on a virtual position % \dp\scratchbox\zeropoint % \wd\scratchbox\makeupwidth % not \zeropoint, else wrong text backgrounds % \hpos\textanchor{\box\scratchbox}% % \endgroup} \def\positions_place_anchors_yes % todo : depth pagebox {\begingroup \setbox\scratchbox\emptyvbox \ht\scratchbox\textheight \dp\scratchbox\zeropoint \wd\scratchbox\makeupwidth \hpos\textanchor{\box\scratchbox}% \endgroup} \def\positions_place_anchors_nop {\vskip\textheight} %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::} %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. \let\MPanchornumber\realfolio \def\positionoverlay % the test prevents too many redundant positions {\ifpositioning % in (not used) text* position layers \expandafter\positions_overlay_indeed \else % also \iftrialtypesetting test here? \expandafter\gobbleoneargument \fi} % keep this for a while % % \def\positions_overlay_indeed#1% the test prevents too many redundant positions % {\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}} \def\positions_overlay_indeed#1% {\doifpositionactionelse{#1::\MPanchoridentifier}% \positions_overlay_yes\positions_overlay_nop{#1}} \def\positions_overlay_yes#1% {\vbox to \overlayheight {\edef\MPanchorid{#1::\MPanchoridentifier:\MPanchornumber}% \edef\MPanchor##1{\MPpos\MPanchorid}% \the\everyinsertpositionaction \copyposition{#1::\MPanchoridentifier}\MPanchorid \hpos \MPanchorid %{\hbox to \overlaywidth{\dopositionaction{#1::\MPanchoridentifier}\hss}}}% oscillation due to rounding issues {\setbox\scratchbox\hbox to \overlaywidth{\dopositionaction{#1::\MPanchoridentifier}\hss}% \ht\scratchbox\overlayheight \dp\scratchbox\zeropoint \box\scratchbox}% \vfill}} % \def\\positions_overlay_nop#1% % {\setbox\scratchbox\emptyvbox % \ht\scratchbox\overlayheight % \wd\scratchbox\overlaywidth % \box\scratchbox} \let\positions_overlay_nop\gobbleoneargument \unexpanded\def\startpositionoverlay {\iftrialtypesetting \expandafter\positions_overlay_start_nop \else \expandafter\positions_overlay_start_yes \fi} \def\positions_overlay_start_nop#1\stoppositionoverlay {} \def\positions_overlay_start_yes#1% {\def\currentpositionoverlay{#1}} \unexpanded\def\stoppositionoverlay {\let\currentpositionoverlay\empty} \def\resetpositionoverlay#1% {\dosetpositionaction{#1::\MPanchoridentifier::}{}} \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 % can be sped up \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\positions_mp_graphic_start} \def\positions_mp_graphic_start#1#2#3\stopMPpositiongraphic % tag list mpcode {\setgvalue{MPG:#1}{\positions_mp_graphic_use{#1}{#2}{#3}}} \let\stopMPpositiongraphic\relax \def\positions_mp_graphic_prepare {\ifcsname\@@meta self\endcsname\else\letvalue{\@@meta self}\currentposition\fi \ifcsname\@@meta from\endcsname\else\letvalue{\@@meta from}\currentposition\fi} \def\positions_mp_graphic_use#1#2#3% {\begingroup \prepareMPvariables{#2}% \positions_mp_graphic_prepare \enableincludeMPgraphics \startMPcode#3\stopMPcode \endgroup} \def\MPpositiongraphic {\dodoublegroupempty\positions_mp_graphic_direct} % \def\positions_mp_graphic_direct#1#2% tag setups % {\begingroup % \def\@@meta{#1:}% % \setupMPvariables[#2]% % \positions_mp_graphic_prepare % \MPshiftdrawingtrue % \def\positions_mp_graphic_direct{\positions_mp_graphic_nested{#2}}% takes two extra arguments % \setbox\positiongraphicbox\hbox % {\ignorespaces % \ifcsname MPM:#1\endcsname \csname MPM:#1\endcsname \else % \ifcsname MPG:#1\endcsname \csname MPG:#1\endcsname \fi\fi % \removelastspace}% % \smashbox\positiongraphicbox % \box\positiongraphicbox % \endgroup} \def\positions_mp_graphic_direct#1% tag setups {\ifcsname MPM:#1\endcsname \expandafter\positions_mp_graphic_direct_indeed_mpm \else\ifcsname MPG:#1\endcsname \doubleexpandafter\positions_mp_graphic_direct_indeed_mpg \else \doubleexpandafter\positions_mp_graphic_direct_indeed_nop \fi\fi{#1}} \let\positions_mp_graphic_direct_indeed_nop\gobbletwoarguments \def\positions_mp_graphic_direct_indeed_mpm {\positions_mp_graphic_direct_indeed{MPM}} \def\positions_mp_graphic_direct_indeed_mpg {\positions_mp_graphic_direct_indeed{MPG}} \def\positions_mp_graphic_direct_indeed#1#2#3% what tag setups {\begingroup \def\@@meta{#2:}% will become a commandhandler \setupMPvariables[#3]% \positions_mp_graphic_prepare \MPshiftdrawingtrue \def\positions_mp_graphic_direct{\positions_mp_graphic_nested{#3}}% takes two extra arguments \setbox\positiongraphicbox\hbox {\ignorespaces\csname#1:#2\endcsname\removelastspace}% \smashbox\positiongraphicbox \box\positiongraphicbox \endgroup} \def\positions_mp_graphic_nested#1#2#3% nesting used in prikkels / pascal {\begingroup \def\@@meta{#2:}% \setupMPvariables[#1,#3]% \positions_mp_graphic_prepare \getvalue{MPG:#2}% \endgroup}% \long\def\startMPpositionmethod#1#2\stopMPpositionmethod {\long\setgvalue{MPM:#1}{#2}} % todo: var list here \let\stopMPpositionmethod\relax %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 (beware, does not cross pages). \unexpanded\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 {\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 %D \macros %D {stackposdown, stackposup, stackposleft,stackposright} %D %D This is sort of obsolete as we have now stacking in the %D margin in a different way. \def\stackposdistance{.5em} \newcount\currentautopos \newcount\previousautopos \def\POSstackprefix{stack:} \unexpanded\def\dostackposbox#1#2% {\dowithnextbox {#2% \bgroup \previousautopos\currentautopos \global\advance\currentautopos\plusone \edef\currentposition {\POSstackprefix\number\currentautopos}% \edef\previousposition{\POSstackprefix\number\previousautopos}% \hpos\currentposition{\doifoverlappingelse\currentposition\previousposition{#1}{\flushnextbox}% \egroup}}% \hbox} \unexpanded\def\stackposup {\dostackposbox{\raise\lineheight\flushnextbox}} \unexpanded\def\stackposdown {\dostackposbox{\lower\lineheight\flushnextbox}} \unexpanded\def\stackposleft {\dostackposbox{\copy\nextbox\hskip\nextboxwd\hskip\stackposdistance}} \unexpanded\def\stackposright{\dostackposbox{\hskip\stackposdistance\hskip\nextboxwd\flushnextbox}} \protect \endinput