%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}{} \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{\clf_dosaveposition {#1}#2 #3 #4\relax} \def\dosavepositionwhd #1#2#3#4#5#6#7{\clf_dosavepositionwhd {#1}#2 #3 #4 #5 #6 #7\relax} \def\dosavepositionplus#1#2#3#4#5#6#7#8{\clf_dosavepositionplus{#1}#2 #3 #4 #5 #6 #7{#8}} \def\dosetposition #1{\clf_dosetposition {#1}} % {} expands \def\dosetpositionwhd #1#2#3#4{\clf_dosetpositionwhd {#1}#2 #3 #4\relax} \def\dosetpositionplus#1#2#3#4#5{\clf_dosetpositionplus {#1}#2 #3 #4{#5}} \def\dosetpositionbox #1#2{\clf_dosetpositionbox {#1}#2\relax} \def\dosetpositionstrut #1{\clf_dosetpositionstrut {#1}} \def\dosetpositionstrutkind #1#2{\clf_dosetpositionstrutkind{#1}#2\relax} % #2 = number \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 {\clf_replacepospxywhd{#1}#2 #3 #4 #5 #6 #7\relax} %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{\clf_MPp {#1}} \def\MPr #1{\clf_MPr {#1}} \def\MPc #1{\clf_MPc {#1}} \def\MPn #1{\clf_MPn {#1}} \def\MPx #1{\clf_MPx {#1}} \def\MPy #1{\clf_MPy {#1}} \def\MPw #1{\clf_MPw {#1}} \def\MPh #1{\clf_MPh {#1}} \def\MPd #1{\clf_MPd {#1}} \def\MPxy #1{\clf_MPxy {#1}} \def\MPwhd #1{\clf_MPwhd {#1}} \def\MPll #1{\clf_MPll {#1}} \def\MPlr #1{\clf_MPlr {#1}} \def\MPur #1{\clf_MPur {#1}} \def\MPul #1{\clf_MPul {#1}} \def\MPpos #1{\clf_MPpos {#1}} \def\MPls #1{\clf_MPls {#1}} \def\MPrs #1{\clf_MPrs {#1}} \def\MPpardata#1{\clf_MPpardata{#1}} \def\MPxywhd #1{\clf_MPxywhd {#1}} \def\MPposset #1{\clf_MPposset {#1}} \let\MPpage \MPp \let\MPregion \MPr \let\MPcolumn \MPc \let\MPparagraph\MPn \let\MPanchor \MPpos % overloaded locally when needed \let\MPleftskip \MPls % compatible feature \let\MPrightkip \MPrs % compatible feature %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{\clf_MPplus{#1}#2{#3}} \let\MPv \MPplus \def\MPrest #1#2{\clf_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 % \hpack {\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 % \hpack {\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 % \hpack {\edef\currentposition{#1}% \dosetpositionstrut\currentposition \anch_positions_trace_left \dopositionaction\currentposition \strut \hss}} \unexpanded\def\setpositionstrutkind {\iftrialtypesetting \expandafter\anch_positions_set_strut_kind_nop \else \expandafter\anch_positions_set_strut_kind_yes \fi} \def\anch_positions_set_strut_kind_yes#1#2% {\anch_positions_initialize \hbox to \zeropoint % \hpack {\edef\currentposition{#1}% \dosetpositionstrutkind\currentposition{#2}% \anch_positions_trace_left \dopositionaction\currentposition \strut \hss}} \def\anch_positions_set_strut_kind_nop#1#2% {\strut} \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 % \hpack {\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 % \hpack {\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 % beware we need to pass \somethingexpanded or { } \unexpanded\def\anch_mark_column_box#1% {\global\advance\c_anch_column\plusone \clf_markregionboxtagged#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% {\clf_markregionbox#1\relax} \unexpanded\def\anch_mark_flow_box#1% will be extended / renamed {\hpack\bgroup % \hpack \global\advance\c_anch_text\plusone \clf_markregionboxtagged#1{textarea:\the\c_anch_text}% \box#1% \egroup} \unexpanded\def\anch_mark_tagged_box#1#2% {\clf_markregionboxtagged#1{#2}} \unexpanded\def\anch_mark_flow_only#1% will be extended / renamed {\global\advance\c_anch_text\plusone \clf_markregionboxcorrected#1{textarea:\the\c_anch_text}} \unexpanded\def\anch_make_page_box#1% maybe like text {\clf_setregionboxtagged#1{page:\the\realpageno}} \unexpanded\def\anch_mark_text_box#1% {\clf_markregionboxtagged#1{text:\the\realpageno}} % needs an hbox \newcount\c_anch_free \unexpanded\def\anch_mark_tagged_box_free#1#2#3#4#5#6% only needed when positions {\ifpositioning \global\advance\c_anch_free\plusone % could be done at the lua end \clf_markregionboxtaggedkind #1% {free:\number\c_anch_free}% #2\space % kind #3\space % leftoffset #4\space % rightoffset #5\space % topoffset #6\relax % bottomoffset \fi} \def\reservedautoregiontag{\clf_reservedautoregiontag} %D We can copy a position with: %D %D \starttyping %D \copyposition {to} {from} %D \stoptyping %D %D Again, this is a global operation. \unexpanded\def\copyposition#1#2% {\clf_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 \unexpanded\def\doifposition #1{\clf_doifposition {#1}} \unexpanded\def\doifelseposition #1{\clf_doifelseposition {#1}} \unexpanded\def\doifelsepositiononpage#1#2{\clf_doifelsepositiononpage{#1}#2\relax} \let\doifpositionelse \doifelseposition \let\doifpositiononpageelse\doifelsepositiononpage %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 {\hpos} and %D \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}} \unexpanded\def\bposkind#1#2{\dontleavehmode\setpositionstrutkind{b:#1}{#2}\ignorespaces} % not public, used in backgrounds \unexpanded\def\eposkind#1#2{\removeunwantedspaces\setpositionstrutkind{e:#1}{#2}} % not public, used in backgrounds %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 {\glet\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\clf_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 \unexpanded\def\doifelseoverlapping#1#2{\clf_doifelseoverlapping{#1}{#2}} \let\doifoverlappingelse\doifelseoverlapping %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 \unexpanded\def\doifelsepositionsonsamepage#1{\clf_doifelsepositionsonsamepage{#1}} \unexpanded\def\doifelsepositionsonthispage#1{\clf_doifelsepositionsonthispage{#1}} \let\doifpositionsonsamepageelse\doifelsepositionsonsamepage \let\doifpositionsonthispageelse\doifelsepositionsonthispage %D Moved here: \unexpanded\def\doifelsepositionsused{\clf_doifelsepositionsused} \let\doifpositionsusedelse\doifelsepositionsused %D Moved here: \unexpanded\def\savepos {\clf_savepos} \unexpanded\def\lastxpos{\numexpr\clf_lastxpos\relax} \unexpanded\def\lastypos{\numexpr\clf_lastypos\relax} \protect \endinput