3
0
mirror of https://github.com/britzl/monarch.git synced 2025-11-26 19:00:53 +01:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Björn Ritzl
1314b43633 monarch.back_to() test 2021-06-28 01:04:23 +02:00
13 changed files with 633 additions and 185 deletions

60
CHANGELOG.md Normal file
View File

@@ -0,0 +1,60 @@
## Monarch 2.8.0 [britzl released 2018-06-10]
NEW: Prevent show/hide operations while busy showing/hiding another screen
FIX: Make sure to properly finish active transitions when layout changes
## Monarch 2.7.0 [britzl released 2018-06-04]
NEW: Added monarch.top([offset]) and monarch.bottom([offset]) to get screen id of top and bottom screens (w. optional offset)
NEW: Transition messages now contain `next_screen` or `previous_screen`
## Monarch 2.6.1 [britzl released 2018-06-04]
FIX: Check if screen has already been preloaded before trying to preload it again (the callback will still be invoked).
## Monarch 2.6.0 [britzl released 2018-06-03]
NEW: monarch.preload() to load but not show a screen. Useful for content heavy screens that you wish to show without delay.
## Monarch 2.5.0 [britzl released 2018-06-01]
NEW: Transitions will send a `transition_done` message to the creator of the transition to notify that the transition has finished. The `message` will contain which transition that was finished.
## Monarch 2.4.0 [britzl released 2018-05-26]
NEW: Screen transitions are remembered so that they can be replayed when the screen layout changes.
## Monarch 2.3.0 [britzl released 2018-03-24]
CHANGE: The functions in monarch.lua that previously only accepted a hash as screen id now also accepts strings (and does the conversion internally)
## Monarch 2.2.0 [britzl released 2018-03-19]
NEW: Transitions now handle layout changes (via `layout_changed` message)
NEW: Transitions can now be notified of changes in window size using transition.window_resize(width, height)
## Monarch 2.1 [britzl released 2017-12-27]
NEW: Added Popup on Popup flag that allows a popup to be shown on top of another popup
## Monarch 2.0 [britzl released 2017-12-08]
BREAKING CHANGE: If you are using custom screen transitions (ie your own transition functions) you need to make a change to the function. The previous function signature was ```(node, to, easing, duration, delay, url)``` where ```url``` was the URL to where the ```transition_done``` message was supposed to be posted. The new function signature for a transition function is: ```(node, to, easing, duration, delay, cb)``` where ```cb``` is a function that should be invoked when the transition is completed.
FIX: Fixed issues related to screen transitions.
FIX: Code cleanup to reduce code duplication.
FIX: Improved documentation regarding transitions.
## Monarch 1.4 [britzl released 2017-12-06]
FIX: Several bugfixes for specific corner cases.
## Monarch 1.3 [britzl released 2017-12-01]
FIX: monarch.back(data, cb) set the data on the previous screen not the new current screen.
NEW: monarch.is_top(id)
NEW: monarch.get_stack()
NEW: monarch.in_stack(id)
## Monarch 1.2 [britzl released 2017-11-28]
NEW: Message id constants exposed from the Monarch module
NEW: Focus lost/gained contains id of next/previous screen
## Monarch 1.1 [britzl released 2017-11-22]
FIX: Bugfixes for transitions and state under certain circumstances
NEW: Added 'reload' option to show() command.
## Monarch 1.0 [britzl released 2017-09-28]
First public stable release
## Monarch 0.9 [britzl released 2017-09-17]

View File

@@ -33,13 +33,6 @@ Hide a screen that has been shown using the `no_stack` option. If used on a scre
* `success` (boolean) - True if the process of hiding the screen was started successfully. * `success` (boolean) - True if the process of hiding the screen was started successfully.
## monarch.clear([callback])
Clear the stack of screens completely. Any visible screen will be hidden by navigating back out from them. This operation will be added to the queue if Monarch is busy.
**PARAMETERS**
* `callback` (function) - Optional function to call when the stack has been cleared.
## monarch.back([data], [callback]) ## monarch.back([data], [callback])
Go back to a previous Monarch screen. This operation will be added to the queue if Monarch is busy. Go back to a previous Monarch screen. This operation will be added to the queue if Monarch is busy.
@@ -149,14 +142,6 @@ Check if a Monarch screen is visible.
* `exists` (boolean) - True if the screen is visible. * `exists` (boolean) - True if the screen is visible.
## monarch.set_timestep_below_popup(screen_id, timestep)
Set the timestep to apply for a screen when below a popup.
**PARAMETERS**
* `screen_id` (string|hash) - Id of the screen to change timestep setting for
* `timestep` (number) - Timestep to apply
## monarch.add_listener([url]) ## monarch.add_listener([url])
Add a URL that will be notified of navigation events. Add a URL that will be notified of navigation events.

View File

@@ -151,3 +151,61 @@ embedded_instances {
z: 1.0 z: 1.0
} }
} }
embedded_instances {
id: "screen3"
data: "components {\n"
" id: \"screen_proxy\"\n"
" component: \"/monarch/screen_proxy.script\"\n"
" position {\n"
" x: 0.0\n"
" y: 0.0\n"
" z: 0.0\n"
" }\n"
" rotation {\n"
" x: 0.0\n"
" y: 0.0\n"
" z: 0.0\n"
" w: 1.0\n"
" }\n"
" properties {\n"
" id: \"screen_id\"\n"
" value: \"screen3\"\n"
" type: PROPERTY_TYPE_HASH\n"
" }\n"
"}\n"
"embedded_components {\n"
" id: \"collectionproxy\"\n"
" type: \"collectionproxy\"\n"
" data: \"collection: \\\"/example/basic/screen3.collection\\\"\\n"
"exclude: false\\n"
"\"\n"
" position {\n"
" x: 0.0\n"
" y: 0.0\n"
" z: 0.0\n"
" }\n"
" rotation {\n"
" x: 0.0\n"
" y: 0.0\n"
" z: 0.0\n"
" w: 1.0\n"
" }\n"
"}\n"
""
position {
x: 0.0
y: 0.0
z: 0.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale3 {
x: 1.0
y: 1.0
z: 1.0
}
}

View File

@@ -11,7 +11,124 @@ background_color {
} }
nodes { nodes {
position { position {
x: 320.0 x: 519.0
y: 568.0
z: 0.0
w: 1.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
size {
x: 200.0
y: 100.0
z: 0.0
w: 1.0
}
color {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
type: TYPE_BOX
blend_mode: BLEND_MODE_ALPHA
texture: ""
id: "showscreen3"
xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE
pivot: PIVOT_CENTER
adjust_mode: ADJUST_MODE_FIT
layer: ""
inherit_alpha: true
slice9 {
x: 0.0
y: 0.0
z: 0.0
w: 0.0
}
clipping_mode: CLIPPING_MODE_NONE
clipping_visible: true
clipping_inverted: false
alpha: 1.0
template_node_child: false
size_mode: SIZE_MODE_AUTO
}
nodes {
position {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
size {
x: 200.0
y: 100.0
z: 0.0
w: 1.0
}
color {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
type: TYPE_TEXT
blend_mode: BLEND_MODE_ALPHA
text: "SHOW 3"
font: "example"
id: "text"
xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE
pivot: PIVOT_CENTER
outline {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
shadow {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
adjust_mode: ADJUST_MODE_FIT
line_break: false
parent: "showscreen3"
layer: ""
inherit_alpha: true
alpha: 1.0
outline_alpha: 1.0
shadow_alpha: 1.0
template_node_child: false
text_leading: 1.0
text_tracking: 0.0
}
nodes {
position {
x: 132.0
y: 568.0 y: 568.0
z: 0.0 z: 0.0
w: 1.0 w: 1.0
@@ -98,7 +215,7 @@ nodes {
blend_mode: BLEND_MODE_ALPHA blend_mode: BLEND_MODE_ALPHA
text: "BACK" text: "BACK"
font: "example" font: "example"
id: "text" id: "text1"
xanchor: XANCHOR_NONE xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE yanchor: YANCHOR_NONE
pivot: PIVOT_CENTER pivot: PIVOT_CENTER

View File

@@ -6,7 +6,9 @@ end
function on_input(self, action_id, action) function on_input(self, action_id, action)
if action_id == hash("touch") and action.pressed then if action_id == hash("touch") and action.pressed then
if gui.pick_node(gui.get_node("backbutton"), action.x, action.y) then if gui.pick_node(gui.get_node("showscreen3"), action.x, action.y) then
monarch.show(hash("screen3"))
elseif gui.pick_node(gui.get_node("backbutton"), action.x, action.y) then
monarch.back() monarch.back()
end end
end end

View File

@@ -0,0 +1,37 @@
name: "screen3"
scale_along_z: 0
embedded_instances {
id: "go"
data: "components {\n"
" id: \"screen3\"\n"
" component: \"/example/basic/screen3.gui\"\n"
" position {\n"
" x: 0.0\n"
" y: 0.0\n"
" z: 0.0\n"
" }\n"
" rotation {\n"
" x: 0.0\n"
" y: 0.0\n"
" z: 0.0\n"
" w: 1.0\n"
" }\n"
"}\n"
""
position {
x: 0.0
y: 0.0
z: 0.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale3 {
x: 1.0
y: 1.0
z: 1.0
}
}

248
example/basic/screen3.gui Normal file
View File

@@ -0,0 +1,248 @@
script: "/example/basic/screen3.gui_script"
fonts {
name: "example"
font: "/assets/example.font"
}
background_color {
x: 0.0
y: 0.0
z: 0.0
w: 0.0
}
nodes {
position {
x: 137.0
y: 568.0
z: 0.0
w: 1.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
size {
x: 200.0
y: 100.0
z: 0.0
w: 1.0
}
color {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
type: TYPE_BOX
blend_mode: BLEND_MODE_ALPHA
texture: ""
id: "backbutton"
xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE
pivot: PIVOT_CENTER
adjust_mode: ADJUST_MODE_FIT
layer: ""
inherit_alpha: true
slice9 {
x: 0.0
y: 0.0
z: 0.0
w: 0.0
}
clipping_mode: CLIPPING_MODE_NONE
clipping_visible: true
clipping_inverted: false
alpha: 1.0
template_node_child: false
size_mode: SIZE_MODE_AUTO
}
nodes {
position {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
size {
x: 200.0
y: 100.0
z: 0.0
w: 1.0
}
color {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
type: TYPE_TEXT
blend_mode: BLEND_MODE_ALPHA
text: "BACK"
font: "example"
id: "text"
xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE
pivot: PIVOT_CENTER
outline {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
shadow {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
adjust_mode: ADJUST_MODE_FIT
line_break: false
parent: "backbutton"
layer: ""
inherit_alpha: true
alpha: 1.0
outline_alpha: 1.0
shadow_alpha: 1.0
template_node_child: false
text_leading: 1.0
text_tracking: 0.0
}
nodes {
position {
x: 525.0
y: 568.0
z: 0.0
w: 1.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
size {
x: 200.0
y: 100.0
z: 0.0
w: 1.0
}
color {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
type: TYPE_BOX
blend_mode: BLEND_MODE_ALPHA
texture: ""
id: "tostart"
xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE
pivot: PIVOT_CENTER
adjust_mode: ADJUST_MODE_FIT
layer: ""
inherit_alpha: true
slice9 {
x: 0.0
y: 0.0
z: 0.0
w: 0.0
}
clipping_mode: CLIPPING_MODE_NONE
clipping_visible: true
clipping_inverted: false
alpha: 1.0
template_node_child: false
size_mode: SIZE_MODE_AUTO
}
nodes {
position {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
size {
x: 200.0
y: 100.0
z: 0.0
w: 1.0
}
color {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
type: TYPE_TEXT
blend_mode: BLEND_MODE_ALPHA
text: "TOSTART"
font: "example"
id: "text1"
xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE
pivot: PIVOT_CENTER
outline {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
shadow {
x: 1.0
y: 1.0
z: 1.0
w: 1.0
}
adjust_mode: ADJUST_MODE_FIT
line_break: false
parent: "tostart"
layer: ""
inherit_alpha: true
alpha: 1.0
outline_alpha: 1.0
shadow_alpha: 1.0
template_node_child: false
text_leading: 1.0
text_tracking: 0.0
}
material: "/builtins/materials/gui.material"
adjust_reference: ADJUST_REFERENCE_PARENT
max_nodes: 512

View File

@@ -0,0 +1,15 @@
local monarch = require "monarch.monarch"
function init(self)
msg.post(".", "acquire_input_focus")
end
function on_input(self, action_id, action)
if action_id == hash("touch") and action.pressed then
if gui.pick_node(gui.get_node("backbutton"), action.x, action.y) then
monarch.back()
elseif gui.pick_node(gui.get_node("tostart"), action.x, action.y) then
monarch.back_to(hash("screen1"))
end
end
end

View File

@@ -1,5 +1,4 @@
local callback_tracker = require "monarch.utils.callback_tracker" local callback_tracker = require "monarch.utils.callback_tracker"
local async = require "monarch.utils.async"
local M = {} local M = {}
@@ -50,7 +49,7 @@ local transition_listeners = {}
-- monarch is considered busy while there are active transitions -- monarch is considered busy while there are active transitions
local active_transition_count = 0 local active_transition_count = 0
local function log(...) end local function log(...) end
function M.debug() function M.debug()
log = print log = print
@@ -605,6 +604,9 @@ local function show_in(screen, previous_screen, reload, add_to_stack, wait_for_t
notify_transition_listeners(M.SCREEN_TRANSITION_FAILED, { screen = screen.id }) notify_transition_listeners(M.SCREEN_TRANSITION_FAILED, { screen = screen.id })
return return
end end
-- wait until screen has had a chance to render
cowait(0)
cowait(0)
reset_timestep(screen) reset_timestep(screen)
transition(screen, M.TRANSITION.SHOW_IN, { previous_screen = previous_screen and previous_screen.id }, wait_for_transition) transition(screen, M.TRANSITION.SHOW_IN, { previous_screen = previous_screen and previous_screen.id }, wait_for_transition)
screen.visible = true screen.visible = true
@@ -629,6 +631,9 @@ local function back_in(screen, previous_screen, wait_for_transition, cb)
notify_transition_listeners(M.SCREEN_TRANSITION_FAILED, { screen = screen.id }) notify_transition_listeners(M.SCREEN_TRANSITION_FAILED, { screen = screen.id })
return return
end end
-- wait until screen has had a chance to render
cowait(0)
cowait(0)
reset_timestep(screen) reset_timestep(screen)
if previous_screen and not previous_screen.popup then if previous_screen and not previous_screen.popup then
transition(screen, M.TRANSITION.BACK_IN, { previous_screen = previous_screen.id }, wait_for_transition) transition(screen, M.TRANSITION.BACK_IN, { previous_screen = previous_screen.id }, wait_for_transition)
@@ -745,9 +750,8 @@ function M.show(id, options, data, cb)
pop = pop - 1 pop = pop - 1
end end
stack[#stack] = nil stack[#stack] = nil
async(function(await, resume) show_out(top, screen, WAIT_FOR_TRANSITION, callbacks.track())
await(show_out, top, screen, WAIT_FOR_TRANSITION, resume) callbacks.yield_until_done()
end)
top = stack[#stack] top = stack[#stack]
end end
@@ -786,16 +790,15 @@ function M.show(id, options, data, cb)
local same_screen = top and top.id == screen.id local same_screen = top and top.id == screen.id
if same_screen or (options and options.sequential) then if same_screen or (options and options.sequential) then
if top then if top then
async(function(await, resume) show_out(top, screen, WAIT_FOR_TRANSITION, callbacks.track())
await(show_out, top, screen, WAIT_FOR_TRANSITION, resume) callbacks.yield_until_done()
end)
end end
show_in(screen, top, options and options.reload, add_to_stack, WAIT_FOR_TRANSITION, callbacks.track()) show_in(screen, top, options and options.reload, add_to_stack, WAIT_FOR_TRANSITION, callbacks.track())
else else
-- show screen -- show screen
local cb = callbacks.track() local cb = callbacks.track()
show_in(screen, top, options and options.reload, add_to_stack, DO_NOT_WAIT_FOR_TRANSITION, function() show_in(screen, top, options and options.reload, add_to_stack, DO_NOT_WAIT_FOR_TRANSITION, function()
if add_to_stack and top and not top.popup then if top and not top.popup then
show_out(top, screen, WAIT_FOR_TRANSITION, callbacks.track()) show_out(top, screen, WAIT_FOR_TRANSITION, callbacks.track())
end end
cb() cb()
@@ -829,7 +832,7 @@ end
-- Hide a screen. The screen must either be at the top of the stack or -- Hide a screen. The screen must either be at the top of the stack or
-- visible but not added to the stack (through the no_stack option) -- visible but not added to the stack (through the no_stack option)
-- @param id (string|hash) - Id of the screen to .hide -- @param id (string|hash) - Id of the screen to show
-- @param cb (function) - Optional callback to invoke when the screen is hidden -- @param cb (function) - Optional callback to invoke when the screen is hidden
-- @return true if successfully hiding, false if busy or for some other reason unable to hide the screen -- @return true if successfully hiding, false if busy or for some other reason unable to hide the screen
function M.hide(id, cb) function M.hide(id, cb)
@@ -866,80 +869,86 @@ function M.hide(id, cb)
end end
local function internal_back(to, data, cb)
if #stack == 0 then
cb()
return
end
if not to then
if #stack > 1 then
to = stack[#stack - 1]
end
end
-- Clear stack completely. Any visible screens will be hidden by navigating back out queue_action(function(action_done)
-- from them. local co
-- @param cb (function) - Optional callback to invoke when the stack has been cleared co = coroutine.create(function()
function M.clear(cb) local callbacks = callback_tracker()
log("clear() queuing action") if not to then
back_out(table.remove(stack), nil, WAIT_FOR_TRANSITION, callbacks.track())
else
if data then
to.data = data
end
queue_action(function(action_done, action_error) -- close visible screens until target screen is below top screen
async(function(await, resume) while to ~= stack[#stack - 1] do
local top = stack[#stack] local top = table.remove(stack)
while top and top.visible do local below = stack[#stack]
stack[#stack] = nil if top.visible then
await(back_out, top, stack[#stack - 1], WAIT_FOR_TRANSITION, resume) back_out(top, below, WAIT_FOR_TRANSITION, callbacks.track())
top = stack[#stack] callbacks.yield_until_done()
end
end
local top = table.remove(stack)
if to == top then
-- 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
back_out(to, to, WAIT_FOR_TRANSITION, function()
back_in(to, to, WAIT_FOR_TRANSITION, callbacks.track())
end)
else
back_in(to, top, DO_NOT_WAIT_FOR_TRANSITION, function()
if top.visible then
back_out(top, to, WAIT_FOR_TRANSITION, callbacks.track())
end
end)
end
end end
while stack[#stack] do callbacks.when_done(function()
table.remove(stack) pcallfn(cb)
end pcallfn(action_done)
end)
pcallfn(cb)
pcallfn(action_done)
end) end)
assert(coroutine.resume(co))
end) end)
end end
-- Go back to the previous screen in the stack. -- Go back to the previous screen in the stack.
-- @param data (*) - Optional data to set for the previous screen -- @param data (*) - Optional data to set for the previous screen
-- @param cb (function) - Optional callback to invoke when the previous screen is visible again -- @param cb (function) - Optional callback to invoke when the previous screen is visible again
function M.back(data, cb) function M.back(data, cb)
log("back() queuing action") log("back() queuing action")
internal_back(nil, data, cb)
queue_action(function(action_done)
local callbacks = callback_tracker()
local back_cb = callbacks.track()
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
if top and screen.id == top.id then
back_out(screen, top, WAIT_FOR_TRANSITION, function()
if data then
top.data = data
end
back_in(top, screen, WAIT_FOR_TRANSITION, back_cb)
end)
else
if top then
if data then
top.data = data
end
back_in(top, screen, DO_NOT_WAIT_FOR_TRANSITION, function()
back_out(screen, top, WAIT_FOR_TRANSITION, back_cb)
end)
else
back_out(screen, top, WAIT_FOR_TRANSITION, back_cb)
end
end
end
callbacks.when_done(function()
pcallfn(cb)
pcallfn(action_done)
end)
end)
return true -- return true for legacy reasons (before queue existed)
end end
-- Go back to the previous screen in the stack.
-- @param data (*) - Optional data to set for the previous screen
-- @param cb (function) - Optional callback to invoke when the previous screen is visible again
function M.back_to(id, data, cb)
log("back_to() queuing action")
id = tohash(id)
assert(screens[id], ("There is no screen registered with id %s"):format(tostring(id)))
local screen = screens[id]
internal_back(screen, data, cb)
end
--- Check if a screen is preloading via monarch.preload() or automatically --- Check if a screen is preloading via monarch.preload() or automatically
-- via the Preload screen option -- via the Preload screen option
-- @param id Screen id -- @param id Screen id
@@ -1155,19 +1164,6 @@ function M.bottom(offset)
return screen and screen.id return screen and screen.id
end end
--- Set the timestep to apply for a screen when below a popup
-- @param id (string|hash) Id of the screen to change timestep setting for
-- @param timestep (number) Timestep to apply
function M.set_timestep_below_popup(id, timestep)
assert(id, "You must provide a screen id")
assert(timestep, "You must provide a timestep")
id = tohash(id)
assert(screens[id], ("There is no screen registered with id %s"):format(tostring(id)))
screens[id].timestep_below_popup = timestep
end
local function url_to_key(url) local function url_to_key(url)
return (url.socket or hash("")) .. (url.path or hash("")) .. (url.fragment or hash("")) return (url.socket or hash("")) .. (url.path or hash("")) .. (url.fragment or hash(""))
end end

View File

@@ -121,15 +121,11 @@ local function create()
local current_transition = nil local current_transition = nil
local function create_transition(transition_id, node, fn, easing, duration, delay) local function create_transition(transition_id, node, fn, easing, duration, delay)
assert(transition_id, "You must provide a valid transition id")
assert(node, "You must provide a node")
assert(fn, "You must provide a transition function")
local t = transitions[transition_id] local t = transitions[transition_id]
-- find if there's already a transition for the node in -- find if there's already a transition for the node in
-- question and if so update it instead of creating a new -- question and if so update it instead of creating a new
-- transition -- transition
for _,transition in ipairs(t.transitions) do for _,transition in ipairs(t) do
if transition.node == node then if transition.node == node then
transition.fn = fn transition.fn = fn
transition.easing = easing transition.easing = easing

View File

@@ -1,47 +0,0 @@
local M = {}
local NOT_STARTED = "not_started"
local YIELDED = "yielded"
local RESUMED = "resumed"
local RUNNING = "running"
function M.async(fn)
local co = coroutine.running()
local state = NOT_STARTED
local function await(fn, ...)
state = RUNNING
fn(...)
if state ~= RUNNING then
return
end
state = YIELDED
local r = { coroutine.yield() }
return unpack(r)
end
local function resume(...)
if state ~= RUNNING then
state = RUNNING
local ok, err = coroutine.resume(co, ...)
if not ok then
print(err)
print(debug.traceback())
end
end
end
if co then
return fn(await, resume)
else
co = coroutine.create(fn)
return resume(await, resume)
end
end
return setmetatable(M, {
__call = function(t, ...)
return M.async(...)
end
})

View File

@@ -6,18 +6,13 @@ function M.create()
local callback = nil local callback = nil
local callback_count = 0 local callback_count = 0
local all_callbacks_done = false
local function is_done() local function is_done()
return callback_count == 0 return callback_count == 0
end end
local function invoke_if_done() local function invoke_if_done()
if all_callbacks_done then
print("Warning: The same callback will be invoked twice from the callback tracker!")
end
if callback_count == 0 and callback then if callback_count == 0 and callback then
all_callbacks_done = true
local ok, err = pcall(callback) local ok, err = pcall(callback)
if not ok then print(err) end if not ok then print(err) end
end end
@@ -46,12 +41,26 @@ function M.create()
invoke_if_done() invoke_if_done()
end end
function instance.yield_until_done()
local co = coroutine.running()
callback = function()
local ok, err = coroutine.resume(co)
if not ok then
print(err)
end
end
invoke_if_done()
if not is_done() then
coroutine.yield()
end
end
return instance return instance
end end
return setmetatable(M, { return setmetatable(M, {
__call = function(_, ...) __call = function(_, ...)
return M.create() return M.create(...)
end end
}) })

View File

@@ -8,12 +8,6 @@ local easing = require "monarch.transitions.easings"
return function() return function()
local function wait_timeout(fn, ...)
local args = { ... }
cowait(function() return fn(unpack(args)) end, 5)
return fn(...)
end
describe("transitions", function() describe("transitions", function()
before(function() before(function()
mock_msg.mock() mock_msg.mock()
@@ -28,28 +22,6 @@ describe("transitions", function()
end) end)
it("should replace an existing transition with a new one", function()
local one = false
function dummy_transition1(node, to, easing, duration, delay, cb)
one = true
end
local two = false
function dummy_transition2(node, to, easing, duration, delay, cb)
two = true
end
local node = gui.new_box_node(vmath.vector3(), vmath.vector3(100, 100, 0))
local duration = 2
local t = transitions.create(node)
t.show_in(dummy_transition1, easing.OUT, duration, delay or 0)
t.show_in(dummy_transition2, easing.OUT, duration, delay or 0)
t.handle(monarch.TRANSITION.SHOW_IN)
wait_timeout(function() return one or two end)
assert(two)
assert(not one)
end)
it("should replay and immediately finish on layout change", function() it("should replay and immediately finish on layout change", function()
function dummy_transition(node, to, easing, duration, delay, cb) function dummy_transition(node, to, easing, duration, delay, cb)
print("dummy transition") print("dummy transition")