typo-ada.lmt /size: 6243 b    last modification: 2024-01-16 10:22
1if not modules then modules = { } end modules ['typo-adj'] = {
2    version   = 1.001,
3    optimize  = true,
4    comment   = "companion to typo-adj.mkxl",
5    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
6    copyright = "PRAGMA ADE / ConTeXt Development Team",
7    license   = "see context related readme files"
8}
9
10local setdimen        = tex.setdimen
11local isdimen         = tex.isdimen
12local setmacro        = tokens.setters.macro
13local expandmacro     = token.expandmacro
14
15local nuts            = nodes.nuts
16local tonut           = nodes.tonut
17local getid           = nuts.getid
18local getlist         = nuts.getlist
19local getwhd          = nuts.getwhd
20local getattr         = nuts.getattr
21local getwidth        = nuts.getwidth
22local getleader       = nuts.getleader
23local setlist         = nuts.setlist
24local setlink         = nuts.setlink
25local setstate        = nuts.setstate
26local setattr         = nuts.setattr
27
28local hlist_code      = nodes.nodecodes.hlist
29local vlist_code      = nodes.nodecodes.vlist
30
31local getbox          = nuts.getbox
32local takebox         = nuts.takebox
33
34local new_kern        = nuts.pool.kern
35
36local flattenleaders  = nuts.flattenleaders
37local traverselist    = nuts.traverselist
38local traverseleader  = nuts.traverseleader
39
40local a_adaptive      = attributes.private("adaptive")
41
42local registervalue   = attributes.registervalue
43local getvalue        = attributes.getvalue
44local hasvalues       = attributes.hasvalues
45local texsetattribute = tex.setattribute
46
47local adaptive        = nodes.adaptive or { }
48nodes.adaptive        = adaptive
49local enabled         = false
50
51----- enableaction    = nodes.tasks.enableaction
52
53local d_adaptive_width  = isdimen("d_adaptive_width")
54local d_adaptive_height = isdimen("d_adaptive_height")
55local d_adaptive_depth  = isdimen("d_adaptive_depth")
56local d_adaptive_line   = isdimen("d_adaptive_line")
57
58local function setadaptive(w,h,d,l,c,a)
59    setdimen(d_adaptive_width,w)
60    setdimen(d_adaptive_height,h)
61    setdimen(d_adaptive_depth,d)
62    setdimen(d_adaptive_line,l)
63    setmacro("m_adaptive_color",c)
64    setmacro("m_adaptive_alternative",a)
65end
66
67local methods = {
68    -- overlay
69    [1] = function(settings,parent,list)
70        local setups = settings.setups
71        if setups and setups ~= ""  then
72            local w, h, d = getwhd(parent)
73            setadaptive(w,h,d,settings.rulethickness,settings.color,settings.alternative)
74            expandmacro("setup",true,setups)
75            local l = takebox("b_adaptive_box")
76            if l then
77                setlist(parent, setlink(l,new_kern(-getwidth(l)),list))
78            end
79        end
80    end
81}
82
83local function handleuleader(n,grp,index)
84    local m = tonut(n)
85    local a = getattr(m,a_adaptive) or index -- index will become a selector
86    if a then
87        local settings = getvalue(a_adaptive,a) -- index triggers ...
88        if settings then
89            setstate(m,0)
90            local action = methods[settings.method or 1]
91            if action then
92                action(settings,m,getlist(m))
93            end
94        end
95    end
96    return n
97end
98
99-- callback.register("handle_uleader", handleuleader) -- will be frozen
100
101function adaptive.set(settings)
102    if not enabled then
103     -- enableaction("vboxbuilders","nodes.adaptive.handlehorizontal")
104     -- enableaction("vboxhandlers","nodes.adaptive.handlevertical")
105        callback.register("handle_uleader", handleuleader) -- will be frozen
106        enabled = true
107    end
108    texsetattribute(a_adaptive,registervalue(a_adaptive,settings))
109end
110
111interfaces.implement {
112    name      = "setadaptive",
113    actions   = adaptive.set,
114    arguments = {
115        {
116            { "setups", "string" },
117            { "method", "integer" },
118            { "mp", "string" },
119            { "color", "string" },
120            { "rulethickness", "dimension" },
121            { "alternative", "string" },
122        }
123    }
124}
125
126-- The hlist leaders get done before we enter vpacking, so that is where the
127-- first call kicks in. Then we do a vpack (so one can indeed also adapt the
128-- ht/dp). After packing we know the glue and do the vlist leaders.
129
130-- This is now done via a callback but it is still experimental!
131
132local function handlehorizontal(n)
133    if hasvalues(a_adaptive) then
134        for _, t, _, l in traverselist(n) do
135            if t == hlist_code then
136                for m, _, _, ll in traverseleader(l) do
137                    local a = getattr(m,a_adaptive)
138                    if a then
139                        local settings = getvalue(a_adaptive,a)
140                        if settings then
141                            setstate(m,0)
142                            local action = methods[settings.method or 1]
143                            if action then
144                                action(settings,m,ll)
145                            end
146                        end
147                    end
148                end
149            end
150        end
151    end
152    return n
153end
154
155local function handlevertical(n)
156    if hasvalues(a_adaptive) then
157        -- not a list just a node
158        for _, t, _, l in traverselist(n) do
159            if t == vlist_code then
160                for m, _, _, ll in traverseleader(l) do
161                    local a = getattr(m,a_adaptive)
162                    if a then
163                        local settings = getvalue(a_adaptive,a)
164                        if settings then
165                            setstate(m,0)
166                            local action = methods[settings.method or 1]
167                            if action then
168                                action(settings,m,ll)
169                            end
170                        end
171                    end
172                end
173            end
174        end
175    end
176    return n
177end
178
179adaptive.handlehorizontal = handlehorizontal
180adaptive.handlevertical   = handlevertical
181
182interfaces.implement {
183    name      = "adaptivecheckbox",
184    arguments = "integer",
185    public    = true,
186    protected = true,
187    actions   = function(n)
188        local b = getbox(n)
189        if b and flattenleaders(b) > 0 then
190            if getid(b) == hlist_code then
191                handlehorizontal(b)
192            else
193                handlevertical(b)
194            end
195        end
196    end,
197}
198