% macros=mkvi %D \module %D [ file=typo-mar, %D version=2010.02.15, % was experimental code %D title=\CONTEXT\ Typesetting Macros, %D subtitle=Margindata, %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. % todo: tags \writestatus{loading}{ConTeXt Typesetting Macros / Margindata} \unprotect %D This module has been on the agenda for a while. Actually, it is %D one of the things that I really need myself, for instance when %D rendering rather unpredictable (educational) tests encoded in %D XML. This module permits anchoring for instance item numbers and %D also overload them when they have subnumbers. In the future it %D might replace the current maginal note mechanism (that then %D will be just an instance). %D %D In spite of what might be expected, the more advanced \LUA\ based %D variant is upto twice as fast on simple entries. Also, we no longer %D need an extra pass to get inner and outer alignments in sync with %D the pagebuilder. \registerctxluafile{typo-mar}{1.001} %definesystemattribute[margindata] % only at the lua end %D In \MKII\ we have three categories and their historically meaning %D is 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 In \MKIV\ we have further integrated the mechanism and we now have: %D %D margindata: This can be anything that needs to go into the margin. %D It can be anchored in the text or given beforehand in which case %D it gets flushed at the first occasion. %D %D margintext: This runs on top of margindata and the only difference %D is that it uses the framed mechanism for packaging. %D %D Stacking is done differently as is inner and outer alignment (in %D most cases more efficient). The functionality is mostly the same %D as in \MKII, but there are a few additions, like names entries, %D where later ones overload preceding not yet flushed ones. Data can %D get catagorized and is then treated as a group (e.g. when stacking %D is needed). %D %D The amount of \TEX\ code is less than in \MKII\ because we do all %D trickery in at the \LUA\ end. At the end of this file we define %D several commands, like \type {\inleftmargin} and \type {\inleft}. %D You can configure them individually or as a group. There is an %D inheritance model in place. %D %D The following notes will be stacked: %D %D \starttyping %D \ininner[line=2]{IM A} %D \ininner[stack=yes]{IM B} %D \ininner[stack=yes]{IM C} %D \stoptyping %D %D The distance between them is determined by \type {dy}: %D %D \starttyping %D \ininner[stack=yes,dy=2ex][frame=on] {IM A} %D \ininner[stack=yes,dy=2ex][frame=on] {IM B} %D \stoptyping %D %D There are several methods of vertical alignment. %D %D \starttyping %D \inmargin [method=first] [frame=on] {first\\second} \input ward \par %D \inmargin [method=first] [frame=on,offset=3pt] {first\\second} \input ward \par %D \inmargin [method=first,voffset=-3pt][frame=on,offset=3pt,rulethickness=3pt] {first\\second} \input ward \par %D \inmargin [method=first,voffset=-6pt][frame=on,offset=3pt,rulethickness=3pt] {first\\second} \input ward \par %D \stoptyping %D %D You sometimes need to combine \type {voffset} with \type {offset}. The first %D argument concerns the data, the second the framed. Not sharing the setup is %D on purpose: location, offset, alignment and other parameters might clash. \def\??mc{@@mc} % margincategory \def\??mf{@@mf} % marginframed \installcommandhandler\??mc{margindata}\??mc \installcommandhandler\??mf{marginframed}\??mf \setupmargindata [\c!location=\v!left, % \c!align=, % \c!method=, \c!style=\v!bold, \c!color=, % maybe textcolor % \c!name=, % \c!category=, \c!threshold=.25ex, \c!margin=\v!normal, \c!scope=\v!global, \c!width=, % \c!stack=, \c!line=0, \c!dy=\zeropoint, \c!distance=\zeropoint, \c!hoffset=\zeropoint, \c!voffset=\zeropoint] \setupmarginframed % so, align should be set with the data command [\c!strut=\v!yes, \c!offset=\v!overlay, \c!fr!analyze=\v!yes, \c!frame=\v!off, \c!width=\margindataparameter\c!width, \c!align=\margindataparameter\c!align] \appendtoks \setuevalue\currentmargindata{\margindata[\currentmargindata]}% \to \everydefinemargindata \newconditional\inhibitmargindata % This one is used at the Lua end! \newtoks \everymargindatacontent % Later on we will set this one. \unexpanded\def\margindata[#name]% {\setfalse\inhibitmargindata % flushing afterwards \begingroup %\settrue\inhibitmargindata % no flushing in here \def\currentmargindata{#name}% \dodoubleempty\domargindata} \appendtoks \settrue\inhibitmargindata \to \everyforgetall % option test -> ruled \appendtoks \forgetall \tf \deactivatecolor \to \everymargindatacontent \unexpanded\def\domargindata[#dataparameters][#textparameters]#content% {\iffirstargument \setupmargindata[\currentmargindata][#dataparameters]% \fi \edef\currentmargindatastrut{\margindataparameter\c!strut}% \the\everymargindatacontent \dostarttagged\t!margintext\currentmargindata \ifcsname\??mf\currentmargindata\s!parent\endcsname \setbox\nextbox\hbox\bgroup \the\everymargindatacontent \dosetmargindataattributes\c!style\c!color \localframedwithsettings[\??mf\currentmargindata][\c!location=\v!normal,#textparameters]\bgroup \ifx\currentmargindatastrut\empty \else \dosetupstrut[\currentmargindatastrut]% \fi \begstrut\margindataparameter\c!command{#content}\endstrut \egroup \egroup \edef\currentmarginfirstheight{\number\dimexpr\framedfirstheight}% \else \edef\currentmargindatawidth{\margindataparameter\c!width}% \ifx\currentmargindatawidth\empty \setbox\nextbox\hbox\bgroup \the\everymargindatacontent \dosetmargindataattributes\c!style\c!color \ifx\currentmargindatastrut\empty \else \dosetupstrut[\currentmargindatastrut]% \fi \begstrut\margindataparameter\c!command{#content}\endstrut \egroup \let\currentmarginfirstheight\empty \else \dosetraggedcommand{\margindataparameter\c!align}% \setbox\nextbox\hbox \bgroup\vtop \bgroup % hbox is needed \the\everymargindatacontent \dosetmargindataattributes\c!style\c!color \hsize\currentmargindatawidth \raggedcommand \ifx\currentmargindatastrut\empty \else \dosetupstrut[\currentmargindatastrut]% \fi \begstrut\margindataparameter\c!command{#content}\endstrut \egroup \egroup \edef\currentmarginfirstheight{true}% \fi \fi \dostoptagged \ctxlua{typesetters.margins.save{ \c!location = "\margindataparameter\c!location", \c!method = "\margindataparameter\c!method", \c!category = "\margindataparameter\c!category", \c!name = "\margindataparameter\c!name", \c!margin = "\margindataparameter\c!margin", % local normal margin edge \c!distance = \number\dimexpr\margindataparameter\c!distance, \c!hoffset = \number\dimexpr\margindataparameter\c!hoffset, \c!voffset = \number\dimexpr\margindataparameter\c!voffset, \c!dy = \number\dimexpr\margindataparameter\c!dy, \ifx\currentmarginfirstheight\empty \else baseline = \currentmarginfirstheight, \fi threshold = \number\dimexpr\margindataparameter\c!threshold, % will change \ifhmode inline = true, \fi \c!scope = "\margindataparameter\c!scope", \c!align = "\margindataparameter\c!align", \c!line = "\margindataparameter\c!line", \c!stack = "\margindataparameter\c!stack", \c!number = \number\nextbox }}% \endgroup} %D Downward compatible hack: \unexpanded\def\spaceorpar {\endgraf\ifhmode\space\fi} \appendtoks \let\\\spaceorpar \to \everymargindatacontent %D Another one: % \letvalue{\??mc->\v!left }\v!right % \letvalue{\??mc->\v!right }\v!left % \letvalue{\??mc->\v!inner }\v!outer % \letvalue{\??mc->\v!outer }\v!inner % \letvalue{\??mc->\v!normal}\v!normal % % \def\oppositemargin#1% % {\csname\??mc->\ifcsname\??mc->#1\endcsname#1\else\v!normal\fi\endcsname} %D Definitions: % common to lines and text \setupmargindata [\v!left ] [\c!method=\v!first,\c!location=\v!left ,\c!margin=\v!margin,\c!align=\v!flushright,\s!parent=\??mc] % we could autoparent when no define yet \setupmargindata [\v!right] [\c!method=\v!first,\c!location=\v!right,\c!margin=\v!margin,\c!align=\v!flushleft, \s!parent=\??mc] \setupmargindata [\v!outer] [\c!method=\v!first,\c!location=\v!outer,\c!margin=\v!margin,\c!align=\v!inner, \s!parent=\??mc] \setupmargindata [\v!inner] [\c!method=\v!first,\c!location=\v!inner,\c!margin=\v!margin,\c!align=\v!outer, \s!parent=\??mc] % lines \definemargindata [inleftmargin] [\v!left ] [\c!margin=\v!margin,\c!width=\leftmarginwidth ,\c!style=,\c!color=] \definemargindata [inrightmargin] [\v!right] [\c!margin=\v!margin,\c!width=\rightmarginwidth,\c!style=,\c!color=] \definemargindata [inoutermargin] [\v!outer] [\c!margin=\v!margin,\c!width=\outermarginwidth,\c!style=,\c!color=] \definemargindata [ininnermargin] [\v!inner] [\c!margin=\v!margin,\c!width=\innermarginwidth,\c!style=,\c!color=] \definemargindata [inleftedge] [\v!left ] [\c!margin=\v!edge ,\c!width=\leftedgewidth ,\c!style=,\c!color=,\c!category=\v!edge] \definemargindata [inrightedge] [\v!right] [\c!margin=\v!edge ,\c!width=\rightedgewidth ,\c!style=,\c!color=,\c!category=\v!edge] \definemargindata [inouteredge] [\v!outer] [\c!margin=\v!edge ,\c!width=\outeredgewidth ,\c!style=,\c!color=,\c!category=\v!edge] \definemargindata [ininneredge] [\v!inner] [\c!margin=\v!edge ,\c!width=\inneredgewidth ,\c!style=,\c!color=,\c!category=\v!edge] \definemargindata [atleftmargin] [\v!left ] [\c!margin=\v!normal,\c!width=\leftmarginwidth ,\c!style=,\c!color=] \definemargindata [atrightmargin] [\v!right] [\c!margin=\v!normal,\c!width=\rightmarginwidth,\c!style=,\c!color=] % text \definemargindata [inleft] [\v!left ] [\c!margin=\c!margin,\c!width=\leftmarginwidth ,\c!align=\v!flushright] \definemargindata [inright] [\v!right] [\c!margin=\c!margin,\c!width=\rightmarginwidth,\c!align=\v!flushleft] \definemargindata [inouter] [\v!outer] [\c!margin=\c!margin,\c!width=\outermarginwidth,\c!align=\v!inner] \definemargindata [ininner] [\v!inner] [\c!margin=\c!margin,\c!width=\innermarginwidth,\c!align=\v!outer] % no longer auto auto-other \definemargindata [inmargin] [\v!left] [\c!margin=\c!margin,\c!width=\leftmarginwidth, \c!align=\v!flushright] \definemargindata [inother] [\v!right] [\c!margin=\c!margin,\c!width=\rightmarginwidth,\c!align=\v!flushleft] \definemargindata [margintext] [\v!left] [\c!margin=\c!margin,\c!width=\leftmarginwidth, \c!align=\v!flushright] \setupmarginframed [\v!left ] [\c!method=\v!first,\c!align=\v!flushright,\s!parent=\??mf] % we could autoparent when no define yet \setupmarginframed [\v!right] [\c!method=\v!first,\c!align=\v!flushleft, \s!parent=\??mf] \setupmarginframed [\v!outer] [\c!method=\v!first,\c!align=\v!inner, \s!parent=\??mf] \setupmarginframed [\v!inner] [\c!method=\v!first,\c!align=\v!outer, \s!parent=\??mf] \definemarginframed [inleft] [\v!left ] \definemarginframed [inright] [\v!right] \definemarginframed [inouter] [\v!outer] \definemarginframed [ininner] [\v!inner] \definemarginframed [inmargin] [\v!inleft] \definemarginframed [inother] [\v!inright] \let\marginword \margintext \let\margintitle\margintext %definemargindata [inouterextra] [\v!outer] [\c!margin=\c!edge,\c!location=\v!outer,\c!width=\outeredgewidth,\c!align=\v!outer,\c!category=\v!edge] %definemargindata [ininnerextra] [\v!inner] [\c!margin=\c!edge,\c!location=\v!inner,\c!width=\inneredgewidth,\c!align=\v!inner,\c!category=\v!edge] % %definemarginframed [inouterextra] [\v!outer] %definemarginframed [ininnerextra] [\v!inner] %D As we have more control we are not backward compatible although in %D practice it won't hurt that much. %D So, from now on use: %D %D \starttyping %D \setupmargindata %D \setupmargintext %D \stoptyping % The following sort of works okay: % % \let\definemarginline\definemargindata % % \unexpanded\def\defineinmargin % {\doquadrupleempty\dodefineinmargin} % % \def\dodefineinmargin[#name][#location][#align][#settings]% not completely compatible % {\definemargindata[#name][\c!location=#location,\c!align=#align,#settings]% % \definemarginframed[#name][#location][\c!align=#align,#settings]} \let\setupinmargin\setupmargindata % The following is too dangerous: % % \unexpanded\def\setupinmargin % {\dodoubleempty\dosetupinmargin} % % \def\dosetupinmargin[#1][#2]% % {\ifsecondargument % \processcommalist[#1]{\dodosetupinmargin[#2]}% % \else % \setupmargindata [#1]% beware, here we can have clashes, so % \setupmarginframed[#1]% don't use setupinmargin any more % \fi} % % \def\dodosetupinmargin[#1]#2% [settings]{class} % {\setupmargindata[#2][#1]% % \setupmargintext[#2][#1]} \protect \endinput