focusable 0.2.9

A trait for types that can be focused
Documentation
use std::fmt::Debug;

use focusable::{Focus, FocusContainer};
use tracing::{info, instrument, trace};

use crate::{Render, Widget};

pub struct Container {
    pub children: Vec<Box<dyn Widget>>,
}

impl Debug for Container {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Container")
            .field("children", &"...")
            .finish()
    }
}

impl Container {
    #[instrument(level = "debug")]
    pub fn new() -> Self {
        Self {
            children: Vec::new(),
        }
    }

    #[instrument(level = "debug", skip(self, child))]
    pub fn add_child(&mut self, child: Box<dyn Widget>) {
        self.children.push(child);
    }
}

impl From<Vec<Box<dyn Widget>>> for Container {
    #[instrument(level = "debug", skip(items))]
    fn from(items: Vec<Box<dyn Widget>>) -> Self {
        Self { children: items }
    }
}

impl FromIterator<Box<dyn Widget>> for Container {
    #[instrument(level = "debug", skip(items))]
    fn from_iter<T: IntoIterator<Item = Box<dyn Widget>>>(items: T) -> Self {
        Self {
            children: items.into_iter().collect(),
        }
    }
}

impl Render for Container {
    #[instrument(level = "trace", skip(self))]
    fn render(&self) {
        info!("Container has {} children", self.children.len());
        for child in &self.children {
            child.render();
        }
    }
}

impl Focus for Container {
    #[instrument(level = "trace", skip(self))]
    fn can_focus(&self) -> bool {
        true
    }

    #[instrument(level = "trace", skip(self))]
    fn is_focused(&self) -> bool {
        self.children.iter().any(|child| child.is_focused())
    }

    #[instrument(level = "trace", skip(self))]
    fn focus(&mut self) {
        self.focus_first()
    }

    #[instrument(level = "trace", skip(self))]
    fn blur(&mut self) {
        self.children.iter_mut().for_each(|child| child.blur());
    }
}

impl FocusContainer for Container {
    #[instrument(level = "trace", skip(self))]
    fn focus_first(&mut self) {
        if let Some(first_child) = self.children.iter_mut().find(|child| child.can_focus()) {
            first_child.focus();
        }
    }

    #[instrument(level = "trace", skip(self))]
    fn focus_next(&mut self) {
        let mut children = self.children.iter_mut();
        if let Some(focused_child) = children.find(|child| child.is_focused()) {
            focused_child.blur();
        }
        let next_child = children.find(|child| child.can_focus());
        if let Some(next_child) = next_child {
            next_child.focus();
        } else {
            trace!("No next child found");
            self.focus_first();
        }
    }

    #[instrument(level = "trace", skip(self))]
    fn focus_previous(&mut self) {
        let mut children = self.children.iter_mut().rev();
        if let Some(focused_child) = children.find(|child| child.is_focused()) {
            focused_child.blur();
        }
        let next_child = children.find(|child| child.can_focus());
        if let Some(next_child) = next_child {
            next_child.focus();
        } else {
            trace!("No previous child found");
            self.focus_last();
        }
    }

    #[instrument(level = "trace", skip(self))]
    fn focus_last(&mut self) {
        if let Some(last_child) = self
            .children
            .iter_mut()
            .rev()
            .find(|child| child.can_focus())
        {
            last_child.focus();
        }
    }
}