0

This is the continuation of the question Drawing tikz line in the margin for multiple pages

The code provided by John Kormylo allows to draw a margin decoration in front of a portion of text surrounded by an environment defined in the code. It uses everypage package and seems to work well. Moreover, the environment is breakable, which is very interesting because it can be nested with package which provide breakable boxes. For instance, the decoration can extend on several pages and in the same time, can include breakable boxes (theorem, paragraphs, citations...).

As I mentionned it in the comments, I'd like to use several different types of decoration for different purposes. I tried to duplicate the code, but even when changing all the names (included counters and function chekmarkpage), it doesn't work. In fact, it draws both decorations at the same time. Plus, some environments are ignored...

Here is the code I am using. If anyone could help me to get the things work, I would appreciate :).

\documentclass[a4paper,12pt]{book}
\usepackage{tikzpagenodes}
\usetikzlibrary{calc,tikzmark}
\usepackage{lipsum}
\usepackage{showframe}
\usepackage{everypage}

\makeatletter
\newcommand{\checkmarkpageredenv}[4]% #1 = tikzmark label, #2 = less, #3 = equal, #4 = greater
{\@ifundefined{save@pt@#1}{#2}{%
  \edef\markid{\csname save@pt@#1\endcsname}%
  \edef\markpage{\csname save@pg@\markid\endcsname}%
  \ifnum\thepage<\markpage\relax #2%
  \else
    \ifnum\thepage=\markpage\relax #3%
    \else #4%
    \fi
  \fi}%
}
\makeatother

\newcounter{redenvid}
\newcounter{redenvdone}

\newenvironment{redenv}{\par\tikzmark{begin\theredenvid}\ignorespaces}%
  {\par\tikzmark{end\theredenvid}\stepcounter{redenvid}\ignorespaces}

\newcommand{\drawredenv}{\checkmarkpageredenv{begin\theredenvdone}{}%
  {\begin{tikzpicture}[remember picture,overlay]
    \path ({pic cs:begin\theredenvdone}-| current page text area.west)
      ++(0pt,\ht\strutbox) coordinate(A);
    \checkmarkpageredenv{end\theredenvdone}%
      {\path (current page text area.south west) ++(0pt,-\dp\strutbox)
         coordinate(B);}%
      {\path ({pic cs:end\theredenvdone}-| current page text area.west)
        ++(0pt,\ht\strutbox) coordinate(B);}%
      {}% this should not happen
    \fill[red] ($(A) + (-.1cm,0pt)$) rectangle ($(B) + (-.9cm,0pt)$);
   \end{tikzpicture}}%
  {\begin{tikzpicture}[remember picture,overlay]
    \coordinate (A) at (current page text area.north west);
    \checkmarkpageredenv{end\theredenvdone}%
      {\path (current page text area.south west) ++(0pt,-\dp\strutbox)
         coordinate(B);}%
      {\path ({pic cs:end\theredenvdone}-| current page text area.west)
        ++(0pt,\ht\strutbox) coordinate(B);}%
      {}% this should not happen
    \fill[red] ($(A) + (-.1cm,0pt)$) rectangle ($(B) + (-.9cm,0pt)$);
   \end{tikzpicture}}%
  \checkmarkpageredenv{end\theredenvdone}{}%
    {\stepcounter{redenvdone}\drawredenv}%
    {}% this should not happen
 }
\AddEverypageHook{\drawredenv}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\makeatletter
\newcommand{\checkmarkpageblueenv}[4]% #1 = tikzmark label, #2 = less, #3 = equal, #4 = greater
{\@ifundefined{save@pt@#1}{#2}{%
        \edef\markid{\csname save@pt@#1\endcsname}%
        \edef\markpage{\csname save@pg@\markid\endcsname}%
        \ifnum\thepage<\markpage\relax #2%
        \else
        \ifnum\thepage=\markpage\relax #3%
        \else #4%
        \fi
        \fi}%
}
\makeatother

\newcounter{blueenvid}
\newcounter{blueenvdone}

\newenvironment{blueenv}{\par\tikzmark{begin\theblueenvid}\ignorespaces}%
{\par\tikzmark{end\theblueenvid}\stepcounter{blueenvid}\ignorespaces}

\newcommand{\drawblueenv}{\checkmarkpageblueenv{begin\theblueenvdone}{}%
    {\begin{tikzpicture}[remember picture,overlay]
        \path ({pic cs:begin\theblueenvdone}-| current page text area.west)
        ++(0pt,\ht\strutbox) coordinate(C);
        \checkmarkpageblueenv{end\theblueenvdone}%
        {\path (current page text area.south west) ++(0pt,-\dp\strutbox)
            coordinate(D);}%
        {\path ({pic cs:end\theblueenvdone}-| current page text area.west)
            ++(0pt,\ht\strutbox) coordinate(D);}%
        {}% this should not happen
        \fill[blue] ($(C) + (-1.0cm,0pt)$) rectangle ($(D) + (-1.8cm,0pt)$);
        \end{tikzpicture}}%
    {\begin{tikzpicture}[remember picture,overlay]
        \coordinate (C) at (current page text area.north west);
        \checkmarkpageblueenv{end\theblueenvdone}%
        {\path (current page text area.south west) ++(0pt,-\dp\strutbox)
            coordinate(D);}%
        {\path ({pic cs:end\theblueenvdone}-| current page text area.west)
            ++(0pt,\ht\strutbox) coordinate(D);}%
        {}% this should not happen
        \fill[blue] ($(C) + (-1.0cm,0pt)$) rectangle ($(D) + (-1.8cm,0pt)$);
        \end{tikzpicture}}%
    \checkmarkpageblueenv{end\theblueenvdone}{}%
    {\stepcounter{blueenvdone}\drawblueenv}%
    {}% this should not happen
}

\AddEverypageHook{\drawblueenv}


\begin{document}

\newpage 

\thispagestyle{empty}

Next line begins the rule for BLUE ENV:

\begin{blueenv}
\lipsum[2]
\end{blueenv}

Line above ends the rule for BLUE ENV.

Two on one page for RED ENV:
\begin{redenv}
    \lipsum[3]
\end{redenv}

One on three pages for BLUE ENV:
\begin{blueenv}
\lipsum[4-12]
\end{blueenv}
That's all, folks.

\end{document}
  • The problem is that the blue and red environments are using the same tikzmark names: begin0 and end0 (for example). – John Kormylo Dec 11 '17 at 18:05
  • I understand the type of problem, but my lack of internal language doesn't let me do it myself! :-( Thanks for the code. – biblio Dec 12 '17 at 10:48
1

Note that you only need one \checkmarkpage since the tikzmark name is passed as an argument.

You might look at the aux file, particularly the \savepointas entries, in order see what is going on.

\documentclass[a4paper,12pt]{book}
\usepackage{tikzpagenodes}
\usetikzlibrary{calc,tikzmark}
\usepackage{lipsum}
\usepackage{showframe}
\usepackage{everypage}

% This macro checks to see if a given tikzmark is on this page, then selects from three possible responses
\makeatletter
\newcommand{\checkmarkpage}[4]% #1 = tikzmark label, #2 = less, #3 = equal, #4 = greater
{\@ifundefined{save@pt@#1}{#2}{%
  \edef\markid{\csname save@pt@#1\endcsname}%
  \edef\markpage{\csname save@pg@\markid\endcsname}%
  \ifnum\thepage<\markpage\relax #2%
  \else
    \ifnum\thepage=\markpage\relax #3%
    \else #4%
    \fi
  \fi}%
}
\makeatother

\newcounter{redenvid}
\newcounter{redenvdone}

\newenvironment{redenv}{\par\tikzmark{beginred\theredenvid}\ignorespaces}%
  {\par\tikzmark{endred\theredenvid}\stepcounter{redenvid}\ignorespaces}

\newcommand{\drawredenv}{\checkmarkpage{beginred\theredenvdone}{}%
  {\begin{tikzpicture}[remember picture,overlay]
    \path ({pic cs:beginred\theredenvdone}-| current page text area.west)
      ++(0pt,\ht\strutbox) coordinate(A);
    \checkmarkpage{endred\theredenvdone}%
      {\path (current page text area.south west) ++(0pt,-\dp\strutbox)
         coordinate(B);}%
      {\path ({pic cs:endred\theredenvdone}-| current page text area.west)
        ++(0pt,\ht\strutbox) coordinate(B);}%
      {}% this should not happen
    \fill[red] ($(A) + (-.1cm,0pt)$) rectangle ($(B) + (-.9cm,0pt)$);
   \end{tikzpicture}}%
  {\begin{tikzpicture}[remember picture,overlay]
    \coordinate (A) at (current page text area.north west);
    \checkmarkpage{endred\theredenvdone}%
      {\path (current page text area.south west) ++(0pt,-\dp\strutbox)
         coordinate(B);}%
      {\path ({pic cs:endred\theredenvdone}-| current page text area.west)
        ++(0pt,\ht\strutbox) coordinate(B);}%
      {}% this should not happen
    \fill[red] ($(A) + (-.1cm,0pt)$) rectangle ($(B) + (-.9cm,0pt)$);
   \end{tikzpicture}}%
  \checkmarkpage{endred\theredenvdone}{}%
    {\stepcounter{redenvdone}\drawredenv}%
    {}% this should not happen
 }
\AddEverypageHook{\drawredenv}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcounter{blueenvid}
\newcounter{blueenvdone}

\newenvironment{blueenv}{\par\tikzmark{beginblue\theblueenvid}\ignorespaces}%
{\par\tikzmark{endblue\theblueenvid}\stepcounter{blueenvid}\ignorespaces}

\newcommand{\drawblueenv}{\checkmarkpage{beginblue\theblueenvdone}{}%
    {\begin{tikzpicture}[remember picture,overlay]
        \path ({pic cs:beginblue\theblueenvdone}-| current page text area.west)
        ++(0pt,\ht\strutbox) coordinate(C);
        \checkmarkpage{endblue\theblueenvdone}%
        {\path (current page text area.south west) ++(0pt,-\dp\strutbox)
            coordinate(D);}%
        {\path ({pic cs:endblue\theblueenvdone}-| current page text area.west)
            ++(0pt,\ht\strutbox) coordinate(D);}%
        {}% this should not happen
        \fill[blue] ($(C) + (-1.0cm,0pt)$) rectangle ($(D) + (-1.8cm,0pt)$);
        \end{tikzpicture}}%
    {\begin{tikzpicture}[remember picture,overlay]
        \coordinate (C) at (current page text area.north west);
        \checkmarkpage{endblue\theblueenvdone}%
        {\path (current page text area.south west) ++(0pt,-\dp\strutbox)
            coordinate(D);}%
        {\path ({pic cs:endblue\theblueenvdone}-| current page text area.west)
            ++(0pt,\ht\strutbox) coordinate(D);}%
        {}% this should not happen
        \fill[blue] ($(C) + (-1.0cm,0pt)$) rectangle ($(D) + (-1.8cm,0pt)$);
        \end{tikzpicture}}%
    \checkmarkpage{endblue\theblueenvdone}{}%
    {\stepcounter{blueenvdone}\drawblueenv}%
    {}% this should not happen
}

\AddEverypageHook{\drawblueenv}


\begin{document}

\newpage 

\thispagestyle{empty}

Next line begins the rule for BLUE ENV:

\begin{blueenv}
\lipsum[2]
\end{blueenv}

Line above ends the rule for BLUE ENV.

Two on one page for RED ENV:
\begin{redenv}
    \lipsum[3]
\end{redenv}

One on three pages for BLUE ENV:
\begin{blueenv}
\lipsum[4-12]
\end{blueenv}
That's all, folks.

\end{document}

It occurred to me that it would be better to have one and only one tikzpicture at the end of each page. This would provide consistent pgfids from one run to the next.

\documentclass[a4paper,12pt]{book}
\usepackage{tikzpagenodes}
\usetikzlibrary{calc,tikzmark}
\usepackage{lipsum}
\usepackage{showframe}
\usepackage{everypage}

% This macro checks to see if a given tikzmark is on this page, then selects from three possible responses
\makeatletter
\newcommand{\checkmarkpage}[4]% #1 = tikzmark label, #2 = less, #3 = equal, #4 = greater
{\@ifundefined{save@pt@#1}{#2}{%
  \edef\markid{\csname save@pt@#1\endcsname}%
  \edef\markpage{\csname save@pg@\markid\endcsname}%
  \ifnum\thepage<\markpage\relax #2%
  \else
    \ifnum\thepage=\markpage\relax #3%
    \else #4%
    \fi
  \fi}%
}
\makeatother

\newcounter{redenvid}
\newcounter{redenvdone}

\newenvironment{redenv}{\par\tikzmark{beginred\theredenvid}\ignorespaces}%
  {\par\tikzmark{endred\theredenvid}\stepcounter{redenvid}\ignorespaces}

\newcommand{\drawredenv}{\checkmarkpage{beginred\theredenvdone}{}%
  {\path ({pic cs:beginred\theredenvdone}-| current page text area.west)
      ++(0pt,\ht\strutbox) coordinate(A);
    \checkmarkpage{endred\theredenvdone}%
      {\path (current page text area.south west) ++(0pt,-\dp\strutbox)
         coordinate(B);}%
      {\path ({pic cs:endred\theredenvdone}-| current page text area.west)
        ++(0pt,\ht\strutbox) coordinate(B);}%
      {}% this should not happen
    \fill[red] ($(A) + (-.1cm,0pt)$) rectangle ($(B) + (-.9cm,0pt)$);
  }%
  {\coordinate (A) at (current page text area.north west);
    \checkmarkpage{endred\theredenvdone}%
      {\path (current page text area.south west) ++(0pt,-\dp\strutbox)
         coordinate(B);}%
      {\path ({pic cs:endred\theredenvdone}-| current page text area.west)
        ++(0pt,\ht\strutbox) coordinate(B);}%
      {}% this should not happen
    \fill[red] ($(A) + (-.1cm,0pt)$) rectangle ($(B) + (-.9cm,0pt)$);
   }%
  \checkmarkpage{endred\theredenvdone}{}%
    {\stepcounter{redenvdone}\drawredenv}%
    {}% this should not happen
 }

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcounter{blueenvid}
\newcounter{blueenvdone}

\newenvironment{blueenv}{\par\tikzmark{beginblue\theblueenvid}\ignorespaces}%
{\par\tikzmark{endblue\theblueenvid}\stepcounter{blueenvid}\ignorespaces}

\newcommand{\drawblueenv}{\checkmarkpage{beginblue\theblueenvdone}{}%
    {\path ({pic cs:beginblue\theblueenvdone}-| current page text area.west)
        ++(0pt,\ht\strutbox) coordinate(C);
        \checkmarkpage{endblue\theblueenvdone}%
        {\path (current page text area.south west) ++(0pt,-\dp\strutbox)
            coordinate(D);}%
        {\path ({pic cs:endblue\theblueenvdone}-| current page text area.west)
            ++(0pt,\ht\strutbox) coordinate(D);}%
        {}% this should not happen
        \fill[blue] ($(C) + (-1.0cm,0pt)$) rectangle ($(D) + (-1.8cm,0pt)$);
    }%
    {\coordinate (C) at (current page text area.north west);
        \checkmarkpage{endblue\theblueenvdone}%
        {\path (current page text area.south west) ++(0pt,-\dp\strutbox)
            coordinate(D);}%
        {\path ({pic cs:endblue\theblueenvdone}-| current page text area.west)
            ++(0pt,\ht\strutbox) coordinate(D);}%
        {}% this should not happen
        \fill[blue] ($(C) + (-1.0cm,0pt)$) rectangle ($(D) + (-1.8cm,0pt)$);
    }%
   \checkmarkpage{endblue\theblueenvdone}{}%
    {\stepcounter{blueenvdone}\drawblueenv}%
    {}% this should not happen
}

\AddEverypageHook{\begin{tikzpicture}[remember picture,overlay]
  \drawredenv
  \drawblueenv
\end{tikzpicture}}


\begin{document}

\newpage 

\thispagestyle{empty}

Next line begins the rule for BLUE ENV:

\begin{blueenv}
\lipsum[2]
\end{blueenv}

Line above ends the rule for BLUE ENV.

Two on one page for RED ENV:
\begin{redenv}
    \lipsum[3]
\end{redenv}

One on three pages for BLUE ENV:
\begin{blueenv}
\lipsum[4-12]
\end{blueenv}
That's all, folks.

\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.