anch-pos.mkxl /size: 17 Kb    last modification: 2025-02-21 11:03
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\unprotect
21
22\newinteger\c_anch_column % will be delegated to lua
23\newinteger\c_anch_text   % will be delegated to lua
24\newinteger\c_anch_free
25\newtoks   \t_anch_positions_tracers
26\newinteger\c_anch_positions_paragraph
27\newbox    \b_anch_position
28\newif     \ifpositioning   % sort of public
29
30\registerctxluafile{anch-pos}{autosuffix}
31
32%D The first application of positional information was embedded graphics. Since we
33%D are interacting with text, it made sense to take the current line height and
34%D depth into account too. This is why we have position macros for simple positions
35%D and one boxes.
36%D
37%D \starttyping
38%D \dosetposition          {identifier}
39%D \dosetpositionwhd       {identifier} {width} {height} {depth}
40%D \dosetpositionplus      {identifier} {width} {height} {depth} {list}
41%D \stoptyping
42
43% \dosaveposition             #1#2#3#4 % defined at lua end
44% \dosavepositionwhd    #1#2#3#4#5#6#7 % defined at lua end
45% \dosavepositionplus #1#2#3#4#5#6#7#8 % defined at lua end
46
47% \dosetposition                    #1 % defined at lua end
48% \dosetpositionwhd           #1#2#3#4 % defined at lua end
49% \dosetpositionplus        #1#2#3#4#5 % defined at lua end
50% \dosetpositionbox               #1#2 % defined at lua end
51% \dosetpositionstrut               #1 % defined at lua end
52% \dosetpositionstrutkind         #1#2 % defined at lua end
53
54% see top: \newbox\b_anch_position
55% see top: \newif \ifpositioning   % sort of public
56
57\mutable\lettonothing\currentposition
58\mutable\lettonothing\currentpositionaction
59\mutable\lettonothing\currentpositionanchor
60\mutable\lettonothing\currentpositionregion
61
62%D Sometimes we want to trick the position handler a bit:
63
64% \replacepospxywhd #1#2#3#4#5#6#7 % defined at lua end
65
66%D \macros
67%D   {MPp, MPx, MPy, MPw, MPh, MPd, MPxy, MPll, MPlr, MPur, MPul, MPpos, MPanchor}
68%D
69%D Access to the positional information is provided by macros with short names
70%S that are clearly meant for \METAPOST\ but nowadays also used for other purposes.
71
72% \MPp       : defined at lua end
73% \MPr       : defined at lua end
74% \MPc       : defined at lua end
75% \MPn       : defined at lua end
76% \MPx       : defined at lua end
77% \MPy       : defined at lua end
78% \MPw       : defined at lua end
79% \MPh       : defined at lua end
80% \MPd       : defined at lua end
81% \MPxy      : defined at lua end
82% \MPwhd     : defined at lua end
83% \MPll      : defined at lua end
84% \MPlr      : defined at lua end
85% \MPur      : defined at lua end
86% \MPul      : defined at lua end
87% \MPpos     : defined at lua end
88% \MPls      : defined at lua end
89% \MPrs      : defined at lua end
90% \MPpardata : defined at lua end
91% \MPxywhd   : defined at lua end
92% \MPposset  : defined at lua end
93
94\aliased\let\MPpage     \MPp
95\aliased\let\MPregion   \MPr
96\aliased\let\MPcolumn   \MPc
97\aliased\let\MPparagraph\MPn
98\aliased\let\MPanchor   \MPpos % overloaded locally when needed  (todo: LMTX)
99
100\aliased\let\MPleftskip \MPls  % compatible feature
101\aliased\let\MPrightkip \MPrs  % compatible feature
102
103%D \macros
104%D  {MPplus, MPrest, MPv, MPvv}
105%D
106%D Since we will probably keep on extending, we provide a general extension
107%D macro. The plus alternative takes an extra argument, denoting what additional
108%D parameter to pick up. So, the third extra is fetched with,
109%D
110%D \starttyping
111%D \MPplus{identifier}{3}{default}
112%D \stoptyping
113%D
114%D All extras (comma separated) are fetched with:
115%D
116%D \starttyping
117%D \MPrest{identifier}
118%D \stoptyping
119%D
120%D The extra parameters are not treated.
121
122% \MPplus #1#2#3 % defined at lua end
123% \MPrest #1     % defined at lua end
124
125\aliased\let\MPv \MPplus
126\aliased\let\MPvv\MPrest
127
128%D There are two low level positioning macros. Both store the position as well
129%D as execute an action associated with that position.
130
131\let\dopositionaction\gobbleoneargument % implemented later
132
133\def\anch_positions_initialize
134  {\ifpositioning \else
135     \global\positioningtrue
136   \fi}
137
138\permanent\protected\def\setpositiononly
139  {\iftrialtypesetting
140     \expandafter\gobbleoneargument
141   \else
142     \expandafter\anch_positions_set_only_indeed
143   \fi}
144
145\def\anch_positions_set_only_indeed#1%
146  {\anch_positions_initialize
147   \cdef\currentposition{#1}%
148   \dosetposition\currentposition}
149
150\permanent\protected\def\setposition
151  {\iftrialtypesetting
152     \expandafter\gobbleoneargument
153   \else
154     \expandafter\anch_positions_set_indeed
155   \fi}
156
157\def\anch_positions_set_indeed#1%
158  {\anch_positions_initialize
159   \cdef\currentposition{#1}%
160   \dosetposition\currentposition
161   \anch_positions_trace_left
162   \dopositionaction\currentposition}
163
164\permanent\protected\def\setpositiondata
165  {\iftrialtypesetting
166     \expandafter\gobblefourarguments
167   \else
168     \expandafter\anch_positions_set_data_indeed
169   \fi}
170
171\def\anch_positions_set_data_indeed#1#2#3#4%
172  {\anch_positions_initialize
173   \hbox % \hpack
174     {\cdef\currentposition{#1}%
175      \dosetpositionwhd\currentposition{#2}{#3}{#4}%
176      \anch_positions_trace_left
177      \dopositionaction\currentposition
178      \hss}}
179
180\permanent\protected\def\setpositionbox
181  {\iftrialtypesetting
182     \expandafter\anch_positions_set_box_nop
183   \else
184     \expandafter\anch_positions_set_box_yes
185   \fi}
186
187\def\anch_positions_set_box_nop#1%
188  {\dowithnextboxcs\flushnextbox}
189
190\def\anch_positions_set_box_yes#1%
191  {\dowithnextbox{\anch_positions_set_box_finish{#1}}}
192
193\def\anch_positions_set_box_finish#1%
194  {\anch_positions_initialize
195  %\hbox to \wd\nextbox
196   \hpack to \wd\nextbox
197     {\cdef\currentposition{#1}%
198      \dosetpositionbox\currentposition\nextbox
199      \anch_positions_trace_left
200      \setbox\b_anch_position\box\nextbox
201      \dopositionaction\currentposition
202      \box\b_anch_position
203      \hss}}
204
205\permanent\protected\def\setpositionstrut
206  {\iftrialtypesetting
207     \expandafter\anch_positions_set_strut_nop
208   \else
209     \expandafter\anch_positions_set_strut_yes
210   \fi}
211
212\def\anch_positions_set_strut_nop#1%
213  {\strut}
214
215\def\anch_positions_set_strut_yes#1%
216  {\anch_positions_initialize
217   \hbox to \zeropoint % \hpack
218     {\cdef\currentposition{#1}%
219      \dosetpositionstrut\currentposition
220      \anch_positions_trace_left
221      \dopositionaction\currentposition
222      \strut
223      \hss}}
224
225\permanent\protected\def\setpositionstrutkind
226  {\iftrialtypesetting
227     \expandafter\anch_positions_set_strut_kind_nop
228   \else
229     \expandafter\anch_positions_set_strut_kind_yes
230   \fi}
231
232\def\anch_positions_set_strut_kind_yes#1#2%
233  {\anch_positions_initialize
234   \hbox to \zeropoint % \hpack
235     {\cdef\currentposition{#1}%
236      \dosetpositionstrutkind\currentposition{#2}%
237      \anch_positions_trace_left
238      \dopositionaction\currentposition
239      \strut
240      \hss}}
241
242\def\anch_positions_set_strut_kind_nop#1#2%
243  {\strut}
244
245\permanent\protected\def\setpositiondataplus
246  {\iftrialtypesetting
247     \expandafter\gobblefivearguments
248   \else
249     \expandafter\anch_positions_set_plus_indeed
250   \fi}
251
252\def\anch_positions_set_plus_indeed#1#2#3#4#5%
253  {\anch_positions_initialize
254   \hbox % \hpack
255     {\cdef\currentposition{#1}%
256      \dosetpositionplus\currentposition{#2}{#3}{#4}{#5}%
257      \anch_positions_trace_right
258      \dopositionaction\currentposition
259      \hss}}
260
261\permanent\protected\def\setpositionplus
262  {\iftrialtypesetting
263     \expandafter\anch_positions_set_plus_nop
264   \else
265     \expandafter\anch_positions_set_plus_yes
266   \fi}
267
268\def\anch_positions_set_plus_nop#1#2%
269  {\dowithnextboxcs\flushnextbox}
270
271\def\anch_positions_set_plus_yes#1#2%
272  {\dowithnextbox{\anch_positions_set_plus_yes_finish{#1}{#2}}}
273
274\def\anch_positions_set_plus_yes_finish#1#2%
275  {\anch_positions_initialize
276   \hbox to \nextboxwd % \hpack
277     {\cdef\currentposition{#1}%
278      \dosetpositionplus\currentposition{\wd\nextbox}{\ht\nextbox}{\dp\nextbox}{#2}%
279      \anch_positions_trace_right
280      \setbox\b_anch_position\flushnextbox
281      \dopositionaction\currentposition
282      \box\b_anch_position
283      \hss}}
284
285\let\currentposition\s!unknown
286
287%D A few special ones .. will be cleaned up
288
289\permanent\def\pageanchor  {page:\the\realpageno} % for the moment only one pagesize
290\permanent\def\textanchor  {text:\the\realpageno}
291\permanent\def\regionanchor{region:0}
292
293% see top: \newinteger\c_anch_column % will be delegated to lua
294% see top: \newinteger\c_anch_text   % will be delegated to lua
295
296% beware we need to pass \somethingexpanded or { }
297
298% Is this really always needed? We use \enabletextarearegistration for page areas so why
299% not also for this.
300%
301% At some point we can switch to dedicated markers because there are not
302% that many variants: text, page, textarea, columnarea, free.
303
304\newfloat\f_anch_extra_y_scale
305
306\def\d_anch_extra_text_depth
307 %{\dimexpr\ifnum\bottomraggednessmode=\plusthree\strutdp\else\zeropoint\fi\relax}
308  {\ifnum\bottomraggednessmode=\plusthree\strutdp\else\zeropoint\fi}
309
310\protected\def\anch_mark_column_box#1#2% box n
311  {\global\advanceby\c_anch_column\plusone
312   \clf_markregionboxtaggedn
313     #1%
314     {columnarea}%
315     \c_anch_column
316     \zeropoint
317     \zerofloat
318     #2%
319   \relax
320   \f_anch_extra_y_scale\zerofloat}
321
322\protected\def\anch_mark_region_box % auto region:index
323  {\iftrialtypesetting
324     \expandafter\gobbleoneargument
325   \orelse\ifpositioning
326     \expandafter\anch_mark_region_box_indeed
327   \else
328     \expandafter\gobbleoneargument
329   \fi}
330
331\protected\def\anch_mark_region_box_indeed#1%
332  {\clf_markregionbox#1\relax}
333
334\protected\def\anch_mark_flow_box#1% will be extended / renamed
335  {\hpack\bgroup
336   \global\advanceby\c_anch_text\plusone
337   \clf_markregionboxtagged % will become flow:
338     #1%
339     {textarea}%
340     \c_anch_text
341     \d_anch_extra_text_depth
342     \f_anch_extra_y_scale
343   \box#1%
344   \egroup
345   \f_anch_extra_y_scale\zerofloat}
346
347\protected\def\anch_mark_tagged_box#1#2#3%
348  {\clf_markregionboxtagged#1{#2}#3\zeropoint\zerofloat\relax}
349
350\protected\def\anch_mark_flow_only#1% will be extended / renamed
351  {\global\advanceby\c_anch_text\plusone
352   \clf_markregionboxcorrected % will become flow:
353     #1%
354     {textarea}%
355     \c_anch_text
356     \d_anch_extra_text_depth
357     \f_anch_extra_y_scale
358   \relax
359   \f_anch_extra_y_scale\zerofloat}
360
361\protected\def\anch_make_page_box#1% maybe like text
362  {\clf_setregionboxtagged
363     #1%
364     {page}%
365     \realpageno
366     \zeropoint
367     \zerofloat
368   \relax
369   \f_anch_extra_y_scale\zerofloat}
370
371\protected\def\anch_mark_text_box#1%
372  {\clf_markregionboxtagged % needs an hbox
373     #1%
374     {text}%
375     \realpageno
376     \d_anch_extra_text_depth
377     \f_anch_extra_y_scale
378   \relax
379   \f_anch_extra_y_scale\zerofloat}
380
381\protected\def\anch_mark_tagged_box_free
382  {\ifpositioning
383     \expandafter\anch_mark_tagged_box_free_yes
384   \else
385     \expandafter\gobblesixarguments
386   \fi}
387
388% see top: \newinteger\c_anch_free
389
390\protected\def\anch_mark_tagged_box_free_yes#1#2#3#4#5#6% only needed when positions
391  {\global\advanceby\c_anch_free\plusone % could be done at the lua end
392   \clf_markregionboxtaggedkind
393     #1%
394     {free}%
395     \c_anch_free
396     \zeropoint
397     \zerofloat
398     #2% kind         % single token value
399     #3% leftoffset   % single token value
400     #4% rightoffset  % single token value
401     #5% topoffset    % single token value
402     #6% bottomoffset % single token value
403   \relax
404   \f_anch_extra_y_scale\zerofloat}
405
406% \reservedautoregiontag % define at lua end
407
408%D We can copy a position with:
409%D
410%D \starttyping
411%D \copyposition {to} {from}
412%D \stoptyping
413%D
414%D Again, this is a global operation.
415
416% \copyposition #1#2 % defined at lua end
417
418%D The fact that handling positions is a two pass operation, is one of the
419%D reasons why we need to be able to test for existence, using:
420%D
421%D \starttyping
422%D \doifpositionelse {identifier} {found action} {not found action}
423%D \stoptyping
424
425% \doifposition            #1   % defined at lua end
426% \doifelseposition        #1#2 % defined at lua end
427% \doifelsepositiononpage  #1#2 % defined at lua end
428
429\aliased\let\doifpositionelse      \doifelseposition
430\aliased\let\doifpositiononpageelse\doifelsepositiononpage
431
432%D \macros
433%D   {xypos}
434%D
435%D We have several macros available to save positions. Later we will see
436%D applications.
437%D
438%D \starttabulate[|l|l||]
439%D \NC \type {\xypos} \NC    \NC simple position with no dimensions \NC \NR
440%D \NC \type {\hpos}  \NC    \NC position and characteristics of a \type {\hbox} \NC \NR
441%D \NC \type {\vpos}  \NC    \NC position and characteristics of a \type {\vbox} \NC \NR
442%D \NC \type {\bpos}  \NC b: \NC begin point in a line \NC \NR
443%D \NC \type {\epos}  \NC e: \NC end point in a line \NC \NR
444%D \stoptabulate
445%D
446%D Each macro takes an identifier as argument, and the \type {\hpos} and
447%D \type {\vpos} also expect box content.
448
449\aliased\let\xypos\setpositiononly
450
451\permanent\protected\def\hpos      #1{\dontleavehmode\setpositionbox{#1}\hbox}
452\permanent\protected\def\vpos      #1{\setpositionbox{#1}\vbox}
453\permanent\protected\def\bpos      #1{\dontleavehmode\setpositionstrut{b:#1}\ignorespaces}
454\permanent\protected\def\epos      #1{\removeunwantedspaces\setpositionstrut{e:#1}}
455\permanent\protected\def\bposkind#1#2{\dontleavehmode\setpositionstrutkind{b:#1}{#2}\ignorespaces} % not public, used in backgrounds
456\permanent\protected\def\eposkind#1#2{\removeunwantedspaces\setpositionstrutkind{e:#1}{#2}}        % not public, used in backgrounds
457
458%D When we want to calculate more complex backgrounds, we need to know what the
459%D current indentation scheme is. At the cost of many positions and memory, we
460%D can keep track of them. This mechanism is activated automatically based on
461%D information collected in the previous pass.
462
463% see top: \newtoks   \t_anch_positions_tracers
464% see top: \newinteger\c_anch_positions_paragraph
465
466\permanent\protected\def\tracepositions
467  {\expand\t_anch_positions_tracers}
468
469\permanent\protected\def\enableparpositions % global
470  {\enforced\aliased\glet\registerparoptions\doregisterparoptions
471   \global\positioningtrue}
472
473\permanent\protected\lettonothing\disableparpositions
474\permanent\protected\lettonothing\registerparoptions % hooks into everypar
475
476\permanent\protected\def\doregisterparoptions
477  {\iftrialtypesetting \orelse\ifinpagebody \orelse\ifmmode \orelse\ifinformula \else
478      \anch_positions_register_par_options
479   \fi}
480
481\def\anch_positions_register_par_options_normal
482  {\dontleavehmode\clf_parpos}
483
484\def\anch_positions_register_par_options_traced
485  {\anch_positions_register_par_options_normal
486   \begingroup
487   \setbox\scratchbox\hpack
488     {\hss
489      \startcolor[blue]%
490      \hpack \s!yoffset -2\onepoint to \zeropoint
491        {\hss\infofont\the\c_anch_positions_paragraph\hskip2\onepoint}%
492      \vrule
493        \s!width 4\onepoint
494        \s!height2\onepoint
495        \s!depth 2\onepoint
496      \stopcolor
497      \hss}%
498   \smashbox\scratchbox
499   \boxxoffset\scratchbox-2\onepoint
500   \box\scratchbox
501   \endgroup}
502
503\let\anch_positions_register_par_options\anch_positions_register_par_options_normal
504
505\appendtoks
506    \let\anch_positions_register_par_options\anch_positions_register_par_options_traced
507\to \t_anch_positions_tracers
508
509\protected\def\anch_positions_trace#1#2#3%
510  {\smashedhbox
511     {#1{\infofont#2#3}%
512      \kern-\onepoint
513      \vrule\s!width2\onepoint\s!height\halfapoint\s!depth\halfapoint}}
514
515\protected\def\anch_positions_trace_left_indeed
516  {\anch_positions_trace\llap\darkmagenta{\currentposition>}}
517
518\protected\def\anch_positions_trace_right_indeed
519  {\anch_positions_trace\rlap\darkcyan{<\currentposition}}
520
521\let\anch_positions_trace_left \relax
522\let\anch_positions_trace_right\relax
523
524\appendtoks
525    \let\anch_positions_trace_left  \anch_positions_trace_left_indeed
526    \let\anch_positions_trace_right \anch_positions_trace_right_indeed
527\to \t_anch_positions_tracers
528
529% \appendtoks \registerparoptions \to \everypar
530
531%D \macros
532%D   {doifoverlappingelse}
533%D
534%D A first application of positional information, is to determine if two boxes do
535%D overlap:
536%D
537%D \starttyping
538%D \doifoverlappingelse{point a}{point b}
539%D   {action when overlapping}
540%D   {action when not overlapping}
541%D \stoptyping
542
543% \doifelseoverlapping #1#2#3#4 % defined at lua end
544
545\aliased\let\doifoverlappingelse\doifelseoverlapping
546
547%D \macros
548%D   {doifpositionsonsamepageelse,
549%D    doifpositionsonthispageelse}
550%D
551%D Instead of letting the user handle fuzzy expansion, we provide a simple test on
552%D positions being on the same page.
553%D
554%D \starttyping
555%D \doifpositionsonsamepageelse{point a,point b}
556%D   {action when on same page}
557%D   {action when not on same page}
558%D \doifpositionsonthispageelse{point a,point b}
559%D   {action when on this page}
560%D   {action when not on this page}
561%D \stoptyping
562
563% \doifelsepositionsonsamepage #1 % defined at lua end
564% \doifelsepositionsonthispage #1 % defined at lua end
565% \doifelsepositionsused          % defined at lua end
566
567\aliased\let\doifpositionsonsamepageelse\doifelsepositionsonsamepage
568\aliased\let\doifpositionsonthispageelse\doifelsepositionsonthispage
569\aliased\let\doifpositionsusedelse      \doifelsepositionsused
570
571%D Moved here:
572
573% \savepos  % define at the lua end
574% \lastxpos % define at the lua end
575% \lastypos % define at the lua end
576
577\protect \endinput
578