pack-com.mkiv /size: 36 Kb    last modification: 2021-10-28 13:50
1%D \module
2%D   [       file=pack-com, % used to be in core-mis,
3%D        version=20120111,
4%D          title=\CONTEXT\ Packing Macros,
5%D       subtitle=Combinations,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14\writestatus{loading}{ConTeXt Packaging Macros / Combinations}
15
16\unprotect
17
18% \startfloatcombination will be redone ... we can decouple the floatcontent
19% and caption and pass them to combinations so that we get better fit when the
20% caption is wider than the float, testcase:
21%
22% \startfloatcombination [2*2]
23%    \placefigure[local]{alpha}{\externalfigure[cow.pdf][width=1cm]}%
24%    \placefigure[local]{beta} {\externalfigure[cow.pdf][width=2cm]}%
25%    \placefigure[local]{gamma}{\externalfigure[cow.pdf][width=3cm]}
26%    \placefigure[local]{delta}{\externalfigure[cow.pdf][width=4cm]}
27% \stopfloatcombination
28
29%D We could of course map combinations onto one of the table
30%D mechanisms but as it has served us well for ages we keep
31%D this one. The code has been cleaned up a bit and mkiv'd.
32%D
33%D Okay ... I might luafy this one eventually.
34
35% \startcombination      {alpha} {a} {beta} {b} \stopcombination
36% \startcombination[2*1] {alpha} {a} {beta} {b} \stopcombination
37% \startcombination[1*2] {alpha} {a} {beta} {b} \stopcombination
38% \startcombination[2]   {alpha} {a} {beta} {b} \stopcombination
39% \startcombination[2]   \combination {alpha} {a} \combination{beta} {b} \stopcombination
40
41%D We do support some structure but the order matters and currently it's
42%D only window dressing:
43%D
44%D \starttyping
45%D \let\startcontent\bgroup
46%D \let\stopcontent \egroup
47%D \let\startcaption\bgroup
48%D \let\stopcaption \egroup
49%D \stoptyping
50%D
51%D Of course we should have started with more structure as it would
52%D simply the code.
53%D
54%D \starttyping
55%D \startcombination
56%D     \startcontent
57%D         \externalfigure[cow]
58%D     \stopcontent
59%D     \startcaption
60%D         Some cow.
61%D     \stopcaption
62%D     \startcontent
63%D         \externalfigure[cow]
64%D     \stopcontent
65%D     \startcaption
66%D         The same cow.
67%D     \stopcaption
68%D \stopcombination
69%D \stoptyping
70
71\ifdefined\dotagcombination \else \let\dotagcombination\relax \fi
72
73\newsystemmode{combination}
74
75\appendtoks
76    \globalresetsystemmode{combination}%
77\to \everyinsidefloat
78
79\newcount\c_pack_combinations_nesting  % local
80
81\newcount\c_pack_combinations_x        % global
82\newcount\c_pack_combinations_y        % global
83\newcount\c_pack_combinations_max      % global
84
85\newdimen\d_pack_combinations_ht       % global
86
87\newbox  \b_pack_combinations_captions % global % can go
88\newbox  \b_pack_combinations_temp     % global % can go
89\newbox  \b_pack_combinations_content  % local
90\newbox  \b_pack_combinations_caption  % local
91
92\installcorenamespace{combination}
93
94\installcommandhandler \??combination {combination} \??combination
95
96\initializeboxstack{\??combination captions}
97\initializeboxstack{\??combination temp}
98
99\newcount\c_pack_combinations_x_saved
100\newcount\c_pack_combinations_y_saved
101\newcount\c_pack_combinations_max_saved
102
103\newdimen\d_pack_combinations_ht_saved
104
105\newbox  \b_pack_combinations_captions_saved
106\newbox  \b_pack_combinations_temp_saved
107\newbox  \b_pack_combinations_content_saved
108\newbox  \b_pack_combinations_caption_saved
109
110\setfalse\c_strc_constructions_define_commands
111
112\def\pack_combinations_push
113  {\advance\c_pack_combinations_nesting\plusone
114   \ifnum\c_pack_combinations_nesting>\plusone
115     \c_pack_combinations_x_saved  \c_pack_combinations_x
116     \c_pack_combinations_y_saved  \c_pack_combinations_y
117     \c_pack_combinations_max_saved\c_pack_combinations_max
118     \d_pack_combinations_ht_saved \d_pack_combinations_ht
119     \setbox\b_pack_combinations_captions_saved\box\b_pack_combinations_captions
120     \setbox\b_pack_combinations_temp_saved    \box\b_pack_combinations_temp
121     \setbox\b_pack_combinations_content_saved \box\b_pack_combinations_content
122     \setbox\b_pack_combinations_caption_saved \box\b_pack_combinations_caption
123   \else
124     \globalsetsystemmode{combination}% why global
125   \fi}
126
127\def\pack_combinations_pop
128  {\ifnum\c_pack_combinations_nesting>\plusone
129     \global\c_pack_combinations_x  \c_pack_combinations_x_saved
130     \global\c_pack_combinations_y  \c_pack_combinations_y_saved
131     \global\c_pack_combinations_max\c_pack_combinations_max_saved
132     \global\d_pack_combinations_ht \d_pack_combinations_ht_saved
133     \global\setbox\b_pack_combinations_captions\box\b_pack_combinations_captions_saved
134     \global\setbox\b_pack_combinations_temp    \box\b_pack_combinations_temp_saved
135     \setbox\b_pack_combinations_content        \box\b_pack_combinations_content_saved
136     \setbox\b_pack_combinations_caption        \box\b_pack_combinations_caption_saved
137   \else
138     \globalresetsystemmode{combination}% why global
139   \fi
140   \advance\c_pack_combinations_nesting\minusone}
141
142\definelabel
143  [\v!combination] % handy for configuring
144  [\c!numberconversion=\v!character,
145   \c!text=]
146
147\settrue\c_strc_constructions_define_commands
148
149\setupcombination
150  [\c!width=\v!fit,
151   \c!height=\v!fit,
152   \c!distance=\emwidth,
153   \c!location=\v!bottom, % can be something {top,left}
154   \c!before=\blank,
155   \c!after=,
156   \c!inbetween={\blank[\v!medium]},
157  %\c!style=,
158  %\c!color=,
159   \c!nx=2, % new
160   \c!ny=1, % new
161   \c!align=\v!middle]
162
163\let\setupcombinations\setupcombination % for the moment (we might distinguish)
164
165\installcorenamespace{combinationlocation}
166\installcorenamespace{combinationalternative}
167
168\appendtoks
169    \setfalse\c_strc_constructions_define_commands
170    \normalexpanded
171      {\definelabel
172         [\v!combination:\currentcombination]%
173         [\v!combination\ifx\currentcombinationparent\empty\else:\currentcombinationparent\fi]}%
174         [\s!counter=\currentcombination,\c!levels=1]%
175    \settrue\c_strc_constructions_define_commands
176\to \everydefinecombination
177
178\setvalue{\??combinationlocation\v!left  }{\let\m_pack_combinations_leftfiller\relax}
179\setvalue{\??combinationlocation\v!right }{\let\m_pack_combinations_rightfiller\relax}
180\setvalue{\??combinationlocation\v!top   }{\let\m_pack_combinations_valigner\depthonlybox}
181\setvalue{\??combinationlocation\v!middle}{\let\m_pack_combinations_valigner\halfwaybox}
182
183\def\pack_combinations_location_reset
184  {\let\m_pack_combinations_rightfiller\hfil
185   \let\m_pack_combinations_leftfiller \hfil
186   \let\m_pack_combinations_valigner   \firstofoneargument}
187
188\pack_combinations_location_reset
189
190\def\pack_combinations_location_step#1%
191  {\csname\??combinationlocation#1\endcsname}
192
193\unexpanded\def\startcombination
194  {\bgroup % so we can grab a group
195   \pack_combinations_push
196   \dodoubleempty\pack_combinations_start}
197
198% formally ok:
199%
200% \unexpanded\def\stopcombination
201%   {\egroup
202%    \egroup}
203%
204% more robust:
205%
206% \unexpanded\def\stopcombination
207%   {{}{}{}{}{}{}{}{}% catches (at most 4) missing entries
208%    \egroup
209%    \egroup}
210%
211% even better:
212%
213% \unexpanded\def\stopcombination
214%   {\bgroup
215%    \scratchtoks{{}}%
216%    \dorecurse\c_pack_combinations_y
217%      {\toksapp{{}{}}}%
218%    \expandafter\egroup\the\scratchtoks
219%    \egroup
220%    \dostoptagged
221%    \egroup}
222%
223% faster
224
225\unexpanded\def\pack_common_content_start{\bgroup\ignorespaces}
226\unexpanded\def\pack_common_content_stop {\removeunwantedspaces\egroup}
227\unexpanded\def\pack_common_caption_start{\bgroup\ignorespaces}
228\unexpanded\def\pack_common_caption_stop {\removeunwantedspaces\egroup}
229
230\unexpanded\def\stopcombination
231  {\bgroup\normalexpanded{\egroup{}\ntimes{{}{}}\c_pack_combinations_y}% brr
232   \dostoptagged
233   \egroup
234   \pack_combinations_pop
235   \egroup}
236
237\newtoks\everycombination
238
239% \def\pack_combinations_start[#1][#2]% needs a cleanup, also nx ny (pretty old, this one)
240%   {\edef\currentcombination{#1}%
241%    \edef\currentcombinationspec{#2}%
242%    \ifx\currentcombinationspec\empty
243%      \doifelseassignment{#1}%
244%        {\let\currentcombination\empty
245%         \setupcurrentcombination[#1]%
246%         \edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}
247%        {\doifelseinstring{*}\currentcombination
248%           {\edef\currentcombinationspec{\currentcombination*\plusone*}%
249%            \let\currentcombination\empty}
250%           {\doifelsenumber\currentcombination
251%              {\edef\currentcombinationspec{\currentcombination*\plusone*}%
252%               \let\currentcombination\empty}
253%              {\edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}}}%
254%    \else
255%      \doifelseassignment{#2}%
256%        {\setupcurrentcombination[#2]%
257%         \edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}
258%        {\edef\currentcombinationspec{\currentcombinationspec*\plusone*}}%
259%    \fi
260%    %
261%    \forgetall
262%    %
263%    \the\everycombination
264%    %
265%    \let\startcontent\pack_common_content_start
266%    \let\stopcontent \pack_common_content_stop
267%    \let\startcaption\pack_common_caption_start
268%    \let\stopcaption \pack_common_caption_stop
269%    %
270%    \edef\p_height  {\combinationparameter\c!height}%
271%    \edef\p_width   {\combinationparameter\c!width}%
272%    \edef\p_location{\combinationparameter\c!location}%
273%    \edef\p_distance{\combinationparameter\c!distance}%
274%    %
275%    \pack_combinations_location_reset
276%    \rawprocesscommacommand[\p_location]\pack_combinations_location_step
277%    %
278%    \dostarttaggedchained\t!combination\currentcombination\??combination
279%    \vbox \ifx\p_height\v!fit\else to \p_height \fi \bgroup
280%    \let\combination\empty % permits \combination{}{} handy for cld
281%    \normalexpanded{\pack_combinations_start_indeed[\currentcombinationspec]}}
282
283\def\pack_combinations_start[#1][#2]% needs a cleanup, also nx ny (pretty old, this one)
284  {\edef\currentcombination{#1}%
285   \edef\currentcombinationspec{#2}%
286   \ifx\currentcombinationspec\empty
287     \ifcondition\validassignment{#1}%
288       \let\currentcombination\empty
289       \setupcurrentcombination[#1]%
290       \edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}%
291     \else
292       \doifelseinstring{*}\currentcombination
293         {\edef\currentcombinationspec{\currentcombination*\plusone*}%
294          \let\currentcombination\empty}
295         {\doifelsenumber\currentcombination
296            {\edef\currentcombinationspec{\currentcombination*\plusone*}%
297             \let\currentcombination\empty}
298            {\edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}}}%
299     \fi
300   \else
301     \ifcondition\validassignment{#2}%
302       \setupcurrentcombination[#2]%
303       \edef\currentcombinationspec{\combinationparameter\c!nx*\combinationparameter\c!ny*}%
304     \else
305       \edef\currentcombinationspec{\currentcombinationspec*\plusone*}%
306     \fi
307   \fi
308   %
309   \forgetall
310   %
311   \the\everycombination
312   %
313   \let\startcontent\pack_common_content_start
314   \let\stopcontent \pack_common_content_stop
315   \let\startcaption\pack_common_caption_start
316   \let\stopcaption \pack_common_caption_stop
317   %
318   \edef\p_height  {\combinationparameter\c!height}%
319   \edef\p_width   {\combinationparameter\c!width}%
320   \edef\p_location{\combinationparameter\c!location}%
321   \edef\p_distance{\combinationparameter\c!distance}%
322   %
323   \pack_combinations_location_reset
324   \rawprocesscommacommand[\p_location]\pack_combinations_location_step
325   %
326   \dostarttaggedchained\t!combination\currentcombination\??combination
327   \vbox \ifx\p_height\v!fit\else to \p_height \fi \bgroup
328   \let\combination\empty % permits \combination{}{} handy for cld
329   \normalexpanded{\pack_combinations_start_indeed[\currentcombinationspec]}}
330
331\let\pack_combinations_check_x_y\relax
332
333\unexpanded\def\pack_combinations_start_indeed[#1*#2*#3]%
334  {\global\c_pack_combinations_x#1\relax
335   \global\c_pack_combinations_y#2\relax
336   \setexpandedcombinationparameter\c!nx{\the\c_pack_combinations_x}% in case we access it
337   \setexpandedcombinationparameter\c!ny{\the\c_pack_combinations_y}% in case we access it
338   \pack_combinations_check_x_y
339   \dotagcombination
340   \global\setbox\b_pack_combinations_captions\emptybox
341   \global\c_pack_combinations_max\c_pack_combinations_x
342   \multiply\c_pack_combinations_y\c_pack_combinations_x
343   \tabskip\zeropoint
344   \halign \ifx\p_width\v!fit\else to \p_width \fi \bgroup % repetitive preamble
345   \aligntab
346   \m_pack_combinations_leftfiller
347   \alignmark\alignmark
348   \m_pack_combinations_rightfiller
349   \aligntab
350   \tabskip\zeropoint \s!plus 1fill % \fillskip
351   \alignmark\alignmark
352   \cr
353   \pack_combinations_pickup}
354
355% \def\pack_combinations_pickup_content % we want to add struts but still ignore an empty box
356%   {\dostoptagged
357%    \setbox\b_pack_combinations_content\box\nextbox
358%    \dostarttagged\t!combinationcaption\empty
359%    \dowithnextboxcs\pack_combinations_pickup_caption\vtop\bgroup
360%      \afterassignment\pack_combinations_caption_first
361%      \let\nexttoken=}
362
363% I've first considered using a constructor directly but it's more overhead
364% and some settings conflict with already used combination settings so instead
365% we plug in labels. This also permits extensions later on.
366
367\appendtoks
368    \edef\p_pack_combinations_alternative{\combinationparameter\c!alternative}%
369\to \everydefinecombination
370
371\def\pack_combinations_pickup
372  {\dostarttagged\t!combinationpair\empty     % better make this text
373   \dostarttagged\t!combinationcontent\empty
374   \assumelongusagecs\pack_combinations_pickup_content_indeed}
375
376\def\pack_combinations_pickup_content_indeed
377  {\dowithnextboxcs\pack_combinations_pickup_content\hbox}
378
379\def\pack_combinations_pickup_content % we want to add struts but still ignore an empty box
380  {\dostoptagged
381   \setbox\b_pack_combinations_content\box\nextbox
382   \dostarttagged\t!combinationcaption\empty
383   \expandnamespacemacro\??combinationalternative\p_pack_combinations_alternative\v!text}
384
385\setvalue{\??combinationalternative\v!text}%
386  {\assumelongusagecs\pack_combinations_alternative_text_indeed}
387
388\setvalue{\??combinationalternative\v!label}%
389  {\assumelongusagecs\pack_combinations_alternative_label_indeed}
390
391\def\pack_combinations_alternative_text_indeed
392  {\dowithnextboxcs\pack_combinations_pickup_caption\vtop\bgroup
393     \afterassignment\pack_combinations_caption_first
394     \let\nexttoken=}
395
396\def\pack_combinations_alternative_label_indeed
397  {\dowithnextboxcs\pack_combinations_pickup_caption\vtop\bgroup
398     \hsize\wd\b_pack_combinations_content
399     \usealignparameter\combinationparameter
400     \usecombinationstyleandcolor\c!style\c!color
401     \begstrut
402       \normalexpanded{\strc_labels_command{\v!combination\ifx\currentcombination\empty\else:\currentcombination\fi}}%
403     \endstrut
404   \egroup}
405
406\appendtoks
407    \edef\p_pack_combinations_alternative{\combinationparameter\c!alternative}%
408    \ifx\p_pack_combinations_alternative\v!label
409      \edef\p_continue{\combinationparameter\c!continue}%
410      \ifx\p_continue\v!yes \else
411        \normalexpanded{\strc_labels_reset{\v!combination\ifx\currentcombination\empty\else:\currentcombination\fi}{1}}%
412     \fi
413    \fi
414\to \everycombination
415
416\def\pack_combinations_pickup_caption
417  {\dostoptagged
418   \dostoptagged
419   \setbox\b_pack_combinations_caption\box\nextbox
420   \pack_combinations_pickup_package_pair}
421
422\def\pack_combinations_caption_first
423  {\futurelet\nexttoken\pack_combinations_caption_second}
424
425\def\pack_combinations_caption_second
426  {\ifx\nexttoken\egroup
427     % the caption is empty
428   \else\ifx\nexttoken\stopcaption
429     % the caption is empty (new per 2014-05-24)
430   \else
431     % todo: \p_pack_combinations_alternative\v!none: no style, strut etc
432     \hsize\wd\b_pack_combinations_content
433     \usealignparameter\combinationparameter
434     \usecombinationstyleandcolor\c!style\c!color
435     \bgroup
436     \aftergroup\endstrut
437     \aftergroup\egroup
438     \begstrut
439   \fi\fi}
440
441\def\pack_combinations_pickup_package_pair % we need to store the caption row
442  {\vbox
443     {\forgetall
444      \m_pack_combinations_valigner{\box\b_pack_combinations_content}%
445      % we need to save the caption for a next alignment line
446      \pack_combinations_save_caption}%
447   \ifnum\c_pack_combinations_y>\plusone
448     \global\advance\c_pack_combinations_y\minusone
449     \global\advance\c_pack_combinations_x\minusone
450     \ifcase\c_pack_combinations_x
451       \doubleexpandafter\pack_combinations_pickup_package_pair_a
452     \else
453       \doubleexpandafter\pack_combinations_pickup_package_pair_b
454     \fi
455   \else
456     \singleexpandafter\pack_combinations_pickup_package_pair_c
457   \fi}
458
459\def\pack_combinations_pickup_package_pair_a
460  {\cr
461   \pack_combinations_flush_captions
462   \noalign
463     {\forgetall
464      \global\setbox\b_pack_combinations_captions\emptybox
465      \nointerlineskip
466      \combinationparameter\c!after
467      \combinationparameter\c!before
468      \vss
469      \nointerlineskip}%
470   \global\c_pack_combinations_x\c_pack_combinations_max
471   \pack_combinations_pickup}
472
473\def\pack_combinations_pickup_package_pair_b
474  {\aligntab
475   \aligntab
476   \aligntab
477   \kern\p_distance
478   \aligntab
479   \pack_combinations_pickup}
480
481\def\pack_combinations_pickup_package_pair_c
482  {\cr
483   \pack_combinations_flush_captions
484   \egroup}
485
486% \def\pack_combinations_save_caption
487%   {\global\setbox\b_pack_combinations_captions\hpack
488%      {\hpack{\box\b_pack_combinations_caption}%
489%       \unhbox\b_pack_combinations_captions}}
490%
491% \def\pack_combinations_flush_captions
492%   {\noalign
493%      {\ifdim\ht\b_pack_combinations_captions>\zeropoint
494%         \nointerlineskip % indeed
495%         \combinationparameter\c!inbetween
496%         \global\c_pack_combinations_x\c_pack_combinations_max
497%         \glet\pack_combinations_flush_captions_indeed\pack_combinations_flush_captions_yes
498%       \else
499%         \global\setbox\b_pack_combinations_captions\emptybox
500%         \glet\pack_combinations_flush_captions_indeed\pack_combinations_flush_captions_nop
501%       \fi}%
502%    \pack_combinations_flush_captions_indeed
503%    \crcr}
504%
505% \def\pack_combinations_flush_captions_yes
506%   {\global\setbox\b_pack_combinations_captions\hpack
507%      {\unhbox\b_pack_combinations_captions
508%       \global\setbox\b_pack_combinations_temp\lastbox}%
509%    \box\b_pack_combinations_temp
510%    \global\advance\c_pack_combinations_x\minusone\relax
511%    \ifnum\c_pack_combinations_x>\zerocount
512%      \expandafter\pack_combinations_flush_captions_yes_followup
513%    \else
514%      \global\setbox\b_pack_combinations_captions\emptybox
515%    \fi}
516
517\installcorenamespace{combinationcaption}
518
519\def\pack_combinations_save_caption
520  {\ifdim\htdp\b_pack_combinations_caption>\d_pack_combinations_ht
521     \global\d_pack_combinations_ht\htdp\b_pack_combinations_caption
522   \fi
523   \savebox{\??combinationcaption:\number\c_pack_combinations_nesting}{\number\c_pack_combinations_x}{\box\b_pack_combinations_caption}}
524
525\def\pack_combinations_flush_captions
526  {\noalign
527     {\ifdim\d_pack_combinations_ht>\zeropoint
528        \nointerlineskip % indeed
529        \combinationparameter\c!inbetween
530        \global\c_pack_combinations_x\c_pack_combinations_max
531        \glet\pack_combinations_flush_captions_indeed\pack_combinations_flush_captions_yes
532      \else
533        \glet\pack_combinations_flush_captions_indeed\pack_combinations_flush_captions_nop
534      \fi}%
535   \pack_combinations_flush_captions_indeed
536   \crcr}
537
538\def\pack_combinations_flush_captions_yes
539  {\vpack to \d_pack_combinations_ht\bgroup
540     \foundbox{\??combinationcaption:\number\c_pack_combinations_nesting}{\number\c_pack_combinations_x}%
541     \vss
542   \egroup
543   \global\advance\c_pack_combinations_x\minusone
544   \ifnum\c_pack_combinations_x>\zerocount % \c_pack_combinations_max
545     \expandafter\pack_combinations_flush_captions_yes_followup
546   \else
547     \global\d_pack_combinations_ht\zeropoint
548     \initializeboxstack{\??combinationcaption:\number-\c_pack_combinations_nesting}%
549   \fi}
550
551
552\let\pack_combinations_flush_captions_nop\donothing
553
554\def\pack_combinations_flush_captions_yes_followup
555  {\aligntab
556   \aligntab
557   \aligntab
558   \aligntab
559   \pack_combinations_flush_captions_indeed}
560
561%D \macros
562%D   {startfloatcombination}
563%D
564%D \setupexternalfigures[directory={../sample}]
565%D \startbuffer
566%D \placefigure
567%D   [left,none]
568%D   {}
569%D   {\startfloatcombination[2*2]
570%D      \placefigure{alpha}{\externalfigure[cow.pdf][width=1cm]}
571%D      \placefigure{beta} {\externalfigure[cow.pdf][width=2cm]}
572%D      \placefigure{gamma}{\externalfigure[cow.pdf][width=3cm]}
573%D      \placefigure{delta}{\externalfigure[cow.pdf][width=4cm]}
574%D    \stopfloatcombination}
575%D
576%D \input tufte
577%D \stopbuffer
578%D
579%D \typebuffer \getbuffer
580
581\unexpanded\def\startfloatcombination
582  {\dodoubleempty\pack_combinations_start_float}
583
584\let\stopfloatcombination\relax
585
586% \unexpanded\def\pack_combinations_float_hack_a#1%
587%   {\strc_floats_build_box_separate_split{\getlocalfloat{#1}}%
588%    \box\b_strc_floats_separate_content}
589
590% \unexpanded\def\pack_combinations_float_hack_b#1%
591%   {\box\b_strc_floats_separate_caption}
592
593\unexpanded\def\pack_combinations_float_hack_a#1%
594  {\strc_floats_build_box_separate_split{#1}%
595   \box\b_strc_floats_separate_content}
596
597\unexpanded\def\pack_combinations_float_hack_b#1%
598  {\box\b_strc_floats_separate_caption}
599
600\def\pack_combinations_start_float[#1][#2]%
601  {\ifinsidefloat\else\dontleavehmode\fi % tricky, floatcombinations fail to align well otherwise
602   \vbox\bgroup
603   \strc_floats_build_box_separate_set
604  %\insidecolumnstrue % trick, forces no centering, todo: proper switch/feature
605   \postcenterfloatmethod\zerocount
606   \forcelocalfloats
607   \unexpanded\def\stopfloatcombination{\pack_combinations_stop_float{#1}}}
608
609\def\pack_combinations_float_check_x_y
610  {\ifnum\numexpr\c_pack_combinations_x*\c_pack_combinations_y\relax<\noflocalfloats\relax
611       \global\c_pack_combinations_x\noflocalfloats
612       \global\c_pack_combinations_y\plusone
613   \fi
614   \let\pack_combinations_check_x_y\relax}%
615
616\def\pack_combinations_stop_float#1%
617  {\scratchtoks\emptytoks
618   \dorecurse\noflocalfloats
619     {\appendetoks
620        {\pack_combinations_float_hack_a{\recurselevel}}%
621        {\pack_combinations_float_hack_b{\recurselevel}}%
622      \to\scratchtoks}% brrr
623   \let\pack_combinations_check_x_y\pack_combinations_float_check_x_y
624   \expanded{\startcombination[#1]\the\scratchtoks}\stopcombination
625   \resetlocalfloats
626   \egroup}
627
628%D \macros
629%D   {definepairedbox, setuppairedbox, placepairedbox}
630%D
631%D Paired boxes, formally called legends, but from now on a
632%D legend is just an instance, are primarily meant for
633%D typesetting some text alongside an illustration. Although
634%D there is quite some variation possible, the functionality is
635%D kept simple, if only because in most cases such pairs are
636%D typeset sober.
637%D
638%D The location specification accepts a pair, where the first
639%D keyword specifies the arrangement, and the second one the
640%D alignment. The first key of the location pair is one of
641%D \type {left}, \type {right}, \type {top} or \type {bottom},
642%D while the second key can also be \type {middle}.
643%D
644%D The first box is just collected in an horizontal box, but
645%D the second one is a vertical box that gets passed the
646%D bodyfont and alignment settings.
647
648%D In many cases the table builders can be used instead, but as
649%D this mechanism is a traditional \CONTEXT\ one we keep it
650%D around.
651
652%D \macros
653%D   {setuplegend, placelegend}
654%D
655%D It makes sense to typeset a legend to a figure in \TEX\
656%D and not in a drawing package. The macro \type {\placelegend}
657%D combines a figure (or something else) and its legend. This
658%D command is just a paired box.
659%D
660%D The legend is placed according to \type {location}, being
661%D \type {bottom} or \type {right}. The macro macro is used as
662%D follows.
663%D
664%D \starttyping
665%D \placefigure
666%D   {whow}
667%D   {\placelegend
668%D      {\externalfigure[cow]}
669%D      {\starttabulate
670%D       \NC 1 \NC head \NC \NR
671%D       \NC 2 \NC legs \NC \NR
672%D       \NC 3 \NC tail \NC \NR
673%D       \stoptabulate}}
674%D
675%D \placefigure
676%D   {whow}
677%D   {\placelegend
678%D      {\externalfigure[cow]}
679%D      {\starttabulate[|l|l|l|l|]
680%D       \NC 1 \NC head \NC 3 \NC tail \NC \NR
681%D       \NC 2 \NC legs \NC   \NC      \NC \NR
682%D       \stoptabulate}}
683%D
684%D \placefigure
685%D   {whow}
686%D   {\placelegend[n=2]
687%D      {\externalfigure[cow]}
688%D      {\starttabulate
689%D       \NC 1 \NC head \NC \NR
690%D       \NC 2 \NC legs \NC \NR
691%D       \NC 3 \NC tail \NC \NR
692%D       \stoptabulate}}
693%D
694%D \placefigure
695%D   {whow}
696%D   {\placelegend[n=2]
697%D      {\externalfigure[cow]}
698%D      {head \par legs \par tail}}
699%D
700%D \placefigure
701%D   {whow}
702%D   {\placelegend[n=2]
703%D      {\externalfigure[cow]}
704%D      {\startitemize[packed]
705%D       \item head \item legs \item  tail \item belly \item horns
706%D       \stopitemize}}
707%D
708%D \placefigure
709%D   {whow}
710%D   {\placelegend[n=2,width=.8\hsize]
711%D      {\externalfigure[cow]}
712%D      {\startitemize[packed]
713%D       \item head \item legs \item  tail \item belly \item horns
714%D       \stopitemize}}
715%D
716%D \def\MytTestTwo#1#2%
717%D   {\placefigure
718%D      {whow}
719%D      {\placelegend[location={#1,#2}]
720%D         {\externalfigure[cow]}
721%D         {\starttabulate
722%D          \NC 1 \NC head \NC \NR
723%D          \NC 2 \NC legs \NC \NR
724%D          \NC 3 \NC tail \NC \NR
725%D          \stoptabulate}}}
726%D
727%D \def\MytTestOne#1{\processcommalist[left,right,top,bottom]{\MytTestTwo{#1}}}
728%D
729%D \processcommalist[left,right,top,bottom,middle]\MytTestOne
730%D \stoptyping
731%D
732%D More structure is also possible (the order matters!):
733%D
734%D \starttyping
735%D \startplacefigure[title=whow]
736%D    \startplacelegend[location={bottom,middle},color=red]
737%D         \startcontent
738%D             \externalfigure[cow]
739%D         \stopcontent
740%D         \startcaption
741%D             \starttabulate[|l|l|]
742%D                 \NC 1 \NC head \NC \NR
743%D                 \NC 2 \NC legs \NC \NR
744%D                 \NC 3 \NC tail \NC \NR
745%D             \stoptabulate
746%D         \stopcaption
747%D    \stopplacelegend
748%D \stopplacefigure
749%D \stoptyping
750
751% todo: natural size
752
753\newsystemmode{pairedbox}
754
755\appendtoks
756    \globalresetsystemmode{pairedbox}%
757\to \everyinsidefloat
758
759\installcorenamespace {pairedbox}
760
761\installcommandhandler \??pairedbox {pairedbox} \??pairedbox
762
763\setuppairedbox
764 [\c!n=1,
765  \c!distance=\bodyfontsize,
766 %\c!before=,
767 %\c!after=,
768 %\c!color=,
769 %\c!style=,
770  \c!inbetween={\blank[\v!medium]},
771  \c!width=\hsize,
772  \c!height=\vsize,
773  \c!maxwidth=\textwidth,   % \makeupwidth,
774  \c!maxheight=\textheight, % \makeupheight,
775 %\c!bodyfont=,
776 %\c!align=,
777  \c!location=\v!bottom]
778
779% watch the hsize/vsize tricks
780
781\newbox  \b_pack_pairedboxes_first
782\newbox  \b_pack_pairedboxes_second
783\newdimen\s_pack_pairedboxes_size
784
785\appendtoks
786   \setuevalue{\e!setup\currentpairedbox\e!endsetup}{\setuppairedbox     [\currentpairedbox]}%
787   \setuevalue{\e!place\currentpairedbox           }{\placepairedbox     [\currentpairedbox]}% one argument is mandate anyway
788   \setuevalue{\e!start\e!place\currentpairedbox   }{\startplacepairedbox[\currentpairedbox]}% one argument is mandate anyway
789   \setuevalue{\e!stop\e!place \currentpairedbox   }{\stopplacepairedbox                    }%
790\to \everydefinepairedbox
791
792\unexpanded\def\placepairedbox[#1]%
793  {\bgroup
794   \edef\currentpairedbox{#1}%
795   \doifelsenextoptionalcs\pack_pairedboxes_place\pack_pairedboxes_place_indeed}
796
797\unexpanded\def\startplacepairedbox[#1]%
798  {\bgroup
799   \edef\currentpairedbox{#1}%
800   \doifelsenextoptionalcs\pack_pairedboxes_place\pack_pairedboxes_place_indeed}
801
802\unexpanded\def\stopplacepairedbox
803  {}
804
805\def\pack_pairedboxes_place[#1]%
806  {\setupcurrentpairedbox[#1]%
807   \pack_pairedboxes_place_indeed}
808
809\def\pack_pairedboxes_place_indeed
810  {\pairedboxparameter\c!before
811   \bgroup
812   \edef\p_location{\pairedboxparameter\c!location}%
813   \edef\p_n       {\pairedboxparameter\c!n}%
814   %
815   \let\startcontent\pack_common_content_start
816   \let\stopcontent \pack_common_content_stop
817   \let\startcaption\pack_common_caption_start
818   \let\stopcaption \pack_common_caption_stop
819   %
820   \globalsetsystemmode{pairedbox}%
821   \pack_pairedboxes_before
822   \assumelongusagecs\pack_pairedboxes_first_pickup}
823
824\def\pack_pairedboxes_first_pickup
825  {\dowithnextboxcs\pack_pairedboxes_first\hbox
826     \bgroup
827     \let\next=}
828
829\def\pack_pairedboxes_first
830  {\pack_pairedboxes_between
831   \assumelongusagecs\pack_pairedboxes_second_pickup}
832
833\def\pack_pairedboxes_second_pickup
834  {\dowithnextboxcs\pack_pairedboxes_second\vbox
835     \bgroup
836     \pack_pairedboxes_inside_second
837     \let\next=}
838
839\def\pack_pairedboxes_second
840  {\pack_pairedboxes_after
841   \egroup
842   \pairedboxparameter\c!after
843   \egroup}
844
845\newconditional\c_pack_pairedboxes_horizontal \settrue\c_pack_pairedboxes_horizontal
846
847\installcorenamespace{pairedboxnature}
848\installcorenamespace{pairedboxalign}
849
850\let\pack_pairedboxes_fill_top   \relax
851\let\pack_pairedboxes_fill_bottom\relax
852
853\setvalue{\??pairedboxnature\v!left}%
854  {\settrue\c_pack_pairedboxes_horizontal
855   \let\pack_pairedboxes_flush\pack_pairedboxes_flush_left}
856
857\setvalue{\??pairedboxnature\v!right}%
858  {\settrue\c_pack_pairedboxes_horizontal
859   \let\pack_pairedboxes_flush\pack_pairedboxes_flush_right}
860
861\setvalue{\??pairedboxnature\v!top}%
862  {\setfalse\c_pack_pairedboxes_horizontal
863   \let\pack_pairedboxes_fill_top\relax
864   \let\pack_pairedboxes_fill_bottom\vss
865   \let\pack_pairedboxes_flush\pack_pairedboxes_flush_top}
866
867\setvalue{\??pairedboxnature\v!bottom}%
868  {\setfalse\c_pack_pairedboxes_horizontal
869   \let\pack_pairedboxes_fill_top\vss
870   \let\pack_pairedboxes_fill_bottom\relax
871   \let\pack_pairedboxes_flush\pack_pairedboxes_flush_bottom}
872
873\def\pack_pairedboxes_flush_left
874  {\box\b_pack_pairedboxes_second
875   \kern\pairedboxparameter\c!distance
876   \box\b_pack_pairedboxes_first}
877
878\def\pack_pairedboxes_flush_right
879  {\box\b_pack_pairedboxes_first
880   \kern\pairedboxparameter\c!distance
881   \box\b_pack_pairedboxes_second}
882
883\def\pack_pairedboxes_flush_top
884  {\box\b_pack_pairedboxes_second
885   \endgraf
886   \nointerlineskip
887   \pairedboxparameter\c!inbetween
888   \box\b_pack_pairedboxes_first}
889
890\def\pack_pairedboxes_flush_bottom
891  {\box\b_pack_pairedboxes_first
892   \endgraf
893   \nointerlineskip
894   \pairedboxparameter\c!inbetween
895   \box\b_pack_pairedboxes_second}
896
897\setvalue{\??pairedboxalign\v!left}% 0
898  {\let\pack_pairedboxes_align_l\relax
899   \let\pack_pairedboxes_align_r\hss
900   \let\pack_pairedboxes_align_t\relax
901   \let\pack_pairedboxes_align_b\relax}
902
903\setvalue{\??pairedboxalign\v!right}% 1
904  {\let\pack_pairedboxes_align_l\hss
905   \let\pack_pairedboxes_align_r\relax
906   \let\pack_pairedboxes_align_t\relax
907   \let\pack_pairedboxes_align_b\relax}
908
909\setvalue{\??pairedboxalign\v!high}% 2
910  {\let\pack_pairedboxes_align_l\relax
911   \let\pack_pairedboxes_align_r\relax
912   \let\pack_pairedboxes_align_t\relax
913   \let\pack_pairedboxes_align_b\vss}
914
915\setvalue{\??pairedboxalign\v!low}% 3
916  {\let\pack_pairedboxes_align_l\relax
917   \let\pack_pairedboxes_align_r\relax
918   \let\pack_pairedboxes_align_t\vss
919   \let\pack_pairedboxes_align_b\relax}
920
921\setvalue{\??pairedboxalign\v!middle}% 4
922  {\let\pack_pairedboxes_align_l\hss
923   \let\pack_pairedboxes_align_r\hss
924   \let\pack_pairedboxes_align_t\vss
925   \let\pack_pairedboxes_align_b\vss}
926
927\setvalue{\??pairedboxalign\v!bottom}{\getvalue{\??pairedboxalign\v!low }}
928\setvalue{\??pairedboxalign   \v!top}{\getvalue{\??pairedboxalign\v!high}}
929
930\def\pack_pairedbox_valign#1{\setbox#1\vpack to \s_pack_pairedboxes_size{\pack_pairedboxes_align_t\box#1\pack_pairedboxes_align_b}}
931\def\pack_pairedbox_halign#1{\setbox#1\hpack to \s_pack_pairedboxes_size{\pack_pairedboxes_align_l\box#1\pack_pairedboxes_align_r}}
932
933\def\pack_pairedboxes_before
934  {\ifx\p_location\empty
935      \csname\??pairedboxnature\v!left  \endcsname
936      \csname\??pairedboxalign \v!middle\endcsname
937   \else
938     \getfromcommacommand[\p_location][1]%
939     \csname\??pairedboxnature
940       \ifcsname\??pairedboxnature\commalistelement\endcsname\commalistelement\else\v!left\fi
941     \endcsname
942     \getfromcommacommand[\p_location][2]%
943     \csname\??pairedboxalign
944       \ifcsname\??pairedboxalign\commalistelement\endcsname\commalistelement\else\v!middle\fi
945     \endcsname
946   \fi}
947
948\def\pack_pairedboxes_between
949  {\usebodyfontparameter\pairedboxparameter
950   \setbox\b_pack_pairedboxes_first\box\nextbox
951   \ifconditional\c_pack_pairedboxes_horizontal
952     \pack_pairedboxes_between_horizontal
953   \else
954     \pack_pairedboxes_between_vertical
955   \fi
956   \ifnum\p_n>\plusone
957     \setrigidcolumnhsize\hsize{\pairedboxparameter\c!distance}\p_n
958   \fi}
959
960% \def\pack_pairedboxes_between_horizontal
961%   {\setlocalhsize
962%    \hsize\wd\b_pack_pairedboxes_first % trick
963%    \hsize\pairedboxparameter\c!width % can be \hsize
964%    \scratchdimen\dimexpr\wd\b_pack_pairedboxes_first+\pairedboxparameter\c!distance\relax
965%    \ifdim\dimexpr\hsize+\scratchdimen\relax>\pairedboxparameter\c!maxwidth\relax
966%      \hsize\dimexpr\pairedboxparameter\c!maxwidth-\scratchdimen\relax
967%    \fi}
968
969\def\pack_pairedboxes_between_horizontal
970  {\scratchdistance\pairedboxparameter\c!distance
971   \scratchwidth\pairedboxparameter\c!maxwidth\relax
972   \setlocalhsize
973   \hsize\dimexpr\availablehsize-\wd\b_pack_pairedboxes_first-\scratchdistance\relax
974   \hsize\pairedboxparameter\c!width\relax % can be \hsize
975   \scratchdimen\dimexpr\wd\b_pack_pairedboxes_first+\scratchdistance\relax
976   \ifdim\dimexpr\hsize+\scratchdimen\relax>\scratchwidth
977     \hsize\dimexpr\scratchwidth-\scratchdimen\relax
978   \fi}
979
980\def\pack_pairedboxes_between_vertical
981  {\scratchwidth\pairedboxparameter\c!maxwidth\relax
982   \hsize\wd\b_pack_pairedboxes_first
983   \hsize\pairedboxparameter\c!width\relax % can be \hsize
984   \ifdim\hsize>\scratchwidth\relax
985     \hsize\scratchwidth
986   \fi}
987
988\def\pack_pairedboxes_after
989  {\setbox\b_pack_pairedboxes_second\vpack
990     {\ifnum\p_n>\plusone
991        \rigidcolumnbalance\nextbox
992      \else
993        \box\nextbox
994      \fi}%
995   \ifconditional\c_pack_pairedboxes_horizontal
996     \pack_pairedboxes_pack_horizontal
997   \else
998     \pack_pairedboxes_pack_vertical
999   \fi}
1000
1001\def\pack_pairedboxes_pack_horizontal
1002  {\dontleavehmode\hbox\bgroup
1003     \forgetall
1004     \s_pack_pairedboxes_size\ht
1005       \ifdim\ht\b_pack_pairedboxes_first>\ht\b_pack_pairedboxes_second
1006         \b_pack_pairedboxes_first
1007       \else
1008         \b_pack_pairedboxes_second
1009       \fi
1010     \vsize\s_pack_pairedboxes_size
1011     \ifdim\s_pack_pairedboxes_size<\pairedboxparameter\c!height\relax % can be \vsize
1012       \s_pack_pairedboxes_size\pairedboxparameter\c!height
1013     \fi
1014     \ifdim\s_pack_pairedboxes_size>\pairedboxparameter\c!maxheight\relax
1015       \s_pack_pairedboxes_size\pairedboxparameter\c!maxheight
1016     \fi
1017     \pack_pairedbox_valign\b_pack_pairedboxes_first
1018     \pack_pairedbox_valign\b_pack_pairedboxes_second
1019     \pack_pairedboxes_flush
1020   \egroup}
1021
1022\def\pack_pairedboxes_pack_vertical
1023  {\dontleavehmode\vpack\bgroup
1024     \forgetall
1025     \s_pack_pairedboxes_size\wd
1026       \ifdim\wd\b_pack_pairedboxes_first>\wd\b_pack_pairedboxes_second
1027         \b_pack_pairedboxes_first
1028       \else
1029         \b_pack_pairedboxes_second
1030       \fi
1031     \pack_pairedbox_halign\b_pack_pairedboxes_first
1032     \pack_pairedbox_halign\b_pack_pairedboxes_second
1033     \s_pack_pairedboxes_size\ht\b_pack_pairedboxes_second
1034     \vsize\s_pack_pairedboxes_size
1035     \ifdim\ht\b_pack_pairedboxes_second<\pairedboxparameter\c!height\relax % can be \vsize
1036       \s_pack_pairedboxes_size\pairedboxparameter\c!height\relax % \relax needed
1037     \fi
1038     \ifdim\s_pack_pairedboxes_size>\pairedboxparameter\c!maxheight\relax % todo: totale hoogte
1039       \s_pack_pairedboxes_size\pairedboxparameter\c!maxheight\relax % \relax needed
1040     \fi
1041     \ifdim\s_pack_pairedboxes_size>\ht\b_pack_pairedboxes_second
1042       \setbox\b_pack_pairedboxes_second\vpack to \s_pack_pairedboxes_size
1043         {\pack_pairedboxes_fill_top
1044          \box\b_pack_pairedboxes_second
1045          \pack_pairedboxes_fill_bottom}% \kern\zeropoint
1046     \fi
1047     \pack_pairedboxes_flush
1048   \egroup}
1049
1050\def\pack_pairedboxes_inside_second
1051  {\forgetall
1052   \setupalign[\pairedboxparameter\c!align]%
1053   \usepairedboxstyleandcolor\c!style\c!color
1054   \tolerantTABLEbreaktrue % hm.
1055   \blank[\v!disable]% use fast one
1056   \everypar{\begstrut}} % also flushers here (see bTABLE)
1057
1058\definepairedbox[\v!legend]
1059
1060\unexpanded\def\placeontopofeachother{\bgroup\dowithnextboxcs\pack_topofeachother_one\hbox}
1061\unexpanded\def\placesidebyside      {\bgroup\dowithnextboxcs\pack_sidebyside_one    \hbox}
1062
1063\def\pack_topofeachother_one{\bgroup\setbox\scratchboxone\box\nextbox\dowithnextboxcs\pack_topofeachother_two\hbox}
1064\def\pack_sidebyside_one    {\bgroup\setbox\scratchboxone\box\nextbox\dowithnextboxcs\pack_sidebyside_two    \hbox}
1065
1066\def\pack_topofeachother_two{\setbox\scratchboxtwo\box\nextbox
1067                             \halign{\hss\alignmark\alignmark\hss\cr\box\scratchboxone\cr\box\scratchboxtwo\cr}%
1068                             \egroup\egroup}
1069\def\pack_sidebyside_two    {\setbox\scratchboxtwo\box\nextbox
1070                             \valign{\vss\alignmark\alignmark\vss\cr\box\scratchboxone\cr\box\scratchboxtwo\cr}%
1071                             \egroup\egroup}
1072
1073\protect \endinput
1074