%D \module
%D   [     file=t-ruby,
%D      version=2010.01.26,
%D        title=\CONTEXT\ User Module,
%D     subtitle=Ruby Markup,
%D       author=Wolfgang Schuster,
%D         date=\currentdate,
%D    copyright=Wolfgang Schuster,
%D        email=schuster.wolfgang@googlemail.com,
%D      license=Public Domain]

\writestatus{loading}{ConTeXt User Module / Ruby Markup}

\unprotect

%D simple ruby:
%D
%D \starttyping
%D <ruby>
%D   <rb>WWW</rb>
%D   <rt>World Wide Web</rt>
%D </ruby>
%D \stoptyping
%D
%D complex ruby:
%D
%D \starttyping
%D <ruby>
%D   <rbc>
%D     <rb>10</rb>
%D     <rb>31</rb>
%D     <rb>2002</rb>
%D   </rbc>
%D   <rtc>
%D     <rt>Month</rt>
%D     <rt>Day</rt>
%D     <rt>Year</rt>
%D   </rtc>
%D   <rtc>
%D     <rt rbspan="3">Expiration Date</rt>
%D   </rtc>
%D </ruby>
%D \stoptyping

%D Constants

\startinterface all
  \setinterfaceconstant {basestyle} {basestyle}
  \setinterfaceconstant {basecolor} {basecolor}
  \setinterfaceconstant {overhang}  {overhang}
\stopinterface

\startinterface all
  \setinterfacevariable {letter} {letter}
  \setinterfacevariable {end}    {end}
  \setinterfacevariable {inline} {inline}
\stopinterface

%D Namespace

\def\????rb{@@@@rb}

%D Additional registers

\newdimen \!!rubywidth
\newdimen \!!rubyleftmargin
\newdimen \!!rubyrightmargin
\newsignal\!!rubysignal
\newcount \!!rubycount
\newtoks  \!!rubybase
\newtoks  \!!rubytext

%D Helpers

\newif\ifideograph

\long\def\doifelseideograph#1%
  {\global\ideographtrue
   \handletokens#1\with\checkideograph
   \ifideograph
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\def\doifinrangeelse#1#2#3%
  {\unless\ifnum#1<#2
     \unless\ifnum#1>#3
       \expandafter\expandafter\expandafter\firstoftwoarguments
     \else
       \expandafter\expandafter\expandafter\secondoftwoarguments
     \fi
   \else
     \expandafter\secondoftwoarguments
   \fi}

\def\checkideograph#1%
  {\doifinrangeelse{`#1}{"3040}{"309F}\donothing
     {\doifinrangeelse{`#1}{"30A0}{"30FF}\donothing
        {\doifinrangeelse{`#1}{"31F0}{"31FF}\donothing
           {\doifinrangeelse{`#1}{"3400}{"4DFF}\donothing
              {\doifinrangeelse{`#1}{"4E00}{"9FFF}\donothing
                 {\doifinrangeelse{`#1}{"AC00}{"D7A3}\donothing
                    {\doifinrangeelse{`#1}{"F900}{"FAFF}\donothing
                       {\doifinrangeelse{`#1}{"FF00}{"FFEF}\donothing
                          {\doifinrangeelse{`#1}{"20000}{"2A6DF}\donothing
                             {\doifinrangeelse{`#1}{"2F800}{"2FA1F}\donothing
                                {\ideographfalse}}}}}}}}}}}

%D \macros
%D   {setupruby}

\def\setupruby
  {\dodoubleargument\getparameters[\????rb]}

\def\rubyparameter#1{\csname\????rb#1\endcsname}

%D \macros
%D   {pdfactualtext}

\ifx\pdfactualtext\undefined \let\pdfactualtext\secondoftwoarguments \fi

%D \macros
%D   {bRUBY,eRUBY,bRB,eRB,bRT,eRT}

\def\bRUBY
  {\dosingleempty\dobRUBY}

\def\dobRUBY[#1]%
  {\begingroup
   \iffirstargument
     \setupruby[#1]%
   \fi
   \scratchdimen\lastskip
   \ifdim\scratchdimen=\!!rubysignal\else\global\!!rubywidth\!!zeropoint\fi
   \global\advance\!!rubycount\plusone
   \xypos{rubyposition:\number\!!rubycount}%
   \doifmodeelse\v!first
     {\edef\rubyposition{\the\onepoint}}%
     {\edef\rubyposition{\the\dimexpr\MPx{rubyposition:\number\!!rubycount}-\MPx{text:\the\realpageno}\relax}}}

\def\eRUBY
  {\setbox\scratchboxone\hbox{\redoconvertfont\doattributes\????rb\c!basestyle\c!basecolor{\the\!!rubybase}}%
   \setbox\scratchboxtwo\hbox{\redoconvertfont\doattributes\????rb\c!textstyle\c!textcolor{\the\!!rubytext}}%
   \scratchdimenone\wd\scratchboxone
   \scratchdimentwo\wd\scratchboxtwo
   %\scratchdimenthree\ifdim\scratchdimenone<\scratchdimentwo\space\scratchdimenone\else\scratchdimentwo\fi
   \scratchdimenthree\scratchdimenone
   \executeifdefined{\????rb:\c!align   :\rubyparameter\c!align   }{\getvalue{\????rb:\c!align   :\v!auto  }}%
   \executeifdefined{\????rb:\c!position:\rubyparameter\c!position}{\getvalue{\????rb:\c!position:\v!before}}%
   \executeifdefined{\????rb:\c!overhang:\rubyparameter\c!overhang}{\getvalue{\????rb:\c!overhang:\v!auto  }}%
   \hskip\!!rubysignal\relax
   \endgroup}

\def\bRB{\dodoubleempty\dobRB}
\def\bRT{\dodoubleempty\dobRT}

\def\dobRB[#1][#2]#3\eRB{\!!rubybase{#3}}
\def\dobRT[#1][#2]#3\eRT{\!!rubytext{#3}}

\def\placerubystrut{\doif{\rubyparameter\c!strut}\v!yes{\setstrut\strut}}

%D Alignment

\def\RUBYdistributespace #1{\doifelseideograph{#1}{\processtokens{\hss  }{\hss\hss}{\hss  }{\hss\hss}{#1}}{\hss#1\hss}}
\def\RUBYdistributeletter#1{\doifelseideograph{#1}{\processtokens{\relax}{\hss    }{\relax}{\hss\hss}{#1}}{\hss#1\hss}}

\setvalue{\????rb:\c!align:\v!space}%
  {\!!rubyleftmargin \zeropoint
   \!!rubyrightmargin\zeropoint
   \ifdim\scratchdimenone>\scratchdimentwo
     \setbox\scratchboxone\hbox to \scratchdimenone{\hss\box\scratchboxone\hss}%
     \setbox\scratchboxtwo\hbox to \scratchdimenone{\redoconvertfont\doattributes\????rb\c!textstyle\c!textcolor{\@EA\RUBYdistributespace\@EA{\the\!!rubytext}}}%
   \else
     \setbox\scratchboxone\hbox to \scratchdimentwo{\redoconvertfont\doattributes\????rb\c!basestyle\c!basecolor{\@EA\RUBYdistributespace\@EA{\the\!!rubybase}}}%
     \setbox\scratchboxtwo\hbox to \scratchdimentwo{\hss\box\scratchboxtwo\hss}%
   \fi}

\setvalue{\????rb:\c!align:\v!letter}%
  {\!!rubyleftmargin \zeropoint
   \!!rubyrightmargin\zeropoint
   \ifdim\scratchdimenone>\scratchdimentwo
     \setbox\scratchboxone\hbox to \scratchdimenone{\hss\box\scratchboxone\hss}%
     \setbox\scratchboxtwo\hbox to \scratchdimenone{\redoconvertfont\doattributes\????rb\c!textstyle\c!textcolor{\@EA\RUBYdistributeletter\@EA{\the\!!rubytext}}}%
   \else
     \setbox\scratchboxone\hbox to \scratchdimentwo{\redoconvertfont\doattributes\????rb\c!basestyle\c!basecolor{\@EA\RUBYdistributeletter\@EA{\the\!!rubybase}}}%
     \setbox\scratchboxtwo\hbox to \scratchdimentwo{\hss\box\scratchboxtwo\hss}%
   \fi}

\setvalue{\????rb:\c!align:\v!auto}% I need special alignments for the begin/end of the line!!!
  {\ifdim\scratchdimenone>\scratchdimentwo
     \getvalue{\????rb:\c!align:\v!space}%
   \else
     \ifdim\rubyposition=\!!zeropoint % begin of the line
       \getvalue{\????rb:\c!align:\v!left}%
     \else\ifdim\rubyposition=\the\dimexpr\textwidth-\scratchdimenthree\relax % end of the line
       \getvalue{\????rb:\c!align:\v!right}%
     \else
       \getvalue{\????rb:\c!align:\v!space}%
     \fi\fi
   \fi}

\setvalue{\????rb:\c!align:\v!left}%
  {\ifdim\scratchdimenone>\scratchdimentwo
     \!!rubyleftmargin \zeropoint
     \!!rubyrightmargin\zeropoint
   \else
     \!!rubyleftmargin \zeropoint
     \!!rubyrightmargin\dimexpr\scratchdimentwo-\scratchdimenone\relax
   \fi
   \setbox\scratchboxone\hbox to \scratchdimenthree{\box\scratchboxone\hss}%
   \setbox\scratchboxtwo\hbox to \scratchdimenthree{\box\scratchboxtwo\hss}}

\setvalue{\????rb:\c!align:\v!start}%
  {\getvalue{\????rb:\c!align:\v!left}}

\setvalue{\????rb:\c!align:\v!center}%
  {\ifdim\scratchdimenone>\scratchdimentwo
     \!!rubyleftmargin \zeropoint
     \!!rubyrightmargin\zeropoint
   \else
     \!!rubyleftmargin \dimexpr(\scratchdimentwo-\scratchdimenone)/2\relax
     \!!rubyrightmargin\dimexpr(\scratchdimentwo-\scratchdimenone)/2\relax
   \fi
   \setbox\scratchboxone\hbox to \scratchdimenthree{\hss\box\scratchboxone\hss}%
   \setbox\scratchboxtwo\hbox to \scratchdimenthree{\hss\box\scratchboxtwo\hss}}

\setvalue{\????rb:\c!align:\v!right}%
  {\ifdim\scratchdimenone>\scratchdimentwo
     \!!rubyleftmargin \zeropoint
     \!!rubyrightmargin\zeropoint
   \else
     \!!rubyleftmargin \dimexpr\scratchdimentwo-\scratchdimenone\relax
     \!!rubyrightmargin\zeropoint
   \fi
   \setbox\scratchboxone\hbox to \scratchdimenthree{\hss\box\scratchboxone}%
   \setbox\scratchboxtwo\hbox to \scratchdimenthree{\hss\box\scratchboxtwo}}

\setvalue{\????rb:\c!align:\v!end}%
  {\getvalue{\v!ruby:\c!align:\v!right}}

\setvalue{\????rb:\c!align:\v!edge}% modify to take care of overlap etc.
  {\ifdim\rubyposition=\zeropoint
     \getvalue{\????rb:\c!align:\v!left}%
   \else\ifdim\rubyposition=\the\dimexpr\textwidth-\scratchdimenthree\relax
     \getvalue{\????rb:\c!align:\v!right}%
   \else
     \getvalue{\????rb:\c!align:\v!center}%
   \fi\fi}

%D Positioning

\setvalue{\????rb:\c!position:\v!before}%
  {\setbox\scratchboxthree\vbox
     {\offinterlineskip
      \hbox{\undepthed{\placerubystrut\box\scratchboxtwo}}
      \rubyparameter\c!inbetween
      \hbox{\placerubystrut\box\scratchboxone}}}

\setvalue{\????rb:\c!position:\v!after}%
  {\setbox\scratchboxthree\vtop
     {\offinterlineskip
      \hbox{\undepthed{\placerubystrut\box\scratchboxone}}
      \rubyparameter\c!inbetween
      \hbox{\placerubystrut\box\scratchboxtwo}}}

\setvalue{\????rb:\c!position:\v!inline}% pure text to allow line breaks in the text
  {\setbox\scratchboxthree\box\voidbox
   \!!rubyleftmargin \zeropoint
   \!!rubyrightmargin\zeropoint
   \the\!!rubybase
   \rubyparameter\c!separator
   \rubyparameter\c!lefttext\the\!!rubytext\rubyparameter\c!righttext}

%D Overhang

\setvalue{\????rb:\c!overhang:\v!auto}%
  {\ifdim\!!rubywidth>\!!zeropoint
     \kern\dimexpr\!!rubyleftmargin+\!!rubywidth\relax
   \fi
   \box\scratchboxthree
   \global\!!rubywidth\!!rubyrightmargin}

\setvalue{\????rb:\c!overhang:\v!start}%
  {\box\scratchboxthree\kern\!!rubyrightmargin
   \global\!!rubywidth\!!rubyrightmargin}

\setvalue{\????rb:\c!overhang:\v!end}%
  {\ifdim\!!rubywidth>\!!zeropoint
     \kern\dimexpr\!!rubyleftmargin+\!!rubywidth\relax
   \else
     \kern\!!rubyleftmargin
   \fi
   \box\scratchboxthree
   \global\!!rubywidth\!!zeropoint}

\setvalue{\????rb:\c!overhang:\v!none}%
  {\kern\!!rubyleftmargin\box\scratchboxthree\kern\!!rubyrightmargin
   \global\!!rubywidth\!!zeropoint}

%D \macros
%D   {ruby}

\def\ruby
  {\dosingleempty\doruby}

\def\doruby[#1]#2#3%
  {\dobRUBY[#1]\bRB#2\eRB\bRT#3\eRT\eRUBY}

%D Default values

\setupruby
  [\c!position=\v!before, % before|after|inline
   \c!align=\v!auto,      % auto|start|left|center|end|right|distribute-letter|distribute-space|line-edge
   \c!overhang=\v!auto,   % auto|start|end|none
   \c!separator={ },
   \c!lefttext=(,
   \c!righttext=),
   \c!strut=\v!no,
   \c!inbetween={\blank[\v!small]},
   \c!textstyle=\txx]

\protect \endinput
