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 |