4

I want to put a small circle with a letter at the margin in a two-column document. To decide in which margin this bullet goes, I use \if@firstcolumn.

It works most of the time, but it sometimes goes wrong in the first paragraph of a new colum. It seems \if@firstcolumn delays a little to be updated.

I currently use the option twocolumn with article. I don't intend to switch to package multicol, to which a solution seems to be available here.

How can I truly know the current column?

My MWE. I don't want the red arrow; it's there only for visualization. This code actually puts a list of bullets. This MWE produces the issue from the second page.

\documentclass[12pt,a4paper,twocolumn]{article}
\usepackage[utf8]{inputenc}
\usepackage[paper height = 10cm]{geometry}

\usepackage{tikz}
\usetikzlibrary{calc, tikzmark}
\newcounter{nivel}
\makeatletter
\newcommand{\niveis}[1]{%
    \if@twocolumn%
        \if@firstcolumn%
            \def\ancora{east}%
            \def\margem{west}%
            \def\deslocamento{+2.25cm}%
        \else%
            \def\ancora{west}%
            \def\margem{east}%
            \def\deslocamento{-2.25cm}%
        \fi%
    \fi%
    \stepcounter{nivel}%
    \tikzmark{exercicio-\thenivel}%
    \begin{tikzpicture}[overlay, remember picture,
        every node/.style = {
            align = center,
            font=\footnotesize\bfseries\sffamily\color{white},
            anchor = center,
        },
        ]
        \coordinate (base) at
            ($(current page.\margem|-{pic cs:exercicio-\thenivel})
            + (\oddsidemargin+\hoffset\deslocamento, 0)$);
        \foreach \n[count = \k from 0] in {#1}{
            \coordinate (item) at ($(base) - (0, 0.6cm * \k)$);
            \draw[thick, red, <-] ({pic cs:exercicio-\thenivel}) -- (item);
            \path[fill = black!75] (item) circle (0.25cm);
            \node at (item) {\n};
        }
    \end{tikzpicture}%
}
\newcommand{\whichcolumn}{\if@firstcolumn LEFT\else RIGHT\fi}
\makeatother

\begin{document}

\foreach \i in {1, ..., 50}{
    \whichcolumn (\i)\niveis{A, B} Lorem ipsum dolor sit amet, consectetur adipiscing elit. Um enim ad minim veniam, quis nostrud exercitation ullamco is in the \whichcolumn\ column.\par%
}

\end{document}
Werner
  • 603,163
Jander
  • 1,128

1 Answers1

2

The following code adaptation uses zref's savepos module to store the x-coordinate on the left side of the text you're placing (LEFT or RIGHT). This x-coordinate is used to identify whether you're in the left/right column, depending on whether it's less than or greater than (or equal to) 50% of the page width. Since you're using tikz already, you can use tikzmark as well. I'm just not as familiar with it as much as zref-savepos.

With the first compilation, all elements are considered LEFT, since the x-coordinate has not been stored and recalled successfully. Over the next couple of compilation, this changes, with elements shifting to the RIGHT as needed. This increases the text in some paragraphs, leading to differing overflow between left/right columns, and consequently differing placements of the tikz arrows and text boxes. In short, you'll have to compile a couple of times until these references "settle." Once that's the case, there only changes in the marking locations may cause additional compilations.

enter image description here

\documentclass[12pt,a4paper,twocolumn]{article}

\usepackage[paper height = 10cm]{geometry}

\usepackage{zref-savepos}

\newcounter{columncheck}

\usepackage{tikz}
\usetikzlibrary{calc, tikzmark}
\newcounter{nivel}
\makeatletter
\newcommand{\niveis}[1]{%
  \if@twocolumn%
    \leftorright{%
      \def\ancora{east}%
      \def\margem{west}%
      \def\deslocamento{+2.25cm}%
    }{%
      \def\ancora{west}%
      \def\margem{east}%
      \def\deslocamento{-2.25cm}%
    }%
  \fi%
  \stepcounter{nivel}%
  \tikzmark{exercicio-\thenivel}%
  \begin{tikzpicture}[overlay, remember picture,
    every node/.style = {
      align = center,
      font=\footnotesize\bfseries\sffamily\color{white},
      anchor = center,
    },
    ]
    \coordinate (base) at
      ($(current page.\margem|-{pic cs:exercicio-\thenivel})
      + (\oddsidemargin+\hoffset\deslocamento, 0)$);
    \foreach \n[count = \k from 0] in {#1}{
      \coordinate (item) at ($(base) - (0, 0.6cm * \k)$);
      \draw[thick, red, <-] ({pic cs:exercicio-\thenivel}) -- (item);
      \path[fill = black!75] (item) circle (0.25cm);
      \node at (item) {\n};
    }
  \end{tikzpicture}%
}
\newcommand{\whichcolumn}{%
  \stepcounter{columncheck}%
  \zsaveposx{columncheck-\thecolumncheck}%
  \ifdim.5\paperwidth > \zposx{columncheck-\thecolumncheck}sp
    LEFT%
    \let\leftorright\@firstoftwo
  \else
    RIGHT%
    \let\leftorright\@secondoftwo
  \fi
}
\makeatother

\begin{document}

\foreach \i in {1, ..., 50}{
  \mbox{}\whichcolumn (\i)\niveis{A, B} Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
  Um enim ad minim veniam, quis nostrud exercitation ullamco is in the \whichcolumn\ column.\par%
}

\end{document}
Werner
  • 603,163
  • Great. I tried your approach (compare to the page center) unsuccessfully using tikzmark. Totally forgot about zref-savepos. And learned also @firstoftwo... – Jander May 12 '20 at 17:46