%D \module %D [ file=page-str, %D version=2006.03.21, %D title=\CONTEXT\ Page Macros, %D subtitle=Page Streams, %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 Page Macros / Page Streams} %D The first version of this component of \CONTEXT\ was written %D for Thomas Schmitz who asked for parallel page streams. While %D playing with the code, I decided to make it into a component %D that can be used to construct all kind of stream related %D mechanisms. Because I could apply this feature in a project, %D there is some additional code here (related to graphics). %D %D These macros were written while listening to and watching the DVD %D \quotation {Rush In Rio}. % not yet ok in mkiv ... marknotes \unprotect % taco, what is the best way to append a otr chunk (insert pagediscards?) \let\currentoutputstream\s!default \newtoks\defaultstreamoutput \defaultstreamoutput=\OTRONEoutput \newtoks\normalstreamoutput \normalstreamoutput={\saveoutputstream[\currentoutputstream]} \newcount\streampenalty \streampenalty=-101010101 \ifx\multicolumnseject\undefined \else \let\normalmulticolumnseject\multicolumnseject \def\multicolumnseject{\ifinoutputstream\else\normalmulticolumnseject\fi} \fi \newif\ifinoutputstream \newtoks \everyenableoutputstream \appendtoks \flushsidefloats \to \everyenableoutputstream \def\enableoutputstream[#1]% {\the\everyenableoutputstream \finishoutputstream \writestatus{otr}{switching to output stream #1}% \inoutputstreamtrue \xdef\currentoutputstream{#1}} \def\disableoutputstream {\finishoutputstream \writestatus{otr}{switching to default output stream}% \inoutputstreamfalse \global\let\currentoutputstream\s!default} \def\useoutputstream[#1]% {\writestatus{otr}{using output stream #1}% \xdef\currentoutputstream{#1}} \def\handlestreamoutput {\doifelse\currentoutputstream\s!default {\ifnum\outputpenalty=\streampenalty \ifvoid\normalpagebox \else \unvbox\normalpagebox \fi \else \the\defaultstreamoutput \fi} {\the\normalstreamoutput}} \OTRONEoutput{\handlestreamoutput} \def\defineoutputstream[#1]% {\doifundefined{otrs:#1}{\expandafter\newbox\csname otrs:#1\endcsname}} \def\outputstreamtag#1% {\csname otrs:#1\endcsname} \def\finishoutputstream % todo: installoutput {\endgraf \penalty\streampenalty \endgraf} \def\saveoutputstream[#1]% {\writestatus{otr}{saving otr stream #1}% \ifvoid\normalpagebox \global\setbox\outputstreamtag{#1}\emptybox \else \global\setbox\outputstreamtag{#1}\vbox {\presetoutputstream \ifvoid\outputstreamtag{#1}\else\unvbox\outputstreamtag{#1}\fi \scratchdimen\dp\normalpagebox \unvbox\normalpagebox \vskip-\scratchdimen \kern\strutdepth}% \fi} % \def\presetoutputstream % {\pdffirstlineheight\strutheight % \pdflastlinedepth \strutdepth % \pdfeachlineheight \strutheight % \pdfeachlinedepth \strutdepth} \let\presetoutputstream\relax \def\outputstreamht [#1]{\ht\outputstreamtag{#1}} \def\outputstreamdp [#1]{\dp\outputstreamtag{#1}} \def\outputstreamwd [#1]{\wd\outputstreamtag{#1}} %def\outputstreambox [#1]{\ifvoid\outputstreamtag{#1}\else\box \outputstreamtag{#1}\fi} %def\outputstreamcopy[#1]{\ifvoid\outputstreamtag{#1}\else\copy\outputstreamtag{#1}\fi} \def\dowithoutputstreambox#1[#2]{\ifvoid\outputstreamtag{#2}\else#1\outputstreamtag{#2}\fi} \def\outputstreamcopy {\dowithoutputstreambox\copy } \def\outputstreambox {\dowithoutputstreambox\box } \def\outputstreamunvcopy{\dowithoutputstreambox\unvcopy} \def\outputstreamunvbox {\dowithoutputstreambox\unvbox } %D Footnotes don't go along with streams, simply because there is no %D way to re-split inserts. A dirty way out is to use marks and store %D notes that way. \def\definemarknote {\dodoubleempty\dodefinemarknote} \def\dodefinemarknote[#1][#2]% {\definemarking[mn:#1]% \setvalue{mn:#1:n}{0}% \getparameters [mn:#1] [\c!before=, \c!after=, \c!inbetween=\endgraf, \c!command=\firstofoneargument, #2]} \def\setmarknote[#1]#2% {\doglobal\incrementvalue{mn:#1:n}% \setgvalue{mn:#1:t:\getvalue{mn:#1:n}}{#2}% \expanded{\marking[mn:#1]{\getvalue{mn:#1:n}}}} \def\flushmarknotes[#1]% assumes split {\begingroup % \edef\firstmarknote{0\fetchmark[mn:#1][column:first]}% % \edef\lastmarknote {0\fetchmark[mn:#1][column:last]}% % \ifnum\firstmarknote<\lastmarknote\relax % \getvalue{mn:#1\c!before}% % \dostepwiserecurse\firstmarknote\lastmarknote\plusone % {\ifnum\recurselevel>\firstmarknote\relax % \ifnum\recurselevel<\lastmarknote\relax % \getvalue{mn:#1\c!inbetween}% % \fi % \fi % \getvalue{mn:#1\c!command}{\getvalue{mn:#1:t:\recurselevel}}}% % \getvalue{mn:#1\c!after}% % \fi \endgroup} \def\erasemarknotes[#1]% {\begingroup \edef\firstmarknote{0\fetchmark[mn:#1][column:first]}% \edef\lastmarknote {0\fetchmark[mn:#1][column:last]}% \dostepwiserecurse\firstmarknote\lastmarknote\plusone {\global\letvalue{mn:#1:t:\recurselevel}\empty}% \endgroup} %D The next section implements synchronization of (currently %D two) output streams. In due time we will implement both a %D vertical and horizontal system, as well as alternative %D splitters (firstpagevsize, succesivevsize etc). \def\synchronizeoutputstreams[#1]% [one,two] [left,right] {\bgroup \getfromcommalist[#1][\plusone]\let\firstoutputstream \commalistelement \getfromcommalist[#1][\plustwo]\let\secondoutputstream\commalistelement \forgeteverypar \def\roundingeps{50sp}% \getboxheight\dimen0\of\box\outputstreamtag\firstoutputstream \getboxheight\dimen2\of\box\outputstreamtag\secondoutputstream \scratchdimen\dimexpr\dimen0-\dimen2\relax \ifdim\scratchdimen<-\roundingeps\relax \scratchdimen-\scratchdimen \writestatus{sync}{compensating first stream: \the\scratchdimen/\number\scratchdimen}% \getroundednoflines\scratchdimen \global\setbox\outputstreamtag\firstoutputstream\vbox {\presetoutputstream \unvbox\outputstreamtag\firstoutputstream\dorecurse\noflines\crlf}% \else\ifdim\scratchdimen>\roundingeps\relax \writestatus{sync}{compensating second stream: \the\scratchdimen/\number\scratchdimen}% \getroundednoflines\scratchdimen \global\setbox\outputstreamtag\secondoutputstream\vbox {\presetoutputstream \unvbox\outputstreamtag\secondoutputstream\dorecurse\noflines\crlf}% \else \writestatus{sync}{no need to compensate streams: \the\scratchdimen/\number\scratchdimen}% \fi\fi \egroup} \def\nofoutputstreamsplitlines {\v!auto} % {40} \def\outputstreamsplittolerance {-5} \def\flushoutputstreampages[#1]% {\bgroup \getfromcommalist[#1][\plusone]\let\firstoutputstream \commalistelement \getfromcommalist[#1][\plustwo]\let\secondoutputstream\commalistelement \doloop {\flushoutputstreams[#1]% \ifvoid\outputstreamtag\firstoutputstream \ifvoid\outputstreamtag\secondoutputstream \exitloop \else \global\setbox\outputstreamtag\firstoutputstream\vbox{\strut}% \fi \else \ifvoid\outputstreamtag\secondoutputstream \global\setbox\outputstreamtag\secondoutputstream\vbox{\strut}% \else % okay \fi \fi}% \egroup} \def\flushoutputstreams[#1]% {\bgroup \getfromcommalist[#1][\plusone]\let\firstoutputstream \commalistelement \getfromcommalist[#1][\plustwo]\let\secondoutputstream\commalistelement \doif\nofoutputstreamsplitlines\v!auto {\getrawnoflines\textheight \edef\nofoutputstreamsplitlines{\the\noflines}}% \splittopskip\strutheight \scratchdimen\nofoutputstreamsplitlines\lineheight\relax \unless\iffalse \dimen0\scratchdimen \doloop {\setbox4\copy\outputstreamtag\firstoutputstream \setbox0\vsplit4 to \dimen0 \setbox0\vbox {\directsetup{stream:\firstoutputstream:top}% \unvbox0 \directsetup{stream:\firstoutputstream:bottom}}% \ifdim\ht0>\scratchdimen \advance\dimen0-\lineheight \else \exitloop \fi}% \scratchdimen\dimen0 \dimen2\scratchdimen \doloop {\setbox6\copy\outputstreamtag\secondoutputstream \setbox2\vsplit6 to \dimen2 \setbox2\vbox {\directsetup{stream:\secondoutputstream:top}% \unvbox0 \directsetup{stream:\secondoutputstream:bottom}}% \ifdim\ht2>\scratchdimen \advance\dimen2-\lineheight \else \exitloop \fi}% \scratchdimen\dimen2 \fi \setbox4\copy\outputstreamtag\firstoutputstream \setbox6\copy\outputstreamtag\secondoutputstream \scratchcounter\zerocount \doloop {\setbox0\vsplit4 to \scratchdimen \setbox0\vbox{\unvbox0}% \setbox2\vsplit6 to \scratchdimen \setbox2\vbox{\unvbox2}% \ifvoid4 \exitloop \else\ifvoid6 \exitloop \else \dimen8=\dimexpr\ht4-\ht6\relax \ifdim\dimen8<\zeropoint\dimen8=-\dimen8\relax\fi \advance\scratchcounter\plusone \ifdim\dimen8<.5\lineheight \exitloop \else\ifnum\outputstreamsplittolerance>\zeropoint \ifnum\scratchcounter>\outputstreamsplittolerance\relax \exitloop \else \advance\scratchdimen\lineheight \fi \else\ifnum\outputstreamsplittolerance<\zeropoint \ifnum-\scratchcounter<\outputstreamsplittolerance\relax \exitloop \else \advance\scratchdimen-\lineheight \fi \else\ifnum\outputstreamsplittolerance=\zeropoint \exitloop \fi\fi\fi\fi \fi\fi}% \setbox0\vsplit\outputstreamtag\firstoutputstream to \scratchdimen \setbox0\vbox to \textheight {\presetoutputstream \directsetup{stream:\firstoutputstream:top}% \unvbox0 \vfill \directsetup{stream:\firstoutputstream:bottom}}% \setbox2\vsplit\outputstreamtag\secondoutputstream to \scratchdimen \setbox2\vbox to \textheight {\presetoutputstream \directsetup{stream:\secondoutputstream:top}% \unvbox2 \vfill \directsetup{stream:\secondoutputstream:bottom}}% \directsetup{stream:\firstoutputstream:reset}% \directsetup{stream:\secondoutputstream:reset}% \page[even] \box0\vfill\page \box2\vfill\page \egroup} %D Because many arrangements are possible, we will implement %D some examples in a runtime loadable module \type {m-streams}. \protect \endinput