page-mar.mkii / last modification: 2020-01-30 14:15
%D \module
%D   [       file=page-mar, % moved here from main-001
%D        version=1997.03.31,
%D          title=\CONTEXT\ Page Macros,
%D       subtitle=Marginal Things,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

%D Support for margin words is one of the reasons for writing
%D \CONTEXT. Over time support for marginal content has been
%D extended en enhanced. Therefore it's always good to watch
%D out for unexpected side effects.

\writestatus{loading}{ConTeXt Page Macros / Maginal Things}

\unprotect

%D There are three categories and their historically grown meaning is
%D as follows:
%D
%D marginlines: these are flushed relative to the start of a line and
%D need to be invoked there.
%D
%D marginwords: these can be issued in the text flow and will migrate
%D sidewards; in spite of the name, it can be a paragraph of text as
%D well, but normally it's words.
%D
%D margintexts: these can be set beforehand and are flushed at the
%D next paragraph of text (of header)
%D
%D While these mechanisms were rather separated, they now are slightly
%D more integrated. Instead of low level instances we now have a mechanism
%D for defining additional ones.

%D \macros
%D   {inleftedge,inleftmargin,inrightmargin,inrightedge}
%D
%D The fast and clean way of putting things in the margin is
%D using \type{\rlap} or \type{\llap}. Unfortunately these
%D macro's don't handle indentation, left and right skips. We
%D therefore embed them in some macro's that (force and)
%D remove the indentation and restore it afterwards.

\def\definemarginline
  {\dodoubleargument\dodefinemarginline}

\def\dodefinemarginline[#1][#2]%
  {\getparameters
     [\??im\??im#1]
     [\c!location=\v!left,
      \c!distance=\zeropoint,
      \c!width=\leftmarginwidth,
      \c!hoffset=\leftmargindistance,
      \c!command=,
      #2]%
   \unexpanded\setvalue{#1}{\dohandlemarginline{#1}}}

\def\marginlineparameter  #1{\csname\??im\??im\currentmarginline#1\endcsname}
\def\marginlineexecuter #1#2{\executeifdefined{\??im\??im\currentmarginline#1}{#2}}

\def\dohandlemarginline#1% #2
  {\def\currentmarginline{#1}%
   \csname\s!do\??im\??im\executeifdefined{\??im\??im#1\c!location}\v!left\endcsname{#1}} % {#2}

\def\doleftmarginline#1#2% #1 is redundant (we can remove it when we group dohandlemarginline; maybe ...
  {\pushindentation
   \llap
     {\def\currentmarginline{#1}%
      \postsignalrightpage
      \hsize\marginlineparameter\c!width\relax
      \marginlineexecuter\c!command\firstofoneargument{#2}\relax
      \hskip\dimexpr
        +\leftskip
        +\compensatedinnermakeupmargin
        +\marginlineparameter\c!hoffset
        +\marginlineparameter\c!distance
      \relax}%
   \popindentation
   \ignorespaces}

\def\dorightmarginline#1#2% #1 is redundant
  {\pushindentation
   \rlap
     {\def\currentmarginline{#1}%
      \postsignalrightpage
      \hskip\dimexpr
        +\hsize
        -\rightskip
        +\compensatedinnermakeupmargin
        +\marginlineparameter\c!hoffset
        +\marginlineparameter\c!distance
      \relax
      \hsize\marginlineparameter\c!width
      \marginlineexecuter\c!command\firstofoneargument{#2}}%
   \popindentation
   \ignorespaces}

\long\def\installmarginlinehandler#1#2{\setvalue{\s!do\??im\??im#1}{#2}}

\installmarginlinehandler \v!left  {\doleftmarginline}
\installmarginlinehandler \v!right {\dorightmarginline}
\installmarginlinehandler \v!inner {\presignalrightpage\doifrightpageelse\doleftmarginline \dorightmarginline}
\installmarginlinehandler \v!outer {\presignalrightpage\doifrightpageelse\dorightmarginline\doleftmarginline }

\definemarginline[inleftmargin] [\c!location=\v!left, \c!width=\leftmarginwidth, \c!distance=\leftmargindistance, \c!hoffset=\zeropoint]
\definemarginline[inrightmargin][\c!location=\v!right,\c!width=\rightmarginwidth,\c!distance=\rightmargindistance,\c!hoffset=\zeropoint]
\definemarginline[inleftedge]   [\c!location=\v!left, \c!width=\leftedgewidth,   \c!distance=\leftedgedistance,   \c!hoffset=\leftmargintotal]
\definemarginline[inrightedge]  [\c!location=\v!right,\c!width=\rightedgewidth,  \c!distance=\rightedgedistance,  \c!hoffset=\rightmargintotal]

\definemarginline[inoutermargin][\c!location=\v!outer,\c!width=\outermarginwidth,\c!distance=\outermargindistance,\c!hoffset=\zeropoint]
\definemarginline[ininnermargin][\c!location=\v!inner,\c!width=\innermarginwidth,\c!distance=\innermargindistance,\c!hoffset=\zeropoint]
\definemarginline[inouteredge]  [\c!location=\v!outer,\c!width=\outeredgewidth,  \c!distance=\outeredgedistance,  \c!hoffset=\outermargintotal]
\definemarginline[ininneredge]  [\c!location=\v!inner,\c!width=\inneredgewidth,  \c!distance=\inneredgedistance,  \c!hoffset=\innermargintotal]

\definemarginline[atleftmargin] [\c!location=\v!left, \c!command=\lrlap,\c!width=\zeropoint,\c!distance=\zeropoint,\c!hoffset=\zeropoint]
\definemarginline[atrightmargin][\c!location=\v!right,\c!command=\rllap,\c!width=\zeropoint,\c!distance=\zeropoint,\c!hoffset=\zeropoint]

\ifx\lrlap\undefined \def\lrlap#1{\llap{\rlap{#1}}} \fi
\ifx\rllap\undefined \def\rllap#1{\rlap{\llap{#1}}} \fi

\def\lrlap#1{\llap{\rlap{#1}}}
\def\rllap#1{\rlap{\hskip\hsize\llap{#1}}}

%D We want to keep things efficient and therefore only handle
%D situations like:
%D
%D \startbuffer
%D                  \inleftedge    {fine} some text \par
%D \strut           \inleftmargin  {fine} some text \par
%D \noindent        \inrightmargin {fine} some text \par
%D \noindent \strut \inrightedge   {fine} some text \par
%D \stopbuffer
%D
%D \typebuffer
%D
%D which looks like:
%D
%D \bgroup
%D \getbuffer
%D \parindent 30pt
%D \getbuffer
%D \egroup
%D
%D A torture test:
%D
%D \starttyping
%D \def\TestLine#1#2{\backgroundline[#1]{\strut\white\tttf#2~\recurselevel}}
%D
%D \startbuffer
%D \inleftmargin {\TestLine{red}   {lm}}  test test test \par
%D \inrightmargin{\TestLine{green} {rm}}  test test test \par
%D \inleftedge   {\TestLine{red}   {le}}  test test test \par
%D \inrightedge  {\TestLine{green} {re}}  test test test \par
%D \inoutermargin{\TestLine{blue}  {om}}  test test test \par
%D \ininnermargin{\TestLine{yellow}{im}}  test test test \par
%D \inouteredge  {\TestLine{blue}  {oe}}  test test test \par
%D \ininneredge  {\TestLine{yellow}{ie}}  test test test \par
%D \atleftmargin {\TestLine{red}   {alm}} \hfill test    \par
%D \atrightmargin{\TestLine{green} {arm}} test \hfill    \par
%D \stopbuffer
%D
%D \dorecurse{40}\getbuffer \page
%D \stoptyping

%D New, yet undocumented:
%D
%D used for pascal:
%D
%D \starttyping
%D \index {test} test \index {west} west \index {rest} rest
%D
%D \startnarrower
%D \placeregister[index][alternative=b,command=\atleftmargin]
%D \stopnarrower
%D \stoptyping

% todo: compensate distance when setuplayout[textwidth=..]
% todo: generalize margin/edge model, now too much duplication

%D The next bunch of macros looks messy which is due to its
%D multi-purpose character.

\chardef\margincontentdisplacement \zerocount
\let    \margincontentdistance     \!!zeropoint
\let    \margincontenthoffset      \!!zeropoint
\def    \margincontentlines        {1}
\def    \margincontenttag          {0}
\let    \margincontentseparator    \empty
\def    \margincontentstrutheight  {\strutht}

\newcount\margincontentlevel
\newdimen\margincontentheight

\def\setupinmargin
  {\dodoubleempty\dosetupinmargin}

\def\dosetupinmargin[#1][#2]%
  {\ifsecondargument
     \processcommalist[#1]{\dodosetupinmargin[#2]}% becomes [#2]{##1}
   \else
     \getparameters[\??im][#1]%
   \fi}

% \def\dodosetupinmargin[#1]#2% [settings]{class}
%   {\checkinmargin[#2]%
%    \getparameters[\??im#2][#1]}

\def\dodosetupinmargin[#1]#2% [settings]{class}
  {\checkinmargin[#2]%
   \getparameters[\??im#2][#1]%
   % will become an \everyinmarginsetup thing
   \ifcase\executeifdefined{\??im#2\c!sidemethod}{0}\else
     \enableparpositions
   \fi}

\def\checkinmargin[#1]%
  {\ifundefined{\??im#1\c!offset}% this offset is related to framed !
     \addtocommalist{#1}\inmargintaglist
     \presetmargintext[#1]%
   \fi}

\def\presetmargintext[#1]%
  {\presetlocalframed
     [\??im#1]%
   \getparameters
     [\??im#1]
     [\c!frame=\v!off,
      \c!offset=\v!overlay,
      \c!line=1,
      \c!separator=,
      \c!width=\v!broad,
      \c!distance=, % empty = signal
      \c!hoffset=\zeropoint,
      \c!style=\@@imstyle,
      \c!color=\@@imcolor,
      \c!strut=\@@imstrut,
      \c!location=\@@imlocation,
      \c!align=\@@imalign,
      \c!before=\@@imbefore,
      \c!after=\@@imafter]}

\newdimen\naturalmargincontentheight

\def\makemargintextblock#1#2#3% width l r content
  {\bgroup
   \forgetall % added, else problems with 'center' and nested itemize
   \dontcomplain
   \hsize\getvalue{\??im#1\c!width}\relax
   \doifnumberelse\margincontenttag
     {\ifcase\margincontenttag\relax
        \edef\margincontenttag{#1}% first one is setups id as well
      \fi}
     \donothing
   \doifnumberelse\margincontenttag
     {\ifnum\margincontenttag>25 % to be translated
        \writestatus\m!systems{potential margin stack overflow (\margincontenttag)}%
      \fi}
     \donothing
   % we need to preserve {a,b,c} kind of settings
   \let\margincontentalign#1%
   \processallactionsinset
     [\getvalue{\??im\margincontenttag\c!align}]
     [     \v!yes=>\let\margincontentalign#1,
            \v!no=>\let\margincontentalign\v!normal,
         \v!inner=>\let\margincontentalign#1,
         \v!outer=>\let\margincontentalign#2,
          \v!left=>\let\margincontentalign\v!left,
        \v!middle=>\let\margincontentalign\v!middle,
         \v!right=>\let\margincontentalign\v!right]%
   \doifvaluesomething{\??im\margincontenttag\c!align} % watch {} around set
     {\edef\margincontentalign{{\getvalue{\??im\margincontenttag\c!align},\margincontentalign}}}%
   %
   \expanded{\getparameters[\??im\margincontenttag][\c!align=\margincontentalign]}%
   %
   \edef\margincontentstrut{\getvalue{\??im\margincontenttag\c!strut}}%
   \savestrut %
   \setbox\scratchbox\vbox\localframed
     [\??im\margincontenttag]
     [\c!strut=\v!no,\c!offset=\v!overlay] % strut handled internally
     {\decrement\margincontentlines
      \dorecurse\margincontentlines{\savedstrut\endgraf\nointerlineskip}% ! savedstrut
      \@@imbefore
      \dostartattributes{\??im\margincontenttag}\c!style\c!color\empty
        \dosetupstrut[\margincontentstrut]% was: \setstrut % yes or no
        \begstrut#3\endstrut\endgraf
        \xdef\margincontentstrutheight{\the\strutht}% so that it's known outside the framed
      \dostopattributes
      \@@imafter}%
   \global        \naturalmargincontentheight\ht\scratchbox
   \global\advance\naturalmargincontentheight\dp\scratchbox
   \doif\@@imstack\v!yes
     {\def\overlappingmargin{-20\scaledpoint}% test value, maybe .25\strutboxdp, maybe configurable
      \setbox\scratchbox\vbox{\stackeddown\vbox{\box\scratchbox}}}% new
   \ht\scratchbox\strutht
   \dp\scratchbox\strutdp % nieuw
   \box\scratchbox
   \egroup}

%D The stacker permits constructs like:
%D
%D \starttyping
%D \setupinmargin[stack=yes]
%D
%D \inleft{test 1}test\break
%D \inleft{test 2}test\break
%D \inleft{test 1}
%D \input tufte
%D \inleft{test 1}
%D \inleft{test 2}
%D \inleft{test 3}
%D \input tufte
%D \inleft{test 1}
%D \inleft{test 2\endgraf test 3}
%D \inleft{test 4}
%D \input tufte
%D \inleft{test 1}
%D \inleft{test 2\endgraf test 3}
%D \inleft{test 4\endgraf test 5\endgraf test 6}
%D \inleft{test 7\endgraf test 8\endgraf test 9}
%D \input tufte
%D \stoptyping

%D This approach permits us to implement a better mechanism
%D later. We need the \type {\graphicvadjust} in order to
%D handle:
%D
%D \starttyping
%D \inleft{test} {\red \dorecurse{40}{test }\par}
%D {\red \inleft{test} \dorecurse{40}{test }\par}
%D \stoptyping
%D
%D The outer margin color is either black or color set as
%D main text color.

\newif\ifrightmargin % documenteren

\ifx\dopositionmarginbox\undefined
  \def\dopositionmarginbox#1{\graphicvadjust{\box#1}}
\fi

% watch out, margin dimensions are swapped locally (\swapmargins)

% with \margincontentmethod one can control pagebreaks
%
% 0 no break
% 1 each entry is one line
% 2 only natural height
% 3 also stack height

\chardef\margincontentmethod  \plusthree % beware: 1 = old method
\chardef\marginpagecheckmethod\plusone

\def\margincontentextralines{1}        % old method, play safe
\def\nofmargincontentlines  {0}

\def\doplacemargintext#1#2#3#4%
  {\dontcomplain
   \strut
   \doifsomething{#1}
     {\def\margincontenttag{#1}}%
   \doifinsetelse{\margincontenttag}{\v!left,\v!right} % ugly hack
     {\let \margincontentdistance                                                      \empty     % signal
      \let \margincontenthoffset                                                       \zeropoint}
     {\edef\margincontentdistance{\executeifdefined{\??im\margincontenttag\c!distance }\empty    }% signal
      \edef\margincontenthoffset {\executeifdefined{\??im\margincontenttag\c!hoffset  }\zeropoint}}%
   \edef\margincontentlines      {\executeifdefined{\??im\margincontenttag\c!line     }\plusone  }%
   \edef\margincontentseparator  {\executeifdefined{\??im\margincontenttag\c!separator}\donothing}%
   \setbox\scratchbox\hbox{#4}% % todo: make sure that color stack works
   \ifcase\margincontentmethod
     \scratchdimen\zeropoint
   \or % old method
     \scratchdimen\ht\scratchbox
     \advance\scratchdimen\dp\scratchbox
   \or
     \scratchdimen\naturalmargincontentheight
   \or
     \scratchdimen\naturalmargincontentheight
     \ifx\laststackvmove\undefined\else\global\advance\scratchdimen\laststackvmove\fi
   \fi
   \ifdim\scratchdimen>\margincontentheight
     \global\margincontentheight\scratchdimen
   \fi
   \setbox\scratchbox\hbox
     {#2{\hskip#3\strut
         \ifcase\margincontentdisplacement
           % normal, move strutheight up
           \scratchdimen\strutdp
           \advance\scratchdimen \margincontentstrutheight
           \advance\scratchdimen -\strutht
           \raise\scratchdimen
         \or
           % low, obey vadjust
         \fi
         \box\scratchbox}}%
   \ht\scratchbox\zeropoint
   \dp\scratchbox\zeropoint
   \gdef\margincontentstrutheight{\the\strutht}%
  %\graphicvadjust{\box\scratchbox}}     % fails in high math lines, let it be
  %\hbox{\lower\strutdp\box\scratchbox}} % alas, wrong lapping, therefore useless
   \dopositionmarginbox\scratchbox}

% \def\domarginblockskip#1%
%   {\hskip\margincontenthoffset
%    \hskip\compensatedinnermakeupmargin\relax
%    \doifelsenothing\margincontentdistance
%      {\hskip\getvalue{\??im#1\c!distance}}
%      {\hskip\margincontentdistance}%
%    \relax}

\def\domarginblockskip#1%
  {\doifelsenothing\margincontentdistance
     {\hskip\dimexpr
        +\margincontenthoffset
        +\compensatedinnermakeupmargin
        +\csname\??im#1\c!distance\endcsname
      \relax}
     {\dimexpr
        +\margincontenthoffset
        +\compensatedinnermakeupmargin
        +\margincontentdistance
      \relax}%
   \relax}

\def\doleftmarginblock#1#2%
  {\doplacemargintext{#1}\llap\zeropoint
     {\llap{\placemargincontentseparator}%
      \makemargintextblock\v!left\v!right{#2}%
      \domarginblockskip\v!left}}

\def\dorightmarginblock#1#2%
  {\doplacemargintext{#1}\rlap\hsize
     {\hskip\textwidth\hskip-\hsize % new: hsize correction
      \domarginblockskip\v!right
      \makemargintextblock\v!right\v!left{#2}%
      \rlap{\placemargincontentseparator}}}

\def\placemargincontentseparator
  {\ifnum\margincontentlevel>\zerocount
     \ifx\margincontentseparator\empty\else
       \bgroup
       \scratchdimen\margincontentlines\lineheight
       \advance\scratchdimen -\lineheight
       \lower\scratchdimen\hbox{\margincontentseparator}%
       \egroup
     \fi
   \fi}

\newbox\marginconstructbox

\def\doinmarginswapped#1#2#3#4%
  {\iffirstsidefloatparagraph\nowhitespace\fi % zo laat mogelijk
   \setbox\marginconstructbox\hbox\bgroup % prevents page break in the middle of construction
     \startsignalrightpage
       \doifswappedrightpageelse
         {\rightmargintrue #2}
         {\rightmarginfalse#1}
         {#3}% setups
         {#4}% content
     \stopsignalrightpage
   \egroup
   \unhbox\marginconstructbox}

% history made this a bit complicated, the +/- was needed before
% we had enough mem/hash to do the page correction

\edef\inmargintaglist{+,-,\v!low,\v!left,\v!right,\v!inner,\v!outer}

% the old one:
%
% \def\doinmargin[#1][#2][#3][#4][#5]% #6 #7
%   {\doifcommonelse{+,-,\v!laag}{#4}
%      {\dodoinmargin[#1][#2][#3][#4][#5]}
%      {\dodoinmargin[#1][#2][#3][][#4]}}
%
% an alternative:
%
% \letvalue{\??im\v!laag\c!offset}\empty
% \letvalue{\??im      +\c!offset}\empty
% \letvalue{\??im      -\c!offset}\empty
%
% \def\doinmargin[#1][#2][#3][#4][#5]% #6 #7
%   {\doifnumberelse{#4}
%      {\dodoinmargin[#1][#2][#3][#4][#5]}
%      {\doifdefinedelse{\??im#4\c!offset}
%         {\dodoinmargin[#1][#2][#3][#4][#5]}
%         {\dodoinmargin[#1][#2][#3][][#4]}}}
%
% the problem is that we need to keep downward compatibility
% with respect to the first argument thing a reference or a
% directive; the alternative is to force users to pass a
% directive along with a reference; anyhow, as long as one
% does not use references that have the same name as a
% directive we can use the (slow) alternative

\def\doinmargin[#1][#2][#3][#4][#5]% #6 #7
  {\expanded{\doifinsetelse{#4}{\inmargintaglist}}
     {\dodoinmargin[#1][#2][#3][#4][#5]}
     {\dodoinmargin[#1][#2][#3][][#4]}}

\def\defineinmargin
  {\doquadrupleempty\dodefineinmargin}

\def\dodefineinmargin[#1][#2][#3][#4]%
  {\doifassignmentelse{#4}
     {\setupinmargin[#1][#4]%
      \setvalue{#1}{\indentation\doquintupleempty\doinmargin[#2][#3][#1]}}
     {\setvalue{#1}{\indentation\doquintupleempty\doinmargin[#2][#3][#4]}}}

\defineinmargin [inleft]   [\v!left]       [\v!normal]   % takes left settings
\defineinmargin [inright]  [\v!right]      [\v!normal]   % takes right settings
\defineinmargin [ininner]  [\v!inner]      [\v!normal]   % takes left/right settings
\defineinmargin [inouter]  [\v!outer]      [\v!normal]   % takes left/right settings
\defineinmargin [inmargin] [\@@imlocation] [\v!normal]   % takes left/right settings
\defineinmargin [inother]  [\@@imlocation] [\v!reverse]  % takes left/right settings

\def\inothermargin{\inother}

%D This permits definitions like:
%D
%D \starttyping
%D \defineinmargin [SomePlace] [inner] [normal] [distance=1cm]
%D \defineinmargin [SomePlace] [inner] [normal] [SomePlace]    \setupinmargin[SomePlace][distance=1cm]
%D \defineinmargin [MyPlace]   [inner] [normal] [SomePlace]
%D \defineinmargin [YourPlace] [inner] [normal] [SomePlace]
%D \stoptyping
%D
%D A torture test:
%D
%D \starttyping
%D \startbuffer
%D \inleft       {\TestLine{red}    {l}} test test test \par
%D \inright      {\TestLine{green}  {r}} test test test \par
%D \inmargin     {\TestLine{blue}   {m}} test test test \par
%D \inothermargin{\TestLine{yellow} {x}} test test test \par
%D \ininner      {\TestLine{cyan}   {i}} test test test \par
%D \inouter      {\TestLine{magenta}{o}} test test test \par
%D \stopbuffer
%D
%D \dorecurse{80}\getbuffer \page
%D \stoptyping
%D
%D and
%D
%D \starttyping
%D \defineinmargin [InOuterA] [outer] [normal] [distance=0cm]
%D \defineinmargin [InOuterB] [outer] [normal] [distance=1cm]
%D \defineinmargin [InOuterC] [outer] [normal] [distance=2cm,line=2]
%D
%D \startbuffer
%D \InOuterA{\TestLine{red}  {A}} test test test \par
%D \InOuterB{\TestLine{green}{B}} test test test \par
%D \InOuterC{\TestLine{blue} {C}} test test test \par
%D \stopbuffer
%D
%D \dorecurse{80}\getbuffer \page
%D
%D \dorecurse{10}{\inleft {one} test \inleft {two} test } \page
%D
%D \start
%D   \margintext {one} \margintext {two} \input thuan \par
%D   \setupinmargin[1][line=3,distance=1cm]
%D   \margintext [1]{one}
%D   \margintext [2]{two}
%D   \input thuan \page
%D \stop
%D
%D \setupinmargin[3][location=inner,distance=1cm]
%D \setupinmargin[4][location=outer,distance=2cm]
%D
%D % \setupinmargin[left] [line=2]
%D % \setupinmargin[right][line=2]
%D
%D \dorecurse
%D   {10}
%D   {\margintext       {\kern3cm\TestLine{blue}{none}}
%D    \margintext[3]    {\TestLine{darkgray}{3}}
%D    \margintext[4]    {\TestLine{darkgray}{4}}
%D    \margintext[left] {\TestLine{red}     {left}}
%D    \margintext[right]{\TestLine{green}   {right}}
%D    \margintext[inner]{\TestLine{cyan}    {inner}}
%D    \margintext[outer]{\TestLine{magenta} {outer}}
%D    \input thuan \endgraf}
%D
%D \dorecurse{10}{\margintext{test\\test\\test} \input thuan \endgraf}
%D \stoptyping

% Test case:
%
% \setuppagenumbering[alternative=doublesided] \setupwhitespace[medium]
%
% \placefigure[right]{}{\externalfigure[dummy][width=2cm]}
% \input tufte \inothermargin{test} \input tufte

% \def\dodoinmargin[#1][#2][#3][#4][#5]#6%
%   {\bgroup
%    \forgetall % otherwise sidefloat problems, added 2005/07/20, maybe dangerous
%    \postponenotes % group is (somehow) needed
%    \doifinsetelse\v!low{#4}
%      {\chardef\margincontentdisplacement\plusone}
%      {\chardef\margincontentdisplacement\zerocount}%
%    \doif\v!reverse{#2}
%      {\swapmacros\dorightmarginblock\doleftmarginblock}%
%    \processaction
%      [#1]
%      [   \v!left=>\let\next\doleftmarginblock,  % no swapping
%         \v!right=>\let\next\dorightmarginblock, % no swapping
%         \v!inner=>\def\next{\doinmarginswapped\dorightmarginblock\doleftmarginblock },
%         \v!outer=>\def\next{\doinmarginswapped\doleftmarginblock \dorightmarginblock},
%       \s!unknown=>\ifdoublesided
%                     \doifcommonelse{+,-}{#4}
%                       {\def\next{\doinmarginswapped\dorightmarginblock\doleftmarginblock }}
%                       {\def\next{\doinmarginswapped\doleftmarginblock \dorightmarginblock}}%
%                   \else
%                     \let\next\doleftmarginblock
%                   \fi]%
%    \next{#3}{#6}%
%    \rawpagereference\s!mar{#5}% naar binnen ! ! ! !
%    \flushnotes
%    \egroup % don't forget the group
%    \ignorespaces}

% test first
%
% setupsystem[random=1235]
%
% \setupinmargin[left][sidemethod=3]
% \dorecurse{10}{test \fakewords{20}{40} test \inleft{test\\test} test \fakewords{20}{40} \par}
% \page
% \setupinmargin[left][sidemethod=4]
% \dorecurse{40}{test \fakewords{50}{80} test \inleft{test\\test} \par}
% \page

\def\dodoinmargin[#1][#2][#3][#4][#5]#6%
  {\bgroup
% \tracingall
   % old stuff, a bit tricky, but now interfaced
   \edef\currentmargincontent{#1}%
   \chardef\marginrepositionmethod\executeifdefined{\??im\currentmargincontent\c!sidemethod }\plusone
   \chardef\margincontentmethod   \executeifdefined{\??im\currentmargincontent\c!textmethod }\plusthree
   \chardef\marginpagecheckmethod \executeifdefined{\??im\currentmargincontent\c!splitmethod}\plusone
   % so far
   \forgetall % otherwise sidefloat problems, added 2005/07/20, maybe dangerous
   \postponenotes % group is (somehow) needed
   \doifinsetelse\v!low{#4}
     {\chardef\margincontentdisplacement\plusone}
     {\chardef\margincontentdisplacement\zerocount}%
   \doif\v!reverse{#2}
     {\swapmacros\dorightmarginblock\doleftmarginblock}%
   \processaction
     [#1]
     [   \v!left=>\let\next\doleftmarginblock,  % no swapping
        \v!right=>\let\next\dorightmarginblock, % no swapping
        \v!inner=>\def\next{\doinmarginswapped\dorightmarginblock\doleftmarginblock },
        \v!outer=>\def\next{\doinmarginswapped\doleftmarginblock \dorightmarginblock},
      \s!unknown=>\ifdoublesided
                    \doifcommonelse{+,-}{#4}
                      {\def\next{\doinmarginswapped\dorightmarginblock\doleftmarginblock }}
                      {\def\next{\doinmarginswapped\doleftmarginblock \dorightmarginblock}}%
                  \else
                    \let\next\doleftmarginblock
                  \fi]%
   \next{#3}{#6}%
   \rawpagereference\s!mar{#5}% naar binnen ! ! ! !
   \flushnotes
   \egroup % don't forget the group
   \ignorespaces}

% dit zijn voorlopig lokale commando's / vervallen
%
% \def\woordinmarge {\indentation\doquintupleempty\doinmargin[\@@implaats][\inleftmargin][\inrightmarge]}
%
% \def\woordinlinker {\inleftmargin  } % vervallen
% \def\woordinrechter{\inrechtermarge} % vervallen

% Some day: \definemarking[\v!margetitel]

%D Now come the margin text collectors. The collected content is
%D flushed at every paragraph by the following macro. Note for
%D myself: here the location (plaats) is no longer a tag (number).

% gone: \def\doflushmargincontent{\doinmargin[\@@implaats][\v!normaal][]} % + [#1][#2]{#3}}

%D These are now all the same (long ago they had different
%D implementations, somewhere in Sork time if I remember
%D right).

\def\margintext {\dodoubleempty\domargincontent}
\def\marginword {\margintext}
\def\margintitle{\margintext} % txt mark as well

\newtoks\collectedmargintexts % so .. delayed!
\chardef\margintextcollected  \zerocount

\def\domargincontent[#1][#2]#3% we used to check for #2/#1 being number, no longer now
  {\global\chardef\margintextcollected\plusone
   \edef\margincontenttag{#1}%
   \ifx\margincontenttag\empty
     \global\advance\margincontentlevel\plusone
     \edef\margincontenttag{\number\margincontentlevel}%
   \fi
   \checkinmargin[\margincontenttag]%
   \doglobal \appendetoks
     \noexpand \checkinmargin[\margincontenttag]%
     \noexpand \doinmargin[\executeifdefined{\??im\margincontenttag\c!location}\@@imlocation][\v!normal][\margincontenttag][\margincontenttag][#2]%
   \to \collectedmargintexts
   \doglobal \appendtoks
     {#3}%
   \to \collectedmargintexts}

\let\restoreinterlinepenalty\relax

\def\flushmargincontents % plural
  {\restoreinterlinepenalty % here?
   \ifcase\margintextcollected\else     % called quite often, so we
     \expandafter\doflushmargincontents % speed up the \fi scan by
   \fi}                                 % using a \do..

\def\doflushmargincontents % links + rechts
  {\bgroup
   \forgetall
   \global\margincontentheight\zeropoint
   \startsignalrightpage
     \the\collectedmargintexts
     \signalrightpage
   \stopsignalrightpage
   \resetmargincontent
   % dirty tricks
   \ifcase\margincontentmethod
     \donefalse
   \else\ifinsidecolumns % brrrr
     \donetrue  % how fuzzy
   \else\ifdim\margincontentheight>\lineheight\relax
     \donetrue  % how dirty
   \else
     \donefalse % how needed
   \fi\fi\fi
   \savemargincontentlines
   \ifdone
     \advance\margincontentheight \margincontentextralines\lineheight
     \ifdim\pagegoal>\pagetotal
       \bgroup % preserve \margincontentheight
       \advance\margincontentheight \pagetotal
       \ifdim\margincontentheight>\pagegoal
         \egroup
         \ifcase\marginpagecheckmethod
           % disabled
         \or
           \setmargincontentpenalties
         \or
           % potentially dangerous, maybe better a \goodbreak; the problem is that
           % there can be a penalty there, which we then overload and we also introduce
           % nasty side effects, so, we drop this option
           % \vadjust pre {\page}%
         \fi
       \else
         \egroup
       \fi
     \fi
   \else % We need the above because interlinepenalties overrule vadjusted \nobreaks.
     % a  bit dangerous
     \vadjust{\nobreak}%
   \fi
   \egroup}

\def\setmargincontentpenalties
  {\getnoflines\margincontentheight
   \keeplinestogether\noflines}

\def\savemargincontentlines
  {\bgroup
   \advance\margincontentheight \margincontentextralines\lineheight % 1 by default
   \getnoflines\margincontentheight
   \xdef\nofmargincontentlines{\the\noflines}%
   \egroup}

\def\fillupmargincontentlines % etex ! ! !
  {\endgraf
   \begingroup
   \scratchcounter\numexpr\nofmargincontentlines-\prevgraf\relax\relax
   \ifnum\scratchcounter>\zerocount
     \forgetall\dorecurse\scratchcounter{\nobreak\crlf}%
   \fi
   \endgroup}

% Yet undocumented, for a manual flush in for instance headers.

\def\resetmargincontent
  {\global\margincontentlevel\zerocount
   \global\chardef\margintextcollected\zerocount
   \global\collectedmargintexts\emptytoks}

% \def\placemargincontent
%   {\ifcase\margintextcollected\else
%      \bgroup
%        \chardef\graphicvadjustmode\zerocount
%        \doflushmargincontents
%      \egroup
%    \fi}
%
% font fix:

\def\placemargincontent
  {\ifcase\margintextcollected\else % was level check
     \bgroup
       \redoconvertfont % !!
       \chardef\graphicvadjustmode\zerocount
       \doflushmargincontents
     \egroup
   \fi}

% For old times sake (i use it in project styles) we provide

\def\placemargintexts {\placemargincontent}
\def\resetmargetitels {\resetmargincontent}
\def\margewoordpositie{\margewoord} % obsolete, now no longer range

% but never use them yourself since they may disappear.

\def\oplinker#1%
  {\strut
   \graphicvadjust
     {\dontcomplain
      \setbox\scratchbox\vtop{\forgetall\strut#1}%
      \getboxheight\scratchdimen\of\box\scratchbox
      \vskip-\scratchdimen % waarom stond hier een \ ?
      \box\scratchbox}}

\setupinmargin
  [\c!style=\v!bold,
   \c!color=,
   \c!strut=\v!auto,
   \c!location=\v!both,
   \c!align=\v!inner,
   \c!stack=\v!no,
   \c!before=,
   \c!after=]

\setupinmargin
  [\v!left]
  [\c!distance=\leftmargindistance,
   \c!width=\leftmarginwidth,
  %\c!align=\v!left, % no
   \c!location=\v!left]

\setupinmargin
  [\v!right]
  [\c!distance=\rightmargindistance,
   \c!width=\rightmarginwidth,
  %\c!align=\v!right, % no
   \c!location=\v!right]

% bonus needed when [inner/outer] is used as tag

\setupinmargin[\v!inner][\c!location=\v!inner,\c!align=\v!inner]
\setupinmargin[\v!outer][\c!location=\v!outer,\c!align=\v!inner]

% more efficient (5K less fotmat file)
%
% \letvalue{\??im\v!inner\c!location}\v!inner \letvalue{\??im\v!inner\c!align}\v!inner
% \letvalue{\??im\v!outer\c!location}\v!outer \letvalue{\??im\v!outer\c!align}\v!inner

\protect \endinput