https://crates.io/crates/focusable
This lets you do things like automatically derive focus for a widget:
#[derive(Debug, Clone, Focus)]
pub(crate) struct TextBox {
pub(crate) is_focused: bool,
pub(crate) content: String,
}
Including widgets that won’t be focusable (can_focus()
/ is_focused
return false and focus()
/ blur()
do nothing).
#[derive(Debug, Clone, Focus)]
pub(crate) struct Label {
pub(crate) text: String,
}
You can use the trait to generically handle focusable widgets, and can derive a FocusContainer trait that navigates between them as appropriate.
trait FocusableWidget: WidgetRef + Focus {
fn boxed(self) -> Box<dyn FocusableWidget>
where
Self: 'static + Sized,
{
Box::new(self)
}
}
#[derive(Focus, FocusContainer)]
pub(crate) struct Form {
pub(crate) children: Vec<Box<dyn FocusableWidget>>,
}
let mut form = Form::from_iter([
Label::new("Label 1:").boxed(),
TextBox::new("Text 1").boxed(),
Label::new("Label 2:").boxed(),
TextBox::new("Text 2").boxed(),
Label::new("Label 3:").boxed(),
TextBox::new("Text 3").boxed(),
]);
And then in your app code:
form.focus_first();
if let event::Event::Key(key) = event::read()? {
match key.code {
KeyCode::Char('q') => running = false,
KeyCode::Tab => form.focus_next(),
KeyCode::BackTab => form.focus_previous(),
_ => {}
}
}