% \iffalse meta-comment % Line endings: UNIX % Tab size: 4 % % Copyright 2004 Jonathan Sauer % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % 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.3 or later is part of all distributions of LaTeX % version 2003/12/01 or later. % % This work has the LPPL maintenance status "maintained". % % The Current Maintainer of this work is Jonathan Sauer % (). % % This work consists of the files parcolumns.dtx and parcolumns.ins % and the derived file parcolumns.sty. % % \fi % % \iffalse % %<*driver> \documentclass{ltxdoc} \usepackage{parcolumns} \EnableCrossrefs \CodelineIndex \RecordChanges % Modification of verbatim for tabs in listings \makeatletter {\catcode`\ =\active% \catcode`\^^I=\active% \gdef\@vobeyspaces{% \catcode`\ \active\let \@xobeysp% \catcode`\^^I\active\def^^I{~~}% }}% \makeatother \begin{document} \DocInput{\jobname.dtx} \end{document} % % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{parcolumns} % [2004/11/25 v1.2 Typeset multiple parallel columns] %\RequirePackage{processkv}[2004/08/05] % % \fi % % \CheckSum{368} % \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 \~} % % \DoNotIndex{\@clubpenalty,\@doendpe,\@ehc,\@ifundefined,\@M,\@ne} % \DoNotIndex{\@one,\@nobreakfalse,\@plus,\@tempa,\@tempb,\@tempboxa} % \DoNotIndex{\@tempcnta,\@tempdima,\@tempdimb,\@tempdimc} % \DoNotIndex{\@tempswafalse,\@testopt,\advance,\afterassignment} % \DoNotIndex{\box,\brokenpenalty,\clubpenalty,\count@,\csname} % \DoNotIndex{\def,\define@key,\displaywidowpenalty,\divide,\dp,\edef} % \DoNotIndex{\else,\endcsname,\endgraf,\everypar,\expandafter} % \DoNotIndex{\fi,\global,\hbadness,\hb@xt@,\hfill,\hsize,\hskip} % \DoNotIndex{\if@tempswa,\ifnum,\ifvoid,\ifx,\interlinepenalty} % \DoNotIndex{\lastbox,\leavevmode,\let,\linewidth,\long,\loop} % \DoNotIndex{\m@ne,\multiply,\newbox,\newcommand,\newcount} % \DoNotIndex{\newdimen,\newenvironment,\newif,\newtoks} % \DoNotIndex{\number,\PackageError,\PackageInfo,\processkeyvalues} % \DoNotIndex{\relax,\repeat,\setbox,\setkeys,\space,\spaceskip} % \DoNotIndex{\splittopsep,\splittopskip,\strut,\strutbox,\the} % \DoNotIndex{\toks@,\tolerance,\unvbox,\vbadness,\vbox,\vfuzz} % \DoNotIndex{\vrule,\vsplit,\widowpenalty,\z@,\z@skip,\\} % % \GetFileInfo{\jobname.sty} % % \title{The \textsf{parcolumns} package\thanks{This document % corresponds to \textsf{\filename}~\fileversion, dated \filedate.}} % % \author{Jonathan Sauer \\ \texttt{jonathan.sauer@gmx.de}} % % \date{\filedate} % % \maketitle % % \begin{abstract} % This file describes the \textsf{parcolumns} package that provides an % environment for typesetting text in two or more columns columns in % parallel. % % \end{abstract} % % \tableofcontents % % \section{Introduction} % % Sometimes it is necessary to typeset text in two or more columns in % parallel, i.e. when typesetting a text in its original language and % in its translation(s). This package provides the \verb|parcolumns| % environment for typesetting text in several columns, where the text % of all columns is aligned vertically. % % Text in the |parcolums| environment is typeset in chunks, where the % chunks of one row are aligned vertically. A chunk consists of one or % more paragraphs of text, including \TeX\ macros. % % % \section{Usage}\label{sec:Usage} % % \DescribeEnv{parcolumns} Usage: |parcolumns| \oarg{options} % \marg{number of colums}. % % Inside the |parcolumns| environment text can be typeset in two or % more columns in parallel via the |\parchunk| macro. Normal text can % also be included. % % The \verb|parcolumns| environment takes an optional parameter that % specifies the options for the environment using the \textsf{keyval} % and \textsf{processkv} packages. The following options exist: % % \begin{description} % \item[\emph{colwidths}] Sets the widths of the columns. The % widths are specified as key-values, % \meta{columnnumber}=\meta{width}. % Columns start at `1'. Note that in % order to be ignored by the % \textsf{keyval} package, the complete % value has to be surrounded by braces, % i.e. `|colwidths={1=2cm,3=5cm,4=2cm}|' % to set the first column to a width of % 2~cm, the third to 5~cm and the fourth % to 2~cm. (the second column is % calculated) % % Columns not set this way will be % distributed evenly across the remaining % horizontal space of the page. % % \item[distance] Sets the distance between two columns. % If omitted set to \verb|2em|. % % \item[rulebetween] (Flag)\footnote{Meaning that if you % just say \texttt{rulebetween}, you set the % flag, as well as when you say % \texttt{rulebetween=true}. Saying % \texttt{rulebetween=false} clears the flag, % even though this does not make much sense, % as it is the default.} % Typeset a vertical bar between two % columns. % % |false| if omitted. % % \item[nofirstindent] (Flag) Suppress the indentation of the first % paragraph in the environment. % % |false| if omitted. % % \item[sloppy] (Flag) Typeset text in the columns in a % more sloppy way, preventing overfull % hboxes at the cost of larger % interword spacing. % % |false| if omitted. % % \item[sloppyspaces] (Flag) Makes spaces in the columns % stretchable, preventing overfull % hboxes at the cost of even larger % interword spacing that |sloppy|. % % |false| if omitted. % % \end{description} % % % \DescribeMacro{\colchunk} Usage: |\colchunk| \oarg{column} % \marg{chunk}. % % The macro |\colchunk| sets a chunk of text for the next column. You % don't have to set chunks for all columns; the colums not set remain % empty. However, the columns are filled from left to right, so if a % column inbetween should remain empty, you must say |\colchunk{}| or % specify the column to set using the optional parameter (columns % start at 1): |\colchunk[2]{|\ldots|}| sets the text of the second % column. Following calls to |\colchunk| without optional parameter % fill the third, fourth et cetera column. % % After a call to |\colplacechunks|, the column number is reset to % one. % % % % \DescribeMacro{\colplacechunks} Usage: |\colplacechunks|. % % The macro |\colplacechunks| places the chunks added with |\colchunk| % on the page. If there are no chunks to place, it does nothing. % % % % \section{Examples} % % Two columns, option |rulebetween=true| (which is the same as % just saying |rulebetween|): % % \addvspace{\baselineskip} % \begin{parcolumns}[rulebetween=true]{2} % \colchunk{Erwarten Sie von mir, dass ich rede? -- Nein, Mister % Bond, ich erwarte von Ihnen, dass Sie sterben!} % % \colchunk{Do you expect me to talk? -- No, Mister Bond, I expect you % to die!} % % \colplacechunks % % \colchunk{Erwarten Sie von mir, dass ich rede? -- Nein, Mister % Bond, ich erwarte von Ihnen, dass Sie sterben!} % % \colchunk{Do you expect me to talk? -- No, Mister Bond, I expect you % to die!} % % \colplacechunks % % \end{parcolumns} % \addvspace{\baselineskip} % As the german text is slightly longer, let's make the left column % alittle bit larger using |colwidths={1=.55\linewidth}|: % % \addvspace{\baselineskip} % \begin{parcolumns}[rulebetween=true,colwidths={1=.55\linewidth}]{2} % \colchunk{Erwarten Sie von mir, dass ich rede? -- Nein, Mister % Bond, ich erwarte von Ihnen, dass Sie sterben!} % % \colchunk{Do you expect me to talk? -- No, Mister Bond, I expect you % to die!} % % \colplacechunks % % \colchunk{Erwarten Sie von mir, dass ich rede? -- Nein, Mister % Bond, ich erwarte von Ihnen, dass Sie sterben!} % % \colchunk{Do you expect me to talk? -- No, Mister Bond, I expect you % to die!} % % \colplacechunks % % \end{parcolumns} % \addvspace{\baselineskip} % Three columns, option |nofirstindent=true|: % % \addvspace{\baselineskip} % \begin{parcolumns}[nofirstindent]{3} % \colchunk{This is just a short english text, just long enough to fill % a few lines.} % % \colchunk{Dies ist nur ein kurzer deutscher Text, gerade lang genug, % um ein paar Zeilen zu fuellen.} % % \colchunk{This is another short english text, as my french is not % that good anymore.} % % \colplacechunks % % \end{parcolumns} % \addvspace{\baselineskip} % There was an overfull |\hbox| in the previous text. Let's % try that again with the option |sloppy|: % % \addvspace{\baselineskip} % \begin{parcolumns}[nofirstindent,sloppy]{3} % \colchunk{This is just a short english text, just long enough to fill % a few lines.} % % \colchunk{Dies ist nur ein kurzer deutscher Text, gerade lang genug, % um ein paar Zeilen zu fuellen.} % % \colchunk{This is another short english text, as my french is not % that good anymore.} % % \colplacechunks % % \end{parcolumns} % \addvspace{\baselineskip} % No overfull hbox this time, but the spacing in the first column % is not optimal. You just have to pick what's better. Or you could % try the interword spacing provided by the \textsf{soul} package. % % \addvspace{\baselineskip}\noindent Maybe we do not want to fill the % first column, but do not want to type |\colchunk{}| either. Then we % can say |\colchunk[2]| to directly start with the second column % (note that we are using the option |sloppy|, too): % % \addvspace{\baselineskip} % \begin{parcolumns}[nofirstindent,sloppy]{3} % \colchunk[2]{This is just a short english text, just long enough to fill % a few lines.} % % \colchunk{Dies ist nur ein kurzer deutscher Text, gerade lang genug, % um ein paar Zeilen zu fuellen.} % % \colplacechunks % % \end{parcolumns} % \addvspace{\baselineskip} % Note that \texttt{parcolumns} does not insert vertical space % before or after the environment! In these examples, the space has % manually been added with |\addvspace|. % % % % \section{Notes}\label{sec:Notes} % % \begin{itemize} % \item The columns will always fill the complete width of the % page by stretching or shrinking the space between the columns. % That means that if the total width of all columns is set % to about half the page width, the space between the columns % will take up the rest, ignoring whatever was set with the % key |distance|.\footnote{The key \texttt{distance} is only % used for calculating the width of the columns and is ignored % afterwards.} % % \item Footnotes are not set in columns. % % \item \textsf{parcolumns} does not work very well with displayed % formula. The best way to typeset a |displaymath| et.al. % environment is to include it in separate |\colchunk| % commands, i.e. (assuming two columns and the same formula % in both): % % \begin{verbatim} % ... some text placed using \colchunk ... % \colchunk{ % Left column % \begin{displaymath} % x^2 + y^2 = z^2 % \end{displaymath} % } % \colchunk{ % Right column % \begin{displaymath} % x^2 + y^2 = z^2 % \end{displaymath} % } % \colplacechunks % ... some more text placed using \colchunk ... % \end{verbatim} % % \end{itemize} % % % % \StopEventually{} % % \section{Implementation} % % \subsection{Allocation} % % The current column (starting with one): % % \begin{macrocode} \newcount\pc@columnctr % \end{macrocode} % % The total number of columns in the current |parcolums| environment. % % \begin{macrocode} \newcount\pc@columncount % \end{macrocode} % % Place a vertical rule between two columns? % % \begin{macrocode} \newif\ifpc@rulebetween % \end{macrocode} % % Stores |\everypar| for use in |\parparagraphs|. % % \begin{macrocode} \newtoks\pc@everypar % \end{macrocode} % % Note that additional allocations are performed later on-demand in % |\pc@alloccolumns|. % % % % \subsection{\textsf{keyvalue} keys} % % \begin{macro}{\pc@boolkey} % % Sets an \verb|if|-condition in \marg{\#1} to the value passed as % \marg{\#2}. If \verb|#2| is \verb|false|, set \verb|if#1| to % \verb|false|, else (any other value) to \verb|true|. % % Usage: |\pc@boolkey| \marg{ifcondition} \marg{value} % % \begin{macrocode} \def\pc@boolkey#1#2{% \edef\@tempa{#2}% \edef\@tempb{false}% \ifx\@tempa\@tempb% \csname #1false\endcsname% \else% \csname #1true\endcsname% \fi% } % \end{macrocode} % \end{macro} % % % Define the keys for the options of |parcolumns|. % % \begin{macrocode} \define@key{parcolumns}{distance}{% \@tempdimc#1\relax% } \define@key{parcolumns}{rulebetween}[true]{% \pc@boolkey{pc@rulebetween}{#1}% } \define@key{parcolumns}{nofirstindent}[true]{% \pc@boolkey{@tempswa}{#1}% % \end{macrocode} % % If the indentation of the first line of the first paragraph should % be suppressed, change |\pc@everypar| accordingly. The token register % is reset after the placing of the first row of chunks in % |\colplacechunks|. % % What exactly are we doing? First we assign box 0 the contents of % |\lastbox|. At the beginning of a paragraph |\lastbox| contains % the glue inserted for the indentation of the first line. By % assigning this box to box 0, we remove the indentation. We do % this in a group as not to change the contents of box 0. % % Afterwards we set |\everypar| to nothing. This is necessary because % we only want to suppress the indentation for the first paragraph of % the |parcolumns| environment, not every paragraph. We set % |\everypar| and not |\pc@everypar| to nothing, because % |\pc@everypar| is only a temporary storage that will be assigned to % |\everypar| when used. % % \begin{macrocode} \if@tempswa\pc@everypar{{\setbox\z@\lastbox}\everypar{}}\fi% } \define@key{parcolumns}{sloppy}[true]{% \pc@boolkey{@tempswa}{#1}% % \end{macrocode} % % If sloppy typesetting is asked for, we set |\hbadness| and % |\tolerance| to 10000, so that \TeX\ breaks lines whenever possible, % even if this means high interword spacing. % % \begin{macrocode} \if@tempswa% \hbadness\@M% \tolerance\@M% \fi% } \define@key{parcolumns}{sloppyspaces}[true]{% \pc@boolkey{@tempswa}{#1}% % \end{macrocode} % % If sloppy spaces are asked for, we make the space stretchable: % % \begin{macrocode} \if@tempswa% \spaceskip.3333em\@plus1em % \fi% } % \end{macrocode} % % % We save the key-value-list containing widths of the columns in % |\toks@| for later use in |\pc@setcolumnwidths|. % % \begin{macrocode} \define@key{parcolumns}{colwidths}{% \toks@{#1}% } % \end{macrocode} % % % \subsection{Main environments and macros} % % \begin{environment}{parcolumns} % % Environment for a number of columns of text set in parallel (see % section \ref{sec:Usage} on page \pageref{sec:Usage} for the possible % options) % % Usage: |\begin{parcolumns}| \oarg{options} \marg{number of columns} % \ldots\ |\end{parcolums}| % % \begin{macrocode} \newenvironment{parcolumns}[2][]{% \pc@rulebetweenfalse% % \end{macrocode} % % |\if@tempswa| is |true|, if the indentation of the first line % should be suppressed, otherwise |false|. Default is |false|: % % \begin{macrocode} \@tempswafalse% % \end{macrocode} % % |\@tempdimc| contains the space between two columns. Default % is |2em|: % % \begin{macrocode} \@tempdimc2em\relax% % \end{macrocode} % % We set the options: % % \begin{macrocode} \toks@{}% \setkeys{parcolumns}{#1}% % \end{macrocode} % % We store the total number of columns and reset the counter for % the current column: % % \begin{macrocode} \pc@columncount#2 % \pc@columnctr\z@% % \end{macrocode} % % We allocate the columns and set their widths: % % \begin{macrocode} \pc@alloccolumns% \pc@setcolumnwidths% % \end{macrocode} % % We switch to vertical mode: % % \begin{macrocode} \endgraf% % \end{macrocode} % % As we are changing |\everypar|, we need to make sure that the most % important flag is reset, which normally happens in the |\everypar| % of a |\section|-command: |\if@nobreak|. (otherwise the next section % is typeset directly after the text of the previous section instead % of leaving some space)\footnote{I discovered this the hard way, % spending one or two hours wondering why the spacing between two % sections was much too small.} % % \begin{macrocode} \@nobreakfalse% % \end{macrocode} % % We reset |\everypar|, as it is of no use for us and can only screw % up things badly: % % \begin{macrocode} \global\everypar{}% }{% % \end{macrocode} % % At the end of the |parcolumns|-environment \ldots\ just in case, we % place the last chunks, if not already done so: % % \begin{macrocode} \colplacechunks% \endgraf% % \end{macrocode} % % We reset |\clubpenalty| globally to its normal value (the |\global| % makes sure that if |\everypar| should have reset |\clubpenalty|, it % is reset now). % % \begin{macrocode} \global\clubpenalty\@clubpenalty% % \end{macrocode} % % We suppress the indentation of the next paragraph immediately % following the environment: % % \begin{macrocode} \@doendpe% } % \end{macrocode} % \end{environment} % % % \begin{macro}{\colchunk} % % Sets the text for the next chunk of the next column. % % Usage: |\colchunk| \oarg{column} \marg{chunk}. (note that the |{| % and |}| are \emph{not} optional, even if the chunk consists of only % one token!) % % We need two macros for handling the optional parameter % \meta{column}, |\colchunk| and |\colchunk@|. First we define % |\colchunk|: % % \changes{1.1}{2004/08/22}{Optional parameter added.} % % \begin{macrocode} \newcommand{\colchunk}{\@testopt\colchunk@{}}% % \end{macrocode} % \end{macro} % % % \begin{macro}{\colchunk@} % % What are we doing now? By suffixing the last (optional) parameter by % |#|, we tell \TeX\ that the last parameter of |\colchunk| is to be % delimited by a right brace |{|, or \TeX\ will complain with a more % comprehensible message that without the |#|: `Use of |\colchunk| % doesn't match its definition.' instead of `Missing |{| inserted.' % % \changes{1.0.1}{2004/08/10}{Parameter added.} % \changes{1.1}{2004/08/22}{Optional parameter added.} % % \begin{macrocode} \long\def\colchunk@[#1]#{% % \end{macrocode} % % We check if the optional parameter is not empty. Then we use it as % the column number, otherwise we simply pick the next column: % % \begin{macrocode} \ifx\\#1\\% \advance\pc@columnctr\@ne% \else% \pc@columnctr#1\relax% \fi% % \end{macrocode} % % If we try to add a column past the last one, we display an error % message: % % \begin{macrocode} \ifnum\pc@columnctr>\pc@columncount% \PackageError{parcolumns}{The column \number\pc@columnctr\space% is too large}{Only \number\pc@columncount\space columns are% \space allowed.} % \end{macrocode} % % As we cannot simply skip the chunk (we could gobble what follows % after the macro, but this would require a lot of jumping, and just % for handling a small mistake \ldots), we simply set the last column: % % \changes{1.0.1}{2004/08/10}{Error handling somewhat improved.} % % \begin{macrocode} \pc@columnctr\pc@columncount% \fi% % \end{macrocode} % % We zero the |\clubpenalty| that could have been changed, i.e. by % |\everypar| of a |\section|-command: |\section| changes the % clubpenalty to prevent a break between the first two lines of the % paragraph following immediately after the section; as we split off % line after line when typesetting the two columns, this would make % splitting of a single line impossible (|\vsplit| uses the same logic % as page-breaking), thus resulting in a lot of overfull vboxes and % weird spacing inbetween, as \emph{two} lines would be split off. % % We do this every time we add chunks just in case some macro in the % chunks has changed |\clubpenalty|. Note that we cannot prevent a % macro in the text of the chunk to change the % |\clubpenalty|.\footnote{Well we could, by redefining the % clubpenalty to be a macro that simply throws its parameter away, and % using some tricks to make this macro behave like a register, % therefore completely ignoring any change of the clubpenalty.} But if % it is changed, at least it will not stay changed (though the typeset % columns will still look bad). % % \changes{1.0.1}{2004/08/09}{clubpenalty is always reset before % adding chunks} % % \begin{macrocode} \clubpenalty\z@% % \end{macrocode} % % The same goes for the other penalties \TeX\ will insert between two % lines, as we absolutely, positively \emph{must} be able to break % between any two lines:\footnote{C.f. chapter 14 of the \TeX book} % % \changes{1.2}{2004/11/25}{other penalties added} % % \begin{macrocode} \interlinepenalty\z@% \displaywidowpenalty\z@% \widowpenalty\z@% \brokenpenalty\z@% % \end{macrocode} % % We set |\everypar| to our self-defined |\pc@everypar| to suppress % the indentation of the first paragraph if so desired: % % \begin{macrocode} \everypar\expandafter{\the\pc@everypar}% % \end{macrocode} % % After the next assignment, insert the width of the column: % % \begin{macrocode} \afterassignment\pc@setcolumnwidth% % \end{macrocode} % % We typeset the chunk's text into the box |\pc@column@|\meta{column % counter}. The text of the chunk follows the macro, meaning that the % last line looks like this: |\vbox{|\meta{chunk text}|}|. % % But what about the width of the box? |\hsize| must be set in the % vbox in order to make it the correct width! We achieve this using % the |\afterassignment| above: After the assignment of the chunk's % text to the box, we are inside the box, therefore the contents of % |\pc@setcolumnwidth| is inserted at the very beginning of the vbox, % setting the correct width. % % Why don't we simply make |\colchunk| take one parameter that % contains the text of the chunk? Because in that case, macros that % change catcodes like |\verb| would be prohibited, which would % restrict this package somewhat. Also it would be slower and would % use more memory. % % \begin{macrocode} \expandafter\setbox\csname pc@column@\number\pc@columnctr\endcsname% \vbox% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\colplacechunks} % % Places all chunks set with |\colchunk|. % % \begin{macrocode} \newcommand{\colplacechunks}{% % \end{macrocode} % % If there are any chunks to place: % % \begin{macrocode} \ifnum\pc@columnctr>\z@% % \end{macrocode} % % We place them: % % \begin{macrocode} \pc@placeboxes% % \end{macrocode} % % We reset the column counter: % % \begin{macrocode} \pc@columnctr\z@% % \end{macrocode} % % We clear |\pc@everypar|, because we only want to suppress the % indentation of the first paragraph of each column at the very top of % the |parcolumns| environment, not of the first paragraph of every % call to |\colchunk|. % % \begin{macrocode} \pc@everypar{}% \fi% } % \end{macrocode} % \end{macro} % % % % % \subsection{Internal environments and macros} % % \begin{macro}{\pc@placeboxes} % % Places the prepared boxes (containing the chunks) on the page. % % \begin{macrocode} \def\pc@placeboxes{% % \end{macrocode} % % We assume we don't have to perform another line (|\@tempa| contains % what we have to to after we are finished with this macro). The % assignment is global because later on when changing |\@tempa| we are % in a group: % % \begin{macrocode} \global\let\@tempa\relax% \count@\z@% % \end{macrocode} % % We create a hbox. Inside a hbox, vboxes are put horizontally % next to each other and are aligned on their baseline: % % \begin{macrocode} \hb@xt@\linewidth{% % \end{macrocode} % % Before doing any work, we change a few parameters: % % \changes{1.2}{2004/11/22}{moved parameter changes from begin of % environment} % % We prevent warnings of overfull and underfull vboxes as they can % happen, but we do not really care (happens when we |\vsplit| the top % off the chunks, this is okay): % % \changes{1.2}{2004/11/22}{vfuzz increased to prevent warnings with % math} % % \changes{1.2}{2004/11/22}{vbadness set} % % \begin{macrocode} \vfuzz30ex % \vbadness\@M% % \end{macrocode} % % We prevent vertical glue to be insert when |vsplit|ting a vbox % (otherwise it screws up the spacing). % % \begin{macrocode} \splittopskip\z@skip% % \end{macrocode} % % Now we loop over all the prepared boxes. We can use |\loop| here as % we are in a group (begun by |\hbox|). Otherwise we would have to % open a group manually or loop manually, as to not screw up a |\loop| % outside the macro: % % \begin{macrocode} \loop\ifnum\count@<\pc@columncount% \advance\count@\@ne% % \end{macrocode} % % If the box |\pc@column@|\meta{counter} is empty, we simply insert a % hskip the width of the box (saved in % |\pc@column@width@|\meta{counter}): % % \begin{macrocode} \expandafter\ifvoid\csname pc@column@\number\count@% \endcsname% \hskip\csname pc@column@width@\number\count@\endcsname% \else% % \end{macrocode} % % Otherwise we |\vsplit| the first line of the box (at the same time % removing it from |\pc@column@|\meta{counter}) and save it in % |\@tempboxa|. Then, we strip this resulting box of its enclosing % vbox and put it into another vbox, which we put into the hbox begun % a few lines ago. % % Why is this so complicated? To ensure that proper vertical glue is % inserted (otherwise the spacing between the lines would be wrong). % % \begin{macrocode} \expandafter\setbox\expandafter\@tempboxa\expandafter% \vsplit\csname pc@column@\number\count@\endcsname% to \dp\strutbox% \vbox{\unvbox\@tempboxa}% \fi% % \end{macrocode} % % If the remaining box is not empty, we have to perform at least % another line: % % \begin{macrocode} \expandafter\ifvoid\csname pc@column@\number\count@% \endcsname\else% \global\let\@tempa\pc@placeboxes% \fi% % \end{macrocode} % % If this is not the last column, we put a strut into the hbox to % ensure propery vertical spacing: % % \begin{macrocode} \ifnum\count@<\pc@columncount% \strut% % \end{macrocode} % % If a vertical line should be placed between two columns, we insert % it now, centering it between two |\hfill|s. Otherwise, we simply % insert a |\hfill| that stretches as much as possible, pushing the % right column to the right margin. (see also section \ref{sec:Notes} % on page \pageref{sec:Notes}) % % \begin{macrocode} \hfill% \ifpc@rulebetween% \vrule% \hfill% \fi% \fi% \repeat% }% % \end{macrocode} % % If necessary, we perform another line: % % \begin{macrocode} \@tempa% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\pc@alloccolumns} % % Allocates a number of |\box|es, named |\pc@column@1|, |\pc@column@2| % et cetera, if not already allocated. % % Also allocates a number of |\dimen|s, named |\pc@column@width@1| et % cetera. % % If the |\box|es and |\dimen|s are already allocated, they are % cleared (|\box|es) or set to zero (|\dimen|s). % % \begin{macrocode} \def\pc@alloccolumns{% \count@\z@% \loop\ifnum\count@<\pc@columncount% \advance\count@\@ne% \@ifundefined{pc@column@\number\count@}{% \expandafter\newbox\csname pc@column@\number\count@% \endcsname% \expandafter\newdimen\csname pc@column@width@\number% \count@\endcsname% }{% \setbox0\box\csname pc@column@\number\count@\endcsname% \csname pc@column@width@\number\count@\endcsname\z@% }% \repeat% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\pc@setcolumnwidths} % % Sets the widths of all columns. The defined widths have been % temporarily stored in |\toks@|. |\@tempdimc| contains the space % between two columns. % % \begin{macrocode} \def\pc@setcolumnwidths{% \expandafter\processkeyvalues\expandafter{\the\toks@}% \pc@setsinglecolwidth% % \end{macrocode} % % |\@tempdima| will contain the total width of all columns that have a % known width (read: have had their width set via the parameter % |colwidths|) % % \begin{macrocode} \@tempdima\z@% % \end{macrocode} % % |\@tempcnta| will contain the count of columns that an unknown width % (read: have had their width \emph{not} set via the parameter % |colwidths|, thus now having a width of zero points, as the widths % of all columns have been reset in |\pc@alloccolumns|): % % \begin{macrocode} \@tempcnta\z@% % \end{macrocode} % % We calculate the total width of all columns known. We count how many % columns have an unknown width: % % \begin{macrocode} \count@\z@% \loop\ifnum\count@<\pc@columncount% \advance\count@\@ne% \@tempdimb\csname pc@column@width@\number\count@\endcsname% \advance\@tempdima\@tempdimb% \ifnum\@tempdimb=\z@% \advance\@tempcnta\@ne% \else% \PackageInfo{parcolumns}{Width of column \number\count@% \space set to \the\@tempdimb} \fi% \repeat% % \end{macrocode} % % If at least one column has an unknown width: % % \begin{macrocode} \ifnum\@tempcnta>\z@% % \end{macrocode} % % |\@tempdimc| contains the distance between columns. We calculate the % space left for the columns with an unknown width. % % |\@tempdimb| will contain the sum of the space between all the % columns \ldots % % \begin{macrocode} \@tempdimb\@tempdimc% \multiply\@tempdimb\pc@columncount% \advance\@tempdimb-\@tempdimc% % \end{macrocode} % % \ldots\ plus the sum of the width of all columns with a known width: % % \begin{macrocode} \advance\@tempdimb\@tempdima% % \end{macrocode} % % |\@tempdima| will contain the space for each column with an unknown % width: % % \begin{macrocode} \@tempdima\linewidth% \advance\@tempdima-\@tempdimb% \divide\@tempdima\@tempcnta% % \end{macrocode} % % We set the widths of the colums with an unknown width: % % \begin{macrocode} \count@\z@% \loop\ifnum\count@<\pc@columncount% \advance\count@\@ne% \ifnum\csname pc@column@width@\number\count@\endcsname=\z@% \csname pc@column@width@\number\count@\endcsname\@tempdima% \PackageInfo{parcolumns}{Width of column \number\count@% \space calculated as \the\@tempdima} \fi% \repeat% \fi% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\pc@setsinglecolwidth} % % Usage: |\pc@setsinglecolwidth| \marg{column} \marg{width}. % % Sets the width of the column \meta{column} to the width % \meta{width}. Displays an error message if the column is not valid. % % \begin{macrocode} \def\pc@setsinglecolwidth#1#2{% \@ifundefined{pc@column@width@\number#1}{ \PackageError{parcolumns}{`#1' is not a valid column number!}% {\@ehc}% }{% \csname pc@column@width@\number#1\endcsname=#2\relax% }% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\pc@setcolumnwidth} % % Sets |\hsize| to the width of a column (stored in % |\pc@column@width@|\meta{pc@columnctr}) and enters horizonal mode. % % \changes{1.2}{2004/11/22}{linewidth set, too} % % \begin{macrocode} \def\pc@setcolumnwidth{% \hsize\csname pc@column@width@\number\pc@columnctr\endcsname% \linewidth\hsize% \leavevmode% } % \end{macrocode} % \end{macro} % % % \Finale % \PrintChanges % \PrintIndex \endinput