%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 \aliased\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\ifempty\currentcombinationparent\else:\currentcombinationparent\fi]}% [\s!counter=\currentcombination,\c!levels=1]% \settrue\c_strc_constructions_define_commands \to \everydefinecombination \defcsname\??combinationlocation\v!left \endcsname{\let\m_pack_combinations_leftfiller \relax} \defcsname\??combinationlocation\v!right \endcsname{\let\m_pack_combinations_rightfiller\relax} \defcsname\??combinationlocation\v!top \endcsname{\let\m_pack_combinations_valigner \depthonlybox} \defcsname\??combinationlocation\v!middle\endcsname{\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 \ifdefined\startcontent \else \aliased\let\startcontent\relax \fi \ifdefined\stopcontent \else \aliased\let\stopcontent \relax \fi \ifdefined\startcaption \else \aliased\let\startcaption\relax \fi \ifdefined\stopcaption \else \aliased\let\stopcaption \relax \fi \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 \aliased\let\combination\empty \let\p_nx_ny\empty % \permanent\tolerant\protected\def\startcombination[#1]#*[#2]% can be simplified % {\bgroup % so we can grab a group % \pack_combinations_push % \edef\currentcombination{#1}% % \edef\p_nx_ny{#2}% % % % \ifempty\p_nx_ny % \ifcondition\validassignment{#1}% % \let\currentcombination\empty % \setupcurrentcombination[#1]% % \edef\p_nx_ny{\combinationparameter\c!nx*\combinationparameter\c!ny*}% % \else % \doifelseinstring{*}\currentcombination % {\edef\p_nx_ny{\currentcombination*\plusone*}% % \let\currentcombination\empty} % {\doifelsenumber\currentcombination % {\edef\p_nx_ny{\currentcombination*\plusone*}% % \let\currentcombination\empty} % {\edef\p_nx_ny{\combinationparameter\c!nx*\combinationparameter\c!ny*}}}% % \fi % \else % \ifcondition\validassignment{#2}% % \setupcurrentcombination[#2]% % \edef\p_nx_ny{\combinationparameter\c!nx*\combinationparameter\c!ny*}% % \else % \edef\p_nx_ny{\p_nx_ny*\plusone*}% % \fi % \fi % % % % test first: % % % % \ifempty\p_nx_ny % % \ifhastok={#1}% % % \let\currentcombination\empty % % \setupcurrentcombination[#1]% % % \edef\p_nx_ny{\combinationparameter\c!nx*\combinationparameter\c!ny*}% % % \orelse\ifhastok*{\currentcombination}% % % \edef\p_nx_ny{\currentcombination*\plusone*}% % % \let\currentcombination\empty % % \orelse\ifchknum\currentcombination\or % % \edef\p_nx_ny{\currentcombination*\plusone*}% % % \let\currentcombination\empty % % \else % % \edef\p_nx_ny{\combinationparameter\c!nx*\combinationparameter\c!ny*}% % % \fi % % \orelse\ifhastok={#2}% % % \setupcurrentcombination[#2]% % % \edef\p_nx_ny{\combinationparameter\c!nx*\combinationparameter\c!ny*}% % % \else % % \edef\p_nx_ny{\p_nx_ny*\plusone*}% % % \fi % % % \forgetall % % % \the\everycombination % % % \enforced\let\startcontent\pack_common_content_start % \enforced\let\stopcontent \pack_common_content_stop % \enforced\let\startcaption\pack_common_caption_start % \enforced\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 % \enforced\let\combination\empty % permits \combination{}{} handy for cld % \normalexpanded{\pack_combinations_start_indeed[\p_nx_ny]}} % % \permanent\protected\def\stopcombination % {\bgroup\normalexpanded{\egroup{}\ntimes{{}{}}\c_pack_combinations_y}% brr % \dostoptagged % \egroup % \pack_combinations_pop % \egroup} \installcorenamespace{combinationmethod} % \defcsname\??combinationmethod:\v!start\endcsname % {} % % \defcsname\??combinationmethod\endcsname % {\vbox} % % \defcsname\??combinationmethod:\v!stop\endcsname % {} \permanent\tolerant\protected\def\startcombination[#1]#*[#2]% can be simplified {\bgroup % so we can grab a group \pack_combinations_push \edef\currentcombination{#1}% \edef\p_nx_ny{#2}% % \ifempty\p_nx_ny \ifcondition\validassignment{#1}% \let\currentcombination\empty \setupcurrentcombination[#1]% \edef\p_nx_ny{\combinationparameter\c!nx*\combinationparameter\c!ny*}% \else \doifelseinstring{*}\currentcombination {\edef\p_nx_ny{\currentcombination*\plusone*}% \let\currentcombination\empty} {\doifelsenumber\currentcombination {\edef\p_nx_ny{\currentcombination*\plusone*}% \let\currentcombination\empty} {\edef\p_nx_ny{\combinationparameter\c!nx*\combinationparameter\c!ny*}}}% \fi \else \ifcondition\validassignment{#2}% \setupcurrentcombination[#2]% \edef\p_nx_ny{\combinationparameter\c!nx*\combinationparameter\c!ny*}% \else \edef\p_nx_ny{\p_nx_ny*\plusone*}% \fi \fi \begincsname\??combinationmethod\combinationparameter\c!method:\v!start\endcsname % % test first: % % \ifempty\p_nx_ny % \ifhastok={#1}% % \let\currentcombination\empty % \setupcurrentcombination[#1]% % \edef\p_nx_ny{\combinationparameter\c!nx*\combinationparameter\c!ny*}% % \orelse\ifhastok*{\currentcombination}% % \edef\p_nx_ny{\currentcombination*\plusone*}% % \let\currentcombination\empty % \orelse\ifchknum\currentcombination\or % \edef\p_nx_ny{\currentcombination*\plusone*}% % \let\currentcombination\empty % \else % \edef\p_nx_ny{\combinationparameter\c!nx*\combinationparameter\c!ny*}% % \fi % \orelse\ifhastok={#2}% % \setupcurrentcombination[#2]% % \edef\p_nx_ny{\combinationparameter\c!nx*\combinationparameter\c!ny*}% % \else % \edef\p_nx_ny{\p_nx_ny*\plusone*}% % \fi % \forgetall % \the\everycombination % \enforced\let\startcontent\pack_common_content_start \enforced\let\stopcontent \pack_common_content_stop \enforced\let\startcaption\pack_common_caption_start \enforced\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 \ifcsname\??combinationmethod\combinationparameter\c!method\endcsname \lastnamedcs\else\vbox \fi\ifx\p_height\v!fit\else to \p_height \fi \bgroup \enforced\let\combination\empty % permits \combination{}{} handy for cld \normalexpanded{\pack_combinations_start_indeed[\p_nx_ny]}} \permanent\protected\def\stopcombination {\bgroup\normalexpanded{\egroup{}\ntimes{{}{}}\c_pack_combinations_y}% brr \dostoptagged \egroup \begincsname\??combinationmethod\combinationparameter\c!method:\v!stop\endcsname \pack_combinations_pop \egroup} \let\pack_combinations_check_x_y\relax \aliased\let\combinationwidth\!!zeropoint \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 \enforced\permanent\protected\edef\combinationwidth % \immutable {\the\dimexpr (\hsize-\numexpr\c_pack_combinations_x-\plusone\relax\dimexpr\combinationparameter\c!distance\relax)/\c_pack_combinations_x \relax}% \halign \ifx\p_width\v!fit\else to \p_width \fi \bgroup % repetitive preamble % \halign noskips \ifx\p_width\v!fit\else to \p_width \fi \bgroup % repetitive preamble \aligntab \m_pack_combinations_leftfiller \aligncontent \m_pack_combinations_rightfiller \aligntab \tabskip\zeropoint \s!plus 1fill % \fillskip \aligncontent \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 \expandafterpars\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} \defcsname\??combinationalternative\v!text\endcsname {\expandafterpars\pack_combinations_alternative_text_indeed} \defcsname\??combinationalternative\v!label\endcsname {\expandafterpars\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\ifempty\currentcombination\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\ifempty\currentcombination\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}} \let\pack_combinations_flush_captions_indeed\relax \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 \enforced\permanent\protected\def\stopfloatcombination{\pack_combinations_stop_float{#1}}} \aliased\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 \normalexpanded{\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 \frozen\protected\instance\edefcsname\e!setup\currentpairedbox\e!endsetup\endcsname{\setuppairedbox [\currentpairedbox]}% \frozen\protected\instance\edefcsname\e!place\currentpairedbox \endcsname{\placepairedbox [\currentpairedbox]}% one argument is mandate anyway \frozen\protected\instance\edefcsname\e!start\e!place\currentpairedbox \endcsname{\startplacepairedbox[\currentpairedbox]}% one argument is mandate anyway \frozen\protected\instance\edefcsname\e!stop\e!place \currentpairedbox \endcsname{\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}% % \enforced\let\startcontent\pack_common_content_start \enforced\let\stopcontent \pack_common_content_stop \enforced\let\startcaption\pack_common_caption_start \enforced\let\stopcaption \pack_common_caption_stop % \globalsetsystemmode{pairedbox}% \pack_pairedboxes_before \expandafterpars\pack_pairedboxes_first_pickup} \permanent\protected\def\stopplacepairedbox{} % we just pick up two boxes \aliased\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 \expandafterpars\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_flush \relax \let\pack_pairedboxes_fill_top \relax \let\pack_pairedboxes_fill_bottom\relax \defcsname\??pairedboxnature\v!left\endcsname {\settrue\c_pack_pairedboxes_horizontal \let\pack_pairedboxes_flush\pack_pairedboxes_flush_left} \defcsname\??pairedboxnature\v!right\endcsname {\settrue\c_pack_pairedboxes_horizontal \let\pack_pairedboxes_flush\pack_pairedboxes_flush_right} \defcsname\??pairedboxnature\v!top\endcsname {\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} \defcsname\??pairedboxnature\v!bottom\endcsname {\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} \let\pack_pairedboxes_align_l\relax \let\pack_pairedboxes_align_r\relax \let\pack_pairedboxes_align_t\relax \let\pack_pairedboxes_align_b\relax \defcsname\??pairedboxalign\v!left\endcsname % 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} \defcsname\??pairedboxalign\v!right\endcsname % 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} \defcsname\??pairedboxalign\v!high\endcsname % 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} \defcsname\??pairedboxalign\v!low\endcsname % 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} \defcsname\??pairedboxalign\v!middle\endcsname % 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} \defcsname\??pairedboxalign\v!bottom\endcsname{\csname\??pairedboxalign\v!low \endcsname} \defcsname\??pairedboxalign \v!top\endcsname{\csname\??pairedboxalign\v!high\endcsname} \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 {\ifempty\p_location \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\aligncontent\hss\cr\box\scratchboxone\cr\box\scratchboxtwo\cr}% \egroup\egroup} \def\pack_sidebyside_two {\setbox\scratchboxtwo\box\nextbox \valign{\vss\aligncontent\vss\cr\box\scratchboxone\cr\box\scratchboxtwo\cr}% \egroup\egroup} \protect \endinput