Detectando la columna actual en multicol

Detectando la columna actual en multicol

Estoy trabajando en un entorno multicol de dos columnas e intento crear citas pull usando wrapfig. El problema es que me gustaría que estas citas colgaran en el margen: el margen izquierdo si estoy en la columna de la izquierda, el margen derecho si estoy en la columna de la derecha.

¿Hay alguna forma de detectar el número de columna actual, de modo que pueda decirle a wrapfig: "Cuelgue la figura hacia la izquierda si el número de columna = 1 y cuélguela hacia la derecha si el número de columna = 2"? Tengo muchos textos de este tipo y sería bastante tedioso configurarlo todo a mano.

He intentado usar estopaquete de cotización, pero hasta ahora he recibido un montón de errores de microtipo (estoy usando XeLaTeX).

Editar: una especie de MWE se vería así, obviamente \imaginarycolumnnumberidentifieres lo que busco. Claramente, este no es un ejemplo "funcional", y en realidad no he intentado usar etoolbox antes, por lo que podría haber otros problemas con este código, pero ya entiendes la idea.

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

No tengo suficiente reputación para publicar una imagen, ¡así que tendrás que imaginar el resultado! Créame, la primera cita está en el lado izquierdo y la segunda está en el lado derecho. En mi mente.

imagen

Respuesta1

Déjame mostrarte cómo implementar esto para twocolumndiseños en lugar de a través del multicolpaquete. Esto solucionará algunos de sus problemas de codificación.

Salida de muestra

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

Lamentablemente, su método general para configurar pquoteuna variación del wrapfigureuso \begin{wrapfigure}no funciona, como verá al crear un documento de prueba simple con una posición fija. Esto tiene algo que ver con la forma en que se procesan los argumentos. En su lugar, utilícelo \wrapfigurecon los argumentos apropiados y equilibrelo con \endwrapfigure. Además, el argumento de posicionamiento debe expandirse directamente a una de las cadenas permitidas, por lo que esto debe hacerse mediante una macro intermedia.

Ahora twocolumntenemos la prueba \if@firstcolumnque se puede utilizar para determinar el posicionamiento. Lamentablemente no es 100% infalible, por lo que mi definición anterior proporciona un argumento opcional que le permite forzar el posicionamiento.

En multicolsrealidad las cosas son bastante más complicadas y no veo ninguna variable de fácil acceso para hacer esto. Básicamente, multicolescribe el material en un cuadro largo y luego divide la cantidad correcta desde la parte superior para cada columna. Hay algunas variables internas que mantienen la cuenta del número de columna, pero no son fácilmente accesibles. Además, multicolequilibra un poco las columnas, intentando dividir el material tipográfico dado en varias cajas de igual altura; si la composición tipográfica va a cambiar en el proceso, entonces esto es más complicado. Un síntoma de esto es que \marginparlos s no están permitidos en multicols, consulte la documentación del paquete, mientras que en twocolumnlos márgenes funcionan (bastante) bien cambiando de lado según sea necesario.

SUMAen respuesta al comentario:

Si desea utilizar multicolsy está preparado para especificar la ubicación, entonces la codificación es más simple, pero aún así es necesario evitarla \begin{wrapfigure}:

Muestra de salida 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}

Respuesta2

Como Andrew comentó en su respuesta, una solución para multicols es bastante más complicada ya que la columna "actual" no se conoce en absoluto mientras se realiza la composición tipográfica. Por lo tanto .aux, se necesita un enfoque bastante complicado con múltiples ejecuciones tipográficas (usando el archivo).

A continuación se muestra un primer borrador de una solución que permite \docolaction{left}{middle}{right}ejecutar código condicional según el tipo de columna. Si aún no se conoce el tipo de columna, se asume la primera columna (por defecto).

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

Si ejecutamos este archivo obtenemos

ingrese la descripción de la imagen aquí

La segunda página muestra que no todo será perfecto, pero en este caso eso se debe al hecho de que deliberadamente lo coloqué \pquotedemasiado cerca del final.

ingrese la descripción de la imagen aquí

Si cambiamos el archivo para usar 4 columnas, terminamos con una figura envolvente cortada entre columnas, claramente algo en lo que los dos paquetes no funcionan lo suficientemente bien juntos como para resolver esto automáticamente.

ingrese la descripción de la imagen aquí

En resumen, diría que funciona bastante bien. En combinación con algo así, wrapfigurenecesitará algo de ayuda en algunos lugares, pero esto es de esperarse ya que wrapfigureno tiene idea de cómo los multicols dividirán las columnas más adelante.

Actualizar

Mejoré ligeramente el código para que ahora también realice un seguimiento de cualquier cambio en los tipos de columnas. Si debido a esto se detecta la necesidad de otra ejecución de LaTeX, generará la conocida advertencia "Es posible que las etiquetas hayan cambiado. Vuelva a ejecutar para obtener las referencias cruzadas correctas".

Por lo tanto, resultados como el siguiente solo deberían ocurrir si el usuario ignora esa advertencia.

ingrese la descripción de la imagen aquí

Actualización II

La versión anterior mccolactionse escribió con la versión SVN que no está en CTAN en este momento. en respuestaSalto de columna solo si está dentro de la primera columna de multicolProporcioné un paquete actualizado que funciona con ambas versiones de multicol.

Actualización III

La funcionalidad descrita anteriormente ahora está disponible en la versión 1.8 y superior de multicol. No se habilita automáticamente (ya que es costoso) --- debes solicitarlo usando la opción colaction. Posteriormente \docolactionse habilita para su uso en su documento.

información relacionada