In this document, from page 12 and following, the notes from the marginpar are overflowing in the footer of each page.
How can this be achieved in LaTeX?
ConTeXT/LuaTeX based solutions are welcome, too!
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It only takes a minute to sign up.
Sign up to join this communityIn this document, from page 12 and following, the notes from the marginpar are overflowing in the footer of each page.
How can this be achieved in LaTeX?
ConTeXT/LuaTeX based solutions are welcome, too!
Here's my solution:
Some general remarks on the implementation:
\footins
. I started from the multicol footnote trick from Appendix D of the TeXbook.\footnotetext
.The following should be put into a file marginfootnotes.sty
:
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{marginfootnotes}[2012/04/03 EXPERIMENTAL package for
putting footnotes into the margin, overflowing into the footer]
\RequirePackage{kvoptions}
\RequirePackage{etoolbox}
% We need this package to do some output / insert recovery magic.
\RequirePackage{afterpage}
% Number of columns in footer.
\DeclareStringOption[2]{columns}
% Should we reorder footnotes on odd pages?
\DeclareBoolOption[true]{fixorder}
\ProcessKeyvalOptions*
% Need a fresh insert for the marginfoornotes.
\newinsert\marginfootnotes@ofn
\skip\marginfootnotes@ofn=\z@
\count\marginfootnotes@ofn=\z@
\dimen\marginfootnotes@ofn=\textheight
% Measure how much material already is in the margin.
\newdimen\marginht@ofn
% We rebuild page geometry such that there are <columns>+1 columns
% (including marginpar) of width \marginparwidth, separated by
% \marginparsep, and \textwidth covers <columns>-1 of them.
\@tempdima\marginparwidth
\marginparwidth
\dimexpr
(\textwidth+\marginparwidth+2\marginparsep)%
/\numexpr\marginfootnotes@columns+\@ne\relax%
-\marginparsep
\relax
\textwidth\dimexpr\marginfootnotes@columns\marginparwidth+\numexpr\marginfootnotes@columns-\@ne\relax\marginparsep\relax
\advance\evensidemargin\dimexpr\marginparwidth-\@tempdima\relax
% As there are <columns> columns of footnotes now, we need to adjust
% the magnification factor.
\count\footins=\numexpr1000/\marginfootnotes@columns\relax
% Redefinition of \@footnotetext. Measure whether footnote still fits
% in the margin, otherwise insert as footnote.
\long\def\@footnotetext#1%
{%
\setbox\@tempboxa=\vbox{\typesetfootnote@ofn{#1}}%
\ifdim\dimexpr\marginht@ofn+\ht\@tempboxa+\dp\@tempboxa\relax>\textheight
\insert\footins{\typesetfootnote@ofn{#1}}%
\else
\insert\marginfootnotes@ofn{\typesetfootnote@ofn{#1}}%
\global\advance\marginht@ofn\dimexpr\ht\@tempboxa+\dp\@tempboxa\relax
\fi
}%
\newcommand\typesetfootnote@ofn[1]
{%
\reset@font\footnotesize
\interlinepenalty\interfootnotelinepenalty
\splittopskip\footnotesep
\splitmaxdepth \dp\strutbox \floatingpenalty \@MM
\hsize\marginparwidth \@parboxrestore
\protected@edef\@currentlabel{%
\csname p@footnote\endcsname\@thefnmark
}%
\color@begingroup
\@makefntext{%
\rule\z@\footnotesep\ignorespaces#1\@finalstrut\strutbox}%
\color@endgroup
}
% We hook into the output routine, replacing the "simple" output of
% \footins by our more complicated scheme.
\patchcmd\@makecol
{%
\ifvoid\footins
\setbox\@outputbox \box\@cclv
\else
\setbox\@outputbox \vbox {%
\boxmaxdepth \@maxdepth
\unvbox \@cclv
\vskip \skip\footins
\color@begingroup
\normalcolor
\footnoterule
\unvbox \footins
\color@endgroup
}%
\fi
}{\output@footins}{}{}
% If \footins is void, we still need to output the margin
% box. Otherwise we call the macro for balancing footnote columns.
\newcommand\output@footins
{%
\ifvoid\footins
\setbox\@outputbox \vbox {%
\boxmaxdepth \@maxdepth
\unvbox \@cclv
\hbox
{%
\if@twoside
\ifodd\c@page
\hskip\textwidth\hskip\marginparsep
\else
\hskip-\marginparwidth\hskip-\marginparsep
\fi
\else
\hskip\textwidth\hskip\marginparsep
\fi
\smash{\box\marginfootnotes@ofn}%
}%
}%
\else
\setbox\@outputbox \vbox {%
\boxmaxdepth \@maxdepth
\unvbox \@cclv
\vskip \skip\footins
\color@begingroup
\normalcolor
\footnoterule
\balancecolumns@ofn
\color@endgroup
}%
\fi
\global\marginht@ofn\z@
}
% The following is roughly based on the example from appendix D of the
% TeXbook, plus outputting the margin column.
\newcount\k
\newcount\lines@ofn
\newbox\footnotetextbox@ofn
\def\balancecolumns@ofn
{%
\setbox\footnotetextbox@ofn=\box\footins
\k=\marginfootnotes@columns
\hbox to\dimexpr\k\marginparwidth+\marginparwidth+\k\marginparsep\relax
{%
\footnotesize
\lines@ofn
\numexpr
\dimexpr\ht\footnotetextbox@ofn+\dp\footnotetextbox@ofn\relax
/\baselineskip
/\marginfootnotes@columns
\relax
\splittopskip\dimexpr\baselineskip-\dp\strutbox\relax
\vbadness\maxdimen
\vfuzz\maxdimen
\splitmaxdepth \dp\strutbox
\if@twoside
\ifodd\c@page
\ifmarginfootnotes@fixorder
\setbox\footnotetextbox@ofn=\vbox{\unvbox\marginfootnotes@ofn\unvbox\footnotetextbox@ofn}%
\fi
\else
\hskip-\marginparwidth\hskip-\marginparsep
\setbox\@tempboxa=\box\marginfootnotes@ofn
\output@tempboxa
\hskip\marginparsep
\fi
\else
\ifmarginfootnotes@fixorder
\setbox\footnotetextbox@ofn=\vbox{\unvbox\marginfootnotes@ofn\unvbox\footnotetextbox@ofn}%
\fi
\fi
\dosplits
\if@twoside
\ifodd\c@page
\ifmarginfootnotes@fixorder
\setbox\@tempboxa=\box\footnotetextbox@ofn
\else
\setbox\@tempboxa=\box\marginfootnotes@ofn
\fi
\output@tempboxa
\fi
\else
\ifmarginfootnotes@fixorder
\setbox\@tempboxa=\box\footnotetextbox@ofn
\else
\setbox\@tempboxa=\box\marginfootnotes@ofn
\fi
\output@tempboxa
\fi
}%
}
\newcommand\output@tempboxa
{%
\@tempcnta
\numexpr
\dimexpr\ht\@tempboxa+\dp\@tempboxa\relax
/\baselineskip
\relax
\smash{\vsplit\@tempboxa to \@tempcnta\baselineskip}%
}
\def\dosplits{\ifnum\k>\@ne \splitoff\hskip\marginparsep
\global\advance\k-1\dosplits\fi}
\def\splitoff
{%
\vsplit\footnotetextbox@ofn to \lines@ofn\baselineskip
}
% Thanks to David Carlisle for pointing me to this easy solution how
% to recover \footins material which was split off by a page break
% and move it into the margin. afterpage code is used and patched
% to avoid conflicts.
\newtoks\output@ofn
\output@ofn{%
\the\AP@output
\ifnum\outputpenalty>-\@Mi
\aftergroup\fixfootins@ofn
\fi
}%
\global\output{\the\output@ofn}%
\newcommand\fixfootins@ofn
{%
\AP@savetop
\addboxcontents\AP@partial
\ifvoid\AP@footins\else
\movefootins@ofn
\fi
\AP@noindent
}
\newcommand\movefootins@ofn
{%
\global\advance\marginht@ofn\dimexpr\ht\AP@footins+\dp\AP@footins\relax
\insert\marginfootnotes@ofn{\unvbox\AP@footins}%
}
\patchcmd\AP@@
{\insert\footins{\unvbox\AP@footins}}
{\movefootins@ofn}{}{}
\patchcmd\AP@@
{\AP@noindent}
{\AP@noindent\global\output{\the\output@ofn}}{}{}
% Disable \marginpar because it would conflict with margin footnotes.
\renewcommand\marginpar[2][]
{%
\PackageError{marginfootnotes}
{\string\marginpar\space disabled}\@eha
}%
Then test with:
\documentclass[a4paper,twoside]{article}
\usepackage[columns=3]{marginfootnotes}
\usepackage[expansion=alltext]{microtype}
\usepackage{lipsum}
\newcommand\fnlipsum[1]
{%
\begingroup
\let\par\empty
\edef\@temp{\csname lipsum@\romannumeral#1\endcsname}%
\@temp\footnote{\@temp}%
\endgroup
\par
}
\usepackage[latin]{babel}
\showboxdepth\maxdimen
\showboxbreadth\maxdimen
\begin{document}
\fnlipsum{1}
\fnlipsum{2}
\fnlipsum{3}
\afterpage{\noindent\fbox{\parbox{\dimexpr\textwidth-2\fboxsep-2\fboxrule\relax}{\lipsum[1]}}}
\fnlipsum{4}
\fnlipsum{5}
\fnlipsum{6}
\fnlipsum{7}
\fnlipsum{8}
\fnlipsum{9}
\fnlipsum{10}
\fnlipsum{11}
\fnlipsum{12}
\fnlipsum{13}
\end{document}
Note that this is a bit rough, but without a clear application perspective and some nice "real" examples it is hard to do significant testing.
The columns
option sets the number of columns in the footer.
By giving the option fixorder=false
, reordering of footnotes on odd pages is turned off. As the first footnotes on a page always go into the margin, on odd pages where the margin is to the left, the numerical order combined with the footer looks strange. So normally (default fixorder=true
), all the footnotes are reordered on odd pages such that the first footnotes start in the footer.
Enjoy!
Recent edits:
oneside
.afterpage
and fixed some issues.\marginpar
(which of course doesn't work at all) and disabled \marginpar
for the time being. If I ever implement the vertical positioning of margin footnotes, I might add \marginpar
back in as a non-numbered note.flowfram
is relevant for this? Please post an answer to achieve the results above with flowfram
.
Apr 6, 2012 at 10:57
sidenotes
, a command and an environment in pdfcomment
, according to marginfix
doc in memoir
is a command \sidebar
– surely there are more), but you can’t catch all cases.
Disclaimer: I don't know anything about output routines. This is just meant to be a very partial first step, and the code is a mess. The idea is to collect the margin notes and the body content in two vertical boxes, check at every paragraph whether we've reached the area of the page (converted to a dimension by dividing it by 100pt, to remain within TeX's max dimension). If so, shipout a horizontal box with two parts: a left column with only notes, (\vsplit
to \vsize
), and a right column with all the body text (hence we assume that this body text fits, in other words that there are at least 1/3 of notes, no check for that), then two columns of notes side by side.
Also, that's plain TeX. Well, I'm not really using much of plain, even.
\catcode`@=11
\newbox\marg@m@galley % contains all marginpars
\newbox\marg@b@galley % contains all of the body text
\newbox\marg@void@box % empty box.
\newdimen\marg@m@area % marginpar surface area
\newdimen\marg@b@area % body surface area
\newdimen\marg@t@area % m+b surface area
\newdimen\marg@p@area % page surface area
\newdimen\marg@m@prevdepth \global\marg@m@prevdepth=-1000pt
\newdimen\marg@b@prevdepth \global\marg@b@prevdepth=-1000pt
\newdimen\marg@notes@space % space between body and bottom notes.
\marg@notes@space=15pt
\def\marg@leavevmode{\begingroup\everypar={}\unhbox\marg@void@box\endgroup}
\def\marg@strip@pt{\expandafter\marg@rem@pt\the}
\begingroup\catcode`P=12\catcode`T=12
\lowercase{\endgroup\def\marg@rem@pt#1PT{#1}}
\def\marg@set@to@area#1#2{%
#1=.01\dp#2\relax
\advance#1by .01\ht#2\relax
#1=\marg@strip@pt#1\wd#2\relax}
\def\marg@conditionally@output{%
\marg@set@to@area\marg@m@area\marg@m@galley
\marg@set@to@area\marg@b@area\marg@b@galley
\marg@t@area\marg@m@area
\advance\marg@t@area by \marg@b@area
\marg@p@area=.0095\hsize
\marg@p@area=\marg@strip@pt\marg@p@area\vsize
\ifdim\marg@t@area>\marg@p@area
\marg@output
\fi}
\def\marg@output{%
\shipout\hbox to \hsize{%
\vbox to \vsize{\ifdim\ht\marg@m@galley>\vsize
\vsplit\marg@m@galley to \vsize\else\unvbox\marg@m@galley\fi\vfill}%
\hfill
\vbox to \vsize{%
\hsize\wd\marg@b@galley
\dimen@\vsize
\advance\dimen@ by -\ht\marg@b@galley
\advance\dimen@ by -\dp\marg@b@galley
\unvbox\marg@b@galley
\vskip\marg@notes@space
\hbox to \hsize {\vbox{\vsplit\marg@m@galley to \dimen@}%
\hfil\vbox{\vsplit\marg@m@galley to \dimen@}}%
\vfill
}%
}%
}
\def\marg@m@start{%
\setbox\marg@m@galley=\vbox\bgroup
\hsize=.30\hsize
\unvbox\marg@m@galley
\prevdepth=\marg@m@prevdepth
\let\@par\par
\def\par{\marg@m@stop\par\marg@m@start}}
\def\marg@m@stop{%
\@par
\global\marg@m@prevdepth=\prevdepth
\egroup
\marg@conditionally@output}
\def\marg@b@start{%
\setbox\marg@b@galley=\vbox\bgroup
\hsize=.65\hsize
\unvbox\marg@b@galley
\prevdepth=\marg@b@prevdepth
\let\@par\par
\def\par{\marg@b@stop\par\marg@b@start}}
\def\marg@b@stop{%
\@par
\global\marg@b@prevdepth=\prevdepth
\egroup
\marg@conditionally@output}
\long\def\marginpar#1{%
\marg@b@stop
\marg@m@start
#1%
\marg@m@stop
\marg@b@start
}
\def\lipsum@i{Lorem ipsum dolor sit amet, consectetuer
adipiscing elit. Ut purus elit, vestibulum ut, placerat ac,
adipiscing vitae, felis. Curabitur dictum gravida mauris. Nam arcu
libero, nonummy eget, consectetuer id, vulputate a, magna. Donec
vehicula augue eu neque. Pellentesque habitant morbi tristique
senectus et netus et malesuada fames ac turpis egestas. Mauris ut
leo. Cras viverra metus rhoncus sem. Nulla et lectus vestibulum urna
fringilla ultrices. Phasellus eu tellus sit amet tortor gravida
placerat. Integer sapien est, iaculis in, pretium quis, viverra ac,
nunc. Praesent eget sem vel leo ultrices bibendum. Aenean faucibus.
Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla.
Curabitur auctor semper nulla. Donec varius orci eget risus. Duis
nibh mi, congue eu, accumsan eleifend, sagittis quis, diam. Duis
eget orci sit amet orci dignissim rutrum.\par}
\emergencystretch=.15\hsize
\marg@b@start
\lipsum@i
\lipsum@i
\marginpar{\lipsum@i\lipsum@i}
\lipsum@i
\marginpar{\lipsum@i\lipsum@i}
\lipsum@i
\marg@b@stop
\marg@output
\bye
\strip@pt
in the LaTeX kernel. The result of \the\len
(where \len
is a dimension register, is a decimal number followed by the two characters pt
of category 12. In order to strip them it's customary to define a macro with a delimited argument (the delimiter is exactly pt
of category 12).
This totally reminds me of the "Typesetting the talmud" challenges presented at the last Dante meeting in Leipzig. In the Talmud the original text version is in the center, around are (onion-like) the texts of scholars commenting on the text.
%PDF-
." from adobe reader, and i'm unable to look past the first page. (trying to read with current adobe reader plugin to current firefox on windows xp.)