diff --git a/README.md b/README.md index 27f8fc7..502a7d2 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ For proxies the recommended setup is to create one game object per screen and pe * **Popup (boolean)** - Check this if the screen should be treated as a [popup](#popups). * **Popup on Popup (boolean)** - Check this if the screen is a [popup](#popups) and it can be shown on top of other popups. * **Timestep below Popup (number)** - Timestep to set on screen proxy when it is below a popup. This is useful when pausing animations and gameplay while a popup is open. +* **Screen Keeps Input Focus When Below Popup (boolean)** - Check this if the screen should keep input focus when it is below a popup. +* **Others Keep Input Focus When Below Screen (boolean)** - Check this if other screens should keep input focus when below this screen. * **Transition Url (url)** - Optional URL to post messages to when the screen is about to be shown/hidden. Use this to trigger a transition (see the section on [transitions](#transitions)). * **Focus Url (url)** - Optional URL to post messages to when the screen gains or loses focus (see the section on [screen focus](#screen-focus-gainloss)). * **Receiver Url (url)** - Optional URL to post messages to using `monarch.post()`. @@ -45,6 +47,8 @@ For factories the recommended setup is to create one game object per screen and * **Screen Id (hash)** - A unique id that can be used to reference the screen when navigating your app. * **Popup (boolean)** - Check this if the screen should be treated as a [popup](#popups). * **Popup on Popup (boolean)** - Check this if the screen is a [popup](#popups) and it can be shown on top of other popups. +* **Screen Keeps Input Focus When Below Popup (boolean)** - Check this if the screen should keep input focus when it is below a popup. +* **Others Keep Input Focus When Below Screen (boolean)** - Check this if other screens should keep input focus when below this screen. * **Transition Id (hash)** - Optional id of the game object to send a message to when the screen is about to be shown/hidden. Use this to trigger a transition (see the section on [transitions](#transitions)). * **Focus Id (hash)** - Optional id of the game object to send a message to when the screen gains or loses focus (see the section on [screen focus](#screen-focus-gainloss)). * **Preload (boolean)** - Check this if the screen should be preloaded and kept loaded at all times. For a collection factory this means that its resources will be dynamically loaded at all times. This can also temporarily be achieved through the `monarch.preload()` function. @@ -114,7 +118,8 @@ You navigate back in the screen hierarchy in one of two ways: ## Input focus -Monarch will acquire and release input focus on the game objects containing the proxies to the screens and ensure that only the top-most screen will ever have input focus. +Monarch will acquire and release input focus on the game objects containing the proxies to the screens and ensure that only the top-most screen will ever have input focus. The screen settings above provide a `Screen Keeps Input Focus When Below Popup` and `Others Keep Input Focus When Below Screen` setting to override this behavior so that a screen can continue to have focus. This is useful when you have for instance a tabbed popup where the tabs are in a root screen and the content of the individual tabs are separate screens. In this case you want the tabs to have input as well as the tab content. + ## Popups A screen that is flagged as a popup (see [list of screen properties](#creating-screens) above) will be treated slightly differently when it comes to navigation. diff --git a/example/example.collection b/example/example.collection index 5877fc8..6193b2e 100644 --- a/example/example.collection +++ b/example/example.collection @@ -359,6 +359,11 @@ embedded_instances { " type: PROPERTY_TYPE_BOOLEAN\n" " }\n" " properties {\n" + " id: \"others_keep_input_focus_when_below_screen\"\n" + " value: \"true\"\n" + " type: PROPERTY_TYPE_BOOLEAN\n" + " }\n" + " properties {\n" " id: \"transition_url\"\n" " value: \"confirm:/go#confirm\"\n" " type: PROPERTY_TYPE_URL\n" diff --git a/game.project b/game.project index 8601249..c3b70c0 100644 --- a/game.project +++ b/game.project @@ -4,7 +4,7 @@ version = 0.9 dependencies = https://github.com/britzl/deftest/archive/2.7.0.zip [bootstrap] -main_collection = /test/test.collectionc +main_collection = /example/example.collectionc [input] game_binding = /input/game.input_bindingc diff --git a/monarch/monarch.lua b/monarch/monarch.lua index 096442f..8bf35ce 100644 --- a/monarch/monarch.lua +++ b/monarch/monarch.lua @@ -150,6 +150,8 @@ local function register(id, settings) popup = settings and settings.popup, popup_on_popup = settings and settings.popup_on_popup, timestep_below_popup = settings and settings.timestep_below_popup or 1, + screen_keeps_input_focus_when_below_popup = settings and settings.screen_keeps_input_focus_when_below_popup or false, + others_keep_input_focus_when_below_screen = settings and settings.others_keep_input_focus_when_below_screen or false, preload_listeners = {}, } return screens[id] @@ -166,13 +168,17 @@ end -- * popup - true the screen is a popup -- * popup_on_popup - true if this popup can be shown on top of -- another popup or false if an underlying popup should be closed +-- * timestep_below_popup - Timestep to set on proxy when below a popup +-- * screen_keeps_input_focus_when_below_popup - If this screen should +-- keep input focus when below a popup +-- * others_keep_input_focus_when_below_screen - If screens below this +-- 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() --- * timestep_below_popup - Timestep to set on proxy when below a popup -- * auto_preload - true if the screen should be automatically preloaded function M.register_proxy(id, proxy, settings) assert(proxy, "You must provide a collection proxy URL") @@ -200,6 +206,10 @@ M.register = M.register_proxy -- * popup - true the screen is a popup -- * popup_on_popup - true if this popup can be shown on top of -- another popup or false if an underlying popup should be closed +-- * screen_keeps_input_focus_when_below_popup - If this screen should +-- keep input focus when below a popup +-- * others_keep_input_focus_when_below_screen - If screens below this +-- 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 @@ -241,17 +251,25 @@ local function acquire_input(screen) end end -local function release_input(screen) +local function release_input(screen, next_screen) log("release_input()", screen.id) if screen.input then - if screen.proxy then - msg.post(screen.script, RELEASE_INPUT_FOCUS) - elseif screen.factory then - for id,instance in pairs(screen.factory_ids) do - msg.post(instance, RELEASE_INPUT_FOCUS) + local next_is_popup = next_screen and next_screen.popup + + local keep_if_next_is_popup = next_is_popup and screen.screen_keeps_input_focus_when_below_popup + local keep_when_below_next = next_screen and next_screen.others_keep_input_focus_when_below_screen + + local release_focus = not keep_if_next_is_popup and not keep_when_below_next + if release_focus then + if screen.proxy then + msg.post(screen.script, RELEASE_INPUT_FOCUS) + elseif screen.factory then + for id,instance in pairs(screen.factory_ids) do + msg.post(instance, RELEASE_INPUT_FOCUS) + end end + screen.input = false end - screen.input = false end end @@ -414,9 +432,10 @@ end local function disable(screen, next_screen) log("disable()", screen.id) + local next_is_popup = next_screen and next_screen.popup run_coroutine(screen, nil, function() change_context(screen) - release_input(screen) + release_input(screen, next_screen) focus_lost(screen, next_screen) if next_screen and next_screen.popup then change_timestep(screen) @@ -442,7 +461,7 @@ local function show_out(screen, next_screen, cb) active_transition_count = active_transition_count + 1 notify_transition_listeners(M.SCREEN_TRANSITION_OUT_STARTED, { screen = screen.id, next_screen = next_screen.id }) change_context(screen) - release_input(screen) + release_input(screen, next_screen) focus_lost(screen, next_screen) reset_timestep(screen) -- if the next screen is a popup we want the current screen to stay visible below the popup @@ -512,7 +531,7 @@ local function back_out(screen, next_screen, cb) 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) - release_input(screen) + release_input(screen, next_screen) focus_lost(screen, next_screen) if next_screen and screen.popup then reset_timestep(next_screen) diff --git a/monarch/screen_factory.script b/monarch/screen_factory.script index 03d1a1c..15b515e 100644 --- a/monarch/screen_factory.script +++ b/monarch/screen_factory.script @@ -4,6 +4,8 @@ go.property("screen_factory", msg.url("#collectionfactory")) go.property("screen_id", hash("UNIQUE ID HERE")) go.property("popup", false) go.property("popup_on_popup", false) +go.property("screen_keeps_input_focus_when_below_popup", false) +go.property("others_keep_input_focus_when_below_screen", false) go.property("transition_id", hash("")) go.property("focus_id", hash("")) go.property("preload", false) @@ -17,6 +19,8 @@ function init(self) local settings = { popup = self.popup, popup_on_popup = self.popup_on_popup, + screen_keeps_input_focus_when_below_popup = self.screen_keeps_input_focus_when_below_popup, + others_keep_input_focus_when_below_screen = self.others_keep_input_focus_when_below_screen, transition_id = self.transition_id, focus_id = self.focus_id, auto_preload = self.preload, diff --git a/monarch/screen_proxy.script b/monarch/screen_proxy.script index c48651c..d6ce5ea 100644 --- a/monarch/screen_proxy.script +++ b/monarch/screen_proxy.script @@ -5,6 +5,8 @@ go.property("screen_id", hash("UNIQUE ID HERE")) go.property("popup", false) go.property("popup_on_popup", false) go.property("timestep_below_popup", 1) +go.property("screen_keeps_input_focus_when_below_popup", false) +go.property("others_keep_input_focus_when_below_screen", false) go.property("transition_url", msg.url()) go.property("focus_url", msg.url()) go.property("receiver_url", msg.url()) @@ -25,6 +27,8 @@ function init(self) focus_url = self.focus_url ~= url and self.focus_url or nil, receiver_url = self.receiver_url ~= url and self.receiver_url or nil, timestep_below_popup = self.timestep_below_popup, + screen_keeps_input_focus_when_below_popup = self.screen_keeps_input_focus_when_below_popup, + others_keep_input_focus_when_below_screen = self.others_keep_input_focus_when_below_screen, auto_preload = self.preload, }