将 \marginpar 发送(并堆叠)到页面顶部或底部

将 \marginpar 发送(并堆叠)到页面顶部或底部
  • 我正在寻找类似的东西的定义\topmarginpar{<text>},它本质上会创建一个\marginpar{<text>}并将其顶部与当前页面的顶部对齐。

  • 我还希望多次\topmarginpar调用来堆叠这些\marginpar对象(而不是让它们重叠)。

  • 最后,我想创建一个类似的\bottommargin命令。

是否有一些现有的软件包提供此功能,或者我只能靠自己(我精通 LaTeX,但对原始 TeX 毫无用处)?

谢谢任何建议...

答案1

该解决方案处理异步输出例程:

  • 页面通过绝对页码来标识,并且在第二次 LaTeX 运行中可以使用标签获得正确的页码。

  • 每页都有两个收集箱,用于收集顶部和底部的页边注。发货时,绝对页码是已知的,页面的收集箱输出到页面的“marginpar”区域。

  • 盒子寄存器是动态分配的,并在池中进行管理。页面送出后,其收集器盒子寄存器将被释放并放回池中。

  • \topskip\maxdepth因“marginpar”区域而受到尊重。

  • 页面上的边注过多将被报告为过度\vbox警告。

  • 不支持LaTeX \marginpar,不同种类的边注彼此不认识,并且会愉快地互相重叠。

示例文档:

\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}

结果

答案2

以下是使用马丁·沙雷尔的包裹tikzpage节点.因为它使用remember picture, overlay选项蒂克兹,您需要编译两次才能正确执行。它提供了两个命令\marpartop,并且\marparbot都接受两个参数:内容和文本颜色,这可以轻松扩展为更具可定制性。

代码

\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}

结果

在此处输入图片描述

答案3

(注意:这是一个社区答案,因为最初的想法来自汤姆·邦巴迪尔。)

以下是 Tom Bombadil 答案的一个变体,并进行了一些改进:

  • 这两个宏的命名\topmarginpar\botmarginpar名称均符合要求。

  • 他们的第一个论点(选修的并且默认为空)是 TikZ 节点的一些选项(用于填充、绘制边框等)。它们的第二个参数是段落的内容。

  • 有一些计算来纠正 tikzpagenodes偶数页的错误(编辑:Martin Scharer 反应非常积极:修复错误的版本即将登陆 CTAN。)。

  • 代码使用了let操作(和calcTikZ 库)。我认为它比 PGF 调用更具可读性。

限制:

  • \botmarginpar应该按相反的顺序堆叠段落!
  • 如果堆栈已满,则不会继续下一页。它会溢出页面的上部或下部。
  • 如果在页面的最后一段调用\topmarginpar(或\bormarginpar),则边距段落可能会出现在下一页,并且顺序不正确。

这里有两页(奇数和偶数):

第一页(奇数) 第二页(偶数)

代码(附有我的注释):

\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}

答案4

我对包进行了简单的破解marginfit并得到了一个简单的解决方案。

\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}

\marginpart它为顶部 marginpar 和底部 marginpar提供了两个新命令\marginparb。其中的数字 47040224 表示\pdflastypos最顶部 marginpar。这个数字还可以更高,marginfit它将在最终位置设置其位置,使其不会越过顶部边缘。根据您的页面大小尝试更高的值。找出答案的最佳方法是首先在文档开头创建一个 marginpar,使其位于最顶部,然后查看辅助文件中的条目。

它的工作原理如下:marginfit包保存所有带有指定标签的边距的 y 位置。我只是借用了将当前边距的 ypos 写入辅助文件的代码,并将 ypos 设置为最大值(底部边距的最小值为 0)。

相关内容