
Я работаю в двухколоночной многоколоночной среде и пытаюсь создать pullquotes с помощью wrapfig. Проблема в том, что я хочу, чтобы эти pullquotes висели на полях: на левом поле, если я в левом столбце, на правом поле, если я в правом.
Есть ли способ определить текущий номер столбца, чтобы я мог сказать wrapfig: "Повесить фигуру слева, если номер столбца = 1, и повесить ее справа, если номер столбца = 2"? У меня много такого текста, и было бы довольно утомительно устанавливать все это вручную.
Я пробовал это использоватьпакет pullquote, но пока что получил кучу ошибок микротипа (я использую XeLaTeX).
Редактировать: что-то вроде MWE будет выглядеть так, очевидно, \imaginarycolumnnumberidentifier
это то, что мне нужно. Очевидно, что это не "рабочий" пример, и я на самом деле не пробовал использовать etoolbox раньше, так что могут быть и другие проблемы с этим кодом, но вы поняли идею.
\documentclass{article}
\usepackage{multicol}
\usepackage{wrapfig}
\usepackage{lipsum}
\usepackage{etoolbox}
\newenvironment{pquote}{%
\begin{wrapfigure}[3]{%
\ifnumequal{1}{\imaginarycolumnnumberidentifier}{l}{r}%
}[0.2\columnwith]{0.4\columnwidth}
}{%
\end{wrapfigure}}
\begin{document}
\begin{multicols}{2}
\lipsum[1]
\begin{pquote}
Lorem ipsum!
\end{pquote}
\lipsum[2]
\begin{pquote}
dolor sit amet!
\end{pquote}
\lipsum[3]
\end{multicols}
\end{document}
У меня недостаточно репутации, чтобы разместить изображение, так что вам придется просто представить себе результат! Поверьте мне, первая цитата слева, а вторая цитата справа. В моем представлении.
решение1
Позвольте мне показать вам, как реализовать это для twocolumn
макетов, а не через multicol
пакет. Это исправит некоторые из ваших проблем с кодированием.
\documentclass[twocolumn]{article}
\usepackage{wrapfig}
\usepackage{lipsum}
\makeatletter
\newenvironment{pquote}[1][\relax]{%
\ifx#1\relax\def\@mypl{\if@firstcolumn l\else r\fi}%
\else\def\@mypl{#1}\fi%
\wrapfigure[3]{\@mypl}[0.2\columnwidth]{0.4\columnwidth}%
\large\bfseries}{\par\endwrapfigure}
\makeatother
\begin{document}
\lipsum[1]
\begin{pquote}
Lorem ipsum!
\end{pquote}
\lipsum[2-4]
\begin{pquote}
Dolor sit amet!
\end{pquote}
\lipsum[5-8]
\begin{pquote}[r]
Mauris ut est.
\end{pquote}
\lipsum[9]
\end{document}
Ваш общий метод установки pquote
на вариант wrapfigure
использования \begin{wrapfigure}
, к сожалению, не работает, как вы увидите, создав простой тестовый документ с фиксированным позиционированием. Это связано с тем, как обрабатываются аргументы. Вместо этого используйте \wrapfigure
с соответствующими аргументами и balacnce его с \endwrapfigure
. Более того, аргумент позиционирования должен расширяться непосредственно до одной из разрешенных строк, поэтому это должно быть сделано через промежуточный макрос.
Теперь у twocolumn
нас есть тест \if@firstcolumn
, который можно использовать для определения позиционирования. К сожалению, он не на 100% защищен от дурака, поэтому мое определение выше предоставляет необязательный аргумент, позволяющий вам принудительно задать позиционирование.
В multicols
вещи гораздо сложнее, и я не вижу легкодоступной переменной для этого. По сути, multicol
набирает материал в один длинный ящик, а затем отделяет правильное количество сверху для каждого столбца. Есть некоторые внутренние переменные, которые ведут подсчет количества столбцов, но они нелегкодоступны. Кроме того, multicol
выполняет некоторую балансировку столбцов, пытаясь разделить данный набранный материал на несколько ящиков одинаковой высоты, если набор должен измениться в процессе, то это более сложно. Одним из симптомов этого является то, что \marginpar
s не разрешены в multicols
, см. документацию пакета, тогда как в twocolumn
margin pars работают (довольно) хорошо, переключая стороны по мере необходимости.
ДОБАВЛЕНИЕв ответ на комментарий:
Если вы хотите использовать multicols
и готовы указать размещение, то кодирование упрощается, но все равно необходимо избегать \begin{wrapfigure}
:
\documentclass{article}
\usepackage{multicol,ragged2e}
\usepackage{wrapfig}
\usepackage{lipsum}
\makeatletter
\newenvironment{pquote}[2]{%
\wrapfigure[#1]{#2}[0.2\columnwidth]{0.4\columnwidth}%
\large\bfseries\Centering}{\par\endwrapfigure}
\makeatother
\begin{document}
\begin{multicols}{2}
\lipsum[1]
\begin{pquote}{4}{l}
Lorem ipsum!
\end{pquote}
\lipsum[2-4]
\begin{pquote}{6}{r}
Dolor sit amet!
\end{pquote}
\lipsum[5-8]
\begin{pquote}{5}{r}
Mauris ut est.
\end{pquote}
\lipsum[9]
\end{multicols}
\end{document}
решение2
Как Эндрю заметил в своем ответе, решение для многоколонок гораздо сложнее, поскольку "текущая" колонка вообще неизвестна во время набора текста. Поэтому .aux
требуется довольно сложный подход с несколькими запусками набора текста (с использованием файла).
Ниже представлен первый черновик решения, обеспечивающего \docolaction{left}{middle}{right}
выполнение условного кода в зависимости от типа столбца. Если тип столбца еще не известен, то предполагается первый столбец (по умолчанию).
\begin{filecontents}{mccolaction.sty}
%
% \begin{macrocode}
\ProvidesPackage{mccolaction}
[2013/05/05 v0.9b column actions for multicolumn formatting (FMi)]
% \end{macrocode}
%
% \begin{macrocode}
\RequirePackage{etoolbox}
\RequirePackage{multicol}[2011/12/20]
% \end{macrocode}
%
% Determining the current column in multicols is difficult because
% (in contrast to the twocolumn mode of standard LaTeX) the
% multicols columns are determined very late in the game and due to
% the balancing routine it is not known where a piece of text is
% going to end up at the time the text is typeset. Only afterwards,
% when everything has be typeset into a single long galley, that
% galley is split into individual columns (at the very end in a
% possibly huge set of trials to balance the column material.
%
% Therefore the approach taken here is to write out a single line
% into the .aux file whenever a column is finally typeset:
%\begin{verbatim}
% \mc@col@status{<number>}
%\end{verbatim}
% The number in the argument denotes the different kind of column: 1
% for left column 2 for any middle column and 3 for the final column.
%
% We only set this up for the LR typesetting case here, something
% similar could be done for the RL version:
% \begin{macrocode}
\patchcmd{\LR@column@boxes}{\box\count@}
{\protected@write\@auxout{}{\string\mc@col@status
{\ifmc@firstcol 1\else 2\fi}}%
\mc@firstcolfalse
\box\count@}
{\typeout{juhu!}}{\typeout{oje!}}%
\patchcmd{\LR@column@boxes}{\box\mult@rightbox}
{\protected@write\@auxout{}{\string\mc@col@status{3}}%
\box\mult@rightbox}%
{\typeout{juhu!}}{\typeout{oje!}}%
\newif\ifmc@firstcol
\mc@firstcoltrue
% \end{macrocode}
%
% Need to reinitiate \verb=\mc@align@columns= as this was let to
% the old definition of \verb=\LR@column@boxes=.
%
% \begin{macrocode}
\LRmulticolcolumns
% Whenever we want to do something that depends on the current
% column we execute \verb=\docolaction=. This command takes one
% optional and three mandatory arguments. The mandatory ones denote
% what to do if this is a ``left'', ``middle'', or ``right'' column
% and the optional one is simply there to say what to do if we don't
% know (default is to use the ``left'' column action in that case).
%
% We use one counter \verb=\mc@col@check@num= to generate us unique
% label names. Each time we execute \verb=\docolaction= we increment
% this counter to get a new name.
% \begin{macrocode}
\newcount\mc@col@check@num
% \end{macrocode}
% The generated ``labels'' are named
% \verb=\mc@col-\the\mc@col@check@num= and they hold as values the
% numbers 1, 2, or 3 denoting the current column type.
% \begin{macrocode}
\newcommand\docolaction[4][1]{%
\global\advance\mc@col@check@num\@ne
\edef\mc@col@type{\expandafter\ifx
\csname mc@col-\the\mc@col@check@num\endcsname\relax
0\else
\csname mc@col-\the\mc@col@check@num\endcsname
\fi}%
% \end{macrocode}
% We prefix with 0 so that an unknown label (that returns
% \verb=\relax=) will result in case 0
% \begin{macrocode}
\ifcase \mc@col@type\relax
% \end{macrocode}
% If column is unknown we use the default action or the action
% denoted by the optional argument (so that arg can take the value
% 1, 2, 3)
% \begin{macrocode}
\ifcase #1\or #2\or#3\or#4\fi % 0 not known use first col as default
\or
% \end{macrocode}
% Otherwise we know (or think we know) that this is a first, middle,
% or last column:
% \begin{macrocode}
#2% % 1 First col
\or
#3% % 2 any middle col
\or
#4% % 3 last col
\else
\ERROR
\fi
% \end{macrocode}
% But how does the column number get associated with our label? We
% do do this by writing another line into the aux file at this point:
% \begin{macrocode}
\edef\next{\write\@auxout
{\string\mc@set@col@status{mc@col-\the\mc@col@check@num}%
{\mc@col@type}}}%
\next
}
% \end{macrocode}
%
% Because of extra data writing to the aux file the aux file will
% now contain something like the following after the document is
% processed the first time:
%\begin{verbatim}
%\relax
%\mc@col@status{1}
%\mc@set@col@status{lcol-1}{0}
%\mc@col@status{2}
%\mc@set@col@status{lcol-2}{0}
%\mc@col@status{3}
%\mc@set@col@status{lcol-3}{0}
%\mc@col@status{1}
%\mc@col@status{2}
%\mc@col@status{3}
%\mc@set@col@status{lcol-4}{0}
%\end{verbatim}
% The \verb=\mc@col@status= line denotes the column type and has been
% writting out just before corresponding the column box was placed
% onto the page.
% The\verb=\mc@set@col@status= lines have been written out as part
% of shipping the column boxes out, e.g.,
% \verb=\mc@set@col@status{lcol-1}{0}= was therefore somewhere within
% the first column as it appears between \verb=\mc@col@status{1}=
% and \verb=\mc@col@status{2}=
% The second argument in that line is the value used in the previous
% run (or zero if there was no previous run. We can use this to
% determine if a rerun is necessary.
%
% Thus with this knowledge we can set things up to get the labels
% working.
%
% When the aux file is read in \verb=\mc@col@status= is used to set
% \verb=\mc@curr@col@status=:
%
% \begin{macrocode}
\def\mc@col@status#1{\gdef\mc@curr@col@status{#1}}
% \end{macrocode}
% And when \verb=\mc@set@col@status= is executed we can simply set
% up the label by associating it with the \verb=\mc@curr@col@status=
% and ignore the second argument:
% \begin{macrocode}
\def\mc@set@col@status#1#2{%
\global\expandafter\let\csname #1\endcsname\mc@curr@col@status}
% \end{macrocode}
%
% The above definition is being used when the \texttt{.aux} file is
% read in at the beginning. At the end we need a different
% definition to test if another typesetting run is needed. There we
% compare the value used in the current run (stored in the second
% argument) with the value used on the next run. If those two values
% differ we set \verb=@tempswa= to false which will trigger the
% ``Label(s) may have changed'' warning.
% \begin{macrocode}
\AtEndDocument{\def\mc@set@col@status#1#2{%
\ifnum #2=\mc@curr@col@status\else
\@tempswatrue
\fi}%
}
% \end{macrocode}
\end{filecontents}
\documentclass{article}
\usepackage{mccolaction}
\usepackage{wrapfig}
\usepackage{lipsum}
% An application of \docolaction. We put the whole wrapfigure into the
% args so that the internal label used is placed after wrapfigure.
\newcommand\pquote[2]{%
\docolaction
{\begin{wrapfigure}[#1]{l}[0.2\columnwidth]{0.4\columnwidth}%
\raggedright\large\bfseries #2\end{wrapfigure}}%
{\begin{wrapfigure}[#1]{l}[0pt]{0.4\columnwidth}%
\raggedright\large\bfseries #2\end{wrapfigure}}%
{\begin{wrapfigure}[#1]{r}[0.2\columnwidth]{0.4\columnwidth}%
\raggedright\large\bfseries #2\end{wrapfigure}}%
\ignorespaces
}
\setlength\columnseprule{.7pt}
\setlength\emergencystretch{2em}
\begin{document}
\begin{multicols}{3}
\lipsum[1]
\pquote{4}{Lorem ipsum!}
\lipsum[2]
\pquote{5}{Dolor sit amet!}
\lipsum[4-5]
\pquote{4}{Mauris ut est.}
\lipsum[6-7]
Only a few words left \ldots
Here the pquote comes in the middle of the paragraph for a change
\pquote{6}{Final test related to the edge}
as we can see. Only a few words left so this drops off the column \ldots
\end{multicols}
\end{document}
Если мы запустим этот файл, то получим
Вторая страница показывает, что не все будет идеально, но в данном случае это связано с тем, что я намеренно поместил текст \pquote
слишком близко к концу.
Если мы изменим файл так, чтобы он использовал 4 столбца, то в итоге получим одну разрезанную на столбцы обертку, что явно не позволяет двум пакетам работать вместе достаточно хорошо, чтобы решить эту проблему автоматически.
Подводя итог, я бы сказал, что работает достаточно хорошо. В сочетании с чем-то вроде этого wrapfigure
местами понадобится некоторая помощь, но это ожидаемо, так как wrapfigure
нет понятия о мультиколонках, разделяющих столбцы позже.
Обновлять
Я немного улучшил код, так что теперь он также отслеживает любые изменения в типах столбцов. Если из-за этого будет обнаружена необходимость в еще одном запуске LaTeX, он выдаст известное предупреждение "Label(s) might have changed. Rerun to get cross-references right."
Таким образом, вывод, подобный следующему, должен происходить только в том случае, если пользователь игнорирует это предупреждение.
Обновление 2
Вышеуказанная версия mccolaction
была написана для версии SVN, которая в данный момент отсутствует на CTAN. В ответРазрыв столбца только в пределах первого столбца многоколоночного текстаЯ предоставил обновленный пакет, который работает с обеими версиями multicol
.
Обновление 3
Описанная выше функциональность теперь доступна в multicol версии 1.8 и выше. Она не включается автоматически (так как она затратная) --- вам нужно запросить ее с помощью опции colaction
. После этого \docolaction
включается для использования в вашем документе.