1if not modules then modules = { } end modules ['attr-lay'] = {
2 version = 1.001,
3 comment = "companion to attr-lay.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
12
13
14
15local type = type
16local insert, remove = table.insert, table.remove
17
18local attributes = attributes
19local nodes = nodes
20local utilities = utilities
21local logs = logs
22local backends = backends
23
24local context = context
25local interfaces = interfaces
26local tex = tex
27
28local implement = interfaces.implement
29
30local allocate = utilities.storage.allocate
31local setmetatableindex = table.setmetatableindex
32local formatters = string.formatters
33
34local report_viewerlayers = logs.reporter("viewerlayers")
35
36
37
38
39
40
41
42
43attributes.viewerlayers = attributes.viewerlayers or { }
44local viewerlayers = attributes.viewerlayers
45
46local variables = interfaces.variables
47local v_local = variables["local"]
48local v_global = variables["global"]
49local v_start = variables["start"]
50local v_yes = variables["yes"]
51
52local a_viewerlayer = attributes.private("viewerlayer")
53
54viewerlayers = viewerlayers or { }
55viewerlayers.data = allocate()
56viewerlayers.registered = viewerlayers.registered or { }
57viewerlayers.values = viewerlayers.values or { }
58viewerlayers.scopes = viewerlayers.scopes or { }
59viewerlayers.listwise = allocate()
60viewerlayers.attribute = a_viewerlayer
61viewerlayers.supported = true
62viewerlayers.hasorder = true
63
64local states = attributes.states
65local enableaction = nodes.tasks.enableaction
66local disableaction = nodes.tasks.disableaction
67local nodeinjections = backends.nodeinjections
68local codeinjections = backends.codeinjections
69
70local texsetattribute = tex.setattribute
71local texgetattribute = tex.getattribute
72local texsettokenlist = tex.settoks
73local unsetvalue = attributes.unsetvalue
74
75local data = viewerlayers.data
76local values = viewerlayers.values
77local listwise = viewerlayers.listwise
78local registered = viewerlayers.registered
79local scopes = viewerlayers.scopes
80
81local f_stamp = formatters["%s"]
82
83storage.register("attributes/viewerlayers/registered", registered, "attributes.viewerlayers.registered")
84storage.register("attributes/viewerlayers/values", values, "attributes.viewerlayers.values")
85storage.register("attributes/viewerlayers/scopes", scopes, "attributes.viewerlayers.scopes")
86
87local layerstacker = utilities.stacker.new("layers")
88
89layerstacker.mode = "stack"
90layerstacker.unset = attributes.unsetvalue
91
92viewerlayers.resolve_reset = layerstacker.resolve_reset
93viewerlayers.resolve_begin = layerstacker.resolve_begin
94viewerlayers.resolve_step = layerstacker.resolve_step
95viewerlayers.resolve_end = layerstacker.resolve_end
96
97
98
99local function startlayer(...) startlayer = nodeinjections.startlayer return startlayer(...) end
100local function stoplayer (...) stoplayer = nodeinjections.stoplayer return stoplayer (...) end
101
102local function extender(viewerlayers,key)
103 if viewerlayers.supported and key == "none" then
104 local d = stoplayer()
105 viewerlayers.none = d
106 return d
107 end
108end
109
110local function reviver(data,n)
111 if viewerlayers.supported then
112 local v = values[n]
113 if v then
114 local d = startlayer(v)
115 data[n] = d
116 return d
117 else
118 report_viewerlayers("error: unknown reference %a",tostring(n))
119 end
120 end
121end
122
123setmetatableindex(viewerlayers,extender)
124setmetatableindex(viewerlayers.data,reviver)
125
126
127
128layerstacker.start = function(...) local f = nodeinjections.startstackedlayer layerstacker.start = f return f(...) end
129layerstacker.stop = function(...) local f = nodeinjections.stopstackedlayer layerstacker.stop = f return f(...) end
130layerstacker.change = function(...) local f = nodeinjections.changestackedlayer layerstacker.change = f return f(...) end
131
132local function initializer(...)
133 return states.initialize(...)
134end
135
136attributes.viewerlayers.handler = nodes.installattributehandler {
137 name = "viewerlayer",
138 namespace = viewerlayers,
139 initializer = initializer,
140 finalizer = states.finalize,
141 processor = states.stacker,
142
143}
144
145local stack, enabled, global = { }, false, false
146
147function viewerlayers.enable(value)
148 if value == false or not viewerlayers.supported then
149 if enabled then
150 disableaction("shipouts","attributes.viewerlayers.handler")
151 end
152 enabled = false
153 else
154 if not enabled then
155 enableaction("shipouts","attributes.viewerlayers.handler")
156 end
157 enabled = true
158 end
159end
160
161function viewerlayers.forcesupport(value)
162 viewerlayers.supported = value
163 report_viewerlayers("viewerlayers are %ssupported",value and "" or "not ")
164 viewerlayers.enable(value)
165end
166
167local function register(name,lw)
168 if not enabled then
169 viewerlayers.enable(true)
170 end
171 local stamp = f_stamp(name)
172 local n = registered[stamp]
173 if not n then
174 n = #values + 1
175 values[n] = name
176 registered[stamp] = n
177 listwise[n] = lw or false
178 end
179 return registered[stamp]
180end
181
182viewerlayers.register = register
183
184function viewerlayers.setfeatures(hasorder)
185 viewerlayers.hasorder = hasorder
186end
187
188local usestacker = true
189
190function viewerlayers.start(name)
191 local a
192 if usestacker then
193 a = layerstacker.push(register(name) or unsetvalue)
194 else
195 insert(stack,texgetattribute(a_viewerlayer))
196 a = register(name) or unsetvalue
197 end
198 if global or scopes[name] == v_global then
199 scopes[a] = v_global
200 texsetattribute("global",a_viewerlayer,a)
201 else
202 texsetattribute(a_viewerlayer,a)
203 end
204
205 texsettokenlist("currentviewerlayertoks",name)
206end
207
208function viewerlayers.stop()
209 local a
210 if usestacker then
211 a = layerstacker.pop()
212 else
213 a = remove(stack)
214 end
215 if not a then
216
217 elseif a >= 0 then
218 if global or scopes[a] == v_global then
219 texsetattribute("global",a_viewerlayer,a)
220 else
221 texsetattribute(a_viewerlayer,a)
222 end
223 texsettokenlist("currentviewerlayertoks",values[a] or "")
224 else
225 if global or scopes[a] == v_global then
226 texsetattribute("global",a_viewerlayer,unsetvalue)
227 else
228 texsetattribute(a_viewerlayer,unsetvalue)
229 end
230 texsettokenlist("currentviewerlayertoks","")
231 end
232end
233
234function viewerlayers.define(settings)
235 local tag = settings.tag
236 if not tag or tag == "" then
237
238 elseif not scopes[tag] then
239 local title = settings.title
240 if not title or title == "" then
241 settings.title = tag
242 end
243 scopes[tag] = settings.scope or v_local
244 codeinjections.defineviewerlayer(settings)
245 end
246end
247
248function viewerlayers.setup(settings)
249
250 codeinjections.setupviewerlayer(settings)
251end
252
253function viewerlayers.definedlayoutcomponent(tag)
254 viewerlayers.define {
255 tag = tag,
256 title = utilities.strings.nice(tag),
257 visible = v_start,
258 editable = v_yes,
259 printable = v_yes,
260 }
261 return register(tag,true)
262end
263
264function viewerlayers.cleanup()
265 layerstacker.clean()
266
267end
268
269implement {
270 name = "cleanuplayers",
271 actions = viewerlayers.cleanup
272}
273
274do
275 local t = {
276 {
277 { "tag" },
278 { "title" },
279 { "visible" },
280 { "editable" },
281 { "export" },
282 { "printable" },
283 { "scope" },
284 }
285 }
286
287 implement {
288 name = "defineviewerlayer",
289 actions = viewerlayers.define,
290 arguments = t
291 }
292
293 implement {
294 name = "setupviewerlayer",
295 actions = viewerlayers.setup,
296 arguments = t
297 }
298
299end
300
301implement {
302 name = "definedlayoutcomponent",
303 actions = { viewerlayers.definedlayoutcomponent, context },
304 arguments = "string"
305}
306
307implement {
308 name = "startviewerlayer",
309 public = true,
310 protected = true,
311 actions = viewerlayers.start,
312 arguments = "optional",
313}
314
315implement {
316 name = "stopviewerlayer",
317 public = true,
318 protected = true,
319 actions = viewerlayers.stop
320}
321
322implement {
323 name = "registeredviewerlayer",
324 actions = { register, context },
325 arguments = { "string", true }
326}
327 |