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 takebox = nuts.takebox
60local takelist = nuts.takelist
61local splitbox = nuts.splitbox
62local getattribute = nuts.getattribute
63local copylist = nuts.copylist
64
65local getbox = nuts.getbox
66local getcount = tex.getcount
67local getdimen = tex.getdimen
68
69local texsetbox = tex.setbox
70local texsetcount = tex.setcount
71local texsetdimen = tex.setdimen
72
73local theprop = nuts.theprop
74
75local nodepool = nuts.pool
76
77local new_vlist = nodepool.vlist
78local new_trace_rule = nodepool.rule
79local new_empty_rule = nodepool.emptyrule
80
81local context = context
82local implement = interfaces.implement
83
84local variables <const> = interfaces.variables
85local v_here <const> = variables.here
86local v_fixed <const> = variables.fixed
87local v_top <const> = variables.top
88local v_bottom <const> = variables.bottom
89local v_repeat <const> = variables["repeat"]
90local v_yes <const> = variables.yes
91local v_page <const> = variables.page
92local v_first <const> = variables.first
93local v_last <const> = variables.last
94
95
96pagebuilders = pagebuilders or { }
97pagebuilders.columnsets = pagebuilders.columnsets or { }
98local columnsets = pagebuilders.columnsets
99
100local data = { [""] = { } }
101
102
103
104local function setstate(t,start)
105 if start or not t.firstcolumn then
106 t.firstcolumn = odd(getcount("realpageno")) and 1 or 2
107 end
108 if t.firstcolumn > 1 then
109 t.firstcolumn = 1
110 t.lastcolumn = t.nofleft
111 t.state = "left"
112 else
113 t.firstcolumn = t.nofleft + 1
114 t.lastcolumn = t.firstcolumn + t.nofright - 1
115 t.state = "right"
116 end
117 t.currentcolumn = t.firstcolumn
118 t.currentrow = 1
119end
120
121function columnsets.define(t)
122 local name = t.name
123 local nofleft = t.nofleft or 1
124 local nofright = t.nofright or 1
125 local nofcolumns = nofleft + nofright
126 local dataset = data[name] or { }
127 data[name] = dataset
128 dataset.nofleft = nofleft
129 dataset.nofright = nofright
130 dataset.nofcolumns = nofcolumns
131 dataset.nofrows = t.nofrows or 1
132 dataset.distance = t.distance or getdimen("bodyfontsize")
133 dataset.maxwidth = t.maxwidth or getdimen("makeupwidth")
134 dataset.lineheight = t.lineheight or getdimen("globalbodyfontstrutheight")
135 dataset.linedepth = t.linedepth or getdimen("globalbodyfontstrutdepth")
136
137 dataset.cells = { }
138 dataset.currentcolumn = 1
139 dataset.currentrow = 1
140
141 dataset.lines = dataset.lines or setmetatableindex("table")
142 dataset.start = dataset.start or setmetatableindex("table")
143
144 dataset.page = 1
145
146 local distances = dataset.distances or setmetatableindex(function(t,k)
147 return dataset.distance
148 end)
149 dataset.distances = distances
150
151 local widths = dataset.widths or setmetatableindex(function(t,k)
152 return dataset.width
153 end)
154 dataset.widths = widths
155
156 local width = t.width
157 if not width or width == 0 then
158 local dl = 0
159 local dr = 0
160 for i=1,nofleft-1 do
161 dl = dl + distances[i]
162 end
163 for i=1,nofright-1 do
164 dr = dr + distances[nofleft+i]
165 end
166 local nl = nofleft
167 local nr = nofright
168 local wl = dataset.maxwidth
169 local wr = wl
170 for i=1,nofleft do
171 local w = rawget(widths,i)
172 if w then
173 nl = nl - 1
174 wl = wl - w
175 end
176 end
177 for i=1,nofright do
178 local w = rawget(widths,nofleft+i)
179 if w then
180 nr = nr - 1
181 wr = wr - w
182 end
183 end
184 dl = (wl - dl) / nl
185 dr = (wr - dr) / nr
186 if dl > dr then
187 report("using %s page column width %p in columnset %a","right",dr,name)
188 width = dr
189 elseif dl < dr then
190 report("using %s page column width %p in columnset %a","left",dl,name)
191 width = dl
192 else
193 width = dl
194 end
195 end
196
197 width = round(width)
198 dataset.width = width
199 local spans = { }
200 dataset.spans = spans
201 for i=1,nofleft do
202 local s = { }
203 local d = 0
204 for j=1,nofleft-i+1 do
205 d = d + width
206 s[j] = round(d)
207 d = d + distances[j]
208 end
209 spans[i] = s
210 end
211 for i=1,nofright do
212 local s = { }
213 local d = 0
214 for j=1,nofright-i+1 do
215 d = d + width
216 s[j] = round(d)
217 d = d + distances[j]
218 end
219 spans[nofleft+i] = s
220 end
221
222 local spreads = copy(spans)
223 dataset.spreads = spreads
224 local gap = 2 * getdimen("backspace")
225 for l=1,nofleft do
226 local s = spreads[l]
227 local n = #s
228 local o = s[n] + gap
229 for r=1,nofright do
230 n = n + 1
231 s[n] = s[r] + o
232 end
233 end
234
235 texsetdimen("d_page_grd_column_width",dataset.width)
236
237 setstate(dataset,true)
238
239 return dataset
240end
241
242local function check(dataset)
243 local cells = dataset.cells
244 local page = dataset.page
245 local offset = odd(page) and dataset.nofleft or 0
246 local start = dataset.start
247 local list = rawget(start,page)
248 if list then
249 for c, n in next, list do
250 local column = cells[offset + c]
251 if column then
252 for r=1,n do
253 column[r] = true
254 end
255 end
256 end
257 start[page] = nil
258 end
259 local lines = dataset.lines
260 local list = rawget(lines,page)
261 local rows = dataset.nofrows
262 if list then
263 for c, n in next, list do
264 local column = cells[offset + c]
265 if column then
266 if n > 0 then
267 for r=n+1,rows do
268 column[r] = true
269 end
270 elseif n < 0 then
271 for r=rows,rows+n+1,-1 do
272 column[r] = true
273 end
274 end
275 end
276 end
277 lines[page] = nil
278 end
279end
280
281local function erase(dataset,all)
282 local cells = dataset.cells
283 local nofrows = dataset.nofrows
284 local first = 1
285 local last = dataset.nofcolumns
286
287 if not all then
288 first = dataset.firstcolumn or first
289 last = dataset.lastcolumn or last
290 end
291 for c=first,last do
292 local column = { }
293 for r=1,nofrows do
294 if column[r] then
295 report("slot (%i,%i) is not empty",c,r)
296 end
297 column[r] = false
298 end
299 cells[c] = column
300 end
301end
302
303function columnsets.reset(t)
304 local dataset = columnsets.define(t)
305 erase(dataset,true)
306 check(dataset)
307end
308
309function columnsets.prepareflush(name)
310 local dataset = data[name]
311 local cells = dataset.cells
312 local firstcolumn = dataset.firstcolumn
313 local lastcolumn = dataset.lastcolumn
314 local nofrows = dataset.nofrows
315 local lineheight = dataset.lineheight
316 local linedepth = dataset.linedepth
317 local widths = dataset.widths
318 local height = (lineheight+linedepth)*nofrows
319
320 local columns = { }
321 dataset.columns = columns
322
323 for c=firstcolumn,lastcolumn do
324 local column = cells[c]
325 for r=1,nofrows do
326 local cell = column[r]
327 if (cell == false) or (cell == true) then
328 if trace_cells then
329 column[r] = new_trace_rule(65536*2,lineheight,linedepth)
330 else
331 column[r] = new_empty_rule(0,lineheight,linedepth)
332 end
333 end
334 end
335 for r=1,nofrows-1 do
336 setlink(column[r],column[r+1])
337 end
338 columns[c] = new_vlist(column[1],widths[c],height,0)
339 end
340
341 texsetcount("c_page_grd_first_column",firstcolumn)
342 texsetcount("c_page_grd_last_column",lastcolumn)
343end
344
345function columnsets.flushcolumn(name,column)
346 local dataset = data[name]
347 local columns = dataset.columns
348 local packed = columns[column]
349 setbox("b_page_grd_column",packed)
350 columns[column] = nil
351end
352
353function columnsets.finishflush(name)
354 local dataset = data[name]
355 local cells = dataset.cells
356 local firstcolumn = dataset.firstcolumn
357 local lastcolumn = dataset.lastcolumn
358 local nofrows = dataset.nofrows
359 for c=firstcolumn,lastcolumn do
360 local column = { }
361 for r=1,nofrows do
362 column[r] = false
363 end
364 cells[c] = column
365 end
366 dataset.page = dataset.page + 1
367 check(dataset)
368 setstate(dataset)
369end
370
371function columnsets.block(t)
372 local dataset = data[t.name]
373 local cells = dataset.cells
374 local nofcolumns = dataset.nofcolumns
375 local nofrows = dataset.nofrows
376
377 local c = t.c or 0
378 local r = t.r or 0
379 if c == 0 or r == 0 or c > nofcolumns or r > nofrows then
380 return
381 end
382 local nc = t.nc or 0
383 local nr = t.nr or 0
384 if nc == 0 then
385 return
386 end
387 if nr == 0 then
388 return
389 end
390 local rr = r + nr - 1
391 local cc = c + nc - 1
392 if rr > nofrows then
393 rr = nofrows
394 end
395 if cc > nofcolumns then
396 cc = nofcolumns
397 end
398 for i=c,cc do
399 local column = cells[i]
400 for j=r,rr do
401 column[j] = true
402 end
403 end
404end
405
406local function here(c,r,nr,nofcolumns,nofrows,cells,width,spans)
407 local rr = r + nr - 1
408 if rr > nofrows then
409 report("%i rows needed, %i rows available, no slots free at (%i,%i), discarding",rr,nofrows,c,r)
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 report("needed %p, no slot free at (%i,%i), discarding",width,c,r)
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 report("width %p, needed %p, checking (%i,%i) x (%i,%i), %s",width,wc,c,r,nc,nr,"quit")
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
662 cfound, rfound, nc = here(c,r,nr,lastcolumn,nofrows,cells,boxwidth-threshold,spans)
663 end
664 if cfound then
665 local ht = nr*(lineheight+linedepth)
666 local wd = spans[cfound][nc]
667 dataset.reserved_ht = ht
668 dataset.reserved_wd = wd
669 dataset.reserved_c = cfound
670 dataset.reserved_r = rfound
671 dataset.reserved_nc = nc
672 dataset.reserved_nr = nr
673 texsetcount("c_page_grd_reserved_state",0)
674 texsetdimen("d_page_grd_reserved_height",ht)
675 texsetdimen("d_page_grd_reserved_width",wd)
676
677 else
678 dataset.reserved_ht = false
679 dataset.reserved_wd = false
680 dataset.reserved_c = false
681 dataset.reserved_r = false
682 dataset.reserved_nc = false
683 dataset.reserved_nr = false
684 texsetcount("c_page_grd_reserved_state",4)
685
686
687
688 end
689end
690
691function columnsets.put(t)
692 local dataset = data[t.name]
693 local cells = dataset.cells
694 local widths = dataset.widths
695 local lineheight = dataset.lineheight
696 local linedepth = dataset.linedepth
697 local boxnumber = t.box
698 local box = boxnumber and takebox(boxnumber)
699
700 local c = t.c or dataset.reserved_c
701 local r = t.r or dataset.reserved_r
702 if not c or not r then
703
704 return
705 end
706 local lastc = c + dataset.reserved_nc - 1
707 local lastr = r + dataset.reserved_nr - 1
708
709 for i=c,lastc do
710 local column = cells[i]
711 for j=r,lastr do
712 column[j] = true
713 end
714 end
715 cells[c][r] = box
716 setwhd(box,widths[c],lineheight,linedepth)
717 dataset.reserved_c = false
718 dataset.reserved_r = false
719 dataset.reserved_nc = false
720 dataset.reserved_nr = false
721
722end
723
724local function findgap(dataset)
725 local cells = dataset.cells
726 local nofcolumns = dataset.nofcolumns
727 local nofrows = dataset.nofrows
728 local currentrow = dataset.currentrow
729 local currentcolumn = dataset.currentcolumn
730
731 local foundc = 0
732 local foundr = 0
733 local foundn = 0
734 for c=currentcolumn,dataset.lastcolumn do
735 local column = cells[c]
736foundn = 0
737 for r=currentrow,nofrows do
738 if not column[r] then
739 if foundc == 0 then
740 foundc = c
741 foundr = r
742 end
743 foundn = foundn + 1
744 elseif foundn > 0 then
745 return foundc, foundr, foundn
746 end
747 end
748 if foundn > 0 then
749 return foundc, foundr, foundn
750 end
751 currentrow = 1
752 end
753end
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
792
793local function checkroom(head,available,row)
794 if row == 1 then
795 while head do
796 local id = getid(head)
797 if id == glue_code then
798 head = getnext(head)
799 else
800 break
801 end
802 end
803 end
804 local used = 0
805 local line = false
806 while head do
807 local id = getid(head)
808 if id == hlist_code or id == vlist_code or id == rule_code then
809 local wd, ht, dp = getwhd(head)
810 used = used + ht + dp
811 line = true
812 if used > available then
813 break
814 end
815 elseif id == glue_code then
816 if line then
817 break
818 end
819 used = used + getwidth(head)
820 if used > available then
821 break
822 end
823 elseif id == kern_code then
824 used = used + getkern(head)
825 if used > available then
826 break
827 end
828 elseif id == penalty_code then
829
830 if getpenalty(head) >= 10000 then
831 line = false
832 else
833 break
834 end
835 end
836 head = getnext(head)
837 end
838 return line, used
839end
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
912
913local function findslice(dataset,head,available,column,row)
914 local first = nil
915 local lineheight = dataset.lineheight
916 local linedepth = dataset.linedepth
917 local linetotal = lineheight + linedepth
918 local slack = 65536
919 local copy = copylist(head)
920 local attempts = 0
921 local usedsize = available
922 while true do
923 attempts = attempts + 1
924 texsetbox("scratchbox",tonode(new_vlist(copy)))
925 local done = splitbox("scratchbox",usedsize,"additional")
926 local used = getheight(done)
927 local rest = takebox("scratchbox")
928 if used > (usedsize+slack) then
929 if trace_details then
930 report("at (%i,%i) available %p, used %p, overflow %p",column,row,usedsize,used,used-usedsize)
931 end
932
933 flushlist(takelist(done))
934 flushlist(takelist(rest))
935
936 usedsize = usedsize - linetotal
937 if usedsize > linetotal then
938 copy = copylist(head)
939 else
940 return 0, nil, head
941 end
942 else
943
944 flushlist(takelist(done))
945 flushlist(takelist(rest))
946
947 texsetbox("scratchbox",tonode(new_vlist(head)))
948 done = splitbox("scratchbox",usedsize,"additional")
949 rest = takebox("scratchbox")
950 used = getheight(done)
951 if attempts > 1 then
952 used = available
953 end
954 first = takelist(done)
955 head = takelist(rest)
956
957 return used, first, head
958 end
959 end
960end
961
962local nofcolumngaps = 0
963
964function columnsets.add(name,box)
965 local dataset = data[name]
966 local cells = dataset.cells
967 local nofcolumns = dataset.nofcolumns
968 local nofrows = dataset.nofrows
969 local currentrow = dataset.currentrow
970 local currentcolumn = dataset.currentcolumn
971 local lineheight = dataset.lineheight
972 local linedepth = dataset.linedepth
973 local widths = dataset.widths
974
975 local b = getbox(box)
976 local l = getlist(b)
977
978 if l then
979 setlist(b,nil)
980 local hd = lineheight + linedepth
981 while l do
982 local foundc, foundr, foundn = findgap(dataset)
983 if foundc then
984 local available = foundn * hd
985 local used, first, last = findslice(dataset,l,available,foundc,foundr)
986 if first then
987 local v
988 if used == available or (foundr+foundn > nofrows) then
989 v = vpack(first,available,"exactly")
990 else
991 v = new_vlist(first)
992 end
993 nofcolumngaps = nofcolumngaps + 1
994
995 properties[v] = { columngap = nofcolumngaps }
996
997 setwhd(v,widths[currentcolumn],lineheight,linedepth)
998 local column = cells[foundc]
999
1000 column[foundr] = v
1001 used = used - hd
1002 if used > 0 then
1003 for r=foundr+1,foundr+foundn-1 do
1004 used = used - hd
1005 foundr = foundr + 1
1006 column[r] = true
1007 if used <= 0 then
1008 break
1009 end
1010 end
1011 end
1012 currentcolumn = foundc
1013 currentrow = foundr
1014 dataset.currentcolumn = currentcolumn
1015 dataset.currentrow = currentrow
1016 l = last
1017 dataset.rest = l
1018 else
1019 local column = cells[foundc]
1020 for i=foundr,foundr+foundn-1 do
1021 column[i] = true
1022 end
1023 l = last
1024 end
1025 else
1026 dataset.rest = l
1027 return
1028 end
1029 end
1030 end
1031end
1032
1033do
1034
1035
1036
1037
1038 local followup = nil
1039 local splitter = lpeg.splitter("*",tonumber)
1040
1041 columnsets["noto"] = function(t)
1042 return followup()
1043 end
1044
1045 columnsets["goto"] = function(name,target)
1046 local dataset = data[name]
1047 local nofcolumns = dataset.nofcolumns
1048 if target == v_yes or target == "" then
1049 local currentcolumn = dataset.currentcolumn
1050 followup = function()
1051 context(dataset.currentcolumn == currentcolumn and 1 or 0)
1052 end
1053 return followup()
1054 end
1055 if target == v_first then
1056 if dataset.currentcolumn > 1 then
1057 target = v_page
1058 else
1059 return context(0)
1060 end
1061 end
1062 if target == v_page then
1063 if dataset.currentcolumn == 1 and dataset.currentrow == 1 then
1064 return context(0)
1065 else
1066 local currentpage = dataset.page
1067 followup = function()
1068 context(dataset.page == currentpage and 1 or 0)
1069 end
1070 return followup()
1071 end
1072 end
1073 if target == v_last then
1074 target = dataset.nofcolumns
1075 if dataset.currentcolumn ~= target then
1076 followup = function()
1077 context(dataset.currentcolumn ~= target and 1 or 0)
1078 end
1079 return followup()
1080 end
1081 return
1082 end
1083 local targetpage = tonumber(target)
1084 if targetpage then
1085 followup = function()
1086 context(dataset.currentcolumn ~= targetpage and 1 or 0)
1087 end
1088 return followup()
1089 end
1090 local targetcolumn, targetrow = lpeg.match(splitter,target)
1091 if targetcolumn and targetrow then
1092 if dataset.currentcolumn ~= targetcolumn and dataset.currentrow ~= targetrow then
1093 followup = function()
1094 if dataset.currentcolumn ~= targetcolumn then
1095 context(1)
1096 return
1097 end
1098 if dataset.currentcolumn == targetcolumn then
1099 context(dataset.currentrow ~= targetrow and 1 or 0)
1100 else
1101 context(0)
1102 end
1103 end
1104 return followup()
1105 end
1106 end
1107 end
1108
1109end
1110
1111function columnsets.currentcolumn(name)
1112 local dataset = data[name]
1113 context(dataset.currentcolumn)
1114end
1115
1116function columnsets.flushrest(name,box)
1117 local dataset = data[name]
1118 local rest = dataset.rest
1119 if rest then
1120 dataset.rest = nil
1121 setbox("global",box,new_vlist(rest))
1122 end
1123end
1124
1125function columnsets.setvsize(name)
1126 local dataset = data[name]
1127 local c, r, n = findgap(dataset)
1128 if n then
1129 dataset.currentcolumn = c
1130 dataset.currentrow = r
1131 else
1132 dataset.currentcolumn = 1
1133 dataset.currentrow = 1
1134 n = 0
1135 end
1136 local gap = n*(dataset.lineheight+dataset.linedepth)
1137 texsetdimen("d_page_grd_gap_height",gap)
1138
1139
1140end
1141
1142function columnsets.sethsize(name)
1143 local dataset = data[name]
1144 texsetdimen("d_page_grd_column_width",dataset.widths[dataset.currentcolumn])
1145end
1146
1147function columnsets.sethspan(name,span)
1148
1149
1150 local dataset = data[name]
1151 local column = dataset.currentcolumn
1152 local available = dataset.lastcolumn - column + 1
1153 if span > available then
1154 span = available
1155 end
1156 local width = dataset.spans[column][span]
1157 texsetdimen("d_page_grd_span_width",width)
1158end
1159
1160function columnsets.setlines(t)
1161 local dataset = data[t.name]
1162 dataset.lines[t.page][t.column] = t.value
1163end
1164
1165function columnsets.setstart(t)
1166 local dataset = data[t.name]
1167 dataset.start[t.page][t.column] = t.value
1168end
1169
1170function columnsets.setproperties(t)
1171 local dataset = data[t.name]
1172 local column = t.column
1173 dataset.distances[column] = t.distance
1174 dataset.widths[column] = t.width
1175end
1176
1177local areas = { }
1178
1179function columnsets.registerarea(t)
1180
1181 areas[#areas+1] = t
1182end
1183
1184
1185
1186local ctx_page_grd_set_area = context.protected.page_grd_set_area
1187
1188function columnsets.flushareas(name)
1189 local nofareas = #areas
1190 if nofareas == 0 then
1191 return
1192 end
1193 local dataset = data[name]
1194 local page = dataset.page
1195 if odd(page) then
1196
1197 local kept = { }
1198 for i=1,nofareas do
1199 local area = areas[i]
1200
1201
1202 local okay = false
1203
1204 local nofcolumns = area.nc
1205 local nofrows = area.nr
1206 local column = area.c
1207 local row = area.r
1208 columnsets.block {
1209 name = name,
1210 c = column,
1211 r = row,
1212 nc = nofcolumns,
1213 nr = nofrows,
1214 }
1215 local left = 0
1216 local start = dataset.nofleft + 1
1217 local overflow = (column + nofcolumns - 1) - dataset.nofleft
1218 local height = nofrows * (dataset.lineheight + dataset.linedepth)
1219 local width = dataset.spreads[column][nofcolumns]
1220
1221 if overflow > 0 then
1222 local used = nofcolumns - overflow
1223 left = dataset.spreads[column][used] + getdimen("backspace")
1224 end
1225 ctx_page_grd_set_area(name,area.name,column,row,width,height,start,left)
1226 if area.state ~= v_repeat then
1227 area = nil
1228 end
1229 if area then
1230 kept[#kept+1] = area
1231 end
1232 end
1233 areas = kept
1234 end
1235end
1236
1237function columnsets.setarea(t)
1238 local dataset = data[t.name]
1239 local cells = dataset.cells
1240 local box = takebox(t.box)
1241 local column = t.c
1242 local row = t.r
1243 if column and row then
1244 setwhd(box,dataset.widths[column],dataset.lineheight,dataset.linedepth)
1245 cells[column][row] = box
1246 end
1247end
1248
1249
1250
1251implement {
1252 name = "definecolumnset",
1253 actions = columnsets.define,
1254 arguments = { {
1255 { "name", "string" },
1256 } }
1257}
1258
1259implement {
1260 name = "resetcolumnset",
1261 actions = columnsets.reset,
1262 arguments = { {
1263 { "name", "string" },
1264 { "nofleft", "integer" },
1265 { "nofright", "integer" },
1266 { "nofrows", "integer" },
1267 { "lineheight", "dimension" },
1268 { "linedepth", "dimension" },
1269 { "width", "dimension" },
1270 { "distance", "dimension" },
1271 { "maxwidth", "dimension" },
1272 } }
1273}
1274
1275implement {
1276 name = "preparecolumnsetflush",
1277 actions = columnsets.prepareflush,
1278 arguments = "string",
1279}
1280
1281implement {
1282 name = "finishcolumnsetflush",
1283 actions = columnsets.finishflush,
1284 arguments = "string",
1285}
1286
1287implement {
1288 name = "flushcolumnsetcolumn",
1289 actions = columnsets.flushcolumn,
1290 arguments = { "string" ,"integer" },
1291}
1292
1293implement {
1294 name = "setvsizecolumnset",
1295 actions = columnsets.setvsize,
1296 arguments = "string",
1297}
1298
1299implement {
1300 name = "sethsizecolumnset",
1301 actions = columnsets.sethsize,
1302 arguments = "string",
1303}
1304
1305implement {
1306 name = "sethsizecolumnspan",
1307 actions = columnsets.sethspan,
1308 arguments = { "string" ,"integer" },
1309}
1310
1311implement {
1312 name = "flushcolumnsetrest",
1313 actions = columnsets.flushrest,
1314 arguments = { "string", "integer" },
1315}
1316
1317implement {
1318 name = "blockcolumnset",
1319 actions = columnsets.block,
1320 arguments = { {
1321 { "name", "string" },
1322 { "c", "integer" },
1323 { "r", "integer" },
1324 { "nc", "integer" },
1325 { "nr", "integer" },
1326 { "method", "string" },
1327 { "box", "integer" },
1328 } }
1329}
1330
1331implement {
1332 name = "checkcolumnset",
1333 actions = columnsets.check,
1334 arguments = { {
1335 { "name", "string" },
1336 { "method", "string" },
1337 { "c", "integer" },
1338 { "r", "integer" },
1339 { "method", "string" },
1340 { "box", "integer" },
1341 { "width", "dimension" },
1342 { "height", "dimension" },
1343 { "option", "string" },
1344 } }
1345}
1346
1347implement {
1348 name = "putincolumnset",
1349 actions = columnsets.put,
1350 arguments = { {
1351 { "name", "string" },
1352 { "c", "integer" },
1353 { "r", "integer" },
1354 { "method", "string" },
1355 { "box", "integer" },
1356 } }
1357}
1358
1359implement {
1360 name = "addtocolumnset",
1361 actions = columnsets.add,
1362 arguments = { "string", "integer" },
1363}
1364
1365implement {
1366 name = "setcolumnsetlines",
1367 actions = columnsets.setlines,
1368 arguments = { {
1369 { "name", "string" },
1370 { "page", "integer" },
1371 { "column", "integer" },
1372 { "value", "integer" },
1373 } }
1374}
1375
1376implement {
1377 name = "setcolumnsetstart",
1378 actions = columnsets.setstart,
1379 arguments = { {
1380 { "name", "string" },
1381 { "page", "integer" },
1382 { "column", "integer" },
1383 { "value", "integer" },
1384 } }
1385}
1386
1387implement {
1388 name = "setcolumnsetproperties",
1389 actions = columnsets.setproperties,
1390 arguments = { {
1391 { "name", "string" },
1392 { "column", "integer" },
1393 { "distance", "dimension" },
1394 { "width", "dimension" },
1395 } }
1396}
1397
1398implement {
1399 name = "registercolumnsetarea",
1400 actions = columnsets.registerarea,
1401 arguments = { {
1402 { "name", "string" },
1403 { "type", "string" },
1404 { "page", "integer" },
1405 { "state", "string" },
1406 { "c", "integer" },
1407 { "r", "integer" },
1408 { "nc", "integer" },
1409 { "nr", "integer" },
1410 } }
1411}
1412
1413implement {
1414 name = "flushcolumnsetareas",
1415 actions = columnsets.flushareas,
1416 arguments = "string",
1417}
1418
1419implement {
1420 name = "setcolumnsetarea",
1421 actions = columnsets.setarea,
1422 arguments = { {
1423 { "name", "string" },
1424 { "c", "integer" },
1425 { "r", "integer" },
1426 { "method", "string" },
1427 { "box", "integer" },
1428 } }
1429}
1430
1431implement {
1432 name = "columnsetgoto",
1433 actions = columnsets["goto"],
1434 arguments = "2 strings",
1435}
1436
1437implement {
1438 name = "columnsetnoto",
1439 actions = columnsets["noto"],
1440}
1441
1442implement {
1443 name = "columnsetcurrentcolumn",
1444 actions = columnsets.currentcolumn,
1445 arguments = "string",
1446}
1447 |