Skip to main content

Module focus

Module focus 

Source
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§

Activate
Decrement
FocusNext
FocusPrev
Increment

Constants§

CONTROL_KEY_CONTEXT
Claimed by every focusable control, so enter and space mean “press this” only where something is actually focused.

Functions§

focusable
Put a stateless control into the tab order, show when it holds focus, and let enter/space press it.
init
Bind tab and shift-tab. Call once at startup.
traversal
Attach the traversal handlers, normally to the app’s root element.