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