%D \module %D [ file=page-otr, %D version=2012.01.25, %D title=\CONTEXT\ Page Macros, %D subtitle=Output Routines, %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 / Output Routines} %D This module will get some of the code from other modules. At the %D same time we provide a bit more control. % When issuing two \par\penalty-\plustenthousand's, only the first % triggers the otr. Is this an obscure feature or an optimization? \registerctxluafile{page-otr}{} \unprotect \let\triggerpagebuilder\clf_triggerpagebuilder \def\m!otr{otr} % todo \installcorenamespace{outputroutine} \installswitchcommandhandler \??outputroutine {outputroutine} \??outputroutine \newtoks\t_page_otr_commands \newtoks\t_page_otr_tracers \unexpanded\def\defineoutputroutinecommand[#name]% doing multiple on one go saves syncing {\processcommalist[#name]\page_otr_commands_define} \unexpanded\def\page_otr_commands_define#name% {\ifcsname#name\endcsname \else \expandafter\let\csname#name\endcsname\relax \normalexpanded{\t_page_otr_commands{\the\t_page_otr_commands\noexpand\page_otr_commands_process{#name}}}% \fi} \let\page_otr_commands_process\gobbleoneargument \appendtoks \let\page_otr_commands_process\page_otr_specifics_preset \the\t_page_otr_commands \let\page_otr_commands_process\gobbleoneargument \to \everyswitchoutputroutine \unexpanded\def\page_otr_specifics_preset#name% {\edef\page_otr_specifics_command{\directoutputroutineparameter{#name}}% no inheritance of commands \ifx\page_otr_specifics_command\empty \writestatus{\currentoutputroutine}{- \expandafter\strippedcsname\csname#name\endcsname}% \expandafter\let\csname#name\endcsname\relax \else \writestatus{\currentoutputroutine}{+ \expandafter\strippedcsname\csname#name\endcsname}% \expandafter\let\csname#name\expandafter\endcsname\page_otr_specifics_command \fi} \unexpanded\def\page_otr_specifics_preset_normal#name% {\edef\page_otr_specifics_command{\directoutputroutineparameter{#name}}% no inheritance of commands \ifx\page_otr_specifics_command\empty \expandafter\let\csname#name\endcsname\relax \else \expandafter\let\csname#name\expandafter\endcsname\page_otr_specifics_command \fi} \unexpanded\def\page_otr_specifics_preset_traced#name% {\edef\page_otr_specifics_command{\directoutputroutineparameter{#name}}% no inheritance of commands \ifx\page_otr_specifics_command\empty \writestatus{\currentoutputroutine}{preset: - \expandafter\strippedcsname\csname#name\endcsname}% \expandafter\let\csname#name\endcsname\relax \else \writestatus{\currentoutputroutine}{preset: + \expandafter\strippedcsname\csname#name\endcsname}% \expandafter\let\csname#name\expandafter\endcsname\page_otr_specifics_command \fi} \let\page_otr_specifics_preset\page_otr_specifics_preset_normal \unexpanded\def\traceoutputroutines {\the\t_page_otr_tracers} \appendtoks \let\page_otr_specifics_preset\page_otr_specifics_preset_traced \to \t_page_otr_tracers %D We have a couple of output routines and the default one is %D the single column routine. Then there is a multicolumn variant %D that can be used mixed, and a columnset variant that is more %D exclusive. \installcorenamespace{otrtriggers} \newconstant\c_page_otr_eject_penalty \c_page_otr_eject_penalty -\plustenthousand \newconstant\c_page_otr_super_penalty \c_page_otr_super_penalty -\plustwentythousand \newcount \c_page_otr_trigger_penalty \c_page_otr_trigger_penalty -100010 \newif \ifinotr % we keep this (name) for old times sake \unexpanded\def\page_otr_message_b{\page_otr_message_s+} \unexpanded\def\page_otr_message_e{\page_otr_message_s-} \unexpanded\def\page_otr_message_s#sign#what% {\writestatus \currentoutputroutine {#sign\space \space #what\space \space p:\the\outputpenalty,\space r:\the\realpageno ,\space c:\number\mofcolumns,\space v:\the\vsize ,\space g:\the\pagegoal ,\space t:\the\pagetotal \ifdim\pagetotal>\pagegoal ,\space d:\the\dimexpr\pagetotal-\pagegoal\relax \fi}} \unexpanded\def\page_otr_trigger#penalty% {\begingroup \par \penalty#penalty% \endgroup} \unexpanded\def\installoutputroutine#invoke#action% \invoke \action {\global\advance\c_page_otr_trigger_penalty\minusone \edef#invoke{\page_otr_trigger{\number\c_page_otr_trigger_penalty}}% \setvalue{\??otrtriggers\number\c_page_otr_trigger_penalty}{#action}} \unexpanded\def\page_otr_triggered_output_routine_traced {\ifcsname\??otrtriggers\the\outputpenalty\endcsname \page_otr_message_b{special}% \csname\??otrtriggers\the\outputpenalty\endcsname % \lastnamedcs can be gone \page_otr_message_e{special}% \else \page_otr_message_b{normal}% \page_otr_command_routine \page_otr_message_e{normal}% \fi} \unexpanded\def\page_otr_triggered_output_routine_normal {\ifcsname\??otrtriggers\the\outputpenalty\endcsname \lastnamedcs \else \page_otr_command_routine \fi} \let\page_otr_triggered_output_routine\page_otr_triggered_output_routine_normal \appendtoks \let\page_otr_triggered_output_routine\page_otr_triggered_output_routine_traced \to \t_page_otr_tracers %D The real routine handler: \ifdefined\everybeforeoutput \else \newtoks\everybeforeoutput \fi \ifdefined\everyafteroutput \else \newtoks\everyafteroutput \fi \def\page_otr_set_engine_output_routine#content% {\global\output {\inotrtrue \the\everybeforeoutput #content\relax \the\everyafteroutput}} % Just as fuzzy (and in 'one' we are okay with \aftergroup anyway): % % \ifdefined\everybeforeoutputgroup \else \newtoks\everybeforeoutputgroup \fi % \ifdefined\everyafteroutputgroup \else \newtoks\everyafteroutputgroup \fi % % \def\page_otr_set_engine_output_routine#content% % {\the\everybeforeoutputgroup % \global\output % {\inotrtrue % \the\everybeforeoutput % #content\relax % \the\everyafteroutput % \aftergroup\the\aftergroup\everyafteroutputgroup}} % % \appendtoks % \ifnum\c_page_postponed_mode=\plusone % \page_postponed_blocks_flush % and then not in \page_otr_construct_and_shipout % \fi % \to \everyafteroutputgroup \page_otr_set_engine_output_routine\page_otr_triggered_output_routine \installoutputroutine\synchronizeoutput % use \triggerpagebuilder instead {\ifvoid\normalpagebox\else \unvbox\normalpagebox % not \pagediscards as it does more harm than good \fi} \installoutputroutine\discardpage {\setbox\scratchbox\box\normalpagebox} % todo: \resetpagebreak -> everyejectpage \def\page_otr_trigger_output_routine {\par \ifvmode \penalty\c_page_otr_eject_penalty \fi \resetpagebreak} \def\page_otr_fill_and_eject_page {\par \ifvmode \vfill \penalty\c_page_otr_eject_penalty \fi \resetpagebreak} \def\page_otr_eject_page {\par \ifvmode \ifdim\pagetotal>\pagegoal \else \normalvfil \fi \penalty\c_page_otr_eject_penalty \fi \resetpagebreak} \def\page_otr_eject_page_and_flush_inserts % can be an installed one {\par \ifvmode \ifdim\pagetotal>\pagegoal \else \normalvfil \fi \penalty\c_page_otr_super_penalty \fi \resetpagebreak} \def\page_otr_check_for_pending_inserts {\ifnum\outputpenalty>\c_page_otr_super_penalty \else \ifnum\insertpenalties>\zerocount % something is being held over so we force a new page \page_otr_force_another_page \fi \fi} \def\page_otr_force_another_page {% we should actually remove the dummy line in the otr \hpack to \hsize{}% \kern-\topskip \nobreak \vfill \penalty\c_page_otr_super_penalty \resetpagebreak} %D For those who've read the plain \TEX\ book, we provide the next %D macro: \unexpanded\def\bye {\writestatus\m!system{Sorry, you're not done yet, so no goodbye!}} %D We define a few constants because that (1) provides some checking %D and (2) is handier when aligning definitions (checks nicer). Most %D routines will use ard codes names but sometimes we want to adapt, %D which is why we have these: \definesystemconstant{page_otr_command_routine} \definesystemconstant{page_otr_command_package_contents} \definesystemconstant{page_otr_command_set_vsize} \definesystemconstant{page_otr_command_set_hsize} \definesystemconstant{page_otr_command_synchronize_hsize} \definesystemconstant{page_otr_command_next_page} \definesystemconstant{page_otr_command_next_page_and_inserts} \definesystemconstant{page_otr_command_set_top_insertions} \definesystemconstant{page_otr_command_set_bottom_insertions} \definesystemconstant{page_otr_command_flush_top_insertions} \definesystemconstant{page_otr_command_flush_bottom_insertions} \definesystemconstant{page_otr_command_check_if_float_fits} \definesystemconstant{page_otr_command_set_float_hsize} \definesystemconstant{page_otr_command_flush_float_box} \definesystemconstant{page_otr_command_side_float_output} \definesystemconstant{page_otr_command_synchronize_side_floats} \definesystemconstant{page_otr_command_flush_floats} \definesystemconstant{page_otr_command_flush_side_floats} \definesystemconstant{page_otr_command_flush_saved_floats} \definesystemconstant{page_otr_command_flush_all_floats} \definesystemconstant{page_otr_command_flush_margin_blocks} \definesystemconstant{page_otr_command_test_column} \definesystemconstant{singlecolumn} \definesystemconstant{multicolumn} % will move \definesystemconstant{columnset} % will move \definesystemconstant{pagecolumn} % will move \defineoutputroutinecommand [\s!page_otr_command_routine, \s!page_otr_command_package_contents, \s!page_otr_command_set_vsize, \s!page_otr_command_set_hsize, \s!page_otr_command_synchronize_hsize, % for columns of different width \s!page_otr_command_next_page, \s!page_otr_command_next_page_and_inserts, \s!page_otr_command_set_top_insertions, \s!page_otr_command_set_bottom_insertions, \s!page_otr_command_flush_top_insertions, \s!page_otr_command_flush_bottom_insertions, \s!page_otr_command_check_if_float_fits, \s!page_otr_command_set_float_hsize, \s!page_otr_command_flush_float_box, \s!page_otr_command_side_float_output, % name will change as will hooks \s!page_otr_command_synchronize_side_floats, \s!page_otr_command_flush_floats, \s!page_otr_command_flush_side_floats, \s!page_otr_command_flush_saved_floats, \s!page_otr_command_flush_all_floats, \s!page_otr_command_flush_margin_blocks, \s!page_otr_command_test_column] \appendtoks \setupoutputroutine[\s!singlecolumn]% \to \everydump \protect \endinput