%D \module
%D [ file=t-ruby,
%D version=2012.03.13,
%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 {overhang} {overhang}
\setinterfaceconstant {base} {base}
\stopinterface
\startinterface all
\setinterfacevariable {letter} {letter}
\setinterfacevariable {end} {end}
\setinterfacevariable {inline} {inline}
\setinterfacevariable {ruby} {ruby}
\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 {rubyoverhang}
%D Additional registers
\newdimen \d_ruby_width
\newdimen \d_ruby_base
\newdimen \d_ruby_text
\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_cmd#name%
{\dontleavehmode
\begingroup
\edef\currentruby{#name}%
\dosingleempty\ruby_cmd_indeed}
\unexpanded\def\ruby_cmd_indeed[#parameters]#base#text%
{\setupcurrentruby[#parameters,\c!base={#base},\c!text={#text}]%
\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!base}}%
\setbox\b_ruby_text\hbox{\userubystyleandcolor\c!textstyle\c!textcolor{\directrubyparameter\c!text}}%
\d_ruby_base\wd\b_ruby_base
\d_ruby_text\wd\b_ruby_text
\expandcheckedcsname\????rubyalign {\rubyparameter\c!align }\v!auto
\expandcheckedcsname\????rubyalternative{\rubyparameter\c!alternative}\v!top
\expandcheckedcsname\????rubyoverhang {\rubyparameter\c!overhang }\v!auto
\hskip\s_ruby_signal\relax
\endgroup}
\appendtoks
\setuevalue\currentruby{\ruby_cmd{\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}}
\setvalue{\????rubyalign\v!space}% stretch?
{\d_ruby_left \zeropoint
\d_ruby_right\zeropoint
\ifdim\d_ruby_base>\d_ruby_text
\setbox\b_ruby_base\hbox to \d_ruby_base{\hss\box\b_ruby_base\hss}%
\setbox\b_ruby_text\hbox to \d_ruby_base{\userubystyleandcolor\c!textstyle\c!textcolor{\normalexpanded{\ruby_distribute_space{\directrubyparameter\c!text}}}}%
\else
\setbox\b_ruby_base\hbox to \d_ruby_text{\userubystyleandcolor\c!basestyle\c!basecolor{\normalexpanded{\ruby_distribute_space{\directrubyparameter\c!base}}}}%
\setbox\b_ruby_text\hbox to \d_ruby_text{\hss\box\b_ruby_text\hss}%
\fi}
\setvalue{\????rubyalign\v!letter}% !!!
{\d_ruby_left \zeropoint
\d_ruby_right\zeropoint
\ifdim\d_ruby_base>\d_ruby_test
\setbox\b_ruby_base\hbox to \d_ruby_base{\hss\box\b_ruby_base\hss}%
\setbox\b_ruby_text\hbox to \d_ruby_base{\userubystyleandcolor\c!textstyle\c!textcolor{\normalexpanded{\ruby_distribute_letter{\directrubyparameter\c!text}}}}%
\else
\setbox\b_ruby_base\hbox to \d_ruby_text{\userubystyleandcolor\c!basestyle\c!basecolor{\normalexpanded{\ruby_distribute_letter{\directrubyparameter\c!base}}}}%
\setbox\b_ruby_text\hbox to \d_ruby_text{\hss\box\b_ruby_text\hss}%
\fi}
\setvalue{\????rubyalign\v!auto}%
{\ifdim\d_ruby_base>\d_ruby_text
\ctxlua{thirddata.ruby.doifelsecjk("\directrubyparameter\c!base")}\donetrue\donefalse
\ifdone
\getvalue{\????rubyalign\v!space}%
\else
\getvalue{\????rubyalign\v!middle}%
\fi
\else
\ifdim\d_ruby_position=\zeropoint % begin of the line
\getvalue{\????rubyalign\v!left}%
\else\ifdim\d_ruby_position=\dimexpr\textwidth-\d_ruby_base\relax % end of the line
\getvalue{\????rubyalign\v!right}%
\else
\ctxlua{thirddata.ruby.doifelsecjk("\directrubyparameter\c!text")}\donetrue\donefalse
\ifdone
\getvalue{\????rubyalign\v!space}%
\else
\getvalue{\????rubyalign\v!middle}%
\fi
\fi\fi
\fi}
\setvalue{\????rubyalign\v!left}%
{\ifdim\d_ruby_base>\d_ruby_text
\d_ruby_left \zeropoint
\d_ruby_right\zeropoint
\else
\d_ruby_left \zeropoint
\d_ruby_right\dimexpr\d_ruby_text-\d_ruby_base\relax
\fi
\setbox\b_ruby_base\hbox to \d_ruby_base{\box\b_ruby_base\hss}%
\setbox\b_ruby_text\hbox to \d_ruby_base{\box\b_ruby_text\hss}}
\setvalue{\????rubyalign\v!middle}%
{\ifdim\d_ruby_base>\d_ruby_text
\d_ruby_left \zeropoint
\d_ruby_right\zeropoint
\else
\d_ruby_left \dimexpr(\d_ruby_text-\d_ruby_base)/2\relax
\d_ruby_right\dimexpr(\d_ruby_text-\d_ruby_base)/2\relax
\fi
\setbox\b_ruby_base\hbox to \d_ruby_base{\hss\box\b_ruby_base\hss}%
\setbox\b_ruby_text\hbox to \d_ruby_base{\hss\box\b_ruby_text\hss}}
\setvalue{\????rubyalign\v!right}%
{\ifdim\d_ruby_base>\d_ruby_base
\d_ruby_left \zeropoint
\d_ruby_right\zeropoint
\else
\d_ruby_left \dimexpr\d_ruby_text-\d_ruby_base\relax
\d_ruby_right\zeropoint
\fi
\setbox\b_ruby_base\hbox to \d_ruby_base{\hss\box\b_ruby_base}%
\setbox\b_ruby_text\hbox to \d_ruby_base{\hss\box\b_ruby_text}}
\setvalue{\????rubyalign\v!margin}% modify to take care of overlap etc.
{\ifdim\d_ruby_position=\zeropoint
\getvalue{\????rubyalign\v!left}%
\else\ifdim\d_ruby_position=\dimexpr\textwidth-\d_ruby_base\relax
\getvalue{\????rubyalign\v!right}%
\else
\getvalue{\????rubyalign\v!middle}%
\fi\fi}
%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!base
% \rubyparameter\c!separator
% \rubyparameter\c!lefttext
% \directrubyparameter\c!text
% \rubyparameter\c!righttext}
\setvalue{\????rubyalternative\v!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}}}
\setvalue{\????rubyalternative\v!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}}}
\setvalue{\????rubyalternative\v!text}% pure text to allow line breaks in the text
{\setbox\b_ruby_box\box\voidbox
\d_ruby_left \zeropoint
\d_ruby_right\zeropoint
\directrubyparameter\c!base
\rubyparameter\c!separator
\rubyparameter\c!lefttext\directrubyparameter\c!text\rubyparameter\c!righttext}
\unexpanded\def\ruby_alternative_vertical#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}
\setvalue{\????rubyalternative\v!vertical}%
{\d_ruby_left \zeropoint
\d_ruby_right\zeropoint
\setbox\b_ruby_box\hbox\bgroup
\begingroup
\userubystyleandcolor\c!basestyle\c!basecolor
\directrubyparameter\c!base
\endgroup
\normalexpanded{\ruby_alternative_vertical{\directrubyparameter\c!text}}%
\egroup}
%D Overhang
%D
%D \startitemize[packed]
%D \item left
%D \item right
%D \item auto
%D \item none
%D \stopitemize
\setvalue{\????rubyoverhang\v!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}
\setvalue{\????rubyoverhang\v!left}%
{\box\b_ruby_box\kern\d_ruby_right
\global\d_ruby_width\d_ruby_right}
\setvalue{\????rubyoverhang\v!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}
\setvalue{\????rubyoverhang\v!none}%
{\kern\d_ruby_left\box\b_ruby_box\kern\d_ruby_right
\global\d_ruby_width\zeropoint}
%D \macros
%D {ruby}
\defineruby[\v!ruby]
%D Default values
\setupruby
[\c!alternative=\v!top,
\c!align=\v!auto,
\c!overhang=\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