Expand description
Keyboard focus traversal — tab and shift-tab between controls.
gpui has all the machinery and none of it is on by default: a focus handle
carries a tab_index and a tab_stop flag, .track_focus registers the
handle for the frame, and Window::focus_next walks the order — but
tab_stop starts false and gpui binds no keys. This module turns it on.
§Order is paint order
gpui sorts tab stops by their tab_index path and then by insertion, so
leaving every index at 0 yields the order the controls are painted in.
Nothing has to be numbered by hand, and inserting a control in the middle of
a form does not renumber the rest — which is the failure mode that makes
HTML tabindex a liability.
§Where the handle lives
Most of this crate is fn(&Theme, ..) -> Div: stateless, with the app
owning whether a checkbox is checked. Focus is more of that state, so the
app owns the handle too and focusable wires it up. Giving every widget a
handle of its own would mean giving every widget an identity and a lifetime,
which is the entity machinery crate::input::TextField needs and a
checkbox does not.
ui::focus::init(cx); // once, at startup
// ..and on the root view, so `tab` works wherever focus currently is:
focus::traversal(div().track_focus(&self.focus_handle))
.child(focus::focusable(&theme, &self.ok_focus, popover::button(&theme, "OK", "ok")))Structs§
Constants§
- CLAIMS_
TAB - Added to a surface’s key context when
tabis its own key — a document nests a list with it.traversalstands down while that surface holds focus. - CONTROL_
KEY_ CONTEXT - Claimed by every
focusablecontrol, soenterandspacemean “press this” only where something is actually focused.
Functions§
- bindings
- Traversal’s keymap, as data, so an app can have it without having to
take it — see
crate::keysfor layering over it or taking a chord away. - focusable
- Put a stateless control into the tab order, show when it holds focus, and
let
enter/spacepress it. - init
- Install the bindings —
bindings, bound. Call once at startup. - pressable
- One activation path for pointer and keyboard, with a shared enabled gate. The caller still owns the value changed by the callback.
- traversal
- Attach the traversal handlers, normally to the app’s root element.