summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/pack-com.mkiv
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/pack-com.mkiv')
-rw-r--r--tex/context/base/mkiv/pack-com.mkiv945
1 files changed, 945 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/pack-com.mkiv b/tex/context/base/mkiv/pack-com.mkiv
new file mode 100644
index 000000000..623d669e7
--- /dev/null
+++ b/tex/context/base/mkiv/pack-com.mkiv
@@ -0,0 +1,945 @@
+%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
+%D mechanisms but as it has served us well for ages we keep
+%D this one. The code has been cleaned up a bit 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
+%D only window dressing:
+%D
+%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
+%D 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
+ \global\resetsystemmode{combination}%
+\to \everyinsidefloat
+
+\newcount\c_pack_combinations_nesting % local
+\newcount\c_pack_combinations_x % global
+\newcount\c_pack_combinations_n % global
+\newcount\c_pack_combinations_max % global
+\newbox \b_pack_combinations_captions % global
+\newbox \b_pack_combinations_temp % global
+\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_n_saved
+\newcount\c_pack_combinations_max_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_n_saved \c_pack_combinations_n
+ \c_pack_combinations_max_saved\c_pack_combinations_max
+ \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
+ \global\setsystemmode{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_n \c_pack_combinations_n_saved
+ \global\c_pack_combinations_max\c_pack_combinations_max_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
+ \global\resetsystemmode{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}
+
+\unexpanded\def\startcombination
+ {\bgroup % so we can grab a group
+ \pack_combinations_push
+ \dodoubleempty\pack_combinations_start}
+
+% formally ok:
+%
+% \unexpanded\def\stopcombination
+% {\egroup
+% \egroup}
+%
+% more robust:
+%
+% \unexpanded\def\stopcombination
+% {{}{}{}{}{}{}{}{}% catches (at most 4) missing entries
+% \egroup
+% \egroup}
+%
+% even better:
+%
+% \unexpanded\def\stopcombination
+% {\bgroup
+% \scratchtoks{{}}%
+% \dorecurse\c_pack_combinations_n
+% {\scratchtoks\expandafter{\the\scratchtoks{}{}}}%
+% \expandafter\egroup\the\scratchtoks
+% \egroup
+% \dostoptagged
+% \egroup}
+%
+% faster
+
+\unexpanded\def\pack_common_content_start{\bgroup\ignorespaces}
+\unexpanded\def\pack_common_content_stop {\removeunwantedspaces\egroup}
+\unexpanded\def\pack_common_caption_start{\bgroup\ignorespaces}
+\unexpanded\def\pack_common_caption_stop {\removeunwantedspaces\egroup}
+
+\unexpanded\def\stopcombination
+ {\bgroup\normalexpanded{\egroup{}\ntimes{{}{}}\c_pack_combinations_n}% brr
+ \dostoptagged
+ \egroup
+ \pack_combinations_pop
+ \egroup}
+
+\newtoks\everycombination
+
+\def\pack_combinations_start[#1][#2]% needs a cleanup, also nx ny (pretty old, this one)
+ {\edef\currentcombination{#1}%
+ \edef\currentcombinationspec{#2}%
+ \ifx\currentcombinationspec\empty
+ \doifelseassignment{#1}%
+ {\let\currentcombination\empty
+ \setupcurrentcombination[#1]%
+ \edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}
+ {\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*}}}}%
+ \else
+ \doifelseassignment{#2}%
+ {\setupcurrentcombination[#2]%
+ \edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}
+ {\edef\currentcombinationspec{\currentcombinationspec*\plusone*}}%
+ \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]}}
+
+\unexpanded\def\pack_combinations_start_indeed[#1*#2*#3]%
+ {\global\c_pack_combinations_x#1\relax
+ \global\c_pack_combinations_n#2\relax
+ \dotagcombination
+ \global\setbox\b_pack_combinations_captions\emptybox
+ \global\c_pack_combinations_max\c_pack_combinations_x
+ \multiply\c_pack_combinations_n\c_pack_combinations_x
+ \tabskip\zeropoint
+ \halign \ifx\p_width\v!fit\else to \p_width \fi \bgroup
+ \aligntab
+ \m_pack_combinations_leftfiller
+ \alignmark\alignmark
+ \m_pack_combinations_rightfiller
+ \aligntab
+ \tabskip\zeropoint \s!plus 1fill
+ \alignmark\alignmark
+ \cr
+ \pack_combinations_pickup}
+
+% \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
+% \dowithnextboxcs\pack_combinations_pickup_caption\vtop\bgroup
+% \afterassignment\pack_combinations_caption_first
+% \let\nexttoken=}
+
+% I've first considered using a constructor directly but it's more overhead
+% and some settings conflict with already used combination settings so instead
+% we plug 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
+ \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
+ \else\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\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_n>\plusone
+ \global\advance\c_pack_combinations_n\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}
+
+\def\pack_combinations_save_caption
+ {\global\setbox\b_pack_combinations_captions\hpack
+ {\hpack{\box\b_pack_combinations_caption}%
+ \unhbox\b_pack_combinations_captions}}
+
+\def\pack_combinations_flush_captions
+ {\noalign
+ {\ifdim\ht\b_pack_combinations_captions>\zeropoint
+ \nointerlineskip % indeed
+ \combinationparameter\c!inbetween
+ \global\c_pack_combinations_x\c_pack_combinations_max
+ \globallet\pack_combinations_flush_captions_indeed\pack_combinations_flush_captions_yes
+ \else
+ \global\setbox\b_pack_combinations_captions\emptybox
+ \globallet\pack_combinations_flush_captions_indeed\pack_combinations_flush_captions_nop
+ \fi}%
+ \pack_combinations_flush_captions_indeed
+ \crcr}
+
+\def\pack_combinations_flush_captions_yes
+ {\global\setbox\b_pack_combinations_captions\hpack
+ {\unhbox\b_pack_combinations_captions
+ \global\setbox\b_pack_combinations_temp\lastbox}%
+ \box\b_pack_combinations_temp
+ \global\advance\c_pack_combinations_x\minusone\relax
+ \ifnum\c_pack_combinations_x>\zerocount
+ \expandafter\pack_combinations_flush_captions_yes_followup
+ \else
+ \global\setbox\b_pack_combinations_captions\emptybox
+ \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
+
+\unexpanded\def\startfloatcombination
+ {\dodoubleempty\pack_combinations_start_float}
+
+\let\stopfloatcombination\relax
+
+\def\pack_combinations_start_float[#1][#2]%
+ {\vbox\bgroup
+ %\insidecolumnstrue % trick, forces no centering, todo: proper switch/feature
+ \postcenterfloatmethod\zerocount
+ \forcelocalfloats
+ \unexpanded\def\stopfloatcombination{\pack_combinations_stop_float{#1}}}
+
+\def\pack_combinations_stop_float#1%
+ {\scratchtoks\emptytoks
+ \dorecurse\noflocalfloats
+ {\appendetoks{\noexpand\getlocalfloat{\recurselevel}}{}\to\scratchtoks}% brrr
+ \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
+%D legend is just an instance, are primarily meant for
+%D typesetting some text alongside an illustration. Although
+%D there is quite some variation possible, the functionality is
+%D kept simple, if only because in most cases such pairs are
+%D typeset sober.
+%D
+%D The location specification accepts a pair, where the first
+%D keyword specifies the arrangement, and the second one the
+%D alignment. The first key of the location pair is one of
+%D \type {left}, \type {right}, \type {top} or \type {bottom},
+%D while the second key can also be \type {middle}.
+%D
+%D The first box is just collected in an horizontal box, but
+%D the second one is a vertical box that gets passed the
+%D bodyfont and alignment settings.
+
+%D In many cases the table builders can be used instead, but as
+%D this mechanism is a traditional \CONTEXT\ one we keep it
+%D around.
+
+%D \macros
+%D {setuplegend, placelegend}
+%D
+%D It makes sense to typeset a legend to a figure in \TEX\
+%D and not in a drawing package. The macro \type {\placelegend}
+%D combines a figure (or something else) and its legend. This
+%D command is just a paired box.
+%D
+%D The legend is placed according to \type {location}, being
+%D \type {bottom} or \type {right}. The macro macro is used as
+%D 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
+ \global\resetsystemmode{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
+
+\unexpanded\def\placepairedbox[#1]%
+ {\bgroup
+ \edef\currentpairedbox{#1}%
+ \doifelsenextoptionalcs\pack_pairedboxes_place\pack_pairedboxes_place_indeed}
+
+\unexpanded\def\startplacepairedbox[#1]%
+ {\bgroup
+ \edef\currentpairedbox{#1}%
+ \doifelsenextoptionalcs\pack_pairedboxes_place\pack_pairedboxes_place_indeed}
+
+\unexpanded\def\stopplacepairedbox
+ {}
+
+\def\pack_pairedboxes_place[#1]%
+ {\setupcurrentpairedbox[#1]%
+ \pack_pairedboxes_place_indeed}
+
+\def\pack_pairedboxes_place_indeed
+ {\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
+ %
+ \global\setsystemmode{pairedbox}%
+ \pack_pairedboxes_before
+ \assumelongusagecs\pack_pairedboxes_first_pickup}
+
+\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
+% {\setlocalhsize
+% \hsize\wd\b_pack_pairedboxes_first % trick
+% \hsize\pairedboxparameter\c!width % can be \hsize
+% \scratchdimen\dimexpr\wd\b_pack_pairedboxes_first+\pairedboxparameter\c!distance\relax
+% \ifdim\dimexpr\hsize+\scratchdimen\relax>\pairedboxparameter\c!maxwidth\relax
+% \hsize\dimexpr\pairedboxparameter\c!maxwidth-\scratchdimen\relax
+% \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]
+
+\unexpanded\def\placeontopofeachother{\bgroup\dowithnextboxcs\pack_topofeachother_one\hbox}
+\unexpanded\def\placesidebyside {\bgroup\dowithnextboxcs\pack_sidebyside_one \hbox}
+
+\def\pack_topofeachother_one{\bgroup\setbox0\box\nextbox\dowithnextboxcs\pack_topofeachother_two\hbox}
+\def\pack_sidebyside_one {\bgroup\setbox0\box\nextbox\dowithnextboxcs\pack_sidebyside_two \hbox}
+
+\def\pack_topofeachother_two{\setbox2\box\nextbox\halign{\hss##\hss\cr\box0\cr\box2\cr}\egroup\egroup}
+\def\pack_sidebyside_two {\setbox2\box\nextbox\valign{\vss##\vss\cr\box0\cr\box2\cr}\egroup\egroup}
+
+\protect \endinput