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