% \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=\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}%
\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}
