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

Compare commits

..

32 Commits
3.0.0 ... 3.2.2

Author SHA1 Message Date
Brian
03baa3eeb3 Only allow editor script to target .gui (#67)
* Only allow editor script to target .gui

Disable .collection and .gui_script

* whitespace
2020-11-23 08:32:12 +01:00
Marius Petcu
00808c0d56 Implement better behaviour for replace() on popups (#64) 2020-05-28 17:18:51 +02:00
Björn Ritzl
4989939817 Always print errors. Do not rely on monarch debugging 2020-05-28 08:20:43 +02:00
Björn Ritzl
bf880b80fd Print errors if caught in the callback tracker 2020-05-28 08:08:35 +02:00
Marius Petcu
4ad86d41fc Implement monarch.replace() (#61) 2020-05-20 15:36:29 +02:00
Marius Petcu
c7fb2ba646 Add sequential loading flag (#62) 2020-05-20 14:58:04 +02:00
Björn Ritzl
909ada9f18 Fix issue when a layout changes and there's an ongoing transition 2020-05-10 22:51:08 +02:00
Björn Ritzl
504ac9223a Fix message mock to properly deal with indexing of URLs 2020-05-10 22:50:31 +02:00
Björn Ritzl
b37cb1ba79 Update .travis.yml 2020-03-11 10:58:20 +01:00
Björn Ritzl
5e826f97d9 Update README.md 2020-03-11 10:58:03 +01:00
Björn Ritzl
be5a375559 Update README.md 2020-03-10 22:47:29 +01:00
Jerakin
c7ff068f79 Added editor script to create base setup (#57) 2020-01-16 08:45:48 +01:00
Björn Ritzl
6a92a0b2dd Update ci-workflow.yml 2019-12-10 07:20:41 +01:00
Björn Ritzl
bb1f34149a Check if proxy is missing resources when loading/showing it
Fixes #56
2019-12-10 07:11:30 +01:00
Björn Ritzl
7b20e48424 Update run.sh 2019-10-21 06:36:12 +02:00
Björn Ritzl
a77431600e Update .travis.yml 2019-10-21 06:35:38 +02:00
Björn Ritzl
68cda52c0d Update monarch.lua 2019-09-14 01:25:43 +02:00
Björn Ritzl
81237762be Transition out and in again if showing the same screen twice
Fixes #54
2019-09-14 01:23:14 +02:00
Björn Ritzl
8001d370c2 Delete foo.txt 2019-09-14 01:16:10 +02:00
Björn Ritzl
ac409eb4c8 Update ci-workflow.yml 2019-08-19 07:17:00 +02:00
Björn Ritzl
5f776b0bc4 Update ci-workflow.yml 2019-08-19 07:15:31 +02:00
Björn Ritzl
9a47129135 Removed test 2019-08-19 07:13:03 +02:00
Björn Ritzl
4ea29a9efa Update ci-workflow.yml 2019-08-19 07:12:29 +02:00
Björn Ritzl
fa7cf75d3a Merge branch 'master' of https://github.com/britzl/monarch 2019-08-19 06:18:36 +02:00
Björn Ritzl
bbc4baa5e1 Update foo.txt 2019-08-19 06:18:34 +02:00
Björn Ritzl
0085704614 Update README.md 2019-08-19 06:17:26 +02:00
Björn Ritzl
e37b9bde89 Update .travis.yml 2019-08-13 06:09:07 +02:00
Björn Ritzl
21b16e1473 Create foo.txt 2019-08-09 07:51:44 +02:00
Björn Ritzl
36291f3762 Added test workflow 2019-08-09 07:30:46 +02:00
Björn Ritzl
fd5f82c40b Update ci-workflow.yml 2019-08-09 07:26:07 +02:00
Björn Ritzl
92bddc742b Create ci-workflow.yml 2019-08-09 07:11:15 +02:00
Björn Ritzl
0c0446746c Update README.md 2019-08-05 14:45:40 +02:00
13 changed files with 460 additions and 58 deletions

19
.github/workflows/ci-workflow.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: CI
on: [push]
jobs:
build_and_run:
name: Build and run
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-java@v1
with:
java-version: '11'
- name: Run.sh
env:
DEFOLD_USER: bjorn.ritzl@gmail.com
DEFOLD_AUTH: foobar
DEFOLD_BOOSTRAP_COLLECTION: /test/test.collectionc
run: ./.travis/run.sh

View File

@@ -1,5 +1,7 @@
sudo: required sudo: required
dist: bionic
script: script:
- sudo unlink /usr/bin/gcc && sudo ln -s /usr/bin/gcc-5 /usr/bin/gcc - sudo unlink /usr/bin/gcc && sudo ln -s /usr/bin/gcc-5 /usr/bin/gcc
- gcc --version - gcc --version
@@ -15,14 +17,10 @@ addons:
language: java language: java
jdk: jdk:
- oraclejdk8 - oraclejdk11
dist: trusty
env: env:
global: global:
- DEFOLD_AUTH=foobar
- DEFOLD_USER=bjorn.ritzl@gmail.com
- DEFOLD_BOOSTRAP_COLLECTION=/test/test.collectionc - DEFOLD_BOOSTRAP_COLLECTION=/test/test.collectionc
script: script:

View File

@@ -26,11 +26,9 @@ chmod +x dmengine_headless
echo "Downloading ${BOB_URL}" echo "Downloading ${BOB_URL}"
curl -o bob.jar ${BOB_URL} curl -o bob.jar ${BOB_URL}
# Fetch libraries if DEFOLD_AUTH and DEFOLD_USER are set # Fetch libraries
if [ -n "${DEFOLD_AUTH}" ] && [ -n "${DEFOLD_USER}" ]; then echo "Running bob.jar - resolving dependencies"
echo "Running bob.jar - resolving dependencies" java -jar bob.jar --auth "foobar" --email "john@doe.com" resolve
java -jar bob.jar --auth "${DEFOLD_AUTH}" --email "${DEFOLD_USER}" resolve
fi
echo "Running bob.jar - building" echo "Running bob.jar - building"
java -jar bob.jar --debug build --keep-unused java -jar bob.jar --debug build --keep-unused

View File

@@ -1,6 +1,6 @@
![](docs/logo.jpg) ![](docs/logo.jpg)
[![Build Status](https://travis-ci.org/britzl/monarch.svg?branch=master)](https://travis-ci.org/britzl/monarch) [![Build Status](https://travis-ci.com/britzl/monarch.svg?branch=master)](https://travis-ci.org/britzl/monarch)
[![Code Coverage](https://codecov.io/gh/britzl/monarch/branch/master/graph/badge.svg)](https://codecov.io/gh/britzl/monarch) [![Code Coverage](https://codecov.io/gh/britzl/monarch/branch/master/graph/badge.svg)](https://codecov.io/gh/britzl/monarch)
[![Latest Release](https://img.shields.io/github/release/britzl/monarch.svg)](https://github.com/britzl/monarch/releases) [![Latest Release](https://img.shields.io/github/release/britzl/monarch.svg)](https://github.com/britzl/monarch/releases)
@@ -19,6 +19,10 @@ Or point to the ZIP file of a [specific release](https://github.com/britzl/monar
# Usage # Usage
Using Monarch requires that screens are created in a certain way. Once you have one or more screens created you can start navigating between the screens. Using Monarch requires that screens are created in a certain way. Once you have one or more screens created you can start navigating between the screens.
## Editor Script
Right click in on a`.gui` file in the outline and selected the menu item, it creates a `.collection` and a `.gui_script` with the same name as the `.gui` file. It adds the file with some basic setup done to them, adding the selected gui script to the created gui scene and in turns adds the gui scene to the newly created collection.
<img src="/docs/editor_script.gif" width="200px">
## Creating screens ## Creating screens
Monarch screens are created in individual collections and either loaded through collection proxies or created through collection factories. Monarch screens are created in individual collections and either loaded through collection proxies or created through collection factories.
@@ -73,12 +77,12 @@ The navigation in Monarch is based around a stack of screens. When a screen is s
### Showing a new screen ### Showing a new screen
You show a screen in one of two ways: You show a screen in one of two ways:
1. Post a ```show``` message to the ```screen.script``` 1. Post a ```show``` message to the screen script (either `screen_proxy.script` or `screen_factory.script`)
2. Call ```monarch.show()``` (see below) 2. Call ```monarch.show()``` (see below)
Showing a screen will push it to the top of the stack and trigger an optional transition. The previous screen will be hidden (with an optional transition) unless the screen to be shown is a [popup](#popups). Showing a screen will push it to the top of the stack and trigger an optional transition. The previous screen will be hidden (with an optional transition) unless the screen to be shown is a [popup](#popups).
NOTE: You must ensure that the ```init()``` function of the ```screen.script``` has run. The ```init()``` function is responsible for registering the screen and it's not possible to show it until this has happened. A good practice is to delay the first call by posting a message to a controller script or similar before calling ```monarch.show()``` the first time: NOTE: You must ensure that the ```init()``` function of the screen script (either `screen_proxy.script` or `screen_factory.script`) has run. The ```init()``` function is responsible for registering the screen and it's not possible to show it until this has happened. A good practice is to delay the first call by posting a message to a controller script or similar before calling ```monarch.show()``` the first time:
function init(self) function init(self)
msg.post("#", "show_first_screen") msg.post("#", "show_first_screen")
@@ -113,7 +117,7 @@ Monarch can also show a screen without adding it to the stack. This can be used
### Going back to a previous screen ### Going back to a previous screen
You navigate back in the screen hierarchy in one of two ways: You navigate back in the screen hierarchy in one of two ways:
1. Post a ```back``` message to the ```screen.script``` 1. Post a ```back``` message to the screen script (either `screen_proxy.script` or `screen_factory.script`)
2. Call ```monarch.back()``` (see below) 2. Call ```monarch.back()``` (see below)
@@ -188,6 +192,15 @@ Monarch comes with a system for setting up transitions easily in a gui_script us
end end
end end
It is also possible to assign transitions to multiple nodes:
function init(self)
self.transition = transitions.create() -- note that no node is passed to transition.create()!
.show_in(gui.get_node("node1"), transitions.slide_in_right, gui.EASING_OUTQUAD, 0.6, 0)
.show_in(gui.get_node("node2"), transitions.slide_in_right, gui.EASING_OUTQUAD, 0.6, 0)
end
The predefined transitions provided by ```monarch.transitions.gui``` are: The predefined transitions provided by ```monarch.transitions.gui``` are:
* ```slide_in_right``` * ```slide_in_right```
@@ -292,7 +305,7 @@ Both the ```monarch.show()``` and ```monarch.back()``` functions take an optiona
## Monarch API ## Monarch API
### monarch.show(screen_id, [options], [data], [callback]) ### monarch.show(screen_id, [options], [data], [callback])
Show a Monarch screen. Note that the screen must be registered before it can be shown. The ```init()``` function of the ```screen.script``` takes care of registration. This operation will be added to the queue if Monarch is busy. Show a Monarch screen. Note that the screen must be registered before it can be shown. The ```init()``` function of the screen script (either `screen_proxy.script` or `screen_factory.script`) takes care of registration. This operation will be added to the queue if Monarch is busy.
**PARAMETERS** **PARAMETERS**
* ```screen_id``` (string|hash) - Id of the screen to show. * ```screen_id``` (string|hash) - Id of the screen to show.
@@ -305,6 +318,11 @@ The options table can contain the following fields:
* ```clear``` (boolean) - If the `clear` flag is set Monarch will search the stack for the screen that is to be shown. If the screen already exists in the stack and the clear flag is set Monarch will remove all screens between the current top and the screen in question. * ```clear``` (boolean) - If the `clear` flag is set Monarch will search the stack for the screen that is to be shown. If the screen already exists in the stack and the clear flag is set Monarch will remove all screens between the current top and the screen in question.
* ```reload``` (boolean) - If the `reload` flag is set Monarch will reload the collection proxy if it's already loaded (this can happen if the previous screen was a popup). * ```reload``` (boolean) - If the `reload` flag is set Monarch will reload the collection proxy if it's already loaded (this can happen if the previous screen was a popup).
* ```no_stack``` (boolean) - If the `no_stack` flag is set Monarch will load the screen without adding it to the screen stack. * ```no_stack``` (boolean) - If the `no_stack` flag is set Monarch will load the screen without adding it to the screen stack.
* ```sequential``` (boolean) - If the `sequential` flag is set Monarch will start loading the screen only after the previous screen finished transitioning out.
* ```pop``` (number) - If `pop` is set to a number, Monarch will pop that number of screens from the stack before adding the new one.
### monarch.replace(screen_id, [options], [data], [callback])
Replace the top of the stack with a new screen. Equivalent to calling `monarch.show()` with `pop = 1`. It takes the same parameters as `monarch.show()`.
### monarch.hide(screen_id, [callback]) ### monarch.hide(screen_id, [callback])

BIN
docs/editor_script.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@@ -0,0 +1,161 @@
local M = {}
local collection_template
local gui_script_content
local gui_file_content
local function ends_with(str, ending)
return ending == "" or str:sub(-#ending) == ending
end
local function file_exists(name)
local f=io.open(name,"r")
if f~=nil then io.close(f) return true else return false end
end
local function get_filename(path)
local main, filename, extension = path:match("(.-)([^\\/]-%.?([^%.\\/]*))$")
return main, filename
end
local function create_files(file_path)
-- Construct paths
local path = editor.get(file_path, "path")
local main, filename = get_filename(path)
local basename = filename:match("(.+)%..+")
local target_collection_path = "." .. main .. basename .. ".collection"
local target_gui_script_path = "." .. main .. basename .. ".gui_script"
local target_gui_path = "." .. main .. basename .. ".gui"
-- Create the files if they don't exists
if not file_exists(target_collection_path) then
local collection_content = collection_template(path, basename)
local collection = io.open(target_collection_path, "w")
collection:write(collection_content)
collection:close()
end
if not file_exists(target_gui_script_path) then
local gui_script = io.open(target_gui_script_path, "w")
gui_script:write(gui_script_content)
gui_script:close()
-- Put the gui_script path into the gui file
local gui_file = io.open("." .. path, "rb")
local gui_text = gui_file:read("*a")
gui_file:close()
gui_text = string.gsub(gui_text, 'script: "%.*"', [[script: "]] .. main .. basename .. ".gui_script" .. [["]])
gui_file = io.open("." .. path, "w")
gui_file:write(gui_text)
gui_file:close()
end
if not file_exists(target_gui_path) then
local gui_content = gui_template(path)
local gui = io.open(target_gui_path, "w")
gui:write(gui_content)
gui:close()
end
end
function M.get_commands()
return {
{
label="Create Monarch Scene From...",
locations = {"Assets"},
query = {
selection = {type = "resource", cardinality = "one"}
},
active = function(opts)
local path = editor.get(opts.selection, "path")
return ends_with(path, ".gui")
end,
run = function(opts)
create_files(opts.selection)
end
}
}
end
gui_template = function(gui_script)
return [[script: "]].. gui_script .. [["
background_color {
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
gui_script_content = [[local monarch = require "monarch.monarch"
function init(self)
msg.post(".", "acquire_input_focus")
end
function final(self)
end
function update(self, dt)
end
function on_message(self, message_id, message, sender)
end
function on_input(self, action_id, action)
end
function on_reload(self)
end
]]
collection_template = function(gui_script, name)
return [[name: "]].. name .. [["
scale_along_z: 0
embedded_instances {
id: "go"
data: "components {\n"
" id: \"monarch\"\n"
" component: \"]].. gui_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
}
}
]]
end
return M

View File

@@ -69,6 +69,16 @@ local function pcallfn(fn, ...)
end end
end end
local function assign(to, from)
if not from then
return to
end
for k, v in pairs(from) do
to[k] = v
end
return to
end
local function cowait(delay) local function cowait(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")
@@ -83,7 +93,7 @@ end
local queue = {} local queue = {}
local function queue_error(message) local function queue_error(message)
log(message) print(message)
log("queue() error - clearing queue") log("queue() error - clearing queue")
while next(queue) do while next(queue) do
table.remove(queue) table.remove(queue)
@@ -371,6 +381,13 @@ local function preload(screen)
screen.preloading = true screen.preloading = true
if screen.proxy then if screen.proxy then
log("preload() proxy") log("preload() proxy")
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))
log(error_message)
screen.preloading = false
return false, error_message
end
screen.wait_for = PROXY_LOADED screen.wait_for = PROXY_LOADED
msg.post(screen.proxy, ASYNC_LOAD) msg.post(screen.proxy, ASYNC_LOAD)
coroutine.yield() coroutine.yield()
@@ -640,6 +657,10 @@ end
-- * clear - Set to true if the stack should be cleared down to an existing instance of the screen -- * clear - Set to true if the stack should be cleared down to an existing instance of the screen
-- * reload - Set to true if screen should be reloaded if it already exists in the stack and is loaded. -- * reload - Set to true if screen should be reloaded if it already exists in the stack and is loaded.
-- This would be the case if doing a show() from a popup on the screen just below the popup. -- This would be the case if doing a show() from a popup on the screen just below the popup.
-- * sequential - Set to true to wait for the previous screen to show itself out before starting the
-- show in transition even when transitioning to a different scene ID.
-- * no_stack - Set to true to load the screen without adding it to the screen stack.
-- * pop - The number of screens to pop from the stack before adding the new one.
-- @param data (*) - Optional data to set on the screen. Can be retrieved by the data() function -- @param data (*) - Optional data to set on the screen. Can be retrieved by the data() function
-- @param cb (function) - Optional callback to invoke when screen is shown -- @param cb (function) - Optional callback to invoke when screen is shown
function M.show(id, options, data, cb) function M.show(id, options, data, cb)
@@ -665,41 +686,61 @@ function M.show(id, options, data, cb)
local top = stack[#stack] local top = stack[#stack]
-- a screen can ignore the stack by setting the no_stack to true -- a screen can ignore the stack by setting the no_stack to true
local add_to_stack = not options or not options.no_stack local add_to_stack = not options or not options.no_stack
if add_to_stack then if add_to_stack and top then
-- manipulate the current top -- manipulate the current top
-- close popup(s) if needed -- close popup(s) if needed
-- transition out -- transition out
if top then local pop = options and options.pop or 0
-- keep top popup visible if new screen can be shown on top of a popup local is_not_popup = not screen.popup
if top.popup and screen.popup_on_popup then local pop_all_popups = is_not_popup -- pop all popups when transitioning screens
disable(top, screen)
else -- keep top popup visible if new screen can be shown on top of a popup
-- close all popups, one by one if top.popup and screen.popup and screen.popup_on_popup then
while top.popup do disable(top, screen)
stack[#stack] = nil else
show_out(top, screen, function() pop_all_popups = true
assert(coroutine.resume(co)) end
end)
coroutine.yield() -- close popups, one by one, either all of them or the number specified by options.pop
top = stack[#stack] while top and top.popup do
end if not pop_all_popups then
-- unload and transition out from top if pop <= 0 then break end
-- unless we're showing the same screen as is already visible pop = pop - 1
if top and top.id ~= screen.id then end
show_out(top, screen, callbacks.track()) stack[#stack] = nil
end show_out(top, screen, callbacks.track())
callbacks.yield_until_done()
top = stack[#stack]
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
end 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
-- including the screen itself -- including the screen itself
if options and options.clear then if options and options.clear then
log("show() clearing") log("show() clearing")
while M.in_stack(id) do while M.in_stack(id) do
table.remove(stack) table.remove(stack)
end
end
-- pop screens off the stack
if is_not_popup then
for i = 1, pop do
local stack_top = #stack
if stack_top < 1 then break end
stack[stack_top] = nil
end
end end
end end
@@ -725,6 +766,20 @@ function M.show(id, options, data, cb)
end end
--- Replace the top of the stack with a new screen
-- @param id (string|hash) - Id of the screen to show
-- @param options (table) - Table with options when showing the screen (can be nil). Valid values:
-- * clear - Set to true if the stack should be cleared down to an existing instance of the screen
-- * reload - Set to true if screen should be reloaded if it already exists in the stack and is loaded.
-- This would be the case if doing a show() from a popup on the screen just below the popup.
-- * no_stack - Set to true to load the screen without adding it to the screen stack.
-- @param data (*) - Optional data to set on the screen. Can be retrieved by the data() function
-- @param cb (function) - Optional callback to invoke when screen is shown
function M.replace(id, options, data, cb)
return M.show(id, assign({ pop = 1 }, options), data, cb)
end
-- Hide a screen. The screen must either be at the top of the stack or -- Hide a screen. The screen must either be at the top of the stack or
-- visible but not added to the stack (through the no_stack option) -- visible but not added to the stack (through the no_stack option)
-- @param id (string|hash) - Id of the screen to show -- @param id (string|hash) - Id of the screen to show
@@ -817,7 +872,13 @@ function M.is_preloading(id)
local screen = screens[id] local screen = screens[id]
return screen.preloading return screen.preloading
end end
function M.is_preloaded(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]
return screen.preloaded
end
--- Invoke a callback when a specific screen has been preloaded --- Invoke a callback when a specific screen has been preloaded
-- This is mainly useful on app start when wanting to show a screen that -- This is mainly useful on app start when wanting to show a screen that

View File

@@ -174,6 +174,7 @@ local function create()
if t.in_progress_count == 0 then if t.in_progress_count == 0 then
table.insert(t.urls, msg.url()) table.insert(t.urls, msg.url())
current_transition = t current_transition = t
current_transition.id = transition_id
if #t.transitions > 0 then if #t.transitions > 0 then
for i=1,#t.transitions do for i=1,#t.transitions do
local transition = t.transitions[i] local transition = t.transitions[i]
@@ -206,7 +207,7 @@ local function create()
transition.fn(transition.node, transition.node_data, transition.easing, 0, 0) transition.fn(transition.node, transition.node_data, transition.easing, 0, 0)
end end
if current_transition.in_progress_count > 0 then if current_transition.in_progress_count > 0 then
finish_transition(message_id) finish_transition(current_transition.id)
end end
end end
elseif message_id == monarch.TRANSITION.SHOW_IN elseif message_id == monarch.TRANSITION.SHOW_IN

View File

@@ -7,6 +7,10 @@ function M.create()
local callback = nil local callback = nil
local callback_count = 0 local callback_count = 0
local function is_done()
return callback_count == 0
end
local function invoke_if_done() local function invoke_if_done()
if callback_count == 0 and callback then if callback_count == 0 and callback then
local ok, err = pcall(callback) local ok, err = pcall(callback)
@@ -37,6 +41,20 @@ function M.create()
invoke_if_done() invoke_if_done()
end end
function instance.yield_until_done()
local co = coroutine.running()
callback = function()
local ok, err = coroutine.resume(co)
if not ok then
print(err)
end
end
invoke_if_done()
if not is_done() then
coroutine.yield()
end
end
return instance return instance
end end

View File

@@ -8,9 +8,25 @@ local recipients = {}
local history = {} local history = {}
local function url_to_key(url)
if type(url) == "string" then
url = msg.url(url)
end
local ok, err = pcall(function() return url.socket end)
if not ok then
return url
end
if url.socket then
return hash_to_hex(url.socket or hash("")) .. hash_to_hex(url.path or hash("")) .. hash_to_hex(url.fragment or hash(""))
else
return url
end
end
local function get_recipient(url) local function get_recipient(url)
recipients[url] = recipients[url] or {} local key = url_to_key(url)
return recipients[url] recipients[key] = recipients[key] or {}
return recipients[key]
end end
local function post(url, message_id, message) local function post(url, message_id, message)

View File

@@ -2,11 +2,13 @@ local deftest = require "deftest.deftest"
local test_monarch = require "test.test_monarch" local test_monarch = require "test.test_monarch"
local test_callback_tracker = require "test.test_callback_tracker" local test_callback_tracker = require "test.test_callback_tracker"
local test_transitions = require "test.test_transitions"
function init(self) function init(self)
deftest.add(test_monarch) deftest.add(test_monarch)
deftest.add(test_callback_tracker) deftest.add(test_callback_tracker)
deftest.add(test_transitions)
deftest.run({ deftest.run({
coverage = { enabled = true }, coverage = { enabled = true },
pattern = "", pattern = "",

View File

@@ -133,6 +133,22 @@ return function()
assert_stack({ }) assert_stack({ })
end) end)
it("should be able to replace screens at the top of the stack", function()
monarch.show(SCREEN1_STR)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
monarch.show(SCREEN2)
assert(wait_until_hidden(SCREEN1), "Screen1 was never hidden")
assert(wait_until_shown(SCREEN2), "Screen2 was never shown")
assert_stack({ SCREEN1, SCREEN2 })
monarch.replace(SCREEN1)
assert(wait_until_hidden(SCREEN2), "Screen2 was never hidden")
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1, SCREEN1 })
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)
@@ -302,6 +318,59 @@ return function()
assert_stack({ SCREEN1, SCREEN2 }) assert_stack({ SCREEN1, SCREEN2 })
end) end)
it("should close any open popups when replacing a non-popup", function()
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown")
assert_stack({ SCREEN1, POPUP1 })
monarch.show(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown")
assert_stack({ SCREEN1, POPUP1, POPUP2 })
monarch.replace(SCREEN2)
assert(wait_until_shown(SCREEN2), "Screen2 was never shown")
assert_stack({ SCREEN2 })
end)
it("should replace a popup", function()
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown")
assert_stack({ SCREEN1, POPUP1 })
monarch.replace(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown")
assert_stack({ SCREEN1, POPUP2 })
end)
it("should replace a pop-up two levels down", function()
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown")
assert_stack({ SCREEN1, POPUP1 })
monarch.show(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown")
assert_stack({ SCREEN1, POPUP1, POPUP2 })
monarch.show(POPUP2, { pop = 2 })
assert(wait_until_shown(POPUP2), "Popup2 was never shown")
assert_stack({ SCREEN1, POPUP2 })
end)
it("shouldn't over-pop popups", function()
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown")
assert_stack({ SCREEN1, POPUP1 })
monarch.show(POPUP2, { pop = 10 })
assert(wait_until_shown(POPUP2), "Popup2 was never shown")
assert_stack({ SCREEN1, POPUP2 })
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()
assert(monarch.top() == nil) assert(monarch.top() == nil)
@@ -405,18 +474,13 @@ return function()
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, nil, { count = 1 }) monarch.show(SCREEN_PRELOAD)
assert(wait_until_shown(SCREEN_PRELOAD), "Screen_preload was never shown") assert(wait_until_shown(SCREEN_PRELOAD), "Screen_preload was never shown")
-- first time the screen gets loaded it will increment the count monarch.back()
assert(monarch.data(SCREEN_PRELOAD).count == 2) assert(wait_until_hidden(SCREEN_PRELOAD), "Screen_preload was never hidden")
assert(monarch.is_preloaded(SCREEN_PRELOAD))
monarch.show(SCREEN_PRELOAD, { clear = true }, { count = 1 })
assert(wait_until_shown(SCREEN_PRELOAD), "Screen_preload was never shown")
-- second time the screen gets shown it will already be loaded and not increment the count
assert(monarch.data(SCREEN_PRELOAD).count == 1)
end) end)
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_shown(SCREEN_PRELOAD), "Screen_preload was never shown")

46
test/test_transitions.lua Normal file
View File

@@ -0,0 +1,46 @@
local cowait = require "test.cowait"
local mock_msg = require "test.msg"
local mock_gui = require "deftest.mock.gui"
local unload = require "deftest.util.unload"
local monarch = require "monarch.monarch"
local transitions = require "monarch.transitions.gui"
local easing = require "monarch.transitions.easings"
return function()
describe("transitions", function()
before(function()
mock_msg.mock()
mock_gui.mock()
transitions = require "monarch.transitions.gui"
end)
after(function()
mock_msg.unmock()
mock_gui.unmock()
unload.unload("monarch%..*")
end)
it("should replay and immediately finish on layout change", function()
function dummy_transition(node, to, easing, duration, delay, cb)
print("dummy transition")
end
local node = gui.new_box_node(vmath.vector3(), vmath.vector3(100, 100, 0))
local duration = 2
local t = transitions.create(node)
.show_in(dummy_transition, easing.OUT, duration, delay or 0)
.show_out(dummy_transition, easing.IN, duration, delay or 0)
.back_in(dummy_transition, easing.OUT, duration, delay or 0)
.back_out(dummy_transition, easing.IN, duration, delay or 0)
t.handle(monarch.TRANSITION.SHOW_IN)
t.handle(hash("layout_changed"))
local messages = mock_msg.messages(msg.url())
assert(#messages == 1, "Expected one message to have been received")
assert(messages[1].message_id == monarch.TRANSITION.DONE, "Expected a TRANSITION.DONE message")
end)
end)
end