m-steps.lua /size: 14 Kb    last modification: 2020-07-01 14:35
1if not modules then modules = { } end modules ['x-flow'] = {
2    version   = 1.001,
3    comment   = "companion to m-flow.mkvi",
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-- when we can resolve mpcolor at the lua end we will use metapost.graphic(....) directly
10
11local tonumber = tonumber
12
13moduledata.steps = moduledata.steps or { }
14
15local context    = context
16local variables  = interfaces.variables
17local formatters = string.formatters
18----- mpcolor    = attributes.colors.mpnamedcolor
19local concat     = table.concat
20
21local report     = logs.reporter("stepcharts")
22local trace      = false
23
24trackers.register("stepcharts",function(v) trace = v end)
25
26local defaults = {
27    chart = {
28        dx              = 10*65436,
29        dy              = 10*65436,
30    },
31    cell = {
32        alternative     = 1,
33        offset          = 2*65436,
34        rulethickness   = 65436,
35        framecolor      = "blue",
36        backgroundcolor = "gray",
37    },
38    text = {
39        alternative     = 1,
40        offset          = 2*65436,
41        distance        = 4*65436,
42        rulethickness   = 65436,
43        framecolor      = "red",
44        backgroundcolor = "gray",
45    },
46    line = {
47        alternative     = 1,
48        rulethickness   = 65436,
49        height          = 30*65436,
50        distance        = 10*65436,
51        offset          = 5*65436,
52        color           = "green",
53    },
54}
55
56-- todo : name (no name then direct)
57-- maybe: includes
58-- maybe: flush ranges
59
60local charts = { } -- not used but we could support nesting
61local chart  = nil
62local steps  = { }
63local count  = 0
64
65local function step_start_chart(name,alternative)
66    name = name or ""
67    steps = table.setmetatableindex(function(t,k)
68        local v = { -- could be metatable
69            cell_top = false,
70            cell_bot = false,
71            text_top = false,
72            text_mid = false,
73            text_bot = false,
74            start_t  = k,
75            start_m  = k,
76            start_b  = k,
77            cell_ali = false,
78        }
79        t[k] = v
80        return v
81    end)
82    count = 0
83    chart = {
84        steps       = steps,
85        count       = count,
86        alternative = alternative,
87    }
88    charts[name] = chart
89end
90
91local function step_stop_chart()
92    chart.count = count
93end
94
95local function step_make_chart(settings)
96    local chartsettings = settings.chart
97    if not chartsettings then
98        if trace then
99            report("no chart")
100        end
101        return
102    end
103    local chartname = chartsettings.name
104    if not chartname then
105        if trace then
106            report("no name given")
107        end
108        return
109    end
110    local chart = charts[chartname]
111    if not chart then
112        if trace then
113            report("no such chart: %s",chartname)
114        end
115        return
116    end
117    local steps = chart.steps or { }
118    --
119    table.setmetatableindex(settings,defaults)
120    --
121    if trace then
122        report(table.serialize(steps,"chartdata"))
123    end
124    --
125    local textsettings = settings.text
126    local cellsettings = settings.cell
127    local linesettings = settings.line
128
129    local start = nil
130    local stop  = nil
131    local flush = nil
132
133    if false then
134
135        -- some 2% faster at most, so neglectable as this kind of graphics
136        -- is hardly used in quantity but it saves mem and tokens in tracing
137        -- and we lose some aspects, like outer color and so (currently)
138
139        local mpcode = false
140
141        start = function()
142            mpcode = { }
143        end
144        stop = function()
145            local code = concat(mpcode,"\n")
146         -- print(code)
147            metapost.graphic {
148             -- instance        = "metafun",
149                instance        = "steps",
150                format          = "metafun",
151                data            = code,
152             -- initializations = "",
153             -- extensions      = "",
154             -- inclusions      = "",
155                definitions     = 'loadmodule "step" ;',
156             -- figure          = "",
157                method          = "double",
158            }
159            mpcode = false
160        end
161        flush = function(fmt,first,...)
162            if first then
163                mpcode[#mpcode+1] = formatters[fmt](first,...)
164            else
165                mpcode[#mpcode+1] = fmt
166            end
167        end
168
169    else
170
171        start = function() context.startMPcode("steps") end
172        stop  = context.stopMPcode
173        flush = context
174
175    end
176    --
177    start()
178    flush("step_begin_chart ;")
179    --
180    local alternative = chartsettings.alternative
181    if not alternative or alternative == "" then
182        alternative = chart.alternative
183    end
184    if not alternative or alternative == "" then
185        alternative = variables.horizontal
186    end
187    local alternative = utilities.parsers.settings_to_hash(alternative)
188    local vertical    = alternative[variables.vertical]
189    local align       = alternative[variables.three]
190    local category    = chartsettings.category
191    --
192    flush('chart_category := "%s" ;',category)
193    --
194    if vertical then
195        flush("chart_vertical := true ;")
196    end
197    if align then
198        flush("chart_align := true ;")
199    end
200    --
201    flush("text_line_color   := %q ;", textsettings.framecolor)
202    flush("text_line_width   := %p ;", textsettings.rulethickness)
203    flush("text_fill_color   := %q ;", textsettings.backgroundcolor)
204    flush("text_offset       := %p ;", textsettings.offset)
205    flush("text_distance_set := %p ;", textsettings.distance)
206    --
207    flush("cell_line_color := %q ;", cellsettings.framecolor)
208    flush("cell_line_width := %p ;", cellsettings.rulethickness)
209    flush("cell_fill_color := %q ;", cellsettings.backgroundcolor)
210    flush("cell_offset     := %p ;", cellsettings.offset)
211    flush("cell_distance_x := %p ;", cellsettings.dx)
212    flush("cell_distance_y := %p ;", cellsettings.dy)
213    --
214    flush("line_line_color := %q ;", linesettings.color)
215    flush("line_line_width := %p ;", linesettings.rulethickness)
216    flush("line_distance   := %p ;", linesettings.distance)
217    flush("line_offset     := %p ;", linesettings.offset)
218    flush("line_height     := %p ;", linesettings.height)
219    --
220    for i=1,chart.count do
221        local step = steps[i]
222        flush("step_begin_cell ;")
223        local ali = step.cell_ali
224        local top = step.cell_top
225        local bot = step.cell_bot
226        if ali then
227            local text = ali.text
228            local shape = ali.shape
229            flush('step_cell_ali(%s,%s,%s,%q,%q,%p,%i) ;',
230                tonumber(text.left) or 0,
231                tonumber(text.middle) or 0,
232                tonumber(text.right) or 0,
233                shape.framecolor,
234                shape.backgroundcolor,
235                shape.rulethickness,
236                tonumber(shape.alternative) or 24
237            )
238        end
239        if top then
240            local shape = top.shape
241            flush('step_cell_top(%s,%q,%q,%p,%i) ;',
242                tonumber(top.text.top) or 0,
243                shape.framecolor,
244                shape.backgroundcolor,
245                shape.rulethickness,
246                tonumber(shape.alternative) or 24
247            )
248        end
249        if bot then
250            local shape = bot.shape
251            flush('step_cell_bot(%s,%q,%q,%p,%i) ;',
252                tonumber(bot.text.bot) or 0,
253                shape.framecolor,
254                shape.backgroundcolor,
255                shape.rulethickness,
256                tonumber(shape.alternative) or 24
257            )
258        end
259        local top = step.text_top
260        local mid = step.text_mid
261        local bot = step.text_bot
262        local s_t = step.start_t
263        local s_m = step.start_m
264        local s_b = step.start_b
265        if top then
266            local shape = top.shape
267            local line  = top.line
268            flush('step_text_top(%s,%q,%q,%p,%i,%q,%p,%i) ;',
269                tonumber(top.text.top) or 0,
270                shape.framecolor,
271                shape.backgroundcolor,
272                shape.rulethickness,
273                tonumber(shape.alternative) or 24,
274                line.color,
275                line.rulethickness,
276                tonumber(line.alternative) or 1
277            )
278        end
279        if mid then -- used ?
280            local shape = mid.shape
281            local line  = mid.line
282            flush('step_text_mid(%s,%q,%q,%p,%i,%q,%p,%i) ;',
283                tonumber(mid.text.mid) or 0,
284                shape.framecolor,
285                shape.backgroundcolor,
286                shape.rulethickness,
287                tonumber(shape.alternative) or 24,
288                line.color,
289                line.rulethickness,
290                tonumber(line.alternative) or 1
291            )
292        end
293        if bot then
294            local shape = bot.shape
295            local line  = bot.line
296            flush('step_text_bot(%s,%q,%q,%p,%i,%q,%p,%i) ;',
297                tonumber(bot.text.bot) or 0,
298                shape.framecolor,
299                shape.backgroundcolor,
300                shape.rulethickness,
301                tonumber(shape.alternative) or 24,
302                line.color,
303                line.rulethickness,
304                tonumber(line.alternative) or 1
305            )
306        end
307        flush('start_t[%i] := %i ;',i,s_t)
308        flush('start_m[%i] := %i ;',i,s_m)
309        flush('start_b[%i] := %i ;',i,s_b)
310        flush("step_end_cell ;")
311    end
312    --
313    flush("step_end_chart ;")
314    stop()
315end
316
317local function step_cells(spec)
318    count = count + 1
319    local step = steps[count]
320    step.cell_top = spec
321    step.cell_bot = spec
322end
323
324local function step_cells_three(spec)
325    count = count + 1
326    local step = steps[count]
327    step.cell_ali = spec
328end
329
330local function step_texts(spec)
331    if count > 0 then
332        local step = steps[count]
333        step.text_top = spec
334        step.text_bot = spec
335    end
336end
337
338local function step_cell(spec)
339    count = count + 1
340    steps[count].cell_top = spec
341end
342
343local function step_text(spec)
344    if count > 0 then
345        local c = count
346        while true do
347            local step = steps[c]
348            if step.text_top then
349                c = c + 1
350                step = steps[c]
351            else
352                step.text_top = spec
353                step.start_b  = count
354                break
355            end
356        end
357    end
358end
359
360local function step_start_cell()
361    count = count + 1
362    local step = steps[count] -- creates
363end
364
365local function step_stop_cell()
366end
367
368local function step_text_top(spec)
369    if count > 0 then
370        steps[count].text_top = spec
371    end
372end
373
374local function step_text_mid(spec)
375    if count > 0 then
376        steps[count].text_mid = spec
377    end
378end
379
380local function step_text_bot(spec)
381    if count > 0 then
382        steps[count].text_bot = spec
383    end
384end
385
386local function step_cell_top(spec)
387    if count > 0 then
388        steps[count].cell_top = spec
389    end
390end
391
392local function step_cell_bot(spec)
393    if count > 0 then
394        steps[count].cell_bot = spec
395    end
396end
397
398--
399
400interfaces.implement {
401    name      = "step_start_chart",
402    arguments = "2 strings",
403    actions   = step_start_chart,
404}
405
406interfaces.implement {
407    name      = "step_stop_chart",
408    actions   = step_stop_chart,
409}
410
411interfaces.implement {
412    name      = "step_make_chart",
413    actions   = step_make_chart,
414    arguments = {
415        {
416            { "chart", {
417                    { "category" },
418                    { "name" },
419                    { "alternative" },
420                }
421            },
422            { "cell", {
423                { "alternative" },
424                { "offset", "dimension" },
425                { "rulethickness", "dimension" },
426                { "framecolor" },
427                { "backgroundcolor" },
428                { "dx", "dimension" },
429                { "dy", "dimension" },
430                }
431            },
432            { "text", {
433                { "alternative" },
434                { "offset", "dimension" },
435                { "distance", "dimension" },
436                { "rulethickness", "dimension" },
437                { "framecolor" },
438                { "backgroundcolor" },
439                }
440            },
441            { "line", {
442                { "alternative" },
443                { "rulethickness", "dimension" },
444                { "height", "dimension" },
445                { "distance", "dimension" },
446                { "offset", "dimension" },
447                { "color" },
448                }
449            }
450        }
451    }
452}
453
454local step_spec = {
455    {
456        { "text", {
457                { "top" },
458                { "middle" },
459                { "mid" },
460                { "bot" },
461                { "left" },
462                { "right" },
463            }
464        },
465        { "shape", {
466                { "rulethickness", "dimension" },
467                { "alternative" },
468                { "framecolor" },
469                { "backgroundcolor" },
470            }
471        },
472        { "line", {
473                { "alternative" },
474                { "rulethickness", "dimension" },
475                { "color" },
476                { "offset", "dimension" },
477            }
478        }
479    }
480}
481
482interfaces.implement {
483    name      = "step_cell",
484    arguments = step_spec,
485    actions   = step_cell,
486}
487
488interfaces.implement {
489    name      = "step_text",
490    arguments = step_spec,
491    actions   = step_text,
492}
493
494interfaces.implement {
495    name      = "step_text_top",
496    arguments = step_spec,
497    actions   = step_text_top,
498}
499
500interfaces.implement {
501    name      = "step_text_mid",
502    arguments = step_spec,
503    actions   = step_text_mid,
504}
505
506interfaces.implement {
507    name      = "step_text_bot",
508    arguments = step_spec,
509    actions   = step_text_bot,
510}
511
512interfaces.implement {
513    name      = "step_cell_top",
514    arguments = step_spec,
515    actions   = step_cell_top,
516}
517
518interfaces.implement {
519    name      = "step_cell_bot",
520    arguments = step_spec,
521    actions   = step_cell_bot,
522}
523
524interfaces.implement {
525    name      = "step_start_cell",
526    actions   = step_start_cell,
527}
528
529interfaces.implement {
530    name      = "step_stop_cell",
531    actions   = step_stop_cell,
532}
533
534interfaces.implement {
535    name      = "step_texts",
536    arguments = step_spec,
537    actions   = step_texts,
538}
539
540interfaces.implement {
541    name      = "step_cells",
542    arguments = step_spec,
543    actions   = step_cells,
544}
545
546interfaces.implement {
547    name      = "step_cells_three",
548    arguments = step_spec,
549    actions   = step_cells_three,
550}
551