strc-pag.mkiv /size: 18 Kb    last modification: 2021-10-28 13:50
1%D \module
2%D   [       file=strc-pag,
3%D        version=2008.10.20,
4%D          title=\CONTEXT\ Structure Macros,
5%D       subtitle=Pagenumbering,
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 Structure Macros / Pagenumbering}
15
16\registerctxluafile{strc-pag}{}
17
18\unprotect
19
20\startcontextdefinitioncode
21
22% Allocation:
23
24\ifdefined\realpageno  \else \countdef\realpageno \zerocount  \fi \realpageno \plusone
25\ifdefined\userpageno  \else \countdef\userpageno \plusone    \fi \userpageno \plusone
26\ifdefined\subpageno   \else \countdef\subpageno  \plustwo    \fi \subpageno  \plusone % was \zerocount but that doesn't work well with bytext
27\ifdefined\arrangeno   \else \countdef\arrangeno  \plusthree  \fi \arrangeno  \zerocount % !
28\ifdefined\pagenoshift \else \countdef\pagenoshift\plusfour   \fi \pagenoshift\zerocount % !
29\ifdefined\lastpageno  \else \countdef\lastpageno \plusfive   \fi \lastpageno \zerocount % !
30
31\ifdefined\pageno \else \let\pageno\userpageno \fi
32
33\def\realfolio{\the\realpageno}
34\def\userfolio{\the\userpageno}
35\def\subfolio {\the\subpageno }
36\def\lastfolio{\the\lastpageno}
37
38\newtoks\everyinitializepagecounters
39
40\unexpanded\def\initializepagecounters
41  {\the\everyinitializepagecounters}
42
43\appendtoks
44    \initializepagecounters
45\to \everyjob
46
47% Page numbers are kind of independent of each other and therefore they
48% all get their own counter. After all, it's easier to combine them in
49% a pseudo counterset than to deal with a complex set itself.
50
51% \defineprefixset   [mine][section-1,section-2]
52% \defineseparatorset[mine][:]
53%
54% \setupuserpagenumber
55%   [way=bypart,
56%    prefix=yes,
57%    prefixset=mine,
58%    prefixseparatorset=mine]
59
60% \defineconversionset[frontpart:pagenumber][][romannumerals]
61% \defineconversionset[bodypart:pagenumber] [][numbers]
62%
63% \setupuserpagenumber[way=byblock]
64% \setupuserpagenumber[way=bychapter]
65% \setupuserpagenumber[numberconversionset=pagenumber]
66%
67% \starttext
68%     \startfrontmatter
69%         \completecontent[criterium=all]
70%         \chapter{tufte} \section{one} \input tufte \page \section{two} \input tufte \page
71%         \chapter{tufte} \section{one} \input tufte \page \section{two} \input tufte \page
72%     \stopfrontmatter
73%     \startbodymatter
74%         \chapter{knuth} \section{one} \input knuth \page \section{two} \input knuth \page \section{three} \input knuth \page
75%         \chapter{knuth} \section{one} \input knuth \page \section{two} \input knuth \page \section{three} \input knuth \page
76%     \stopbodymatter
77% \stoptext
78
79\definecounter[\s!realpage][\c!prefix=\v!no,\c!start=\plusone,\c!prefixsegments=,\s!counter=realpageno,\c!method=\v!page]
80\definecounter[\s!userpage][\c!prefix=\v!no,\c!start=\plusone,\c!prefixsegments=,\s!counter=userpageno,\c!method=\v!page]
81\definecounter[\s!subpage] [\c!prefix=\v!no,\c!start=\plusone,\c!prefixsegments=,\s!counter=subpageno, \c!method=\v!page]
82
83\newtoks\everysetuprealpagenumber % todo: set state: none, start, stop, reset
84\newtoks\everysetupuserpagenumber % todo: set state: none, start, stop, reset
85\newtoks\everysetupsubpagenumber  % todo: set state: none, start, stop, reset
86
87\unexpanded\def\setuprealpagenumber{\dosingleargument\strc_pagenumbers_setup_realpage}
88\unexpanded\def\setupuserpagenumber{\dosingleargument\strc_pagenumbers_setup_userpage}
89\unexpanded\def\setupsubpagenumber {\dosingleargument\strc_pagenumbers_setup_subpage }
90
91\let\m_strc_pagenumbers_state_old\zerocount
92\let\m_strc_pagenumbers_state_new\zerocount
93
94\def\strc_pagenumbers_save_state#1{\edef\m_strc_pagenumbers_state_old{\namedcounterparameter#1\c!state}}
95
96\def\strc_pagenumbers_setup_realpage[#1]{\strc_pagenumbers_save_state\s!realpage\setupcounter[\s!realpage][#1]\the\everysetuprealpagenumber}
97\def\strc_pagenumbers_setup_userpage[#1]{\strc_pagenumbers_save_state\s!userpage\setupcounter[\s!userpage][#1]\the\everysetupuserpagenumber}
98\def\strc_pagenumbers_setup_subpage [#1]{\strc_pagenumbers_save_state\s!subpage \setupcounter[\s!subpage ][#1]\the\everysetupsubpagenumber }
99
100\unexpanded\def\resetrealpagenumber {} % not permitted
101\unexpanded\def\resetuserpagenumber {\strc_counters_reset\s!userpage}
102\unexpanded\def\resetsubpagenumber  {\strc_counters_reset\s!subpage}
103
104\appendtoks
105    \strc_counters_set\s!realpage\realpageno
106    \strc_counters_set\s!userpage\userpageno
107    \strc_counters_set\s!subpage \subpageno
108    \lastpageno\lastcountervalue[\s!realpage]\relax
109\to \everyinitializepagecounters
110
111\let\setuppagenumber\setupuserpagenumber
112\let\resetpagenumber\resetuserpagenumber
113
114% invisible =
115
116\def\strc_pagenumbers_page_state_save % \normalexpanded?
117  {\clf_savepagedata
118     {
119        prefix        {\namedcounterparameter\s!userpage\c!prefix}
120        separatorset  {\namedcounterparameter\s!userpage\c!prefixseparatorset}
121        conversion    {\namedcounterparameter\s!userpage\c!prefixconversion}
122        conversionset {\namedcounterparameter\s!userpage\c!prefixconversionset}
123        set           {\namedcounterparameter\s!userpage\c!prefixset}
124        segments      {\namedcounterparameter\s!userpage\c!prefixsegments}
125        connector     {\namedcounterparameter\s!userpage\c!prefixconnector}
126     }{
127        conversion    {\namedcounterparameter\s!userpage\c!numberconversion}
128        conversionset {\namedcounterparameter\s!userpage\c!numberconversionset}
129        starter       {\namedcounterparameter\s!userpage\c!numberstarter}
130        stopper       {\namedcounterparameter\s!userpage\c!numberstopper}
131     }{
132        viewerprefix  {\namedcounterparameter\s!userpage\c!viewerprefix}
133        state         {\namedcounterparameter\s!userpage\c!state}
134     }%
135   \relax}
136
137\prependtoks
138    \strc_pagenumbers_page_state_save
139\to \everyshipout
140
141\installcorenamespace{pagestatestack} % no level yet
142
143\unexpanded\def\strc_pagenumbers_page_state_push{\setxvalue{\??pagestatestack\c!state}{\namedcounterparameter\s!userpage\c!state}}
144\unexpanded\def\strc_pagenumbers_page_state_pop {\normalexpanded{\setuppagenumber[\c!state=\getvalue{\??pagestatestack\c!state}]}}
145
146\setuppagenumber
147  [\c!way=\v!by\v!text,
148   \c!prefix=\v!no,
149   \c!prefixset=\v!part,
150   \c!prefixconnector=\endash,
151   \c!state=\v!start]
152
153\setupsubpagenumber
154  [\c!way=\v!by\v!part,
155   \c!state=\v!start] % was stop but start looks better in logging
156
157% Counters
158
159\def\firstrealpagenumber{\convertedcounter[\s!realpage][\c!type=\v!first]}
160\def\firstuserpagenumber{\convertedcounter[\s!userpage][\c!type=\v!first]}
161\def\firstsubpagenumber {\convertedcounter[\s!subpage ][\c!type=\v!first]}
162
163\def\lastrealpagenumber {\convertedcounter[\s!realpage][\c!type=\v!last]}
164\def\lastuserpagenumber {\convertedcounter[\s!userpage][\c!type=\v!last]}
165\def\lastsubpagenumber  {\convertedcounter[\s!subpage ][\c!type=\v!last]}
166
167\def\prevrealpagenumber {\convertedcounter[\s!realpage][\c!type=\v!previous]}
168\def\prevuserpagenumber {\convertedcounter[\s!userpage][\c!type=\v!previous]}
169\def\prevsubpagenumber  {\convertedcounter[\s!subpage ][\c!type=\v!previous]}
170
171\def\nextrealpagenumber {\convertedcounter[\s!realpage][\c!type=\v!next]}
172\def\nextuserpagenumber {\convertedcounter[\s!userpage][\c!type=\v!next]}
173\def\nextsubpagenumber  {\convertedcounter[\s!subpage ][\c!type=\v!next]}
174
175\def\firstrealpage{\strc_counters_first\s!realpage}
176\def\firstuserpage{\strc_counters_first\s!userpage}
177\def\firstsubpage {\strc_counters_first\s!subpage }
178
179\def\prevrealpage {\strc_counters_prev \s!realpage}
180\def\prevuserpage {\strc_counters_prev \s!userpage}
181\def\prevsubpage  {\strc_counters_prev \s!subpage }
182
183\def\nextrealpage {\strc_counters_next \s!realpage}
184\def\nextuserpage {\strc_counters_next \s!userpage}
185\def\nextsubpage  {\strc_counters_next \s!subpage }
186
187\def\lastrealpage {\strc_counters_last \s!realpage}
188\def\lastuserpage {\strc_counters_last \s!userpage}
189\def\lastsubpage  {\strc_counters_last \s!subpage }
190
191\let\firstpage\firstrealpage
192\let\prevpage \prevrealpage
193\let\nextpage \nextrealpage
194\let\lastpage \lastrealpage
195
196% Compatibility counters:
197
198\def\nofrealpages {\lastrealpage} \def\totalnumberofpages{\lastrealpage}
199\def\nofuserpages {\lastuserpage} \def\lastpagenumber    {\lastuserpage}
200\def\nofsubpages  {\lastsubpage }
201
202% Renderers:
203
204\def\pagenumber         {\strc_counters_raw\s!userpage}
205\def\prefixedpagenumber {\directconvertedcounter\s!userpage\empty} % \userpagenumber
206
207\def\realpagenumber     {\directconvertedcounter\s!realpage\empty}
208\def\userpagenumber     {\directconvertedcounter\s!userpage\empty}
209\def\subpagenumber      {\directconvertedcounter\s!subpage \empty}
210
211\def\firstrealpagenumber{\directconvertedcounter\s!realpage\v!first}
212\def\firstuserpagenumber{\directconvertedcounter\s!userpage\v!first}
213\def\firstsubpagenumber {\directconvertedcounter\s!subpage \v!first}
214
215\def\lastrealpagenumber {\directconvertedcounter\s!realpage\v!last}
216\def\lastuserpagenumber {\directconvertedcounter\s!userpage\v!last}
217\def\lastsubpagenumber  {\directconvertedcounter\s!subpage \v!last}
218
219\def\prevrealpagenumber {\directconvertedcounter\s!realpage\v!previous}
220\def\prevuserpagenumber {\directconvertedcounter\s!userpage\v!previous}
221\def\prevsubpagenumber  {\directconvertedcounter\s!subpage \v!previous}
222
223\def\nextrealpagenumber {\directconvertedcounter\s!realpage\v!next}
224\def\nextuserpagenumber {\directconvertedcounter\s!userpage\v!next}
225\def\nextsubpagenumber  {\directconvertedcounter\s!subpage \v!next}
226
227\unexpanded\def\strc_pagenumbers_decrement_counters % only at the end
228   {\strc_counters_decrement\s!realpage
229    \strc_counters_decrement\s!userpage
230    \strc_counters_decrement\s!subpage}
231
232\unexpanded\def\strc_pagenumbers_increment_counters
233  {\incrementpagenumber
234   \incrementsubpagenumber}
235
236\appendtoks
237    \strc_pagenumbers_decrement_counters
238\to \everygoodbye
239
240\newcount\c_strc_subpage_first_real \c_strc_subpage_first_real\plusone
241
242\appendtoks
243   \ifcase\subpageno\relax
244     \global\c_strc_subpage_first_real\realpageno
245   \or
246     \global\c_strc_subpage_first_real\realpageno
247   \fi
248\to \everybeforepagebody
249
250\def\therealsubpageno#1% new helper
251  {\the\numexpr\c_strc_subpage_first_real+#1+\minusone\relax}
252
253% Equivalents (compatibility):
254%
255% todo: maybe leave lastpage etc lua calls
256
257\def\realpage{\the\realpageno}
258\def\userpage{\the\userpageno}
259\def\subpage {\the\subpageno}
260
261% Hooks:
262
263\def\currentpage{\the\realpageno}% rather useless
264
265\appendtoks
266    \ifnum\realpageno>\lastpage \glet\lastpage\lastrealpage \fi
267\to \everyinitializepagecounters
268
269% States:
270
271\newconditional\layoutisdoublesided % already defined: \newif\ifdoublesided
272\newconditional\layoutissinglesided % already defined: \newif\ifsinglesided
273
274% Realpage and subpage numbers:
275
276\unexpanded\def\setnextrealpageno{\global\realpageno\strc_counters_incremented\s!realpage\relax}
277\unexpanded\def\setnextsubpageno {\global\subpageno \strc_counters_incremented\s!subpage \relax}
278
279% Page numbers: (can move to lua) ... inconsistent names
280
281\installcorenamespace{pagenumberinc}
282\installcorenamespace{pagenumberdec}
283
284\unexpanded\def\strc_pagenumbers_decrement_userpage{\global\userpageno\strc_counters_decremented\s!userpage\relax}
285\unexpanded\def\strc_pagenumbers_increment_userpage{\global\userpageno\strc_counters_incremented\s!userpage\relax}
286
287\unexpanded\def\decrementsubpagenumber{\global\subpageno \strc_counters_decremented\s!subpage \relax}
288\unexpanded\def\incrementsubpagenumber{\global\subpageno \strc_counters_incremented\s!subpage \relax}
289
290\unexpanded\def\strc_pagenumbers_synchronize_userpage{\global\c_strc_pagenumbers_state_userpage\plustwo} % start and visible
291
292\unexpanded\def\decrementpagenumber{\csname\??pagenumberdec\namedcounterparameter\s!userpage\c!state\endcsname}
293\unexpanded\def\incrementpagenumber{\csname\??pagenumberinc\namedcounterparameter\s!userpage\c!state\endcsname}
294
295\letvalue{\??pagenumberdec\v!start}\strc_pagenumbers_decrement_userpage
296\letvalue{\??pagenumberdec\v!none }\strc_pagenumbers_decrement_userpage
297\letvalue{\??pagenumberdec\v!empty}\strc_pagenumbers_decrement_userpage
298
299\letvalue{\??pagenumberinc\v!start}\strc_pagenumbers_increment_userpage
300\letvalue{\??pagenumberinc\v!none }\strc_pagenumbers_increment_userpage
301\setvalue{\??pagenumberinc\v!empty}{\strc_pagenumbers_increment_userpage\strc_pagenumbers_synchronize_userpage}
302\letvalue{\??pagenumberinc\v!keep }\strc_pagenumbers_synchronize_userpage
303
304% Setup general page numbering
305
306\installcorenamespace{pagenumbering}
307
308\installdirectcommandhandler \??pagenumbering {pagenumbering}
309
310% some day ifsinglesided and ifdoublesided will become obsolete
311
312\newtoks\everysidedswitch
313
314\appendtoks
315   \singlesidedfalse \setfalse\layoutisdoublesided
316   \doublesidedfalse \setfalse\layoutissinglesided
317   \resetsystemmode\v!singlesided
318   \resetsystemmode\v!doublesided
319   \processallactionsinset
320     [\directpagenumberingparameter\c!alternative]%
321     [ \v!singlesided=>\setsystemmode\v!singlesided\singlesidedtrue\settrue\layoutissinglesided,
322       \v!doublesided=>\setsystemmode\v!doublesided\doublesidedtrue\settrue\layoutisdoublesided]%
323   \the\everysidedswitch
324   \pageduplexmode
325     \ifsinglesided
326       \ifdoublesided\plustwo\else\zerocount\fi
327     \else
328       \ifdoublesided\plusone\else\zerocount\fi
329     \fi
330   \page_backgrounds_recalculate
331   \strc_pagenumbers_set_location
332\to \everysetuppagenumbering
333
334\appendtoks
335   \ifdefined\trackingmarginnotestrue
336     \ifdoublesided
337       \trackingmarginnotestrue
338     \else
339       \trackingmarginnotesfalse
340     \fi
341   \fi
342\to \everysidedswitch
343
344\ifdefined \page_backgrounds_recalculate \else
345    \let\page_backgrounds_recalculate\relax
346\fi
347
348\ifdefined \strc_pagenumbers_set_location \else
349    \let\strc_pagenumbers_set_location\relax
350\fi
351
352\unexpanded\def\strc_pagenumbers_flush_final_page
353  {\edef\p_strc_pagenumbers_page{\directpagenumberingparameter\c!page}%
354   \ifx\p_strc_pagenumbers_page\empty \else
355     \ifx\p_strc_pagenumbers_page\v!no \else
356       \page[\p_strc_pagenumbers_page]%
357     \fi
358   \fi}
359
360% The numbered location handler is there because we need to be downward
361% compatible. So, in fact there can be multiple handlers active at the
362% same time, but only the current one does something.
363
364% Rendering:
365
366\unexpanded\def\strc_pagenumbers_place_location
367  {\ifnum\c_strc_pagenumbers_state_userpage=\plustwo
368     \ifnum\c_strc_pagenumbers_state=\plusone
369        \doif{\directpagenumberingparameter\c!strut}\v!yes\strut
370        \begingroup
371        \usepagenumberingstyleandcolor\c!style\c!color
372        \directpagenumberingparameter\c!command
373          {\directpagenumberingparameter\c!left
374           \labeltexts\v!pagenumber\prefixedpagenumber
375           \directpagenumberingparameter\c!right}%
376        \endgroup
377     \fi
378   \fi}
379
380\unexpanded\def\completepagenumber
381  {\ifnum\c_strc_pagenumbers_state_userpage=\plustwo
382     \ifnum\c_strc_pagenumbers_state=\plusone
383        \directpagenumberingparameter\c!left
384        \labeltexts\v!pagenumber\prefixedpagenumber
385        \directpagenumberingparameter\c!right
386     \fi
387   \fi}
388
389\unexpanded\def\placepagenumber
390  {\ifnum\c_strc_pagenumbers_state_userpage=\plustwo
391     \ifnum\c_strc_pagenumbers_state=\plusone
392        \labeltexts\v!pagenumber\pagenumber
393     \fi
394   \fi}
395
396\unexpanded\def\referencepagenumber[#1]%
397  {\doifelsenothing{#1}{?}{}}
398
399% The numbered location handler is there because we need to be downward
400% compatible. So, in fact there can be multiple handlers active at the
401% same time, but only the current one does something.
402
403\setnewconstant\c_strc_pagenumbers_state_realpage\plustwo % counter state : 0=stop, 1=start, 2=start and visible
404\setnewconstant\c_strc_pagenumbers_state_userpage\plustwo % counter state : 0=stop, 1=start, 2=start and visible
405\setnewconstant\c_strc_pagenumbers_state_subpage \plustwo % counter state : 0=stop, 1=start, 2=start and visible
406\setnewconstant\c_strc_pagenumbers_state         \plusone % general number: 0=invisible, 1=visible
407
408\unexpanded\def\strc_pagenumbers_check_state_change#1#2%
409  {\edef\m_strc_pagenumbers_state_new{\namedcounterparameter#1\c!state}%
410   \ifx\m_strc_pagenumbers_state_new\m_strc_pagenumbers_state_old \else
411     #2\ifx\m_strc_pagenumbers_state_new\v!start\plustwo\else\zerocount\fi
412   \fi}
413
414
415\appendtoks % todo: set state: none, start, stop, reset
416    \strc_pagenumbers_check_state_change\s!realpage\c_strc_pagenumbers_state_realpage
417\to \everysetuprealpagenumber
418
419\appendtoks % todo: set state: none, start, stop, reset
420    \strc_pagenumbers_check_state_change\s!userpage\c_strc_pagenumbers_state_userpage
421\to \everysetupuserpagenumber
422
423\appendtoks % todo: set state: none, start, stop, reset
424    \strc_pagenumbers_check_state_change\s!subpage\c_strc_pagenumbers_state_subpage
425\to \everysetupsubpagenumber
426
427\appendtoks % todo: set state: none, start, stop, reset
428    \doifelse{\directpagenumberingparameter\c!state}\v!start
429      {\c_strc_pagenumbers_state\plusone  }%
430      {\c_strc_pagenumbers_state\zerocount}%
431\to \everysetuppagenumbering
432
433% Done
434
435% \c!way=\v!by\v!part
436% \c!text=
437% \v!chapter\v!number=\v!no
438% \v!part\v!number=\v!yes
439% \c!numberseparator=--
440% \c!conversion=\v!numbers
441
442\setuppagenumbering
443  [\c!alternative=\v!singlesided,
444   \c!location={\v!header,\v!middle},
445   \c!width=, % in geval van \v!marginedge
446   \c!left=,
447   \c!right=,
448   \c!page=\v!last,
449   \c!textseparator=\tfskip,
450   \c!state=\v!start,
451   \c!command=,
452   \c!strut=\v!yes,
453   \c!style=, % empty, otherwise conflict
454   \c!color=]
455
456% just for downward compatbility
457
458\appendtoks
459    \edef\askeduserpagenumber{\namedcounterparameter\s!userpage\c!number}%
460    \ifx\askeduserpagenumber\empty \else
461      \normalexpanded{\setuppagenumber[\c!start=\askeduserpagenumber,\c!number=]}%
462      \userpageno\strc_counters_raw\s!userpage
463    \fi
464\to \everysetupuserpagenumber % todo: set state: none, start, stop, reset
465
466\appendtoks
467    \edef\askedsubpagenumber{\namedcounterparameter\s!subpage\c!number}%
468    \ifx\askedsubpagenumber\empty \else
469      \normalexpanded{\setupsubpagenumber[\c!start=\askedsubpagenumber,\c!number=]}%
470      \subpageno\strc_counters_raw\s!subpage\relax
471    \fi
472\to \everysetupsubpagenumber % todo: set state: none, start, stop, reset
473
474% \setuplayout[width=300pt,backspace=4cm]
475% \setuppagenumbering [alternative=doublesided]
476% \setupuserpagenumber[start=2]
477% \starttext \dorecurse{20}{\input knuth \par} \stoptext
478
479\unexpanded\def\strc_pagenumbers_check_change_shift
480  {\userpageno\strc_counters_raw\s!userpage\relax
481   \ifnum\realpageno=\plusone
482     \ifodd\userpageno
483     \else
484       \global\pagenoshift\plusone
485     \fi
486   \fi}
487
488\appendtoks % todo: set state: none, start, stop, reset
489    % this makes starting at an even page possible
490    \strc_pagenumbers_check_change_shift
491\to \everysetupuserpagenumber
492
493\appendtoks % todo: set state: none, start, stop, reset
494    % this makes starting at an even page possible
495    \strc_pagenumbers_check_change_shift
496\to \everysetuppagenumbering
497
498\initializepagecounters
499
500\stopcontextdefinitioncode
501
502\protect \endinput
503