diff options
Diffstat (limited to 'tex/context/base/mkiv/page-mix.mkxl')
-rw-r--r-- | tex/context/base/mkiv/page-mix.mkxl | 1092 |
1 files changed, 1092 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/page-mix.mkxl b/tex/context/base/mkiv/page-mix.mkxl new file mode 100644 index 000000000..20f4ff3ca --- /dev/null +++ b/tex/context/base/mkiv/page-mix.mkxl @@ -0,0 +1,1092 @@ +%D \module +%D [ file=page-mix, +%D version=2012.07.12, +%D title=\CONTEXT\ Page Macros, +%D subtitle=Mixed Columns, +%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 / Mixed Columns} + +%D This is a very experimental module. Eventually it will replace the current +%D multi column mechanism (that then will be an instance). The \LUA\ part of +%D the interface will quite probably change so don't use that one directly +%D (yet). + +% todo: +% +% consult note class +% notes per page +% notes in each column +% notes in last column +% notes local/global +% top and bottom inserts +% wide floats +% move floats +% offsets (inner ones, so we change the hsize ... needed with backgrounds +% when no content we currently loose the page + +% luatex buglet: +% +% \ctxlua{tex.setbox("global",0,node.hpack(nodes.pool.glyph("a",font.current())))}\box0 + +\registerctxluafile{page-mix}{} + +\unprotect + +%D The mixed output routine replaces the traditional multi column handler that +%D started out in \MKII. One of the complications of a routine is that it needs +%D to align nicely when mixed in a single column layout. Instead of using all +%D kind of shift juggling in this mechanism we simply switch to grid mode +%D locally. After all, columns don't look nice when not on a. As the grid +%D snapper in \MKIV\ is more advanced not that much extra code is needed. + +%D We use the command handler but the parent settings are not to be changed. +%D Instead we could have used a dedicated root setup, but it's not worth the +%D trouble. + +\installcorenamespace{mixedcolumns} + +\installframedcommandhandler \??mixedcolumns {mixedcolumns} \??mixedcolumns + +% old multicolumns mechanism +% +% \c!ntop=1, +% \c!rule=\v!off, : now separator=rule +% \c!height=, +% \c!blank={\v!line,\v!fixed}, +% \c!rulethickness=\linewidth, +% \c!offset=.5\bodyfontsize, + +\setupmixedcolumns + [\c!distance=1.5\bodyfontsize, + \c!n=\plustwo, + %\c!align=, % inherit (also replaces tolerance) + %\c!before=, + %\c!after=, + %\c!separator=\v!none, + %\c!setups=, + %\c!balance=\v!no, + %\c!blank={\v!line,\v!fixed}, yes or no + \c!frame=\v!off, + \c!strut=\v!no, + \c!offset=\v!overlay, + \c!alternative=\v!local, + \c!maxheight=\textheight, + \c!maxwidth=\makeupwidth, + \c!grid=\v!tolerant, + \c!internalgrid=\v!line, + \c!step=.25\lineheight, % needs some experimenting + %\c!splitmethod=\v!fixed, % will be default + \c!direction=\v!normal, % new (also todo in the new columnsets) + \c!notes=\v!yes, + \c!method=\ifinner\s!box\else\s!otr\fi] % automatic as suggested by WS + +\let\startmixedcolumns\relax % defined later +\let\stopmixedcolumns \relax % defined later + +\appendtoks % could become an option + \setuevalue{\e!start\currentmixedcolumns}{\startmixedcolumns[\currentmixedcolumns]}% + \setuevalue{\e!stop \currentmixedcolumns}{\stopmixedcolumns}% +\to \everydefinemixedcolumns + +%D In order to avoid a mixup we use quite some local registers. + +\newdimen \d_page_mix_column_width +\newdimen \d_page_mix_max_height +\newdimen \d_page_mix_max_width +\newdimen \d_page_mix_distance +\newcount \c_page_mix_n_of_columns +\newdimen \d_page_mix_threshold +\newdimen \d_page_mix_leftskip +\newdimen \d_page_mix_rightskip + +\newdimen \d_page_mix_balance_step +\setnewconstant\c_page_mix_balance_cycles 500 + +\setnewconstant\c_page_mix_break_forced -123 + +\newbox \b_page_mix_preceding +\newdimen \d_page_mix_preceding_height + +\newbox \b_page_mix_collected + +\newconstant \c_page_mix_routine + +\setnewconstant\c_page_mix_routine_regular \zerocount +\setnewconstant\c_page_mix_routine_intercept\plusone +\setnewconstant\c_page_mix_routine_continue \plustwo +\setnewconstant\c_page_mix_routine_balance \plusthree +\setnewconstant\c_page_mix_routine_error \plusfour + +\newconditional\c_page_mix_process_notes +\newconditional\c_page_mix_grid_snapping + +%D The main environment is called as follows: +%D +%D \starttyping +%D \startmixedcolumns[instance][settings] +%D \startmixedcolumns[instance] +%D \startmixedcolumns[settings] +%D \stoptyping +%D +%D However, best is not to use this one directly but define an instance and +%D use that one. + +% % For the moment only on my machine: +% +% \definemixedcolumns +% [\v!columns] +% +% \protected\def\setupcolumns +% {\setupmixedcolumns[\v!columns]} + +%D In itemizations we also need columns, so let's define a apecial instance +%D for them. These need to work well in situations like this: +%D +%D \starttyping +%D \input zapf +%D +%D \startnarrower +%D \startitemize[columns,two,packed][before=,after=] +%D \dorecurse{10}{\startitem item #1 \stopitem} +%D \stopitemize +%D \stopnarrower +%D +%D \input zapf +%D +%D \startnarrower +%D \startitemize[columns,two][before=,after=] +%D \dorecurse{10}{\startitem item #1 \stopitem} +%D \stopitemize +%D \stopnarrower +%D +%D \input zapf +%D +%D \startnarrower +%D \startitemize[columns,two] +%D \dorecurse{10}{\startitem item #1 \stopitem} +%D \stopitemize +%D \stopnarrower +%D +%D \input zapf +%D \stoptyping + +\ifdefined\s!itemgroupcolumns \else \def\s!itemgroupcolumns{itemgroupcolumns} \fi + +\definemixedcolumns + [\s!itemgroupcolumns] + [\c!n=\itemgroupparameter\c!n, + \c!direction=\itemgroupparameter\c!direction, + \c!separator=\v!none, + \c!splitmethod=\v!none, + \c!grid=\v!tolerant, + \c!internalgrid=\v!halfline, % new, we may still revert to \v!line + \c!balance=\v!yes, + \c!notes=\v!no] % kind of hidden + +% better + +\setupmixedcolumns + [\s!itemgroupcolumns] + [\c!splitmethod=\v!fixed, + \c!grid=\v!yes, + \c!internalgrid=\v!line] + +% even better: + +\setupitemgroup + [\c!grid=\v!tolerant:10] % 10 pct tolerance in columns snapping + +\setupmixedcolumns + [\s!itemgroupcolumns] + [\c!grid=\itemgroupparameter\c!grid] + +% the fast hooks: + +\protected\def\strc_itemgroups_start_columns + {\startmixedcolumns[\s!itemgroupcolumns]} % we could have a fast one + +\protected\def\strc_itemgroups_stop_columns + {\stopmixedcolumns} + +%D The mixed output routine can be in different states. First we need to intercept +%D the already present content. This permits mixed single and multi column usage. +%D Then we have the continuous routine, one that intercepts pages in sequence. +%D Finally, when we finish the mixed columns mode, we can (optionally) balance the +%D last page. + +\protected\def\page_mix_command_routine + {\ifcase\c_page_mix_routine + \page_one_command_routine + \or + \page_mix_routine_intercept + \or + \page_mix_routine_continue + \or + \page_mix_routine_balance + \or + \page_mix_routine_error + \fi} + +%D The interceptor is quite simple, at least for the moment. + +\def\page_mix_routine_intercept + {\ifdim\pagetotal>\pagegoal + % testcase: preceding-001 ... if we don't do this, text can disappear as + % preceding is overwritten ... needs to be figured out some day + \page_one_command_routine + \fi + \global\setbox\b_page_mix_preceding\vbox % pack ? + {\forgetall + \page_otr_command_flush_top_insertions + \ifdim\htdp\b_page_mix_preceding=\zeropoint \else + \writestatus\m!columns{preceding error}% + \unvbox\b_page_mix_preceding + \fi + \unvbox\normalpagebox}} + +%D The error routine is there but unlikely to be called. It is a left-over from +%D the traditional routine that might come in handy some day. + +\def\page_mix_construct_and_shipout#1#2#3% + {\ifconditional\c_page_mix_grid_snapping\else\gridsnappingfalse\fi % maybe only for notes (bottom alignment) + \page_otr_construct_and_shipout#1#2#3% + \ifconditional\c_page_mix_grid_snapping \gridsnappingtrue \fi} + + +\def\page_mix_routine_error + {\showmessage\m!columns3\empty + \page_mix_construct_and_shipout\unvbox\normalpagebox\zerocount} % three arguments + +%D Some settings (and actions) depend on the current output routine and setting the +%D hsize and vsize is among them. The calculation of the hsize is done elsewhere. + +\protected\def\page_mix_command_set_hsize + {\hsize\d_page_mix_column_width + \columnwidth\d_page_mix_column_width} + +%D When setting the vsize we make sure that we collect a few more lines than needed +%D so that we have enough to split over the columns. Collecting too much is somewhat +%D tricky as they will spill over to the next page. + +\protected\def\page_mix_command_set_vsize + {\vsize\dimexpr\c_page_mix_n_of_columns\textheight+\c_page_mix_n_of_columns\lineheight\relax + \pagegoal\dimexpr + \vsize +% -\d_page_floats_inserted_top % needs checking +% -\d_page_floats_inserted_bottom % needs checking + -\c_page_mix_n_of_columns\insertheights + \relax} + +%D As we use \LUA\ there is the usual amount of tracing at that end. At the tex end +%D we only visualize boxes. + +\let\page_mix_hbox\hbox +\let\page_mix_vbox\vbox + +\installtextracker + {mixedcolumns.boxes} + {\let\page_mix_hbox\ruledhbox + \let\page_mix_vbox\ruledvbox} + {\let\page_mix_hbox\hbox + \let\page_mix_vbox\vbox} + +%D We provide a few column break options. Interesting is that while forcing a new +%D column in the traditional mechanism was a pain, here it works quite well. + +\installcolumnbreakmethod \s!mixedcolumn \v!preference + {\goodbreak} + +\installcolumnbreakmethod \s!mixedcolumn \v!yes + {\par + \penalty\c_page_mix_break_forced\relax} + +%D As we operate in grid snapping mode, we use a dedicated macro to enable this +%D mechamism. + +\def\page_mix_enable_grid_snapping + {\edef\p_grid{\mixedcolumnsparameter\c!grid}% + \setfalse\c_page_mix_grid_snapping + \ifempty\p_grid + % just follow the default grid settings + \else + \ifgridsnapping\settrue\c_page_mix_grid_snapping\fi + \gridsnappingtrue + \setsystemmode\v!grid + \spac_grids_snap_value_set\p_grid + \fi} + +%D Between columns there is normally just spacing unless one enforces a rule. +%D +%D \starttyping +%D \input zapf +%D +%D \startnarrower +%D \startmixedcolumns[n=2,background=color,backgroundcolor=red,rulethickness=1mm,rulecolor=green,separator=rule] +%D \input zapf +%D \stopmixedcolumns +%D \stopnarrower +%D +%D \input zapf +%D \stoptyping + +\installcorenamespace{mixedcolumnsseparator} + +\protected\def\installmixedcolumnseparator#1#2% + {\setvalue{\??mixedcolumnsseparator#1}{#2}} + +\installmixedcolumnseparator\v!rule + {\vrule + \s!width \mixedcolumnsparameter\c!rulethickness + \s!height\mixedcolumnseparatorheight + \s!depth \mixedcolumnseparatordepth + \relax} + +\protected\def\page_mix_command_inject_separator + {\begingroup + \setbox\scratchbox\hbox to \zeropoint \bgroup + \hss + \starttextproperties + \usemixedcolumnscolorparameter\c!rulecolor + \begincsname\??mixedcolumnsseparator\p_separator\endcsname % was \c!rule + \stoptextproperties + \hss + \egroup + \ht\scratchbox\zeropoint + \dp\scratchbox\zeropoint + \hss + \box\scratchbox + \hss + \endgroup} + +%D We've now arrived at the real code. The start command mostly sets up the +%D environment and variables that are used in the splitter. One of the last +%D things happening at the start is switching over to the mixed continuous +%D routine. + +\installcorenamespace{mixedcolumnsbefore} +\installcorenamespace{mixedcolumnsstart} +\installcorenamespace{mixedcolumnsstop} +\installcorenamespace{mixedcolumnsafter} + +%D For practical reasons there is always a first argument needed that +%D indicates the class. +%D +%D \starttyping +%D \startmixedcolumns[n=3,alternative=global] +%D \dorecurse{200}{Zomaar wat #1 met een footnote\footnote{note #1}. } +%D \stopmixedcolumns +%D \stoptyping + +\let\currentmixedcolumnsmethod\empty + +\installmacrostack\currentmixedcolumns +\installmacrostack\currentmixedcolumnsmethod + +\protected\def\startmixedcolumns + {\dodoubleempty\page_mix_start_columns} + +\def\page_mix_start_columns_checked#1#2% + {\edef\currentmixedcolumnsmethod{\mixedcolumnsparameter\c!method}% + \ifx\currentmixedcolumnsmethod\v!box + \singleexpandafter#1% + \orelse\ifinsidecolumns + \doubleexpandafter#2% + \else + \doubleexpandafter#1% + \fi} + +\protected\def\page_mix_start_columns + {\push_macro_currentmixedcolumns + \push_macro_currentmixedcolumnsmethod + \ifsecondargument + \singleexpandafter\page_mix_start_columns_a + \orelse\iffirstargument + \doubleexpandafter\page_mix_start_columns_b + \else + \doubleexpandafter\page_mix_start_columns_c + \fi} + +\def\page_mix_start_columns_a[#1]% [#2]% + {\edef\currentmixedcolumns{#1}% + \page_mix_start_columns_checked + \page_mix_start_columns_a_yes + \page_mix_start_columns_a_nop} + +\def\page_mix_start_columns_a_yes[#1]% + {\mixedcolumnsparameter\c!before\relax + \begincsname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax + \begingroup + \setupcurrentmixedcolumns[#1]% + \page_mix_initialize_columns + \begincsname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname + \let\stopmixedcolumns\page_mix_columns_stop_yes} + +\def\page_mix_start_columns_a_nop[#1]% + {\begingroup + \let\stopmixedcolumns\page_mix_columns_stop_nop} + +\def\page_mix_start_columns_b[#1][#2]% + {\doifelseassignment{#1}% + {\let\currentmixedcolumns\empty + \page_mix_error_b} + {\edef\currentmixedcolumns{#1}% + \firstargumentfalse}% + \page_mix_start_columns_checked + \page_mix_start_columns_b_yes + \page_mix_start_columns_b_nop + [#1]} + +\def\page_mix_start_columns_b_yes[#1]% + {\mixedcolumnsparameter\c!before\relax % so, it doesn't listen to local settings ! + \begincsname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax + \begingroup + \iffirstargument + \setupcurrentmixedcolumns[#1]% + \fi + \page_mix_initialize_columns + \begincsname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname % no \relax + \let\stopmixedcolumns\page_mix_columns_stop_yes} + +\def\page_mix_start_columns_b_nop[#1]% + {\begingroup + \let\stopmixedcolumns\page_mix_columns_stop_nop} + +\def\page_mix_error_b + {\writestatus\m!columns{best use an instance of mixed columns}} + +\def\page_mix_start_columns_c[#1][#2]% + {\let\currentmixedcolumns\empty + \page_mix_start_columns_checked + \page_mix_start_columns_c_yes + \page_mix_start_columns_c_nop} + +\def\page_mix_start_columns_c_yes + {\mixedcolumnsparameter\c!before\relax + \begincsname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax + \begingroup + \page_mix_initialize_columns + \begincsname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname + \let\stopmixedcolumns\page_mix_columns_stop_yes} + +\def\page_mix_start_columns_c_nop + {\begingroup + \let\stopmixedcolumns\page_mix_columns_stop_nop} + +\protected\def\page_mix_fast_columns_start#1% + {\push_macro_currentmixedcolumns + \push_macro_currentmixedcolumnsmethod + \edef\currentmixedcolumns{#1}% + \edef\currentmixedcolumnsmethod{\mixedcolumnsparameter\c!method}% + \mixedcolumnsparameter\c!before\relax % so, it doesn't listen to local settings ! + \begincsname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax + \begingroup + \page_mix_initialize_columns + \begincsname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname % no \relax + \let\page_mix_fast_columns_stop\page_mix_columns_stop_yes} + +%D When we stop, we switch over to the balancing routine. After we're done we +%D make sure to set the sizes are set, a somewhat redundant action when we +%D already have flushed but better be safe. + +\let\page_mix_fast_columns_stop\relax + +\newtoks\t_page_mix_at_the_end + +\def\page_mix_finalize_columns + {\ifconditional\c_page_mix_process_notes \else + \global\t_page_mix_at_the_end{\stoppostponingnotes}% + \fi} + +\protected\def\page_mix_columns_stop_yes + {\begincsname\??mixedcolumnsstop\currentmixedcolumnsmethod\endcsname % no \relax + \page_mix_finalize_columns + \endgroup + \begincsname\??mixedcolumnsafter\currentmixedcolumnsmethod\endcsname\relax + \mixedcolumnsparameter\c!after\relax + \pop_macro_currentmixedcolumnsmethod + \pop_macro_currentmixedcolumns + \the\t_page_mix_at_the_end\global\t_page_mix_at_the_end\emptytoks} + +\protected\def\page_mix_columns_stop_nop + {\page_mix_finalize_columns + \endgroup + \pop_macro_currentmixedcolumnsmethod + \pop_macro_currentmixedcolumns + \the\t_page_mix_at_the_end\global\t_page_mix_at_the_end\emptytoks} + +% \protected\def\page_mix_columns_stop_yes +% {\begincsname\??mixedcolumnsstop \currentmixedcolumnsmethod\endcsname % no \relax +% \endgroup +% \begincsname\??mixedcolumnsafter\currentmixedcolumnsmethod\endcsname\relax +% \mixedcolumnsparameter\c!after\relax +% \ifx\currentmixedcolumnsmethod\s!otr +% \pop_macro_currentmixedcolumnsmethod +% \pop_macro_currentmixedcolumns +% \synchronizeoutput % brrr, otherwise sometimes issues in itemize +% \else +% \pop_macro_currentmixedcolumnsmethod +% \pop_macro_currentmixedcolumns +% \fi +% } + +%D This is how the fast one is used: + +\protected\def\strc_itemgroups_start_columns + {\page_mix_fast_columns_start\s!itemgroupcolumns} + +\protected\def\strc_itemgroups_stop_columns + {\page_mix_fast_columns_stop} % set by start + +% not used nor documented so commented: +% +% \setupmixedcolumns +% [\s!itemgroupcolumns] +% [\c!grid=\itemgroupparameter\c!grid] +% +% \setupitemgroup +% [\c!grid=\v!yes] % we need a value + +% better + +%D The common initialization: + +\def\page_mix_initialize_columns + {\page_mix_enable_grid_snapping + % + \d_page_mix_distance \mixedcolumnsparameter\c!distance + \c_page_mix_n_of_columns\mixedcolumnsparameter\c!n + \d_page_mix_max_height \mixedcolumnsparameter\c!maxheight + \d_page_mix_max_width \mixedcolumnsparameter\c!maxwidth + \d_page_mix_balance_step\mixedcolumnsparameter\c!step + % + \d_page_mix_max_width\dimexpr\d_page_mix_max_width-\leftskip-\rightskip\relax + \d_page_mix_leftskip \leftskip + \d_page_mix_rightskip\rightskip + \leftskip \zeropoint + \rightskip\zeropoint + % + \doifelse{\mixedcolumnsparameter\c!notes}\v!yes\settrue\setfalse\c_page_mix_process_notes + \ifconditional\c_page_mix_process_notes \else + \startpostponingnotes + \fi + % + \d_page_mix_threshold\zeropoint + % + \d_page_mix_column_width\dimexpr(\d_page_mix_max_width-\d_page_mix_distance*\numexpr(\c_page_mix_n_of_columns-\plusone)\relax)/\c_page_mix_n_of_columns\relax + % + \columnwidth \d_page_mix_column_width + \columndistance\d_page_mix_distance + \nofcolumns \c_page_mix_n_of_columns + \textwidth \d_page_mix_column_width % kind of redundant but we had it so ... + % + \usemixedcolumnscolorparameter\c!color + % + \insidecolumnstrue % new + % + \usealignparameter \mixedcolumnsparameter + \useblankparameter \mixedcolumnsparameter + \useprofileparameter\mixedcolumnsparameter % new + % + \nofcolumns\c_page_mix_n_of_columns} % public + +%D The otr method related hooks are defined next: + +% \setvalue{\??mixedcolumnsbefore\s!otr}% +% {\par +% \ifdim\pagetotal=\zeropoint \else +% \verticalstrut % probably no longer needed +% \vskip-\struttotal % probably no longer needed +% \fi} + +\newcount\c_page_mix_otr_nesting + +% \setvalue{\??mixedcolumnsbefore\s!otr}% +% {\par +% \global\advance\c_page_mix_otr_nesting\plusone +% \ifcase\c_page_mix_otr_nesting\or +% \ifdim\pagetotal=\zeropoint \else +% \obeydepth % we could handle this in pre material +% \fi +% \fi} + +\setvalue{\??mixedcolumnsbefore\s!otr}% + {\par + \global\advance\c_page_mix_otr_nesting\plusone + \ifcase\c_page_mix_otr_nesting\or + \ifdim\pagetotal=\zeropoint \else + % make sure that whitespace an dblanks are done + \strut + \vskip-\lineheight + % no, bad spacing: \obeydepth % we could handle this in pre material + \fi + \fi} + +\setvalue{\??mixedcolumnsstart\s!otr}% + {\ifcase\c_page_mix_otr_nesting\or + \scratchwidth\textwidth + \setupoutputroutine[\s!mixedcolumn]% + \c_page_mix_routine\c_page_mix_routine_intercept + \page_otr_trigger_output_routine + % + \holdinginserts\maxdimen + % + \ifvoid\b_page_mix_preceding \else + % moved here, before the packaging + \page_postprocessors_linenumbers_deepbox\b_page_mix_preceding + % we need to avoid unvboxing with successive balanced on one page + \global\setbox\b_page_mix_preceding\vpack{\box\b_page_mix_preceding}% + \wd\b_page_mix_preceding\scratchwidth % \makeupwidth + \page_grids_add_to_one\b_page_mix_preceding + \fi + \global\d_page_mix_preceding_height\ht\b_page_mix_preceding + \c_page_mix_routine\c_page_mix_routine_continue + % + \page_mix_command_set_vsize + \page_mix_command_set_hsize + \fi + \usealignparameter\mixedcolumnsparameter + \usesetupsparameter\mixedcolumnsparameter} + +% \setvalue{\??mixedcolumnsstop\s!otr}% +% {\par +% \ifcase\c_page_mix_otr_nesting\or +% \c_page_mix_routine\c_page_mix_routine_balance +% \page_otr_trigger_output_routine +% \fi} + +\setvalue{\??mixedcolumnsstop\s!otr}% + {\par + \ifcase\c_page_mix_otr_nesting\or + \doifelse{\mixedcolumnsparameter\c!balance}\v!yes + {\c_page_mix_routine\c_page_mix_routine_balance}% + {\penalty-\plustenthousand}% weird hack, we need to trigger the otr sometimes (new per 20140306, see balancing-001.tex) + \page_otr_trigger_output_routine + \ifvoid\b_page_mix_preceding \else + % empty columns so we need to make sure pending content is flushed + \unvbox\b_page_mix_preceding % new per 2014.10.25 + \fi + \fi} + +\setvalue{\??mixedcolumnsafter\s!otr}% + {\ifcase\c_page_mix_otr_nesting\or + \prevdepth\strutdp + \page_otr_command_set_vsize + \page_otr_command_set_hsize + \fi + \global\advance\c_page_mix_otr_nesting\minusone} + +%D The splitting and therefore balancing is done at the \LUA\ end. This gives +%D more readable code and also makes it easier to deal with insertions like +%D footnotes. Eventually we will have multiple strategies available. + +\protected\def\page_mix_routine_construct#1% + {\d_page_mix_max_height\mixedcolumnsparameter\c!maxheight % can have changed due to header=high + \ifconditional\c_page_mix_process_notes + \totalnoteheight\zeropoint + \else + \settotalinsertionheight + \fi + \clf_mixsetsplit + box \b_page_mix_collected + nofcolumns \c_page_mix_n_of_columns + maxheight \d_page_mix_max_height + noteheight \totalnoteheight + step \d_page_mix_balance_step + cycles \c_page_mix_balance_cycles + preheight \d_page_mix_preceding_height + prebox \b_page_mix_preceding + strutht \strutht + strutdp \strutdp + threshold \d_page_mix_threshold + splitmethod {\mixedcolumnsparameter\c!splitmethod}% + balance {#1}% + alternative {\mixedcolumnsparameter\c!alternative}% + internalgrid {\mixedcolumnsparameter\c!internalgrid}% + grid \ifgridsnapping tru\else fals\fi e % + notes \ifconditional\c_page_mix_process_notes tru\else fals\fi e % + \relax + \deadcycles\zerocount} + +\newdimen\mixedcolumnseparatorheight +\newdimen\mixedcolumnseparatordepth +\newdimen\mixedcolumnseparatorwidth + +\def\page_mix_routine_package_step + {% needs packaging anyway + \setbox\scratchbox\page_mix_command_package_column + \page_lines_add_numbers_to_box\scratchbox\recurselevel\c_page_mix_n_of_columns\plusone % new + \page_marks_synchronize_column\plusone\c_page_mix_n_of_columns\recurselevel\scratchbox + % backgrounds + \anch_mark_column_box\scratchbox\recurselevel + % for the moment a quick and dirty patch .. we need to go into the box (hence the \plusone) .. a slowdowner + % moved to start: \page_lines_add_numbers_to_box\scratchbox\recurselevel\c_page_mix_n_of_columns\plusone + % the framed needs a reset of strut, align, setups etc + \mixedcolumnseparatorheight\ht\scratchbox + \mixedcolumnseparatordepth \dp\scratchbox + \inheritedmixedcolumnsframedbox\currentmixedcolumns\scratchbox} + +\def\page_mix_routine_package_separate + {\ifcsname\??mixedcolumnsseparator\p_separator\endcsname + \page_mix_command_inject_separator + \else + \hss + \fi} + +\protected\def\page_mix_routine_package + {\clf_mixfinalize + \setbox\b_page_mix_collected\vbox \bgroup + \ifvoid\b_page_mix_preceding \else + % \page_postprocessors_linenumbers_deepbox\b_page_mix_preceding % already done + \vpack\bgroup + \box\b_page_mix_preceding + \egroup + \global\d_page_mix_preceding_height\zeropoint + \nointerlineskip + % no no: + % \prevdepth\strutdepth + \fi + \hskip\d_page_mix_leftskip + \page_mix_hbox to \d_page_mix_max_width \bgroup + \edef\p_separator{\mixedcolumnsparameter\c!separator}% + \mixedcolumnseparatorwidth\d_page_mix_distance % \mixedcolumnsparameter\c!rulethickness\relax + \edef\p_direction{\mixedcolumnsparameter\c!direction}% + \ifx\p_direction\v!reverse + \dostepwiserecurse\c_page_mix_n_of_columns\plusone\minusone + {\page_mix_routine_package_step + \ifnum\recurselevel>\plusone + \page_mix_routine_package_separate + \fi}% + \else + \dorecurse\c_page_mix_n_of_columns + {\page_mix_routine_package_step + \ifnum\recurselevel<\c_page_mix_n_of_columns + \page_mix_routine_package_separate + \fi}% + \fi + \egroup + \hskip\d_page_mix_rightskip + \egroup + \wd\b_page_mix_collected\dimexpr + \d_page_mix_max_width + +\d_page_mix_rightskip + +\d_page_mix_leftskip + \relax } + +\protected\def\page_mix_command_package_column + {\page_mix_hbox to \d_page_mix_column_width \bgroup + % maybe intercept empty + \clf_mixgetsplit\recurselevel\relax + \hskip-\d_page_mix_column_width + \vbox \bgroup + \hsize\d_page_mix_column_width + \ifconditional\c_page_mix_process_notes + \placenoteinserts + \fi + \egroup + \hss + \egroup} + +% \protected\def\page_mix_command_package_column +% {\page_mix_hbox to \d_page_mix_column_width \bgroup +% % maybe intercept empty +% \ruledhpack\bgroup +% \clf_mixgetsplit\recurselevel\relax +% \egroup +% \hskip-\d_page_mix_column_width +% \ruledhpack \bgroup +% \hsize\d_page_mix_column_width +% \ifconditional\c_page_mix_process_notes +% \placenoteinserts +% \fi +% \egroup +% \hss +% \egroup} + +\protected\def\page_mix_routine_continue + {\bgroup + \forgetall + \dontcomplain + \setbox\b_page_mix_collected\vpack{\unvbox\normalpagebox}% brrr we need to make a tight box (combine this in lua) + \page_mix_routine_construct\v!no + \page_mix_routine_package + \page_mix_construct_and_shipout\box\b_page_mix_collected\zerocount % three arguments + \clf_mixflushrest + \clf_mixcleanup + \egroup} + +\protected\def\page_mix_routine_balance + {\bgroup + \forgetall + \dontcomplain + \setbox\b_page_mix_collected\vpack{\unvbox\normalpagebox}% brrr we need to make a tight box (combine this in lua) + \doloop + {%writestatus\m!columns{construct continue (\the\htdp\b_page_mix_collected)}% + \page_mix_routine_construct\v!no + \ifcase\clf_mixstate\relax + % 0 = okay, we can balance + \setbox\b_page_mix_collected\vpack{\clf_mixflushlist}% we could avoid this + %writestatus\m!columns{construct balance}% + \page_mix_routine_construct\v!yes + \page_mix_routine_package + \c_page_mix_routine\c_page_mix_routine_regular + % \setupoutputroutine[\s!singlecolumn]% + \page_otr_command_set_vsize + \page_otr_command_set_hsize + \par + %writestatus\m!columns{flush balance}% + \page_grids_add_to_mix\b_page_mix_collected % no linenumbers here + \box\b_page_mix_collected + \vskip\zeropoint % triggers recalculation of page stuff (weird that this is needed but it *is* needed, see mixed-001.tex) + \par + \nointerlineskip + \prevdepth\strutdp + \clf_mixflushrest% rubish + \clf_mixcleanup % rubish + \exitloop + \or + % 1 = we have stuff left, so flush and rebalance + %writestatus\m!columns{flush continue}% + \page_mix_routine_package + \page_mix_construct_and_shipout\box\b_page_mix_collected\zerocount % three arguments + \setbox\b_page_mix_collected\vpack{\clf_mixflushrest}% we could avoid this + \clf_mixcleanup + \ifdim\ht\b_page_mix_collected=\zeropoint + \exitloop + \fi + \fi}% + \egroup} + +%D We also implement a variant compatible with the so called simple columns +%D mechanism: +%D +%D \starttyping +%D \startboxedcolumns +%D \input zapf +%D \stopboxedcolumns +%D \stoptyping +%D +%D This is a rather mininimalistic variant. + +% Maybe we also need a variant with obeydepth before and prevdepth after so +% that we get a nice spacing. + +\definemixedcolumns + [boxedcolumns] + [\c!balance=\v!yes, + \c!n=2, + \c!method=\s!box, + \c!strut=\v!yes, + \c!maxwidth=\availablehsize] + +%D Boxed columns can be used nested: +%D +%D \starttyping +%D \setupmixedcolumns +%D [boxedcolumns] +%D [n=2, +%D background=color, +%D backgroundcolor=darkred, +%D color=white, +%D backgroundoffset=1mm] +%D +%D \definemixedcolumns +%D [nestedboxedcolumns] +%D [boxedcolumns] +%D [n=2, +%D background=color, +%D backgroundcolor=white, +%D color=darkred, +%D strut=yes, +%D backgroundoffset=0mm] +%D +%D \startboxedcolumns +%D \input zapf \par \input ward \par \obeydepth +%D \startnestedboxedcolumns +%D \input zapf +%D \stopnestedboxedcolumns +%D \par \input zapf \par \obeydepth +%D \startnestedboxedcolumns +%D \input zapf +%D \stopnestedboxedcolumns +%D \par \input zapf +%D \stopboxedcolumns +%D \stoptyping + +%D Next we define the hooks: + +\letvalue{\??mixedcolumnsbefore\s!box}\donothing +\letvalue{\??mixedcolumnsafter \s!box}\donothing + +\setvalue{\??mixedcolumnsstart\s!box}% + {\edef\p_page_mix_strut{\mixedcolumnsparameter\c!strut}% + \setbox\b_page_mix_collected\vbox \bgroup + \let\currentoutputroutine\s!mixedcolumn % makes \column work + \forgetall + \usegridparameter\mixedcolumnsparameter + % \useprofileparameter\mixedcolumnsparameter + \page_mix_command_set_hsize + \ifx\p_page_mix_strut\v!yes + \begstrut + \ignorespaces + \fi} + +\setvalue{\??mixedcolumnsstop\s!box}% + {\ifx\p_page_mix_strut\v!yes + \removeunwantedspaces + \endstrut + \fi + \egroup + \edef\p_profile{\mixedcolumnsparameter\c!profile}% + \ifempty\p_profile \else + % this can never be ok because we cheat with depth and height + % and glue in between and when we're too large we run into issues + % so mayb best limit correction to one line + \profilegivenbox\p_profile\b_page_mix_collected + \setbox\b_page_mix_collected\vpack{\unvbox\b_page_mix_collected}% + % tracing + % \addprofiletobox\b_page_mix_collected + \fi + \page_mix_box_balance} + +%D The related balancer is only a few lines: + +\protected\def\page_mix_box_balance + {\bgroup + \dontcomplain + \page_mix_routine_construct\v!yes + \page_mix_routine_package + \dontleavehmode\box\b_page_mix_collected + \clf_mixflushrest + \clf_mixcleanup + \egroup} + +%D As usual, floats complicates matters and this is where experimental code +%D starts. + +\let\page_mix_command_package_contents\page_one_command_package_contents +\let\page_mix_command_flush_float_box \page_one_command_flush_float_box + +\protected\def\page_mix_command_check_if_float_fits + {\ifpostponecolumnfloats + \global\setfalse\c_page_floats_room + \orelse\ifconditional\c_page_floats_not_permitted + \global\setfalse\c_page_floats_room + \else +% \bgroup +% \getcolumnstatus{\count255}{\dimen0}{\dimen2}% +% \page_floats_get_info\s!text +% \setbox\scratchbox\vbox % tricky met objecten ? +% {\blank[\rootfloatparameter\c!spacebefore] +% \snaptogrid\vbox{\vskip\floatheight}}% copy? +% \advance\dimen0\dimexpr\ht\scratchbox+2\openlineheight+.5\lineheight\relax\relax % needed because goal a bit higher +% \ifdim\dimen0>\dimen2 +% \global\setfalse\c_page_floats_room +% \else + \global\settrue\c_page_floats_room + \fi + \ifdim\floatwidth>\hsize + \showmessage\m!columns{11}\empty + \global\setfalse\c_page_floats_room + \fi} + +\protected\def\page_mix_command_flush_floats + {\page_one_command_flush_floats} + +\protected\def\page_mix_command_flush_saved_floats + {\page_one_command_flush_saved_floats} + +% \protected\def\page_mix_command_flush_top_insertions +% {\page_one_command_flush_top_insertions} + +\protected\def\page_mix_place_float_top + {\showmessage\m!columns4\empty\page_one_place_float_here} + +\protected\def\page_mix_place_float_bottom + {\showmessage\m!columns5\empty\page_one_place_float_here} + +\protected\def\page_mix_place_float_here + {\page_one_place_float_here} + +\protected\def\page_mix_place_float_force + {\page_one_place_float_force} + +\protected\def\page_mix_command_side_float_output + {\page_mix_construct_and_shipout\unvbox\normalpagebox\zerocount} % three arguments + +\protected\def\page_mix_command_synchronize_side_floats + {\page_sides_forget_floats} + +\protected\def\page_mix_command_flush_side_floats + {\page_sides_forget_floats} + +\protected\def\page_mix_command_next_page + {\page_otr_eject_page} + +\protected\def\page_mix_command_next_page_and_inserts + {\page_otr_eject_page_and_flush_inserts} + +%D Moved here and dedicated: + +\protected\def\page_mix_command_test_column + {\dodoubleempty\page_mix_command_test_column_indeed} + +\protected\def\page_mix_command_test_column_indeed[#1][#2]% works on last column + {\par + \begingroup + \scratchdimen\dimexpr#1\lineheight\ifsecondargument+#2\fi\relax + \ifdim\scratchdimen>\zeropoint + \c_attr_checkedbreak\number\scratchdimen % why \number + \penalty\c_page_mix_break_forced\relax + \fi + \endgroup} + +%D We need to hook some handlers into the output routine and we define +%D a dedicated one: + +\let\page_mix_command_flush_all_floats\page_one_command_flush_all_floats + +\defineoutputroutine + [\s!mixedcolumn] + [\s!page_otr_command_routine =\page_mix_command_routine, + \s!page_otr_command_package_contents =\page_mix_command_package_contents, + \s!page_otr_command_set_vsize =\page_mix_command_set_vsize, + \s!page_otr_command_set_hsize =\page_mix_command_set_hsize, + % \s!page_otr_command_synchronize_hsize =\page_mix_command_synchronize_hsize, + \s!page_otr_command_next_page =\page_mix_command_next_page, + \s!page_otr_command_next_page_and_inserts =\page_mix_command_next_page_and_inserts, + % \s!page_otr_command_set_top_insertions =\page_mix_command_set_top_insertions, + % \s!page_otr_command_set_bottom_insertions =\page_mix_command_set_bottom_insertions, + % \s!page_otr_command_flush_top_insertions =\page_mix_command_flush_top_insertions, + % \s!page_otr_command_flush_bottom_insertions=\page_mix_command_flush_bottom_insertions, + \s!page_otr_command_check_if_float_fits =\page_mix_command_check_if_float_fits, + % \s!page_otr_command_set_float_hsize =\page_mix_command_set_float_hsize, + \s!page_otr_command_flush_float_box =\page_mix_command_flush_float_box, + \s!page_otr_command_side_float_output =\page_mix_command_side_float_output, + \s!page_otr_command_synchronize_side_floats=\page_mix_command_synchronize_side_floats, + \s!page_otr_command_flush_floats =\page_mix_command_flush_floats, + \s!page_otr_command_flush_side_floats =\page_mix_command_flush_side_floats, + \s!page_otr_command_flush_saved_floats =\page_mix_command_flush_saved_floats, + \s!page_otr_command_flush_all_floats =\page_mix_command_flush_all_floats, + % \s!page_otr_command_flush_margin_blocks =\page_mix_command_flush_margin_blocks, % not used + \s!page_otr_command_test_column =\page_mix_command_test_column + ] + +%D Only a few float placement options are supported: + +\installfloatmethod \s!mixedcolumn \v!here \page_mix_place_float_here +\installfloatmethod \s!mixedcolumn \v!force \page_mix_place_float_force +\installfloatmethod \s!mixedcolumn \v!top \page_mix_place_float_top +\installfloatmethod \s!mixedcolumn \v!bottom \page_mix_place_float_bottom + +\installfloatmethod \s!mixedcolumn \v!local \somelocalfloat + +%D It ends here. + +\protect \endinput |