1if not modules then modules = { } end modules ['tabl-xtb'] = {
2 version = 1.001,
3 comment = "companion to tabl-xtb.mkvi",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
25
26
27
28
29local tonumber, next = tonumber, next
30
31local commands = commands
32local context = context
33local ctxnode = context.nodes.flush
34
35local implement = interfaces.implement
36
37local tex = tex
38local texgetcount = tex.getcount
39local texsetcount = tex.setcount
40local texgetdimen = tex.getdimen
41local texsetdimen = tex.setdimen
42local texget = tex.get
43
44local format = string.format
45local concat = table.concat
46local points = number.points
47
48local todimen = string.todimen
49
50local ctx_beginvbox = context.beginvbox
51local ctx_endvbox = context.endvbox
52local ctx_blank = context.blank
53local ctx_nointerlineskip = context.nointerlineskip
54local ctx_dummyxcell = context.dummyxcell
55
56local variables = interfaces.variables
57
58local setmetatableindex = table.setmetatableindex
59local settings_to_hash = utilities.parsers.settings_to_hash
60
61local nuts = nodes.nuts
62local tonut = nuts.tonut
63local tonode = nuts.tonode
64
65local getnext = nuts.getnext
66local getprev = nuts.getprev
67local getlist = nuts.getlist
68local getwidth = nuts.getwidth
69local getbox = nuts.getbox
70local getwhd = nuts.getwhd
71
72local setlink = nuts.setlink
73local setdirection = nuts.setdirection
74local setshift = nuts.setshift
75
76local copynodelist = nuts.copylist
77local hpacknodelist = nuts.hpack
78local flushnodelist = nuts.flushlist
79local takebox = nuts.takebox
80
81local nodepool = nuts.pool
82
83local new_glue = nodepool.glue
84local new_kern = nodepool.kern
85local new_hlist = nodepool.hlist
86
87local lefttoright_code = nodes.dirvalues.lefttoright
88
89local v_stretch = variables.stretch
90local v_normal = variables.normal
91local v_width = variables.width
92local v_height = variables.height
93local v_repeat = variables["repeat"]
94local v_max = variables.max
95local v_fixed = variables.fixed
96
97local v_before = variables.before
98local v_after = variables.after
99local v_both = variables.both
100local v_samepage = variables.samepage
101local v_tight = variables.tight
102
103local xtables = { }
104typesetters.xtables = xtables
105
106local trace_xtable = false
107local report_xtable = logs.reporter("xtable")
108
109trackers.register("xtable.construct", function(v) trace_xtable = v end)
110
111local null_mode = 0
112local head_mode = 1
113local foot_mode = 2
114local more_mode = 3
115local body_mode = 4
116
117local namedmodes = { [0] =
118 "null",
119 "head",
120 "foot",
121 "next",
122 "body",
123}
124
125local stack, data = { }, nil
126
127function xtables.create(settings)
128 table.insert(stack,data)
129 local rows = { }
130 local widths = { }
131 local heights = { }
132 local depths = { }
133
134 local distances = { }
135 local autowidths = { }
136 local modes = { }
137 local fixedrows = { }
138 local fixedcolumns = { }
139
140 local frozencolumns = { }
141 local options = { }
142 local rowproperties = { }
143 data = {
144 rows = rows,
145 widths = widths,
146 heights = heights,
147 depths = depths,
148
149 distances = distances,
150 modes = modes,
151 autowidths = autowidths,
152 fixedrows = fixedrows,
153 fixedcolumns = fixedcolumns,
154
155 frozencolumns = frozencolumns,
156 options = options,
157 nofrows = 0,
158 nofcolumns = 0,
159 currentrow = 0,
160 currentcolumn = 0,
161 settings = settings or { },
162 rowproperties = rowproperties,
163 }
164 local function add_zero(t,k)
165 t[k] = 0
166 return 0
167 end
168 local function add_table(t,k)
169 local v = { }
170 t[k] = v
171 return v
172 end
173 local function add_cell(row,c)
174 local cell = {
175 nx = 0,
176 ny = 0,
177 list = false,
178 wd = 0,
179 ht = 0,
180 dp = 0,
181 }
182 row[c] = cell
183 if c > data.nofcolumns then
184 data.nofcolumns = c
185 end
186 return cell
187 end
188 local function add_row(rows,r)
189 local row = { }
190 setmetatableindex(row,add_cell)
191 rows[r] = row
192 if r > data.nofrows then
193 data.nofrows = r
194 end
195 return row
196 end
197 setmetatableindex(rows,add_row)
198 setmetatableindex(widths,add_zero)
199 setmetatableindex(heights,add_zero)
200 setmetatableindex(depths,add_zero)
201 setmetatableindex(distances,add_zero)
202 setmetatableindex(modes,add_zero)
203 setmetatableindex(fixedrows,add_zero)
204 setmetatableindex(fixedcolumns,add_zero)
205 setmetatableindex(options,add_table)
206
207
208 local globaloptions = settings_to_hash(settings.option)
209
210 settings.columndistance = tonumber(settings.columndistance) or 0
211 settings.rowdistance = tonumber(settings.rowdistance) or 0
212 settings.leftmargindistance = tonumber(settings.leftmargindistance) or 0
213 settings.rightmargindistance = tonumber(settings.rightmargindistance) or 0
214 settings.options = globaloptions
215 settings.textwidth = tonumber(settings.textwidth) or texget("hsize")
216 settings.lineheight = tonumber(settings.lineheight) or texgetdimen("lineheight")
217 settings.maxwidth = tonumber(settings.maxwidth) or settings.textwidth/8
218
219
220
221 data.criterium_v = 2 * data.settings.lineheight
222 data.criterium_h = .75 * data.settings.textwidth
223
224 data.tight = globaloptions[v_tight] and true or false
225end
226
227function xtables.initialize_reflow_width(option,width)
228 local r = data.currentrow
229 local c = data.currentcolumn + 1
230 local drc = data.rows[r][c]
231 drc.nx = texgetcount("c_tabl_x_nx")
232 drc.ny = texgetcount("c_tabl_x_ny")
233 local distances = data.distances
234 local distance = texgetdimen("d_tabl_x_distance")
235 if distance > distances[c] then
236 distances[c] = distance
237 end
238 if option and option ~= "" then
239 local options = settings_to_hash(option)
240 data.options[r][c] = options
241 if options[v_fixed] then
242 data.frozencolumns[c] = true
243 end
244 end
245 data.currentcolumn = c
246end
247
248
249
250function xtables.set_reflow_width()
251 local r = data.currentrow
252 local c = data.currentcolumn
253 local rows = data.rows
254 local row = rows[r]
255 local cold = c
256 while row[c].span do
257 c = c + 1
258 end
259
260 if c > cold then
261 local ro = row[cold]
262 local rx = ro.nx
263 local ry = ro.ny
264 if rx > 1 or ry > 1 then
265 local rn = row[c]
266 rn.nx = rx
267 rn.ny = ry
268 ro.nx = 1
269 ro.ny = 1
270
271 end
272 end
273 local tb = getbox("b_tabl_x")
274 local drc = row[c]
275
276 drc.list = true
277
278 local width, height, depth = getwhd(tb)
279
280 local widths = data.widths
281 local heights = data.heights
282 local depths = data.depths
283 local cspan = drc.nx
284 if cspan < 2 then
285 if width > widths[c] then
286 widths[c] = width
287 end
288 else
289 local options = data.options[r][c]
290 if data.tight then
291
292 elseif not options then
293 if width > widths[c] then
294 widths[c] = width
295 end
296 elseif not options[v_tight] then
297 if width > widths[c] then
298 widths[c] = width
299 end
300 end
301 end
302
303
304
305
306
307
308
309 if drc.ny < 2 then
310
311
312 if height > heights[r] then
313 heights[r] = height
314 end
315 if depth > depths[r] then
316 depths[r] = depth
317 end
318 end
319
320 drc.wd = width
321 drc.ht = height
322 drc.dp = depth
323
324 local dimensionstate = texgetcount("frameddimensionstate")
325 local fixedcolumns = data.fixedcolumns
326 local fixedrows = data.fixedrows
327 if dimensionstate == 1 then
328 if cspan > 1 then
329
330 elseif width > fixedcolumns[c] then
331 fixedcolumns[c] = width
332 end
333 elseif dimensionstate == 2 then
334 fixedrows[r] = height
335 elseif dimensionstate == 3 then
336 fixedrows[r] = height
337 fixedcolumns[c] = width
338 elseif width <= data.criterium_h and height >= data.criterium_v then
339
340 if width > fixedcolumns[c] then
341
342 fixedcolumns[c] = width
343 end
344 end
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378 drc.dimensionstate = dimensionstate
379
380 local nx = drc.nx
381 local ny = drc.ny
382 if nx > 1 or ny > 1 then
383
384 local self = true
385 for y=1,ny do
386 for x=1,nx do
387 if self then
388 self = false
389 else
390 local ry = r + y - 1
391 local cx = c + x - 1
392
393
394
395 rows[ry][cx].span = true
396 end
397 end
398 end
399 c = c + nx - 1
400 end
401 if c > data.nofcolumns then
402 data.nofcolumns = c
403 end
404 data.currentcolumn = c
405end
406
407function xtables.initialize_reflow_height()
408 local r = data.currentrow
409 local c = data.currentcolumn + 1
410 local rows = data.rows
411 local row = rows[r]
412 while row[c].span do
413 c = c + 1
414 end
415 data.currentcolumn = c
416 local widths = data.widths
417 local w = widths[c]
418 local drc = row[c]
419 for x=1,drc.nx-1 do
420 w = w + widths[c+x]
421 end
422 texsetdimen("d_tabl_x_width",w)
423 local dimensionstate = drc.dimensionstate or 0
424 if dimensionstate == 1 or dimensionstate == 3 then
425
426 texsetcount("c_tabl_x_skip_mode",1)
427 elseif dimensionstate == 2 then
428
429 texsetcount("c_tabl_x_skip_mode",1)
430 elseif data.autowidths[c] then
431
432 texsetcount("c_tabl_x_skip_mode",0)
433 elseif data.fixedcolumns[c] then
434 texsetcount("c_tabl_x_skip_mode",0)
435 else
436 texsetcount("c_tabl_x_skip_mode",1)
437 end
438end
439
440function xtables.set_reflow_height()
441 local r = data.currentrow
442 local c = data.currentcolumn
443 local rows = data.rows
444 local row = rows[r]
445
446
447
448 local tb = getbox("b_tabl_x")
449 local drc = row[c]
450
451 local width, height, depth = getwhd(tb)
452
453 if drc.ny < 2 then
454 if data.fixedrows[r] == 0 then
455 if drc.ht + drc.dp <= height + depth then
456 local heights = data.heights
457 local depths = data.depths
458
459
460 if height > heights[r] then
461 heights[r] = height
462 end
463 if depth > depths[r] then
464 depths[r] = depth
465 end
466 end
467 end
468 end
469
470 drc.wd = width
471 drc.ht = height
472 drc.dp = depth
473
474
475
476end
477
478function xtables.initialize_construct()
479 local r = data.currentrow
480 local c = data.currentcolumn + 1
481 local settings = data.settings
482 local rows = data.rows
483 local row = rows[r]
484 while row[c].span do
485 c = c + 1
486 end
487 data.currentcolumn = c
488 local widths = data.widths
489 local heights = data.heights
490 local depths = data.depths
491 local distances = data.distances
492
493 local drc = row[c]
494 local wd = drc.wd
495 local ht = drc.ht
496 local dp = drc.dp
497 local nx = drc.nx - 1
498 local ny = drc.ny - 1
499
500 local width = widths[c]
501 local height = heights[r]
502 local depth = depths[r]
503
504 local total = height + depth
505
506 if nx > 0 then
507 for x=1,nx do
508 width = width + widths[c+x] + distances[c+x-1]
509 end
510 local distance = settings.columndistance
511 if distance ~= 0 then
512 width = width + nx * distance
513 end
514 end
515
516 if ny > 0 then
517 for y=1,ny do
518 local nxt = r + y
519 total = total + heights[nxt] + depths[nxt]
520 end
521 local distance = settings.rowdistance
522 if distance ~= 0 then
523 total = total + ny * distance
524 end
525 end
526
527 texsetdimen("d_tabl_x_width",width)
528 texsetdimen("d_tabl_x_height",total)
529 texsetdimen("d_tabl_x_depth",0)
530end
531
532function xtables.set_construct()
533 local r = data.currentrow
534 local c = data.currentcolumn
535 local rows = data.rows
536 local row = rows[r]
537
538
539
540 local drc = row[c]
541
542 drc.list = takebox("b_tabl_x")
543
544
545end
546
547local function showwidths(where,widths,autowidths)
548 local result = { }
549 for i=1,#widths do
550 result[#result+1] = format("%12s%s",points(widths[i]),autowidths[i] and "*" or " ")
551 end
552 return report_xtable("%s widths: %s",where,concat(result," "))
553end
554
555function xtables.reflow_width()
556 local nofrows = data.nofrows
557 local nofcolumns = data.nofcolumns
558 local rows = data.rows
559 for r=1,nofrows do
560 local row = rows[r]
561 for c=1,nofcolumns do
562 local drc = row[c]
563 if drc.list then
564
565 drc.list = false
566 end
567 end
568 end
569
570 local settings = data.settings
571 local options = settings.options
572 local maxwidth = settings.maxwidth
573
574 local widths = data.widths
575 local heights = data.heights
576 local depths = data.depths
577 local distances = data.distances
578 local autowidths = data.autowidths
579 local fixedcolumns = data.fixedcolumns
580 local frozencolumns = data.frozencolumns
581 local width = 0
582 local distance = 0
583 local nofwide = 0
584 local widetotal = 0
585 local available = settings.textwidth - settings.leftmargindistance - settings.rightmargindistance
586 if trace_xtable then
587 showwidths("stage 1",widths,autowidths)
588 end
589 local noffrozen = 0
590
591 if options[v_max] then
592 for c=1,nofcolumns do
593 width = width + widths[c]
594 if width > maxwidth then
595 autowidths[c] = true
596 nofwide = nofwide + 1
597 widetotal = widetotal + widths[c]
598 end
599 if c < nofcolumns then
600 distance = distance + distances[c]
601 end
602 if frozencolumns[c] then
603 noffrozen = noffrozen + 1
604 end
605 end
606 else
607 for c=1,nofcolumns do
608 local fixedwidth = fixedcolumns[c]
609 if fixedwidth > 0 then
610 widths[c] = fixedwidth
611 width = width + fixedwidth
612 else
613 local wc = widths[c]
614 width = width + wc
615
616 if wc > maxwidth then
617 autowidths[c] = true
618 nofwide = nofwide + 1
619 widetotal = widetotal + wc
620 end
621 end
622 if c < nofcolumns then
623 distance = distance + distances[c]
624 end
625 if frozencolumns[c] then
626 noffrozen = noffrozen + 1
627 end
628 end
629 end
630 if trace_xtable then
631 showwidths("stage 2",widths,autowidths)
632 end
633 local delta = available - width - distance - (nofcolumns-1) * settings.columndistance
634 if delta == 0 then
635
636 if trace_xtable then
637 report_xtable("perfect fit")
638 end
639 elseif delta > 0 then
640
641 if not options[v_stretch] then
642
643 if trace_xtable then
644 report_xtable("too wide but no stretch, delta %p",delta)
645 end
646 elseif options[v_width] then
647 local factor = delta / width
648 if trace_xtable then
649 report_xtable("proportional stretch, delta %p, width %p, factor %a",delta,width,factor)
650 end
651 for c=1,nofcolumns do
652 widths[c] = widths[c] + factor * widths[c]
653 end
654 else
655
656 local extra = delta / (nofcolumns - noffrozen)
657 if trace_xtable then
658 report_xtable("normal stretch, delta %p, extra %p",delta,extra)
659 end
660 for c=1,nofcolumns do
661 if not frozencolumns[c] then
662 widths[c] = widths[c] + extra
663 end
664 end
665 end
666 elseif nofwide > 0 then
667 while true do
668 done = false
669 local available = (widetotal + delta) / nofwide
670 if trace_xtable then
671 report_xtable("shrink check, total %p, delta %p, columns %s, fixed %p",widetotal,delta,nofwide,available)
672 end
673 for c=1,nofcolumns do
674 if autowidths[c] and available >= widths[c] then
675 autowidths[c] = nil
676 nofwide = nofwide - 1
677 widetotal = widetotal - widths[c]
678 done = true
679 end
680 end
681 if not done then
682 break
683 end
684 end
685
686
687 if options[v_width] then
688 local factor = (widetotal + delta) / width
689 if trace_xtable then
690 report_xtable("proportional shrink used, total %p, delta %p, columns %s, factor %s",widetotal,delta,nofwide,factor)
691 end
692 for c=1,nofcolumns do
693 if autowidths[c] then
694 widths[c] = factor * widths[c]
695 end
696 end
697 else
698 local available = (widetotal + delta) / nofwide
699 if trace_xtable then
700 report_xtable("normal shrink used, total %p, delta %p, columns %s, fixed %p",widetotal,delta,nofwide,available)
701 end
702 for c=1,nofcolumns do
703 if autowidths[c] then
704 widths[c] = available
705 end
706 end
707 end
708 end
709 if trace_xtable then
710 showwidths("stage 3",widths,autowidths)
711 end
712
713 data.currentrow = 0
714 data.currentcolumn = 0
715end
716
717function xtables.reflow_height()
718 data.currentrow = 0
719 data.currentcolumn = 0
720 local settings = data.settings
721
722
723
724 local nofrows = data.nofrows
725 local nofcolumns = data.nofcolumns
726 local widths = data.widths
727 local heights = data.heights
728 local depths = data.depths
729
730 for r=1,nofrows do
731 for c=1,nofcolumns do
732 local drc = data.rows[r][c]
733 if drc then
734 local ny = drc.ny
735 if ny > 1 then
736 local height = heights[r]
737 local depth = depths[r]
738 local total = height + depth
739 local htdp = drc.ht + drc.dp
740 for y=1,ny-1 do
741 local nxt = r + y
742 total = total + heights[nxt] + depths[nxt]
743 end
744 local delta = htdp - total
745 if delta > 0 then
746 delta = delta / ny
747 for y=0,ny-1 do
748 local nxt = r + y
749 heights[nxt] = heights[nxt] + delta
750 end
751 end
752 end
753 end
754 end
755 end
756
757 if settings.options[v_height] then
758 local totalheight = 0
759 local totaldepth = 0
760 for i=1,nofrows do
761 totalheight = totalheight + heights[i]
762 totalheight = totalheight + depths [i]
763 end
764 local total = totalheight + totaldepth
765 local leftover = settings.textheight - total
766 if leftover > 0 then
767 local leftheight = (totalheight / total) * leftover / #heights
768 local leftdepth = (totaldepth / total) * leftover / #depths
769 for i=1,nofrows do
770 heights[i] = heights[i] + leftheight
771 depths [i] = depths [i] + leftdepth
772 end
773 end
774 end
775end
776
777local function showspans(data)
778 local rows = data.rows
779 local modes = data.modes
780 local nofcolumns = data.nofcolumns
781 local nofrows = data.nofrows
782 for r=1,nofrows do
783 local line = { }
784 local row = rows[r]
785 for c=1,nofcolumns do
786 local cell =row[c]
787 if cell.list then
788 line[#line+1] = "list"
789 elseif cell.span then
790 line[#line+1] = "span"
791 else
792 line[#line+1] = "none"
793 end
794 end
795 report_xtable("%3d : %s : % t",r,namedmodes[modes[r]] or "----",line)
796 end
797end
798
799function xtables.construct()
800 local rows = data.rows
801 local heights = data.heights
802 local depths = data.depths
803 local widths = data.widths
804
805 local distances = data.distances
806 local modes = data.modes
807 local settings = data.settings
808 local nofcolumns = data.nofcolumns
809 local nofrows = data.nofrows
810 local columndistance = settings.columndistance
811 local rowdistance = settings.rowdistance
812 local leftmargindistance = settings.leftmargindistance
813 local rightmargindistance = settings.rightmargindistance
814 local rowproperties = data.rowproperties
815
816
817 if trace_xtable then
818 showspans(data)
819 end
820
821 local ranges = {
822 [head_mode] = { },
823 [foot_mode] = { },
824 [more_mode] = { },
825 [body_mode] = { },
826 }
827 for r=1,nofrows do
828 local m = modes[r]
829 if m == 0 then
830 m = body_mode
831 end
832 local range = ranges[m]
833 range[#range+1] = r
834 end
835
836
837
838 local function packaged_column(r)
839 local row = rows[r]
840 local start = nil
841 local stop = nil
842 if leftmargindistance > 0 then
843 start = new_kern(leftmargindistance)
844 stop = start
845 end
846 local hasspan = false
847 for c=1,nofcolumns do
848 local drc = row[c]
849 if not hasspan then
850 hasspan = drc.span
851 end
852 local list = drc.list
853 if list then
854 local w, h, d = getwhd(list)
855 setshift(list,h+d)
856
857
858
859 local h = new_hlist(list)
860 list = h
861
862 if start then
863 setlink(stop,list)
864 else
865 start = list
866 end
867 stop = list
868 end
869 local step = widths[c]
870 if c < nofcolumns then
871 step = step + columndistance + distances[c]
872 end
873 local kern = new_kern(step)
874 if stop then
875 setlink(stop,kern)
876 else
877 start = kern
878 end
879 stop = kern
880 end
881 if start then
882 if rightmargindistance > 0 then
883 local kern = new_kern(rightmargindistance)
884 setlink(stop,kern)
885
886 end
887 return start, heights[r] + depths[r], hasspan
888 end
889 end
890 local function collect_range(range)
891 local result, nofr = { }, 0
892 local nofrange = #range
893 for i=1,#range do
894 local r = range[i]
895
896 local list, size, hasspan = packaged_column(r)
897 if list then
898 if hasspan and nofr > 0 then
899 result[nofr][4] = true
900 end
901 nofr = nofr + 1
902 local rp = rowproperties[r]
903
904
905 local hbox = hpacknodelist(list)
906 setdirection(hbox,lefttoright_code)
907 result[nofr] = {
908 hbox,
909 size,
910 i < nofrange and rowdistance > 0 and rowdistance or false,
911 false,
912 rp or false,
913 }
914 end
915 end
916 if nofr > 0 then
917
918 result[1] [5] = false
919 result[nofr][5] = false
920 for i=2,nofr-1 do
921 local r = result[i][5]
922 if r == v_both or r == v_before then
923 result[i-1][5] = true
924 elseif r == v_after then
925 result[i][5] = true
926 end
927 end
928 end
929 return result
930 end
931 local body = collect_range(ranges[body_mode])
932 data.results = {
933 [head_mode] = collect_range(ranges[head_mode]),
934 [foot_mode] = collect_range(ranges[foot_mode]),
935 [more_mode] = collect_range(ranges[more_mode]),
936 [body_mode] = body,
937 }
938 if #body == 0 then
939 texsetcount("global","c_tabl_x_state",0)
940 texsetdimen("global","d_tabl_x_final_width",0)
941 else
942 texsetcount("global","c_tabl_x_state",1)
943 texsetdimen("global","d_tabl_x_final_width",getwidth(body[1][1]))
944 end
945end
946
947
948
949local function inject(row,copy,package)
950 local list = row[1]
951 if copy then
952 row[1] = copynodelist(list)
953 end
954 if package then
955 ctx_beginvbox()
956 ctxnode(tonode(list))
957 ctxnode(tonode(new_kern(row[2])))
958 ctx_endvbox()
959 ctx_nointerlineskip()
960 if row[4] then
961
962 elseif row[5] then
963 if row[3] then
964 ctx_blank { v_samepage, row[3] .. "sp" }
965 else
966 ctx_blank { v_samepage }
967 end
968 elseif row[3] then
969 ctx_blank { row[3] .. "sp" }
970 else
971 ctxnode(tonode(new_glue(0)))
972 end
973 else
974 ctxnode(tonode(list))
975 ctxnode(tonode(new_kern(row[2])))
976 if row[3] then
977 ctxnode(tonode(new_glue(row[3])))
978 end
979 end
980end
981
982local function total(row,distance)
983 local n = #row > 0 and rowdistance or 0
984 for i=1,#row do
985 local ri = row[i]
986 n = n + ri[2] + (ri[3] or 0)
987 end
988 return n
989end
990
991
992
993
994
995
996
997
998
999
1000
1001
1002local function spanheight(body,i)
1003 local height, n = 0, 1
1004 while true do
1005 local bi = body[i]
1006 if bi then
1007 height = height + bi[2] + (bi[3] or 0)
1008 if bi[4] then
1009 n = n + 1
1010 i = i + 1
1011 else
1012 break
1013 end
1014 else
1015 break
1016 end
1017 end
1018 return height, n
1019end
1020
1021function xtables.flush(directives)
1022 local height = directives.height
1023 local method = directives.method or v_normal
1024 local settings = data.settings
1025 local results = data.results
1026 local rowdistance = settings.rowdistance
1027 local head = results[head_mode]
1028 local foot = results[foot_mode]
1029 local more = results[more_mode]
1030 local body = results[body_mode]
1031 local repeatheader = settings.header == v_repeat
1032 local repeatfooter = settings.footer == v_repeat
1033 if height and height > 0 then
1034 ctx_beginvbox()
1035 local bodystart = data.bodystart or 1
1036 local bodystop = data.bodystop or #body
1037 if bodystart > 0 and bodystart <= bodystop then
1038 local bodysize = height
1039 local footsize = total(foot,rowdistance)
1040 local headsize = total(head,rowdistance)
1041 local moresize = total(more,rowdistance)
1042 local firstsize, firstspans = spanheight(body,bodystart)
1043 if bodystart == 1 then
1044 bodysize = bodysize - headsize - footsize
1045 if headsize > 0 and bodysize >= firstsize then
1046 for i=1,#head do
1047 inject(head[i],repeatheader)
1048 end
1049 if rowdistance > 0 then
1050 ctxnode(tonode(new_glue(rowdistance)))
1051 end
1052 if not repeatheader then
1053 results[head_mode] = { }
1054 end
1055 end
1056 elseif moresize > 0 then
1057 bodysize = bodysize - footsize - moresize
1058 if bodysize >= firstsize then
1059 for i=1,#more do
1060 inject(more[i],true)
1061 end
1062 if rowdistance > 0 then
1063 ctxnode(tonode(new_glue(rowdistance)))
1064 end
1065 end
1066 elseif headsize > 0 and repeatheader then
1067 bodysize = bodysize - footsize - headsize
1068 if bodysize >= firstsize then
1069 for i=1,#head do
1070 inject(head[i],true)
1071 end
1072 if rowdistance > 0 then
1073 ctxnode(tonode(new_glue(rowdistance)))
1074 end
1075 end
1076 else
1077 bodysize = bodysize - footsize
1078 end
1079 if bodysize >= firstsize then
1080 local i = bodystart
1081 while i <= bodystop do
1082 local total, spans = spanheight(body,i)
1083 local bs = bodysize - total
1084 if bs > 0 then
1085 bodysize = bs
1086 for s=1,spans do
1087 inject(body[i])
1088 body[i] = nil
1089 i = i + 1
1090 end
1091 bodystart = i
1092 else
1093 break
1094 end
1095 end
1096 if bodystart > bodystop then
1097
1098 if footsize > 0 then
1099 if rowdistance > 0 then
1100 ctxnode(tonode(new_glue(rowdistance)))
1101 end
1102 for i=1,#foot do
1103 inject(foot[i])
1104 end
1105 results[foot_mode] = { }
1106 end
1107 results[body_mode] = { }
1108 texsetcount("global","c_tabl_x_state",0)
1109 else
1110
1111
1112 if repeatfooter and footsize > 0 then
1113 if rowdistance > 0 then
1114 ctxnode(tonode(new_glue(rowdistance)))
1115 end
1116 for i=1,#foot do
1117 inject(foot[i],true)
1118 end
1119 else
1120
1121 end
1122 texsetcount("global","c_tabl_x_state",2)
1123 end
1124 else
1125 if firstsize > height then
1126
1127 for s=1,firstspans do
1128 inject(body[bodystart])
1129 body[bodystart] = nil
1130 bodystart = bodystart + 1
1131 end
1132 end
1133 texsetcount("global","c_tabl_x_state",2)
1134 end
1135 else
1136 texsetcount("global","c_tabl_x_state",0)
1137 end
1138 data.bodystart = bodystart
1139 data.bodystop = bodystop
1140 ctx_endvbox()
1141 else
1142 if method == variables.split then
1143
1144
1145 for i=1,#head do
1146 inject(head[i],false,true)
1147 end
1148 if #head > 0 and rowdistance > 0 then
1149 ctx_blank { rowdistance .. "sp" }
1150 end
1151 for i=1,#body do
1152 inject(body[i],false,true)
1153 end
1154 if #foot > 0 and rowdistance > 0 then
1155 ctx_blank { rowdistance .. "sp" }
1156 end
1157 for i=1,#foot do
1158 inject(foot[i],false,true)
1159 end
1160 else
1161 ctx_beginvbox()
1162 for i=1,#head do
1163 inject(head[i])
1164 end
1165 if #head > 0 and rowdistance > 0 then
1166 ctxnode(tonode(new_glue(rowdistance)))
1167 end
1168 for i=1,#body do
1169 inject(body[i])
1170 end
1171 if #foot > 0 and rowdistance > 0 then
1172 ctxnode(tonode(new_glue(rowdistance)))
1173 end
1174 for i=1,#foot do
1175 inject(foot[i])
1176 end
1177 ctx_endvbox()
1178 end
1179 results[head_mode] = { }
1180 results[body_mode] = { }
1181 results[foot_mode] = { }
1182 texsetcount("global","c_tabl_x_state",0)
1183 end
1184end
1185
1186function xtables.cleanup()
1187 for mode, result in next, data.results do
1188 for _, r in next, result do
1189 flushnodelist(r[1])
1190 end
1191 end
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207 data = table.remove(stack)
1208end
1209
1210function xtables.next_row(specification)
1211 local r = data.currentrow + 1
1212 data.modes[r] = texgetcount("c_tabl_x_mode")
1213 data.currentrow = r
1214 data.currentcolumn = 0
1215 data.rowproperties[r] = specification
1216end
1217
1218function xtables.finish_row()
1219 local c = data.currentcolumn
1220 local r = data.currentrow
1221 local d = data.rows[r][c]
1222 local n = data.nofcolumns - c
1223 if d then
1224 local nx = d.nx
1225 if nx > 0 then
1226 n = n - nx + 1
1227 end
1228 end
1229 if n > 0 then
1230 for i=1,n do
1231 ctx_dummyxcell()
1232 end
1233 end
1234end
1235
1236
1237
1238implement {
1239 name = "x_table_create",
1240 actions = xtables.create,
1241 arguments = {
1242 {
1243 { "option" },
1244 { "textwidth", "dimen" },
1245 { "textheight", "dimen" },
1246 { "maxwidth", "dimen" },
1247 { "lineheight", "dimen" },
1248 { "columndistance", "dimen" },
1249 { "leftmargindistance", "dimen" },
1250 { "rightmargindistance", "dimen" },
1251 { "rowdistance", "dimen" },
1252 { "header" },
1253 { "footer" },
1254 }
1255 }
1256}
1257
1258implement {
1259 name = "x_table_flush",
1260 actions = xtables.flush,
1261 arguments = {
1262 {
1263 { "method" },
1264 { "height", "dimen" }
1265 }
1266 }
1267}
1268
1269implement { name = "x_table_reflow_width", actions = xtables.reflow_width }
1270implement { name = "x_table_reflow_height", actions = xtables.reflow_height }
1271implement { name = "x_table_construct", actions = xtables.construct }
1272implement { name = "x_table_cleanup", actions = xtables.cleanup }
1273implement { name = "x_table_next_row", actions = xtables.next_row }
1274implement { name = "x_table_next_row_option", actions = xtables.next_row, arguments = "string" }
1275implement { name = "x_table_finish_row", actions = xtables.finish_row }
1276implement { name = "x_table_init_reflow_width", actions = xtables.initialize_reflow_width }
1277implement { name = "x_table_init_reflow_height", actions = xtables.initialize_reflow_height }
1278implement { name = "x_table_init_reflow_width_option", actions = xtables.initialize_reflow_width, arguments = "string" }
1279implement { name = "x_table_init_reflow_height_option", actions = xtables.initialize_reflow_height, arguments = "string" }
1280implement { name = "x_table_init_construct", actions = xtables.initialize_construct }
1281implement { name = "x_table_set_reflow_width", actions = xtables.set_reflow_width }
1282implement { name = "x_table_set_reflow_height", actions = xtables.set_reflow_height }
1283implement { name = "x_table_set_construct", actions = xtables.set_construct }
1284implement { name = "x_table_r", actions = function() context(data.currentrow or 0) end }
1285implement { name = "x_table_c", actions = function() context(data.currentcolumn or 0) end }
1286
1287
1288
1289do
1290
1291 local context = context
1292 local ctxcore = context.core
1293
1294 local startxtable = ctxcore.startxtable
1295 local stopxtable = ctxcore.stopxtable
1296
1297 local startcollecting = context.startcollecting
1298 local stopcollecting = context.stopcollecting
1299
1300 function ctxcore.startxtable(...)
1301 startcollecting()
1302 startxtable(...)
1303 end
1304
1305 function ctxcore.stopxtable()
1306 stopxtable()
1307 stopcollecting()
1308 end
1309
1310end
1311 |