beta 2014.02.14 17:07
[context.git] / tex / context / base / page-mul.mkii
blobdecf784f04ed44f3b124def1bbae409ebde5c51b
1 %D \module
2 %D   [       file=page-mul, % was: core-mul
3 %D        version=1998.03.15,
4 %D          title=\CONTEXT\ Page Macros,
5 %D       subtitle=Multi Column Output,
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.
14 \writestatus{loading}{ConTeXt Page Macros / Simple Multi Column}
16 %D This module is mostly a copy from the original multi column
17 %D routine as implemented in \type {core-mul}. When the main
18 %D OTR macro's were isolated in modules and column sets were
19 %D introduced, this module became part of the OTR modules. As
20 %D a result this module is no longer generic. It also needs
21 %D an overhaul.
23 \unprotect
25 % TO DO !
27 \let\OTRMULsetvsize            \OTRONEsetvsize
28 \let\OTRMULsethsize            \OTRONEsethsize
29 \let\OTRMULdopagecontents      \OTRONEdopagecontents
30 \let\OTRMULfinalsidefloatoutput\OTRONEfinalsidefloatoutput % ???
31 \let\OTRMULflushfloatbox       \OTRONEflushfloatbox
33 \let\OTRMULdosettopinserts   \relax
34 \let\OTRMULdosetbotinserts   \relax
35 \let\OTRMULdotopinsertions   \relax
36 \let\OTRMULdobotinsertions   \relax
37 \let\OTRMULdosetbothinserts  \relax
38 \let\OTRMULflushsavedfloats  \relax
40 \let\OTRMULflushsidefloats      \forgetsidefloats % \relax
41 \let\OTRMULsynchronizesidefloats\forgetsidefloats % \relax
43 \newtoks \OTRMULoutput
45 \def\OTRMULgotonextpage
46   {\ejectpage}
48 \def\OTRMULgotonextpageX % will become obsolete
49   {\superejectpage}
51 % check \count<insert> multiplications
53 % some day try this in balancing routine
55 % \ifdim\pagetotal>\pagegoal
56 %   \eject
57 % \else
58 %   \goodbreak
59 % \fi
61 %D The following macro's implement a multi||column output
62 %D routine. The original implementation was based on Donald
63 %D Knuth's implementation, which was adapted by Craig Platt to
64 %D support balancing of the last page. I gradually adapted
65 %D Platt's version to our needs but under certain
66 %D circumstances things still went wrong. I considered all
67 %D calls to Platt's \type{\balancingerror} as undesirable.
69 %D This completely new implementation can handle enough
70 %D situations for everyday documents, but is still far from
71 %D perfect. While at the moment the routine doesn't support
72 %D all kind of floats, it does support:
74 %D \startitemize[packed]
75 %D \item  an unlimitted number of columns
76 %D \item  ragged or not ragged bottoms
77 %D \item  optional balancing without \type{\balancingerrors}
78 %D \item  different \type{\baselineskips}, \type{\spacing},
79 %D       \type{\topskip} and \type{\maxdepth}
80 %D \item  left- and right indentation, e.g. within lists
81 %D \item  moving columns floats to the next column or page
82 %D \item  handling of floats that are to wide for a columns
83 %D \stopitemize
85 %D One could wonder why single and multi||columns modes are
86 %D still separated. One reason for this is that \TeX\ is not
87 %D suited well for handling multi||columns. As a result, the
88 %D single columns routines are more robust. Handling one
89 %D column as a special case of multi||columns is posible but at
90 %D the cost of worse float handling, worse page breaking,
91 %D worse etc. Complicated multi||column page handling should
92 %D be done in \cap{DTP}||systems anyway.
94 %D There are three commands provided for entering and leaving
95 %D multi||column mode and for going to the next column:
97 %D \interface \type{\beginmulticolumns} \\ \\
98 %D \interface \type{\endmulticolumns}   \\ \\
99 %D \interface \type{\ejectcolumn}       \\ \\
101 %D This routines are sort of stand||alone. They communicate
102 %D with the rest of \CONTEXT\ by means of some interface
103 %D macro's, which we only mention.
105 %D \interface \type{\nofcolumns} \\
106 %D   the number of columns \\
107 %D \interface \type{\minbalancetoplines} \\
108 %D   the minimum number op balanced top lines \\
109 %D \interface \type{\betweencolumns} \\
110 %D   the stuff between columns \\
111 %D \interface \type{\finaloutput{action}{box}} \\
112 %D   some kind of \type{\pagebody} and \type{\shipout} \\
114 %D \interface \type{\ifbalancecolumns} \\
115 %D   balancing the colums or not \\
116 %D \interface \type{\ifstretchcolumns} \\
117 %D   ragging the bottom or not \\
119 %D \interface \type{\ifheightencolumns} \\
120 %D     fix the heigh tor not \\
121 %D \interface \type{\fixedcolumnheight} \\
122 %D     the optional fixed height \\
124 %D \interface \type{\ifinheritcolumns} \\
125 %D     handle ragging or not \\
126 %D \interface \type{\ifr@ggedbottom} \\
127 %D     use ragged bottoms \\
128 %D \interface \type{\ifb@selinebottom} \\
129 %D     put the bottom line on the baseline \\
130 %D \interface \type{\ifnormalbottom} \\
131 %D     put the bottom line at the baseline \\
133 %D \interface \type{\ifreversecolumns} \\
134 %D     reverse the order in wich columns are flushed \\
136 %D \interface \type{\usercolumnwidth} \\
137 %D     the calculated width of a column \\
138 %D \interface \type{\columntextwidth} \\
139 %D     the maximum width of a column \\
140 %D \interface \type{\columntextheight} \\
141 %D     the minimum width of a column \\
143 %D \interface \type{\spacingfactor} \\
144 %D     the spacing factor \\
145 %D \interface \type{\bodyfontsize} \\
146 %D     the (local) bodyfontsize \\
147 %D \interface \type{\openlineheight} \\
148 %D     the lineheight (including \type{\spacing}) \\
150 %D \interface \type{\EveryBodyFont} \\
151 %D     communication channel to font switching routines \\
153 %D \interface \type{\global\settopskip} \\
154 %D   set \type{\topskip} \\
155 %D \interface \type{\setvsize} \\
156 %D   set \type{\vsize} and \type{\pagegoal} \\
157 %D \interface \type{\sethsize} \\
158 %D   set \type{\hsize} \\
160 %D \interface \type{\flushcolumnfloats} \\
161 %D   push saved column floats (next page) \\
162 %D \interface \type{\flushcolumnfloat} \\
163 %D   push saved column floats (next column) \\
164 %D \interface \type{\setcolumnfloats} \\
165 %D   initialize column floats \\
167 %D \interface \type{\finishcolumnbox} \\
168 %D   do something special (a hook) \\
169 %D \interface \type{\postprocesscolumnpagebox} \\
170 %D   do something with each columnbox (also a hook) \\
171 %D \interface \type{\postprocesscolumnbox} \\
172 %D   do something with each columnbox (also a hook) \\
173 %D \interface \type{\postprocesscolumnline} \\
174 %D   do something with each columnline (also a hook) \\
175 %D \interface \type{\currentcolumn} \\
176 %D   the current column \\
178 %D These interface macro's are called upon or initialized
179 %D by the multi||column macro's.
181 %D A lot of footnote stuff added!
183 \def\finalcolumntextwidth   {\makeupwidth}
184 \def\finalcolumntextheight  {\textheight}
185 \def\columntextwidth        {\makeupwidth}
186 \def\columntextheight       {\textheight}
187 \def\usercolumnwidth        {\textwidth}
188 \def\columntextoffset       {\!!zeropoint}
190 \def\fixedcolumnheight      {\textheight}
191 \def\betweencolumns         {\hskip\bodyfontsize}
193 \let\setcolumnfloats        \relax % in CONTEXT used for floats
194 \let\flushcolumnfloats      \relax % in CONTEXT used for floats
195 \let\flushcolumnfloat       \relax % in CONTEXT used for floats
196 \let\finishcolumnbox        \relax % in CONTEXT used for backgrounds
198 % %D In fact, the column height and width are set by means of
199 % %D two macro's. One can change their meaning if needed:
201 % \def\setcolumntextheight
202 %   {\def\columntextheight{\teksthoogte}}
204 % \def\setcolumntextwidth
205 %   {\def\columntextwidth{\zetbreedte}}
207 %D Both macros are redefined in \CONTEXT\ when backgrounds
208 %D are applied to columns. The final values are used when
209 %D flushing the columns.
211 \newtoks\singlecolumnout % remove that one
213 %D It's more convenient to use \type {\columnwidth} instead
214 %D of messing around with boxes each time.
216 \newdimen\columnwidth
217 \newdimen\gutterwidth
219 \def\determinecolumnwidth
220   {\bgroup
221    \setbox\scratchbox\hbox
222      {\setcolumnhsize
223       \global\columnwidth\usercolumnwidth
224       \global\gutterwidth\intercolumnwidth}%
225    \egroup}
227 %D Going to a new columns is done by means of a
228 %D \type{\ejectcolumn}. The following definition does not
229 %D always work.
231 \def\ejectcolumn
232   {\goodbreak\showmessage\m!columns2\empty}
234 %D The next macro should never be called so let's deal with it.
235 %D There were several solutions to these kind of errors. First
236 %D we check for a good breakpoint before firing up the
237 %D multi||column routine (\type{\break} or \type{\allowbreak}).
238 %D We do the same at the end of the routine
239 %D (\type{\allowbreak}). These allowances are definitely
240 %D needed!
242 %D Some on first sight redundant calls to for instance
243 %D \type{\setvsize} in the flushing, splitting and balancing
244 %D macro's can definitely not be omitted! Some are just there
245 %D to handle situations that only few times arise. One of
246 %D those can be that the output routine is invoked before
247 %D everything is taken care of. This happens when we
248 %D flush (part of) the current page with an \type{\unvbox}
249 %D with a \type{\pagetotal}~$\approx$ \type{\pagegoal}. One
250 %D simply cannot balance columns that are just balanced.
252 %D I hope one never sees the following message. Because it
253 %D took me a lot of time to develop the multi||columns
254 %D routines, every (although seldom) warning gives me the
255 %D creeps!
257 \def\balancingerror
258   {\showmessage\m!columns3\empty
259    \finaloutput\unvbox\normalpagebox}
261 \def\OTRMULsometopsfloat{\showmessage\m!columns4\empty \someherefloat}
262 \def\OTRMULsomebotsfloat{\showmessage\m!columns5\empty \someherefloat}
264 \def\OTRMULsomeherefloat{\OTRONEsomeherefloat}
266 %D The local column width is available in the dimension
267 %D register \type{\localcolumnwidth}, which is calculated as:
269 \def\setcolumnhsize % beware, this one is available for use in macros
270   {\setbox\scratchbox\hbox{\parindent\zeropoint\betweencolumns}%
271    \intercolumnwidth\wd\scratchbox
272    \localcolumnwidth\columntextwidth
273    \advance\localcolumnwidth -\leftskip
274    \advance\localcolumnwidth -\rightskip
275    % new
276    \advance\localcolumnwidth -\colleftskip
277    \advance\localcolumnwidth -\colrightskip
278    %
279    \advance\localcolumnwidth -\nofcolumns\intercolumnwidth
280    \advance\localcolumnwidth  \intercolumnwidth
281    \divide \localcolumnwidth  \nofcolumns
282    \scratchdimen\columntextoffset
283    \multiply\scratchdimen \plustwo
284    \advance\localcolumnwidth -\scratchdimen
285    \usercolumnwidth\localcolumnwidth
286    \hsize\localcolumnwidth} % we don't do it \global
288 %D Torture test:
290 %D \startbuffer
291 %D \startbuffer[b]
292 %D \startcolumns
293 %D   \input tufte
294 %D \stopcolumns
295 %D \stopbuffer
296 %D \typebuffer[b] \getbuffer[b]
298 %D \startbuffer[b]
299 %D \startnarrower
300 %D   \input tufte
301 %D \stopnarrower
302 %D \stopbuffer
303 %D \typebuffer[b] \getbuffer[b]
305 %D \startbuffer[b]
306 %D \startcolumns \startnarrower
307 %D   \input tufte
308 %D \stopnarrower \stopcolumns
309 %D \stopbuffer
310 %D \typebuffer[b] \getbuffer[b]
312 %D \startbuffer[b]
313 %D \startnarrower \startcolumns
314 %D   \input tufte
315 %D \stopcolumns \stopnarrower
316 %D \stopbuffer
317 %D \typebuffer[b] \getbuffer[b]
319 %D \startbuffer[b]
320 %D \startcolumns \startnarrower[left]
321 %D   \input tufte
322 %D \stopnarrower \stopcolumns
323 %D \stopbuffer
324 %D \typebuffer[b] \getbuffer[b]
326 %D \startbuffer[b]
327 %D \startnarrower[left] \startcolumns
328 %D   \input tufte
329 %D \stopcolumns \stopnarrower
330 %D \stopbuffer
331 %D \typebuffer[b] \getbuffer[b]
333 %D \startbuffer[b]
334 %D \startnarrower \startcolumns \startnarrower
335 %D   \input tufte
336 %D \stopnarrower\stopcolumns \stopnarrower
337 %D \stopbuffer
338 %D \typebuffer[b] \getbuffer[b]
340 %D \startbuffer[b]
341 %D \startnarrower[left] \startcolumns \startnarrower
342 %D   \input tufte
343 %D \stopnarrower\stopcolumns \stopnarrower
344 %D \stopbuffer
345 %D \typebuffer[b] \getbuffer[b]
346 %D \stopbuffer
348 %D \start
349 %D \def\postprocesscolumnline#1{\ruledhbox{\strut\box#1}\hss}
350 %D \getbuffer
351 %D \stop
353 %D One should be aware that when font related dimensions are
354 %D used in typesetting the in||between material, these
355 %D dimensions are influenced by bodyfont switches inside
356 %D multi||column mode.
358 \newdimen\mcscratchdimen
359 \newcount\nofcolumnlines
361 \chardef\multicolumnlinemethod\zerocount % 0: overshoot (old default), 1: tight
362 % \chardef\multicolumnlinemethod\plusone
364 \def\getmulticolumnlines
365   {\mcscratchdimen-\columntextoffset
366    \multiply\mcscratchdimen \plustwo
367    \advance\mcscratchdimen \columntextheight
368    \ifdim\precolumnboxheight>\zeropoint
369       \advance\mcscratchdimen -\precolumnboxheight
370    \fi
371    \settotalinsertionheight
372    \advance\mcscratchdimen -\totalinsertionheight
373    \ifcase\multicolumnlinemethod \getnoflines\mcscratchdimen
374    \or                           \getrawnoflines\mcscratchdimen
375    \else                         \getrawnoflines\mcscratchdimen
376    \fi
377    % added 30/7/2004
378    \ifnum\layoutlines>\zerocount \ifnum\noflines>\layoutlines
379      \noflines\layoutlines
380    \fi \fi
381    \nofcolumnlines\noflines}
383 \def\multicolumnovershootratio{.5} % {\ifgridsnapping0\else.5\fi}
385 \def\setcolumnvsize
386   {\getmulticolumnlines
387    \mcscratchdimen\nofcolumnlines\openlineheight
388    \advance\mcscratchdimen \multicolumnovershootratio\openlineheight % collect enough data
389    \global\vsize\nofcolumns\mcscratchdimen
390    \global\pagegoal\vsize} % let's do it only here
392 %D It really starts here. After some checks and initializations
393 %D we change the output routine to continous multi||column
394 %D mode. This mode handles columns that fill the current and
395 %D next full pages. The method used is (more or less)
396 %D multiplying \type{\vsize} and dividing \type{\hsize} by
397 %D \type{\nofcolumns}. More on this can be found in the
398 %D \TeX book. We save the top of the current page in box
399 %D \type{\precolumnbox}.
401 %D We manipulate \type{\topskip} a bit, just to be shure that
402 %D is has no flexibility. This has te be done every time a
403 %D font switch takles place, because \type{\topskip} can depend
404 %D on this.
406 %D Watch the trick with the \type{\vbox}. This way we get the
407 %D right interlining and white space.
409 \def\beginmulticolumns
410   {\par
411    \flushnotes
412    \xdef\precolumndepth{\the\prevdepth}%
413    \begingroup
414    % new
415    \leftskip1\leftskip
416    \rightskip1\rightskip
417    \edef\colleftskip {\the\leftskip}%
418    \edef\colrightskip{\the\rightskip}%
419    \leftskip\zeropoint
420    \rightskip\zeropoint
421    %
422    \dontshowcomposition
423   %\setcolumntextwidth\relax
424   %\setcolumntextheight\relax
425    \widowpenalty\zerocount % is gewoon beter
426    \clubpenalty \zerocount % zeker bij grids
427    \ifsomefloatwaiting
428      \showmessage\m!columns6{\the\savednoffloats}%
429      \global\setbox\savedfloatlist\box\floatlist
430      \xdef\restoresavedfloats
431        {\global\savednoffloats\the\savednoffloats
432         \global\setbox\floatlist\box\savedfloatlist
433         \global\noexpand\somefloatwaitingtrue}%
434      \global\savednoffloats\zerocount
435      \global\somefloatwaitingfalse
436    \else
437      \global\let\restoresavedfloats\relax
438    \fi
439    \dimen0\pagetotal
440    \advance\dimen0 \parskip
441    \advance\dimen0 \openlineheight
442    \ifdim\dimen0<\pagegoal
443      \allowbreak
444    \else
445      \break % Sometimes fails
446    \fi
447    \appendtoks\topskip1\topskip\to\everybodyfont
448    \the\everybodyfont % ugly here
449    \saveinterlinespace % ugly here
450    \initializecolumns\nofcolumns
451    \hangafter\zerocount
452    \hangindent\zeropoint
453    \everypar\emptytoks
454    \ifdim\pagetotal=\zeropoint \else
455      \verticalstrut
456      \vskip-\struttotal
457    \fi
458    \global\savedpagetotal\pagetotal
459    \global\singlecolumnout\output
460   %\global\output{\global\setbox\precolumnbox\vbox{\unvbox\normalpagebox}}%
461    \global\output{\global\setbox\precolumnbox\vbox{\dotopinsertions\unvbox\normalpagebox}}%
462    \eject % no \holdinginserts=1, can make footnote disappear !
463    \global\precolumnboxheight\ht\precolumnbox
464    \global\output{\continuousmulticolumnsout}%
465    \setcolumnfloats
466    \dohandleallcolumns
467      {\global\setbox\currenttopcolumnbox\emptybox}%
468    \checkbegincolumnfootnotes
469    \activateotr{MUL}{ONE}% todo ! ! ! !
470    \let\sethsize\setcolumnhsize
471    \let\setvsize\setcolumnvsize
472    \sethsize
473    \setvsize
474    \showcomposition}
476 %D When we leave the multi||column mode, we have to process the
477 %D not yet shipped out part of the columns. When we don't
478 %D balance, we simply force a continuous output, but a balanced
479 %D output is more tricky.
481 %D First we try to fill up the page and when all or something
482 %D is left we try to balance things. This is another useful
483 %D adaption of the ancesters of these macro's. It takes some
484 %D reasoning to find out what happens and maybe I'm making
485 %D some mistake, but it works.
487 %D Voiding box \type{\precolumnbox} is sometimes necessary,
488 %D e.g. when there is no text given between \type{\begin..}
489 %D and \type{\end..}. The \type{\par} is needed!
491 \chardef\multicolumnendsyncmethod\plusone % 1: old sync 2: new sync (cont-loc/project) / may fail ! ! ! !
493 \def\endmulticolumns
494   {%\par
495    \ifnum\multicolumnendsyncmethod=\plustwo
496      \synchronizeoutput
497    \else
498      % don't combine these
499      \vskip\lineheight
500      \vskip-\lineheight % take footnotes into account
501    \fi
502    \dontshowcomposition
503    \doflushcolumnfloat  % added recently
504   %\doflushcolumnfloats % no, since it results in wrong top floats
505    \flushnotes          % before start of columns
506    \par
507    \ifbalancecolumns
508      \ifnum\multicolumnendsyncmethod=\plusone
509        \global\output{\continuousmulticolumnsout}%
510        \goodbreak
511      \fi
512      \global\output{\balancedmulticolumnsout}%
513    \else
514      \goodbreak
515    \fi
516    \eject               % the prevdepth is important, try e.g. toclist in
517    \prevdepth\zeropoint % columns before some noncolumned text text
518    \global\output\singlecolumnout
519    \global\output{\the\mainoutput}% % % % % todo
520    \ifvoid\precolumnbox\else
521      \unvbox\precolumnbox
522    \fi
523    \global\precolumnboxheight\zeropoint
524    \endgroup % here
525    \nofcolumns\plusone
526    \setvsize % the outer one!
527    \synchronizeoutput % new may 2004 / we need to: \pagegoal\vsize
528    \checkendcolumnfootnotes
529    \dosomebreak\allowbreak
530    \restoresavedfloats}
532 %D Because some initializations happen three times, we
533 %D defined a macro for them. Erasing \type{\everypar} is
534 %D needed because we don't want anything to interfere.
536 \def\setmulticolumnsout
537   {\everypar\emptytoks
538    \dontcomplain
539    \settopskip
540    \setmaxdepth
541    \topskip1\topskip
542    \splittopskip\topskip
543    \splitmaxdepth\maxdepth
544    \boxmaxdepth\maxdepth % dangerous
545    \emergencystretch\zeropoint\relax} % sometimes needed !
547 %D Flushing the page comes to pasting the columns together and
548 %D appending the result to box \type{\precolumnbox}, if not
549 %D void. I've seen a lot of implementations in which some skip
550 %D was put between normal text and multi||column text. When we
551 %D don't want this, the baselines can be messed up. I hope the
552 %D seemingly complicated calculation of a correction
553 %D \type{\kern} is adequate to overcome this. Although not
554 %D watertight, spacing is taken into account and even multiple
555 %D mode changes on one page go well. But cross your fingers and
556 %D don't blame me.
558 %D One of the complications of flushing out the boxes is that
559 %D \type{\precolumnbox} needs to be \type{\unvbox}'ed, otherwise
560 %D there is too less flexibility in the page when using
561 %D \type{\r@ggedbottom}. It took a lot of time before these
562 %D kind of problems were overcome. Using \type{\unvbox} at the
563 %D wrong moment can generate \type{\balancingerror}'s.
565 %D One can use the macros \type {\maxcolumnheight} and \type
566 %D {\maxcolumndepth} when generating material between columns
567 %D as well as postprocessing column lines.
569 \let\maxcolumnheight=\zeropoint
570 \let\maxcolumndepth =\zeropoint
572 \newbox\columnpagebox
574 \def\setmaxcolumndimensions
575   {\let\maxcolumnheight\!!zeropoint
576    \let\maxcolumndepth \!!zeropoint
577    \dohandleallcolumns
578      {\ifdim\ht\currentcolumnbox>\maxcolumnheight
579         \edef\maxcolumnheight{\the\ht\currentcolumnbox}%
580       \fi
581       \ifdim\dp\currentcolumnbox>\maxcolumndepth
582         \edef\maxcolumndepth{\the\dp\currentcolumnbox}%
583       \fi}}
585 \chardef\multicolumntopflushmethod\plusone % 0: no correction, 1: correction when topstuff, 2: correction, 3: correction++
586 \chardef\multicolumntopalignmethod\plustwo % 0: nothing, 1: force grid, 2: follow grid
588 \def\flushprecolumnboxnogrid
589   {\unvbox\precolumnbox}
591 \def\flushprecolumnboxongrid
592   {\scratchdimen\savedpagetotal
593    \advance\scratchdimen -\ht\precolumnbox
594    \advance\scratchdimen -\dp\precolumnbox
595    \advance\scratchdimen -\topskip
596    \box\precolumnbox
597    \kern\scratchdimen}
599 \newconditional\someprecolumncontent
601 \def\flushcolumnedpage#1%
602   {\bgroup
603    \ifvoid\precolumnbox
604      \setfalse\someprecolumncontent % will be set elsewhere
605    \else
606      \settrue\someprecolumncontent
607 \mkprocessboxcontents\precolumnbox
608    \fi
609    \forgetall
610    \setmulticolumnsout
611    \showcomposition
612    \setmaxcolumndimensions
613    \dohandleallcolumns
614      {\mkprocesscolumncontents\currentcolumnbox}%
615    \postprocesscolumns
616    \dohandleallcolumns % \hbox i.v.m. \showcomposition
617      {\global\setbox\currentcolumnbox\hbox to \localcolumnwidth
618         {\box\currentcolumnbox}%
619       \wd\currentcolumnbox\localcolumnwidth
620       \ifheightencolumns
621         \ht\currentcolumnbox\fixedcolumnheight
622       \fi}%
623    \setmaxcolumndimensions
624    \overlaycolumnfootnotes
625    \setbox\columnpagebox\vbox
626      {\hbox to \finalcolumntextwidth
627         {\hskip\colleftskip\relax % new, \relax needed
628          \ifreversecolumns
629            \popsplitproperties % else wrong color stack
630            \@EA\dohandlerevcolumns
631          \else
632            \@EA\dohandleallcolumns
633          \fi
634            {\finishcolumnbox{\hbox
635               {\ifx\finishcolumnbox\relax\else\strut\fi
636                \box\currentcolumnbox}}%
637             \hfil}%
638          \unskip
639          \hskip\colrightskip}}% new
640    \scratchdimen\zeropoint
641    \dohandleallcolumns
642      {\ifdim-\ht\currenttopcolumnbox<\scratchdimen
643         \scratchdimen-\ht\currenttopcolumnbox
644       \fi
645       \global\setbox\currenttopcolumnbox\emptybox}%
646    \advance\scratchdimen \ht\columnpagebox
647    \setbox\scratchbox\hbox to \columntextwidth
648      {\vrule
649         \!!width\zeropoint
650         \!!height\scratchdimen
651         \!!depth\dp\columnpagebox
652       \dostepwiserecurse2\nofcolumns1{\hfil\betweencolumns}\hfil}%
653    \setbox\columnpagebox\hbox
654      {\box\columnpagebox
655       \hskip-\columntextwidth
656       \restoretextcolor{\box\scratchbox}}%
657    \postprocesscolumnpagebox % new, acts upon \box\columnpagebox
658    \ifconditional\someprecolumncontent
659      \settrue\someprecolumncontent
660      % next some incredible crappy code
661      \ifcase\multicolumntopalignmethod
662        \flushprecolumnboxnogrid % not on grid
663      \or
664        \flushprecolumnboxongrid % force on grid
665      \else\ifgridsnapping % somehow this junk fails in pascal
666        \flushprecolumnboxongrid % obey grid settings, force on grid
667      \else
668        \flushprecolumnboxnogrid % ignore grid settings, not on grid
669      \fi \fi
670    \fi
671    \global\precolumnboxheight\zeropoint
672    \setvsize
673    \dosomebreak\nobreak % hm, only needed when topstuff
674    \ifgridsnapping
675    \else
676      \ifcase\multicolumntopflushmethod
677        % sometimes method 1 goes wrong, so we need a way out; best sort this out
678        % when we run into it again
679      \or
680        % \input tufte \startcolumns \showbaselines \input tufte \stopcolumns \input tufte
681        \ifconditional\someprecolumncontent
682 %          \scratchdimen\topskip
683 %          \advance\scratchdimen -\openstrutheight
684 %          \nointerlineskip
685 %          \vskip-\scratchdimen
686          \nointerlineskip
687          \vskip\dimexpr\openstrutheight-\topskip\relax
688        \fi
689      \or
690 %        \scratchdimen\topskip
691 %        \advance\scratchdimen -\openstrutheight
692 %        \nointerlineskip
693 %        \vskip-\scratchdimen
694        \nointerlineskip
695        \vskip\dimexpr\openstrutheight-\topskip\relax
696      \or
697        % untested but maybe handy
698 %        \scratchdimen\topskip
699 %        \advance\scratchdimen -\openstrutheight
700 %        \nointerlineskip
701 %        \vskip-\scratchdimen
702 %        \vskip-\lineheight
703 %        \vbox{\strut}%
704        \nointerlineskip
705        \vskip\dimexpr\openstrutheight-\topskip-\lineheight\relax
706        \vbox{\strut}%
707      \fi
708    \fi
709    \prevdepth\openstrutdepth
710    \nointerlineskip
711    \dp\columnpagebox\zeropoint
712    \global\finalcolumnheights\ht\columnpagebox
713    \getnoflines\finalcolumnheights
714    \global\finalcolumnlines\noflines
715    \ifcase#1\else
716      % messy correction, we need to rewrite this module (newcolumns)
717      \setbox\columnpagebox\vbox
718        {\offinterlineskip
719         \scratchdimen\ht\columnpagebox
720         \advance\scratchdimen\dp\columnpagebox % we probably lost that one already
721         \box\columnpagebox
722         \vskip-\scratchdimen}%
723      \scratchdimen\noflines\openlineheight
724      \advance\scratchdimen-\openstrutdepth
725      \advance\scratchdimen-\openlineheight
726      \advance\scratchdimen\topskip
727      \ht\columnpagebox\scratchdimen
728      \dp\columnpagebox\openstrutdepth
729      % end of mess
730    \fi
731    \box\columnpagebox
732    \egroup}
734 %D In case one didn't notice, finaly \type{\finishcolumnbox} is
735 %D applied to all boxes. One can use these hooks for special
736 %D purposes.
738 %D Once upon a time I wanted to manipulate the individual lines
739 %D in a column. This feature is demonstrated in the two examples
740 %D below.
742 %D \startbuffer
743 %D \def\postprocesscolumnline#1% or \postprocesscolumnbox
744 %D   {\ruledhbox{\box#1}\hss}
746 %D \startcolumns[n=4]
747 %D \dorecurse{25}{line: \recurselevel\par}
748 %D \stopcolumns
749 %D \stopbuffer
751 %D \typebuffer
753 %D Here we show the natural width of the lines:
755 %D {\getbuffer}
757 %D The next example does a bit more advanced manipulation:
759 %D \startbuffer
760 %D \def\postprocesscolumnline#1%
761 %D   {\ifodd\currentcolumn
762 %D      \hfill\unhbox#1\relax
763 %D    \else
764 %D      \relax\unhbox#1\hfill
765 %D    \fi}
767 %D \startcolumns[n=4]
768 %D \dorecurse{25}{line \recurselevel\par}
769 %D \stopcolumns
770 %D \stopbuffer
772 %D \typebuffer
774 %D Here we also see an application of \type{\currentcolumn}:
776 %D {\getbuffer}
778 %D This feature is implemented using the reshape macros
779 %D presented in \type{supp-box}.
781 \def\postprocesscolumns
782   {\ifx\postprocesscolumnline\undefined \else
783      \dohandleallcolumns
784        {\global\setbox\currentcolumnbox\vtop
785           {\beginofshapebox
786            \unvbox\currentcolumnbox
787            \unskip\unskip
788            \endofshapebox
789            \reshapebox
790              {\dimen0\ht\shapebox
791               \dimen2\dp\shapebox
792               \setbox\shapebox\hbox to \hsize
793                 {\postprocesscolumnline\shapebox}%
794               \ht\shapebox\dimen0
795               \dp\shapebox\dimen2
796               \box\shapebox}%
797            \flushshapebox
798            \everypar\emptytoks
799            \parskip\zeropoint % = \forgetall
800            \verticalstrut
801            \vskip-\struttotal
802            \vfil}}%
803    \fi
804    \ifx\postprocesscolumnbox\undefined \else
805      \dohandleallcolumns
806        {\global\setbox\currentcolumnbox\hbox
807           {\postprocesscolumnbox\currentcolumnbox}}
808    \fi}
810 %D We default to doing nothing!
812 \let\postprocesscolumnline   =\undefined
813 \let\postprocesscolumnbox    =\undefined
814 \let\postprocesscolumnpagebox=\relax
816 %D \macros
817 %D   {reversecolumnstrue}
819 %D We can force the macro that takes care of combining
820 %D the columns, to flush them in the revere order. Of
821 %D course, by default we don't reverse.
823 \newif\ifreversecolumns
825 %D Here comes the simple splitting routine. It's a bit
826 %D longer than expected because of ragging bottoms or not.
827 %D This part can be a bit shorter but I suppose that I will
828 %D forget what happens. The splitting takes some already
829 %D present material (think of floats) into account!
831 %D First we present some auxiliary routines. Any material,
832 %D like for instance floats, that is already present in the
833 %D boxes is preserved.
835 \def\splitcolumn#1from \box#2to \dimen#3 top \box#4%
836   {\bgroup
837    \ifdim\ht#4>\zeropoint
838      \dimen0\dimen#3\relax
839      \dimen2\dimen0
840      \advance\dimen0 -\ht#4%
841      \columnfootnotecorrection{#1}{\dimen0}%
842      \setbox0\vsplit#2 to \dimen0
843      \global\setbox#1\vbox to \dimen2
844        {\ifgridsnapping
845           \dimen0-\openstrutheight
846           \advance\dimen0 \topskip
847           \vskip\dimen0\copy#4\vskip-\dimen0
848         \else
849           \unvcopy#4%
850         \fi
851         \fuzzysnappedbox\unvbox0
852         \fakecolumnfootnotes{#1}}%
853    \else
854      \ifcase\clevernotes
855        \global\setbox#1\vsplit#2 to \dimen#3%
856        \global\setbox#1\vbox
857          {\fuzzysnappedbox\unvbox{#1}}% % or \box ?
858      \else
859        \columnfootnotecorrection{#1}{\dimen#3}%
860        \setbox0\vsplit#2 to \dimen#3%
861        \global\setbox#1\vbox to \dimen#3%
862          {\fuzzysnappedbox\unvbox0
863           \fakecolumnfootnotes{#1}}%
864      \fi
865    \fi
866    \egroup}
868 \def\splitcurrentcolumn from \box#1to \dimen#2%
869   {\splitcolumn\currentcolumnbox from \box#1 to \dimen#2 top \box\currenttopcolumnbox}
871 \def\splitfirstcolumn from \box#1to \dimen#2%
872   {\splitcolumn\firstcolumnbox from \box#1 to \dimen#2 top \box\firsttopcolumnbox}
874 \def\splitlastcolumn from \box#1to \dimen#2%
875   {\global\setbox\lastcolumnbox\vbox
876      {\unvcopy\lasttopcolumnbox
877       \fuzzysnappedbox\unvbox{#1}%
878       \fakecolumnfootnotes\lastcolumnbox}}
880 %D NEW: still to be documented.
882 \def\fakecolumnfootnotes#1%
883   {\relax
884    \ifcase\clevernotes\else
885      \ifnum#1=\lastcolumnbox
886        \fakenotes
887      \fi
888    \fi}
890 \def\columnfootnotecorrection#1#2%
891   {\relax
892    \ifcase\clevernotes
893      % page notes
894    \or
895      \ifnum#1=\firstcolumnbox\relax
896        \calculatetotalclevernoteheight
897        \advance#2 -\totalnoteheight
898      \fi
899    \else
900      \ifnum#1=\lastcolumnbox\relax
901        \calculatetotalclevernoteheight
902        \advance#2 -\totalnoteheight
903      \fi
904    \fi}
906 \def\overlaycolumnfootnotes
907   {\relax
908    \ifcase\clevernotes
909      % page notes
910    \else
911      \checknotepresence
912      \ifnotespresent
913        % the note box has the depth of the notefont
914        % because a column (i.e. first column has no depth,
915        % we need to anchor top down)
916        \bgroup
917        \ifcase\clevernotes\or
918          \getmulticolumnlines
919          \advance\nofcolumnlines \minustwo
920          \scratchdimen\nofcolumnlines\lineheight
921          \advance\scratchdimen \topskip
922          \setbox0\hbox
923            {\lower\scratchdimen\vbox{\placenoteinserts}}%
924          \ht0=\openstrutheight % \strutht
925          \dp0=\openstrutdepth  % \strutdp
926          \scratchdimen\ht\firstcolumnbox
927          \global\setbox\firstcolumnbox\vbox to \scratchdimen
928            {\box\firstcolumnbox
929             \vskip-\scratchdimen
930             \restoretextcolor{\box0}}%
931        \else
932          % maybe here also \getmulticolumnlines
933          \scratchdimen\ht\firstcolumnbox
934          \advance\scratchdimen -\openstrutdepth % \strutdp
935          \getnoflines\scratchdimen
936          \advance\noflines \minustwo
937          \scratchdimen\noflines\lineheight
938          \advance\scratchdimen \topskip
939          \setbox0\hbox
940            {\lower\scratchdimen\vbox{\placenoteinserts}}%
941          \ht0=\openstrutheight % \strutht
942          \dp0=\openstrutdepth  % \strutdp
943          \scratchdimen\ht\lastcolumnbox
944          \global\setbox\lastcolumnbox\vbox to \scratchdimen
945            {\box\lastcolumnbox
946             \vskip-\scratchdimen
947             \restoretextcolor{\box0}}%
948        \fi
949        \egroup
950      \fi
951    \fi}
953 %D Here comes the routine that splits the long box in columns.
954 %D The macro \type{\flushcolumnfloats} can be used to flush
955 %D either floats that were present before the multi||column
956 %D mode was entered, or floats that migrate to next columns.
957 %D Flushing floats is a delicate process.
959 \def\continuousmulticolumnsout
960   {\bgroup
961    \forgetall
962    \setmulticolumnsout
963    \dontshowcomposition
964 %    \dimen0=\columntextheight
965 %    \advance\dimen0 -\precolumnboxheight
966 %    \settotalinsertionheight
967 %    \advance\dimen0 -\totalinsertionheight
968 %    \ifgridsnapping % evt altijd, nog testen
969 %      \getnoflines{\dimen0}
970 %      \dimen0=\noflines\openlineheight
971 %    \fi
972    \getmulticolumnlines
973    \dimen0=\nofcolumnlines\openlineheight
974    \dohandleallcolumns
975      {\splitcurrentcolumn from \box\normalpagebox to \dimen0}%
976    \setbox\restofpage\vbox{\unvbox\normalpagebox}%
977    \ifinheritcolumns
978      \ifr@ggedbottom % vreemd
979        \dohandleallcolumns
980          {\global\setbox\currentcolumnbox\vbox to \ht\firstcolumnbox
981             {\dimen0\dp\currentcolumnbox
982              \unvbox\currentcolumnbox
983              \vskip-\dimen0
984              \vskip\openstrutdepth % \strutdp
985              \prevdepth\openstrutdepth % \strutdp
986              \vfill}}%
987        \ifbottomnotes \else
988          \dimen0\ht\firstcolumnbox
989        \fi
990      \fi
991      \ifn@rmalbottom
992        \advance\dimen0 \maxdepth
993        \dohandleallcolumns
994          {\global\setbox\currentcolumnbox\vbox to \dimen0
995             {\unvbox\currentcolumnbox}}%
996      \fi
997      \ifb@selinebottom
998        % the columns are on top of the baseline
999      \fi
1000    \else
1001      \dohandleallcolumns
1002        {\global\setbox\currentcolumnbox\vbox to \dimen0
1003           {\ifstretchcolumns
1004              \unvbox\currentcolumnbox
1005            \else
1006              \unvbox\currentcolumnbox % wel of niet \unvbox ?
1007              \vfill
1008            \fi}}%
1009      \dohandleallcolumns
1010        {\ht\currentcolumnbox\dimen0}% redundant
1011    \fi
1012    \setbox\precolumnbox\vbox{\flushcolumnedpage\zerocount}%
1013    \finaloutput\box\precolumnbox
1014    \sethsize
1015    \setvsize
1016    \flushcolumnfloats
1017    \unvbox\restofpage
1018    % \penalty\outputpenalty % gaat gruwelijk mis in opsommingen
1019    \egroup}
1021 %D And this is the balancing stuff. Again, part of the routine
1022 %D is dedicated to handling ragged bottoms, but here we also
1023 %D see some handling concerning the stretching of columns.
1024 %D We set \type{\widowpenalty} at~0, which enables us to
1025 %D balance columns with few lines. The use of \type{\box2} and
1026 %D \type{\box4} garantees a more robust check when skips are
1027 %D used.
1029 \def\multicolumnsbalancemax{250} % 100 is too small when floats are involved
1031 \def\balancedmulticolumnsout
1032   {\bgroup
1033    \setmulticolumnsout
1034    \dontshowcomposition
1035    \widowpenalty\zerocount
1036    \setbox0\vbox{\unvbox\normalpagebox}%
1037 \ifdim\ht0>\openlineheight % at least one line
1038   \ifnum\minbalancetoplines<2 % balance anyway
1039     \donetrue
1040   \else % check criterium to available lines
1041     \getnoflines{\ht0}%
1042     \divide\noflines \nofcolumns \relax
1043     \ifnum\noflines<\minbalancetoplines \relax
1044       \dimen0\ht0
1045       \advance\dimen0 \ht\firsttopcolumnbox
1046       \advance\dimen0 \openlineheight \relax % let's play safe
1047       \ifdim\dimen0>\columntextheight % column exceeding text height
1048         \donetrue
1049       \else % it seems to fit
1050         \donefalse
1051       \fi
1052     \else % balance indeed
1053       \donetrue
1054     \fi
1055   \fi
1056 \else % balancing does not make sense
1057   \donefalse
1059 \ifdone % start balancing
1060   %\ifdim\ht0>\openlineheight
1061      \dimen0\ht0
1062      \advance\dimen0 \topskip
1063      \advance\dimen0 -\baselineskip
1064      \dohandleallcolumns
1065        {\advance\dimen0 \ht\currenttopcolumnbox}%
1066      \divide\dimen0 \nofcolumns
1067      \vbadness\!!tenthousand\relax
1068      \count255=\zerocount
1069      \bgroup
1070      \ifgridsnapping
1071        \dimen2\lineheight
1072      \else
1073        \dimen2=\onepoint % RUBISH
1074        \dimen2=\spacingfactor\dimen2
1075      \fi
1076      \doloop
1077        {\advance\count255 \plusone
1078         \global\setbox\restofpage\copy0\relax
1079         \splitfirstcolumn from \box\restofpage to \dimen0
1080         \dohandlemidcolumns
1081           {\splitcurrentcolumn from \box\restofpage to \dimen0}%
1082         \splitlastcolumn from \box\restofpage to \dimen0
1083         \setbox2\vbox{\unvcopy\firstcolumnbox}%
1084         \dimen4\zeropoint
1085         \dohandleallcolumns
1086           {\setbox4\vbox
1087              {\unvcopy\currentcolumnbox
1088              %rather new, test this on pdftex-z.tex
1089               \unpenalty\unskip\unpenalty\unskip}% maybe better in main splitter
1090           %\writestatus{balance}{\the\currentcolumnbox: \the\ht4}%
1091 %            \dimen6\ht4 \ifdim\dimen6>\dimen4 \dimen4=\dimen6 \fi}%
1092            \ifdim\ht4>\dimen4 \dimen4=\ht4 \fi}%
1093         \advance\dimen4 -.0005pt % get rid of accurracy problem, pretty new
1094         \ifnum\count255>\multicolumnsbalancemax\relax
1095           \exitloop
1096         \else\ifdim\dimen4>\ht2
1097           \advance\dimen0 \dimen2\relax
1098         \else
1099           \exitloop
1100         \fi\fi}%
1101      \dohandleallcolumns
1102        {\global\setbox\currentcolumnbox\vbox{\unvcopy\currentcolumnbox}}% NIEUW
1103      \ifnum\count255>\multicolumnsbalancemax\relax
1104        \showmessage\m!columns7\empty
1105      \else
1106        \showmessage\m!columns8{\the\count255\space}%
1107      \fi
1108      \egroup
1109      \ifinheritcolumns
1110        % We cannot assume that the first column is the tallest, if
1111        % only because we may have an aborted balance (one line in the
1112        % first column and a graphic in the second one).
1113        %
1114        % \dimen0\ht\firstcolumnbox
1115        % \dimen2\ht\firstcolumnbox
1116        %
1117        \dimen0=\zeropoint
1118        \dohandleallcolumns
1119          {\ifdim\ht\currentcolumnbox>\dimen0
1120             \dimen0=\ht\currentcolumnbox
1121           \fi}%
1122        \dimen2\dimen0
1123        % so far
1124        \advance\dimen2 -\openlineheight
1125        \dohandleallcolumns
1126          {\dimen4\ht\currentcolumnbox
1127           \dimen6=10\openlineheight % funny value
1128           \global\setbox\currentcolumnbox\vbox to \dimen0
1129             {\unvbox\currentcolumnbox
1130              \ifdim\dimen4>\dimen6
1131                \ifdim\dimen4<\dimen0
1132                  \ifdim\dimen4>\dimen2
1133                    \vskip\zeropoint  % !!
1134                  \else
1135                    \vskip\openlineheight
1136                    \vfill
1137                  \fi
1138                \else
1139                  \vskip\zeropoint
1140                \fi
1141              \else
1142                \vskip\openlineheight
1143                \vfill
1144              \fi}}%
1145      \else
1146        \bgroup
1147        \ifstretchcolumns
1148          \dimen0\ht\firstcolumnbox
1149          \dimen2=\bottomtolerance\ht\firstcolumnbox
1150          \setbox0\vbox{\unvcopy\lastcolumnbox}%
1151          \advance\dimen0 -\ht0\relax
1152          \advance\dimen0 -\dp0\relax
1153          \ifdim\dimen0>\openlineheight\relax
1154            \ifdim\dimen0>\dimen2\relax
1155              % \stretchcolumnsfalse % beter goed slecht dan slecht goed
1156              \showmessage\m!columns9\empty
1157            \fi
1158          \fi
1159        \fi
1160        \dohandleallcolumns
1161          {\global\setbox\currentcolumnbox\vbox to \ht\firstcolumnbox
1162             {\ifstretchcolumns
1163                \unvbox\currentcolumnbox
1164              \else
1165                \box\currentcolumnbox
1166                \vfill
1167              \fi}}%
1168        \egroup
1169      \fi
1170    \else
1171      % a one liner is not properly handled here, so best rewrite the text then
1172      \showmessage\m!columns{10}\empty
1173      \global\setbox\firstcolumnbox\vbox{\unvbox0}%
1174    \fi
1175    \global\output{\balancingerror}%
1176    \b@selinebottomtrue % forces depth in separation rule
1177    \flushcolumnedpage\plusone
1178    \multicolumnseject
1179    \egroup}
1181 \def\multicolumnseject
1182   {%\ifdim\pagetotal>\textheight
1183    %  \eject % new, but wrong as fails on mixed-001.tex (wrong pagetotal at this point)
1184    %\else
1185      \allowbreak
1186    }%\fi}
1188 %D The multicolumn mechanism is incorporated in a \CONTEXT\
1189 %D interface, which acts like:
1191 %D \starttyping
1192 %D \startcolumns[n=4,balance=no]
1193 %D   some text
1194 %D \stopcolumns
1195 %D \stoptyping
1197 %D The setup is optional. The default behaviour of columns
1198 %D can be set up with:
1200 %D \starttyping
1201 %D \setupcolumns
1202 %D   [n=2,
1203 %D    balance=yes]
1204 %D \stoptyping
1206 %D In this case, stretching is according to the way it's
1207 %D done outside columns (\type{\inheritcolumnstrue}). Also
1208 %D we can setup the \type{tolerance} within a column, the
1209 %D \type{distance} between columns and the fixed
1210 %D \type{height} of a column.
1212 %D Multi||column output: the float routines
1214 %D Here come the routines that handle the placement of column
1215 %D floats. Floats that are to big migrate to the next
1216 %D column. Floats that are too wide, migrate to the top of the
1217 %D next page, where they span as much columns as needed.
1218 %D Floats that are left over from outside the multi||column
1219 %D mode are flushed first. In macro \type{\finaloutput} the
1220 %D topfloats that are left from previous text should be set.
1222 %D When there are some floats in the queue, we inhibit the
1223 %D flushing of floats on top of columns. The number of
1224 %D waiting floats is preswent in \type{\savednoftopfloats} and
1225 %D is saved. As long as there are floats waiting, the topfloats
1226 %D are places as if we are outside multi||column mode. This is
1227 %D neccessary for e.g. multicolumn lists.
1229 %D When all those floats are flushed, we switch to the local
1230 %D flushing routine.
1232 \def\setcolumnfloats
1233   {\xdef\globalsavednoffloats{\the\savednoffloats}%
1234    \ifnum\globalsavednoffloats>\zerocount
1235      \setglobalcolumnfloats
1236    \else
1237      \setlocalcolumnfloats
1238    \fi}
1240 \def\setglobalcolumnfloats
1241   {\everypar\emptytoks
1242    \let\flushcolumnfloat\relax
1243   %\let\doroomfloat\relax
1244    \let\docheckiffloatfits\relax
1245    \let\flushcolumnfloats\noflushcolumnfloats}
1247 \def\setlocalcolumnfloats
1248   {\everypar{\flushnotes\flushcolumnfloat\flushmargincontents\checkindentation}%
1249    \let\flushcolumnfloat\doflushcolumnfloat
1250   %\let\doroomfloat\docolumnroomfloat
1251    \let\docheckiffloatfits\docolumnroomfloat
1252    \let\flushcolumnfloats\doflushcolumnfloats
1253    \let\doflushfloats\doflushcolumnfloats % new
1254    \let\dosetbothinserts\relax
1255    \let\dotopinsertions\relax}
1257 \def\noflushcolumnfloats
1258   {\bgroup
1259    \xdef\localsavednoffloats{\the\savednoffloats}%
1260    \global\savednoffloats\globalsavednoffloats
1261    \dotopinsertions
1262    \xdef\globalsavenoffloats{\the\savednoffloats}%
1263    \ifnum\globalsavednoffloats=\zerocount
1264      \setlocalcolumnfloats
1265    \fi
1266    \global\savednoffloats\localsavednoffloats
1267    \egroup}
1269 %D We need to calculate the amount of free space in a columns.
1270 %D When there is not enough room, we migrate the float to the
1271 %D next column. These macro's are alternatives (and
1272 %D look||alikes) of \type{\doroomfloat}. When a float is to
1273 %D wide, for one column, it is moved to the top of the next
1274 %D page. Of course such moved floats have to be taken into
1275 %D account when we calculate the available space. It's a pitty
1276 %D that such things are no integral part of \TEX.
1278 \def\getcolumnstatus\column#1\total#2\goal#3\\%
1279   {\dimen0=\ifdim\pagegoal<\maxdimen \pagetotal \else \zeropoint \fi
1280    \dimen2=\zeropoint
1281    \count255=\zerocount
1282    \dimen8=\columntextheight
1283    \advance\dimen8 -\precolumnboxheight
1284    \def\dogetcolumnstatus
1285      {\advance\count255 \plusone
1286       \advance\dimen2 \ht\currenttopcolumnbox
1287       \advance\dimen2 \dp\currenttopcolumnbox
1288       \dimen4\dimen2
1289       \advance\dimen4 \dimen0
1290       \dimen6=\count255\dimen8
1291       \ifdim\dimen4>\dimen6
1292       \else
1293         \let\dogetcolumnstatus\relax
1294       \fi}%
1295    \dohandleallcolumns{\dogetcolumnstatus}%
1296    \ifnum\count255=0 \count255=1 \fi
1297    #1=\count255
1298    #2=\dimen4
1299    #3=\dimen6 }
1301 \def\getinsertionheight
1302   {\ifdim\pagegoal<\maxdimen
1303      \bgroup
1304      \dimen0=\columntextheight
1305      \advance\dimen0 -\pagegoal
1306      \xdef\insertionheight{\the\dimen0}%
1307      \egroup
1308    \else
1309      \global\let\insertionheight\zeropoint
1310    \fi}
1312 \def\docolumnroomfloat
1313   {\ifpostponecolumnfloats
1314      \global\roomforfloatfalse
1315    \else\ifnofloatpermitted
1316      \global\roomforfloatfalse
1317    \else
1318      \bgroup
1319      \getcolumnstatus\column\count255\total\dimen0\goal\dimen2\\%
1320      \advance\dimen0 2\openlineheight % nog nodig ?
1321     %\ifnum\count255=\nofcolumns
1322     %  \getinsertionheight
1323     % %\message{\insertionheight}\wait
1324     %  \advance\dimen0 \insertionheight
1325     %\fi
1326      \setbox\scratchbox\vbox % tricky met objecten ?
1327        {\blank[\@@bkspacebefore]
1328         \snaptogrid\vbox{\copy\floatbox}}%
1329      \advance\dimen0 \ht\scratchbox
1330      \advance\dimen0 .5\lineheight % needed because goal a bit higher
1331     %\message{column: \the\count255; total: \the\dimen0; goal: \the\dimen2}\wait
1332      \ifdim\dimen0>\dimen2
1333        \global\roomforfloatfalse
1334      \else
1335        \global\roomforfloattrue
1336      \fi
1337      \ifdim\wd\floatbox>\hsize
1338        \showmessage\m!columns{11}\empty
1339        \global\roomforfloatfalse
1340      \fi
1341      \egroup
1342    \fi\fi}
1344 %D Flushing one float is done as soon as possible, i.e.
1345 %D \type{\everypar}. This means that (at the moment)
1346 %D sidefloats are not supported (overulled)!
1348 \newif\ifflushingcolumnfloats \flushingcolumnfloatstrue
1350 \def\doflushcolumnfloat
1351   {\ifpostponecolumnfloats\else\ifflushingcolumnfloats\ifprocessingverbatim\else\ifsomefloatwaiting
1352      \bgroup
1353      \forgetall
1354      \let\doflushcolumnfloat\relax
1355      \getcolumnstatus\column\mofcolumns\total\dimen0\goal\dimen2\\%
1356      \ifdim\dimen0>\zeropoint
1357        \dogetfloat
1358        \ifdim\wd\floatbox>\hsize
1359          \doresavefloat
1360        \else
1361         %\setbox2=\vbox
1362         %  {\blank[\@@bkspacebefore]
1363         %   \snaptogrid\vbox{\copy\floatbox}%
1364         %   \blank[\@@bkspaceafter]
1365          \setbox2=\vbox
1366            {\blank[\@@bkspacebefore]
1367             \snaptogrid\vbox{\copy\floatbox}}%
1368          \advance\dimen0 \ht2
1369          \ifdim\dimen0>\dimen2
1370            \ifnum\mofcolumns<\nofcolumns
1371              \advance\mofcolumns \plusone
1372 %% bug %%    \edef\currenttopcolumnbox{\getvalue{\@@topcol\the\count255}}%
1373              \ifdim\ht\currenttopcolumnbox=\zeropoint
1374                \global\setbox\currenttopcolumnbox\vbox
1375                  {\snaptogrid\vbox{\copy\floatbox}
1376                   \whitespace % nodig ?
1377                   \blank[\@@bkspaceafter]}%
1378                \dimen4=\ht\currenttopcolumnbox
1379                \advance\dimen4 \dp\currenttopcolumnbox
1380                \global\advance\vsize -\dimen4
1381                \advance\dimen4 -\pagegoal
1382                \global\pagegoal-\dimen4
1383                \showmessage\m!columns{12}a%
1384              \else
1385                \showmessage\m!columns{12}b%
1386                \doresavefloat
1387              \fi
1388            \else
1389              \showmessage\m!columns{12}c%
1390              \doresavefloat
1391            \fi
1392          \else
1393            \ifhmode{\setbox0\lastbox}\fi% waar is die er in geslopen
1394            \par
1395            \ifdim\prevdepth<\zeropoint \else % anders bovenaan kolom witruimte
1396              \nobreak
1397              \blank[\@@bkspacebefore]
1398              \nobreak
1399            \fi
1400            \flushfloatbox
1401            \blank[\@@bkspaceafter]
1402          \fi
1403        \fi
1404      \fi
1405      \egroup
1406    \fi\fi\fi\fi}
1408 %D This one looks complicated. Upto \type{\nofcolumns} floats
1409 %D are placed, taking the width of a float into account. This
1410 %D routine can be improved on different ways:
1412 %D \startitemize[intro,packed]
1413 %D \item taking into account some imaginary baseline, just to
1414 %D      get the captions in line
1415 %D \item multipass flushing until as many floats are displaced
1416 %D      as possible
1417 %D \stopitemize
1419 %D When handling lots of (small) floats spacing can get worse
1420 %D because of lining out the columns.
1422 \def\doflushcolumnfloats
1423   {\ifpostponecolumnfloats\else
1424      \bgroup
1425      \forgetall
1426      \ifsomefloatwaiting
1427        \dimen8\zeropoint
1428        \dimen4\zeropoint
1429        \count0\zerocount   % count0 can be used local
1430        \count2\nofcolumns  % count2 can be used local
1431        \dohandleallcolumns
1432          {\ifnum\count0>\zerocount % the wide one's reserved space
1433             \global\setbox\currenttopcolumnbox\vbox
1434               {\snaptogrid\vbox
1435                  {\copy\currenttopcolumnbox
1436                   \hbox{\vphantom{\copy\floatbox}}}
1437                   \whitespace % nodig ?
1438                   \blank[\@@bkspaceafter]}%
1439           \else
1440             \dogetfloat
1441             \ifdim\wd\floatbox>\finalcolumntextwidth % better somewhere else too
1442               \global\setbox\floatbox\hbox to \finalcolumntextwidth{\hss\box\floatbox\hss}%
1443             \fi % otherwise the graphic may disappear
1444             \ifdim\wd\floatbox>\hsize
1445               \dimen0\wd\floatbox
1446               \advance\dimen0 \intercolumnwidth
1447               \dimen2\hsize
1448               \advance\dimen2 \intercolumnwidth
1449               \advance\dimen0 .5pt % hm, why 1
1450               \advance\dimen2 .5pt % hm, why 2
1451               \divide\dimen0 \dimen2
1452               \count0\dimen0
1453               \advance\count0 \plusone
1454               \ifnum\count0>\count2
1455                 \doresavefloat
1456                 \count0\zerocount
1457               \else
1458                 \dimen0=\count0\hsize
1459                 \advance\dimen0 \count0\intercolumnwidth
1460                 \advance\dimen0 -\intercolumnwidth
1461                 \global\setbox\floatbox\hbox to \dimen0
1462                  %{\hss\hbox{\copy\floatbox}\hss}%
1463                   {\processaction[\@@bklocation] % how easy to forget
1464                      [  \v!left=>\copy\floatbox\hss,
1465                        \v!right=>\hss\copy\floatbox,
1466                       \s!default=>\hss\copy\floatbox\hss,
1467                       \s!unknown=>\hss\copy\floatbox\hss]}%
1468               \fi
1469               \showmessage\m!columns{13}\empty
1470             \else
1471             %  \showmessage\m!columns{13}\empty
1472             \fi
1473             \ifdim\ht\floatbox>\zeropoint\relax
1474               \global\setbox\currenttopcolumnbox\vbox
1475                 {\snaptogrid\vbox
1476                    {\copy\currenttopcolumnbox
1477                     \copy\floatbox}
1478                  \whitespace % nodig ?
1479                  \blank[\@@bkspaceafter]}%
1480             \fi
1481             \dimen6\ht\currenttopcolumnbox
1482             \advance\dimen6 \dp\currenttopcolumnbox
1483           \fi
1484           \ifdim\dimen4<\ht\currenttopcolumnbox
1485             \dimen4\ht\currenttopcolumnbox
1486           \fi
1487           \advance\dimen8 \dimen6
1488           \advance\count2 \minusone
1489           \advance\count0 \minusone }%
1490        \setvsize
1491        \global\advance\vsize -\dimen8
1492        \global\pagegoal\vsize
1493      \else
1494        %\doflushfloats % does not snap!
1495      \fi
1496      \egroup
1497    \fi}
1499 %D The next macro can be used to flush floats in the current
1500 %D stream. No width checking is (yet) done.
1502 \def\insertcolumnfloats
1503   {\doloop
1504      {\ifsomefloatwaiting
1505         \bgroup
1506         \forgetall
1507         % no check for width
1508         \dogetfloat
1509         \blank[\@@bkspacebefore]
1510         \snaptogrid\vbox{\copy\floatbox}
1511         \blank[\@@bkspaceafter]
1512         \egroup
1513       \else
1514         \exitloop
1515       \fi}}
1517 %D This were the multi||column routines. They can and need to
1518 %D be improved but at the moment their behaviour is acceptable.
1520 %D One inprovement can be to normalize the height of floats
1521 %D to $n\times$\type{\lineheight} with a macro like:
1523 %D \starttyping
1524 %D \normalizevbox{...}
1525 %D \stoptyping
1527 % border case, should fit on one page
1529 % \startcolumns
1531 % 1 \input tufte  \par \plaatsfiguur{}{\omlijnd[breedte=\hsize,hoogte=3cm]{1}}
1532 % 2 \input tufte  \par \plaatsfiguur{}{\omlijnd[breedte=\hsize,hoogte=3cm]{2}}
1533 % 3 \input tufte  \par \plaatsfiguur{}{\omlijnd[breedte=\hsize,hoogte=3cm]{3}}
1535 % \stopcolumns
1537 \def\setupcolumns
1538   {\dosingleempty\dosetupcolumns}
1540 \def\dosetupcolumns[#1]%
1541   {\getparameters[\??kl][#1]%
1542    \nofcolumns\@@kln\relax
1543    \processaction
1544      [\@@klrule]
1545      [     \v!on=>\let\betweencolumns\linebetweencolumns,
1546           \v!off=>\let\betweencolumns\spacebetweencolumns,
1547       \s!default=>\let\betweencolumns\spacebetweencolumns,
1548       \s!unknown=>\let\betweencolumns\@@klrule]}
1550 \def\linebetweencolumns
1551   {\bgroup
1552    \starttextproperties
1553    \ifdim\@@kldistance>\zeropoint
1554      \dimen0=\@@kldistance
1555    \else
1556      \dimen0=\linewidth
1557    \fi
1558    \advance\dimen0 -\linewidth
1559    \hskip.5\dimen0
1560    \vrule
1561      \!!width\linewidth
1562      \ifb@selinebottom\!!depth\strutdepth\fi
1563    \hskip.5\dimen0\relax
1564    \stoptextproperties
1565    \egroup}
1567 \def\spacebetweencolumns
1568   {\hskip\@@kldistance}
1570 \presetlocalframed[\??kl]
1572 \def\backgroundfinishcolumnbox
1573   {\doifinsetelse\@@kloffset{\v!none,\v!overlay}
1574      {\let\@@kloffset\!!zeropoint}
1575      {\scratchdimen\@@kloffset
1576       \advance\scratchdimen -\@@klrulethickness
1577       \edef\@@kloffset{\the\scratchdimen}}%
1578    \localframed
1579      [\??kl]
1580      [\c!strut=\v!no,
1581       \c!width=\v!fit,
1582       \c!height=\v!fit,
1583       \c!align=]}
1585 \let\restorecolumnsettings\relax
1587 \definecomplexorsimpleempty\startcolumns
1589 \def\complexstartcolumns[#1]% %% \startcolumns
1590   {\bgroup
1591    \let\stopcolumns\egroup
1592    \ifinsidecolumns
1593    \else
1594      \setupcolumns[#1]%
1595      \ifnum\@@kln>1\relax
1596        \whitespace
1597        \begingroup
1598        \doif\@@kloption\v!background
1599          {\let\finishcolumnbox\backgroundfinishcolumnbox
1600           \let\columntextoffset\@@kloffset}%
1601        \ifx\@@klcommand\empty\else
1602          \let\postprocesscolumnline\@@klcommand
1603        \fi
1604        \doifelsenothing\@@klheight
1605          \heightencolumnsfalse
1606          \heightencolumnstrue
1607        \doifelse\@@kldirection\v!right
1608          \reversecolumnsfalse
1609          \reversecolumnstrue
1610        \doifelse\@@klbalance\v!yes
1611          \balancecolumnstrue
1612          \balancecolumnsfalse
1613 \installalign\v!yes {\stretchcolumnstrue \inheritcolumnsfalse}% todo: new key
1614 \installalign\v!no  {\stretchcolumnsfalse\inheritcolumnsfalse}% todo: new key
1615 \installalign\v!text{\stretchcolumnsfalse\inheritcolumnstrue }%
1616 \stretchcolumnsfalse
1617 \inheritcolumnstrue
1618 \doifsomething\@@klalign{\expanded{\setupalign[\@@klalign]}}%
1619 %        \processaction
1620 %          [\@@klalign]
1621 %          [   \v!yes=>\stretchcolumnstrue
1622 %                     \inheritcolumnsfalse,
1623 %             \v!no=>\stretchcolumnsfalse
1624 %                     \inheritcolumnsfalse,
1625 %           \v!text=>\stretchcolumnsfalse
1626 %                     \inheritcolumnstrue]%
1627        \nofcolumns=\@@kln
1628        %
1629        % probably more is needed, and how about nesting save's
1630        %
1631        \savecurrentblank
1632        \savecurrentwhitespace
1633        \def\restorecolumnsettings
1634          {\boxmaxdepth\maxdimen % done elsewhere
1635           \restorecurrentblank
1636           \restorecurrentwhitespace}%
1637        %
1638        \edef\fixedcolumnheight{\@@klheight}%
1639        \edef\minbalancetoplines{\@@klntop}%
1640        \setuptolerance[\@@kltolerance]%     %% \startcolumns
1641        \setupblank[\@@klblank]%
1642        \ifdim\ctxparskip>\zeropoint\relax
1643          \setupwhitespace[\@@klblank]%
1644        \fi
1645        \def\stopcolumns
1646          {\endmulticolumns
1647           \global\insidecolumnsfalse
1648           \endgroup
1649           \egroup}%
1650        \global\insidecolumnstrue
1651        \beginmulticolumns
1652      \fi
1653    \fi}
1655 \installcolumnbreakhandler {MUL} \v!preference
1656   {\goodbreak}
1658 \installcolumnbreakhandler {MUL} \v!yes
1659   {\par                                             % todo: since
1660    {\testrulewidth\zeropoint\ruledvskip\textheight} % we misuse a
1661    \penalty-200                                     % side effect
1662    \vskip-\textheight
1663    }% bugged : \prevdepth-\thousandpoint} % signals top of column to \blank
1665 %D New: only at start of columns; may change ! Rather
1666 %D interwoven and therefore to be integrated when the multi
1667 %D column modules are merged. (moved from cont-new.tex)
1669 \def\setupcolumnspan[#1]%
1670   {\getparameters[\??ks][#1]}
1672 \presetlocalframed
1673   [\??ks]
1675 \setupcolumnspan
1676   [\c!n=2,
1677    \c!offset=\v!overlay,
1678    \c!frame=\v!off]
1680 \newbox\columnspanbox \let\postprocesscolumnspanbox\gobbleoneargument
1682 \def\dostartcolumnspan[#1]%
1683   {\bgroup
1684    \setupcolumnspan[#1]%
1685    \forgetall
1686    \ifinsidecolumns
1687      \advance\hsize \intercolumnwidth
1688      \hsize\@@ksn\hsize
1689      \advance\hsize -\intercolumnwidth
1690    \fi
1691    \dowithnextbox
1692      {\setbox\columnspanbox\flushnextbox
1693       \ifinsidecolumns\wd\columnspanbox\hsize\fi
1694       \postprocesscolumnspanbox\columnspanbox
1695       \scratchdimen\ht\columnspanbox
1696       \setbox\columnspanbox\hbox % depth to be checked, probably option!
1697         {\localframed[\??ks][\c!offset=\v!overlay]{\box\columnspanbox}}%
1698       \ht\columnspanbox\scratchdimen
1699       \dp\columnspanbox\strutdp
1700       \wd\columnspanbox\hsize
1701       \ifinsidecolumns
1702         \ifnum\@@ksn>1
1703           \setvsize
1704           \dohandleallcolumns
1705             {\ifnum\currentcolumn>\@@ksn\else
1706                \global\setbox\currenttopcolumnbox=\vbox
1707                  {\ifnum\currentcolumn=1
1708                     \snaptogrid\vbox{\copy\columnspanbox}
1709                   \else
1710                     \snaptogrid\vbox{\vphantom{\copy\columnspanbox}}
1711                   \fi}%
1712                \wd\currenttopcolumnbox\hsize
1713                \global\advance\vsize -\ht\currenttopcolumnbox
1714              \fi}
1715           \global\pagegoal\vsize
1716         \else
1717           \snaptogrid\vbox{\box\columnspanbox}
1718         \fi
1719       \else
1720         \snaptogrid\vbox{\box\columnspanbox}
1721       \fi
1722       \endgraf
1723       \ifvmode\prevdepth\strutdp\fi
1724       \egroup}
1725      \vbox\bgroup
1726       %\topskipcorrection % becomes an option !
1727        \EveryPar{\begstrut\EveryPar{}}} % also !
1729 \def\startcolumnspan
1730   {\dosingleempty\dostartcolumnspan}
1732 \def\stopcolumnspan
1733   {\egroup}
1735 \setupcolumns
1736   [\c!n=2,
1737    \c!ntop=1,
1738    \c!command=,
1739    \c!direction=\v!right,
1740    \c!rule=\v!off,
1741    \c!tolerance=\v!tolerant,
1742    \c!distance=1.5\bodyfontsize, % influenced by switching
1743    \c!height=,
1744    \c!balance=\v!yes,
1745    \c!align=\v!text,
1746    \c!blank={\v!line,\v!fixed},
1747    \c!option=,
1748    \c!rulethickness=\linewidth,
1749    \c!offset=.5\bodyfontsize]
1751 %D Undocumented and still under development.
1753 \def\startsimplecolumns
1754   {\dosingleempty\dostartsimplecolumns}
1756 \def\dostartsimplecolumns[#1]%
1757   {\bgroup
1758    \nopenalties
1759    \getparameters[\??kl]
1760      [\c!width=\hsize,\c!distance=1.5\bodyfontsize,%
1761       \c!n=2,\c!lines=0,#1]%
1762    \let\rigidcolumnlines\@@kllines
1763    \setrigidcolumnhsize\@@klwidth\@@kldistance\@@kln
1764    \setbox\scratchbox\vbox\bgroup
1765    \forgetall} % \blank[\v!disable]
1767 \def\stopsimplecolumns
1768   {\removebottomthings
1769    \egroup
1770    \rigidcolumnbalance\scratchbox
1771    \egroup}
1773 \protect \endinput