# Vertical stacked parboxes: Spacing and Calculating

I need a table which will work in twocolumn mode and can span over multiple pages. Since I've given up with supertabular (too buggy, too less control), I wrote a simple solution for my purposes with vertical stacked parboxes. This is, what I've got so far:

(I've added fboxes to make the "cells" visible. Image shows only the upper part of the output.)

Problem 1: The vertical rule isn't aligned to the top and I have no clue how I can calculate the manual offset correct. (The next step will be to add some extra height to the rule so it closes with the upper rule.)

Problem 2: In this example I commented out the vertical rule. Now you see that the space after the parboxes is "incorrect", it's too less.

MWE:

\documentclass[10pt]{article}
\usepackage{lipsum}
\usepackage{forloop}
\usepackage{geometry}
\usepackage{ragged2e}
\geometry{a4paper, twocolumn, columnsep=10mm, top=10mm, left=10mm, right=10mm, bottom=10mm,

\newlength\pataCellAWidth
\newlength\pataCellBWidth

%calculated
\newlength\pataCellAHeight
\newlength\pataCellBHeight
\newlength\pataRuleHeight
\newlength\pataLineHeight

\newsavebox{\pataBox}

% \newlength\pataTemp

\setlength\fboxsep{0pt}%for demonstration

%To be done
% \newlength\pataRowSep%vertical space between cells
% \setlength\pataRowSep{0.25\baselineskip}
\newcommand\pataNewRow{%
\\%[\pataLineSep]%
}

\parbox[t]{\pataCellAWidth}{\RaggedRight #1}%
}

\hfill%
\parbox[t]{1pt}{\rule[\dimexpr-#1]{1pt}{\dimexpr#1}}%
\hfill%
}

\parbox[t]{\pataCellBWidth}{#1}%
}

%estimate parbox heights
\savebox{\pataBox}{{\parbox[b]{\pataCellAWidth}{#1}}}%
\setlength\pataCellAHeight{\ht\pataBox}
\savebox{\pataBox}{{\parbox[b]{\pataCellBWidth}{#2}}}%
\setlength\pataCellBHeight{\ht\pataBox}%
%always use the longer parbox for the rule
\setlength\pataRuleHeight{\pataCellAHeight}
\ifdim\pataCellBHeight>\pataRuleHeight%
\setlength\pataRuleHeight{\pataCellBHeight}
\fi%
%
%Output
\pataNewRow%
}

\begin{document}
\setlength\parindent{0pt}
\setlength\pataCellAWidth{20mm}
\setlength\pataCellBWidth{\dimexpr66mm}
Table\par

\newcounter{thenumberA}
\newcounter{thenumberB}
\forloop{thenumberA}{1}{\value{thenumberA} < 3}{%
\forloop{thenumberB}{1}{\value{thenumberB} < 8}{%
}%
}%
\lipsum[1]
\end{document}


You should take into account How to keep a constant baselineskip when using minipages (or \parboxes)? and use \parbox[t].

Here's an implementation that also takes into account the possibility that the left box has more lines than the right box.

\documentclass[10pt]{article}
\usepackage{lipsum}
\usepackage{forloop}
\usepackage{geometry}
\usepackage{ragged2e}
\geometry{a4paper, twocolumn, columnsep=10mm, top=10mm, left=10mm, right=10mm, bottom=10mm,

\newlength\pataCellAWidth
\newlength\pataCellBWidth
\newlength\pataCellAHeight
\newlength\pataCellBHeight
\newsavebox{\pataBox}

\par
\sbox{\pataBox}{\parbox[t]{\pataCellAWidth}{#1}}
\setlength{\pataCellAHeight}{\dp\pataBox}%
\sbox{\pataBox}{\parbox[t]{\pataCellBWidth}{#2}}
\setlength{\pataCellBHeight}{\dp\pataBox}%
\makebox[\linewidth][s]{%
\hfill
}%
\par\prevdepth\savedprevdepth
}

\newcommand{\maybeprevdepth}[1]{\par\xdef#1{\the\prevdepth}}
\newcommand{\savedprevdepth}{%
\ifdim\pataCellAHeight>\pataCellBHeight
\else
\fi
}

\begin{document}
\setlength\parindent{0pt}
\setlength\pataCellAWidth{20mm}
\setlength\pataCellBWidth{\dimexpr66mm}
Table\par

\newcounter{thenumberA}
\newcounter{thenumberB}
\forloop{thenumberA}{1}{\value{thenumberA} < 3}{%
\forloop{thenumberB}{1}{\value{thenumberB} < 5}{%
}%
}%
\lipsum[1]
\end{document}


A different implementation that allows for a rule separating the left column from the right column. I added an environment around the body of the table.

\documentclass[10pt]{article}
\usepackage{lipsum}
\usepackage{forloop}
\usepackage{geometry}
\usepackage{ragged2e}
\geometry{a4paper, twocolumn, columnsep=10mm, top=10mm, left=10mm, right=10mm, bottom=10mm,

\newlength\pataCellAWidth
\newlength\pataCellBWidth

\newenvironment{pataCells}[1]
{\par\setlength{\parindent}{0pt}%
\setlength{\pataCellAWidth}{#1}%
\setlength{\pataCellBWidth}{\dimexpr\linewidth-#1-1em}}
{\par\prevdepth=\dp\strutbox}

\par\ifdim\prevdepth=-1002pt\penalty0 \nointerlineskip\fi
\makebox[\linewidth][s]{%
\parbox[t]{\pataCellAWidth}{\strut#1\unskip\nobreak\strut}%
\hfill\vrule\hfill
\parbox[t]{\pataCellBWidth}{\strut#2\unskip\nobreak\strut}
}%
\par\prevdepth-1002pt
}

\begin{document}
\lipsum[2]

\begin{pataCells}{20mm}
\newcounter{thenumberA}
\newcounter{thenumberB}
\forloop{thenumberA}{1}{\value{thenumberA} < 3}{%
\forloop{thenumberB}{1}{\value{thenumberB} < 5}{%
}%
}
\end{pataCells}
\lipsum[1]
\end{document}


• Thanks you very much, that solves Problem 2. But the column seperator | (\rule) is missing now, see Problem 1 – musicman Jun 26 '15 at 12:44
• @musicman Should the rules be connected with each other? – egreg Jun 26 '15 at 13:21
• yes. For parbox 1 the rule should span over its height. For each further parbox the rule should span over its height + connect to the rule of the previous parbox = some extra height. – musicman Jun 26 '15 at 13:42

Another relatively simple approach based on use of minipages and TikZ node:

Code:

\documentclass[10pt]{article}
\usepackage{lipsum}
\usepackage{geometry}
\usepackage{ragged2e}
\geometry{a4paper, twocolumn, columnsep=10mm, top=10mm, left=10mm, right=10mm, bottom=10mm,

\newlength\ShortCell
\newlength\LongCell

\newcommand\pataRow[2]{
\parbox[t]{\ShortCell}{#1}
\parbox[t]{\LongCell}{\hspace{0.5ex}
\tikz{\node[inner sep=0pt,outer sep=0pt,
align=justify, text width=\hsize-2ex]
(LongCell) {#2};
\draw[ultra thick,%<-- line thickness
transform canvas={xshift=-2ex}]
(LongCell.north west) -- (LongCell.south west);
}
}}

\setlength\parindent{0pt}
\setlength\parskip{1ex}

\begin{document}
\setlength\ShortCell{20mm}
\setlength\LongCell{\columnwidth-\ShortCell}

\lipsum[1]
\textbf{Table}\par
\pataRow{longer text}{\lipsum[1]}

\pataRow{short text}{dummytext\\more dummy text}%
\pataRow{short text}{dummytext\\more dummy text}%
\pataRow{short text}{dummytext\\more dummy text}%
\pataRow{short text}{dummytext\\more dummy text}%

\pataRow{short text\\two lines}{dummy text}%

\lipsum[1-3]
\end{document}


In my proposition I skip generation of stacked parboxes in a loop. Determine it is straightforward.

Tanks to @egreg I could manage to write a working solution as an alternative for supertabular. The code is sure not perfect, but I want to share it, in case someone has use for it.

A few notes:

1. The code was only written for my purposes: a table with two columns which can span over multiple pages and does automatic column breaks.
2. \RaggedLeft won't work as precode for a column (right alignment).
3. The calculation for automatic column breaks: Supertabular is very weak in this point. I noticed that in LaTeX \pagetotal doesn't get updated if a column break appears, only after 1-2 more rows. My code takes care of that problem (see code). The calculation seems to be pretty exact, but footnotes etc. are not taken into account.
4. Since \\ wont work in the table, you can use \pataContinueRow to imitate a line break. It will add a row with no vertical separator.
5. The code for the vertical space between the cells is not very good. That could need improvement.

MWE:

\documentclass[10pt]{article}
\usepackage{forloop}
\usepackage{geometry}
\usepackage{ragged2e}
\usepackage{etoolbox}

\geometry{a4paper, twocolumn, columnsep=10mm, top=10mm, left=10mm, right=10mm, bottom=10mm,

\newlength\pataCellAWidth
\newlength\pataCellBWidth

\newtoggle{pataVeryFirstRow}%First of Row doesn't get ever a separator
\newtoggle{pataNewColHasARowAlready}%only don't use a separator if it's the first row on the new column
\newtoggle{pataUseSeparator}%use the separator for this row?
\newtoggle{pataContinueRow}%row is just continued, no separator

\newlength\pataRowSep{}%length of the vspace
\setlength\pataRowSep{-120mm}%%TODO:there should be a better way to handle the additional vertical space

\newlength\pataRestHeight%temporary calculated rest after boxes are printed
\newlength\pataSafetyDistance%if remaining margin is below 4pt or something there are automatical column breaks
\setlength\pataSafetyDistance{4pt}%
\newsavebox\pataTempBox%for calculation

\newenvironment{pataCells}[1]
{\par\setlength{\parindent}{0pt}%
\setlength\parskip{0pt}
\setlength{\pataCellAWidth}{#1}%
\setlength{\pataCellBWidth}{\dimexpr\linewidth-#1-1em}%
\toggletrue{pataVeryFirstRow}%
}
{\par\prevdepth=\dp\strutbox}

\newcommand\pataPreCellA{}%in case \RaggedRight or something must be added
\newcommand\pataPreCellB{}

\newcommand\pataEstimateBox[2]{%calculate height of a box
\sbox\pataTempBox{\makebox[\linewidth][s]{%
\parbox[t]{\pataCellAWidth}{\strut#1\unskip\nobreak\strut}%
\hfill\vrule\hfill
\parbox[t]{\pataCellBWidth}{\strut#2\unskip\nobreak\strut}
}}%
}

\newcommand\pataWriteBox[2]{%just write the box
\makebox[\linewidth][s]{%
\parbox[t]{\pataCellAWidth}{\strut#1\unskip\nobreak\strut}%
\hfill\vrule\hfill%
\parbox[t]{\pataCellBWidth}{\strut#2\unskip\nobreak\strut}%
}%
\par\prevdepth-10002pt%connect the par with the previous one
}

\wlog{CellA: #1}%for debugging
\toggletrue{pataUseSeparator}%reset
\iftoggle{pataContinueRow}{\togglefalse{pataUseSeparator}}{}
\iftoggle{pataVeryFirstRow}%
{\togglefalse{pataUseSeparator}}%if it's the first row just print it
{%it's not the very first row
%calculate content height
\pataEstimateBox{{\pataPreCellA{}#1}}{{\pataPreCellB{}#2}}
\iftoggle{pataNewColHasARowAlready}{%add the separator box height if it's not the first row of a new column
\tiny\pataEstimateBox{\vspace{\pataRowSep}}{\vspace{\pataRowSep}}\normalsize%estimate height
}{}
\wlog{Height of content+safety distance: \the\pataRestHeight}%
\setlength\pataRestHeight{\dimexpr\textheight-\pagetotal-\pataRestHeight}%remaining space on page%not working with footnotes etc.
\wlog{Remaining space after content: \the\pataRestHeight}
%
\ifdimcomp{\pataRestHeight}{>}{0pt}{%enough space
}{%there was somewhere in time a column break
\nottoggle{pataNewColHasARowAlready}{%it's the first row in the new column
\togglefalse{pataUseSeparator}%
\newpage%
\wlog{Breaking the column manually}
}{%it's not the first column
\toggletrue{pataUseSeparator}%I hope this 'blind' rows have 'normal' heights
}%\nottoggle
}%\ifdimcomp
}%
%Output
\par
\iftoggle{pataUseSeparator}{%Add space above the row if needed
\tiny\pataWriteBox{\vspace{\pataRowSep}}{\vspace{\pataRowSep}}\normalsize%TODO:there should be a better way to handle the additional vertical space
}{}%
\pataWriteBox{{\pataPreCellA{}#1}}{{\pataPreCellB{}#2}}%write the row, finally
\togglefalse{pataVeryFirstRow}
\togglefalse{pataContinueRow}
% \ifdim\prevdepth=-1002pt\penalty0 \nointerlineskip\fi
}

\newcommand\pataContinueRow[2]{%behaves like a linebreak: writes a Row but doesn't use the separator
\toggletrue{pataContinueRow}%
}

\begin{document}

\newcommand\lip{Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.}
\lip

\newcounter{thenumberA}
\newcounter{thenumberB}
\begin{pataCells}{20mm}