1if not modules then modules = { } end modules ["page-cst"] = {
2 version = 1.001,
3 comment = "companion to page-cst.mkiv",
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
10
11local next, type, tonumber, rawget = next, type, tonumber, rawget
12local ceil, odd, round = math.ceil, math.odd, math.round
13local lower = string.lower
14local copy = table.copy
15
16local trace_state = false trackers.register("columnsets.trace", function(v) trace_state = v end)
17local trace_details = false trackers.register("columnsets.details", function(v) trace_details = v end)
18local trace_cells = false trackers.register("columnsets.cells", function(v) trace_cells = v end)
19
20local report = logs.reporter("column sets")
21
22local setmetatableindex = table.setmetatableindex
23
24local properties = nodes.properties.data
25
26local nodecodes = nodes.nodecodes
27
28local hlist_code = nodecodes.hlist
29local vlist_code = nodecodes.vlist
30local kern_code = nodecodes.kern
31local glue_code = nodecodes.glue
32local penalty_code = nodecodes.penalty
33local rule_code = nodecodes.rule
34
35local nuts = nodes.nuts
36local tonode = nuts.tonode
37local tonut = nuts.tonut
38
39local vpack = nuts.vpack
40local flushlist = nuts.flushlist
41
42local setlink = nuts.setlink
43local setlist = nuts.setlist
44local setnext = nuts.setnext
45local setprev = nuts.setprev
46local setsubtype = nuts.setsubtype
47local setbox = nuts.setbox
48local getwhd = nuts.getwhd
49local setwhd = nuts.setwhd
50local getkern = nuts.getkern
51local getpenalty = nuts.getpenalty
52local getwidth = nuts.getwidth
53local getheight = nuts.getheight
54
55local getnext = nuts.getnext
56local getprev = nuts.getprev
57local getid = nuts.getid
58local getlist = nuts.getlist
59local getsubtype = nuts.getsubtype
60local takebox = nuts.takebox
61local takelist = nuts.takelist
62local splitbox = nuts.splitbox
63local getattribute = nuts.getattribute
64local copylist = nuts.copylist
65
66local getbox = nuts.getbox
67local getcount = tex.getcount
68local getdimen = tex.getdimen
69
70local texsetbox = tex.setbox
71local texsetcount = tex.setcount
72local texsetdimen = tex.setdimen
73
74local theprop = nuts.theprop
75
76local nodepool = nuts.pool
77
78local new_vlist = nodepool.vlist
79local new_trace_rule = nodepool.rule
80local new_empty_rule = nodepool.emptyrule
81
82local context = context
83local implement = interfaces.implement
84
85local variables = interfaces.variables
86local v_here = variables.here
87local v_fixed = variables.fixed
88local v_top = variables.top
89local v_bottom = variables.bottom
90local v_repeat = variables["repeat"]
91local v_yes = variables.yes
92local v_page = variables.page
93local v_first = variables.first
94local v_last = variables.last
95
96
97pagebuilders = pagebuilders or { }
98pagebuilders.columnsets = pagebuilders.columnsets or { }
99local columnsets = pagebuilders.columnsets
100
101local data = { [""] = { } }
102
103
104
105local function setstate(t,start)
106 if start or not t.firstcolumn then
107 t.firstcolumn = odd(getcount("realpageno")) and 1 or 2
108 end
109 if t.firstcolumn > 1 then
110 t.firstcolumn = 1
111 t.lastcolumn = t.nofleft
112 t.state = "left"
113 else
114 t.firstcolumn = t.nofleft + 1
115 t.lastcolumn = t.firstcolumn + t.nofright - 1
116 t.state = "right"
117 end
118 t.currentcolumn = t.firstcolumn
119 t.currentrow = 1
120end
121
122function columnsets.define(t)
123 local name = t.name
124 local nofleft = t.nofleft or 1
125 local nofright = t.nofright or 1
126 local nofcolumns = nofleft + nofright
127 local dataset = data[name] or { }
128 data[name] = dataset
129 dataset.nofleft = nofleft
130 dataset.nofright = nofright
131 dataset.nofcolumns = nofcolumns
132 dataset.nofrows = t.nofrows or 1
133 dataset.distance = t.distance or getdimen("bodyfontsize")
134 dataset.maxwidth = t.maxwidth or getdimen("makeupwidth")
135 dataset.lineheight = t.lineheight or getdimen("globalbodyfontstrutheight")
136 dataset.linedepth = t.linedepth or getdimen("globalbodyfontstrutdepth")
137
138 dataset.cells = { }
139 dataset.currentcolumn = 1
140 dataset.currentrow = 1
141
142 dataset.lines = dataset.lines or setmetatableindex("table")
143 dataset.start = dataset.start or setmetatableindex("table")
144
145 dataset.page = 1
146
147 local distances = dataset.distances or setmetatableindex(function(t,k)
148 return dataset.distance
149 end)
150 dataset.distances = distances
151
152 local widths = dataset.widths or setmetatableindex(function(t,k)
153 return dataset.width
154 end)
155 dataset.widths = widths
156
157 local width = t.width
158 if not width or width == 0 then
159 local dl = 0
160 local dr = 0
161 for i=1,nofleft-1 do
162 dl = dl + distances[i]
163 end
164 for i=1,nofright-1 do
165 dr = dr + distances[nofleft+i]
166 end
167 local nl = nofleft
168 local nr = nofright
169 local wl = dataset.maxwidth
170 local wr = wl
171 for i=1,nofleft do
172 local w = rawget(widths,i)
173 if w then
174 nl = nl - 1
175 wl = wl - w
176 end
177 end
178 for i=1,nofright do
179 local w = rawget(widths,nofleft+i)
180 if w then
181 nr = nr - 1
182 wr = wr - w
183 end
184 end
185 dl = (wl - dl) / nl
186 dr = (wr - dr) / nr
187 if dl > dr then
188 report("using %s page column width %p in columnset %a","right",dr,name)
189 width = dr
190 elseif dl < dr then
191 report("using %s page column width %p in columnset %a","left",dl,name)
192 width = dl
193 else
194 width = dl
195 end
196 end
197
198 width = round(width)
199 dataset.width = width
200 local spans = { }
201 dataset.spans = spans
202 for i=1,nofleft do
203 local s = { }
204 local d = 0
205 for j=1,nofleft-i+1 do
206 d = d + width
207 s[j] = round(d)
208 d = d + distances[j]
209 end
210 spans[i] = s
211 end
212 for i=1,nofright do
213 local s = { }
214 local d = 0
215 for j=1,nofright-i+1 do
216 d = d + width
217 s[j] = round(d)
218 d = d + distances[j]
219 end
220 spans[nofleft+i] = s
221 end
222
223 local spreads = copy(spans)
224 dataset.spreads = spreads
225 local gap = 2 * getdimen("backspace")
226 for l=1,nofleft do
227 local s = spreads[l]
228 local n = #s
229 local o = s[n] + gap
230 for r=1,nofright do
231 n = n + 1
232 s[n] = s[r] + o
233 end
234 end
235
236 texsetdimen("d_page_grd_column_width",dataset.width)
237
238 setstate(dataset,true)
239
240 return dataset
241end
242
243local function check(dataset)
244 local cells = dataset.cells
245 local page = dataset.page
246 local offset = odd(page) and dataset.nofleft or 0
247 local start = dataset.start
248 local list = rawget(start,page)
249 if list then
250 for c, n in next, list do
251 local column = cells[offset + c]
252 if column then
253 for r=1,n do
254 column[r] = true
255 end
256 end
257 end
258 start[page] = nil
259 end
260 local lines = dataset.lines
261 local list = rawget(lines,page)
262 local rows = dataset.nofrows
263 if list then
264 for c, n in next, list do
265 local column = cells[offset + c]
266 if column then
267 if n > 0 then
268 for r=n+1,rows do
269 column[r] = true
270 end
271 elseif n < 0 then
272 for r=rows,rows+n+1,-1 do
273 column[r] = true
274 end
275 end
276 end
277 end
278 lines[page] = nil
279 end
280end
281
282local function erase(dataset,all)
283 local cells = dataset.cells
284 local nofrows = dataset.nofrows
285 local first = 1
286 local last = dataset.nofcolumns
287
288 if not all then
289 first = dataset.firstcolumn or first
290 last = dataset.lastcolumn or last
291 end
292 for c=first,last do
293 local column = { }
294 for r=1,nofrows do
295 if column[r] then
296 report("slot (%i,%i) is not empty",c,r)
297 end
298 column[r] = false
299 end
300 cells[c] = column
301 end
302end
303
304function columnsets.reset(t)
305 local dataset = columnsets.define(t)
306 erase(dataset,true)
307 check(dataset)
308end
309
310function columnsets.prepareflush(name)
311 local dataset = data[name]
312 local cells = dataset.cells
313 local firstcolumn = dataset.firstcolumn
314 local lastcolumn = dataset.lastcolumn
315 local nofrows = dataset.nofrows
316 local lineheight = dataset.lineheight
317 local linedepth = dataset.linedepth
318 local widths = dataset.widths
319 local height = (lineheight+linedepth)*nofrows
320
321 local columns = { }
322 dataset.columns = columns
323
324 for c=firstcolumn,lastcolumn do
325 local column = cells[c]
326 for r=1,nofrows do
327 local cell = column[r]
328 if (cell == false) or (cell == true) then
329 if trace_cells then
330 column[r] = new_trace_rule(65536*2,lineheight,linedepth)
331 else
332 column[r] = new_empty_rule(0,lineheight,linedepth)
333 end
334 end
335 end
336 for r=1,nofrows-1 do
337 setlink(column[r],column[r+1])
338 end
339 columns[c] = new_vlist(column[1],widths[c],height,0)
340 end
341
342 texsetcount("c_page_grd_first_column",firstcolumn)
343 texsetcount("c_page_grd_last_column",lastcolumn)
344end
345
346function columnsets.flushcolumn(name,column)
347 local dataset = data[name]
348 local columns = dataset.columns
349 local packed = columns[column]
350 setbox("b_page_grd_column",packed)
351 columns[column] = nil
352end
353
354function columnsets.finishflush(name)
355 local dataset = data[name]
356 local cells = dataset.cells
357 local firstcolumn = dataset.firstcolumn
358 local lastcolumn = dataset.lastcolumn
359 local nofrows = dataset.nofrows
360 for c=firstcolumn,lastcolumn do
361 local column = { }
362 for r=1,nofrows do
363 column[r] = false
364 end
365 cells[c] = column
366 end
367 dataset.page = dataset.page + 1
368 check(dataset)
369 setstate(dataset)
370end
371
372function columnsets.block(t)
373 local dataset = data[t.name]
374 local cells = dataset.cells
375 local nofcolumns = dataset.nofcolumns
376 local nofrows = dataset.nofrows
377
378 local c = t.c or 0
379 local r = t.r or 0
380 if c == 0 or r == 0 or c > nofcolumns or r > nofrows then
381 return
382 end
383 local nc = t.nc or 0
384 local nr = t.nr or 0
385 if nc == 0 then
386 return
387 end
388 if nr == 0 then
389 return
390 end
391 local rr = r + nr - 1
392 local cc = c + nc - 1
393 if rr > nofrows then
394 rr = nofrows
395 end
396 if cc > nofcolumns then
397 cc = nofcolumns
398 end
399 for i=c,cc do
400 local column = cells[i]
401 for j=r,rr do
402 column[j] = true
403 end
404 end
405end
406
407local function here(c,r,nr,nofcolumns,nofrows,cells,width,spans)
408 local rr = r + nr - 1
409 if rr > nofrows then
410 return false
411 end
412 local cc = 0
413 local wd = spans[c]
414 local wc = 0
415 local nc = 0
416 for i=c,nofcolumns do
417 nc = nc + 1
418 wc = wd[nc]
419 if not wc then
420 break
421 elseif wc >= width then
422 cc = i
423 break
424 end
425 end
426 if cc == 0 or cc > nofcolumns then
427
428 return false
429 end
430 for i=c,cc do
431 local column = cells[i]
432 for j=r,rr do
433 if column[j] then
434
435 return false
436 end
437 end
438 end
439
440 return c, r, nc
441end
442
443
444
445local methods = {
446 [v_here] = here,
447 [v_fixed] = here,
448 tblr = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
449 for j=r,nofrows-nr+1 do
450 for i=c,nofcolumns do
451 if not cells[i][j] then
452 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
453 if c then
454 return c, r, cc
455 end
456 end
457 end
458 end
459 end,
460 lrtb = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
461 for i=c,nofcolumns do
462 for j=r,nofrows-nr+1 do
463 if not cells[i][j] then
464 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
465 if c then
466 return c, r, cc
467 end
468 end
469 end
470 end
471 end,
472 tbrl = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
473 for j=r,nofrows-nr+1 do
474 for i=nofcolumns,c,-1 do
475 if not cells[i][j] then
476 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
477 if c then
478 return c, r, cc
479 end
480 end
481 end
482 end
483 end,
484 rltb = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
485 for i=nofcolumns,c,-1 do
486 for j=r,nofrows-nr+1 do
487 if not cells[i][j] then
488 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
489 if c then
490 return c, r, cc
491 end
492 end
493 end
494 end
495 end,
496 btlr = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
497
498 for j=nofrows-nr+1-r+1,1,-1 do
499 for i=c,nofcolumns do
500 if not cells[i][j] then
501 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
502 if c then
503 return c, r, cc
504 end
505 end
506 end
507 end
508 end,
509 lrbt = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
510 for i=c,nofcolumns do
511
512 for j=nofrows-nr+1-r+1,1,-1 do
513 if not cells[i][j] then
514 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
515 if c then
516 return c, r, cc
517 end
518 end
519 end
520 end
521 end,
522 btrl = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
523
524 for j=nofrows-nr+1-r+1,1,-1 do
525 for i=nofcolumns,c,-1 do
526 if not cells[i][j] then
527 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
528 if c then
529 return c, r, cc
530 end
531 end
532 end
533 end
534 end,
535 rlbt = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
536 for i=nofcolumns,c,-1 do
537
538 for j=nofrows-nr+1-r+1,1,-1 do
539 if not cells[i][j] then
540 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
541 if c then
542 return c, r, cc
543 end
544 end
545 end
546 end
547 end,
548 fxtb = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
549 for i=c,nofcolumns do
550 for j=r,nofrows-nr+1 do
551 if not cells[i][j] then
552 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
553 if c then
554 return c, r, cc
555 end
556 end
557 r = 1
558 end
559 end
560 end,
561 fxbt = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
562 for i=c,nofcolumns do
563 for j=nofrows-nr+1,r,-1 do
564 if not cells[i][j] then
565 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
566 if c then
567 return c, r, cc
568 end
569 end
570 end
571 r = 1
572 end
573 end,
574 [v_top] = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
575 for i=c,nofcolumns do
576 for j=1,nofrows-nr+1 do
577 if cells[i][j] then
578 break
579 else
580 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
581 if c then
582 return c, r, cc
583 end
584 end
585 end
586 end
587 end,
588 [v_bottom] = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
589 for i=c,nofcolumns do
590 for j=1,nofrows-nr+1 do
591 if cells[i][j] then
592 break
593 else
594 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
595 if c then
596 return c, r, cc
597 end
598 end
599 end
600 end
601 end,
602}
603
604local threshold = 50
605
606function columnsets.check(t)
607 local dataset = data[t.name]
608 local cells = dataset.cells
609 local nofcolumns = dataset.nofcolumns
610 local nofrows = dataset.nofrows
611 local widths = dataset.widths
612 local lineheight = dataset.lineheight
613 local linedepth = dataset.linedepth
614 local distances = dataset.distances
615 local spans = dataset.spans
616
617 local method = lower(t.method or "tblr")
618 local boxwidth = t.width or 0
619 local boxheight = t.height or 0
620 local boxnumber = t.box
621 local box = boxnumber and getbox(boxnumber)
622
623 if boxwidth > 0 and boxheight > 0 then
624
625 elseif box then
626 local wd, ht, dp = getwhd(box)
627 boxwidth = wd
628 boxheight = ht + dp
629 else
630 report("empty box")
631 return
632 end
633
634 local c = t.c or 0
635 local r = t.r or 0
636 if c == 0 then
637 c = dataset.currentcolumn
638 end
639 if r == 0 then
640 r = dataset.currentrow
641 end
642 if c == 0 or r == 0 or c > nofcolumns or r > nofrows then
643 texsetcount("c_page_grd_reserved_state",5)
644 return
645 end
646
647 local nr = ceil(boxheight/(lineheight+linedepth))
648
649 local action = methods[method]
650 local cfound = false
651 local rfound = false
652 local lastcolumn = dataset.lastcolumn
653
654
655
656
657 if action then
658 cfound, rfound, nc = action(c,r,nr,lastcolumn,nofrows,cells,boxwidth-threshold,spans)
659 end
660 if not cfound and method ~= v_here then
661 cfound, rfound, nc = here(c,r,nr,lastcolumn,nofrows,cells,boxwidth-threshold,spans)
662 end
663 if cfound then
664 local ht = nr*(lineheight+linedepth)
665 local wd = spans[cfound][nc]
666 dataset.reserved_ht = ht
667 dataset.reserved_wd = wd
668 dataset.reserved_c = cfound
669 dataset.reserved_r = rfound
670 dataset.reserved_nc = nc
671 dataset.reserved_nr = nr
672 texsetcount("c_page_grd_reserved_state",0)
673 texsetdimen("d_page_grd_reserved_height",ht)
674 texsetdimen("d_page_grd_reserved_width",wd)
675
676 else
677 dataset.reserved_ht = false
678 dataset.reserved_wd = false
679 dataset.reserved_c = false
680 dataset.reserved_r = false
681 dataset.reserved_nc = false
682 dataset.reserved_nr = false
683 texsetcount("c_page_grd_reserved_state",4)
684
685
686
687 end
688end
689
690function columnsets.put(t)
691 local dataset = data[t.name]
692 local cells = dataset.cells
693 local widths = dataset.widths
694 local lineheight = dataset.lineheight
695 local linedepth = dataset.linedepth
696 local boxnumber = t.box
697 local box = boxnumber and takebox(boxnumber)
698
699 local c = t.c or dataset.reserved_c
700 local r = t.r or dataset.reserved_r
701 if not c or not r then
702
703 return
704 end
705 local lastc = c + dataset.reserved_nc - 1
706 local lastr = r + dataset.reserved_nr - 1
707
708 for i=c,lastc do
709 local column = cells[i]
710 for j=r,lastr do
711 column[j] = true
712 end
713 end
714 cells[c][r] = box
715 setwhd(box,widths[c],lineheight,linedepth)
716 dataset.reserved_c = false
717 dataset.reserved_r = false
718 dataset.reserved_nc = false
719 dataset.reserved_nr = false
720
721end
722
723local function findgap(dataset)
724 local cells = dataset.cells
725 local nofcolumns = dataset.nofcolumns
726 local nofrows = dataset.nofrows
727 local currentrow = dataset.currentrow
728 local currentcolumn = dataset.currentcolumn
729
730 local foundc = 0
731 local foundr = 0
732 local foundn = 0
733 for c=currentcolumn,dataset.lastcolumn do
734 local column = cells[c]
735foundn = 0
736 for r=currentrow,nofrows do
737 if not column[r] then
738 if foundc == 0 then
739 foundc = c
740 foundr = r
741 end
742 foundn = foundn + 1
743 elseif foundn > 0 then
744 return foundc, foundr, foundn
745 end
746 end
747 if foundn > 0 then
748 return foundc, foundr, foundn
749 end
750 currentrow = 1
751 end
752end
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792local function checkroom(head,available,row)
793 if row == 1 then
794 while head do
795 local id = getid(head)
796 if id == glue_code then
797 head = getnext(head)
798 else
799 break
800 end
801 end
802 end
803 local used = 0
804 local line = false
805 while head do
806 local id = getid(head)
807 if id == hlist_code or id == vlist_code or id == rule_code then
808 local wd, ht, dp = getwhd(head)
809 used = used + ht + dp
810 line = true
811 if used > available then
812 break
813 end
814 elseif id == glue_code then
815 if line then
816 break
817 end
818 used = used + getwidth(head)
819 if used > available then
820 break
821 end
822 elseif id == kern_code then
823 used = used + getkern(head)
824 if used > available then
825 break
826 end
827 elseif id == penalty_code then
828
829 if getpenalty(head) >= 10000 then
830 line = false
831 else
832 break
833 end
834 end
835 head = getnext(head)
836 end
837 return line, used
838end
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912local function findslice(dataset,head,available,column,row)
913 local first = nil
914 local lineheight = dataset.lineheight
915 local linedepth = dataset.linedepth
916 local linetotal = lineheight + linedepth
917 local slack = 65536
918 local copy = copylist(head)
919 local attempts = 0
920 local usedsize = available
921 while true do
922 attempts = attempts + 1
923 texsetbox("scratchbox",tonode(new_vlist(copy)))
924 local done = splitbox("scratchbox",usedsize,"additional")
925 local used = getheight(done)
926 local rest = takebox("scratchbox")
927 if used > (usedsize+slack) then
928 if trace_details then
929 report("at (%i,%i) available %p, used %p, overflow %p",column,row,usedsize,used,used-usedsize)
930 end
931
932 flushlist(takelist(done))
933 flushlist(takelist(rest))
934
935 usedsize = usedsize - linetotal
936 if usedsize > linetotal then
937 copy = copylist(head)
938 else
939 return 0, nil, head
940 end
941 else
942
943 flushlist(takelist(done))
944 flushlist(takelist(rest))
945
946 texsetbox("scratchbox",tonode(new_vlist(head)))
947 done = splitbox("scratchbox",usedsize,"additional")
948 rest = takebox("scratchbox")
949 used = getheight(done)
950 if attempts > 1 then
951 used = available
952 end
953 first = takelist(done)
954 head = takelist(rest)
955
956 return used, first, head
957 end
958 end
959end
960
961local nofcolumngaps = 0
962
963function columnsets.add(name,box)
964 local dataset = data[name]
965 local cells = dataset.cells
966 local nofcolumns = dataset.nofcolumns
967 local nofrows = dataset.nofrows
968 local currentrow = dataset.currentrow
969 local currentcolumn = dataset.currentcolumn
970 local lineheight = dataset.lineheight
971 local linedepth = dataset.linedepth
972 local widths = dataset.widths
973
974 local b = getbox(box)
975 local l = getlist(b)
976
977 if l then
978 setlist(b,nil)
979 local hd = lineheight + linedepth
980 while l do
981 local foundc, foundr, foundn = findgap(dataset)
982 if foundc then
983 local available = foundn * hd
984 local used, first, last = findslice(dataset,l,available,foundc,foundr)
985 if first then
986 local v
987 if used == available or (foundr+foundn > nofrows) then
988 v = vpack(first,available,"exactly")
989 else
990 v = new_vlist(first)
991 end
992 nofcolumngaps = nofcolumngaps + 1
993
994 properties[v] = { columngap = nofcolumngaps }
995
996 setwhd(v,widths[currentcolumn],lineheight,linedepth)
997 local column = cells[foundc]
998
999 column[foundr] = v
1000 used = used - hd
1001 if used > 0 then
1002 for r=foundr+1,foundr+foundn-1 do
1003 used = used - hd
1004 foundr = foundr + 1
1005 column[r] = true
1006 if used <= 0 then
1007 break
1008 end
1009 end
1010 end
1011 currentcolumn = foundc
1012 currentrow = foundr
1013 dataset.currentcolumn = currentcolumn
1014 dataset.currentrow = currentrow
1015 l = last
1016 dataset.rest = l
1017 else
1018 local column = cells[foundc]
1019 for i=foundr,foundr+foundn-1 do
1020 column[i] = true
1021 end
1022 l = last
1023 end
1024 else
1025 dataset.rest = l
1026 return
1027 end
1028 end
1029 end
1030end
1031
1032do
1033
1034
1035
1036
1037 local followup = nil
1038 local splitter = lpeg.splitter("*",tonumber)
1039
1040 columnsets["noto"] = function(t)
1041 return followup()
1042 end
1043
1044 columnsets["goto"] = function(name,target)
1045 local dataset = data[name]
1046 local nofcolumns = dataset.nofcolumns
1047 if target == v_yes or target == "" then
1048 local currentcolumn = dataset.currentcolumn
1049 followup = function()
1050 context(dataset.currentcolumn == currentcolumn and 1 or 0)
1051 end
1052 return followup()
1053 end
1054 if target == v_first then
1055 if dataset.currentcolumn > 1 then
1056 target = v_page
1057 else
1058 return context(0)
1059 end
1060 end
1061 if target == v_page then
1062 if dataset.currentcolumn == 1 and dataset.currentrow == 1 then
1063 return context(0)
1064 else
1065 local currentpage = dataset.page
1066 followup = function()
1067 context(dataset.page == currentpage and 1 or 0)
1068 end
1069 return followup()
1070 end
1071 end
1072 if target == v_last then
1073 target = dataset.nofcolumns
1074 if dataset.currentcolumn ~= target then
1075 followup = function()
1076 context(dataset.currentcolumn ~= target and 1 or 0)
1077 end
1078 return followup()
1079 end
1080 return
1081 end
1082 local targetpage = tonumber(target)
1083 if targetpage then
1084 followup = function()
1085 context(dataset.currentcolumn ~= targetpage and 1 or 0)
1086 end
1087 return followup()
1088 end
1089 local targetcolumn, targetrow = lpeg.match(splitter,target)
1090 if targetcolumn and targetrow then
1091 if dataset.currentcolumn ~= targetcolumn and dataset.currentrow ~= targetrow then
1092 followup = function()
1093 if dataset.currentcolumn ~= targetcolumn then
1094 context(1)
1095 return
1096 end
1097 if dataset.currentcolumn == targetcolumn then
1098 context(dataset.currentrow ~= targetrow and 1 or 0)
1099 else
1100 context(0)
1101 end
1102 end
1103 return followup()
1104 end
1105 end
1106 end
1107
1108end
1109
1110function columnsets.currentcolumn(name)
1111 local dataset = data[name]
1112 context(dataset.currentcolumn)
1113end
1114
1115function columnsets.flushrest(name,box)
1116 local dataset = data[name]
1117 local rest = dataset.rest
1118 if rest then
1119 dataset.rest = nil
1120 setbox("global",box,new_vlist(rest))
1121 end
1122end
1123
1124function columnsets.setvsize(name)
1125 local dataset = data[name]
1126 local c, r, n = findgap(dataset)
1127 if n then
1128 dataset.currentcolumn = c
1129 dataset.currentrow = r
1130 else
1131 dataset.currentcolumn = 1
1132 dataset.currentrow = 1
1133 n = 0
1134 end
1135 local gap = n*(dataset.lineheight+dataset.linedepth)
1136 texsetdimen("d_page_grd_gap_height",gap)
1137
1138
1139end
1140
1141function columnsets.sethsize(name)
1142 local dataset = data[name]
1143 texsetdimen("d_page_grd_column_width",dataset.widths[dataset.currentcolumn])
1144end
1145
1146function columnsets.sethspan(name,span)
1147
1148
1149 local dataset = data[name]
1150 local column = dataset.currentcolumn
1151 local available = dataset.lastcolumn - column + 1
1152 if span > available then
1153 span = available
1154 end
1155 local width = dataset.spans[column][span]
1156 texsetdimen("d_page_grd_span_width",width)
1157end
1158
1159function columnsets.setlines(t)
1160 local dataset = data[t.name]
1161 dataset.lines[t.page][t.column] = t.value
1162end
1163
1164function columnsets.setstart(t)
1165 local dataset = data[t.name]
1166 dataset.start[t.page][t.column] = t.value
1167end
1168
1169function columnsets.setproperties(t)
1170 local dataset = data[t.name]
1171 local column = t.column
1172 dataset.distances[column] = t.distance
1173 dataset.widths[column] = t.width
1174end
1175
1176local areas = { }
1177
1178function columnsets.registerarea(t)
1179
1180 areas[#areas+1] = t
1181end
1182
1183
1184
1185local ctx_page_grd_set_area = context.protected.page_grd_set_area
1186
1187function columnsets.flushareas(name)
1188 local nofareas = #areas
1189 if nofareas == 0 then
1190 return
1191 end
1192 local dataset = data[name]
1193 local page = dataset.page
1194 if odd(page) then
1195
1196 local kept = { }
1197 for i=1,nofareas do
1198 local area = areas[i]
1199
1200
1201 local okay = false
1202
1203 local nofcolumns = area.nc
1204 local nofrows = area.nr
1205 local column = area.c
1206 local row = area.r
1207 columnsets.block {
1208 name = name,
1209 c = column,
1210 r = row,
1211 nc = nofcolumns,
1212 nr = nofrows,
1213 }
1214 local left = 0
1215 local start = dataset.nofleft + 1
1216 local overflow = (column + nofcolumns - 1) - dataset.nofleft
1217 local height = nofrows * (dataset.lineheight + dataset.linedepth)
1218 local width = dataset.spreads[column][nofcolumns]
1219
1220 if overflow > 0 then
1221 local used = nofcolumns - overflow
1222 left = dataset.spreads[column][used] + getdimen("backspace")
1223 end
1224 ctx_page_grd_set_area(name,area.name,column,row,width,height,start,left)
1225 if area.state ~= v_repeat then
1226 area = nil
1227 end
1228 if area then
1229 kept[#kept+1] = area
1230 end
1231 end
1232 areas = kept
1233 end
1234end
1235
1236function columnsets.setarea(t)
1237 local dataset = data[t.name]
1238 local cells = dataset.cells
1239 local box = takebox(t.box)
1240 local column = t.c
1241 local row = t.r
1242 if column and row then
1243 setwhd(box,dataset.widths[column],dataset.lineheight,dataset.linedepth)
1244 cells[column][row] = box
1245 end
1246end
1247
1248
1249
1250interfaces.implement {
1251 name = "definecolumnset",
1252 actions = columnsets.define,
1253 arguments = { {
1254 { "name", "string" },
1255 } }
1256}
1257
1258interfaces.implement {
1259 name = "resetcolumnset",
1260 actions = columnsets.reset,
1261 arguments = { {
1262 { "name", "string" },
1263 { "nofleft", "integer" },
1264 { "nofright", "integer" },
1265 { "nofrows", "integer" },
1266 { "lineheight", "dimension" },
1267 { "linedepth", "dimension" },
1268 { "width", "dimension" },
1269 { "distance", "dimension" },
1270 { "maxwidth", "dimension" },
1271 } }
1272}
1273
1274interfaces.implement {
1275 name = "preparecolumnsetflush",
1276 actions = columnsets.prepareflush,
1277 arguments = "string",
1278}
1279
1280interfaces.implement {
1281 name = "finishcolumnsetflush",
1282 actions = columnsets.finishflush,
1283 arguments = "string",
1284}
1285
1286interfaces.implement {
1287 name = "flushcolumnsetcolumn",
1288 actions = columnsets.flushcolumn,
1289 arguments = { "string" ,"integer" },
1290}
1291
1292interfaces.implement {
1293 name = "setvsizecolumnset",
1294 actions = columnsets.setvsize,
1295 arguments = "string",
1296}
1297
1298interfaces.implement {
1299 name = "sethsizecolumnset",
1300 actions = columnsets.sethsize,
1301 arguments = "string",
1302}
1303
1304interfaces.implement {
1305 name = "sethsizecolumnspan",
1306 actions = columnsets.sethspan,
1307 arguments = { "string" ,"integer" },
1308}
1309
1310interfaces.implement {
1311 name = "flushcolumnsetrest",
1312 actions = columnsets.flushrest,
1313 arguments = { "string", "integer" },
1314}
1315
1316interfaces.implement {
1317 name = "blockcolumnset",
1318 actions = columnsets.block,
1319 arguments = { {
1320 { "name", "string" },
1321 { "c", "integer" },
1322 { "r", "integer" },
1323 { "nc", "integer" },
1324 { "nr", "integer" },
1325 { "method", "string" },
1326 { "box", "integer" },
1327 } }
1328}
1329
1330interfaces.implement {
1331 name = "checkcolumnset",
1332 actions = columnsets.check,
1333 arguments = { {
1334 { "name", "string" },
1335 { "method", "string" },
1336 { "c", "integer" },
1337 { "r", "integer" },
1338 { "method", "string" },
1339 { "box", "integer" },
1340 { "width", "dimension" },
1341 { "height", "dimension" },
1342 { "option", "string" },
1343 } }
1344}
1345
1346interfaces.implement {
1347 name = "putincolumnset",
1348 actions = columnsets.put,
1349 arguments = { {
1350 { "name", "string" },
1351 { "c", "integer" },
1352 { "r", "integer" },
1353 { "method", "string" },
1354 { "box", "integer" },
1355 } }
1356}
1357
1358interfaces.implement {
1359 name = "addtocolumnset",
1360 actions = columnsets.add,
1361 arguments = { "string", "integer" },
1362}
1363
1364interfaces.implement {
1365 name = "setcolumnsetlines",
1366 actions = columnsets.setlines,
1367 arguments = { {
1368 { "name", "string" },
1369 { "page", "integer" },
1370 { "column", "integer" },
1371 { "value", "integer" },
1372 } }
1373}
1374
1375interfaces.implement {
1376 name = "setcolumnsetstart",
1377 actions = columnsets.setstart,
1378 arguments = { {
1379 { "name", "string" },
1380 { "page", "integer" },
1381 { "column", "integer" },
1382 { "value", "integer" },
1383 } }
1384}
1385
1386interfaces.implement {
1387 name = "setcolumnsetproperties",
1388 actions = columnsets.setproperties,
1389 arguments = { {
1390 { "name", "string" },
1391 { "column", "integer" },
1392 { "distance", "dimension" },
1393 { "width", "dimension" },
1394 } }
1395}
1396
1397interfaces.implement {
1398 name = "registercolumnsetarea",
1399 actions = columnsets.registerarea,
1400 arguments = { {
1401 { "name", "string" },
1402 { "type", "string" },
1403 { "page", "integer" },
1404 { "state", "string" },
1405 { "c", "integer" },
1406 { "r", "integer" },
1407 { "nc", "integer" },
1408 { "nr", "integer" },
1409 } }
1410}
1411
1412interfaces.implement {
1413 name = "flushcolumnsetareas",
1414 actions = columnsets.flushareas,
1415 arguments = "string",
1416}
1417
1418interfaces.implement {
1419 name = "setcolumnsetarea",
1420 actions = columnsets.setarea,
1421 arguments = { {
1422 { "name", "string" },
1423 { "c", "integer" },
1424 { "r", "integer" },
1425 { "method", "string" },
1426 { "box", "integer" },
1427 } }
1428}
1429
1430interfaces.implement {
1431 name = "columnsetgoto",
1432 actions = columnsets["goto"],
1433 arguments = "2 strings",
1434}
1435
1436interfaces.implement {
1437 name = "columnsetnoto",
1438 actions = columnsets["noto"],
1439}
1440
1441interfaces.implement {
1442 name = "columnsetcurrentcolumn",
1443 actions = columnsets.currentcolumn,
1444 arguments = "string",
1445}
1446 |