page-mvl.mkxl /size: 66 Kb    last modification: 2025-02-21 11:03
1%D \module
2%D   [       file=page-mvl,
3%D        version=2024.10.15, % variant on page-cst etc
4%D          title=\CONTEXT\ Page Macros,
5%D       subtitle=Columnsets,
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% todo : markings per column
15% todo : linenumbers per slot
16% todo : \ignoremvl
17% todo : intercept in mvl
18% todo : inserts like top
19% todo : flush pages when flush
20% todo : color now mess up grid color
21% todo : wipe all mvls
22
23%D This is the new columnset module. For sure it will evolve a bit over time.
24%D We don't really need an output routine but it just fits in.
25
26\writestatus{loading}{ConTeXt Page Macros / Columnsets}
27
28\unprotect
29
30\ifdefined\v!columnset             \else \cdef\v!columnset            {columnset}             \fi
31\ifdefined\v!columnsetsheet        \else \cdef\v!columnsetsheet       {columnsetsheet}        \fi
32\ifdefined\v!columnsetsheetdelayed \else \cdef\v!columnsetsheetdelayed{columnsetsheetdelayed} \fi
33\ifdefined\v!columnsetspreadsheets \else \cdef\v!columnsetspreadsheets{columnsetspreadsheets} \fi
34\ifdefined\v!slot                  \else \cdef\v!slot                 {slot}                  \fi
35\ifdefined\s!index                 \else \cdef\s!index                {index}                 \fi
36
37\newdimension\d_page_mvl_column_width
38\newdimension\d_page_mvl_max_height
39\newdimension\d_page_mvl_max_width
40\newdimension\d_page_mvl_distance
41
42\newdimension\d_page_mvl_reserved_height
43\newdimension\d_page_mvl_reserved_width
44\newinteger  \c_page_mvl_reserved_state
45
46\newdimension\d_page_mvl_last_ht
47\newdimension\d_page_mvl_last_dp
48
49\newinteger\c_page_mvl_n_of_left
50\newinteger\c_page_mvl_n_of_right
51\newinteger\c_page_mvl_n_of_rows
52\newinteger\c_page_mvl_first_column
53\newinteger\c_page_mvl_last_column
54\newinteger\c_page_mvl_current_sheet
55\newinteger\c_page_mvl_current_spreadsheet
56\newinteger\c_page_mvl_level
57\newinteger\c_page_mvl_main_level
58
59\newconditional\c_page_mvl_active
60
61\newbox\b_page_mvl_collected
62\newbox\b_page_mvl_column
63
64\permanent\protected\untraced\def\currentsheet{\the\c_page_mvl_current_sheet}
65
66\registerctxluafile{page-mvl}{autosuffix}
67
68% maybe some protected def ([esc])
69
70%D Columnsets are kind of special. They are mostly meant for special products with
71%D magazine like properties. They are normally not mixed with single column layouts
72%D and not all features of \CONTEXT\ might cooperate well with a mechanism like
73%D this. We use the name page grid because (as with other reimplementations of
74%D \MKII\ features in \MKIV, we need another namespace in order to migrate stepwise.
75%D
76%D This implementation is not neccessarily better than the previous one but it might
77%D be easier to extend it. It should be a bit more efficient.
78%D
79%D When writing this code I occasionally needed a motivational musical time||out and
80%D watching the latest Snarky Puppy DVD brought me the musically and visually videos
81%D of Jacob Collier (Piano, voice, anything) on YouTube (and yes, music keeps amazing
82%D me). It's definitely more fun to watch that than to write code like this.
83
84%D Many years later: subcolumnsets, nested columnsets, split notes, etc. much was
85%D done with Frost* on the headphone(s); new double cd plus all stuff I hadn't yet
86%D on cd gotten from bandcamp, so a 2024 crossing into 2025 timestamp, waiting for
87%D the DVD.
88
89\installcorenamespace{columnset}
90
91\installframedcommandhandler \??columnset {columnset} \??columnset
92
93\setupcolumnset
94  [\c!distance=1.5\bodyfontsize,
95   \c!n=\plustwo,
96   \c!nleft=\columnsetparameter\c!n,
97   \c!nright=\columnsetparameter\c!n,
98  %\c!align=, % inherit
99  %\c!separator=\v!none,
100  %\c!setups=,
101   \c!lines=\layoutparameter\c!lines,
102   \c!frame=\v!off,
103   \c!strut=\v!no,
104   \c!offset=\v!overlay,
105  %\c!alternative=\v!local, % gone
106   \c!width=\v!auto,
107   \c!limit=\plusone,
108   \c!page=,
109   \c!state=\v!start,
110   \c!direction=\v!normal, % todo
111   \c!maxheight=\textheight,
112   \c!maxwidth=\makeupwidth]
113
114%         lineheight \strutht
115%         linedepth  \strutdp
116%       \ifchkdimension\p_width\or
117%         width      \p_width
118%       \fi
119%         distance   \d_page_mvl_distance
120%         maxwidth   \d_page_mvl_max_width
121
122\appendtoks % could become an option
123    \ifempty\currentcolumnset\else
124      \frozen\instance\protected\edefcsname\e!start\currentcolumnset\endcsname{\startcolumnset[\currentcolumnset]}%
125      \frozen\instance\protected\edefcsname\e!stop \currentcolumnset\endcsname{\stopcolumnset}%
126      \clf_definecolumnset {
127        name     {\currentcolumnset}%
128        nofrows  {\columnsetparameter\c!lines}%
129        nofleft  {\columnsetparameter\c!nleft}%
130        nofright {\columnsetparameter\c!nright}%
131      }%
132    \fi
133\to \everydefinecolumnset
134
135\appendtoks
136    \ifcstok{\columnsetparameter\c!state}\v!start
137       \expandafter\setmode
138    \else
139       \expandafter\resetmode
140    \fi{\v!columnset:\currentcolumnset}%
141\to \everysetupcolumnset
142
143\newtoks\t_every_columnset_yes
144\newtoks\t_every_columnset_nop
145
146%D All the parameters are mandate!
147
148\permanent\tolerant\protected\def\setupcolumnsetlines[#1]#*[#2]#*[#3]#*[#4]% id page col value
149  {\ifcstok{\namedcolumnsetparameter{#1}\c!state}\v!start
150     % todo : check validity of arguments
151     \clf_setcolumnsetlines{name {#1} sheet #2 column #3 value #4}%
152   \fi}
153
154\permanent\tolerant\protected\def\setupcolumnsetstart[#1]#*[#2]#*[#3]#*[#4]% id page col value
155  {\ifcstok{\namedcolumnsetparameter{#1}\c!state}\v!start
156     % todo : check validity of arguments
157     % todo : check validity of arguments
158     \clf_setcolumnsetstart{name {#1} sheet #2 column #3 value #4}%
159   \fi}
160
161\protected\def\page_mvl_check
162  {\dorecurse{(\columnsetparameter\c!nleft)+(\columnsetparameter\c!nright)}%
163     {\page_mvl_check_column{##1}}}
164
165\protected\def\page_mvl_check_column#1%
166  {\chaintocurrentcolumnset{\currentcolumnset:#1}%
167   \begingroup
168   % We group because we cannot inherit as unset signal auto. This is realy
169   % ugly coding.
170   \let\tempstring\currentcolumnset
171   \cdef\currentcolumnset{\currentcolumnset:#1}%
172   \clf_setcolumnsetproperties {%
173      name {\tempstring}%
174      column {#1}%
175      \ifchkdimexpr\directcolumnsetparameter\c!distance\or
176        distance \lastchkdimension
177      \fi
178      \ifchkdimexpr\directcolumnsetparameter\c!width\or
179        width \lastchkdimension
180      \fi
181   }%
182   \endgroup}
183
184\appendtoks
185   \dorecurse{(\columnsetparameter\c!nleft)+(\columnsetparameter\c!nright)}%
186     {\chaintocurrentcolumnset{\currentcolumnset:#1}}%
187\to \everydefinecolumnset
188
189% \nooutputboxerror\plusthree % bitset as we have two cases where it's checked
190
191\mutable\let\maincolumnset\empty
192
193\def\page_mvl_unknown
194  {\writestatus\m!columns{unknown columnset '\currentcolumnset'}%
195   \page_mvl_start_dummy}
196
197\permanent\tolerant\protected\def\startcolumnset[#S#1]#*[#S#2]%
198  {\bgroup
199   \let\maincolumnset\currentcolumnset
200   \cdef\currentcolumnset{#1}%
201   \advanceby\c_page_mvl_main_level\plusone
202   \ifcase\c_page_mvl_main_level
203     % can't happen
204   \or
205   \else
206     \enforced\let\startcolumnset\page_mvl_start_dummy
207   \fi
208   \ifempty\currentcolumnset
209     \expandafter\page_mvl_unknown
210   \orelse\ifhastok={#1}%
211     \expandafter\page_mvl_unknown
212   \orunless\ifcstok{\columnsetparameter\c!state}\v!start
213     \page_mvl_start_dummy
214   \else
215     \doifelsecommandhandler\??columnset\currentcolumnset
216       {\setupcurrentcolumnset[#2]%
217        \expandafter\page_mvl_start}
218       {\expandafter\page_mvl_unknown}%
219   \fi}
220 % \orelse\ifcommandhandler{\??columnset\currentcolumnset}%
221 %   \setupcurrentcolumnset[#2]%
222 %   \expandafter\page_mvl_start
223 % \else
224 %   \expandafter\page_mvl_unknown
225 % \fi}
226
227\def\page_mvl_start
228  {\c_page_mvl_active\conditionaltrue
229   \expand\t_every_columnset_nop\relax
230   %
231   \nooutputboxerror\plusthree % bitset as we have two cases where it's checked
232   %
233   \usepageparameter\columnsetparameter
234   \c_page_mvl_n_of_left {\columnsetparameter\c!nleft}%
235   \c_page_mvl_n_of_right{\columnsetparameter\c!nright}%
236   \c_page_mvl_n_of_rows {\columnsetparameter\c!lines}%
237   \d_page_mvl_max_width {\columnsetparameter\c!maxwidth}%
238   \d_page_mvl_max_height{\columnsetparameter\c!maxheight}%
239   \d_page_mvl_distance  {\columnsetparameter\c!distance}%
240   %
241   \usealignparameter\columnsetparameter
242   %
243   \ifcase\c_page_mvl_n_of_rows
244     \getrawnoflines{\dimexpr\d_page_mvl_max_height-\strutheight+\topskip\relax}%
245     \c_page_mvl_n_of_rows\noflines
246   \fi
247   %
248   \insidecolumnstrue % will be different flag in addition
249   %
250   \page_mvl_check
251   %
252   \clf_resetcolumnset {
253        name       {\currentcolumnset}
254        nofrows    \c_page_mvl_n_of_rows
255        nofleft    \c_page_mvl_n_of_left
256        nofright   \c_page_mvl_n_of_right
257       %topskip
258        lineheight \strutht
259        linedepth  \strutdp
260      \ifchkdimexpr\columnsetparameter\c!width\or
261        width      \lastchkdimension
262      \fi
263        distance   \d_page_mvl_distance
264        maxwidth   \d_page_mvl_max_width
265        limit      {\columnsetparameter\c!limit}%
266   }%
267   %
268   \clf_flushcolumnsetareas{\currentcolumnset}\relax
269   \setupoutputroutine[\s!columnset]%
270   \page_mvl_command_set_hsize
271   \page_mvl_command_set_vsize
272   %
273   \columnwidth   \d_page_mvl_column_width
274   \columndistance\d_page_mvl_distance
275   \nofcolumns    \c_page_mvl_n_of_left    % not always ok
276   \textwidth     \d_page_mvl_column_width % kind of redundant but we had it so ...
277   %
278 % \let\topskipcorrection\relax % maybe here too, see below
279   \letinterlinespaceparameter\c!top\v!height % we have to check this
280   %
281   \page_mvl_command_set_vsize
282   \nointerlineskip
283   \page_mvl_main_mvl_begin}
284
285\tolerant\def\page_mvl_start_dummy[#S#1]#*[#S#2]%
286  {\c_page_mvl_active\conditionalfalse
287   \expand\t_every_columnset_nop\relax
288   \let\page_mvl_stop\egroup}
289
290\def\page_mvl_stop
291  {\scratchcounter\mvlcurrentlyactive
292   \page_mvl_main_mvl_end
293   \page_mvl_command_set_vsize
294   \clf_presetcolumnsetspreadsheets\currentcolumnset
295   \clf_presetcolumnsetsheets\currentcolumnset
296   \clf_columnsetlimit\currentcolumnset
297   \page_mvl_command_set_vsize
298   \begingroup
299   \dontcomplain
300   %
301   \enforced\let\topskipcorrection\relax % otherwise we get a displaced \showgrid
302   %
303   \automigrationmode\zerocount
304   %
305   \ifnum\scratchcounter=\plusone
306     \scratchcounterone\plusone
307     \scratchcountertwo\plusone
308   \else % \ifcsname\??subcolumnset\currentcolumnset\endcsname
309     \scratchcounterone\plustwo
310     \scratchcountertwo\columnsetlastmvl{\currentcolumnset}\relax % lookahead
311   \fi
312   \ifconditional\c_page_mvl_trace_n
313     \writestatus\m!columnset{flushing mlv: \the\scratchcounterone ..\the\scratchcountertwo}%
314   \fi
315   \localcontrolledloop \scratchcounterone \scratchcountertwo \plusone {%
316     \clf_setcolumnsetmvl{\currentcolumnset}\currentloopiterator\relax
317     \clf_gotocolumnsetslot{\currentcolumnset}\relax
318     \setbox\scratchboxone\flushmvl\currentloopiterator\relax
319     \page_mvl_process_mvl
320   }%
321   %
322   \scratchcounter\columnsetlastfuture\currentcolumnset\relax % lookahead
323   \clf_columnsetresetdirect\maincolumnset\relax
324   \localcontrolledrepeat \scratchcounter {%
325     \clf_setcolumnsetpresent\currentcolumnset\currentloopiterator
326     \scratchcounterone\columnsethascontent\currentcolumnset\currentloopiterator\relax
327     \ifcase\scratchcounterone
328       % nothing
329     \or
330       % 1 = left
331       \page_mvl_command_flush_page
332     \or
333       % 2 = right
334       \page_mvl_command_flush_page
335     \or
336       % 3 = both
337       \page_mvl_command_flush_page
338       \page_mvl_command_flush_page
339     \fi
340   }%
341   \endgroup
342   \clf_cleancolumnset{\currentcolumnset}%
343   \egroup
344   \page_otr_command_set_vsize
345   \page_otr_command_set_hsize}
346
347\permanent\protected\def\stopcolumnset
348  {\page_mvl_stop}
349
350\def\page_mvl_common_dummy_preset % [#1]
351  {\c_page_floats_ignore_method\conditionaltrue
352   \letdummyparameter\c!c      \zerocount
353   \letdummyparameter\c!r      \zerocount
354   \letdummyparameter\c!method \v!here
355   \letdummyparameter\c!option \v!none
356   \letdummyparameter\c!height \lineheight % convenient
357   \letdummyparameter\c!width  \emwidth    % the last one
358   \letdummyparameter\c!ntop   \zerocount
359   \letdummyparameter\c!nbottom\zerocount
360   \getdummyparameters} % [#1]
361
362\permanent\protected\def\reservecolumnset
363  {\ifcstok{\columnsetparameter\c!state}\v!start
364     \expandafter\page_mvl_reserve_columnset
365   \else
366     \expandafter\gobbleoneoptional
367   \fi}
368
369\tolerant\def\page_mvl_reserve_columnset[#S#1]%
370  {\begingroup
371   \letdummyparameter\c!c\plusone
372   \letdummyparameter\c!r\plusone
373   \letdummyparameter\c!nc\plusone
374   \letdummyparameter\c!nr\plusone
375   \getdummyparameters[#1]%
376   \clf_blockcolumnset {%
377     name {\currentcolumnset}%
378     c    {\dummyparameter\c!c}%
379     r    {\dummyparameter\c!r}%
380     nc   {\dummyparameter\c!nc}%
381     nr   {\dummyparameter\c!nr}%
382   }%
383   \endgroup}
384
385\permanent\protected\def\setcolumnset
386  {\ifcstok{\columnsetparameter\c!state}\v!start
387     \expandafter\page_mvl_set_column_set_yes
388   \else
389     \expandafter\gobbleoneoptional
390   \fi}
391
392\tolerant\def\page_mvl_set_column_set_yes[#S#1]%
393  {\begingroup
394   \page_mvl_common_dummy_preset[#1]%
395  %\dowithnextboxcs\page_mvl_set_indeed\hbox}
396   \afterassigned{%
397     \aftergroup\page_mvl_set_indeed
398     \atendofgroup\removeunwantedspaces
399     \ignorespaces
400   }\setbox\nextbox\hbox}
401
402\permanent\protected\def\startsetcolumnset % todo: interface
403  {\ifcstok{\columnsetparameter\c!state}\v!start
404     \expandafter\page_mvl_start_set_column_set_yes
405   \else
406     \expandafter\page_mvl_start_set_column_set_nop
407   \fi}
408
409\tolerant\protected\def\page_mvl_start_set_column_set_yes[#S#1]%
410  {\begingroup
411   \page_mvl_common_dummy_preset[#1]%
412   \setbox\nextbox\hbox\bgroup\ignorespaces}
413
414\def\page_mvl_start_set_column_set_nop
415  {\ignorenestedupto\startsetcolumnset\stopsetcolumnset} % todo: interface
416
417\permanent\protected\def\stopsetcolumnset % todo: interface
418  {\removeunwantedspaces
419   \egroup
420   \page_mvl_set_indeed}
421
422\def\page_mvl_set_indeed
423  {\clf_checkcolumnset {
424     name    {\currentcolumnset}
425     c       \dummyparameter\c!c
426     r       \dummyparameter\c!r
427     box     \nextbox
428     method  {\dummyparameter\c!method}
429     option  {\dummyparameter\c!option}
430   \ifempty{\dummyparameter\c!ntop}\else
431     ntop    \lastnamedcs
432   \fi
433   \ifempty{\dummyparameter\c!nbottom}\else
434     nbottom \lastnamedcs
435   \fi
436   }%
437   \ifcase\c_page_mvl_reserved_state
438     \setbox\nextbox\vpack to \d_page_mvl_reserved_height \bgroup
439       \vss
440       \hpack to \d_page_mvl_reserved_width \bgroup
441         \box\nextbox
442         \hss
443       \egroup
444       \vss
445     \egroup
446     \wd\nextbox\d_page_mvl_reserved_width
447     \clf_putincolumnset {
448       name {\currentcolumnset}
449       box \nextbox
450     }%
451   \fi
452   \endgroup}
453
454\permanent\protected\def\emptycolumnset
455  {\ifcstok{\columnsetparameter\c!state}\v!start
456     \expandafter\page_mvl_empty_columnset
457   \else
458     \expandafter\gobbleoneoptional
459   \fi}
460
461\tolerant\protected\def\page_mvl_empty_columnset[#S#1]%
462  {\begingroup
463   \page_mvl_common_dummy_preset[#1]%
464   \setbox\nextbox\hpack\bgroup
465     \page_mvl_show_ruled
466       \s!width  {\dummyparameter\c!width}%
467       \s!height {\dummyparameter\c!height}%
468   \egroup
469   \page_mvl_set_indeed}
470
471\protected\def\page_mvl_command_set_vsize % todo: just intercept
472  {\vsize\textheight}
473
474\protected\def\page_mvl_command_set_hsize
475  {\ifempty\currentsubcolumnset
476     \clf_sethsizecolumnset{\currentcolumnset}%
477     \hsize\d_page_mvl_column_width
478     \textwidth\d_page_mvl_column_width
479   \else
480     % hack
481   \fi}
482
483\protected\def\page_mvl_command_synchronize_hsize
484  {\page_mvl_command_set_hsize}
485
486\protected\def\page_mvl_command_flush_page_column#1#2%
487  {\privatescratchcounter#1\relax % or just currentcolumn as in page-col.mkiv
488   \clf_flushcolumnsetcolumn{\currentcolumnset}\privatescratchcounter
489   \anch_mark_column_box\b_page_mvl_column\privatescratchcounter
490% \page_marks_synchronize_column\c_page_mvl_first_column\c_page_mvl_last_column\privatescratchcounter\b_page_mvl_column
491   \ifnum\privatescratchcounter>\c_page_mvl_n_of_left
492     \advanceby\privatescratchcounter-\c_page_mvl_n_of_left
493     \page_lines_add_numbers_to_box\b_page_mvl_column\privatescratchcounter\c_page_mvl_n_of_right\plustwo
494   \else
495     \page_lines_add_numbers_to_box\b_page_mvl_column\privatescratchcounter\c_page_mvl_n_of_left\plustwo
496   \fi
497   \begingroup
498   \cdef\currentcolumnset{\currentcolumnset:#1}%
499   \setbox\scratchbox\hpack\bgroup
500     \novrule
501       \s!width \wd\b_page_mvl_column
502       \s!height\ht\b_page_mvl_column
503       \s!depth \dp\b_page_mvl_column
504     \relax
505   \egroup
506   \global\setbox\globalscratchbox\hpack\bgroup
507      \box\globalscratchbox
508      \inheritedcolumnsetframedbox\currentcolumnset\scratchbox
509      \ifzeropt#2\else\kern#2\fi
510   \egroup
511   \relax
512   \box\b_page_mvl_column
513   \ifzeropt#2\else\kern#2\fi
514   \endgroup}
515
516\installtextracker{columnsets.state}
517  {\let\page_mvl_show_state\page_mvl_show_state_indeed
518   \let\page_mvl_show_ruled\vrule
519   \let\page_mvl_show_slot \ruledhpack}
520  {\let\page_mvl_show_state\relax
521   \let\page_mvl_show_ruled\novrule
522   \let\page_mvl_show_slot \hpack}
523
524\installtextracker{columnsets.noisy}
525  {\c_page_mvl_trace\conditionaltrue}
526  {\c_page_mvl_trace\conditionalfalse}
527
528\let\page_mvl_show_state\relax
529\let\page_mvl_show_ruled\novrule
530\let\page_mvl_show_slot \hpack
531
532\def\page_mvl_show_state_indeed
533  {\setbox\scratchbox\hpack \s!yoffset -1.5\globalbodyfontsize\bgroup
534     \infofont\clf_columnsetstatus{\currentcolumnset}%
535   \egroup
536   \smashboxed\scratchbox}
537
538\protected\def\page_mvl_command_next_page_and_inserts
539  {\page_mvl_command_flush_all_floats
540   \page_mvl_command_next_page}
541
542\let\page_mvl_command_flush_all_floats  \page_one_command_flush_all_floats
543\let\page_mvl_command_package_contents  \page_one_command_package_contents
544\let\page_mvl_command_flush_all_floats  \page_one_command_flush_all_floats
545\let\page_mvl_command_flush_saved_floats\relax
546
547% needs checking
548
549\protected\def\page_mvl_command_flush_floats
550  {\wait\global\c_page_floats_flushing\conditionaltrue
551   \ifconditional\c_page_floats_some_waiting
552     \par
553     \page_mvl_command_flush_floats_indeed
554   \fi
555   \global\savednoffloats\zerocount
556   \global\c_page_floats_some_waiting\conditionalfalse
557   \global\c_page_floats_flushing\conditionalfalse}
558
559\def\page_mvl_command_flush_floats_indeed % much in common with OTRSET
560  {\ifconditional\c_page_floats_some_waiting
561     \ifconditional\c_page_floats_compress_flushed
562       \page_floats_collect\s!text\hsize\d_page_floats_compress_distance
563       \ifcase\nofcollectedfloats
564         \page_floats_get
565     % \or
566     %   \page_floats_get
567       \else
568         \c_page_floats_center_box\conditionalfalse % not needed as we do call directly
569         \global\setbox\floatbox\hbox to \hsize
570           {\hfil
571            \dorecurse\nofcollectedfloats
572              {\ifcase\columndirection % nog document wide
573                 \page_floats_flush\s!text\plusone
574               \else
575                 \page_floats_flush\s!text{\tointeger{\nofcollectedfloats-\recurselevel+1}}%
576               \fi
577               \ifdim\wd\floatbox>\makeupwidth % \hsize
578                 \hbox to \makeupwidth{\hss\box\floatbox\hss}%
579               \else
580                 \box\floatbox
581               \fi
582               \ifnum\recurselevel<\nofcollectedfloats
583                 \hfil
584               \fi}%
585            \hfil}%
586         \fi
587     \else
588       \page_floats_get
589     \fi
590     \doplacefloatbox
591     \expandafter\page_mvl_command_flush_floats_indeed
592   \fi}
593
594% so far
595
596\protected\def\page_mvl_command_check_if_float_fits
597  {\clf_checkcolumnset {
598     name   {\currentcolumnset}
599     method {\floatmethod}
600   % c      \zerocount
601   % r      \zerocount
602     box    \floatbox
603   }%
604   \ifcase\c_page_mvl_reserved_state
605     \global\c_page_floats_room\conditionaltrue
606   \else
607     \global\c_page_floats_room\conditionalfalse
608   \fi}
609
610\protected\def\page_mvl_place_float_here_indeed
611  {\setbox\floatbox\vpack to \d_page_mvl_reserved_height \bgroup
612     \vss
613     \hpack to \d_page_mvl_reserved_width \bgroup
614     % \hss % no
615       \box\floatbox
616       \hss
617     \egroup
618     \vss
619   \egroup
620   \clf_putincolumnset {
621     name {\currentcolumnset}
622     box  \floatbox
623   }}
624
625\def\page_mvl_place_float_slot
626  {\ifempty\floatmethod
627     \let\floatmethod\v!here
628   \fi
629   \ifconditional\c_page_mvl_inside_specification
630     % synchronize
631    %\penalty\c_page_otr_eject_penalty % really ?
632     % push
633     \setbox\savedfloatbox\box\floatbox
634     \page_mvl_command_flush_saved_floats
635     \setbox\floatbox\box\savedfloatbox
636     % pop
637     \ifconditional\c_page_floats_some_waiting
638       \page_floats_save\s!text % check this
639       \nonoindentation
640     \else
641       \clf_checkcolumnset {
642         name   {\currentcolumnset}
643         method {\floatmethod}
644       \ifempty\floatcolumn \else
645         c      \floatcolumn
646       \fi
647       \ifempty\floatrow \else
648         r      \floatrow
649       \fi
650         box    \floatbox
651       }%
652       \ifcase\c_page_mvl_reserved_state
653         \page_mvl_place_float_here_indeed
654       \else
655         \page_floats_save\s!text
656         \nonoindentation
657       \fi
658     \fi
659   \else
660     \page_mvl_place_float_force
661   \fi}
662
663\def\page_mvl_place_float_fixed % todo: fallback on here
664  {\page_mvl_place_float_force}
665
666\def\page_mvl_place_float_here
667  {\ifconditional\c_page_mvl_inside_specification
668     \let\floatmethod\v!here
669     \page_mvl_place_float_slot
670   \else
671     \page_mvl_place_float_force
672   \fi}
673
674\def\page_mvl_place_float_page
675  {\ifdim\wd\floatbox>\columnwidth
676     \page_floats_save\s!text % check this
677   \else
678     \page_mvl_place_float_force
679   \fi}
680
681%D Kind of neat:
682
683\ifdefined\s!columnsettop    \else \cdef\s!columnsettop   {columnsettop}    \fi
684\ifdefined\s!columnsetbottom \else \cdef\s!columnsetbottom{columnsetbottom} \fi
685
686\defineinsertion[\s!columnsettop]
687\defineinsertion[\s!columnsetbottom]
688
689\newdimension\d_page_mvl_top_insertions_height
690\newdimension\d_page_mvl_bottom_insertions_height
691
692\definesystemattribute[balancescaled][public]
693
694\newbox\b_page_inserts_uinsert
695
696\def\c_page_mvl_traced_float_indeed
697  {\framed
698     [\c!offset=\v!overlay,
699      \c!framecolor=darkgray,
700      \c!rulethickness=5\linewidth]}
701
702\let\c_page_mvl_traced_float\relax
703
704\installtextracker{columnsets.floats}
705  {\let\c_page_mvl_traced_float\c_page_mvl_traced_float_indeed}
706  {\let\c_page_mvl_traced_float\relax}
707
708\permanent\protected\def\page_inserts_handle_uinsert#1%
709  {\setbox\b_page_inserts_uinsert\hpack\bgroup
710     \c_page_mvl_traced_float{\scale[\c!sx=1,\c!sy=#1]{\box\b_page_inserts_uinsert}}%
711   \egroup}
712
713\def\page_mvl_top_insertions
714  {\setcurrentinsertion\s!columnsettop
715   \setbox\scratchbox\hpack\bgroup\vbalancedinsert\b_page_mvl_current_content
716     \s!index \currentinsertionnumber
717     \s!descend
718   \relax\egroup
719   \global\d_page_mvl_top_insertions_height\htdp\scratchbox
720   \ifvoid\scratchbox\else
721     \box\scratchbox
722   \fi}
723
724\def\page_mvl_bottom_insertions
725  {\setcurrentinsertion\s!columnsetbottom
726   \setbox\scratchbox\hpack\bgroup\vbalancedinsert\b_page_mvl_current_content
727     \s!index \currentinsertionnumber
728     \s!descend
729   \relax\egroup
730   \global\d_page_mvl_bottom_insertions_height\htdp\scratchbox
731   \ifvoid\scratchbox\else
732     \box\scratchbox
733   \fi}
734
735\def\page_mvl_place_float_top
736  {\begingroup
737   \setcurrentinsertion\s!columnsettop
738   \insertstretch\currentinsertionnumber.5\lineheight
739 % \insertshrink \currentinsertionnumber.5\lineheight
740   \insert
741     \s!callback \plusone
742     \s!index    \currentinsertionnumber
743   \bgroup
744     \boxattribute\floatbox\balancescaledattribute\plusone
745     \box\floatbox
746     \vkern\lineheight % for the moment hard coded
747   \egroup
748   \endgroup}
749
750\def\page_mvl_place_float_bottom
751  {\begingroup
752   \setcurrentinsertion\s!columnsetbottom
753   \insertstretch\currentinsertionnumber.5\lineheight
754 % \insertshrink \currentinsertionnumber.5\lineheight
755   \insert
756     \s!callback \plustwo
757     \s!index    \currentinsertionnumber
758   \bgroup
759     \vkern\lineheight % for the moment hard coded
760     \boxattribute\floatbox\balancescaledattribute\plusone
761     \box\floatbox
762   \egroup
763   \endgroup}
764
765%permanent\untraced\protected\def\columnsetgridlines#1{\dimexpr#1lh-1sd\relax}
766\permanent\untraced\protected\def\columnsetgridlines#1{\dimexpr#1\lineheight-\strutdp\relax}
767
768%D Till here. The nbext one is used when inside a sheet or spread setting environment:
769
770\def\page_mvl_place_float_box{\box\floatbox} % none was taklen for aligned
771
772\installfloatmethod \s!columnset \s!box         \page_mvl_place_float_box
773\installfloatmethod \s!columnset \v!here        \page_mvl_place_float_here
774\installfloatmethod \s!columnset \v!force       \page_mvl_place_float_force % todo
775%installfloatmethod \s!columnset \v!left
776%installfloatmethod \s!columnset \v!right
777%installfloatmethod \s!columnset \v!text
778\installfloatmethod \s!columnset \v!top         \page_mvl_place_float_top
779\installfloatmethod \s!columnset \v!bottom      \page_mvl_place_float_bottom
780%installfloatmethod \s!columnset \v!auto
781%installfloatmethod \s!columnset \v!margin
782%installfloatmethod \s!columnset \v!opposite
783\installfloatmethod \s!columnset \v!page        \page_mvl_place_float_page
784%installfloatmethod \s!columnset \v!leftpage
785%installfloatmethod \s!columnset \v!rightpage
786%installfloatmethod \s!columnset \v!inmargin
787%installfloatmethod \s!columnset \v!inleft
788%installfloatmethod \s!columnset \v!inright
789%installfloatmethod \s!columnset \v!leftmargin
790%installfloatmethod \s!columnset \v!rightmargin
791%installfloatmethod \s!columnset \v!leftedge
792%installfloatmethod \s!columnset \v!rightedge
793%installfloatmethod \s!columnset \v!somewhere
794%installfloatmethod \s!columnset \v!backspace
795%installfloatmethod \s!columnset \v!cutspace
796\installfloatmethod \s!columnset \s!tblr        \page_mvl_place_float_slot
797\installfloatmethod \s!columnset \s!lrtb        \page_mvl_place_float_slot
798\installfloatmethod \s!columnset \s!tbrl        \page_mvl_place_float_slot
799\installfloatmethod \s!columnset \s!rltb        \page_mvl_place_float_slot
800\installfloatmethod \s!columnset \s!fxtb        \page_mvl_place_float_slot
801\installfloatmethod \s!columnset \s!btlr        \page_mvl_place_float_slot
802\installfloatmethod \s!columnset \s!lrbt        \page_mvl_place_float_slot
803\installfloatmethod \s!columnset \s!btrl        \page_mvl_place_float_slot
804\installfloatmethod \s!columnset \s!rlbt        \page_mvl_place_float_slot
805\installfloatmethod \s!columnset \s!fxbt        \page_mvl_place_float_slot
806\installfloatmethod \s!columnset \s!fixd        \page_mvl_place_float_fixed
807
808\protected\def\page_mvl_command_side_float_output      {} % nothing, reset anyway
809\protected\def\page_mvl_command_flush_side_floats      {\page_sides_forget_floats}
810\protected\def\page_mvl_command_synchronize_side_floats{\page_sides_forget_floats}
811
812% spans
813
814\installcorenamespace{columnsetspan}
815
816\installframedcommandhandler \??columnsetspan {columnsetspan} \??columnsetspan
817
818\setupcolumnsetspan
819  [\c!frame=\v!off,
820   \c!before=,
821   \c!after=,
822   \c!offset=\v!overlay,
823   \c!location=\v!left,
824   \c!linecorrection=\v!off,
825   \c!depthcorrection=\v!off,
826   \c!n=\plustwo,
827   \c!nlines=\zerocount,
828   \c!align=\v!normal,
829   \c!width=\d_page_mvl_span_width,
830   \c!indenting=,
831   \c!indentnext=\v!yes,
832   \c!method=\s!tblr,
833  %\c!alternative=\v!a, % gone
834   \c!default=\v!here]
835
836\newdimension\d_page_mvl_span_width
837
838\let\page_mvl_span_stop\relax
839
840\permanent\protected\def\startcolumnsetspan
841  {\ifcstok{\columnsetparameter\c!state}\v!start
842     \expandafter\page_mvl_start_columnset_span_yes
843   \else
844   \fi}
845
846\permanent\tolerant\protected\def\page_mvl_start_columnset_span_yes[#1]#*[#2]#*[#3]% [#3] gobbles space
847  {\endgraf % else rubish output if forgotten
848  %\synchronizecolumnset
849  %\balancesubcolumnsets\relax % [#1]%
850   \bgroup
851   \forgetall
852   \cdef\currentcolumnsetspan{#1}%
853   \clf_sethsizecolumnspan{\currentcolumnset}\columnsetspanparameter\c!n\relax
854   \setbox\scratchbox\hbox\bgroup\inheritedcolumnsetspanframed\bgroup
855     \def\page_mvl_span_stop{\page_mvl_span_stop_indeed{#2}}%
856     \usecolumnsetspanstyleandcolor\c!style\c!color
857     \columnsetspanparameter\c!before
858     \ignorespaces}
859
860\protected\def\page_mvl_span_stop_indeed#1%
861  {\removeunwantedspaces
862   \par
863   \verticalstrut
864   \kern-2\struttotal
865   \verticalstrut
866   \endgraf
867   \columnsetspanparameter\c!after
868   \egroup\egroup
869   \setcolumnset[#1]{\box\scratchbox}%
870   % todo: push into slot
871   \egroup
872   \endgraf}
873
874\permanent\tolerant\protected\def\page_mvl_start_columnset_span_nop
875  {\ignorenestedupto\startcolumnsetspan\stopcolumnsetspan} % todo: interface
876
877\permanent\protected\def\stopcolumnsetspan % indirectness permits aliasing
878  {\page_mvl_span_stop}
879
880\permanent\protected\def\columnsethspan#1#2%
881  {\ifconditional\c_page_mvl_active
882     \clf_columnsethspan\currentcolumnset{#1}{#2}%
883   \else
884     \textwidth
885   \fi}
886
887\permanent\def\columnsetspanwidth#1% assumes equal distances, expanded
888  {\todimension{%
889    \ifconditional\c_page_mvl_active
890       #1\d_page_mvl_column_width
891      +#1\d_page_mvl_distance
892      -  \d_page_mvl_distance
893     \else
894       \textwidth
895     \fi
896   }}
897
898% areas
899
900\installcorenamespace{columnsetarea}
901
902\installframedcommandhandler \??columnsetarea {columnsetarea} \??columnsetarea
903
904\setupcolumnsetarea
905  [\c!x=\plusone,
906   \c!y=\plusone,
907   \c!nx=\plusone,
908   \c!ny=\plusone,
909   \c!clipoffset=2\lineheight,
910   \c!leftoffset=\zeropoint,
911   \c!rightoffset=\zeropoint,
912   \c!offset=\v!overlay,
913   \c!strut=\v!no,
914   \c!frame=\v!off,
915  %\c!type=\v!next,
916   \c!align=\v!normal,
917   \c!page=,
918   \c!sheet=\plusone,
919   \c!state=\v!stop]
920
921% type: both fixed left right next (not now), then better
922% lefttext and righttext or so
923
924\appendtoks
925     \clf_registercolumnsetarea {%
926        name  {\currentcolumnsetarea}%
927        kind  {\columnsetareaparameter\c!type}%
928        sheet {\columnsetareaparameter\c!sheet}%
929        state {\columnsetareaparameter\c!state}%
930        c     {\columnsetareaparameter\c!x}%
931        r     {\columnsetareaparameter\c!y}%
932        nc    {\columnsetareaparameter\c!nx}%
933        nr    {\columnsetareaparameter\c!ny}%
934     }%
935\to \everydefinecolumnsetarea
936
937\permanent\tolerant\protected\def\setupcolumnsetareatext[#1]#*[#S#2]% a it like headers and footers, use setups
938  {\ifcstok{\columnsetparameter\c!state}\v!start
939     \cdef\currentcolumnsetarea{#1}%
940     \setcolumnsetareaparameter\c!text{#2}%
941   \fi}
942
943% maybe move the left/right correction to the tex end or the offset to lua
944
945% used at the lua end: name,area.name,column,row,width,height,start,left
946
947\permanent\protected\def\page_mvl_set_area#1#2#3#4#5#6#7#8% can be optimized
948  {\begingroup
949   \cdef\currentcolumnsetarea{#2}%
950   \setcolumnsetareaparameter\c!width {#5\scaledpoint}%
951   \setcolumnsetareaparameter\c!height{#6\scaledpoint}%
952   \setbox\nextbox\hpack\bgroup\inheritedcolumnsetareaframed\bgroup
953     \usecolumnsetareastyleandcolor\c!style\c!color
954     \ignorespaces
955     \columnsetareaparameter\c!text
956   \egroup\egroup
957   %
958   \scratchdimen#8\scaledpoint
959   \ifdim\scratchdimen>\zeropoint
960     \setbox\scratchbox\vbox\bgroup
961       \clip
962         [     \c!offset=\columnsetareaparameter\c!clipoffset,%
963          \c!rightoffset=\columnsetareaparameter\c!rightoffset,%
964                \c!width=\scratchdimen,%
965             % \c!height=
966         ]%
967         {\copy\nextbox}%
968     \egroup
969     \clf_setcolumnsetarea{name {#1} box \scratchbox c #3 r #4}%
970     \setbox\scratchbox\vbox\bgroup
971       \hskip-\layoutparameter\c!backspace % todo: #9
972       \clip
973         [    \c!offset=\columnsetareaparameter\c!clipoffset,%
974          \c!leftoffset=\columnsetareaparameter\c!rightoffset,%
975             \c!hoffset=\scratchdimen,%
976               \c!width=\wd\nextbox-\scratchdimen,%
977            % \c!height=
978         ]%
979         {\box\nextbox}%
980     \egroup
981     \clf_setcolumnsetarea{name {#1} box \scratchbox c #7 r #4}%
982   \else
983     \setbox\scratchbox\vbox\bgroup
984        \box\nextbox % wrapping needed
985     \egroup
986     \clf_setcolumnsetarea{name {#1} box \scratchbox c #3 r #4}%
987   \fi
988   \endgroup}
989
990% sheets
991
992\mutable\lettonothing\askedsheet
993
994\permanent\protected\defcsname\e!start\v!columnsetsheet\endcsname
995  {\begingroup
996   \obeylines
997  %\lettonothing\currentcolumnset
998   \cdef\askedsheet{1}%
999   \page_mvl_sheet_start}
1000
1001\permanent\protected\defcsname\e!stop\v!columnsetsheet\endcsname
1002  {\ifcstok{\columnsetparameter\c!state}\v!start
1003     \clf_registercolumnsetsheet{\currentcolumnset}{\askedsheet}{\askedsheetoption}\relax
1004   \else
1005     \rawbuffer{page:mvl:temp}% no real need for usung a buffer in this case
1006   \fi
1007   \endgroup}
1008
1009\permanent\protected\defcsname\e!start\v!columnsetsheetdelayed\endcsname
1010  {\begingroup
1011   \obeylines
1012  %\lettonothing\currentcolumnset
1013   \cdef\askedsheet{1}%
1014   \page_mvl_sheet_start_delayed}
1015
1016\permanent\protected\defcsname\e!stop\v!columnsetsheetdelayed\endcsname
1017  {\ifcstok{\columnsetparameter\c!state}\v!start
1018     \clf_registercolumnsetsheet{\currentcolumnset}{\askedsheet}{\v!page}\relax
1019   \else
1020     \rawbuffer{page:mvl:temp}% no real need for usung a buffer in this case
1021   \fi
1022   \endgroup}
1023
1024\tolerant\def\page_mvl_sheet_start_delayed[#1]#*[#2]%  columnset sheetnumber
1025  {\ifparameter#2\or
1026     \ifchknum#2\or
1027       \cdef\currentcolumnset{#1}%
1028       \cdef\askedsheet{#2}%
1029     \orelse\ifchknum#1\or
1030       \cdef\askedsheet{#1}%
1031     \fi
1032   \orelse\ifparameter#1\or
1033     \ifchknum#1\or
1034       \cdef\askedsheet{#1}%
1035     \fi
1036   \fi
1037   \grabbufferdatadirect{page:mvl:temp}{\e!start\v!columnsetsheetdelayed}{\e!stop\v!columnsetsheetdelayed}}
1038
1039\tolerant\def\page_mvl_sheet_start[#1]#*[#2]#*[#3]%  columnset sheetnumber [page]
1040  {\ifparameter#2\or
1041     \ifchknum#2\or
1042       \cdef\currentcolumnset{#1}%
1043       \cdef\askedsheet{#2}%
1044       \cdef\askedsheetoption{#3}%
1045     \orelse\ifchknum#1\or
1046       \cdef\askedsheet{#1}%
1047       \cdef\askedsheetoption{#2}%
1048     \fi
1049   \orelse\ifparameter#1\or
1050     \ifchknum#1\or
1051       \cdef\askedsheet{#1}%
1052       \cdef\askedsheetoption{#2}%
1053     \fi
1054   \fi
1055   \grabbufferdatadirect{page:mvl:temp}{\e!start\v!columnsetsheet}{\e!stop\v!columnsetsheet}}
1056
1057\permanent\protected\defcsname\e!start\v!columnsetspreadsheets\endcsname
1058  {\begingroup
1059   \obeylines
1060  %\lettonothing\currentcolumnset
1061   \cdef\askedspreadsheets{1}%
1062   \page_mvl_spreadsheets_start}
1063
1064\permanent\protected\defcsname\e!stop\v!columnsetspreadsheets\endcsname
1065  {\ifcstok{\columnsetparameter\c!state}\v!start
1066     \clf_registercolumnsetspreadsheets{\currentcolumnset}{\askedspreadsheets}\relax
1067   \else
1068     \rawbuffer{page:mvl:temp}% no real need for usung a buffer in this case
1069   \fi
1070   \endgroup}
1071
1072\tolerant\def\page_mvl_spreadsheets_start[#1]#*[#2]%  columnset spreadnumber
1073  {\ifparameter#2\or
1074     \ifchknum#2\or
1075       \cdef\currentcolumnset{#1}%
1076       \cdef\askedspreadsheets{#2}%
1077     \orelse\ifchknum#1\or
1078       \cdef\askedspreadsheets{#1}%
1079     \fi
1080   \orelse\ifparameter#1\or
1081     \ifchknum#1\or
1082       \cdef\askedspreadsheets{#1}%
1083     \fi
1084   \fi
1085   \grabbufferdatadirect{page:mvl:temp}{\e!start\v!columnsetspreadsheets}{\e!stop\v!columnsetspreadsheets}}
1086
1087% we need a discard otr .. beware: these buffers are grouped
1088
1089\newconditional\c_page_mvl_inside_specification
1090
1091\cdef\m_page_mvl_buffer{page:mvl:temp} % todo low level buffer call
1092
1093\def\page_mvl_process_sheet
1094  {\begingroup
1095   \c_page_mvl_inside_specification\conditionaltrue
1096   \setbox\scratchbox\vpack{\rawbuffer{\m_page_mvl_buffer}}%
1097   \endgroup}
1098
1099\def\page_mvl_process_delayed
1100  {\begingroup
1101   \c_page_mvl_inside_specification\conditionaltrue
1102   \setbox\scratchbox\vpack{\rawbuffer{\m_page_mvl_buffer}}%
1103   \endgroup}
1104
1105\def\page_mvl_process_spread
1106  {\begingroup
1107   \setbox\scratchbox\vpack{\rawbuffer{\m_page_mvl_buffer}}%
1108   \endgroup}
1109
1110%D Experimental:
1111
1112\installcorenamespace {subcolumnset}
1113
1114\installcommandhandler \??subcolumnset {subcolumnset} \??subcolumnset
1115
1116\pushoverloadmode
1117
1118% \permanent\tolerant\protected\def\definesubcolumnset[#1]#*[#2]#*[#3]%
1119%   {\ifcsname\??subcolumnset#1\endcsname\else
1120%      \xdefcsname\??subcolumnset#1\endcsname{#2}%
1121%    \fi
1122%    \scratchcounter\clf_definesubcolumnset
1123%        name    {#1}%
1124%        subname {#2}%
1125%        columns {#3}%
1126%    \relax
1127%    \expandafter\integerdef\csname\??subcolumnset:#1:#2\endcsname\scratchcounter}
1128
1129\permanent\tolerant\protected\def\definesubcolumnset[#1]#*[#2]#*[#3]%
1130  {\ifcsname\??subcolumnset#1\endcsname\else
1131     \xdefcsname\??subcolumnset#1\endcsname{#2}%
1132     \ifcsname\namedsubcolumnsethash#1:#2\s!parent\endcsname\else
1133       \edefcsname\??subcolumnset#1:#2:\s!parent\endcsname{\??subcolumnset#1}%
1134     \fi
1135   \fi
1136   \scratchcounter\clf_definesubcolumnset
1137       name    {#1}%
1138       subname {#2}%
1139       columns {#3}%
1140   \relax
1141   \expandafter\integerdef\csname\??subcolumnset:#1:#2\endcsname\scratchcounter}
1142
1143\popoverloadmode
1144
1145\newconditional\c_page_mvl_trace_n
1146
1147\installtextracker{columnsets.mvl}
1148  {\c_page_mvl_trace_n\conditionaltrue}
1149  {\c_page_mvl_trace_n\conditionalfalse}
1150
1151\def\page_mvl_sub_columnset_start#1%
1152   {\beginmvl
1153      \s!options {\ignoreprevdepthmvloptioncode+\discardtopmvloptioncode}%
1154      \s!index   {#1}%
1155    \relax
1156    \ifconditional\c_page_mvl_trace_n
1157      \writestatus\m!columnset{start sub mvl \number\mvlcurrentlyactive}%
1158    \fi}
1159
1160\def\page_mvl_sub_columnset_stop
1161  {\ifconditional\c_page_mvl_trace_n
1162     \writestatus\m!columnset{stop sub mvl \number\mvlcurrentlyactive}%
1163   \fi
1164   \endmvl}
1165
1166\def\page_mvl_main_mvl_begin
1167  {\beginmvl
1168     \s!options {\ignoreprevdepthmvloptioncode+\discardtopmvloptioncode}%
1169     \s!index   \plusone
1170   \relax
1171   \ifconditional\c_page_mvl_trace_n
1172     \writestatus\m!columnset{start main mvl \number\mvlcurrentlyactive}%
1173   \fi
1174   \ifcsname\??subcolumnset\currentcolumnset\endcsname
1175     \hsize\clf_columnsetcolumnwidth\currentcolumnset{\lastnamedcs}\relax
1176   \fi}
1177
1178\def\page_mvl_main_mvl_end
1179  {\ifconditional\c_page_mvl_trace_n
1180     \writestatus\m!columnset{stop main mvl \number\mvlcurrentlyactive}%
1181   \fi
1182   \endmvl}
1183
1184\permanent\tolerant\protected\def\startsubcolumnset[#1]#*[#2]% #,[#1]#,#*[#2]
1185  {\unless\ifconditional\c_page_mvl_active
1186     \par
1187   \orelse\ifcase\c_page_mvl_level
1188     \page_mvl_main_mvl_end
1189     \let\page_mvl_main_mvl_end\relax
1190   \fi
1191   \begingroup
1192   \advanceby\c_page_mvl_level\plusone
1193   \ifnum\c_page_mvl_level=\plusone
1194     \ifhastok={#1}%
1195       \cdef\currentsubcolumnset{\currentcolumnset:}%
1196       \setupcurrentsubcolumnset[#1]%
1197     \else
1198       \cdef\currentsubcolumnset{\currentcolumnset:#1}%
1199       \ifparameter#2\or
1200         \setupcurrentsubcolumnset[#2]%
1201       \fi
1202     \fi
1203     \uselanguageparameter\subcolumnsetparameter
1204     \usesubcolumnsetstyleandcolor\c!style\c!color
1205     \usealignparameter\subcolumnsetparameter
1206     \hsize\clf_columnsetcolumnwidth\currentcolumnset{#1}%
1207     \scratchcounter\ifcsname\??subcolumnset:\currentsubcolumnset\endcsname\lastnamedcs\else\plusone\fi
1208     \ifconditional\c_page_mvl_active
1209       \page_mvl_sub_columnset_start\scratchcounter
1210     \else
1211       \subcolumnsetparameter\c!before
1212     \fi
1213   \fi}
1214
1215\permanent\protected\def\stopsubcolumnset
1216  {\unless\ifconditional\c_page_mvl_active
1217     \par
1218     \subcolumnsetparameter\c!after
1219   \orelse\ifnum\c_page_mvl_level=\plusone
1220     \page_mvl_sub_columnset_stop
1221   \fi
1222   \endgroup}
1223
1224% \startsetups example:balance
1225%     \balancevsize            \vsize
1226%     \balancetopskip          \strutht
1227%     \balancebottomskip       \strutdp
1228%     \balanceadjdemerits      10000
1229%     \balancetolerance        10 % or 0
1230%   % \balanceemergencystretch 1\lineheight
1231% \stopsetups
1232
1233%D The balancing code is kind of complex with call outs to \LUA\ because we store
1234%D specification and states there. Much of what is below can therefore as well be
1235%D done at the \LUA\ end but it is also a demonstration of some recent (2024)
1236%D \LUAMETATEX\ primitives. Eventually I might decide to do more in \LUA\ and
1237%D comment code here. Performance is no argument, clearity is, although the \LUA\
1238%D end also needs a cleanup (some old code in there).
1239
1240\newconditional\c_page_mvl_balancing
1241\newconditional\c_page_mvl_trace
1242\newconditional\c_page_mvl_preroll_quit
1243
1244\newconditional\c_page_mvl_inserts       \c_page_mvl_inserts      \conditionaltrue
1245\newconditional\c_page_mvl_split_inserts \c_page_mvl_split_inserts\conditionaltrue
1246\newconditional\c_page_mvl_discard       \c_page_mvl_discard      \conditionaltrue
1247
1248\newbox        \b_page_mvl_collected_content
1249\newbox        \b_page_mvl_split_content
1250\newbox        \b_page_mvl_current_content
1251
1252\newinteger    \c_page_mvl_global_dead_cycles
1253\newinteger    \c_page_mvl_local_dead_cycles
1254\newinteger    \c_page_mvl_current_n_of_slots
1255\newinteger    \c_page_mvl_previous_n_of_slots
1256
1257\newinteger    \c_page_mvl_balance_dead_cycles
1258\newinteger    \c_page_mvl_balance_boundary
1259\newinteger    \c_page_mvl_balance_n_of_slots
1260\newinteger    \c_page_mvl_balance_n_of_sheets
1261\newinteger    \c_page_mvl_balance_n_of_columns
1262\newinteger    \c_page_mvl_balance_first_htdp   % gone
1263
1264\lettonothing  \d_d_page_mvl_htdp % \mutable
1265
1266\def\c_page_mvl_balance_sheet{\columnsetshapepage\currentcolumnset\c_page_mvl_current_n_of_slots}
1267
1268\newinteger\c_page_mvl_htdp_options \c_page_mvl_htdp_options\numexpr
1269    \defaultspecificationoptioncode
1270  + \doublespecificationoptioncode
1271  + \rotatespecificationoptioncode
1272\relax
1273
1274\newinteger\c_page_mvl_balance_extra
1275\newinteger\c_page_mvl_balance_first
1276\newinteger\c_page_mvl_balance_last
1277\newinteger\c_page_mvl_balance_page  % redundant, used for tracing
1278
1279\newinteger\globaldeadcycles \globaldeadcycles\plusonethousand
1280\newinteger\localdeadcycles  \localdeadcycles \plushundred
1281
1282\def\page_mvl_process_mvl_preroll_step
1283  {\ifconditional\c_page_mvl_inserts
1284     \ifconditional\c_page_mvl_split_inserts
1285       \vbalanceddeinsert\scratchboxone
1286         \s!descend \relaxedspace
1287         \s!forcedepth
1288       \relax
1289     \fi
1290   \fi
1291   \setbox\b_page_mvl_split_content\vbalance\scratchboxone\s!trial\relax
1292   \c_page_mvl_current_n_of_slots \zerocount
1293   \c_page_mvl_local_dead_cycles  \localdeadcycles
1294   \c_page_mvl_previous_n_of_slots\zerocount
1295   \c_page_mvl_global_dead_cycles \globaldeadcycles
1296   %
1297   \d_page_mvl_last_ht \zeropoint
1298   \d_page_mvl_last_dp \zeropoint
1299   %
1300   \relax
1301   \localcontrolledendless {%
1302     \ifcase\c_page_mvl_local_dead_cycles
1303       \writestatus\m!columnset\empty
1304       \writestatus\m!columnset{quitting '\currentcolumnset' due to local deadcyling}%
1305       \writestatus\m!columnset\empty
1306       \quitloop
1307     \orelse\ifcase\c_page_mvl_global_dead_cycles
1308       \writestatus\m!columnset\empty
1309       \writestatus\m!columnset{quitting '\currentcolumnset' due to global deadcyling}%
1310       \writestatus\m!columnset\empty
1311       \quitloop
1312     \orelse\ifvoid\b_page_mvl_split_content
1313       \quitloop
1314     \else
1315       \advanceby\c_page_mvl_current_n_of_slots\plusone
1316       \setbox\b_page_mvl_current_content\vbalancedbox\b_page_mvl_split_content
1317       \scratchheight\balanceshapevsize\c_page_mvl_current_n_of_slots\relax
1318       \scratchdimen{\ht\b_page_mvl_current_content-\scratchheight}%
1319       \d_page_mvl_last_ht\ht\b_page_mvl_current_content
1320       \d_page_mvl_last_dp\dp\b_page_mvl_current_content
1321       \ifconditional\c_page_mvl_balancing
1322         \d_d_page_mvl_htdp\currentloopiterator\d_page_mvl_last_ht\d_page_mvl_last_dp
1323       \fi
1324       \ifdim\scratchdimen>\zeropoint
1325         \ifnum\clf_columnsetsetshapeextra\currentcolumnset\c_page_mvl_current_n_of_slots=\plusone
1326          %\writestatus\m!columnset\empty
1327          %\writestatus\m!columnset{set '\currentcolumnset', slot \the\c_page_mvl_current_n_of_slots, target \the\scratchheight, height \the\ht\b_page_mvl_current_content, delta \the\scratchdimen}%
1328          %\writestatus\m!columnset\empty
1329           \clf_columnsetreshape\currentcolumnset
1330           \setbox\b_page_mvl_split_content\vbalance\scratchboxone\s!trial\relax
1331           \advance\c_page_mvl_global_dead_cycles\minusone
1332           \ifnum\c_page_mvl_current_n_of_slots>\c_page_mvl_previous_n_of_slots
1333             \c_page_mvl_local_dead_cycles\plushundred
1334           \else
1335             \advance\c_page_mvl_local_dead_cycles\minusone
1336           \fi
1337           \c_page_mvl_current_n_of_slots\zerocount
1338         \else
1339           \c_page_mvl_previous_n_of_slots\c_page_mvl_current_n_of_slots
1340         \fi
1341       \else
1342         \c_page_mvl_previous_n_of_slots\c_page_mvl_current_n_of_slots
1343       \fi
1344     \fi}%
1345     }
1346
1347\def\page_mvl_process_mvl_preroll_balance_more
1348  {\localcontrolledloop \c_page_mvl_balance_first\c_page_mvl_balance_last \plusone {%
1349     \ifcase\clf_columnsetsetshapeextra\currentcolumnset\currentloopiterator\relax
1350       \c_page_mvl_balance_dead_cycles\plustwohundred
1351     \fi}%
1352   \ifconditional\c_page_mvl_trace
1353     \writestatus\m!columnset{more: \the\c_page_mvl_balance_first..\the\c_page_mvl_balance_last}%
1354     \columnsetshowshape\currentcolumnset
1355   \fi
1356   \clf_columnsetreshape\currentcolumnset\relax
1357   \page_mvl_process_mvl_preroll_step\relax}
1358
1359\def\page_mvl_process_mvl_preroll_balance_less
1360  {\localcontrolledloop \c_page_mvl_balance_first\c_page_mvl_balance_last \plusone {%
1361     \ifcase\clf_columnsetresetshapeextra\currentcolumnset\currentloopiterator\relax
1362       \c_page_mvl_balance_dead_cycles\plustwohundred
1363     \fi}%
1364    \ifconditional\c_page_mvl_trace
1365     \writestatus\m!columnset{less: \the\c_page_mvl_balance_first..\the\c_page_mvl_balance_last}%
1366     \columnsetshowshape\currentcolumnset
1367   \fi
1368   \clf_columnsetreshape\currentcolumnset\relax
1369   \page_mvl_process_mvl_preroll_step\relax}
1370
1371\newinteger\c_page_mvl_max_used_cells
1372
1373\def\page_mvl_process_mvl_preroll_balance
1374  {\relax
1375   \ifcase\c_page_mvl_current_n_of_slots
1376   \orelse\ifcase\c_page_mvl_local_dead_cycles
1377   \orelse\ifcase\c_page_mvl_global_dead_cycles
1378   \orelse\ifconditional\c_page_mvl_balancing
1379     \ifconditional\c_page_mvl_trace
1380       \writestatus\m!columnset{balancing \the\c_page_mvl_current_n_of_slots\space slots}%
1381       \columnsetshowshape\currentcolumnset
1382     \fi
1383     % we need to make sure we add shapes for the rest of the spread / sheet
1384     \clf_columnsetshapebalanceextend\currentcolumnset{\c_page_mvl_current_n_of_slots+\nofcolumns}% can be automatic
1385     \clf_columnsetshapesetbalancerange\currentcolumnset\c_page_mvl_current_n_of_slots
1386     \c_page_mvl_balance_n_of_slots\columnsetshapeslots\currentcolumnset
1387     \c_page_mvl_balance_first\clf_columnsetbalancefirst\currentcolumnset
1388     \c_page_mvl_balance_last\clf_columnsetbalancelast\currentcolumnset
1389     \c_page_mvl_balance_page\clf_columnsetbalancepage\currentcolumnset
1390     \ifnum\c_page_mvl_balance_last !>\c_page_mvl_balance_first
1391       \writestatus\m!columnset\empty
1392       \writestatus\m!columnset{quit balancing, no valid slot in sheet \the\c_page_mvl_balance_page}%
1393       \writestatus\m!columnset\empty
1394       \c_page_mvl_preroll_quit\conditionaltrue
1395     \orelse\ifcase\clf_columnsetshapebalancecheck\currentcolumnset\c_page_mvl_balance_first\relax
1396% not yet ok on right sheet while actually we are on the next
1397       \writestatus\m!columnset\empty
1398       \writestatus\m!columnset{quit balancing, multiple slots in sheet \the\c_page_mvl_balance_page}%
1399       \writestatus\m!columnset\empty
1400       \c_page_mvl_preroll_quit\conditionaltrue
1401     \or
1402       \ifconditional\c_page_mvl_trace
1403         \writestatus\m!columnset{analyzed,
1404           \the\c_page_mvl_balance_n_of_slots\space slots,
1405           sheet \the\c_page_mvl_balance_page,
1406           first \the\c_page_mvl_balance_first,
1407           last  \the\c_page_mvl_balance_last,
1408           index \the\c_page_mvl_current_n_of_slots
1409         }%
1410         \columnsetshowshape\currentcolumnset
1411       \fi
1412       % we are one ahead as we have the generic shape slot too
1413       \advanceby\c_page_mvl_balance_n_of_slots\minusone
1414       \c_page_mvl_balance_extra{\c_page_mvl_balance_n_of_slots-\c_page_mvl_current_n_of_slots}%
1415       \c_page_mvl_balance_n_of_sheets\columnsetshapepage\currentcolumnset\c_page_mvl_current_n_of_slots
1416       \ifconditional\c_page_mvl_trace
1417         \writestatus\m!columnset{\the\c_page_mvl_balance_extra\space extra slots}%
1418         \writestatus\m!columnset{balancing sheet \the\c_page_mvl_balance_n_of_sheets}%
1419       \fi
1420       %
1421       \c_page_mvl_balance_n_of_columns\nofcolumns % \c_page_mvl_balance_n_of_slots
1422       \c_page_mvl_balance_boundary{\c_page_mvl_balance_first+\minusone}%
1423       %
1424       \c_page_mvl_balance_dead_cycles\zerocount
1425       \localcontrolledendless {%
1426         \advanceby\c_page_mvl_balance_dead_cycles\plusone
1427         \page_mvl_process_mvl_preroll_balance_more
1428         \ifnum\c_page_mvl_balance_dead_cycles !<\localdeadcycles\relax % todo: its own one
1429           \ifconditional\c_page_mvl_trace
1430             \writestatus\m!columnset{quit balancing, dead cycles}%
1431           \fi
1432           \page_mvl_process_mvl_preroll_balance_less
1433           \quitloop
1434         \orelse\ifcase\c_page_mvl_current_n_of_slots\relax
1435           \ifconditional\c_page_mvl_trace
1436             \writestatus\m!columnset{quit balancing, no slots}%
1437           \fi
1438           \page_mvl_process_mvl_preroll_balance_less
1439           \quitloop
1440         \orelse\ifnum\c_page_mvl_balance_sheet>\c_page_mvl_balance_n_of_sheets\relax
1441           \page_mvl_process_mvl_preroll_balance_less
1442           \ifconditional\c_page_mvl_trace
1443             \writestatus\m!columnset{quit balancing, reached}%
1444             \columnsetshowshape\currentcolumnset
1445           \fi
1446           \quitloop
1447         \fi}%
1448     \fi
1449  \fi}
1450
1451\protected\def\page_mvl_process_mvl_preroll
1452  {\relax
1453  %\balancetolerance        \plustwohundred
1454   \balancevsize            \vsize
1455   \balancetopskip          \strutht    % set otherwise
1456   \balancebottomskip       \strutdp
1457   \balanceemergencystretch \lineheight
1458   %balanceemergencyshrink  \lineheight
1459   \usesetupsparameter\columnsetparameter
1460   \clf_columnsetshape\currentcolumnset
1461   \forgetall
1462   \dontcomplain
1463   \resetgridsnapping
1464   \specificationdef\d_d_page_mvl_htdp\dimen
1465      {\nofcolumns}%
1466      \s!options \c_page_mvl_htdp_options
1467      \zeropoint \zeropoint
1468   \relax
1469   \c_page_mvl_preroll_quit\conditionalfalse
1470   \ifconditional\c_page_mvl_trace
1471     \writestatus\m!columnset{before preroll, shapes \the\columnsetshapecount\currentcolumnset}%
1472     \columnsetshowshape\currentcolumnset
1473     \page_mvl_process_mvl_preroll_step
1474     \writestatus\m!columnset{after  preroll, shapes \the\columnsetshapecount\currentcolumnset, slots \the\c_page_mvl_current_n_of_slots}%
1475     \columnsetshowshape\currentcolumnset
1476   \else
1477     \page_mvl_process_mvl_preroll_step
1478   \fi
1479   \page_mvl_process_mvl_preroll_balance}
1480
1481% TODO: no need for notes that are not used, we can have some flag per
1482% note
1483
1484\def\page_mvl_place_note_inserts
1485  {\c_strc_notes_first_placed\conditionalfalse
1486   \strc_notes_process\page_mvl_place_note_inserts_indeed}
1487
1488\def\page_mvl_place_note_inserts_indeed % similar to page
1489  {\setbox\b_strc_notes_inserts\vbalancedinsert\b_page_mvl_current_content
1490     \s!index \currentnoteinsertionnumber
1491     \s!descend
1492   \relax
1493   \ifvoid\b_strc_notes_inserts\else
1494     \ifcase\insertmultiplier\currentnoteinsertionnumber\else
1495       \strc_notes_place_inserts_very_indeed\relax
1496       \c_strc_notes_first_placed\conditionaltrue
1497     \fi
1498   \fi}
1499
1500\def\page_mvl_process_mvl_final
1501  {\clf_columnsetreshape\currentcolumnset
1502   \setbox\scratchboxtwo\vbalance\scratchboxone\relax % otherwise loop expands
1503   \ifconditional\c_page_mvl_discard
1504     \vbalanceddiscard\scratchboxtwo
1505       \s!descend
1506     \relax
1507   \fi
1508   \localcontrolledendless {%
1509     \ifvoid\scratchboxtwo
1510       \expandafter\quitloop
1511     \else
1512       \setbox\b_page_mvl_current_content\page_mvl_show_slot\bgroup\vbalancedbox\scratchboxtwo\egroup
1513       \ifconditional\c_page_mvl_inserts
1514         \ifconditional\c_page_mvl_split_inserts
1515           \vbalancedreinsert\b_page_mvl_current_content
1516              \s!descend
1517           \relax
1518         \fi
1519         \ifnum\boxinserts\b_page_mvl_current_content>\plusthree
1520           \setbox\scratchboxfour\vpack to \ht\b_page_mvl_current_content\bgroup
1521             \page_mvl_top_insertions
1522             \vfill
1523             \page_mvl_bottom_insertions
1524             \page_mvl_place_note_inserts
1525           \egroup
1526           \ifvoid\scratchboxfour\else
1527             \setbox\b_page_mvl_current_content\hpack to \wd\b_page_mvl_current_content\bgroup
1528               \wd\b_page_mvl_current_content\zeropoint
1529               \getnoflines\d_page_mvl_top_insertions_height
1530               \boxyoffset\b_page_mvl_current_content-\noflines\lineheight
1531             % \boxyoffset\b_page_mvl_c urrent_content-\d_page_mvl_top_insertions_height % only when testing overlap
1532               \box\b_page_mvl_current_content
1533               \box\scratchboxfour
1534             \egroup
1535           \fi
1536         \fi
1537       \fi
1538       \boxyoffset\b_page_mvl_current_content-\strutdp
1539       \clf_addtocolumnsetmvl\currentcolumnset\b_page_mvl_current_content\currentloopiterator
1540   \fi}}
1541
1542\installtextracker{columnsets.keepdiscard}
1543  {\c_page_mvl_discard\conditionalfalse}
1544  {\c_page_mvl_discard\conditionaltrue}
1545
1546\def\page_mvl_process_mvl_flush
1547  {\clf_columnsetreshape\currentcolumnset
1548   \setbox\b_page_mvl_split_content\vbalance\scratchboxone\relax % otherwise loop expands
1549   \ifconditional\c_page_mvl_discard
1550     \vbalanceddiscard\b_page_mvl_split_content
1551       \s!descend
1552     \relax
1553   \fi
1554   \localcontrolledendless {%
1555     \ifvoid\b_page_mvl_split_content
1556       \expandafter\quitloop
1557     \else
1558       \setbox\b_page_mvl_current_content\page_mvl_show_slot\bgroup\vbalancedbox\b_page_mvl_split_content\egroup
1559       \ifconditional\c_page_mvl_inserts
1560         \ifconditional\c_page_mvl_split_inserts
1561           \vbalancedreinsert\b_page_mvl_current_content
1562             \s!descend
1563           \relax
1564         \fi
1565         \ifnum\boxinserts\b_page_mvl_current_content>\plusthree
1566           \donetrue
1567         \else
1568           \donefalse
1569         \fi
1570       \else
1571         \donefalse
1572       \fi
1573       \ifdone
1574         \setbox\scratchboxfour\vpack to \ht\b_page_mvl_current_content\bgroup
1575           \page_mvl_top_insertions
1576           \vfill
1577           \page_mvl_bottom_insertions
1578           \page_mvl_place_note_inserts
1579         \egroup
1580         \ifvoid\scratchboxfour\else
1581           \setbox\b_page_mvl_current_content\hpack to \wd\b_page_mvl_current_content\bgroup
1582             \wd\b_page_mvl_current_content\zeropoint
1583             \box\b_page_mvl_current_content
1584             \box\scratchboxfour
1585           \egroup
1586         \fi
1587         \boxyoffset\b_page_mvl_current_content-\strutdp
1588         \clf_addtocolumnsetmvl\currentcolumnset\b_page_mvl_current_content\currentloopiterator
1589       \else
1590         \boxyoffset\b_page_mvl_current_content-\strutdp
1591         \ifvoid\b_page_mvl_split_content
1592           \boxyoffset\b_page_mvl_current_content-\dimexpr\ht\b_page_mvl_current_content-\d_page_mvl_last_ht\relax
1593           \ht\b_page_mvl_current_content\d_page_mvl_last_ht
1594           \dp\b_page_mvl_current_content\d_page_mvl_last_dp
1595           \clf_subtocolumnsetmvl\currentcolumnset\b_page_mvl_current_content\currentloopiterator
1596         \else\ifconditional\c_page_mvl_balancing
1597           \ifnum\currentloopiterator>\c_page_mvl_balance_boundary
1598             \scratchheight\d_d_page_mvl_htdp\numexpr\currentloopiterator\relax\plusone
1599             \scratchdepth \d_d_page_mvl_htdp\numexpr\currentloopiterator\relax\plustwo
1600             \boxyoffset\b_page_mvl_current_content{\scratchheight-\ht\b_page_mvl_current_content}%
1601             \ht\b_page_mvl_current_content\scratchheight
1602             \dp\b_page_mvl_current_content\scratchdepth
1603             \clf_subtocolumnsetmvlbalance\currentcolumnset\b_page_mvl_current_content\currentloopiterator
1604           \else
1605             \clf_addtocolumnsetmvl\currentcolumnset\b_page_mvl_current_content\currentloopiterator
1606           \fi
1607         \else
1608           \clf_addtocolumnsetmvl\currentcolumnset\b_page_mvl_current_content\currentloopiterator
1609         \fi
1610        \fi
1611       \fi
1612   \fi}}
1613
1614\def\page_mvl_process_mvl
1615  {\page_mvl_process_mvl_preroll
1616   \page_mvl_process_mvl_final}
1617
1618\def\page_mvl_flush_mvl
1619  {\page_mvl_process_mvl_preroll
1620   \ifconditional\c_page_mvl_preroll_quit
1621     \page_mvl_process_mvl_final
1622   \else
1623     \page_mvl_process_mvl_flush
1624   \fi}
1625
1626\def\page_mvl_intermediate#1%
1627  {\clf_presetcolumnsetspreadsheets\currentcolumnset
1628   \clf_presetcolumnsetsheets\currentcolumnset
1629   \clf_columnsetlimit\currentcolumnset
1630   \begingroup
1631   \dontcomplain
1632   \scratchcounterone\plustwo
1633   \scratchcountertwo\columnsetlastmvl{\currentcolumnset}\relax % lookahead
1634   \ifnum\scratchcounterone>\scratchcountertwo
1635     \scratchcounterone\plusone
1636     \scratchcountertwo\plusone
1637   \fi
1638   \ifconditional\c_page_mvl_trace_n
1639     \writestatus\m!columnset{intermediate mlv: \the\scratchcounterone ..\the\scratchcountertwo}%
1640   \fi
1641   \localcontrolledloop \scratchcounterone \scratchcountertwo \plusone {%
1642     \clf_setcolumnsetmvl{\currentcolumnset}\currentloopiterator\relax
1643     \clf_gotocolumnsetslot{\currentcolumnset}\relax
1644     \setbox\scratchboxone\flushmvl\currentloopiterator\relax
1645     #1%
1646   }%
1647   \endgroup}
1648
1649\permanent\protected\def\flushcolumnset
1650  {\ifconditional\c_page_mvl_active
1651     \page_mvl_intermediate\page_mvl_flush_mvl
1652   \fi}
1653
1654\permanent\protected\def\processcolumnset
1655  {\ifconditional\c_page_mvl_active
1656     \page_mvl_intermediate\page_mvl_process_mvl
1657   \fi}
1658
1659\permanent\tolerant\protected\def\balancesubcolumnsets[#1]%
1660  {\unless\ifconditional\c_page_mvl_active
1661     % do nothing
1662%    \orelse\ifcase\columnsetlastmvl{\currentcolumnset}\or
1663   \else%\ifcase\columnsetlastmvl{\currentcolumnset}\or
1664    % messy, we're counting mvls from 2 if we have subs
1665    %\writestatus{>>>>}{\the\columnsetlastmvl{\currentcolumnset}}%
1666     \c_page_mvl_balancing\conditionaltrue
1667     \flushsubcolumnsets[#1]%
1668     \c_page_mvl_balancing\conditionalfalse
1669%    \else
1670%      \flushsubcolumnsets[#1]%
1671   \fi
1672   \relax}
1673
1674\protected\def\page_mvl_command_flush_page
1675  {\ifnum\c_page_mvl_main_level>\plusone
1676     \page_mvl_flush_nested_page
1677   \else % e.g. specific backgrounds
1678     \clf_delayedcolumnsetsheet\currentcolumnset
1679   \fi
1680   \setbox\b_page_mvl_collected\hpack\bgroup
1681     \clf_preparecolumnsetflush{\currentcolumnset}%
1682     \global\setbox\globalscratchbox\emptybox
1683     \page_mvl_show_state
1684     \letcolumnsetparameter\c!region\currentcolumnset
1685     \ifcstok{\columnsetparameter\c!direction}\v!reverse
1686       \dostepwiserecurse\c_page_mvl_last_column\c_page_mvl_first_column\minusone
1687         {\scratchdistance
1688            \ifnum##1>\plusone
1689              {\namedcolumnsetparameter{\currentcolumnset:##1}\c!distance}%
1690            \else
1691              \zeropoint
1692            \fi
1693          \page_mvl_command_flush_page_column{##1}\scratchdistance}%
1694     \else
1695       \dostepwiserecurse\c_page_mvl_first_column\c_page_mvl_last_column\plusone
1696         {\scratchdistance
1697            \ifnum##1<\c_page_mvl_last_column
1698              {\namedcolumnsetparameter{\currentcolumnset:##1}\c!distance}%
1699            \else
1700              \zeropoint
1701            \fi
1702          \page_mvl_command_flush_page_column{##1}\scratchdistance}%
1703     \fi
1704     \clf_finishcolumnsetflush{\currentcolumnset}%
1705   \egroup
1706   \setbox\b_page_mvl_collected\hpack\bgroup
1707     \wd\globalscratchbox\zeropoint
1708     \box\globalscratchbox
1709     \box\b_page_mvl_collected
1710   \egroup
1711   \ifnum\c_page_mvl_main_level>\plusone
1712     \page_mvl_flush_nested_page
1713   \else
1714     \page_boxes_shipout{\page_boxes_constructed_page\box\b_page_mvl_collected}% \hbox removed
1715     \strc_pagenumbers_increment_counters % should hook into an every
1716   \fi}
1717
1718\def\page_mvl_flush_nested_page
1719  {\begingroup
1720   \scratchtotal \ht\b_page_mvl_collected
1721   \boxyoffset\b_page_mvl_collected{-\scratchtotal+\strutht}%
1722   \clf_putincolumnsetdirect {
1723     name     {\maincolumnset}%
1724     box       \b_page_mvl_collected
1725     location {\columnsetparameter\c!location}%
1726     lines    {\columnsetparameter\c!lines}%
1727   }%
1728  %\columnsetshowgrid\maincolumnset
1729   \endgroup}
1730
1731\permanent\tolerant\protected\def\flushsubcolumnsets[#1]%
1732  {\begingroup
1733   \dontcomplain
1734   \automigrationmode\zerocount
1735   \flushcolumnset
1736   % todo: numbers
1737   \clf_columnsetsblockrows\currentcolumnset{#1}\columnsetlastfuture\currentcolumnset\relax
1738   \endgroup}
1739
1740\permanent\protected\def\blockcolumnsetrows
1741  {\ifconditional\c_page_mvl_active
1742     % maybe left and right keys, currently spread
1743     \clf_columnsetsblockrows\currentcolumnset{\v!spread}\columnsetlastfuture\currentcolumnset\relax
1744   \fi}
1745
1746% We start an mvl so whatever is there wil be flushed afterwards. Actually we don't
1747% end up in the output routine because we intercept and directly shipout. So we can
1748% just assume the main single column one to work.
1749
1750\protected\def\page_mvl_command_routine
1751  {\page_mvl_command_set_vsize}
1752
1753% \setupfloats
1754%   [spacebefore=halflinebefore,
1755%    spaceafter=halflineafter]
1756
1757% \setupfloats
1758%   [spacebefore=halfline, % maybe spacearound
1759%    spaceafter=halfline]
1760
1761\def\page_mvl_place_float_force
1762  {\let\floatmethod\v!force
1763   \ifdim\wd\floatbox>\columnwidth
1764     \page_floats_save\s!text % check this
1765   \else
1766     \begingroup
1767     \edef\m_spacebefore{\floatparameter\c!spacebefore}%
1768     \edef\m_spaceafter {\floatparameter\c!spaceafter}%
1769     \ifx\m_spacebefore\v!halfline
1770       \blank[\v!keep,\v!halfline]% \direct...
1771     \else
1772       \blank[\m_spacebefore]%
1773     \fi
1774    %\snaptogrid\ruledvpack\bgroup
1775     \ruledvpack\bgroup
1776       \getnoflines{\ht\floatbox}%
1777       \scratchheight{\noflines\lineheight-\strutdp}%
1778       \boxyoffset\floatbox{\ht\floatbox-\scratchheight}%
1779       \ht\floatbox\scratchheight
1780       \dp\floatbox\zeropoint
1781       \box\floatbox
1782     \egroup
1783     \ifx\m_spacebefore\v!halfline
1784       \blank[\v!halfline]%
1785     \else
1786       \blank[\m_spaceafter]%
1787     \fi
1788     \endgroup
1789   \fi}
1790
1791\def\page_mvl_break#1%
1792  {\ifconditional\c_page_mvl_active
1793     \begingroup
1794     \forgetall
1795     \par
1796     \balanceboundary#1\plusone\relax
1797     \scratchcounter{\columnsetshapeworst\currentcolumnset+\plusone}%
1798     \multiplyby\scratchcounter\plustwo
1799     \localcontrolledrepeat \scratchcounter
1800       {\vskip\zeropoint
1801        \balanceboundary#1\zerocount}%
1802     \par
1803     \balanceboundary\zerocount\zerocount\relax
1804     \endgroup
1805   \fi}
1806
1807\protected\def\page_mvl_command_next_spread{\page_mvl_break\plusone}
1808\protected\def\page_mvl_command_next_page  {\page_mvl_break\plustwo}
1809\protected\def\page_mvl_command_next_column{\page_mvl_break\plusthree}
1810
1811\protected\def\page_mvl_command_next_slot
1812  {\ifconditional\c_page_mvl_active
1813     \begingroup
1814     \forgetall
1815     \par
1816     \balanceboundary\plusfour\plusone\relax
1817     \endgroup
1818   \fi}
1819
1820\protected\def\page_mvl_command_test_column[#1][#2]% we ignore the second argument
1821  {\ifconditional\c_page_mvl_active
1822     \ifchknumber#1\or
1823       \balanceboundary\plusfive\lastchknumber
1824     \orelse\ifchkdimension#1\or
1825       \balanceboundary\plussix\lastchkdimension
1826     \else
1827       % error
1828     \fi
1829   \fi}
1830
1831% todo: also make this installable
1832
1833%installpagebreakmethod              \v!unknown{\page_mvl_command_next_page}
1834%installpagebreakmethod              \v!yes    {\page_mvl_command_next_page}
1835\installpagebreakmethod              \v!spread {\page_mvl_command_next_spread}
1836
1837\installcolumnbreakmethod\s!columnset\s!unknown{\page_mvl_command_next_column}
1838\installcolumnbreakmethod\s!columnset\v!yes    {\page_mvl_command_next_column}
1839\installcolumnbreakmethod\s!columnset\v!slot   {\page_mvl_command_next_slot}
1840
1841\installcolumnbreakmethod\s!columnset\v!here   {\flushcolumnset}
1842\installcolumnbreakmethod\s!columnset\v!force  {\processcolumnset}
1843
1844%D Spanning all columns (single column mode):
1845
1846% \permanent\tolerant\protected\def\startwidecolumnset[#1]%
1847%   {\flushsubcolumnsets
1848%    \startsubcolumnset[\c!width=\makeupwidth,#1]\relax}
1849
1850% \permanent\protected\def\stopwidecolumnset
1851%   {\stopsubcolumnset
1852%    \flushsubcolumnsets}
1853
1854% \let\page_mvl_wide_before\donothing
1855% \let\page_mvl_wide_after \donothing
1856
1857% \enabletrackers[columnsets.keepdiscard]
1858
1859\def\page_mvl_wide_before
1860  {\begingroup
1861   \unless\ifempty{\subcolumnsetparameter\c!top}%
1862     \forgetall \par \vskip\zeropoint % skip not really needed
1863     \ruledvbox
1864       \s!discardable
1865       {\hpack{\strut\lastnamedcs}}%
1866     \par
1867   \orelse\ifcstok{\subcolumnsetparameter\c!spacebefore}\v!line
1868     \forgetall \par \vskip\zeropoint
1869     \hrule
1870       \s!discardable
1871       \s!width  \emwidth
1872       \s!height \strutht
1873       \s!depth  \strutdp
1874     \relax
1875     \par
1876   \fi
1877   \endgroup}
1878
1879\def\page_mvl_wide_after
1880  {\begingroup
1881   \unless\ifempty{\subcolumnsetparameter\c!bottom}%
1882     \forgetall \par \vskip\zeropoint
1883     \ruledvbox
1884       \s!discardable
1885       {\hpack{\strut\lastnamedcs}}%
1886     \penalty\minusone % really needed to trigger a flush
1887     \par
1888   \orelse\ifcstok{\subcolumnsetparameter\c!spaceafter}\v!line
1889     \forgetall \par \vskip\zeropoint % skip not really needed
1890     \hrule
1891       \s!discardable
1892       \s!width  \emwidth
1893       \s!height \strutht
1894       \s!depth  \strutdp
1895     \relax
1896     \par
1897   \fi
1898   \endgroup}
1899
1900\permanent\tolerant\protected\def\page_mvl_start_wide_yes[#1]%
1901  {%\flushsubcolumnsets\relax
1902   \begingroup
1903   \ifnum\columnsetlastmvl{\currentcolumnset}=\plusone
1904     \startsubcolumnset[\c!width=\makeupwidth,#1]\relax
1905     \page_mvl_wide_before\relax
1906     \enforced\let\stopwidecolumnset\page_mvl_stop_wide_yes
1907   \else
1908     \enforced\let\stopwidecolumnset\page_mvl_stop_wide_nop
1909   \fi
1910   \enforced\let\startwidecolumnset\page_mvl_start_wide_nop}
1911
1912\permanent\tolerant\protected\def\page_mvl_start_wide_nop[#1]%
1913  {\flushsubcolumnsets
1914   \begingroup}
1915
1916\aliased\let\startwidecolumnset\page_mvl_start_wide_yes
1917\aliased\let\stopwidecolumnset \relax
1918
1919\permanent\protected\def\page_mvl_stop_wide_yes
1920  {\par
1921   \page_mvl_wide_after\relax
1922   \stopsubcolumnset
1923   % hm:
1924   \startsubcolumnset\relax
1925   \stopsubcolumnset
1926   \endgroup
1927   \clf_columnsetenablewide\currentcolumnset\relax
1928   \flushsubcolumnsets\relax
1929   \clf_columnsetdisablewide\currentcolumnset\relax}
1930
1931\permanent\protected\def\page_mvl_stop_wide_nop
1932  {\par
1933   \endgroup
1934   \flushsubcolumnsets}
1935
1936%D
1937
1938\defineoutputroutine
1939  [\s!columnset]
1940  [\s!page_otr_command_routine                =\page_mvl_command_routine,
1941   \s!page_otr_command_package_contents       =\page_mvl_command_package_contents,
1942   \s!page_otr_command_set_vsize              =\page_mvl_command_set_vsize,
1943   \s!page_otr_command_set_hsize              =\page_mvl_command_set_hsize, % tricky, goes wrong
1944   \s!page_otr_command_synchronize_hsize      =\page_mvl_command_synchronize_hsize,
1945   \s!page_otr_command_next_page              =\page_mvl_command_next_page,
1946   \s!page_otr_command_next_page_and_inserts  =\page_mvl_command_next_page_and_inserts,
1947 % \s!page_otr_command_set_top_insertions     =\page_mvl_command_set_top_insertions,
1948 % \s!page_otr_command_set_bottom_insertions  =\page_mvl_command_set_bottom_insertions,
1949 % \s!page_otr_command_flush_top_insertions   =\page_mvl_command_flush_top_insertions,
1950 % \s!page_otr_command_flush_bottom_insertions=\page_mvl_command_flush_bottom_insertions,
1951   \s!page_otr_command_check_if_float_fits    =\page_mvl_command_check_if_float_fits,
1952 % \s!page_otr_command_set_float_hsize        =\page_mvl_command_set_float_hsize,
1953 % \s!page_otr_command_flush_float_box        =\page_mvl_command_flush_float_box,
1954   \s!page_otr_command_synchronize_side_floats=\page_mvl_command_synchronize_side_floats,
1955   \s!page_otr_command_side_float_output      =\page_mvl_command_side_float_output,
1956   \s!page_otr_command_flush_floats           =\page_mvl_command_flush_floats,
1957   \s!page_otr_command_flush_side_floats      =\page_mvl_command_flush_side_floats,
1958   \s!page_otr_command_flush_saved_floats     =\page_mvl_command_flush_saved_floats,
1959   \s!page_otr_command_flush_all_floats       =\page_mvl_command_flush_all_floats,
1960 % \s!page_otr_command_flush_margin_blocks    =\page_mvl_command_flush_margin_blocks, % not used
1961   \s!page_otr_command_test_column            =\page_mvl_command_test_column,
1962  ]
1963
1964\protect \endinput
1965