if not modules then modules = { } end modules ['pack-rul'] = { version = 1.001, optimize = true, comment = "companion to pack-rul.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } -- we need to be careful with display math as it uses shifts -- \framed[align={lohi,middle}]{$x$} -- \framed[align={lohi,middle}]{$ $} -- \framed[align={lohi,middle}]{\hbox{ }} -- \framed[align={lohi,middle}]{\hbox{}} -- \framed[align={lohi,middle}]{$\hskip2pt$} local type = type local context = context local nodecodes = nodes.nodecodes local listcodes = nodes.listcodes local hlist_code = nodecodes.hlist local vlist_code = nodecodes.vlist local boxlist_code = listcodes.box local linelist_code = listcodes.line local equationlist_code = listcodes.equation local texsetdimen = tex.setdimen local texsetcount = tex.setcount local texisdimen = tex.isdimen local texiscount = tex.iscount local implement = interfaces.implement local nuts = nodes.nuts local getnext = nuts.getnext local getprev = nuts.getprev local getlist = nuts.getlist local setlist = nuts.setlist local getwhd = nuts.getwhd local getid = nuts.getid local getsubtype = nuts.getsubtype local getbox = nuts.getbox local getdirection = nuts.getdirection local setshift = nuts.setshift local setwidth = nuts.setwidth local getwidth = nuts.getwidth local setboxglue = nuts.setglue local getboxglue = nuts.getglue local hpack = nuts.hpack local getdimensions = nuts.dimensions local naturalhsize = nuts.naturalhsize local flushnode = nuts.flush local traversers = nuts.traversers local nexthlist = traversers.hlist local nextvlist = traversers.vlist local nextlist = traversers.list local checkformath = false directives.register("framed.checkmath",function(v) checkformath = v end) -- experiment -- beware: dir nodes and pseudostruts can end up on lines of their own local c_framednoflines = texiscount("framednoflines") local d_framedfirstheight = texisdimen("framedfirstheight") local d_framedlastdepth = texisdimen("framedlastdepth") local d_framedminwidth = texisdimen("framedminwidth") local d_framedmaxwidth = texisdimen("framedmaxwidth") local d_framedaveragewidth = texisdimen("framedaveragewidth") local function doreshapeframedbox(n,resync) if resync then resync = drivers.converters.resyncbox end local box = resync and resync(n) or getbox(n) local noflines = 0 local nofnonzero = 0 local firstheight = nil local lastdepth = nil local lastlinelength = 0 local minwidth = 0 local maxwidth = 0 local totalwidth = 0 local averagewidth = 0 local boxwidth = getwidth(box) -- if boxwidth ~= 0 and getsubtype(box) == vlist_code then if boxwidth ~= 0 then local list = getlist(box) if list then local hdone = false for n, id, subtype, list in nextlist, list do -- no dir etc needed local width, height, depth = getwhd(n) if not firstheight then firstheight = height end lastdepth = depth noflines = noflines + 1 if list then if id == hlist_code then if subtype == boxlist_code or subtype == linelist_code then -- the fast one also returns compensation (plus node) local w, c, n = naturalhsize(list) if n then -- can become an option in framed: strict w = w - c else -- print("no compensation found") end lastlinelength = w else lastlinelength = width end hdone = true else lastlinelength = width -- vdone = true end if lastlinelength > maxwidth then maxwidth = lastlinelength end if lastlinelength < minwidth or minwidth == 0 then minwidth = lastlinelength end if lastlinelength > 0 then nofnonzero = nofnonzero + 1 end totalwidth = totalwidth + lastlinelength end end if not firstheight then -- done) elseif maxwidth ~= 0 then if hdone then for h, id, subtype, list in nextlist, list do if list and id == hlist_code then -- called a lot so maybe a simple case is needed if subtype == boxlist_code or subtype == linelist_code then -- -- getdirection is irrelevant here so it will go -- local p = hpack(list,maxwidth,'exactly',getdirection(h)) -- multiple return value local p = hpack(list,maxwidth,'exactly') -- multiple return value local set, order, sign = getboxglue(p) setboxglue(h,set,order,sign) setlist(p) flushnode(p) elseif checkformath and subtype == equationlist_code then -- display formulas use a shift .. actually we never have display mode if nofnonzero == 1 then setshift(h,0) end end setwidth(h,maxwidth) end end end -- if vdone then -- for v in nextvlist, list do -- local width = getwidth(n) -- if width > maxwidth then -- setwidth(v,maxwidth) -- end -- end -- end setwidth(box,maxwidth) averagewidth = noflines > 0 and totalwidth/noflines or 0 else -- e.g. empty math {$ $} or \hbox{} or ... setwidth(box,0) end end end texsetcount("global",c_framednoflines,noflines) texsetdimen("global",d_framedfirstheight,firstheight or 0) -- also signal texsetdimen("global",d_framedlastdepth,lastdepth or 0) texsetdimen("global",d_framedminwidth,minwidth) texsetdimen("global",d_framedmaxwidth,maxwidth) texsetdimen("global",d_framedaveragewidth,averagewidth) end local function doanalyzeframedbox(n) local box = getbox(n) local noflines = 0 local firstheight = nil local lastdepth = nil if getwidth(box) ~= 0 then local list = getlist(box) if list then for n in nextlist, list do local width, height, depth = getwhd(n) if not firstheight then firstheight = height end lastdepth = depth noflines = noflines + 1 end -- for n in nexthlist, list do -- local width, height, depth = getwhd(n) -- if not firstheight then -- firstheight = height -- end -- lastdepth = depth -- noflines = noflines + 1 -- end -- for n in nextvlist, list do -- local width, height, depth = getwhd(n) -- if not firstheight then -- firstheight = height -- end -- lastdepth = depth -- noflines = noflines + 1 -- end end end texsetcount("global",c_framednoflines,noflines) texsetdimen("global",d_framedfirstheight,firstheight or 0) texsetdimen("global",d_framedlastdepth,lastdepth or 0) end implement { name = "doreshapeframedbox", actions = doreshapeframedbox, arguments = "integer" } implement { name = "doresyncframedbox", actions = doreshapeframedbox, arguments = { "integer", true } } implement { name = "doanalyzeframedbox", actions = doanalyzeframedbox, arguments = "integer" } local function maxboxwidth(box) local boxwidth = getwidth(box) if boxwidth == 0 then return 0 end local list = getlist(box) if not list then return 0 end if getid(box) == hlist_code then return boxwidth end local lastlinelength = 0 local maxwidth = 0 for n, subtype in nexthlist, list do -- no dir etc needed local l = getlist(n) if l then if subtype == boxlist_code or subtype == linelist_code then lastlinelength = getdimensions(l) else lastlinelength = getwidth(n) end if lastlinelength > maxwidth then maxwidth = lastlinelength end end end for n, subtype in nextvlist, list do -- no dir etc needed local l = getlist(n) if l then lastlinelength = getwidth(n) if lastlinelength > maxwidth then maxwidth = lastlinelength end end end return maxwidth end nodes.maxboxwidth = maxboxwidth implement { name = "themaxboxwidth", public = true, actions = function(n) context("%rsp",maxboxwidth(getbox(n))) end, -- r = rounded arguments = "integer" }