summaryrefslogtreecommitdiff
path: root/macros/optex/base/multicolumns.opm
blob: d84aef69c6f1a853e395c79a258b20c1c7259498 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
%% This is part of the OpTeX project, see http://petr.olsak.net/optex

\_codedecl \begmulti {Balanced columns <2022-11-26>} % preloaded in format

   \_doc -----------------------------
   \`\_betweencolumns` or \`\_leftofcolumns` or \`\_rightofcolumns` include
   a material printed between columns or left of all columns or right of all
   columns respectivelly. The \^`\_betweencolumns` must include a
   stretchability or a material with exactly \^`\colsep` width. You can
   redefine these macros. For example the rule between colums can be reached
   by `\_def\_betweencolumns{\hss\vrule\hss}`.\nl
   \`\_multiskip` puts its material at the start and at the end of
   \^`\begmulti`...\^`\endmulti`.
   \_cod -----------------------------

\_def\_betweencolumns{\_hss} \_def\_leftofcolumns{} \_def\_rightofcolumns{}
\_def\_multiskip{\_medskip}   % space above and below \begmulti...\endmulti

   \_doc -----------------------------
   The code used here is documented in detail in the \"\TeX/book naruby", pages 244--246,
   free available, \url{http://petr.olsak.net/tbn.html}, but in Czech.
   Roughly speaking, macros complete all material between
   \`\begmulti``<num-columns>` and \`\endmulti`
   into one `\vbox 6`. Then the macro measures the amount of free space at the current
   page using `\pagegoal` and `\pagtotal` and does `\vsplit` of `\vbox 6` to
   columns with a height of such free space. This is done only if we have
   enough amount of material in `\vbox 6` to fill the full page by columns.
   This is repeated in a loop until we have less amount of material in `\vbox 6`.
   Then we run \`\_balancecolumns` which balances the last part of the columns.
   Each part of printed material is distributed to the main vertical list as
   `\hbox{<columns>}` and we need not do any change in the output routine.

   If you have paragraphs in \^`\begmulti`... \^`\endmulti` environment then
   you may say `\raggedright` inside this environment and you can re-assign
   `\widowpenalty` and `\clubppenalty` (they are set to 10000 in \OpTeX/).
   \_cod -----------------------------

\_newcount\_mullines

\_def\_begmulti #1 {\_par\_bgroup\_wipeepar
   \_ifnum\_lastpenalty>10000 \_vskip4.5\_baselineskip\_penalty9999 \_vskip-4.5\_baselineskip \_fi
   \_multiskip \_def\_Ncols{#1}
   \_setbox6=\_vbox\_bgroup\_bgroup \_let\_setxhsize=\_relax \_penalty-99
   %% \hsize := column width = (\hsize+\colsep) / n - \colsep
   \_setbox0=\_hbox{\_leftofcolumns\_rightofcolumns}%
   \_advance\_hsize by-\_wd0 \_advance\_hsize by\_colsep
   \_divide\_hsize by\_Ncols  \_advance\_hsize by-\_colsep
   \_mullines=0
   \_def\_par{\_ifhmode\_endgraf\_global\_advance\_mullines by\_prevgraf\_fi}%
}
\_def\_endmulti{\_vskip-\_prevdepth\_vfil
   \_ea\_egroup\_ea\_egroup\_ea\_baselineskip\_the\_baselineskip\_relax
   \_dimen0=.8\_maxdimen \_tmpnum=\_dimen0 \_divide\_tmpnum by\_baselineskip
   \_splittopskip=\_baselineskip
   \_setbox1=\_vsplit6 to0pt % initialize first \splittopskip in \box6
   %% \dimen1 := the free space on the page
   \_penalty0 % initialize \_pageoal
   \_ifdim\_pagegoal=\_maxdimen \_setcolsize\_vsize
   \_else \_setcolsize{\_dimexpr\_pagegoal-\_pagetotal}\_fi
   \_ifdim \_dimen1<2\_baselineskip
     \_vfil\_break \_setcolsize\_vsize \_fi
   \_ifnum\_mullines<\_tmpnum \_dimen0=\_ht6 \_else \_dimen0=.8\_maxdimen \_fi
   \_divide\_dimen0 by\_Ncols \_relax
   %% split the material to more pages?
   \_ifdim \_dimen0>\_dimen1 \_splitpart
   \_else \_balancecolumns \_fi  % only balancing
   \_multiskip \_egroup
}

   \_doc -----------------------------
   Splitting columns...
   \_cod -----------------------------

\_def\_makecolumns{\_bgroup % full page, destination height: \dimen1
   \_vbadness=20000 \_dimen6=\_wd6
   \_createcolumns
   \_printcolumns
   \_dimen0=\_dimen1 \_divide\_dimen0 by\_baselineskip \_multiply\_dimen0 by\_Ncols
   \_global\_advance\_mullines by-\_dimen0
   \_egroup
}
\_def\_splitpart{%
   \_makecolumns % full page
   \_vskip 0pt plus 1fil minus\_baselineskip \_break
   \_ifnum\_mullines<\_tmpnum \_dimen0=\_ht6 \_else \_dimen0=.8\_maxdimen \_fi
   \_divide\_dimen0 by\_Ncols \_relax
   \_ifx\_balancecolumns\_flushcolumns \_advance\_dimen0 by-.5\_vsize \_fi
   \_setcolsize\_vsize \_dimen2=\_dimen1
   \_advance\_dimen2 by-\_baselineskip
   %% split the material to more pages?
   \_ifvoid6 \_else
      \_ifdim \_dimen0>\_dimen2 \_ea\_ea\_ea \_splitpart
      \_else \_balancecolumns % last balancing
   \_fi \_fi
}

   \_doc -----------------------------
   Final balancing of the columns.
   \_cod -----------------------------

\_def\_balancecolumns{\_bgroup \_setbox7=\_copy6 % destination height: \dimen0
   \_ifdim\_dimen0>\_baselineskip \_else \_dimen0=\_baselineskip \_fi
   \_vbadness=20000 \_dimen6=\_wd6 \_dimen1=\_dimen0
   \_def\_tmp{\_createcolumns
      \_ifvoid6 \_else
         \_advance \_dimen1 by.2\_baselineskip
         \_setbox6=\_copy7
         \_ea \_tmp \_fi}\_tmp
   \_printcolumns
   \_egroup
}

   \_doc -----------------------------
   \`\_setcolsize``<dimen>` sets initial value `\dimen1=<size>` which is
   used as height of columns at given page.
   The correction `\splittopskip`$-$`\topskip` is done if the columns start
   at the top of the page.\nl
   \`\_createcolumns` prepares columns with given height `\dimen1` side
   by side to the `\box1`.\nl
   \`\_printcolumns` prints the columns prepared in `\box1`.
   The first `\hbox{}` moves typesetting point to the next baseline.
   Next negative skip ensures that the first line from
   splitted columns is at this position.
   \_cod -----------------------------

\_def\_setcolsize #1{\_dimen1=#1\_relax
   \_ifdim\_dimen1=\_vsize
      \_advance \_dimen1 by \_splittopskip \_advance \_dimen1 by-\_topskip \_fi
}
\_def\_createcolumns{%
   \_setbox1=\_hbox{\_leftofcolumns}\_tmpnum=0
   \_loop \_ifnum\_Ncols>\_tmpnum
      \_advance\_tmpnum by1
      \_setbox1=\_hbox{\_unhbox1
         \_ifvoid6 \_hbox to\_dimen6{\_hss}\_else \_vsplit6 to\_dimen1 \_fi
         \_ifnum\_Ncols=\_tmpnum \_rightofcolumns \_else \_betweencolumns \_fi}%
   \_repeat
}
\_def\_printcolumns{%
   \_hbox{}\_nobreak\_vskip-\_splittopskip \_nointerlineskip
   \_hbox to\_hsize{\_unhbox1}%
}
\_public \begmulti \endmulti ;

\_endcode % -------------------------------------

2022-11-26 \at least three lines in the beginning of \begmulti at the page
2022-05-05 `\_betweencolumns` etc. introduced.
2021-05-20 Colors inside \begmulti...\endmuti, bug fixed
2020-03-26 Introduced