1if not modules then modules = { } end modules ['page-flt'] = {
2 version = 1.001,
3 comment = "companion to page-flt.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
9
10
11
12local next = next
13local tostring = tostring
14local insert, remove = table.insert, table.remove
15local find = string.find
16local abs = math.abs
17
18local trace_floats = false trackers.register("floats.caching", function(v) trace_floats = v end)
19local trace_collecting = false trackers.register("floats.collecting", function(v) trace_collecting = v end)
20
21local report_floats = logs.reporter("floats","caching")
22local report_collecting = logs.reporter("floats","collecting")
23
24local C, S, P, lpegmatch = lpeg.C, lpeg.S, lpeg.P, lpeg.match
25
26
27
28
29local setdimen = tex.setdimen
30local getdimen = tex.getdimen
31local setcount = tex.setcount
32local texsetbox = tex.setbox
33local textakebox = nodes.takebox
34
35floats = floats or { }
36local floats = floats
37
38local context = context
39local commands = commands
40local interfaces = interfaces
41local showmessage = interfaces.showmessage
42local implement = interfaces.implement
43local setmacro = interfaces.setmacro
44
45local noffloats = 0
46local last = nil
47local default = "text"
48local pushed = { }
49
50local function initialize()
51 return {
52 text = { },
53 page = { },
54 leftpage = { },
55 rightpage = { },
56 somewhere = { },
57 }
58end
59
60local stacks = initialize()
61
62
63
64function floats.stacked(which)
65 return #stacks[which or default]
66end
67
68function floats.push()
69 insert(pushed,stacks)
70 stacks = initialize()
71 setcount("global","savednoffloats",0)
72end
73
74function floats.pop()
75 local popped = remove(pushed)
76 if popped then
77 for which, stack in next, stacks do
78 for i=1,#stack do
79 insert(popped[which],stack[i])
80 end
81 end
82 stacks = popped
83 setcount("global","savednoffloats",#stacks[default])
84 end
85end
86
87local function setdimensions(t,b)
88 local bw, bh, bd = 0, 0, 0
89 local nw, nh, nd = 0, 0, 0
90 local cw, ch, cd = 0, 0, 0
91 if b then
92 bw = b.width
93 bh = b.height
94 bd = b.depth
95 cw = b.cwidth
96 ch = b.cheight
97 cd = b.cdepth
98 end
99 if t then
100 nw = t.width or bw
101 nh = t.height or bh
102 nd = t.depth or bd
103 cw = t.cwidth or cw
104 ch = t.cheight or ch
105 cd = t.cdepth or cd
106 end
107 setdimen("global","floatwidth", bw)
108 setdimen("global","floatheight", bh+bd)
109 setdimen("global","naturalfloatwd", nw)
110 setdimen("global","naturalfloatht", nh)
111 setdimen("global","naturalfloatdp", nd)
112 setdimen("global","floatcaptionwd", cw)
113 setdimen("global","floatcaptionht", ch)
114 setdimen("global","floatcaptiondp", cd)
115 return bw, bh, bd, nw, nh, dp, cw, xh, xp
116end
117
118local function get(stack,n,bylabel)
119 if bylabel then
120 for i=1,#stack do
121 local s = stack[i]
122 local n = string.topattern(tostring(n))
123 if find(s.data.label,n) then
124 return s, s.box, i
125 end
126 end
127 else
128 n = n or #stack
129 if n > 0 then
130 local t = stack[n]
131 if t then
132 return t, t.box, n
133 end
134 end
135 end
136end
137
138function floats.save(which,data)
139 which = which or default
140 local b = textakebox("floatbox")
141 if b then
142 local stack = stacks[which]
143 noffloats = noffloats + 1
144 local t = {
145 n = noffloats,
146 data = data or { },
147 width = getdimen("naturalfloatwd"),
148 height = getdimen("naturalfloatht"),
149 depth = getdimen("naturalfloatdp"),
150 cwidth = getdimen("floatcaptionwd"),
151 cheight = getdimen("floatcaptionht"),
152 cdepth = getdimen("floatcaptiondp"),
153 box = b,
154 }
155 insert(stack,t)
156
157 setcount("global","savednoffloats",#stacks[default])
158 if trace_floats then
159 report_floats("%s, category %a, number %a, slot %a, width %p, height %p, depth %p","saving",
160 which,noffloats,#stack,b.width,b.height,b.depth)
161 else
162 showmessage("floatblocks",2,noffloats)
163 end
164 else
165 report_floats("ignoring empty, category %a, number %a",which,noffloats)
166 end
167end
168
169function floats.resave(which)
170 if last then
171 which = which or default
172 local stack = stacks[which]
173 local b = textakebox("floatbox")
174 if not b then
175 report_floats("resaved float is empty")
176 end
177 last.box = b
178 insert(stack,1,last)
179 setcount("global","savednoffloats",#stacks[default])
180 if trace_floats then
181 report_floats("%s, category %a, number %a, slot %a width %p, height %p, depth %p","resaving",
182 which,noffloats,#stack,b.width,b.height,b.depth)
183 else
184 showmessage("floatblocks",2,noffloats)
185 end
186 else
187 report_floats("unable to resave float")
188 end
189end
190
191function floats.flush(which,n,bylabel)
192 which = which or default
193 local stack = stacks[which]
194 local t, b, n = get(stack,n or 1,bylabel)
195 if t then
196 if not b then
197 showmessage("floatblocks",1,t.n)
198 end
199 local w, h, d = setdimensions(t,b)
200 if trace_floats then
201 report_floats("%s, category %a, number %a, slot %a width %p, height %p, depth %p","flushing",
202 which,t.n,n,w,h,d)
203 else
204 showmessage("floatblocks",3,t.n)
205 end
206 texsetbox("floatbox",b)
207 last = remove(stack,n)
208 last.box = nil
209 setcount("global","savednoffloats",#stacks[which])
210 else
211 setdimensions()
212 end
213end
214
215function floats.consult(which,n)
216 which = which or default
217 local stack = stacks[which]
218 local t, b, n = get(stack,n)
219 if t then
220 local w, h, d = setdimensions(t,b)
221 if trace_floats then
222 report_floats("%s, category %a, number %a, slot %a width %p, height %p, depth %p","consulting",
223 which,t.n,n,w,h,d)
224 end
225 return t, b, n
226 else
227 if trace_floats then
228 report_floats("nothing to consult")
229 end
230 setdimensions()
231 end
232end
233
234function floats.collect(which,maxwidth,distance)
235 local usedwhich = which or default
236 local stack = stacks[usedwhich]
237 local stacksize = #stack
238 local collected = 0
239 local maxheight = 0
240 local maxdepth = 0
241
242 local function register()
243 collected = collected + 1
244 maxwidth = rest
245 if h > maxheight then
246 maxheight = h
247 end
248 if d > maxdepth then
249 maxdepth = d
250 end
251 end
252
253 for i=1,stacksize do
254 local t, b, n = get(stack,i)
255 if t then
256 local w, h, d, nw, nh, nd, cw, ch, cd = setdimensions(t,b)
257
258 if cw > nw then
259 w = cw
260 else
261 w = nw
262 end
263
264 local rest = maxwidth - w - distance
265 local fits = rest > -10
266 if trace_collecting then
267 report_collecting("%s, category %a, number %a, slot %a width %p, rest %p, fit %a","collecting",
268 usedwhich,t.n,n,w,rest,fits)
269 end
270 if fits then
271 collected = collected + 1
272 maxwidth = rest
273 if h > maxheight then
274 maxheight = h
275 end
276 if d > maxdepth then
277 maxdepth = d
278 end
279 else
280 break
281 end
282 else
283 break
284 end
285 end
286 setcount("global","nofcollectedfloats",collected)
287 setdimen("global","maxcollectedfloatstotal",maxheight+maxdepth)
288end
289
290function floats.getvariable(name,default)
291 local value = last and last.data[name] or default
292 return value ~= "" and value
293end
294
295function floats.checkedpagefloat(packed)
296 if structures.pages.is_odd() then
297 if #stacks.rightpage > 0 then
298 return "rightpage"
299 elseif #stacks.page > 0 then
300 return "page"
301 elseif #stacks.leftpage > 0 then
302 if packed then
303 return "leftpage"
304 end
305 end
306 else
307 if #stacks.leftpage > 0 then
308 return "leftpage"
309 elseif #stacks.page > 0 then
310 return "page"
311 elseif #stacks.rightpage > 0 then
312 if packed then
313 return "rightpage"
314 end
315 end
316 end
317end
318
319function floats.nofstacked(which)
320 return #stacks[which or default] or 0
321end
322
323function floats.hasstacked(which)
324 return (#stacks[which or default] or 0) > 0
325end
326
327
328
329local method = C((1-S(", :"))^1)
330local position = P(":") * C((1-S("*,"))^1) * (P("*") * C((1-S(","))^1))^0
331local label = P(":") * C((1-S(",*: "))^0)
332
333local pattern = method * (
334 label * position * C("")
335 + C("") * position * C("")
336 + label * C("") * C("")
337 + C("") * C("") * C("")
338) + C("") * C("") * C("") * C("")
339
340
341
342
343
344
345
346
347
348function floats.analysemethod(str)
349 return lpegmatch(pattern,str or "")
350end
351
352
353
354implement {
355 name = "flushfloat",
356 actions = floats.flush,
357 arguments = { "string", "integer" },
358}
359
360implement {
361 name = "flushlabeledfloat",
362 actions = floats.flush,
363 arguments = { "string", "string", true },
364}
365
366implement {
367 name = "savefloat",
368 actions = floats.save,
369 arguments = "string"
370}
371
372implement {
373 name = "savespecificfloat",
374 actions = floats.save,
375 arguments = {
376 "string",
377 {
378 { "specification" },
379 { "label" },
380 }
381 }
382}
383
384implement {
385 name = "resavefloat",
386 actions = floats.resave,
387 arguments = "string"
388}
389
390implement {
391 name = "pushfloat",
392 actions = floats.push
393}
394
395implement {
396 name = "popfloat",
397 actions = floats.pop
398}
399
400implement {
401 name = "consultfloat",
402 actions = floats.consult,
403 arguments = "string",
404}
405
406implement {
407 name = "collectfloat",
408 actions = floats.collect,
409 arguments = { "string", "dimen", "dimen" }
410}
411
412implement {
413 name = "getfloatvariable",
414 actions = { floats.getvariable, context },
415 arguments = "string"
416}
417
418implement {
419 name = "checkedpagefloat",
420 actions = { floats.checkedpagefloat, context },
421 arguments = "string"
422}
423
424implement {
425 name = "nofstackedfloats",
426 actions = { floats.nofstacked, context },
427 arguments = "string"
428}
429
430implement {
431 name = "doifelsestackedfloats",
432 actions = { floats.hasstacked, commands.doifelse },
433 arguments = "string"
434}
435
436implement {
437 name = "analysefloatmethod",
438 actions = function(str)
439 local method, label, column, row = floats.analysemethod(str)
440 setmacro("floatmethod",method or "")
441 setmacro("floatlabel", label or "")
442 setmacro("floatrow", row or "")
443 setmacro("floatcolumn",column or "")
444 end,
445 arguments = "string"
446}
447 |