1if not modules then modules = { } end modules ['x-cals'] = {
2 version = 1.001,
3 comment = "companion to x-cals.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, type = next, type
10local format, lower = string.format, string.lower
11local xmlcprint, xmlcollected, xmlelements = xml.cprint, xml.collected, xml.elements
12local n_todimen, s_todimen = number.todimen, string.todimen
13
14
15
16local cals = { }
17moduledata.cals = cals
18lxml.mathml = cals
19
20cals.ignore_widths = false
21cals.shrink_widths = false
22cals.stretch_widths = false
23
24
25
26
27
28
29
30
31
32
33local halignments = {
34 left = "flushleft",
35 right = "flushright",
36 center = "middle",
37 centre = "middle",
38 justify = "normal",
39}
40
41local valignments = {
42 top = "high",
43 bottom = "low",
44 middle = "lohi",
45}
46
47local function adapt(widths,b,w,delta,sum,n,what)
48 if b == "equal" then
49 delta = delta/n
50 for k, v in next, w do
51 widths[k] = n_todimen(v - delta)
52 end
53 elseif b == "proportional" then
54 delta = delta/sum
55 for k, v in next, w do
56 widths[k] = n_todimen(v - v*delta)
57 end
58 elseif type(b) == "number" and b < 1 then
59 delta = b*delta/sum
60 for k, v in next, w do
61 widths[k] = n_todimen(v - v*delta)
62 end
63 end
64end
65
66local function getspecs(root, pattern, names, widths)
67
68
69 local ignore_widths = cals.ignore_widths
70
71
72 local shrink_widths = cals.shrink_widths
73 local stretch_widths = cals.stretch_widths
74 for e in xmlcollected(root,pattern) do
75 local at = e.at
76 local column = at.colnum
77 if column then
78 if not ignore_widths then
79 local width = at.colwidth
80 if width then
81 widths[tonumber(column)] = lower(width)
82 end
83 end
84 local name = at.colname
85 if name then
86 names[name] = tonumber(column)
87 end
88 end
89 end
90 if ignore_width then
91
92 elseif shrink_widths or stretch_widths then
93 local sum, n, w = 0, 0, { }
94 for _, v in next, widths do
95 n = n + 1
96 v = (type(v) == "string" and s_todimen(v)) or v
97 if v then
98 w[n] = v
99 sum = sum + v
100 end
101 end
102 local hsize = tex.hsize
103 if type(hsize) == "string" then
104 hsize = s_todimen(hsize)
105 end
106 local delta = sum - hsize
107 if shrink_widths and delta > 0 then
108 adapt(widths,shrink_widths,w,delta,sum,n,"shrink")
109 elseif stretch_widths and delta < 0 then
110 adapt(widths,stretch_widths,w,delta,sum,n,"stretch")
111 end
112 end
113end
114
115local function getspans(root, pattern, names, spans)
116 for e in xmlcollected(root,pattern) do
117 local at = e.at
118 local name, namest, nameend = at.colname, names[at.namest or "?"], names[at.nameend or "?"]
119 if name and namest and nameend then
120 spans[name] = tonumber(nameend) - tonumber(namest) + 1
121 end
122 end
123end
124
125local bTR, eTR, bTD, eTD = context.bTR, context.eTR, context.bTD, context.eTD
126
127function cals.table(root,namespace)
128
129 local prefix = (namespace or "cals") .. ":"
130
131 local prefix = namespace and namespace ~= "" and (namespace .. ":") or ""
132 local p = "/" .. prefix
133
134 local tgroupspec = p .. "tgroup"
135 local colspec = p .. "colspec"
136 local spanspec = p .. "spanspec"
137 local hcolspec = p .. "thead" .. p .. "colspec"
138 local bcolspec = p .. "tbody" .. p .. "colspec"
139 local fcolspec = p .. "tfoot" .. p .. "colspec"
140 local entryspec = p .. "entry" .. "|" .. prefix .. "entrytbl"
141 local hrowspec = p .. "thead" .. p .. "row"
142 local browspec = p .. "tbody" .. p .. "row"
143 local frowspec = p .. "tfoot" .. p .. "row"
144
145 local function tablepart(root, xcolspec, xrowspec, before, after)
146 before()
147 local at = root.at
148 local pphalign, ppvalign = at.align, at.valign
149 local names, widths, spans = { }, { }, { }
150 getspecs(root, colspec , names, widths)
151 getspecs(root, xcolspec, names, widths)
152 getspans(root, spanspec, names, spans)
153 for r, d, k in xmlelements(root,xrowspec) do
154 bTR()
155 local dk = d[k]
156 local at = dk.at
157 local phalign, pvalign = at.align or pphalign, at.valign or ppvalign
158 local col = 1
159 for rr, dd, kk in xmlelements(dk,entryspec) do
160 local dk = dd[kk]
161 if dk.tg == "entrytbl" then
162
163 bTD()
164 context("{")
165 cals.table(dk)
166 context("}")
167 eTD()
168 col = col + 1
169 else
170 local at = dk.at
171 local b, e, s, m = names[at.namest or "?"], names[at.nameend or "?"], spans[at.spanname or "?"], at.morerows
172 local halign, valign = at.align or phalign, at.valign or pvalign
173 if b and e then
174 s = e - b + 1
175 end
176 if halign then
177 halign = halignments[halign]
178 end
179 if valign then
180 valign = valignments[valign]
181 end
182 local width = widths[col]
183 if s or m or halign or valign or width then
184 bTD {
185 nx = s or 1,
186 ny = (m or 0) + 1,
187 align = format("{%s,%s}",halign or "flushleft",valign or "high"),
188 width = width or "fit",
189 }
190 else
191 bTD {
192 align = "{flushleft,high}",
193 width = "fit",
194 }
195 end
196 xmlcprint(dk)
197 eTD()
198 col = col + (s or 1)
199 end
200 end
201 eTR()
202 end
203 after()
204 end
205
206 for tgroup in lxml.collected(root,tgroupspec) do
207 context.directsetup("cals:table:before")
208 lxml.directives.before(root,"cdx")
209 context.bgroup()
210 lxml.directives.setup(root,"cdx")
211 context.bTABLE()
212 tablepart(tgroup, hcolspec, hrowspec, context.bTABLEhead, context.eTABLEhead)
213 tablepart(tgroup, bcolspec, browspec, context.bTABLEbody, context.eTABLEbody)
214 tablepart(tgroup, fcolspec, frowspec, context.bTABLEfoot, context.eTABLEfoot)
215 context.eTABLE()
216 context.egroup()
217 lxml.directives.after(root,"cdx")
218 context.directsetup("cals:table:after")
219 end
220
221end
222 |