tabl-xtb.mkvi /size: 32 Kb    last modification: 2023-12-21 09:44
1% macros=mkvi
2
3%D \module
4%D   [       file=tabl-xtb,
5%D        version=2011.10.26,
6%D          title=\CONTEXT\ Table Macros,
7%D       subtitle=Xtreme,
8%D         author=Hans Hagen,
9%D           date=\currentdate,
10%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
11%C
12%C This module is part of the \CONTEXT\ macro||package and is
13%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
14%C details.
15
16\writestatus{loading}{ConTeXt Table Macros / Xtreme}
17
18\registerctxluafile{tabl-xtb}{}
19
20% todo:
21%
22% - yes or no: foregroundstyle/color <- style/color
23% - template alignment
24% - maybe split horizontal (a la linetables)
25% - before/after and wrapping (linecorrection)
26% - maybe also some before/after commands
27% - maybe correction when non float usage
28% - tagging needs to be checked
29% - maybe only tag the box
30% - scale to fit
31%
32% - buffers permit verbatim but are not always handy
33
34%D This module started as an afternoon experiment and surprisingly could be
35%D mostly finished the same evening. Of course it builds upon existing
36%D functionality. The main reason for writing it is that we occasionally
37%D run into pretty large tables that take tens of pages and need to be split
38%D into floats. Speed is one issue there, avoiding to use vsplit is another.
39%D
40%D \starttyping
41%D \definextable [tag] | [tag][parent]
42%D \setupxtable [settings] | [tag][settings]
43%D
44%D \startxtable[tag|settings]
45%D     \startxtablehead|\startxtablenext|\startxtablebody|\startxtablefoot
46%D         \startxrowgroup[tag|settings]
47%D             \startxrow[settings]
48%D                 \startxcellgroup[tag|settings]
49%D                     \startxcell[settings] ... \stopxcell
50%D                 \stopxcellgroup
51%D             \stopxrow
52%D         \startxrowgroup
53%D     \stopxtablehead|\stopxtablenext|\stopxtablebody|\stopxtablefoot
54%D \stopxtable
55%D \stoptyping
56%D
57%D See xtables-001.tex etc for some examples.
58
59% We can avoid some checking by using the fastoptionalcheckcs helpers
60% instead of dosingleempty but the speed gain is neglectable.
61
62\unprotect
63
64% option=stretch         : equal distribution
65% option={stretch,width} : proportional distribution
66% option={max}           : prefer max over forced width/height
67%
68% cells: option=fixed    : nils autostretch (not yet complete)
69
70% \setbox\scratchbox\hbox attr \taggedattribute \c_attr_tagged {...}
71%
72% \let\tsplitbeforeresult\donothing
73% \let\tsplitafterresult \donothing
74% \let\tsplitinbetween   \donothing
75% \let\tsplitbefore      \donothing
76% \let\tsplitafter       \donothing
77% \let\postprocesstsplit \donothing
78
79\let\dotagxtablecell  \relax % names will change
80\let\dotagxtablesignal\relax % names will change
81
82\appendtoks
83    \def\dotagxtablecell
84      {\clf_settagtablecell
85         \numexpr\tablecellrows\relax
86         \numexpr\tablecellcolumns\relax
87         \numexpr\raggedstatus\relax}%
88    \def\dotagxtablesignal
89      {\signalcharacter}% not used
90\to \everyenableelements
91
92\newdimen\d_tabl_x_width
93\newdimen\d_tabl_x_height
94\newdimen\d_tabl_x_depth        % not used
95\newdimen\d_tabl_x_distance
96\newcount\c_tabl_x_nx
97\newcount\c_tabl_x_ny
98\newcount\c_tabl_x_mode
99\newbox  \b_tabl_x
100\newcount\c_tabl_x_state        % 0=empty 1=content 3=splitleft
101\newdimen\d_tabl_x_final_width
102\newcount\c_tabl_x_nesting
103\newcount\c_tabl_x_skip_mode    % 1 = skip
104\newdimen\d_tabl_x_textwidth
105\newcount\c_tabl_x_swapped
106\newcount\c_tabl_x_swapped_max
107
108\let\m_tabl_x_swapped_settings\empty
109
110\let\currentxtablerow   \clf_x_table_r
111\let\currentxtablecolumn\clf_x_table_c
112
113% \setupxtable[one][parent][a=b,c=d]
114% \setupxtable[one]        [a=b,c=d]
115% \setupxtable             [a=b,c=d]
116
117\installcorenamespace{xtable}
118\installcorenamespace{xtablecheck}
119\installcorenamespace{xtableswap}
120
121\installframedautocommandhandler \??xtable {xtable} \??xtable
122
123\appendtoks
124    \checkxtableparent % so we can deal with undefined settings, not that it's efficient
125\to \everysetupxtable
126
127\setupxtable[%
128    \c!nr=\plusone,
129    \c!nc=\plusone,
130    \c!nx=\plusone, % slow
131    \c!ny=\plusone, % slow
132    \c!align=\v!table, % {\v!flushleft,\v!broad,\v!high}, % just as \bTABLE .. \eTABLE
133    \c!frameoffset=.5\linewidth,
134    \c!backgroundoffset=\v!frame,
135  % \c!framecolor=\s!black,
136  % \c!foregroundstyle=\xtableparameter\c!style, % not clean, better capture elsewhere
137  % \c!foregroundcolor=\xtableparameter\c!color, % not clean, better capture elsewhere
138  % \c!bodyfont=,
139    \c!width=\v!fit,
140    \c!height=\v!fit,
141    \c!maxwidth=8\emwidth,
142    \c!autowidth=\v!yes,              % controls framed
143    \c!rulethickness=\linewidth,
144    \c!strut=\v!yes,
145    \c!autostrut=\v!no,
146    \c!split=\v!auto,                 % a number will take that many lines
147    \c!splitoffset=\zeropoint,        % extra space taken
148    \c!aligncharacter=\v!no,
149    \c!alignmentcharacter={,},
150    \c!alignmentleftsample=,
151    \c!alignmentrightsample=,
152    \c!alignmentleftwidth=\zeropoint,
153    \c!alignmentrightwidth=\zeropoint,
154  % \c!option=,                       % \v!stretch {\v!stretch,\v!width}
155  % \c!footer=,
156  % \c!header=,
157    \c!spaceinbetween=,
158    \c!textwidth=\v!local,            % was \hsize,
159    \c!textheight=\vsize,             % used for vertical spread
160    \c!distance=\zeropoint,           % individual column
161    \c!columndistance=\zeropoint,     % each column (whole table)
162    \c!leftmargindistance=\zeropoint, % whole table
163    \c!rightmargindistance=\zeropoint,% whole table
164]
165
166\unexpanded\def\startxtable
167  {\dosingleempty\tabl_x_start_table}
168
169\let\stopxtable\relax
170
171\def\tabl_x_default_buffer{x_table_\number\c_tabl_x_nesting}
172\let\tabl_x_current_buffer\empty
173
174\unexpanded\def\tabl_x_start_table[#settings]% maybe two arguments: [tag][settings] | [tag] | [settings]
175  {\bgroup
176   \tabl_x_prepare{#settings}%
177   \edef\tabl_x_current_buffer{\tabl_x_default_buffer}%
178   \buff_pickup{\tabl_x_current_buffer}{startxtable}{stopxtable}\relax\tabl_x_process\zerocount}
179
180\unexpanded\def\processxtablebuffer
181  {\dosingleempty\tabl_x_process_buffer_directly}
182
183% These direct buffers can be somewhat faster but it's probably neglectable.
184% Anyway, no nesting is supported as we then need to catch (e.g.) rows and
185% keep track of nesting and have a more complex redefinition of nested
186% instanced \unknown\ it's not worth the trouble. Only use them when you
187% really need them and use the embeddedxtable command when nesting them.
188% Implementing nesting would be slower than not using direct buffers.
189
190\unexpanded\def\tabl_x_process_buffer_directly[#name]%
191  {\bgroup
192   \let\tabl_x_start_table\tabl_x_process_buffer
193   \edef\tabl_x_current_buffer{#name}%
194   \tabl_x_get_buffer %      settings
195   \tabl_x_process}
196
197\unexpanded\def\tabl_x_start_ignore[#settings]%
198  {}
199
200\unexpanded\def\tabl_x_process_buffer[#settings]%
201  {\tabl_x_prepare{#settings}%
202   \let\tabl_x_start_table\tabl_x_start_ignore
203   \gobbleuntil\stopxtable} % nested xtables are not supported,
204
205%D A bonus: you have to use the following construct inside a macro or
206%D direct buffer.
207
208\unexpanded\def\startembeddedxtable
209  {\dosingleempty\tabl_x_embedded_start}
210
211\unexpanded\def\tabl_x_embedded_start[#settings]#content\stopembeddedxtable
212  {\tabl_x_prepare{#settings}%
213   \clf_assignbuffer{embedded_x_table}{\detokenize{#content}}\catcodetable\relax
214   \bgroup
215   \let\tabl_x_start_table\tabl_x_process_buffer
216   \edef\tabl_x_current_buffer{embedded_x_table}%
217   \tabl_x_process}
218
219\let\stopembeddedxtable\relax
220
221%D We can also define xtables.
222
223\appendtoks
224    \setuevalue{\e!start\currentxtable}{\tabl_x_start_named{\currentxtable}}%
225    \setuevalue{\e!stop \currentxtable}{\tabl_x_stop_named}%
226\to \everydefinextable
227
228\unexpanded\def\tabl_x_start_named#tag%
229  {\bgroup
230   \edef\currentxtable{#tag}%
231   \dosingleempty\tabl_x_start_named_indeed}
232
233\unexpanded\def\tabl_x_start_named_indeed[#settings]%
234  {\advance\c_tabl_x_nesting\plusone
235   \dostarttaggedchained\t!table\empty\??xtable
236   \iffirstargument
237     \setupcurrentxtable[#settings]%
238   \fi
239   \tabl_x_check_textwidth
240  %\forgetall % else whitespace mess
241   \edef\tabl_x_current_buffer{\tabl_x_default_buffer}%
242   \normalexpanded{\buff_pickup{\tabl_x_current_buffer}{\e!start\currentxtable}{\e!stop\currentxtable}\relax\tabl_x_process\zerocount}}
243
244\unexpanded\def\tabl_x_stop_named
245  {}
246
247%D Now we come to processing:
248
249\unexpanded\def\tabl_x_check_textwidth
250  {\edef\p_textwidth{\xtableparameter\c!textwidth}%
251   \ifx\p_textwidth\v!local
252     \d_tabl_x_textwidth\availablehsize
253   \else
254     \d_tabl_x_textwidth\p_textwidth
255   \fi}
256
257\newtoks\everypreparextable
258
259\unexpanded\def\tabl_x_prepare#settings% assumes \iffirstargument to be set
260  {\advance\c_tabl_x_nesting\plusone
261   \dostarttaggedchained\t!table\empty\??xtable
262   \iffirstargument
263     \tabl_x_set_checked{#settings}%
264   \fi
265   \tabl_x_check_textwidth
266   \the\everypreparextable
267   }% else whitespace mess
268
269\def\tabl_x_get_buffer
270  {\clf_getbuffertex{\tabl_x_current_buffer}}
271
272\let\tabl_x_start_row_yes \relax
273\let\tabl_x_start_row_nop \relax
274\let\tabl_x_stop_row      \relax
275\let\tabl_x_start_cell_yes\relax
276\let\tabl_x_start_cell_nop\relax
277\let\tabl_x_stop_cell     \relax
278
279\newtoks\t_table_x_cleanup
280
281\unexpanded\def\tabl_x_process
282  {\begingroup % *
283   \forgetall % moved here
284   \dontcomplain % for the moment here till we figure out where we get the overflow
285   \usebodyfontparameter\xtableparameter
286   \setbox\scratchbox\vbox
287     {\doifsomething{\xtableparameter\c!spaceinbetween}{\blank[\xtableparameter\c!spaceinbetween]}}%
288   \clf_x_table_create
289        option              {\xtableparameter\c!option}%
290        textwidth           \d_tabl_x_textwidth
291        textheight          \dimexpr\xtableparameter\c!textheight\relax
292        maxwidth            \dimexpr\xtableparameter\c!maxwidth\relax
293        lineheight          \openlineheight
294        columndistance      \dimexpr\xtableparameter\c!columndistance\relax
295        leftmargindistance  \dimexpr\xtableparameter\c!leftmargindistance\relax
296        rightmargindistance \dimexpr\xtableparameter\c!rightmargindistance\relax
297        rowdistance         \ht\scratchbox
298        header              {\xtableparameter\c!header}%
299        footer              {\xtableparameter\c!footer}%
300   \relax
301   %
302   \letxtableparameter\c!option\empty
303   % not so nice but needed as we use this in the setup
304   \linewidth\xtableparameter\c!rulethickness\relax
305   % so we freeze it
306   \c_tabl_x_swapped_max\zerocount
307   \begingroup
308     \let\tabl_x_start_row_yes \tabl_x_start_row_reflow_width_yes
309     \let\tabl_x_start_row_nop \tabl_x_start_row_reflow_width_nop
310     \let\tabl_x_stop_row      \tabl_x_stop_row_reflow_width
311     \let\tabl_x_start_cell_yes\tabl_x_start_cell_reflow_width_yes
312     \let\tabl_x_start_cell_nop\tabl_x_start_cell_reflow_width_nop
313     \let\tabl_x_stop_cell     \tabl_x_stop_cell_reflow_width
314     \settrialtypesetting
315     \tabl_x_get_buffer
316     \ifcase\c_tabl_x_swapped_max
317     \else
318       \tabl_x_flush_swapped
319     \fi
320     \clf_x_table_reflow_width
321   \endgroup
322   \begingroup
323     \let\tabl_x_start_row_yes \tabl_x_start_row_reflow_height_yes
324     \let\tabl_x_start_row_nop \tabl_x_start_row_reflow_height_nop
325     \let\tabl_x_stop_row      \tabl_x_stop_row_reflow_height
326     \let\tabl_x_start_cell_yes\tabl_x_start_cell_reflow_height_yes
327     \let\tabl_x_start_cell_nop\tabl_x_start_cell_reflow_height_nop
328     \let\tabl_x_stop_cell     \tabl_x_stop_cell_reflow_height
329     \settrialtypesetting
330     \ifcase\c_tabl_x_swapped_max
331       \tabl_x_get_buffer
332     \else
333       \tabl_x_flush_swapped
334     \fi
335     \clf_x_table_reflow_height
336   \endgroup
337   \begingroup
338     \let\tabl_x_start_row_yes \tabl_x_start_row_construct_yes
339     \let\tabl_x_start_row_nop \tabl_x_start_row_construct_nop
340     \let\tabl_x_stop_row      \tabl_x_stop_row_construct
341     \let\tabl_x_start_cell_yes\tabl_x_start_cell_construct_yes
342     \let\tabl_x_start_cell_nop\tabl_x_start_cell_construct_nop
343     \let\tabl_x_stop_cell     \tabl_x_stop_cell_construct
344     \ifcase\c_tabl_x_swapped_max
345       \tabl_x_get_buffer
346     \else
347       \tabl_x_flush_swapped
348     \fi
349     \clf_x_table_construct
350   \endgroup
351   \endgroup % *
352   \ifinsidesplitfloat
353     \tabl_x_flush_float_split
354   \else\ifinsidefloat
355     \tabl_x_flush_float_normal
356   \else
357     \tabl_x_flush_text_checked
358   \fi\fi
359   \clf_x_table_cleanup
360   \dostoptagged
361   \resetbuffer[\tabl_x_current_buffer]%
362   \resetcharacteralign
363   \the\t_table_x_cleanup
364   \egroup}
365
366% text flow split modes
367
368\installcorenamespace{xtableflushsplit}
369
370\unexpanded\def\tabl_x_flush_text_checked
371  {\expandnamespaceparameter\??xtableflushsplit\xtableparameter\c!split\v!no}
372
373% in text flow: headers and footers only once
374
375\setvalue{\??xtableflushsplit\v!yes}%
376  {\clf_x_table_flush
377     method {\v!split}%
378   \relax}
379
380% in text flow: headers and footers only once
381
382\setvalue{\??xtableflushsplit\v!no}%
383  {% \noindent       % gives extra line after table
384   % \noindentation  % messes up the next indentation
385   % \dontleavehmode % no leftskip
386   \kern\zeropoint   % yet another guess
387   \ignorespaces
388   \clf_x_table_flush
389     method {\v!normal}%
390   \relax
391   \removeunwantedspaces}
392
393% in text flow: headers and footers get repeated
394
395% \setvalue{\??xtableflushsplit\v!repeat}%
396%   {\doloop
397%      {\clf_x_table_flush
398%         method {\v!split}%
399%         height \ifdim\pagegoal=\maxdimen\textheight\else\pagegoal\fi
400%       \relax
401%       \ifcase\c_tabl_x_state
402%         \exitloop
403%       \else
404%         \page
405%       \fi}}
406
407\defcsname\??xtableflushsplit\v!repeat\endcsname
408  {\doloop
409     {\testpage[5]% for now hard coded, just as the \lineheight below, see mail end of april 2021
410      \clf_x_table_flush
411        method {\v!split}%
412        height \ifdim\pagegoal=\maxdimen\textheight\else\dimexpr\pagegoal-\pagetotal-\lineheight\relax\fi
413      \relax
414      \ifcase\c_tabl_x_state
415        \exitloop
416      \else
417        \page
418      \fi}}
419
420% \setvalue{\??xtableflushsplit\v!setups}%
421%   {\directsetup{xtable:split:user}}
422%
423% \startsetups[xtable:split:user]
424%     \doloop {
425%         \xtablesplitflush % uses \xtablesplitvsize (a macro)
426%         \ifcase\xtablesplitstate
427%             \exitloop
428%         \else
429%             \page
430%         \fi
431%     }
432% \stopsetups
433%
434% \unexpanded\def\xtablesplitflush
435%   {\clf_x_table_flush
436%      method {\v!split}%
437%      height \dimexpr\xtablesplitvsize\relax
438%    \relax}
439%
440% \def\xtablesplitvsize
441%   {\ifdim\pagegoal=\maxdimen\textheight\else\pagegoal\fi}
442%
443% \let\xtablesplitstate\c_tabl_x_state
444
445\let\extratxtablesplitheight\zeropoint % might disappear so don't depend on it
446
447\unexpanded\def\tabl_x_flush_float_normal
448  {\clf_x_table_flush
449     method {\v!normal}%
450   \relax}
451
452\unexpanded\def\tabl_x_flush_float_split
453  {\resetdirecttsplit
454   \edef\extrasplitfloatlines  {\xtableparameter\c!split}%
455   \edef\tsplitminimumfreespace{\the\dimexpr\extratxtablesplitheight+\xtableparameter\c!splitoffset\relax}%
456 % \edef\tsplitminimumfreelines{2}% not needed here as we're precise enough
457   \let\tsplitdirectsplitter\tabl_x_split_splitter
458   \let\tsplitdirectwidth   \d_tabl_x_final_width
459   \handledirecttsplit}
460
461\unexpanded\def\tabl_x_split_splitter#height%
462  {\setbox\tsplitresult\vbox
463     {\clf_x_table_flush
464        method {\v!split}%
465        height \dimexpr#height\relax
466      \relax}%
467   \ifcase\c_tabl_x_state
468     \global\setfalse\somenextsplitofffloat
469   \else
470     \global\settrue \somenextsplitofffloat
471   \fi}
472
473\unexpanded\def\startxrow
474  {\begingroup
475   \doifelsenextoptionalcs\tabl_x_start_row_yes\tabl_x_start_row_nop}
476
477\unexpanded\def\tabl_x_start_row_reflow_width_yes[#settings]%
478  {\setupcurrentxtable[#settings]%
479   \clf_x_table_next_row}
480
481\unexpanded\def\tabl_x_start_row_reflow_width_nop
482  {\clf_x_table_next_row}
483
484\unexpanded\def\tabl_x_stop_row_reflow_width
485  {}
486
487\let\tabl_x_start_row_reflow_height_yes\tabl_x_start_row_reflow_width_yes
488\let\tabl_x_start_row_reflow_height_nop\tabl_x_start_row_reflow_width_nop
489\let\tabl_x_stop_row_reflow_height     \tabl_x_stop_row_reflow_width
490
491\unexpanded\def\tabl_x_start_row_construct_yes[#settings]%
492  {\setupcurrentxtable[#settings]%
493   \dostarttagged\t!tablerow\empty
494   \clf_x_table_next_row_option{\xtableparameter\c!samepage}}
495
496\unexpanded\def\tabl_x_start_row_construct_nop
497  {\dostarttagged\t!tablerow\empty
498   \clf_x_table_next_row}
499
500\unexpanded\def\tabl_x_stop_row_construct
501  {\clf_x_table_finish_row
502   \dostoptagged}
503
504\unexpanded\def\stopxrow
505  {\tabl_x_stop_row
506   \endgroup}
507
508\unexpanded\def\startxcell
509  {\doifelsenextoptionalcs\tabl_x_start_cell_yes\tabl_x_start_cell_nop}
510
511\unexpanded\def\stopxcell
512  {\tabl_x_stop_cell}
513
514% \unexpanded\def\dummyxcell
515%   {\tabl_x_start_cell_nop
516%    \tabl_x_stop_cell}
517
518\unexpanded\def\dummyxcell
519  {\begingroup
520   \let\inheritedxtableframed\relax
521   \tabl_x_start_cell_nop
522   \tabl_x_stop_cell
523   \endgroup}
524
525% \unexpanded\def\tabl_x_begin_of_cell
526%   {%\inhibitblank % already in framed
527%    \everypar{\delayedbegstrut}}
528
529\def\tabl_x_setup_character_align
530  {\edef\p_left {\directxtableparameter\c!alignmentleftsample}%
531   \edef\p_right{\directxtableparameter\c!alignmentrightsample}%
532   \ifx\p_left\empty
533     \scratchdimenone\dimexpr\directxtableparameter\c!alignmentleftwidth\relax
534   \else
535     \setbox\scratchbox\hbox{\p_left}%
536     \scratchdimenone\wd\scratchbox
537   \fi
538   \ifx\p_right\empty
539     \scratchdimentwo\dimexpr\directxtableparameter\c!alignmentrightwidth\relax
540   \else
541     \setbox\scratchbox\hbox{\p_right}%
542     \scratchdimentwo\wd\scratchbox
543   \fi
544   \clf_setcharacteraligndetail
545     \clf_x_table_c
546     {\directxtableparameter\c!alignmentcharacter}%
547     \scratchdimenone
548     \scratchdimentwo
549   \relax}
550
551\newtoks\t_tabl_x_every_cell
552
553% \appendtoks
554%     \inhibitblank % already in framed
555% \to \t_tabl_x_every_cell
556
557\appendtoks
558    \edef\p_characteralign{\directxtableparameter\c!aligncharacter}%
559    \ifx\p_characteralign\v!yes
560        \ifcase\clf_x_table_r\or
561            \tabl_x_setup_character_align
562        \fi
563        \signalcharacteralign\clf_x_table_c\clf_x_table_r
564    \fi
565\to \t_tabl_x_every_cell
566
567\unexpanded\def\tabl_x_begin_of_cell
568  {\the\t_tabl_x_every_cell
569   \everypar{\delayedbegstrut}}
570
571\unexpanded\def\tabl_x_end_of_cell
572  {\ifhmode
573     \delayedendstrut
574     \par
575   \else
576     \par
577     \ifdim\prevdepth<\zeropoint % =-1000pt ?
578       \vskip-\strutdp
579     \else
580       \removebottomthings
581     \fi
582   \fi}
583
584% For historic reasons we support both nx/nc and ny/nr : maybe nx/ny becomes
585% obsolete some day. The let as well as the direct speed things up a bit. We
586% could also consider a \defaultxtableparameter.
587%
588% \c_tabl_x_nx\defaultxtableparameter\c!nc{\defaultxtableparameter\c!nx\plusone}
589% \c_tabl_x_ny\defaultxtableparameter\c!nr{\defaultxtableparameter\c!ny\plusone}
590%
591% Although this becomes kind of messy. It saves already time that we only check
592% for it when we have settings.
593
594% \def\tabl_x_set_hsize
595%   {\hsize.25\maxdimen} % let's be reasonable
596
597% \def\tabl_x_set_hsize
598%   {\edef\p_width{\xtableparameter\c!width}%
599%    \ifx\p_width\empty
600%      \hsize.25\maxdimen % is this really needed
601%    \fi}
602
603\let\tabl_x_set_hsize\relax
604
605\unexpanded\def\tabl_x_start_cell_reflow_width_yes[#settings]%
606  {\setbox\b_tabl_x\hpack\bgroup
607   \ifnum\c_tabl_x_nesting>\plusone
608     \letxtableparameter\c!width \v!fit  % overloads given width
609     \letxtableparameter\c!height\v!fit  % overloads given height
610   \fi
611   %
612   \letxtableparameter\c!nx\plusone
613   \letxtableparameter\c!ny\plusone
614   \letxtableparameter\c!nc\plusone
615   \letxtableparameter\c!nr\plusone
616   %
617   \setupcurrentxtable[#settings]%
618   %
619   \c_tabl_x_nx\directxtableparameter\c!nc\relax
620   \c_tabl_x_ny\directxtableparameter\c!nr\relax
621   \ifnum\c_tabl_x_nx=\plusone
622     \c_tabl_x_nx\directxtableparameter\c!nx\relax
623   \fi
624   \ifnum\c_tabl_x_ny=\plusone
625     \c_tabl_x_ny\directxtableparameter\c!ny\relax
626   \fi
627   %
628   \d_tabl_x_distance\xtableparameter\c!distance\relax
629   \clf_x_table_init_reflow_width_option{\xtableparameter\c!option}%
630   \inheritedxtableframed\bgroup
631   \tabl_x_begin_of_cell
632   \tabl_x_set_hsize}
633
634\unexpanded\def\tabl_x_start_cell_reflow_width_nop
635  {\setbox\b_tabl_x\hpack\bgroup
636   \ifnum\c_tabl_x_nesting>\plusone
637     \letxtableparameter\c!width \v!fit  % overloads given width
638     \letxtableparameter\c!height\v!fit  % overloads given height
639   \fi
640   \c_tabl_x_nx\plusone
641   \c_tabl_x_ny\plusone
642   \d_tabl_x_distance\xtableparameter\c!distance\relax
643   \clf_x_table_init_reflow_width
644   \inheritedxtableframed\bgroup
645   \tabl_x_begin_of_cell
646   \tabl_x_set_hsize}
647
648\unexpanded\def\tabl_x_stop_cell_reflow_width
649  {\tabl_x_end_of_cell
650   \egroup
651   \egroup
652   \clf_x_table_set_reflow_width}
653
654\unexpanded\def\tabl_x_start_cell_reflow_height_yes[#settings]%
655  {\setbox\b_tabl_x\hpack\bgroup
656   \clf_x_table_init_reflow_height
657   \ifcase\c_tabl_x_skip_mode % can be sped up
658     \ifnum\c_tabl_x_nesting>\plusone
659       \letxtableparameter\c!height\v!fit  % overloads given height
660     \fi
661     \setupcurrentxtable[#settings]%
662     \relax
663     \letxtableparameter\c!width\d_tabl_x_width  % overloads given width
664     \inheritedxtableframed\bgroup
665     \tabl_x_begin_of_cell
666   \fi}
667
668\unexpanded\def\tabl_x_start_cell_reflow_height_nop
669  {\setbox\b_tabl_x\hpack\bgroup
670   \clf_x_table_init_reflow_height
671   \ifcase\c_tabl_x_skip_mode % can be sped up
672     \ifnum\c_tabl_x_nesting>\plusone
673       \letxtableparameter\c!height\v!fit  % overloads given height
674     \fi
675     \relax
676     \letxtableparameter\c!width\d_tabl_x_width  % overloads given width
677     \inheritedxtableframed\bgroup
678     \tabl_x_begin_of_cell
679   \fi}
680
681\unexpanded\def\tabl_x_stop_cell_reflow_height
682  {\ifcase\c_tabl_x_skip_mode
683     \tabl_x_end_of_cell
684     \egroup
685   \fi
686   \egroup
687   \clf_x_table_set_reflow_height}
688
689\unexpanded\def\tabl_x_start_cell_construct_yes[#settings]%
690  {\dostarttagged\t!tablecell\empty % can't we just tag the box
691   \setbox\b_tabl_x\hpack\bgroup
692   \setupcurrentxtable[#settings]%
693   \letxtableparameter\c!width \d_tabl_x_width  % overloads given width
694   \letxtableparameter\c!height\d_tabl_x_height % overloads given height
695   \clf_x_table_init_construct
696   \inheritedxtableframed\bgroup
697   \tabl_x_begin_of_cell
698   \dotagxtablecell}
699
700\unexpanded\def\tabl_x_start_cell_construct_nop
701  {\dostarttagged\t!tablecell\empty % can't we just tag the box
702   \setbox\b_tabl_x\hpack\bgroup
703   \letxtableparameter\c!width \d_tabl_x_width  % overloads given width
704   \letxtableparameter\c!height\d_tabl_x_height % overloads given height (commenting it ... nice option)
705   \clf_x_table_init_construct
706   \inheritedxtableframed\bgroup
707   \tabl_x_begin_of_cell
708   \dotagxtablecell}
709
710\unexpanded\def\tabl_x_stop_cell_construct
711  {\tabl_x_end_of_cell
712   \egroup
713   \dotagxtablesignal % harmless spot
714   \egroup
715   \clf_x_table_set_construct
716   \dostoptagged}
717
718\unexpanded\def\startxcellgroup
719  {\begingroup
720   \dosingleempty\tabl_x_start_cell_group}
721
722\unexpanded\def\stopxcellgroup
723  {\endgroup}
724
725\unexpanded\def\tabl_x_start_cell_group[#settings]%
726  {\iffirstargument
727     \tabl_x_set_checked{#settings}%
728   \fi}
729
730\unexpanded\def\startxrowgroup
731  {\begingroup
732   \dosingleempty\tabl_x_start_row_group}
733
734\unexpanded\def\stopxrowgroup
735  {\dostoptagged
736   \endgroup}
737
738\unexpanded\def\tabl_x_start_row_group[#settings]%
739  {\iffirstargument
740     \tabl_x_set_checked{#settings}%
741   \fi}
742
743% \def\tabl_x_set_checked#settings
744%   {\doifassignmentelse{#settings}
745%      {\setupcurrentxtable[#settings]}
746%      {\ifcsname\namedxtablehash{#settings}\s!parent\endcsname
747%         \edef\currentxtable{#settings}%
748%       \fi}}
749
750\unexpanded\def\tabl_x_set_checked#settings%
751  {\ifcsname\namedxtablehash{#settings}\s!parent\endcsname
752     \edef\currentxtable{#settings}%
753   \else
754     \setupcurrentxtable[#settings]%
755   \fi}
756
757\unexpanded\def\startxtablehead{\begingroup\c_tabl_x_mode\plusone  \dosingleempty\tabl_x_start_partition}
758\unexpanded\def\startxtablefoot{\begingroup\c_tabl_x_mode\plustwo  \dosingleempty\tabl_x_start_partition}
759\unexpanded\def\startxtablenext{\begingroup\c_tabl_x_mode\plusthree\dosingleempty\tabl_x_start_partition}
760\unexpanded\def\startxtablebody{\begingroup\c_tabl_x_mode\plusfour \dosingleempty\tabl_x_start_partition}
761
762\unexpanded\def\tabl_x_start_partition[#settings]%
763  {\iffirstargument
764     \tabl_x_set_checked{#settings}%
765   \fi}
766
767\unexpanded\def\tabl_x_stop_partition
768  {\endgroup}
769
770\let\stopxtablehead\tabl_x_stop_partition
771\let\stopxtablefoot\tabl_x_stop_partition
772\let\stopxtablenext\tabl_x_stop_partition
773\let\stopxtablebody\tabl_x_stop_partition
774
775%D This is an experiment! Beware: you can create loops by using nested
776%D references to already chained settings.
777%D
778%D \startbuffer
779%D \setupxtable[suffix][align=middle,foregroundcolor=red]
780%D \setupxtable[blabla][foregroundstyle=slanted]
781%D \setupxtable[crap]  [foregroundcolor=blue]
782%D \setupxtable[bold]  [crap][foregroundstyle=bold]
783%D
784%D \startxtable[frame=off]
785%D     \startxtablehead
786%D         \startxrow[bold]
787%D             \startxcell[suffix] a 0 \stopxcell
788%D             \startxcell[blabla] a 1 \stopxcell
789%D             \startxcell         a 2 \stopxcell
790%D         \stopxrow
791%D     \stopxtablehead
792%D     \startxtablebody
793%D         \startxrow \startxcell[suffix][ny=2] a 1 \stopxcell \startxcell b 1 \stopxcell \startxcell c 1 \stopxcell \stopxrow
794%D         \startxrow                                          \startxcell b 2 \stopxcell \startxcell c 2 \stopxcell \stopxrow
795%D         \startxrow \startxcell[suffix]       a 3 \stopxcell \startxcell b 3 \stopxcell \startxcell c 3 \stopxcell \stopxrow
796%D         \startxrow \startxcell[suffix]       a 4 \stopxcell \startxcell b 4 \stopxcell \startxcell c 4 \stopxcell \stopxrow
797%D         \startxrow \startxcell[suffix]       a 5 \stopxcell \startxcell b 5 \stopxcell \startxcell c 5 \stopxcell \stopxrow
798%D     \stopxtablebody
799%D \stopxtable
800%D \stopbuffer
801%D
802%D \typebuffer \placetable{}{\getbuffer}
803
804\appendtoks
805    \letvalue{\??xtablecheck\currentxtable}\relax % faster than checking parent
806\to \everysetupxtable
807
808% \definefontfamily[newtimes][serif][TeX Gyre Termes]
809% \setupxtable[newtimes][foregroundstyle=\newtimes]
810% \startxcell[newtimes]                  ...\stopxcell
811% \startxcell[foregroundstyle=\newtimes] ...\stopxcell
812
813% % \ifcsname\namedxtablehash{#tag}\s!parent\endcsname
814% % \ifcsname\??xtablecheck#tag\endcsname
815%   \ifcsname\??xtablecheck\detokenize\expandafter{\normalexpanded{#tag}}\endcsname % two times slower on keywords
816%     \expandafter\whatever                                                         % but more tolerant for tricky key=value
817%   \else
818%     \expandafter\whatever
819%   \fi[#tag]
820
821% groups
822
823\unexpanded\def\startxgroup
824  {\begingroup
825   \doifelsenextoptionalcs\tabl_x_start_group_delayed_one\relax}
826
827\unexpanded\def\stopxgroup
828  {\endgroup}
829
830\unexpanded\def\tabl_x_start_group_delayed_one[#tag]%
831  {\ifcsname\??xtablecheck\detokenize\expandafter{\normalexpanded{#tag}}\endcsname
832     \expandafter\tabl_x_start_group_delayed_two
833   \else
834     \expandafter\setupcurrentxtable
835   \fi[#tag]}
836
837\unexpanded\def\tabl_x_start_group_delayed_two[#tag]%
838  {\ifx\currentxtable\empty \else
839     \chaintocurrentxtable{#tag}%
840   \fi
841   \edef\currentxtable{#tag}%
842   \doifelsenextoptionalcs\setupcurrentxtable\relax}
843
844\let\startxrowgroup \startxgroup
845\let\stopxrowgroup  \stopxgroup
846\let\startxcellgroup\startxgroup
847\let\stopxcellgroup \stopxgroup
848
849% cells (maybe also check for 1 etc but it becomes messy)
850
851\unexpanded\def\startxcell
852  {\begingroup
853   \doifelsenextoptionalcs\tabl_x_start_cell_delayed_one\tabl_x_start_cell_nop}
854
855\unexpanded\def\tabl_x_start_cell_delayed_one[#tag]%
856  {\ifcsname\??xtablecheck\detokenize\expandafter{\normalexpanded{#tag}}\endcsname
857     \expandafter\tabl_x_start_cell_delayed_two
858   \else
859     \expandafter\tabl_x_start_cell_yes
860   \fi[#tag]}
861
862\unexpanded\def\tabl_x_start_cell_delayed_two[#tag]%
863  {\ifx\currentxtable\empty \else
864     \chaintocurrentxtable{#tag}%
865   \fi
866   \edef\currentxtable{#tag}%
867   \doifelsenextoptionalcs\tabl_x_start_cell_yes\tabl_x_start_cell_nop}
868
869\unexpanded\def\stopxcell
870  {\tabl_x_stop_cell
871   \endgroup}
872
873% rows
874
875\unexpanded\def\startxrow
876  {\begingroup
877   \doifelsenextoptionalcs\tabl_x_start_row_delayed_one\tabl_x_start_row_nop}
878
879\unexpanded\def\tabl_x_start_row_delayed_one[#tag]%
880  {\ifcsname\??xtablecheck\detokenize\expandafter{\normalexpanded{#tag}}\endcsname
881     \expandafter\tabl_x_start_row_delayed_two
882   \else
883     \expandafter\tabl_x_start_row_yes
884   \fi[#tag]}
885
886\unexpanded\def\tabl_x_start_row_delayed_two[#tag]%
887  {\ifx\currentxtable\empty \else
888     \chaintocurrentxtable{#tag}%
889   \fi
890   \edef\currentxtable{#tag}%
891   \doifelsenextoptionalcs\tabl_x_start_row_yes\tabl_x_start_row_nop}
892
893\unexpanded\def\stopxrow
894  {\tabl_x_stop_row
895   \endgroup}
896
897%D A bonus, not advertised but some like it this way:
898
899\unexpanded\def\tabl_x_nc
900  {\startxrow
901   \let\NC\tabl_x_nc_next
902   \let\NR\tabl_x_nr
903   \startxcell}
904
905\unexpanded\def\tabl_x_nc_next
906  {\stopxcell
907   \startxcell}
908
909\unexpanded\def\tabl_x_nr
910  {\stopxcell
911   \stopxrow
912   \let\NC\tabl_x_nc}
913
914\appendtoks
915   \let\NC\tabl_x_nc
916   \let\NR\tabl_x_nr
917\to \everypreparextable
918
919%D Another bonus, suggested by Taco at the 2018 \CONTEXT\ meeting.
920
921\unexpanded\def\tabl_x_c_cell_start#settings%
922  {\begingroup
923   \tabl_x_set_checked{#settings}%
924   \doifelsenextoptionalcs\tabl_x_start_cell_yes\tabl_x_start_cell_nop}
925
926\unexpanded\def\tabl_x_c_cell_stop
927  {\tabl_x_stop_cell
928   \endgroup}
929
930% \unexpanded\def\dummyxcell
931%   {\tabl_x_start_cell_nop
932%    \tabl_x_stop_cell}
933
934\def\tabl_x_flush_swapped
935  {\dorecurse\c_tabl_x_swapped_max
936     {\expandafter
937      \startxrow
938        \the\csname\??xtableswap##1\endcsname\relax
939      \stopxrow}}
940
941\def\tabl_x_collect_allocate
942  {\expandafter\newtoks\csname\??xtableswap\number\c_tabl_x_swapped\endcsname
943   \expandafter\let\expandafter\t_tabl_x_swapped\csname\??xtableswap\number\c_tabl_x_swapped\endcsname}
944
945\def\tabl_x_collect_advance
946  {\global\advance\c_tabl_x_swapped\plusone
947   \ifnum\c_tabl_x_swapped>\c_tabl_x_swapped_max
948     \global\c_tabl_x_swapped_max\c_tabl_x_swapped
949   \fi
950   \expandafter\let\expandafter\t_tabl_x_swapped\csname\??xtableswap\number\c_tabl_x_swapped\endcsname
951   \ifx\t_tabl_x_swapped\relax
952     \tabl_x_collect_allocate
953   \fi}
954
955\unexpanded\def\tabl_x_collect_cell_start
956  {\doifelsenextoptionalcs
957     \tabl_x_collect_cell_start_yes
958     \tabl_x_collect_cell_start_nop}
959
960\def\tabl_x_collect_cell_start_nop#content\stopxcell
961  {\tabl_x_collect_advance
962   \ifx\m_tabl_x_swapped_settings\empty
963     \gtoksapp\t_tabl_x_swapped{\tabl_x_c_cell_start{}#content\tabl_x_c_cell_stop}%
964   \else
965     \gtoksapp\t_tabl_x_swapped\expandafter{\expandafter\tabl_x_c_cell_start\expandafter{\m_tabl_x_swapped_settings}#content\tabl_x_c_cell_stop}%
966   \fi}
967
968\def\tabl_x_collect_cell_start_yes[#settings]#content\stopxcell
969  {\tabl_x_collect_advance
970   \ifx\m_tabl_x_swapped_settings\empty
971     \gtoksapp\t_tabl_x_swapped{\tabl_x_c_cell_start{}[#settings]#content\tabl_x_c_cell_stop}%
972   \else
973     \gtoksapp\t_tabl_x_swapped\expandafter{\expandafter\tabl_x_c_cell_start\expandafter{\m_tabl_x_swapped_settings}[#settings]#content\tabl_x_c_cell_stop}%
974   \fi
975   \getdummyparameters[\c!ny=1,#settings]%
976   \scratchcounter\numexpr\dummyparameter\c!ny-\plusone\relax
977   \ifcase\scratchcounter\else
978     \dorecurse\scratchcounter\tabl_x_collect_advance
979   \fi}
980
981\unexpanded\def\startxcolumn % todo: arguments
982  {\begingroup
983   \global\c_tabl_x_swapped\zerocount
984   \let\startxcell\tabl_x_collect_cell_start
985   \let\stopxcell \relax
986   \doifelsenextoptionalcs\tabl_x_start_column_yes\tabl_x_start_column_nop}
987
988\def\tabl_x_start_column_yes[#1]%
989  {\xdef\m_tabl_x_swapped_settings{#1}}
990
991\def\tabl_x_start_column_nop
992  {\glet\m_tabl_x_swapped_settings\empty}
993
994\unexpanded\def\stopxcolumn
995  {\endgroup}
996
997\appendtoks
998    \dorecurse\c_tabl_x_swapped_max
999      {\global\csname\??xtableswap\number#1\endcsname\emptytoks}%
1000\to \t_table_x_cleanup
1001
1002%D \stopbuffer
1003%D \setupxtable[one][foregroundcolor=red]
1004%D \setupxtable[two][foregroundcolor=blue]
1005%D
1006%D \startlinecorrection
1007%D \startxtable
1008%D    \startxrow[one]
1009%D        \startxcell[width=5cm] Row 1, Column 1 \stopxcell
1010%D        \startxcell Row 1, Column 2 \stopxcell
1011%D        \startxcell Row 1, Column 3 \stopxcell
1012%D    \stopxrow
1013%D    \startxrow[two]
1014%D        \startxcell Row 2, Column 1 \stopxcell
1015%D        \startxcell Row 2, Column 2 \stopxcell
1016%D        \startxcell Row 2, Column 3 \stopxcell
1017%D    \stopxrow
1018%D \stopxtable
1019%D \stoplinecorrection
1020%D
1021%D \startlinecorrection
1022%D \startxtable
1023%D    \startxcolumn[one]
1024%D        \startxcell[width=5cm] Row 1, Column 1 \stopxcell
1025%D        \startxcell Row 1, Column 2 \stopxcell
1026%D        \startxcell Row 1, Column 3 \stopxcell
1027%D    \stopxcolumn
1028%D    \startxcolumn[two]
1029%D        \startxcell Row 2, Column 1 \stopxcell
1030%D        \startxcell Row 2, Column 2 \stopxcell
1031%D        \startxcell Row 2, Column 3 \stopxcell
1032%D    \stopxcolumn
1033%D \stopxtable
1034%D \stoplinecorrection
1035%D \stopbuffer
1036%D
1037%D \typebuffer \getbuffer
1038
1039\protect \endinput
1040