Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

What is the most robust way of increase the effective \marginparsep on even pages only?

I have been playing with outdented lists, section heads etc. which leads to an issue with margin notes: I need to increase the effective \marginparsep on even pages to allow for the outdents. Since this is a length, I cannot simply include a macro such as KOMA's \ifthispageodd.

If possible, I would like a solution that works with the standard \marginpar as well as with marginnote or similar packages.

Update:

Werner's answer below almost solves the problem, but there is a bug closely related to that fixed by mparhack. This MWE demonstrates the problem:

\documentclass[twoside]{scrbook}
\usepackage{etoolbox}
\usepackage{lipsum}% http://ctan.org/pkg/lipsum
\usepackage{everyshi}% http://ctan.org/pkg/everyshi
\usepackage{xifthen}% http://ctan.org/pkg/xifthen
\usepackage{mparhack}

\begin{document}
\EveryShipout{%
  \ifthenelse{\isodd{\value{page}}}%
    {\global\marginparsep=22pt}% Next page is even
    {\global\marginparsep=11pt}% Next page is odd
}
\lipsum[1]
\marginpar[This is a paragraph in the left margin]{This is a paragraph in the right margin}
\lipsum[2]

\begin{itemize}
  \def\do#1{\item This is a line #1 and should have a note with the same
    number:\marginpar{Note #1 and a bit.}}
  \docsvlist{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}
\end{itemize}

\lipsum[3-5]
\marginpar[This is a paragraph in the left margin]{This is a paragraph in the right margin}
\lipsum[6-8]
\marginpar[This is a paragraph in the left margin]{This is a paragraph in the right margin}
\lipsum[9-10]
\end{document}

enter image description here

Note 17 at the top of the second page does not receive the proper adjustment. If the mparhack package is not used, then this note also appears on the wrong side of the page, so the full solution probably involves somehow applying a similar patch. Is there a simple way of doing this?

share|improve this question
    
The problem seems to be that when margin par is on the bottom of the page, it is moved to the next page. But all this is done before \shipout for the next page. –  tohecz Jan 29 '12 at 15:55

2 Answers 2

I would think that accessing the page number at shipout would be robust enough. For this, use the everyshi package. Here is a small trial run:

\documentclass[twoside]{scrartcl}
\usepackage{lipsum}% http://ctan.org/pkg/lipsum
\usepackage{everyshi}% http://ctan.org/pkg/everyshi
\usepackage{xifthen}% http://ctan.org/pkg/xifthen

\begin{document}
\EveryShipout{%
  \ifthenelse{\isodd{\value{page}}}%
    {\global\marginparsep=22pt}% Next page is even
    {\global\marginparsep=11pt}% Next page is odd
}

\lipsum[1]
\marginpar[This is a paragraph in the left margin]{This is a paragraph in the right margin}
\lipsum[2-5]
\marginpar[This is a paragraph in the left margin]{This is a paragraph in the right margin}
\lipsum[6-8]
\end{document}

Different marginparsep values for odd/even pages

The key is to make the change \global within \EveryShipout, since it is grouped. You could apply similar modification to the \marginparwidth.

share|improve this answer
    
The bundle KOMA provides the command ifthispageodd which is also recommended by the documentation. (only suggestion) –  Marco Daniel Sep 5 '11 at 7:11
    
@Marco: Tried it within \EveryShipout and it didn't work, so I reverted to the traditional \isodd from xifthen. –  Werner Sep 5 '11 at 7:15
    
@Werner: \ifthispageodd works for me. What problem are you having? Note that your example is missing the following needed to correspond to your output: \marginpar[This is a paragraph in the left margin]{This is a paragraph in the right margin}\lipsum[9-10]. This answer almost solves my problem, but I am having an issue with some lines at the very top of some even pages not getting the correction. I am having a hard time reproducing this with a minimal example though right now... –  mforbes Sep 5 '11 at 8:49
    
@Werner: I have updated my question to demonstrate the issue I am having with lines at the top of even pages. Do you have any idea how to apply a patch similar to that in mparhack to your solution? –  mforbes Dec 4 '11 at 5:22
up vote 1 down vote accepted

A key to solving this problem is the mparhack package, without which the circled margin par in the question update appears on the wrong side of the page. The mparhack package redefines the \@addmarginpar command to have:

\renewcommand\@addmarginpar{%
    ...
    \c@page=\mph@pg@new     % At this point, \c@page is correct
    ...
    \mph@orig@addmarginpar  % This typesets the note using \marginparsep
    ...
}

It is straightforward to use \patchcmd from the etoolbox package to insert my \marginparsep changes immediately before \mph@orig@addmarginpar which does the actual setting of the margin par. This eschews the need for using everyshi.

A similar patch can be applied to \@mn@@@marginnote to solve the problem for marginnote, replacing \kern\marginparsep with a conditional statement. This is a little more tricky because there are several places this needs to be changed, so we use the trick of recursively applying the patch until the \patchcmd fails (after there is nothing left to patch).

In principle, one might be able to replace \marginparsep everywhere with the appropriate conditional, but it seems non-trivial to properly determine the page parity, and independent tests have to be made in each case: \ifodd\c@page for \marginpar and \ifodd\@mn@currpage for \marginnote.

This is a somewhat messy hack, but I have not found a simpler working solution:

\documentclass[twoside]{scrbook}
\usepackage{etoolbox}
\usepackage{lipsum}% http://ctan.org/pkg/lipsum
\usepackage{marginnote}
\usepackage{mparhack}

\newlength\marginparsepodd
\newlength\marginparsepeven
\marginparsepodd=11pt
\marginparsepeven=22pt

\makeatletter
% First we patch \@addmarginpar
% The \patchcmd command does a search and replace. 
\patchcmd{\@addmarginpar}                 % In this command
         {\mph@orig@addmarginpar}         % ... replace this...
         {\if@twoside\ifodd\c@page\relax  % ... with this
              \marginparsep=\marginparsepodd  % Page is odd
            \else
              \marginparsep=\marginparsepeven  % Page is even
            \fi
          \else
            \marginparsep=\marginparsepodd
          \fi
          \mph@orig@addmarginpar}
         {}                                           % success
         {\message{Error! Couldn't hook into command  % failure
             `\string\@addmarginpar'}} 

% Now we patch \@mn@@@marginnote
{%% Group to keep patching commands local
  %
  % Here we use a little trick to repeatedly patch the \@mn@@@marginnote
  % command, replacing all instances of \kern\marginparsep with a
  % conditional. We call \patch recursively each time on success, and stop
  % when the patch fails (because all instances have been replaced).  If the
  % patch fails the first time, we show an error message.
  \def\patcherr{%
    \message{Error! Couldn't hook into command `\string\@mn@@@marginnote'}}
  \def\patchok{%
    \let\patcherr\relax % Only display error if first patch fails
    \patch              % Now patch again.
  }
  \def\patch{
    \patchcmd{\@mn@@@marginnote}                   % In this command
             {\kern\marginparsep}                  % ... replace this...
             {\ifx\@mn@currpage\relax\else         % ... with this
                \if@twoside\ifodd\@mn@currpage\relax 
                    \kern\marginparsepodd
                  \else
                    \kern\marginparsepeven
                  \fi
                \else
                  \kern\marginparsepodd
                \fi
              \fi}
             {\message{Patched!}\patchok}          % success (recurse)
             {\patcherr}                           % fail 
  }
  \message{Patching `\string\@mn@@@marginnote`!}
  \patch
  \global\let\@mn@@@marginnote\@mn@@@marginnote    % Make patch global
}
\makeatother

\begin{document}
\lipsum[1]
\marginpar[This is a paragraph in the left margin]{This is a paragraph in the right margin}
\lipsum[2]

\begin{itemize}
  \def\do#1{\item This is a line #1 and should have a note with the same
    number:\marginpar{Note #1 and a bit.}}
  \docsvlist{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}
\end{itemize}

\lipsum[3-4]
\marginpar[This is a paragraph in the left margin]{This is a paragraph in the right margin}
\lipsum[5]
\end{document}

Output of working solution.

share|improve this answer
    
I think this is really ugly, but could not find a cleaner solution. I will wait a bit to accept my answer in case anyone has a simpler complete solution. –  mforbes Mar 28 '12 at 8:55

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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