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

Compare commits

..

No commits in common. "master" and "4.0.1" have entirely different histories.

26 changed files with 247 additions and 350 deletions

View File

@ -7,13 +7,13 @@ jobs:
name: Build and run name: Build and run
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - uses: actions/checkout@v1
- uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 - uses: actions/setup-java@v1
with: with:
java-version: '21.0.5+11.0.LTS' java-version: '11'
distribution: 'temurin'
- name: Run.sh - name: Run.sh
env: env:
DEFOLD_USER: bjorn.ritzl@gmail.com DEFOLD_USER: bjorn.ritzl@gmail.com
DEFOLD_AUTH: foobar DEFOLD_AUTH: foobar
DEFOLD_BOOSTRAP_COLLECTION: /test/test.collectionc
run: ./.test/run.sh run: ./.test/run.sh

3
.gitignore vendored
View File

@ -9,6 +9,3 @@ build
builtins builtins
.internal .internal
luacov.report.out luacov.report.out
/.editor_settings
manifest.private.der
manifest.public.der

View File

@ -5,6 +5,7 @@ else
PLATFORM="$1" PLATFORM="$1"
fi fi
echo "${PLATFORM}" echo "${PLATFORM}"
# {"version": "1.2.89", "sha1": "5ca3dd134cc960c35ecefe12f6dc81a48f212d40"} # {"version": "1.2.89", "sha1": "5ca3dd134cc960c35ecefe12f6dc81a48f212d40"}
@ -15,28 +16,26 @@ echo "Using Defold dmengine_headless version ${SHA1}"
# Create dmengine_headless and bob.jar URLs # Create dmengine_headless and bob.jar URLs
DMENGINE_URL="http://d.defold.com/archive/${SHA1}/engine/${PLATFORM}/dmengine_headless" DMENGINE_URL="http://d.defold.com/archive/${SHA1}/engine/${PLATFORM}/dmengine_headless"
BOB_URL="http://d.defold.com/archive/${SHA1}/bob/bob.jar" BOB_URL="http://d.defold.com/archive/${SHA1}/bob/bob.jar"
DMENGINE_FILE=dmengine_headless_${SHA1}
BOB_FILE=bob_${SHA1}.jar
# Download dmengine_headless # Download dmengine_headless
if ! [ -f ${DMENGINE_FILE} ]; then echo "Downloading ${DMENGINE_URL}"
echo "Downloading ${DMENGINE_URL} to ${DMENGINE_FILE}" curl -L -o dmengine_headless ${DMENGINE_URL}
curl -L -o ${DMENGINE_FILE} ${DMENGINE_URL} chmod +x dmengine_headless
chmod +x ${DMENGINE_FILE}
fi
# Download bob.jar # Download bob.jar
if ! [ -f ${BOB_FILE} ]; then echo "Downloading ${BOB_URL}"
echo "Downloading ${BOB_URL} to ${BOB_FILE}" curl -L -o bob.jar ${BOB_URL}
curl -L -o ${BOB_FILE} ${BOB_URL}
fi
# Fetch libraries # Fetch libraries
echo "Running ${BOB_FILE} - resolving dependencies" echo "Running bob.jar - resolving dependencies"
java -jar ${BOB_FILE} --auth "foobar" --email "john@doe.com" resolve java -jar bob.jar --auth "foobar" --email "john@doe.com" resolve
echo "Running ${BOB_FILE} - building" echo "Running bob.jar - building"
java -jar ${BOB_FILE} --debug build --settings=test.settings java -jar bob.jar --debug build --keep-unused
echo "Starting ${DMENGINE_FILE}" echo "Starting dmengine_headless"
./${DMENGINE_FILE} if [ -n "${DEFOLD_BOOSTRAP_COLLECTION}" ]; then
./dmengine_headless --config=bootstrap.main_collection=${DEFOLD_BOOSTRAP_COLLECTION}
else
./dmengine_headless
fi

View File

@ -40,18 +40,13 @@ Clear the stack of screens completely. Any visible screen will be hidden by navi
* `callback` (function) - Optional function to call when the stack has been cleared. * `callback` (function) - Optional function to call when the stack has been cleared.
## monarch.back([options], [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.
**PARAMETERS** **PARAMETERS**
* `options` (table) - Options when showing the new screen (see below).
* `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.
The options table can contain the following fields:
* `sequential` (boolean) - If the `sequential` flag is set Monarch will start loading the screen only after the previous screen finished transitioning out.
## monarch.preload(screen_id, [options], [callback]) ## monarch.preload(screen_id, [options], [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. This operation will be added to the queue if Monarch is busy. 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. This operation will be added to the queue if Monarch is busy.
@ -182,7 +177,7 @@ Remove a previously added listener.
## monarch.post(screen_id, message_id, [message]) ## monarch.post(screen_id, message_id, [message])
Post a message to a visible screen. The screen must have set a message listener using `monarch.on_post()`. Post a message to a visible screen. If the screen is created through a collection proxy it must have specified a receiver url. If the screen is created through a collection factory the function will post the message to all game objects within the collection.
**PARAMETERS** **PARAMETERS**
* `screen_id` (string|hash) - Id of the screen to post message to * `screen_id` (string|hash) - Id of the screen to post message to
@ -212,21 +207,12 @@ IMPORTANT! You must call `monarch.on_message(message_id, message, sender)` from
* `fn` (function) - The function to call screen focus changes * `fn` (function) - The function to call screen focus changes
## monarch.on_post(screen_id, fn_or_url) ## monarch.on_post(screen_id, fn)
Set either a function to be called when `msg.post()` is called on a specific screen or a URL where the message is sent. Set a function to be called when `msg.post()` is called on a specific screen. IMPORTANT! You must call `monarch.on_message(message_id, message, sender)` from the same script as this function was called.
IMPORTANT! If you provide a function you must also make sure to call `monarch.on_message(message_id, message, sender)` from the same script as this function was called.
**PARAMETERS** **PARAMETERS**
* `screen_id` (string|hash) - Id of the screen * `screen_id` (string|hash) - Id of the screen
* `fn_or_url` (function) - The function to call or URL to send message to * `fn` (function) - The function to call when the screen receives a message using `msg.post`
## monarch.has_missing_resources(screen_id)
Check if a screen has any missing resources. If the screen is loaded by a collection proxy with Load Dynamically this will use `collectionproxy.missing_resources()`. For other cases this function will always return false.
**RETURN**
* `result` (boolean) - true if the screen has missing resources
## monarch.debug() ## monarch.debug()

View File

@ -114,7 +114,7 @@ end
function on_message(self, message_id, message, sender) function on_message(self, message_id, message, sender)
if message_id == hash("my_resize_message") then if message_id == hash("my_resize_message") then
transition.window_resized(message.width, message.height) self.transition.window_resized(message.width, message.height)
end end
end end
``` ```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -5,13 +5,11 @@ function init(self)
msg.post(".", "acquire_input_focus") msg.post(".", "acquire_input_focus")
gui.set_render_order(15) gui.set_render_order(15)
local transition = transitions.create(gui.get_node("root")) self.transition = transitions.create(gui.get_node("root"))
.show_in(transitions.slide_in_top, gui.EASING_OUTQUAD, 0.6, 0) .show_in(transitions.slide_in_top, gui.EASING_OUTQUAD, 0.6, 0)
.show_out(transitions.slide_out_top, gui.EASING_INQUAD, 0.6, 0) .show_out(transitions.slide_out_top, gui.EASING_INQUAD, 0.6, 0)
.back_in(transitions.slide_in_top, gui.EASING_OUTQUAD, 0.6, 0) .back_in(transitions.slide_in_top, gui.EASING_OUTQUAD, 0.6, 0)
.back_out(transitions.slide_out_top, gui.EASING_INQUAD, 0.6, 0) .back_out(transitions.slide_out_top, gui.EASING_INQUAD, 0.6, 0)
monarch.on_transition("about", transition)
end end
function on_input(self, action_id, action) function on_input(self, action_id, action)
@ -29,5 +27,5 @@ function on_input(self, action_id, action)
end end
function on_message(self, message_id, message, sender) function on_message(self, message_id, message, sender)
monarch.on_message(message_id, message, sender) self.transition.handle(message_id, message, sender)
end end

View File

@ -21,6 +21,16 @@ embedded_instances {
" value: \"menu\"\n" " value: \"menu\"\n"
" type: PROPERTY_TYPE_HASH\n" " type: PROPERTY_TYPE_HASH\n"
" }\n" " }\n"
" properties {\n"
" id: \"transition_id\"\n"
" value: \"/go\"\n"
" type: PROPERTY_TYPE_HASH\n"
" }\n"
" properties {\n"
" id: \"focus_id\"\n"
" value: \"/go\"\n"
" type: PROPERTY_TYPE_HASH\n"
" }\n"
" property_decls {\n" " property_decls {\n"
" }\n" " }\n"
"}\n" "}\n"
@ -136,6 +146,11 @@ embedded_instances {
" value: \"pregame\"\n" " value: \"pregame\"\n"
" type: PROPERTY_TYPE_HASH\n" " type: PROPERTY_TYPE_HASH\n"
" }\n" " }\n"
" properties {\n"
" id: \"transition_url\"\n"
" value: \"pregame:/go#pregame\"\n"
" type: PROPERTY_TYPE_URL\n"
" }\n"
" property_decls {\n" " property_decls {\n"
" }\n" " }\n"
"}\n" "}\n"
@ -196,6 +211,11 @@ embedded_instances {
" value: \"game\"\n" " value: \"game\"\n"
" type: PROPERTY_TYPE_HASH\n" " type: PROPERTY_TYPE_HASH\n"
" }\n" " }\n"
" properties {\n"
" id: \"transition_url\"\n"
" value: \"game:/go#game\"\n"
" type: PROPERTY_TYPE_URL\n"
" }\n"
" property_decls {\n" " property_decls {\n"
" }\n" " }\n"
"}\n" "}\n"
@ -267,6 +287,16 @@ embedded_instances {
" type: PROPERTY_TYPE_BOOLEAN\n" " type: PROPERTY_TYPE_BOOLEAN\n"
" }\n" " }\n"
" properties {\n" " properties {\n"
" id: \"transition_url\"\n"
" value: \"about:/go#about\"\n"
" type: PROPERTY_TYPE_URL\n"
" }\n"
" properties {\n"
" id: \"focus_url\"\n"
" value: \"about:/go#about\"\n"
" type: PROPERTY_TYPE_URL\n"
" }\n"
" properties {\n"
" id: \"preload\"\n" " id: \"preload\"\n"
" value: \"true\"\n" " value: \"true\"\n"
" type: PROPERTY_TYPE_BOOLEAN\n" " type: PROPERTY_TYPE_BOOLEAN\n"
@ -346,6 +376,11 @@ embedded_instances {
" value: \"true\"\n" " value: \"true\"\n"
" type: PROPERTY_TYPE_BOOLEAN\n" " type: PROPERTY_TYPE_BOOLEAN\n"
" }\n" " }\n"
" properties {\n"
" id: \"transition_url\"\n"
" value: \"confirm:/go#confirm\"\n"
" type: PROPERTY_TYPE_URL\n"
" }\n"
" property_decls {\n" " property_decls {\n"
" }\n" " }\n"
"}\n" "}\n"

View File

@ -7,13 +7,11 @@ function init(self)
self.no = gui.get_node("no_button") self.no = gui.get_node("no_button")
gui.set_render_order(15) gui.set_render_order(15)
local transition = transitions.create(gui.get_node("root")) self.transition = transitions.create(gui.get_node("root"))
.show_in(transitions.scale_in, gui.EASING_OUTBACK, 0.3, 0) .show_in(transitions.scale_in, gui.EASING_OUTBACK, 0.3, 0)
.show_out(transitions.scale_out, gui.EASING_INBACK, 0.3, 0) .show_out(transitions.scale_out, gui.EASING_INBACK, 0.3, 0)
.back_in(transitions.scale_in, gui.EASING_OUTBACK, 0.3, 0) .back_in(transitions.scale_in, gui.EASING_OUTBACK, 0.3, 0)
.back_out(transitions.scale_out, gui.EASING_INBACK, 0.3, 0) .back_out(transitions.scale_out, gui.EASING_INBACK, 0.3, 0)
monarch.on_transition("confirm", transition)
end end
function on_input(self, action_id, action) function on_input(self, action_id, action)
@ -29,7 +27,7 @@ function on_input(self, action_id, action)
end end
elseif gui.pick_node(self.no, action.x, action.y) then elseif gui.pick_node(self.no, action.x, action.y) then
print("no") print("no")
monarch.back(nil, nil, function() monarch.back(function()
print("back from popup done") print("back from popup done")
end) end)
end end
@ -37,5 +35,5 @@ function on_input(self, action_id, action)
end end
function on_message(self, message_id, message, sender) function on_message(self, message_id, message, sender)
monarch.on_message(message_id, message, sender) self.transition.handle(message_id, message, sender)
end end

View File

@ -3,12 +3,11 @@ local transitions = require "monarch.transitions.gui"
function init(self) function init(self)
msg.post(".", "acquire_input_focus") msg.post(".", "acquire_input_focus")
local data = monarch.data(hash("game")) local data = monarch.data(hash("game"))
gui.set_text(gui.get_node("level"), tostring(data.level)) gui.set_text(gui.get_node("level"), tostring(data.level))
local transition = transitions.in_right_out_left(gui.get_node("root"), 0.6, 0) self.transition = transitions.in_right_out_left(gui.get_node("root"), 0.6, 0)
monarch.on_transition("game", transition)
end end
function on_input(self, action_id, action) function on_input(self, action_id, action)
@ -22,5 +21,5 @@ function on_input(self, action_id, action)
end end
function on_message(self, message_id, message, sender) function on_message(self, message_id, message, sender)
monarch.on_message(message_id, message, sender) self.transition.handle(message_id, message, sender)
end end

View File

@ -8,8 +8,7 @@ function init(self)
gui.animate(gui.get_node("spinner"), gui.PROP_ROTATION, vmath.vector3(0, 0, -360), gui.EASING_INOUTQUAD, 2, 0, nil, gui.PLAYBACK_LOOP_FORWARD) gui.animate(gui.get_node("spinner"), gui.PROP_ROTATION, vmath.vector3(0, 0, -360), gui.EASING_INOUTQUAD, 2, 0, nil, gui.PLAYBACK_LOOP_FORWARD)
local transition = transitions.fade_in_out(gui.get_node("root"), 0.6, 0) self.transition = transitions.fade_in_out(gui.get_node("root"), 0.6, 0)
monarch.on_transition("menu", transition)
end end
function on_input(self, action_id, action) function on_input(self, action_id, action)
@ -29,7 +28,7 @@ function on_input(self, action_id, action)
end end
function on_message(self, message_id, message, sender) function on_message(self, message_id, message, sender)
monarch.on_message(message_id, message, sender) self.transition.handle(message_id, message, sender)
if message_id == monarch.FOCUS.GAINED then if message_id == monarch.FOCUS.GAINED then
gui.set_text(gui.get_node("timestamp"), os.date()) gui.set_text(gui.get_node("timestamp"), os.date())
end end

View File

@ -9,13 +9,12 @@ function init(self)
gui.set_render_order(14) gui.set_render_order(14)
gui.animate(gui.get_node("spinner"), gui.PROP_ROTATION, vmath.vector3(0, 0, -360), gui.EASING_INOUTQUAD, 2, 0, nil, gui.PLAYBACK_LOOP_FORWARD) gui.animate(gui.get_node("spinner"), gui.PROP_ROTATION, vmath.vector3(0, 0, -360), gui.EASING_INOUTQUAD, 2, 0, nil, gui.PLAYBACK_LOOP_FORWARD)
local transition = transitions.create(gui.get_node("root")) self.transition = transitions.create(gui.get_node("root"))
.show_in(transitions.scale_in, gui.EASING_OUTBACK, 0.3, 0) .show_in(transitions.scale_in, gui.EASING_OUTBACK, 0.3, 0)
.show_out(transitions.scale_out, gui.EASING_INBACK, 0.3, 0) .show_out(transitions.scale_out, gui.EASING_INBACK, 0.3, 0)
.back_in(transitions.scale_in, gui.EASING_OUTBACK, 0.3, 0) .back_in(transitions.scale_in, gui.EASING_OUTBACK, 0.3, 0)
.back_out(transitions.scale_out, gui.EASING_INBACK, 0.3, 0) .back_out(transitions.scale_out, gui.EASING_INBACK, 0.3, 0)
monarch.on_transition("popup", transition)
end end
function on_input(self, action_id, action) function on_input(self, action_id, action)
@ -27,7 +26,7 @@ function on_input(self, action_id, action)
end) end)
elseif gui.pick_node(self.cancel, action.x, action.y) then elseif gui.pick_node(self.cancel, action.x, action.y) then
print("cancel") print("cancel")
monarch.back(nil, nil, function() monarch.back(function()
print("back from popup done") print("back from popup done")
end) end)
elseif gui.pick_node(self.about, action.x, action.y) then elseif gui.pick_node(self.about, action.x, action.y) then
@ -40,5 +39,5 @@ function on_input(self, action_id, action)
end end
function on_message(self, message_id, message, sender) function on_message(self, message_id, message, sender)
monarch.on_message(message_id, message, sender) self.transition.handle(message_id, message, sender)
end end

View File

@ -5,9 +5,8 @@ function init(self)
msg.post(".", "acquire_input_focus") msg.post(".", "acquire_input_focus")
self.play = gui.get_node("play_button") self.play = gui.get_node("play_button")
self.back = gui.get_node("back_button") self.back = gui.get_node("back_button")
local transition = transitions.in_right_out_left(gui.get_node("root"), 0.6, 0) self.transition = transitions.in_right_out_left(gui.get_node("root"), 0.6, 0)
monarch.on_transition("pregame", transition)
end end
function on_input(self, action_id, action) function on_input(self, action_id, action)
@ -19,7 +18,7 @@ function on_input(self, action_id, action)
end) end)
elseif gui.pick_node(self.back, action.x, action.y) then elseif gui.pick_node(self.back, action.x, action.y) then
print("back") print("back")
monarch.back(nil, nil, function() monarch.back(function()
print("back from pregame done") print("back from pregame done")
end) end)
end end
@ -27,5 +26,5 @@ function on_input(self, action_id, action)
end end
function on_message(self, message_id, message, sender) function on_message(self, message_id, message, sender)
monarch.on_message(message_id, message, sender) self.transition.handle(message_id, message, sender)
end end

View File

@ -4,25 +4,10 @@ function init(self)
monarch.debug() monarch.debug()
msg.post("@render:/", "clear_color", { color = vmath.vector4(0.4, 0.6, 0.8,1.0) }) msg.post("@render:/", "clear_color", { color = vmath.vector4(0.4, 0.6, 0.8,1.0) })
msg.post("#", "init_monarch") -- wait until init() has been called for all screen.script instances msg.post("#", "init_monarch") -- wait until init() has been called for all screen.script instances
monarch.add_listener()
end
function final(self)
monarch.remove_listener()
end end
function on_message(self, message_id, message, sender) function on_message(self, message_id, message, sender)
if message_id == hash("init_monarch") then if message_id == hash("init_monarch") then
monarch.show(hash("window1")) monarch.show(hash("window1"))
elseif message_id == monarch.SCREEN_TRANSITION_IN_STARTED then
print("Monarch screen transition in started", message.screen)
elseif message_id == monarch.SCREEN_TRANSITION_IN_FINISHED then
print("Monarch screen transition in finished", message.screen)
elseif message_id == monarch.SCREEN_TRANSITION_OUT_STARTED then
print("Monarch screen transition out started", message.screen)
elseif message_id == monarch.SCREEN_TRANSITION_OUT_FINISHED then
print("Monarch screen transition out finished", message.screen)
elseif message_id == monarch.SCREEN_TRANSITION_FAILED then
print("Monarch screen transition failed")
end end
end end

View File

@ -23,5 +23,6 @@ function on_input(self, action_id, action)
end end
function on_message(self, message_id, message, sender) function on_message(self, message_id, message, sender)
print("window2", message_id, message, sender)
monarch.on_message(message_id, message, sender) monarch.on_message(message_id, message, sender)
end end

View File

@ -5,7 +5,7 @@ dependencies#0 = https://github.com/britzl/deftest/archive/2.7.0.zip
dependencies#1 = https://github.com/defold/lua-language-server/releases/download/v0.0.3/release.zip dependencies#1 = https://github.com/defold/lua-language-server/releases/download/v0.0.3/release.zip
[bootstrap] [bootstrap]
main_collection = /example/advanced/advanced.collectionc main_collection = /example/slidingwindow/slidingwindow.collectionc
[input] [input]
game_binding = /input/game.input_bindingc game_binding = /input/game.input_bindingc

View File

@ -79,9 +79,16 @@ end
gui_template = function(gui_script) gui_template = function(gui_script)
return [[script: "]].. gui_script .. [[" return [[script: "]].. gui_script .. [["
material: "/builtins/materials/gui.material" background_color {
adjust_reference: ADJUST_REFERENCE_PARENT x: 0.0
]] y: 0.0
z: 0.0
w: 0.0
}
material: "/builtins/materials/gui.material"
adjust_reference: ADJUST_REFERENCE_PARENT
max_nodes: 512
]]
end end
gui_script_content = [[local monarch = require "monarch.monarch" gui_script_content = [[local monarch = require "monarch.monarch"
@ -109,43 +116,43 @@ end
collection_template = function(gui_script, name) collection_template = function(gui_script, name)
return [[name: "]].. name .. [[" return [[name: "]].. name .. [["
scale_along_z: 0 scale_along_z: 0
embedded_instances { embedded_instances {
id: "go" id: "go"
data: "components {\n" data: "components {\n"
" id: \"monarch\"\n" " id: \"monarch\"\n"
" component: \"]].. gui_script .. [[\"\n" " component: \"]].. gui_script .. [[\"\n"
" position {\n" " position {\n"
" x: 0.0\n" " x: 0.0\n"
" y: 0.0\n" " y: 0.0\n"
" z: 0.0\n" " z: 0.0\n"
" }\n" " }\n"
" rotation {\n" " rotation {\n"
" x: 0.0\n" " x: 0.0\n"
" y: 0.0\n" " y: 0.0\n"
" z: 0.0\n" " z: 0.0\n"
" w: 1.0\n" " w: 1.0\n"
" }\n" " }\n"
"}\n" "}\n"
"" ""
position { position {
x: 0.0 x: 0.0
y: 0.0 y: 0.0
z: 0.0 z: 0.0
} }
rotation { rotation {
x: 0.0 x: 0.0
y: 0.0 y: 0.0
z: 0.0 z: 0.0
w: 1.0 w: 1.0
} }
scale3 { scale3 {
x: 1.0 x: 1.0
y: 1.0 y: 1.0
z: 1.0 z: 1.0
} }
} }
]] ]]
end end

View File

@ -3,7 +3,6 @@ local async = require "monarch.utils.async"
local M = {} local M = {}
local WAITFOR_COWAIT = hash("waitfor_cowait")
local WAITFOR_CONTEXT = hash("waitfor_monarch_context") local WAITFOR_CONTEXT = hash("waitfor_monarch_context")
local WAITFOR_PROXY_LOADED = hash("waitfor_proxy_loaded") local WAITFOR_PROXY_LOADED = hash("waitfor_proxy_loaded")
local WAITFOR_PROXY_UNLOADED = hash("waitfor_proxy_unloaded") local WAITFOR_PROXY_UNLOADED = hash("waitfor_proxy_unloaded")
@ -20,9 +19,6 @@ local MSG_UNLOAD = hash("unload")
local MSG_ENABLE = hash("enable") local MSG_ENABLE = hash("enable")
local MSG_DISABLE = hash("disable") local MSG_DISABLE = hash("disable")
local DEPRECATED = hash("__DEPRECATED__")
-- transition messages -- transition messages
M.TRANSITION = {} M.TRANSITION = {}
M.TRANSITION.DONE = hash("transition_done") M.TRANSITION.DONE = hash("transition_done")
@ -90,13 +86,10 @@ local function assign(to, from)
return to return to
end end
local function cowait(screen, delay) local function cowait(delay)
log("cowait()", screen.id, delay)
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")
screen.wait_for = WAITFOR_COWAIT
timer.delay(delay, false, function() timer.delay(delay, false, function()
screen.wait_for = nil
assert(coroutine.resume(co)) assert(coroutine.resume(co))
end) end)
coroutine.yield() coroutine.yield()
@ -228,17 +221,6 @@ function M.is_visible(id)
end end
--- Check if a screen is loaded
-- @param id (string|hash)
-- @return true if the screen is loaded
function M.is_loaded(id)
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)))
return screens[id].loaded
end
--- Check if a screen is a popup --- Check if a screen is a popup
-- @param id Screen id -- @param id Screen id
-- @return true if the screen is a popup -- @return true if the screen is a popup
@ -283,6 +265,12 @@ end
-- keep input focus when below a popup -- keep input focus when below a popup
-- * others_keep_input_focus_when_below_screen - If screens below this -- * others_keep_input_focus_when_below_screen - If screens below this
-- screen should keep input focus -- screen should keep input focus
-- * transition_url - URL to a script that is responsible for the
-- screen transitions
-- * focus_url - URL to a script that is to be notified of focus
-- lost/gained events
-- * receiver_url - URL to a script that is to receive messages sent
-- using monarch.send()
-- * auto_preload - true if the screen should be automatically preloaded -- * auto_preload - true if the screen should be automatically preloaded
function M.register_proxy(id, proxy, settings) function M.register_proxy(id, proxy, settings)
assert(proxy, "You must provide a collection proxy URL") assert(proxy, "You must provide a collection proxy URL")
@ -292,15 +280,6 @@ function M.register_proxy(id, proxy, settings)
screen.focus_url = settings and settings.focus_url screen.focus_url = settings and settings.focus_url
screen.receiver_url = settings and settings.receiver_url screen.receiver_url = settings and settings.receiver_url
screen.auto_preload = settings and settings.auto_preload screen.auto_preload = settings and settings.auto_preload
if screen.transition_url.fragment == DEPRECATED then
screen.transition_url = nil
end
if screen.focus_url.fragment == DEPRECATED then
screen.focus_url = nil
end
if screen.receiver_url.fragment == DEPRECATED then
screen.receiver_url = nil
end
if screen.auto_preload then if screen.auto_preload then
M.preload(id) M.preload(id)
end end
@ -323,6 +302,10 @@ M.register = M.register_proxy
-- keep input focus when below a popup -- keep input focus when below a popup
-- * others_keep_input_focus_when_below_screen - If screens below this -- * others_keep_input_focus_when_below_screen - If screens below this
-- screen should keep input focus -- screen should keep input focus
-- * transition_id - Id of the game object in the collection that is responsible
-- for the screen transitions
-- * focus_id - Id of the game object in the collection that is to be notified
-- of focus lost/gained events
-- * auto_preload - true if the screen should be automatically preloaded -- * auto_preload - true if the screen should be automatically preloaded
function M.register_factory(id, factory, settings) function M.register_factory(id, factory, settings)
assert(factory, "You must provide a collection factory URL") assert(factory, "You must provide a collection factory URL")
@ -331,13 +314,6 @@ function M.register_factory(id, factory, settings)
screen.transition_id = settings and settings.transition_id screen.transition_id = settings and settings.transition_id
screen.focus_id = settings and settings.focus_id screen.focus_id = settings and settings.focus_id
screen.auto_preload = settings and settings.auto_preload screen.auto_preload = settings and settings.auto_preload
if screen.transition_id == DEPRECATED then
screen.transition_id = nil
end
if screen.focus_id == DEPRECATED then
screen.focus_id = nil
end
if screen.auto_preload then if screen.auto_preload then
M.preload(id) M.preload(id)
end end
@ -351,7 +327,6 @@ function M.unregister(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)))
log("unregister()", id) log("unregister()", id)
local screen = screens[id]
screens[id] = nil screens[id] = nil
-- remove screen from stack -- remove screen from stack
for i = #stack, 1, -1 do for i = #stack, 1, -1 do
@ -359,10 +334,6 @@ function M.unregister(id)
table.remove(stack, i) table.remove(stack, i)
end end
end end
screen.unregistered = true
if screen.wait_for then
assert(coroutine.resume(screen.co))
end
end end
local function acquire_input(screen) local function acquire_input(screen)
@ -410,7 +381,6 @@ local function change_context(screen)
end end
local function unload(screen, force) local function unload(screen, force)
if screen.unregistered then return end
if screen.proxy then if screen.proxy then
log("unload() proxy", screen.id) log("unload() proxy", screen.id)
if screen.auto_preload and not force then if screen.auto_preload and not force then
@ -430,9 +400,7 @@ local function unload(screen, force)
elseif screen.factory then elseif screen.factory then
log("unload() factory", screen.id) log("unload() factory", screen.id)
for id, instance in pairs(screen.factory_ids) do for id, instance in pairs(screen.factory_ids) do
if go.exists(instance) then go.delete(instance)
go.delete(instance)
end
end end
screen.factory_ids = nil screen.factory_ids = nil
if screen.auto_preload and not force then if screen.auto_preload and not force then
@ -447,8 +415,8 @@ local function unload(screen, force)
-- we need to wait here in case the unloaded screen contained any screens -- we need to wait here in case the unloaded screen contained any screens
-- if this is the case we need to let these sub-screens have their final() -- if this is the case we need to let these sub-screens have their final()
-- functions called so that they have time to call unregister() -- functions called so that they have time to call unregister()
cowait(screen, 0) cowait(0)
cowait(screen, 0) cowait(0)
end end
@ -464,7 +432,8 @@ local function preload(screen)
screen.preloading = true screen.preloading = true
if screen.proxy then if screen.proxy then
log("preload() proxy") log("preload() proxy")
if M.has_missing_resources(screen.id) then local missing_resources = collectionproxy.missing_resources(screen.proxy)
if #missing_resources > 0 then
local error_message = ("preload() collection proxy %s is missing resources"):format(tostring(screen.id)) local error_message = ("preload() collection proxy %s is missing resources"):format(tostring(screen.id))
log(error_message) log(error_message)
screen.preloading = false screen.preloading = false
@ -474,9 +443,6 @@ local function preload(screen)
msg.post(screen.proxy, MSG_ASYNC_LOAD) msg.post(screen.proxy, MSG_ASYNC_LOAD)
coroutine.yield() coroutine.yield()
screen.wait_for = nil screen.wait_for = nil
if screen.unregistered then
return false, "Screen was unregistered while loading"
end
elseif screen.factory then elseif screen.factory then
log("preload() factory") log("preload() factory")
if collectionfactory.get_status(screen.factory) == collectionfactory.STATUS_UNLOADED then if collectionfactory.get_status(screen.factory) == collectionfactory.STATUS_UNLOADED then
@ -484,9 +450,6 @@ local function preload(screen)
assert(coroutine.resume(screen.co)) assert(coroutine.resume(screen.co))
end) end)
coroutine.yield() coroutine.yield()
if screen.unregistered then
return false, "Screen was unregistered while loading"
end
end end
if collectionfactory.get_status(screen.factory) ~= collectionfactory.STATUS_LOADED then if collectionfactory.get_status(screen.factory) ~= collectionfactory.STATUS_LOADED then
@ -521,12 +484,8 @@ local function load(screen)
msg.post(screen.proxy, MSG_ENABLE) msg.post(screen.proxy, MSG_ENABLE)
elseif screen.factory then elseif screen.factory then
screen.factory_ids = collectionfactory.create(screen.factory) screen.factory_ids = collectionfactory.create(screen.factory)
if screen.transition_id then screen.transition_url = screen.factory_ids[screen.transition_id]
screen.transition_url = screen.factory_ids[screen.transition_id] screen.focus_url = screen.factory_ids[screen.focus_id]
end
if screen.focus_id then
screen.focus_url = screen.factory_ids[screen.focus_id]
end
end end
screen.loaded = true screen.loaded = true
screen.preloaded = false screen.preloaded = false
@ -535,7 +494,6 @@ end
local function transition(screen, message_id, message, wait) local function transition(screen, message_id, message, wait)
log("transition()", screen.id) log("transition()", screen.id)
if screen.unregistered then return end
if screen.transition_url then if screen.transition_url then
screen.wait_for = WAITFOR_TRANSITION_DONE screen.wait_for = WAITFOR_TRANSITION_DONE
msg.post(screen.transition_url, message_id, message) msg.post(screen.transition_url, message_id, message)
@ -559,15 +517,14 @@ end
local function focus_lost(screen, next_screen) local function focus_lost(screen, next_screen)
log("focus_lost()", screen.id) log("focus_lost()", screen.id)
if screen.unregistered then return end
if screen.focus_url then if screen.focus_url then
msg.post(screen.focus_url, M.FOCUS.LOST, { id = next_screen and next_screen.id }) msg.post(screen.focus_url, M.FOCUS.LOST, { id = next_screen and next_screen.id })
-- if there's no transition on the screen losing focus and it gets -- if there's no transition on the screen losing focus and it gets
-- unloaded this will happen before the focus_lost message reaches -- unloaded this will happen before the focus_lost message reaches
-- 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(screen, 0) cowait(0)
cowait(screen, 0) cowait(0)
else else
log("focus_lost() no focus url - ignoring") log("focus_lost() no focus url - ignoring")
end end
@ -688,7 +645,7 @@ local function show_in(screen, previous_screen, reload, add_to_stack, wait_for_t
return return
end end
-- wait one frame so that the init() of any script have time to run before starting transitions -- wait one frame so that the init() of any script have time to run before starting transitions
cowait(screen, 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
@ -714,7 +671,7 @@ local function back_in(screen, previous_screen, wait_for_transition, cb)
return return
end end
-- wait one frame so that the init() of any script have time to run before starting transitions -- wait one frame so that the init() of any script have time to run before starting transitions
cowait(screen, 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)
@ -731,8 +688,8 @@ 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) assert(wait_for_transition ~= nil)
run_coroutine(screen, cb, function() run_coroutine(screen, cb, function()
active_transition_count = active_transition_count + 1
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
change_context(screen) change_context(screen)
release_input(screen, next_screen) release_input(screen, next_screen)
focus_lost(screen, next_screen) focus_lost(screen, next_screen)
@ -879,10 +836,13 @@ function M.show(id, options, data, cb)
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
show_in(screen, top, options and options.reload, add_to_stack, WAIT_FOR_TRANSITION, callbacks.track()) local cb = callbacks.track()
if add_to_stack and top and not top.popup then show_in(screen, top, options and options.reload, add_to_stack, DO_NOT_WAIT_FOR_TRANSITION, function()
show_out(top, screen, WAIT_FOR_TRANSITION, callbacks.track()) if add_to_stack and top and not top.popup then
end show_out(top, screen, WAIT_FOR_TRANSITION, callbacks.track())
end
cb()
end)
end end
callbacks.when_done(function() callbacks.when_done(function()
@ -925,7 +885,7 @@ function M.hide(id, cb)
log("hide() you can only hide the screen at the top of the stack", id) log("hide() you can only hide the screen at the top of the stack", id)
return false return false
end end
return M.back(nil, nil, cb) return M.back(id, cb)
else else
log("hide() queuing action", id) log("hide() queuing action", id)
queue_action(function(action_done, action_error) queue_action(function(action_done, action_error)
@ -978,27 +938,21 @@ end
-- Go back to the previous screen in the stack. -- Go back to the previous screen in the stack.
-- @param options (table) - Table with options when backing out from the screen (can be nil).
-- Valid values:
-- * sequential - Set to true to wait for the current screen to hide itself out before starting the
-- back in transition even when transitioning to a different scene ID.
-- @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(options, data, cb) function M.back(data, cb)
log("back() queuing action") log("back() queuing action")
queue_action(function(action_done) queue_action(function(action_done)
local callbacks = callback_tracker() local callbacks = callback_tracker()
local back_cb = callbacks.track()
local screen = table.remove(stack) local screen = table.remove(stack)
if screen then if screen then
log("back()", screen.id) log("back()", screen.id)
local top = stack[#stack] local top = stack[#stack]
-- if we go back to the same screen we need to first hide it -- if we go back to the same screen we need to first hide it
-- and wait until it is hidden before we show it again -- and wait until it is hidden before we show it again
local same_screen = top and top.id == screen.id if top and screen.id == top.id then
if same_screen or (options and options.sequential) then
local back_cb = callbacks.track()
back_out(screen, top, WAIT_FOR_TRANSITION, function() back_out(screen, top, WAIT_FOR_TRANSITION, function()
if data then if data then
top.data = data top.data = data
@ -1016,16 +970,16 @@ function M.back(options, data, cb)
-- we do this to ensure that we do not reset the times step of the screen -- we do this to ensure that we do not reset the times step of the screen
-- we go back to until it is no longer obscured by the popup -- we go back to until it is no longer obscured by the popup
if screen.popup and not top.popup then if screen.popup and not top.popup then
local back_cb = callbacks.track()
back_out(screen, top, WAIT_FOR_TRANSITION, function() back_out(screen, top, WAIT_FOR_TRANSITION, function()
back_in(top, screen, WAIT_FOR_TRANSITION, back_cb) back_in(top, screen, WAIT_FOR_TRANSITION, back_cb)
end) end)
else else
back_in(top, screen, WAIT_FOR_TRANSITION, callbacks.track()) back_in(top, screen, DO_NOT_WAIT_FOR_TRANSITION, function()
back_out(screen, top, WAIT_FOR_TRANSITION, callbacks.track()) back_out(screen, top, WAIT_FOR_TRANSITION, back_cb)
end)
end end
else else
back_out(screen, top, WAIT_FOR_TRANSITION, callbacks.track()) back_out(screen, top, WAIT_FOR_TRANSITION, back_cb)
end end
end end
end end
@ -1132,20 +1086,6 @@ function M.preload(id, options, cb)
return true -- return true for legacy reasons (before queue existed) return true -- return true for legacy reasons (before queue existed)
end end
--- Check if a screen has missing resources, always returns false for factory
-- @param id (string|hash) - Id of the screen to preload
function M.has_missing_resources(id)
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.proxy then
local missing_resources = collectionproxy.missing_resources(screen.proxy)
return #missing_resources > 0
end
return false
end
--- Unload a preloaded monarch screen --- Unload a preloaded monarch screen
-- @param id (string|hash) - Id of the screen to unload -- @param id (string|hash) - Id of the screen to unload
@ -1197,8 +1137,8 @@ end
-- @return error (string|nil) Error message if unable to send message -- @return error (string|nil) Error message if unable to send message
function M.post(id, message_id, message) function M.post(id, message_id, message)
assert(id, "You must provide a screen id") assert(id, "You must provide a screen id")
if not M.is_loaded(id) then if not M.is_visible(id) then
return false, "Unable to post message to screen if it isn't loaded" return false, "Unable to post message to screen if it isn't visible"
end end
assert(message_id, "You must provide a message_id") assert(message_id, "You must provide a message_id")
@ -1206,11 +1146,17 @@ function M.post(id, message_id, message)
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)))
local screen = screens[id] local screen = screens[id]
if screen.receiver_url then if screen.proxy then
log("post() sending message to", screen.receiver_url) if screen.receiver_url then
msg.post(screen.receiver_url, message_id, message) log("post() sending message to", screen.receiver_url)
msg.post(screen.receiver_url, message_id, message)
else
return false, "Unable to post message since screen has no receiver url specified"
end
else else
return false, "Unable to post message since screen has no receiver url specified. Set one using monarch.on_post()." for id,instance in pairs(screen.factory_ids) do
msg.post(instance, message_id, message)
end
end end
return true return true
end end
@ -1350,36 +1296,24 @@ function M.on_focus_changed(id, fn)
end end
--- ---
-- Set either a function to be called when msg.post() is called on a specific -- Set a function to call when a screen is sent a message using monarch.post()
-- screen or a URL where the message is sent. -- The function will receive (message_id, message, sender)
-- IMPORTANT! If you provide a function you must also make sure to call -- IMPORTANT! You must call monarch.on_message() from the same script as
-- monarch.on_message(message_id, message, sender) from the same script as -- this function was called
-- this function was called.
-- @param id Screen id to associate the message listener function with -- @param id Screen id to associate the message listener function with
-- @param fn_or_url The function to call or URL to send message to -- @param fn Message listener function
function M.on_post(id, fn_or_url) function M.on_post(id, fn)
assert(id, "You must provide a screen id") assert(id, "You must provide a screen id")
assert(fn, "You must provide a post receiver function")
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)))
local screen = screens[id] local screen = screens[id]
screen.receiver_url = msg.url()
local t = type(fn_or_url) screen.receiver_fn = fn
if t == "function" then
screen.receiver_fn = fn_or_url
screen.receiver_url = msg.url()
elseif t == "userdata" or t == "string" then
screen.receiver_fn = nil
screen.receiver_url = fn_or_url
else
screen.receiver_fn = nil
screen.receiver_url = msg.url()
end
end end
local empty_hash = hash("")
local function url_to_key(url) local function url_to_key(url)
return (url.socket or empty_hash) .. (url.path or empty_hash) .. (url.fragment or empty_hash) return (url.socket or hash("")) .. (url.path or hash("")) .. (url.fragment or hash(""))
end end

View File

@ -6,8 +6,8 @@ go.property("popup", false)
go.property("popup_on_popup", false) go.property("popup_on_popup", false)
go.property("screen_keeps_input_focus_when_below_popup", false) go.property("screen_keeps_input_focus_when_below_popup", false)
go.property("others_keep_input_focus_when_below_screen", false) go.property("others_keep_input_focus_when_below_screen", false)
go.property("transition_id", hash("__DEPRECATED__")) go.property("transition_id", hash(""))
go.property("focus_id", hash("__DEPRECATED__")) go.property("focus_id", hash(""))
go.property("preload", false) go.property("preload", false)
@ -15,7 +15,7 @@ function init(self)
monarch = require "monarch.monarch" monarch = require "monarch.monarch"
assert(not self.popup_on_popup or (self.popup_on_popup and self.popup), "Popup on Popups can only be set if the Popup flag is set") assert(not self.popup_on_popup or (self.popup_on_popup and self.popup), "Popup on Popups can only be set if the Popup flag is set")
assert(self.screen_factory ~= msg.url(), "You must specify either a factory URL") assert(self.screen_factory ~= msg.url(), "You must specify either a factory URL")
local settings = { local settings = {
popup = self.popup, popup = self.popup,
popup_on_popup = self.popup_on_popup, popup_on_popup = self.popup_on_popup,

View File

@ -7,9 +7,9 @@ go.property("popup_on_popup", false)
go.property("timestep_below_popup", 1) go.property("timestep_below_popup", 1)
go.property("screen_keeps_input_focus_when_below_popup", false) go.property("screen_keeps_input_focus_when_below_popup", false)
go.property("others_keep_input_focus_when_below_screen", false) go.property("others_keep_input_focus_when_below_screen", false)
go.property("transition_url", msg.url("#__DEPRECATED__")) go.property("transition_url", msg.url())
go.property("focus_url", msg.url("#__DEPRECATED__")) go.property("focus_url", msg.url())
go.property("receiver_url", msg.url("#__DEPRECATED__")) go.property("receiver_url", msg.url())
go.property("preload", false) go.property("preload", false)
@ -19,7 +19,7 @@ function init(self)
assert(not self.popup_on_popup or (self.popup_on_popup and self.popup), "Popup on Popups can only be set if the Popup flag is set") assert(not self.popup_on_popup or (self.popup_on_popup and self.popup), "Popup on Popups can only be set if the Popup flag is set")
assert(self.screen_proxy ~= url, "You must specify either a proxy URL") assert(self.screen_proxy ~= url, "You must specify either a proxy URL")
assert(self.timestep_below_popup >= 0, "Timestep must be positive") assert(self.timestep_below_popup >= 0, "Timestep must be positive")
local settings = { local settings = {
popup = self.popup, popup = self.popup,
popup_on_popup = self.popup_on_popup, popup_on_popup = self.popup_on_popup,

View File

@ -1,2 +0,0 @@
[bootstrap]
main_collection = /test/test.collectionc

View File

@ -1,11 +1,5 @@
local monarch
function init(self) function init(self)
monarch = require "monarch.monarch" print("init - screen1")
print("init - screen1", msg.url())
monarch.on_post("screen1", function(message_id, message, sender)
_G.screen1_on_post = message or true
end)
end end
function final(self) function final(self)
@ -13,8 +7,7 @@ function final(self)
end end
function on_message(self, message_id, message, sender) function on_message(self, message_id, message, sender)
monarch.on_message(message_id, message, sender)
if message_id == hash("foobar") then if message_id == hash("foobar") then
_G.screen1_on_message = message or true _G.screen1_foobar = message or true
end end
end end

View File

@ -1,11 +1,5 @@
local monarch
function init(self) function init(self)
monarch = require "monarch.monarch" print("init - screen2")
print("init - screen2", msg.url())
monarch.on_post("screen2", function(message_id, message, sender)
_G.screen2_on_post = message or true
end)
end end
function final(self) function final(self)
@ -13,8 +7,7 @@ function final(self)
end end
function on_message(self, message_id, message, sender) function on_message(self, message_id, message, sender)
monarch.on_message(message_id, message, sender)
if message_id == hash("foobar") then if message_id == hash("foobar") then
_G.screen2_on_message = message or true _G.screen2_foobar = message or true
end end
end end

View File

@ -64,17 +64,5 @@ function M.last(url)
return messages[#messages] return messages[#messages]
end end
function M.filter(url, fn)
local t = {}
local messages = M.messages(url)
for i=1,#messages do
local message = messages[i]
if fn(message) then
t[#t + 1] = message
end
end
return t
end
return M return M

View File

@ -12,6 +12,7 @@ local FOCUS1 = hash("focus1")
local BACKGROUND = hash("background") local BACKGROUND = hash("background")
local POPUP1 = hash("popup1") local POPUP1 = hash("popup1")
local POPUP2 = hash("popup2") local POPUP2 = hash("popup2")
local FOOBAR = hash("foobar")
local TRANSITION1 = hash("transition1") local TRANSITION1 = hash("transition1")
local function check_stack(expected_screens) local function check_stack(expected_screens)
@ -81,7 +82,7 @@ return function()
monarch.when_preloaded(screen_id, done) monarch.when_preloaded(screen_id, done)
end) end)
end end
describe("monarch", function() describe("monarch", function()
before(function() before(function()
mock_msg.mock() mock_msg.mock()
@ -142,12 +143,12 @@ return function()
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_stack({ SCREEN1 })) assert(wait_until_stack({ SCREEN1 }))
assert(wait_until_visible(SCREEN1)) assert(wait_until_visible(SCREEN1))
monarch.show(SCREEN2) monarch.show(SCREEN2)
assert(wait_until_stack({ SCREEN1, SCREEN2 })) assert(wait_until_stack({ SCREEN1, SCREEN2 }))
assert(wait_until_hidden(SCREEN1)) assert(wait_until_hidden(SCREEN1))
assert(wait_until_visible(SCREEN2)) assert(wait_until_visible(SCREEN2))
monarch.show(POPUP1) monarch.show(POPUP1)
assert(wait_until_stack({ SCREEN1, SCREEN2, POPUP1 })) assert(wait_until_stack({ SCREEN1, SCREEN2, POPUP1 }))
assert(wait_until_hidden(SCREEN1)) assert(wait_until_hidden(SCREEN1))
@ -155,17 +156,6 @@ return function()
assert(wait_until_visible(POPUP1)) assert(wait_until_visible(POPUP1))
end) end)
it("should be able to tell if a screen is loaded or not", function()
assert(not monarch.is_loaded(SCREEN1))
monarch.show(SCREEN1)
assert(wait_until_visible(SCREEN1))
assert(monarch.is_loaded(SCREEN1))
monarch.hide(SCREEN1)
assert(wait_until_hidden(SCREEN1))
assert(not monarch.is_loaded(SCREEN1))
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_visible(BACKGROUND), "Background was never shown") assert(wait_until_visible(BACKGROUND), "Background was never shown")
@ -230,7 +220,7 @@ return function()
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(nil, data_back) monarch.back(data_back)
assert(wait_until_visible(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")
@ -418,37 +408,43 @@ return function()
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_not_busy()) 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.screen == SCREEN1)
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(URL1)[2].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED)
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.screen == SCREEN1)
monarch.remove_listener(URL2) monarch.remove_listener(URL2)
monarch.show(SCREEN2) monarch.show(SCREEN2)
assert(wait_until_not_busy()) assert(wait_until_not_busy())
assert(#mock_msg.messages(URL1) == 6)
assert(#mock_msg.messages(URL2) == 2)
assert(mock_msg.messages(URL1)[3].message_id == monarch.SCREEN_TRANSITION_IN_STARTED)
assert(mock_msg.messages(URL1)[3].message.screen == SCREEN2)
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)[5].message_id == monarch.SCREEN_TRANSITION_OUT_STARTED)
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.screen == SCREEN1)
monarch.back() monarch.back()
assert(wait_until_not_busy()) assert(wait_until_not_busy())
local messages = mock_msg.filter(URL1, function(m) assert(#mock_msg.messages(URL1) == 10)
return m.message.screen == SCREEN1 assert(#mock_msg.messages(URL2) == 2)
end) assert(mock_msg.messages(URL1)[7].message_id == monarch.SCREEN_TRANSITION_IN_STARTED)
assert(messages[1].message_id == monarch.SCREEN_TRANSITION_IN_STARTED) assert(mock_msg.messages(URL1)[7].message.screen == SCREEN1)
assert(messages[2].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED) assert(mock_msg.messages(URL1)[8].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED)
assert(messages[3].message_id == monarch.SCREEN_TRANSITION_OUT_STARTED) assert(mock_msg.messages(URL1)[8].message.screen == SCREEN1)
assert(messages[4].message_id == monarch.SCREEN_TRANSITION_OUT_FINISHED) assert(mock_msg.messages(URL1)[9].message_id == monarch.SCREEN_TRANSITION_OUT_STARTED)
assert(messages[5].message_id == monarch.SCREEN_TRANSITION_IN_STARTED) assert(mock_msg.messages(URL1)[9].message.screen == SCREEN2)
assert(messages[6].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED) assert(mock_msg.messages(URL1)[10].message_id == monarch.SCREEN_TRANSITION_OUT_FINISHED)
assert(mock_msg.messages(URL1)[10].message.screen == SCREEN2)
messages = mock_msg.filter(URL2, function(m)
return m.message.screen == SCREEN1
end)
assert(messages[1].message_id == monarch.SCREEN_TRANSITION_IN_STARTED)
assert(messages[2].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED)
messages = mock_msg.filter(URL1, function(m)
return m.message.screen == SCREEN2
end)
assert(messages[1].message_id == monarch.SCREEN_TRANSITION_IN_STARTED)
assert(messages[2].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED)
assert(messages[3].message_id == monarch.SCREEN_TRANSITION_OUT_STARTED)
assert(messages[4].message_id == monarch.SCREEN_TRANSITION_OUT_FINISHED)
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()
@ -495,56 +491,49 @@ return function()
it("should be able to post messages without message data to visible screens", function() it("should be able to post messages without message data to visible screens", function()
_G.screen1_on_message = nil _G.screen1_foobar = nil
_G.screen1_on_post = nil _G.screen2_foobar = nil
_G.screen2_on_message = nil
_G.screen2_on_post = nil
-- proxy screen -- proxy screen
monarch.show(SCREEN1) monarch.show(SCREEN1)
wait_until_visible(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_on_message, "Screen1 never received a message") assert(_G.screen1_foobar, "Screen1 never received a message")
assert(_G.screen1_on_post, "Screen1 never received a callback")
-- factory screen -- factory screen
monarch.show(SCREEN2) monarch.show(SCREEN2)
wait_until_visible(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_on_message, "Screen2 never received a message") assert(_G.screen2_foobar, "Screen2 never received a message")
assert(_G.screen2_on_post, "Screen2 never received a callback")
end) end)
it("should be able to post messages with message data to visible screens", function() it("should be able to post messages with message data to visible screens", function()
_G.screen1_on_message = nil _G.screen1_foobar = nil
_G.screen1_on_post = nil _G.screen2_foobar = nil
_G.screen2_on_message = nil
_G.screen2_on_post = nil
-- proxy screen -- proxy screen
monarch.show(SCREEN1) monarch.show(SCREEN1)
wait_until_visible(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_on_message, "Screen1 never received a message") assert(_G.screen1_foobar, "Screen1 never received a message")
assert(_G.screen1_on_message.foo == "bar", "Screen1 never received message data") assert(_G.screen1_foobar.foo == "bar", "Screen1 never received message data")
-- factory screen -- factory screen
monarch.show(SCREEN2) monarch.show(SCREEN2)
wait_until_visible(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_on_message, "Screen2 never received a message") assert(_G.screen2_foobar, "Screen2 never received a message")
assert(_G.screen2_on_message.foo == "bar", "Screen2 never received message data") assert(_G.screen2_foobar.foo == "bar", "Screen2 never received message data")
end) end)
it("should not be able to post messages to hidden screens", function() it("should not be able to post messages to hidden screens", function()
_G.screen1_on_message = nil _G.screen1_foobar = nil
_G.screen1_on_post = nil
monarch.show(SCREEN1) monarch.show(SCREEN1)
monarch.show(SCREEN2) monarch.show(SCREEN2)
@ -553,7 +542,7 @@ return function()
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)
assert(not _G.screen1_on_message, "Screen1 should not have received a message") assert(not _G.screen1_foobar, "Screen1 should not have received a message")
end) end)