Handle Back
Escape, gamepad B, a mouse's back button, a browser's Back and a phone's back gesture all reach your app as one cancel request, and you decide what it does.
What makes a request
| Input | Makes a request |
|---|---|
| Escape | while focus navigation acts in your app, and always in a focused text field |
| Gamepad B | while focus navigation acts in your app |
| A mouse's back button, natively | while focus navigation acts in your app |
| A browser's Back: its button, a mouse's back button, Alt+Left | always |
| A phone's back gesture | always |
| Escape or B at a focused Continue chip | always |
Focus navigation acts while your app shows a widget that can take focus
and ui.focus_navigation is on
(Keyboard and gamepad). So a canvas game
with no widgets keeps Escape and B for itself.
Where a request goes
A request goes to the first of these that can take it:
- A dialog of the workstation's own: it presses its Cancel.
- A Continue chip the workstation shows (Fit any window size): it goes away.
- An open menu, or a popover made with
light_dismiss = true: it closes, and focus in it goes back to the menu's button, or to what held focus before the popover took it. - A focused text field: it runs its
on_canceland lets go of focus, so the next request goes past it. - From the focused element outward, the first element with an
on_cancelhandler, or the first router made withpop_on_cancel = truethat has a page to go back to. With nothing focused, the router you moved last goes back first. - The window manager that framed your app, which usually takes the person out of your app.
While a modal popover shows, a request starts inside it: with nothing in
it focused, the popover's own on_cancel hears it first. A press outside
a light_dismiss popover closes it too, but leaves focus where the press
puts it.
In a browser, a request nobody takes lets Back leave the site. When something takes a Back and the next one would leave the site, the workstation shows "Press Back again to leave DatumHue".
Clear a field, then go back a page
local ui = datumhue.ui
local token = datumhue.theme.token
local page = ui.root:panel({ width = 480, gap = 12 })
local status = page:label({
text = "Escape, gamepad B or Back goes back",
color = token("text_secondary"),
})
local search
search = page:text_input({
placeholder = "Search fruit",
on_cancel = function(e)
search.text = ""
status.text = "Search cleared by " .. e.source
end,
})
local router = page:panel({ padding = 0 }):router({
pop_on_cancel = true,
})
local fruit = router:route(function(p, params)
p:label({ text = params.name, font_size = "1.5rem" })
end, { title = "Fruit" })
local list = router:route(function(p)
p:update({ gap = 8 })
for _, name in ipairs({ "Apple", "Pear", "Plum" }) do
p:button({
text = name,
on_click = function()
router:push(fruit, { name = name })
end,
})
end
end, { title = "All fruit" })
router:show(list)
In this example: datumhue.ui datumhue.theme.token datumhue.ui.root UiElement:panel UiElement:label UiElement:text_input UiElement.text UiElement:router Router:route UiElement:button Router:push Router:show
- Escape in the search field runs its
on_cancel, which empties it. The field lets go of focus, so the next Escape goes on. e.sourcenames what made the request: the keyboard, a gamepad, a mouse, or the system's Back.- Open a fruit, and Escape, B or Back goes back to the list, as
Router:popdoes. The page'son_leavestill has its say. - At the list the router has nothing to go back to, so the request goes on to what framed your app.
Take Back for yourself
UiElement:on_cancel makes an element take every request that reaches
it: one made while focus is on it or inside it, or, on ui.root, one
made with nothing focused. The handler runs once the request is decided.
Take only the requests you undo something for: a handler on ui.root
keeps Back from ever leaving your app.
Back in a window manager
A request an app leaves reaches the frame its window manager made with
wm.wrap_app. Set UiElement:on_cancel on that frame to decide what
Back means there, such as showing the workstation. A frame without one
hands the request to the window manager's own widgets, and so on up to
the root app. wm.send_cancel sends an app a Back, as a phone's back
gesture would, for a window manager's own Back button.
See also
- Pages and tabs: routers and their pages.
- Write a window manager or launcher: frames and what reaches them.
- Input, focus and Back: which app hears a request.
ui.CancelSource: every source a request names.
Reference used on this page: datumhue.ui datumhue.theme.token datumhue.ui.root UiElement:panel UiElement:label UiElement:text_input UiElement.text UiElement:router Router:route UiElement:button Router:push Router:show datumhue.ui.focus_navigation Router:pop UiElement:on_cancel datumhue.input.is_key_pressed datumhue.wm.wrap_app datumhue.wm.send_cancel ui.CancelSource