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 report("%i rows needed, %i rows available, no slots free at (%i,%i), discarding",rr,nofrows,c,r)
411 return false
412 end
413 local cc = 0
414 local wd = spans[c]
415 local wc = 0
416 local nc = 0
417 for i=c,nofcolumns do
418 nc = nc + 1
419 wc = wd[nc]
420 if not wc then
421 break
422 elseif wc >= width then
423 cc = i
424 break
425 end
426 end
427 if cc == 0 or cc > nofcolumns then
428 report("needed %p, no slot free at (%i,%i), discarding",width,c,r)
429 return false
430 end
431 for i=c,cc do
432 local column = cells[i]
433 for j=r,rr do
434 if column[j] then
435 report("width %p, needed %p, checking (%i,%i) x (%i,%i), %s",width,wc,c,r,nc,nr,"quit")
436 return false
437 end
438 end
439 end
440
441 return c, r, nc
442end
443
444
445
446local methods = {
447 [v_here] = here,
448 [v_fixed] = here,
449 tblr = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
450 for j=r,nofrows-nr+1 do
451 for i=c,nofcolumns do
452 if not cells[i][j] then
453 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
454 if c then
455 return c, r, cc
456 end
457 end
458 end
459 end
460 end,
461 lrtb = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
462 for i=c,nofcolumns do
463 for j=r,nofrows-nr+1 do
464 if not cells[i][j] then
465 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
466 if c then
467 return c, r, cc
468 end
469 end
470 end
471 end
472 end,
473 tbrl = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
474 for j=r,nofrows-nr+1 do
475 for i=nofcolumns,c,-1 do
476 if not cells[i][j] then
477 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
478 if c then
479 return c, r, cc
480 end
481 end
482 end
483 end
484 end,
485 rltb = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
486 for i=nofcolumns,c,-1 do
487 for j=r,nofrows-nr+1 do
488 if not cells[i][j] then
489 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
490 if c then
491 return c, r, cc
492 end
493 end
494 end
495 end
496 end,
497 btlr = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
498
499 for j=nofrows-nr+1-r+1,1,-1 do
500 for i=c,nofcolumns do
501 if not cells[i][j] then
502 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
503 if c then
504 return c, r, cc
505 end
506 end
507 end
508 end
509 end,
510 lrbt = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
511 for i=c,nofcolumns do
512
513 for j=nofrows-nr+1-r+1,1,-1 do
514 if not cells[i][j] then
515 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
516 if c then
517 return c, r, cc
518 end
519 end
520 end
521 end
522 end,
523 btrl = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
524
525 for j=nofrows-nr+1-r+1,1,-1 do
526 for i=nofcolumns,c,-1 do
527 if not cells[i][j] then
528 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
529 if c then
530 return c, r, cc
531 end
532 end
533 end
534 end
535 end,
536 rlbt = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
537 for i=nofcolumns,c,-1 do
538
539 for j=nofrows-nr+1-r+1,1,-1 do
540 if not cells[i][j] then
541 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
542 if c then
543 return c, r, cc
544 end
545 end
546 end
547 end
548 end,
549 fxtb = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
550 for i=c,nofcolumns do
551 for j=r,nofrows-nr+1 do
552 if not cells[i][j] then
553 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
554 if c then
555 return c, r, cc
556 end
557 end
558 r = 1
559 end
560 end
561 end,
562 fxbt = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
563 for i=c,nofcolumns do
564 for j=nofrows-nr+1,r,-1 do
565 if not cells[i][j] then
566 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
567 if c then
568 return c, r, cc
569 end
570 end
571 end
572 r = 1
573 end
574 end,
575 [v_top] = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
576 for i=c,nofcolumns do
577 for j=1,nofrows-nr+1 do
578 if cells[i][j] then
579 break
580 else
581 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
582 if c then
583 return c, r, cc
584 end
585 end
586 end
587 end
588 end,
589 [v_bottom] = function(c,r,nr,nofcolumns,nofrows,cells,width,spans)
590 for i=c,nofcolumns do
591 for j=1,nofrows-nr+1 do
592 if cells[i][j] then
593 break
594 else
595 local c, r, cc = here(i,j,nr,nofcolumns,nofrows,cells,width,spans)
596 if c then
597 return c, r, cc
598 end
599 end
600 end
601 end
602 end,
603}
604
605local threshold = 50
606
607function columnsets.check(t)
608 local dataset = data[t.name]
609 local cells = dataset.cells
610 local nofcolumns = dataset.nofcolumns
611 local nofrows = dataset.nofrows
612 local widths = dataset.widths
613 local lineheight = dataset.lineheight
614 local linedepth = dataset.linedepth
615 local distances = dataset.distances
616 local spans = dataset.spans
617
618 local method = lower(t.method or "tblr")
619 local boxwidth = t.width or 0
620 local boxheight = t.height or 0
621 local boxnumber = t.box
622 local box = boxnumber and getbox(boxnumber)
623
624 if boxwidth > 0 and boxheight > 0 then
625
626 elseif box then
627 local wd, ht, dp = getwhd(box)
628 boxwidth = wd
629 boxheight = ht + dp
630 else
631 report("empty box")
632 return
633 end
634
635 local c = t.c or 0
636 local r = t.r or 0
637 if c == 0 then
638 c = dataset.currentcolumn
639 end
640 if r == 0 then
641 r = dataset.currentrow
642 end
643 if c == 0 or r == 0 or c > nofcolumns or r > nofrows then
644 texsetcount("c_page_grd_reserved_state",5)
645 return
646 end
647
648 local nr = ceil(boxheight/(lineheight+linedepth))
649
650 local action = methods[method]
651 local cfound = false
652 local rfound = false
653 local lastcolumn = dataset.lastcolumn
654
655
656
657
658 if action then
659 cfound, rfound, nc = action(c,r,nr,lastcolumn,nofrows,cells,boxwidth-threshold,spans)
660 end
661 if not cfound and method ~= v_here then
662
663 cfound, rfound, nc = here(c,r,nr,lastcolumn,nofrows,cells,boxwidth-threshold,spans)
664 end
665 if cfound then
666 local ht = nr*(lineheight+linedepth)
667 local wd = spans[cfound][nc]
668 dataset.reserved_ht = ht
669 dataset.reserved_wd = wd
670 dataset.reserved_c = cfound
671 dataset.reserved_r = rfound
672 dataset.reserved_nc = nc
673 dataset.reserved_nr = nr
674 texsetcount("c_page_grd_reserved_state",0)
675 texsetdimen("d_page_grd_reserved_height",ht)
676 texsetdimen("d_page_grd_reserved_width",wd)
677
678 else
679 dataset.reserved_ht = false
680 dataset.reserved_wd = false
681 dataset.reserved_c = false
682 dataset.reserved_r = false
683 dataset.reserved_nc = false
684 dataset.reserved_nr = false
685 texsetcount("c_page_grd_reserved_state",4)
686
687
688
689 end
690end
691
692function columnsets.put(t)
693 local dataset = data[t.name]
694 local cells = dataset.cells
695 local widths = dataset.widths
696 local lineheight = dataset.lineheight
697 local linedepth = dataset.linedepth
698 local boxnumber = t.box
699 local box = boxnumber and takebox(boxnumber)
700
701 local c = t.c or dataset.reserved_c
702 local r = t.r or dataset.reserved_r
703 if not c or not r then
704
705 return
706 end
707 local lastc = c + dataset.reserved_nc - 1
708 local lastr = r + dataset.reserved_nr - 1
709
710 for i=c,lastc do
711 local column = cells[i]
712 for j=r,lastr do
713 column[j] = true
714 end
715 end
716 cells[c][r] = box
717 setwhd(box,widths[c],lineheight,linedepth)
718 dataset.reserved_c = false
719 dataset.reserved_r = false
720 dataset.reserved_nc = false
721 dataset.reserved_nr = false
722
723end
724
725local function findgap(dataset)
726 local cells = dataset.cells
727 local nofcolumns = dataset.nofcolumns
728 local nofrows = dataset.nofrows
729 local currentrow = dataset.currentrow
730 local currentcolumn = dataset.currentcolumn
731
732 local foundc = 0
733 local foundr = 0
734 local foundn = 0
735 for c=currentcolumn,dataset.lastcolumn do
736 local column = cells[c]
737foundn = 0
738 for r=currentrow,nofrows do
739 if not column[r] then
740 if foundc == 0 then
741 foundc = c
742 foundr = r
743 end
744 foundn = foundn + 1
745 elseif foundn > 0 then
746 return foundc, foundr, foundn
747 end
748 end
749 if foundn > 0 then
750 return foundc, foundr, foundn
751 end
752 currentrow = 1
753 end
754end
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
792
793
794local function checkroom(head,available,row)
795 if row == 1 then
796 while head do
797 local id = getid(head)
798 if id == glue_code then
799 head = getnext(head)
800 else
801 break
802 end
803 end
804 end
805 local used = 0
806 local line = false
807 while head do
808 local id = getid(head)
809 if id == hlist_code or id == vlist_code or id == rule_code then
810 local wd, ht, dp = getwhd(head)
811 used = used + ht + dp
812 line = true
813 if used > available then
814 break
815 end
816 elseif id == glue_code then
817 if line then
818 break
819 end
820 used = used + getwidth(head)
821 if used > available then
822 break
823 end
824 elseif id == kern_code then
825 used = used + getkern(head)
826 if used > available then
827 break
828 end
829 elseif id == penalty_code then
830
831 if getpenalty(head) >= 10000 then
832 line = false
833 else
834 break
835 end
836 end
837 head = getnext(head)
838 end
839 return line, used
840end
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
912
913
914local function findslice(dataset,head,available,column,row)
915 local first = nil
916 local lineheight = dataset.lineheight
917 local linedepth = dataset.linedepth
918 local linetotal = lineheight + linedepth
919 local slack = 65536
920 local copy = copylist(head)
921 local attempts = 0
922 local usedsize = available
923 while true do
924 attempts = attempts + 1
925 texsetbox("scratchbox",tonode(new_vlist(copy)))
926 local done = splitbox("scratchbox",usedsize,"additional")
927 local used = getheight(done)
928 local rest = takebox("scratchbox")
929 if used > (usedsize+slack) then
930 if trace_details then
931 report("at (%i,%i) available %p, used %p, overflow %p",column,row,usedsize,used,used-usedsize)
932 end
933
934 flushlist(takelist(done))
935 flushlist(takelist(rest))
936
937 usedsize = usedsize - linetotal
938 if usedsize > linetotal then
939 copy = copylist(head)
940 else
941 return 0, nil, head
942 end
943 else
944
945 flushlist(takelist(done))
946 flushlist(takelist(rest))
947
948 texsetbox("scratchbox",tonode(new_vlist(head)))
949 done = splitbox("scratchbox",usedsize,"additional")
950 rest = takebox("scratchbox")
951 used = getheight(done)
952 if attempts > 1 then
953 used = available
954 end
955 first = takelist(done)
956 head = takelist(rest)
957
958 return used, first, head
959 end
960 end
961end
962
963local nofcolumngaps = 0
964
965function columnsets.add(name,box)
966 local dataset = data[name]
967 local cells = dataset.cells
968 local nofcolumns = dataset.nofcolumns
969 local nofrows = dataset.nofrows
970 local currentrow = dataset.currentrow
971 local currentcolumn = dataset.currentcolumn
972 local lineheight = dataset.lineheight
973 local linedepth = dataset.linedepth
974 local widths = dataset.widths
975
976 local b = getbox(box)
977 local l = getlist(b)
978
979 if l then
980 setlist(b,nil)
981 local hd = lineheight + linedepth
982 while l do
983 local foundc, foundr, foundn = findgap(dataset)
984 if foundc then
985 local available = foundn * hd
986 local used, first, last = findslice(dataset,l,available,foundc,foundr)
987 if first then
988 local v
989 if used == available or (foundr+foundn > nofrows) then
990 v = vpack(first,available,"exactly")
991 else
992 v = new_vlist(first)
993 end
994 nofcolumngaps = nofcolumngaps + 1
995
996 properties[v] = { columngap = nofcolumngaps }
997
998 setwhd(v,widths[currentcolumn],lineheight,linedepth)
999 local column = cells[foundc]
1000
1001 column[foundr] = v
1002 used = used - hd
1003 if used > 0 then
1004 for r=foundr+1,foundr+foundn-1 do
1005 used = used - hd
1006 foundr = foundr + 1
1007 column[r] = true
1008 if used <= 0 then
1009 break
1010 end
1011 end
1012 end
1013 currentcolumn = foundc
1014 currentrow = foundr
1015 dataset.currentcolumn = currentcolumn
1016 dataset.currentrow = currentrow
1017 l = last
1018 dataset.rest = l
1019 else
1020 local column = cells[foundc]
1021 for i=foundr,foundr+foundn-1 do
1022 column[i] = true
1023 end
1024 l = last
1025 end
1026 else
1027 dataset.rest = l
1028 return
1029 end
1030 end
1031 end
1032end
1033
1034do
1035
1036
1037
1038
1039 local followup = nil
1040 local splitter = lpeg.splitter("*",tonumber)
1041
1042 columnsets["noto"] = function(t)
1043 return followup()
1044 end
1045
1046 columnsets["goto"] = function(name,target)
1047 local dataset = data[name]
1048 local nofcolumns = dataset.nofcolumns
1049 if target == v_yes or target == "" then
1050 local currentcolumn = dataset.currentcolumn
1051 followup = function()
1052 context(dataset.currentcolumn == currentcolumn and 1 or 0)
1053 end
1054 return followup()
1055 end
1056 if target == v_first then
1057 if dataset.currentcolumn > 1 then
1058 target = v_page
1059 else
1060 return context(0)
1061 end
1062 end
1063 if target == v_page then
1064 if dataset.currentcolumn == 1 and dataset.currentrow == 1 then
1065 return context(0)
1066 else
1067 local currentpage = dataset.page
1068 followup = function()
1069 context(dataset.page == currentpage and 1 or 0)
1070 end
1071 return followup()
1072 end
1073 end
1074 if target == v_last then
1075 target = dataset.nofcolumns
1076 if dataset.currentcolumn ~= target then
1077 followup = function()
1078 context(dataset.currentcolumn ~= target and 1 or 0)
1079 end
1080 return followup()
1081 end
1082 return
1083 end
1084 local targetpage = tonumber(target)
1085 if targetpage then
1086 followup = function()
1087 context(dataset.currentcolumn ~= targetpage and 1 or 0)
1088 end
1089 return followup()
1090 end
1091 local targetcolumn, targetrow = lpeg.match(splitter,target)
1092 if targetcolumn and targetrow then
1093 if dataset.currentcolumn ~= targetcolumn and dataset.currentrow ~= targetrow then
1094 followup = function()
1095 if dataset.currentcolumn ~= targetcolumn then
1096 context(1)
1097 return
1098 end
1099 if dataset.currentcolumn == targetcolumn then
1100 context(dataset.currentrow ~= targetrow and 1 or 0)
1101 else
1102 context(0)
1103 end
1104 end
1105 return followup()
1106 end
1107 end
1108 end
1109
1110end
1111
1112function columnsets.currentcolumn(name)
1113 local dataset = data[name]
1114 context(dataset.currentcolumn)
1115end
1116
1117function columnsets.flushrest(name,box)
1118 local dataset = data[name]
1119 local rest = dataset.rest
1120 if rest then
1121 dataset.rest = nil
1122 setbox("global",box,new_vlist(rest))
1123 end
1124end
1125
1126function columnsets.setvsize(name)
1127 local dataset = data[name]
1128 local c, r, n = findgap(dataset)
1129 if n then
1130 dataset.currentcolumn = c
1131 dataset.currentrow = r
1132 else
1133 dataset.currentcolumn = 1
1134 dataset.currentrow = 1
1135 n = 0
1136 end
1137 local gap = n*(dataset.lineheight+dataset.linedepth)
1138 texsetdimen("d_page_grd_gap_height",gap)
1139
1140
1141end
1142
1143function columnsets.sethsize(name)
1144 local dataset = data[name]
1145 texsetdimen("d_page_grd_column_width",dataset.widths[dataset.currentcolumn])
1146end
1147
1148function columnsets.sethspan(name,span)
1149
1150
1151 local dataset = data[name]
1152 local column = dataset.currentcolumn
1153 local available = dataset.lastcolumn - column + 1
1154 if span > available then
1155 span = available
1156 end
1157 local width = dataset.spans[column][span]
1158 texsetdimen("d_page_grd_span_width",width)
1159end
1160
1161function columnsets.setlines(t)
1162 local dataset = data[t.name]
1163 dataset.lines[t.page][t.column] = t.value
1164end
1165
1166function columnsets.setstart(t)
1167 local dataset = data[t.name]
1168 dataset.start[t.page][t.column] = t.value
1169end
1170
1171function columnsets.setproperties(t)
1172 local dataset = data[t.name]
1173 local column = t.column
1174 dataset.distances[column] = t.distance
1175 dataset.widths[column] = t.width
1176end
1177
1178local areas = { }
1179
1180function columnsets.registerarea(t)
1181
1182 areas[#areas+1] = t
1183end
1184
1185
1186
1187local ctx_page_grd_set_area = context.protected.page_grd_set_area
1188
1189function columnsets.flushareas(name)
1190 local nofareas = #areas
1191 if nofareas == 0 then
1192 return
1193 end
1194 local dataset = data[name]
1195 local page = dataset.page
1196 if odd(page) then
1197
1198 local kept = { }
1199 for i=1,nofareas do
1200 local area = areas[i]
1201
1202
1203 local okay = false
1204
1205 local nofcolumns = area.nc
1206 local nofrows = area.nr
1207 local column = area.c
1208 local row = area.r
1209 columnsets.block {
1210 name = name,
1211 c = column,
1212 r = row,
1213 nc = nofcolumns,
1214 nr = nofrows,
1215 }
1216 local left = 0
1217 local start = dataset.nofleft + 1
1218 local overflow = (column + nofcolumns - 1) - dataset.nofleft
1219 local height = nofrows * (dataset.lineheight + dataset.linedepth)
1220 local width = dataset.spreads[column][nofcolumns]
1221
1222 if overflow > 0 then
1223 local used = nofcolumns - overflow
1224 left = dataset.spreads[column][used] + getdimen("backspace")
1225 end
1226 ctx_page_grd_set_area(name,area.name,column,row,width,height,start,left)
1227 if area.state ~= v_repeat then
1228 area = nil
1229 end
1230 if area then
1231 kept[#kept+1] = area
1232 end
1233 end
1234 areas = kept
1235 end
1236end
1237
1238function columnsets.setarea(t)
1239 local dataset = data[t.name]
1240 local cells = dataset.cells
1241 local box = takebox(t.box)
1242 local column = t.c
1243 local row = t.r
1244 if column and row then
1245 setwhd(box,dataset.widths[column],dataset.lineheight,dataset.linedepth)
1246 cells[column][row] = box
1247 end
1248end
1249
1250
1251
1252implement {
1253 name = "definecolumnset",
1254 actions = columnsets.define,
1255 arguments = { {
1256 { "name", "string" },
1257 } }
1258}
1259
1260implement {
1261 name = "resetcolumnset",
1262 actions = columnsets.reset,
1263 arguments = { {
1264 { "name", "string" },
1265 { "nofleft", "integer" },
1266 { "nofright", "integer" },
1267 { "nofrows", "integer" },
1268 { "lineheight", "dimension" },
1269 { "linedepth", "dimension" },
1270 { "width", "dimension" },
1271 { "distance", "dimension" },
1272 { "maxwidth", "dimension" },
1273 } }
1274}
1275
1276implement {
1277 name = "preparecolumnsetflush",
1278 actions = columnsets.prepareflush,
1279 arguments = "string",
1280}
1281
1282implement {
1283 name = "finishcolumnsetflush",
1284 actions = columnsets.finishflush,
1285 arguments = "string",
1286}
1287
1288implement {
1289 name = "flushcolumnsetcolumn",
1290 actions = columnsets.flushcolumn,
1291 arguments = { "string" ,"integer" },
1292}
1293
1294implement {
1295 name = "setvsizecolumnset",
1296 actions = columnsets.setvsize,
1297 arguments = "string",
1298}
1299
1300implement {
1301 name = "sethsizecolumnset",
1302 actions = columnsets.sethsize,
1303 arguments = "string",
1304}
1305
1306implement {
1307 name = "sethsizecolumnspan",
1308 actions = columnsets.sethspan,
1309 arguments = { "string" ,"integer" },
1310}
1311
1312implement {
1313 name = "flushcolumnsetrest",
1314 actions = columnsets.flushrest,
1315 arguments = { "string", "integer" },
1316}
1317
1318implement {
1319 name = "blockcolumnset",
1320 actions = columnsets.block,
1321 arguments = { {
1322 { "name", "string" },
1323 { "c", "integer" },
1324 { "r", "integer" },
1325 { "nc", "integer" },
1326 { "nr", "integer" },
1327 { "method", "string" },
1328 { "box", "integer" },
1329 } }
1330}
1331
1332implement {
1333 name = "checkcolumnset",
1334 actions = columnsets.check,
1335 arguments = { {
1336 { "name", "string" },
1337 { "method", "string" },
1338 { "c", "integer" },
1339 { "r", "integer" },
1340 { "method", "string" },
1341 { "box", "integer" },
1342 { "width", "dimension" },
1343 { "height", "dimension" },
1344 { "option", "string" },
1345 } }
1346}
1347
1348implement {
1349 name = "putincolumnset",
1350 actions = columnsets.put,
1351 arguments = { {
1352 { "name", "string" },
1353 { "c", "integer" },
1354 { "r", "integer" },
1355 { "method", "string" },
1356 { "box", "integer" },
1357 } }
1358}
1359
1360implement {
1361 name = "addtocolumnset",
1362 actions = columnsets.add,
1363 arguments = { "string", "integer" },
1364}
1365
1366implement {
1367 name = "setcolumnsetlines",
1368 actions = columnsets.setlines,
1369 arguments = { {
1370 { "name", "string" },
1371 { "page", "integer" },
1372 { "column", "integer" },
1373 { "value", "integer" },
1374 } }
1375}
1376
1377implement {
1378 name = "setcolumnsetstart",
1379 actions = columnsets.setstart,
1380 arguments = { {
1381 { "name", "string" },
1382 { "page", "integer" },
1383 { "column", "integer" },
1384 { "value", "integer" },
1385 } }
1386}
1387
1388implement {
1389 name = "setcolumnsetproperties",
1390 actions = columnsets.setproperties,
1391 arguments = { {
1392 { "name", "string" },
1393 { "column", "integer" },
1394 { "distance", "dimension" },
1395 { "width", "dimension" },
1396 } }
1397}
1398
1399implement {
1400 name = "registercolumnsetarea",
1401 actions = columnsets.registerarea,
1402 arguments = { {
1403 { "name", "string" },
1404 { "type", "string" },
1405 { "page", "integer" },
1406 { "state", "string" },
1407 { "c", "integer" },
1408 { "r", "integer" },
1409 { "nc", "integer" },
1410 { "nr", "integer" },
1411 } }
1412}
1413
1414implement {
1415 name = "flushcolumnsetareas",
1416 actions = columnsets.flushareas,
1417 arguments = "string",
1418}
1419
1420implement {
1421 name = "setcolumnsetarea",
1422 actions = columnsets.setarea,
1423 arguments = { {
1424 { "name", "string" },
1425 { "c", "integer" },
1426 { "r", "integer" },
1427 { "method", "string" },
1428 { "box", "integer" },
1429 } }
1430}
1431
1432implement {
1433 name = "columnsetgoto",
1434 actions = columnsets["goto"],
1435 arguments = "2 strings",
1436}
1437
1438implement {
1439 name = "columnsetnoto",
1440 actions = columnsets["noto"],
1441}
1442
1443implement {
1444 name = "columnsetcurrentcolumn",
1445 actions = columnsets.currentcolumn,
1446 arguments = "string",
1447}
1448 |