
#! lua
local sys, !, $, dim in riscos
@ = require "wimp.toolbox"
-------------- drawfile stuff ---------------
local Drawfile_Load = \ (fpath)
local r0,r1,r2,r3,r4 = sys (8, 17, fpath) -- OS_File
if r0 ~= 1 then => nil,fpath.." not a file" end -- if
local buf = dim (r4)
sys (8, 16, fpath, buf, 0) -- load file into b
=> buf, r4
end
local Drawfile_Render = \ (buf, buf_size)
=> \ (@, x, y)
local b in @
local u, v = 1<<16, 1<<8
![b + 256] = u
![b + 260] = 0
![b + 264] = 0
![b + 268] = u
![b + 272] = v*x
![b + 276] = v*y
sys (0x45540, 0, buf, buf_size, b + 256, b + 28) -- DrawFile_Render
end end
-----------------------------------------------
local page = dofile "codex:index"
local cache = { } -- storing loaded Drawfile data
local where = "codex:%s"
local getfile = \ (n) => where:format (page[n]) end
local getpage = \ (n)
local data = cache[n]
if data then => data.buf, data.bufsize end -- if
local b, bs = Drawfile_Load (getfile (n))
cache[n] = { buf = b, bufsize = bs }
=> b, bs
end
_ENV = @
handler[1] = \ (@) -- Wimp_RedrawWindow
local Drawfile_Redraw = Drawfile_Render (getpage (@.pageno))
=> @:user_redraw (Drawfile_Redraw) end
handler.tbox[0xa0] = \ (@) -- Select clicked on iconbar
local self_id, parent_id, parent_comp in @.obj.codex_win
if 1 & (@:GetObjectState (0, self_id)) == 1 then
if pageno < #page then pageno + = 1 end -- if
@:winredraw (self_id)
else
pageno = 1
@:Show_Object (0, self_id, 0, 0, parent_id, parent_comp)
end -- if
end
handler.tbox[0xa1] = \ (@) -- Adjust clicked on iconbar
local self_id, parent_id, parent_comp in @.obj.codex_win
if 1 & (@:GetObjectState (0, self_id)) == 1 then
if pageno > 1 then pageno - = 1 end -- if
@:winredraw (self_id)
else
pageno = #page
@:Show_Object (0, self_id, 0, 0, parent_id, parent_comp)
end -- if
end
handler.tbox[0xa2] = \ (@) -- Help on iconbar menu
local b in @
$[b] = "filer_run codex:!Help\0"
sys (0x400de, b) -- Wimp_StartTask
end
$[resdir] = arg[1] -- Tell the toolbox where to find res
init (@, { }, { }) -- All wimp, all toolbox events signify.
mask = 257 -- No null or kbd events
run (@) -- This has to be last.The third line loads the library wimp.toolbox and calls it @. Lua libraries are tables. The keys in the
table name values that are made available to programs that
require the library, hiding the implementation details. As
yet the toolbox library does not export any Drawfile stuff,
so the program has to define it itself. The next section defines
two functions: Drawfile_Load and Drawfile_Render. Drawfile_Load uses OS_File to
find the size of the file at the given path, reserve an appropriately
sized buffer, load the file into the buffer, and return the address of the buffer and its size. Drawfile_Render takes a pointer to a buffer, and
its size, as arguments, and returns a function. The function's
first argument is a wimp task, its second and third the coordinates of
where the Drawfile is to be rendered. It stores the appropriate affine
transformation in the message buffer b of its first argument,
then calls the SWI Drawfile_Render. This perhaps calls
for an explanatory interlude about how RiscLua sees wimp tasks.A wimp task is a coroutine of the taskmanager. When it calls Wimp_Poll or Wimp_PollIdle the thread of execution passes out of its control to the taskmanager, and returns when those SWIs return. Information is conveyed between the two processes in CPU registers and the message buffer. The SWI Wimp_Init registers the program with the taskmanager, telling it where the message buffer is and so forth. The RiscLua library wimp.task spawns wimp tasks as copies of itself. Two special methods stand out: init which registers the wimp task with the taskmanager, and run which sets it going. The core of the latter is a loop:
local run = \ (self, idle)
local poll <const> = idle and 0x400e1 or 0x400c7
local b, handler, preclosedown in self
local reason, quit, action, err
local when = ((not idle) and 0) or self.time or 100
while not (quit or err) do
reason = sys (poll, self.mask or 0, b, when)
action = handler[reason]
quit, err = action and action (self)
if err then
self:report (err)
quit = true
end -- if
end -- while
self:closedown ( )
end
Wimp tasks come with an array of functions, handler, indexed by the codes returned by the taskmanager, which determine
how the wimp task reacts when control returns to it. I find it convenient
to adopt the convention that handlers only return a non-nil value
in order to signal that the wimp task should close down. This means
that if a handler is not defined for some circumstance, that does not
shut the wimp task down. Another array of handlers handler.mesg
responds to messages. The wimp.toolbox library
extends the wimp.task library with an array handler.tbox of
responders to toolbox events.Recall that I used three numbers, &a0, &a1 and &a2 in setting up the Resource file. These appear above in the definitions of handler.tbox[0xa0], handler.tbox[0xa1] and handler.tbox[0xa2] which deal respectively with clicks of Select on the iconbar icon, Adjust on the iconbar icon and either on the Help option in the iconbar menu. There is one more handler definition, for handler[1] -- Wimp_RedrawWindow.
The statement
_ENV = @is worth explaining. This makes the table @, our wimp task, the global environment. So that any variable not previously declared as local, is looked up from, or written to, @. This is a syntactic trick making for more readable code. Without it the last four lines would read
$[@.resdir] = arg[1]
@:init ({ }, { })
@.mask = 257
@:run ( )Note how the Drawfile data is cached. Once a Drawfile has been loaded
there is no point in it being loaded again.