use crate::widget::Widget;
pub(super) fn collect_focusable(
widget: &dyn Widget,
current_path: &mut Vec<usize>,
out: &mut Vec<Vec<usize>>,
) {
if !widget.is_visible() || widget.blocks_child_interaction() {
return;
}
if widget.is_focusable() {
out.push(current_path.clone());
}
for (i, child) in widget.children().iter().enumerate() {
current_path.push(i);
collect_focusable(child.as_ref(), current_path, out);
current_path.pop();
}
}
pub(super) fn widget_at_path<'a>(
root: &'a mut Box<dyn Widget>,
path: &[usize],
) -> &'a mut dyn Widget {
if path.is_empty() {
return root.as_mut();
}
let idx = path[0];
widget_at_path(&mut root.children_mut()[idx], &path[1..])
}
pub(super) fn widget_at_path_ref<'a>(root: &'a dyn Widget, path: &[usize]) -> &'a dyn Widget {
if path.is_empty() {
return root;
}
let idx = path[0];
widget_at_path_ref(root.children()[idx].as_ref(), &path[1..])
}
#[cfg(test)]
mod tests {
use super::*;
use crate::draw_ctx::DrawCtx;
use crate::event::{Event, EventResult};
use crate::geometry::{Rect, Size};
struct Focusable {
bounds: Rect,
children: Vec<Box<dyn Widget>>,
}
impl Widget for Focusable {
fn bounds(&self) -> Rect {
self.bounds
}
fn set_bounds(&mut self, b: Rect) {
self.bounds = b;
}
fn children(&self) -> &[Box<dyn Widget>] {
&self.children
}
fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> {
&mut self.children
}
fn layout(&mut self, available: Size) -> Size {
available
}
fn paint(&mut self, _ctx: &mut dyn DrawCtx) {}
fn on_event(&mut self, _e: &Event) -> EventResult {
EventResult::Ignored
}
fn is_focusable(&self) -> bool {
true
}
}
struct Scope {
bounds: Rect,
children: Vec<Box<dyn Widget>>,
visible: bool,
blocked: bool,
}
impl Widget for Scope {
fn bounds(&self) -> Rect {
self.bounds
}
fn set_bounds(&mut self, b: Rect) {
self.bounds = b;
}
fn children(&self) -> &[Box<dyn Widget>] {
&self.children
}
fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> {
&mut self.children
}
fn layout(&mut self, available: Size) -> Size {
available
}
fn paint(&mut self, _ctx: &mut dyn DrawCtx) {}
fn on_event(&mut self, _e: &Event) -> EventResult {
EventResult::Ignored
}
fn is_visible(&self) -> bool {
self.visible
}
fn blocks_child_interaction(&self) -> bool {
self.blocked
}
}
fn scope(visible: bool, blocked: bool) -> Scope {
Scope {
bounds: Rect::new(0.0, 0.0, 10.0, 10.0),
children: vec![Box::new(Focusable {
bounds: Rect::new(0.0, 0.0, 10.0, 10.0),
children: Vec::new(),
})],
visible,
blocked,
}
}
fn focusable_paths(root: &dyn Widget) -> Vec<Vec<usize>> {
let mut out = Vec::new();
collect_focusable(root, &mut Vec::new(), &mut out);
out
}
#[test]
fn interactive_scope_exposes_child_to_focus() {
let root = scope(true, false);
assert_eq!(focusable_paths(&root), vec![vec![0]]);
}
#[test]
fn non_interactive_scope_hides_child_from_focus() {
let root = scope(true, true);
assert!(focusable_paths(&root).is_empty());
}
#[test]
fn invisible_scope_hides_child_from_focus() {
let root = scope(false, false);
assert!(focusable_paths(&root).is_empty());
}
}