page-brk.mkiv /size: 17 Kb    last modification: 2020-07-01 14:35
1%D \module
2%D   [       file=page-brk,   % moved from page-ini
3%D        version=2011.12.07, % 2000.10.20,
4%D          title=\CONTEXT\ Page Macros,
5%D       subtitle=Breaks,
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 Page Macros / Breaks}
15
16\unprotect
17
18\ifdefined\resetcurrentstructuremarkswithpage \else \let\resetcurrentstructuremarkswithpage\relax \fi
19\ifdefined\noheaderandfooterlines             \else \let\noheaderandfooterlines            \relax \fi
20
21%D Page breaks.
22
23% \definepagebreak
24%   [chapter]
25%   [yes,header,right]
26%
27% \setuphead
28%   [chapter]
29%   [page=chapter,
30%    header=empty,
31%    footer=chapter]
32%
33% \definepagebreak % untested
34%   [lastpage]
35%   [left,{empty,right},{empty,left}]
36
37% public page handler, beware: definepage already in use (core-ref)
38%
39% \definepagebreak[instance][forsure]
40% \definepagebreak[forsure][yes,+4]
41
42\newconditional\c_page_breaks_enabled   \settrue\c_page_breaks_enabled
43\newcount      \c_page_breaks_prevpage
44
45\newtoks\everybeforepagebreak
46\newtoks\everyafterpagebreak
47
48\let\page_breaks_current_option \empty
49\let\page_breaks_current_options\empty
50
51\installcorenamespace{pagebreakmethod}
52\installcorenamespace{pagebreaks}
53
54\def\page_breaks_handle#1%
55  {\edef\page_breaks_current_options{#1}% handy for tracing
56   \processcommacommand[\page_breaks_current_options]\page_breaks_handle_step}
57
58\def\page_breaks_handle_step#1%
59  {\edef\page_breaks_current_option{#1}% can be used in handler
60   \ifcsname\??pagebreakmethod\page_breaks_current_option\endcsname
61     \lastnamedcs
62   \else\ifcsname\??pagebreaks\page_breaks_current_option\endcsname
63     \expandafter\page_breaks_handle\lastnamedcs
64   \else
65     \page_breaks_unknown
66   \fi\fi}
67
68\def\page_breaks_handle_direct#1%
69 %{\csname\??pagebreakmethod#1\endcsname}
70  {\begincsname\??pagebreakmethod#1\endcsname}
71
72\unexpanded\def\installpagebreakmethod#1#2% low level definer
73  {\setvalue{\??pagebreakmethod#1}{#2}}
74
75\let\installpagebreakhandler\installpagebreakmethod % will go
76
77\unexpanded\def\definepagebreak
78  {\dodoubleargument\page_breaks_define}
79
80\def\page_breaks_define[#1][#2]%
81  {\setvalue{\??pagebreaks#1}{#2}}
82
83\unexpanded\def\pagebreak
84  {\par % else no vertical penalties
85   \dosingleempty\page_breaks_process}
86
87\let\page\pagebreak
88
89\appendtoks
90    \flushnotes
91\to \everybeforepagebreak
92
93\def\page_breaks_process[#1]% so, page ornaments are reset after a pagebreak command, unless set
94  {\par % always before group so that we clear hangs etc (as in side floats)
95   \ifvmode % extra check
96     \begingroup
97     \the\everybeforepagebreak
98     \c_page_breaks_prevpage\realpageno
99     \ifcase\pageornamentstate \or
100       % disable reset after shipout
101       \global\pageornamentstate\plustwo
102     \fi
103     \iffirstargument % or if empty i.e. []
104       \page_breaks_handle{#1}%
105     \else % so, no pagebreak when \pagebreak[] ! ! !
106       \page_breaks_handle_direct\v!yes
107     \fi
108     \relax
109     \ifnum\c_page_breaks_prevpage<\realpageno
110       \global\pageornamentstate\zerocount
111     \fi
112     \the\everyafterpagebreak
113     \endgroup
114   \fi}
115
116\unexpanded\def\usepageparameter#1%
117  {\edef\m_page_breaks_asked{#1\c!page}%
118   \ifx\m_page_breaks_asked\empty\else
119     \firstargumenttrue
120     \page_breaks_process[\m_page_breaks_asked]%
121   \fi}
122
123\unexpanded\def\dousepageparameter#1%
124  {\edef\m_page_breaks_asked{#1}%
125   \ifx\m_spac_align_asked\empty\else
126     \firstargumenttrue
127     \page_breaks_process[\m_page_breaks_asked]%
128   \fi}
129
130\unexpanded\def\resetpagebreak % used elsewhere too
131  {\global\settrue\c_page_breaks_enabled}
132
133\unexpanded\def\simplifypagebreak % to be used grouped !
134  {\def\page_breaks_process[##1]{\goodbreak}}
135
136\unexpanded\def\disablepagebreaks % to be used grouped !
137  {\def\page_breaks_process[##1]{}}
138
139\installpagebreakmethod \s!dummy
140  {\page_otr_command_flush_all_floats
141   \page_otr_command_next_page
142   \page_otr_insert_dummy_page}
143
144\installpagebreakmethod \v!frame
145  {\page
146   \begingroup
147   \showframe
148   \page[\v!empty]
149   \endgroup}
150
151\unexpanded\def\page_breaks_unknown % how often called ?
152  {\doifelseinstring{+}\page_breaks_current_option
153     {\page_otr_command_flush_all_floats
154      \page_otr_command_next_page
155      \dorecurse\page_breaks_current_option\page_otr_insert_dummy_page}
156     {\doifelsenumber\page_breaks_current_option
157        {\page_otr_command_flush_all_floats
158         \page_otr_command_next_page
159         \doloop
160           {\ifnum\userpageno<\page_breaks_current_option\relax
161              \page_otr_insert_dummy_page
162            \else
163              \exitloop
164            \fi}}
165        {}}}
166
167\installpagebreakmethod \s!unknown
168 {\page_breaks_unknown}
169
170\installpagebreakmethod \s!default
171  {} % do nothing if empty
172
173\installpagebreakmethod \v!reset
174  {% better not: \global\pageornamentstate\zerocount
175   \resetpagebreak}
176
177\installpagebreakmethod \v!disable
178  {\global\setfalse\c_page_breaks_enabled}
179
180\installpagebreakmethod \v!yes
181  {\ifconditional\c_page_breaks_enabled
182     \page_otr_command_flush_all_floats
183     \page_otr_command_next_page
184     \ifinsidecolumns       % this will move to MUL
185       \page_otr_eject_page % otherwise sometimes no change
186     \fi
187   \fi}
188
189\installpagebreakmethod \v!makeup
190  {\ifconditional\c_page_breaks_enabled
191     \page_otr_fill_and_eject_page
192   \fi}
193
194\installpagebreakmethod \v!blank
195  {\ifcase\pageornamentstate
196     \global\pageornamentstate\plusone
197   \fi}
198
199% also needed: \page \doifoddpageelse\relax{\page[\v!blank,\v!right]
200
201\installpagebreakmethod \v!no
202  {\ifconditional\c_page_breaks_enabled
203     \dosomebreak\nobreak
204   \fi}
205
206\installpagebreakmethod \v!preference
207  {\ifconditional\c_page_breaks_enabled
208     \ifinsidecolumns % this will move to MUL
209       \dosomebreak\goodbreak
210     \else
211       \testpage[3][\zeropoint]%
212     \fi
213   \fi}
214
215\installpagebreakmethod \v!bigpreference
216  {\ifconditional\c_page_breaks_enabled
217     \ifinsidecolumns % this will move to MUL
218       \dosomebreak\goodbreak
219     \else
220       \testpage[5][\zeropoint]%
221     \fi
222   \fi}
223
224% \installpagebreakmethod \v!empty {} % defined in page-txt.mkiv
225% \installpagebreakmethod \v!header{} % defined in page-txt.mkiv
226% \installpagebreakmethod \v!footer{} % defined in page-txt.mkiv
227
228\def\page_reset_marks_and_insert_dummy
229  {\resetcurrentstructuremarkswithpage\page_otr_insert_dummy_page}
230
231\installpagebreakmethod \v!left
232  {\page_otr_command_flush_all_floats
233   \page_otr_command_next_page_and_inserts
234   \doifbothsidesoverruled\donothing\page_reset_marks_and_insert_dummy\donothing}
235
236\installpagebreakmethod \v!right
237  {\page_otr_command_flush_all_floats
238   \page_otr_command_next_page_and_inserts
239   \doifbothsidesoverruled\donothing\donothing\page_reset_marks_and_insert_dummy}
240
241\installpagebreakmethod \v!even
242  {\page
243   \doifelseoddpage\page_reset_marks_and_insert_dummy\donothing}
244
245\installpagebreakmethod \v!odd
246  {\page
247   \doifelseoddpage\donothing\page_reset_marks_and_insert_dummy}
248
249% \installpagebreakmethod \v!quadruple % not yet ok inside columnsets
250%   {\ifdoublesided
251%      \ifnum\numexpr\realpageno/\plusfour\relax=\numexpr\realpageno/\plustwo\relax\else
252%        \page_breaks_handle_direct\v!yes
253%        \page_breaks_handle_direct\v!empty
254%        \page_breaks_handle_direct\v!empty
255%      \fi
256%    \fi}
257
258\installpagebreakmethod \v!quadruple % not yet ok inside columnsets
259  {\ifdoublesided
260     \ifcase\modulonumber\plusfour\realpageno\else
261       \page_breaks_handle_direct\v!yes
262       \doloop
263         {\ifcase\modulonumber\plusfour\realpageno\relax
264            \exitloop
265          \else
266            \page_breaks_handle_direct\v!empty
267          \fi}%
268     \fi
269   \fi}
270
271\installpagebreakmethod \v!last
272  {\page_otr_command_flush_all_floats
273   \page_otr_command_next_page_and_inserts
274   \relax
275   \doifbothsidesoverruled
276     \page_facings_flush % hm
277     \donothing
278     {\noheaderandfooterlines
279      \page_otr_insert_dummy_page}%
280   \filluparrangedpages}
281
282\installpagebreakmethod \v!lastpage % handy for backpage preceded by empty pages
283  {\page_breaks_handle_direct\v!yes
284   \ifdoublesided
285     \page_breaks_handle_direct\v!left
286     \page_breaks_handle_direct\v!empty
287     \page_breaks_handle_direct\v!empty
288   \fi}
289
290\installpagebreakmethod \v!start {\global\settrue \c_otr_shipout_enabled}
291\installpagebreakmethod \v!stop  {\global\setfalse\c_otr_shipout_enabled}
292
293\installpagebreakmethod{xy}% for Mojca
294  {\page_breaks_handle_direct\v!yes
295   \scratchcounterone  \numexpr\rootlayouttargetparameter\c!nx*\rootlayouttargetparameter\c!ny\relax
296   \scratchcountertwo  \luaexpr{math.mod(\the\realpageno-1,\the\scratchcounterone)}\relax
297   \scratchcounterthree\numexpr\scratchcounterone-\scratchcountertwo\relax
298   \dorecurse\scratchcounterthree{\page_breaks_handle_direct\v!empty}}
299
300% Column breaks.
301
302\installcorenamespace{columnbreakmethod}
303\installcorenamespace{columnbreaks}
304
305\newtoks\everybeforecolumnbreak
306\newtoks\everyaftercolumnbreak
307\newtoks\everysynchronizecolumn
308
309\let\page_breaks_columns_current_option \empty
310\let\page_breaks_columns_current_options\empty
311
312\def\page_breaks_columns_handle#1%
313  {\edef\page_breaks_columns_current_options{#1}%
314   \processcommacommand[#1]\page_breaks_columns_handle_step}
315
316\def\page_breaks_columns_handle_step#1%
317  {\edef\page_breaks_columns_current_option{#1}%
318   \ifcsname\??columnbreakmethod\currentoutputroutine:\page_breaks_columns_current_option\endcsname
319     \lastnamedcs
320   \else\ifcsname\??columnbreaks\page_breaks_columns_current_option\endcsname
321    %\expandafter\csname\page_breaks_columns_handle\??columnbreaks\page_breaks_columns_current_option\endcsname
322     \lastnamedcs
323   \else\ifcsname\??columnbreakmethod\currentoutputroutine:\s!unknown\endcsname
324     \lastnamedcs
325   \fi\fi\fi}
326
327\def\page_breaks_columns_handle_direct#1%
328 %{\csname\??columnbreakmethod\currentoutputroutine:#1\endcsname}
329  {\begincsname\??columnbreakmethod\currentoutputroutine:#1\endcsname}
330
331\unexpanded\def\installcolumnbreakmethod#1#2#3% #1=otr-id #2=tag #3=action
332  {\setvalue{\??columnbreakmethod#1:#2}{#3}}
333
334\let\installcolumnbreakhandler\installcolumnbreakmethod % will go
335
336\unexpanded\def\definecolumnbreak
337  {\dodoubleargument\page_break_columns_define}
338
339\def\page_break_columns_define[#1][#2]%
340  {\setvalue{\??columnbreaks#1}{#2}}
341
342\unexpanded\def\columnbreak
343  {\par % else no vertical penalties
344   \dosingleempty\page_breaks_columns_process}
345
346\let\column\columnbreak
347
348\def\page_breaks_columns_process[#1]% so, page ornaments are reset after a pagebreak command, unless set
349  {\begingroup
350   \the\everybeforecolumnbreak
351   \iffirstargument
352     \page_breaks_columns_handle{#1}%
353   \else
354     \page_breaks_columns_handle_direct\v!yes
355   \fi
356   \relax
357   \the\everyaftercolumnbreak
358   \endgroup
359   % outside group e.g. setting hsize
360   \the\everysynchronizecolumn}
361
362\appendtoks
363    \page_otr_command_set_hsize
364\to \everysynchronizecolumn
365
366%D Test page breaks.
367
368% \newdimen   \d_page_tests_test
369% \newconstant\c_page_tests_mode
370
371\newconstant\testpagemethod  % old
372\newconstant\testpagetrigger % old
373
374% \unexpanded\def\testpage    {\c_page_tests_mode\plusone  \dodoubleempty\page_tests_test} %
375% \unexpanded\def\testpageonly{\c_page_tests_mode\plustwo  \dodoubleempty\page_tests_test} % no penalties added to the mvl
376% \unexpanded\def\testpagesync{\c_page_tests_mode\plusthree\dodoubleempty\page_tests_test} % force sync
377%
378% \def\page_tests_test[#1][#2]% don't change, only add more methods
379%   {\relax % needed before \if
380%    \ifconditional\c_page_breaks_enabled
381%      % new from here
382%      \ifcase\testpagetrigger
383%        \endgraf
384%      \or\ifvmode
385%        \dosomebreak\allowbreak
386%      \else % indeed?
387%        \vadjust{\allowbreak}%
388%        \endgraf
389%      \fi\fi
390%      % till here
391%      \ifdim\pagegoal<\maxdimen \relax
392%        \ifdim\pagetotal<\pagegoal \relax
393%          \d_page_tests_test\dimexpr
394%             #1\lineheight
395%            +\pagetotal
396%            \ifdim\lastskip<\parskip+\parskip\fi
397%            \ifsecondargument+#2\fi
398%          \relax
399%          \ifcase\testpagemethod
400%            \ifdim\d_page_tests_test>.99\pagegoal
401%              \penalty-\plustenthousand
402%            \fi
403%          \or
404%            \ifdim\dimexpr\d_page_tests_test-\pagegoal\relax>-\lineheight
405%              \penalty-\plustenthousand
406%            \fi
407%          \or
408%            \getnoflines\pagegoal
409%            \ifdim\dimexpr\d_page_tests_test-\noflines\lineheight\relax>-\lineheight
410%              \penalty-\plustenthousand
411%            \fi
412%          \or % same as 0 but more accurate
413%            \ifdim\dimexpr\d_page_tests_test-10\scaledpoint\relax>\pagegoal
414%              \penalty-\plustenthousand
415%            \fi
416%          \fi
417%        \else\ifnum\c_page_tests_mode=\plusthree
418%          \page_tests_flush_so_far
419%        \fi\fi
420%      \else\ifnum\c_page_tests_mode=\plusone
421%        \goodbreak
422%      \fi\fi
423%    \else
424%      \endgraf
425%    \fi}
426%
427% \def\page_tests_flush_so_far
428%   {\endgraf
429%    \ifdim\pagetotal>\pagegoal
430%      \ifdim\dimexpr\pagetotal-\pageshrink\relax>\pagegoal
431%        \goodbreak
432%      \else
433%        \page
434%      \fi
435%    \fi}
436
437\installcorenamespace {pagechecker}
438\installcorenamespace {pagecheckermethod}
439
440\installcommandhandler \??pagechecker {pagechecker} \??pagechecker
441
442\setuppagechecker
443  [\c!method=1,
444   \c!before=,
445   \c!after=,
446   \c!inbetween=,
447   \c!lines=\plusthree,
448   \c!offset=\zeropoint]
449
450\def\page_check_amount
451  {\dimexpr
452      \pagecheckerparameter\c!lines\lineheight
453     +\pagetotal
454     \ifdim\lastskip<\parskip+\parskip\fi
455     +\pagecheckerparameter\c!offset
456   \relax}
457
458\unexpanded\def\checkpage
459  {\dodoubleempty\page_check}
460
461\def\page_check[#1][#2]%
462  {\relax % needed before \if
463   \endgraf
464   \triggerpagebuilder
465   \relax
466   \ifconditional\c_page_breaks_enabled
467     \begingroup
468     \edef\currentpagechecker{#1}%
469     \ifsecondargument\setupcurrentpagechecker[#2]\fi
470     \csname\??pagecheckermethod\pagecheckerparameter\c!method\endcsname
471     \endgroup
472   \fi}
473
474\setvalue{\??pagecheckermethod 0}%
475  {\ifdim\pagegoal<\maxdimen \relax
476     \ifdim\pagetotal<\pagegoal \relax
477       \ifdim\page_check_amount>.99\pagegoal
478         \pagecheckerparameter\c!before
479         \penalty-\plustenthousand
480         \pagecheckerparameter\c!after
481       \else
482         \pagecheckerparameter\c!inbetween
483       \fi
484     \else
485       \pagecheckerparameter\c!inbetween
486     \fi
487   \else
488     \pagecheckerparameter\c!inbetween
489   \fi}
490
491\setvalue{\??pagecheckermethod 1}%
492  {\ifdim\pagegoal<\maxdimen \relax
493     \ifdim\pagetotal<\pagegoal \relax
494       \ifdim\dimexpr\page_check_amount-\pagegoal\relax>-\lineheight
495         \pagecheckerparameter\c!before
496         \penalty-\plustenthousand
497         \pagecheckerparameter\c!after
498       \else
499         \pagecheckerparameter\c!inbetween
500       \fi
501     \else
502       \pagecheckerparameter\c!inbetween
503     \fi
504   \else
505     \goodbreak
506     \pagecheckerparameter\c!inbetween
507   \fi}
508
509\setvalue{\??pagecheckermethod 2}%
510  {\ifdim\pagegoal<\maxdimen \relax
511     \ifdim\pagetotal<\pagegoal \relax
512       \getnoflines\pagegoal
513       \ifdim\dimexpr\page_check_amount-\noflines\lineheight\relax>-\lineheight
514         \pagecheckerparameter\c!before
515         \penalty-\plustenthousand
516         \pagecheckerparameter\c!after
517       \else
518         \pagecheckerparameter\c!inbetween
519       \fi
520     \else
521       \pagecheckerparameter\c!inbetween
522     \fi
523   \else
524     \pagecheckerparameter\c!inbetween
525   \fi}
526
527\setvalue{\??pagecheckermethod 3}%
528  {\ifdim\pagegoal<\maxdimen \relax
529     \ifdim\pagetotal<\pagegoal \relax
530       \ifdim\dimexpr\page_check_amount-10\scaledpoint\relax>\pagegoal
531         \pagecheckerparameter\c!before
532         \penalty-\plustenthousand
533         \pagecheckerparameter\c!after
534       \else
535         \pagecheckerparameter\c!inbetween
536       \fi
537     \else
538       \ifdim\pagetotal>\pagegoal
539         \ifdim\dimexpr\pagetotal-\pageshrink\relax>\pagegoal
540           \goodbreak
541           \pagecheckerparameter\c!inbetween
542         \else
543           \pagecheckerparameter\c!before
544           \page
545           \pagecheckerparameter\c!after
546         \fi
547       \else
548         \pagecheckerparameter\c!inbetween
549       \fi
550     \fi
551   \else
552     \pagecheckerparameter\c!inbetween
553   \fi}
554
555\definepagechecker[\s!unknown:0]              [\c!method=0,\c!before=,\c!after=,\c!inbetween=]
556\definepagechecker[\s!unknown:1][\s!unknown:0][\c!method=1]
557\definepagechecker[\s!unknown:2][\s!unknown:0][\c!method=2]
558\definepagechecker[\s!unknown:3][\s!unknown:0][\c!method=3]
559
560\def\page_tests_test_a[#1][#2]{\normalexpanded{\checkpage[\s!unknown:1][\c!lines=#1,\c!offset=\ifsecondargument#2\else\zeropoint\fi]}}
561\def\page_tests_test_b[#1][#2]{\normalexpanded{\checkpage[\s!unknown:2][\c!lines=#1,\c!offset=\ifsecondargument#2\else\zeropoint\fi]}}
562\def\page_tests_test_c[#1][#2]{\normalexpanded{\checkpage[\s!unknown:3][\c!lines=#1,\c!offset=\ifsecondargument#2\else\zeropoint\fi]}}
563
564\unexpanded\def\testpage    {\dodoubleempty\page_tests_test_a} %
565\unexpanded\def\testpageonly{\dodoubleempty\page_tests_test_b} % no penalties added to the mvl
566\unexpanded\def\testpagesync{\dodoubleempty\page_tests_test_c} % force sync
567
568%D Test column breaks.
569
570\unexpanded\def\testcolumn
571  {\dodoubleempty\page_tests_columns_test}
572
573\def\page_tests_columns_test[#1][#2]%
574  {\ifdefined\page_otr_command_test_column
575     \ifsecondargument
576        \page_otr_command_test_column[#1][#2]%
577     \else
578        \page_otr_command_test_column[#1][\zeropoint]%
579     \fi
580   \fi}
581
582\protect \endinput
583