mirror of
https://github.com/britzl/monarch.git
synced 2025-06-27 10:27:49 +02:00
Merge branch 'dev/agulev'
This commit is contained in:
commit
995843ff20
30
README.md
30
README.md
@ -84,6 +84,8 @@ You can add optional transitions when navigating between screens. The default be
|
||||
|
||||
When a transition is completed it is up to the developer to send a ```transition_done``` (constant ```monarch.TRANSITION.DONE```) message back to the sender to indicate that the transition is completed and that Monarch can continue the navigation sequence. Monarch comes with a system for setting up transitions easily in a gui_script. Example:
|
||||
|
||||
Monarch comes with a system for setting up transitions easily in a gui_script using the ```monarch.transitions.gui``` module. Example:
|
||||
|
||||
local transitions = require "monarch.transitions.gui"
|
||||
|
||||
function init(self)
|
||||
@ -101,6 +103,34 @@ When a transition is completed it is up to the developer to send a ```transition
|
||||
self.transition.handle(message_id, message, sender)
|
||||
end
|
||||
|
||||
### Predefined transitions
|
||||
The predefined transitions provided by ```monarch.transitions.gui``` are:
|
||||
|
||||
* ```slide_in_right```
|
||||
* ```slide_in_left```
|
||||
* ```slide_in_top```
|
||||
* ```slide_in_bottom```
|
||||
* ```slide_out_right```
|
||||
* ```slide_out_left```
|
||||
* ```slide_out_top```
|
||||
* ```slide_out_bottom```
|
||||
* ```scale_in```
|
||||
* ```scale_out```
|
||||
|
||||
### Custom transitions
|
||||
You can create and use your own transition as long as the provided transition function has the following function signature:
|
||||
|
||||
custom_transition(node, to, easing, duration, delay, cb)
|
||||
|
||||
**PARAMETERS**
|
||||
* ```node``` (node) - Gui node to animate.
|
||||
* ```to``` (vector3) - Target position.
|
||||
* ```easing``` (number) - One of gui.EASING_* constants.
|
||||
* ```duration``` (number) - Transition duration in seconds.
|
||||
* ```delay``` (number) - Transition delay in seconds.
|
||||
* ```cb``` (function) - This function must be called when the transition is completed.
|
||||
|
||||
|
||||
## Screen focus gain/loss
|
||||
Monarch will send focus gain and focus loss messages if a Focus Url was provided when the screen was created. The focus gained message will contain the id of the previous screen and the focus loss message will contain the id of the next screen. Example:
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
local monarch = require "monarch.monarch"
|
||||
|
||||
function init(self)
|
||||
monarch.debug()
|
||||
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
|
||||
end
|
||||
|
@ -26,6 +26,12 @@ M.FOCUS.GAINED = hash("monarch_focus_gained")
|
||||
M.FOCUS.LOST = hash("monarch_focus_lost")
|
||||
|
||||
|
||||
local function log(...) end
|
||||
|
||||
function M.debug()
|
||||
log = print
|
||||
end
|
||||
|
||||
local function screen_from_proxy(proxy)
|
||||
for _, screen in pairs(screens) do
|
||||
if screen.proxy == proxy then
|
||||
@ -101,29 +107,86 @@ function M.unregister(id)
|
||||
screens[id] = nil
|
||||
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)
|
||||
log("show_out()", screen.id)
|
||||
local co
|
||||
co = coroutine.create(function()
|
||||
screen.co = co
|
||||
msg.post(screen.script, RELEASE_INPUT_FOCUS)
|
||||
screen.input = false
|
||||
|
||||
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()
|
||||
change_context(screen)
|
||||
release_input(screen)
|
||||
focus_lost(screen, next_screen)
|
||||
-- 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
|
||||
local next_is_popup = next_screen and not next_screen.popup
|
||||
local current_is_popup = screen.popup
|
||||
if (next_is_popup and not current_is_popup) or (current_is_popup) then
|
||||
msg.post(screen.transition_url, M.TRANSITION.SHOW_OUT)
|
||||
coroutine.yield()
|
||||
msg.post(screen.proxy, UNLOAD)
|
||||
coroutine.yield()
|
||||
screen.loaded = false
|
||||
transition(screen, M.TRANSITION.SHOW_OUT)
|
||||
unload(screen)
|
||||
end
|
||||
screen.co = nil
|
||||
if cb then cb() end
|
||||
@ -132,39 +195,25 @@ local function show_out(screen, next_screen, cb)
|
||||
end
|
||||
|
||||
local function show_in(screen, previous_screen, reload, cb)
|
||||
log("show_in()", screen.id)
|
||||
local co
|
||||
co = coroutine.create(function()
|
||||
screen.co = co
|
||||
msg.post(screen.script, CONTEXT)
|
||||
coroutine.yield()
|
||||
|
||||
change_context(screen)
|
||||
if reload and screen.loaded then
|
||||
msg.post(screen.proxy, UNLOAD)
|
||||
coroutine.yield()
|
||||
screen.loaded = false
|
||||
log("show_in() reloading", screen.id)
|
||||
unload(screen)
|
||||
end
|
||||
|
||||
-- the screen could be loaded if the previous screen was a popup
|
||||
-- and the popup asked to show this screen again
|
||||
-- in that case we shouldn't attempt to load it again
|
||||
if not screen.loaded then
|
||||
msg.post(screen.proxy, ASYNC_LOAD)
|
||||
coroutine.yield()
|
||||
msg.post(screen.proxy, ENABLE)
|
||||
screen.loaded = true
|
||||
async_load(screen)
|
||||
end
|
||||
stack[#stack + 1] = screen
|
||||
msg.post(screen.transition_url, M.TRANSITION.SHOW_IN)
|
||||
coroutine.yield()
|
||||
|
||||
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
|
||||
transition(screen, M.TRANSITION.SHOW_IN)
|
||||
acquire_input(screen)
|
||||
focus_gained(screen, previous_screen)
|
||||
screen.co = nil
|
||||
if cb then cb() end
|
||||
end)
|
||||
@ -172,30 +221,19 @@ local function show_in(screen, previous_screen, reload, cb)
|
||||
end
|
||||
|
||||
local function back_in(screen, previous_screen, cb)
|
||||
log("back_in()", screen.id)
|
||||
local co
|
||||
co = coroutine.create(function()
|
||||
screen.co = co
|
||||
msg.post(screen.script, CONTEXT)
|
||||
coroutine.yield()
|
||||
change_context(screen)
|
||||
if not screen.loaded then
|
||||
msg.post(screen.proxy, ASYNC_LOAD)
|
||||
coroutine.yield()
|
||||
msg.post(screen.proxy, ENABLE)
|
||||
screen.loaded = true
|
||||
async_load(screen)
|
||||
end
|
||||
if previous_screen and not previous_screen.popup then
|
||||
msg.post(screen.transition_url, 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})
|
||||
transition(screen, M.TRANSITION.BACK_IN)
|
||||
end
|
||||
acquire_input(screen)
|
||||
focus_gained(screen, previous_screen)
|
||||
screen.co = nil
|
||||
if cb then cb() end
|
||||
end)
|
||||
@ -203,21 +241,15 @@ local function back_in(screen, previous_screen, cb)
|
||||
end
|
||||
|
||||
local function back_out(screen, next_screen, cb)
|
||||
log("back_out()", screen.id)
|
||||
local co
|
||||
co = coroutine.create(function()
|
||||
screen.co = co
|
||||
msg.post(screen.script, RELEASE_INPUT_FOCUS)
|
||||
screen.input = false
|
||||
if screen.focus_url then
|
||||
msg.post(screen.focus_url, M.FOCUS.LOST, {id = next_screen and next_screen.id})
|
||||
end
|
||||
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
|
||||
change_context(screen)
|
||||
release_input(screen)
|
||||
focus_lost(screen, next_screen)
|
||||
transition(screen, M.TRANSITION.BACK_OUT)
|
||||
unload(screen)
|
||||
screen.co = nil
|
||||
if cb then cb() end
|
||||
end)
|
||||
@ -256,6 +288,8 @@ function M.show(id, options, data, cb)
|
||||
local screen = screens[id]
|
||||
screen.data = data
|
||||
|
||||
log("show()", screen.id)
|
||||
|
||||
-- manipulate the current top
|
||||
-- close popup if needed
|
||||
-- transition out
|
||||
@ -279,6 +313,7 @@ function M.show(id, options, data, cb)
|
||||
-- to remove every screen on the stack up until and
|
||||
-- including the screen itself
|
||||
if options and options.clear then
|
||||
log("show() clearing")
|
||||
while M.in_stack(id) do
|
||||
table.remove(stack)
|
||||
end
|
||||
@ -295,6 +330,7 @@ end
|
||||
function M.back(data, cb)
|
||||
local screen = table.remove(stack)
|
||||
if screen then
|
||||
log("back()", screen.id)
|
||||
local top = stack[#stack]
|
||||
-- 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
|
||||
@ -324,19 +360,27 @@ function M.on_message(message_id, message, sender)
|
||||
if message_id == PROXY_LOADED then
|
||||
local screen = screen_from_proxy(sender)
|
||||
assert(screen, "Unable to find screen for loaded proxy")
|
||||
assert(coroutine.resume(screen.co))
|
||||
if screen.wait_for == PROXY_LOADED then
|
||||
assert(coroutine.resume(screen.co))
|
||||
end
|
||||
elseif message_id == PROXY_UNLOADED then
|
||||
local screen = screen_from_proxy(sender)
|
||||
assert(screen, "Unable to find screen for unloaded proxy")
|
||||
assert(coroutine.resume(screen.co))
|
||||
if screen.wait_for == PROXY_UNLOADED then
|
||||
assert(coroutine.resume(screen.co))
|
||||
end
|
||||
elseif message_id == CONTEXT then
|
||||
local screen = screen_from_script()
|
||||
assert(screen, "Unable to find screen for current script url")
|
||||
assert(coroutine.resume(screen.co))
|
||||
if screen.wait_for == CONTEXT then
|
||||
assert(coroutine.resume(screen.co))
|
||||
end
|
||||
elseif message_id == M.TRANSITION.DONE then
|
||||
local screen = screen_from_script()
|
||||
assert(screen, "Unable to find screen for current script url")
|
||||
assert(coroutine.resume(screen.co))
|
||||
if screen.wait_for == M.TRANSITION.DONE then
|
||||
assert(coroutine.resume(screen.co))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -12,71 +12,63 @@ local BOTTOM = vmath.vector3(0, - HEIGHT * 2, 0)
|
||||
|
||||
local ZERO_SCALE = vmath.vector3(0, 0, 1)
|
||||
|
||||
function M.instant(node, to, easing, duration, delay, url)
|
||||
msg.post(url, monarch.TRANSITION.DONE)
|
||||
function M.instant(node, to, easing, duration, delay, cb)
|
||||
cb()
|
||||
end
|
||||
|
||||
local function slide_in(direction, node, to, easing, duration, delay, url)
|
||||
local function slide_in(direction, node, to, easing, duration, delay, cb)
|
||||
local from = to + direction
|
||||
gui.set_position(node, from)
|
||||
gui.animate(node, gui.PROP_POSITION, to, easing, duration, delay, function()
|
||||
msg.post(url, monarch.TRANSITION.DONE)
|
||||
end)
|
||||
gui.animate(node, gui.PROP_POSITION, to, easing, duration, delay, cb)
|
||||
end
|
||||
|
||||
function M.slide_in_left(node, to, easing, duration, delay, url)
|
||||
return slide_in(LEFT, node, to.pos, easing, duration, delay, url)
|
||||
function M.slide_in_left(node, to, easing, duration, delay, cb)
|
||||
return slide_in(LEFT, node, to.pos, easing, duration, delay, cb)
|
||||
end
|
||||
|
||||
function M.slide_in_right(node, to, easing, duration, delay, url)
|
||||
slide_in(RIGHT, node, to.pos, easing, duration, delay, url)
|
||||
function M.slide_in_right(node, to, easing, duration, delay, cb)
|
||||
slide_in(RIGHT, node, to.pos, easing, duration, delay, cb)
|
||||
end
|
||||
|
||||
function M.slide_in_top(node, to, easing, duration, delay, url)
|
||||
slide_in(TOP, node, to.pos, easing, duration, delay, url)
|
||||
function M.slide_in_top(node, to, easing, duration, delay, cb)
|
||||
slide_in(TOP, node, to.pos, easing, duration, delay, cb)
|
||||
end
|
||||
|
||||
function M.slide_in_bottom(node, to, easing, duration, delay, url)
|
||||
slide_in(BOTTOM, node, to.pos, easing, duration, delay, url)
|
||||
function M.slide_in_bottom(node, to, easing, duration, delay, cb)
|
||||
slide_in(BOTTOM, node, to.pos, easing, duration, delay, cb)
|
||||
end
|
||||
|
||||
|
||||
local function slide_out(direction, node, from, easing, duration, delay, url)
|
||||
local function slide_out(direction, node, from, easing, duration, delay, cb)
|
||||
local to = from + direction
|
||||
gui.set_position(node, from)
|
||||
gui.animate(node, gui.PROP_POSITION, to, easing, duration, delay, function()
|
||||
msg.post(url, monarch.TRANSITION.DONE)
|
||||
end)
|
||||
gui.animate(node, gui.PROP_POSITION, to, easing, duration, delay, cb)
|
||||
end
|
||||
|
||||
function M.slide_out_left(node, from, easing, duration, delay, url)
|
||||
slide_out(LEFT, node, from.pos, easing, duration, delay, url)
|
||||
function M.slide_out_left(node, from, easing, duration, delay, cb)
|
||||
slide_out(LEFT, node, from.pos, easing, duration, delay, cb)
|
||||
end
|
||||
|
||||
function M.slide_out_right(node, from, easing, duration, delay, url)
|
||||
slide_out(RIGHT, node, from.pos, easing, duration, delay, url)
|
||||
function M.slide_out_right(node, from, easing, duration, delay, cb)
|
||||
slide_out(RIGHT, node, from.pos, easing, duration, delay, cb)
|
||||
end
|
||||
|
||||
function M.slide_out_top(node, from, easing, duration, delay, url)
|
||||
slide_out(TOP, node, from.pos, easing, duration, delay, url)
|
||||
function M.slide_out_top(node, from, easing, duration, delay, cb)
|
||||
slide_out(TOP, node, from.pos, easing, duration, delay, cb)
|
||||
end
|
||||
|
||||
function M.slide_out_bottom(node, from, easing, duration, delay, url)
|
||||
slide_out(BOTTOM, node, from.pos, easing, duration, delay, url)
|
||||
function M.slide_out_bottom(node, from, easing, duration, delay, cb)
|
||||
slide_out(BOTTOM, node, from.pos, easing, duration, delay, cb)
|
||||
end
|
||||
|
||||
function M.scale_in(node, to, easing, duration, delay, url)
|
||||
function M.scale_in(node, to, easing, duration, delay, cb)
|
||||
gui.set_scale(node, ZERO_SCALE)
|
||||
gui.animate(node, gui.PROP_SCALE, to.scale, easing, duration, delay, function()
|
||||
msg.post(url, monarch.TRANSITION.DONE)
|
||||
end)
|
||||
gui.animate(node, gui.PROP_SCALE, to.scale, easing, duration, delay, cb)
|
||||
end
|
||||
|
||||
function M.scale_out(node, from, easing, duration, delay, url)
|
||||
function M.scale_out(node, from, easing, duration, delay, cb)
|
||||
gui.set_scale(node, from.scale)
|
||||
gui.animate(node, gui.PROP_SCALE, ZERO_SCALE, easing, duration, delay, function()
|
||||
msg.post(url, monarch.TRANSITION.DONE)
|
||||
end)
|
||||
gui.animate(node, gui.PROP_SCALE, ZERO_SCALE, easing, duration, delay, cb)
|
||||
end
|
||||
|
||||
--- Create a transition for a node
|
||||
@ -86,24 +78,45 @@ function M.create(node)
|
||||
|
||||
local instance = {}
|
||||
|
||||
local transitions = {
|
||||
[monarch.TRANSITION.SHOW_IN] = M.instant,
|
||||
[monarch.TRANSITION.SHOW_OUT] = M.instant,
|
||||
[monarch.TRANSITION.BACK_IN] = M.instant,
|
||||
[monarch.TRANSITION.BACK_OUT] = M.instant,
|
||||
}
|
||||
local transitions = {}
|
||||
|
||||
local initial_data = {}
|
||||
initial_data.pos = gui.get_position(node)
|
||||
initial_data.scale = gui.get_scale(node)
|
||||
|
||||
-- Forward on_message calls here
|
||||
function instance.handle(message_id, message, sender)
|
||||
if transitions[message_id] then
|
||||
transitions[message_id](sender)
|
||||
local function create_transition(fn, easing, duration, delay)
|
||||
return {
|
||||
fn = fn,
|
||||
easing = easing,
|
||||
duration = duration,
|
||||
delay = delay,
|
||||
in_progress = false,
|
||||
urls = {},
|
||||
}
|
||||
end
|
||||
|
||||
local function start_transition(transition, url)
|
||||
table.insert(transition.urls, url)
|
||||
if not transition.in_progress then
|
||||
transition.in_progress = true
|
||||
transition.fn(node, initial_data, transition.easing, transition.duration, transition.delay or 0, function()
|
||||
transition.in_progress = false
|
||||
while #transition.urls > 0 do
|
||||
local url = table.remove(transition.urls)
|
||||
msg.post(url, monarch.TRANSITION.DONE)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- Forward on_message calls here
|
||||
function instance.handle(message_id, message, sender)
|
||||
local transition = transitions[message_id]
|
||||
if transition then
|
||||
start_transition(transition, sender)
|
||||
end
|
||||
end
|
||||
|
||||
-- Specify the transition function when this node is transitioned
|
||||
-- to
|
||||
-- @param fn Transition function (see slide_in_left and other above)
|
||||
@ -111,39 +124,37 @@ function M.create(node)
|
||||
-- @param duration Transition duration
|
||||
-- @param delay Transition delay
|
||||
function instance.show_in(fn, easing, duration, delay)
|
||||
transitions[monarch.TRANSITION.SHOW_IN] = function(url)
|
||||
fn(node, initial_data, easing, duration, delay or 0, url)
|
||||
end
|
||||
transitions[monarch.TRANSITION.SHOW_IN] = create_transition(fn, easing, duration, delay)
|
||||
return instance
|
||||
end
|
||||
|
||||
-- Specify the transition function when this node is transitioned
|
||||
-- from when showing another screen
|
||||
function instance.show_out(fn, easing, duration, delay)
|
||||
transitions[monarch.TRANSITION.SHOW_OUT] = function(url)
|
||||
fn(node, initial_data, easing, duration, delay or 0, url)
|
||||
end
|
||||
transitions[monarch.TRANSITION.SHOW_OUT] = create_transition(fn, easing, duration, delay)
|
||||
return instance
|
||||
end
|
||||
|
||||
--- Specify the transition function when this node is transitioned
|
||||
-- to when navigating back in the screen stack
|
||||
function instance.back_in(fn, easing, duration, delay)
|
||||
transitions[monarch.TRANSITION.BACK_IN] = function(url)
|
||||
fn(node, initial_data, easing, duration, delay or 0, url)
|
||||
end
|
||||
transitions[monarch.TRANSITION.BACK_IN] = create_transition(fn, easing, duration, delay)
|
||||
return instance
|
||||
end
|
||||
|
||||
--- Specify the transition function when this node is transitioned
|
||||
-- from when navigating back in the screen stack
|
||||
function instance.back_out(fn, easing, duration, delay)
|
||||
transitions[monarch.TRANSITION.BACK_OUT] = function(url)
|
||||
fn(node, initial_data, easing, duration, delay or 0, url)
|
||||
end
|
||||
transitions[monarch.TRANSITION.BACK_OUT] = create_transition(fn, easing, duration, delay)
|
||||
return instance
|
||||
end
|
||||
|
||||
-- set default transitions (instant)
|
||||
instance.show_in(M.instant)
|
||||
instance.show_out(M.instant)
|
||||
instance.back_in(M.instant)
|
||||
instance.back_out(M.instant)
|
||||
|
||||
return instance
|
||||
end
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user