% varwidth.sty v 0.92 Mar 2009 Donald Arseneau asnd@triumf.ca % % Copyright 2003-2004,2009 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, that fact must be clearly displayed to the user.) % % 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, with 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}[2009/03/30 ver 0.92; \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\pdfliteral\@vwid@pdfliteral % \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 \unskip % Handle minipage-style notes. \ifvoid\@mpfootins\else \vskip\skip\@mpfootins \normalcolor \@vwid@wrap\footnoterule \unvbox\@mpfootins \fi \unskip \@minipagefalse \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@ (compare \the\hsize) }% \unvbox\@tempboxa % Choose the natural width or the declared width, whichever is smaller. \ifdim\@vwid@<\hsize \hsize\@vwid@ \fi % Go through the vertical list reboxing and moving everything into % \@vwid@box; then spill \@vwid@box. If the natural width is narrower, \setbox\@vwid@box\vbox{}% \sift@deathcycles\z@ %\message{----------------------------------------------------------------}% %\message{Second pass; hsize=\the\hsize... }%{\tracingall\showlists}% \@vwid@sift %\message{After sifting:}% %{\showoutput\showbox\@vwid@box}% \unvbox\@vwid@box % 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@ %\message{Test if \the\wd\z@ > \the\@tempdima, }% \ifdim\wd\z@>\@tempdima % full-width line; rebox it %\message{An ordinary line or alignment. (\the\wd\z@ > \the\@tempdima) }% \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 %\message{Plain narrow box}% \box\z@ \fi\fi\fi\fi \egroup} % Measure a line (in box \z@) and keep a running tally of the % widest natural width in \@tempdima \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@pdfliteral\pdfliteral \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@pdfliteral#1{\@vwid@wrap{\@@vwid@pdfliteral{#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}}} }{} } % V 0.91 Always restack contents, even if width didn't change. % V 0.92 fix \special, \pdfliteral