if not modules then modules = { } end modules ['anch-snc'] = { version = 1.001, comment = "companion to anch-snc.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } local tonumber, next, setmetatable, rawget = tonumber, next, setmetatable, rawget local concat, sort, remove, copy = table.concat, table.sort, table.remove, table.copy local match, find = string.match, string.find local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns local setmetatableindex = table.setmetatableindex local P, Cc = lpeg.P, lpeg.Cc graphics = graphics or { } local synchronizers = { } graphics.synchronizers = synchronizers local jobpositions = job.positions local p_number = lpegpatterns.cardinal/tonumber local p_space = lpegpatterns.whitespace^0 local p_option = p_number * ((P(",") * p_space * P("reset") * Cc(true)) + Cc(false)) -- for now local list = { } local kinds = { above = 1, continue = 2, nothing = 3, normal = 4, below = 5, } local lastdone = { } function synchronizers.collect(category,realpage,region) local all = jobpositions.getsync(category) local m = 0 local n = #all list = { } if region and region ~= "" then -- successive can be optimized when we sort by region local start = 1 local done = false local last, rtop, rbot for i=start,n do local pos = all[i] local p = pos.p local r = pos.r if r == region then if not done then local region = jobpositions.collected[r] list.region = region list.page = region rtop = (region.y or 0) + (region.h or 0) rbot = (region.y or 0) - (region.d or 0) last = { kind = "nothing", top = rtop, bottom = 0, task = 0 } m = m + 1 ; list[m] = last done = true end local top = pos.y + pos.h last.bottom = top local task, reset = lpegmatch(p_option,pos.e) last = { kind = "normal", top = top, bottom = 0, task = task } m = m + 1 ; list[m] = last end end if done then last.bottom = rbot end else local start = all.start or 1 local done = false local last, rtop, rbot, ptop, pbot for i=start,n do local pos = all[i] local p = pos.p if p == realpage then if not done then local region = jobpositions.collected[pos.r] local page = jobpositions.collected["page:"..realpage] or region list.region = region list.page = page rtop = (region.y or 0) + (region.h or 0) rbot = (region.y or 0) - (region.d or 0) ptop = (page .y or 0) + (page .h or 0) pbot = (page .y or 0) - (page .d or 0) last = { kind = "above", top = ptop, bottom = rtop, task = 0 } m = m + 1 ; list[m] = last if i > 1 then local task, reset = lpegmatch(p_option,all[i-1].e) last = { kind = "continue", top = rtop, bottom = 0, task = task } m = m + 1 ; list[m] = last else last = { kind = "nothing", top = rtop, bottom = 0, task = 0 } m = m + 1 ; list[m] = last end done = true end local top = pos.y + pos.h last.bottom = top local task, reset = lpegmatch(p_option,pos.e) if reset then local l = list[2] l.kind = "nothing" l.task = 0 end last = { kind = "normal", top = top, bottom = 0, task = task } m = m + 1 ; list[m] = last elseif p > realpage then all.start = i -- tricky, only for page break end end if done then last.bottom = rbot last = { kind = "below", top = rbot, bottom = pbot, task = 0 } m = m + 1 ; list[m] = last lastdone[category] = { { kind = "above", top = ptop, bottom = rtop, task = 0 }, { kind = "continue", top = rtop, bottom = rbot, task = list[#list-1].task }, -- lasttask { kind = "below", top = rbot, bottom = pbot, task = 0 }, region = list.region, page = list.page, } else local l = lastdone[category] if l then list = copy(l) -- inefficient, maybe metatable for region/page m = 3 end end end return m end function synchronizers.extend() local n = #list if n > 0 then for i=1,n do local l = list[i] local k = l.kind if k == "nothing" then local ll = list[i+1] if ll and ll.kind == "normal" then ll.top = l.top remove(list,i) n = #list break end end end end return n end function synchronizers.prune() local n = #list if n > 0 then if list[1].kind == "above" then remove(list,1) end if list[1].kind == "nothing" then remove(list,1) end if list[#list].kind == "below" then remove(list,#list) end n = #list end return n end function synchronizers.collapse() local n = #list if n > 0 then local m = 0 local p = nil for i=1,n do local l = list[i] local t = l.task if p == t then list[m].bottom = l.bottom else m = m + 1 list[m] = l end p = t end for i=n,m+1,-1 do list[i] = nil end n = m end return n end -- These operate on the currently set list: function synchronizers.getsize () return #list end function synchronizers.gettop (n) return list[n].top end function synchronizers.getbottom(n) return list[n].bottom end function synchronizers.getkind (n) return kinds[list[n].kind] end function synchronizers.gettask (n) return list[n].task end function synchronizers.getx() return list.page.x or 0 end function synchronizers.gety() return list.page.y or 0 end function synchronizers.getw() return list.page.w or 0 end function synchronizers.geth() return list.page.h or 0 end function synchronizers.getd() return list.page.d or 0 end -- function mp.xxOverlayRegion() -- local r = tokens.getters.macro("m_overlay_region") -- mp.quoted('"'.. r .. '"') -- end