agg_gui/widgets/text_field/keyboard_mode.rs
1//! Keyboard-mode hooks for `TextField`.
2//!
3//! Split out of `text_field.rs` to keep that file under the 800-line
4//! cap. The storage (`keyboard_mode: Rc<Cell<KeyboardInputMode>>`)
5//! lives on `TextField`; everything else — builders, the shared-cell
6//! handle, and the runtime setter — lives here.
7//!
8//! Why a `Cell` instead of a plain field?
9//! Demo / app code that wants a radio button to swap a focused field
10//! between "letters" and "numeric" needs to mutate the mode after the
11//! widget tree has been built and handed off as `Box<dyn Widget>`.
12//! Threading a `&mut TextField` back out is awkward; an `Rc<Cell<…>>`
13//! gives the demo a stable handle to flip whenever the radio fires.
14
15use std::cell::Cell;
16use std::rc::Rc;
17
18use super::TextField;
19use crate::widgets::on_screen_keyboard::KeyboardInputMode;
20
21impl TextField {
22 /// Assign a stable id for the programmatic focus channel. App code can
23 /// then call [`crate::focus::request_focus(id)`](crate::focus::request_focus)
24 /// to move keyboard focus here (and raise the on-screen keyboard) the
25 /// next frame — e.g. to auto-focus a search field when its overlay opens.
26 pub fn with_focus_id(mut self, id: crate::focus::FocusId) -> Self {
27 self.focus_request_id = Some(id);
28 self
29 }
30
31 /// Set the preferred keyboard input mode for this field — picks
32 /// which layer the on-screen software keyboard slides up into the
33 /// next time this field gains focus. Defaults to
34 /// [`KeyboardInputMode::Text`].
35 ///
36 /// This does **not** install a character filter: a numeric field
37 /// still accepts whatever the user actually types (including via
38 /// a paste or the on-screen `ABC` mode switch). Combine with
39 /// [`TextField::with_char_filter`] when you want hard validation.
40 pub fn with_keyboard_mode(self, mode: KeyboardInputMode) -> Self {
41 self.keyboard_mode.set(mode);
42 self
43 }
44
45 /// Bind the field's keyboard mode to an externally-owned cell.
46 /// The caller keeps a clone and can flip the mode at any time —
47 /// the next focus event re-queries the cell, so the keyboard
48 /// re-targets without a widget rebuild. Mirrors the
49 /// [`TextField::with_text_cell`](super::TextField) pattern.
50 pub fn with_keyboard_mode_cell(mut self, cell: Rc<Cell<KeyboardInputMode>>) -> Self {
51 self.keyboard_mode = cell;
52 self
53 }
54
55 /// Read the current mode. Used by the `Widget::text_input_mode`
56 /// override and exposed publicly so app code can inspect it
57 /// without going through a `dyn Widget` trait dispatch.
58 pub fn keyboard_mode(&self) -> KeyboardInputMode {
59 self.keyboard_mode.get()
60 }
61
62 /// Update the mode at runtime — typically called from a callback
63 /// (e.g. a radio button's `on_change`). Equivalent to mutating
64 /// the cell directly via [`TextField::keyboard_mode_handle`] but
65 /// reads better at the call site.
66 pub fn set_keyboard_mode(&self, mode: KeyboardInputMode) {
67 self.keyboard_mode.set(mode);
68 }
69
70 /// Clone the underlying cell so a parent can drive this field's
71 /// mode from somewhere else in the tree (a radio button, a menu
72 /// item, a feature-flag observer). Multiple fields can share the
73 /// same handle to ride a single switch.
74 pub fn keyboard_mode_handle(&self) -> Rc<Cell<KeyboardInputMode>> {
75 Rc::clone(&self.keyboard_mode)
76 }
77}