node-rul.mkiv / last modification: 2020-01-30 14:16
%D \module
%D   [       file=node-rul,
%D        version=2009.11.03, % 1995.10.10,
%D          title=\CONTEXT\ Core Macros,
%D       subtitle=Bars,
%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: ex and and em traveling with attribute
% todo: this will move to typo-rul + ctxcommands

\writestatus{loading}{ConTeXt Core Macros / Bars}

%D \macros
%D   {underbar,underbars,
%D    overbar,overbars,
%D    overstrike,overstrikes,
%D    setupbar}
%D
%D In the rare case that we need undelined words, for instance because all font
%D alternatives are already in use, one can use \type {\underbar} and \type
%D {\overstrike} and their plural forms.
%D
%D \startbuffer
%D \underbars {drawing \underbar{bars} under words is a typewriter leftover}
%D \overstrikes {striking words makes them \overstrike {unreadable} but
%D sometimes even \overbar {top lines} come into view.}
%D \stopbuffer
%D
%D \typebuffer
%D
%D \startlines
%D \getbuffer
%D \stoplines
%D
%D The formal definitions are:
%D
%D \showsetup{underbar}
%D \showsetup{underbars}
%D \showsetup{overbar}
%D \showsetup{overbars}
%D \showsetup{overstrike}
%D \showsetup{overstrikes}
%D
%D \showsetup{setupbars}
%D
%D Units can be any normal \TEX\ unit:
%D
%D \startbuffer
%D \setupbars[unit=mm,rulethickness=1]     bar\startbar[underbar]foo\stopbar bar\blank
%D \setupbars[unit=ex,rulethickness=1]     bar\startbar[underbar]foo\stopbar bar\blank
%D \setupbars[unit=pt,rulethickness=1]     bar\startbar[underbar]foo\stopbar bar\blank
%D \setupbars[unit=pt,rulethickness=10pt]  bar\startbar[underbar]foo\stopbar bar
%D \stopbuffer
%D
%D \typebuffer \blank \getbuffer \blank
%D
%D As with many early usage of \LUA\ in \MKIV\ this mechanism explores a way
%D to deal with local settings at the \TEX\ end and remembering parameters
%D at the \LUA\ end. We might do things differently now, but as settings normally
%D don't change that often, we're not in a hurry to do that now. The problem at
%D the \LUA\ end is that we don't know when to clean up.

\unprotect

%definesystemattribute[ruled]
%definesystemattribute[shifted]

\registerctxluafile{node-rul}{optimize}

\installcorenamespace{bar}
\installcorenamespace{barindex}
\installcorenamespace{barattribute}
\installcorenamespace{barstack}

\installcommandhandler \??bar {bar} \??bar

\newtoks\t_node_rules_checklist

\let\c_node_rules_index\relax % temporary synonym
\let\p_node_rules_color\empty

\let\setupbars\setupbar

\appendtoks
    \ifsecondargument
        \node_rules_define
    \else
        \the\t_node_rules_checklist
    \fi
\to \everysetupbar

\appendtoks
    \ifcsname\??barindex\currentbar\endcsname
        \lastnamedcs\zerocount
    \else
        \expandafter\newcount\csname\??barindex\currentbar\endcsname
    \fi
  % \normalexpanded{\t_node_rules_checklist{\node_rules_redefine{\currentbar}\the\t_node_rules_checklist}}%
    \normalexpanded{\t_node_rules_checklist{\the\t_node_rules_checklist\relax\node_rules_redefine{\currentbar}}}%
  % \etoksapp\t_node_rules_checklist{\node_rules_redefine{\currentbar}}%
    \node_rules_define
    \setuevalue\currentbar{\node_rules_direct{\currentbar}}%
\to \everydefinebar

\newbox\b_node_rules

\unexpanded\def\node_rules_define
  {\edef\p_node_rules_color{\barparameter\c!color}%
   \edef\p_node_text{\barparameter\c!text}%
   \ifx\p_node_text\empty\else
     \setbox\b_node_rules\hbox{\p_node_text}%
   \fi
   \setevalue{\??barattribute\currentbar}{\number
     \clf_definerule
        continue      {\barparameter\c!continue}%
        unit          {\barparameter\c!unit}%
        order         {\barparameter\c!order}%
        rulethickness {\barparameter\c!rulethickness}%
        method        \barparameter\c!method
        max           \barparameter\c!max\space % number
        mp           {\includeMPgraphic{\barparameter\c!mp}}
        ma            \thecolormodelattribute
        ca            \thecolorattribute\p_node_rules_color
        ta            \thetransparencyattribute\p_node_rules_color
        offset        \barparameter\c!offset\space % number
        dy            \barparameter\c!dy\space % number
        empty        {\barparameter\c!empty}%
     \ifx\p_node_text\empty\else
        % not that useful and efficient, more for testing something
        text         \b_node_rules
        repeat       {\barparameter\c!repeat}%
     \fi
     \relax}}

\unexpanded\def\node_rules_redefine#1%
  {\def\currentbar{#1}\node_rules_define}

\unexpanded\def\node_rules_direct#1%
  {\groupedcommand
     {\node_rules_set{#1}\barparameter\c!left}%
     {\relax\barparameter\c!right}}

\unexpanded\def\inlinebar[#1]%
  {\node_rules_direct{#1}}

% \unexpanded\def\inlinecurrentbar
%   {\node_rules_direct{\currentbar}}

% store in properties

\unexpanded\def\node_rules_set#1% maybe reverse the 1000 (also maybe use more attributes instead of settings)
  {\edef\currentbar{#1}%
   \usebarstyleandcolor\c!foregroundstyle\c!foregroundcolor
   % maybe: \usebarstyleandcolor\c!textgroundstyle\c!textcolor
   % todo: move this to lua .. we callout anyway
   \expandafter\let\expandafter\c_node_rules_index\csname\??barindex#1\endcsname
   \advance\c_node_rules_index\plusone
   \clf_enablerules % will be relaxed
   \attribute\ruledattribute\numexpr
      \plusthousand*\c_node_rules_index
      % optimizing this one needs testing
     +\csname\??barattribute#1\ifcsname\??bar#1:\number\c_node_rules_index\s!parent\endcsname:\number\c_node_rules_index\fi\endcsname
   \relax}

\unexpanded\def\resetbar
  {\attribute\ruledattribute\attributeunsetvalue}

\unexpanded\def\nobar
  {\groupedcommand
     {\resetbar\barparameter\c!left}%
     {\relax\barparameter\c!right}}

\unexpanded\def\startbar[#1]%
  {\begingroup
   \node_rules_set{#1}%
   \ignorespaces
   \barparameter\c!left}

\unexpanded\def\stopbar
  {\removeunwantedspaces
   \barparameter\c!right
   \endgroup}

\unexpanded\def\setbar[#1]%
  {\node_rules_set{#1}}

\let\directsetbar\node_rules_set

% ungrouped

\newcount\c_node_rules_nesting % todo: same as colors

\unexpanded\def\pushbar[#1]%
  {\global\advance\c_node_rules_nesting\plusone
   \expandafter\edef\csname\??barstack\number\c_node_rules_nesting\endcsname{\attribute\ruledattribute\the\attribute\ruledattribute}%
   \node_rules_set{#1}}

\unexpanded\def\popbar
  {\csname\??barstack\number\c_node_rules_nesting\endcsname
   \global\advance\c_node_rules_nesting\minusone}

\setupbars
  [\c!method=0,                 % new: 0=center nested, 1=stack nested
   \c!continue=\v!no,
   \c!empty=,                   % new: yes = hide text
   \c!offset=0,                 % upwards, replaces: topoffset bottomoffset
   \c!dy=0,
   \c!max=3,
   \c!style=,
   \c!rulethickness=.1,
   \c!order=\v!foreground,
   \c!unit=ex,                  % so now we are relative
   \c!color=]                   % replaces: rulecolor

% \definebar[touchbar]    [\c!method=0,\c!dy=-0.4,\c!offset=-0.0]
% \definebar[touchbars]   [touchbar]   [\c!continue=\v!yes]

\let\normalmathoverbar    \overbar
\let\normalmathunderbar   \underbar
\let\normalmathoverstrike \overstrike
\let\normalmathunderstrike\understrike

\definebar[\v!overbar]   [\c!method=1,\c!dy=0.4,\c!offset=1.8,\c!continue=\v!yes]
\definebar[\v!underbar]  [\c!method=1,\c!dy=-0.4,\c!offset=-0.3,\c!continue=\v!yes]
\definebar[\v!overstrike][\c!method=0,\c!dy=0.4,\c!offset=0.5,\c!continue=\v!yes]

\definebar
  [\v!understrike]
  [\c!method=0,
   \c!offset=1.375,
   \c!rulethickness=2.5,
   \c!continue=\v!yes,
   \c!order=\v!background,
   \c!color=lightgray]

\definebar[\v!overbars]    [\v!overbar]    [\c!continue=\v!no]
\definebar[\v!underbars]   [\v!underbar]   [\c!continue=\v!no]
\definebar[\v!overstrikes] [\v!overstrike] [\c!continue=\v!no]
\definebar[\v!understrikes][\v!understrike][\c!continue=\v!no]

\definebar
  [\v!hiddenbar]
  [\v!underbar]
  [\c!continue=\v!yes,
   \c!empty=\v!yes,
   \c!left=\zwj,
   \c!right=\zwj]

% \setupbar[\v!overstrike][continue=all]

% we want these always so ...

\ifdefined\normalmathunderbar
    \expandafter\let\expandafter\normaltextunderbar\csname\v!underbar\endcsname
    \unexpanded\def\underbar{\mathortext\normalmathunderbar\normaltextunderbar}
\else
    \expandafter\let\expandafter\underbar\csname\v!underbar\endcsname
\fi

\ifdefined\normalmathoverbar
    \expandafter\let\expandafter\normaltextoverbar\csname\v!overbar\endcsname
    \unexpanded\def\overbar{\mathortext\normalmathoverbar\normaltextoverbar}
\else
    \expandafter\let\expandafter\overbar\csname\v!overbar\endcsname
\fi

\ifdefined\normalmathunderstrike
    \expandafter\let\expandafter\normaltextunderstrike\csname\v!understrike\endcsname
    \unexpanded\def\understrike{\mathortext\normalmathunderstrike\normaltextunderstrike}
\else
    \expandafter\let\expandafter\understrike\csname\v!understrike\endcsname
\fi

\ifdefined\normalmathoverstrike
    \expandafter\let\expandafter\normaltextoverstrike\csname\v!overstrike\endcsname
    \unexpanded\def\overstrike{\mathortext\normalmathoverstrike \normaltextoverstrike}
\else
    \expandafter\let\expandafter\overstrike\csname\v!overstrike\endcsname
\fi

\expandafter\let\expandafter\overstrikes\csname\v!overstrikes\endcsname
\expandafter\let\expandafter\underbars  \csname\v!underbars  \endcsname
\expandafter\let\expandafter\overbars   \csname\v!overbars   \endcsname

\unexpanded\def\setupunderbar[#1]% too incompatible for the moment
  {}

%D An experimental new feature:
%D
%D \startbuffer
%D test {\red\underrandoms{test me}} and \underrandom{test} or \underrandom{grep} \blank
%D test {\red\underdashes {test me}} and \underdash  {test} or \underdash  {grep} \blank
%D test {\red\underdots   {test me}} and \underdot   {test} or \underdot   {grep} \blank
%D \stopbuffer
%D
%D \typebuffer \getbuffer

\startuseMPgraphic{rules:under:random}
    draw
        ((0,RuleDepth) ... (RuleWidth,RuleDepth)) randomized (4*RuleThickness)
        shifted (0,RuleFactor*RuleOffset)
        withpen pencircle scaled RuleThickness
        withcolor RuleColor ;
    setbounds currentpicture to unitsquare xysized(RuleWidth,RuleHeight) ;
\stopuseMPgraphic

\startuseMPgraphic{rules:under:dash}
    draw
        ((0,RuleDepth) -- (RuleWidth,RuleDepth))
        shifted (0,RuleFactor*RuleOffset)
        dashed dashpattern(on RuleFactor/2 off RuleFactor/2)
        withpen pencircle scaled RuleThickness
        withcolor RuleColor ;
    setbounds currentpicture to unitsquare xysized(RuleWidth,RuleHeight) ;
\stopuseMPgraphic

\startuseMPgraphic{rules:under:dots}
    path p ; p := (0,RuleDepth) -- (RuleWidth,RuleDepth) ;
    numeric l ; l := arclength(p);
    l := l mod RuleThickness/4;
    draw
        p
        shifted (l,RuleFactor*RuleOffset)
        dashed dashpattern(off 2RuleThickness+l on 0 off 2RuleThickness)
        withpen pencircle scaled 2RuleThickness
        withcolor RuleColor ;
    setbounds currentpicture to unitsquare xysized(RuleWidth,RuleHeight) ;
\stopuseMPgraphic

\definebar
  [undergraphic]
  [\c!mp=rules:under:dash,
   \c!offset=-.2,
   \c!order=\v!background]

\definebar[underrandom] [undergraphic][\c!mp=rules:under:random]
\definebar[underrandoms][underrandom] [\c!continue=\v!yes]

\definebar[underdash]   [undergraphic][\c!mp=rules:under:dash]
\definebar[underdashes] [underdash]   [\c!continue=\v!yes]

\definebar[underdot]    [undergraphic][\c!mp=rules:under:dots]
\definebar[underdots]   [underdot]    [\c!continue=\v!yes]

%D This will move: (a bit duplicated)

\installcorenamespace{shift}
\installcorenamespace{shiftindex}
\installcorenamespace{shiftattribute}

\installcommandhandler \??shift {shift} \??shift

\newtoks\t_node_shifts_checklist

\let\c_node_shifts_index\relax % temporary synonym

\let\setupshifts\setupshift

\appendtoks
    \ifsecondargument
        \node_shifts_define
    \else
        \the\t_node_shifts_checklist
    \fi
\to \everysetupshift

\appendtoks
    \ifcsname\??shiftindex\currentshift\endcsname
        \lastnamedcs\zerocount
    \else
        \expandafter\newcount\csname\??shiftindex\currentshift\endcsname
    \fi
    \normalexpanded{\t_node_shifts_checklist{\the\t_node_shifts_checklist\node_shifts_redefine{\currentshift}}}% order ?
    \node_shifts_define
    \setuevalue\currentshift{\node_shifts_direct{\currentshift}}%
\to \everydefineshift

\unexpanded\def\node_shifts_define
  {\setevalue{\??shiftattribute\currentshift}{\number
   \clf_defineshift
     continue {\shiftparameter\c!continue}%
     unit     {\shiftparameter\c!unit}%
     method    \shiftparameter\c!method
     dy        \shiftparameter\c!dy % number
   \relax}}

\unexpanded\def\node_shifts_redefine#1%
  {\def\currentshift{#1}\node_shifts_define}

% \unexpanded\def\node_shifts_set
%   {\clf_enableshifts
%    \glet\node_shifts_set\node_shifts_set_indeed
%    \node_shifts_set}
%
% \def\node_shifts_set_indeed#1% todo: check parent !

\unexpanded\def\node_shifts_set#1% todo: check parent ! todo: move attr etc to lua
  {\def\currentshift{#1}%
   \expandafter\let\expandafter\c_node_shifts_index\csname\??shiftindex#1\endcsname
   \advance\c_node_shifts_index\plusone
   \clf_enableshifts % will be relaxed
   \attribute\shiftedattribute\numexpr
      \plusthousand*\c_node_shifts_index
     +\csname\??shiftattribute#1\ifcsname\??shift#1:\number\c_node_shifts_index\s!parent\endcsname:\number\c_node_shifts_index\fi\endcsname
   \relax
   \useshiftstyleandcolor\c!style\c!color
   \dosetupisolatedalign{\shiftparameter\c!align}} % weird feature that i probably needed once

\unexpanded\def\startshift[#1]%
  {\begingroup
   \node_shifts_set{#1}%
   \ignorespaces}

\unexpanded\def\stopshift
  {\removeunwantedspaces
   \endgroup}

% \unexpanded\def\node_shifts_direct#1%
%   {\doisolatedgroupedalign{\node_shifts_set{#1}}\donothing}

\unexpanded\def\node_shifts_direct#1%
  {\groupedcommand
     {\begingroup\dostartisolation\begingroup\node_shifts_set{#1}\ignorespaces}
     {\removeunwantedspaces\endgroup\dostopisolation\endgroup}}

\setupshifts
  [\c!method=0,
   \c!continue=\v!no,
   \c!dy=0,
   \c!unit=ex,
   \c!align=,
   \c!style=,
   \c!color=]

\defineshift [\v!shiftup]   [\c!method=0,\c!dy=-1,\c!unit=ex,\c!continue=\v!yes,\c!style=\txx,\c!color=]
\defineshift [\v!shiftdown] [\c!method=1,\c!dy=.3,\c!unit=ex,\c!continue=\v!yes,\c!style=\txx,\c!color=]

% we want these always so ...

\expandafter\let\expandafter\shiftup   \csname\v!shiftup   \endcsname
\expandafter\let\expandafter\shiftdown \csname\v!shiftdown \endcsname

% This is a weird helper:

\unexpanded\def\dostartisolation{\signalcharacter}
\unexpanded\def\dostopisolation {\signalcharacter}
\unexpanded\def\doisolator      {\signalcharacter}

\unexpanded\def\dosetupisolatedalign#1%
  {\doisolator
   \setupalign[#1]\relax}

\unexpanded\def\doisolatedgroupedalign#1#2%
  {\groupedcommand
     {\begingroup\dostartisolation\begingroup#1}
     {#2\endgroup\dostopisolation\endgroup}}

%D More rules.

% The following code rocks and was written with the Toto Live in Poland bluray
% in loop mode on my 5.1 surround development setup (the Toto lineup with Simon
% Phillips on drums). The Amsterdam concert is equally energizing.

\installcorenamespace{linefiller}
\installcorenamespace{linefillerindex}
\installcorenamespace{linefillerattribute}

\installcommandhandler \??linefiller {linefiller} \??linefiller

\definesystemattribute[linefiller][public]

\newtoks\t_node_linefiller_checklist

\let\c_node_linefiller_index\relax % temporary synonym

\let\setuplinefillers\setuplinefiller

\appendtoks
    \ifsecondargument
        \node_linefiller_define
    \else
        \the\t_node_linefiller_checklist
    \fi
\to \everysetuplinefiller

\appendtoks
    \ifcsname\??linefillerindex\currentlinefiller\endcsname
        \lastnamedcs\zerocount
    \else
        \expandafter\newcount\csname\??linefillerindex\currentlinefiller\endcsname
    \fi
    \etoksapp\t_node_linefiller_checklist{\t_node_linefiller_checklist\node_linefiller_redefine{\currentlinefiller}}%
    \node_linefiller_define
\to \everydefinelinefiller

\unexpanded\def\node_linefiller_define
  {\edef\p_node_rules_color{\linefillerparameter\c!color}%
   \setevalue{\??linefillerattribute\currentlinefiller}{\number
   \clf_definelinefiller
    %method         \linefillerparameter\c!method
     location      {\linefillerparameter\c!location}%
     scope         {\linefillerparameter\c!scope}%
     mp            {\includeMPgraphic{\linefillerparameter\c!mp}}%
     ma             \thecolormodelattribute
     ca             \thecolorattribute\p_node_rules_color
     ta             \thetransparencyattribute\p_node_rules_color
     height         \dimexpr\linefillerparameter\c!height\relax
     depth          \dimexpr\linefillerparameter\c!depth\relax
     distance       \dimexpr\linefillerparameter\c!distance\relax
     threshold      \dimexpr\linefillerparameter\c!threshold\relax
     rulethickness  \dimexpr\linefillerparameter\c!rulethickness\relax
   \relax}}

\unexpanded\def\node_linefiller_redefine#1%
  {\def\currentlinefiller{#1}\node_linefiller_define}

\unexpanded\def\node_linefiller_set#1% todo: check parent ! todo: move attr etc to lua
  {\def\currentlinefiller{#1}%
   \expandafter\let\expandafter\c_node_linefiller_index\csname\??linefillerindex#1\endcsname
   \advance\c_node_linefiller_index\plusone
   \clf_enablelinefillers
   \attribute\linefillerattribute\numexpr
      \plusthousand*\c_node_linefiller_index
     +\csname\??linefillerattribute#1\ifcsname\??linefiller#1:\number\c_node_linefiller_index\s!parent\endcsname:\number\c_node_linefiller_index\fi\endcsname
   \relax}

\unexpanded\def\startlinefiller
  {\dodoubleempty\node_linefiller_start}

\unexpanded\def\node_linefiller_start[#1][#2]%
  {\begingroup
   \par
   \def\currentlinefiller{#1}%
   \ifsecondargument
     % we need to update settings
     \setuplinefiller[#1][#2]% no \setupcurrentlinefiller as we need to update settings
   \fi
   \node_linefiller_set{#1}%
   \linefillerparameter\c!before
   \usealignparameter\linefillerparameter
   \uselinefillerstyleandcolor\c!textstyle\c!textcolor} % bars have foregroundcolor

\unexpanded\def\stoplinefiller
  {\par
   \linefillerparameter\c!after
   \endgroup}

\unexpanded\def\setlinefiller[#1]%
  {\node_linefiller_set{#1}}

\setuplinefillers
  [%c!method=0,
   %c!mp=,
   \c!location=\v!both,
   \c!scope=\v!local,
   \c!distance=\zeropoint,
   \c!threshold=\zeropoint,
   \c!rulethickness=\linewidth,
   \c!height=\linewidth,
   \c!depth=\zeropoint,
  %\c!textcolor=,
  %\c!textstyle=,
  %\c!align=,
  %\c!before=,
  %\c!after=,
   \c!color=]

\definelinefiller
  [filler]
  [\c!height=.75\exheight,
  %\c!mp=rules:filler:demo,
  %\c!threshold=.25\emwidth,
   \c!distance=.25\emwidth,
   \c!rulethickness=.25\exheight]

%D Bonus:
%D
%D \starttyping
%D \startuseMPgraphic{foo}
%D     fill unitsquare
%D         xyscaled (RuleWidth,RuleHeight+RuleDepth) enlarged (ExHeight/4,ExHeight/8)
%D         shifted  (-ExHeight/8,ExHeight/16)
%D         withcolor RuleColor ;
%D \stopuseMPgraphic
%D
%D \definelinefiller[foo][mp=foo,color=darkred]
%D
%D \linefillerhbox[foo]{OEPS}
%D \stoptyping

\unexpanded\def\node_backgrounds_filler_box#1#2[#3]%
  {\bgroup
   \clf_enablebackgroundboxes
   \dowithnextbox{%
     \node_linefiller_set{#3}% already sets the attribute
     #1%
        attr \backgroundattribute \plusone
      % attr \linefillerattribute \the\attribute\linefillerattribute
       {\box\nextbox}%
     \egroup}%
   #2}

\unexpanded\def\linefillerhbox{\node_backgrounds_filler_box\hpack\hbox}
\unexpanded\def\linefillervbox{\node_backgrounds_filler_box\vpack\vbox}
\unexpanded\def\linefillervtop{\node_backgrounds_filler_box\tpack\vtop}

%D Bonus:

\unexpanded\def\autorule{\clf_autorule}

\protect \endinput