summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/mkxl/node-bck.lmt
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkxl/node-bck.lmt')
-rw-r--r--Master/texmf-dist/tex/context/base/mkxl/node-bck.lmt294
1 files changed, 294 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkxl/node-bck.lmt b/Master/texmf-dist/tex/context/base/mkxl/node-bck.lmt
new file mode 100644
index 00000000000..9dff3ac40cb
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkxl/node-bck.lmt
@@ -0,0 +1,294 @@
+if not modules then modules = { } end modules ['node-bck'] = {
+ version = 1.001,
+ optimize = true,
+ comment = "companion to node-bck.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- beware, this one takes quite some runtime, so we need a status flag
+-- maybe some page related state
+
+-- todo: done (or just get rid of done altogether) ... saves no purpose
+-- any longer
+
+local attributes, nodes, node = attributes, nodes, node
+
+local enableaction = nodes.tasks.enableaction
+
+local nodecodes = nodes.nodecodes
+local listcodes = nodes.listcodes
+
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+
+local alignmentlist_code = listcodes.alignment
+local celllist_code = listcodes.cell
+
+local nuts = nodes.nuts
+local nodepool = nuts.pool
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getlist = nuts.getlist
+local getattr = nuts.getattr
+local getsubtype = nuts.getsubtype
+local getwhd = nuts.getwhd
+local getwidth = nuts.getwidth
+local getprop = nuts.getprop
+
+local setattr = nuts.setattr
+local setlink = nuts.setlink
+local setlist = nuts.setlist
+local setattributelist = nuts.setattributelist
+local setprop = nuts.setprop
+
+local takebox = nuts.takebox
+local findtail = nuts.tail
+
+local nextnode = nuts.traversers.node
+local nexthlist = nuts.traversers.hlist
+local nextlist = nuts.traversers.list
+
+local flush_node_list = nuts.flush_list
+
+local new_rule = nodepool.rule
+local new_kern = nodepool.kern
+local new_hlist = nodepool.hlist
+
+local privateattributes = attributes.private
+local unsetvalue = attributes.unsetvalue
+
+local linefillers = nodes.linefillers
+
+local a_background = privateattributes("background")
+local a_alignbackground = privateattributes("alignbackground")
+local a_linefiller = privateattributes("linefiller")
+local a_ruled = privateattributes("ruled")
+
+local trace_alignment = false
+local report_alignment = logs.reporter("backgrounds","alignment")
+
+trackers.register("backgrounds.alignments",function(v) trace_alignment = v end)
+
+-- We can't use listbuilders with where=alignment because at that stage we have
+-- unset boxes. Also, post_linebreak is unsuitable for nested processing as we
+-- get the same stuff many times (wrapped again and again).
+--
+-- After many experiments with different callbacks the shipout is still the best
+-- place but then we need to store some settings longer or save them with the node.
+-- For color only we can get away with it with an extra attribute flagging a row
+-- but for more complex stuff we can better do as we do here now.
+
+local overshoot = math.floor(65781/5) -- could be an option per table (just also store it)
+
+local function colored_a(current,list,template,id)
+ local width, height, depth = getwhd(current)
+ local total = height + depth
+ if width > 0 and total > 0 then
+ local rule = nil
+ --
+ local a = getattr(template,a_linefiller)
+ if a then
+ local d = linefillers.data[a%1000]
+ if d then
+ rule = linefillers.filler(template,d,width,height,depth)
+ end
+ end
+ --
+ if not rule then
+ rule = new_rule(width,height,depth)
+ setattributelist(rule,template)
+ end
+ local back = new_kern(-((id == vlist_code and total) or width))
+ return setlink(rule,back,list)
+ end
+end
+
+local function colored_b(current,list,template,id,indent)
+ local width, height, depth = getwhd(current)
+ local total = height + depth
+ if width > 0 and total > 0 then
+ local fore = (indent ~= 0) and new_kern(indent)
+ local rule = nil
+ --
+ local a = getattr(template,a_linefiller)
+ if a then
+ local d = linefillers.data[a%1000]
+ if d then
+ rule = linefillers.filler(template,d,width-indent,height,depth)
+ end
+ end
+ --
+ if not rule then
+ rule = new_rule(width-indent,height+overshoot,depth+overshoot)
+ setattributelist(rule,template)
+ end
+ if overshoot == 0 then
+ local back = new_kern(-((id == vlist_code and total) or width))
+ return setlink(fore,rule,back,list)
+ else
+ rule = new_hlist(rule)
+ return setlink(fore,rule,list)
+ end
+ end
+end
+
+local templates = { }
+local currentrow = 0
+local enabled = false
+local alignments = false
+
+local function add_alignbackgrounds(head,list)
+ for current, id, subtype, list in nextlist, list do
+ if list and id == hlist_code and subtype == celllist_code then
+ for template in nexthlist, list do
+ local background = getattr(template,a_alignbackground)
+ if background then
+ local list = colored_a(current,list,template)
+ if list then
+ setlist(current,list)
+ end
+ setattr(template,a_alignbackground,unsetvalue) -- or property
+ end
+ break
+ end
+ end
+ end
+ local template = getprop(head,"alignmentchecked")
+ if template then
+ list = colored_b(head,list,template[1],hlist_code,template[2])
+ flush_node_list(template)
+ templates[currentrow] = false
+ return list
+ end
+end
+
+local function add_backgrounds(head,id,list)
+ if list then
+ for current, id, subtype, list in nextlist, list do
+ if list then
+ if alignments and subtype == alignmentlist_code then
+ local l = add_alignbackgrounds(current,list)
+ if l then
+ list = l
+ setlist(current,list)
+ end
+ end
+ local l = add_backgrounds(current,id,list)
+ if l then
+ list = l
+ setlist(current,l)
+ end
+ end
+ end
+ end
+ if id == hlist_code or id == vlist_code then
+ local background = getattr(head,a_background)
+ if background then
+ list = colored_a(head,list,head,id)
+ -- not needed
+ setattr(head,a_background,unsetvalue) -- or property -- todo
+ return list
+ end
+ end
+end
+
+function nodes.handlers.backgrounds(head)
+ add_backgrounds(head,getid(head),getlist(head))
+ return head
+end
+
+function nodes.handlers.backgroundspage(head,where)
+ if head and where == "alignment" then
+ for n in nexthlist, head do
+ local p = getprop(n,"alignmentchecked")
+ if not p and getsubtype(n) == alignmentlist_code then
+ currentrow = currentrow + 1
+ local template = templates[currentrow]
+ if trace_alignment then
+ report_alignment("%03i %s %s",currentrow,"page",template and "+" or "-")
+ end
+ setprop(n,"alignmentchecked",template)
+ end
+ end
+ end
+ return head
+end
+
+function nodes.handlers.backgroundsvbox(head,where)
+ if head and where == "vbox" then
+ local list = getlist(head)
+ if list then
+ for n in nexthlist, list do
+ local p = getprop(n,"alignmentchecked")
+ if not p and getsubtype(n) == alignmentlist_code then
+ currentrow = currentrow + 1
+ local template = templates[currentrow]
+ if trace_alignment then
+ report_alignment("%03i %s %s",currentrow,"vbox",template and "+" or "-")
+ end
+ setprop(n,"alignmentchecked",template)
+ end
+ end
+ end
+ end
+ return head
+end
+
+-- interfaces.implement {
+-- name = "enablebackgroundboxes",
+-- onlyonce = true,
+-- actions = enableaction,
+-- arguments = { "'shipouts'", "'nodes.handlers.backgrounds'" }
+-- }
+--
+-- doing it in the shipout works as well but this is nicer
+
+local function enable(alignmentstoo)
+ if not enabled then
+ enabled = true
+ enableaction("shipouts","nodes.handlers.backgrounds")
+ end
+ if not alignments and alignmentstoo then
+ alignments = true
+ enableaction("vboxbuilders","nodes.handlers.backgroundsvbox")
+ enableaction("mvlbuilders", "nodes.handlers.backgroundspage")
+ end
+end
+
+interfaces.implement {
+ name = "enablebackgroundboxes",
+ onlyonce = true,
+ actions = enable,
+}
+
+interfaces.implement {
+ name = "enablebackgroundalign",
+ onlyonce = true,
+ actions = function()
+ enable(true)
+ end,
+}
+
+interfaces.implement {
+ name = "setbackgroundrowdata",
+ arguments = { "integer", "integer", "dimension" },
+ actions = function(row,box,indent)
+ row = row -1 -- better here than in tex
+ if box == 0 then
+ templates[row] = false
+ else
+ templates[row] = { takebox(box), indent }
+ end
+ end,
+}
+
+interfaces.implement {
+ name = "resetbackgroundrowdata",
+ actions = function()
+ currentrow = 0
+ end,
+}