% \iffalse meta-comment % % Copyright (C) 2017 Scott Pakin % ---------------------------------------------------- % % This package may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3c or later is part of all distributions of LaTeX % version 2008/05/04 or later. % % \fi % % \iffalse %<*driver> \ProvidesFile{eqparbox.dtx} % %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{eqparbox} %<*package> [2017/09/03 v4.1 Create equal-widthed boxes] % % %<*driver> \documentclass{ltxdoc} \usepackage{eqparbox} \usepackage{calligra} \usepackage{array} \usepackage{boxedminipage} \usepackage{needspace} \usepackage{ifmtarg} \usepackage[subrefformat=parens,labelformat=parens]{subfig} \usepackage[bookmarksopen]{hyperref} \EnableCrossrefs \CodelineIndex \RecordChanges % Uncomment the following line if you don't want to include a % source-code listing. %\OnlyDescription \begin{document} \sloppy \DocInput{eqparbox.dtx} \Needspace{10\baselineskip} \phantomsection\addcontentsline{toc}{section}{Change History} \PrintChanges \makeatletter \let\orig@index@prologue=\index@prologue \def\index@prologue{% \phantomsection\addcontentsline{toc}{section}{Index} \orig@index@prologue }% \makeatother \Needspace{12\baselineskip} \PrintIndex \end{document} % % \fi % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \CheckSum{536} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % \changes{v1.0}{2001/04/19}{Initial version} % \changes{v2.0}{2004/07/31}{Rewrote to use only two \meta{dimen}s total % and the rest macros (problem reported by Gilles P\'erez-Lambert and % Plamen Tanovski; solution suggested by David Kastrup and Donald % Arseneau)} % % \GetFileInfo{eqparbox.dtx} % % \DoNotIndex{\@auxout,\@cons,\@ifnextchar,\@ifundefined,\@ne,\@tempboxa} % \DoNotIndex{\@tempdima,\DeclareRobustCommand,\\,\advance,\begin} % \DoNotIndex{\begingroup,\bgroup,\box,\csname,\def,\egroup,\else,\end} % \DoNotIndex{\endcsname,\endgroup,\expandafter,\fi,\gdef,\global,\hbox} % \DoNotIndex{\ifdim,\ifnum,\ifx,\immediate,\let,\long,\m@ne,\mbox} % \DoNotIndex{\newcommand,\newdimen,\newif,\newlength,\noexpand,\relax} % \DoNotIndex{\renewcommand,\renewenvironment,\romannumeral,\sbox,\setbox} % \DoNotIndex{\space,\string,\the,\wd,\xdef,\z@} % % ^^A The following environment, which typesets a declaration of a command % ^^A in a box set out into the margin, was copied almost verbatim from % ^^A ltxguide.cls. % \newenvironment{decl}[1][]^^A % {\par\small\addvspace{4.5ex plus 1ex}^^A % \vskip -\parskip % \ifx\relax#1\relax % \def\@decl@date{}^^A % \else % \def\@decl@date{\NEWfeature{#1}}^^A % \fi % \noindent\hspace{-\leftmargini}^^A % \begin{tabular}{|l|}\hline\ignorespaces}^^A % {\\\hline\end{tabular}\nobreak\@decl@date\par\nobreak % \vspace{2.3ex}\vskip -\parskip} % % ^^A Define a style for typesetting package names. % \DeclareRobustCommand{\pkgname}[1]{^^A % \textsf{#1}\index{#1=\textsf{#1} (package)}} % % ^^A Give LaTeX some more leeway in placing floats % ^^A (suggested by Donald Arseneau ). % \renewcommand{\topfraction}{0.85} % \renewcommand{\bottomfraction}{0.7} % \renewcommand{\textfraction}{0.15} % \renewcommand{\floatpagefraction}{0.66} % \renewcommand{\dbltopfraction}{0.66} % \renewcommand{\dblfloatpagefraction}{0.66} % \setcounter{topnumber}{9} % \setcounter{bottomnumber}{9} % \setcounter{totalnumber}{20} % \setcounter{dbltopnumber}{9} % % ^^A Because we put table captions *above* tables, we should add a % ^^A little extra space between the caption and the table. % \setlength{\belowcaptionskip}{2ex} % % ^^A Properly hyphenate Rob Verhoeven's name. % \hyphenation{Ver-hoe-ven} % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \title{The \pkgname{eqparbox} package\thanks{This document % corresponds to \pkgname{eqparbox}~\fileversion, dated \filedate.}} % \author{Scott Pakin \\ \textit{scott+eqp@pakin.org}} % \hypersetup{^^A % pdftitle={The eqparbox package}, % pdfauthor={Scott Pakin }, % pdfsubject={LaTeX package for typesetting text in equal-widthed boxes}, % pdfkeywords={LaTeX2e, parbox, makebox, framebox, savebox, boxes, automatic width, largest} % } % % \maketitle % % \begin{abstract} % The \pkgname{eqparbox} package makes it easy to define a group of % boxes (such as those produced by |\parbox| or |\makebox|) whose % members all have the same width, the natural width of the widest % member. A document can contain any number of groups, and each group % can contain any number of members. This simple, equal-width % mechanism can be used for a variety of alignment purposes, as is % evidenced by the examples in this document. % \end{abstract} % % \section{Motivation} % \label{sec:motivation} % % Let's start with a little test. How would you typeset % Figure~\ref{fig:quotations}, in which the names of the quotations' % authors are left-justified relative to each other but as a group abut % the right margin? And second, how would you typeset the r\'esum\'e % excerpt shown in Figure~\ref{fig:resume-excerpt} while meeting the % following requirements: % % \begin{enumerate} % \item The header columns must be left-justified relative to each % other. % \item The header columns should be evenly spaced across the page. % \item Page breaks should be allowed within the r\'esum\'e. % \end{enumerate} % % \begin{figure}[htbp] % \centering % \makeatletter % \newcommand{\showquote}[2]{^^A % \begin{flushright} % ---~\eqparbox{quotebox}{\sffamily#1}^^A % \@ifnotmtarg{#2}{\\ % \mbox{}\phantom{---}~\eqparbox{quotebox}{\sffamily\itshape#2}^^A % }^^A % \end{flushright}^^A % \par % } % \makeatother % \begin{boxedminipage}{\linewidth} % The only medicine for suffering, crime, and all other woes of mankind, % is wisdom. Teach a man to read and write, and you have put into his % hands the great keys of the wisdom box. But it is quite another thing % to open the box. % \showquote{Thomas Huxley}{} % % I would like a simple life \\ % yet all night I am laying \\ % poems away in a long box. \par % \bigskip % It is my immortality box, \\ % my lay-away plan, \\ % my coffin. % \showquote{Anne Sexton}{The Ambition Bird} % % \bigskip % % We have four boxes with which to defend our freedom: the soap box, the % ballot box, the jury box, and the cartridge box. % \showquote{Larry McDonald}{} % % \bigskip % % I saw the Count lying within the box upon the earth, some of which the % rude falling from the cart had scattered over him. He was deathly % pale, just like a waxen image, and the red eyes glared with the % horrible vindictive look which I knew so well. % \showquote{Bram Stoker}{Dracula} % % \bigskip % % Life in a box is better than no life at all, I expect. You'd % have a chance, at least. You could lie there thinking, ``Well, % at least I'm not dead.'' % \showquote{Tom Stoppard}{Rosencrantz~\& Guildenstern Are Dead} % % \bigskip % % Alla fin del gioco tanto va nel sacco il re quanto la pedina. \\ % \textit{(After the game, the king and pawn go into the same box.)} % \showquote{Italian proverb}{} % \end{boxedminipage} % \caption{Quotations with left-aligned attributions} % \label{fig:quotations} % \end{figure} % % \begin{figure}[htbp] % \bigskip\noindent\rule{\linewidth}{1pt}\bigskip\par % \noindent % \eqparbox{place}{\textbf{Widgets, Inc.}} \hfill % \eqparbox{title}{\textbf{Senior Widget Designer}} \hfill % \eqparbox{dates}{\textbf{1/95--present}} % % \begin{itemize} % \item Supervised the development of the new orange and blue widget lines. % \item Improved the design of various widgets, making them less sticky % and far less likely to explode. % \item Made widget management ten times more cost-effective. % \end{itemize} % % \noindent % \eqparbox{place}{\textbf{Thingamabobs, Ltd.}} \hfill % \eqparbox{title}{\textbf{Lead Engineer}} \hfill % \eqparbox{dates}{\textbf{9/92--12/94}} % % \begin{itemize} % \item Found a way to make thingamabobs run on solar power. % \item Drafted a blueprint for a new doohickey-compatibility module for % all cool-mint thingamabobs. % \item Upgraded superthingamabob specification document from Microsoft % Word to \LaTeXe. % \end{itemize} % \noindent\rule{\linewidth}{1pt} % \caption{Excerpt from a sample r\'esum\'e} % \label{fig:resume-excerpt} % \end{figure} % % The two questions can be answered the same way: by putting various % blocks of text into equal-widthed boxes. If the author names in % Figure~\ref{fig:quotations} are placed within a |flushright| % environment and in |\parbox|es as wide as the widest text % (``Rosencrantz~\& Guildenstern Are Dead''), they will appear as % desired. Similarly, if the company names in % Figure~\ref{fig:resume-excerpt} are both put in a |\parbox| as wide as % ``Thingamabobs, Ltd.,'' the job titles in a |\parbox| as wide as % ``Senior Widget Designer,'' and the dates in a |\parbox| as wide as % ``1/95--present,'' then they can be spaced evenly by separating them % with |\hfill|s. % % The problem is in choosing the width for each set of |\parbox|es. % Considering for now just Figure~\ref{fig:resume-excerpt}, the user % must typeset the r\'esum\'e once to see which entry in each column is % the widest and then assign lengths appropriately: % % \begin{verbatim} % \newlength{\placewidth} % \settowidth{\placewidth}{Thingamabobs, Ltd.} % Employment 2 % \newlength{\jobtitlewidth} % \settowidth{\jobtitlewidth}{Senior Widget Designer} % Employment 1 % \newlength{\dateswidth} % \settowidth{\dateswidth}{1/95--present} % Employment 1 % \end{verbatim} % % \noindent % Every time a piece of information changes, it must be changed in two % places: in the r\'esum\'e itself and in the |\settowidth| % command. When employment information is added or deleted, the % |\settowidth| commands must be modified to reflect the new % maximum-widthed entry in each column. If only there were a simpler % way to keep a set of |\parbox|es as wide as the widest entry in the % set\,\dots % % That simpler way is the \pkgname{eqparbox} package. % \pkgname{eqparbox} exports an |\eqparbox| macro that works just like % |\parbox|, except that instead of specifying the width of the box, one % specifies the group that the box belongs to. All boxes in the same % group will be typeset as wide as the widest member of the group. In % that sense, an |\eqparbox| behaves like a cell in an~|l|, |c|, or~|r| % column in a |tabular|; |\eqparbox|es in the same group are analogous % to cells in the same column. Unlike the cells in a |tabular| column, % however, a group of |\eqparbox|es can be spread throughout the % document. % % \section{Usage} % \label{sec:usage} % % \begin{decl} % |\eqparbox| \oarg{pos} \oarg{height} \oarg{inner-pos} \marg{tag} \marg{text} \\ % |\eqmakebox| \oarg{tag} \oarg{pos} \marg{text} \\ % |\eqframebox| \oarg{tag} \oarg{pos} \marg{text} \\ % |\eqsavebox| \marg{cmd} \oarg{tag} \oarg{pos} \marg{text} \\[1ex] % |\begin{eqminipage}| \oarg{pos} \oarg{height} \oarg{inner-pos} \marg{tag} \\ % \quad \meta{text} \\ % |\end{eqminipage}| % \end{decl} % % These are almost identical to, respectively, the |\parbox|, % |\makebox|, |\framebox|, and |\savebox| macros and the |minipage| % environment. The key difference is that the \meta{width} argument is % replaced by a \meta{tag} argument. (For a description of the % remaining arguments, look up |\parbox|, |\makebox|, |\framebox|, % |\savebox|, and |minipage| in any \LaTeXe\ book or in the % \texttt{usrguide.pdf} file that comes with all \TeX\ distributions.) % \meta{tag} can be any valid identifier. All boxes produced using the % same tag are typeset in a box wide enough to hold the widest of them. % Discounting \TeX's limitations, any number of tags can be used in the % same document, and any number of boxes can share a tag. The only % catch is that \texttt{latex} will need to be run a second time for the % various box widths to stabilize. % % \begin{decl} % |\eqboxwidth| \marg{tag} % \end{decl} % % It is sometimes useful to take the width of a box produced by one of % the preceding commands. While the width can be determined by creating % an |\eqparbox| and using |\settowidth| to measure it, the % \pkgname{eqparbox} package defines a convenience routine called % |\eqboxwidth| that achieves the same result. % % |\eqboxwidth| makes it easy to typeset something like % Table~\ref{tbl:mixed-tabular}. Table~\ref{tbl:mixed-tabular}'s only % column expands to fit the widest cell in the column, excluding the % final cell. The final cell's text word-wraps within whatever space is % allocated to it. In a sense, the first four cells behave as if they % were typeset in an~|l| column, while the final cell behaves as if it % were typeset in a~|p| column. In actuality, the column is an~|l| % column; an |\eqparbox| for the first four cells ensures the column % stretches appropriately while a |\parbox| of width % |\eqboxwidth{|\meta{tag}|}| in the final cell ensures that the final % cell word-wraps. % % Section~\ref{sec:tabular-l-p} presents a more general version of this % approach that doesn't require cells to be divided explicitly into % |\eqparbox| cells and |\parbox| cells. % % \begin{table}[htbp] % \centering % \caption{A \texttt{tabular} that stretches to fit some cells while % forcing others to wrap} % \label{tbl:mixed-tabular} % \DeleteShortVerb{\|} % \begin{tabular}{|@{}l@{}|} % \hline % \eqparbox[b]{wtab}{Wide} \\ \hline % \eqparbox[b]{wtab}{Wider} \\ \hline % \eqparbox[b]{wtab}{Wider than that} \\ \hline % \eqparbox[b]{wtab}{This is a fairly wide cell} \\ \hline % \parbox[b]{\eqboxwidth{wtab}}{\strut % While this cell's text wraps, the previous cells (whose text % doesn't wrap) determine the width of the column.} \\ \hline % \end{tabular} % \MakeShortVerb{\|} % \end{table} % % \begin{decl} % |\eqsetminwidth| \marg{tag} \marg{width} \\ % |\eqsetmaxwidth| \marg{tag} \marg{width} % \end{decl} % % These macros override the width calculation for boxes associated with % tag \meta{tag}, ensuring that they are no narrower than a given % minimum (|\eqsetminwidth|) and no wider than a given maximum % (|\eqsetmaxwidth|). % % \begin{decl} % |\eqsetminwidthto| \marg{tag} \marg{text} \\ % |\eqsetmaxwidthto| \marg{tag} \marg{text} % \end{decl} % % These macros are analogous to |\eqsetminwidth| and |\eqsetmaxwidth| % but automatically compute the natural width of the given text and use % that as the minimum (|\eqsetminwidthto|) or maximum % (|\eqsetmaxwidthto|) width for boxes using tag \meta{tag}. % % % \section{Examples} % \label{sec:examples} % % This section presents some sample uses of the macros described in % Section~\ref{sec:usage}. % % \subsection{Figures and tables from previous sections} % \label{sec:prev-figs-tabs} % % Figure~\ref{fig:quotations} was typeset using an |\eqparbox|-based % helper macro, |\showquote|: % % \begin{verbatim} % \usepackage{ifmtarg} % \makeatletter % \newcommand{\showquote}[2]{% % \begin{flushright} % ---~\eqparbox{quotebox}{\sffamily#1}% % \@ifnotmtarg{#2}{\\ % \mbox{}\phantom{---}~\eqparbox{quotebox}{\sffamily\itshape#2}% % }% % \end{flushright}% % \par % } % \makeatother % \end{verbatim} % \centerline{$\vdots$} % \begin{verbatim} % Alla fin del gioco tanto va nel sacco il re quanto la pedina. \\ % \textit{(After the game, the king and pawn go into the same box.)} % \showquote{Italian proverb}{} % \end{verbatim} % % Figure~\ref{fig:resume-excerpt}'s headings were typeset with the % following code: % % \begin{verbatim} % \noindent % \eqparbox{place}{\textbf{Widgets, Inc.}} \hfill % \eqparbox{title}{\textbf{Senior Widget Designer}} \hfill % \eqparbox{dates}{\textbf{1/95--present}} % \end{verbatim} % \centerline{$\vdots$} % \begin{verbatim} % \noindent % \eqparbox{place}{\textbf{Thingamabobs, Ltd.}} \hfill % \eqparbox{title}{\textbf{Lead Engineer}} \hfill % \eqparbox{dates}{\textbf{9/92--12/94}} % \end{verbatim} % \centerline{$\vdots$} % \bigskip % % Finally, Table~\ref{tbl:mixed-tabular} was typeset using the % following code: % % \begin{verbatim} % \begin{tabular}{|@{}l@{}|} % \hline % \eqparbox[b]{wtab}{Wide} \\ \hline % \eqparbox[b]{wtab}{Wider} \\ \hline % \eqparbox[b]{wtab}{Wider than that} \\ \hline % \eqparbox[b]{wtab}{This is a fairly wide cell} \\ \hline % \parbox[b]{\eqboxwidth{wtab}}{\strut % While this cell's text wraps, the previous cells (whose text % doesn't wrap) determine the width of the column.} \\ \hline % \end{tabular} % \end{verbatim} % % \subsection{Lists within \texttt{tabular}s} % \label{sec:lists-tabulars} % % List environments (|itemize|, |enumerate|, etc.) cannot appear % directly within a |tabular| cell. Instead, they must be wrapped % within a |\parbox|. The problem is that the |\parbox| width must be % specified; it can't be determined automatically. Fortunately, as of % version~4.0 of \pkgname{eqparbox}, the |\eqparbox| macro can contain % list environments, and these are automatically sized to their widest % item, just like any other |\eqparbox| contents. % Table~\ref{tbl:lists-tabular} presents an example of |enumerate| lists % appearing within |tabular| cells. The code for this is % straightforward, thanks to \pkgname{eqparbox}: % % \begin{table}[tbp] % \centering % \caption{Lists within a \texttt{tabular}} % \label{tbl:lists-tabular} % \begin{tabular}{c|c} % \textbf{Meeting date} & \textbf{Topics discussed} \\ % \hline % 2017-02-22 % & \eqparbox{topiclist}{^^A % \begin{enumerate} % \item Hardware upgrades % \item Barbara's retirement % \item Revised 27B/6 paperwork % \end{enumerate} % }^^A % \\ \hline % 2017-03-01 % & \eqparbox{topiclist}{^^A % \begin{enumerate} % \item Printer low on toner % \item Message from the V.P. % \end{enumerate} % }^^A % \\ \hline % 2017-03-08 % & \eqparbox{topiclist}{^^A % \begin{enumerate} % \item Product to ship next week % \item Floors to be recarpeted % \item Too many meetings % \end{enumerate} % }^^A % \end{tabular} % \end{table} % % \begin{verbatim} % 2017-02-22 & \eqparbox{topiclist}{% % \begin{enumerate} % \item Hardware upgrades % \item Barbara's retirement % \item Revised 27B/6 paperwork % \end{enumerate} % } \\ \hline % \end{verbatim} % % \subsection{Hanging indentation} % \label{sec:hang-indent} % % Consider the paragraphs depicted in Figure~\ref{fig:hang-indent}. % We'd like the paragraph labels set on the left, as shown, but we'd % also like to allow both intra-~and inter-paragraph page breaks. Of % course, if the labels are made wider or narrower, we'd like the % paragraph widths to adjust automatically. By using a custom |list| % environment that typesets its labels with |\eqparbox| this is fairly % straightforward: % % \begin{verbatim} % \begin{list}{}{% % \renewcommand{\makelabel}[1]{\eqparbox[b]{listlab}{#1}}% % \setlength{\labelwidth}{\eqboxwidth{listlab}}% % \setlength{\labelsep}{2em}% % \setlength{\parsep}{2ex plus 2pt minus 1pt}% % \setlength{\itemsep}{0pt}% % \setlength{\leftmargin}{\labelwidth+\labelsep}% % \setlength{\rightmargin}{0pt}} % % \item[Stuff about me] I am great. Blah, blah, blah, ... % % \item[More stuff] I am wonderful. Blah, blah, blah, ... % % \item[The final exciting thing] I am fantastic. Blah, % blah, blah, ... % \end{list} % \end{verbatim} % % \begin{figure}[htbp] % \rule{\linewidth}{1pt} % \begin{list}{}{^^A % \renewcommand{\makelabel}[1]{\eqparbox[b]{listlab}{#1}}^^A % \setlength{\labelwidth}{\eqboxwidth{listlab}}^^A % \setlength{\labelsep}{2em}^^A % \setlength{\parsep}{2ex plus 2pt minus 1pt}^^A % \setlength{\itemsep}{0pt}^^A % \setlength{\leftmargin}{\labelwidth}^^A % \addtolength{\leftmargin}{\labelsep}^^A % \setlength{\rightmargin}{0pt}} % % \item[Stuff about me] I am great. Blah, blah, blah, blah, blah, % blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, % blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, % blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, % blah. % % \item[More stuff] I am wonderful. Blah, blah, blah, blah, blah, % blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, % blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, % blah. % % Did I mention that blah, blah, blah, blah, blah, blah, blah, blah, % blah, blah, blah, blah, blah, blah, blah? % % \item[The final exciting thing] I am fantastic. Blah, blah, blah, % blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, % blah, blah, blah, blah, blah, blah, blah, blah, blah. % \end{list} % \rule{\linewidth}{1pt} % \caption{Paragraphs with hanging indentation} % \label{fig:hang-indent} % \end{figure} % % \subsection{Justified, parallel text} % \label{sec:parallel-text} % % Consider line-by-line transcription of a piece of text as illustrated % by the mockup in Figure~\ref{fig:line-by-line}. The idea is to % juxtapose a scanned piece of handwritten text with its typeset version % (or, similarly, to typeset a piece of text in one language alongside a % line-by-line translation into another language). The challenge is in % ensuring that (1)~the same words appear on corresponding lines of text % and that (2)~the typeset text is fully justified. While the % \pkgname{parallel} package can typeset fully justified paragraphs % aligned in parallel columns, it does not support the alignment of % individual lines. |tabular| and |minipage| environments provide % control of line breaks but do not support full justification of the % text when explicit line breaks are used. % % \begin{figure}[htbp] % \centering % \DeleteShortVerb{\|} % \newsavebox{\tstretchbox} % \newcolumntype{S}[1]{^^A % >{\begin{lrbox}{\tstretchbox}}^^A % l^^A % <{\end{lrbox}^^A % \eqmakebox[#1][s]{\unhcopy\tstretchbox}}} % \begin{tabular}{|l|l|} % \hline % \calligra % \begin{tabular}{S{handwritten}} % Lorem ipsum dolor sit amet, \\ % consectetur adipiscing elit. \\ % Phasellus volutpat, nibh sit \\ % amet mattis convallis, metus \\ % libero rhoncus justo, sed auctor \\ % erat mauris sit amet tellus. \\ % \end{tabular} % & % \begin{tabular}{S{typeset}} % Lorem ipsum dolor sit amet, \\ % consectetur adipiscing elit. \\ % Phasellus volutpat, nibh sit \\ % amet mattis convallis, metus \\ % libero rhoncus justo, sed auctor \\ % erat mauris sit amet tellus. \\ % \end{tabular} \\ % \hline % \end{tabular} % \MakeShortVerb{\|} % \caption{Line-by-line transcription of text with full justification} % \label{fig:line-by-line} % \end{figure} % % One solution is to use \pkgname{eqparbox}'s |\eqmakebox| macro. Like % |\makebox|, |\eqmakebox| supports the ``|s|'' (stretch) value for the % \meta{pos} argument, which causes the \meta{text} argument to stretch % to the width of the box. However, while |\makebox| requires the width % to be specified explicitly, |\eqmakebox| automatically sizes all boxes % that use the same tag (in this case, each line of the input paragraph) % to the widest text's natural width. Here's how to use the % \pkgname{array} package's |\newcolumntype| macro to define a new % |tabular| column type, ``|S|'', that stretches whitespace as needed to % fit the widest line in the column: % % \begin{verbatim} % \newsavebox{\tstretchbox} % \newcolumntype{S}[1]{% % >{\begin{lrbox}{\tstretchbox}}% % l% % <{\end{lrbox}% % \eqmakebox[#1][s]{\unhcopy\tstretchbox}}} % \end{verbatim} % % \noindent % That code works by storing the current cell's contents within a box % called |\tstretchbox| then passing |\tstretchbox|'s contents to % |\eqmakebox|. (The |tabular| environment does not enable a cell's % contents to be passed directly to a macro, hence the |lrbox| % trickery.) Note that the ``|S|'' column type takes an argument, which % is the tag to pass to |\eqmakebox|. Using the preceding definition we % can typeset Figure~\ref{fig:line-by-line} as follows. To simulate % scanned handwriting in the left column we use the Calligra handwriting % font provided by the \pkgname{calligra} package. % % \begin{verbatim} % \begin{tabular}{|l|l|} % \hline % \calligra % \begin{tabular}{S{handwritten}} % Lorem ipsum dolor sit amet, \\ % consectetur adipiscing elit. \\ % Phasellus volutpat, nibh sit \\ % amet mattis convallis, metus \\ % libero rhoncus justo, sed auctor \\ % erat mauris sit amet tellus. \\ % \end{tabular} % & % \begin{tabular}{S{typeset}} % Lorem ipsum dolor sit amet, \\ % consectetur adipiscing elit. \\ % Phasellus volutpat, nibh sit \\ % amet mattis convallis, metus \\ % libero rhoncus justo, sed auctor \\ % erat mauris sit amet tellus. \\ % \end{tabular} \\ % \hline % \end{tabular} % \end{verbatim} % % \subsection{Combining \texttt{l} and \texttt{p} column properties in a \texttt{tabular}} % \label{sec:tabular-l-p} % % In a |tabular| environment, |l|~columns, which automatically fit the % column to its contents, are good for short pieces of text. Long % pieces of text are best set within a |p|~column, which wraps text % within a specified width. But which column type should you use to % typeset text whose width is unknown (e.g.,~if the text is generated % programmatically)? With the help of \pkgname{eqparbox}'s % |\eqsetmaxwidth| macro (and the \pkgname{array} package's % |\newcolumntype| macro), it is possible to define a column type that % behaves like~|l| for short pieces of text and like~|p| for long pieces % of text: % % \begin{verbatim} % \newcolumntype{M}[1]{% % >{\begin{lrbox}{\csname#1box\endcsname}}% % l% % <{\end{lrbox}% % \eqparbox[t]{#1}{\unhcopy\csname#1box\endcsname\strut}}% % } % \end{verbatim} % % This can then be used as follows to produce the output shown in % Figure~\subref*{fig:maxwd-narrow}: % % \begin{verbatim} % \eqsetmaxwidth{maybebig}{0.5\linewidth} % \newsavebox{\maybebigbox} % \begin{tabular}{|M{maybebig}|l|} % \hline % Very short & Good \\ % A little bit longer & Okay \\ % \end{tabular} % \end{verbatim} % % \noindent % Because the text in the first column is narrower than half the line % width, the column behaves like an |l|~column. Now observe what % happens if we add a long piece of text to the column: % % \begin{verbatim} % \eqsetmaxwidth{maybebig}{0.5\linewidth} % \newsavebox{\maybebigbox} % \begin{tabular}{|M{maybebig}|l|} % \hline % Very short & Good \\ % A little bit longer & Okay \\ % Almost certainly excessively long, even given the point we're % trying to make about box widths & Bad \\ % \end{tabular} % \end{verbatim} % % \noindent % As Figure~\subref*{fig:maxwd-wide} shows, the first column now behaves % like a |p|~column, specifically |p{0.5\linewidth}|. % % \begin{figure}[htbp] % \centering % \subfloat[Output when the text is narrow\label{fig:maxwd-narrow}]{% % \begin{tabular}{|l|l|} % \hline % Very short & Good \\ % A little bit longer & Okay \\ % \hline % \end{tabular}% % } % \par % \subfloat[Output when the text is wide\label{fig:maxwd-wide}]{% % \begin{tabular}{|p{0.5\linewidth}|l|} % \hline % Very short & Good \\ % A little bit longer & Okay \\ % Almost certainly excessively long, even given the point we're % trying to make about box widths & Bad \\ % \hline % \end{tabular}% % } % \caption{Combining the features of \texttt{l} and \texttt{p} columns} % \label{fig:maxwd} % \end{figure} % % \subsection{Centering a column of right-justified data} % \label{tbl:center-justified} % % The data in each of the Sales columns in Table~\ref{tbl:sales-data} % are centered relative to their column header. However, they are also % right-justified relative to each other. To achieve this effect we % simply need to put the data in each column in a right-justified box % using |\eqmakebox|\oarg{tag}|[r]|\marg{text} and center that: % % \begin{verbatim} % \begin{tabular}{@{}lccc@{}} \hline % & \multicolumn{3}{c}{Sales (in millions)} \\ \cline{2-4} % \multicolumn{1}{c}{\raisebox{1ex}[2ex]{Product}} & % October & November & December \\ \hline % % Widgets & \eqmakebox[oct][r]{ 55.2} & % \eqmakebox[nov][r]{\bfseries 89.2} & % \eqmakebox[dec][r]{ 57.9} \\ % Doohickeys & \eqmakebox[oct][r]{\bfseries 65.0} & % \eqmakebox[nov][r]{\tiny N/A} & % \eqmakebox[dec][r]{ 9.3} \\ % Thingamabobs & \eqmakebox[oct][r]{ 10.4} & % \eqmakebox[nov][r]{ 8.0} & % \eqmakebox[dec][r]{\bfseries 109.7} \\ \hline % \end{tabular} % \end{verbatim} % % \begin{table}[htbp] % \centering % \caption{Sample sales data} % \label{tbl:sales-data} % \begin{tabular}{@{}lccc@{}} \hline % & \multicolumn{3}{c}{Sales (in millions)} \\ \cline{2-4} % \multicolumn{1}{c}{\raisebox{1ex}[2ex]{Product}} & % October & November & December \\ \hline % % Widgets & \eqmakebox[oct][r]{ 55.2} & % \eqmakebox[nov][r]{\bfseries 89.2} & % \eqmakebox[dec][r]{ 57.9} \\ % Doohickeys & \eqmakebox[oct][r]{\bfseries 65.0} & % \eqmakebox[nov][r]{\tiny N/A} & % \eqmakebox[dec][r]{ 9.3} \\ % Thingamabobs & \eqmakebox[oct][r]{ 10.4} & % \eqmakebox[nov][r]{ 8.0} & % \eqmakebox[dec][r]{\bfseries 109.7} \\ \hline % \end{tabular} % \end{table} % % % \section{Limitations} % \label{sec:limitations} % % Unfortunately, \pkgname{eqparbox}'s macros have a number of % limitations not exhibited by the corresponding \LaTeXe\ commands. % First, \pkgname{eqparbox}'s macros internally typeset the given text % within a |tabular| environment---specifically, using ``|@{}l@{}|'' as % the template---in order to determine the text's natural width. % Consequently, commands not valid within such a |tabular| % (e.g.,~|verbatim| environments) are also not valid within the % \meta{text} argument of an \pkgname{eqparbox} macro. As a corollary, % the macros defined by the \pkgname{eqparbox} package can appear only % where a |tabular| is also acceptable. % % A second limitation is that \pkgname{eqparbox}'s macros typeset their % \meta{text} argument \emph{twice}: once within a |tabular| to % determine the natural width and again within a box wide enough to hold % all text associated with tag \meta{tag}. This approach may cause % unexpected results if \meta{text} is non-idempotent (i.e.,~has side % effects). For example, if \meta{text} increments a counter, the % counter will be incremented twice per invocation of |\eqparbox|. % % \StopEventually{} % % \section{Implementation} % \label{sec:implementation} % % The one-sentence summary of the implementation is, ``As % \pkgname{eqparbox} goes along, it keeps track of the maximum width of % each box type, and when it's finished, it writes those widths to % the~|.aux| file for use on subsequent runs.'' If you're satisfied % with that summary, then read no further. Otherwise, get ready to % tackle the following annotated code listing. % % \subsection{Preliminaries} % % \begin{macro}{\eqp@tempdima} % \begin{macro}{\eqp@tempdimb} % Define a couple temporary \meta{dimen}s for use in a variety of locations. % \begin{macrocode} \newlength{\eqp@tempdima} \newlength{\eqp@tempdimb} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\eqp@taglist} % Define a list of all of the tags we encountered in the author's document. % \begin{macrocode} \def\eqp@taglist{} % \end{macrocode} % \end{macro} % % \begin{macro}{\ifeqp@must@rerun} % \begin{macro}{\eqp@must@reruntrue} % \begin{macro}{\eqp@must@rerunfalse} % If an |eqparbox| is wider than the maximum-width |eqparbox| with the % same tag, we need to store the new maximum width and request that the % user re-run |latex|. We use |\ifeqp@must@rerun| and |\eqp@must@reruntrue| % to assist with this. % \begin{macrocode} \newif\ifeqp@must@rerun % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % The |\eqp@settowidth| macro requires the \pkgname{array} package's % ability to inject code into every cell. % \begin{macrocode} \RequirePackage{array} % \end{macrocode} % % \begin{macro}{\eqp@tabular@box} % \begin{macro}{\eqp@list@box} % The |\eqp@settowidth| macro requires a box, |\eqp@tabular@box|, in % which to store the entire input text. |\eqp@settowidth| also requires % a box, |\eqp@list@box|, in which to store nested |list| environments. % \begin{macrocode} \newsavebox{\eqp@tabular@box} \newsavebox{\eqp@list@box} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\eqp@list@indent} % The |\eqp@settowidth| macro stores the accumulated |list| indentation % in |\eqp@list@indent|. % \begin{macrocode} \newlength{\eqp@list@indent} % \end{macrocode} % \end{macro} % % The |eqminipage| environment requires the \pkgname{environ} package's % |\Collect@Body|, which passes the body of an environment to a macro as % a single argument. % \begin{macrocode} \RequirePackage{environ} % \end{macrocode} % % % \subsection{Width calculation} % % \begin{macro}{\eqp@storefont} % \begin{macro}{\eqp@restorefont} % To find the natural width of a piece of text, we put it in a table and % take the width of that. The problem is that font changes are not % preserved across line breaks (table cells). We therefore define an % |\eqp@storefont| macro which itself defines an |\eqp@restorefont| % macro that restores the current font and font size to its current % state. % \begin{macrocode} \newcommand*{\eqp@storefont}{% \xdef\eqp@restorefont{% \noexpand\usefont{\f@encoding}{\f@family}{\f@series}{\f@shape}% \noexpand\fontsize{\f@size}{\f@baselineskip}% \noexpand\selectfont }% } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\eqp@settowidth} % This macro is just like |\settowidth|, but it puts its argument in a % |tabular|, which means that it can contain |\\|. We use the % \pkgname{array} package's ``|>|'' and ``|<|'' template parameters to % inject an |\eqp@restorefont| at the start of every cell and an % |\eqp@storefont| at the end of every cell. Doing so preserves fonts % and font sizes across |\\| boundaries, just like |\parbox|. % % One catch is that lists cannot be included directly within a % |tabular|. True, they can be placed within a |\parbox| that itself is % within a |tabular| cell, but the whole point is that we're trying to % calculate how wide that |\parbox| should be, The trick we use here, % therefore, is to redefine the |list| environment as a single-column % |tabular| plus space for |\labelwidth| and |\labelsep|---we ignore all % other list-formatting parameters---and |\item| as~|\\|. There will be % an extra row at the beginning, but all we care about here is computing % a width, not a height, so that's acceptable. % \changes{v2.0}{2004/08/01}{Modified to store and restore the font % across \texttt{\string\string\string\\}~boundaries (suggested by % Mike Shell)} % \changes{v4.0}{2013/03/09}{Added support for list environments} % \changes{v4.0}{2013/03/15}{Added support for multi-paragraph input} % \begin{macrocode} \newcommand{\eqp@settowidth}[2]{% \begingroup \global\setbox\eqp@tabular@box=\hbox{% % \end{macrocode} % \begin{macro}{\eqp@endings} % Unfortunately, we can't simply redefine the |list| environment, which % underlies |itemize|, |enumerate|, and |description| lists, because % their definitions in the standard classes do not include a proper % |\begin{list}|\dots\linebreak[0]|\end{list}|. Instead, those parent % environments call |\list| directly and % |\let\end|\{|itemize|,\linebreak[0]|enumerate|,\linebreak[0]|description|\}|=\endlist|. % Our workaround is to reissue those |\let| bindings after redefining % |\list| and |\endlist| ourselves. % \begin{macrocode} \def\eqp@endings{}% \ifx\enditemize\endlist \g@addto@macro\eqp@endings{\let\enditemize=\endlist}% \fi \ifx\endenumerate\endlist \g@addto@macro\eqp@endings{\let\endenumerate=\endlist}% \fi \ifx\enddescription\endlist \g@addto@macro\eqp@endings{\let\enddescription=\endlist}% \fi % \end{macrocode} % \begin{environment}{list} % As described above, we locally redefine the |list| environment as a % single-column |tabular| and the |\item| macro as~|\\|. We begin by % copying a block of code from |ltlists.dtx| that sets the default % formatting parameters for a list of the current depth. This is % important because |trivlist| environments (e.g.,~|center| and % |flushleft|) reset some of the parameters, which would otherwise screw % up our width calculation. % \begin{macrocode} \renewenvironment{list}[2]{% \ifnum \@listdepth >5\relax \@toodeep \else \global\advance\@listdepth\@ne \fi \rightmargin\z@ \listparindent\z@ \itemindent\z@ \csname @list\romannumeral\the\@listdepth\endcsname ##2\relax % \end{macrocode} % \begin{macro}{\item} % We locally redefine |\item| to start a new row of the |tabular|, then % flush any nested lists from the previous |\item| at the current % nesting level, and finally adjust the current indentation based on % the item's label. % \begin{macrocode} \renewcommand*{\item}[1][]{% \mbox{}\\ \box\eqp@list@box\mbox{} \\ \sbox\@tempboxa{\makelabel{####1}}% \ifdim\wd\@tempboxa>\labelwidth \advance\eqp@list@indent by -\labelwidth \advance\eqp@list@indent by \wd\@tempboxa \fi \hspace*{\eqp@list@indent}% }% % \end{macrocode} % To measure the width of a |list| we introduce a single-column % |tabular| that includes |\eqp@list@indent|'s worth of padding % ($=$~|\leftmargin|~$+$ |\rightmargin|~$+$ |\itemindent|) % to mimic the width of the original |list| environment. % \begin{macrocode} \hspace*{-\eqp@list@indent}% \advance\eqp@list@indent by \leftmargin \advance\eqp@list@indent by \rightmargin \advance\eqp@list@indent by \itemindent \global\setbox\eqp@list@box=\hbox\bgroup \begin{tabular}{@{}l@{}}% }{% \item[]% \end{tabular}% \egroup \global\advance\@listdepth\m@ne }% \eqp@endings % \end{macrocode} % Finally, we place the given text---list or not---within a |tabular| so % the preceding |\settowidth| can measure its width. Because the text % may contain paragraph breaks we redefine |\par| as~|\\| to turn them % into line breaks and restore |\par|'s original definition when the % |tabular| ends. % \begin{macrocode} \global\let\eqp@par=\par \eqp@storefont \begin{tabular}{@{}>{\eqp@restorefont}l<{\eqp@storefont}@{}}% \global\@setpar{\\}% #2% \\ \box\eqp@list@box \end{tabular}% \global\@restorepar }% \endgroup % \end{macrocode} % Now that we've constructed a |tabular| with lines of the input text as % cells we can use \LaTeX's |\settowidth| macro to take its width. % \begin{macrocode} \settowidth{#1}{\box\eqp@tabular@box}% } % \end{macrocode} % \end{macro} % \end{environment} % \end{macro} % \end{macro} % % \begin{macro}{\eqp@compute@width} % The following function does all the real work for the % \pkgname{eqparbox} package. It takes two parameters---\meta{tag} and % \meta{text}---and ensures that all boxes with the same tag will be as % wide as the widest box with that tag. It ends by passing \meta{tag} % and \meta{text} to the |\eqp@produce@box| command, which was defined % by the calling macro to produce a box using one of the existing % \LaTeXe\ commands. % % To keep track of box widths, |\eqp@compute@width| makes use of two global % variables for each tag: |\eqp@this@|\meta{tag} and % |\eqp@next|\meta{tag}. |\eqp@this@|\meta{tag} is the maximum width % ever seen for tag \meta{tag}, including in previous |latex| runs. % |\eqp@next@|\meta{tag} works the same way but is always initialized % to~|0.0pt|. It represents the maximum width to assume in % \emph{subsequent} |latex| runs. It is needed to detect whether the % widest text with tag \meta{tag} has been removed/shrunk. At the end of % a run, \pkgname{eqparbox} prepares the next run (via the~|.aux| file) % to initialize |\eqp@this@|\meta{tag} to the final value of % |\eqp@next@|\meta{tag}. % \changes{v2.0}{2004/07/30}{Removed extraneous \texttt{\string\string\string\global}s % (suggested by David Kastrup)} % \changes{v3.1}{2010/01/01}{Restructured the package to make all % user-callable functions eventually call % \texttt{\string\string\string\eqp@compute@width}, which does the % bulk of the work} % \begin{macrocode} \long\def\eqp@compute@width#1#2{% \eqp@settowidth{\eqp@tempdimb}{#2}% % \end{macrocode} % We first clamp the box width, currently in |\eqp@tempdimb|, to the % range [|\eqp@minwd@|\meta{tag}, |\eqp@maxwd@|\meta{tag}]. As these % bounds are not necessarily defined we first have to check for their % existence. % \begin{macrocode} \@ifundefined{eqp@minwd@#1}{}{% \ifdim\eqp@tempdimb<\csname eqp@minwd@#1\endcsname \eqp@tempdimb=\csname eqp@minwd@#1\endcsname \fi }% \@ifundefined{eqp@maxwd@#1}{}{% \ifdim\eqp@tempdimb>\csname eqp@maxwd@#1\endcsname \eqp@tempdimb=\csname eqp@maxwd@#1\endcsname \fi }% \expandafter \ifx\csname eqp@this@#1\endcsname\relax % \end{macrocode} % If we get here, then we've never encountered tag \meta{tag}, even in % a previous |latex| run. We request that the user re-run |latex|. % This is not always necessary (e.g.,~when all uses of the |\eqparbox| % with tag \meta{tag} are left-justified), but it's better to be safe % than sorry. % \begin{macrocode} \global\eqp@must@reruntrue \expandafter\xdef\csname eqp@this@#1\endcsname{\the\eqp@tempdimb}% \expandafter\xdef\csname eqp@next@#1\endcsname{\the\eqp@tempdimb}% \else % \end{macrocode} % If we get here, then we \emph{have} previously seen tag \meta{tag}. % We just have to keep track of the maximum text width associated with % it. % \begin{macrocode} \eqp@tempdima=\csname eqp@this@#1\endcsname\relax \ifdim\eqp@tempdima<\eqp@tempdimb \expandafter\xdef\csname eqp@this@#1\endcsname{\the\eqp@tempdimb}% \global\eqp@must@reruntrue \fi % \end{macrocode} % \begin{macrocode} \eqp@tempdima=\csname eqp@next@#1\endcsname\relax \ifdim\eqp@tempdima<\eqp@tempdimb \expandafter\xdef\csname eqp@next@#1\endcsname{\the\eqp@tempdimb}% \fi \fi % \end{macrocode} % % The first time we encounter tag \meta{tag} in the current document we % ensure \LaTeX{} will notify the user if he needs to re-run |latex| on % account of that tag. % \begin{macrocode} \@ifundefined{eqp@seen@#1}{% \expandafter\gdef\csname eqp@seen@#1\endcsname{}% \@cons\eqp@taglist{{#1}}% }{}% % \end{macrocode} % % Finally, we can call |\eqp@produce@box|. We pass it % |\eqp@this@|\meta{tag} for its \meta{width} argument and |#2| for its % \meta{text} argument. % \begin{macrocode} \eqp@tempdima=\csname eqp@this@#1\endcsname\relax \eqp@produce@box{\eqp@tempdima}{#2}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\eqp@set@min@width} % Given a tag and a textual length, ensure that |\eqp@this@|\meta{tag} % represents a width of at least \meta{length}. % \changes{v4.1}{2017/09/03}{Introduced this helper macro for % \texttt{\string\string\string\eqsetminwidth} and % \texttt{\string\string\string\eqsetminwidthto}} % \begin{macrocode} \def\eqp@set@min@width#1#2{% \expandafter\ifx\csname eqp@this@#1\endcsname\relax % \end{macrocode} % If we get here, then we've never encountered tag \meta{tag}, even in % a previous |latex| run. We assign a value to \meta{tag} and request % that the user re-run |latex|. % \begin{macrocode} \global\eqp@must@reruntrue \expandafter\xdef\csname eqp@this@#1\endcsname{#2}% \expandafter\xdef\csname eqp@next@#1\endcsname{#2}% \else % \end{macrocode} % If we get here, then we \emph{have} previously seen tag \meta{tag}. % We ensure its width is at least~|#2|. % \begin{macrocode} \eqp@tempdima=\csname eqp@this@#1\endcsname\relax \eqp@tempdimb=#2\relax \ifdim\eqp@tempdima<\eqp@tempdimb \expandafter\xdef\csname eqp@this@#1\endcsname{\the\eqp@tempdimb}% \fi \eqp@tempdima=\csname eqp@next@#1\endcsname\relax \ifdim\eqp@tempdima<\eqp@tempdimb \expandafter\xdef\csname eqp@next@#1\endcsname{\the\eqp@tempdimb}% \fi \fi \@ifundefined{eqp@seen@#1}{% \expandafter\gdef\csname eqp@seen@#1\endcsname{}% \@cons\eqp@taglist{{#1}}% }{}% } % \end{macrocode} % \end{macro} % % % \subsection{Author macros} % % \begin{macro}{\eqparbox} % We want |\eqparbox| to take the same arguments as |\parbox|, with the % same default values for the optional arguments. The only difference % in argument processing is that |\eqparbox| has a \meta{tag} argument % where |\parbox| has \meta{width}. % % Because |\eqparbox| has more than one optional argument, we can't use % a single function defined by |\DeclareRobustCommand|. Instead, we % have to split |\eqparbox| into |\eqparbox|, |\eqparbox@i|, % |\eqparbox@ii|, and |\eqparbox@iii| macros, which correspond to % |\parbox|, |\@iparbox|, |\@iiparbox|, and |\@iiiparbox| in % |ltboxes.dtx|. % % |\eqparbox| takes an optional \meta{pos} argument that defaults % to~|c|. It passes the value of this argument to |\eqparbox@i|. % \begin{macrocode} \DeclareRobustCommand{\eqparbox}{% \@ifnextchar[%] {\eqparbox@i}% {\eqparbox@iii[c][\relax][s]}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\eqparbox@i} % |\eqparbox@i| takes a \meta{pos} argument followed by an optional % \meta{height} argument that defaults to~|\relax|. It passes both % \meta{pos} and \meta{height} to |\eqparbox@ii|. % \begin{macrocode} \def\eqparbox@i[#1]{% \@ifnextchar[%] {\eqparbox@ii[#1]}% {\eqparbox@iii[#1][\relax][s]}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\eqparbox@ii} % |\eqparbox@ii| takes \meta{pos} and \meta{height} arguments followed % by an optional \meta{inner-pos} argument that defaults to \meta{pos}. % It passes \meta{pos}, \meta{height}, and \meta{inner-pos} to % |\eqparbox@iii|. % \begin{macrocode} \def\eqparbox@ii[#1][#2]{% \@ifnextchar[%] {\eqparbox@iii[#1][#2]}% {\eqparbox@iii[#1][#2][#1]}% } % \end{macrocode} % \end{macro} % \begin{macro}{\eqparbox@iii} % \begin{macro}{\eqp@produce@box} % |\eqparbox@iii| takes \meta{pos}, \meta{height} and \meta{inner-pos} % arguments. It defines an |\eqp@produce@box| macro that takes a % \meta{width} argument and a \meta{text} argument and passes all of % \meta{pos}, \meta{height}, \meta{inner-pos}, \meta{width}, and % \meta{text} to \LaTeX's |\parbox| macro. |\eqparbox@iii| ends by % calling |\eqp@compute@width|, which will eventually invoke % |\eqp@produce@box|. % \begin{macrocode} \def\eqparbox@iii[#1][#2][#3]{% \long\gdef\eqp@produce@box##1##2{% \parbox[#1][#2][#3]{##1}{##2}% }% \eqp@compute@width } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{environment}{eqminipage} % The |eqminipage| environment is implemented almost exactly like the % |\eqparbox| macro above. Just like |\eqparbox|, |eqminipage| takes an % optional \meta{pos} argument that defaults to~|c|. It passes the % value of this argument to |\eqminipage@i|. % \changes{v4.0}{2013/03/14}{Introduced this environment} % \begin{macrocode} \DeclareRobustCommand{\eqminipage}{% \@ifnextchar[%] {\eqminipage@i}% {\eqminipage@iii[c][\relax][s]}% } \let\endeqpminipage=\relax % \end{macrocode} % \end{environment} % % \begin{macro}{\eqminipage@i} % |\eqminipage@i| takes a \meta{pos} argument followed by an optional % \meta{height} argument that defaults to~|\relax|. It passes both % \meta{pos} and \meta{height} to |\eqminipage@ii|. % \begin{macrocode} \long\def\eqminipage@i[#1]{% \@ifnextchar[%] {\eqminipage@ii[#1]}% {\eqminipage@iii[#1][\relax][s]}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\eqminipage@ii} % |\eqminipage@ii| takes \meta{pos} and \meta{height} arguments followed % by an optional \meta{inner-pos} argument that defaults to \meta{pos}. % It passes \meta{pos}, \meta{height}, and \meta{inner-pos} to % |\eqminipage@iii|. % \begin{macrocode} \def\eqminipage@ii[#1][#2]{% \@ifnextchar[%] {\eqminipage@iii[#1][#2]}% {\eqminipage@iii[#1][#2][#1]}% } % \end{macrocode} % \end{macro} % \begin{macro}{\eqminipage@iii} % This is where |eqminipage| differs from |\eqparbox|. Like % |\eqparbox@iii|, |\eqminipage@iii| takes \meta{pos}, \meta{height} and % \meta{inner-pos} arguments. However, while |\eqparbox@iii| expects to % be followed by a tag and text, |\eqminipage@iii| consumes the tag % itself. |\eqminipage@iii| then uses \pkgname{environ}'s % |\Collect@Body| macro to collect everything up to the % |\end{eqminipage}| into a single argument, which it passes to % |\eqminipage@iv|. % \begin{macrocode} \def\eqminipage@iii[#1][#2][#3]#4{% % \end{macrocode} % \begin{macro}{\eqminipage@iv} % \begin{macro}{\eqp@produce@box} % This code is a bit confusing due to the definition of a macro within a % macro within a macro. |\eqminipage@iv|, which is invoked by % |\collect@body|, is passed the body of the |eqminipage| environment as % an argument. In then defines an |\eqp@produce@box| macro with the % parameter list that |\eqp@compute@width| expects: a width (|####1|) % and text (|####2|). |\eqp@produce@box| typesets a |minipage| with % that width and text and the formatting parameters provided to % |\eqminipage@iii| (|#1|, |#2|, and~|#3|). Finally, |\eqminipage@iv| % invokes |\eqp@compute@width| with the tag passed to |\eqminipage@iii| % as~|#4| and the text passed to |\eqminipage@iv| as~|##1|. % \begin{macrocode} \long\def\eqminipage@iv##1{% \long\gdef\eqp@produce@box####1####2{% \begin{minipage}[#1][#2][#3]{####1}% ####2% \end{minipage}% }% \eqp@compute@width{#4}{##1}% }% \Collect@Body\eqminipage@iv } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\eqmakebox} % |\eqmakebox| provides an automatic-width analogue to \LaTeX's % |\makebox|. It takes the same arguments as |\makebox| with the same % default values for the optional arguments. The only difference in % argument processing is that |\eqmakebox| has a \meta{tag} argument % where |\makebox| has \meta{width}. Note that if \meta{width} is not % specified, |\eqmakebox| simply invokes |\makebox|. % \changes{v3.0}{2010/01/01}{Included Rob Verhoeven's % \texttt{\string\string\string\eqmakebox} macro} % \changes{v3.1}{2010/01/01}{Modified the argument processing to match % \texttt{\string\string\string\makebox}'s} % \begin{macrocode} \DeclareRobustCommand{\eqmakebox}{% \@ifnextchar[%] {\eqlrbox@i\makebox}% {\makebox}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\eqframebox} % |\eqframebox| provides an automatic-width analogue to \LaTeX's % |\framebox|. It takes the same arguments as |\framebox| with the same % default values for the optional arguments. The only difference in % argument processing is that |\eqframebox| has a \meta{tag} argument % where |\framebox| has \meta{width}. Note that if \meta{width} is not % specified, |\eqframebox| simply invokes |\framebox|. % \changes{v3.1}{2010/01/01}{Introduced this macro} % \begin{macrocode} \DeclareRobustCommand{\eqframebox}{% \@ifnextchar[%] {\eqlrbox@i\framebox}% {\framebox}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\eqsavebox} % |\eqsavebox| provides an automatic-width analogue to \LaTeX's % |\savebox|. It takes the same arguments as |\savebox| with the same % default values for the optional arguments. The only difference in % argument processing is that |\eqsavebox| has a \meta{tag} argument % where |\savebox| has \meta{width}. Note that if \meta{width} is not % specified, |\eqsavebox| simply invokes |\savebox|. % \changes{v3.1}{2010/01/01}{Introduced this macro} % \begin{macrocode} \DeclareRobustCommand{\eqsavebox}[1]{% \@ifnextchar[%] {\eqlrbox@i{\savebox{#1}}}% {\savebox{#1}}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\eqlrbox@i} % |\eqlrbox@i| takes a \marg{command} argument (one of |\makebox|, % |\framebox|, or |\savebox|\marg{cmd}) and a \oarg{tag} argument and % checks if those arguments are followed by a \oarg{pos} argument. If % not, then \meta{pos} defaults to ``|c|''. All of \meta{command}, % \meta{tag}, and \meta{pos} are passed to |\eqlrbox@ii|. % \begin{macrocode} \def\eqlrbox@i#1[#2]{% \@ifnextchar[%] {\eqlrbox@ii{#1}[#2]}% {\eqlrbox@ii{#1}[#2][c]}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\eqlrbox@ii} % \begin{macro}{\eqp@produce@box} % |\eqlrbox@i| takes a \marg{command} argument (one of |\makebox|, % |\framebox|, or |\savebox|\marg{cmd}), a \oarg{tag} argument, and a % \oarg{pos} argument. It defines |\eqp@produce@box| to take a % \meta{width} argument and a \meta{text} argument and invoke % \meta{command}\oarg{width}\oarg{pos}\marg{text}. |\eqlrbox@ii| ends % by calling |\eqp@compute@width|, which will eventually invoke % |\eqp@produce@box|. % \begin{macrocode} \def\eqlrbox@ii#1[#2][#3]{% \long\gdef\eqp@produce@box##1##2{% #1[##1][#3]{##2}% }% \eqp@compute@width{#2}% } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\eqboxwidth} % For the times that the user wants to make something other than a box to % match an |\eqparbox|'s width, we provide |\eqboxwidth|. |\eqboxwidth| % returns the width of a box corresponding to a given tag. More % precisely, if |\eqp@this@|\meta{tag} is defined, it's returned. % Otherwise,~|0pt| is returned. % \changes{v2.1}{2004/08/02}{Rewrote so as to be compatible with the % \pkgname{calc} package's \texttt{\string\string\string\setlength} % command (problem initially reported by Gary L. Gray and narrowed % down by Martin Vaeth)} % \begin{macrocode} \newcommand*{\eqboxwidth}[1]{% \@ifundefined{eqp@this@#1}{0pt}{\csname eqp@this@#1\endcsname}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\eqsetminwidth} % The |\eqsetminwidth| macro accepts a tag and a length and records that % the user wants the associated box to be no narrower than the given % length. % \changes{v4.0}{2013/03/04}{Introduced this macro} % \changes{v4.1}{2017/09/03}{Define % \texttt{\string\string\string\eqp@this@}\meta{tag} and % \texttt{\string\string\string\eqp@next@}\meta{tag} appropriately} % \begin{macrocode} \newcommand{\eqsetminwidth}[2]{% \@tempdima=#2\relax \expandafter\xdef\csname eqp@minwd@#1\endcsname{\the\@tempdima}% \eqp@set@min@width{#1}{\csname eqp@minwd@#1\endcsname}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\eqsetmaxwidth} % The |\eqsetmaxwidth| macro accepts a tag and a length and records that % the user wants the associated box to be no wider than the given % length. % \changes{v4.0}{2013/03/04}{Introduced this macro} % \begin{macrocode} \newcommand{\eqsetmaxwidth}[2]{% \@tempdima=#2\relax \expandafter\xdef\csname eqp@maxwd@#1\endcsname{\the\@tempdima}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\eqsetminwidthto} % The |\eqsetminwidthto| macro accepts a tag and a piece of text and % records that the user wants the associated box to be no narrower than % the text, typeset at its natural width. % \changes{v4.0}{2013/03/04}{Introduced this macro} % \changes{v4.1}{2017/09/03}{Define % \texttt{\string\string\string\eqp@this@}\meta{tag} and % \texttt{\string\string\string\eqp@next@}\meta{tag} appropriately} % \begin{macrocode} \newcommand{\eqsetminwidthto}[2]{% \eqp@settowidth{\@tempdima}{#2}% \expandafter\xdef\csname eqp@minwd@#1\endcsname{\the\@tempdima}% \eqp@set@min@width{#1}{\csname eqp@minwd@#1\endcsname}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\eqsetmaxwidthto} % The |\eqsetmaxwidthto| macro accepts a tag and a piece of text and % records that the user wants the associated box to be no wider than % the text, typeset at its natural width. % \changes{v4.0}{2013/03/04}{Introduced this macro} % \begin{macrocode} \newcommand{\eqsetmaxwidthto}[2]{% \eqp@settowidth{\@tempdima}{#2}% \expandafter\xdef\csname eqp@maxwd@#1\endcsname{\the\@tempdima}% } % \end{macrocode} % \end{macro} % % \subsection{End-of-document processing} % % At the |\end{document}|, for each tag \meta{tag} we see if % |\eqp@next@|\meta{tag}, which was initialized to~|0.0pt|, is different % from |\eqp@this@|\meta{tag}, which was initialized to the maximum box % width from the previous run. If so, we issue an informational % message. In any case, we initialize the next run's % |\eqp@this@|\meta{tag} to |\eqp@next@|\meta{tag} and the next run's % |\eqp@next@|\meta{tag} to |0pt|. % \begin{macrocode} \AtEndDocument{% \begingroup % \end{macrocode} % \begin{macro}{\@elt} % The |\eqp@taglist| list is of the form ``|\@elt| |{|\meta{tag$_1$}|}| % |\@elt| |{|\meta{tag$_2$}|}|~\ldots''. We therefore locally define % |\@elt| to take the name of a tag and perform all of the checking % described above and then merely execute |\eqp@taglist|. % \changes{v2.0}{2004/08/01}{Modified to allow numbers in tag names % (suggested by Martin Vaeth)} % \changes{v4.0}{2013/03/04}{Modified to honor minimum and maximum % text widths, as set by % \texttt{\string\string\string\eqset}\{\texttt{max},\texttt{min}\}\texttt{width} and % \texttt{\string\string\string\eqset}\{\texttt{max},\texttt{min}\}\texttt{widthto}} % \begin{macrocode} \def\@elt#1{% % \end{macrocode} % Complain if the tag's minimum width is greater than its maximum width. % \begin{macrocode} \@ifundefined{eqp@minwd@#1}{}{% \@ifundefined{eqp@maxwd@#1}{}{% \ifdim\csname eqp@minwd@#1\endcsname>\csname eqp@maxwd@#1\endcsname \PackageWarning{eqparbox}{For tag `#1', minimum width (\csname eqp@minwd@#1\endcsname) > maximum width (\csname eqp@maxwd@#1\endcsname)}% \fi }% }% % \end{macrocode} % Make the |.aux| file define |\eqp@this@|\meta{tag} to the current % value of |\eqp@next@|\meta{tag} and |\eqp@next@|\meta{tag} to |0pt|. % \begin{macrocode} \eqp@tempdima\csname eqp@this@#1\endcsname\relax \eqp@tempdimb\csname eqp@next@#1\endcsname\relax \ifdim\eqp@tempdima=\eqp@tempdimb \else \@latex@warning@no@line{Rerun to correct the width of eqparbox `#1'}% \fi \immediate\write\@auxout{% \string\expandafter\string\gdef\string\csname\space eqp@this@#1\string\endcsname{% \csname eqp@next@#1\endcsname }% ^^J% \string\expandafter\string\gdef\string\csname\space eqp@next@#1\string\endcsname{0pt}% }% % \end{macrocode} % Also make the |.aux| file define |\eqp@minwd@|\meta{tag} and % |\eqp@maxwd@|\meta{tag} to their current value, if any. % \begin{macrocode} \@ifundefined{eqp@minwd@#1}{}{% \immediate\write\@auxout{% \string\expandafter\string\gdef\string\csname\space eqp@minwd@#1\string\endcsname{% \csname eqp@minwd@#1\endcsname }% }% }% \@ifundefined{eqp@maxwd@#1}{}{% \immediate\write\@auxout{% \string\expandafter\string\gdef\string\csname\space eqp@maxwd@#1\string\endcsname{% \csname eqp@maxwd@#1\endcsname }% }% }% }% \eqp@taglist \endgroup % \end{macrocode} % We output a generic ``rerun |latex|'' message if we encountered a % tag that was not present on the previous run. (This is always the % case on the first run or the first run after deleting the % corresponding |.aux| file. % \begin{macrocode} \ifeqp@must@rerun \@latex@warning@no@line{Rerun to correct eqparbox widths} \fi } % \end{macrocode} % \end{macro} % % \Finale \endinput