\startluacode xtables = typesetters.xtables local orig = xtables.reflow_width local data = nil local trace_xtable = nil local showwidths = nil local v_max = nil local report_xtable = nil local v_stretch = nil local v_width = nil function reflow_width() local nofrows = data.nofrows local nofcolumns = data.nofcolumns local rows = data.rows for r=1,nofrows do local row = rows[r] for c=1,nofcolumns do local drc = row[c] if drc.list then -- flush_node_list(drc.list) drc.list = false end end end -- spread local settings = data.settings local options = settings.options local maxwidth = settings.maxwidth -- calculate width local widths = data.widths local heights = data.heights local depths = data.depths local distances = data.distances local autowidths = data.autowidths local fixedcolumns = data.fixedcolumns local frozencolumns = data.frozencolumns local width = 0 local distance = 0 local nofwide = 0 local widetotal = 0 local available = settings.textwidth - settings.leftmargindistance - settings.rightmargindistance if trace_xtable then showwidths("stage 1",widths,autowidths) end local noffrozen = 0 -- here we can also check spans if options[v_max] then for c=1,nofcolumns do width = width + widths[c] if width > maxwidth then autowidths[c] = true nofwide = nofwide + 1 widetotal = widetotal + widths[c] end if c < nofcolumns then distance = distance + distances[c] end if frozencolumns[c] then noffrozen = noffrozen + 1 -- brr, should be nx or so end end else for c=1,nofcolumns do -- also keep track of forced local fixedwidth = fixedcolumns[c] if fixedwidth > 0 then widths[c] = fixedwidth width = width + fixedwidth else local wc = widths[c] width = width + wc -- if width > maxwidth then if wc > maxwidth then -- per 2015-08-09 autowidths[c] = true nofwide = nofwide + 1 widetotal = widetotal + wc end end if c < nofcolumns then distance = distance + distances[c] end if frozencolumns[c] then noffrozen = noffrozen + 1 -- brr, should be nx or so end end end if trace_xtable then showwidths("stage 2",widths,autowidths) end local delta = available - width - distance - (nofcolumns-1) * settings.columndistance if delta == 0 then -- nothing to be done if trace_xtable then report_xtable("perfect fit") end elseif delta > 0 then -- we can distribute some if not options[v_stretch] then -- not needed if trace_xtable then report_xtable("too wide but no stretch, delta %p",delta) end elseif options[v_width] then local factor = delta / width if trace_xtable then report_xtable("proportional stretch, delta %p, width %p, factor %a",delta,width,factor) end for c=1,nofcolumns do widths[c] = widths[c] + factor * widths[c] end else -- frozen -> a column with option=fixed will not stretch local extra = delta / (nofcolumns - noffrozen) if trace_xtable then report_xtable("normal stretch, delta %p, extra %p",delta,extra) end for c=1,nofcolumns do if not frozencolumns[c] then widths[c] = widths[c] + extra end end end elseif nofwide > 0 then while true do done = false local available = (widetotal + delta) / nofwide if trace_xtable then report_xtable("shrink check, total %p, delta %p, columns %s, fixed %p",widetotal,delta,nofwide,available) end for c=1,nofcolumns do if autowidths[c] and available >= widths[c] then autowidths[c] = nil nofwide = nofwide - 1 widetotal = widetotal - widths[c] done = true end end if not done then break end end -- maybe also options[v_width] here but tricky as width does not say -- much about amount if options[v_width] then -- not that much (we could have a clever vpack loop balancing .. no fun) local factor = (widetotal + delta) / widetotal -- PATCHED! if trace_xtable then report_xtable("proportional shrink used, total %p, delta %p, columns %s, factor %s",widetotal,delta,nofwide,factor) end for c=1,nofcolumns do if autowidths[c] then widths[c] = factor * widths[c] end end else local available = (widetotal + delta) / nofwide if trace_xtable then report_xtable("normal shrink used, total %p, delta %p, columns %s, fixed %p",widetotal,delta,nofwide,available) end for c=1,nofcolumns do if autowidths[c] then widths[c] = available end end end end if trace_xtable then showwidths("stage 3",widths,autowidths) end -- data.currentrow = 0 data.currentcolumn = 0 end for i = 1, debug.getinfo(orig).nups do debug.upvaluejoin(reflow_width, i, orig, i) end -- Run with or without these lines to compare -- xtables.reflow_width = reflow_width -- interfaces.implement { name = "x_table_reflow_width", actions = xtables.reflow_width } \stopluacode \starttext \showframe \startxtable[option={stretch}] \startxrow \startxcell a \stopxcell \startxcell abcdefghijklmnopqrstuvwxyz \stopxcell \startxcell abcdefghijklmnopqrstuvwxyz \stopxcell \startxcell abcdefghijklmnopqrstuvwxyz \stopxcell \stopxrow \stopxtable \startxtable[option={stretch,width}] \startxrow \startxcell a \stopxcell \startxcell abcdefghijklmnopqrstuvwxyz \stopxcell \startxcell abcdefghijklmnopqrstuvwxyz \stopxcell \startxcell abcdefghijklmnopqrstuvwxyz \stopxcell \stopxrow \stopxtable \stoptext