I'm trying to typeset marginpars more accurately on the correct side of the page using a solution based on pdfsavepos
by David Carlisle. (The code below is a slight alteration of it.) I got most of the alignment to work correctly, as can be seen for the marginpars below:
The problem arises when I try typesetting marginpars at the bottom of the margin. The output is as follows:
The margins clearly flow out of the height of the text column, and that's obviously undesirable. The ideal workaround would maintain horizontal spacing conditionally, if the column is not overflown. In this specific case, that would possibly require marginpars 2 to 5 to move up.
A possible idea I have is to store the boxes and typeset them later, by iteratively calculating height and width of each box and setting the last box first, then the one but last box, etc. Except, I'm not sure how to get it done and where to start.
The code I'm using is pretty complex, so I've made annotations explaining (to the best of my abilities) what's happening. If you know any alternative solutions to fix the issue of the overflowing margin column, while maintaining the horizontal spacing of the \textsuperscripts
from sidenotes
, I'm open to suggestions.
As a final note, I've used the sidenotes
package to make it clearer what alignment I'm looking for, which really quite clearly shows the required horizontal alignment of the superscripts. The sidenotes
package is not related to the question.
\documentclass[twoside]{article}
\usepackage[paperwidth=170mm, paperheight=240mm,top=40pt, textwidth=280pt, marginparwidth=100pt,footskip=40pt]{geometry}%
\makeatletter
\newbox\@mpbox%
\newdimen\marginparmindistance \marginparmindistance=10\p@% "marginparpush"
\global\setbox\@mpbox\vbox{}% empty vertical box
\long\def\marginpar#1{%
\saveposition{mpar}%
\global\setbox\@mpbox\vbox{\unvbox\@mpbox\hbox{%
\hbox{\parbox{\marginparwidth}{\@marginparreset#1\@minipagefalse}}% set marginparboxes for both sides
\hbox{\parbox{\marginparwidth}{\@marginparreset#1\@minipagefalse}}%
}\break}}%
\def\saveposition#1{%
\pdfsavepos\write\@auxout{% save positions
\noexpand\savedpos% write to aux using saved position
{#1}{\the\c@page}{\the\pdflastxpos}{\the\pdflastypos}}}
\def\savedpos#1#2#3#4{% format to store the position: #1 = type // #2 = page // #3 = x // #4 = y
\begingroup
\let\@positions\relax
\expandafter\xdef\csname sp@#1-#2\endcsname{% define \csname sp@<something>
\expandafter\ifx\csname sp@#1-#2\endcsname\relax% if control sequence is \relax, do nothing
\else% else
\csname sp@#1-#2\endcsname%
\fi%
\@positions{#3}{#4}}% append @positions to existing macro to create chain of \@positions
\endgroup}% @positions is just a placeholder to hold the pdflastxpos and pdflastypos
\def\@oddfoot{%
\thepage\hss\rlap{\hskip\marginparsep\mcolumn}}% append mcolumn to the footer (odd pages)
\def\@evenfoot{%
\llap{\mcolumn\hskip\marginparsep}\hss\thepage\saveposition{foot}}% save position of foot amd append mcolumn to footer (even pages)
\def\mcolumn{%
\saveposition{foot}% save position of the footer
\expandafter\ifx\csname sp@foot-\the\c@page\endcsname\relax% is a footer position known? no = do nothing
\else% yes,
\let\@positions\origin@positions% @positions is temporarily parsed by \origin@positions
\csname sp@foot-\the\c@page\endcsname% expand to look what absolute y position of foot is
\smash{\raise\footskip\vbox to \textheight{\hsize\marginparwidth%
\hrule\@height\z@%
\let\@positions\mp@positions% the @positions from marginpars are now parsed by \mp@positions.
\csname sp@mpar-\the\c@page\endcsname% the current expansion is the chain of \@positions
\vskip\z@\@plus\textheight% each instance of \@positions will be parsed by mp@positions (down)
\hrule\@height\z@}}% This calculates the necessary vskip between the marginpars and typesets the
\fi}% marginpars
\def\origin@positions#1#2{% this macro calculates the height of the top hrule (as determined by the footer @positions
% the problem is that we have to measure from the bottom of the page, since
% pdfsavedpos has an xy coordinate system that goes from the bottom left part
% of the page....
\dimen@#2sp% set dimen@ to space between bottom edge of paper and baseline of footer
\advance\dimen@\footskip% add the value of \footskip
% note that we've now added slightly too much, since footskip is more than
% the spacing between the baseline and the edge of the body text
\advance\dimen@-.195\baselineskip% to address this issue, we adjust it by a value measured ``by hand''
% one could also decide to use \fontcharht and so on to do this
\advance\dimen@\textheight% we now know the absolute value of the y height of the rule at the top of the
% margin column
\typeout{(page \thepage) Calculated absolute height of the top hrule: \the\dimen@^^J}% we're going through this twice, since we have two pages
}% why does this typeset twice on page two? Who knows...
\count6=0% auxiliary for the typeout info
\def\mp@positions#1#2{% This calculates the necessary vskip between the marginpars
\advance\count6 by 1% count the marginpars
\advance\vbadness\@M
\setbox\tw@=\vsplit\@mpbox to \maxdimen
\advance\vbadness-\@M
\setbox\tw@\vbox{% following rows check/set the marginpar boxes, not very interesting for the
\unvbox\tw@% for the spacing, I guess
\setbox\tw@\lastbox
\setbox\tw@\hbox{%
\unhbox\tw@
\ifodd\c@page
\global\setbox1\lastbox% box1 --> a single marginpar
\fi
\global\setbox1\lastbox% kill the right marginbox if page is odd, otherwise, simply use lastbox
}}% since it already holds the right marginpar
% we're iterating over this, since we have a CHAIN of `\@positions`
\@tempdimb\dimen@% temporarily set tempdimb to dimen@ and determine how large the vskip must be
\advance\@tempdimb-#2sp% subtract the x position height of the marginpar
\typeout{(page \thepage) Calculated vskip from bottom of last marginpar (or top of hrule) for \the\count6: \the\@tempdimb^^J}%
\ifdim\@tempdimb<\marginparmindistance% marginparpush: if the calculated height of tempdimb is smaller than this,
\@tempdimb\marginparmindistance% simply set this as the next marginpar vskip...
\fi%
\vskip\@tempdimb% this is where the magic happens: we have now determined the vskip
\advance\dimen@-\@tempdimb% subtract the vskip and the height and depth of the marginparbox
\advance\dimen@-\ht\@ne% and use \dimen@ for the next use of \@positions
\advance\dimen@-\dp\@ne% in that sense \dimen@ is really an anchor point of current ypositioning to
\hrule\@height\z@% determine vskip iteratively for the next marginpar.
\box\@ne% (typeset the marginpar)
\hrule\@height\z@
}
\makeatother
\usepackage{sidenotes}
\def\blindtext{Hello, here is some text without a meaning. This text should
show what a printed text will look like at this place. If you
read this text, you will get no information. Really? Is there no
information? Is there a difference between this text and some
nonsense like Huardest gefburn"? Kjift not at all! A blind
text like this gives you information about the selected font, how
the letters are written and an impression of the look. This text
should contain all letters of the alphabet and it should be written
in of the original language. There is no need for special content,
but the length of words should match the language.}
\begin{document}
Hello, here is some text without a meaning. This text should
show what a printed text will look like at this place. If you
read this text, you will get no information. Really? Is there no
information? Is there a difference between this text and some
nonsense like Huardest gefburn"? Kjift not at all! A blind
text like this gives you information about the selected font, how
the letters are written and an impression of the look. This text
should contain all letters of the alphabet and it should be written
in of the original language. There is no need for special content,
but the length of words should match the language. Some words.\sidenote{ Really? Is there no
information? Is there a difference between this text and some
nonsense like .}
\blindtext\sidenote{ Is there a difference between this text and some
nonsense like Huardest gefburn"? Kjift not at all! A blind
text like this gives you information about the selected font, how
the letters are written and an impression of the look.}
\blindtext\sidenote{ Is there a difference between this text and some
nonsense like Huardest gefburn"? }
\blindtext\sidenote{ This text
should contain all letters of the alphabet and it should be written
in of the original language.}\sidenote{ This text
should contain all letters of the alphabet and it should be written
in of the original language.}
\blindtext\sidenote{ This text
should contain all letters of the alphabet and it should be written
in of the original language.}
\blindtext\sidenote{ This text
should contain all letters of the alphabet and it should be written
in of the original language.}
\blindtext\sidenote{ This text
should contain all letters of the alphabet and it should be written
in of the original language.}
\end{document}
\marginpar
s), but in no way automated like you would desire: tex.stackexchange.com/questions/142863/…, and tex.stackexchange.com/questions/101553/…