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

Compare commits

..

5 Commits
3.3.0 ... 3.4.1

Author SHA1 Message Date
Björn Ritzl
9e81b3a327 Removed one-frame delay during show/back-in
If the screen had a transition the delay caused the screen to render in its initial position for one frame before the transition was applied
2021-07-01 15:04:52 +02:00
Björn Ritzl
4927d6e766 Update stack earlier when showing new screen
Fixes #76
2021-06-27 00:34:32 +02:00
Björn Ritzl
20cf731fdb Wait with screen unload until next screen is loaded and ready to be shown (#74)
* Removed screen flicker when transitioning between screens

* Moved advanced example to subfolder. Added basic example.

* Remove flicker on back navigation too

* Fix issue with no_stack screens added at any time
2021-06-24 07:45:09 +02:00
Björn Ritzl
466b558e73 Update game.project 2021-04-26 22:49:08 +02:00
Björn Ritzl
398e78670f Moved advanced example to subfolder. Added basic example. 2021-04-26 22:48:44 +02:00
36 changed files with 762 additions and 226 deletions

View File

@@ -4,7 +4,7 @@ embedded_instances {
id: "go" id: "go"
data: "components {\n" data: "components {\n"
" id: \"about\"\n" " id: \"about\"\n"
" component: \"/example/about.gui\"\n" " component: \"/example/advanced/about.gui\"\n"
" position {\n" " position {\n"
" x: 0.0\n" " x: 0.0\n"
" y: 0.0\n" " y: 0.0\n"

View File

@@ -1,4 +1,4 @@
script: "/example/about.gui_script" script: "/example/advanced/about.gui_script"
fonts { fonts {
name: "example" name: "example"
font: "/assets/example.font" font: "/assets/example.font"

View File

@@ -1,4 +1,4 @@
name: "example" name: "advanced"
scale_along_z: 0 scale_along_z: 0
embedded_instances { embedded_instances {
id: "menu" id: "menu"
@@ -35,7 +35,7 @@ embedded_instances {
"embedded_components {\n" "embedded_components {\n"
" id: \"collectionfactory\"\n" " id: \"collectionfactory\"\n"
" type: \"collectionfactory\"\n" " type: \"collectionfactory\"\n"
" data: \"prototype: \\\"/example/menu.collection\\\"\\n" " data: \"prototype: \\\"/example/advanced/menu.collection\\\"\\n"
"load_dynamically: true\\n" "load_dynamically: true\\n"
"\"\n" "\"\n"
" position {\n" " position {\n"
@@ -72,7 +72,7 @@ embedded_instances {
id: "main" id: "main"
data: "components {\n" data: "components {\n"
" id: \"main\"\n" " id: \"main\"\n"
" component: \"/example/main.script\"\n" " component: \"/example/advanced/advanced.script\"\n"
" position {\n" " position {\n"
" x: 0.0\n" " x: 0.0\n"
" y: 0.0\n" " y: 0.0\n"
@@ -87,7 +87,7 @@ embedded_instances {
"}\n" "}\n"
"components {\n" "components {\n"
" id: \"gui\"\n" " id: \"gui\"\n"
" component: \"/example/debug.gui\"\n" " component: \"/example/advanced/debug.gui\"\n"
" position {\n" " position {\n"
" x: 0.0\n" " x: 0.0\n"
" y: 0.0\n" " y: 0.0\n"
@@ -148,7 +148,7 @@ embedded_instances {
"embedded_components {\n" "embedded_components {\n"
" id: \"collectionproxy\"\n" " id: \"collectionproxy\"\n"
" type: \"collectionproxy\"\n" " type: \"collectionproxy\"\n"
" data: \"collection: \\\"/example/pregame.collection\\\"\\n" " data: \"collection: \\\"/example/advanced/pregame.collection\\\"\\n"
"exclude: false\\n" "exclude: false\\n"
"\"\n" "\"\n"
" position {\n" " position {\n"
@@ -211,7 +211,7 @@ embedded_instances {
"embedded_components {\n" "embedded_components {\n"
" id: \"collectionproxy\"\n" " id: \"collectionproxy\"\n"
" type: \"collectionproxy\"\n" " type: \"collectionproxy\"\n"
" data: \"collection: \\\"/example/game.collection\\\"\\n" " data: \"collection: \\\"/example/advanced/game.collection\\\"\\n"
"exclude: false\\n" "exclude: false\\n"
"\"\n" "\"\n"
" position {\n" " position {\n"
@@ -294,7 +294,7 @@ embedded_instances {
"embedded_components {\n" "embedded_components {\n"
" id: \"collectionproxy\"\n" " id: \"collectionproxy\"\n"
" type: \"collectionproxy\"\n" " type: \"collectionproxy\"\n"
" data: \"collection: \\\"/example/about.collection\\\"\\n" " data: \"collection: \\\"/example/advanced/about.collection\\\"\\n"
"exclude: false\\n" "exclude: false\\n"
"\"\n" "\"\n"
" position {\n" " position {\n"
@@ -372,7 +372,7 @@ embedded_instances {
"embedded_components {\n" "embedded_components {\n"
" id: \"collectionproxy\"\n" " id: \"collectionproxy\"\n"
" type: \"collectionproxy\"\n" " type: \"collectionproxy\"\n"
" data: \"collection: \\\"/example/confirm.collection\\\"\\n" " data: \"collection: \\\"/example/advanced/confirm.collection\\\"\\n"
"exclude: false\\n" "exclude: false\\n"
"\"\n" "\"\n"
" position {\n" " position {\n"
@@ -430,7 +430,7 @@ embedded_instances {
"embedded_components {\n" "embedded_components {\n"
" id: \"collectionfactory\"\n" " id: \"collectionfactory\"\n"
" type: \"collectionfactory\"\n" " type: \"collectionfactory\"\n"
" data: \"prototype: \\\"/example/background.collection\\\"\\n" " data: \"prototype: \\\"/example/advanced/background.collection\\\"\\n"
"load_dynamically: false\\n" "load_dynamically: false\\n"
"\"\n" "\"\n"
" position {\n" " position {\n"

View File

@@ -4,7 +4,7 @@ embedded_instances {
id: "go" id: "go"
data: "components {\n" data: "components {\n"
" id: \"confirm\"\n" " id: \"confirm\"\n"
" component: \"/example/confirm.gui\"\n" " component: \"/example/advanced/confirm.gui\"\n"
" position {\n" " position {\n"
" x: 0.0\n" " x: 0.0\n"
" y: 0.0\n" " y: 0.0\n"

View File

@@ -1,4 +1,4 @@
script: "/example/confirm.gui_script" script: "/example/advanced/confirm.gui_script"
fonts { fonts {
name: "example" name: "example"
font: "/assets/example.font" font: "/assets/example.font"

View File

@@ -1,4 +1,4 @@
script: "/example/debug.gui_script" script: "/example/advanced/debug.gui_script"
fonts { fonts {
name: "example" name: "example"
font: "/assets/example.font" font: "/assets/example.font"

View File

@@ -4,7 +4,7 @@ embedded_instances {
id: "go" id: "go"
data: "components {\n" data: "components {\n"
" id: \"game\"\n" " id: \"game\"\n"
" component: \"/example/game.gui\"\n" " component: \"/example/advanced/game.gui\"\n"
" position {\n" " position {\n"
" x: 0.0\n" " x: 0.0\n"
" y: 0.0\n" " y: 0.0\n"

View File

@@ -1,4 +1,4 @@
script: "/example/game.gui_script" script: "/example/advanced/game.gui_script"
fonts { fonts {
name: "example" name: "example"
font: "/assets/example.font" font: "/assets/example.font"

View File

@@ -4,7 +4,7 @@ embedded_instances {
id: "go" id: "go"
data: "components {\n" data: "components {\n"
" id: \"menu\"\n" " id: \"menu\"\n"
" component: \"/example/menu.gui\"\n" " component: \"/example/advanced/menu.gui\"\n"
" position {\n" " position {\n"
" x: 0.0\n" " x: 0.0\n"
" y: 0.0\n" " y: 0.0\n"
@@ -80,7 +80,7 @@ embedded_instances {
"embedded_components {\n" "embedded_components {\n"
" id: \"collectionfactory\"\n" " id: \"collectionfactory\"\n"
" type: \"collectionfactory\"\n" " type: \"collectionfactory\"\n"
" data: \"prototype: \\\"/example/popup.collection\\\"\\n" " data: \"prototype: \\\"/example/advanced/popup.collection\\\"\\n"
"load_dynamically: false\\n" "load_dynamically: false\\n"
"\"\n" "\"\n"
" position {\n" " position {\n"

View File

@@ -1,4 +1,4 @@
script: "/example/menu.gui_script" script: "/example/advanced/menu.gui_script"
fonts { fonts {
name: "example" name: "example"
font: "/assets/example.font" font: "/assets/example.font"

View File

@@ -4,7 +4,7 @@ embedded_instances {
id: "go" id: "go"
data: "components {\n" data: "components {\n"
" id: \"popup\"\n" " id: \"popup\"\n"
" component: \"/example/popup.gui\"\n" " component: \"/example/advanced/popup.gui\"\n"
" position {\n" " position {\n"
" x: 0.0\n" " x: 0.0\n"
" y: 0.0\n" " y: 0.0\n"

View File

@@ -1,4 +1,4 @@
script: "/example/popup.gui_script" script: "/example/advanced/popup.gui_script"
fonts { fonts {
name: "example" name: "example"
font: "/assets/example.font" font: "/assets/example.font"

View File

@@ -4,7 +4,7 @@ embedded_instances {
id: "go" id: "go"
data: "components {\n" data: "components {\n"
" id: \"pregame\"\n" " id: \"pregame\"\n"
" component: \"/example/pregame.gui\"\n" " component: \"/example/advanced/pregame.gui\"\n"
" position {\n" " position {\n"
" x: 0.0\n" " x: 0.0\n"
" y: 0.0\n" " y: 0.0\n"

View File

@@ -1,4 +1,4 @@
script: "/example/pregame.gui_script" script: "/example/advanced/pregame.gui_script"
fonts { fonts {
name: "example" name: "example"
font: "/assets/example.font" font: "/assets/example.font"

View File

@@ -0,0 +1,153 @@
name: "basic"
scale_along_z: 0
embedded_instances {
id: "screen1"
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: \"screen1\"\n"
" type: PROPERTY_TYPE_HASH\n"
" }\n"
"}\n"
"embedded_components {\n"
" id: \"collectionproxy\"\n"
" type: \"collectionproxy\"\n"
" data: \"collection: \\\"/example/basic/screen1.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
}
}
embedded_instances {
id: "basic"
data: "components {\n"
" id: \"basic\"\n"
" component: \"/example/basic/basic.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"
"}\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
}
}
embedded_instances {
id: "screen2"
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: \"screen2\"\n"
" type: PROPERTY_TYPE_HASH\n"
" }\n"
"}\n"
"embedded_components {\n"
" id: \"collectionproxy\"\n"
" type: \"collectionproxy\"\n"
" data: \"collection: \\\"/example/basic/screen2.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

@@ -0,0 +1,12 @@
local monarch = require "monarch.monarch"
function init(self)
msg.post(".", "acquire_input_focus")
msg.post("#", "show_screen1")
end
function on_message(self, message_id, message, sender)
if message_id == hash("show_screen1") then
monarch.show("screen1")
end
end

View File

@@ -0,0 +1,37 @@
name: "screen1"
scale_along_z: 0
embedded_instances {
id: "go"
data: "components {\n"
" id: \"screen1\"\n"
" component: \"/example/basic/screen1.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
}
}

131
example/basic/screen1.gui Normal file
View File

@@ -0,0 +1,131 @@
script: "/example/basic/screen1.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: 320.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: "showscreen2"
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 SCREEN 2"
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: "showscreen2"
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,13 @@
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("showscreen2"), action.x, action.y) then
monarch.show("screen2")
end
end
end

View File

@@ -0,0 +1,37 @@
name: "screen2"
scale_along_z: 0
embedded_instances {
id: "go"
data: "components {\n"
" id: \"screen2\"\n"
" component: \"/example/basic/screen2.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
}
}

131
example/basic/screen2.gui Normal file
View File

@@ -0,0 +1,131 @@
script: "/example/basic/screen2.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: 320.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
}
material: "/builtins/materials/gui.material"
adjust_reference: ADJUST_REFERENCE_PARENT
max_nodes: 512

View File

@@ -0,0 +1,13 @@
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()
end
end
end

View File

@@ -4,7 +4,7 @@ version = 0.9
dependencies = https://github.com/britzl/deftest/archive/2.7.0.zip dependencies = https://github.com/britzl/deftest/archive/2.7.0.zip
[bootstrap] [bootstrap]
main_collection = /example/example.collectionc main_collection = /example/advanced/advanced.collectionc
[input] [input]
game_binding = /input/game.input_bindingc game_binding = /input/game.input_bindingc

View File

@@ -33,6 +33,8 @@ M.SCREEN_TRANSITION_OUT_STARTED = hash("monarch_screen_transition_out_started")
M.SCREEN_TRANSITION_OUT_FINISHED = hash("monarch_screen_transition_out_finished") M.SCREEN_TRANSITION_OUT_FINISHED = hash("monarch_screen_transition_out_finished")
M.SCREEN_TRANSITION_FAILED = hash("monarch_screen_transition_failed") M.SCREEN_TRANSITION_FAILED = hash("monarch_screen_transition_failed")
local WAIT_FOR_TRANSITION = true
local DO_NOT_WAIT_FOR_TRANSITION = false
-- all registered screens -- all registered screens
local screens = {} local screens = {}
@@ -47,7 +49,6 @@ 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()
@@ -93,8 +94,8 @@ end
local queue = {} local queue = {}
local function queue_error(message) local function queue_error(message)
print(message)
log("queue() error - clearing queue") log("queue() error - clearing queue")
print(message)
while next(queue) do while next(queue) do
table.remove(queue) table.remove(queue)
end end
@@ -184,7 +185,7 @@ function M.is_visible(id)
assert(id, "You must provide a screen id") assert(id, "You must provide a screen id")
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)))
return screens[id].loaded return screens[id].visible
end end
@@ -337,7 +338,7 @@ end
local function change_context(screen) local function change_context(screen)
log("change_context()", screen.id) log("change_context()", screen.id)
screen.wait_for = CONTEXT screen.wait_for = CONTEXT
msg.post(screen.script, CONTEXT) msg.post(screen.script, CONTEXT, { id = screen.id })
coroutine.yield() coroutine.yield()
screen.wait_for = nil screen.wait_for = nil
end end
@@ -451,12 +452,14 @@ local function load(screen)
return true return true
end end
local function transition(screen, message_id, message) local function transition(screen, message_id, message, wait)
log("transition()", screen.id) log("transition()", screen.id)
if screen.transition_url then if screen.transition_url then
screen.wait_for = M.TRANSITION.DONE screen.wait_for = M.TRANSITION.DONE
msg.post(screen.transition_url, message_id, message) msg.post(screen.transition_url, message_id, message)
coroutine.yield() if wait then
coroutine.yield()
end
screen.wait_for = nil screen.wait_for = nil
else else
log("transition() no transition url - ignoring") log("transition() no transition url - ignoring")
@@ -481,6 +484,7 @@ local function focus_lost(screen, next_screen)
-- the focus_url -- the focus_url
-- we add a delay to ensure the message queue has time to be processed -- we add a delay to ensure the message queue has time to be processed
cowait(0) cowait(0)
cowait(0)
else else
log("focus_lost() no focus url - ignoring") log("focus_lost() no focus url - ignoring")
end end
@@ -538,8 +542,21 @@ local function enable(screen, previous_screen)
end) end)
end end
local function show_out(screen, next_screen, cb) local function show_out(screen, next_screen, wait_for_transition, cb)
log("show_out()", screen.id) log("show_out()", screen.id)
assert(wait_for_transition ~= nil)
-- make sure the screen is loaded. scenario:
-- show A - stack [A]
-- - show_in for A
-- show B with no_stack = true - stack [A]
-- - show_in for B and show_out for A
-- show C
-- - show_in for C and show_out for A again!
if not screen.loaded then
log("show_out() screen was not loaded")
cb()
return
end
run_coroutine(screen, cb, function() run_coroutine(screen, cb, function()
active_transition_count = active_transition_count + 1 active_transition_count = active_transition_count + 1
notify_transition_listeners(M.SCREEN_TRANSITION_OUT_STARTED, { screen = screen.id, next_screen = next_screen.id }) notify_transition_listeners(M.SCREEN_TRANSITION_OUT_STARTED, { screen = screen.id, next_screen = next_screen.id })
@@ -552,7 +569,8 @@ local function show_out(screen, next_screen, cb)
local next_is_popup = next_screen and next_screen.popup local next_is_popup = next_screen and next_screen.popup
local current_is_popup = screen.popup local current_is_popup = screen.popup
if (not next_is_popup and not current_is_popup) or (current_is_popup) then if (not next_is_popup and not current_is_popup) or (current_is_popup) then
transition(screen, M.TRANSITION.SHOW_OUT, { next_screen = next_screen.id }) transition(screen, M.TRANSITION.SHOW_OUT, { next_screen = next_screen.id }, wait_for_transition)
screen.visible = false
unload(screen) unload(screen)
elseif next_is_popup then elseif next_is_popup then
change_timestep(screen) change_timestep(screen)
@@ -562,8 +580,9 @@ local function show_out(screen, next_screen, cb)
end) end)
end end
local function show_in(screen, previous_screen, reload, add_to_stack, cb) local function show_in(screen, previous_screen, reload, add_to_stack, wait_for_transition, cb)
log("show_in()", screen.id) log("show_in()", screen.id, wait_for_transition)
assert(wait_for_transition ~= nil)
run_coroutine(screen, cb, function() run_coroutine(screen, cb, function()
active_transition_count = active_transition_count + 1 active_transition_count = active_transition_count + 1
notify_transition_listeners(M.SCREEN_TRANSITION_IN_STARTED, { screen = screen.id, previous_screen = previous_screen and previous_screen.id }) notify_transition_listeners(M.SCREEN_TRANSITION_IN_STARTED, { screen = screen.id, previous_screen = previous_screen and previous_screen.id })
@@ -572,18 +591,22 @@ local function show_in(screen, previous_screen, reload, add_to_stack, cb)
log("show_in() reloading", screen.id) log("show_in() reloading", screen.id)
unload(screen, reload) unload(screen, reload)
end end
if add_to_stack then
stack[#stack + 1] = screen
end
local ok, err = load(screen) local ok, err = load(screen)
if not ok then if not ok then
log("show_in()", err) log("show_in()", err)
if add_to_stack then
stack[#stack] = nil
end
active_transition_count = active_transition_count - 1 active_transition_count = active_transition_count - 1
notify_transition_listeners(M.SCREEN_TRANSITION_FAILED, { screen = screen.id }) notify_transition_listeners(M.SCREEN_TRANSITION_FAILED, { screen = screen.id })
return return
end end
if add_to_stack then
stack[#stack + 1] = screen
end
reset_timestep(screen) reset_timestep(screen)
transition(screen, M.TRANSITION.SHOW_IN, { previous_screen = previous_screen and previous_screen.id }) transition(screen, M.TRANSITION.SHOW_IN, { previous_screen = previous_screen and previous_screen.id }, wait_for_transition)
screen.visible = true
acquire_input(screen) acquire_input(screen)
focus_gained(screen, previous_screen) focus_gained(screen, previous_screen)
active_transition_count = active_transition_count - 1 active_transition_count = active_transition_count - 1
@@ -591,8 +614,9 @@ local function show_in(screen, previous_screen, reload, add_to_stack, cb)
end) end)
end end
local function back_in(screen, previous_screen, cb) local function back_in(screen, previous_screen, wait_for_transition, cb)
log("back_in()", screen.id) log("back_in()", screen.id)
assert(wait_for_transition ~= nil)
run_coroutine(screen, cb, function() run_coroutine(screen, cb, function()
active_transition_count = active_transition_count + 1 active_transition_count = active_transition_count + 1
notify_transition_listeners(M.SCREEN_TRANSITION_IN_STARTED, { screen = screen.id, previous_screen = previous_screen and previous_screen.id }) notify_transition_listeners(M.SCREEN_TRANSITION_IN_STARTED, { screen = screen.id, previous_screen = previous_screen and previous_screen.id })
@@ -606,8 +630,9 @@ local function back_in(screen, previous_screen, cb)
end end
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 }) transition(screen, M.TRANSITION.BACK_IN, { previous_screen = previous_screen.id }, wait_for_transition)
end end
screen.visible = true
acquire_input(screen) acquire_input(screen)
focus_gained(screen, previous_screen) focus_gained(screen, previous_screen)
active_transition_count = active_transition_count - 1 active_transition_count = active_transition_count - 1
@@ -615,8 +640,9 @@ local function back_in(screen, previous_screen, cb)
end) end)
end end
local function back_out(screen, next_screen, cb) local function back_out(screen, next_screen, wait_for_transition, cb)
log("back_out()", screen.id) log("back_out()", screen.id)
assert(wait_for_transition ~= nil)
run_coroutine(screen, cb, function() run_coroutine(screen, cb, function()
notify_transition_listeners(M.SCREEN_TRANSITION_OUT_STARTED, { screen = screen.id, next_screen = next_screen and next_screen.id }) notify_transition_listeners(M.SCREEN_TRANSITION_OUT_STARTED, { screen = screen.id, next_screen = next_screen and next_screen.id })
active_transition_count = active_transition_count + 1 active_transition_count = active_transition_count + 1
@@ -626,7 +652,8 @@ local function back_out(screen, next_screen, cb)
if next_screen and screen.popup then if next_screen and screen.popup then
reset_timestep(next_screen) reset_timestep(next_screen)
end end
transition(screen, M.TRANSITION.BACK_OUT, { next_screen = next_screen and next_screen.id }) transition(screen, M.TRANSITION.BACK_OUT, { next_screen = next_screen and next_screen.id }, wait_for_transition)
screen.visible = false
unload(screen) unload(screen)
active_transition_count = active_transition_count - 1 active_transition_count = active_transition_count - 1
notify_transition_listeners(M.SCREEN_TRANSITION_OUT_FINISHED, { screen = screen.id, next_screen = next_screen and next_screen.id }) notify_transition_listeners(M.SCREEN_TRANSITION_OUT_FINISHED, { screen = screen.id, next_screen = next_screen and next_screen.id })
@@ -679,9 +706,7 @@ function M.show(id, options, data, cb)
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)))
log("show() queuing action", id)
queue_action(function(action_done, action_error) queue_action(function(action_done, action_error)
log("show()", id)
local screen = screens[id] local screen = screens[id]
if not screen then if not screen then
action_error(("show() there is no longer a screen with id %s"):format(tostring(id))) action_error(("show() there is no longer a screen with id %s"):format(tostring(id)))
@@ -719,21 +744,11 @@ function M.show(id, options, data, cb)
pop = pop - 1 pop = pop - 1
end end
stack[#stack] = nil stack[#stack] = nil
show_out(top, screen, callbacks.track()) show_out(top, screen, WAIT_FOR_TRANSITION, callbacks.track())
callbacks.yield_until_done() callbacks.yield_until_done()
top = stack[#stack] top = stack[#stack]
end end
-- unload the previous screen and transition out from top
-- wait until we are done if showing the same screen as is already visible
if top and not top.popup then
local same_screen = top and top.id == screen.id
show_out(top, screen, callbacks.track())
if same_screen or (options and options.sequential) then
callbacks.yield_until_done()
end
end
-- if the screen we want to show is in the stack -- if the screen we want to show is in the stack
-- already and the clear flag is set then we need -- already and the clear flag is set then we need
-- to remove every screen on the stack up until and -- to remove every screen on the stack up until and
@@ -755,8 +770,8 @@ function M.show(id, options, data, cb)
end end
end end
-- show screen, wait until preloaded if it is already preloading -- wait until preloaded if it is already preloading
-- this can typpically happen if you do a show() on app start for a -- this can typically happen if you do a show() on app start for a
-- screen that has Preload set to true -- screen that has Preload set to true
if M.is_preloading(id) then if M.is_preloading(id) then
M.when_preloaded(id, function() M.when_preloaded(id, function()
@@ -764,7 +779,25 @@ function M.show(id, options, data, cb)
end) end)
coroutine.yield() coroutine.yield()
end end
show_in(screen, top, options and options.reload, add_to_stack, callbacks.track())
-- showing and hiding the same screen?
local same_screen = top and top.id == screen.id
if same_screen or (options and options.sequential) then
if top then
show_out(top, screen, WAIT_FOR_TRANSITION, callbacks.track())
callbacks.yield_until_done()
end
show_in(screen, top, options and options.reload, add_to_stack, WAIT_FOR_TRANSITION, callbacks.track())
else
-- show screen
local cb = callbacks.track()
show_in(screen, top, options and options.reload, add_to_stack, DO_NOT_WAIT_FOR_TRANSITION, function()
if top and not top.popup then
show_out(top, screen, WAIT_FOR_TRANSITION, callbacks.track())
end
cb()
end)
end
callbacks.when_done(function() callbacks.when_done(function()
pcallfn(cb) pcallfn(cb)
@@ -818,7 +851,7 @@ function M.hide(id, cb)
action_error(("hide() there is no longer a screen with id %s"):format(tostring(id))) action_error(("hide() there is no longer a screen with id %s"):format(tostring(id)))
return return
end end
back_out(screen, nil, callbacks.track()) back_out(screen, nil, WAIT_FOR_TRANSITION, callbacks.track())
end end
callbacks.when_done(function() callbacks.when_done(function()
pcallfn(cb) pcallfn(cb)
@@ -845,19 +878,22 @@ function M.back(data, cb)
-- 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
if top and screen.id == top.id then if top and screen.id == top.id then
back_out(screen, top, function() back_out(screen, top, WAIT_FOR_TRANSITION, function()
if data then if data then
top.data = data top.data = data
end end
back_in(top, screen, callbacks.track()) back_in(top, screen, WAIT_FOR_TRANSITION, callbacks.track())
end) end)
else else
back_out(screen, top, callbacks.track())
if top then if top then
if data then if data then
top.data = data top.data = data
end end
back_in(top, screen, callbacks.track()) back_in(top, screen, DO_NOT_WAIT_FOR_TRANSITION, function()
back_out(screen, top, WAIT_FOR_TRANSITION, callbacks.track())
end)
else
back_out(screen, top, WAIT_FOR_TRANSITION, callbacks.track())
end end
end end
end end
@@ -1021,13 +1057,9 @@ function M.post(id, message_id, message)
return false, "Unable to post message since screen has no receiver url specified" return false, "Unable to post message since screen has no receiver url specified"
end end
else else
run_coroutine(screen, nil, function() for id,instance in pairs(screen.factory_ids) do
change_context(screen) msg.post(instance, message_id, message)
log("post() sending message to", screen.receiver_url) end
for id,instance in pairs(screen.factory_ids) do
msg.post(instance, message_id, message)
end
end)
end end
return true return true
end end
@@ -1120,4 +1152,9 @@ function M.dump_stack()
return s return s
end end
function M.queue_size()
return #queue
end
return M return M

View File

@@ -4,7 +4,10 @@ function M.seconds(amount)
local co = coroutine.running() local co = coroutine.running()
assert(co, "You must run this from within a coroutine") assert(co, "You must run this from within a coroutine")
timer.delay(amount, false, function() timer.delay(amount, false, function()
coroutine.resume(co) local ok, err = coroutine.resume(co)
if not ok then
print(err)
end
end) end)
coroutine.yield() coroutine.yield()
end end
@@ -13,10 +16,13 @@ function M.eval(fn, timeout)
local co = coroutine.running() local co = coroutine.running()
assert(co, "You must run this from within a coroutine") assert(co, "You must run this from within a coroutine")
local start = socket.gettime() local start = socket.gettime()
timer.delay(0.01, true, function(self, handle, time_elapsed) timer.delay(0.02, true, function(self, handle, time_elapsed)
if fn() or (timeout and socket.gettime() > (start + timeout)) then if fn() or (timeout and socket.gettime() > (start + timeout)) then
timer.cancel(handle) timer.cancel(handle)
coroutine.resume(co) local ok, err = coroutine.resume(co)
if not ok then
print(err)
end
end end
end) end)
coroutine.yield() coroutine.yield()

View File

@@ -1,5 +1,5 @@
function init(self) function init(self)
local monarch = require "monarch.monarch" local monarch = require "monarch.monarch"
local data = monarch.data(hash("screen_preload")) local data = monarch.data(hash("screen_preload"))
data.count = data.count + 1 if data then data.count = data.count + 1 end
end end

View File

@@ -39,7 +39,7 @@ return function()
local screens_instances = {} local screens_instances = {}
local function is_shown(screen_id) local function is_visible(screen_id)
return monarch.is_visible(screen_id) return monarch.is_visible(screen_id)
end end
@@ -65,9 +65,6 @@ return function()
local function wait_until_visible(screen_id) local function wait_until_visible(screen_id)
return wait_timeout(is_visible, screen_id) return wait_timeout(is_visible, screen_id)
end end
local function wait_until_shown(screen_id)
return wait_timeout(is_shown, screen_id)
end
local function wait_until_hidden(screen_id) local function wait_until_hidden(screen_id)
return wait_timeout(is_hidden, screen_id) return wait_timeout(is_hidden, screen_id)
end end
@@ -77,6 +74,9 @@ return function()
local function wait_until_not_busy() local function wait_until_not_busy()
return wait_timeout(function() return not monarch.is_busy() end) return wait_timeout(function() return not monarch.is_busy() end)
end end
local function wait_until_stack(expected_screens)
return wait_timeout(function() return check_stack(expected_screens) end)
end
local function wait_until_loaded(screen_id) local function wait_until_loaded(screen_id)
wait_until_done(function(done) wait_until_done(function(done)
monarch.when_preloaded(screen_id, done) monarch.when_preloaded(screen_id, done)
@@ -115,75 +115,79 @@ return function()
it("should be able to show screens and go back to previous screens", function() it("should be able to show screens and go back to previous screens", function()
monarch.show(SCREEN1_STR) monarch.show(SCREEN1_STR)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
assert_stack({ SCREEN1 })
monarch.show(SCREEN2) monarch.show(SCREEN2)
assert(wait_until_hidden(SCREEN1), "Screen1 was never hidden") assert(wait_until_stack({ SCREEN1, SCREEN2 }))
assert(wait_until_shown(SCREEN2), "Screen2 was never shown")
assert_stack({ SCREEN1, SCREEN2 })
monarch.back() monarch.back()
assert(wait_until_hidden(SCREEN2), "Screen2 was never hidden") assert(wait_until_stack({ SCREEN1 }))
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
monarch.back() monarch.back()
assert(wait_until_hidden(SCREEN1), "Screen1 was never hidden") assert(wait_until_stack({ }))
assert_stack({ })
end) end)
it("should be able to replace screens at the top of the stack", function() it("should be able to replace screens at the top of the stack", function()
monarch.show(SCREEN1_STR) monarch.show(SCREEN1_STR)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }), "Screen1 was never shown")
assert_stack({ SCREEN1 })
monarch.show(SCREEN2) monarch.show(SCREEN2)
assert(wait_until_hidden(SCREEN1), "Screen1 was never hidden") assert(wait_until_stack({ SCREEN1, SCREEN2 }))
assert(wait_until_shown(SCREEN2), "Screen2 was never shown")
assert_stack({ SCREEN1, SCREEN2 })
monarch.replace(SCREEN1) monarch.replace(SCREEN1)
assert(wait_until_hidden(SCREEN2), "Screen2 was never hidden") assert(wait_until_stack({ SCREEN1, SCREEN1 }))
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1, SCREEN1 })
end) end)
it("should be able to tell if a screen is visible or not", function() it("should be able to tell if a screen is visible or not", function()
assert(not monarch.is_visible(SCREEN1)) assert(not monarch.is_visible(SCREEN1))
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
assert_stack({ SCREEN1 }) assert(wait_until_visible(SCREEN1))
assert(monarch.is_visible(SCREEN1))
monarch.show(SCREEN2) monarch.show(SCREEN2)
assert(wait_until_hidden(SCREEN1), "Screen1 was never hidden") assert(wait_until_stack({ SCREEN1, SCREEN2 }))
assert(wait_until_shown(SCREEN2), "Screen2 was never shown") assert(wait_until_hidden(SCREEN1))
assert_stack({ SCREEN1, SCREEN2 }) assert(wait_until_visible(SCREEN2))
assert(not monarch.is_visible(SCREEN1))
assert(monarch.is_visible(SCREEN2))
monarch.show(POPUP1) monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown") assert(wait_until_stack({ SCREEN1, SCREEN2, POPUP1 }))
assert_stack({ SCREEN1, SCREEN2, POPUP1 }) assert(wait_until_hidden(SCREEN1))
assert(not monarch.is_visible(SCREEN1)) assert(wait_until_visible(SCREEN2))
assert(monarch.is_visible(SCREEN2)) assert(wait_until_visible(POPUP1))
assert(monarch.is_visible(POPUP1))
end) end)
it("should be able to show a screen without adding it to the stack", function() it("should be able to show a screen without adding it to the stack", function()
monarch.show(BACKGROUND, { no_stack = true }) monarch.show(BACKGROUND, { no_stack = true })
assert(wait_until_shown(BACKGROUND), "Background was never shown") assert(wait_until_visible(BACKGROUND), "Background was never shown")
assert_stack({ }) assert(wait_until_stack({ }))
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
assert_stack({ SCREEN1 }) end)
it("should be able to show a screen without adding it to the stack at any time", function()
monarch.show(SCREEN1)
assert(wait_until_not_busy())
assert(wait_until_stack({ SCREEN1 }))
monarch.show(BACKGROUND, { no_stack = true })
assert(wait_until_not_busy())
assert(wait_until_visible(BACKGROUND))
assert(wait_until_stack({ SCREEN1 }))
monarch.show(SCREEN2)
assert(wait_until_not_busy())
assert(wait_until_stack({ SCREEN1, SCREEN2 }))
monarch.back()
assert(wait_until_not_busy())
assert(wait_until_visible(SCREEN1))
assert(wait_until_stack({ SCREEN1 }))
end) end)
it("should be able to hide a screen not added to the stack", function() it("should be able to hide a screen not added to the stack", function()
monarch.show(BACKGROUND, { no_stack = true }) monarch.show(BACKGROUND, { no_stack = true })
assert(wait_until_shown(BACKGROUND), "Background was never shown") assert(wait_until_visible(BACKGROUND), "Background was never shown")
assert_stack({ }) assert_stack({ })
monarch.hide(BACKGROUND) monarch.hide(BACKGROUND)
@@ -193,36 +197,31 @@ return function()
it("should be able to hide the top screen", function() it("should be able to hide the top screen", function()
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
assert_stack({ SCREEN1 })
monarch.show(SCREEN2) monarch.show(SCREEN2)
assert(wait_until_hidden(SCREEN1), "Screen1 was never hidden") assert(wait_until_stack({ SCREEN1, SCREEN2 }))
assert(wait_until_shown(SCREEN2), "Screen2 was never shown")
assert_stack({ SCREEN1, SCREEN2 })
assert(monarch.hide(SCREEN1) == false) assert(monarch.hide(SCREEN1) == false)
assert(monarch.hide(SCREEN2) == true) assert(monarch.hide(SCREEN2) == true)
assert(wait_until_hidden(SCREEN2), "Screen2 was never hidden") assert(wait_until_stack({ SCREEN1 }))
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
end) end)
it("should be able to pass data to a screen when showing it or going back to it", function() it("should be able to pass data to a screen when showing it or going back to it", function()
local data1 = { foo = "bar" } local data1 = { foo = "bar" }
monarch.show(SCREEN1, nil, data1) monarch.show(SCREEN1, nil, data1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_visible(SCREEN1), "Screen1 was never shown")
local data2 = { boo = "car" } local data2 = { boo = "car" }
monarch.show(SCREEN2, nil, data2) monarch.show(SCREEN2, nil, data2)
assert(wait_until_shown(SCREEN2), "Screen2 was never shown") assert(wait_until_visible(SCREEN2), "Screen2 was never shown")
assert(monarch.data(SCREEN1) == data1, "Expected data on screen1 doesn't match actual data") assert(monarch.data(SCREEN1) == data1, "Expected data on screen1 doesn't match actual data")
assert(monarch.data(SCREEN2) == data2, "Expected data on screen2 doesn't match actual data") assert(monarch.data(SCREEN2) == data2, "Expected data on screen2 doesn't match actual data")
local data_back = { going = "back" } local data_back = { going = "back" }
monarch.back(data_back) monarch.back(data_back)
assert(wait_until_shown(SCREEN1)) assert(wait_until_visible(SCREEN1))
assert(monarch.data(SCREEN1) == data_back, "Expected data on screen1 doesn't match actual data") assert(monarch.data(SCREEN1) == data_back, "Expected data on screen1 doesn't match actual data")
end) end)
@@ -230,51 +229,40 @@ return function()
it("should be able to show the same screen twice", function() it("should be able to show the same screen twice", function()
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
assert_stack({ SCREEN1 })
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1, SCREEN1 }))
assert_stack({ SCREEN1, SCREEN1 })
end) end)
it("should be able to clear the stack if trying to show the same screen twice", function() it("should be able to clear the stack if trying to show the same screen twice", function()
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
assert_stack({ SCREEN1 })
monarch.show(SCREEN2) monarch.show(SCREEN2)
assert(wait_until_shown(SCREEN2), "Screen2 was never shown") assert(wait_until_stack({ SCREEN1, SCREEN2 }))
assert_stack({ SCREEN1, SCREEN2 })
monarch.show(SCREEN1, { clear = true }) monarch.show(SCREEN1, { clear = true })
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
assert_stack({ SCREEN1 })
end) end)
it("should be able to show one popup on top of another if the Popup On Popup flag is set", function() it("should be able to show one popup on top of another if the Popup On Popup flag is set", function()
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
assert_stack({ SCREEN1 })
monarch.show(POPUP1) monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown") assert(wait_until_stack({ SCREEN1, POPUP1 }))
assert_stack({ SCREEN1, POPUP1 })
monarch.show(POPUP2) monarch.show(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown") assert(wait_until_stack({ SCREEN1, POPUP1, POPUP2 }))
assert_stack({ SCREEN1, POPUP1, POPUP2 })
end) end)
it("should prevent further operations while hiding/showing a screen", function() it("should be able to queue multiple display commands", function()
monarch.show(SCREEN1) monarch.show(SCREEN1)
monarch.show(SCREEN2) monarch.show(SCREEN2)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1, SCREEN2 }))
assert(wait_until_shown(SCREEN2), "Screen2 was never shown")
assert_stack({ SCREEN1, SCREEN2 })
assert(monarch.back()) assert(monarch.back())
assert(monarch.back()) assert(monarch.back())
assert(wait_until_hidden(SCREEN1), "Screen1 was never hidden") assert(wait_until_stack({}), "Stack never became empty")
assert(wait_until_hidden(SCREEN2), "Screen2 was never hidden")
end) end)
@@ -292,84 +280,63 @@ return function()
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_stack({ SCREEN1 }))
assert_stack({ SCREEN1 })
monarch.show(POPUP2) monarch.show(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown") assert(wait_until_stack({ SCREEN1, POPUP2 }))
assert_stack({ SCREEN1, POPUP2 })
monarch.show(POPUP1) monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown") assert(wait_until_stack({ SCREEN1, POPUP1 }))
assert_stack({ SCREEN1, POPUP1 })
end) end)
it("should close any open popups when showing a non-popup", function() it("should close any open popups when showing a non-popup", function()
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
assert_stack({ SCREEN1 })
monarch.show(POPUP1) monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown") assert(wait_until_stack({ SCREEN1, POPUP1 }))
assert_stack({ SCREEN1, POPUP1 })
monarch.show(POPUP2) monarch.show(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown") assert(wait_until_stack({ SCREEN1, POPUP1, POPUP2 }))
assert_stack({ SCREEN1, POPUP1, POPUP2 })
monarch.show(SCREEN2) monarch.show(SCREEN2)
assert(wait_until_shown(SCREEN2), "Popup2 was never shown") assert(wait_until_stack({ SCREEN1, SCREEN2 }))
assert_stack({ SCREEN1, SCREEN2 })
end) end)
it("should close any open popups when replacing a non-popup", function() it("should close any open popups when replacing a non-popup", function()
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
assert_stack({ SCREEN1 })
monarch.show(POPUP1) monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown") assert(wait_until_stack({ SCREEN1, POPUP1 }))
assert_stack({ SCREEN1, POPUP1 })
monarch.show(POPUP2) monarch.show(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown") assert(wait_until_stack({ SCREEN1, POPUP1, POPUP2 }))
assert_stack({ SCREEN1, POPUP1, POPUP2 })
monarch.replace(SCREEN2) monarch.replace(SCREEN2)
assert(wait_until_shown(SCREEN2), "Screen2 was never shown") assert(wait_until_stack({ SCREEN2 }))
assert_stack({ SCREEN2 })
end) end)
it("should replace a popup", function() it("should replace a popup", function()
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
assert_stack({ SCREEN1 })
monarch.show(POPUP1) monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown") assert(wait_until_stack({ SCREEN1, POPUP1 }))
assert_stack({ SCREEN1, POPUP1 })
monarch.replace(POPUP2) monarch.replace(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown") assert(wait_until_stack({ SCREEN1, POPUP2 }))
assert_stack({ SCREEN1, POPUP2 })
end) end)
it("should replace a pop-up two levels down", function() it("should replace a pop-up two levels down", function()
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
assert_stack({ SCREEN1 })
monarch.show(POPUP1) monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown") assert(wait_until_stack({ SCREEN1, POPUP1 }))
assert_stack({ SCREEN1, POPUP1 })
monarch.show(POPUP2) monarch.show(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown") assert(wait_until_stack({ SCREEN1, POPUP1, POPUP2 }))
assert_stack({ SCREEN1, POPUP1, POPUP2 })
monarch.show(POPUP2, { pop = 2 }) monarch.show(POPUP2, { pop = 2 })
assert(wait_until_shown(POPUP2), "Popup2 was never shown") assert(wait_until_stack({ SCREEN1, POPUP2 }))
assert_stack({ SCREEN1, POPUP2 })
end) end)
it("shouldn't over-pop popups", function() it("shouldn't over-pop popups", function()
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
assert_stack({ SCREEN1 })
monarch.show(POPUP1) monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown") assert(wait_until_stack({ SCREEN1, POPUP1 }))
assert_stack({ SCREEN1, POPUP1 })
monarch.show(POPUP2, { pop = 10 }) monarch.show(POPUP2, { pop = 10 })
assert(wait_until_shown(POPUP2), "Popup2 was never shown") assert(wait_until_stack({ SCREEN1, POPUP2 }))
assert_stack({ SCREEN1, POPUP2 })
end) end)
it("should be able to get the id of the screen at the top and bottom of the stack", function() it("should be able to get the id of the screen at the top and bottom of the stack", function()
@@ -379,7 +346,7 @@ return function()
assert(monarch.bottom(-1) == nil) assert(monarch.bottom(-1) == nil)
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
assert(monarch.top() == SCREEN1) assert(monarch.top() == SCREEN1)
assert(monarch.top(0) == SCREEN1) assert(monarch.top(0) == SCREEN1)
assert(monarch.top(1) == nil) assert(monarch.top(1) == nil)
@@ -388,9 +355,7 @@ return function()
assert(monarch.bottom(-1) == nil) assert(monarch.bottom(-1) == nil)
monarch.show(SCREEN2) monarch.show(SCREEN2)
assert(wait_until_hidden(SCREEN1), "Screen1 was never hidden") assert(wait_until_stack({ SCREEN1, SCREEN2 }))
assert(wait_until_shown(SCREEN2), "Screen2 was never shown")
assert_stack({ SCREEN1, SCREEN2 })
assert(monarch.top(0) == SCREEN2) assert(monarch.top(0) == SCREEN2)
assert(monarch.top(-1) == SCREEN1) assert(monarch.top(-1) == SCREEN1)
assert(monarch.bottom(0) == SCREEN1) assert(monarch.bottom(0) == SCREEN1)
@@ -399,8 +364,8 @@ return function()
it("should be busy while transition is running", function() it("should be busy while transition is running", function()
monarch.show(TRANSITION1) monarch.show(TRANSITION1)
assert(wait_until_shown(TRANSITION1), "Transition1 was never shown")
assert(monarch.is_busy()) assert(monarch.is_busy())
assert(wait_until_visible(TRANSITION1), "Transition1 was never shown")
assert(wait_until_not_busy()) assert(wait_until_not_busy())
end) end)
@@ -418,7 +383,7 @@ return function()
-- previously a call to preload() while also showing a screen would -- previously a call to preload() while also showing a screen would
-- lock up monarch. See issue #32 -- lock up monarch. See issue #32
monarch.preload(TRANSITION1) monarch.preload(TRANSITION1)
assert(wait_until_shown(TRANSITION1), "Transition1 was never shown") assert(wait_until_visible(TRANSITION1), "Transition1 was never shown")
end) end)
it("should be able to notify listeners of navigation events", function() it("should be able to notify listeners of navigation events", function()
@@ -428,11 +393,11 @@ return function()
monarch.add_listener(URL2) monarch.add_listener(URL2)
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_not_busy())
assert(mock_msg.messages(URL1)[1].message_id == monarch.SCREEN_TRANSITION_IN_STARTED) assert(mock_msg.messages(URL1)[1].message_id == monarch.SCREEN_TRANSITION_IN_STARTED)
assert(mock_msg.messages(URL1)[1].message.screen == SCREEN1) assert(mock_msg.messages(URL1)[1].message.screen == SCREEN1)
assert(mock_msg.messages(URL2)[1].message_id == monarch.SCREEN_TRANSITION_IN_STARTED) assert(mock_msg.messages(URL2)[1].message_id == monarch.SCREEN_TRANSITION_IN_STARTED)
assert(mock_msg.messages(URL2)[1].message.screen == SCREEN1) assert(mock_msg.messages(URL2)[1].message.screen == SCREEN1)
assert(wait_until_not_busy())
assert(mock_msg.messages(URL1)[2].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED) assert(mock_msg.messages(URL1)[2].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED)
assert(mock_msg.messages(URL1)[2].message.screen == SCREEN1) assert(mock_msg.messages(URL1)[2].message.screen == SCREEN1)
assert(mock_msg.messages(URL2)[2].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED) assert(mock_msg.messages(URL2)[2].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED)
@@ -444,12 +409,12 @@ return function()
assert(#mock_msg.messages(URL1) == 6) assert(#mock_msg.messages(URL1) == 6)
assert(#mock_msg.messages(URL2) == 2) assert(#mock_msg.messages(URL2) == 2)
assert(mock_msg.messages(URL1)[3].message_id == monarch.SCREEN_TRANSITION_OUT_STARTED) assert(mock_msg.messages(URL1)[3].message_id == monarch.SCREEN_TRANSITION_IN_STARTED)
assert(mock_msg.messages(URL1)[3].message.screen == SCREEN1) assert(mock_msg.messages(URL1)[3].message.screen == SCREEN2)
assert(mock_msg.messages(URL1)[4].message_id == monarch.SCREEN_TRANSITION_IN_STARTED) assert(mock_msg.messages(URL1)[4].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED)
assert(mock_msg.messages(URL1)[4].message.screen == SCREEN2) assert(mock_msg.messages(URL1)[4].message.screen == SCREEN2)
assert(mock_msg.messages(URL1)[5].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED) assert(mock_msg.messages(URL1)[5].message_id == monarch.SCREEN_TRANSITION_OUT_STARTED)
assert(mock_msg.messages(URL1)[5].message.screen == SCREEN2) assert(mock_msg.messages(URL1)[5].message.screen == SCREEN1)
assert(mock_msg.messages(URL1)[6].message_id == monarch.SCREEN_TRANSITION_OUT_FINISHED) assert(mock_msg.messages(URL1)[6].message_id == monarch.SCREEN_TRANSITION_OUT_FINISHED)
assert(mock_msg.messages(URL1)[6].message.screen == SCREEN1) assert(mock_msg.messages(URL1)[6].message.screen == SCREEN1)
@@ -458,24 +423,24 @@ return function()
assert(#mock_msg.messages(URL1) == 10) assert(#mock_msg.messages(URL1) == 10)
assert(#mock_msg.messages(URL2) == 2) assert(#mock_msg.messages(URL2) == 2)
assert(mock_msg.messages(URL1)[7].message_id == monarch.SCREEN_TRANSITION_OUT_STARTED) assert(mock_msg.messages(URL1)[7].message_id == monarch.SCREEN_TRANSITION_IN_STARTED)
assert(mock_msg.messages(URL1)[7].message.screen == SCREEN2) assert(mock_msg.messages(URL1)[7].message.screen == SCREEN1)
assert(mock_msg.messages(URL1)[8].message_id == monarch.SCREEN_TRANSITION_IN_STARTED) assert(mock_msg.messages(URL1)[8].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED)
assert(mock_msg.messages(URL1)[8].message.screen == SCREEN1) assert(mock_msg.messages(URL1)[8].message.screen == SCREEN1)
assert(mock_msg.messages(URL1)[9].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED) assert(mock_msg.messages(URL1)[9].message_id == monarch.SCREEN_TRANSITION_OUT_STARTED)
assert(mock_msg.messages(URL1)[9].message.screen == SCREEN1) assert(mock_msg.messages(URL1)[9].message.screen == SCREEN2)
assert(mock_msg.messages(URL1)[10].message_id == monarch.SCREEN_TRANSITION_OUT_FINISHED) assert(mock_msg.messages(URL1)[10].message_id == monarch.SCREEN_TRANSITION_OUT_FINISHED)
assert(mock_msg.messages(URL1)[10].message.screen == SCREEN2) assert(mock_msg.messages(URL1)[10].message.screen == SCREEN2)
end) end)
it("should be able to show a screen even while it is preloading", function() it("should be able to show a screen even while it is preloading", function()
monarch.show(SCREEN_PRELOAD, nil, { count = 1 }) monarch.show(SCREEN_PRELOAD, nil, { count = 1 })
assert(wait_until_shown(SCREEN_PRELOAD), "Screen_preload was never shown") assert(wait_until_visible(SCREEN_PRELOAD), "Screen_preload was never shown")
end) end)
it("should be able to preload a screen and always keep it loaded", function() it("should be able to preload a screen and always keep it loaded", function()
monarch.show(SCREEN_PRELOAD) monarch.show(SCREEN_PRELOAD)
assert(wait_until_shown(SCREEN_PRELOAD), "Screen_preload was never shown") assert(wait_until_visible(SCREEN_PRELOAD), "Screen_preload was never shown")
monarch.back() monarch.back()
assert(wait_until_hidden(SCREEN_PRELOAD), "Screen_preload was never hidden") assert(wait_until_hidden(SCREEN_PRELOAD), "Screen_preload was never hidden")
assert(monarch.is_preloaded(SCREEN_PRELOAD)) assert(monarch.is_preloaded(SCREEN_PRELOAD))
@@ -483,12 +448,12 @@ return function()
it("should be able to reload a preloaded screen", function() it("should be able to reload a preloaded screen", function()
monarch.show(SCREEN_PRELOAD, nil, { count = 1 }) monarch.show(SCREEN_PRELOAD, nil, { count = 1 })
assert(wait_until_shown(SCREEN_PRELOAD), "Screen_preload was never shown") assert(wait_until_visible(SCREEN_PRELOAD), "Screen_preload was never shown")
-- first time the screen gets loaded it will increment the count -- first time the screen gets loaded it will increment the count
assert(monarch.data(SCREEN_PRELOAD).count == 2) assert(monarch.data(SCREEN_PRELOAD).count == 2)
monarch.show(SCREEN_PRELOAD, { clear = true, reload = true }, { count = 1 }) monarch.show(SCREEN_PRELOAD, { clear = true, reload = true }, { count = 1 })
assert(wait_until_shown(SCREEN_PRELOAD), "Screen_preload was never shown") assert(wait_until_visible(SCREEN_PRELOAD), "Screen_preload was never shown")
-- second time the screen gets shown it will be reloaded and increment the count -- second time the screen gets shown it will be reloaded and increment the count
assert(monarch.data(SCREEN_PRELOAD).count == 2) assert(monarch.data(SCREEN_PRELOAD).count == 2)
end) end)
@@ -499,13 +464,14 @@ return function()
_G.focus1_lost = nil _G.focus1_lost = nil
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1 }))
monarch.show(FOCUS1) monarch.show(FOCUS1)
assert(wait_until_shown(FOCUS1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1, FOCUS1 }))
assert(wait_until_visible(FOCUS1))
assert(_G.focus1_gained) assert(_G.focus1_gained)
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_stack({ SCREEN1, FOCUS1, SCREEN1 }))
assert(wait_until_hidden(FOCUS1), "Focus1 was never hidden") assert(wait_until_hidden(FOCUS1))
assert(_G.focus1_lost) assert(_G.focus1_lost)
end) end)
@@ -516,14 +482,14 @@ return function()
-- proxy screen -- proxy screen
monarch.show(SCREEN1) monarch.show(SCREEN1)
wait_until_shown(SCREEN1) wait_until_visible(SCREEN1)
assert(monarch.post(SCREEN1, "foobar"), "Expected monarch.post() to return true") assert(monarch.post(SCREEN1, "foobar"), "Expected monarch.post() to return true")
cowait(0.1) cowait(0.1)
assert(_G.screen1_foobar, "Screen1 never received a message") assert(_G.screen1_foobar, "Screen1 never received a message")
-- factory screen -- factory screen
monarch.show(SCREEN2) monarch.show(SCREEN2)
wait_until_shown(SCREEN2) wait_until_visible(SCREEN2)
assert(monarch.post(SCREEN2, "foobar"), "Expected monarch.post() to return true") assert(monarch.post(SCREEN2, "foobar"), "Expected monarch.post() to return true")
cowait(0.1) cowait(0.1)
assert(_G.screen2_foobar, "Screen2 never received a message") assert(_G.screen2_foobar, "Screen2 never received a message")
@@ -536,7 +502,7 @@ return function()
-- proxy screen -- proxy screen
monarch.show(SCREEN1) monarch.show(SCREEN1)
wait_until_shown(SCREEN1) wait_until_visible(SCREEN1)
assert(monarch.post(SCREEN1, "foobar", { foo = "bar" }), "Expected monarch.post() to return true") assert(monarch.post(SCREEN1, "foobar", { foo = "bar" }), "Expected monarch.post() to return true")
cowait(0.1) cowait(0.1)
assert(_G.screen1_foobar, "Screen1 never received a message") assert(_G.screen1_foobar, "Screen1 never received a message")
@@ -544,7 +510,7 @@ return function()
-- factory screen -- factory screen
monarch.show(SCREEN2) monarch.show(SCREEN2)
wait_until_shown(SCREEN2) wait_until_visible(SCREEN2)
assert(monarch.post(SCREEN2, "foobar", { foo = "bar" }), "Expected monarch.post() to return true") assert(monarch.post(SCREEN2, "foobar", { foo = "bar" }), "Expected monarch.post() to return true")
cowait(0.1) cowait(0.1)
assert(_G.screen2_foobar, "Screen2 never received a message") assert(_G.screen2_foobar, "Screen2 never received a message")
@@ -556,9 +522,9 @@ return function()
_G.screen1_foobar = nil _G.screen1_foobar = nil
monarch.show(SCREEN1) monarch.show(SCREEN1)
wait_until_shown(SCREEN1)
monarch.show(SCREEN2) monarch.show(SCREEN2)
wait_until_shown(SCREEN2) assert(wait_until_stack({ SCREEN1, SCREEN2 }))
assert(wait_until_hidden(SCREEN1))
local ok, err = monarch.post(SCREEN1, "foobar") local ok, err = monarch.post(SCREEN1, "foobar")
assert(not ok and err, "Expected monarch.post() to return false plus an error message") assert(not ok and err, "Expected monarch.post() to return false plus an error message")
cowait(0.1) cowait(0.1)
@@ -568,7 +534,7 @@ return function()
it("should not be able to post messages to proxy screens without a receiver url", function() it("should not be able to post messages to proxy screens without a receiver url", function()
monarch.show(POPUP1) monarch.show(POPUP1)
wait_until_shown(POPUP1) wait_until_visible(POPUP1)
local ok, err = monarch.post(POPUP1, "foobar") local ok, err = monarch.post(POPUP1, "foobar")
assert(not ok and err, "Expected monarch.post() to return false plus an error message") assert(not ok and err, "Expected monarch.post() to return false plus an error message")
end) end)