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