anch-pos.mkiv /size: 15 Kb    last modification: 2023-12-21 09:44
1%D \module
2%D   [       file=anch-pos, % was core-pos
3%D        version=1999.08.01,
4%D          title=\CONTEXT\ Anchoring Macros,
5%D       subtitle=Positioning Support,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14\writestatus{loading}{ConTeXt Anchoring Macros / Positioning}
15
16%D In \MKIV\ there was already a different housekeeping model for positions quite
17%D early, but starting in 2012 more dramatic changes started to happen, especially
18%D in relation to background graphics. It will probably take some time to settle.
19
20\registerctxluafile{anch-pos}{}
21
22\unprotect
23
24%D The first application of positional information was embedded graphics. Since we
25%D are interacting with text, it made sense to take the current line height and
26%D depth into account too. This is why we have position macros for simple positions
27%D and one boxes.
28%D
29%D \starttyping
30%D \dosetposition          {identifier}
31%D \dosetpositionwhd       {identifier} {width} {height} {depth}
32%D \dosetpositionplus      {identifier} {width} {height} {depth} {list}
33%D \stoptyping
34
35\def\dosaveposition            #1#2#3#4{\clf_dosaveposition    {#1}#2 #3 #4\relax}
36\def\dosavepositionwhd   #1#2#3#4#5#6#7{\clf_dosavepositionwhd {#1}#2 #3 #4 #5 #6 #7\relax}
37\def\dosavepositionplus#1#2#3#4#5#6#7#8{\clf_dosavepositionplus{#1}#2 #3 #4 #5 #6 #7{#8}}
38
39\def\dosetposition            #1{\clf_dosetposition         {#1}} % {} expands
40\def\dosetpositionwhd   #1#2#3#4{\clf_dosetpositionwhd      {#1}#2 #3 #4\relax}
41\def\dosetpositionplus#1#2#3#4#5{\clf_dosetpositionplus     {#1}#2 #3 #4{#5}}
42\def\dosetpositionbox       #1#2{\clf_dosetpositionbox      {#1}#2\relax}
43\def\dosetpositionstrut       #1{\clf_dosetpositionstrut    {#1}}
44\def\dosetpositionstrutkind #1#2{\clf_dosetpositionstrutkind{#1}#2\relax} % #2 = number
45
46\newbox\b_anch_position
47\newif \ifpositioning   % sort of public
48
49%D Sometimes we want to trick the position handler a bit:
50
51\def\replacepospxywhd#1#2#3#4#5#6#7% when used we can better make a helper
52  {\clf_replacepospxywhd{#1}#2 #3 #4 #5 #6 #7\relax}
53
54%D \macros
55%D   {MPp, MPx, MPy, MPw, MPh, MPd, MPxy, MPll, MPlr, MPur, MPul, MPpos, MPanchor}
56%D
57%D Access to the positional information is provided by macros with short names
58%S that are clearly meant for \METAPOST\ but nowadays also used for other purposes.
59
60\def\MPp      #1{\clf_MPp      {#1}}
61\def\MPr      #1{\clf_MPr      {#1}}
62\def\MPc      #1{\clf_MPc      {#1}}
63\def\MPn      #1{\clf_MPn      {#1}}
64\def\MPx      #1{\clf_MPx      {#1}}
65\def\MPy      #1{\clf_MPy      {#1}}
66\def\MPw      #1{\clf_MPw      {#1}}
67\def\MPh      #1{\clf_MPh      {#1}}
68\def\MPd      #1{\clf_MPd      {#1}}
69\def\MPxy     #1{\clf_MPxy     {#1}}
70\def\MPwhd    #1{\clf_MPwhd    {#1}}
71\def\MPll     #1{\clf_MPll     {#1}}
72\def\MPlr     #1{\clf_MPlr     {#1}}
73\def\MPur     #1{\clf_MPur     {#1}}
74\def\MPul     #1{\clf_MPul     {#1}}
75\def\MPpos    #1{\clf_MPpos    {#1}}
76\def\MPls     #1{\clf_MPls     {#1}}
77\def\MPrs     #1{\clf_MPrs     {#1}}
78\def\MPpardata#1{\clf_MPpardata{#1}}
79\def\MPxywhd  #1{\clf_MPxywhd  {#1}}
80\def\MPposset #1{\clf_MPposset {#1}}
81
82\let\MPpage     \MPp
83\let\MPregion   \MPr
84\let\MPcolumn   \MPc
85\let\MPparagraph\MPn
86
87\let\MPanchor   \MPpos % overloaded locally when needed
88\let\MPleftskip \MPls  % compatible feature
89\let\MPrightkip \MPrs  % compatible feature
90
91%D \macros
92%D  {MPplus, MPrest, MPv, MPvv}
93%D
94%D Since we will probably keep on extending, we provide a general extension
95%D macro. The plus alternative takes an extra argument, denoting what additional
96%D parameter to pick up. So, the third extra is fetched with,
97%D
98%D \starttyping
99%D \MPplus{identifier}{3}{default}
100%D \stoptyping
101%D
102%D All extras (comma separated) are fetched with:
103%D
104%D \starttyping
105%D \MPrest{identifier}
106%D \stoptyping
107%D
108%D The extra parameters are not treated.
109
110\def\MPplus#1#2#3{\clf_MPplus{#1}#2{#3}}  \let\MPv \MPplus
111\def\MPrest  #1#2{\clf_MPrest{#1}{#2}}    \let\MPvv\MPrest
112
113%D There are two low level positioning macros. Both store the position as well
114%D as execute an action associated with that position.
115
116\let\dopositionaction\gobbleoneargument % implemented later
117
118\def\anch_positions_initialize
119  {\ifpositioning \else
120     \global\positioningtrue
121   \fi}
122
123\unexpanded\def\setpositiononly
124  {\iftrialtypesetting
125     \expandafter\gobbleoneargument
126   \else
127     \expandafter\anch_positions_set_only_indeed
128   \fi}
129
130\def\anch_positions_set_only_indeed#1%
131  {\anch_positions_initialize
132   \edef\currentposition{#1}%
133   \dosetposition\currentposition}
134
135\unexpanded\def\setposition
136  {\iftrialtypesetting
137     \expandafter\gobbleoneargument
138   \else
139     \expandafter\anch_positions_set_indeed
140   \fi}
141
142\def\anch_positions_set_indeed#1%
143  {\anch_positions_initialize
144   \edef\currentposition{#1}%
145   \dosetposition\currentposition
146   \anch_positions_trace_left
147   \dopositionaction\currentposition}
148
149\unexpanded\def\setpositiondata
150  {\iftrialtypesetting
151     \expandafter\gobblefourarguments
152   \else
153     \expandafter\anch_positions_set_data_indeed
154   \fi}
155
156\def\anch_positions_set_data_indeed#1#2#3#4%
157  {\anch_positions_initialize
158   \hbox % \hpack
159     {\edef\currentposition{#1}%
160      \dosetpositionwhd\currentposition{#2}{#3}{#4}% already \the\dimexpr
161      \anch_positions_trace_left
162      \dopositionaction\currentposition
163      \hss}}
164
165\unexpanded\def\setpositionbox
166  {\iftrialtypesetting
167     \expandafter\anch_positions_set_box_nop
168   \else
169     \expandafter\anch_positions_set_box_yes
170   \fi}
171
172\def\anch_positions_set_box_nop#1%
173  {\dowithnextboxcs\flushnextbox}
174
175\def\anch_positions_set_box_yes#1%
176  {\dowithnextbox{\anch_positions_set_box_finish{#1}}}
177
178\def\anch_positions_set_box_finish#1%
179  {\anch_positions_initialize
180   \hbox to \wd\nextbox % \hpack
181     {\edef\currentposition{#1}%
182      \dosetpositionbox\currentposition\nextbox
183      \anch_positions_trace_left
184      \setbox\b_anch_position\box\nextbox
185      \dopositionaction\currentposition
186      \box\b_anch_position
187      \hss}}
188
189\unexpanded\def\setpositionstrut
190  {\iftrialtypesetting
191     \expandafter\anch_positions_set_strut_nop
192   \else
193     \expandafter\anch_positions_set_strut_yes
194   \fi}
195
196\def\anch_positions_set_strut_nop#1%
197  {\strut}
198
199\def\anch_positions_set_strut_yes#1%
200  {\anch_positions_initialize
201   \hbox to \zeropoint % \hpack
202     {\edef\currentposition{#1}%
203      \dosetpositionstrut\currentposition
204      \anch_positions_trace_left
205      \dopositionaction\currentposition
206      \strut
207      \hss}}
208
209\unexpanded\def\setpositionstrutkind
210  {\iftrialtypesetting
211     \expandafter\anch_positions_set_strut_kind_nop
212   \else
213     \expandafter\anch_positions_set_strut_kind_yes
214   \fi}
215
216\def\anch_positions_set_strut_kind_yes#1#2%
217  {\anch_positions_initialize
218   \hbox to \zeropoint % \hpack
219     {\edef\currentposition{#1}%
220      \dosetpositionstrutkind\currentposition{#2}%
221      \anch_positions_trace_left
222      \dopositionaction\currentposition
223      \strut
224      \hss}}
225
226\def\anch_positions_set_strut_kind_nop#1#2%
227  {\strut}
228
229\unexpanded\def\setpositiondataplus
230  {\iftrialtypesetting
231     \expandafter\gobblefivearguments
232   \else
233     \expandafter\anch_positions_set_plus_indeed
234   \fi}
235
236\def\anch_positions_set_plus_indeed#1#2#3#4#5%
237  {\anch_positions_initialize
238   \hbox % \hpack
239     {\edef\currentposition{#1}%
240      \dosetpositionplus\currentposition{#2}{#3}{#4}{#5}% already \the\dimexpr
241      \anch_positions_trace_right
242      \dopositionaction\currentposition
243      \hss}}
244
245\unexpanded\def\setpositionplus
246  {\iftrialtypesetting
247     \expandafter\anch_positions_set_plus_nop
248   \else
249     \expandafter\anch_positions_set_plus_yes
250   \fi}
251
252\def\anch_positions_set_plus_nop#1#2%
253  {\dowithnextboxcs\flushnextbox}
254
255\def\anch_positions_set_plus_yes#1#2%
256  {\dowithnextbox{\anch_positions_set_plus_yes_finish{#1}{#2}}}
257
258\def\anch_positions_set_plus_yes_finish#1#2%
259  {\anch_positions_initialize
260   \hbox to \nextboxwd % \hpack
261     {\edef\currentposition{#1}%
262      \dosetpositionplus\currentposition{\wd\nextbox}{\ht\nextbox}{\dp\nextbox}{#2}%
263      \anch_positions_trace_right
264      \setbox\b_anch_position\flushnextbox
265      \dopositionaction\currentposition
266      \box\b_anch_position
267      \hss}}
268
269\let\currentposition\s!unknown
270
271%D A few special ones .. will be cleaned up
272
273\def\pageanchor  {page:\the\realpageno} % for the moment only one pagesize
274\def\textanchor  {text:\the\realpageno}
275\def\regionanchor{region:0}
276
277\newcount\c_anch_column % will be delegated to lua
278\newcount\c_anch_text   % will be delegated to lua
279
280% beware we need to pass \somethingexpanded or { }
281
282\unexpanded\def\anch_mark_column_box#1#2% box n
283  {\global\advance\c_anch_column\plusone
284   \clf_markregionboxtaggedn#1{columnarea:\the\c_anch_column}#2\relax} % extra height
285
286\unexpanded\def\anch_mark_region_box
287  {\iftrialtypesetting
288     \singleexpandafter\gobbleoneargument
289   \else\ifpositioning
290     \doubleexpandafter\anch_mark_region_box_indeed
291   \else
292     \doubleexpandafter\gobbleoneargument
293   \fi\fi}
294
295\unexpanded\def\anch_mark_region_box_indeed#1%
296  {\clf_markregionbox#1\relax}
297
298\unexpanded\def\anch_mark_flow_box#1% will be extended / renamed
299  {\hpack\bgroup
300   \global\advance\c_anch_text\plusone
301   \clf_markregionboxtagged#1{textarea:\the\c_anch_text}%
302   \box#1%
303   \egroup}
304
305\unexpanded\def\anch_mark_tagged_box#1#2%
306  {\clf_markregionboxtagged#1{#2}}
307
308\unexpanded\def\anch_mark_flow_only#1% will be extended / renamed
309  {\global\advance\c_anch_text\plusone
310   \clf_markregionboxcorrected#1{textarea:\the\c_anch_text}}
311
312\unexpanded\def\anch_make_page_box#1% maybe like text
313  {\clf_setregionboxtagged#1{page:\the\realpageno}}
314
315\unexpanded\def\anch_mark_text_box#1%
316  {\clf_markregionboxtagged#1{text:\the\realpageno}} % needs an hbox
317
318\newcount\c_anch_free
319
320\unexpanded\def\anch_mark_tagged_box_free#1#2#3#4#5#6% only needed when positions
321  {\ifpositioning
322     \global\advance\c_anch_free\plusone % could be done at the lua end
323     \clf_markregionboxtaggedkind
324       #1%
325       {free:\number\c_anch_free}%
326       #2\space % kind
327       #3\space % leftoffset
328       #4\space % rightoffset
329       #5\space % topoffset
330       #6\relax % bottomoffset
331   \fi}
332
333\def\reservedautoregiontag{\clf_reservedautoregiontag}
334
335%D We can copy a position with:
336%D
337%D \starttyping
338%D \copyposition {to} {from}
339%D \stoptyping
340%D
341%D Again, this is a global operation.
342
343\unexpanded\def\copyposition#1#2%
344  {\clf_copyposition{#1}{#2}}
345
346%D The fact that handling positions is a two pass operation, is one of the
347%D reasons why we need to be able to test for existence, using:
348%D
349%D \starttyping
350%D \doifpositionelse {identifier} {found action} {not found action}
351%D \stoptyping
352
353\unexpanded\def\doifposition            #1{\clf_doifposition          {#1}}
354\unexpanded\def\doifelseposition        #1{\clf_doifelseposition      {#1}}
355\unexpanded\def\doifelsepositiononpage#1#2{\clf_doifelsepositiononpage{#1}#2\relax}
356
357\let\doifpositionelse      \doifelseposition
358\let\doifpositiononpageelse\doifelsepositiononpage
359
360%D \macros
361%D   {xypos}
362%D
363%D We have several macros available to save positions. Later we will see
364%D applications.
365%D
366%D \starttabulate[|l|l||]
367%D \NC \type {\xypos} \NC    \NC simple position with no dimensions \NC \NR
368%D \NC \type {\hpos}  \NC    \NC position and characteristics of a \type {\hbox} \NC \NR
369%D \NC \type {\vpos}  \NC    \NC position and characteristics of a \type {\vbox} \NC \NR
370%D \NC \type {\bpos}  \NC b: \NC begin point in a line \NC \NR
371%D \NC \type {\epos}  \NC e: \NC end point in a line \NC \NR
372%D \stoptabulate
373%D
374%D Each macro takes an identifier as argument, and the \type {\hpos} and
375%D \type {\vpos} also expect box content.
376
377\let\xypos\setpositiononly
378
379\unexpanded\def\hpos      #1{\dontleavehmode\setpositionbox{#1}\hbox}
380\unexpanded\def\vpos      #1{\setpositionbox{#1}\vbox}
381\unexpanded\def\bpos      #1{\dontleavehmode\setpositionstrut{b:#1}\ignorespaces}
382\unexpanded\def\epos      #1{\removeunwantedspaces\setpositionstrut{e:#1}}
383\unexpanded\def\bposkind#1#2{\dontleavehmode\setpositionstrutkind{b:#1}{#2}\ignorespaces} % not public, used in backgrounds
384\unexpanded\def\eposkind#1#2{\removeunwantedspaces\setpositionstrutkind{e:#1}{#2}}        % not public, used in backgrounds
385
386%D When we want to calculate more complex backgrounds, we need to know what the
387%D current indentation scheme is. At the cost of many positions and memory, we
388%D can keep track of them. This mechanism is activated automatically based on
389%D information collected in the previous pass.
390
391\newtoks \t_anch_positions_tracers
392\newcount\c_anch_positions_paragraph
393
394\unexpanded\def\tracepositions
395  {\the\t_anch_positions_tracers}
396
397\unexpanded\def\enableparpositions % global
398  {\glet\registerparoptions\doregisterparoptions
399   \global\positioningtrue}
400
401\let\disableparpositions\relax
402
403\let\registerparoptions\relax
404
405\unexpanded\def\doregisterparoptions
406  {\iftrialtypesetting \else
407     \ifinpagebody \else \ifmmode \else \ifinformula \else
408       \anch_positions_register_par_options
409     \fi \fi \fi
410   \fi}
411
412\def\anch_positions_register_par_options_normal
413  {\dontleavehmode\clf_parpos}
414
415\def\anch_positions_register_par_options_traced
416  {\anch_positions_register_par_options_normal
417   \smashedhbox to \zeropoint
418     {\hss
419      \startcolor[blue]%
420      \llap{\infofont\number\c_anch_positions_paragraph}%
421      \vrule
422        \s!width 4\onepoint
423        \s!height2\onepoint
424        \s!depth 2\onepoint
425      \stopcolor
426      \hss}}
427
428\let\anch_positions_register_par_options\anch_positions_register_par_options_normal
429
430\appendtoks
431    \let\anch_positions_register_par_options\anch_positions_register_par_options_traced
432\to \t_anch_positions_tracers
433
434\unexpanded\def\anch_positions_trace#1#2#3%
435  {\smashedhbox
436     {#1{\infofont#2#3}%
437      \kern-\onepoint
438      \vrule\s!width2\onepoint\s!height\halfapoint\s!depth\halfapoint}}
439
440\unexpanded\def\anch_positions_trace_left_indeed
441  {\anch_positions_trace\llap\darkmagenta{\currentposition>}}
442
443\unexpanded\def\anch_positions_trace_right_indeed
444  {\anch_positions_trace\rlap\darkcyan{<\currentposition}}
445
446\let\anch_positions_trace_left \relax
447\let\anch_positions_trace_right\relax
448
449\appendtoks
450    \let\anch_positions_trace_left  \anch_positions_trace_left_indeed
451    \let\anch_positions_trace_right \anch_positions_trace_right_indeed
452\to \t_anch_positions_tracers
453
454% \appendtoks \registerparoptions \to \everypar
455
456%D \macros
457%D   {doifoverlappingelse}
458%D
459%D A first application of positional information, is to determine if two
460%D boxes do overlap:
461%D
462%D \starttyping
463%D \doifoverlappingelse{point a}{point b}
464%D   {action when overlapping}
465%D   {action when not overlapping}
466%D \stoptyping
467
468\unexpanded\def\doifelseoverlapping#1#2{\clf_doifelseoverlapping{#1}{#2}}
469
470\let\doifoverlappingelse\doifelseoverlapping
471
472%D \macros
473%D   {doifpositionsonsamepageelse,
474%D    doifpositionsonthispageelse}
475%D
476%D Instead of letting the user handle fuzzy expansion, we provide a simple test on
477%D positions being on the same page.
478%D
479%D \starttyping
480%D \doifpositionsonsamepageelse{point a,point b}
481%D   {action when on same page}
482%D   {action when not on same page}
483%D \doifpositionsonthispageelse{point a,point b}
484%D   {action when on this page}
485%D   {action when not on this page}
486%D \stoptyping
487
488\unexpanded\def\doifelsepositionsonsamepage#1{\clf_doifelsepositionsonsamepage{#1}}
489\unexpanded\def\doifelsepositionsonthispage#1{\clf_doifelsepositionsonthispage{#1}}
490
491\let\doifpositionsonsamepageelse\doifelsepositionsonsamepage
492\let\doifpositionsonthispageelse\doifelsepositionsonthispage
493
494%D Moved here:
495
496\unexpanded\def\doifelsepositionsused{\clf_doifelsepositionsused}
497
498\let\doifpositionsusedelse\doifelsepositionsused
499
500%D Moved here:
501
502\unexpanded\def\savepos {\clf_savepos}
503\unexpanded\def\lastxpos{\numexpr\clf_lastxpos\relax}
504\unexpanded\def\lastypos{\numexpr\clf_lastypos\relax}
505
506\protect \endinput
507