Senden (und stapeln) Sie \marginpar an den Anfang oder das Ende der Seite.

Senden (und stapeln) Sie \marginpar an den Anfang oder das Ende der Seite.
  • Ich möchte etwas wie definieren \topmarginpar{<text>}, das im Wesentlichen ein erstellt \marginpar{<text>}und dessen Oberseite mit der Oberseite der aktuellen Seite ausrichtet.

  • Ich möchte \topmarginpardiese Objekte auch durch mehrere Aufrufe stapeln \marginpar(anstatt sie überlappen zu lassen).

  • Und schließlich möchte ich einen ähnlichen \bottommarginBefehl erstellen.

Gibt es ein bestehendes Paket, das diese Funktionalität bereitstellt, oder bin ich hier auf mich allein gestellt (ich beherrsche LaTeX, bin aber mit reinem TeX nicht vertraut)?

Danke für alle Vorschläge ...

Antwort1

Diese Lösung befasst sich mit der asynchronen Ausgaberoutine:

  • Die Seiten werden durch absolute Seitenzahlen identifiziert und die richtigen Seitenzahlen stehen im zweiten LaTeX-Durchlauf durch Labels zur Verfügung.

  • Jede Seite erhält zwei Sammelboxen, die die Randnotizen für den oberen und unteren Rand sammeln. Beim Versand ist die absolute Seitenzahl bekannt und die Sammelboxen für die Seite werden im Bereich "marginpar" der Seite ausgegeben.

  • Boxregister werden dynamisch zugeordnet und in einem Pool verwaltet. Nach dem Versand einer Seite werden die zugehörigen Collector-Boxregister freigegeben und wieder in den Pool zurückgelegt.

  • \topskipund \maxdepthwerden für den „Randbereich“ respektiert.

  • Zu viele Randnotizen auf einer Seite werden als Überfüllungswarnung gemeldet \vbox.

  • LaTeX \marginparwird nicht unterstützt, die Randnotizen unterschiedlicher Art kennen sich nicht und überdrucken sich munter gegenseitig.

Das Beispieldokument:

\documentclass{article}

\usepackage{atbegshi}
\usepackage{zref-abspage}
\usepackage{picture}

\makeatletter
\providecommand*{\c@zabspage}{\c@abspage}

% * User macros for configuring
%
% \tbmparItemSep is inserted between marginal notes
% \tbmparMiddleSep is inserted between top and bottom marginal notes.

\newcommand*{\tbmparItemSep}{%
  \vspace{1ex minus .5ex}%
  \hrule
  \vspace{1ex minus .5ex}%
}
\newcommand*{\tbmparMiddleSep}{%
  \vspace*{0pt plus 1fil}%
}

% * Debug messages
%
\newcommand*{\tbmparDebug}[1]{%
  \typeout{[tbmpar] #1}%
}

% * Label management to remember absolute page number
%
% \tbmpar@PageByLabel stores and loads absolute page number from
% label and defines \tbmpar@page with absolute page number or
% zero if the label is not yet available.

\newcount\c@tbmpar@item
\c@tbmpar@item\z@

\newcommand*{\tbmpar@PageByLabel}{%
  \global\advance\c@tbmpar@item\@ne
  \zref@labelbyprops{tbmpar\the\c@tbmpar@item}{abspage}%
  \edef\tbmpar@page{%
    \zref@extractdefault{tbmpar\the\c@tbmpar@item}{abspage}{0}%
  }%
  \zref@refused{tbmpar\the\c@tbmpar@item}%
  \tbmparDebug{Item \the\c@tbmpar@item\space on page \tbmpar@page}%
}

% * Box register management

\newcount\c@tbmpar@box
\c@tbmpar@box\z@

\let\tbmpar@boxfreelist\@empty

% Get a new free box register either from the free list or,
% if the free list is empty, allocate a new box register.
\newcommand*{\tbmpar@NextBox}[1]{%
  \@next#1\tbmpar@boxfreelist{%  
    \tbmparDebug{Reused box: #1}%
  }{%
    \global\advance\c@tbmpar@box\@ne
    \expandafter\newbox\csname tbmpar@box\the\c@tbmpar@box\endcsname
    \edef#1{\csname tbmpar@box\the\c@tbmpar@box\endcsname}%
    \tbmparDebug{New box: #1}%
  }%
}
% Put free box in free list.
\newcommand*{\tbmpar@FreeBox}[1]{%
  \begingroup
    \let\@elt\relax
    \xdef\tbmpar@boxfreelist{%
      \tbmpar@boxfreelist
      \@elt#1%
    }%
    \tbmparDebug{Free box: #1}%
  \endgroup
}

\newsavebox{\tbmpar@box}

% Each marginpar is put in a box that is initialized as
% parbox/minipage.
\newcommand*{\tbmparBoxSetup}{}
\newcommand{\tbmpar@VBox}[1]{% 
  \vbox{%
    \color@begingroup
    \hsize\marginparwidth
    \edef\tbmpar@restore@ifminipage{%
      \if@minipage
        \noexpand\@minipagetrue
      \else
        \noexpand\@minipagefalse
      \fi
    }%   
    \@parboxrestore
    \@marginparreset
    \tbmparBoxSetup 
    #1%
    \tbmpar@restore@ifminipage
    \color@endgroup
  }%
}   

% Macro \tbmpar@marginpar looks for the page, where the margin note
% belongs to, stores the note in a box and appends the box to the  
% note collector register of the page.
% Each page is assigned a box collector registers that collect
% the top notes and a register that collect the bottom notes. 
% The name of the box register is \tbmpar@<top|bot>box<page>. 
\newcommand{\tbmpar@marginpar}[4]{%
  \ifhmode
    \@bsphack
  \fi
  \tbmpar@PageByLabel
  \ifnum\tbmpar@page>\z@
    \setbox\tbmpar@box\tbmpar@VBox{#4}%
    \@ifundefined{tbmpar@#1box\tbmpar@page}{%
      \tbmpar@NextBox\tbmpar@currbox
      \global\expandafter\let
          \csname tbmpar@#1box\tbmpar@page\endcsname
          \tbmpar@currbox
      \global\setbox\tbmpar@currbox=\vbox{%
        \unvbox\tbmpar@box
      }%
    }{% 
      \tbmparDebug{Use box: \tbmpar@currbox}%
      \expandafter\let\expandafter\tbmpar@currbox
          \csname tbmpar@#1box\tbmpar@page\endcsname
      \global\setbox\tbmpar@currbox\tbmpar@VBox{%   
        \unvbox#2%
        \par
        \begingroup
          \tbmparItemSep
        \endgroup
        \unvbox#3%
      }%
    }%  
  \fi   
  \ifhmode
    \@esphack
  \fi
}
\newcommand*{\topmarginpar}{%
  \tbmpar@marginpar{top}\tbmpar@currbox\tbmpar@box
}
\newcommand*{\botmarginpar}{%
  \tbmpar@marginpar{bot}\tbmpar@box\tbmpar@currbox
}

% At shipout time we look for the box collector registers of this
% page and set these boxes in the marginpar box with respecting  
% \topskip and \maxdepth.
\AtBeginShipout{%
  \AtBeginShipoutUpperLeft{%
    \put(%
      \dimexpr 1in+\oddsidemargin+\textwidth+\marginparsep\relax,%
      -\dimexpr 1in+\topmargin+\headheight+\headsep+\textheight\relax
    ){%
      \begingroup
        \global\let\tbmpar@inuse=N%
        \setbox\tbmpar@box=\tbmpar@VBox{%
          \penalty-\@M
          \edef\tbmpar@tmp{tbmpar@topbox\the\value{zabspage}}%
          \@ifundefined{\tbmpar@tmp}{%
          }{%
            \expandafter\let\expandafter\tbmpar@currbox
                \csname\tbmpar@tmp\endcsname
            \unvbox\tbmpar@currbox
            \tbmpar@FreeBox\tbmpar@currbox
            \global\let\tbmpar@inuse=Y%   
          }%
          \endgraf
          \tbmparMiddleSep
          \edef\tbmpar@tmp{tbmpar@botbox\the\value{zabspage}}%
          \@ifundefined{\tbmpar@tmp}{%
          }{%
            \expandafter\let\expandafter\tbmpar@currbox
                \csname\tbmpar@tmp\endcsname
            \unvbox\tbmpar@currbox
            \tbmpar@FreeBox\tbmpar@currbox
            \global\let\tbmpar@inuse=Y%   
          }%
        }%  
        \ifx\tbmpar@inuse Y%
          \splittopskip=\topskip
          \setbox0=\vsplit\tbmpar@box to\z@
          \boxmaxdepth=\maxdepth
          \setbox\tbmpar@box=\vbox to\textheight{%
            \unvbox\tbmpar@box
          }%
          \box\tbmpar@box
        \fi
      \endgroup
    }%
  }%  
}     

\makeatother

% Testing

\usepackage[
  a5paper,   
  left=10mm, 
  right=10mm,
  marginparwidth=40mm,
  includemp,
]{geometry}
\usepackage{microtype}  
\usepackage[T1]{fontenc}
\usepackage{lmodern}

\clubpenalty=10000
\flushbottom
\settodepth\maxdepth{g}  
\setlength{\fboxsep}{1ex}
\usepackage{lipsum}
\usepackage{color}

\newcommand*{\shortlipsum}[1]{%
  \begingroup
    \long\def\y##1. ##2\@nil{##1.}%
    \edef\x{\csname lipsum@\romannumeral#1\endcsname}%
    \expandafter\y\x. \@nil
  \endgroup
}

\begin{document}
  \topmarginpar{\color{blue}\shortlipsum{1}}
  \lipsum[1]
  \botmarginpar{%
    Show effect of \texttt{\textbackslash maxdepth}:
    $\displaystyle\sum_{\textstyle i=\frac{a}{g}}^\infty i = x$}
  \lipsum[2]
  \topmarginpar{\shortlipsum{3}}%
  \botmarginpar{Second bottom marginal note}%
  \lipsum[3-4]
  \noindent a\botmarginpar{a} b\botmarginpar{b} c \botmarginpar{c} d\\
  e\\f\par
  \topmarginpar{\fbox{\shortlipsum{5}}}
  \lipsum[5]
  Text with footnote and marginal note\footnote{Marginal note X}.
  \topmarginpar{This is marginal note X}
  \lipsum[6]
  \botmarginpar{\shortlipsum{7}}
  \lipsum[7]  
\end{document}

Ergebnis

Antwort2

Hier ist ein Versuch mitMartin Scharrer's PaketAbonnieren. Da es die remember picture, overlayMöglichkeiten vonTikZ, Sie müssen es zweimal kompilieren, damit es richtig funktioniert. Es stellt die beiden Befehle bereit \marpartop, \marparbotdie beide zwei Argumente annehmen: den Inhalt und die Textfarbe. Dies könnte leicht erweitert werden, um es anpassbarer zu machen.

Code

\documentclass{scrartcl}
\usepackage[left=15mm,top=40mm,bottom=40mm,right=50mm,a4paper]{geometry}
\usepackage{tikzpagenodes}
\usepackage{xifthen}

\usepackage{lipsum}

\setlength{\marginparwidth}{40mm}
\pagestyle{empty}

\def\myyshifttop{0}
\def\mypagetop{0}

\newcommand{\marpartop}[2]% content, color
{   \begin{tikzpicture}[remember picture, overlay]
        \ifthenelse{\thepage=\mypagetop}{}{\xdef\myyshifttop{0}}        
        \xdef\mypagetop{\thepage}
        \node[below right, yshift=\myyshifttop, text width=\marginparwidth-4pt, inner sep=2pt, #2] (tempnode) at (current page marginpar area.north west) {#1};
        \path (current page marginpar area.north west);
        \pgfgetlastxy{\tempxone}{\tempyone}
        \path (tempnode.south west);
        \pgfgetlastxy{\tempxtwo}{\tempytwo}
        \pgfmathsetmacro{\diffy}{(\tempytwo-\tempyone)}
        \xdef\myyshifttop{\diffy}
    \end{tikzpicture}
}

\def\myyshiftbot{0}
\def\mypagebot{0}

\newcommand{\marparbot}[2]% content, color
{   \begin{tikzpicture}[remember picture, overlay]
        \ifthenelse{\thepage=\mypagebot}{}{\xdef\myyshiftbot{0}}        
        \xdef\mypagebot{\thepage}
        \node[above right, yshift=\myyshiftbot, text width=\marginparwidth-4pt, inner sep=2pt, #2] (tempnode) at (current page marginpar area.south west) {#1};
        \path (current page marginpar area.south west);
        \pgfgetlastxy{\tempxone}{\tempyone}
        \path (tempnode.north west);
        \pgfgetlastxy{\tempxtwo}{\tempytwo}
        \pgfmathsetmacro{\diffy}{(\tempytwo-\tempyone)}
        \xdef\myyshiftbot{\diffy}
    \end{tikzpicture}
}

\begin{document}
\marpartop{On a journey to find the cure for a Tatarigami's curse, Ashitaka finds himself in the middle of a war between the forest gods and Tatara, a mining colony.}{red}
\marparbot{What begins as an open and shut case of murder soon becomes a mini-drama of each of the jurors' prejudices and preconceptions about the trial, the accused, and each other.}{orange!50!gray}
\lipsum[1-3]
\marparbot{The defense and the prosecution have rested and the jury is filing into the jury room to decide if a young Spanish-American is guilty or innocent of murdering his father.}{green!50!gray}
\marpartop{In this quest he also meets San, the Mononoke Hime.}{blue}
\lipsum[4-7]
\marpartop{On a journey to find the cure for a Tatarigami's curse, Ashitaka finds himself in the middle of a war between the forest gods and Tatara, a mining colony.}{red}
\marparbot{What begins as an open and shut case of murder soon becomes a mini-drama of each of the jurors' prejudices and preconceptions about the trial, the accused, and each other.}{orange!50!gray}
\lipsum[8]
\marpartop{In this quest he also meets San, the Mononoke Hime.}{blue}
\marparbot{The defense and the prosecution have rested and the jury is filing into the jury room to decide if a young Spanish-American is guilty or innocent of murdering his father.}{green!50!gray}
\lipsum[9-12]
\end{document}

Ergebnis

Bildbeschreibung hier eingeben

Antwort3

(Hinweis: Dies ist eine Community-Antwort, da die ursprüngliche Idee von Tom Bombadil stammt.)

Hier ist eine Variante von Tom Bombadils Antwort mit einigen Verbesserungen:

  • Die beiden Makros sind benannt \topmarginparund \botmarginparentsprechen der Anforderung.

  • Ihr erstes Argument (Optionalund standardmäßig leer) sind einige Optionen für den TikZ-Knoten (um Füllen, Zeichnen eines Rahmens usw. zu ermöglichen). Ihr zweites Argument ist der Inhalt des Absatzes.

  • Es gibt einige Berechnungen, um einen Fehler tikzpagenodesmit gerader Seite zu korrigieren (Bearbeiten: Martin Scharer reagiert sehr schnell: Eine Version mit behobenen Fehlern kommt zu CTAN.).

  • Der Code verwendet letOperationen (und calcdie TikZ-Bibliothek). Ich denke, er ist lesbarer als PGF-Aufrufe.

Grenzen:

  • \botmarginparAbsätze sollten in umgekehrter Reihenfolge gestapelt werden!
  • Wenn ein Stapel voll ist, wird er nicht mit der nächsten Seite fortgesetzt. Er läuft auf der Seite nach oben oder unten über.
  • Wenn \topmarginpar(oder \bormarginpar) im letzten Absatz einer Seite aufgerufen wird, kann es sein, dass der Randabsatz auf der nächsten Seite und nicht in der richtigen Reihenfolge erscheint.

Hier sind zwei Seiten (erst ungerade und dann gerade):

erste Seite (ungerade) zweite Seite (gerade)

Der Code (mit meinen Kommentaren):

\documentclass[twoside]{report}
\usepackage{tikzpagenodes}
\usepackage{xifthen}
\usetikzlibrary{calc}

\def\myyshifttop{0}
\def\mypagetop{0}
\newcommand{\topmarginpar}[2][]{% tikz options of node, content
  \begin{tikzpicture}[remember picture, overlay]
    % reset position on new page
    \ifthenelse{\thepage=\mypagetop}{}{\xdef\myyshifttop{0}\xdef\mypagetop{\thepage}}
    % a big path with many actions
    \path let
    % patch for bug in tikzpagenodes with even pages
    \p1=(current page marginpar area.north west),
    \p2=(current page marginpar area.north east)
    in \pgfextra{
      \pgfmathsetmacro{\xw}{\x1<\x2?\x1:\x2}
      \pgfmathsetmacro{\yw}{\y1<\y2?\y1:\y2}
      \edef\coord{\xw pt,\yw pt}
    }
    % draw topmarginpar
    node[below right, yshift=\myyshifttop, text width=\marginparwidth-4pt, inner sep=2pt, #1]
    (tempnode) at (\coord) {#2}
    % next position
    let \p1=(\coord), \p2=(tempnode.south west) in \pgfextra{
      \pgfmathsetmacro{\diffy}{(\y2-\y1)}
      \xdef\myyshifttop{\diffy}
    };
  \end{tikzpicture}%
}

\def\myyshiftbot{0}
\def\mypagebot{0}
\newcommand{\botmarginpar}[2][]{% tikz options of node, content
  \begin{tikzpicture}[remember picture, overlay]
    % reset position on new page
    \ifthenelse{\thepage=\mypagebot}{}{\xdef\myyshiftbot{0}\xdef\mypagebot{\thepage}}
    % a big path with many actions
    \path let
    % patch for bug in tikzpagenodes with even pages
    \p1=(current page marginpar area.south west),
    \p2=(current page marginpar area.south east)
    in \pgfextra{
      \pgfmathsetmacro{\xw}{\x1<\x2?\x1:\x2}
      \pgfmathsetmacro{\yw}{\y1<\y2?\y1:\y2}
      \edef\coord{\xw pt,\yw pt}
    }
    % draw botmarginpar
    node[above right, yshift=\myyshiftbot, text width=\marginparwidth-4pt, inner sep=2pt, #1]
    (tempnode) at (\coord) {#2}
    % next position
    let \p1=(\coord), \p2=(tempnode.north west) in \pgfextra{
      \pgfmathsetmacro{\diffy}{(\y2-\y1)}
      \xdef\myyshiftbot{\diffy}
    };
  \end{tikzpicture}%
}

\usepackage{lipsum}

\begin{document}
\topmarginpar[red,fill=yellow!30]{On a journey to find the cure for a
  Tatarigami's curse, Ashitaka finds himself in the middle of a war
  between the forest gods and Tatara, a mining colony.}%
\botmarginpar{What begins as an open and shut case of murder soon
  becomes a mini-drama of each of the jurors' prejudices and
  preconceptions about the trial, the accused, and each other.}%
\lipsum[1-3]%
\botmarginpar[font=\itshape\footnotesize,text=green!50!black]{The
  defense and the prosecution have rested and the jury is filing into
  the jury room to decide if a young Spanish-American is guilty or
  innocent of murdering his father.}%
\topmarginpar[blue]{In this quest he also meets San, the Mononoke
  Hime.}%
\lipsum[4-7]%
\topmarginpar[red]{On a journey to find the cure for a Tatarigami's
  curse, Ashitaka finds himself in the middle of a war between the
  forest gods and Tatara, a mining colony.}%
\botmarginpar[orange!50!gray]{What begins as an open and shut case of
  murder soon becomes a mini-drama of each of the jurors' prejudices and
  preconceptions about the trial, the accused, and each other.}%
\lipsum[8]%
\topmarginpar[blue]{In this quest he also meets San, the Mononoke
  Hime.}%
\botmarginpar[green!50!gray]{The defense and the prosecution have rested
  and the jury is filing into the jury room to decide if a young
  Spanish-American is guilty or innocent of murdering his father.}%
\lipsum[9-12]
\end{document}

Antwort4

Ich habe das Paket einfach gehackt marginfitund eine einfache Lösung erhalten.

\documentclass[11pt,a4paper]{article}

%% Needs marginfit package to be loaded before:
\RequirePackage{marginfit}

\makeatletter
%% Top marginpar:
\def\marginfit@writepost#1{%
    \write\@auxout{\string\@newl@bel{label@marginfit}{#1}{47040224}}%  %% Note it from aux file entry with @t
}
\def\marginpart{%
    \global\advance\c@marginfit@w\@ne%
    \expandafter\marginfit@writepost\expandafter{\the\c@marginfit@w @m}%
    \@ifnextchar[\marginfit@mpar@ii\marginfit@mpar@i%
}
%% Bottom marginpar:
\def\marginfit@writeposb#1{%
    \write\@auxout{\string\@newl@bel{label@marginfit}{#1}{0}}%  %% Minimum is 0
}
\def\marginparb{%
    \global\advance\c@marginfit@w\@ne%
    \expandafter\marginfit@writeposb\expandafter{\the\c@marginfit@w @m}%
    \@ifnextchar[\marginfit@mpar@ii\marginfit@mpar@i%
}
\makeatother


\begin{document}

\marginpar{OM O MO M M M M M M}

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC


\marginpar{OM O MO M M M M M M\par\medskip\hrule}


ABC


\marginpart{To be Top OM O MO M M M M M M}


\newpage  %--------------------------------------------------------------------


ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC

ABC


\marginpart{Top OM O MO M M M M M M}

\marginparb{Bottom OM O MO M M M M M M}


ABC

ABC

ABC

ABC

\end{document}

Es bietet zwei neue Befehle \marginpartfür den oberen und \marginparbunteren Rand. Die Nummer 47040224 steht \pdflastyposfür den obersten Rand. Diese Nummer kann noch höher sein, marginfitum die endgültige Position so festzulegen, dass sie die obere Kante nicht überschreitet. Versuchen Sie je nach Seitengröße höhere Werte. Die beste Methode, dies herauszufinden, besteht darin, zunächst einen einzelnen Rand am Anfang des Dokuments zu erstellen, sodass er ganz oben steht, und seinen Eintrag in der AUX-Datei zu prüfen.

So funktioniert es: marginfitDas Paket speichert die Y-Position aller Randparameter mit einem zugewiesenen Label. Ich habe einfach den Code übernommen, der die Y-Position des aktuellen Randparameters in die AUX-Datei schreibt, und ihn so eingerichtet, dass die Y-Position auf das Maximum (und das Minimum 0 für den unteren Randparameter) gesetzt wird.

verwandte Informationen