1if not modules then modules = { } end modules ['page-ins'] = {
2 version = 1.001,
3 comment = "companion to page-mix.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files",
7}
8
9local next = next
10local remove = table.remove
11
12structures = structures or { }
13structures.inserts = structures.inserts or { }
14local inserts = structures.inserts
15
16local allocate = utilities.storage.allocate
17
18inserts.stored = inserts.stored or allocate { }
19inserts.data = inserts.data or allocate { }
20
21local variables = interfaces.variables
22local v_page <const> = variables.page
23local v_auto <const> = variables.auto
24
25local context = context
26local implement = interfaces.implement
27
28storage.register("structures/inserts/stored", inserts.stored, "structures.inserts.stored")
29
30local data = inserts.data
31local stored = inserts.stored
32
33for name, specification in next, stored do
34 data[specification.number] = specification
35 data[name] = specification
36end
37
38function inserts.define(name,specification)
39 specification.name= name
40 local number = specification.number or 0
41 data[name] = specification
42 data[number] = specification
43
44 stored[name] = specification
45 if not specification.location then
46 specification.location = v_page
47 end
48 return specification
49end
50
51function inserts.setup(name,settings)
52 local specification = data[name]
53 for k, v in next, settings do
54
55 specification[k] = v
56 end
57 return specification
58end
59
60function inserts.setlocation(name,location)
61 data[name].location = location
62end
63
64function inserts.getlocation(name,location)
65 return data[name].location or v_page
66end
67
68function inserts.getdata(name)
69 return data[name]
70end
71
72function inserts.getname(number)
73 return data[name].name
74end
75
76function inserts.getnumber(name)
77 return data[name].number
78end
79
80
81
82implement {
83 name = "defineinsertion",
84 actions = inserts.define,
85 arguments = {
86 "string",
87 {
88 { "number", "integer" }
89 }
90 }
91}
92
93implement {
94 name = "setupinsertion",
95 actions = inserts.setup,
96 arguments = {
97 "string",
98 {
99 { "location" }
100 }
101 }
102}
103
104implement {
105 name = "setinsertionlocation",
106 actions = inserts.setlocation,
107 arguments = "2 strings",
108}
109
110implement {
111 name = "insertionnumber",
112 actions = function(name) context(data[name].number or 0) end,
113 arguments = "string"
114}
115
116implement {
117 name = "setinsertmigration",
118 arguments = "string",
119 actions = function(state)
120 nodes.migrations.setinserts(state == v_auto)
121 end
122}
123
124
125
126
127do
128
129 local insert_code <const> = nodes.nodecodes.insert
130 local integer_value <const> = tokens.values.integer
131
132 local nuts = nodes.nuts
133 local tonode = nodes.tonode
134
135 local getpost = nuts.getpost
136 local setpost = nuts.setpost
137 local getlist = nuts.getlist
138 local setlist = nuts.setlist
139
140 local getbox = nuts.getbox
141 local getid = nuts.getid
142 local getindex = nuts.getindex
143 local getnext = nuts.getnext
144 local flushlist = nuts.flushlist
145 local traverseid = nuts.traverseid
146
147 local detached = false
148 local nofdetached = false
149
150 local function detach(n)
151 local box = getbox(n)
152 if box then
153 local post = getpost(box)
154 if post then
155 setpost(box)
156 if detached then
157 flushlist(detached)
158 end
159 detached = post
160 nofdetached = 0
161 for d in traverseid(insert_code,detached) do
162 nofdetached = nofdetached + 1
163 end
164 if nofdetached == 0 then
165 flushlist(detached)
166 detached = false
167 end
168 end
169 end
170 end
171
172 local function attach(index,cs)
173 if detached then
174 for d in traverseid(insert_code,detached) do
175 local idx = getindex(d)
176 if not index or idx == index or index == 0 then
177 local list = getlist(d)
178 context[cs](tonode(list))
179 setlist(d)
180 nofdetached = nofdetached - 1
181 end
182 end
183 if nofdetached == 0 then
184 flushlist(detached)
185 detached = false
186 end
187 end
188 end
189
190 local function nofdetached(index)
191 local n = 0
192 if detached then
193 for d in traverseid(insert_code,detached) do
194 local idx = getindex(d)
195 if not index or idx == index or index == 0 then
196 n = n + 1
197 end
198 end
199 end
200 return integer_value, n
201 end
202
203 implement {
204 name = "detachinsertions",
205 arguments = "integer",
206 public = true,
207 protected = true,
208 actions = detach,
209 }
210
211 implement {
212 name = "attachinsertions",
213 arguments = "csname",
214 public = true,
215 protected = true,
216 actions = function(cs) attach(0,cs) end,
217 }
218
219 implement {
220 name = "attachinsertion",
221 arguments = { "integer", "csname" },
222 public = true,
223 protected = true,
224 actions = attach,
225 }
226
227 implement {
228 name = "nofdetachedinsertions",
229 actions = nofdetached,
230 public = true,
231
232 usage = "value",
233 arguments = "integer",
234 }
235
236 inserts.attach = attach
237 inserts.detach = detach
238 inserts.nofdetached = nofdetached
239
240end
241
242
243
244local tostring = tostring
245local abs = math.abs
246
247local nuts = nodes.nuts
248local tonut = nuts.tonut
249local tonode = nuts.tonode
250local traverselist = nuts.traverselist
251local getlist = nuts.getlist
252local setlist = nuts.setlist
253local getattr = nuts.getattr
254local getheight = nuts.getheight
255local setheight = nuts.setheight
256local hpack = nuts.hpack
257local setattrlist = nuts.setattrlist
258
259local setbox = nuts.setbox
260local takebox = nuts.takebox
261local expandmacro = token.expandmacro
262
263do
264
265
266 local report = logs.reporter("balance","uinsert")
267
268 local trace = false trackers.register("columnsets.uinsert", function(v) trace = v end)
269
270 local a_balancescaled <const> = attributes.private("balancescaled")
271
272 local threshold <const> = 1.01
273
274 local packlist = { }
275
276 local function locate(p)
277 for n in traverselist(p) do
278 if getattr(n,a_balancescaled) then
279 packlist[#packlist+1] = n
280 return n
281 else
282 packlist[#packlist+1] = p
283 return locate(getlist(p),t)
284 end
285 end
286 end
287
288 local function processuinsert(l,scale)
289 setbox("b_page_inserts_uinsert",hpack(l))
290 expandmacro("page_inserts_handle_uinsert",true,tostring(scale))
291 return takebox("b_page_inserts_uinsert")
292 end
293
294 callback.register("handle_uinsert", function(callback,index,order,packed,height,amount)
295 if (callback == 1 or callback == 2) and amount ~= 0 then
296 packed = tonut(packed)
297 local p = locate(getlist(packed))
298 if p then
299 local oldheight = getheight(p)
300 local newheight = oldheight + amount
301 local scale = newheight/oldheight
302 if abs(scale) >= threshold then
303 if trace then
304 report("index %i, order %i, scaling %.3f",index,order,scale)
305 end
306 local l = processuinsert(getlist(p),scale)
307 setlist(p,l)
308 setattrlist(l,insert)
309 local h = getheight(l)
310 for i=#packlist,1,-1 do
311 setheight(packlist[i],h)
312 end
313 end
314 end
315 packlist = { }
316 return tonode(packed)
317 else
318 return packed
319 end
320 end)
321
322end
323 |