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