Определение текущего столбца в многостолбцовом

Определение текущего столбца в многостолбцовом

Я работаю в двухколоночной многоколоночной среде и пытаюсь создать 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выполняет некоторую балансировку столбцов, пытаясь разделить данный набранный материал на несколько ящиков одинаковой высоты, если набор должен измениться в процессе, то это более сложно. Одним из симптомов этого является то, что \marginpars не разрешены в multicols, см. документацию пакета, тогда как в twocolumnmargin 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включается для использования в вашем документе.

Связанный контент