Add a module that wraps the dialogs as "blocking" coroutine functions.
parent
abf503fcdc
commit
bd3d3061ae
@ -0,0 +1,151 @@
|
||||
-- Support for scripted interaction sequences via coroutines.
|
||||
|
||||
local _ENV = mkmodule('gui.script')
|
||||
|
||||
local dlg = require('gui.dialogs')
|
||||
|
||||
--[[
|
||||
Example:
|
||||
|
||||
start(function()
|
||||
sleep(100, 'frames')
|
||||
print(showYesNoPrompt('test', 'print true?'))
|
||||
end)
|
||||
]]
|
||||
|
||||
-- Table of running background scripts.
|
||||
if not scripts then
|
||||
scripts = {}
|
||||
setmetatable(scripts, { __mode = 'k' })
|
||||
end
|
||||
|
||||
local function do_resume(inst, ...)
|
||||
inst.gen = inst.gen + 1
|
||||
return (dfhack.saferesume(inst.coro, ...))
|
||||
end
|
||||
|
||||
-- Starts a new background script by calling the function.
|
||||
function start(fn,...)
|
||||
local coro = coroutine.create(fn)
|
||||
local inst = {
|
||||
coro = coro,
|
||||
gen = 0,
|
||||
}
|
||||
scripts[coro] = inst
|
||||
return do_resume(inst, ...)
|
||||
end
|
||||
|
||||
-- Checks if called from a background script
|
||||
function in_script()
|
||||
return scripts[coroutine.running()] ~= nil
|
||||
end
|
||||
|
||||
local function getinst()
|
||||
local inst = scripts[coroutine.running()]
|
||||
if not inst then
|
||||
error('Not in a gui script coroutine.')
|
||||
end
|
||||
return inst
|
||||
end
|
||||
|
||||
local function invoke_resume(inst,gen,quiet,...)
|
||||
local state = coroutine.status(inst.coro)
|
||||
if state ~= 'suspended' then
|
||||
if state ~= 'dead' then
|
||||
dfhack.printerr(debug.traceback('resuming a non-waiting continuation'))
|
||||
end
|
||||
elseif inst.gen > gen then
|
||||
if not quiet then
|
||||
dfhack.printerr(debug.traceback('resuming an expired continuation'))
|
||||
end
|
||||
else
|
||||
do_resume(inst, ...)
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns a callback that resumes the script from wait with given return values
|
||||
function mkresume(...)
|
||||
local inst = getinst()
|
||||
return curry(invoke_resume, inst, inst.gen, false, ...)
|
||||
end
|
||||
|
||||
-- Like mkresume, but does not complain if already resumed from this wait
|
||||
function qresume(...)
|
||||
local inst = getinst()
|
||||
return curry(invoke_resume, inst, inst.gen, true, ...)
|
||||
end
|
||||
|
||||
-- Wait until a mkresume callback is called, then return its arguments.
|
||||
-- Once it returns, all mkresume callbacks created before are invalidated.
|
||||
function wait()
|
||||
getinst() -- check that the context is right
|
||||
return coroutine.yield()
|
||||
end
|
||||
|
||||
-- Wraps dfhack.timeout for coroutines.
|
||||
function sleep(time, quantity)
|
||||
if dfhack.timeout(time, quantity, mkresume()) then
|
||||
wait()
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- Some dialog wrappers:
|
||||
|
||||
function showMessage(title, text, tcolor)
|
||||
dlg.MessageBox{
|
||||
frame_title = title,
|
||||
text = text,
|
||||
text_pen = tcolor,
|
||||
on_close = qresume(nil)
|
||||
}:show()
|
||||
|
||||
return wait()
|
||||
end
|
||||
|
||||
function showYesNoPrompt(title, text, tcolor)
|
||||
dlg.MessageBox{
|
||||
frame_title = title,
|
||||
text = text,
|
||||
text_pen = tcolor,
|
||||
on_accept = mkresume(true),
|
||||
on_cancel = mkresume(false),
|
||||
on_close = qresume(nil)
|
||||
}:show()
|
||||
|
||||
return wait()
|
||||
end
|
||||
|
||||
function showInputPrompt(title, text, tcolor, input, min_width)
|
||||
dlg.InputBox{
|
||||
frame_title = title,
|
||||
text = text,
|
||||
text_pen = tcolor,
|
||||
input = input,
|
||||
frame_width = min_width,
|
||||
on_input = mkresume(true),
|
||||
on_cancel = mkresume(false),
|
||||
on_close = qresume(nil)
|
||||
}:show()
|
||||
|
||||
return wait()
|
||||
end
|
||||
|
||||
function showListPrompt(title, text, tcolor, choices, min_width)
|
||||
dlg.ListBox{
|
||||
frame_title = title,
|
||||
text = text,
|
||||
text_pen = tcolor,
|
||||
choices = choices,
|
||||
frame_width = min_width,
|
||||
on_select = mkresume(true),
|
||||
on_cancel = mkresume(false),
|
||||
on_close = qresume(nil)
|
||||
}:show()
|
||||
|
||||
return wait()
|
||||
end
|
||||
|
||||
return _ENV
|
Loading…
Reference in New Issue