%D \module
%D [ file=t-ruby,
%D version=2012.12.01,
%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
%D WWW
%D
%D
%D \stoptyping
%D
%D complex ruby:
%D
%D \starttyping
%D
%D
%D 10
%D 31
%D 2002
%D
%D
%D
%D
%D \stoptyping
%D Constants/variables
\startinterface all
\setinterfaceconstant {basestyle} {basestyle}
\setinterfaceconstant {basecolor} {basecolor}
\setinterfaceconstant {rubybase} {rubybase}
\setinterfaceconstant {rubytext} {rubytext}
\stopinterface
\startinterface all
\setinterfacevariable {letter} {letter}
\stopinterface
%D Lua
\startluacode
thirddata = thirddata or { }
thirddata.ruby = thirddata.ruby or { }
function thirddata.ruby.doifelsecjk(string)
local state = true
for c in unicode.utf8.gmatch(string,".") do
local n = scripts.hash[utf.byte(c)]
if not ( n == "chinese" or n == "korean" ) then
state = false
break
end
end
commands.doifelse(state)
end
\stopluacode
%D Namespace
\installnamespace {ruby}
\installnamespace {rubyalign}
\installnamespace {rubyalternative}
\installnamespace {rubyhang}
%D Additional registers
\newdimen \d_ruby_width
\newdimen \d_ruby_left
\newdimen \d_ruby_right
\newdimen \d_ruby_position
\newsignal \s_ruby_signal
\newcount \c_ruby_n
\newtoks \t_ruby_base
\newtoks \t_ruby_text
\newbox \b_ruby_base
\newbox \b_ruby_text
\newbox \b_ruby_box
%D \macros
%D {defineruby,setupruby}
\installcommandhandler \????ruby {ruby} \????ruby
%D \macros
%D {ruby}
\unexpanded\def\ruby
{\dontleavehmode
\begingroup
\let\currentruby\empty
\dosingleempty\ruby_direct_indeed}
\unexpanded\def\ruby_direct#name%
{\dontleavehmode
\begingroup
\edef\currentruby{#name}%
\dosingleempty\ruby_direct_indeed}
\def\ruby_direct_indeed[#parameters]#rubybase#rubytext%
{\setupcurrentruby[#parameters,\c!rubybase={#rubybase},\c!rubytext={#rubytext}]%
%
\scratchdimen\lastskip
\ifdim\scratchdimen=\s_ruby_signal\else\global\d_ruby_width\zeropoint\fi
%
\global\advance\c_ruby_n\plusone
%
\xypos{rubyposition:\number\c_ruby_n}%
\doifmodeelse\v!first
{\d_ruby_position\onepoint}
{\d_ruby_position\dimexpr\MPx{rubyposition:\number\c_ruby_n}-\MPx{text:\number\realpageno}\relax}%
%
\setbox\b_ruby_base\hbox{\userubystyleandcolor\c!basestyle\c!basecolor\directrubyparameter\c!rubybase}%
\setbox\b_ruby_text\hbox{\userubystyleandcolor\c!textstyle\c!textcolor\directrubyparameter\c!rubytext}%
%
\edef\p_ruby_align {\rubyparameter\c!align }%
\edef\p_ruby_alternative{\rubyparameter\c!alternative}%
\edef\p_ruby_hang {\rubyparameter\c!hang }%
%
\ruby_align
\ruby_alternative
\ruby_hang
%
\hskip\s_ruby_signal\relax
\endgroup}
\appendtoks
\setuevalue\currentruby{\ruby_direct{\currentruby}}%
\to \everydefineruby
%D Alignment
%D
%D \startitemize[packed]
%D \item left
%D \item middle
%D \item right
%D \item auto
%D \item letter
%D \item space
%D \stopitemize
\unexpanded\def\ruby_distribute_space #1{\processtokens{\hss }{\hss\hss}{\hss }{\hss\hss}{#1}}
\unexpanded\def\ruby_distribute_letter#1{\processtokens{\relax}{\hss }{\relax}{\hss\hss}{#1}}
\def\ruby_align_stretch
{\d_ruby_left \zeropoint
\d_ruby_right\zeropoint
\ifdim\wd\b_ruby_base>\wd\b_ruby_text
\setbox\b_ruby_base\hbox to \wd\b_ruby_base{\hss\box\b_ruby_base\hss}%
\setbox\b_ruby_text\hbox to \wd\b_ruby_base{\userubystyleandcolor\c!textstyle\c!textcolor\normalexpanded{\ruby_distribute_space{\directrubyparameter\c!rubytext}}}%
\else
\setbox\b_ruby_base\hbox to \wd\b_ruby_text{\userubystyleandcolor\c!basestyle\c!basecolor\normalexpanded{\ruby_distribute_space{\directrubyparameter\c!rubybase}}}%
\setbox\b_ruby_text\hbox to \wd\b_ruby_text{\hss\box\b_ruby_text\hss}%
\fi}
\def\ruby_align_letter
{\d_ruby_left \zeropoint
\d_ruby_right\zeropoint
\ifdim\wd\b_ruby_base>\wd\b_ruby_test
\setbox\b_ruby_base\hbox to \wd\b_ruby_base{\hss\box\b_ruby_base\hss}%
\setbox\b_ruby_text\hbox to \wd\b_ruby_base{\userubystyleandcolor\c!textstyle\c!textcolor\normalexpanded{\ruby_distribute_letter{\directrubyparameter\c!rubytext}}}%
\else
\setbox\b_ruby_base\hbox to \wd\b_ruby_text{\userubystyleandcolor\c!basestyle\c!basecolor\normalexpanded{\ruby_distribute_letter{\directrubyparameter\c!rubybase}}}%
\setbox\b_ruby_text\hbox to \wd\b_ruby_text{\hss\box\b_ruby_text\hss}%
\fi}
\def\ruby_align_auto
{\ifdim\wd\b_ruby_base>\wd\b_ruby_text
\ctxlua{thirddata.ruby.doifelsecjk("\directrubyparameter\c!rubybase")}\donetrue\donefalse
\ifdone
\ruby_align_stretch
\else
\ruby_align_middle
\fi
\else
\ifdim\d_ruby_position=\zeropoint % begin of the line
\ruby_align_left
\else\ifdim\d_ruby_position=\dimexpr\textwidth-\wd\b_ruby_base\relax % end of the line
\ruby_align_right
\else
\ctxlua{thirddata.ruby.doifelsecjk("\directrubyparameter\c!rubytext")}\donetrue\donefalse
\ifdone
\ruby_align_stretch
\else
\ruby_align_middle
\fi
\fi\fi
\fi}
\def\ruby_align_left
{\ifdim\wd\b_ruby_base>\wd\b_ruby_text
\d_ruby_left \zeropoint
\d_ruby_right\zeropoint
\else
\d_ruby_left \zeropoint
\d_ruby_right\dimexpr\wd\b_ruby_text-\wd\b_ruby_base\relax
\fi
\setbox\b_ruby_base\hbox to \wd\b_ruby_base{\box\b_ruby_base\hss}%
\setbox\b_ruby_text\hbox to \wd\b_ruby_base{\box\b_ruby_text\hss}}
\def\ruby_align_middle
{\ifdim\wd\b_ruby_base>\wd\b_ruby_text
\d_ruby_left \zeropoint
\d_ruby_right\zeropoint
\else
\d_ruby_left \dimexpr(\wd\b_ruby_text-\wd\b_ruby_base)/2\relax
\d_ruby_right\dimexpr(\wd\b_ruby_text-\wd\b_ruby_base)/2\relax
\fi
\setbox\b_ruby_base\hbox to \wd\b_ruby_base{\hss\box\b_ruby_base\hss}%
\setbox\b_ruby_text\hbox to \wd\b_ruby_base{\hss\box\b_ruby_text\hss}}
\def\ruby_align_right
{\ifdim\wd\b_ruby_base>\wd\b_ruby_base
\d_ruby_left \zeropoint
\d_ruby_right\zeropoint
\else
\d_ruby_left \dimexpr\wd\b_ruby_text-\wd\b_ruby_base\relax
\d_ruby_right\zeropoint
\fi
\setbox\b_ruby_base\hbox to \wd\b_ruby_base{\hss\box\b_ruby_base}%
\setbox\b_ruby_text\hbox to \wd\b_ruby_base{\hss\box\b_ruby_text}}
\def\ruby_align_margin
{\ifdim\d_ruby_position=\zeropoint
\ruby_align_left
\else\ifdim\d_ruby_position=\dimexpr\textwidth-\wd\b_ruby_base\relax
\ruby_align_right
\else
\ruby_align_middle
\fi\fi}
\def\ruby_align
{\csname\????rubyalign
\ifcsname\????rubyalign\p_ruby_align\endcsname\p_ruby_align\else\v!auto\fi
\endcsname}
\setvalue{\????rubyalign\v!auto }{\ruby_align_auto }
\setvalue{\????rubyalign\v!left }{\ruby_align_left }
\setvalue{\????rubyalign\v!right }{\ruby_align_right }
\setvalue{\????rubyalign\v!middle }{\ruby_align_middle }
\setvalue{\????rubyalign\v!letter }{\ruby_align_letter }
\setvalue{\????rubyalign\v!stretch}{\ruby_align_stretch}
\setvalue{\????rubyalign\v!margin }{\ruby_align_margin }
%D Alternative
%D
%D \startitemize[packed]
%D \item top
%D \item bottom
%D \item text
%D \stopitemize
% \setvalue{\????rubyalternative\v!none}% needed for \pdfactualtext
% {\directrubyparameter\c!rubybase
% \rubyparameter\c!separator
% \rubyparameter\c!lefttext
% \directrubyparameter\c!rubytext
% \rubyparameter\c!righttext}
\def\ruby_alternative_top
{\setbox\b_ruby_box\vbox
{\doifsomething{\rubyparameter\c!strut}{\setupstrut[\rubyparameter\c!strut]}%
\offinterlineskip
\hbox{\undepthed{\begstrut\box\b_ruby_text\endstrut}}
\rubyparameter\c!inbetween
\hbox{\begstrut\box\b_ruby_base\endstrut}}}
\def\ruby_alternative_bottom
{\setbox\b_ruby_box\vtop
{\doifsomething{\rubyparameter\c!strut}{\setupstrut[\rubyparameter\c!strut]}%
\offinterlineskip
\hbox{\undepthed{\begstrut\box\b_ruby_base\endstrut}}
\rubyparameter\c!inbetween
\hbox{\begstrut\box\b_ruby_text\endstrut}}}
\def\ruby_alternative_text
{\setbox\b_ruby_box\box\voidbox
\d_ruby_left \zeropoint
\d_ruby_right\zeropoint
\directrubyparameter\c!rubybase
\rubyparameter\c!separator
\rubyparameter\c!lefttext\directrubyparameter\c!rubytext\rubyparameter\c!righttext}
\unexpanded\def\ruby_alternative_vertical_process#text%
{\setbox\scratchbox\vbox
{\userubystyleandcolor\c!textstyle\c!textcolor
\setupinterlinespace[\rubyparameter\c!interlinespace]%
\handletokens#text\with\hbox
\par}%
\lower\dimexpr(\ht\scratchbox+\strutdp-\strutht)/2-\rubyparameter\c!dy\relax\box\scratchbox}
\def\ruby_alternative_vertical
{\d_ruby_left \zeropoint
\d_ruby_right\zeropoint
\setbox\b_ruby_box\hbox\bgroup
\begingroup
\userubystyleandcolor\c!basestyle\c!basecolor
\directrubyparameter\c!rubybase
\endgroup
\normalexpanded{\ruby_alternative_vertical_process{\directrubyparameter\c!rubytext}}%
\egroup}
\def\ruby_alternative
{\csname\????rubyalternative
\ifcsname\????rubyalternative\p_ruby_alternative\endcsname\p_ruby_alternative\else\v!text\fi
\endcsname}
\setvalue{\????rubyalternative\v!top }{\ruby_alternative_top }
\setvalue{\????rubyalternative\v!bottom}{\ruby_alternative_bottom}
\setvalue{\????rubyalternative\v!text }{\ruby_alternative_text }
%D Overhang
%D
%D \startitemize[packed]
%D \item left
%D \item right
%D \item auto
%D \item none
%D \stopitemize
\def\ruby_hang_auto
{\ifdim\d_ruby_width>\zeropoint
\kern\dimexpr\d_ruby_left+\d_ruby_width\relax
\fi
\box\b_ruby_box
\global\d_ruby_width\d_ruby_right}
\def\ruby_hang_left
{\box\b_ruby_box\kern\d_ruby_right
\global\d_ruby_width\d_ruby_right}
\def\ruby_hang_right
{\ifdim\d_ruby_width>\zeropoint
\kern\dimexpr\d_ruby_left+\d_ruby_width\relax
\else
\kern\d_ruby_left
\fi
\box\b_ruby_box
\global\d_ruby_width\zeropoint}
\def\ruby_hang_none
{\kern\d_ruby_left\box\b_ruby_box\kern\d_ruby_right
\global\d_ruby_width\zeropoint}
\def\ruby_hang
{\csname\????rubyhang
\ifcsname\????rubyhang\p_ruby_hang\endcsname\p_ruby_hang\else\v!auto\fi
\endcsname}
\setvalue{\????rubyhang\v!auto }{\ruby_hang_auto }
\setvalue{\????rubyhang\v!left }{\ruby_hang_left }
\setvalue{\????rubyhang\v!right}{\ruby_hang_right}
\setvalue{\????rubyhang\v!none }{\ruby_hang_none }
%D Default values
\setupruby
[\c!alternative=\v!top,
\c!align=\v!auto,
\c!hang=\v!auto,
\c!dy=\zeropoint,
\c!separator={ },
\c!lefttext={(},
\c!righttext={)},
\c!strut=\v!no,
\c!inbetween={\blank[\v!small]},
\c!textstyle=\txx]
\protect \endinput