1if not modules then modules = { } end modules ['anch-pos'] = {
2 version = 1.001,
3 comment = "companion to anch-pos.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
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30local tostring, next, setmetatable, tonumber = tostring, next, setmetatable, tonumber
31local sort = table.sort
32local format, gmatch = string.format, string.gmatch
33local lpegmatch = lpeg.match
34local insert, remove = table.insert, table.remove
35local allocate = utilities.storage.allocate
36
37local report = logs.reporter("positions")
38
39local scanners = tokens.scanners
40local scanstring = scanners.string
41local scaninteger = scanners.integer
42local scandimen = scanners.dimen
43
44local implement = interfaces.implement
45
46local commands = commands
47local context = context
48
49local ctx_latelua = context.latelua
50
51local tex = tex
52local texgetcount = tex.getcount
53local texgetinteger = tex.getintegervalue or tex.getcount
54local texsetcount = tex.setcount
55local texget = tex.get
56local texsp = tex.sp
57
58
59local setmetatableindex = table.setmetatableindex
60local setmetatablenewindex = table.setmetatablenewindex
61
62local nuts = nodes.nuts
63
64local setlink = nuts.setlink
65local getlist = nuts.getlist
66local setlist = nuts.setlist
67local getbox = nuts.getbox
68local getid = nuts.getid
69local getwhd = nuts.getwhd
70
71local hlist_code = nodes.nodecodes.hlist
72
73local find_tail = nuts.tail
74
75
76local new_latelua = nuts.pool.latelua
77
78local variables = interfaces.variables
79local v_text = variables.text
80local v_column = variables.column
81
82local pt = number.dimenfactors.pt
83local pts = number.pts
84local formatters = string.formatters
85
86local collected = allocate()
87local tobesaved = allocate()
88
89local jobpositions = {
90 collected = collected,
91 tobesaved = tobesaved,
92}
93
94job.positions = jobpositions
95
96local default = {
97 __index = {
98 x = 0,
99 y = 0,
100 w = 0,
101 h = 0,
102 d = 0,
103 p = 0,
104 n = 0,
105 ls = 0,
106 rs = 0,
107 hi = 0,
108 ha = 0,
109 hs = 0,
110 pi = 0,
111 ps = false,
112 dir = 0,
113 }
114}
115
116local f_b_tag = formatters["b:%s"]
117local f_e_tag = formatters["e:%s"]
118local f_p_tag = formatters["p:%s"]
119local f_w_tag = formatters["w:%s"]
120
121local f_region = formatters["region:%s"]
122
123local f_tag_three = formatters["%s:%s:%s"]
124local f_tag_two = formatters["%s:%s"]
125
126local nofregular = 0
127local nofspecial = 0
128local splitter = lpeg.splitat(":",true)
129
130local pagedata = { }
131local columndata = setmetatableindex("table")
132local freedata = setmetatableindex("table")
133
134local function initializer()
135 tobesaved = jobpositions.tobesaved
136 collected = jobpositions.collected
137 for tag, data in next, collected do
138 local prefix, rest = lpegmatch(splitter,tag)
139 if prefix == "p" then
140 nofregular = nofregular + 1
141 elseif prefix == "page" then
142 nofregular = nofregular + 1
143 pagedata[tonumber(rest) or 0] = data
144 elseif prefix == "free" then
145 nofspecial = nofspecial + 1
146 local t = freedata[data.p or 0]
147 t[#t+1] = data
148 elseif prefix == "columnarea" then
149 columndata[data.p or 0][data.c or 0] = data
150 end
151 setmetatable(data,default)
152 end
153
154 local pages = structures.pages.collected
155 if pages then
156 local last = nil
157 for p=1,#pages do
158 local region = "page:" .. p
159 local data = pagedata[p]
160 local free = freedata[p]
161 if free then
162 sort(free,function(a,b) return b.y < a.y end)
163 end
164 if data then
165 last = data
166 last.free = free
167 elseif last then
168 local t = setmetatableindex({ free = free, p = p },last)
169 if not collected[region] then
170 collected[region] = t
171 else
172
173 end
174 pagedata[p] = t
175 end
176 end
177 end
178 jobpositions.pagedata = pagedata
179end
180
181function jobpositions.used()
182 return next(collected)
183end
184
185function jobpositions.getfree(page)
186 return freedata[page]
187end
188
189
190
191
192
193
194
195
196local function finalizer()
197
198
199
200 for k, v in next, tobesaved do
201 local s = v.s
202 if s then
203 for p, data in next, s do
204 local n = #data
205 if n > 1 then
206 local ph = data[1][2]
207 local pd = data[1][3]
208 local xl = data[1][4]
209 local xr = data[1][5]
210 for i=2,n do
211 local di = data[i]
212 local h = di[2]
213 local d = di[3]
214 local l = di[4]
215 local r = di[5]
216 if r == xr then
217 di[5] = nil
218 if l == xl then
219 di[4] = nil
220 if d == pd then
221 di[3] = nil
222 if h == ph then
223 di[2] = nil
224 else
225 ph = h
226 end
227 else
228 pd, ph = d, h
229 end
230 else
231 ph, pd, xl = h, d, l
232 end
233 else
234 ph, pd, xl, xr = h, d, l, r
235 end
236 end
237 end
238 end
239 end
240 end
241end
242
243job.register('job.positions.collected', tobesaved, initializer, finalizer)
244
245local regions = { }
246local nofregions = 0
247local region = nil
248
249local columns = { }
250local nofcolumns = 0
251local column = nil
252
253local nofpages = nil
254
255
256
257local getpos, gethpos, getvpos, getrpos
258
259function jobpositions.registerhandlers(t)
260 getpos = t and t.getpos or function() return 0, 0 end
261 getrpos = t and t.getrpos or function() return 0, 0, 0 end
262 gethpos = t and t.gethpos or function() return 0 end
263 getvpos = t and t.getvpos or function() return 0 end
264end
265
266function jobpositions.getpos () return getpos () end
267function jobpositions.getrpos() return getrpos() end
268function jobpositions.gethpos() return gethpos() end
269function jobpositions.getvpos() return getvpos() end
270
271
272
273jobpositions.registerhandlers()
274
275local function setall(name,p,x,y,w,h,d,extra)
276 tobesaved[name] = {
277 p = p,
278 x = x ~= 0 and x or nil,
279 y = y ~= 0 and y or nil,
280 w = w ~= 0 and w or nil,
281 h = h ~= 0 and h or nil,
282 d = d ~= 0 and d or nil,
283 e = extra ~= "" and extra or nil,
284 r = region,
285 c = column,
286 r2l = texgetinteger("inlinelefttoright") == 1 and true or nil,
287 }
288end
289
290local function enhance(data)
291 if not data then
292 return nil
293 end
294 if data.r == true then
295 data.r = region
296 end
297 if data.x == true then
298 if data.y == true then
299 local x, y = getpos()
300 data.x = x ~= 0 and x or nil
301 data.y = y ~= 0 and y or nil
302 else
303 local x = gethpos()
304 data.x = x ~= 0 and x or nil
305 end
306 elseif data.y == true then
307 local y = getvpos()
308 data.y = y ~= 0 and y or nil
309 end
310 if data.p == true then
311 data.p = texgetcount("realpageno")
312 end
313 if data.c == true then
314 data.c = column
315 end
316 if data.w == 0 then
317 data.w = nil
318 end
319 if data.h == 0 then
320 data.h = nil
321 end
322 if data.d == 0 then
323 data.d = nil
324 end
325 return data
326end
327
328
329
330
331local function set(name,index,value)
332
333 local data = enhance(value or {})
334 if value then
335 container = tobesaved[name]
336 if not container then
337 tobesaved[name] = {
338 [index] = data
339 }
340 else
341 container[index] = data
342 end
343 else
344 tobesaved[name] = data
345 end
346end
347
348local function setspec(specification)
349 local name = specification.name
350 local index = specification.index
351 local value = specification.value
352 local data = enhance(value or {})
353 if value then
354 container = tobesaved[name]
355 if not container then
356 tobesaved[name] = {
357 [index] = data
358 }
359 else
360 container[index] = data
361 end
362 else
363 tobesaved[name] = data
364 end
365end
366
367local function get(id,index)
368 if index then
369 local container = collected[id]
370 return container and container[index]
371 else
372 return collected[id]
373 end
374end
375
376
377jobpositions.setall = setall
378jobpositions.set = set
379jobpositions.setspec = setspec
380jobpositions.get = get
381
382implement {
383 name = "dosaveposition",
384 arguments = { "string", "integer", "dimen", "dimen" },
385 actions = setall,
386}
387
388implement {
389 name = "dosavepositionwhd",
390 arguments = { "string", "integer", "dimen", "dimen", "dimen", "dimen", "dimen" },
391 actions = setall,
392}
393
394implement {
395 name = "dosavepositionplus",
396 arguments = { "string", "integer", "dimen", "dimen", "dimen", "dimen", "dimen", "string" },
397 actions = setall,
398}
399
400
401
402
403
404
405local function b_column(specification)
406 local tag = specification.tag
407 local x = gethpos()
408 tobesaved[tag] = {
409 r = true,
410 x = x ~= 0 and x or nil,
411
412 }
413 insert(columns,tag)
414 column = tag
415end
416
417local function e_column()
418 local t = tobesaved[column]
419 if not t then
420
421 else
422 local x = gethpos() - t.x
423 t.w = x ~= 0 and x or nil
424 t.r = region
425 end
426 remove(columns)
427 column = columns[#columns]
428end
429
430jobpositions.b_column = b_column
431jobpositions.e_column = e_column
432
433implement {
434 name = "bposcolumn",
435 arguments = "string",
436 actions = function(tag)
437 insert(columns,tag)
438 column = tag
439 end
440}
441
442implement {
443 name = "bposcolumnregistered",
444 arguments = "string",
445 actions = function(tag)
446 insert(columns,tag)
447 column = tag
448 ctx_latelua { action = b_column, tag = tag }
449 end
450}
451
452implement {
453 name = "eposcolumn",
454 actions = function()
455 remove(columns)
456 column = columns[#columns]
457 end
458}
459
460implement {
461 name = "eposcolumnregistered",
462 actions = function()
463 ctx_latelua { action = e_column }
464 remove(columns)
465 column = columns[#columns]
466 end
467}
468
469
470
471local function b_region(specification)
472 local tag = specification.tag or specification
473 local last = tobesaved[tag]
474 local x, y = getpos()
475 last.x = x ~= 0 and x or nil
476 last.y = y ~= 0 and y or nil
477 last.p = texgetcount("realpageno")
478 insert(regions,tag)
479 region = tag
480end
481
482local function e_region(specification)
483 local last = tobesaved[region]
484 local y = getvpos()
485 local x, y = getpos()
486 if specification.correct then
487 local h = (last.y or 0) - y
488 last.h = h ~= 0 and h or nil
489 end
490 last.y = y ~= 0 and y or nil
491 remove(regions)
492 region = regions[#regions]
493end
494
495jobpositions.b_region = b_region
496jobpositions.e_region = e_region
497
498local lastregion
499
500local function setregionbox(n,tag,k,lo,ro,to,bo,column)
501 if not tag or tag == "" then
502 nofregions = nofregions + 1
503 tag = f_region(nofregions)
504 end
505 local box = getbox(n)
506 local w, h, d = getwhd(box)
507 tobesaved[tag] = {
508
509 x = 0,
510 y = 0,
511 w = w ~= 0 and w or nil,
512 h = h ~= 0 and h or nil,
513 d = d ~= 0 and d or nil,
514 k = k ~= 0 and k or nil,
515 lo = lo ~= 0 and lo or nil,
516 ro = ro ~= 0 and ro or nil,
517 to = to ~= 0 and to or nil,
518 bo = bo ~= 0 and bo or nil,
519 c = column or nil,
520 }
521 lastregion = tag
522 return tag, box
523end
524
525local function markregionbox(n,tag,correct,...)
526 local tag, box = setregionbox(n,tag,...)
527
528 local push = new_latelua { action = b_region, tag = tag }
529 local pop = new_latelua { action = e_region, correct = correct }
530
531 local head = getlist(box)
532
533
534
535
536
537 if head then
538 local tail = find_tail(head)
539 setlink(push,head)
540 setlink(tail,pop)
541 else
542 setlink(push,pop)
543 end
544 setlist(box,push)
545end
546
547jobpositions.markregionbox = markregionbox
548jobpositions.setregionbox = setregionbox
549
550function jobpositions.enhance(name)
551 enhance(tobesaved[name])
552end
553
554function jobpositions.gettobesaved(name,tag)
555 local t = tobesaved[name]
556 if t and tag then
557 return t[tag]
558 else
559 return t
560 end
561end
562
563function jobpositions.settobesaved(name,tag,data)
564 local t = tobesaved[name]
565 if t and tag and data then
566 t[tag] = data
567 end
568end
569
570local nofparagraphs = 0
571
572implement {
573 name = "parpos",
574 actions = function()
575 nofparagraphs = nofparagraphs + 1
576 texsetcount("global","c_anch_positions_paragraph",nofparagraphs)
577 local box = getbox("strutbox")
578 local w, h, d = getwhd(box)
579 local t = {
580 p = true,
581 c = true,
582 r = true,
583 x = true,
584 y = true,
585 h = h,
586 d = d,
587 hs = texget("hsize"),
588 }
589 local leftskip = texget("leftskip",false)
590 local rightskip = texget("rightskip",false)
591 local hangindent = texget("hangindent")
592 local hangafter = texget("hangafter")
593 local parindent = texget("parindent")
594 local parshape = texget("parshape")
595 if leftskip ~= 0 then
596 t.ls = leftskip
597 end
598 if rightskip ~= 0 then
599 t.rs = rightskip
600 end
601 if hangindent ~= 0 then
602 t.hi = hangindent
603 end
604 if hangafter ~= 1 and hangafter ~= 0 then
605 t.ha = hangafter
606 end
607 if parindent ~= 0 then
608 t.pi = parindent
609 end
610 if parshape and #parshape > 0 then
611 t.ps = parshape
612 end
613 local name = f_p_tag(nofparagraphs)
614 tobesaved[name] = t
615 ctx_latelua { action = enhance, specification = t }
616 end
617}
618
619implement {
620 name = "dosetposition",
621 arguments = "string",
622 actions = function(name)
623 local spec = {
624 p = true,
625 c = column,
626 r = true,
627 x = true,
628 y = true,
629 n = nofparagraphs > 0 and nofparagraphs or nil,
630 r2l = texgetinteger("inlinelefttoright") == 1 or nil,
631 }
632 tobesaved[name] = spec
633 ctx_latelua { action = enhance, specification = spec }
634 end
635}
636
637implement {
638 name = "dosetpositionwhd",
639 arguments = { "string", "dimen", "dimen", "dimen" },
640 actions = function(name,w,h,d)
641 local spec = {
642 p = true,
643 c = column,
644 r = true,
645 x = true,
646 y = true,
647 w = w ~= 0 and w or nil,
648 h = h ~= 0 and h or nil,
649 d = d ~= 0 and d or nil,
650 n = nofparagraphs > 0 and nofparagraphs or nil,
651 r2l = texgetinteger("inlinelefttoright") == 1 or nil,
652 }
653 tobesaved[name] = spec
654 ctx_latelua { action = enhance, specification = spec }
655 end
656}
657
658implement {
659 name = "dosetpositionbox",
660 arguments = { "string", "integer" },
661 actions = function(name,n)
662 local box = getbox(n)
663 local w, h, d = getwhd(box)
664 local spec = {
665 p = true,
666 c = column,
667 r = true,
668 x = true,
669 y = true,
670 w = w ~= 0 and w or nil,
671 h = h ~= 0 and h or nil,
672 d = d ~= 0 and d or nil,
673 n = nofparagraphs > 0 and nofparagraphs or nil,
674 r2l = texgetinteger("inlinelefttoright") == 1 or nil,
675 }
676 tobesaved[name] = spec
677 ctx_latelua { action = enhance, specification = spec }
678 end
679}
680
681implement {
682 name = "dosetpositionplus",
683 arguments = { "string", "dimen", "dimen", "dimen" },
684 actions = function(name,w,h,d)
685 local spec = {
686 p = true,
687 c = column,
688 r = true,
689 x = true,
690 y = true,
691 w = w ~= 0 and w or nil,
692 h = h ~= 0 and h or nil,
693 d = d ~= 0 and d or nil,
694 n = nofparagraphs > 0 and nofparagraphs or nil,
695 e = scanstring(),
696 r2l = texgetinteger("inlinelefttoright") == 1 or nil,
697 }
698 tobesaved[name] = spec
699 ctx_latelua { action = enhance, specification = spec }
700 end
701}
702
703implement {
704 name = "dosetpositionstrut",
705 arguments = "string",
706 actions = function(name)
707 local box = getbox("strutbox")
708 local w, h, d = getwhd(box)
709 local spec = {
710 p = true,
711 c = column,
712 r = true,
713 x = true,
714 y = true,
715 h = h ~= 0 and h or nil,
716 d = d ~= 0 and d or nil,
717 n = nofparagraphs > 0 and nofparagraphs or nil,
718 r2l = texgetinteger("inlinelefttoright") == 1 or nil,
719 }
720 tobesaved[name] = spec
721 ctx_latelua { action = enhance, specification = spec }
722 end
723}
724
725implement {
726 name = "dosetpositionstrutkind",
727 arguments = { "string", "integer" },
728 actions = function(name,kind)
729 local box = getbox("strutbox")
730 local w, h, d = getwhd(box)
731 local spec = {
732 k = kind,
733 p = true,
734 c = column,
735 r = true,
736 x = true,
737 y = true,
738 h = h ~= 0 and h or nil,
739 d = d ~= 0 and d or nil,
740 n = nofparagraphs > 0 and nofparagraphs or nil,
741 r2l = texgetinteger("inlinelefttoright") == 1 or nil,
742 }
743 tobesaved[name] = spec
744 ctx_latelua { action = enhance, specification = spec }
745 end
746}
747
748function jobpositions.getreserved(tag,n)
749 if tag == v_column then
750 local fulltag = f_tag_three(tag,texgetcount("realpageno"),n or 1)
751 local data = collected[fulltag]
752 if data then
753 return data, fulltag
754 end
755 tag = v_text
756 end
757 if tag == v_text then
758 local fulltag = f_tag_two(tag,texgetcount("realpageno"))
759 return collected[fulltag] or false, fulltag
760 end
761 return collected[tag] or false, tag
762end
763
764function jobpositions.copy(target,source)
765 collected[target] = collected[source]
766end
767
768function jobpositions.replace(id,p,x,y,w,h,d)
769 collected[id] = { p = p, x = x, y = y, w = w, h = h, d = d }
770end
771
772local function getpage(id)
773 local jpi = collected[id]
774 return jpi and jpi.p
775end
776
777local function getcolumn(id)
778 local jpi = collected[id]
779 return jpi and jpi.c or false
780end
781
782local function getparagraph(id)
783 local jpi = collected[id]
784 return jpi and jpi.n
785end
786
787local function getregion(id)
788 local jpi = collected[id]
789 if jpi then
790 local r = jpi.r
791 if r then
792 return r
793 end
794 local p = jpi.p
795 if p then
796 return "page:" .. p
797 end
798 end
799 return false
800end
801
802jobpositions.page = getpage
803jobpositions.column = getcolumn
804jobpositions.paragraph = getparagraph
805jobpositions.region = getregion
806
807jobpositions.p = getpage
808jobpositions.c = getcolumn
809jobpositions.n = getparagraph
810jobpositions.r = getregion
811
812function jobpositions.x(id)
813 local jpi = collected[id]
814 return jpi and jpi.x
815end
816
817function jobpositions.y(id)
818 local jpi = collected[id]
819 return jpi and jpi.y
820end
821
822function jobpositions.width(id)
823 local jpi = collected[id]
824 return jpi and jpi.w
825end
826
827function jobpositions.height(id)
828 local jpi = collected[id]
829 return jpi and jpi.h
830end
831
832function jobpositions.depth(id)
833 local jpi = collected[id]
834 return jpi and jpi.d
835end
836
837function jobpositions.whd(id)
838 local jpi = collected[id]
839 if jpi then
840 return jpi.h, jpi.h, jpi.d
841 end
842end
843
844function jobpositions.leftskip(id)
845 local jpi = collected[id]
846 return jpi and jpi.ls
847end
848
849function jobpositions.rightskip(id)
850 local jpi = collected[id]
851 return jpi and jpi.rs
852end
853
854function jobpositions.hsize(id)
855 local jpi = collected[id]
856 return jpi and jpi.hs
857end
858
859function jobpositions.parindent(id)
860 local jpi = collected[id]
861 return jpi and jpi.pi
862end
863
864function jobpositions.hangindent(id)
865 local jpi = collected[id]
866 return jpi and jpi.hi
867end
868
869function jobpositions.hangafter(id)
870 local jpi = collected[id]
871 return jpi and jpi.ha or 1
872end
873
874function jobpositions.xy(id)
875 local jpi = collected[id]
876 if jpi then
877 return jpi.x, jpi.y
878 else
879 return 0, 0
880 end
881end
882
883function jobpositions.lowerleft(id)
884 local jpi = collected[id]
885 if jpi then
886 return jpi.x, jpi.y - jpi.d
887 else
888 return 0, 0
889 end
890end
891
892function jobpositions.lowerright(id)
893 local jpi = collected[id]
894 if jpi then
895 return jpi.x + jpi.w, jpi.y - jpi.d
896 else
897 return 0, 0
898 end
899end
900
901function jobpositions.upperright(id)
902 local jpi = collected[id]
903 if jpi then
904 return jpi.x + jpi.w, jpi.y + jpi.h
905 else
906 return 0, 0
907 end
908end
909
910function jobpositions.upperleft(id)
911 local jpi = collected[id]
912 if jpi then
913 return jpi.x, jpi.y + jpi.h
914 else
915 return 0, 0
916 end
917end
918
919function jobpositions.position(id)
920 local jpi = collected[id]
921 if jpi then
922 return jpi.p, jpi.x, jpi.y, jpi.w, jpi.h, jpi.d
923 else
924 return 0, 0, 0, 0, 0, 0
925 end
926end
927
928local splitter = lpeg.splitat(",")
929
930function jobpositions.extra(id,n,default)
931 local jpi = collected[id]
932 if jpi then
933 local e = jpi.e
934 if e then
935 local split = jpi.split
936 if not split then
937 split = lpegmatch(splitter,jpi.e)
938 jpi.split = split
939 end
940 return texsp(split[n]) or default
941 end
942 end
943 return default
944end
945
946local function overlapping(one,two,overlappingmargin)
947 one = collected[one]
948 two = collected[two]
949 if one and two and one.p == two.p then
950 if not overlappingmargin then
951 overlappingmargin = 2
952 end
953 local x_one = one.x
954 local x_two = two.x
955 local w_two = two.w
956 local llx_one = x_one - overlappingmargin
957 local urx_two = x_two + w_two + overlappingmargin
958 if llx_one > urx_two then
959 return false
960 end
961 local w_one = one.w
962 local urx_one = x_one + w_one + overlappingmargin
963 local llx_two = x_two - overlappingmargin
964 if urx_one < llx_two then
965 return false
966 end
967 local y_one = one.y
968 local y_two = two.y
969 local d_one = one.d
970 local h_two = two.h
971 local lly_one = y_one - d_one - overlappingmargin
972 local ury_two = y_two + h_two + overlappingmargin
973 if lly_one > ury_two then
974 return false
975 end
976 local h_one = one.h
977 local d_two = two.d
978 local ury_one = y_one + h_one + overlappingmargin
979 local lly_two = y_two - d_two - overlappingmargin
980 if ury_one < lly_two then
981 return false
982 end
983 return true
984 end
985end
986
987local function onsamepage(list,page)
988 for id in gmatch(list,"(, )") do
989 local jpi = collected[id]
990 if jpi then
991 local p = jpi.p
992 if not p then
993 return false
994 elseif not page then
995 page = p
996 elseif page ~= p then
997 return false
998 end
999 end
1000 end
1001 return page
1002end
1003
1004local function columnofpos(realpage,xposition)
1005 local p = columndata[realpage]
1006 if p then
1007 for i=1,#p do
1008 local c = p[i]
1009 local x = c.x or 0
1010 local w = c.w or 0
1011 if xposition >= x and xposition <= (x + w) then
1012 return i
1013 end
1014 end
1015 end
1016 return 1
1017end
1018
1019jobpositions.overlapping = overlapping
1020jobpositions.onsamepage = onsamepage
1021jobpositions.columnofpos = columnofpos
1022
1023
1024
1025implement {
1026 name = "replacepospxywhd",
1027 arguments = { "string", "integer", "dimen", "dimen", "dimen", "dimen", "dimen" },
1028 actions = function(name,page,x,y,w,h,d)
1029 collected[name] = {
1030 p = page,
1031 x = x,
1032 y = y,
1033 w = w,
1034 h = h,
1035 d = d,
1036 }
1037 end
1038}
1039
1040implement {
1041 name = "copyposition",
1042 arguments = "2 strings",
1043 actions = function(target,source)
1044 collected[target] = collected[source]
1045 end
1046}
1047
1048implement {
1049 name = "MPp",
1050 arguments = "string",
1051 actions = function(name)
1052 local jpi = collected[name]
1053 if jpi then
1054 local p = jpi.p
1055 if p and p ~= true then
1056 context(p)
1057 return
1058 end
1059 end
1060 context('0')
1061 end
1062}
1063
1064implement {
1065 name = "MPx",
1066 arguments = "string",
1067 actions = function(name)
1068 local jpi = collected[name]
1069 if jpi then
1070 local x = jpi.x
1071 if x and x ~= true and x ~= 0 then
1072 context("%.5Fpt",x*pt)
1073 return
1074 end
1075 end
1076 context('0pt')
1077 end
1078}
1079
1080implement {
1081 name = "MPy",
1082 arguments = "string",
1083 actions = function(name)
1084 local jpi = collected[name]
1085 if jpi then
1086 local y = jpi.y
1087 if y and y ~= true and y ~= 0 then
1088 context("%.5Fpt",y*pt)
1089 return
1090 end
1091 end
1092 context('0pt')
1093 end
1094}
1095
1096implement {
1097 name = "MPw",
1098 arguments = "string",
1099 actions = function(name)
1100 local jpi = collected[name]
1101 if jpi then
1102 local w = jpi.w
1103 if w and w ~= 0 then
1104 context("%.5Fpt",w*pt)
1105 return
1106 end
1107 end
1108 context('0pt')
1109 end
1110}
1111
1112implement {
1113 name = "MPh",
1114 arguments = "string",
1115 actions = function(name)
1116 local jpi = collected[name]
1117 if jpi then
1118 local h = jpi.h
1119 if h and h ~= 0 then
1120 context("%.5Fpt",h*pt)
1121 return
1122 end
1123 end
1124 context('0pt')
1125 end
1126}
1127
1128implement {
1129 name = "MPd",
1130 arguments = "string",
1131 actions = function(name)
1132 local jpi = collected[name]
1133 if jpi then
1134 local d = jpi.d
1135 if d and d ~= 0 then
1136 context("%.5Fpt",d*pt)
1137 return
1138 end
1139 end
1140 context('0pt')
1141 end
1142}
1143
1144implement {
1145 name = "MPxy",
1146 arguments = "string",
1147 actions = function(name)
1148 local jpi = collected[name]
1149 if jpi then
1150 context('(%.5Fpt,%.5Fpt)',
1151 jpi.x*pt,
1152 jpi.y*pt
1153 )
1154 else
1155 context('(0,0)')
1156 end
1157 end
1158}
1159
1160implement {
1161 name = "MPwhd",
1162 arguments = "string",
1163 actions = function(name)
1164 local jpi = collected[name]
1165 if jpi then
1166 local w = jpi.w or 0
1167 local h = jpi.h or 0
1168 local d = jpi.d or 0
1169 if w ~= 0 or h ~= 0 or d ~= 0 then
1170 context("%.5Fpt,%.5Fpt,%.5Fpt",w*pt,h*pt,d*pt)
1171 return
1172 end
1173 end
1174 context('0pt,0pt,0pt')
1175 end
1176}
1177
1178implement {
1179 name = "MPll",
1180 arguments = "string",
1181 actions = function(name)
1182 local jpi = collected[name]
1183 if jpi then
1184 context('(%.5Fpt,%.5Fpt)',
1185 jpi.x *pt,
1186 (jpi.y-jpi.d)*pt
1187 )
1188 else
1189 context('(0,0)')
1190 end
1191 end
1192}
1193
1194implement {
1195 name = "MPlr",
1196 arguments = "string",
1197 actions = function(name)
1198 local jpi = collected[name]
1199 if jpi then
1200 context('(%.5Fpt,%.5Fpt)',
1201 (jpi.x + jpi.w)*pt,
1202 (jpi.y - jpi.d)*pt
1203 )
1204 else
1205 context('(0,0)')
1206 end
1207 end
1208}
1209
1210implement {
1211 name = "MPur",
1212 arguments = "string",
1213 actions = function(name)
1214 local jpi = collected[name]
1215 if jpi then
1216 context('(%.5Fpt,%.5Fpt)',
1217 (jpi.x + jpi.w)*pt,
1218 (jpi.y + jpi.h)*pt
1219 )
1220 else
1221 context('(0,0)')
1222 end
1223 end
1224}
1225
1226implement {
1227 name = "MPul",
1228 arguments = "string",
1229 actions = function(name)
1230 local jpi = collected[name]
1231 if jpi then
1232 context('(%.5Fpt,%.5Fpt)',
1233 jpi.x *pt,
1234 (jpi.y + jpi.h)*pt
1235 )
1236 else
1237 context('(0,0)')
1238 end
1239 end
1240}
1241
1242local function MPpos(id)
1243 local jpi = collected[id]
1244 if jpi then
1245 local p = jpi.p
1246 if p then
1247 context("%s,%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt",
1248 p,
1249 jpi.x*pt,
1250 jpi.y*pt,
1251 jpi.w*pt,
1252 jpi.h*pt,
1253 jpi.d*pt
1254 )
1255 return
1256 end
1257 end
1258 context('0,0,0,0,0,0')
1259end
1260
1261implement {
1262 name = "MPpos",
1263 arguments = "string",
1264 actions = MPpos
1265}
1266
1267implement {
1268 name = "MPn",
1269 arguments = "string",
1270 actions = function(name)
1271 local jpi = collected[name]
1272 if jpi then
1273 local n = jpi.n
1274 if n then
1275 context(n)
1276 return
1277 end
1278 end
1279 context(0)
1280 end
1281}
1282
1283implement {
1284 name = "MPc",
1285 arguments = "string",
1286 actions = function(name)
1287 local jpi = collected[name]
1288 if jpi then
1289 local c = jpi.c
1290 if c and c ~= true then
1291 context(c)
1292 return
1293 end
1294 end
1295 context('0')
1296 end
1297}
1298
1299implement {
1300 name = "MPr",
1301 arguments = "string",
1302 actions = function(name)
1303 local jpi = collected[name]
1304 if jpi then
1305 local r = jpi.r
1306 if r and r ~= true then
1307 context(r)
1308 return
1309 end
1310 local p = jpi.p
1311 if p and p ~= true then
1312 context("page:" .. p)
1313 end
1314 end
1315 end
1316}
1317
1318local function MPpardata(id)
1319 local t = collected[id]
1320 if not t then
1321 local tag = f_p_tag(id)
1322 t = collected[tag]
1323 end
1324 if t then
1325 context("%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt,%s,%.5Fpt",
1326 t.hs*pt,
1327 t.ls*pt,
1328 t.rs*pt,
1329 t.hi*pt,
1330 t.ha,
1331 t.pi*pt
1332 )
1333 else
1334 context("0,0,0,0,0,0")
1335 end
1336end
1337
1338implement {
1339 name = "MPpardata",
1340 arguments = "string",
1341 actions = MPpardata
1342}
1343
1344implement {
1345 name = "MPposset",
1346 arguments = "string",
1347 actions = function(name)
1348 local b = f_b_tag(name)
1349 local e = f_e_tag(name)
1350 local w = f_w_tag(name)
1351 local p = f_p_tag(getparagraph(b))
1352 MPpos(b) context(",") MPpos(e) context(",") MPpos(w) context(",") MPpos(p) context(",") MPpardata(p)
1353 end
1354}
1355
1356implement {
1357 name = "MPls",
1358 arguments = "string",
1359 actions = function(name)
1360 local jpi = collected[name]
1361 if jpi then
1362 context("%.5Fpt",jpi.ls*pt)
1363 else
1364 context("0pt")
1365 end
1366 end
1367}
1368
1369implement {
1370 name = "MPrs",
1371 arguments = "string",
1372 actions = function(name)
1373 local jpi = collected[name]
1374 if jpi then
1375 context("%.5Fpt",jpi.rs*pt)
1376 else
1377 context("0pt")
1378 end
1379 end
1380}
1381
1382local splitter = lpeg.tsplitat(",")
1383
1384implement {
1385 name = "MPplus",
1386 arguments = { "string", "integer", "string" },
1387 actions = function(name,n,default)
1388 local jpi = collected[name]
1389 if jpi then
1390 local e = jpi.e
1391 if e then
1392 local split = jpi.split
1393 if not split then
1394 split = lpegmatch(splitter,jpi.e)
1395 jpi.split = split
1396 end
1397 context(split[n] or default)
1398 return
1399 end
1400 end
1401 context(default)
1402 end
1403}
1404
1405implement {
1406 name = "MPrest",
1407 arguments = { "string", "string" },
1408 actions = function(name,default)
1409 local jpi = collected[name]
1410 context(jpi and jpi.e or default)
1411 end
1412}
1413
1414implement {
1415 name = "MPxywhd",
1416 arguments = "string",
1417 actions = function(name)
1418 local jpi = collected[name]
1419 if jpi then
1420 context("%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt",
1421 jpi.x*pt,
1422 jpi.y*pt,
1423 jpi.w*pt,
1424 jpi.h*pt,
1425 jpi.d*pt
1426 )
1427 else
1428 context("0,0,0,0,0")
1429 end
1430 end
1431}
1432
1433local doif = commands.doif
1434local doifelse = commands.doifelse
1435
1436implement {
1437 name = "doifelseposition",
1438 arguments = "string",
1439 actions = function(name)
1440 doifelse(collected[name])
1441 end
1442}
1443
1444implement {
1445 name = "doifposition",
1446 arguments = "string",
1447 actions = function(name)
1448 doif(collected[name])
1449 end
1450}
1451
1452implement {
1453 name = "doifelsepositiononpage",
1454 arguments = { "string", "integer" },
1455 actions = function(name,p)
1456 local c = collected[name]
1457 doifelse(c and c.p == p)
1458 end
1459}
1460
1461implement {
1462 name = "doifelseoverlapping",
1463 arguments = { "string", "string" },
1464 actions = function(one,two)
1465 doifelse(overlapping(one,two))
1466 end
1467}
1468
1469implement {
1470 name = "doifelsepositionsonsamepage",
1471 arguments = "string",
1472 actions = function(list)
1473 doifelse(onsamepage(list))
1474 end
1475}
1476
1477implement {
1478 name = "doifelsepositionsonthispage",
1479 arguments = "string",
1480 actions = function(list)
1481 doifelse(onsamepage(list,tostring(texgetcount("realpageno"))))
1482 end
1483}
1484
1485implement {
1486 name = "doifelsepositionsused",
1487 actions = function()
1488 doifelse(next(collected))
1489 end
1490}
1491
1492implement {
1493 name = "markregionbox",
1494 arguments = "integer",
1495 actions = markregionbox
1496}
1497
1498implement {
1499 name = "setregionbox",
1500 arguments = "integer",
1501 actions = setregionbox
1502}
1503
1504implement {
1505 name = "markregionboxtagged",
1506 arguments = { "integer", "string" },
1507 actions = markregionbox
1508}
1509
1510implement {
1511 name = "markregionboxtaggedn",
1512 arguments = { "integer", "string", "integer" },
1513 actions = function(box,tag,n)
1514 markregionbox(box,tag,nil,nil,nil,nil,nil,nil,n)
1515 end
1516}
1517
1518implement {
1519 name = "setregionboxtagged",
1520 arguments = { "integer", "string" },
1521 actions = setregionbox
1522}
1523
1524implement {
1525 name = "markregionboxcorrected",
1526 arguments = { "integer", "string", true },
1527 actions = markregionbox
1528}
1529
1530implement {
1531 name = "markregionboxtaggedkind",
1532 arguments = { "integer", "string", "integer", "dimen", "dimen", "dimen", "dimen" },
1533 actions = function(box,tag,n,d1,d2,d3,d4)
1534 markregionbox(box,tag,nil,n,d1,d2,d3,d4)
1535 end
1536}
1537
1538implement {
1539 name = "reservedautoregiontag",
1540 actions = function()
1541 nofregions = nofregions + 1
1542 context(f_region(nofregions))
1543 end
1544}
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558statistics.register("positions", function()
1559 local total = nofregular + nofspecial
1560 if total > 0 then
1561 return format("%s collected, %s regular, %s special",total,nofregular,nofspecial)
1562 else
1563 return nil
1564 end
1565end)
1566
1567
1568
1569local newsavepos = nodes.pool.savepos
1570
1571implement { name = "savepos", actions = function() context(newsavepos()) end }
1572implement { name = "lastxpos", actions = function() context(gethpos()) end }
1573implement { name = "lastypos", actions = function() context(getvpos()) end }
1574 |