scrn-wid.lmt /size: 9997 b    last modification: 2025-02-21 11:03
1if not modules then modules = { } end modules ['scrn-wid'] = {
2    version   = 1.001,
3    comment   = "companion to scrn-wid.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-- Support for interactive features is handled elsewhere. Now that is some mess! In
10-- the early days one had media features like sound and movies that were easy to set
11-- up. Then at some point renditions came around which were more work and somewhat
12-- unreliable. Now, both mechanism are obsolete and replaced by rich media which is
13-- a huge mess and has no real concept of what media are supported. There's flash
14-- cq. shockwave (basically obsolete too), and for instance mp4 needs to be handled
15-- by a swf player, and there's u3d which somehow has its own specification. One
16-- would expect native support for video and audio to be en-par with browsers but
17-- alas ... pdf has lost the battle with html here due to a few decades of
18-- unstability and changing support. So far we could catch on and even were ahead
19-- but I wonder if we should keep doing that. As we can't trust support for media we
20-- can better not embed anything and just use a hyperlink to an external resource. No
21-- sane person will create media rich pdf's as long as it's that unpredictable. Just
22-- look at the specification and viewer preferences and decide.
23
24local next = next
25
26interactions             = interactions or { }
27local interactions       = interactions
28
29local context            = context
30local implement          = interfaces.implement
31
32local allocate           = utilities.storage.allocate
33
34local attachments        = allocate()
35local comments           = allocate()
36local renderings         = allocate()
37local linkedlists        = allocate()
38
39interactions.attachments = attachments
40interactions.renderings  = renderings
41interactions.linkedlists = linkedlists
42
43local texsetbox          = tex.setbox
44
45local texgetcount        = tex.getcount
46
47local codeinjections     = backends.codeinjections
48local nodeinjections     = backends.nodeinjections
49
50local v_auto             <const> = interfaces.variables.auto
51
52local trace_attachments = false  trackers.register("widgets.attachments", function(v) trace_attachments = v end)
53
54local report_attachments = logs.reporter("widgets","attachments")
55
56-- Symbols
57
58implement {
59    name      = "presetsymbollist",
60    arguments = "string",
61    actions   = function(list)
62        codeinjections.presetsymbollist(list)
63    end
64}
65
66-- Attachments
67--
68-- registered : unique id
69-- tag        : used at the tex end
70-- file       : name that the file has on the filesystem
71-- name       : name that the file will get in the output
72-- title      : up to the backend
73-- subtitle   : up to the backend
74-- author     : up to the backend
75-- method     : up to the backend (hidden == no rendering)
76
77local nofautoattachments, lastregistered = 0, nil
78
79local function checkregistered(specification)
80    local registered = specification.registered
81    if not registered or registered == "" or registered == v_auto then
82        nofautoattachments = nofautoattachments + 1
83        lastregistered = "attachment-" .. nofautoattachments
84        specification.registered = lastregistered
85        return lastregistered
86    else
87        return registered
88    end
89end
90
91local function checkbuffer(specification)
92    local buffer = specification.buffer
93    if buffer ~= "" then
94        specification.data = buffers.getcontent(buffer) or "<no data>"
95    end
96end
97
98function attachments.register(specification) -- beware of tag/registered mixup(tag is namespace)
99    local registered = checkregistered(specification)
100    checkbuffer(specification)
101    attachments[registered] = specification
102    if trace_attachments then
103        report_attachments("registering %a",registered)
104    end
105    return specification
106end
107
108function attachments.insert(specification)
109    local registered = checkregistered(specification)
110    local r = attachments[registered]
111    if r then
112        if trace_attachments then
113            report_attachments("including registered %a",registered)
114        end
115        for k, v in next, r do
116            local s = specification[k]
117            if s == "" then
118                specification[k] = v
119            end
120        end
121    elseif trace_attachments then
122        report_attachments("including unregistered %a",registered)
123    end
124    checkbuffer(specification)
125    return nodeinjections.attachfile(specification)
126end
127
128implement {
129    name      = "registerattachment",
130    actions   = attachments.register,
131    arguments = {
132        {
133            { "tag" },
134            { "registered" },
135            { "title" },
136            { "subtitle" },
137            { "author" },
138            { "file" },
139            { "name" },
140            { "buffer" },
141            { "mimetype" },
142        }
143    }
144}
145
146implement {
147    name      = "insertattachment",
148    actions   = function(specification)
149                    texsetbox("b_scrn_attachment_link",(attachments.insert(specification)))
150                end,
151    arguments = {
152        {
153            { "tag" },
154            { "registered" },
155            { "method" },
156            { "width", "dimen" },
157            { "height", "dimen" },
158            { "depth", "dimen" },
159            { "colormodel", "integer" },
160            { "colorvalue", "integer" },
161            { "color" },
162            { "transparencyvalue", "integer" },
163            { "symbol" },
164            { "layer" },
165            { "title" },
166            { "subtitle" },
167            { "author" },
168            { "file" },
169            { "name" },
170            { "buffer" },
171            { "mimetype" },
172        }
173    }
174}
175
176-- Comment
177
178function comments.insert(specification)
179    local buffer = specification.buffer
180    if buffer ~= "" then
181        specification.data = buffers.getcontent(buffer) or ""
182    end
183    return nodeinjections.comment(specification)
184end
185
186implement {
187    name      = "insertcomment",
188    actions   = function(specification)
189                    texsetbox("b_scrn_comment_link",(comments.insert(specification)))
190                end,
191    arguments = {
192        {
193            { "tag" },
194            { "title" },
195            { "subtitle" },
196            { "author" },
197            { "width", "dimen" },
198            { "height", "dimen" },
199            { "depth", "dimen" },
200            { "nx" },
201            { "ny" },
202            { "colormodel", "integer" },
203            { "colorvalue", "integer" },
204            { "transparencyvalue", "integer" },
205            { "option" },
206            { "symbol" },
207            { "buffer" },
208            { "layer" },
209            { "space" },
210        }
211    }
212}
213
214-- Renderings
215
216function renderings.register(specification)
217    if specification.label then
218        renderings[specification.label] = specification
219        return specification
220    end
221end
222
223function renderings.rendering(label)
224    local rn = renderings[label]
225    if not rn then
226        -- todo: message
227        return renderings.register { label = label }
228    else
229        return rn
230    end
231end
232
233function renderings.var(label,key)
234    local rn = renderings[label]
235    return rn and rn[key] or ""
236end
237
238implement {
239    name      = "renderingvar",
240    actions   = { renderings.var, context },
241    arguments = "2 strings",
242}
243
244implement {
245    name      = "registerrendering",
246    actions   = renderings.register,
247    arguments = {
248        {
249            { "label" },
250            { "mime" },
251            { "filename" },
252            { "option" },
253        }
254    }
255}
256
257-- Rendering:
258
259implement {
260    name      = "insertrenderingwindow",
261    actions   = function(specification)
262                    codeinjections.insertrenderingwindow(specification)
263                end,
264    arguments = {
265        {
266            { "label" },
267            { "width", "dimen" },
268            { "height", "dimen"  },
269            { "option" },
270            { "page", "integer" },
271            { "openpage" },
272            { "closepage" },
273        }
274    }
275}
276
277-- Linkedlists (only a context interface) .. untested, just adapted from old code.
278
279local collected = allocate()
280local tobesaved = allocate()
281
282local c_realpageno <const> = tex.iscount("realpageno")
283
284local linkedlists = {
285    collected = collected,
286    tobesaved = tobesaved,
287}
288
289job.linkedlists = linkedlists
290
291local function initializer()
292    collected = linkedlists.collected
293    tobesaved = linkedlists.tobesaved
294end
295
296job.register("job.linkedlists.collected", tobesaved, initializer, nil)
297
298implement {
299    name      = "definelinkedlist",
300    arguments = "string",
301    actions   = function(tag)
302                    -- no need
303                end
304}
305
306implement {
307    name      = "enhancelinkedlist",
308    arguments = { "string", "integer" },
309    actions   = function(tag,n)
310                    local linkedlist = tobesaved[tag]
311                    if not linkedlist then
312                        linkedlist     = { }
313                        tobesaved[tag] = linkedlist
314                    end
315                    linkedlist[n] = texgetcount(c_realpageno)
316                end
317}
318
319implement {
320    name      = "addlinklistelement",
321    arguments = "string",
322    actions   = function(tag)
323                    local tobesaved   = tobesaved[tag] or { }
324                    local collected   = collected[tag] or { }
325                    local currentlink = #tobesaved + 1
326                    local noflinks    = #collected
327                    --
328                    tobesaved[currentlink] = 0 -- needs checking
329                    --
330                    local f = collected[1] or 0
331                    local l = collected[noflinks] or 0
332                    local p = collected[currentlink-1] or f
333                    local n = collected[currentlink+1] or l
334                    --
335                    context.setlinkedlistproperties(currentlink,noflinks,f,p,n,l)
336                 -- context.ctxlatelua(function() commands.enhancelinkedlist(tag,currentlink) end)
337                end
338}
339