Estou procurando definir algo como
\topmarginpar{<text>}
, que essencialmente criaria um\marginpar{<text>}
e alinharia seu topo com o topo da página atual.Eu também gostaria que várias
\topmarginpar
chamadas empilhassem esses\marginpar
objetos (em vez de sobrepô-los).E finalmente gostaria de criar um
\bottommargin
comando semelhante.
Existe algum pacote existente que fornece essa funcionalidade ou estou sozinho aqui (sou fluente em LaTeX, mas inútil em relação ao TeX bruto)?
Obrigado por qualquer sugestão...
Responder1
Esta solução trata da rotina de saída assíncrona:
As páginas são identificadas por números de páginas absolutos e os números de páginas corretos estão disponíveis na segunda execução do LaTeX usando rótulos.
Cada página recebe duas caixas coletoras que coletam as notas marginais de cima e de baixo. No momento do envio, o número absoluto da página é conhecido e as caixas coletoras da página são exibidas na área "marginpar" da página.
Os registradores de caixa são alocados dinamicamente e gerenciados em um pool. Após o envio da página, seus registros da caixa coletora são liberados e recolocados no pool.
\topskip
e\maxdepth
são respeitados pela área “marginpar”.Muitas notas marginais em uma página são relatadas como
\vbox
avisos excessivamente completos.LaTeX
\marginpar
não é suportado, as notas marginais de diferentes tipos não se conhecem e ficarão felizmente sobrepostas umas às outras.
O documento de exemplo:
\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}
Responder2
Aqui está uma tentativa usandoMartin Scharrerpacote detikzpagenodes. Como utiliza as remember picture, overlay
opções deTikZ, você precisará compilar duas vezes para acertar. Ele fornece os dois comandos \marpartop
e \marparbot
ambos levam dois argumentos: o conteúdo e a cor do texto, que pode ser facilmente expandido para ser mais personalizável.
Código
\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}
Resultado
Responder3
(Nota: é uma resposta da comunidade porque a ideia original é de Tom Bombadil.)
Aqui está uma variante da resposta de Tom Bombadil com algumas melhorias:
As duas macros são nomeadas
\topmarginpar
e\botmarginpar
conforme solicitado.Seu primeiro argumento (opcionale vazio por padrão) são algumas opções para o nó TikZ (para permitir preenchimento, desenho de borda, etc.). O segundo argumento é o conteúdo do parágrafo.
Existem alguns cálculos para corrigir um bug na
tikzpagenodes
página par (edit: Martin Scharer é muito reativo: uma versão com bug corrigido está chegando ao CTAN.).O código usa
let
operações (ecalc
a biblioteca TikZ). Acho que é mais legível que as chamadas PGF.
Limites:
\botmarginpar
deve empilhar os parágrafos na ordem inversa!- Se uma pilha estiver cheia, ela não continuará na próxima página. Ele transborda para cima ou para baixo na página.
- Se
\topmarginpar
(ou\bormarginpar
) for chamado no último parágrafo de uma página, o parágrafo de margem poderá aparecer na próxima página e não na ordem correta.
Aqui estão duas páginas (ímpares e pares):
O código (com meus comentários):
\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}
Responder4
Fiz um hack simples no marginfit
pacote e consegui uma solução simples.
\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}
Ele fornece dois novos comandos \marginpart
para marginpar superior e \marginparb
marginpar inferior. O número 47040224 nele é \pdflastypos
para a margem superior. Este número pode ser ainda maior, marginfit
definirá sua posição no posicionamento final para que não ultrapasse a borda superior. Experimente valores mais altos dependendo do tamanho da página. O melhor método para descobrir é primeiro criar um único marginpar no início do documento para que fique no topo e examinar sua entrada no arquivo aux.
É assim que funciona: marginfit
o pacote salva a posição de todos os marginpars com um rótulo atribuído. Acabei de pegar emprestado o código que grava os ypos do marginpar atual no arquivo aux e configurei o ypos para o máximo (e mínimo 0 para o marginpar inferior).