math-arr.mkiv / last modification: 2020-01-30 14:16
%D \module
%D   [       file=math-arr,
%D        version=2007.07.19,
%D          title=\CONTEXT\ Math Macros,
%D       subtitle=Arrows,
%D         author={Hans Hagen \& Taco Hoekwater \& Aditya Mahajan},
%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 We keep this file around as reference of his things were done in the
%D past. You can still load this module but it has been replaced by more
%D modern code.

\writestatus{loading}{ConTeXt Math Macros / Arrows}

\unprotect

%D These will be generalized! Is it still needed in \MKIV? Also, we need to
%D to it using regular opentype math!

% Plain code:
%
% \def\rightarrowfill
%   {$%
%    \mathsurround\zeropoint
%    \smash-%
%    \mkern-7mu%
%    \cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
%    \mkern-7mu%
%    \mathord\rightarrow
%    $}
%
% \def\leftarrowfill % brrr no longer in luatex
%   {$%
%    \mathsurround\zeropoint
%    \mathord\leftarrow
%    \mkern-7mu%
%    \cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
%    \mkern-7mu
%    \smash-%
%    $}

%D Extensible arrows are arrows that change their length according to the width of
%D the text to be placed above and below the arrow.
%D
%D Since we need to define a lot of arrows, we first define some helper macros. The
%D basic idea is to measure the width of the box to be placed above and below the
%D arrow, and make the \quote {body} of the arrow as long as the bigger of the two
%D widths.

\installcorenamespace{matharrowsettings}

\def\m_math_arrows_factor{1}
\def\m_math_arrows_extra {0}

\setvalue{\??matharrowsettings\v!none   }{\def\m_math_arrows_factor{0}}
\setvalue{\??matharrowsettings\v!small  }{\def\m_math_arrows_extra{10}}
\setvalue{\??matharrowsettings\v!medium }{\def\m_math_arrows_extra{15}}
\setvalue{\??matharrowsettings\v!big    }{\def\m_math_arrows_extra{20}}
\setvalue{\??matharrowsettings\v!normal }{}
\setvalue{\??matharrowsettings          }{}
\setvalue{\??matharrowsettings\s!unknown}{\doifelsenumber\p_math_spacing{\let\m_math_arrows_extra\p_math_spacing}\donothing}

\def\math_arrows_construct#1#2#3#4#5% hm, looks like we do a double mathrel (a bit cleaned up .. needs checking)
  {\begingroup
   \let\m_math_arrows_factor\!!plusone
   \let\m_math_arrows_extra \!!zerocount
   \edef\p_math_spacing{#1}%
   \csname\??matharrowsettings
     \ifcsname\??matharrowsettings\p_math_spacing\endcsname\p_math_spacing\else\s!unknown\fi
   \endcsname
   \mathsurround\zeropoint
   \scratchmuskipone\muexpr\m_math_arrows_factor\muexpr\thirdoffourarguments #2\onemuskip\relax+\m_math_arrows_extra\onemuskip+\firstoffourarguments #2\onemuskip\relax
   \scratchmuskiptwo\muexpr\m_math_arrows_factor\muexpr\fourthoffourarguments#2\onemuskip\relax+\m_math_arrows_extra\onemuskip+\secondoffourarguments#2\onemuskip\relax
   \setbox\scratchboxone\hbox
     {\normalstartimath
      \scriptstyle
      \mkern\scratchmuskipone\relax
      #5\relax
      \mkern\scratchmuskiptwo\relax
      \normalstopimath}%
   \setbox\scratchboxtwo\hbox
     {\normalstartimath
      \scriptstyle
      \mkern\scratchmuskipone\relax
      #4\relax
      \mkern\scratchmuskiptwo\relax
      \normalstopimath}%
   \setbox\scratchboxthree\hbox{#3\displaystyle}%
   \scratchdimenone\wd\scratchboxone\relax
   \ifdim\wd\scratchboxtwo>\scratchdimenone
     \scratchdimenone\wd\scratchboxtwo\relax
   \fi
   \ifdim\wd\scratchboxthree>\scratchdimenone
     \scratchdimenone\wd\scratchboxthree\relax
   \fi
   \ifdim\wd\scratchboxthree=\scratchdimenone\else
     \setbox\scratchboxthree\hbox to \scratchdimenone{#3\displaystyle}%
   \fi
   \mathrel
     {\mathop
        {\hpack to \scratchdimenone{\hss\box\scratchboxthree\hss}}% pack ? copy ?
        \limits
        \normalsuperscript{\box\scratchboxone}%
        \normalsubscript  {\box\scratchboxtwo}}%
   \endgroup}

\let\math_arrows_construct_single\math_arrows_construct

%D There are some arrows which are created by stacking two arrows. The next
%D macro helps in defining such \quotation{double arrows}.

% weird, we get a shift with the double ... but will become core luatex anyway
%
% \startchemicalformula
%     \chemical{S}
%     \chemical{+}
%     \chemical{O_2}
%     \chemical{EQUILIBRIUM}{boven}{onder}
%     \chemical{SO_2}
% \stopchemicalformula

\def\math_arrows_construct_double#1#2#3#4#5#6#7% opt l r sp rs top bot
  {\mathrel
     {\scratchdimen.32\exheight\relax % was .22, todo: make configurable
      \setbox\scratchboxone\hbox{\normalstartimath\math_arrows_construct{#1}{#2}{#4}{\phantom{#6}}{#7}\normalstopimath}%
      \setbox\scratchboxtwo\hbox{\normalstartimath\math_arrows_construct{#1}{#3}{#5}{#6}{\phantom{#7}}\normalstopimath}%
      \raise\scratchdimen\box\scratchboxone
      \kern-\wd\scratchboxtwo
      \lower\scratchdimen\box\scratchboxtwo}}

%D \macros{definematharrow}
%D
%D Macro for defining new arrows. We can define two types of arrows|<|single arrows
%D and double arrows. Single arrows are defined as
%D
%D \starttyping
%D \definematharrow [xrightarrow]        [0359] [\rightarrowfill]
%D \stoptyping
%D
%D The first argument is the name of the arrow (\tex {xrightarrow} in this case.) The
%D second argument consists of a set of 4 numbers and specify the spacing correction
%D in math units~\type {mu}. These numbers define:
%D
%D \startlines
%D   1st number: arrow||tip correction
%D   2nd number: arrow||tip correction
%D   3rd number: space (multiplied by \tex{matharrfactor} and advanced by \tex{matharrextra})
%D   4th number: space (multiplied by \tex{matharrfactor} and advanced by \tex{matharrextra})
%D \stoplines
%D
%D The third argument is the name of the extensible fill. The third argument is optional
%D when the arrow is redefined later (this is useful for font specific tweaking of the
%D skips.) For example,
%D
%D \startbuffer
%D \math{\xrightarrow{above}}
%D \definematharrow[xrightarrow][0000]
%D \math{\xrightarrow{above}}
%D \definematharrow[xrightarrow][55{50}{50}]
%D \math{\xrightarrow{above}}
%D \stopbuffer
%D \typebuffer gives {\getbuffer}
%D
%D The double arrows are defined as follows
%D
%D \starttyping
%D \definematharrow [xrightleftharpoons] [3095,0359]
%D                  [\rightharpoonupfill,\leftharpoondownfill]
%D \stoptyping
%D
%D The second and the third set of arguments consist of comma separated values. The
%D first element of the second argument (\type {3095}) corresponds to the spacing
%D correction of top arrow fill (\tex{rightarrowupfill}). Similarly, \type {0359}
%D corresponds to bottom arrow fill \tex {leftharpoondownfill}). Stacking them on
%D top of each other we get $\xrightleftharpoons [big] {above} {below}$. The
%D following math arrows are defined
%D
%D \placetable[none]{}{\starttable[|l|m|]
%D   \NC \tex{xrightarrow}        \NC \xrightarrow        [big] \NC \NR
%D   \NC \tex{xleftarrow}         \NC \xleftarrow         [big] \NC \NR
%D   \NC \tex{xequal}             \NC \xequal             [big] \NC \NR
%D   \NC \tex{xRightarrow}        \NC \xRightarrow        [big] \NC \NR
%D   \NC \tex{xLeftarrow}         \NC \xLeftarrow         [big] \NC \NR
%D   \NC \tex{xLeftrightarrow}    \NC \xLeftrightarrow    [big] \NC \NR
%D   \NC \tex{xleftrightarrow}    \NC \xleftrightarrow    [big] \NC \NR
%D   \NC \tex{xmapsto}            \NC \xmapsto            [big] \NC \NR
%D   \NC \tex{xtwoheadrightarrow} \NC \xtwoheadrightarrow [big] \NC \NR
%D   \NC \tex{xtwoheadleftarrow}  \NC \xtwoheadleftarrow  [big] \NC \NR
%D   \NC \tex{xrightharpoondown}  \NC \xrightharpoondown  [big] \NC \NR
%D   \NC \tex{xrightharpoonup}    \NC \xrightharpoonup    [big] \NC \NR
%D   \NC \tex{xleftharpoondown}   \NC \xleftharpoondown   [big] \NC \NR
%D   \NC \tex{xleftharpoonup}     \NC \xleftharpoonup     [big] \NC \NR
%D   \NC \tex{xhookleftarrow}     \NC \xhookleftarrow     [big] \NC \NR
%D   \NC \tex{xhookrightarrow}    \NC \xhookrightarrow    [big] \NC \NR
%D   \NC \tex{xleftrightharpoons} \NC \xleftrightharpoons [big] \NC \NR
%D   \NC \tex{xrightleftharpoons} \NC \xrightleftharpoons [big] \NC \NR
%D \stoptable}

%D If needed this can be optimized (i.e. we can preexpand using \type
%D {\docheckedpair}).

\unexpanded\def\definematharrow
  {\doquadrupleargument\math_arrows_define}

\def\math_arrows_define[#1][#2][#3][#4]% name type[none|both] template command
  {\iffourthargument
      \executeifdefined{math_arrows_define_#2}\gobblethreearguments{#1}{#3}{#4}%
   \else\ifthirdargument
      \math_arrows_define_both{#1}{#2}{#3}%
   \else\ifsecondargument
      \math_arrows_define_both_again{#1}{#2}{#3}%
   \fi\fi\fi}

\def\math_arrows_define_both_again#1#2#3% real dirty, this overload!
  {\ifcsname#1\endcsname
     \pushmacro\math_arrows_do
     \def\math_arrows_do[##1][##2]{\setuvalue{#1}{\math_arrows_do[#2][##2]}}%
     \csname#1\endcsname
     \popmacro\math_arrows_do
   \fi}

\def\math_arrows_define_both#1#2#3%
  {\setuvalue{#1}{\math_arrows_do[#2][#3]}}

\unexpanded\def\math_arrows_do
  {\doquadrupleempty\math_arrows_handle}

\def\math_arrows_handle[#1][#2][#3][#4]% #3 == optional arg .. \empty can be just 'empty' [#4] gobbles spaces
  {\def\math_arrows_handle_indeed{\math_arrows_handle_finalize[#1,\empty,\empty][#2,\empty,\empty][#3]}% {##1}{##2}
   \dodoublegroupempty\math_arrows_handle_indeed}

\def\math_arrows_handle_finalize[#1,#2,#3][#4,#5,#6][#7]#8#9% [#7] is the optional arg
  {\edef\!!stringa{#2}%
   \ifx\!!stringa\empty
     \ifsecondargument
       \mathrel{\math_arrows_construct_single{#7}{#1}{#4}{#8}{#9}}%
     \else
       \mathrel{\math_arrows_construct_single{#7}{#1}{#4}{}{#8}}%
     \fi
   \else
     \ifsecondargument
       \mathrel{\math_arrows_construct_double{#7}{#1}{#2}{#4}{#5}{#8}{#9}}%
     \else
       \mathrel{\math_arrows_construct_double{#7}{#1}{#2}{#4}{#5}{}{#8}}%
     \fi
   \fi}

% Adapted from amsmath.

%D \macros{mtharrowfill,defaultmtharrowfill}
%D
%D To extend the arrows we need to define a \quotation {math arrow fill}. This
%D command takes 8 arguments: the first four correspond the second argument of
%D \tex {definematharrow} explained above. The other three specify the tail,
%D body and head of the arrow. The last argument specifies the math-mode in which
%D the arrow is drawn. \tex {defaultmtharrowfill} has values tweaked to match
%D Latin Modern fonts. For fonts that are significantly different (e.g. cows) a
%D different set of values need to be determined.

\def\mtharrowfill#1#2#3#4#5#6#7#8%
  {\normalstartimath
   \mathsurround\zeropoint
   \thickmuskip\zeromuskip\medmuskip\thickmuskip\thinmuskip\thickmuskip
   \relax#8#5%
   \mkern-#1\onemuskip
   \cleaders\hbox{\normalstartimath#8\mkern-#2\onemuskip#6\mkern-#3\onemuskip\normalstopimath}\hfill
   \mkern-#4\onemuskip#7%
   \normalstopimath}

\def\defaultmtharrowfill{\mtharrowfill 7227}

%D We now define some arrow fills that will be used for defining the arrows. Plain
%D \TEX\ already defines \tex {leftarrowfill} and \tex {rightarrowfill}. The \tex
%D {defaultmtharrowfill} command defines an arrowfill that takes an argument (so
%D that it can also be used with over and under arrows). However the Plain \TEX\
%D definitions of \tex {leftarrowfill} and \tex {rightarrowfill} do not take this
%D extra argument. To be backward compatible with Plain \TEX, we define two
%D arrowfills: \tex {specrightarrowfill} which takes an extra argument, and \tex
%D {rightarrowfill} which does not.

\unexpanded\def\specrightarrowfill   {\defaultmtharrowfill \relbar               \relbar \rightarrow}
\unexpanded\def\specleftarrowfill    {\defaultmtharrowfill \leftarrow            \relbar \relbar}

\unexpanded\def\rightarrowfill       {\specrightarrowfill\textstyle}
\unexpanded\def\leftarrowfill        {\specleftarrowfill \textstyle}

\unexpanded\def\equalfill            {\defaultmtharrowfill \Relbar               \Relbar \Relbar}
\unexpanded\def\Rightarrowfill       {\defaultmtharrowfill \Relbar               \Relbar \Rightarrow}
\unexpanded\def\Leftarrowfill        {\defaultmtharrowfill \Leftarrow            \Relbar \Relbar}
\unexpanded\def\Leftrightarrowfill   {\defaultmtharrowfill \Leftarrow            \Relbar \Rightarrow}
\unexpanded\def\leftrightarrowfill   {\defaultmtharrowfill \leftarrow            \relbar \rightarrow}
\unexpanded\def\mapstofill           {\defaultmtharrowfill{\mapstochar\relbar}   \relbar \rightarrow}
\unexpanded\def\twoheadrightarrowfill{\defaultmtharrowfill \relbar               \relbar \twoheadrightarrow}
\unexpanded\def\twoheadleftarrowfill {\defaultmtharrowfill \twoheadleftarrow     \relbar \relbar}
\unexpanded\def\rightharpoondownfill {\defaultmtharrowfill \relbar               \relbar \rightharpoondown}
\unexpanded\def\rightharpoonupfill   {\defaultmtharrowfill \relbar               \relbar \rightharpoonup}
\unexpanded\def\leftharpoondownfill  {\defaultmtharrowfill \leftharpoondown      \relbar \relbar}
\unexpanded\def\leftharpoonupfill    {\defaultmtharrowfill \leftharpoonup        \relbar \relbar}
\unexpanded\def\hookleftfill         {\defaultmtharrowfill \leftarrow            \relbar{\relbar\joinrel\rhook}}
\unexpanded\def\hookrightfill        {\defaultmtharrowfill{\lhook\joinrel\relbar}\relbar \rightarrow}
\unexpanded\def\relfill              {\defaultmtharrowfill \relbar               \relbar \relbar}

\unexpanded\def\triplerelbar {\mathrel\equiv}
\unexpanded\def\triplerelfill{\defaultmtharrowfill\triplerelbar\triplerelbar\triplerelbar}

\unexpanded\def\singlebond{{\xrel}} % or \def\singlebond{{\xrel[2]}}
\unexpanded\def\doublebond{{\xequal}}
\unexpanded\def\triplebond{{\xtriplerel}}

%D A bit or arrow juggling:
%D
%D \startbuffer
%D \hbox to \hsize{\rightoverleftarrowfill}
%D \stopbuffer
%D
%D \typebuffer \blank \getbuffer \blank

\unexpanded\def\rightoverleftarrowfill
   {\specrightoverleftarrowfill}

\unexpanded\def\specrightoverleftarrowfill
  {\defaultmtharrowfill
     \ctxdoublearrowfillleftend
     \ctxdoublearrowfillmiddlepart
     \ctxdoublearrowfillrightend
     \textstyle}

%D Now we define most commonly used arrows. These include arrows defined in \filename
%D {amsmath.sty}, \filename {extarrows.sty}, \filename {extpfel.sty} and \filename
%D {mathtools.sty} packages for \LATEX\ (plus a few more).

\definematharrow [xrightarrow]         [0359]      [\specrightarrowfill]
\definematharrow [xleftarrow]          [3095]      [\specleftarrowfill]
\definematharrow [xequal]              [0099]      [\equalfill]
\definematharrow [xRightarrow]         [0359]      [\Rightarrowfill]
\definematharrow [xLeftarrow]          [3095]      [\Leftarrowfill]
\definematharrow [xLeftrightarrow]     [0099]      [\Leftrightarrowfill]
\definematharrow [xleftrightarrow]     [0099]      [\leftrightarrowfill]
\definematharrow [xmapsto]             [3599]      [\mapstofill]
\definematharrow [xtwoheadrightarrow]  [5009]      [\twoheadrightarrowfill]
\definematharrow [xtwoheadleftarrow]   [0590]      [\twoheadleftarrowfill]
\definematharrow [xrightharpoondown]   [0359]      [\rightharpoondownfill]
\definematharrow [xrightharpoonup]     [0359]      [\rightharpoonupfill]
\definematharrow [xleftharpoondown]    [3095]      [\leftharpoondownfill]
\definematharrow [xleftharpoonup]      [3095]      [\leftharpoonupfill]
\definematharrow [xhookleftarrow]      [3095]      [\hookleftfill]
\definematharrow [xhookrightarrow]     [0395]      [\hookrightfill]
\definematharrow [xrel]                [0099]      [\relfill]
\definematharrow [xtriplerel]          [0099]      [\triplerelfill]
\definematharrow [xrightoverleftarrow] [0359,3095] [\specrightarrowfill,\specleftarrowfill]
\definematharrow [xleftrightharpoons]  [3399,3399] [\leftharpoonupfill,\rightharpoondownfill]
\definematharrow [xrightleftharpoons]  [3399,3399] [\rightharpoonupfill,\leftharpoondownfill]

%D These arrows can be used as follows:
%D
%D \startbuffer
%D \startformula \xrightarrow{stuff on top}\stopformula
%D \startformula \xrightarrow{}{stuff on top}\stopformula
%D \startformula \xrightarrow{stuff below}{}\stopformula
%D \startformula \xrightarrow{stuff below}{stuff on top}\stopformula
%D
%D \startformula \xleftarrow [none]{stuff below}{stuff on top}\stopformula
%D \startformula \xleftarrow [small]{stuff below}{stuff on top}\stopformula
%D \startformula \xleftarrow [medium]{stuff below}{stuff on top}\stopformula
%D \startformula \xleftarrow [big]{stuff below}{stuff on top}\stopformula
%D \stopbuffer
%D
%D \typebuffer which gives \getbuffer

%D \macros{definemathoverarrow,defineunderarrow}
%D
%D These macros for define math-overarrows are adapted from \filename {amsmath.sty}

\unexpanded\def\definemathoverarrow
  {\dotripleargument\math_arrows_define_over}

\def\math_arrows_define_over[#1][#2][#3]%
  {\ifthirdargument
      \setuvalue{#1}{\math_arrows_over_handle[#2][#3]}%
    \else
      \setuvalue{#1}{\math_arrows_over_handle[\zeropoint][#2]}%
    \fi}

\def\math_arrows_over_handle[#1][#2]%
  {\mathpalette{\math_arrows_over_handle_indeed{#1}{#2}}}

%D Note: \filename {math-pln.tex} has \type {\kern-\onepoint} and \filename
%D {amsmath.sty} does not. We keep the kern amount configurable. This is useful
%D for harpoons.

\def\math_arrows_over_handle_indeed#1#2#3#4%
  {\vbox{\ialign{%
     \alignmark\alignmark
     \crcr
     #2#3%
     \crcr
     \noalign{\kern#1\nointerlineskip}%
     \normalstartimath
     \mathsurround\zeropoint\hfil#3#4\hfil
     \normalstopimath
     \crcr
  }}}

%D Now the under arrows

\unexpanded\def\definemathunderarrow
  {\dotripleargument\math_arrows_define_under}

%D For underarrows the default kern is 0.3ex

\def\math_arrows_define_under[#1][#2][#3]%
  {\ifthirdargument
      \setuvalue{#1}{\math_arrows_under_handle[#2][#3]}%
    \else
      \setuvalue{#1}{\math_arrows_under_handle[0.3ex][#2]}%
    \fi}

\def\math_arrows_under_handle[#1][#2]%
  {\mathpalette{\math_arrows_under_handle_indeed{#1}{#2}}}

\def\math_arrows_under_handle_indeed#1#2#3#4%
  {\vtop{\ialign{%
     \alignmark\alignmark
     \crcr
     \normalstartimath\mathsurround\zeropoint\hfil#3#4\hfil\normalstopimath
     \crcr
     \noalign{\nointerlineskip\kern#1}%
     #2#3%
     \crcr
  }}}

%D Now we define the arrows

\definemathoverarrow  [overleftarrow]         [\specleftarrowfill]
\definemathoverarrow  [overrightarrow]        [\specrightarrowfill]
\definemathoverarrow  [overleftrightarrow]    [\leftrightarrowfill]
\definemathoverarrow  [overtwoheadrightarrow] [\twoheadrightarrowfill]
\definemathoverarrow  [overtwoheadleftarrow]  [\twoheadleftarrowfill]
\definemathoverarrow  [overrightharpoondown]  [1pt] [\rightharpoondownfill]
\definemathoverarrow  [overrightharpoonup]    [\rightharpoonupfill]
\definemathoverarrow  [overleftharpoondown]   [1pt] [\leftharpoondownfill]
\definemathoverarrow  [overleftharpoonup]     [\leftharpoonupfill]

\definemathunderarrow [underleftarrow]        [\specleftarrowfill]
\definemathunderarrow [underrightarrow]       [\specrightarrowfill]
\definemathunderarrow [underleftrightarrow]   [\leftrightarrowfill]
\definemathunderarrow [undertwoheadrightarrow][\twoheadrightarrowfill]
\definemathunderarrow [undertwoheadleftarrow] [\twoheadleftarrowfill]
\definemathunderarrow [underrightharpoondown] [\rightharpoondownfill]
\definemathunderarrow [underrightharpoonup]   [\rightharpoonupfill]
\definemathunderarrow [underleftharpoondown]  [\leftharpoondownfill]
\definemathunderarrow [underleftharpoonup]    [\leftharpoonupfill]

%D These can be used as follows:
%D
%D \startbuffer
%D  $\overleftarrow{A}$ $\overleftarrow{ABC}$
%D  $a_{\overleftarrow{A}}$ $b_{\overleftarrow{ABC}}$
%D \stopbuffer
%D \typebuffer which gives \getbuffer

%D TODO: Possibly have a single arrow command define all the arrows.

\protect \endinput