Detectando coluna atual em multicol

Detectando coluna atual em multicol

Estou trabalhando em um ambiente multicol de duas colunas e tentando criar pullquotes usando wrapfig. O problema é que eu gostaria que essas aspas ficassem na margem: a margem esquerda se eu estiver na coluna da esquerda, a margem direita se eu estiver na coluna da direita.

Existe alguma maneira de detectar o número da coluna atual, para que eu possa dizer ao wrapfig: "Pendure a figura à esquerda se o número da coluna = 1 e pendure-a à direita se o número da coluna = 2"? Eu tenho muitos textos desse tipo e seria muito tedioso definir tudo isso manualmente.

Eu tentei usar issopacote pullquote, mas até agora recebi vários erros de microtipo (estou usando o XeLaTeX).

Editar: uma espécie de MWE ficaria assim, obviamente \imaginarycolumnnumberidentifieré o que procuro. É claro que este não é um exemplo "funcional" e, na verdade, nunca tentei usar o etoolbox antes, portanto pode haver outros problemas com esse código, mas essa é a ideia.

\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}

Não tenho reputação suficiente para postar uma imagem, então você só precisa imaginar o resultado! Acredite em mim, a primeira cotação está no lado esquerdo e a segunda cotação está no lado direito. Em minha mente.

imagem

Responder1

Deixe-me mostrar como implementar isso para twocolumnlayouts, e não por meio do multicolpacote. Isso corrigirá alguns dos seus problemas de codificação.

Exemplo de saída

\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}

Infelizmente, seu método geral de configuração pquotepara uma variação de wrapfigureuso \begin{wrapfigure}não funciona, como você verá ao criar um documento de teste simples com posicionamento fixo. Isso tem algo a ver com a forma como os argumentos são processados. Em vez disso, use \wrapfigurecom os argumentos apropriados e equilibre-os com \endwrapfigure. Além disso, o argumento de posicionamento precisa ser expandido diretamente para uma das strings permitidas, portanto isso deve ser feito através de uma macro intermediária.

Agora twocolumntemos o teste \if@firstcolumnque pode ser usado para determinar o posicionamento. Infelizmente não é 100% infalível, então minha definição acima fornece um argumento opcional que permite forçar o posicionamento.

As multicolscoisas são um pouco mais complicadas e não vejo nenhuma variável facilmente acessível para fazer isso. Essencialmente, multicolcompõe o material em uma caixa longa e, em seguida, divide a quantidade correta do topo para cada coluna. Existem algumas variáveis ​​internas que mantêm a contagem do número da coluna, mas elas não são facilmente acessíveis. Além disso, multicolfaz algum balanceamento de colunas, tentando dividir o material da composição em um número de caixas de igual altura, se a composição for alterada no processo, então isso é mais complicado. Um sintoma disso é que \marginpars não são permitidos no multicols, consulte a documentação do pacote, enquanto em twocolumnmargin pars funcionam (razoavelmente) alternando bem os lados conforme necessário.

ADIÇÃOem resposta ao comentário:

Se você quiser usar multicolse estiver preparado para especificar o posicionamento, a codificação será mais simples, mas ainda assim será necessário evitar \begin{wrapfigure}:

Exemplo de saída multicol

\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}

Responder2

Como Andrew observou em sua resposta, uma solução para multicols é um pouco mais complicada, pois a coluna "atual" não é conhecida durante a composição. Portanto, é necessária uma abordagem bastante complicada com múltiplas execuções de composição tipográfica (usando o .auxarquivo).

Abaixo está um primeiro rascunho de uma solução que prevê \docolaction{left}{middle}{right}a execução de código condicional dependendo do tipo de coluna. Se o tipo de coluna ainda não for conhecido, a primeira coluna será assumida (como padrão).

\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}

Se executarmos este arquivo, obteremos

insira a descrição da imagem aqui

A segunda página mostra então que nem tudo será perfeito, mas neste caso isso se deve ao fato de eu ter colocado deliberadamente \pquotemuito perto do final.

insira a descrição da imagem aqui

Se alterarmos o arquivo para usar 4 colunas, acabaremos com um wrapfigure cortado nas colunas, claramente algo em que os dois pacotes não funcionam juntos bem o suficiente para resolver isso automaticamente.

insira a descrição da imagem aqui

Em resumo, eu diria que funciona bem o suficiente. Em combinação com algo parecido, wrapfigureserá necessária alguma ajuda em alguns lugares, mas isso é de se esperar, pois wrapfigurenão há ideia de que multicols dividirá as colunas posteriormente.

Atualizar

Melhorei um pouco o código, para que agora ele também acompanhe quaisquer alterações nos tipos de colunas. Se devido a isso for detectada a necessidade de outra execução do LaTeX, será gerado o conhecido aviso "Rótulo(s) pode(m) ter sido alterado(s). Execute novamente para obter referências cruzadas corretas."

Portanto, uma saída como a seguinte só deve acontecer se o usuário ignorar esse aviso.

insira a descrição da imagem aqui

Atualização II

A versão acima mccolactionfoi escrita contra a versão SVN que não está no CTAN no momento. Em respostaQuebra de coluna somente se estiver na primeira coluna de multicolForneci um pacote atualizado que funciona com ambas as versões do multicol.

Atualização III

A funcionalidade descrita acima está agora disponível no multicol versão 1.8 e superior. Não é ativado automaticamente (pois é caro) --- você deve solicitá-lo usando a opção colaction. Depois \docolactionestá habilitado para uso em seu documento.

informação relacionada