%D \module
%D   [       file=scrn-bar, % was part of scrn-int
%D        version=1995.01.01,
%D          title=\CONTEXT\ Core Macros,
%D       subtitle=Progress 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.

\writestatus{loading}{ConTeXt Screen Macros / Progress Bars}

\unprotect

%D The code is a bit upgraded to \MKIV\ but the output is mostly the same. In
%D retrospect this should have been a module. We can move some definitions to
%D scrn-run-bar.mkiv if needed. We can also make the code a bit more efficient.

% todo: replace blackrule by stupid rules

%D \starttyping
%D \setupinteraction
%D   [state=start]
%D
%D \setupsubpagenumber
%D   [state=start]
%D
%D \setuplayout
%D   [middle]
%D
%D \setuppapersize
%D   [S4][S4]
%D
%D \startsetups bars
%D     \ruledvbox to \textheight \bgroup
%D         a \ruledhbox{\interactionbar[a]}\vss
%D         b \ruledhbox{\interactionbar[b]}\vss
%D         c \ruledhbox{\interactionbar[c]}\vss
%D         d \ruledhbox{\interactionbar[d]}\vss
%D         e \ruledhbox{\interactionbar[e]}\vss
%D         f \ruledhbox{\interactionbar[f]}\vss
%D         g \ruledhbox{\interactionbar[g]}\vss
%D     \egroup
%D \stopsetups
%D
%D \setuptexttexts[\setups{bars}]
%D
%D \starttext
%D     \dorecurse {12} {
%D         \startstandardmakeup
%D         \stopstandardmakeup
%D     }
%D \stoptext
%D \stoptyping

\installcorenamespace{interactionbar}

\installframedcommandhandler \??interactionbar {interactionbar} \??interactionbar

\permanent\tolerant\protected\def\interactionbar[#tag]#spacer[#S#settings]% somewhat messy
  {\iflocation
     \begingroup
     \ifhastok={#tag}%
       \lettonothing\currentinteractionbar
       \setupcurrentinteractionbar[#tag]%
       \cdef\currentinteractionbar{\interactionbarparameter\c!alternative}%
     \else
       \cdef\currentinteractionbar{#tag}%
       \setupcurrentinteractionbar[#settings]%
     \fi
     \ifcstok{\interactionbarparameter\c!state}\v!start
       \interactionbarparameter\c!command
     \fi
     \endgroup
   \fi}

\newdimension\d_scrn_bar_width
\newdimension\d_scrn_bar_height
\newdimension\d_scrn_bar_depth
\newdimension\d_scrn_bar_distance

%D Interaction buttons, in fact a row of tiny buttons, are typically only used for
%D navigational purposed. The next macro builds such a row based on a specification
%D list.
%D
%D \startbuffer
%D \interactionbuttons[width=\hsize][page,PreviousJump,ExitViewer]
%D \stopbuffer
%D
%D \typebuffer
%D
%D gives
%D
%D \getbuffer
%D
%D Apart from individual entries, one can use \type{page} and \type {subpage} as
%D shortcuts to their four associated buttons. The symbols are derived from the
%D symbols linked to the entries.

\permanent\tolerant\protected\def\interactionbuttons[#S#settings]#spacer[#list]%
  {\iflocation
      \ifcstok{\interactionbarparameter\c!state}\v!start
        \ifparameter#list\or
          \scrn_bar_buttons_indeed{#settings}{#list}%
        \else
          \scrn_bar_buttons_indeed{}{#settings}%
        \fi
      \fi
   \fi}

\def\scrn_bar_buttons_indeed#settings#list%
  {\begingroup
  %\lettonothing\currentinteractionbar
   \setupcurrentinteractionbar[#settings]%
   \d_scrn_bar_width   {\interactionbarparameter\c!width}%
   \d_scrn_bar_distance{\interactionbarparameter\c!distance}%
   \ifzeropt\d_scrn_bar_width
     \d_scrn_bar_width1.5\emwidth
   \fi
   \ifempty{\interactionbarparameter\c!height}%
     \letinteractionbarparameter\c!height\v!broad
   \fi
   \ifempty{\interactionbarparameter\c!depth}%
     \letinteractionbarparameter\c!depth\zeropoint
   \fi
   \resetinteractionbarparameter\c!background
   \setbox2\hbox{\inheritedinteractionbarframed{\symbol[\interactionparameter\c!symbolset][\v!previouspage]}}%
   \scratchheight\ht2 % needed because we default to nothing
   \letinteractionbarparameter\c!strut\v!no
 % \letinteractionparameter\c!width\zeropoint
   \scratchcounterone\zerocount % new, was 1
   \processallactionsinset
     [#list]
     [   \v!page=>\advanceby\scratchcounterone\plusfour,
      \v!subpage=>\advanceby\scratchcounterone\plusfour,
      \s!unknown=>\advanceby\scratchcounterone\plusone]%
   \ifzeropt\d_scrn_bar_width
     \scratchdimenone{2\emwidth+\d_scrn_bar_distance}%
     \scratchdimentwo{\scratchcounterone\scratchdimenone-\d_scrn_bar_distance}%
   \else
     \scratchdimenone\d_scrn_bar_width
     \scratchdimentwo{\scratchcounterone\d_scrn_bar_distance-\d_scrn_bar_distance}%
     \advanceby\scratchdimenone -\scratchdimentwo
     \divideby\scratchdimenone \scratchcounterone
     \scratchdimentwo\d_scrn_bar_width
   \fi
   \hbox to \scratchdimentwo
     {\setnostrut
      \startsymbolset[\interactionparameter\c!symbolset]%
      \setupbuttons
        [#settings,%
         \c!height=\the\scratchheight,%
         \c!width=\the\scratchdimenone]%
      \processallactionsinset
        [#list]
        [   \v!page=>\scrn_bar_goto\v!firstpage
                     \scrn_bar_goto\v!nextpage
                     \scrn_bar_goto\v!previouspage
                     \scrn_bar_goto\v!lastpage,
         \v!subpage=>\scrn_bar_goto\v!firstsubpage
                     \scrn_bar_goto\v!nextsubpage
                     \scrn_bar_goto\v!previoussubpage
                     \scrn_bar_goto\v!lastsubpage,
         \s!unknown=>\scrn_bar_goto\commalistelement]%
      \unskip
      \stopsymbolset}%
   \endgroup}

\def\scrn_bar_goto#action%
  {\button{\symbol[#action]}[#action]\hss}

\def\scrn_bar_alternative_a
  {\d_scrn_bar_width   {\interactionbarparameter\c!width}%
   \d_scrn_bar_distance{\interactionbarparameter\c!distance}%
   \d_scrn_bar_height  {\interactionbarparameter\c!height}%
   \d_scrn_bar_depth   {\interactionbarparameter\c!depth}%
   \noindent\hbox to \d_scrn_bar_width \bgroup
    \dontcomplain
    \setupblackrules[\c!height=\v!max,\c!depth=\v!max]%
    \scratchdimentwo{\d_scrn_bar_width-4\emwidth}%
    \processaction
      [\interactionbarparameter\c!step]
      [   \v!small=>\scratchcounter 20,
         \v!medium=>\scratchcounter 10,
            \v!big=>\scratchcounter  5,
        \s!unknown=>\scratchcounter 10]%
    \scratchdimenone{\scratchdimentwo/\scratchcounter}%
    \setupblackrules[\c!width=\scratchdimenone]%
    \setbox\scratchbox\hbox to \d_scrn_bar_width
      {\hskip2\emwidth
       \setbox\scratchbox\hpack{\blackrule[\c!color=\interactionbarparameter\c!backgroundcolor]}%
       \dorecurse\scratchcounter
         {\hss\expanded{\directgotodumbbox{\copy\scratchbox}[page(\tointeger{\recurselevel*\lastpage/\scratchcounter})]}}%
       \hss
       \hskip2\emwidth}%
    \wd\scratchbox\zeropoint
    \box \scratchbox
    \setupblackrules[\c!width=\emwidth]%
    \expanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[\v!firstpage]}%
    \hskip\emwidth
    \ifnum\realpageno>\plusone
      \hskip\zeropoint\s!plus\numexpr\realpageno-\plustwo\relax\s!sp\relax % cm gives overflow
      \expanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[\v!previouspage)]}%
    \fi
    \expanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[page(\the\realpageno)]}% todo: \v!currentpage
    \ifnum\realpageno<\lastpage\relax
      \expanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[\v!nextpage]}%
      \hskip\zeropoint\s!plus\numexpr\lastpage-\realpageno-\plusone\relax\s!sp\relax % cm gives overflow
    \fi
    \hskip\emwidth
    \expanded{\directgotospecbox\noexpand\interactionbarparameter{\blackrule}[\v!lastpage]}%
   \egroup}

\def\scrn_bar_alternative_b
  {\ifnum\lastpage>\firstpage\relax
     \interactionbuttons[\v!firstpage,\v!previouspage,\v!nextpage,\v!lastpage]%
   \fi}

\def\scrn_bar_alternative_c
  {\ifnum\lastpage>\plusone
     \d_scrn_bar_width{\interactionbarparameter\c!width}%
     \hbox to \d_scrn_bar_width
       {\setupblackrules[\c!height=\interactionbarparameter\c!height,\c!depth=\interactionbarparameter\c!depth,\c!width=\emwidth]%
        \scratchdimen{(\d_scrn_bar_width-4\emwidth)/\numexpr\lastpage+\minusone\relax}%
        \scratchdimenone{\numexpr\realpageno+\minusone\relax\scratchdimen}%
        \scratchdimentwo{\numexpr\lastpage-\realpageno\relax\scratchdimen}%
        \directgotospecbox\interactionbarparameter{\blackrule}[\v!firstpage]%
        \hss
        \directgotospecbox\interactionbarparameter{\blackrule[\c!width=\scratchdimenone]}[\v!previouspage]%
        \blackrule[\c!color=\interactionbarparameter\c!contrastcolor]%
        \directgotospecbox\interactionbarparameter{\blackrule[\c!width=\scratchdimentwo]}[\v!nextpage]%
        \hss
        \directgotospecbox\interactionbarparameter{\blackrule}[\v!lastpage]}%
   \fi}

\protected\def\scrn_bar_goto_a#whereto%
  {\symbol[\ifcase#whereto\v!previous\or\v!somewhere\or\v!next\fi]}

\protected\def\scrn_bar_goto_b#whereto%
  {\vrule\s!height\d_scrn_bar_height\s!depth\d_scrn_bar_depth\s!width\scratchdimenone\relax}

\protected\def\scrn_bar_goto_c#whereto%
  {\symbol[\ifcase#whereto\v!previous\or\v!somewhere\or\v!somewhere\or\v!somewhere\or\v!next\fi}

\protected\def\scrn_bar_goto_d#whereto%
  {\vrule \s!width\scratchdimenone \ifcase#whereto%
     \s!height  \d_scrn_bar_height \s!depth  \d_scrn_bar_depth \or
     \s!height.5\d_scrn_bar_height \s!depth.5\d_scrn_bar_depth \or
     \s!height  \d_scrn_bar_height \s!depth  \d_scrn_bar_depth \or
     \s!height.5\d_scrn_bar_height \s!depth.5\d_scrn_bar_depth \else
     \s!height  \d_scrn_bar_height \s!depth  \d_scrn_bar_depth \fi}

\newconstant\c_scrn_bar_mode

\let\scrn_bar_goto_indeed\relax

\protected\def\scrn_bar_goto_x#command%
  {\ifcstok{\interactionbarparameter\c!symbol}\v!yes
     \setupsymbolset[\interactionparameter\c!symbolset]%
     \let\scrn_bar_goto_indeed\scrn_bar_goto_a
   \else
     \let\scrn_bar_goto_indeed\scrn_bar_goto_b
   \fi
   \dorecurse\nofsubpages
    %{\scratchcounter{\recurselevel+\firstsubpage+\minusone}%
     {\scratchcounter\therealsubpageno\recurselevel
      \c_scrn_bar_mode
        \ifnum\scratchcounter<\realpageno \zerocount \else
        \ifnum\scratchcounter=\realpageno \plusone   \else
                                          \plustwo   \fi\fi
      \expanded{\directgotospecbox\noexpand\interactionbarparameter{\scrn_bar_goto_indeed\c_scrn_bar_mode}[page(\the\scratchcounter)]}%
      #command}%
   \unskip}

\def\scrn_bar_alternative_d
  {\ifnum\nofsubpages>\plusone
     \ifcstok{\namedcounterparameter\s!subpage\c!state}\v!start
       \d_scrn_bar_width   {\interactionbarparameter\c!width}%
       \d_scrn_bar_distance{\interactionbarparameter\c!distance}%
       \d_scrn_bar_height  {\interactionbarparameter\c!height}%
       \d_scrn_bar_depth   {\interactionbarparameter\c!depth}%
       \scratchdimenone\d_scrn_bar_width
       \noindent\hbox{\scrn_bar_goto_x{\hskip\d_scrn_bar_distance}}% \hpack ?
     \fi
   \fi}

\def\scrn_bar_alternative_e
  {\ifnum\nofsubpages>\plusone
     \ifcstok{\namedcounterparameter\s!subpage\c!state}\v!start
       \d_scrn_bar_width   {\interactionbarparameter\c!width}%
       \d_scrn_bar_distance{\interactionbarparameter\c!distance}%
       \d_scrn_bar_height  {\interactionbarparameter\c!height}%
       \d_scrn_bar_depth   {\interactionbarparameter\c!depth}%
       \scratchdimentwo{\nofsubpages\d_scrn_bar_distance-\d_scrn_bar_distance}% (n-1)
       \scratchdimenone{(\d_scrn_bar_width-\scratchdimentwo)/\nofsubpages}%
       \ifdim\scratchdimenone<\d_scrn_bar_distance
         \scrn_bar_alternative_f
       \else
         \noindent\hbox to \d_scrn_bar_width{\scrn_bar_goto_x{\hss}\unskip}% \hpack ?
       \fi
     \fi
   \fi}

\def\scrn_bar_alternative_f
  {\ifnum\nofsubpages>\plusone
     \ifcstok{\namedcounterparameter\s!subpage\c!state}\v!start
       \d_scrn_bar_width   {\interactionbarparameter\c!width}%
       \d_scrn_bar_distance{\interactionbarparameter\c!distance}%
       \d_scrn_bar_height  {\interactionbarparameter\c!height}%
       \d_scrn_bar_depth   {\interactionbarparameter\c!depth}%
       \noindent \hbox to \d_scrn_bar_width \bgroup
         \doloop
           {\scratchcounterthree{\nofsubpages/\recurselevel+\plusone}% rounding
            \scratchdimentwo\d_scrn_bar_distance
            \multiplyby\scratchdimentwo \scratchcounterthree
            \advanceby\scratchdimentwo -\d_scrn_bar_distance
            \scratchdimenone\d_scrn_bar_width
            \advanceby\scratchdimenone -\scratchdimentwo
            \divideby\scratchdimenone \scratchcounterthree
            \ifdim\scratchdimenone<\d_scrn_bar_distance\else
              \scratchcountertwo\recurselevel
              \exitloop
            \fi}%
         \ifnum\scratchcounterthree>\plusone
           % this is not that well tested
           \advanceby\scratchcounterthree \minustwo
           \scratchdimenone-\d_scrn_bar_distance
           \scratchdimenone\scratchcounterthree\scratchdimenone
           \advanceby\scratchdimenone \d_scrn_bar_width
           \advanceby\scratchcounterthree \plusone
           \divideby\scratchdimenone \scratchcounterthree
         \fi
         \ifcstok{\interactionbarparameter\c!symbol}\v!yes
           \setupsymbolset[\interactionparameter\c!symbolset]%
           \let\scrn_bar_goto_indeed\scrn_bar_goto_c
         \else
           \let\scrn_bar_goto_indeed\scrn_bar_goto_d
         \fi
         \scratchcounterthree{\realpageno-\plustwo}%
         \scratchcounterfour{\realpageno+\plustwo}%
         \ifnum\scratchcounterthree<\plusone \scratchcounterthree\plusone \fi
         \scratchcounterfive\zerocount
         \dostepwiserecurse\firstsubpage\lastsubpage\plusone
           {\donefalse
            \advanceby\scratchcounterfive \plusone
            \ifnum\recurselevel=\firstsubpage\relax \donetrue \fi
            \ifnum\recurselevel=\lastsubpage \relax \donetrue \fi
            \scratchcountersix\therealsubpageno\recurselevel\relax
            \c_scrn_bar_mode
              \ifdone
                \ifnum\scratchcountersix<\realpageno
                  \zerocount
                \orelse\ifnum\scratchcountersix>\realpageno
                  \plustwo
                \else
                  \plusfour
                \fi
              \else
                \ifnum\scratchcounterfive=\scratchcountertwo
                  \ifnum\scratchcountersix<\realpageno
                    \plusone
                  \orelse\ifnum\scratchcountersix>\realpageno
                    \plusthree
                  \else
                    \plustwo
                  \fi
                \else
                  \minusone
                \fi
              \fi
            \ifnum\c_scrn_bar_mode<\zerocount\else
              \expanded{\directgotospecbox\noexpand\interactionbarparameter{\scrn_bar_goto_indeed\c_scrn_bar_mode}[realpage(\the\scratchcountersix)]}%
              \hss
              \scratchcounterfive\zerocount
            \fi}%
         \unskip
       \egroup
     \fi
   \fi}

\def\scrn_bar_alternative_g
  {\ifnum\lastsubpage>\firstsubpage\relax % no test for state?
     \interactionbuttons[\v!firstsubpage,\v!previoussubpage,\v!nextsubpage,\v!lastsubpage]%
   \fi}

\setupinteractionbar
  [\c!state=\v!start,
   \c!alternative=a,
   \c!symbol=\v!no,
   \c!width=10\emwidth,
   \c!height=.5\emwidth,
   \c!depth=\zeropoint,
   \c!distance=.5\emwidth,
   \c!step=\v!medium,
   \c!foregroundcolor=\interactionbarparameter\c!color,
   \c!foregroundstyle=\interactionbarparameter\c!style,
   \c!color=\interactionparameter\c!color,
   \c!contrastcolor=\interactionparameter\c!contrastcolor,
   \c!style=,
   \c!frame=\v!on,
   \c!background=color,
   \c!backgroundcolor=gray,
   \c!samepage=\v!yes]

\defineinteractionbar[a][\c!command=\scrn_bar_alternative_a]
\defineinteractionbar[b][\c!command=\scrn_bar_alternative_b,\c!height=\v!broad]
\defineinteractionbar[c][\c!command=\scrn_bar_alternative_c,\c!height=\v!max,\c!depth=\v!max]
\defineinteractionbar[d][\c!command=\scrn_bar_alternative_d,\c!width=.5\emwidth]
\defineinteractionbar[e][\c!command=\scrn_bar_alternative_e]
\defineinteractionbar[f][\c!command=\scrn_bar_alternative_f]
\defineinteractionbar[g][\c!command=\scrn_bar_alternative_g,\c!height=\v!broad]

\protect \endinput
