|
1 \NeedsTeXFormat{LaTeX2e} |
|
2 \ProvidesPackage{sphinxmulticell}% |
|
3 [2017/02/23 v1.6 better span rows and columns of a table (Sphinx team)]% |
|
4 \DeclareOption*{\PackageWarning{sphinxmulticell}{Option `\CurrentOption' is unknown}}% |
|
5 \ProcessOptions\relax |
|
6 % |
|
7 % --- MULTICOLUMN --- |
|
8 % standard LaTeX's \multicolumn |
|
9 % 1. does not allow verbatim contents, |
|
10 % 2. interacts very poorly with tabulary. |
|
11 % |
|
12 % It is needed to write own macros for Sphinx: to allow code-blocks in merged |
|
13 % cells rendered by tabular/longtable, and to allow multi-column cells with |
|
14 % paragraphs to be taken into account sanely by tabulary algorithm for column |
|
15 % widths. |
|
16 % |
|
17 % This requires quite a bit of hacking. First, in Sphinx, the multi-column |
|
18 % contents will *always* be wrapped in a varwidth environment. The issue |
|
19 % becomes to pass it the correct target width. We must trick tabulary into |
|
20 % believing the multicolumn is simply separate columns, else tabulary does not |
|
21 % incorporate the contents in its algorithm. But then we must clear the |
|
22 % vertical rules... |
|
23 % |
|
24 % configuration of tabulary |
|
25 \setlength{\tymin}{3\fontcharwd\font`0 }% minimal width of "squeezed" columns |
|
26 \setlength{\tymax}{10000pt}% allow enough room for paragraphs to "compete" |
|
27 % we need access to tabulary's final computed width. \@tempdima is too volatile |
|
28 % to hope it has kept tabulary's value when \sphinxcolwidth needs it. |
|
29 \newdimen\sphinx@TY@tablewidth |
|
30 \def\tabulary{% |
|
31 \def\TY@final{\sphinx@TY@tablewidth\@tempdima\tabular}% |
|
32 \let\endTY@final\endtabular |
|
33 \TY@tabular}% |
|
34 % next hack is needed only if user has set latex_use_latex_multicolumn to True: |
|
35 % it fixes tabulary's bug with \multicolumn defined "short" in first pass. (if |
|
36 % upstream tabulary adds a \long, our extra one causes no harm) |
|
37 \def\sphinx@tempa #1\def\multicolumn#2#3#4#5#6#7#8#9\sphinx@tempa |
|
38 {\def\TY@tab{#1\long\def\multicolumn####1####2####3{\multispan####1\relax}#9}}% |
|
39 \expandafter\sphinx@tempa\TY@tab\sphinx@tempa |
|
40 % |
|
41 % TN. 1: as \omit is never executed, Sphinx multicolumn does not need to worry |
|
42 % like standard multicolumn about |l| vs l|. On the other hand it assumes |
|
43 % columns are separated by a | ... (if not it will add extraneous |
|
44 % \arrayrulewidth space for each column separation in its estimate of available |
|
45 % width). |
|
46 % |
|
47 % TN. 1b: as Sphinx multicolumn uses neither \omit nor \span, it can not |
|
48 % (easily) get rid of extra macros from >{...} or <{...} between columns. At |
|
49 % least, it has been made compatible with colortbl's \columncolor. |
|
50 % |
|
51 % TN. 2: tabulary's second pass is handled like tabular/longtable's single |
|
52 % pass, with the difference that we hacked \TY@final to set in |
|
53 % \sphinx@TY@tablewidth the final target width as computed by tabulary. This is |
|
54 % needed only to handle columns with a "horizontal" specifier: "p" type columns |
|
55 % (inclusive of tabulary's LJRC) holds the target column width in the |
|
56 % \linewidth dimension. |
|
57 % |
|
58 % TN. 3: use of \begin{sphinxmulticolumn}...\end{sphinxmulticolumn} mark-up |
|
59 % would need some hacking around the fact that groups can not span across table |
|
60 % cells (the code does inserts & tokens, see TN1b). It was decided to keep it |
|
61 % simple with \sphinxstartmulticolumn...\sphinxstopmulticolumn. |
|
62 % |
|
63 % MEMO about nesting: if sphinxmulticolumn is encountered in a nested tabular |
|
64 % inside a tabulary it will think to be at top level in the tabulary. But |
|
65 % Sphinx generates no nested tables, and if some LaTeX macro uses internally a |
|
66 % tabular this will not have a \sphinxstartmulticolumn within it! |
|
67 % |
|
68 \def\sphinxstartmulticolumn{% |
|
69 \ifx\equation$% $ tabulary's first pass |
|
70 \expandafter\sphinx@TYI@start@multicolumn |
|
71 \else % either not tabulary or tabulary's second pass |
|
72 \expandafter\sphinx@start@multicolumn |
|
73 \fi |
|
74 }% |
|
75 \def\sphinxstopmulticolumn{% |
|
76 \ifx\equation$% $ tabulary's first pass |
|
77 \expandafter\sphinx@TYI@stop@multicolumn |
|
78 \else % either not tabulary or tabulary's second pass |
|
79 \ignorespaces |
|
80 \fi |
|
81 }% |
|
82 \def\sphinx@TYI@start@multicolumn#1{% |
|
83 % use \gdef always to avoid stack space build up |
|
84 \gdef\sphinx@tempa{#1}\begingroup\setbox\z@\hbox\bgroup |
|
85 }% |
|
86 \def\sphinx@TYI@stop@multicolumn{\egroup % varwidth was used with \tymax |
|
87 \xdef\sphinx@tempb{\the\dimexpr\wd\z@/\sphinx@tempa}% per column width |
|
88 \endgroup |
|
89 \expandafter\sphinx@TYI@multispan\expandafter{\sphinx@tempa}% |
|
90 }% |
|
91 \def\sphinx@TYI@multispan #1{% |
|
92 \kern\sphinx@tempb\ignorespaces % the per column occupied width |
|
93 \ifnum#1>\@ne % repeat, taking into account subtleties of TeX's & ... |
|
94 \expandafter\sphinx@TYI@multispan@next\expandafter{\the\numexpr#1-\@ne\expandafter}% |
|
95 \fi |
|
96 }% |
|
97 \def\sphinx@TYI@multispan@next{&\relax\sphinx@TYI@multispan}% |
|
98 % |
|
99 % Now the branch handling either the second pass of tabulary or the single pass |
|
100 % of tabular/longtable. This is the delicate part where we gather the |
|
101 % dimensions from the p columns either set-up by tabulary or by user p column |
|
102 % or Sphinx \X, \Y columns. The difficulty is that to get the said width, the |
|
103 % template must be inserted (other hacks would be horribly complicated except |
|
104 % if we rewrote crucial parts of LaTeX's \@array !) and we can not do |
|
105 % \omit\span like standard \multicolumn's easy approach. Thus we must cancel |
|
106 % the \vrule separators. Also, perhaps the column specifier is of the l, c, r |
|
107 % type, then we attempt an ad hoc rescue to give varwidth a reasonable target |
|
108 % width. |
|
109 \def\sphinx@start@multicolumn#1{% |
|
110 \gdef\sphinx@multiwidth{0pt}\gdef\sphinx@tempa{#1}\sphinx@multispan{#1}% |
|
111 }% |
|
112 \def\sphinx@multispan #1{% |
|
113 \ifnum#1=\@ne\expandafter\sphinx@multispan@end |
|
114 \else\expandafter\sphinx@multispan@next |
|
115 \fi {#1}% |
|
116 }% |
|
117 \def\sphinx@multispan@next #1{% |
|
118 % trick to recognize L, C, R, J or p, m, b type columns |
|
119 \ifdim\baselineskip>\z@ |
|
120 \gdef\sphinx@tempb{\linewidth}% |
|
121 \else |
|
122 % if in an l, r, c type column, try and hope for the best |
|
123 \xdef\sphinx@tempb{\the\dimexpr(\ifx\TY@final\@undefined\linewidth\else |
|
124 \sphinx@TY@tablewidth\fi-\arrayrulewidth)/\sphinx@tempa |
|
125 -\tw@\tabcolsep-\arrayrulewidth\relax}% |
|
126 \fi |
|
127 \noindent\kern\sphinx@tempb\relax |
|
128 \xdef\sphinx@multiwidth |
|
129 {\the\dimexpr\sphinx@multiwidth+\sphinx@tempb+\tw@\tabcolsep+\arrayrulewidth}% |
|
130 % hack the \vline and the colortbl macros |
|
131 \sphinx@hack@vline\sphinx@hack@CT&\relax |
|
132 % repeat |
|
133 \expandafter\sphinx@multispan\expandafter{\the\numexpr#1-\@ne}% |
|
134 }% |
|
135 % packages like colortbl add group levels, we need to "climb back up" to be |
|
136 % able to hack the \vline and also the colortbl inserted tokens. This creates |
|
137 % empty space whether or not the columns were | separated: |
|
138 \def\sphinx@hack@vline{\ifnum\currentgrouptype=6\relax |
|
139 \kern\arrayrulewidth\arrayrulewidth\z@\else\aftergroup\sphinx@hack@vline\fi}% |
|
140 \def\sphinx@hack@CT{\ifnum\currentgrouptype=6\relax |
|
141 \let\CT@setup\sphinx@CT@setup\else\aftergroup\sphinx@hack@CT\fi}% |
|
142 % It turns out \CT@row@color is not expanded contrarily to \CT@column@color |
|
143 % during LaTeX+colortbl preamble preparation, hence it would be possible for |
|
144 % \sphinx@CT@setup to discard only the column color and choose to obey or not |
|
145 % row color and cell color. It would even be possible to propagate cell color |
|
146 % to row color for the duration of the Sphinx multicolumn... the (provisional?) |
|
147 % choice has been made to cancel the colortbl colours for the multicolumn |
|
148 % duration. |
|
149 \def\sphinx@CT@setup #1\endgroup{\endgroup}% hack to remove colour commands |
|
150 \def\sphinx@multispan@end#1{% |
|
151 % first, trace back our steps horizontally |
|
152 \noindent\kern-\dimexpr\sphinx@multiwidth\relax |
|
153 % and now we set the final computed width for the varwidth environment |
|
154 \ifdim\baselineskip>\z@ |
|
155 \xdef\sphinx@multiwidth{\the\dimexpr\sphinx@multiwidth+\linewidth}% |
|
156 \else |
|
157 \xdef\sphinx@multiwidth{\the\dimexpr\sphinx@multiwidth+ |
|
158 (\ifx\TY@final\@undefined\linewidth\else |
|
159 \sphinx@TY@tablewidth\fi-\arrayrulewidth)/\sphinx@tempa |
|
160 -\tw@\tabcolsep-\arrayrulewidth\relax}% |
|
161 \fi |
|
162 % we need to remove colour set-up also for last cell of the multi-column |
|
163 \aftergroup\sphinx@hack@CT |
|
164 }% |
|
165 \newcommand*\sphinxcolwidth[2]{% |
|
166 % this dimension will always be used for varwidth, and serves as maximum |
|
167 % width when cells are merged either via multirow or multicolumn or both, |
|
168 % as always their contents is wrapped in varwidth environment. |
|
169 \ifnum#1>\@ne % multi-column (and possibly also multi-row) |
|
170 % we wrote our own multicolumn code especially to handle that (and allow |
|
171 % verbatim contents) |
|
172 \ifx\equation$%$ |
|
173 \tymax % first pass of tabulary (cf MEMO above regarding nesting) |
|
174 \else % the \@gobble thing is for compatibility with standard \multicolumn |
|
175 \sphinx@multiwidth\@gobble{#1/#2}% |
|
176 \fi |
|
177 \else % single column multirow |
|
178 \ifx\TY@final\@undefined % not a tabulary. |
|
179 \ifdim\baselineskip>\z@ |
|
180 % in a p{..} type column, \linewidth is the target box width |
|
181 \linewidth |
|
182 \else |
|
183 % l, c, r columns. Do our best. |
|
184 \dimexpr(\linewidth-\arrayrulewidth)/#2- |
|
185 \tw@\tabcolsep-\arrayrulewidth\relax |
|
186 \fi |
|
187 \else % in tabulary |
|
188 \ifx\equation$%$% first pass |
|
189 \tymax % it is set to a big value so that paragraphs can express themselves |
|
190 \else |
|
191 % second pass. |
|
192 \ifdim\baselineskip>\z@ |
|
193 \linewidth % in a L, R, C, J column or a p, \X, \Y ... |
|
194 \else |
|
195 % we have hacked \TY@final to put in \sphinx@TY@tablewidth the table width |
|
196 \dimexpr(\sphinx@TY@tablewidth-\arrayrulewidth)/#2- |
|
197 \tw@\tabcolsep-\arrayrulewidth\relax |
|
198 \fi |
|
199 \fi |
|
200 \fi |
|
201 \fi |
|
202 }% |
|
203 % fallback default in case user has set latex_use_latex_multicolumn to True: |
|
204 % \sphinxcolwidth will use this only inside LaTeX's standard \multicolumn |
|
205 \def\sphinx@multiwidth #1#2{\dimexpr % #1 to gobble the \@gobble (!) |
|
206 (\ifx\TY@final\@undefined\linewidth\else\sphinx@TY@tablewidth\fi |
|
207 -\arrayrulewidth)*#2-\tw@\tabcolsep-\arrayrulewidth\relax}% |
|
208 % |
|
209 % --- MULTIROW --- |
|
210 % standard \multirow |
|
211 % 1. does not allow verbatim contents, |
|
212 % 2. does not allow blank lines in its argument, |
|
213 % 3. its * specifier means to typeset "horizontally" which is very |
|
214 % bad for paragraph content. 2016 version has = specifier but it |
|
215 % must be used with p type columns only, else results are bad, |
|
216 % 4. it requires manual intervention if the contents is too long to fit |
|
217 % in the asked-for number of rows. |
|
218 % 5. colour panels (either from \rowcolor or \columncolor) will hide |
|
219 % the bottom part of multirow text, hence manual tuning is needed |
|
220 % to put the multirow insertion at the _bottom_. |
|
221 % |
|
222 % The Sphinx solution consists in always having contents wrapped |
|
223 % in a varwidth environment so that it makes sense to estimate how many |
|
224 % lines it will occupy, and then ensure by insertion of suitable struts |
|
225 % that the table rows have the needed height. The needed mark-up is done |
|
226 % by LaTeX writer, which has its own id for the merged cells. |
|
227 % |
|
228 % The colour issue is solved by clearing colour panels in all cells, |
|
229 % whether or not the multirow is single-column or multi-column. |
|
230 % |
|
231 % In passing we obtain baseline alignements across rows (only if |
|
232 % \arraylinestretch is 1, as LaTeX's does not obey \arraylinestretch in "p" |
|
233 % multi-line contents, only first and last line...) |
|
234 % |
|
235 % TODO: examine the situation with \arraylinestretch > 1. The \extrarowheight |
|
236 % is hopeless for multirow anyhow, it makes baseline alignment strictly |
|
237 % impossible. |
|
238 \newcommand\sphinxmultirow[2]{\begingroup |
|
239 % #1 = nb of spanned rows, #2 = Sphinx id of "cell", #3 = contents |
|
240 % but let's fetch #3 in a way allowing verbatim contents ! |
|
241 \def\sphinx@nbofrows{#1}\def\sphinx@cellid{#2}% |
|
242 \afterassignment\sphinx@multirow\let\next= |
|
243 }% |
|
244 \def\sphinx@multirow {% |
|
245 \setbox\z@\hbox\bgroup\aftergroup\sphinx@@multirow\strut |
|
246 }% |
|
247 \def\sphinx@@multirow {% |
|
248 % The contents, which is a varwidth environment, has been captured in |
|
249 % \box0 (a \hbox). |
|
250 % We have with \sphinx@cellid an assigned unique id. The goal is to give |
|
251 % about the same height to all the involved rows. |
|
252 % For this Sphinx will insert a \sphinxtablestrut{cell_id} mark-up |
|
253 % in LaTeX file and the expansion of the latter will do the suitable thing. |
|
254 \dimen@\dp\z@ |
|
255 \dimen\tw@\ht\@arstrutbox |
|
256 \advance\dimen@\dimen\tw@ |
|
257 \advance\dimen\tw@\dp\@arstrutbox |
|
258 \count@=\dimen@ % type conversion dim -> int |
|
259 \count\tw@=\dimen\tw@ |
|
260 \divide\count@\count\tw@ % TeX division truncates |
|
261 \advance\dimen@-\count@\dimen\tw@ |
|
262 % 1300sp is about 0.02pt. For comparison a rule default width is 0.4pt. |
|
263 % (note that if \count@ holds 0, surely \dimen@>1300sp) |
|
264 \ifdim\dimen@>1300sp \advance\count@\@ne \fi |
|
265 % now \count@ holds the count L of needed "lines" |
|
266 % and \sphinx@nbofrows holds the number N of rows |
|
267 % we have L >= 1 and N >= 1 |
|
268 % if L is a multiple of N, ... clear what to do ! |
|
269 % else write L = qN + r, 1 <= r < N and we will |
|
270 % arrange for each row to have enough space for: |
|
271 % q+1 "lines" in each of the first r rows |
|
272 % q "lines" in each of the (N-r) bottom rows |
|
273 % for a total of (q+1) * r + q * (N-r) = q * N + r = L |
|
274 % It is possible that q == 0. |
|
275 \count\tw@\count@ |
|
276 % the TeX division truncates |
|
277 \divide\count\tw@\sphinx@nbofrows\relax |
|
278 \count4\count\tw@ % q |
|
279 \multiply\count\tw@\sphinx@nbofrows\relax |
|
280 \advance\count@-\count\tw@ % r |
|
281 \expandafter\xdef\csname sphinx@tablestrut_\sphinx@cellid\endcsname |
|
282 {\noexpand\sphinx@tablestrut{\the\count4}{\the\count@}{\sphinx@cellid}}% |
|
283 \dp\z@\z@ |
|
284 % this will use the real height if it is >\ht\@arstrutbox |
|
285 \sphinxtablestrut{\sphinx@cellid}\box\z@ |
|
286 \endgroup % group was opened in \sphinxmultirow |
|
287 }% |
|
288 \newcommand*\sphinxtablestrut[1]{% |
|
289 % #1 is a "cell_id", i.e. the id of a merged group of table cells |
|
290 \csname sphinx@tablestrut_#1\endcsname |
|
291 }% |
|
292 % LaTeX typesets the table row by row, hence each execution can do |
|
293 % an update for the next row. |
|
294 \newcommand*\sphinx@tablestrut[3]{\begingroup |
|
295 % #1 = q, #2 = (initially) r, #3 = cell_id, q+1 lines in first r rows |
|
296 % if #2 = 0, create space for max(q,1) table lines |
|
297 % if #2 > 0, create space for q+1 lines and decrement #2 |
|
298 \leavevmode |
|
299 \count@#1\relax |
|
300 \ifnum#2=\z@ |
|
301 \ifnum\count@=\z@\count@\@ne\fi |
|
302 \else |
|
303 % next row will be with a #2 decremented by one |
|
304 \expandafter\xdef\csname sphinx@tablestrut_#3\endcsname |
|
305 {\noexpand\sphinx@tablestrut{#1}{\the\numexpr#2-\@ne}{#3}}% |
|
306 \advance\count@\@ne |
|
307 \fi |
|
308 \vrule\@height\ht\@arstrutbox |
|
309 \@depth\dimexpr\count@\ht\@arstrutbox+\count@\dp\@arstrutbox-\ht\@arstrutbox\relax |
|
310 \@width\z@ |
|
311 \endgroup |
|
312 % we need this to avoid colour panels hiding bottom parts of multirow text |
|
313 \sphinx@hack@CT |
|
314 }% |
|
315 \endinput |
|
316 %% |
|
317 %% End of file `sphinxmulticell.sty'. |