3
0
mirror of https://github.com/britzl/monarch.git synced 2025-06-27 02:17:53 +02:00
2017-09-04 12:01:57 +02:00

198 lines
4.7 KiB
Lua

local M = {}
local screens = {}
local stack = {}
local function screen_from_proxy(proxy)
for id,screen in pairs(screens) do
if screen.proxy == proxy then
return screen
end
end
end
local function screen_from_script()
local url = msg.url()
for id,screen in pairs(screens) do
if screen.script == url then
return screen
end
end
end
local function in_stack(id)
for i=1,#stack do
if stack[i].id == id then
return true
end
end
return false
end
function M.register(id, proxy, popup, transitions)
assert(not screens[id], ("There is already a screen registered with id %s"):format(tostring(id)))
screens[id] = { id = id, proxy = proxy, script = msg.url(), popup = popup, transitions = transitions }
end
function M.unregister(id)
assert(screens[id], ("There is no screen registered with id %s"):format(tostring(id)))
screens[id] = nil
end
local function show_out(screen, next_screen)
local co
co = coroutine.create(function()
screen.co = co
msg.post(screen.script, "release_input_focus")
msg.post(screen.script, "monarch_context")
coroutine.yield()
if not next_screen.popup then
msg.post(screen.transitions.show_out, "transition_show_out")
coroutine.yield()
msg.post(screen.proxy, "unload")
coroutine.yield()
end
screen.co = nil
end)
coroutine.resume(co)
end
local function show_in(screen)
local co
co = coroutine.create(function()
screen.co = co
msg.post(screen.script, "monarch_context")
coroutine.yield()
msg.post(screen.proxy, "async_load")
coroutine.yield()
msg.post(screen.proxy, "enable")
stack[#stack + 1] = screen
msg.post(screen.transitions.show_in, "transition_show_in")
coroutine.yield()
msg.post(screen.script, "acquire_input_focus")
screen.co = nil
end)
coroutine.resume(co)
end
local function back_in(screen, previous_screen)
local co
co = coroutine.create(function()
screen.co = co
msg.post(screen.script, "monarch_context")
coroutine.yield()
if not previous_screen.popup then
msg.post(screen.proxy, "async_load")
coroutine.yield()
msg.post(screen.proxy, "enable")
msg.post(screen.transitions.back_in, "transition_back_in")
coroutine.yield()
end
msg.post(screen.script, "acquire_input_focus")
screen.co = nil
end)
coroutine.resume(co)
end
local function back_out(screen)
local co
co = coroutine.create(function()
screen.co = co
msg.post(screen.script, "monarch_context")
coroutine.yield()
msg.post(screen.transitions.back_out, "transition_back_out")
coroutine.yield()
msg.post(screen.proxy, "unload")
screen.co = nil
end)
coroutine.resume(co)
end
--- Show a new screen
-- @param id Id of the screen to show
-- @param clear Set to true if the stack should be cleared down to an existing instance of the screen. Optional
function M.show(id, clear)
assert(id, "You must provide a screen id")
assert(screens[id], ("There is no screen registered with id %s"):format(tostring(id)))
local screen = screens[id]
-- manipulate the current top
-- close popup if needed
-- transition out
local top = stack[#stack]
if top then
-- if top is popup then close it
if top.popup then
stack[#stack] = nil
show_out(top, screen)
top = stack[#stack]
end
-- unload and transition out from top
if top then
show_out(top, screen)
end
end
-- if the screen we want to show is in the stack
-- already and the clear flag is set then we need
-- to remove every screen on the stack up until and
-- including the screen itself
if clear and in_stack(id) then
while true do
if table.remove(stack).id == id then
break
end
end
end
-- show screen
show_in(screen)
end
-- Go back to the previous screen in the stack
function M.back()
local screen = table.remove(stack)
if screen then
back_out(screen)
local top = stack[#stack]
if top then
back_in(top, screen)
end
end
end
function M.on_message(message_id, message, sender)
if message_id == hash("proxy_loaded") then
local screen = screen_from_proxy(sender)
assert(screen, "Unable to find screen for loaded proxy")
coroutine.resume(screen.co)
elseif message_id == hash("proxy_unloaded") then
local screen = screen_from_proxy(sender)
assert(screen, "Unable to find screen for unloaded proxy")
elseif message_id == hash("monarch_context") then
local screen = screen_from_script()
assert(screen, "Unable to find screen for current script url")
coroutine.resume(screen.co)
elseif message_id == hash("transition_done") then
local screen = screen_from_script()
assert(screen, "Unable to find screen for current script url")
coroutine.resume(screen.co)
end
end
function M.dump_stack()
local s = ""
for i,screen in ipairs(stack) do
s = s .. ("%d = %s\n"):format(i, tostring(screen.id))
end
return s
end
return M