%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 the reference point %D on the page. The next macros do so and are hooked into the page building routine. \registerctxluafile{anch-pgr}{} \unprotect %D A few more low level macros take care of defining and recalling actions. Actions %D are saved globally! The lists can become quite long because there can be lots of %D parameters passed on so we clean up the list afterwards. \newtoks\everypositionaction \newtoks\everyinsertpositionaction \newtoks\everycleanpositionaction \installcorenamespace{positionaction} \installcorenamespace{positioncleanup} \unexpanded\def\anch_positions_set_action#1% {\expandafter\gdef\csname\??positionaction#1\endcsname} % nicely gobbles spaces \unexpanded\def\doifpositionaction#1% {\ifcsname\??positionaction#1\endcsname \expandafter\firstofoneargument \else \expandafter\gobbleoneargument \fi} \unexpanded\def\doifelsepositionaction#1% {\ifcsname\??positionaction#1\endcsname \expandafter\firstoftwoarguments \else \expandafter\secondoftwoarguments \fi} \let\doifpositionactionelse\doifelsepositionaction \unexpanded\def\dopositionaction#1% {\edef\currentpositionaction{#1}% \ifcsname\??positionaction\currentpositionaction\endcsname \anch_positions_action_indeed \fi} \def\anch_positions_action_indeed {\doifelseposition\currentpositionaction \anch_positions_action_indeed_yes \anch_positions_action_indeed_nop} \def\anch_positions_action_indeed_nop {\anch_positions_trace_action_nop} \def\anch_positions_action_indeed_yes % we need a way to figure out if we have actions {\begingroup \setbox\scratchbox\hbox % \hpack {\anch_positions_trace_action_yes \the\everyinsertpositionaction \the\everypositionaction \begincsname\??positionaction\currentpositionaction\endcsname \anch_positions_cleanup_action}% \smashedbox\scratchbox % smashing is really needed else we get problems with too big overlays \endgroup} \unexpanded\def\anch_positions_trace_action_nop_indeed {\anch_positions_trace\clap\darkred{<\currentpositionaction>}} \unexpanded\def\anch_positions_trace_action_yes_indeed {\anch_positions_trace\clap\darkgreen{<\currentpositionaction>}} \let\anch_positions_trace_action_nop\relax \let\anch_positions_trace_action_yes\relax \appendtoks \let\anch_positions_trace_action_nop\anch_positions_trace_action_nop_indeed \let\anch_positions_trace_action_yes\anch_positions_trace_action_yes_indeed \to \t_anch_positions_tracers %D Here the complication has to do with collecting actions for later execution. This %D collection is especially handy when we want to move actions to a specific layer. %D Such series of actions are stored in a macro that is cleaned up after each %D invocation. \def\anch_positions_cleanup_action % not in trialtypesetting {\ifcsname\??positioncleanup\currentpositionaction\endcsname \the\everycleanpositionaction \setxvalue{\??positioncleanup\currentpositionaction}{\csname\??positioncleanup\currentpositionaction\endcsname}% \fi} \def\handlepositionaction#1\with#2\on#3% ugly {\begingroup \edef\currentpositionanchor {\ifx\currentpositionoverlay\empty#3\else\currentpositionoverlay::\MPanchoridentifier\fi}% \normalexpanded{\anch_positions_set_action{\currentpositionanchor}{\noexpand\getvalue{\??positioncleanup\currentpositionanchor}}}% \let#1\relax \ifcsname\??positioncleanup\currentpositionanchor\endcsname \setxvalue{\??positioncleanup\currentpositionanchor}% {\csname\??positioncleanup\currentpositionanchor\endcsname#1#2}% \else \setxvalue{\??positioncleanup\currentpositionanchor}% {#1#2}% \fi \endgroup} %D The first version of this module implemented head and tail anchors. Currently we %D stick to just one anchor and derive the head and tail anchors from this one. We %D set these anchors before and after each page. \newdimen\c_anch_page_width \newdimen\c_anch_page_height \unexpanded\def\anch_positions_register_page#1% this one is flushed first ! ... can't we avoid this one {\ifpositioning\ifcase\realpageno\or \ifdim\c_anch_page_height=\paperheight \ifdim\c_anch_page_width=\paperwidth % no change \else \c_anch_page_width \paperwidth \c_anch_page_height\paperheight \anch_make_page_box{#1}% \ifvbox#1\setbox#1\hpack{\box#1}\fi \fi \else \c_anch_page_width \paperwidth \c_anch_page_height\paperheight \anch_make_page_box{#1}% \ifvbox#1\setbox#1\hpack{\box#1}\fi \fi \fi\fi} \unexpanded\def\anch_positions_place_anchors {\ifpositioning \anch_positions_place_anchors_yes \else \anch_positions_place_anchors_nop \fi} \def\anch_positions_place_anchors_yes % todo : depth pagebox {\begingroup \setbox\scratchbox\emptyhbox \ht\scratchbox\textheight \dp\scratchbox\zeropoint % redundant \wd\scratchbox\makeupwidth \anch_mark_text_box\scratchbox \box\scratchbox \endgroup} \def\anch_positions_place_anchors_nop {\vkern\textheight} %D \macros %D {positionoverlay,startpositionoverlay} %D %D As long as we're dealing with graphics it makes much sense to use the available %D overlay mechanism. For this purpose, we 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 macros defined in an %D auxiliary \METAPOST\ module that is preloaded. %D %D \typebuffer[graphic] \def\MPanchoridentifier{mpa} % {mp-anchor} %D The rest of the definitions concerning such overlays may look complicated, \let\currentpositionoverlay\empty %D Position actions are automatically executed when a position is set. \def\textbackgroundoverlay#1{\v!text#1} \def\MPanchornumber {\the\realpageno} \unexpanded\def\positionoverlay % the test prevents too many redundant positions {\ifpositioning % in (not used) text* position layers \expandafter\anch_positions_overlay_indeed \else % also \iftrialtypesetting test here? \expandafter\gobbleoneargument \fi} \def\anch_positions_overlay_indeed#1% {\begingroup \edef\currentpositionoverlay{#1}% \ifcsname\??positionaction\currentpositionoverlay::\MPanchoridentifier\endcsname \anch_positions_overlay_compose \fi \endgroup} \def\MPoverlayanchor#1{\MPpos\MPanchorid} \def\anch_positions_overlay_compose {\vpack to \d_overlay_height {%\writestatus{!!!}{\currentpositionoverlay/\MPanchoridentifier/\MPanchornumber}% \edef\MPanchorid{\currentpositionoverlay::\MPanchoridentifier:\MPanchornumber}% realpageno % \edef\MPanchor##1{\MPpos\MPanchorid}% \let\MPanchor\MPoverlayanchor % no need to fetch it already, seldom used \the\everyinsertpositionaction \copyposition{\currentpositionoverlay::\MPanchoridentifier}\MPanchorid \setbox\scratchbox\hbox to \d_overlay_width % \hpack {\dopositionaction{\currentpositionoverlay::\MPanchoridentifier}\hss}% \ht\scratchbox\d_overlay_height \dp\scratchbox\zeropoint \anch_mark_tagged_box\scratchbox\MPanchorid % needs an hbox \box\scratchbox \vfill}} \unexpanded\def\positionregionoverlay % shares regions {\ifpositioning \expandafter\anch_positions_region_overlay_indeed \else % also \iftrialtypesetting test here? \expandafter\gobbletwoarguments \fi} \let\currentpositionregion\empty \def\anch_positions_region_overlay_indeed#1#2% {\begingroup \edef\currentpositionregion {#1}% \edef\currentpositionoverlay{#2}% \ifcsname\??positionaction\currentpositionoverlay::\MPanchoridentifier\endcsname \anch_positions_region_overlay_compose \fi \endgroup} \def\anch_positions_region_overlay_compose {\vpack to \d_overlay_height {\let\MPanchorid\currentpositionregion \let\MPanchor\MPoverlayanchor % no need to fetch it already, seldom used \the\everyinsertpositionaction \copyposition{\currentpositionoverlay::\MPanchoridentifier}\MPanchorid \setbox\scratchbox\hbox to \d_overlay_width % \hpack {\dopositionaction{\currentpositionoverlay::\MPanchoridentifier}\hss}% \ht\scratchbox\d_overlay_height \dp\scratchbox\zeropoint \box\scratchbox \vfill}} % \let\anch_positions_overlay_nop\gobbleoneargument \unexpanded\def\startpositionoverlay {\iftrialtypesetting \expandafter\anch_positions_overlay_start_nop \else \expandafter\anch_positions_overlay_start_yes \fi} \let\stoppositionoverlay\relax \def\anch_positions_overlay_start_nop#1\stoppositionoverlay {} \ifdefined\checkpositionoverlays \else \let\checkpositionoverlays\relax \fi \let\currentpositionoverlay\empty \def\anch_positions_overlay_start_yes#1% {\checkpositionoverlays \edef\currentpositionoverlay{#1}} \unexpanded\def\stoppositionoverlay {\let\currentpositionoverlay\empty} %D A position graphic is a normal (non||reused) \METAPOST\ graphic, used %D immediately, with zero dimensions, so that a sequence of them does not harm. \installcorenamespace{positiongraphic} \installcorenamespace{positionmethod} %installcorenamespace{graphicvariable} \newbox\b_anch_positions_graphic \def\startMPpositiongraphic % id setups {\dodoublegroupempty\anch_positions_meta_graphic_start} \def\anch_positions_meta_graphic_start#1#2#3\stopMPpositiongraphic % tag list mpcode {\setgvalue{\??positiongraphic#1}{\anch_positions_meta_graphic_use{#1}{#2}{#3}}} \let\stopMPpositiongraphic\relax \def\anch_positions_meta_graphic_prepare {\ifcsname\??graphicvariable\currentmpvariableclass:self\endcsname \else \letvalue{\??graphicvariable\currentmpvariableclass:self}\currentposition \fi \ifcsname\??graphicvariable\currentmpvariableclass:from\endcsname \else \letvalue{\??graphicvariable\currentmpvariableclass:from}\currentposition \fi} \def\anch_positions_meta_graphic_use#1#2#3% {\begingroup \meta_prepare_variables{#2}% \anch_positions_meta_graphic_prepare \startMPcode#3\stopMPcode \endgroup} \unexpanded\def\MPpositiongraphic {\dodoublegroupempty\anch_positions_meta_graphic_direct} \def\anch_positions_meta_graphic_direct#1% tag setups {\ifcsname\??positionmethod#1\endcsname % method \expandafter\anch_positions_meta_graphic_direct_indeed_method \else\ifcsname\??positiongraphic#1\endcsname \doubleexpandafter\anch_positions_meta_graphic_direct_indeed_normal \else \doubleexpandafter\anch_positions_meta_graphic_direct_indeed_unknown \fi\fi{#1}} \let\anch_positions_meta_graphic_direct_indeed_unknown\gobbletwoarguments \def\anch_positions_meta_graphic_direct_indeed_method {\anch_positions_meta_graphic_direct_indeed\??positionmethod} \def\anch_positions_meta_graphic_direct_indeed_normal {\anch_positions_meta_graphic_direct_indeed\??positiongraphic} \def\anch_positions_meta_graphic_direct_indeed#1#2#3% what tag setups {\begingroup \setupMPvariables[#2][#3]% \edef\currentmpvariableclass{#2}% \anch_positions_meta_graphic_prepare \obeyMPboxorigin % do we also set the size ? when needed this must be done in mp ... might change \def\anch_positions_meta_graphic_direct{\anch_positions_meta_graphic_nested{#3}}% takes two extra arguments \setbox\b_anch_positions_graphic\hbox % \hpack {\ignorespaces\begincsname#1#2\endcsname\removelastspace}% \smashbox\b_anch_positions_graphic \box\b_anch_positions_graphic \endgroup} \def\anch_positions_meta_graphic_nested#1#2#3% nesting used in prikkels / pascal (might go away) {\begingroup \setupMPvariables[#2][#1,#3]% \edef\currentmpvariableclass{#2}% \anch_positions_meta_graphic_prepare \begincsname\??positiongraphic#2\endcsname \endgroup}% \def\startMPpositionmethod#1#2\stopMPpositionmethod {\setgvalue{\??positionmethod#1}{#2}} % todo: var list here \let\stopMPpositionmethod\relax %D Simple one position graphics. \unexpanded\def\setMPpositiongraphic {\dotriplegroupempty\anch_positions_meta_graphic_set} \def\anch_positions_meta_graphic_set#1#2#3% pos tag vars {\ifx\currentpositionoverlay\empty \anch_positions_set_action{#1}{\MPpositiongraphic{#2}{#3}}% \else % silly can be one \anch_positions_meta_graphic_handle{#1}{#2}{#3}% \fi} \def\anch_positions_meta_graphic_handle#1#2#3% combine with boxes {\handlepositionaction\anch_positions_meta_graphic_handle_indeed\with{#1}{#2}{#3}\on{#2}} \def\anch_positions_meta_graphic_insert#1#2#3% pos tag setups {\ifnum\MPp{#1}=\realpageno\relax % extra saveguard \def\currentposition{#1}\MPpositiongraphic{#2}{#3}% \fi} \let\anch_positions_meta_graphic_handle_indeed\relax \appendtoks \let\anch_positions_meta_graphic_handle_indeed\anch_positions_meta_graphic_insert \to \everyinsertpositionaction \def\anch_positions_meta_graphic_cleanup#1#2#3% pos tag setups {\ifnum\MPp{#1}<\realpageno \else \noexpand\anch_positions_meta_graphic_handle_indeed{#1}{#2}{#3}% \fi} \appendtoks \let\anch_positions_meta_graphic_handle_indeed\anch_positions_meta_graphic_cleanup \to \everycleanpositionaction %D Graphics that span two positions (beware, does not cross pages). \unexpanded\def\setMPpositiongraphicrange {\doquadruplegroupempty\anch_positions_meta_graphic_set_range} \def\anch_positions_meta_graphic_set_range#1#2#3#4% bpos epos tag vars {\ifx\currentpositionoverlay\empty \anch_positions_set_action{#1}{\MPpositiongraphic{#3}{#4}}% \else \anch_positions_meta_graphic_handle_range{#1}{#2}{#3}{#4}% \fi} \def\anch_positions_meta_graphic_handle_range#1#2#3#4% {\handlepositionaction\anch_positions_meta_graphic_handle_range_indeed\with{#1}{#2}{#3}{#4}\on{#2}} \def\anch_positions_meta_graphic_insert_range#1#2#3#4% pos pos tag setups {\clf_doifelserangeonpage{#1}{#2}\realpageno {\def\currentposition{#1}% \MPpositiongraphic{#3}{#4}}% {}} \appendtoks \let\anch_positions_meta_graphic_handle_range_indeed\anch_positions_meta_graphic_insert_range \to \everyinsertpositionaction \def\anch_positions_meta_graphic_cleanup_range#1#2#3#4% pos tag setups {\ifnum\MPp{#2}<\realpageno \else \noexpand \anch_positions_meta_graphic_handle_range_indeed{#1}{#2}{#3}{#4}% \fi} \appendtoks \let\anch_positions_meta_graphic_handle_range_indeed\anch_positions_meta_graphic_cleanup_range \to \everycleanpositionaction \let\anch_positions_meta_graphic_handle_range_indeed\gobblefourarguments % Helpers: \def\MPgetposboxes #1#2{\clf_fetchposboxes{#1}{#2}\realpageno} \def\MPgetmultipars#1#2{\clf_fetchmultipar{#1}{#2}\realpageno} \protect \endinput