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

Compare commits

...

14 Commits
2.3.0 ... 2.8.0

Author SHA1 Message Date
Björn Ritzl
4231b0b89c Prevent show/back operations while busy
Fixes #22
2018-06-10 16:17:41 +02:00
Alexey Gulev
c2239d67e5 Finish transition when layout changes (#21)
* If layout changes when transaction in progress we have to finish current transaction
2018-06-10 14:31:46 +02:00
Björn Ritzl
9765daa2a9 Updated changelog (again) 2018-06-08 07:48:33 +02:00
Björn Ritzl
7b2b269c72 Update changelog 2018-06-08 07:42:17 +02:00
Björn Ritzl
cf75bef8da Merge branch 'master' of https://github.com/britzl/monarch 2018-06-04 13:56:47 +02:00
Björn Ritzl
66b1f7ca2e Added monarch.top() and bottom() 2018-06-04 13:56:45 +02:00
Björn Ritzl
0fdfb6fd11 Send information about the next/prev screen in transition message 2018-06-04 13:56:23 +02:00
Alexey Gulev
6fbec4ab8f preventing double preload of the screen (#20)
* preventing double preload of the screen
2018-06-04 07:48:46 +02:00
Björn Ritzl
ffc148b4bf Added preload() 2018-06-03 17:32:13 +02:00
Björn Ritzl
724713f9e4 Include transition id in TRANSITION.DONE message
Also send the TRANSITION.DONE message to the gui that was transitioned
2018-06-01 08:43:08 +02:00
Björn Ritzl
39628b75af Merge pull request #17 from britzl/resizefix
Replay transitions when the layout changes
2018-05-26 19:43:42 +02:00
Björn Ritzl
dbf1bdea9d Replay transitions when the layout changes 2018-05-25 15:33:51 +02:00
Björn Ritzl
d45005cd90 Added documentation about monarch.debug()
Fixes #16
2018-05-24 16:34:33 +02:00
Björn Ritzl
a701f6cd92 Fixed broken tests 2018-03-26 06:33:11 +02:00
5 changed files with 296 additions and 21 deletions

56
CHANGELOG.md Normal file
View File

@@ -0,0 +1,56 @@
## 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

@@ -6,6 +6,7 @@
# Monarch # Monarch
Monarch is a screen manager for the [Defold](https://www.defold.com) game engine. Monarch is a screen manager for the [Defold](https://www.defold.com) game engine.
# Installation # Installation
You can use Monarch in your own project by adding this project as a [Defold library dependency](http://www.defold.com/manuals/libraries/). Open your game.project file and in the dependencies field under project add: You can use Monarch in your own project by adding this project as a [Defold library dependency](http://www.defold.com/manuals/libraries/). Open your game.project file and in the dependencies field under project add:
@@ -13,9 +14,11 @@ https://github.com/britzl/monarch/archive/master.zip
Or point to the ZIP file of a [specific release](https://github.com/britzl/monarch/releases). Or point to the ZIP file of a [specific release](https://github.com/britzl/monarch/releases).
# Usage # Usage
Using Monarch requires that screens are created in a certain way. Once you have one or more screens created you can start navigating between the screens. Using Monarch requires that screens are created in a certain way. Once you have one or more screens created you can start navigating between the screens.
## Creating screens ## Creating screens
Monarch screens are created in individual collections and loaded through collection proxies. The recommended setup is to create one game object per screen and per game object attach a collection proxy component and an instance of the ```screen.script``` provided by Monarch. The ```screen.script``` will take care of the setup of the screen. All you need to do is to make sure that the script properties on the ```screen.script``` are correct: Monarch screens are created in individual collections and loaded through collection proxies. The recommended setup is to create one game object per screen and per game object attach a collection proxy component and an instance of the ```screen.script``` provided by Monarch. The ```screen.script``` will take care of the setup of the screen. All you need to do is to make sure that the script properties on the ```screen.script``` are correct:
@@ -28,6 +31,7 @@ Monarch screens are created in individual collections and loaded through collect
![](docs/setup.png) ![](docs/setup.png)
## Navigating between screens ## Navigating between screens
The navigation in Monarch is based around a stack of screens. When a screen is shown it is pushed to the top of the stack. When going back to a previous screen the topmost screen on the stack is removed. Example: The navigation in Monarch is based around a stack of screens. When a screen is shown it is pushed to the top of the stack. When going back to a previous screen the topmost screen on the stack is removed. Example:
@@ -123,6 +127,7 @@ When a transition is completed it is up to the developer to send a ```transition
Monarch comes with a system for setting up transitions easily in a gui_script using the ```monarch.transitions.gui``` module. 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" local transitions = require "monarch.transitions.gui"
local monarch = require "monarch.monarch"
function init(self) function init(self)
-- create transitions for the node 'root' -- create transitions for the node 'root'
@@ -137,6 +142,10 @@ Monarch comes with a system for setting up transitions easily in a gui_script us
function on_message(self, message_id, message, sender) function on_message(self, message_id, message, sender)
self.transition.handle(message_id, message, sender) self.transition.handle(message_id, message, sender)
-- you can also check when a transition has completed:
if message_id == monarch.TRANSITION.DONE and message.transition == monarch.TRANSITION.SHOW_IN then
print("Show in done!")
end
end end
### Predefined transitions ### Predefined transitions
@@ -182,6 +191,26 @@ When using dynamic screen orientation together with gui layouts or using transit
end end
### Screen stack info and transitions
The transition message sent to the Transition Url specified in the screen configuration contains additional information about the transition. For the ```transition_show_in``` and ```transition_back_out``` messages the message contains the previous screen id:
function on_message(self, message_id, message, sender)
if message_id == hash("transition_show_in") or message_id == hash("transition_back_out") then
print(message.previous_screen)
end
end
For the ```transition_show_out``` and ```transition_back_in``` messages the message contains the next screen id:
function on_message(self, message_id, message, sender)
if message_id == hash("transition_show_out") or message_id == hash("transition_back_in") then
print(message.next_screen)
end
end
This information can be used to create dynamic transitions where the direction of the transition depends on the previous/next screen
## Screen focus gain/loss ## 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: 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:
@@ -195,9 +224,11 @@ Monarch will send focus gain and focus loss messages if a Focus Url was provided
end end
end end
## Callbacks ## Callbacks
Both the ```monarch.show()``` and ```monarch.back()``` functions take an optional callback function that will be invoked when the ```transition_show_in``` (or the ```transition_back_in``` in the case of a ```monarch.back()``` call) transition is completed. The transition is considered completed when a ```transition_done``` message has been received (see section on [transitions](#transitions) above). Both the ```monarch.show()``` and ```monarch.back()``` functions take an optional callback function that will be invoked when the ```transition_show_in``` (or the ```transition_back_in``` in the case of a ```monarch.back()``` call) transition is completed. The transition is considered completed when a ```transition_done``` message has been received (see section on [transitions](#transitions) above).
## Monarch API ## Monarch API
### monarch.show(screen_id, [options], [data], [callback]) ### monarch.show(screen_id, [options], [data], [callback])
@@ -214,6 +245,10 @@ The options table can contain the following fields:
* ```clear``` (boolean) - If the clear flag is set Monarch will search the stack for the screen that is to be shown. If the screen already exists in the stack and the clear flag is set Monarch will remove all screens between the current top and the screen in question. * ```clear``` (boolean) - If the clear flag is set Monarch will search the stack for the screen that is to be shown. If the screen already exists in the stack and the clear flag is set Monarch will remove all screens between the current top and the screen in question.
* ```reload``` (boolean) - If the reload flag is set Monarch will reload the collection proxy if it's already loaded (this can happen if the previous screen was a popup). * ```reload``` (boolean) - If the reload flag is set Monarch will reload the collection proxy if it's already loaded (this can happen if the previous screen was a popup).
**RETURN**
* ```success``` (boolean) - True if the process of showing the screen was started successfully. False if already busy showing/hiding a screen.
### monarch.back([data], [callback]) ### monarch.back([data], [callback])
Go back to a previous Monarch screen Go back to a previous Monarch screen
@@ -221,6 +256,37 @@ Go back to a previous Monarch screen
* ```data``` (table) - Optional data to associate with the screen you are going back to. Retrieve using ```monarch.data()```. * ```data``` (table) - Optional data to associate with the screen you are going back to. Retrieve using ```monarch.data()```.
* ```callback``` (function) - Optional function to call when the previous screen is visible. * ```callback``` (function) - Optional function to call when the previous screen is visible.
**RETURN**
* ```success``` (boolean) - True if the process of going back to a previous screen was started successfully. False if already busy showing/hiding a screen.
### monarch.preload(screen_id, [callback])
Preload a Monarch screen. This will load but not enable the screen. This is useful for content heavy screens that you wish to be able to show without having to wait for it load.
**PARAMETERS**
* ```screen_id``` (hash) - Id of the screen to preload.
* ```callback``` (function) - Optional function to call when the new screen is preloaded.
### monarch.top([offset])
Get the id of the screen at the top of the stack.
**PARAMETERS**
* ```offset``` (number) - Optional offset from the top of the stack, ie -1 to get the previous screen
**RETURN**
* ```screen_id``` (hash) - Id of the requested screen
### monarch.bottom([offset])
Get the id of the screen at the bottom of the stack.
**PARAMETERS**
* ```offset``` (number) - Optional offset from the bottom of the stack
**RETURN**
* ```screen_id``` (hash) - Id of the requested screen
### monarch.data(screen_id) ### monarch.data(screen_id)
Get the data associated with a screen (from a call to ```monarch.show()``` or ```monarch.back()```). Get the data associated with a screen (from a call to ```monarch.show()``` or ```monarch.back()```).
@@ -240,3 +306,7 @@ Check if a Monarch screen exists.
**RETURN** **RETURN**
* ```exists``` (boolean) - True if the screen exists. * ```exists``` (boolean) - True if the screen exists.
### monarch.debug()
Enable verbose logging of the internals of Monarch.

View File

@@ -1,9 +1,5 @@
local M = {} local M = {}
local screens = {}
local stack = {}
local CONTEXT = hash("monarch_context") local CONTEXT = hash("monarch_context")
local PROXY_LOADED = hash("proxy_loaded") local PROXY_LOADED = hash("proxy_loaded")
local PROXY_UNLOADED = hash("proxy_unloaded") local PROXY_UNLOADED = hash("proxy_unloaded")
@@ -25,6 +21,15 @@ M.FOCUS = {}
M.FOCUS.GAINED = hash("monarch_focus_gained") M.FOCUS.GAINED = hash("monarch_focus_gained")
M.FOCUS.LOST = hash("monarch_focus_lost") M.FOCUS.LOST = hash("monarch_focus_lost")
-- all registered screens
local screens = {}
-- the current stack of screens
local stack = {}
-- true while busy showing/hiding something
local busy = false
local function log(...) end local function log(...) end
@@ -171,10 +176,10 @@ local function async_load(screen)
screen.wait_for = nil screen.wait_for = nil
end end
local function transition(screen, message_id) local function transition(screen, message_id, message)
log("transition()", screen.id) log("transition()", screen.id)
screen.wait_for = M.TRANSITION.DONE screen.wait_for = M.TRANSITION.DONE
msg.post(screen.transition_url, message_id) msg.post(screen.transition_url, message_id, message)
coroutine.yield() coroutine.yield()
screen.wait_for = nil screen.wait_for = nil
end end
@@ -225,6 +230,7 @@ local function show_out(screen, next_screen, cb)
log("show_out()", screen.id) log("show_out()", screen.id)
local co local co
co = coroutine.create(function() co = coroutine.create(function()
busy = true
screen.co = co screen.co = co
change_context(screen) change_context(screen)
release_input(screen) release_input(screen)
@@ -234,10 +240,11 @@ local function show_out(screen, next_screen, cb)
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
transition(screen, M.TRANSITION.SHOW_OUT) transition(screen, M.TRANSITION.SHOW_OUT, { next_screen = next_screen.id })
unload(screen) unload(screen)
end end
screen.co = nil screen.co = nil
busy = false
if cb then cb() end if cb then cb() end
end) end)
coroutine.resume(co) coroutine.resume(co)
@@ -247,23 +254,32 @@ local function show_in(screen, previous_screen, reload, cb)
log("show_in()", screen.id) log("show_in()", screen.id)
local co local co
co = coroutine.create(function() co = coroutine.create(function()
busy = true
screen.co = co screen.co = co
change_context(screen) change_context(screen)
if reload and screen.loaded then if reload and screen.loaded then
log("show_in() reloading", screen.id) log("show_in() reloading", screen.id)
unload(screen) unload(screen)
end end
-- if the screen has been preloaded we need to enable it
if screen.preloaded then
log("show_in() screen was preloaded", screen.id)
msg.post(screen.proxy, ENABLE)
screen.loaded = true
screen.preloaded = false
-- 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 elseif not screen.loaded then
log("show_in() loading screen", screen.id)
async_load(screen) async_load(screen)
end end
stack[#stack + 1] = screen stack[#stack + 1] = screen
transition(screen, M.TRANSITION.SHOW_IN) transition(screen, M.TRANSITION.SHOW_IN, { previous_screen = previous_screen and previous_screen.id })
acquire_input(screen) acquire_input(screen)
focus_gained(screen, previous_screen) focus_gained(screen, previous_screen)
screen.co = nil screen.co = nil
busy = false
if cb then cb() end if cb then cb() end
end) end)
coroutine.resume(co) coroutine.resume(co)
@@ -273,17 +289,25 @@ local function back_in(screen, previous_screen, cb)
log("back_in()", screen.id) log("back_in()", screen.id)
local co local co
co = coroutine.create(function() co = coroutine.create(function()
busy = true
screen.co = co screen.co = co
change_context(screen) change_context(screen)
if not screen.loaded then if screen.preloaded then
log("back_in() screen was preloaded", screen.id)
msg.post(screen.proxy, ENABLE)
screen.preloaded = false
screen.loaded = true
elseif not screen.loaded then
log("back_in() loading screen", screen.id)
async_load(screen) async_load(screen)
end end
if previous_screen and not previous_screen.popup then if previous_screen and not previous_screen.popup then
transition(screen, M.TRANSITION.BACK_IN) transition(screen, M.TRANSITION.BACK_IN, { previous_screen = previous_screen.id })
end end
acquire_input(screen) acquire_input(screen)
focus_gained(screen, previous_screen) focus_gained(screen, previous_screen)
screen.co = nil screen.co = nil
busy = false
if cb then cb() end if cb then cb() end
end) end)
coroutine.resume(co) coroutine.resume(co)
@@ -293,13 +317,15 @@ local function back_out(screen, next_screen, cb)
log("back_out()", screen.id) log("back_out()", screen.id)
local co local co
co = coroutine.create(function() co = coroutine.create(function()
busy = true
screen.co = co screen.co = co
change_context(screen) change_context(screen)
release_input(screen) release_input(screen)
focus_lost(screen, next_screen) focus_lost(screen, next_screen)
transition(screen, M.TRANSITION.BACK_OUT) transition(screen, M.TRANSITION.BACK_OUT, { next_screen = next_screen and next_screen.id })
unload(screen) unload(screen)
screen.co = nil screen.co = nil
busy = false
if cb then cb() end if cb then cb() end
end) end)
coroutine.resume(co) coroutine.resume(co)
@@ -330,11 +356,16 @@ end
-- @param options (table) - Table with options when showing the screen (can be nil). Valid values: -- @param options (table) - Table with options when showing the screen (can be nil). Valid values:
-- * clear - Set to true if the stack should be cleared down to an existing instance of the screen -- * clear - Set to true if the stack should be cleared down to an existing instance of the screen
-- * reload - Set to true if screen should be reloaded if it already exists in the stack and is loaded. -- * reload - Set to true if screen should be reloaded if it already exists in the stack and is loaded.
-- This would be the case if doing a show() from a popup on the screen just below the popup. -- This would be the case if doing a show() from a popup on the screen just below the popup.
-- @param data (*) - Optional data to set on the screen. Can be retrieved by the data() function -- @param data (*) - Optional data to set on the screen. Can be retrieved by the data() function
-- @param cb (function) - Optional callback to invoke when screen is shown -- @param cb (function) - Optional callback to invoke when screen is shown
-- @return success True if screen is successfully shown, false if busy performing another operation
function M.show(id, options, data, cb) function M.show(id, options, data, cb)
assert(id, "You must provide a screen id") assert(id, "You must provide a screen id")
if busy then
return false
end
id = tohash(id) id = tohash(id)
assert(screens[id], ("There is no screen registered with id %s"):format(tostring(id))) assert(screens[id], ("There is no screen registered with id %s"):format(tostring(id)))
@@ -379,13 +410,20 @@ function M.show(id, options, data, cb)
-- show screen -- show screen
show_in(screen, top, options and options.reload, cb) show_in(screen, top, options and options.reload, cb)
return true
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
-- @return true if successfully going back, false if busy performing another operation
function M.back(data, cb) function M.back(data, cb)
if busy then
return false
end
local screen = table.remove(stack) local screen = table.remove(stack)
if screen then if screen then
log("back()", screen.id) log("back()", screen.id)
@@ -411,6 +449,35 @@ function M.back(data, cb)
elseif cb then elseif cb then
cb() cb()
end end
return true
end
--- Preload a screen. This will load but not enable and show a screen. Useful for "heavier" screens
-- that you wish to show without any delay.
-- @param id (string|hash) - Id of the screen to preload
-- @param cb (function) - Optional callback to invoke when screen is loaded
function M.preload(id, cb)
assert(id, "You must provide a screen id")
id = tohash(id)
assert(screens[id], ("There is no screen registered with id %s"):format(tostring(id)))
local screen = screens[id]
if screen.preloaded then
if cb then cb() end
return
end
local co
co = coroutine.create(function()
screen.co = co
change_context(screen)
screen.wait_for = PROXY_LOADED
msg.post(screen.proxy, ASYNC_LOAD)
coroutine.yield()
screen.preloaded = true
screen.wait_for = nil
if cb then cb() end
end)
coroutine.resume(co)
end end
@@ -454,6 +521,25 @@ function M.get_stack()
return s return s
end end
--- Get the screen on top of the stack
-- @param offset Optional offset from the top of the stack, (eg -1 for the previous screen)
-- @return Id of the requested screen
function M.top(offset)
local screen = stack[#stack + (offset or 0)]
return screen and screen.id
end
--- Get the screen at the bottom of the stack
-- @param offset Optional offset from the bottom of the stack
-- @return Id of the requested screen
function M.bottom(offset)
local screen = stack[1 + (offset or 0)]
return screen and screen.id
end
function M.dump_stack() function M.dump_stack()
local s = "" local s = ""
for i, screen in ipairs(stack) do for i, screen in ipairs(stack) do

View File

@@ -96,6 +96,8 @@ function M.create(node)
local transitions = {} local transitions = {}
local current_transition = nil
local initial_data = {} local initial_data = {}
initial_data.pos = gui.get_position(node) initial_data.pos = gui.get_position(node)
initial_data.scale = gui.get_scale(node) initial_data.scale = gui.get_scale(node)
@@ -108,19 +110,28 @@ function M.create(node)
delay = delay, delay = delay,
in_progress = false, in_progress = false,
urls = {}, urls = {},
id = nil
} }
end end
local function start_transition(transition, url) local function finish_transition(transition)
transition.in_progress = false
local message = { transition = transition.id }
while #transition.urls > 0 do
local url = table.remove(transition.urls)
msg.post(url, monarch.TRANSITION.DONE, message)
end
end
local function start_transition(transition, transition_id, url)
table.insert(transition.urls, url) table.insert(transition.urls, url)
if not transition.in_progress then if not transition.in_progress then
table.insert(transition.urls, msg.url())
transition.in_progress = true transition.in_progress = true
transition.id = transition_id
current_transition = transition
transition.fn(node, initial_data, transition.easing, transition.duration, transition.delay or 0, function() transition.fn(node, initial_data, transition.easing, transition.duration, transition.delay or 0, function()
transition.in_progress = false finish_transition(transition)
while #transition.urls > 0 do
local url = table.remove(transition.urls)
msg.post(url, monarch.TRANSITION.DONE)
end
end) end)
end end
end end
@@ -129,10 +140,19 @@ function M.create(node)
function instance.handle(message_id, message, sender) function instance.handle(message_id, message, sender)
if message_id == LAYOUT_CHANGED then if message_id == LAYOUT_CHANGED then
initial_data.pos = gui.get_position(node) initial_data.pos = gui.get_position(node)
-- replay the current transition if the layout changes
-- this will ensure that things are still hidden if they
-- were transitioned out
if current_transition then
current_transition.fn(node, initial_data, current_transition.easing, 0, 0)
if current_transition.in_progress then
finish_transition(current_transition)
end
end
else else
local transition = transitions[message_id] local transition = transitions[message_id]
if transition then if transition then
start_transition(transition, sender) start_transition(transition, message_id, sender)
end end
end end
end end

View File

@@ -1,6 +1,7 @@
local cowait = require "test.cowait" local cowait = require "test.cowait"
local monarch = require "monarch.monarch" local monarch = require "monarch.monarch"
local SCREEN1_STR = hash("screen1")
local SCREEN1 = hash(SCREEN1_STR) local SCREEN1 = hash(SCREEN1_STR)
local SCREEN2 = hash("screen2") local SCREEN2 = hash("screen2")
local POPUP1 = hash("popup1") local POPUP1 = hash("popup1")
@@ -147,6 +148,23 @@ return function()
end) end)
it("should prevent further operations while hiding/showing a screen", function()
assert(monarch.show(SCREEN1) == true)
assert(monarch.show(SCREEN2) == false)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(monarch.show(SCREEN2) == true)
assert(wait_until_shown(SCREEN2), "Screen1 was never shown")
assert_stack({ SCREEN1, SCREEN2 })
assert(monarch.back() == true)
assert(monarch.back() == false)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
end)
it("should close any open popups when showing a popup without the Popup On Popup flag", function() it("should close any open popups when showing a popup without the Popup On Popup flag", function()
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
@@ -174,6 +192,31 @@ return function()
assert(wait_until_shown(SCREEN2), "Popup2 was never shown") assert(wait_until_shown(SCREEN2), "Popup2 was never shown")
assert_stack({ SCREEN1, SCREEN2 }) assert_stack({ SCREEN1, SCREEN2 })
end) end)
it("should be able to get the id of the screen at the top and bottom of the stack", function()
assert(monarch.top() == nil)
assert(monarch.bottom() == nil)
assert(monarch.top(1) == nil)
assert(monarch.bottom(-1) == nil)
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert(monarch.top() == SCREEN1)
assert(monarch.top(0) == SCREEN1)
assert(monarch.top(1) == nil)
assert(monarch.bottom() == SCREEN1)
assert(monarch.bottom(0) == SCREEN1)
assert(monarch.bottom(-1) == nil)
monarch.show(SCREEN2)
assert(wait_until_hidden(SCREEN1), "Screen1 was never hidden")
assert(wait_until_shown(SCREEN2), "Screen2 was never shown")
assert_stack({ SCREEN1, SCREEN2 })
assert(monarch.top(0) == SCREEN2)
assert(monarch.top(-1) == SCREEN1)
assert(monarch.bottom(0) == SCREEN1)
assert(monarch.bottom(1) == SCREEN2)
end)
end) end)
end end