summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/pack-com.mkxl
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/pack-com.mkxl')
-rw-r--r--tex/context/base/mkiv/pack-com.mkxl949
1 files changed, 949 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/pack-com.mkxl b/tex/context/base/mkiv/pack-com.mkxl
new file mode 100644
index 000000000..5b7a16359
--- /dev/null
+++ b/tex/context/base/mkiv/pack-com.mkxl
@@ -0,0 +1,949 @@
+%D \module
+%D [ file=pack-com, % used to be in core-mis,
+%D version=20120111,
+%D title=\CONTEXT\ Packing Macros,
+%D subtitle=Combinations,
+%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 Packaging Macros / Combinations}
+
+\unprotect
+
+% \startfloatcombination will be redone ... we can decouple the floatcontent
+% and caption and pass them to combinations so that we get better fit when the
+% caption is wider than the float, testcase:
+%
+% \startfloatcombination [2*2]
+% \placefigure[local]{alpha}{\externalfigure[cow.pdf][width=1cm]}%
+% \placefigure[local]{beta} {\externalfigure[cow.pdf][width=2cm]}%
+% \placefigure[local]{gamma}{\externalfigure[cow.pdf][width=3cm]}
+% \placefigure[local]{delta}{\externalfigure[cow.pdf][width=4cm]}
+% \stopfloatcombination
+
+%D We could of course map combinations onto one of the table mechanisms but as it
+%D has served us well for ages we keep this one. The code has been cleaned up a bit
+%D and mkiv'd.
+%D
+%D Okay ... I might luafy this one eventually.
+
+% \startcombination {alpha} {a} {beta} {b} \stopcombination
+% \startcombination[2*1] {alpha} {a} {beta} {b} \stopcombination
+% \startcombination[1*2] {alpha} {a} {beta} {b} \stopcombination
+% \startcombination[2] {alpha} {a} {beta} {b} \stopcombination
+% \startcombination[2] \combination {alpha} {a} \combination{beta} {b} \stopcombination
+
+%D We do support some structure but the order matters and currently it's only window
+%D dressing:
+
+%D \starttyping
+%D \let\startcontent\bgroup
+%D \let\stopcontent \egroup
+%D \let\startcaption\bgroup
+%D \let\stopcaption \egroup
+%D \stoptyping
+%D
+%D Of course we should have started with more structure as it would simply the code.
+%D
+%D \starttyping
+%D \startcombination
+%D \startcontent
+%D \externalfigure[cow]
+%D \stopcontent
+%D \startcaption
+%D Some cow.
+%D \stopcaption
+%D \startcontent
+%D \externalfigure[cow]
+%D \stopcontent
+%D \startcaption
+%D The same cow.
+%D \stopcaption
+%D \stopcombination
+%D \stoptyping
+
+\ifdefined\dotagcombination \else \let\dotagcombination\relax \fi
+
+\newsystemmode{combination}
+
+\appendtoks
+ \globalresetsystemmode{combination}%
+\to \everyinsidefloat
+
+\newcount\c_pack_combinations_nesting % local
+
+\newcount\c_pack_combinations_x % global
+\newcount\c_pack_combinations_y % global
+\newcount\c_pack_combinations_max % global
+
+\newdimen\d_pack_combinations_ht % global
+
+\newbox \b_pack_combinations_captions % global % can go
+\newbox \b_pack_combinations_temp % global % can go
+\newbox \b_pack_combinations_content % local
+\newbox \b_pack_combinations_caption % local
+
+\installcorenamespace{combination}
+
+\installcommandhandler \??combination {combination} \??combination
+
+\initializeboxstack{\??combination captions}
+\initializeboxstack{\??combination temp}
+
+\newcount\c_pack_combinations_x_saved
+\newcount\c_pack_combinations_y_saved
+\newcount\c_pack_combinations_max_saved
+
+\newdimen\d_pack_combinations_ht_saved
+
+\newbox \b_pack_combinations_captions_saved
+\newbox \b_pack_combinations_temp_saved
+\newbox \b_pack_combinations_content_saved
+\newbox \b_pack_combinations_caption_saved
+
+\setfalse\c_strc_constructions_define_commands
+
+\def\pack_combinations_push
+ {\advance\c_pack_combinations_nesting\plusone
+ \ifnum\c_pack_combinations_nesting>\plusone
+ \c_pack_combinations_x_saved \c_pack_combinations_x
+ \c_pack_combinations_y_saved \c_pack_combinations_y
+ \c_pack_combinations_max_saved\c_pack_combinations_max
+ \d_pack_combinations_ht_saved \d_pack_combinations_ht
+ \setbox\b_pack_combinations_captions_saved\box\b_pack_combinations_captions
+ \setbox\b_pack_combinations_temp_saved \box\b_pack_combinations_temp
+ \setbox\b_pack_combinations_content_saved \box\b_pack_combinations_content
+ \setbox\b_pack_combinations_caption_saved \box\b_pack_combinations_caption
+ \else
+ \globalsetsystemmode{combination}% why global
+ \fi}
+
+\def\pack_combinations_pop
+ {\ifnum\c_pack_combinations_nesting>\plusone
+ \global\c_pack_combinations_x \c_pack_combinations_x_saved
+ \global\c_pack_combinations_y \c_pack_combinations_y_saved
+ \global\c_pack_combinations_max\c_pack_combinations_max_saved
+ \global\d_pack_combinations_ht \d_pack_combinations_ht_saved
+ \global\setbox\b_pack_combinations_captions\box\b_pack_combinations_captions_saved
+ \global\setbox\b_pack_combinations_temp \box\b_pack_combinations_temp_saved
+ \setbox\b_pack_combinations_content \box\b_pack_combinations_content_saved
+ \setbox\b_pack_combinations_caption \box\b_pack_combinations_caption_saved
+ \else
+ \globalresetsystemmode{combination}% why global
+ \fi
+ \advance\c_pack_combinations_nesting\minusone}
+
+\definelabel
+ [\v!combination] % handy for configuring
+ [\c!numberconversion=\v!character,
+ \c!text=]
+
+\settrue\c_strc_constructions_define_commands
+
+\setupcombination
+ [\c!width=\v!fit,
+ \c!height=\v!fit,
+ \c!distance=\emwidth,
+ \c!location=\v!bottom, % can be something {top,left}
+ \c!before=\blank,
+ \c!after=,
+ \c!inbetween={\blank[\v!medium]},
+ %\c!style=,
+ %\c!color=,
+ \c!nx=2, % new
+ \c!ny=1, % new
+ \c!align=\v!middle]
+
+\let\setupcombinations\setupcombination % for the moment (we might distinguish)
+
+\installcorenamespace{combinationlocation}
+\installcorenamespace{combinationalternative}
+
+\appendtoks
+ \setfalse\c_strc_constructions_define_commands
+ \normalexpanded
+ {\definelabel
+ [\v!combination:\currentcombination]%
+ [\v!combination\ifx\currentcombinationparent\empty\else:\currentcombinationparent\fi]}%
+ [\s!counter=\currentcombination,\c!levels=1]%
+ \settrue\c_strc_constructions_define_commands
+\to \everydefinecombination
+
+\setvalue{\??combinationlocation\v!left }{\let\m_pack_combinations_leftfiller\relax}
+\setvalue{\??combinationlocation\v!right }{\let\m_pack_combinations_rightfiller\relax}
+\setvalue{\??combinationlocation\v!top }{\let\m_pack_combinations_valigner\depthonlybox}
+\setvalue{\??combinationlocation\v!middle}{\let\m_pack_combinations_valigner\halfwaybox}
+
+\def\pack_combinations_location_reset
+ {\let\m_pack_combinations_rightfiller\hfil
+ \let\m_pack_combinations_leftfiller \hfil
+ \let\m_pack_combinations_valigner \firstofoneargument}
+
+\pack_combinations_location_reset
+
+\def\pack_combinations_location_step#1%
+ {\csname\??combinationlocation#1\endcsname}
+
+% formally ok:
+%
+% \protected\def\stopcombination
+% {\egroup
+% \egroup}
+%
+% more robust:
+%
+% \protected\def\stopcombination
+% {{}{}{}{}{}{}{}{}% catches (at most 4) missing entries
+% \egroup
+% \egroup}
+%
+% even better:
+%
+% \protected\def\stopcombination
+% {\bgroup
+% \scratchtoks{{}}%
+% \dorecurse\c_pack_combinations_y
+% {\toksapp{{}{}}}%
+% \expandafter\egroup\the\scratchtoks
+% \egroup
+% \dostoptagged
+% \egroup}
+%
+% faster
+
+\protected\def\pack_common_content_start{\bgroup\ignorespaces}
+\protected\def\pack_common_content_stop {\removeunwantedspaces\egroup}
+\protected\def\pack_common_caption_start{\bgroup\ignorespaces}
+\protected\def\pack_common_caption_stop {\removeunwantedspaces\egroup}
+
+\newtoks\everycombination
+
+\protected\def\stopcombination
+ {\bgroup\normalexpanded{\egroup{}\ntimes{{}{}}\c_pack_combinations_y}% brr
+ \dostoptagged
+ \egroup
+ \pack_combinations_pop
+ \egroup}
+
+\permanent\tolerant\protected\def\startcombination[#1]#*[#2]% can be simplified
+ {\bgroup % so we can grab a group
+ \pack_combinations_push
+ \edef\currentcombination{#1}%
+ \edef\currentcombinationspec{#2}%
+ \ifx\currentcombinationspec\empty
+ \ifcondition\validassignment{#1}%
+ \let\currentcombination\empty
+ \setupcurrentcombination[#1]%
+ \edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}%
+ \else
+ \doifelseinstring{*}\currentcombination
+ {\edef\currentcombinationspec{\currentcombination*\plusone*}%
+ \let\currentcombination\empty}
+ {\doifelsenumber\currentcombination
+ {\edef\currentcombinationspec{\currentcombination*\plusone*}%
+ \let\currentcombination\empty}
+ {\edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}}%
+ \fi
+ \else
+ \ifcondition\validassignment{#2}%
+ \setupcurrentcombination[#2]%
+ \edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}%
+ \else
+ \edef\currentcombinationspec{\currentcombinationspec*\plusone*}%
+ \fi
+ \fi
+ %
+ \forgetall
+ %
+ \the\everycombination
+ %
+ \let\startcontent\pack_common_content_start
+ \let\stopcontent \pack_common_content_stop
+ \let\startcaption\pack_common_caption_start
+ \let\stopcaption \pack_common_caption_stop
+ %
+ \edef\p_height {\combinationparameter\c!height}%
+ \edef\p_width {\combinationparameter\c!width}%
+ \edef\p_location{\combinationparameter\c!location}%
+ \edef\p_distance{\combinationparameter\c!distance}%
+ %
+ \pack_combinations_location_reset
+ \rawprocesscommacommand[\p_location]\pack_combinations_location_step
+ %
+ \dostarttaggedchained\t!combination\currentcombination\??combination
+ \vbox \ifx\p_height\v!fit\else to \p_height \fi \bgroup
+ \let\combination\empty % permits \combination{}{} handy for cld
+ \normalexpanded{\pack_combinations_start_indeed[\currentcombinationspec]}}
+
+\let\pack_combinations_check_x_y\relax
+
+\protected\def\pack_combinations_start_indeed[#1*#2*#3]%
+ {\global\c_pack_combinations_x#1\relax
+ \global\c_pack_combinations_y#2\relax
+ \setexpandedcombinationparameter\c!nx{\the\c_pack_combinations_x}% in case we access it
+ \setexpandedcombinationparameter\c!ny{\the\c_pack_combinations_y}% in case we access it
+ \pack_combinations_check_x_y
+ \dotagcombination
+ \global\setbox\b_pack_combinations_captions\emptybox
+ \global\c_pack_combinations_max\c_pack_combinations_x
+ \multiply\c_pack_combinations_y\c_pack_combinations_x
+ \tabskip\zeropoint
+ \halign \ifx\p_width\v!fit\else to \p_width \fi \bgroup % repetitive preamble
+ \aligntab
+ \m_pack_combinations_leftfiller
+ \alignmark\alignmark
+ \m_pack_combinations_rightfiller
+ \aligntab
+ \tabskip\zeropoint \s!plus 1fill % \fillskip
+ \alignmark\alignmark
+ \cr
+ \pack_combinations_pickup}
+
+%D I've first considered using a constructor directly but it's more overhead and
+%D some settings conflict with already used combination settings so instead we plug
+%D in labels. This also permits extensions later on.
+
+\appendtoks
+ \edef\p_pack_combinations_alternative{\combinationparameter\c!alternative}%
+\to \everydefinecombination
+
+\def\pack_combinations_pickup
+ {\dostarttagged\t!combinationpair\empty % better make this text
+ \dostarttagged\t!combinationcontent\empty
+ \assumelongusagecs\pack_combinations_pickup_content_indeed}
+
+\def\pack_combinations_pickup_content_indeed
+ {\dowithnextboxcs\pack_combinations_pickup_content\hbox}
+
+\def\pack_combinations_pickup_content % we want to add struts but still ignore an empty box
+ {\dostoptagged
+ \setbox\b_pack_combinations_content\box\nextbox
+ \dostarttagged\t!combinationcaption\empty
+ \expandnamespacemacro\??combinationalternative\p_pack_combinations_alternative\v!text}
+
+\setvalue{\??combinationalternative\v!text}%
+ {\assumelongusagecs\pack_combinations_alternative_text_indeed}
+
+\setvalue{\??combinationalternative\v!label}%
+ {\assumelongusagecs\pack_combinations_alternative_label_indeed}
+
+\def\pack_combinations_alternative_text_indeed
+ {\dowithnextboxcs\pack_combinations_pickup_caption\vtop\bgroup
+ \afterassignment\pack_combinations_caption_first
+ \let\nexttoken=}
+
+\def\pack_combinations_alternative_label_indeed
+ {\dowithnextboxcs\pack_combinations_pickup_caption\vtop\bgroup
+ \hsize\wd\b_pack_combinations_content
+ \usealignparameter\combinationparameter
+ \usecombinationstyleandcolor\c!style\c!color
+ \begstrut
+ \normalexpanded{\strc_labels_command[\v!combination\ifx\currentcombination\empty\else:\currentcombination\fi]}%
+ \endstrut
+ \egroup}
+
+\appendtoks
+ \edef\p_pack_combinations_alternative{\combinationparameter\c!alternative}%
+ \ifx\p_pack_combinations_alternative\v!label
+ \edef\p_continue{\combinationparameter\c!continue}%
+ \ifx\p_continue\v!yes \else
+ \normalexpanded{\strc_labels_reset{\v!combination\ifx\currentcombination\empty\else:\currentcombination\fi}{1}}%
+ \fi
+ \fi
+\to \everycombination
+
+\def\pack_combinations_pickup_caption
+ {\dostoptagged
+ \dostoptagged
+ \setbox\b_pack_combinations_caption\box\nextbox
+ \pack_combinations_pickup_package_pair}
+
+\def\pack_combinations_caption_first
+ {\futurelet\nexttoken\pack_combinations_caption_second}
+
+\def\pack_combinations_caption_second
+ {\ifx\nexttoken\egroup
+ % the caption is empty
+ \orelse\ifx\nexttoken\stopcaption
+ % the caption is empty (new per 2014-05-24)
+ \else
+ % todo: \p_pack_combinations_alternative\v!none: no style, strut etc
+ \hsize\wd\b_pack_combinations_content
+ \usealignparameter\combinationparameter
+ \usecombinationstyleandcolor\c!style\c!color
+ \bgroup
+ \aftergroup\endstrut
+ \aftergroup\egroup
+ \begstrut
+ \fi}
+
+\def\pack_combinations_pickup_package_pair % we need to store the caption row
+ {\vbox
+ {\forgetall
+ \m_pack_combinations_valigner{\box\b_pack_combinations_content}%
+ % we need to save the caption for a next alignment line
+ \pack_combinations_save_caption}%
+ \ifnum\c_pack_combinations_y>\plusone
+ \global\advance\c_pack_combinations_y\minusone
+ \global\advance\c_pack_combinations_x\minusone
+ \ifcase\c_pack_combinations_x
+ \doubleexpandafter\pack_combinations_pickup_package_pair_a
+ \else
+ \doubleexpandafter\pack_combinations_pickup_package_pair_b
+ \fi
+ \else
+ \singleexpandafter\pack_combinations_pickup_package_pair_c
+ \fi}
+
+\def\pack_combinations_pickup_package_pair_a
+ {\cr
+ \pack_combinations_flush_captions
+ \noalign
+ {\forgetall
+ \global\setbox\b_pack_combinations_captions\emptybox
+ \nointerlineskip
+ \combinationparameter\c!after
+ \combinationparameter\c!before
+ \vss
+ \nointerlineskip}%
+ \global\c_pack_combinations_x\c_pack_combinations_max
+ \pack_combinations_pickup}
+
+\def\pack_combinations_pickup_package_pair_b
+ {\aligntab
+ \aligntab
+ \aligntab
+ \kern\p_distance
+ \aligntab
+ \pack_combinations_pickup}
+
+\def\pack_combinations_pickup_package_pair_c
+ {\cr
+ \pack_combinations_flush_captions
+ \egroup}
+
+\installcorenamespace{combinationcaption}
+
+\def\pack_combinations_save_caption
+ {\ifdim\htdp\b_pack_combinations_caption>\d_pack_combinations_ht
+ \global\d_pack_combinations_ht\htdp\b_pack_combinations_caption
+ \fi
+ \savebox{\??combinationcaption:\number\c_pack_combinations_nesting}{\number\c_pack_combinations_x}{\box\b_pack_combinations_caption}}
+
+\def\pack_combinations_flush_captions
+ {\noalign
+ {\ifdim\d_pack_combinations_ht>\zeropoint
+ \nointerlineskip % indeed
+ \combinationparameter\c!inbetween
+ \global\c_pack_combinations_x\c_pack_combinations_max
+ \glet\pack_combinations_flush_captions_indeed\pack_combinations_flush_captions_yes
+ \else
+ \glet\pack_combinations_flush_captions_indeed\pack_combinations_flush_captions_nop
+ \fi}%
+ \pack_combinations_flush_captions_indeed
+ \crcr}
+
+\def\pack_combinations_flush_captions_yes
+ {\vpack to \d_pack_combinations_ht\bgroup
+ \foundbox{\??combinationcaption:\number\c_pack_combinations_nesting}{\number\c_pack_combinations_x}%
+ \vss
+ \egroup
+ \global\advance\c_pack_combinations_x\minusone
+ \ifnum\c_pack_combinations_x>\zerocount % \c_pack_combinations_max
+ \expandafter\pack_combinations_flush_captions_yes_followup
+ \else
+ \global\d_pack_combinations_ht\zeropoint
+ \initializeboxstack{\??combinationcaption:\number-\c_pack_combinations_nesting}%
+ \fi}
+
+\let\pack_combinations_flush_captions_nop\donothing
+
+\def\pack_combinations_flush_captions_yes_followup
+ {\aligntab
+ \aligntab
+ \aligntab
+ \aligntab
+ \pack_combinations_flush_captions_indeed}
+
+%D \macros
+%D {startfloatcombination}
+%D
+%D \setupexternalfigures[directory={../sample}]
+%D \startbuffer
+%D \placefigure
+%D [left,none]
+%D {}
+%D {\startfloatcombination[2*2]
+%D \placefigure{alpha}{\externalfigure[cow.pdf][width=1cm]}
+%D \placefigure{beta} {\externalfigure[cow.pdf][width=2cm]}
+%D \placefigure{gamma}{\externalfigure[cow.pdf][width=3cm]}
+%D \placefigure{delta}{\externalfigure[cow.pdf][width=4cm]}
+%D \stopfloatcombination}
+%D
+%D \input tufte
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\protected\def\pack_combinations_float_hack_a#1%
+ {\strc_floats_build_box_separate_split{#1}%
+ \box\b_strc_floats_separate_content}
+
+\protected\def\pack_combinations_float_hack_b#1%
+ {\box\b_strc_floats_separate_caption}
+
+\permanent\tolerant\protected\def\startfloatcombination[#1]#*[#2]%
+ {\ifinsidefloat\else\dontleavehmode\fi % tricky, floatcombinations fail to align well otherwise
+ \vbox\bgroup
+ \strc_floats_build_box_separate_set
+ %\insidecolumnstrue % trick, forces no centering, todo: proper switch/feature
+ \postcenterfloatmethod\zerocount
+ \forcelocalfloats
+ \protected\def\stopfloatcombination{\pack_combinations_stop_float{#1}}}
+
+\let\stopfloatcombination\relax
+
+\def\pack_combinations_float_check_x_y
+ {\ifnum\numexpr\c_pack_combinations_x*\c_pack_combinations_y\relax<\noflocalfloats\relax
+ \global\c_pack_combinations_x\noflocalfloats
+ \global\c_pack_combinations_y\plusone
+ \fi
+ \let\pack_combinations_check_x_y\relax}%
+
+\def\pack_combinations_stop_float#1%
+ {\scratchtoks\emptytoks
+ \dorecurse\noflocalfloats
+ {\appendetoks
+ {\pack_combinations_float_hack_a{\recurselevel}}%
+ {\pack_combinations_float_hack_b{\recurselevel}}%
+ \to\scratchtoks}% brrr
+ \let\pack_combinations_check_x_y\pack_combinations_float_check_x_y
+ \expanded{\startcombination[#1]\the\scratchtoks}\stopcombination
+ \resetlocalfloats
+ \egroup}
+
+%D \macros
+%D {definepairedbox, setuppairedbox, placepairedbox}
+%D
+%D Paired boxes, formally called legends, but from now on a legend is just an
+%D instance, are primarily meant for typesetting some text alongside an
+%D illustration. Although there is quite some variation possible, the functionality
+%D is kept simple, if only because in most cases such pairs are typeset sober.
+%D
+%D The location specification accepts a pair, where the first keyword specifies the
+%D arrangement, and the second one the alignment. The first key of the location pair
+%D is one of \type {left}, \type {right}, \type {top} or \type {bottom}, while the
+%D second key can also be \type {middle}.
+%D
+%D The first box is just collected in an horizontal box, but the second one is a
+%D vertical box that gets passed the bodyfont and alignment settings.
+%D
+%D In many cases the table builders can be used instead, but as this mechanism is a
+%D traditional \CONTEXT\ one we keep it around.
+
+%D \macros
+%D {setuplegend, placelegend}
+%D
+%D It makes sense to typeset a legend to a figure in \TEX\ and not in a drawing
+%D package. The macro \type {\placelegend} combines a figure (or something else) and
+%D its legend. This command is just a paired box.
+%D
+%D The legend is placed according to \type {location}, being \type {bottom} or \type
+%D {right}. The macro macro is used as follows.
+%D
+%D \starttyping
+%D \placefigure
+%D {whow}
+%D {\placelegend
+%D {\externalfigure[cow]}
+%D {\starttabulate
+%D \NC 1 \NC head \NC \NR
+%D \NC 2 \NC legs \NC \NR
+%D \NC 3 \NC tail \NC \NR
+%D \stoptabulate}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend
+%D {\externalfigure[cow]}
+%D {\starttabulate[|l|l|l|l|]
+%D \NC 1 \NC head \NC 3 \NC tail \NC \NR
+%D \NC 2 \NC legs \NC \NC \NC \NR
+%D \stoptabulate}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2]
+%D {\externalfigure[cow]}
+%D {\starttabulate
+%D \NC 1 \NC head \NC \NR
+%D \NC 2 \NC legs \NC \NR
+%D \NC 3 \NC tail \NC \NR
+%D \stoptabulate}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2]
+%D {\externalfigure[cow]}
+%D {head \par legs \par tail}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2]
+%D {\externalfigure[cow]}
+%D {\startitemize[packed]
+%D \item head \item legs \item tail \item belly \item horns
+%D \stopitemize}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2,width=.8\hsize]
+%D {\externalfigure[cow]}
+%D {\startitemize[packed]
+%D \item head \item legs \item tail \item belly \item horns
+%D \stopitemize}}
+%D
+%D \def\MytTestTwo#1#2%
+%D {\placefigure
+%D {whow}
+%D {\placelegend[location={#1,#2}]
+%D {\externalfigure[cow]}
+%D {\starttabulate
+%D \NC 1 \NC head \NC \NR
+%D \NC 2 \NC legs \NC \NR
+%D \NC 3 \NC tail \NC \NR
+%D \stoptabulate}}}
+%D
+%D \def\MytTestOne#1{\processcommalist[left,right,top,bottom]{\MytTestTwo{#1}}}
+%D
+%D \processcommalist[left,right,top,bottom,middle]\MytTestOne
+%D \stoptyping
+%D
+%D More structure is also possible (the order matters!):
+%D
+%D \starttyping
+%D \startplacefigure[title=whow]
+%D \startplacelegend[location={bottom,middle},color=red]
+%D \startcontent
+%D \externalfigure[cow]
+%D \stopcontent
+%D \startcaption
+%D \starttabulate[|l|l|]
+%D \NC 1 \NC head \NC \NR
+%D \NC 2 \NC legs \NC \NR
+%D \NC 3 \NC tail \NC \NR
+%D \stoptabulate
+%D \stopcaption
+%D \stopplacelegend
+%D \stopplacefigure
+%D \stoptyping
+
+% todo: natural size
+
+\newsystemmode{pairedbox}
+
+\appendtoks
+ \globalresetsystemmode{pairedbox}%
+\to \everyinsidefloat
+
+\installcorenamespace {pairedbox}
+
+\installcommandhandler \??pairedbox {pairedbox} \??pairedbox
+
+\setuppairedbox
+ [\c!n=1,
+ \c!distance=\bodyfontsize,
+ %\c!before=,
+ %\c!after=,
+ %\c!color=,
+ %\c!style=,
+ \c!inbetween={\blank[\v!medium]},
+ \c!width=\hsize,
+ \c!height=\vsize,
+ \c!maxwidth=\textwidth, % \makeupwidth,
+ \c!maxheight=\textheight, % \makeupheight,
+ %\c!bodyfont=,
+ %\c!align=,
+ \c!location=\v!bottom]
+
+% watch the hsize/vsize tricks
+
+\newbox \b_pack_pairedboxes_first
+\newbox \b_pack_pairedboxes_second
+\newdimen\s_pack_pairedboxes_size
+
+\appendtoks
+ \setuevalue{\e!setup\currentpairedbox\e!endsetup}{\setuppairedbox [\currentpairedbox]}%
+ \setuevalue{\e!place\currentpairedbox }{\placepairedbox [\currentpairedbox]}% one argument is mandate anyway
+ \setuevalue{\e!start\e!place\currentpairedbox }{\startplacepairedbox[\currentpairedbox]}% one argument is mandate anyway
+ \setuevalue{\e!stop\e!place \currentpairedbox }{\stopplacepairedbox }%
+\to \everydefinepairedbox
+
+\permanent\tolerant\protected\def\startplacepairedbox[#1]#*[#2]%
+ {\bgroup
+ \edef\currentpairedbox{#1}%
+ \setupcurrentpairedbox[#2]%
+ \pairedboxparameter\c!before
+ \bgroup
+ \edef\p_location{\pairedboxparameter\c!location}%
+ \edef\p_n {\pairedboxparameter\c!n}%
+ %
+ \let\startcontent\pack_common_content_start
+ \let\stopcontent \pack_common_content_stop
+ \let\startcaption\pack_common_caption_start
+ \let\stopcaption \pack_common_caption_stop
+ %
+ \globalsetsystemmode{pairedbox}%
+ \pack_pairedboxes_before
+ \assumelongusagecs\pack_pairedboxes_first_pickup}
+
+\permanent\protected\def\stopplacepairedbox{} % we just pick up two boxes
+
+\let\placepairedbox\startplacepairedbox % we just pick up two boxes
+
+\def\pack_pairedboxes_first_pickup
+ {\dowithnextboxcs\pack_pairedboxes_first\hbox
+ \bgroup
+ \let\next=}
+
+\def\pack_pairedboxes_first
+ {\pack_pairedboxes_between
+ \assumelongusagecs\pack_pairedboxes_second_pickup}
+
+\def\pack_pairedboxes_second_pickup
+ {\dowithnextboxcs\pack_pairedboxes_second\vbox
+ \bgroup
+ \pack_pairedboxes_inside_second
+ \let\next=}
+
+\def\pack_pairedboxes_second
+ {\pack_pairedboxes_after
+ \egroup
+ \pairedboxparameter\c!after
+ \egroup}
+
+\newconditional\c_pack_pairedboxes_horizontal \settrue\c_pack_pairedboxes_horizontal
+
+\installcorenamespace{pairedboxnature}
+\installcorenamespace{pairedboxalign}
+
+\let\pack_pairedboxes_fill_top \relax
+\let\pack_pairedboxes_fill_bottom\relax
+
+\setvalue{\??pairedboxnature\v!left}%
+ {\settrue\c_pack_pairedboxes_horizontal
+ \let\pack_pairedboxes_flush\pack_pairedboxes_flush_left}
+
+\setvalue{\??pairedboxnature\v!right}%
+ {\settrue\c_pack_pairedboxes_horizontal
+ \let\pack_pairedboxes_flush\pack_pairedboxes_flush_right}
+
+\setvalue{\??pairedboxnature\v!top}%
+ {\setfalse\c_pack_pairedboxes_horizontal
+ \let\pack_pairedboxes_fill_top\relax
+ \let\pack_pairedboxes_fill_bottom\vss
+ \let\pack_pairedboxes_flush\pack_pairedboxes_flush_top}
+
+\setvalue{\??pairedboxnature\v!bottom}%
+ {\setfalse\c_pack_pairedboxes_horizontal
+ \let\pack_pairedboxes_fill_top\vss
+ \let\pack_pairedboxes_fill_bottom\relax
+ \let\pack_pairedboxes_flush\pack_pairedboxes_flush_bottom}
+
+\def\pack_pairedboxes_flush_left
+ {\box\b_pack_pairedboxes_second
+ \kern\pairedboxparameter\c!distance
+ \box\b_pack_pairedboxes_first}
+
+\def\pack_pairedboxes_flush_right
+ {\box\b_pack_pairedboxes_first
+ \kern\pairedboxparameter\c!distance
+ \box\b_pack_pairedboxes_second}
+
+\def\pack_pairedboxes_flush_top
+ {\box\b_pack_pairedboxes_second
+ \endgraf
+ \nointerlineskip
+ \pairedboxparameter\c!inbetween
+ \box\b_pack_pairedboxes_first}
+
+\def\pack_pairedboxes_flush_bottom
+ {\box\b_pack_pairedboxes_first
+ \endgraf
+ \nointerlineskip
+ \pairedboxparameter\c!inbetween
+ \box\b_pack_pairedboxes_second}
+
+\setvalue{\??pairedboxalign\v!left}% 0
+ {\let\pack_pairedboxes_align_l\relax
+ \let\pack_pairedboxes_align_r\hss
+ \let\pack_pairedboxes_align_t\relax
+ \let\pack_pairedboxes_align_b\relax}
+
+\setvalue{\??pairedboxalign\v!right}% 1
+ {\let\pack_pairedboxes_align_l\hss
+ \let\pack_pairedboxes_align_r\relax
+ \let\pack_pairedboxes_align_t\relax
+ \let\pack_pairedboxes_align_b\relax}
+
+\setvalue{\??pairedboxalign\v!high}% 2
+ {\let\pack_pairedboxes_align_l\relax
+ \let\pack_pairedboxes_align_r\relax
+ \let\pack_pairedboxes_align_t\relax
+ \let\pack_pairedboxes_align_b\vss}
+
+\setvalue{\??pairedboxalign\v!low}% 3
+ {\let\pack_pairedboxes_align_l\relax
+ \let\pack_pairedboxes_align_r\relax
+ \let\pack_pairedboxes_align_t\vss
+ \let\pack_pairedboxes_align_b\relax}
+
+\setvalue{\??pairedboxalign\v!middle}% 4
+ {\let\pack_pairedboxes_align_l\hss
+ \let\pack_pairedboxes_align_r\hss
+ \let\pack_pairedboxes_align_t\vss
+ \let\pack_pairedboxes_align_b\vss}
+
+\setvalue{\??pairedboxalign\v!bottom}{\getvalue{\??pairedboxalign\v!low }}
+\setvalue{\??pairedboxalign \v!top}{\getvalue{\??pairedboxalign\v!high}}
+
+\def\pack_pairedbox_valign#1{\setbox#1\vpack to \s_pack_pairedboxes_size{\pack_pairedboxes_align_t\box#1\pack_pairedboxes_align_b}}
+\def\pack_pairedbox_halign#1{\setbox#1\hpack to \s_pack_pairedboxes_size{\pack_pairedboxes_align_l\box#1\pack_pairedboxes_align_r}}
+
+\def\pack_pairedboxes_before
+ {\ifx\p_location\empty
+ \csname\??pairedboxnature\v!left \endcsname
+ \csname\??pairedboxalign \v!middle\endcsname
+ \else
+ \getfromcommacommand[\p_location][1]%
+ \csname\??pairedboxnature
+ \ifcsname\??pairedboxnature\commalistelement\endcsname\commalistelement\else\v!left\fi
+ \endcsname
+ \getfromcommacommand[\p_location][2]%
+ \csname\??pairedboxalign
+ \ifcsname\??pairedboxalign\commalistelement\endcsname\commalistelement\else\v!middle\fi
+ \endcsname
+ \fi}
+
+\def\pack_pairedboxes_between
+ {\usebodyfontparameter\pairedboxparameter
+ \setbox\b_pack_pairedboxes_first\box\nextbox
+ \ifconditional\c_pack_pairedboxes_horizontal
+ \pack_pairedboxes_between_horizontal
+ \else
+ \pack_pairedboxes_between_vertical
+ \fi
+ \ifnum\p_n>\plusone
+ \setrigidcolumnhsize\hsize{\pairedboxparameter\c!distance}\p_n
+ \fi}
+
+\def\pack_pairedboxes_between_horizontal
+ {\scratchdistance\pairedboxparameter\c!distance
+ \scratchwidth\pairedboxparameter\c!maxwidth\relax
+ \setlocalhsize
+ \hsize\dimexpr\availablehsize-\wd\b_pack_pairedboxes_first-\scratchdistance\relax
+ \hsize\pairedboxparameter\c!width\relax % can be \hsize
+ \scratchdimen\dimexpr\wd\b_pack_pairedboxes_first+\scratchdistance\relax
+ \ifdim\dimexpr\hsize+\scratchdimen\relax>\scratchwidth
+ \hsize\dimexpr\scratchwidth-\scratchdimen\relax
+ \fi}
+
+\def\pack_pairedboxes_between_vertical
+ {\scratchwidth\pairedboxparameter\c!maxwidth\relax
+ \hsize\wd\b_pack_pairedboxes_first
+ \hsize\pairedboxparameter\c!width\relax % can be \hsize
+ \ifdim\hsize>\scratchwidth\relax
+ \hsize\scratchwidth
+ \fi}
+
+\def\pack_pairedboxes_after
+ {\setbox\b_pack_pairedboxes_second\vpack
+ {\ifnum\p_n>\plusone
+ \rigidcolumnbalance\nextbox
+ \else
+ \box\nextbox
+ \fi}%
+ \ifconditional\c_pack_pairedboxes_horizontal
+ \pack_pairedboxes_pack_horizontal
+ \else
+ \pack_pairedboxes_pack_vertical
+ \fi}
+
+\def\pack_pairedboxes_pack_horizontal
+ {\dontleavehmode\hbox\bgroup
+ \forgetall
+ \s_pack_pairedboxes_size\ht
+ \ifdim\ht\b_pack_pairedboxes_first>\ht\b_pack_pairedboxes_second
+ \b_pack_pairedboxes_first
+ \else
+ \b_pack_pairedboxes_second
+ \fi
+ \vsize\s_pack_pairedboxes_size
+ \ifdim\s_pack_pairedboxes_size<\pairedboxparameter\c!height\relax % can be \vsize
+ \s_pack_pairedboxes_size\pairedboxparameter\c!height
+ \fi
+ \ifdim\s_pack_pairedboxes_size>\pairedboxparameter\c!maxheight\relax
+ \s_pack_pairedboxes_size\pairedboxparameter\c!maxheight
+ \fi
+ \pack_pairedbox_valign\b_pack_pairedboxes_first
+ \pack_pairedbox_valign\b_pack_pairedboxes_second
+ \pack_pairedboxes_flush
+ \egroup}
+
+\def\pack_pairedboxes_pack_vertical
+ {\dontleavehmode\vpack\bgroup
+ \forgetall
+ \s_pack_pairedboxes_size\wd
+ \ifdim\wd\b_pack_pairedboxes_first>\wd\b_pack_pairedboxes_second
+ \b_pack_pairedboxes_first
+ \else
+ \b_pack_pairedboxes_second
+ \fi
+ \pack_pairedbox_halign\b_pack_pairedboxes_first
+ \pack_pairedbox_halign\b_pack_pairedboxes_second
+ \s_pack_pairedboxes_size\ht\b_pack_pairedboxes_second
+ \vsize\s_pack_pairedboxes_size
+ \ifdim\ht\b_pack_pairedboxes_second<\pairedboxparameter\c!height\relax % can be \vsize
+ \s_pack_pairedboxes_size\pairedboxparameter\c!height\relax % \relax needed
+ \fi
+ \ifdim\s_pack_pairedboxes_size>\pairedboxparameter\c!maxheight\relax % todo: totale hoogte
+ \s_pack_pairedboxes_size\pairedboxparameter\c!maxheight\relax % \relax needed
+ \fi
+ \ifdim\s_pack_pairedboxes_size>\ht\b_pack_pairedboxes_second
+ \setbox\b_pack_pairedboxes_second\vpack to \s_pack_pairedboxes_size
+ {\pack_pairedboxes_fill_top
+ \box\b_pack_pairedboxes_second
+ \pack_pairedboxes_fill_bottom}% \kern\zeropoint
+ \fi
+ \pack_pairedboxes_flush
+ \egroup}
+
+\def\pack_pairedboxes_inside_second
+ {\forgetall
+ \setupalign[\pairedboxparameter\c!align]%
+ \usepairedboxstyleandcolor\c!style\c!color
+ \tolerantTABLEbreaktrue % hm.
+ \blank[\v!disable]% use fast one
+ \everypar{\begstrut}} % also flushers here (see bTABLE)
+
+\definepairedbox[\v!legend]
+
+\permanent\protected\def\placeontopofeachother{\bgroup\dowithnextboxcs\pack_topofeachother_one\hbox}
+\permanent\protected\def\placesidebyside {\bgroup\dowithnextboxcs\pack_sidebyside_one \hbox}
+
+\def\pack_topofeachother_one{\bgroup\setbox\scratchboxone\box\nextbox\dowithnextboxcs\pack_topofeachother_two\hbox}
+\def\pack_sidebyside_one {\bgroup\setbox\scratchboxone\box\nextbox\dowithnextboxcs\pack_sidebyside_two \hbox}
+
+\def\pack_topofeachother_two{\setbox\scratchboxtwo\box\nextbox
+ \halign{\hss\alignmark\alignmark\hss\cr\box\scratchboxone\cr\box\scratchboxtwo\cr}%
+ \egroup\egroup}
+\def\pack_sidebyside_two {\setbox\scratchboxtwo\box\nextbox
+ \valign{\vss\alignmark\alignmark\vss\cr\box\scratchboxone\cr\box\scratchboxtwo\cr}%
+ \egroup\egroup}
+
+\protect \endinput