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