if not modules then modules = { } end modules ['page-ins'] = { version = 1.001, comment = "companion to page-mix.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files", } local next = next local remove = table.remove structures = structures or { } structures.inserts = structures.inserts or { } local inserts = structures.inserts local allocate = utilities.storage.allocate inserts.stored = inserts.stored or allocate { } -- combining them in one is inefficient in the inserts.data = inserts.data or allocate { } -- bytecode storage pool local variables = interfaces.variables local v_page = variables.page local v_auto = variables.auto local context = context local implement = interfaces.implement storage.register("structures/inserts/stored", inserts.stored, "structures.inserts.stored") local data = inserts.data local stored = inserts.stored for name, specification in next, stored do data[specification.number] = specification data[name] = specification end function inserts.define(name,specification) specification.name= name local number = specification.number or 0 data[name] = specification data[number] = specification -- only needed at runtime as this get stored in a bytecode register stored[name] = specification if not specification.location then specification.location = v_page end return specification end function inserts.setup(name,settings) local specification = data[name] for k, v in next, settings do -- maybe trace change specification[k] = v end return specification end function inserts.setlocation(name,location) -- a practical fast one data[name].location = location end function inserts.getlocation(name,location) return data[name].location or v_page end function inserts.getdata(name) -- or number return data[name] end function inserts.getname(number) return data[name].name end function inserts.getnumber(name) return data[name].number end -- interface implement { name = "defineinsertion", actions = inserts.define, arguments = { "string", { { "number", "integer" } } } } implement { name = "setupinsertion", actions = inserts.setup, arguments = { "string", { { "location" } } } } implement { name = "setinsertionlocation", actions = inserts.setlocation, arguments = "2 strings", } implement { name = "insertionnumber", actions = function(name) context(data[name].number or 0) end, arguments = "string" } implement { name = "setinsertmigration", arguments = "string", actions = function(state) nodes.migrations.setinserts(state == v_auto) end } -- nasty do local insert_code = nodes.nodecodes.insert local integer_value = tokens.values.integer local nuts = nodes.nuts local tonode = nodes.tonode local getpost = nuts.getpost local setpost = nuts.setpost local getlist = nuts.getlist local setlist = nuts.setlist -- local setboth = nuts.setboth local getbox = nuts.getbox local getid = nuts.getid local getindex = nuts.getindex local getnext = nuts.getnext local flushlist = nuts.flushlist local traverseid = nuts.traverseid local detached = false local nofdetached = false local function detach(n) local box = getbox(n) if box then local post = getpost(box) if post then setpost(box) if detached then flushlist(detached) end detached = post nofdetached = 0 for d in traverseid(insert_code,detached) do nofdetached = nofdetached + 1 end if nofdetached == 0 then flushlist(detached) detached = false end end end end local function attach(index,cs) if detached then for d in traverseid(insert_code,detached) do local idx = getindex(d) if not index or idx == index or index == 0 then local list = getlist(d) context[cs](tonode(list)) setlist(d) nofdetached = nofdetached - 1 end end if nofdetached == 0 then flushlist(detached) detached = false end end end local function nofdetached(index) local n = 0 if detached then for d in traverseid(insert_code,detached) do local idx = getindex(d) if not index or idx == index or index == 0 then n = n + 1 end end end return integer_value, n end implement { name = "detachinsertions", arguments = "integer", public = true, protected = true, actions = detach, } implement { name = "attachinsertions", arguments = "csname", public = true, protected = true, actions = function(cs) attach(0,cs) end, } implement { name = "attachinsertion", arguments = { "integer", "csname" }, public = true, protected = true, actions = attach, } implement { name = "nofdetachedinsertions", actions = nofdetached, public = true, -- protected = true, usage = "value", arguments = "integer", } inserts.attach = attach inserts.detach = detach inserts.nofdetached = nofdetached end -- Maybe this will get its own module. local tostring = tostring local abs = math.abs local nuts = nodes.nuts local tonut = nuts.tonut local tonode = nuts.tonode local traverselist = nuts.traverselist local getlist = nuts.getlist local setlist = nuts.setlist local getattr = nuts.getattr local getheight = nuts.getheight local setheight = nuts.setheight local hpack = nuts.hpack local setattrlist = nuts.setattrlist local setbox = nuts.setbox local takebox = nuts.takebox local expandmacro = token.expandmacro do -- we actually get a split one local report = logs.reporter("balance","uinsert") local trace = false trackers.register("columnsets.uinsert", function(v) trace = v end) local a_balancescaled = attributes.private("balancescaled") local threshold = 1.01 local packlist = { } -- can be reused local function locate(p) for n in traverselist(p) do if getattr(n,a_balancescaled) then packlist[#packlist+1] = n return n else packlist[#packlist+1] = p return locate(getlist(p),t) end end end local function processuinsert(l,scale) setbox("b_page_inserts_uinsert",hpack(l)) expandmacro("page_inserts_handle_uinsert",true,tostring(scale)) return takebox("b_page_inserts_uinsert") end callback.register("handle_uinsert", function(callback,index,order,packed,height,amount) if (callback == 1 or callback == 2) and amount ~= 0 then packed = tonut(packed) local p = locate(getlist(packed)) if p then local oldheight = getheight(p) local newheight = oldheight + amount local scale = newheight/oldheight if abs(scale) >= threshold then if trace then report("index %i, order %i, scaling %.3f",index,order,scale) end local l = processuinsert(getlist(p),scale) setlist(p,l) setattrlist(l,insert) local h = getheight(l) for i=#packlist,1,-1 do setheight(packlist[i],h) end end end packlist = { } return tonode(packed) else return packed end end) end