Test for vertically overfull parbox

I'm currently updating an old class written in mostly plain TeX into LaTeX (mostly for readability) and I changed a combination of hbox and vbox into a single parbox with all the optional arguments.

The problem is that this class was clever and when the text in the box overflowed, it attempted to typeset it in two columns instead of one. It did this using \ifnum\badness=1000000 which worked fine for the old hbox/vbox method but fails using the parbox method.

Is there some way to test the vertical badness of a parbox?

MWE

\documentclass{article}
\usepackage{blindtext}
\begin{document}
% New code
\noindent\parbox[c][3cm][t]{\linewidth}{
\blindtext
}                               %parbox
\ifnum\badness=1000000\relax \vspace{3em} THE PREVIOUS BOX HAS BECOME OVERFULLxs\fi%

\vspace{5cm}

\makeatletter
% Old code
\noindent\vbox to 3cm{\hbox{
\parbox{\linewidth}{
\blindtext
}                               % parbox
}%          hbox
\vfill}%    vbox
\ifnum\badness=1000000\relax \vspace{3em} THE PREVIOUS BOX HAS BECOME OVERFULL\fi%
\makeatother

\end{document}


• Not without plunging deep into the code for \parbox, I'm afraid. – egreg Oct 3 '13 at 9:30

There are two problems, the first is that the parbox is not overfull as it is padded with \vss which is infinitely shrinkable. So you need to modify it to \vfil instead so that the glue will stretch but not shrink below zero. Then the next problem is that the box that is overfull is hidden a bit in the parbox handling so you need to save the badness at that point for testing later:

\documentclass{article}
\usepackage{blindtext}

\makeatletter
\long\def\@iiiparbox#1#2[#3]#4#5{%
\leavevmode
\@pboxswfalse
\setlength\@tempdima{#4}%
\@begin@tempboxa\vbox{\hsize\@tempdima\@parboxrestore#5\@@par}%
\ifx\relax#2\else
\setlength\@tempdimb{#2}%
\edef\@parboxto{to\the\@tempdimb}%
\fi
\if#1b\vbox
\else\if #1t\vtop
\else\ifmmode\vcenter
\else\@pboxswtrue $\vcenter \fi\fi\fi \@parboxto{\let\hss\vfil\let\unhbox\unvbox \csname bm@#3\endcsname}% \xdef\parboxbadness{\the\badness}% \if@pboxsw \m@th$\fi
\@end@tempboxa}

\makeatother
\begin{document}
% New code
\noindent\parbox[c][3cm][t]{\linewidth}{
\blindtext
}                               %parbox

\vspace{5em} THE PREVIOUS BOX HAS BECOME OVERFULL\fi%

\vspace{5cm}

\makeatletter
% Old code
\vbox to 3cm{\hbox{%
\parbox{\linewidth}{
\blindtext
}                               % parbox
}%          hbox
\vfill}%    vbox
\ifnum\badness=1000000\relax \vspace{3em} THE PREVIOUS BOX HAS BECOME OVERFULL\fi%
\makeatother

\end{document}


If you want to limit the scope of the redefinition then perhaps the simplest thing to do is replace

\long\def\@iiiparbox#1#2[#3]#4#5{%


by

\def\standardparbox{\let\@iiiparbox\orig@iiiparbox}
\def\measuringparbox{\let\@iiiparbox\my@iiiparbox}

\let\orig@iiiparbox\@iiiparbox

\long\def\my@iiiparbox#1#2[#3]#4#5{%


in the above then you can use \measuringparbox and \standardparbox to switch the behaviour of \parbox locally.

• How would you change the name of the environment macro to something else in order to preserve the original behaviour of parbox? e.g. \fullornotparbox instead of \parbox. I see lots of \defs but none that are \def\parbox. – Nathanael Farley Oct 3 '13 at 12:19
• @NathanaelFarley er too much code for a comment: I put something into the answer – David Carlisle Oct 3 '13 at 12:27