page-mix.mkxl /size: 36 Kb    last modification: 2023-12-21 09:44
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\dimexpr\c_page_mix_n_of_columns\textheight+\c_page_mix_n_of_columns\lineheight\relax
297   \pagegoal\dimexpr
298     \vsize
299%   -\d_page_floats_inserted_top    % needs checking
300%   -\d_page_floats_inserted_bottom % needs checking
301    -\c_page_mix_n_of_columns\insertheights
302   \relax}
303
304%D As we use \LUA\ there is the usual amount of tracing at that end. At the tex end
305%D we only visualize boxes.
306
307\let\page_mix_hbox\hbox
308\let\page_mix_vbox\vbox
309
310\installtextracker
311  {mixedcolumns.boxes}
312  {\let\page_mix_hbox\ruledhbox
313   \let\page_mix_vbox\ruledvbox}
314  {\let\page_mix_hbox\hbox
315   \let\page_mix_vbox\vbox}
316
317%D We provide a few column break options. Interesting is that while forcing a new
318%D column in the traditional mechanism was a pain, here it works quite well.
319
320\installcolumnbreakmethod \s!mixedcolumn \v!preference
321  {\goodbreak}
322
323\installcolumnbreakmethod \s!mixedcolumn \v!yes
324  {\par
325   \penalty\c_page_mix_break_forced\relax}
326
327%D As we operate in grid snapping mode, we use a dedicated macro to enable this
328%D mechamism.
329
330\def\page_mix_enable_grid_snapping
331  {\edef\p_grid{\mixedcolumnsparameter\c!grid}%
332   \c_page_mix_grid_snapping\conditionalfalse
333   \ifempty\p_grid
334     % just follow the default grid settings
335   \else
336     \ifgridsnapping\c_page_mix_grid_snapping\conditionaltrue\fi
337     \gridsnappingtrue
338     \setsystemmode\v!grid
339     \spac_grids_snap_value_set\p_grid
340   \fi}
341
342%D Between columns there is normally just spacing unless one enforces a rule.
343%D
344%D \starttyping
345%D \input zapf
346%D
347%D \startnarrower
348%D   \startmixedcolumns[n=2,background=color,backgroundcolor=red,rulethickness=1mm,rulecolor=green,separator=rule]
349%D     \input zapf
350%D   \stopmixedcolumns
351%D \stopnarrower
352%D
353%D \input zapf
354%D \stoptyping
355
356\installcorenamespace{mixedcolumnsseparator}
357
358\permanent\protected\def\installmixedcolumnseparator#1#2%
359  {\defcsname\??mixedcolumnsseparator#1\endcsname{#2}}
360
361\installmixedcolumnseparator\v!rule
362  {\vrule
363     \s!width \mixedcolumnsparameter\c!rulethickness
364     \s!height\mixedcolumnseparatorheight
365     \s!depth \mixedcolumnseparatordepth
366   \relax}
367
368\protected\def\page_mix_command_inject_separator
369  {\begingroup
370   \setbox\scratchbox\hbox to \zeropoint \bgroup
371     \hss
372     \starttextproperties
373     \usemixedcolumnscolorparameter\c!rulecolor
374     \begincsname\??mixedcolumnsseparator\p_separator\endcsname % was \c!rule
375     \stoptextproperties
376     \hss
377   \egroup
378   \ht\scratchbox\zeropoint
379   \dp\scratchbox\zeropoint
380   \hss
381   \box\scratchbox
382   \hss
383   \endgroup}
384
385%D We've now arrived at the real code. The start command mostly sets up the
386%D environment and variables that are used in the splitter. One of the last
387%D things happening at the start is switching over to the mixed continuous
388%D routine.
389
390\installcorenamespace{mixedcolumnsbefore}
391\installcorenamespace{mixedcolumnsstart}
392\installcorenamespace{mixedcolumnsstop}
393\installcorenamespace{mixedcolumnsafter}
394
395%D For practical reasons there is always a first argument needed that
396%D indicates the class.
397%D
398%D \starttyping
399%D \startmixedcolumns[n=3,alternative=global]
400%D   \dorecurse{200}{Zomaar wat #1 met een footnote\footnote{note #1}. }
401%D \stopmixedcolumns
402%D \stoptyping
403
404\mutable\lettonothing\currentmixedcolumnsmethod
405
406\installmacrostack\currentmixedcolumns
407\installmacrostack\currentmixedcolumnsmethod
408
409\permanent\tolerant\protected\def\startmixedcolumns[#S#1]#*[#S#2]%
410  {\push_macro_currentmixedcolumns
411   \push_macro_currentmixedcolumnsmethod
412   \ifparameters
413     \expandafter\page_mix_start_columns_c
414   \or
415     \expandafter\page_mix_start_columns_b
416   \or
417     \expandafter\page_mix_start_columns_a
418   \fi[#1][#2]}
419
420\def\page_mix_start_columns_checked#1#2%
421  {\edef\currentmixedcolumnsmethod{\mixedcolumnsparameter\c!method}%
422   \ifx\currentmixedcolumnsmethod\v!box
423     \expandafter#1%
424   \orelse\ifinsidecolumns
425     \expandafter#2%
426   \else
427     \expandafter#1%
428   \fi}
429
430\def\page_mix_start_columns_a[#1]% [#2]%
431  {\cdef\currentmixedcolumns{#1}%
432   \page_mix_start_columns_checked
433     \page_mix_start_columns_a_yes
434     \page_mix_start_columns_a_nop}
435
436\def\page_mix_start_columns_a_yes[#S#1]%
437  {\mixedcolumnsparameter\c!before\relax
438   \begincsname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax
439   \begingroup
440   \setupcurrentmixedcolumns[#1]%
441   \page_mix_initialize_columns
442   \begincsname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname
443   \enforced\let\stopmixedcolumns\page_mix_columns_stop_yes}
444
445\def\page_mix_start_columns_a_nop[#S#1]%
446  {\begingroup
447   \enforced\let\stopmixedcolumns\page_mix_columns_stop_nop}
448
449\def\page_mix_start_columns_b[#S#1][#S#2]%
450  {\ifhastok={#1}%
451     \lettonothing\currentmixedcolumns
452     \page_mix_error_b
453     \page_mix_start_columns_checked\page_mix_start_columns_b_yes\page_mix_start_columns_b_nop[#1]%
454   \else
455     \cdef\currentmixedcolumns{#1}%
456     \page_mix_start_columns_checked\page_mix_start_columns_b_yes\page_mix_start_columns_b_nop[#2]%
457   \fi}
458
459\def\page_mix_start_columns_b_yes[#S#1]%
460  {\mixedcolumnsparameter\c!before\relax % so, it doesn't listen to local settings !
461   \begincsname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax
462   \begingroup
463   \setupcurrentmixedcolumns[#1]%
464   \page_mix_initialize_columns
465   \begincsname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname % no \relax
466   \enforced\let\stopmixedcolumns\page_mix_columns_stop_yes}
467
468\def\page_mix_start_columns_b_nop[#1]%
469  {\begingroup
470   \enforced\let\stopmixedcolumns\page_mix_columns_stop_nop}
471
472\def\page_mix_error_b
473  {\writestatus\m!columns{best use an instance of mixed columns}}
474
475\def\page_mix_start_columns_c[#1][#2]%
476  {\lettonothing\currentmixedcolumns
477   \page_mix_start_columns_checked
478     \page_mix_start_columns_c_yes
479     \page_mix_start_columns_c_nop}
480
481\def\page_mix_start_columns_c_yes
482  {\mixedcolumnsparameter\c!before\relax
483   \begincsname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax
484   \begingroup
485   \page_mix_initialize_columns
486   \begincsname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname
487   \enforced\let\stopmixedcolumns\page_mix_columns_stop_yes}
488
489\def\page_mix_start_columns_c_nop
490  {\begingroup
491   \enforced\let\stopmixedcolumns\page_mix_columns_stop_nop}
492
493\protected\def\page_mix_fast_columns_start#1%
494  {\push_macro_currentmixedcolumns
495   \push_macro_currentmixedcolumnsmethod
496   \cdef\currentmixedcolumns{#1}%
497   \edef\currentmixedcolumnsmethod{\mixedcolumnsparameter\c!method}%
498   \mixedcolumnsparameter\c!before\relax % so, it doesn't listen to local settings !
499   \begincsname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax
500   \begingroup
501   \page_mix_initialize_columns
502   \begincsname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname % no \relax
503   \let\page_mix_fast_columns_stop\page_mix_columns_stop_yes}
504
505%D When we stop, we switch over to the balancing routine. After we're done we
506%D make sure to set the sizes are set, a somewhat redundant action when we
507%D already have flushed but better be safe.
508
509\let\page_mix_fast_columns_stop\relax
510
511\newtoks\t_page_mix_at_the_end
512
513\def\page_mix_finalize_columns
514  {\ifconditional\c_page_mix_process_notes \else
515     \global\t_page_mix_at_the_end{\stoppostponingnotes}%
516   \fi}
517
518\protected\def\page_mix_columns_stop_yes
519  {\begincsname\??mixedcolumnsstop\currentmixedcolumnsmethod\endcsname % no \relax
520   \page_mix_finalize_columns
521   \endgroup
522   \begincsname\??mixedcolumnsafter\currentmixedcolumnsmethod\endcsname\relax
523   \mixedcolumnsparameter\c!after\relax
524   \pop_macro_currentmixedcolumnsmethod
525   \pop_macro_currentmixedcolumns
526   \expand\t_page_mix_at_the_end\global\t_page_mix_at_the_end\emptytoks}
527
528\protected\def\page_mix_columns_stop_nop
529  {\page_mix_finalize_columns
530   \endgroup
531   \pop_macro_currentmixedcolumnsmethod
532   \pop_macro_currentmixedcolumns
533   \expand\t_page_mix_at_the_end\global\t_page_mix_at_the_end\emptytoks}
534
535% \protected\def\page_mix_columns_stop_yes
536%   {\begincsname\??mixedcolumnsstop \currentmixedcolumnsmethod\endcsname % no \relax
537%    \endgroup
538%    \begincsname\??mixedcolumnsafter\currentmixedcolumnsmethod\endcsname\relax
539%    \mixedcolumnsparameter\c!after\relax
540% \ifx\currentmixedcolumnsmethod\s!otr
541%    \pop_macro_currentmixedcolumnsmethod
542%    \pop_macro_currentmixedcolumns
543%    \synchronizeoutput % brrr, otherwise sometimes issues in itemize
544% \else
545%    \pop_macro_currentmixedcolumnsmethod
546%    \pop_macro_currentmixedcolumns
547% \fi
548%    }
549
550%D This is how the fast one is used:
551
552\protected\def\strc_itemgroups_start_columns
553  {\page_mix_fast_columns_start\s!itemgroupcolumns}
554
555\protected\def\strc_itemgroups_stop_columns
556  {\page_mix_fast_columns_stop} % set by start
557
558% not used nor documented so commented:
559%
560% \setupmixedcolumns
561%   [\s!itemgroupcolumns]
562%   [\c!grid=\itemgroupparameter\c!grid]
563%
564% \setupitemgroup
565%   [\c!grid=\v!yes] % we need a value
566
567% better
568
569%D The common initialization:
570
571%D !!! todo: notes \automigrationmode\zerocount as well as notes=yes
572
573\def\page_mix_initialize_columns
574  {\page_mix_enable_grid_snapping
575   %
576   \d_page_mix_distance    \mixedcolumnsparameter\c!distance
577   \c_page_mix_n_of_columns\mixedcolumnsparameter\c!n
578   \d_page_mix_max_height  \mixedcolumnsparameter\c!maxheight
579   \d_page_mix_max_width   \mixedcolumnsparameter\c!maxwidth
580   \d_page_mix_balance_step\mixedcolumnsparameter\c!step
581   %
582   \d_page_mix_max_width\dimexpr\d_page_mix_max_width-\leftskip-\rightskip\relax
583   \d_page_mix_leftskip \leftskip
584   \d_page_mix_rightskip\rightskip
585   % \frozen ?
586   \leftskip \zeroskip
587   \rightskip\zeroskip
588   %
589   \ifcstok{\mixedcolumnsparameter\c!notes}\v!yes
590     \c_page_mix_process_notes\conditionaltrue
591   \else
592     \c_page_mix_process_notes\conditionalfalse
593   \fi
594   \ifconditional\c_page_mix_process_notes \else
595     \startpostponingnotes
596   \fi
597   %
598   \d_page_mix_threshold\zeropoint
599   %
600   \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
601   %
602   \columnwidth   \d_page_mix_column_width
603   \columndistance\d_page_mix_distance
604   \nofcolumns    \c_page_mix_n_of_columns
605   \textwidth     \d_page_mix_column_width % kind of redundant but we had it so ...
606   %
607   \usemixedcolumnscolorparameter\c!color
608   %
609   \insidecolumnstrue % new
610   %
611   \usealignparameter  \mixedcolumnsparameter
612   \useblankparameter  \mixedcolumnsparameter
613   \useprofileparameter\mixedcolumnsparameter % new
614   %
615   \automigrationmode\zerocount % for now (see notes=yes)
616   %
617   \nofcolumns\c_page_mix_n_of_columns} % public
618
619%D The otr method related hooks are defined next:
620
621% \defcsname\??mixedcolumnsbefore\s!otr\endcsname
622%   {\par
623%    \ifzeropt\pagetotal\else
624%      \verticalstrut     % probably no longer needed
625%      \vskip-\struttotal % probably no longer needed
626%    \fi}
627
628\newinteger\c_page_mix_otr_nesting
629
630% \defcsname\??mixedcolumnsbefore\s!otr\endcsname
631%   {\par
632%    \global\advanceby\c_page_mix_otr_nesting\plusone
633%    \ifcase\c_page_mix_otr_nesting\or
634%      \ifzeropt\pagetotal\else
635%        \obeydepth % we could handle this in pre material
636%      \fi
637%    \fi}
638
639\defcsname\??mixedcolumnsbefore\s!otr\endcsname
640  {\par
641   \global\advanceby\c_page_mix_otr_nesting\plusone
642   \ifcase\c_page_mix_otr_nesting\or
643     \ifzeropt\pagetotal\else
644       % make sure that whitespace and blanks are done
645       \strut
646       \vskip-\lineheight
647      % no, bad spacing: \obeydepth % we could handle this in pre material
648     \fi
649   \fi}
650
651\defcsname\??mixedcolumnsstart\s!otr\endcsname
652  {\ifcase\c_page_mix_otr_nesting\or
653     \scratchwidth\textwidth
654     \setupoutputroutine[\s!mixedcolumn]%
655     \c_page_mix_routine\c_page_mix_routine_intercept
656     \page_otr_trigger_output_routine
657     %
658     \holdinginserts\maxdimen
659     %
660     \ifvoid\b_page_mix_preceding \else
661       % moved here, before the packaging
662       \page_postprocessors_linenumbers_deepbox\b_page_mix_preceding
663       % we need to avoid unvboxing with successive balanced on one page
664       \global\setbox\b_page_mix_preceding\vpack{\box\b_page_mix_preceding}%
665       \wd\b_page_mix_preceding\scratchwidth % \makeupwidth
666       \page_grids_add_to_one\b_page_mix_preceding
667     \fi
668     \global\d_page_mix_preceding_height\ht\b_page_mix_preceding
669     \c_page_mix_routine\c_page_mix_routine_continue
670     %
671     \page_mix_command_set_vsize
672     \page_mix_command_set_hsize
673   \fi
674   \usealignparameter\mixedcolumnsparameter
675   \usesetupsparameter\mixedcolumnsparameter}
676
677% \defcsname\??mixedcolumnsstop\s!otr\endcsname
678%   {\par
679%    \ifcase\c_page_mix_otr_nesting\or
680%      \c_page_mix_routine\c_page_mix_routine_balance
681%      \page_otr_trigger_output_routine
682%    \fi}
683
684\defcsname\??mixedcolumnsstop\s!otr\endcsname
685  {\par
686   \ifcase\c_page_mix_otr_nesting\or
687     \ifcstok{\mixedcolumnsparameter\c!balance}\v!yes
688       \c_page_mix_routine\c_page_mix_routine_balance
689     \else
690       \penalty-\plustenthousand % weird hack, we need to trigger the otr sometimes (new per 20140306, see balancing-001.tex)
691     \fi
692     \page_otr_trigger_output_routine
693     \ifvoid\b_page_mix_preceding \else
694        % empty columns so we need to make sure pending content is flushed
695        \unvbox\b_page_mix_preceding % new per 2014.10.25
696     \fi
697   \fi}
698
699\defcsname\??mixedcolumnsafter\s!otr\endcsname
700  {\ifcase\c_page_mix_otr_nesting\or
701     \prevdepth\strutdp
702     \page_otr_command_set_vsize
703     \page_otr_command_set_hsize
704   \fi
705   \global\advanceby\c_page_mix_otr_nesting\minusone}
706
707%D The splitting and therefore balancing is done at the \LUA\ end. This gives
708%D more readable code and also makes it easier to deal with insertions like
709%D footnotes. Eventually we will have multiple strategies available.
710
711\protected\def\page_mix_routine_construct#1%
712  {\d_page_mix_max_height\mixedcolumnsparameter\c!maxheight % can have changed due to header=high
713   \ifconditional\c_page_mix_process_notes
714     \totalnoteheight\zeropoint
715   \else
716     \settotalinsertionheight
717   \fi
718   \clf_mixsetsplit
719       box          \b_page_mix_collected
720       nofcolumns   \c_page_mix_n_of_columns
721       maxheight    \d_page_mix_max_height
722       noteheight   \totalnoteheight
723       step         \d_page_mix_balance_step
724       cycles       \c_page_mix_balance_cycles
725       preheight    \d_page_mix_preceding_height
726       prebox       \b_page_mix_preceding
727       strutht      \strutht
728       strutdp      \strutdp
729       threshold    \d_page_mix_threshold
730       splitmethod  {\mixedcolumnsparameter\c!splitmethod}%
731       balance      {#1}%
732       alternative  {\mixedcolumnsparameter\c!alternative}%
733       internalgrid {\mixedcolumnsparameter\c!internalgrid}%
734       grid         \ifgridsnapping tru\else fals\fi e %
735       notes        \ifconditional\c_page_mix_process_notes tru\else fals\fi e %
736   \relax
737   \deadcycles\zerocount}
738
739\newdimension\mixedcolumnseparatorheight
740\newdimension\mixedcolumnseparatordepth
741\newdimension\mixedcolumnseparatorwidth
742
743\def\page_mix_routine_package_step
744  {% needs packaging anyway
745   \setbox\scratchbox\page_mix_command_package_column
746   \page_lines_add_numbers_to_box\scratchbox\recurselevel\c_page_mix_n_of_columns\plusone % new
747   \page_marks_synchronize_column\plusone\c_page_mix_n_of_columns\recurselevel\scratchbox
748   % backgrounds
749   \anch_mark_column_box\scratchbox\recurselevel
750   % for the moment a quick and dirty patch .. we need to go into the box (hence the \plusone) .. a slowdowner
751   % moved to start: \page_lines_add_numbers_to_box\scratchbox\recurselevel\c_page_mix_n_of_columns\plusone
752   % the framed needs a reset of strut, align, setups etc
753   \mixedcolumnseparatorheight\ht\scratchbox
754   \mixedcolumnseparatordepth \dp\scratchbox
755   \inheritedmixedcolumnsframedbox\currentmixedcolumns\scratchbox}
756
757\def\page_mix_routine_package_separate
758  {\ifcsname\??mixedcolumnsseparator\p_separator\endcsname
759     \page_mix_command_inject_separator
760   \else
761     \hss
762   \fi}
763
764\protected\def\page_mix_routine_package
765  {\clf_mixfinalize
766   \setbox\b_page_mix_collected\vbox \bgroup
767     \ifvoid\b_page_mix_preceding \else
768     % \page_postprocessors_linenumbers_deepbox\b_page_mix_preceding % already done
769       \vpack\bgroup
770         \box\b_page_mix_preceding
771       \egroup
772       \global\d_page_mix_preceding_height\zeropoint
773       \nointerlineskip
774       % no no:
775       % \prevdepth\strutdepth
776     \fi
777     \hskip\d_page_mix_leftskip
778     \page_mix_hbox to \d_page_mix_max_width \bgroup
779       \edef\p_separator{\mixedcolumnsparameter\c!separator}%
780       \mixedcolumnseparatorwidth\d_page_mix_distance % \mixedcolumnsparameter\c!rulethickness\relax
781       \ifcstok{\mixedcolumnsparameter\c!direction}\v!reverse
782         \dostepwiserecurse\c_page_mix_n_of_columns\plusone\minusone
783            {\page_mix_routine_package_step
784             \ifnum\recurselevel>\plusone
785               \page_mix_routine_package_separate
786             \fi}%
787       \else
788         \dorecurse\c_page_mix_n_of_columns
789            {\page_mix_routine_package_step
790             \ifnum\recurselevel<\c_page_mix_n_of_columns
791               \page_mix_routine_package_separate
792             \fi}%
793       \fi
794     \egroup
795     \hskip\d_page_mix_rightskip
796   \egroup
797   \wd\b_page_mix_collected\dimexpr
798     \d_page_mix_max_width
799    +\d_page_mix_rightskip
800    +\d_page_mix_leftskip
801   \relax }
802
803\protected\def\page_mix_command_package_column
804  {\page_mix_hbox to \d_page_mix_column_width \bgroup
805     % maybe intercept empty
806     \clf_mixgetsplit\recurselevel\relax
807     \hskip-\d_page_mix_column_width
808     \vbox \bgroup
809       \hsize\d_page_mix_column_width
810       \ifconditional\c_page_mix_process_notes
811         \placenoteinserts
812       \fi
813     \egroup
814     \hss
815   \egroup}
816
817% \protected\def\page_mix_command_package_column
818%   {\page_mix_hbox to \d_page_mix_column_width \bgroup
819%      % maybe intercept empty
820%      \ruledhpack\bgroup
821%        \clf_mixgetsplit\recurselevel\relax
822%      \egroup
823%      \hskip-\d_page_mix_column_width
824%      \ruledhpack \bgroup
825%        \hsize\d_page_mix_column_width
826%        \ifconditional\c_page_mix_process_notes
827%          \placenoteinserts
828%        \fi
829%      \egroup
830%      \hss
831%    \egroup}
832
833\protected\def\page_mix_routine_continue
834  {\bgroup
835   \forgetall
836   \dontcomplain
837   \setbox\b_page_mix_collected\vpack{\unvbox\normalpagebox}% brrr we need to make a tight box (combine this in lua)
838   \page_mix_routine_construct\v!no
839   \page_mix_routine_package
840   \page_mix_construct_and_shipout\box\b_page_mix_collected\zerocount % three arguments
841   \clf_mixflushrest
842   \clf_mixcleanup
843   \egroup}
844
845\protected\def\page_mix_routine_balance
846  {\bgroup
847   \forgetall
848   \dontcomplain
849   \setbox\b_page_mix_collected\vpack{\unvbox\normalpagebox}% brrr we need to make a tight box (combine this in lua)
850   \doloop
851     {%writestatus\m!columns{construct continue (\the\htdp\b_page_mix_collected)}%
852      \page_mix_routine_construct\v!no
853      \ifcase\clf_mixstate\relax
854        % 0 = okay, we can balance
855        \setbox\b_page_mix_collected\vpack{\clf_mixflushlist}% we could avoid this
856        %writestatus\m!columns{construct balance}%
857        \page_mix_routine_construct\v!yes
858        \page_mix_routine_package
859      % \c_page_mix_routine\c_page_mix_routine_regular % no, because we also need to set vsize
860        \setupoutputroutine[\s!singlecolumn]%
861        \page_otr_command_set_vsize
862        \page_otr_command_set_hsize
863        \par
864        %writestatus\m!columns{flush balance}%
865        \page_grids_add_to_mix\b_page_mix_collected % no linenumbers here
866        \box\b_page_mix_collected
867        % can't we do this differently now?
868%         \vskip\zeroskip % triggers recalculation of page stuff (weird that this is needed but it *is* needed, see mixed-001.tex)
869%         \par
870        \nointerlineskip
871        \prevdepth\strutdp
872        \clf_mixflushrest% rubish
873        \clf_mixcleanup  % rubish
874        \exitloop
875      \or
876        % 1 = we have stuff left, so flush and rebalance
877        %writestatus\m!columns{flush continue}%
878        \page_mix_routine_package
879        \page_mix_construct_and_shipout\box\b_page_mix_collected\zerocount % three arguments
880        \setbox\b_page_mix_collected\vpack{\clf_mixflushrest}% we could avoid this
881        \clf_mixcleanup
882        \ifzeropt\ht\b_page_mix_collected
883            \exitloop
884        \fi
885      \fi}%
886   \egroup}
887
888%D We also implement a variant compatible with the so called simple columns
889%D mechanism:
890%D
891%D \starttyping
892%D \startboxedcolumns
893%D   \input zapf
894%D \stopboxedcolumns
895%D \stoptyping
896%D
897%D This is a rather mininimalistic variant.
898
899% Maybe we also need a variant with obeydepth before and prevdepth after so
900% that we get a nice spacing.
901
902\definemixedcolumns
903  [boxedcolumns]
904  [\c!balance=\v!yes,
905   \c!n=2,
906   \c!method=\s!box,
907   \c!strut=\v!yes,
908   \c!maxwidth=\availablehsize]
909
910%D Boxed columns can be used nested:
911%D
912%D \starttyping
913%D \setupmixedcolumns
914%D   [boxedcolumns]
915%D   [n=2,
916%D    background=color,
917%D    backgroundcolor=darkred,
918%D    color=white,
919%D    backgroundoffset=1mm]
920%D
921%D \definemixedcolumns
922%D   [nestedboxedcolumns]
923%D   [boxedcolumns]
924%D   [n=2,
925%D    background=color,
926%D    backgroundcolor=white,
927%D    color=darkred,
928%D    strut=yes,
929%D    backgroundoffset=0mm]
930%D
931%D \startboxedcolumns
932%D     \input zapf \par \input ward \par \obeydepth
933%D     \startnestedboxedcolumns
934%D         \input zapf
935%D     \stopnestedboxedcolumns
936%D     \par \input zapf \par \obeydepth
937%D     \startnestedboxedcolumns
938%D         \input zapf
939%D     \stopnestedboxedcolumns
940%D     \par \input zapf
941%D \stopboxedcolumns
942%D \stoptyping
943
944%D Next we define the hooks:
945
946\letcsname\??mixedcolumnsbefore\s!box\endcsname\donothing
947\letcsname\??mixedcolumnsafter \s!box\endcsname\donothing
948
949\defcsname\??mixedcolumnsstart\s!box\endcsname
950  {\edef\p_page_mix_strut{\mixedcolumnsparameter\c!strut}%
951   \setbox\b_page_mix_collected\vbox \bgroup
952     \let\currentoutputroutine\s!mixedcolumn % makes \column work
953     \forgetall
954     \usegridparameter\mixedcolumnsparameter
955   % \useprofileparameter\mixedcolumnsparameter
956     \page_mix_command_set_hsize
957     \ifx\p_page_mix_strut\v!yes
958       \begstrut
959       \ignorespaces
960     \fi}
961
962\defcsname\??mixedcolumnsstop\s!box\endcsname
963  {\ifx\p_page_mix_strut\v!yes
964     \removeunwantedspaces
965     \endstrut
966   \fi
967   \egroup
968   \edef\p_profile{\mixedcolumnsparameter\c!profile}%
969   \ifempty\p_profile \else
970      % this can never be ok because we cheat with depth and height
971      % and glue in between and when we're too large we run into issues
972      % so mayb best limit correction to one line
973      \profilegivenbox\p_profile\b_page_mix_collected
974      \setbox\b_page_mix_collected\vpack{\unvbox\b_page_mix_collected}%
975      % tracing
976      % \addprofiletobox\b_page_mix_collected
977   \fi
978   \page_mix_box_balance}
979
980%D The related balancer is only a few lines:
981
982\protected\def\page_mix_box_balance
983  {\bgroup
984   \dontcomplain
985   \page_mix_routine_construct\v!yes
986   \page_mix_routine_package
987   \dontleavehmode\box\b_page_mix_collected
988   \clf_mixflushrest
989   \clf_mixcleanup
990   \egroup}
991
992%D As usual, floats complicates matters and this is where experimental code
993%D starts.
994
995\let\page_mix_command_package_contents\page_one_command_package_contents
996\let\page_mix_command_flush_float_box \page_one_command_flush_float_box
997
998\protected\def\page_mix_command_check_if_float_fits
999  {\ifpostponecolumnfloats
1000     \global\c_page_floats_room\conditionalfalse
1001   \orelse\ifconditional\c_page_floats_not_permitted
1002     \global\c_page_floats_room\conditionalfalse
1003   \else
1004%        \bgroup
1005%        \getcolumnstatus{\count255}{\dimen0}{\dimen2}%
1006%        \page_floats_get_info\s!text
1007%        \setbox\scratchbox\vbox % tricky met objecten ?
1008%          {\blank[\rootfloatparameter\c!spacebefore]
1009%           \snaptogrid\vbox{\vskip\floatheight}}% copy?
1010%        \advanceby\dimen0\dimexpr\ht\scratchbox+2\openlineheight+.5\lineheight\relax\relax % needed because goal a bit higher
1011%        \ifdim\dimen0>\dimen2
1012%          \global\c_page_floats_room\conditionalfalse
1013%    \else
1014      \global\c_page_floats_room\conditionaltrue
1015   \fi
1016   \ifdim\floatwidth>\hsize
1017     \showmessage\m!columns{11}\empty
1018     \global\c_page_floats_room\conditionalfalse
1019   \fi}
1020
1021\protected\def\page_mix_command_flush_floats
1022  {\page_one_command_flush_floats}
1023
1024\protected\def\page_mix_command_flush_saved_floats
1025  {\page_one_command_flush_saved_floats}
1026
1027% \protected\def\page_mix_command_flush_top_insertions
1028%   {\page_one_command_flush_top_insertions}
1029
1030\protected\def\page_mix_place_float_top
1031  {\showmessage\m!columns4\empty\page_one_place_float_here}
1032
1033\protected\def\page_mix_place_float_bottom
1034  {\showmessage\m!columns5\empty\page_one_place_float_here}
1035
1036\protected\def\page_mix_place_float_here
1037  {\page_one_place_float_here}
1038
1039\protected\def\page_mix_place_float_force
1040  {\page_one_place_float_force}
1041
1042\protected\def\page_mix_command_side_float_output
1043  {\page_mix_construct_and_shipout\unvbox\normalpagebox\zerocount} % three arguments
1044
1045\protected\def\page_mix_command_synchronize_side_floats
1046  {\page_sides_forget_floats}
1047
1048\protected\def\page_mix_command_flush_side_floats
1049  {\page_sides_forget_floats}
1050
1051\protected\def\page_mix_command_next_page
1052  {\page_otr_eject_page}
1053
1054\protected\def\page_mix_command_next_page_and_inserts
1055  {\page_otr_eject_page_and_flush_inserts}
1056
1057%D Moved here and dedicated:
1058
1059\tolerant\protected\def\page_mix_command_test_column[#1]#*[#2]% works on last column
1060  {\par
1061   \begingroup
1062   \scratchdimen\dimexpr#1\lineheight\ifparameter#2\or+#2\fi\relax
1063   \ifdim\scratchdimen>\zeropoint
1064     \c_attr_checkedbreak\number\scratchdimen % why \number
1065     \penalty\c_page_mix_break_forced\relax
1066   \fi
1067   \endgroup}
1068
1069%D We need to hook some handlers into the output routine and we define
1070%D a dedicated one:
1071
1072\let\page_mix_command_flush_all_floats\page_one_command_flush_all_floats
1073
1074\defineoutputroutine
1075  [\s!mixedcolumn]
1076  [\s!page_otr_command_routine                =\page_mix_command_routine,
1077   \s!page_otr_command_package_contents       =\page_mix_command_package_contents,
1078   \s!page_otr_command_set_vsize              =\page_mix_command_set_vsize,
1079   \s!page_otr_command_set_hsize              =\page_mix_command_set_hsize,
1080 % \s!page_otr_command_synchronize_hsize      =\page_mix_command_synchronize_hsize,
1081   \s!page_otr_command_next_page              =\page_mix_command_next_page,
1082   \s!page_otr_command_next_page_and_inserts  =\page_mix_command_next_page_and_inserts,
1083 % \s!page_otr_command_set_top_insertions     =\page_mix_command_set_top_insertions,
1084 % \s!page_otr_command_set_bottom_insertions  =\page_mix_command_set_bottom_insertions,
1085 % \s!page_otr_command_flush_top_insertions   =\page_mix_command_flush_top_insertions,
1086 % \s!page_otr_command_flush_bottom_insertions=\page_mix_command_flush_bottom_insertions,
1087   \s!page_otr_command_check_if_float_fits    =\page_mix_command_check_if_float_fits,
1088 % \s!page_otr_command_set_float_hsize        =\page_mix_command_set_float_hsize,
1089   \s!page_otr_command_flush_float_box        =\page_mix_command_flush_float_box,
1090   \s!page_otr_command_side_float_output      =\page_mix_command_side_float_output,
1091   \s!page_otr_command_synchronize_side_floats=\page_mix_command_synchronize_side_floats,
1092   \s!page_otr_command_flush_floats           =\page_mix_command_flush_floats,
1093   \s!page_otr_command_flush_side_floats      =\page_mix_command_flush_side_floats,
1094   \s!page_otr_command_flush_saved_floats     =\page_mix_command_flush_saved_floats,
1095   \s!page_otr_command_flush_all_floats       =\page_mix_command_flush_all_floats,
1096 % \s!page_otr_command_flush_margin_blocks    =\page_mix_command_flush_margin_blocks, % not used
1097   \s!page_otr_command_test_column            =\page_mix_command_test_column
1098  ]
1099
1100%D Only a few float placement options are supported:
1101
1102\installfloatmethod \s!mixedcolumn  \v!here   \page_mix_place_float_here
1103\installfloatmethod \s!mixedcolumn  \v!force  \page_mix_place_float_force
1104\installfloatmethod \s!mixedcolumn  \v!top    \page_mix_place_float_top
1105\installfloatmethod \s!mixedcolumn  \v!bottom \page_mix_place_float_bottom
1106
1107\installfloatmethod \s!mixedcolumn  \v!local  \somelocalfloat
1108
1109%D It ends here.
1110
1111\protect \endinput
1112