You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

303 lines
10 KiB
TeX

% varwidth.sty v 0.9a Mar 2003 Donald Arseneau asnd@triumf.ca
%
% Copyright 2003 by Donald Arseneau (asnd@triumf.ca).
% This software is released under the terms of the LaTeX Project Public
% License (ftp://ctan.tug.org/tex-archive/macros/latex/base/lppl.txt).
% (Essentially: Free to use, copy, distribute (sell) and change, but, if
% changed, the name must be changed.)
%
% The varwidth environment is based on minipage, and takes the same
% parameters, but the specified width is just a maximum value -- the
% environment will be typeset with a narrower "natural" width if
% possible.
%
% In a varwidth environment, paragraph line-breaks are chosen
% according to the specified width, but each line is reset to
% match a narrower natural width, if there is one.
%
% The \narrowragged command works like \raggedright, but produces
% generally narrower lines in paragraphs, but more text in the last
% line (the lines have more-equal lengths).
%
% This version works fine, but there are still many questions about
% how it would work best. Should there be a version that avoids the
% usual minipage formatting style?
%
% Numbered equations are not handled well, especially with leqno.
% AMSmath environments have not been tried, and undoubtedly fail.
%
% To do: Extend v-list wrappers to handle all e-TeX primitives.
% (pdfTeX too?)
% Capture marks and floats, propagating them out of the box
% Support numbered equations, including ams math.
%
\ProvidesPackage{varwidth}[2003/03/10 ver 0.9a; \space
Variable-width minipages]
\newcommand\narrowragged{\rightskip \z@ plus .25\hsize
\@rightskip\rightskip \parfillskip\z@ plus .15\hsize
\sloppy }
\newbox\@vwid@box
% The varwidth environment is based on minipage, and takes the same
% parameters, but the specified width is only a limit -- a narrower
% natural width may be used. \varwidth uses \minipage.
\def\varwidth{\let\@minipagerestore\@vwid@setup \minipage}
% Many things may appear on vertical lists that can't be re-processed,
% so they have to be modified.
\def\@vwid@setup{%
% several things can't appear in vertical mode, so they may get
% a \vbox wrapped around them.
\let\@bsphack\@vwid@bsphack % \label and others
\let\mark\@gobble % Marks disappear in minipages anyway
\let\@special\@vwid@special % \color and others
\let\addtocontents\@vwid@addtocontents % \addcontentsline
% Shifted boxes (\parshape,\hangindent) will have their shifts
% indicated in a separate box.
\let\@hangfrom\@vwid@hangfrom % hanging indents
\let\list\@vwid@list
\let\endtrivlist\@vwid@endtrivlist
\postdisplaypenalty\@vwid@posteqp
\predisplaypenalty\@vwid@preeqp
\def\@eqnnum{\aftergroup\@vwid@afterva\@@vwid@eqnnum}%
\global\@vwid@roff\z@ \global\@vwid@loff\z@
% Begin an inner minipage-like vertical box (in \@tempboxa)
\let\@minipagerestore\@@vwid@minipagerestore \@minipagerestore
\setbox\@tempboxa\vbox\bgroup\begingroup
% Flag the top of the list
\penalty\@vwid@toppen
}
\let\@@vwid@minipagerestore\@minipagerestore
% At end of varwidth environment.
\def\endvarwidth{\par\@@par
% Handle minipage-style notes.
\ifvoid\@mpfootins\else
\vskip\skip\@mpfootins
\normalcolor
\@vwid@wrap\footnoterule
\unvbox\@mpfootins
\fi
\unskip
\endgroup\egroup % got my \@tempboxa
% {\showoutput\showbox\@tempboxa}%
% in a discarded box, sift through list measuring max width.
\begingroup\setbox\z@\vbox\bgroup
%\message{-------------------------------------------------------------}%
%\message{First pass; hsize=\the\hsize... }%{\tracingall\showlists}%%
\unvcopy\@tempboxa
\@tempdima-\maxdimen
\let\@vwid@resetb\@vwid@measure
\let\@vwid@append\relax
\sift@deathcycles\z@
\@vwid@sift
\xdef\@vwid@{\the\@tempdima}%
\egroup\endgroup
% Done measuring. Now empty \@tempboxa onto current vertical list
% which is the contents of a minipage environment
%\message{Got natural width \@vwid@. }%
\unvbox\@tempboxa
% If the natural width is narrower, then go back through the list
% reboxing and moving everything into \@vwid@box; then spill \@vwid@box
\ifdim\@vwid@<\hsize
\hsize\@vwid@
\setbox\@vwid@box\vbox{}%
\sift@deathcycles\z@
%\message{----------------------------------------------------------------}%
%\message{Second pass; hsize=\the\hsize... }%{\tracingall\showlists}%
\@vwid@sift
\unvbox\@vwid@box
\fi
% end the minipage environment
\endminipage}
%
% Here are definitions for sifting through the vertical list, either
% measuring things or reboxing them.
%
% Penalties used as signals to the vertical-list processor:
\mathchardef\@vwid@posteqp 17321 % Penalty below equations
\mathchardef\@vwid@preeqp 17322 % Penalty above equations
\mathchardef\@vwid@postnump 17323 % Penalty below numbered equations
\mathchardef\@vwid@toppen 17324 % Penalty marking top of vertical list
\mathchardef\@vwid@offsets 17325 % Penalty below special h-offsets box
\mathchardef\@vwid@postw 17326 % Penalty below a \vbox-wrapped object
\newcount\sift@deathcycles
\def\@vwid@sift{%
\skip@\lastskip\unskip
\dimen@\lastkern\unkern
\count@\lastpenalty\unpenalty
\setbox\z@\lastbox
%{\showoutput\showbox\z@}%
\ifvoid\z@ \advance\sift@deathcycles\@ne \else \sift@deathcycles\z@ \fi
\ifnum\sift@deathcycles>33
\let\@vwid@sift\relax
\PackageWarning{varwidth}{Failed to reprocess entire contents}%
\fi
%\message{\the\sift@deathcycles: skip \the\skip@; kern \the\dimen@; penalty \the\count@. }%
%\ifhbox\z@\setbox99\hbox to0pt{\unhcopy\z@}\fi % = message
\ifnum\count@=\@vwid@preeqp \@vwid@eqmodefalse\fi
%\ifnum\count@=\@vwid@preeqp \message{End equation mode. }\fi
\ifnum\count@=\@vwid@posteqp \@vwid@eqmodetrue\fi
%\ifnum\count@=\@vwid@posteqp\message{Begin equation mode. }\fi
%\if@vwid@eqmode {\showoutput\showbox\z@}\fi
\ifnum\count@=\@vwid@toppen % finished
\let\@vwid@sift\relax
\else\ifnum\count@=\@vwid@offsets
\@vwid@setoffsets
\else
\ifnum\count@=\@vwid@postw
\else
\@vwid@resetb % reset box \z@ or measure it
\fi
\@vwid@append
\fi\fi
\@vwid@sift}
\def\@vwid@setoffsets{%
\setbox\z@=\hbox{\unhbox\z@
\global\@vwid@roff\lastkern\unkern
\global\@vwid@loff\lastkern\unkern}%
%\message{Set offsets to \the\@vwid@loff, \the\@vwid@roff. }%
}
\def\@vwid@append{% Append contents of box \z@ and glue to \@vwid@box
\setbox\@vwid@box\vbox{%
\unvbox\z@
\ifdim\dimen@=\z@\else \kern\dimen@ \fi
\vskip\skip@
\unvbox\@vwid@box
}%{\tracingall\showbox\@vwid@box}%
}
% reset box \z@ to \hsize, applying shifts, and wrap in vbox
% Don't worry about numbered equations because we won't get
% here if there are any.
\def\@vwid@resetb{%
\setbox\z@\vbox\bgroup
\ifvoid\z@
\else
\ifvbox\z@
\box\z@
\else % \hbox
\@tempdima\hsize
\advance\@tempdima-\@vwid@roff
\advance\@tempdima-\@vwid@loff
\advance\@tempdima-\p@
\ifdim\wd\z@>\@tempdima % full-width line; rebox it
%\message{An ordinary line or alignment. }%
\hbox to\hsize
{\kern\@vwid@loff \unhbox\z@ \kern\@vwid@roff}%
\else % an equation or direct \hbox
\if@vwid@eqmode % re-center unnumbered equations
%\message{A centered equation hsize=\the\hsize. }%
\hbox to\hsize
{\hskip\@vwid@loff\@plus1fil
\unhbox\z@ \hskip\@vwid@roff\@plus1fil}%
\else % plain narrow \hbox; leave it as-is
\box\z@
\fi\fi\fi\fi
\egroup}
\def\@vwid@measure{%
\ifvoid\z@
\else
% numbered equations not part of alignments can't be reset,
% so force retention of full width.
\ifnum\count@=\@vwid@postnump \ifdim\wd\z@<\linewidth
\ifdim\@tempdima<\linewidth \@tempdima\linewidth \fi
\fi\fi
\ifhbox\z@
\setbox\z@=\hbox
{\kern\@vwid@loff \unhbox\z@ \kern\@vwid@roff}%
\fi
\ifdim\wd\z@>\@tempdima \@tempdima\wd\z@ \fi
\fi}
\newdimen\@vwid@loff
\newdimen\@vwid@roff
\let\@@bsphack\@bsphack
\let\@@esphack\@esphack
\let\@@esphack\@Esphack
\def\@vwid@bsphack{\@@bsphack
\ifx\@vwid@wrap\@firstofone
\bgroup
\else
\ifvmode
\setbox\@vwid@box \vbox\bgroup \vbox\bgroup
\let\@vwid@wrap\@firstofone
\def\@esphack{\@vwid@esphack\@@esphack}%
\def\@Esphack{\@vwid@esphack\@@Esphack}%
\fi
\fi}
\def\@vwid@esphack{\egroup
\ifx\@vwid@wrap\@firstofone\else
\egroup % end outer box
\unvbox\@vwid@box % put inner box on list without lineskip
\penalty\@vwid@postw
\fi}
% \vbox Wrapper for misc vlist items
\long\def\@vwid@wrap{\relax
\ifvmode\expandafter\@vwid@dowrap \else \expandafter\@firstofone \fi}
\long\def\@vwid@dowrap#1{%
\setbox\@vwid@box \vbox{\vbox{\let\@vwid@wrap\@firstofone
#1}\penalty\@vwid@postw
}\unvbox\@vwid@box }
\let\@@vwid@special\special
\let\@@vwid@addtocontents\addtocontents
\let\@@vwid@list\list
\let\@@vwid@endtrivlist\endtrivlist
\let\@@vwid@eqnnum\@eqnnum
\long\def\@vwid@special#1{\@vwid@wrap{\@@vwid@special{#1}}}
\long\def\@vwid@addtocontents#1#2{\@vwid@wrap{\@@vwid@addtocontents{#1}{#2}}}
\long\def\@vwid@hangfrom#1{\par
\setbox\@tempboxa\hbox{{#1}}%
\setbox\@vwid@box \vbox{\hbox{\kern\z@ \kern\z@
}\penalty\@vwid@offsets}\unvbox\@vwid@box
\def\par{\relax\ifhmode\unskip\fi
\vadjust{\hbox{\kern\hangindent\kern\z@}\penalty\@vwid@offsets}%
\@restorepar\par}%
\hangindent \wd\@tempboxa\noindent\box\@tempboxa}
\def\@vwid@list{\@vwid@setlist\@@vwid@list}
\def\@vwid@endtrivlist{\@vwid@setlist\@@vwid@endtrivlist}
\def\@vwid@setlist{\relax\ifhmode \unskip\expandafter\vadjust\fi
{\setbox\@vwid@box \vbox{\hbox{%
\advance\hsize-\linewidth \advance\hsize-\@totalleftmargin
\kern\@totalleftmargin \kern\hsize}%
\penalty\@vwid@offsets}%
\unvbox\@vwid@box}}
\newif\if@vwid@eqmode
\def\@vwid@afterva{\vadjust{\penalty\@vwid@postnump}}
% Should I do this? ...
\@ifundefined{newcolumntype}{}{%
\@ifundefined{NC@rewrite@V}{
\newcolumntype{V}[1]{%
>{\begin{varwidth}[t]{#1}\narrowragged\let\\\tabularnewline}%
l%
<{\@finalstrut\@arstrutbox\end{varwidth}}}
}{}
}