pack-rul.lmt /size: 9 Kb    last modification: 2023-12-21 09:44
1if not modules then modules = { } end modules ['pack-rul'] = {
2    version   = 1.001,
3    optimize  = true,
4    comment   = "companion to pack-rul.mkiv",
5    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
6    copyright = "PRAGMA ADE / ConTeXt Development Team",
7    license   = "see context related readme files"
8}
9
10-- we need to be careful with display math as it uses shifts
11
12-- \framed[align={lohi,middle}]{$x$}
13-- \framed[align={lohi,middle}]{$ $}
14-- \framed[align={lohi,middle}]{\hbox{ }}
15-- \framed[align={lohi,middle}]{\hbox{}}
16-- \framed[align={lohi,middle}]{$\hskip2pt$}
17
18local type = type
19
20local context           = context
21
22local nodecodes         = nodes.nodecodes
23local listcodes         = nodes.listcodes
24
25local hlist_code        = nodecodes.hlist
26local vlist_code        = nodecodes.vlist
27
28local boxlist_code      = listcodes.box
29local linelist_code     = listcodes.line
30local equationlist_code = listcodes.equation
31
32local texsetdimen       = tex.setdimen
33local texsetcount       = tex.setcount
34local texisdimen        = tex.isdimen
35local texiscount        = tex.iscount
36
37local implement         = interfaces.implement
38
39local nuts              = nodes.nuts
40
41local getnext           = nuts.getnext
42local getprev           = nuts.getprev
43local getlist           = nuts.getlist
44local setlist           = nuts.setlist
45local getwhd            = nuts.getwhd
46local getid             = nuts.getid
47local getsubtype        = nuts.getsubtype
48local getbox            = nuts.getbox
49local getdirection      = nuts.getdirection
50local setshift          = nuts.setshift
51local setwidth          = nuts.setwidth
52local getwidth          = nuts.getwidth
53local setboxglue        = nuts.setglue
54local getboxglue        = nuts.getglue
55
56local hpack             = nuts.hpack
57local getdimensions     = nuts.dimensions
58local naturalhsize      = nuts.naturalhsize
59local flushnode         = nuts.flush
60
61local traversers        = nuts.traversers
62local nexthlist         = traversers.hlist
63local nextvlist         = traversers.vlist
64local nextlist          = traversers.list
65
66local checkformath      = false
67
68directives.register("framed.checkmath",function(v) checkformath = v end) -- experiment
69
70-- beware: dir nodes and pseudostruts can end up on lines of their own
71
72local c_framednoflines     = texiscount("framednoflines")
73local d_framedfirstheight  = texisdimen("framedfirstheight")
74local d_framedlastdepth    = texisdimen("framedlastdepth")
75local d_framedminwidth     = texisdimen("framedminwidth")
76local d_framedmaxwidth     = texisdimen("framedmaxwidth")
77local d_framedaveragewidth = texisdimen("framedaveragewidth")
78
79local function doreshapeframedbox(n,resync)
80    if resync then
81        resync = drivers.converters.resyncbox
82    end
83    local box            = resync and resync(n) or getbox(n)
84    local noflines       = 0
85    local nofnonzero     = 0
86    local firstheight    = nil
87    local lastdepth      = nil
88    local lastlinelength = 0
89    local minwidth       = 0
90    local maxwidth       = 0
91    local totalwidth     = 0
92    local averagewidth   = 0
93    local boxwidth       = getwidth(box)
94 -- if boxwidth ~= 0 and getsubtype(box) == vlist_code then
95    if boxwidth ~= 0 then
96        local list = getlist(box)
97        if list then
98            local hdone = false
99            for n, id, subtype, list in nextlist, list do -- no dir etc needed
100                local width, height, depth = getwhd(n)
101                if not firstheight then
102                    firstheight = height
103                end
104                lastdepth = depth
105                noflines  = noflines + 1
106                if list then
107                    if id == hlist_code then
108                        if subtype == boxlist_code or subtype == linelist_code then
109                            -- the fast one also returns compensation (plus node)
110                            local w, c, n = naturalhsize(list)
111                            if n then
112                                -- can become an option in framed: strict
113                                w = w - c
114                            else
115                             -- print("no compensation found")
116                            end
117                            lastlinelength = w
118                        else
119                            lastlinelength = width
120                        end
121                        hdone = true
122                    else
123                        lastlinelength = width
124                     -- vdone = true
125                    end
126                    if lastlinelength > maxwidth then
127                        maxwidth = lastlinelength
128                    end
129                    if lastlinelength < minwidth or minwidth == 0 then
130                        minwidth = lastlinelength
131                    end
132                    if lastlinelength > 0 then
133                        nofnonzero = nofnonzero + 1
134                    end
135                    totalwidth = totalwidth + lastlinelength
136                end
137            end
138            if not firstheight then
139                -- done)
140            elseif maxwidth ~= 0 then
141                if hdone then
142                    for h, id, subtype, list in nextlist, list do
143                        if list and id == hlist_code then
144                            -- called a lot so maybe a simple case is needed
145                            if subtype == boxlist_code or subtype == linelist_code then
146                             -- -- getdirection is irrelevant here so it will go
147                             -- local p = hpack(list,maxwidth,'exactly',getdirection(h)) -- multiple return value
148                                local p = hpack(list,maxwidth,'exactly') -- multiple return value
149                                local set, order, sign = getboxglue(p)
150                                setboxglue(h,set,order,sign)
151                                setlist(p)
152                                flushnode(p)
153                            elseif checkformath and subtype == equationlist_code then
154                             -- display formulas use a shift .. actually we never have display mode
155                                if nofnonzero == 1 then
156                                    setshift(h,0)
157                                end
158                            end
159                            setwidth(h,maxwidth)
160                        end
161                    end
162                end
163             -- if vdone then
164             --     for v in nextvlist, list do
165             --         local width = getwidth(n)
166             --         if width > maxwidth then
167             --             setwidth(v,maxwidth)
168             --         end
169             --     end
170             -- end
171                setwidth(box,maxwidth)
172                averagewidth = noflines > 0 and totalwidth/noflines or 0
173            else -- e.g. empty math {$ $} or \hbox{} or ...
174                setwidth(box,0)
175            end
176        end
177    end
178    texsetcount("global",c_framednoflines,noflines)
179    texsetdimen("global",d_framedfirstheight,firstheight or 0) -- also signal
180    texsetdimen("global",d_framedlastdepth,lastdepth or 0)
181    texsetdimen("global",d_framedminwidth,minwidth)
182    texsetdimen("global",d_framedmaxwidth,maxwidth)
183    texsetdimen("global",d_framedaveragewidth,averagewidth)
184end
185
186local function doanalyzeframedbox(n)
187    local box         = getbox(n)
188    local noflines    = 0
189    local firstheight = nil
190    local lastdepth   = nil
191    if getwidth(box) ~= 0 then
192        local list = getlist(box)
193        if list then
194            for n in nextlist, list do
195                local width, height, depth = getwhd(n)
196                if not firstheight then
197                    firstheight = height
198                end
199                lastdepth = depth
200                noflines  = noflines + 1
201            end
202         -- for n in nexthlist, list do
203         --     local width, height, depth = getwhd(n)
204         --     if not firstheight then
205         --         firstheight = height
206         --     end
207         --     lastdepth = depth
208         --     noflines  = noflines + 1
209         -- end
210         -- for n in nextvlist, list do
211         --     local width, height, depth = getwhd(n)
212         --     if not firstheight then
213         --         firstheight = height
214         --     end
215         --     lastdepth = depth
216         --     noflines  = noflines + 1
217         -- end
218        end
219    end
220    texsetcount("global",c_framednoflines,noflines)
221    texsetdimen("global",d_framedfirstheight,firstheight or 0)
222    texsetdimen("global",d_framedlastdepth,lastdepth or 0)
223end
224
225implement { name = "doreshapeframedbox", actions = doreshapeframedbox, arguments = "integer" }
226implement { name = "doresyncframedbox",  actions = doreshapeframedbox, arguments = { "integer", true } }
227implement { name = "doanalyzeframedbox", actions = doanalyzeframedbox, arguments = "integer" }
228
229local function maxboxwidth(box)
230    local boxwidth = getwidth(box)
231    if boxwidth == 0 then
232        return 0
233    end
234    local list = getlist(box)
235    if not list then
236        return 0
237    end
238    if getid(box) == hlist_code then
239        return boxwidth
240    end
241    local lastlinelength = 0
242    local maxwidth       = 0
243    for n, subtype in nexthlist, list do -- no dir etc needed
244        local l = getlist(n)
245        if l then
246            if subtype == boxlist_code or subtype == linelist_code then
247                lastlinelength = getdimensions(l)
248            else
249                lastlinelength = getwidth(n)
250            end
251            if lastlinelength > maxwidth then
252                maxwidth = lastlinelength
253            end
254        end
255    end
256    for n, subtype in nextvlist, list do -- no dir etc needed
257        local l = getlist(n)
258        if l then
259            lastlinelength = getwidth(n)
260            if lastlinelength > maxwidth then
261                maxwidth = lastlinelength
262            end
263        end
264    end
265    return maxwidth
266end
267
268nodes.maxboxwidth = maxboxwidth
269
270implement {
271    name      = "themaxboxwidth",
272    public    = true,
273    actions   = function(n) context("%rsp",maxboxwidth(getbox(n))) end, -- r = rounded
274    arguments = "integer"
275}
276