summaryrefslogtreecommitdiff
path: root/tex/context/base/x-cals.mkiv
blob: 3d264404584442d9d97471e9b3f9ba7b28d51845 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
%D \module
%D   [       file=x-cals,
%D        version=2007.09.05,
%D          title=\CONTEXT\ XML Modules,
%D       subtitle=Cals table renderer,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

\writestatus{loading}{ConTeXt XML Macros / Cals Tables}

\startluacode
do

    lxml.cals = { }
    lxml.cals.ignore_widths  = false

    -- the following flags only apply to columns that have a specified width
    --
    -- proportional : shrink or stretch proportionally to the width
    -- equal        : shrink or stretch equaly distributed
    -- n < 1        : shrink or stretch proportionally to the width but multiplied by n
    --
    -- more clever things, e.g. the same but applied to unspecified widths
    -- has to happen at the core-ntb level (todo)

    lxml.cals.shrink_widths  = false
    lxml.cals.stretch_widths = false

    local format    = string.format
    local texsprint = tex.sprint
    local xmlsprint = xml.sprint
    local xmlcprint = xml.cprint

    local halignments = {
        left = "flushleft",
        right = "flushright",
        center = "middle",
        centre = "middle",
        justify = "normal",
    }

    local valignments = {
        top = "high",
        bottom = "low",
        middle = "lohi",
    }

    local function getspecs(root, pattern, names, widths)
        -- here, but actually we need this in core-ntb.tex
        -- but ideally we need an mkiv enhanced core-ntb.tex
        local ignore_widths = lxml.cals.ignore_widths
        local shrink_widths = lxml.cals.shrink_widths
        local stretch_widths = lxml.cals.stretch_widths
        for r, d, k in xml.elements(root,pattern) do
            local dk = d[k]
            local at = dk.at
            local column = at.colnum
            if column then
                if not ignore_widths then
                    local width = at.colwidth
                    if width then
                        widths[tonumber(column)] = width:lower()
                    end
                end
                local name = at.colname
                if name then
                    names[name] = tonumber(column)
                end
            end
        end
        local function adapt(b,w,delta,sum,n,what)
            if b == "equal" then
                delta = delta/n
                for k, v in pairs(w) do
                    widths[k] = number.todimen(v - delta)
                end
            elseif b == "proportional" then
                delta = delta/sum
                for k, v in pairs(w) do
                    widths[k] = number.todimen(v - v*delta)
                end
            elseif type(b) == "number" and b < 1 then
                delta = b*delta/sum
                for k, v in pairs(w) do
                    widths[k] = number.todimen(v - v*delta)
                end
            end
        end
        if ignore_width then
            -- forget about it
        elseif shrink_widths or stretch_widths then
            local sum, n, w = 0, 0, { }
            for _, v in pairs(widths) do
                n = n + 1
                v = (type(v) == "string" and v:todimen()) or v
                if v then
                    w[n] = v
                    sum = sum + v
                end
            end
            local hsize = tex.hsize
            if type(hsize) == "string" then
                hsize = hsize:todimen()
            end
            local delta = sum - hsize
            if shrink_widths and delta > 0 then
                adapt(shrink_widths,w,delta,sum,n,"shrink")
            elseif stretch_widths and delta < 0 then
                adapt(stretch_widths,w,delta,sum,n,"stretch")
            end
        end
    end

    local function getspans(root, pattern, names, spans)
        for r, d, k in xml.elements(root,pattern) do
            local dk = d[k]
            local at = dk.at
            local name, namest, nameend = at.colname, names[at.namest or "?"], names[at.nameend or "?"]
            if name and namest and nameend then
                spans[name] = tonumber(nameend) - tonumber(namest) + 1
            end
        end
    end

    --local function texsprint(a,b) print(b) end
    --local function xmlsprint(a) print(a) end

    function lxml.cals.table(root,namespace)

        local prefix = (namespace or "cals") .. ":"
        local p = "/" .. prefix

        local tgroupspec = p .. "tgroup"
        local colspec    = p .. "colspec"
        local spanspec   = p .. "spanspec"
        local hcolspec   = p .. "thead" .. p .. "colspec"
        local bcolspec   = p .. "tbody" .. p .. "colspec"
        local fcolspec   = p .. "tfoot" .. p .. "colspec"
        local entryspec  = p .. "entry" .. "|" ..prefix .. "entrytbl"
        local hrowspec   = p .. "thead" .. p .. "row"
        local browspec   = p .. "tbody" .. p .. "row"
        local frowspec   = p .. "tfoot" .. p .. "row"

        local function tablepart(root, xcolspec, xrowspec, before, after)
            texsprint(tex.ctxcatcodes,before)
            local at = root.at
            local pphalign, ppvalign = at.align, at.valign
            local names, widths, spans = { }, { }, { }
            getspecs(root, colspec , names, widths)
            getspecs(root, xcolspec, names, widths)
            getspans(root, spanspec, names, spans)
            for r, d, k in xml.elements(root,xrowspec) do
                texsprint(tex.ctxcatcodes,"\\bTR")
                local dk = d[k]
                local at = dk.at
                local phalign, pvalign = at.align or pphalign, at.valign or ppvalign -- todo: __p__ test
                local col = 1
                for rr, dd, kk in xml.elements(dk,entryspec) do
                    local dk = dd[kk]
                    if dk.tg == "entrytbl" then
                        texsprint(tex.ctxcatcodes,"\\bTD{")
                        lxml.cals.table(dk)
                        texsprint(tex.ctxcatcodes,"}\\eTD")
                        col = col + 1
                    else
                        local at = dk.at
                        local b, e, s, m = names[at.namest or "?"], names[at.nameend or "?"], spans[at.spanname or "?"], at.morerows
                        local halign, valign = at.align or phalign, at.valign or pvalign
                        if b and e then
                            s = e - b + 1
                        end
                        if halign then
                            halign = halignments[halign]
                        end
                        if valign then
                            valign = valignments[valign]
                        end
                        local width = widths[col]
                        if s or m or halign or valign or width then -- only english interface !
                            texsprint(tex.ctxcatcodes,format("\\bTD[nx=%s,ny=%s,align={%s,%s},width=%s]",
                                s or 1, (m or 0)+1, halign or "flushleft", valign or "high", width or "fit"))
                        else
                            texsprint(tex.ctxcatcodes,"\\bTD[align={flushleft,high},width=fit]") -- else problems with vertical material
                        end
                    --    xmlsprint(dk)
                        xmlcprint(dk)
                        texsprint(tex.ctxcatcodes,"\\eTD")
                        col = col + (s or 1)
                    end
                end
                texsprint(tex.ctxcatcodes,"\\eTR")
            end
            texsprint(tex.ctxcatcodes,after)
        end

        for r, d, k in xml.elements(lxml.id(root),tgroupspec) do
            local tgroup = d[k]
            texsprint(tex.ctxcatcodes, "\\directsetup{cals:table:before}")
            lxml.directives.before(root,"cdx") -- "cals:table"
            texsprint(tex.ctxcatcodes, "\\bgroup")
            lxml.directives.setup(root,"cdx") -- "cals:table"
            texsprint(tex.ctxcatcodes, "\\bTABLE")
            tablepart(tgroup, hcolspec, hrowspec, "\\bTABLEhead", "\\eTABLEhead")
            tablepart(tgroup, bcolspec, browspec, "\\bTABLEbody", "\\eTABLEbody")
            tablepart(tgroup, fcolspec, frowspec, "\\bTABLEfoot", "\\eTABLEfoot")
            texsprint(tex.ctxcatcodes, "\\eTABLE")
            texsprint(tex.ctxcatcodes, "\\egroup")
            lxml.directives.after(root,"cdx") -- "cals:table"
            texsprint(tex.ctxcatcodes, "\\directsetup{cals:table:after}")
        end
    end

end
\stopluacode

% \startxmlsetups xml:cals:process
%     \xmlsetsetup {\xmldocument} {cals:table} {*}
% \stopxmlsetups
% \startxmlsetups cals:table
%     \ctxlua{lxml.cals.table("#1")}
% \stopxmlsetups
% \xmlregistersetup{xml:cals:process}

\startxmlsetups xml:cals:process
    \xmlsetfunction {\xmldocument} {cals:table} {lxml.cals.table}
\stopxmlsetups

\xmlregistersetup{xml:cals:process}

\xmlregisterns{cals}{cals}

\endinput