summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/cals/cals/cell.dtx
blob: 3ced564b6d6330d795639893c5d7329b130d1be5 (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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
% \subsection{Creating cells}

% \begin{macro}{\cals@cell}
% \begin{macro}{\cals@cell@end}
% Creates an individual cell before socialization into a table.
% Content of the cell is typeset inside a group.
% Execution continues in |\cals@celll@end|. Parameters:
% \begin{enumerate}
% \item Width of the cell
% \item Vertical correction: when we have a rowspan, the cell is created while processing the last row. The vertical correction is required to raise the text back to the first row of the rowspan.
% \item (Implicit parameter.) Content. It is important that it contains a switch to the horizontal mode, otherwise horizontal dimensions of the cell will be incorrect.
% \end{enumerate}
% Using an implicit parameter instead of putting it to a macro
% parameter is probably a premature optimization.
%
%
%    \begin{macrocode}
\newcommand\cals@cell[3]{}
\def\cals@cell#1#2{%
%    \end{macrocode}
%
% Start immediately with |\vbox| to allow |\setbox0=\cals@cell{...}|
% construction. Later, white integrating the cell into
% a row, the content will be unvboxed and put to a vbox
% of the row height.
%
%    \begin{macrocode}
\vbox\bgroup%
%    \end{macrocode}
%
% Implicitely sets the width and the horizontal paddings
% of the cell. These settings come into effect on
% switch from the restricted vertical mode (our |\vbox|) to
% the horizontal mode. Therefore, the content must force such
% switch, otherwise the code fails.
%
%    \begin{macrocode}
\hsize=#1
\linewidth=#1
\leftskip=\cals@paddingL %
\rightskip=\cals@paddingR %
%    \end{macrocode}
%
% Vertical correction and top padding
%
%    \begin{macrocode}
\ifdim #2>0pt %
 \vskip-#2
\fi
\vskip\cals@paddingT %
%    \end{macrocode}
%
% Tuning the top padding. First, compensate the |\parskip|,
% which appears on the mode switch. Second, adjusts baselineskip,
% so in the case of the right preliminimary setup, the top of the
% letters "Al" touches the padding border. Meanwhile, setting
% prevdepth aligns the baselines of the first text lines
% of the row cells.
%
%    \begin{macrocode}
\vskip-\parskip %
\prevdepth=\cals@paddingD %
%    \end{macrocode}
%
% Finally, the content. And the switch to the horizontal mode (we hope).
%
% We want more work afrer typesetting the content, but it is not
% desirable to collect all the tokens. Instead, start a group and use
% |\aftergroup| to finish typesetting. For more explanations, see
% ``\TeX{} by Topic'', Chapter 12 ``Expansion''.
%
%    \begin{macrocode}
\bgroup\aftergroup\cals@cell@end
\cals@AtBeginCell\let\next=% eat '{' of the content
}%{Implicit content}

%    \end{macrocode}
%
% The infinite glue before the bottom padding is useful later,
% when we will re-height the cells in a row.
%
%    \begin{macrocode}
\def\cals@cell@end{\vfil\vskip\cals@paddingB
\cals@AtEndCell\egroup % finish vbox
%    \end{macrocode}
% Call the caller
%    \begin{macrocode}
\cals@celll@end}
%    \end{macrocode}
% \end{macro}
% \end{macro}

% \begin{macro}{\cell}
% Creates a cell and appends it to the hbox |\cals@current@row|.
%    \begin{macrocode}
\newcommand\cell[1]{}
\def\cell{%
%    \end{macrocode}
% Get the width of the cell and typeset it to the box 0.
% The execution flow is: |\cell| to |\cals@cell|
% to |\cals@cell@end| to |\cals@celll@end|.
%    \begin{macrocode}
\llt@rot\cals@colwidths
\let\cals@cell@width=\llt@car
\setbox0=\cals@cell\cals@cell@width{0pt}%
}
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\cals@AtBeginCell}
% \begin{macro}{\cals@AtEndCell}
% Additional code to be executed at the begin and at the end
% of a cell. An use case is a hook for pdfsync:
% |\def\cals@AtBeginCell{\pdfsyncstart}|. I am not sure if the end-hook
% is useful because all the changes are local for the cell group,
% but decided to retain it for symmetry.
%    \begin{macrocode}
\let\cals@AtBeginCell=\relax
\let\cals@AtEndCell=\relax
%    \end{macrocode}
% \end{macro}
% \end{macro}

% \begin{macro}{\cals@width@cell@put@row}
% Implicit setting of the cell width can fail (example is an empty cell).
% In this case, force the width explicitely. Then put the cell
% to the current row. This code should be a part of |\cals@celll@end|,
% but due to |\spancontent| is in a separate macro.
%    \begin{macrocode}
\newcommand\cals@width@cell@put@row{%
\ifdim \cals@cell@width=\wd0 \relax \else \wd0=\cals@cell@width \fi
\setbox\cals@current@row=\hbox{\unhbox\cals@current@row\box0 }}%
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\cals@celll@end}
% After a cell is typeset to the box 0, execution continues here
% (see notes to |\cell|). Update the current row and its decorations.
%    \begin{macrocode}
\newcommand\cals@celll@end{%
\cals@width@cell@put@row
\cals@decor@next\cals@cell@width}
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\spancontent}
% Typesets a spanned cell (the content is in the implicit argument)
% and puts it to the current row.
% The width and height correction are
% already calculated, the decorations are also already added.
%    \begin{macrocode}
\newcommand\spancontent[1]{}
\def\spancontent{%
\let\cals@tmp@celll=\cals@celll@end
\let\cals@cell@width=\cals@span@width
\def\cals@celll@end{%
  \cals@width@cell@put@row%
  \let\cals@celll@end=\cals@tmp@celll}%
\setbox0=\cals@cell{\cals@span@width}{\cals@span@height}%
}%{Implicit content}
%    \end{macrocode}
% \end{macro}

% \subsubsection{Cell padding}

% \begin{macro}{\cals@setpadding}
% \begin{macro}{\cals@paddingL}
% \begin{macro}{\cals@paddingR}
% \begin{macro}{\cals@paddingT}
% \begin{macro}{\cals@paddingB}
% 
% Calculates and sets the cell padding. It seems that a good value
% is the half of the font size, calculated as the full height of
% a box with the content \#1. The calstable environment uses
% the letters ``Ag''.
%
%    \begin{macrocode}
\newskip\cals@paddingL
\newskip\cals@paddingR
\newskip\cals@paddingT
\newskip\cals@paddingB

\newcommand{\cals@setpadding}[1]{%
\setbox0=\hbox{#1}%
\dimen0=\ht0 \advance\dimen0 by \dp0 \divide\dimen0 by 2
\cals@paddingL=\dimen0 \relax
\cals@paddingR=\cals@paddingL
\cals@paddingT=\cals@paddingL
\cals@paddingB=\cals@paddingL
}
%    \end{macrocode}
% \end{macro}\end{macro}\end{macro}\end{macro}\end{macro}

% \begin{macro}{\cals@setcellprevdepth}
% \begin{macro}{\cals@paddingD}
% The function |\cals@cell| uses the
% length |\cals@paddingD| to tune the top padding. The macro
% |\cals@setcellprevdepth| calculates and sets this parameter,
% so that a box with the content \#1 touches the padding border.
% The calstable environment uses the letters ``Al''.
%
%    \begin{macrocode}
\newdimen\cals@paddingD

\newcommand{\cals@setcellprevdepth}[1]{%
\setbox0=\vbox{\prevdepth=0pt #1}%
\setbox1=\vbox{#1}%
\dimen0=\ht0 \advance\dimen0 by \dp0 %
\advance\dimen0 by -\ht1 \advance\dimen0 by -\dp1%
\cals@paddingD=\dimen0 }
%    \end{macrocode}
% \end{macro}\end{macro}

% \begin{macro}{\alignL}
% \begin{macro}{\alignC}
% \begin{macro}{\alignR}
% To align the table cell text left, center or right we add or
% remove vfill-part of the left and right padding. Executed
% by assigning skip to dimen.
%    \begin{macrocode}
\newcommand\alignL{%
\cals@vfillDrop\cals@paddingL
\cals@vfillDrop\cals@paddingR}

\newcommand\alignC{%
\cals@vfillAdd\cals@paddingL
\cals@vfillAdd\cals@paddingR}

\newcommand\alignR{%
\cals@vfillAdd\cals@paddingL
\cals@vfillDrop\cals@paddingR}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}

% \begin{macro}{\cals@vfillAdd}
% \begin{macro}{\cals@vfillDrop}
% Add or remove the |vfill|-part of a skip. Retain the existing
% value if possible.
%    \begin{macrocode}
\newcommand\cals@vfillAdd[1]{\ifnum\gluestretchorder#1>1\relax\else
\dimen0=#1\relax #1=\dimen0 plus 1fill\relax \fi}
\newcommand\cals@vfillDrop[1]{\ifnum\gluestretchorder#1>0\relax
\dimen0=#1\relax #1=\dimen0\relax \fi}
%    \end{macrocode}
% \end{macro}
% \end{macro}

% \subsection{From cells to a row}

% \begin{macro}{\cals@current@row}
% Rows are first typeset to this hbox.
%    \begin{macrocode}
\newbox\cals@current@row
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\colwidths}
% \begin{macro}{\cals@colwidths}
% The macro |\cals@colwidths| contains a list of column widths.
% The user sets it through the API macro |\colwidths|, which performs
% expansion. The list is alive, it is rotated after a cell is finished,
% so the width of the next cell is always the first element.
%    \begin{macrocode}
\newcommand\colwidths[1]{}
\def\colwidths#{\edef\cals@colwidths}
\def\cals@colwidths{{100pt}}
%    \end{macrocode}
% \end{macro}\end{macro}

% Initially, I planned to use |\row{...}| to create a row.
% In order to perform actions at the end of the row I used
% the aftergroup-trick, like for |\cell| command. Unfortunately,
% the decorations were lost after the
% group finished. I tried to save them to global temporary
% macros at the end of each cell, but the saving list was big.
% Finally, I decided that the construction |\brow...\erow|
% is much easier to implement.

% \begin{macro}{\brow}
% Starts a row. Resets the rowspan markers, |\cals@current@row|
% and decorations.
%    \begin{macrocode}
\newcommand\brow{%
\cals@updateRspanMarkers
\setbox\cals@current@row=\hbox{}%
\cals@decor@begin}
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\erow}
% Finishes a row. All the cells are re-layouted to the row height.
% Decorations are finalized, and the row is dispatched.
%    \begin{macrocode}
\newcommand\erow{%
\cals@reheight@cells\cals@current@row
\cals@last@row@height=\ht\cals@current@row\relax
\cals@decor@end\cals@lastWidth
\ht\cals@current@cs=\ht\cals@current@row
\cals@row@dispatch
}
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\cals@reheight@cells}
% Re-heights all the boxes of a row.
% Retains the widths of these boxes.
%    \begin{macrocode}
\newcommand\cals@reheight@cells[1]{%
\dimen0=\ht#1\relax
\setbox2=\hbox{}%
\def\next{%
 \setbox4=\lastbox
 \ifvoid4
   \def\next{\global\setbox2=\box2}%
 \else
   \dimen4=\wd4
   \setbox4=\vbox to \dimen0{\unvbox4}%
   \ifdim \dimen4=\wd4 \relax \else \wd4=\dimen4 \fi
   \setbox2=\hbox{\box4\unhbox2 }%
 \fi
 \next}%
\setbox0=\hbox{\unhbox#1\next}%
\setbox#1=\box2 }
%    \end{macrocode}
% \end{macro}