anch-pos.mkxl /size: 16 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\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\protected\def\anch_mark_column_box#1#2% box n
305  {\global\advanceby\c_anch_column\plusone
306   \clf_markregionboxtaggedn#1{columnarea}\c_anch_column#2\relax} % extra height
307
308\protected\def\anch_mark_region_box % auto region:index
309  {\iftrialtypesetting
310     \expandafter\gobbleoneargument
311   \orelse\ifpositioning
312     \expandafter\anch_mark_region_box_indeed
313   \else
314     \expandafter\gobbleoneargument
315   \fi}
316
317\protected\def\anch_mark_region_box_indeed#1%
318  {\clf_markregionbox#1\relax}
319
320\protected\def\anch_mark_flow_box#1% will be extended / renamed
321  {\hpack\bgroup
322   \global\advanceby\c_anch_text\plusone
323   \clf_markregionboxtagged#1{textarea}\c_anch_text % will become flow:
324   \box#1%
325   \egroup}
326
327\protected\def\anch_mark_tagged_box#1#2#3%
328  {\clf_markregionboxtagged#1{#2}#3\relax}
329
330\protected\def\anch_mark_flow_only#1% will be extended / renamed
331  {\global\advanceby\c_anch_text\plusone
332   \clf_markregionboxcorrected#1{textarea}\c_anch_text}% will become flow:
333
334\protected\def\anch_make_page_box#1% maybe like text
335  {\clf_setregionboxtagged#1{page}\realpageno}
336
337\protected\def\anch_mark_text_box#1%
338  {\clf_markregionboxtagged#1{text}\realpageno} % needs an hbox
339
340\protected\def\anch_mark_tagged_box_free
341  {\ifpositioning
342     \expandafter\anch_mark_tagged_box_free_yes
343   \else
344     \expandafter\gobblesixarguments
345   \fi}
346
347% see top: \newinteger\c_anch_free
348
349\protected\def\anch_mark_tagged_box_free_yes#1#2#3#4#5#6% only needed when positions
350  {\global\advanceby\c_anch_free\plusone % could be done at the lua end
351   \clf_markregionboxtaggedkind
352     #1%
353     {free}%
354     \c_anch_free
355     #2% kind         % single token value
356     #3% leftoffset   % single token value
357     #4% rightoffset  % single token value
358     #5% topoffset    % single token value
359     #6% bottomoffset % single token value
360   \relax}
361
362% \reservedautoregiontag % define at lua end
363
364%D We can copy a position with:
365%D
366%D \starttyping
367%D \copyposition {to} {from}
368%D \stoptyping
369%D
370%D Again, this is a global operation.
371
372% \copyposition #1#2 % defined at lua end
373
374%D The fact that handling positions is a two pass operation, is one of the
375%D reasons why we need to be able to test for existence, using:
376%D
377%D \starttyping
378%D \doifpositionelse {identifier} {found action} {not found action}
379%D \stoptyping
380
381% \doifposition            #1   % defined at lua end
382% \doifelseposition        #1#2 % defined at lua end
383% \doifelsepositiononpage  #1#2 % defined at lua end
384
385\aliased\let\doifpositionelse      \doifelseposition
386\aliased\let\doifpositiononpageelse\doifelsepositiononpage
387
388%D \macros
389%D   {xypos}
390%D
391%D We have several macros available to save positions. Later we will see
392%D applications.
393%D
394%D \starttabulate[|l|l||]
395%D \NC \type {\xypos} \NC    \NC simple position with no dimensions \NC \NR
396%D \NC \type {\hpos}  \NC    \NC position and characteristics of a \type {\hbox} \NC \NR
397%D \NC \type {\vpos}  \NC    \NC position and characteristics of a \type {\vbox} \NC \NR
398%D \NC \type {\bpos}  \NC b: \NC begin point in a line \NC \NR
399%D \NC \type {\epos}  \NC e: \NC end point in a line \NC \NR
400%D \stoptabulate
401%D
402%D Each macro takes an identifier as argument, and the \type {\hpos} and
403%D \type {\vpos} also expect box content.
404
405\aliased\let\xypos\setpositiononly
406
407\permanent\protected\def\hpos      #1{\dontleavehmode\setpositionbox{#1}\hbox}
408\permanent\protected\def\vpos      #1{\setpositionbox{#1}\vbox}
409\permanent\protected\def\bpos      #1{\dontleavehmode\setpositionstrut{b:#1}\ignorespaces}
410\permanent\protected\def\epos      #1{\removeunwantedspaces\setpositionstrut{e:#1}}
411\permanent\protected\def\bposkind#1#2{\dontleavehmode\setpositionstrutkind{b:#1}{#2}\ignorespaces} % not public, used in backgrounds
412\permanent\protected\def\eposkind#1#2{\removeunwantedspaces\setpositionstrutkind{e:#1}{#2}}        % not public, used in backgrounds
413
414%D When we want to calculate more complex backgrounds, we need to know what the
415%D current indentation scheme is. At the cost of many positions and memory, we
416%D can keep track of them. This mechanism is activated automatically based on
417%D information collected in the previous pass.
418
419% see top: \newtoks   \t_anch_positions_tracers
420% see top: \newinteger\c_anch_positions_paragraph
421
422\permanent\protected\def\tracepositions
423  {\expand\t_anch_positions_tracers}
424
425\permanent\protected\def\enableparpositions % global
426  {\enforced\aliased\glet\registerparoptions\doregisterparoptions
427   \global\positioningtrue}
428
429\permanent\protected\lettonothing\disableparpositions
430\permanent\protected\lettonothing\registerparoptions % hooks into everypar
431
432\permanent\protected\def\doregisterparoptions
433  {\iftrialtypesetting \orelse\ifinpagebody \orelse\ifmmode \orelse\ifinformula \else
434      \anch_positions_register_par_options
435   \fi}
436
437\def\anch_positions_register_par_options_normal
438  {\dontleavehmode\clf_parpos}
439
440\def\anch_positions_register_par_options_traced
441  {\anch_positions_register_par_options_normal
442   \begingroup
443   \setbox\scratchbox\hpack
444     {\hss
445      \startcolor[blue]%
446      \hpack \s!yoffset -2\onepoint to \zeropoint
447        {\hss\infofont\the\c_anch_positions_paragraph\hskip2\onepoint}%
448      \vrule
449        \s!width 4\onepoint
450        \s!height2\onepoint
451        \s!depth 2\onepoint
452      \stopcolor
453      \hss}%
454   \smashbox\scratchbox
455   \boxxoffset\scratchbox-2\onepoint
456   \box\scratchbox
457   \endgroup}
458
459\let\anch_positions_register_par_options\anch_positions_register_par_options_normal
460
461\appendtoks
462    \let\anch_positions_register_par_options\anch_positions_register_par_options_traced
463\to \t_anch_positions_tracers
464
465\protected\def\anch_positions_trace#1#2#3%
466  {\smashedhbox
467     {#1{\infofont#2#3}%
468      \kern-\onepoint
469      \vrule\s!width2\onepoint\s!height\halfapoint\s!depth\halfapoint}}
470
471\protected\def\anch_positions_trace_left_indeed
472  {\anch_positions_trace\llap\darkmagenta{\currentposition>}}
473
474\protected\def\anch_positions_trace_right_indeed
475  {\anch_positions_trace\rlap\darkcyan{<\currentposition}}
476
477\let\anch_positions_trace_left \relax
478\let\anch_positions_trace_right\relax
479
480\appendtoks
481    \let\anch_positions_trace_left  \anch_positions_trace_left_indeed
482    \let\anch_positions_trace_right \anch_positions_trace_right_indeed
483\to \t_anch_positions_tracers
484
485% \appendtoks \registerparoptions \to \everypar
486
487%D \macros
488%D   {doifoverlappingelse}
489%D
490%D A first application of positional information, is to determine if two boxes do
491%D overlap:
492%D
493%D \starttyping
494%D \doifoverlappingelse{point a}{point b}
495%D   {action when overlapping}
496%D   {action when not overlapping}
497%D \stoptyping
498
499% \doifelseoverlapping #1#2#3#4 % defined at lua end
500
501\aliased\let\doifoverlappingelse\doifelseoverlapping
502
503%D \macros
504%D   {doifpositionsonsamepageelse,
505%D    doifpositionsonthispageelse}
506%D
507%D Instead of letting the user handle fuzzy expansion, we provide a simple test on
508%D positions being on the same page.
509%D
510%D \starttyping
511%D \doifpositionsonsamepageelse{point a,point b}
512%D   {action when on same page}
513%D   {action when not on same page}
514%D \doifpositionsonthispageelse{point a,point b}
515%D   {action when on this page}
516%D   {action when not on this page}
517%D \stoptyping
518
519% \doifelsepositionsonsamepage #1 % defined at lua end
520% \doifelsepositionsonthispage #1 % defined at lua end
521% \doifelsepositionsused          % defined at lua end
522
523\aliased\let\doifpositionsonsamepageelse\doifelsepositionsonsamepage
524\aliased\let\doifpositionsonthispageelse\doifelsepositionsonthispage
525\aliased\let\doifpositionsusedelse      \doifelsepositionsused
526
527%D Moved here:
528
529\permanent\protected\def\savepos {\clf_savepos}
530\permanent\protected\def\lastxpos{\numexpr\clf_lastxpos\relax}
531\permanent\protected\def\lastypos{\numexpr\clf_lastypos\relax}
532
533\protect \endinput
534