# Breakable vboxes

In Plain TeX how can I make vboxes breakable, and can I handle/measure them separately? What I'm trying to do, is that I have a portion of text, that is treated separately (no indention, narrower, coloured background, with the use of \hrule/\vrule) and make it breakable.

Additionally I'm interested in how to brake automatically hboxes

-
hboxes cannot break - that is rather the point of them! –  Joseph Wright Jun 16 '11 at 12:34
You can't break the content of \vbox or \hbox because they force restricted mode. –  Martin Scharrer Jun 16 '11 at 12:34
In a sense it is possible to break. OK, to be more precise: It is possible to split boxes, and in this case this was the solution I needed. –  Adam L. S. Jun 20 '11 at 20:38

A \vbox is by itself not breakable. But assigning it to a box register allows TeX to split it with the \vsplit operation.

\newbox\totalbox
\newbox\partialbox
\newdimen\partialboxdim
\setbox\totalbox=\vbox{<settings><text>}
<measurements setting \partialboxdim to the available space>
\setbox\partialbox=\vsplit\totalbox to \partialdim
<measurements setting \partialboxdim to the available space>
...


This is the scheme, you have to provide the \addcoloredbackground macro and the measurements, probably based on \pagegoal and \pagetotal. The TeXbook and TeX by Topic have examples about \vsplit.

Let's expand a bit; I assume you have a \colorthisbox macro that adds a colored background to a box and requirese 3pt of extra space above and below it. The strategy is first to gather the text to be boxed:

\newbox\totalbox
\newbox\partialbox
\newdimen\partialboxdim
\def\startcoloredbox{\par\bigskip
\def\endcoloredbox{\egroup\splitcoloredbox}


At this point we have all the text; now we start the splitting:

\def\splitcoloredbox{\ifvoid\totalbox\finishcoloredbox
\else\continuesplitting\fi}
\def\finishcoloredbox{\bigskip}


The macro \finishcoloredbox should provide the finishing touches, I've only put a \bigskip. The macro \continuesplitting is the heart of the process: it first measures the available space, but first of all it places a \null box in the main vertical list, because when the current page is empty, \pagetotal equals \maxdimen. The 6pt is the extra space reserved for printing the colored box. If the (remaining) part of box \totalbox is less high than the available space, we simply set box \partialbox to it, otherwise we split off from \totalbox what is necessary to fill the available space; then we pass the control to \colorthisbox, but we add \eject in the second case, since we are sure that we have reached the bottom of a page and we want to start at a fresh one with \pagetotal=0pt. After processing we call \splitcoloredbox again.

\def\continuesplitting{\null % In case this starts a new page
\dimen255=\dimexpr\pagegoal-\pagetotal-\pageshrink-6pt\relax
\ifdim\ht\totalbox<\dimen255
\setbox\partialbox=\box\totalbox
\colorthisbox
\else
\setbox\partialbox=\vsplit\totalbox to\dimen255
\colorthisbox\eject
\fi
\splitcoloredbox}


Here is the definition of \colorthisbox I used for testing; it's important that it encloses everything in a box (\hbox or \vbox) in order not to start horizontal mode.

\def\colorthisbox{\hbox{\fbox{\vbox{\unvbox\partialbox}}}}


(yes, the testing was done in LaTeX, because of \lipsum). The \vbox{\unvbox\partialbox} part is important because it avoids underfull boxes.

-
@egreg: Am I correct in thinking that this approach means that splitting has to come before adding background colour? –  Joseph Wright Jun 16 '11 at 14:01
@Joseph: I think this is the easiest way, but I'm no expert in pdfTeX color management. –  egreg Jun 16 '11 at 14:07
@egreg: neither am I. A quick look at color.sty shows me that \colorbox is implemented using a rule the size of the box, which of course can't then be split. So if the colour goes in before splitting it would have to be done some other way. –  Joseph Wright Jun 16 '11 at 14:37
@Joseph: so it's better to delay the coloring –  egreg Jun 16 '11 at 14:45
Well that does not solve the underfull boxes, and also seems awkward, when it splits at the first line, but it does the trick. Thanks. –  Adam L. S. Jun 18 '11 at 10:54

An experiment

This approach of breaking vertical boxes helped me. I tried to figure out how many lines I am dealing with in a block. I am usually using the lineno package for that and its \linelabel and \lineref commands. These commands are similar to their \label and \ref counterparts. I am able to get a number of lines using this method. If I need a number of section I use common \label next to the \linelabel command.

However, when I am typesetting via \parbox, this approach is not working. We can list line numbers using the internal command \internallinenumbers from the lineno package but I don't know how to refer to them.

Therefore, I saved my paragraph into a vertical box and started to splitting lines up by \baselineskip. Once the height of that box (\myboxtemp) is equal to 0pt I am done. I am enclosing an example where I rotated and coloured the lines differently. Number of lines is stored in the counter named \mycounter.

\documentclass[a4paper]{article}
\usepackage[nopar]{kantlipsum}
\parindent=0pt
\usepackage{tikz}
\usepackage{xcolor}
\usepackage{lineno}
\pagestyle{empty}

\begin{document}
\newdimen\mujtemp
\mujtemp=\textwidth

\section{My section}
\linenumbers
My first line.\par My second line.\linelabel{myfavoriteline}\label{mysection}
\par My third line.\par
\nolinenumbers

I am referring to line~\lineref{myfavoriteline}, section~\ref{mysection} on page~\pageref{myfavoriteline}.
\bigskip

\newsavebox{\mojkovo}%
\savebox{\mojkovo}{\parbox{\mujtemp}{%
\kant[1]%
\internallinenumbers
}}%
\usebox{\mojkovo}
\bigskip

\newbox\mybox
\setbox\mybox=\hbox{\usebox{\mojkovo}}
width \the\wd\mybox, height \the\ht\mybox, depth \the\dp\mybox
\vspace{6mm}\par

\setbox\mybox=\vbox to \vsize{\rightskip=35mm\kant[1]}%
\newbox\myboxtemp
\newcount\mycounter\mycounter=0%
\loop
\setbox\myboxtemp=\vsplit\mybox to \baselineskip%

\makebox[35mm][l]{\ifnum\mycounter<10 0\fi
\the\mycounter---\the\ht\myboxtemp\ \the\dp\myboxtemp\  }
\ifnum\ht\myboxtemp=0 There are no more lines!\fi
{\color{green}\vbox to 1\baselineskip
{%
\begin{tikzpicture}[remember picture, overlay]
\begin{pgfinterruptboundingbox}
\pgfmathparse{8*\the\mycounter+30}
\end{pgfinterruptboundingbox}
\end{tikzpicture}%
}}\par%
\ifnum\mycounter<18\repeat

\end{document}


Edit: This is my best shot of rewriting and cutting down the code into Plain TeX format. We couldn't use \newsavebox, \savebox and \usebox commands as these are the LaTeX format commands, please see latex.ltx for more details. I didn't know how to load a paragraph from the kantlipsum package, so I extracted a small portion of their code. I enclose the source code and a page preview.

%! pdftex boxes-plain.tex
\hsize=345pt % Taken from LaTeX...
\parindent=0pt
{\bf From kantlipsum package:}\par\vskip2mm
\def\mypara{As any dedicated reader can clearly see, the Ideal of practical reason is a representation of, as far as I know, the things in themselves; as I have shown elsewhere, the phenomena should only be used as a canon for our understanding. The paralogisms of practical reason are what first give rise to the architectonic of practical reason. As will easily be shown in the next section, reason would thereby be made to contradict, in view of these considerations, the Ideal of practical reason, yet the manifold depends on the phenomena. Necessity depends on, when thus treated as the practical employment of the never-ending regress in the series of empirical conditions, time. Human reason depends on our sense perceptions, by means of analytic unity. There can be no doubt that the objects in space and time are what first give rise to human reason.}
\newbox\mybox
\setbox\mybox=\vbox{\rightskip=35mm\mypara}
\copy\mybox
\vskip2mm
\newbox\myboxtemp
\newcount\mycounter
\mycounter=0
\loop

Yes, it happens to me quite often, I am mixing LaTeX commands with the TeX primitives. I have used the \newsavebox in the first part of the example which is defined in the latex.ltx file, that part is not going to work for you right away. This is working for me \newbox\mybox\setbox\mybox=\vbox{\rightskip=35mm typeset material}. –  Malipivo Mar 25 at 9:18