3
0
mirror of https://github.com/britzl/monarch.git synced 2025-06-27 10:27:49 +02:00

Improved on the state handling while showing/hiding screens

Also added simple debug logging
This commit is contained in:
Björn Ritzl 2017-12-07 20:49:48 +01:00
parent 6caa41e9f6
commit 007a4eced3
2 changed files with 111 additions and 69 deletions

View File

@ -1,6 +1,7 @@
local monarch = require "monarch.monarch" local monarch = require "monarch.monarch"
function init(self) function init(self)
monarch.debug()
msg.post("@render:/", "clear_color", { color = vmath.vector4(0.4, 0.6, 0.8,1.0) }) msg.post("@render:/", "clear_color", { color = vmath.vector4(0.4, 0.6, 0.8,1.0) })
msg.post("#", "init_monarch") -- wait until init() has been called for all screen.script instances msg.post("#", "init_monarch") -- wait until init() has been called for all screen.script instances
end end

View File

@ -26,6 +26,12 @@ M.FOCUS.GAINED = hash("monarch_focus_gained")
M.FOCUS.LOST = hash("monarch_focus_lost") M.FOCUS.LOST = hash("monarch_focus_lost")
local function log(...) end
function M.debug()
log = print
end
local function screen_from_proxy(proxy) local function screen_from_proxy(proxy)
for _, screen in pairs(screens) do for _, screen in pairs(screens) do
if screen.proxy == proxy then if screen.proxy == proxy then
@ -101,29 +107,85 @@ function M.unregister(id)
screens[id] = nil screens[id] = nil
end end
local function acquire_input(screen)
log("change_context()", screen.id)
if not screen.input then
msg.post(screen.script, ACQUIRE_INPUT_FOCUS)
screen.input = true
end
end
local function release_input(screen)
log("change_context()", screen.id)
if screen.input then
msg.post(screen.script, RELEASE_INPUT_FOCUS)
screen.input = false
end
end
local function change_context(screen)
log("change_context()", screen.id)
screen.wait_for = CONTEXT
msg.post(screen.script, CONTEXT)
coroutine.yield()
screen.wait_for = nil
end
local function unload(screen)
log("unload()", screen.id)
screen.wait_for = PROXY_UNLOADED
msg.post(screen.proxy, UNLOAD)
coroutine.yield()
screen.loaded = false
screen.wait_for = nil
end
local function async_load(screen)
log("async_load()", screen.id)
screen.wait_for = PROXY_LOADED
msg.post(screen.proxy, ASYNC_LOAD)
coroutine.yield()
msg.post(screen.proxy, ENABLE)
screen.loaded = true
screen.wait_for = nil
end
local function transition(screen, message_id)
log("transition()", screen.id)
screen.wait_for = M.TRANSITION.DONE
msg.post(screen.transition_url, message_id)
coroutine.yield()
screen.wait_for = nil
end
local function focus_gained(screen, previous_screen)
log("focus_gained()", screen.id)
if screen.focus_url then
msg.post(screen.focus_url, M.FOCUS.GAINED, {id = previous_screen and previous_screen.id})
end
end
local function focus_lost(screen, next_screen)
log("focus_lost()", screen.id)
if screen.focus_url then
msg.post(screen.focus_url, M.FOCUS.LOST, {id = next_screen and next_screen.id})
end
end
local function show_out(screen, next_screen, cb) local function show_out(screen, next_screen, cb)
local co local co
co = coroutine.create(function() co = coroutine.create(function()
screen.co = co screen.co = co
msg.post(screen.script, RELEASE_INPUT_FOCUS) change_context(screen)
screen.input = false release_input(screen)
focus_lost(screen, next_screen)
if screen.focus_url then
msg.post(screen.focus_url, M.FOCUS.LOST, {id = next_screen.id})
end
msg.post(screen.script, CONTEXT)
coroutine.yield()
-- if the next screen is a popup we want the current screen to stay visible below the popup -- if the next screen is a popup we want the current screen to stay visible below the popup
-- if the next screen isn't a popup the current one should be unloaded and transitioned out -- if the next screen isn't a popup the current one should be unloaded and transitioned out
local next_is_popup = next_screen and not next_screen.popup local next_is_popup = next_screen and not next_screen.popup
local current_is_popup = screen.popup local current_is_popup = screen.popup
if (next_is_popup and not current_is_popup) or (current_is_popup) then if (next_is_popup and not current_is_popup) or (current_is_popup) then
msg.post(screen.transition_url, M.TRANSITION.SHOW_OUT) transition(screen, M.TRANSITION.SHOW_OUT)
coroutine.yield() unload(screen)
msg.post(screen.proxy, UNLOAD)
coroutine.yield()
screen.loaded = false
end end
screen.co = nil screen.co = nil
if cb then cb() end if cb then cb() end
@ -132,39 +194,25 @@ local function show_out(screen, next_screen, cb)
end end
local function show_in(screen, previous_screen, reload, cb) local function show_in(screen, previous_screen, reload, cb)
log("show_in()", screen.id)
local co local co
co = coroutine.create(function() co = coroutine.create(function()
screen.co = co screen.co = co
msg.post(screen.script, CONTEXT) change_context(screen)
coroutine.yield()
if reload and screen.loaded then if reload and screen.loaded then
msg.post(screen.proxy, UNLOAD) log("show_in() reloading", screen.id)
coroutine.yield() unload(screen)
screen.loaded = false
end end
-- the screen could be loaded if the previous screen was a popup -- the screen could be loaded if the previous screen was a popup
-- and the popup asked to show this screen again -- and the popup asked to show this screen again
-- in that case we shouldn't attempt to load it again -- in that case we shouldn't attempt to load it again
if not screen.loaded then if not screen.loaded then
msg.post(screen.proxy, ASYNC_LOAD) async_load(screen)
coroutine.yield()
msg.post(screen.proxy, ENABLE)
screen.loaded = true
end end
stack[#stack + 1] = screen stack[#stack + 1] = screen
msg.post(screen.transition_url, M.TRANSITION.SHOW_IN) transition(screen, M.TRANSITION.SHOW_IN)
coroutine.yield() acquire_input(screen)
focus_gained(screen, previous_screen)
if not screen.input then
msg.post(screen.script, ACQUIRE_INPUT_FOCUS)
screen.input = true
end
if screen.focus_url then
msg.post(screen.focus_url, M.FOCUS.GAINED, {id = previous_screen and previous_screen.id})
end
screen.co = nil screen.co = nil
if cb then cb() end if cb then cb() end
end) end)
@ -175,27 +223,15 @@ local function back_in(screen, previous_screen, cb)
local co local co
co = coroutine.create(function() co = coroutine.create(function()
screen.co = co screen.co = co
msg.post(screen.script, CONTEXT) change_context(screen)
coroutine.yield()
if not screen.loaded then if not screen.loaded then
msg.post(screen.proxy, ASYNC_LOAD) async_load(screen)
coroutine.yield()
msg.post(screen.proxy, ENABLE)
screen.loaded = true
end end
if previous_screen and not previous_screen.popup then if previous_screen and not previous_screen.popup then
msg.post(screen.transition_url, M.TRANSITION.BACK_IN) transition(screen, M.TRANSITION.BACK_IN)
coroutine.yield()
end
if not screen.input then
msg.post(screen.script, ACQUIRE_INPUT_FOCUS)
screen.input = true
end
if screen.focus_url then
msg.post(screen.focus_url, M.FOCUS.GAINED, {id = previous_screen.id})
end end
acquire_input(screen)
focus_gained(screen, previous_screen)
screen.co = nil screen.co = nil
if cb then cb() end if cb then cb() end
end) end)
@ -206,18 +242,11 @@ local function back_out(screen, next_screen, cb)
local co local co
co = coroutine.create(function() co = coroutine.create(function()
screen.co = co screen.co = co
msg.post(screen.script, RELEASE_INPUT_FOCUS) change_context(screen)
screen.input = false release_input(screen)
if screen.focus_url then focus_lost(screen, next_screen)
msg.post(screen.focus_url, M.FOCUS.LOST, {id = next_screen and next_screen.id}) transition(screen, M.TRANSITION.BACK_OUT)
end unload(screen)
msg.post(screen.script, CONTEXT)
coroutine.yield()
msg.post(screen.transition_url, M.TRANSITION.BACK_OUT)
coroutine.yield()
msg.post(screen.proxy, UNLOAD)
coroutine.yield()
screen.loaded = false
screen.co = nil screen.co = nil
if cb then cb() end if cb then cb() end
end) end)
@ -256,6 +285,8 @@ function M.show(id, options, data, cb)
local screen = screens[id] local screen = screens[id]
screen.data = data screen.data = data
log("show()", screen.id)
-- manipulate the current top -- manipulate the current top
-- close popup if needed -- close popup if needed
-- transition out -- transition out
@ -279,6 +310,7 @@ function M.show(id, options, data, cb)
-- to remove every screen on the stack up until and -- to remove every screen on the stack up until and
-- including the screen itself -- including the screen itself
if options and options.clear then if options and options.clear then
log("show() clearing")
while M.in_stack(id) do while M.in_stack(id) do
table.remove(stack) table.remove(stack)
end end
@ -295,6 +327,7 @@ end
function M.back(data, cb) function M.back(data, cb)
local screen = table.remove(stack) local screen = table.remove(stack)
if screen then if screen then
log("back()", screen.id)
local top = stack[#stack] local top = stack[#stack]
-- if we go back to the same screen we need to first hide it -- if we go back to the same screen we need to first hide it
-- and wait until it is hidden before we show it again -- and wait until it is hidden before we show it again
@ -324,21 +357,29 @@ function M.on_message(message_id, message, sender)
if message_id == PROXY_LOADED then if message_id == PROXY_LOADED then
local screen = screen_from_proxy(sender) local screen = screen_from_proxy(sender)
assert(screen, "Unable to find screen for loaded proxy") assert(screen, "Unable to find screen for loaded proxy")
if screen.wait_for == PROXY_LOADED then
assert(coroutine.resume(screen.co)) assert(coroutine.resume(screen.co))
end
elseif message_id == PROXY_UNLOADED then elseif message_id == PROXY_UNLOADED then
local screen = screen_from_proxy(sender) local screen = screen_from_proxy(sender)
assert(screen, "Unable to find screen for unloaded proxy") assert(screen, "Unable to find screen for unloaded proxy")
if screen.wait_for == PROXY_UNLOADED then
assert(coroutine.resume(screen.co)) assert(coroutine.resume(screen.co))
end
elseif message_id == CONTEXT then elseif message_id == CONTEXT then
local screen = screen_from_script() local screen = screen_from_script()
assert(screen, "Unable to find screen for current script url") assert(screen, "Unable to find screen for current script url")
if screen.wait_for == CONTEXT then
assert(coroutine.resume(screen.co)) assert(coroutine.resume(screen.co))
end
elseif message_id == M.TRANSITION.DONE then elseif message_id == M.TRANSITION.DONE then
local screen = screen_from_script() local screen = screen_from_script()
assert(screen, "Unable to find screen for current script url") assert(screen, "Unable to find screen for current script url")
if screen.wait_for == M.TRANSITION.DONE then
assert(coroutine.resume(screen.co)) assert(coroutine.resume(screen.co))
end end
end end
end
--- Get a list of ids for the current screen stack --- Get a list of ids for the current screen stack
-- (primarily used for unit testing, but could have uses outside testing) -- (primarily used for unit testing, but could have uses outside testing)