page-mix.mkiv /size: 35 Kb    last modification: 2021-10-28 13:50
1%D \module
2%D   [       file=page-mix,
3%D        version=2012.07.12,
4%D          title=\CONTEXT\ Page Macros,
5%D       subtitle=Mixed Columns,
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 / Mixed Columns}
15
16%D This is a very experimental module. Eventually it will replace the current
17%D multi column mechanism (that then will be an instance). The \LUA\ part of
18%D the interface will quite probably change so don't use that one directly
19%D (yet).
20
21% todo:
22%
23% consult note class
24% notes per page
25% notes in each column
26% notes in last column
27% notes local/global
28% top and bottom inserts
29% wide floats
30% move floats
31% offsets (inner ones, so we change the hsize  ... needed with backgrounds
32% when no content we currently loose the page
33
34\registerctxluafile{page-mix}{}
35
36\unprotect
37
38%D The mixed output routine replaces the traditional multi column handler that
39%D started out in \MKII. One of the complications of a routine is that it needs
40%D to align nicely when mixed in a single column layout. Instead of using all
41%D kind of shift juggling in this mechanism we simply switch to grid mode
42%D locally. After all, columns don't look nice when not on a. As the grid
43%D snapper in \MKIV\ is more advanced not that much extra code is needed.
44
45%D We use the command handler but the parent settings are not to be changed.
46%D Instead we could have used a dedicated root setup, but it's not worth the
47%D trouble.
48
49\installcorenamespace{mixedcolumns}
50
51\installframedcommandhandler \??mixedcolumns {mixedcolumns} \??mixedcolumns
52
53% old multicolumns mechanism
54%
55% \c!ntop=1,
56% \c!rule=\v!off, : now separator=rule
57% \c!height=,
58% \c!blank={\v!line,\v!fixed},
59% \c!rulethickness=\linewidth,
60% \c!offset=.5\bodyfontsize,
61
62\setupmixedcolumns
63  [\c!distance=1.5\bodyfontsize,
64   \c!n=\plustwo,
65  %\c!align=, % inherit (also replaces tolerance)
66  %\c!before=,
67  %\c!after=,
68  %\c!separator=\v!none,
69  %\c!setups=,
70  %\c!balance=\v!no,
71  %\c!blank={\v!line,\v!fixed}, yes or no
72   \c!frame=\v!off,
73   \c!strut=\v!no,
74   \c!offset=\v!overlay,
75   \c!alternative=\v!local,
76   \c!maxheight=\textheight,
77   \c!maxwidth=\makeupwidth,
78   \c!grid=\v!tolerant,
79   \c!internalgrid=\v!line,
80   \c!step=.25\lineheight, % needs some experimenting
81  %\c!splitmethod=\v!fixed, % will be default
82   \c!direction=\v!normal, % new (also todo in the new columnsets)
83   \c!notes=\v!yes,
84   \c!method=\ifinner\s!box\else\s!otr\fi] % automatic as suggested by WS
85
86\let\startmixedcolumns\relax % defined later
87\let\stopmixedcolumns \relax % defined later
88
89\appendtoks % could become an option
90    \setuevalue{\e!start\currentmixedcolumns}{\startmixedcolumns[\currentmixedcolumns]}%
91    \setuevalue{\e!stop \currentmixedcolumns}{\stopmixedcolumns}%
92\to \everydefinemixedcolumns
93
94%D In order to avoid a mixup we use quite some local registers.
95
96\newdimen      \d_page_mix_column_width
97\newdimen      \d_page_mix_max_height
98\newdimen      \d_page_mix_max_width
99\newdimen      \d_page_mix_distance
100\newcount      \c_page_mix_n_of_columns
101\newdimen      \d_page_mix_threshold
102\newdimen      \d_page_mix_leftskip
103\newdimen      \d_page_mix_rightskip
104
105\newdimen      \d_page_mix_balance_step
106\setnewconstant\c_page_mix_balance_cycles   500
107
108\setnewconstant\c_page_mix_break_forced    -123
109
110\newbox        \b_page_mix_preceding
111\newdimen      \d_page_mix_preceding_height
112
113\newbox        \b_page_mix_collected
114
115\newconstant   \c_page_mix_routine
116
117\setnewconstant\c_page_mix_routine_regular  \zerocount
118\setnewconstant\c_page_mix_routine_intercept\plusone
119\setnewconstant\c_page_mix_routine_continue \plustwo
120\setnewconstant\c_page_mix_routine_balance  \plusthree
121\setnewconstant\c_page_mix_routine_error    \plusfour
122
123\newconditional\c_page_mix_process_notes
124\newconditional\c_page_mix_grid_snapping
125
126%D The main environment is called as follows:
127%D
128%D \starttyping
129%D \startmixedcolumns[instance][settings]
130%D \startmixedcolumns[instance]
131%D \startmixedcolumns[settings]
132%D \stoptyping
133%D
134%D However, best is not to use this one directly but define an instance and
135%D use that one.
136
137% % For the moment only on my machine:
138%
139% \definemixedcolumns
140%   [\v!columns]
141%
142% \unexpanded\def\setupcolumns
143%   {\setupmixedcolumns[\v!columns]}
144
145%D In itemizations we also need columns, so let's define a apecial instance
146%D for them. These need to work well in situations like this:
147%D
148%D \starttyping
149%D \input zapf
150%D
151%D \startnarrower
152%D     \startitemize[columns,two,packed][before=,after=]
153%D         \dorecurse{10}{\startitem item #1 \stopitem}
154%D     \stopitemize
155%D \stopnarrower
156%D
157%D \input zapf
158%D
159%D \startnarrower
160%D     \startitemize[columns,two][before=,after=]
161%D         \dorecurse{10}{\startitem item #1 \stopitem}
162%D     \stopitemize
163%D \stopnarrower
164%D
165%D \input zapf
166%D
167%D \startnarrower
168%D     \startitemize[columns,two]
169%D         \dorecurse{10}{\startitem item #1 \stopitem}
170%D     \stopitemize
171%D \stopnarrower
172%D
173%D \input zapf
174%D \stoptyping
175
176\ifdefined\s!itemgroupcolumns \else \def\s!itemgroupcolumns{itemgroupcolumns} \fi
177
178\definemixedcolumns
179  [\s!itemgroupcolumns]
180  [\c!n=\itemgroupparameter\c!n,
181   \c!direction=\itemgroupparameter\c!direction,
182   \c!separator=\v!none,
183   \c!splitmethod=\v!none,
184   \c!grid=\v!tolerant,
185   \c!internalgrid=\v!halfline, % new, we may still revert to \v!line
186   \c!balance=\v!yes,
187   \c!notes=\v!no] % kind of hidden
188
189% better
190
191\setupmixedcolumns
192  [\s!itemgroupcolumns]
193  [\c!splitmethod=\v!fixed,
194   \c!grid=\v!yes,
195   \c!internalgrid=\v!line]
196
197% even better:
198
199\setupitemgroup
200  [\c!grid=\v!tolerant:10] % 10 pct tolerance in columns snapping
201
202\setupmixedcolumns
203  [\s!itemgroupcolumns]
204  [\c!grid=\itemgroupparameter\c!grid]
205
206% the fast hooks:
207
208\unexpanded\def\strc_itemgroups_start_columns
209  {\startmixedcolumns[\s!itemgroupcolumns]} % we could have a fast one
210
211\unexpanded\def\strc_itemgroups_stop_columns
212  {\stopmixedcolumns}
213
214%D The mixed output routine can be in different states. First we need to intercept
215%D the already present content. This permits mixed single and multi column usage.
216%D Then we have the continuous routine, one that intercepts pages in sequence.
217%D Finally, when we finish the mixed columns mode, we can (optionally) balance the
218%D last page.
219
220\unexpanded\def\page_mix_command_routine
221  {\ifcase\c_page_mix_routine
222     \page_one_command_routine
223   \or
224     \page_mix_routine_intercept
225   \or
226     \page_mix_routine_continue
227   \or
228     \page_mix_routine_balance
229   \or
230     \page_mix_routine_error
231   \fi}
232
233%D The interceptor is quite simple, at least for the moment.
234
235\def\page_mix_routine_intercept
236  {\ifdim\pagetotal>\pagegoal
237     % testcase: preceding-001 ... if we don't do this, text can disappear as
238     % preceding is overwritten ... needs to be figured out some day
239     \page_one_command_routine
240   \fi
241   \global\setbox\b_page_mix_preceding\vbox % pack ?
242     {\forgetall
243      \page_otr_command_flush_top_insertions
244      \ifdim\htdp\b_page_mix_preceding=\zeropoint \else
245        \writestatus\m!columns{preceding error}%
246        \unvbox\b_page_mix_preceding
247      \fi
248      \unvbox\normalpagebox}}
249
250%D The error routine is there but unlikely to be called. It is a left-over from
251%D the traditional routine that might come in handy some day.
252
253\def\page_mix_construct_and_shipout#1#2#3%
254  {\ifconditional\c_page_mix_grid_snapping\else\gridsnappingfalse\fi % maybe only for notes (bottom alignment)
255   \page_otr_construct_and_shipout#1#2#3%
256   \ifconditional\c_page_mix_grid_snapping     \gridsnappingtrue \fi}
257
258
259\def\page_mix_routine_error
260  {\showmessage\m!columns3\empty
261   \page_mix_construct_and_shipout\unvbox\normalpagebox\zerocount} % three arguments
262
263%D Some settings (and actions) depend on the current output routine and setting the
264%D hsize and vsize is among them. The calculation of the hsize is done elsewhere.
265
266\unexpanded\def\page_mix_command_set_hsize
267  {\hsize\d_page_mix_column_width
268   \columnwidth\d_page_mix_column_width}
269
270%D When setting the vsize we make sure that we collect a few more lines than needed
271%D so that we have enough to split over the columns. Collecting too much is somewhat
272%D tricky as they will spill over to the next page.
273
274\unexpanded\def\page_mix_command_set_vsize
275  {\vsize\dimexpr\c_page_mix_n_of_columns\textheight+\c_page_mix_n_of_columns\lineheight\relax
276   \pagegoal\vsize}
277
278%D As we use \LUA\ there is the usual amount of tracing at that end. At the tex end
279%D we only visualize boxes.
280
281\let\page_mix_hbox\hbox
282\let\page_mix_vbox\vbox
283
284\installtextracker
285  {mixedcolumns.boxes}
286  {\let\page_mix_hbox\ruledhbox
287   \let\page_mix_vbox\ruledvbox}
288  {\let\page_mix_hbox\hbox
289   \let\page_mix_vbox\vbox}
290
291%D We provide a few column break options. Interesting is that while forcing a new
292%D column in the traditional mechanism was a pain, here it works quite well.
293
294\installcolumnbreakmethod \s!mixedcolumn \v!preference
295  {\goodbreak}
296
297\installcolumnbreakmethod \s!mixedcolumn \v!yes
298  {\par
299   \penalty\c_page_mix_break_forced\relax}
300
301%D As we operate in grid snapping mode, we use a dedicated macro to enable this
302%D mechamism.
303
304\def\page_mix_enable_grid_snapping
305  {\edef\p_grid{\mixedcolumnsparameter\c!grid}%
306   \setfalse\c_page_mix_grid_snapping
307   \ifx\p_grid\empty
308     % just follow the default grid settings
309   \else
310     \ifgridsnapping\settrue\c_page_mix_grid_snapping\fi
311     \gridsnappingtrue
312     \setsystemmode\v!grid
313     \spac_grids_snap_value_set\p_grid
314   \fi}
315
316%D Between columns there is normally just spacing unless one enforces a rule.
317%D
318%D \starttyping
319%D \input zapf
320%D
321%D \startnarrower
322%D   \startmixedcolumns[n=2,background=color,backgroundcolor=red,rulethickness=1mm,rulecolor=green,separator=rule]
323%D     \input zapf
324%D   \stopmixedcolumns
325%D \stopnarrower
326%D
327%D \input zapf
328%D \stoptyping
329
330\installcorenamespace{mixedcolumnsseparator}
331
332\unexpanded\def\installmixedcolumnseparator#1#2%
333  {\setvalue{\??mixedcolumnsseparator#1}{#2}}
334
335\installmixedcolumnseparator\v!rule
336  {\vrule
337     \s!width \mixedcolumnsparameter\c!rulethickness
338     \s!height\mixedcolumnseparatorheight
339     \s!depth \mixedcolumnseparatordepth
340   \relax}
341
342\unexpanded\def\page_mix_command_inject_separator
343  {\begingroup
344   \setbox\scratchbox\hbox to \zeropoint \bgroup
345     \hss
346     \starttextproperties
347     \usemixedcolumnscolorparameter\c!rulecolor
348     \begincsname\??mixedcolumnsseparator\p_separator\endcsname % was \c!rule
349     \stoptextproperties
350     \hss
351   \egroup
352   \ht\scratchbox\zeropoint
353   \dp\scratchbox\zeropoint
354   \hss
355   \box\scratchbox
356   \hss
357   \endgroup}
358
359%D We've now arrived at the real code. The start command mostly sets up the
360%D environment and variables that are used in the splitter. One of the last
361%D things happening at the start is switching over to the mixed continuous
362%D routine.
363
364\installcorenamespace{mixedcolumnsbefore}
365\installcorenamespace{mixedcolumnsstart}
366\installcorenamespace{mixedcolumnsstop}
367\installcorenamespace{mixedcolumnsafter}
368
369%D For practical reasons there is always a first argument needed that
370%D indicates the class.
371%D
372%D \starttyping
373%D \startmixedcolumns[n=3,alternative=global]
374%D   \dorecurse{200}{Zomaar wat #1 met een footnote\footnote{note #1}. }
375%D \stopmixedcolumns
376%D \stoptyping
377
378\let\currentmixedcolumnsmethod\empty
379
380\installmacrostack\currentmixedcolumns
381\installmacrostack\currentmixedcolumnsmethod
382
383\unexpanded\def\startmixedcolumns
384  {\dodoubleempty\page_mix_start_columns}
385
386\def\page_mix_start_columns_checked#1#2%
387  {\edef\currentmixedcolumnsmethod{\mixedcolumnsparameter\c!method}%
388   \ifx\currentmixedcolumnsmethod\v!box
389     \singleexpandafter#1%
390   \else\ifinsidecolumns
391     \doubleexpandafter#2%
392   \else
393     \doubleexpandafter#1%
394   \fi\fi}
395
396\unexpanded\def\page_mix_start_columns
397  {\push_macro_currentmixedcolumns
398   \push_macro_currentmixedcolumnsmethod
399   \ifsecondargument
400     \singleexpandafter\page_mix_start_columns_a
401   \else\iffirstargument
402     \doubleexpandafter\page_mix_start_columns_b
403   \else
404     \doubleexpandafter\page_mix_start_columns_c
405   \fi\fi}
406
407\def\page_mix_start_columns_a[#1]% [#2]%
408  {\edef\currentmixedcolumns{#1}%
409   \page_mix_start_columns_checked
410     \page_mix_start_columns_a_yes
411     \page_mix_start_columns_a_nop}
412
413\def\page_mix_start_columns_a_yes[#1]%
414  {\mixedcolumnsparameter\c!before\relax
415   \begincsname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax
416   \begingroup
417   \setupcurrentmixedcolumns[#1]%
418   \page_mix_initialize_columns
419   \begincsname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname
420   \let\stopmixedcolumns\page_mix_columns_stop_yes}
421
422\def\page_mix_start_columns_a_nop[#1]%
423  {\begingroup
424   \let\stopmixedcolumns\page_mix_columns_stop_nop}
425
426\def\page_mix_start_columns_b[#1][#2]%
427  {\doifelseassignment{#1}%
428     {\let\currentmixedcolumns\empty
429      \page_mix_error_b}
430     {\edef\currentmixedcolumns{#1}%
431      \firstargumentfalse}%
432   \page_mix_start_columns_checked
433     \page_mix_start_columns_b_yes
434     \page_mix_start_columns_b_nop
435   [#1]}
436
437\def\page_mix_start_columns_b_yes[#1]%
438  {\mixedcolumnsparameter\c!before\relax % so, it doesn't listen to local settings !
439   \begincsname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax
440   \begingroup
441   \iffirstargument
442     \setupcurrentmixedcolumns[#1]%
443   \fi
444   \page_mix_initialize_columns
445   \begincsname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname % no \relax
446   \let\stopmixedcolumns\page_mix_columns_stop_yes}
447
448\def\page_mix_start_columns_b_nop[#1]%
449  {\begingroup
450   \let\stopmixedcolumns\page_mix_columns_stop_nop}
451
452\def\page_mix_error_b
453  {\writestatus\m!columns{best use an instance of mixed columns}}
454
455\def\page_mix_start_columns_c[#1][#2]%
456  {\let\currentmixedcolumns\empty
457   \page_mix_start_columns_checked
458     \page_mix_start_columns_c_yes
459     \page_mix_start_columns_c_nop}
460
461\def\page_mix_start_columns_c_yes
462  {\mixedcolumnsparameter\c!before\relax
463   \begincsname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax
464   \begingroup
465   \page_mix_initialize_columns
466   \begincsname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname
467   \let\stopmixedcolumns\page_mix_columns_stop_yes}
468
469\def\page_mix_start_columns_c_nop
470  {\begingroup
471   \let\stopmixedcolumns\page_mix_columns_stop_nop}
472
473\unexpanded\def\page_mix_fast_columns_start#1%
474  {\push_macro_currentmixedcolumns
475   \push_macro_currentmixedcolumnsmethod
476   \edef\currentmixedcolumns{#1}%
477   \edef\currentmixedcolumnsmethod{\mixedcolumnsparameter\c!method}%
478   \mixedcolumnsparameter\c!before\relax % so, it doesn't listen to local settings !
479   \begincsname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax
480   \begingroup
481   \page_mix_initialize_columns
482   \begincsname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname % no \relax
483   \let\page_mix_fast_columns_stop\page_mix_columns_stop_yes}
484
485%D When we stop, we switch over to the balancing routine. After we're done we
486%D make sure to set the sizes are set, a somewhat redundant action when we
487%D already have flushed but better be safe.
488
489\let\page_mix_fast_columns_stop\relax
490
491\newtoks\t_page_mix_at_the_end
492
493\def\page_mix_finalize_columns
494  {\ifconditional\c_page_mix_process_notes \else
495     \global\t_page_mix_at_the_end{\stoppostponingnotes}%
496   \fi}
497
498\unexpanded\def\page_mix_columns_stop_yes
499  {\begincsname\??mixedcolumnsstop\currentmixedcolumnsmethod\endcsname % no \relax
500   \page_mix_finalize_columns
501   \endgroup
502   \begincsname\??mixedcolumnsafter\currentmixedcolumnsmethod\endcsname\relax
503   \mixedcolumnsparameter\c!after\relax
504   \pop_macro_currentmixedcolumnsmethod
505   \pop_macro_currentmixedcolumns
506   \the\t_page_mix_at_the_end\global\t_page_mix_at_the_end\emptytoks}
507
508\unexpanded\def\page_mix_columns_stop_nop
509  {\page_mix_finalize_columns
510   \endgroup
511   \pop_macro_currentmixedcolumnsmethod
512   \pop_macro_currentmixedcolumns
513   \the\t_page_mix_at_the_end\global\t_page_mix_at_the_end\emptytoks}
514
515% \unexpanded\def\page_mix_columns_stop_yes
516%   {\begincsname\??mixedcolumnsstop \currentmixedcolumnsmethod\endcsname % no \relax
517%    \endgroup
518%    \begincsname\??mixedcolumnsafter\currentmixedcolumnsmethod\endcsname\relax
519%    \mixedcolumnsparameter\c!after\relax
520% \ifx\currentmixedcolumnsmethod\s!otr
521%    \pop_macro_currentmixedcolumnsmethod
522%    \pop_macro_currentmixedcolumns
523%    \synchronizeoutput % brrr, otherwise sometimes issues in itemize
524% \else
525%    \pop_macro_currentmixedcolumnsmethod
526%    \pop_macro_currentmixedcolumns
527% \fi
528%    }
529
530%D This is how the fast one is used:
531
532\unexpanded\def\strc_itemgroups_start_columns
533  {\page_mix_fast_columns_start\s!itemgroupcolumns}
534
535\unexpanded\def\strc_itemgroups_stop_columns
536  {\page_mix_fast_columns_stop} % set by start
537
538% not used nor documented so commented:
539%
540% \setupmixedcolumns
541%   [\s!itemgroupcolumns]
542%   [\c!grid=\itemgroupparameter\c!grid]
543%
544% \setupitemgroup
545%   [\c!grid=\v!yes] % we need a value
546
547% better
548
549%D The common initialization:
550
551\def\page_mix_initialize_columns
552  {\page_mix_enable_grid_snapping
553   %
554   \d_page_mix_distance    \mixedcolumnsparameter\c!distance
555   \c_page_mix_n_of_columns\mixedcolumnsparameter\c!n
556   \d_page_mix_max_height  \mixedcolumnsparameter\c!maxheight
557   \d_page_mix_max_width   \mixedcolumnsparameter\c!maxwidth
558   \d_page_mix_balance_step\mixedcolumnsparameter\c!step
559   %
560   \d_page_mix_max_width\dimexpr\d_page_mix_max_width-\leftskip-\rightskip\relax
561   \d_page_mix_leftskip \leftskip
562   \d_page_mix_rightskip\rightskip
563   \leftskip \zeropoint
564   \rightskip\zeropoint
565   %
566   \doifelse{\mixedcolumnsparameter\c!notes}\v!yes\settrue\setfalse\c_page_mix_process_notes
567   \ifconditional\c_page_mix_process_notes \else
568     \startpostponingnotes
569   \fi
570   %
571   \d_page_mix_threshold\zeropoint
572   %
573   \d_page_mix_column_width\dimexpr(\d_page_mix_max_width-\d_page_mix_distance*\numexpr(\c_page_mix_n_of_columns-\plusone)\relax)/\c_page_mix_n_of_columns\relax
574   %
575   \columnwidth   \d_page_mix_column_width
576   \columndistance\d_page_mix_distance
577   \nofcolumns    \c_page_mix_n_of_columns
578   \textwidth     \d_page_mix_column_width % kind of redundant but we had it so ...
579   %
580   \usemixedcolumnscolorparameter\c!color
581   %
582   \insidecolumnstrue % new
583   %
584   \usealignparameter  \mixedcolumnsparameter
585   \useblankparameter  \mixedcolumnsparameter
586   \useprofileparameter\mixedcolumnsparameter % new
587   %
588   \nofcolumns\c_page_mix_n_of_columns} % public
589
590%D The otr method related hooks are defined next:
591
592% \setvalue{\??mixedcolumnsbefore\s!otr}%
593%   {\par
594%    \ifdim\pagetotal=\zeropoint \else
595%      \verticalstrut     % probably no longer needed
596%      \vskip-\struttotal % probably no longer needed
597%    \fi}
598
599\newcount\c_page_mix_otr_nesting
600
601% \setvalue{\??mixedcolumnsbefore\s!otr}%
602%   {\par
603%    \global\advance\c_page_mix_otr_nesting\plusone
604%    \ifcase\c_page_mix_otr_nesting\or
605%      \ifdim\pagetotal=\zeropoint \else
606%        \obeydepth % we could handle this in pre material
607%      \fi
608%    \fi}
609
610\setvalue{\??mixedcolumnsbefore\s!otr}%
611  {\par
612   \global\advance\c_page_mix_otr_nesting\plusone
613   \ifcase\c_page_mix_otr_nesting\or
614     \ifdim\pagetotal=\zeropoint \else
615       % make sure that whitespace an dblanks are done
616       \strut
617       \vskip-\lineheight
618      % no, bad spacing: \obeydepth % we could handle this in pre material
619     \fi
620   \fi}
621
622\setvalue{\??mixedcolumnsstart\s!otr}%
623  {\ifcase\c_page_mix_otr_nesting\or
624     \scratchwidth\textwidth
625     \setupoutputroutine[\s!mixedcolumn]%
626     \c_page_mix_routine\c_page_mix_routine_intercept
627     \page_otr_trigger_output_routine
628     %
629     \holdinginserts\maxdimen
630     %
631     \ifvoid\b_page_mix_preceding \else
632       % moved here, before the packaging
633       \page_postprocessors_linenumbers_deepbox\b_page_mix_preceding
634       % we need to avoid unvboxing with successive balanced on one page
635       \global\setbox\b_page_mix_preceding\vpack{\box\b_page_mix_preceding}%
636       \wd\b_page_mix_preceding\scratchwidth % \makeupwidth
637       \page_grids_add_to_one\b_page_mix_preceding
638     \fi
639     \global\d_page_mix_preceding_height\ht\b_page_mix_preceding
640     \c_page_mix_routine\c_page_mix_routine_continue
641     %
642     \page_mix_command_set_vsize
643     \page_mix_command_set_hsize
644   \fi
645   \usealignparameter\mixedcolumnsparameter
646   \usesetupsparameter\mixedcolumnsparameter}
647
648% \setvalue{\??mixedcolumnsstop\s!otr}%
649%   {\par
650%    \ifcase\c_page_mix_otr_nesting\or
651%      \c_page_mix_routine\c_page_mix_routine_balance
652%      \page_otr_trigger_output_routine
653%    \fi}
654
655\setvalue{\??mixedcolumnsstop\s!otr}%
656  {\par
657   \ifcase\c_page_mix_otr_nesting\or
658     \doifelse{\mixedcolumnsparameter\c!balance}\v!yes
659       {\c_page_mix_routine\c_page_mix_routine_balance}%
660       {\penalty-\plustenthousand}% weird hack, we need to trigger the otr sometimes (new per 20140306, see balancing-001.tex)
661     \page_otr_trigger_output_routine
662     \ifvoid\b_page_mix_preceding \else
663        % empty columns so we need to make sure pending content is flushed
664        \unvbox\b_page_mix_preceding % new per 2014.10.25
665     \fi
666   \fi}
667
668\setvalue{\??mixedcolumnsafter\s!otr}%
669  {\ifcase\c_page_mix_otr_nesting\or
670     \prevdepth\strutdp
671     \page_otr_command_set_vsize
672     \page_otr_command_set_hsize
673   \fi
674   \global\advance\c_page_mix_otr_nesting\minusone}
675
676%D The splitting and therefore balancing is done at the \LUA\ end. This gives
677%D more readable code and also makes it easier to deal with insertions like
678%D footnotes. Eventually we will have multiple strategies available.
679
680\unexpanded\def\page_mix_routine_construct#1%
681  {\d_page_mix_max_height\mixedcolumnsparameter\c!maxheight % can have changed due to header=high
682   \ifconditional\c_page_mix_process_notes
683     \totalnoteheight\zeropoint
684   \else
685     \settotalinsertionheight
686   \fi
687   \clf_mixsetsplit
688       box          \b_page_mix_collected
689       nofcolumns   \c_page_mix_n_of_columns
690       maxheight    \d_page_mix_max_height
691       noteheight   \totalnoteheight
692       step         \d_page_mix_balance_step
693       cycles       \c_page_mix_balance_cycles
694       preheight    \d_page_mix_preceding_height
695       prebox       \b_page_mix_preceding
696       strutht      \strutht
697       strutdp      \strutdp
698       threshold    \d_page_mix_threshold
699       splitmethod  {\mixedcolumnsparameter\c!splitmethod}%
700       balance      {#1}%
701       alternative  {\mixedcolumnsparameter\c!alternative}%
702       internalgrid {\mixedcolumnsparameter\c!internalgrid}%
703       grid         \ifgridsnapping tru\else fals\fi e %
704       notes        \ifconditional\c_page_mix_process_notes tru\else fals\fi e %
705   \relax
706   \deadcycles\zerocount}
707
708\newdimen\mixedcolumnseparatorheight
709\newdimen\mixedcolumnseparatordepth
710\newdimen\mixedcolumnseparatorwidth
711
712\def\page_mix_routine_package_step
713  {% needs packaging anyway
714   \setbox\scratchbox\page_mix_command_package_column
715   \page_lines_add_numbers_to_box\scratchbox\recurselevel\c_page_mix_n_of_columns\plusone % new
716   \page_marks_synchronize_column\plusone\c_page_mix_n_of_columns\recurselevel\scratchbox
717   % backgrounds
718   \anch_mark_column_box\scratchbox\recurselevel
719   % for the moment a quick and dirty patch .. we need to go into the box (hence the \plusone) .. a slowdowner
720   % moved to start: \page_lines_add_numbers_to_box\scratchbox\recurselevel\c_page_mix_n_of_columns\plusone
721   % the framed needs a reset of strut, align, setups etc
722   \mixedcolumnseparatorheight\ht\scratchbox
723   \mixedcolumnseparatordepth \dp\scratchbox
724   \inheritedmixedcolumnsframedbox\currentmixedcolumns\scratchbox}
725
726\def\page_mix_routine_package_separate
727  {\ifcsname\??mixedcolumnsseparator\p_separator\endcsname
728     \page_mix_command_inject_separator
729   \else
730     \hss
731   \fi}
732
733\unexpanded\def\page_mix_routine_package
734  {\clf_mixfinalize
735   \setbox\b_page_mix_collected\vbox \bgroup
736     \ifvoid\b_page_mix_preceding \else
737     % \page_postprocessors_linenumbers_deepbox\b_page_mix_preceding % already done
738       \vpack\bgroup
739         \box\b_page_mix_preceding
740       \egroup
741       \global\d_page_mix_preceding_height\zeropoint
742       \nointerlineskip
743       % no no:
744       % \prevdepth\strutdepth
745     \fi
746     \hskip\d_page_mix_leftskip
747     \page_mix_hbox to \d_page_mix_max_width \bgroup
748       \edef\p_separator{\mixedcolumnsparameter\c!separator}%
749       \mixedcolumnseparatorwidth\d_page_mix_distance % \mixedcolumnsparameter\c!rulethickness\relax
750       \edef\p_direction{\mixedcolumnsparameter\c!direction}%
751       \ifx\p_direction\v!reverse
752         \dostepwiserecurse\c_page_mix_n_of_columns\plusone\minusone
753            {\page_mix_routine_package_step
754             \ifnum\recurselevel>\plusone
755               \page_mix_routine_package_separate
756             \fi}%
757       \else
758         \dorecurse\c_page_mix_n_of_columns
759            {\page_mix_routine_package_step
760             \ifnum\recurselevel<\c_page_mix_n_of_columns
761               \page_mix_routine_package_separate
762             \fi}%
763       \fi
764     \egroup
765     \hskip\d_page_mix_rightskip
766   \egroup
767   \wd\b_page_mix_collected\dimexpr
768     \d_page_mix_max_width
769    +\d_page_mix_rightskip
770    +\d_page_mix_leftskip
771   \relax }
772
773\unexpanded\def\page_mix_command_package_column
774  {\page_mix_hbox to \d_page_mix_column_width \bgroup
775     % maybe intercept empty
776     \clf_mixgetsplit\recurselevel\relax
777     \hskip-\d_page_mix_column_width
778     \vbox \bgroup
779       \hsize\d_page_mix_column_width
780       \ifconditional\c_page_mix_process_notes
781         \placenoteinserts
782       \fi
783     \egroup
784     \hss
785   \egroup}
786
787% \unexpanded\def\page_mix_command_package_column
788%   {\page_mix_hbox to \d_page_mix_column_width \bgroup
789%      % maybe intercept empty
790%      \ruledhpack\bgroup
791%        \clf_mixgetsplit\recurselevel\relax
792%      \egroup
793%      \hskip-\d_page_mix_column_width
794%      \ruledhpack \bgroup
795%        \hsize\d_page_mix_column_width
796%        \ifconditional\c_page_mix_process_notes
797%          \placenoteinserts
798%        \fi
799%      \egroup
800%      \hss
801%    \egroup}
802
803\unexpanded\def\page_mix_routine_continue
804  {\bgroup
805   \forgetall
806   \dontcomplain
807   \setbox\b_page_mix_collected\vpack{\unvbox\normalpagebox}% brrr we need to make a tight box (combine this in lua)
808   \page_mix_routine_construct\v!no
809   \page_mix_routine_package
810   \page_mix_construct_and_shipout\box\b_page_mix_collected\zerocount % three arguments
811   \clf_mixflushrest
812   \clf_mixcleanup
813   \egroup}
814
815\unexpanded\def\page_mix_routine_balance
816  {\bgroup
817   \forgetall
818   \dontcomplain
819   \setbox\b_page_mix_collected\vpack{\unvbox\normalpagebox}% brrr we need to make a tight box (combine this in lua)
820   \doloop
821     {%writestatus\m!columns{construct continue (\the\htdp\b_page_mix_collected)}%
822      \page_mix_routine_construct\v!no
823      \ifcase\clf_mixstate\relax
824        % 0 = okay, we can balance
825        \setbox\b_page_mix_collected\vpack{\clf_mixflushlist}% we could avoid this
826        %writestatus\m!columns{construct balance}%
827        \page_mix_routine_construct\v!yes
828        \page_mix_routine_package
829        \c_page_mix_routine\c_page_mix_routine_regular
830      % \setupoutputroutine[\s!singlecolumn]%
831        \page_otr_command_set_vsize
832        \page_otr_command_set_hsize
833        \par
834        %writestatus\m!columns{flush balance}%
835        \page_grids_add_to_mix\b_page_mix_collected % no linenumbers here
836        \box\b_page_mix_collected
837        \vskip\zeropoint % triggers recalculation of page stuff (weird that this is needed but it *is* needed, see mixed-001.tex)
838        \par
839        \nointerlineskip
840        \prevdepth\strutdp
841        \clf_mixflushrest% rubish
842        \clf_mixcleanup  % rubish
843        \exitloop
844      \or
845        % 1 = we have stuff left, so flush and rebalance
846        %writestatus\m!columns{flush continue}%
847        \page_mix_routine_package
848        \page_mix_construct_and_shipout\box\b_page_mix_collected\zerocount % three arguments
849        \setbox\b_page_mix_collected\vpack{\clf_mixflushrest}% we could avoid this
850        \clf_mixcleanup
851        \ifdim\ht\b_page_mix_collected=\zeropoint
852            \exitloop
853        \fi
854      \fi}%
855   \egroup}
856
857%D We also implement a variant compatible with the so called simple columns
858%D mechanism:
859%D
860%D \starttyping
861%D \startboxedcolumns
862%D   \input zapf
863%D \stopboxedcolumns
864%D \stoptyping
865%D
866%D This is a rather mininimalistic variant.
867
868% Maybe we also need a variant with obeydepth before and prevdepth after so
869% that we get a nice spacing.
870
871\definemixedcolumns
872  [boxedcolumns]
873  [\c!balance=\v!yes,
874   \c!n=2,
875   \c!method=\s!box,
876   \c!strut=\v!yes,
877   \c!maxwidth=\availablehsize]
878
879%D Boxed columns can be used nested:
880%D
881%D \starttyping
882%D \setupmixedcolumns
883%D   [boxedcolumns]
884%D   [n=2,
885%D    background=color,
886%D    backgroundcolor=darkred,
887%D    color=white,
888%D    backgroundoffset=1mm]
889%D
890%D \definemixedcolumns
891%D   [nestedboxedcolumns]
892%D   [boxedcolumns]
893%D   [n=2,
894%D    background=color,
895%D    backgroundcolor=white,
896%D    color=darkred,
897%D    strut=yes,
898%D    backgroundoffset=0mm]
899%D
900%D \startboxedcolumns
901%D     \input zapf \par \input ward \par \obeydepth
902%D     \startnestedboxedcolumns
903%D         \input zapf
904%D     \stopnestedboxedcolumns
905%D     \par \input zapf \par \obeydepth
906%D     \startnestedboxedcolumns
907%D         \input zapf
908%D     \stopnestedboxedcolumns
909%D     \par \input zapf
910%D \stopboxedcolumns
911%D \stoptyping
912
913%D Next we define the hooks:
914
915\letvalue{\??mixedcolumnsbefore\s!box}\donothing
916\letvalue{\??mixedcolumnsafter \s!box}\donothing
917
918\setvalue{\??mixedcolumnsstart\s!box}%
919  {\edef\p_page_mix_strut{\mixedcolumnsparameter\c!strut}%
920   \setbox\b_page_mix_collected\vbox \bgroup
921     \let\currentoutputroutine\s!mixedcolumn % makes \column work
922     \forgetall
923     \usegridparameter\mixedcolumnsparameter
924   % \useprofileparameter\mixedcolumnsparameter
925     \page_mix_command_set_hsize
926     \ifx\p_page_mix_strut\v!yes
927       \begstrut
928       \ignorespaces
929     \fi}
930
931\setvalue{\??mixedcolumnsstop\s!box}%
932  {\ifx\p_page_mix_strut\v!yes
933     \removeunwantedspaces
934     \endstrut
935   \fi
936   \egroup
937   \edef\p_profile{\mixedcolumnsparameter\c!profile}%
938   \ifx\p_profile\empty \else
939      % this can never be ok because we cheat with depth and height
940      % and glue in between and when we're too large we run into issues
941      % so mayb best limit correction to one line
942      \profilegivenbox\p_profile\b_page_mix_collected
943      \setbox\b_page_mix_collected\vpack{\unvbox\b_page_mix_collected}%
944      % tracing
945      % \addprofiletobox\b_page_mix_collected
946   \fi
947   \page_mix_box_balance}
948
949%D The related balancer is only a few lines:
950
951\unexpanded\def\page_mix_box_balance
952  {\bgroup
953   \dontcomplain
954   \page_mix_routine_construct\v!yes
955   \page_mix_routine_package
956   \dontleavehmode\box\b_page_mix_collected
957   \clf_mixflushrest
958   \clf_mixcleanup
959   \egroup}
960
961%D As usual, floats complicates matters and this is where experimental code
962%D starts.
963
964\let\page_mix_command_package_contents\page_one_command_package_contents
965\let\page_mix_command_flush_float_box \page_one_command_flush_float_box
966
967\unexpanded\def\page_mix_command_check_if_float_fits
968  {\ifpostponecolumnfloats
969     \global\setfalse\c_page_floats_room
970   \else\ifconditional\c_page_floats_not_permitted
971     \global\setfalse\c_page_floats_room
972   \else
973%        \bgroup
974%        \getcolumnstatus{\count255}{\dimen0}{\dimen2}%
975%        \page_floats_get_info\s!text
976%        \setbox\scratchbox\vbox % tricky met objecten ?
977%          {\blank[\rootfloatparameter\c!spacebefore]
978%           \snaptogrid\vbox{\vskip\floatheight}}% copy?
979%        \advance\dimen0\dimexpr\ht\scratchbox+2\openlineheight+.5\lineheight\relax\relax % needed because goal a bit higher
980%        \ifdim\dimen0>\dimen2
981%          \global\setfalse\c_page_floats_room
982%    \else
983      \global\settrue\c_page_floats_room
984   \fi\fi
985   \ifdim\floatwidth>\hsize
986     \showmessage\m!columns{11}\empty
987     \global\setfalse\c_page_floats_room
988   \fi}
989
990\unexpanded\def\page_mix_command_flush_floats
991  {\page_one_command_flush_floats}
992
993\unexpanded\def\page_mix_command_flush_saved_floats
994  {\page_one_command_flush_saved_floats}
995
996% \unexpanded\def\page_mix_command_flush_top_insertions
997%   {\page_one_command_flush_top_insertions}
998
999\unexpanded\def\page_mix_place_float_top
1000  {\showmessage\m!columns4\empty\page_one_place_float_here}
1001
1002\unexpanded\def\page_mix_place_float_bottom
1003  {\showmessage\m!columns5\empty\page_one_place_float_here}
1004
1005\unexpanded\def\page_mix_place_float_here
1006  {\page_one_place_float_here}
1007
1008\unexpanded\def\page_mix_place_float_force
1009  {\page_one_place_float_force}
1010
1011\unexpanded\def\page_mix_command_side_float_output
1012  {\page_mix_construct_and_shipout\unvbox\normalpagebox\zerocount} % three arguments
1013
1014\unexpanded\def\page_mix_command_synchronize_side_floats
1015  {\page_sides_forget_floats}
1016
1017\unexpanded\def\page_mix_command_flush_side_floats
1018  {\page_sides_forget_floats}
1019
1020\unexpanded\def\page_mix_command_next_page
1021  {\page_otr_eject_page}
1022
1023\unexpanded\def\page_mix_command_next_page_and_inserts
1024  {\page_otr_eject_page_and_flush_inserts}
1025
1026%D Moved here and dedicated:
1027
1028\unexpanded\def\page_mix_command_test_column
1029  {\dodoubleempty\page_mix_command_test_column_indeed}
1030
1031\unexpanded\def\page_mix_command_test_column_indeed[#1][#2]% works on last column
1032  {\par
1033   \begingroup
1034   \scratchdimen\dimexpr#1\lineheight\ifsecondargument+#2\fi\relax
1035   \ifdim\scratchdimen>\zeropoint
1036     \c_attr_checkedbreak\number\scratchdimen % why \number
1037     \penalty\c_page_mix_break_forced\relax
1038   \fi
1039   \endgroup}
1040
1041%D We need to hook some handlers into the output routine and we define
1042%D a dedicated one:
1043
1044\let\page_mix_command_flush_all_floats\page_one_command_flush_all_floats
1045
1046\defineoutputroutine
1047  [\s!mixedcolumn]
1048  [\s!page_otr_command_routine                =\page_mix_command_routine,
1049   \s!page_otr_command_package_contents       =\page_mix_command_package_contents,
1050   \s!page_otr_command_set_vsize              =\page_mix_command_set_vsize,
1051   \s!page_otr_command_set_hsize              =\page_mix_command_set_hsize,
1052 % \s!page_otr_command_synchronize_hsize      =\page_mix_command_synchronize_hsize,
1053   \s!page_otr_command_next_page              =\page_mix_command_next_page,
1054   \s!page_otr_command_next_page_and_inserts  =\page_mix_command_next_page_and_inserts,
1055 % \s!page_otr_command_set_top_insertions     =\page_mix_command_set_top_insertions,
1056 % \s!page_otr_command_set_bottom_insertions  =\page_mix_command_set_bottom_insertions,
1057 % \s!page_otr_command_flush_top_insertions   =\page_mix_command_flush_top_insertions,
1058 % \s!page_otr_command_flush_bottom_insertions=\page_mix_command_flush_bottom_insertions,
1059   \s!page_otr_command_check_if_float_fits    =\page_mix_command_check_if_float_fits,
1060 % \s!page_otr_command_set_float_hsize        =\page_mix_command_set_float_hsize,
1061   \s!page_otr_command_flush_float_box        =\page_mix_command_flush_float_box,
1062   \s!page_otr_command_side_float_output      =\page_mix_command_side_float_output,
1063   \s!page_otr_command_synchronize_side_floats=\page_mix_command_synchronize_side_floats,
1064   \s!page_otr_command_flush_floats           =\page_mix_command_flush_floats,
1065   \s!page_otr_command_flush_side_floats      =\page_mix_command_flush_side_floats,
1066   \s!page_otr_command_flush_saved_floats     =\page_mix_command_flush_saved_floats,
1067   \s!page_otr_command_flush_all_floats       =\page_mix_command_flush_all_floats,
1068 % \s!page_otr_command_flush_margin_blocks    =\page_mix_command_flush_margin_blocks, % not used
1069   \s!page_otr_command_test_column            =\page_mix_command_test_column
1070  ]
1071
1072%D Only a few float placement options are supported:
1073
1074\installfloatmethod \s!mixedcolumn  \v!here   \page_mix_place_float_here
1075\installfloatmethod \s!mixedcolumn  \v!force  \page_mix_place_float_force
1076\installfloatmethod \s!mixedcolumn  \v!top    \page_mix_place_float_top
1077\installfloatmethod \s!mixedcolumn  \v!bottom \page_mix_place_float_bottom
1078
1079\installfloatmethod \s!mixedcolumn  \v!local  \somelocalfloat
1080
1081%D It ends here.
1082
1083\protect \endinput
1084