%D \module %D [ file=anch-pos, % was core-pos %D version=1999.08.01, %D title=\CONTEXT\ Anchoring Macros, %D subtitle=Positioning Support, %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 / Positioning} %D In \MKIV\ there was already a different housekeeping model for positions quite %D early, but starting in 2012 more dramatic changes started to happen, especially %D in relation to background graphics. It will probably take some time to settle. \registerctxluafile{anch-pos}{1.001} \unprotect %D The first application of positional information was embedded graphics. Since we %D are interacting with text, it made sense to take the current line height and %D depth into account too. This is why we have position macros for simple positions %D and one boxes. %D %D \starttyping %D \dosetposition {identifier} %D \dosetpositionwhd {identifier} {width} {height} {depth} %D \dosetpositionplus {identifier} {width} {height} {depth} {list} %D \stoptyping \def\dosaveposition #1#2#3#4{\ctxcommand{setpos("#1",\number#2,\number\dimexpr#3,\number\dimexpr#4)}} \def\dosavepositionwhd #1#2#3#4#5#6#7{\ctxcommand{setpos("#1",\number#2,\number\dimexpr#3,\number\dimexpr#4,\number\dimexpr#5,\number\dimexpr#6,\number\dimexpr#7)}} \def\dosavepositionplus#1#2#3#4#5#6#7#8{\ctxcommand{setpos("#1",\number#2,\number\dimexpr#3,\number\dimexpr#4,\number\dimexpr#5,\number\dimexpr#6,\number\dimexpr#7,"#8")}} \def\dosetposition #1{\ctxcommand{posxy("#1")}} \def\dosetpositionwhd #1#2#3#4{\ctxcommand{poswhd("#1",\number\dimexpr#2,\number\dimexpr#3,\number\dimexpr#4)}} \def\dosetpositionplus#1#2#3#4#5{\ctxcommand{posplus("#1",\number\dimexpr#2,\number\dimexpr#3,\number\dimexpr#4,"#5")}} \def\dosetpositionbox #1#2{\ctxcommand{poswhd("#1",\number\wd#2,\number\ht#2,\number\dp#2)}} \def\dosetpositionstrut #1{\ctxcommand{posstrut("#1")}} \newbox\b_anch_position \newif \ifpositioning % sort of public %D Sometimes we want to trick the position handler a bit: \def\replacepospxywhd#1#2#3#4#5#6#7% when used we can better make a helper {\ctxcommand{replacepospxywhd('#1',\number#2,\number\dimexpr#3,\number\dimexpr#4,\number\dimexpr#5,\number\dimexpr#6,\number\dimexpr#7)}} %D \macros %D {MPp, MPx, MPy, MPw, MPh, MPd, MPxy, MPll, MPlr, MPur, MPul, MPpos, MPanchor} %D %D Access to the positional information is provided by macros with short names %S that are clearly meant for \METAPOST\ but nowadays also used for other purposes. \def\MPp #1{\ctxcommand{MPp("#1")}} \let\MPpage \MPp \def\MPr #1{\ctxcommand{MPr("#1")}} \let\MPregion \MPr \def\MPc #1{\ctxcommand{MPc("#1")}} \let\MPcolumn \MPc \def\MPn #1{\ctxcommand{MPn("#1")}} \let\MPparagraph\MPn \def\MPx #1{\ctxcommand{MPx("#1")}} \def\MPy #1{\ctxcommand{MPy("#1")}} \def\MPw #1{\ctxcommand{MPw("#1")}} % first we need to replace \MPwidth etc \def\MPh #1{\ctxcommand{MPh("#1")}} \def\MPd #1{\ctxcommand{MPd("#1")}} \def\MPxy #1{\ctxcommand{MPxy("#1")}} \def\MPll #1{\ctxcommand{MPll("#1")}} \def\MPlr #1{\ctxcommand{MPlr("#1")}} \def\MPur #1{\ctxcommand{MPur("#1")}} \def\MPul #1{\ctxcommand{MPul("#1")}} \def\MPpos #1{\ctxcommand{MPpos("#1")}} \let\MPanchor\MPpos % overloaded locally when needed \def\MPe #1{\ctxcommand{MPe("#1")}} \def\MPls #1{\ctxcommand{MPls("#1")}} \let\MPleftskip\MPls % compatible feature \def\MPrs #1{\ctxcommand{MPrs("#1")}} \let\MPrightkip\MPrs % compatible feature \def\MPpardata#1{\ctxcommand{MPpardata("#1")}} \def\MPxywhd #1{\ctxcommand{MPxywhd("#1")}} %D \macros %D {MPplus, MPrest, MPv, MPvv} %D %D Since we will probably keep on extending, we provide a general extension %D macro. The plus alternative takes an extra argument, denoting what additional %D parameter to pick 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#1#2#3{\ctxcommand{MPplus("#1",#2,"#3")}} \let\MPv \MPplus \def\MPrest #1#2{\ctxcommand{MPrest("#1","#2")}} \let\MPvv\MPrest %D There are two low level positioning macros. Both store the position as well %D as execute an action associated with that position. \let\dopositionaction\gobbleoneargument % implemented later \def\anch_positions_initialize {\ifpositioning \else \global\positioningtrue \fi} \unexpanded\def\setpositiononly {\iftrialtypesetting \expandafter\gobbleoneargument \else \expandafter\anch_positions_set_only_indeed \fi} \def\anch_positions_set_only_indeed#1% {\anch_positions_initialize \edef\currentposition{#1}% \dosetposition\currentposition} \unexpanded\def\setposition {\iftrialtypesetting \expandafter\gobbleoneargument \else \expandafter\anch_positions_set_indeed \fi} \def\anch_positions_set_indeed#1% {\anch_positions_initialize \edef\currentposition{#1}% \dosetposition\currentposition \anch_positions_trace_left \dopositionaction\currentposition} \unexpanded\def\setpositiondata {\iftrialtypesetting \expandafter\gobblefourarguments \else \expandafter\anch_positions_set_data_indeed \fi} \def\anch_positions_set_data_indeed#1#2#3#4% {\anch_positions_initialize \hbox {\edef\currentposition{#1}% \dosetpositionwhd\currentposition{#2}{#3}{#4}% already \the\dimexpr \anch_positions_trace_left \dopositionaction\currentposition \hss}} \unexpanded\def\setpositionbox {\iftrialtypesetting \expandafter\anch_positions_set_box_nop \else \expandafter\anch_positions_set_box_yes \fi} \def\anch_positions_set_box_nop#1% {\dowithnextboxcs\flushnextbox} \def\anch_positions_set_box_yes#1% {\dowithnextbox{\anch_positions_set_box_finish{#1}}} \def\anch_positions_set_box_finish#1% {\anch_positions_initialize \hbox to \wd\nextbox {\edef\currentposition{#1}% \dosetpositionbox\currentposition\nextbox \anch_positions_trace_left \setbox\b_anch_position\box\nextbox \dopositionaction\currentposition \box\b_anch_position \hss}} \unexpanded\def\setpositionstrut {\iftrialtypesetting \expandafter\anch_positions_set_strut_nop \else \expandafter\anch_positions_set_strut_yes \fi} \def\anch_positions_set_strut_nop#1% {\strut} \def\anch_positions_set_strut_yes#1% {\anch_positions_initialize \hbox to \zeropoint {\edef\currentposition{#1}% \dosetpositionstrut\currentposition \anch_positions_trace_left \dopositionaction\currentposition \strut \hss}} \unexpanded\def\setpositiondataplus {\iftrialtypesetting \expandafter\gobblefivearguments \else \expandafter\anch_positions_set_plus_indeed \fi} \def\anch_positions_set_plus_indeed#1#2#3#4#5% {\anch_positions_initialize \hbox % just package {\edef\currentposition{#1}% \dosetpositionplus\currentposition{#2}{#3}{#4}{#5}% already \the\dimexpr \anch_positions_trace_right \dopositionaction\currentposition \hss}} \unexpanded\def\setpositionplus {\iftrialtypesetting \expandafter\anch_positions_set_plus_nop \else \expandafter\anch_positions_set_plus_yes \fi} \def\anch_positions_set_plus_nop#1#2% {\dowithnextboxcs\flushnextbox} \def\anch_positions_set_plus_yes#1#2% {\dowithnextbox{\anch_positions_set_plus_yes_finish{#1}{#2}}} \def\anch_positions_set_plus_yes_finish#1#2% {\anch_positions_initialize \hbox to \nextboxwd {\edef\currentposition{#1}% \dosetpositionplus\currentposition{\wd\nextbox}{\ht\nextbox}{\dp\nextbox}{#2}% \anch_positions_trace_right \setbox\b_anch_position\flushnextbox \dopositionaction\currentposition \box\b_anch_position \hss}} \let\currentposition\s!unknown %D A few special ones .. will be cleaned up \def\pageanchor {page:\the\realpageno} % for the moment only one pagesize \def\textanchor {text:\the\realpageno} \def\regionanchor{region:0} \newcount\c_anch_column % will be delegated to lua \newcount\c_anch_text % will be delegated to lua \unexpanded\def\anch_mark_column_box#1% {\global\advance\c_anch_column\plusone \ctxcommand{markregionbox(\number#1,"columnarea:\the\c_anch_column")}} % extra height \unexpanded\def\anch_mark_region_box {\iftrialtypesetting \singleexpandafter\gobbleoneargument \else\ifpositioning \doubleexpandafter\anch_mark_region_box_indeed \else \doubleexpandafter\gobbleoneargument \fi\fi} \unexpanded\def\anch_mark_region_box_indeed#1% {\ctxcommand{markregionbox(\number#1)}} \unexpanded\def\anch_mark_flow_box#1% will be extended / renamed {\hbox\bgroup \global\advance\c_anch_text\plusone \ctxcommand{markregionbox(\number#1,"textarea:\the\c_anch_text")}% \box#1% \egroup} \unexpanded\def\anch_mark_flow_only#1% will be extended / renamed {\global\advance\c_anch_text\plusone \ctxcommand{markregionbox(\number#1,"textarea:\the\c_anch_text",true)}} \unexpanded\def\anch_make_page_box#1% maybe like text {\ctxcommand{markregionbox(\number#1,"\pageanchor")}} % needs an hbox \unexpanded\def\anch_mark_text_box#1% {\ctxcommand{markregionbox(\number#1,"\textanchor")}} % needs an hbox %D We can copy a position with: %D %D \starttyping %D \copyposition {to} {from} %D \stoptyping %D %D Again, this is a global operation. \def\copyposition#1#2{\ctxcommand{copyposition('#1','#2')}} %D The fact that handling positions is a two pass operation, is one of the %D reasons why we need to be able to test for existence, using: %D %D \starttyping %D \doifpositionelse {identifier} {found action} {not found action} %D \stoptyping \def\doifpositionelse#1{\ctxcommand{doifpositionelse('#1')}} \def\doifposition #1{\ctxcommand{doifposition('#1')}} %D \macros %D {xypos} %D %D We have several macros available to save positions. Later we will see %D 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 \stoptabulate %D %D Each macro takes an identifier as argument, and the \type %D {\hpos} and \type {\vpos} also expect box content. \let\xypos\setpositiononly \unexpanded\def\hpos#1{\dontleavehmode\setpositionbox{#1}\hbox} \unexpanded\def\vpos#1{\setpositionbox{#1}\vbox} \unexpanded\def\bpos#1{\dontleavehmode \setpositionstrut{b:#1}\ignorespaces} \unexpanded\def\epos#1{\removeunwantedspaces\setpositionstrut{e:#1}} %D When we want to calculate more complex backgrounds, we need to know what the %D current indentation scheme is. At the cost of many positions and memory, we %D can keep track of them. This mechanism is activated automatically based on %D information collected in the previous pass. \newtoks \t_anch_positions_tracers \newcount\c_anch_positions_paragraph \unexpanded\def\tracepositions {\the\t_anch_positions_tracers} \unexpanded\def\enableparpositions % global {\global\let\registerparoptions\doregisterparoptions \global\positioningtrue} \let\disableparpositions\relax \let\registerparoptions\relax \unexpanded\def\doregisterparoptions {\iftrialtypesetting \else \ifinpagebody \else \ifmmode \else \ifinformula \else \anch_positions_register_par_options \fi \fi \fi \fi} \def\anch_positions_register_par_options_normal {\dontleavehmode\ctxcommand{parpos()}} \def\anch_positions_register_par_options_traced {\anch_positions_register_par_options_normal \smashedhbox to \zeropoint {\hss \startcolor[blue]% \llap{\infofont\number\c_anch_positions_paragraph}% \vrule \s!width 4\onepoint \s!height2\onepoint \s!depth 2\onepoint \stopcolor \hss}} \let\anch_positions_register_par_options\anch_positions_register_par_options_normal \appendtoks \let\anch_positions_register_par_options\anch_positions_register_par_options_traced \to \t_anch_positions_tracers \unexpanded\def\anch_positions_trace#1#2#3% {\smashedhbox {#1{\infofont#2#3}% \kern-\onepoint \vrule\s!width2\onepoint\s!height\halfapoint\s!depth\halfapoint}} \unexpanded\def\anch_positions_trace_left_indeed {\anch_positions_trace\llap\darkmagenta{\currentposition>}} \unexpanded\def\anch_positions_trace_right_indeed {\anch_positions_trace\rlap\darkcyan{<\currentposition}} \let\anch_positions_trace_left \relax \let\anch_positions_trace_right\relax \appendtoks \let\anch_positions_trace_left \anch_positions_trace_left_indeed \let\anch_positions_trace_right \anch_positions_trace_right_indeed \to \t_anch_positions_tracers % \appendtoks \registerparoptions \to \everypar %D \macros %D {doifoverlappingelse} %D %D A first application of positional information, is to determine if two %D 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{\ctxcommand{doifoverlappingelse("#1","#2")}} %D \macros %D {doifpositionsonsamepageelse, %D doifpositionsonthispageelse} %D %D Instead of letting the user handle fuzzy expansion, we provide a simple test on %D positions 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\doifpositionsonsamepageelse#1{\ctxcommand{doifpositionsonsamepageelse("#1")}} \def\doifpositionsonthispageelse#1{\ctxcommand{doifpositionsonthispageelse("#1")}} \protect \endinput