use embedded_graphics::prelude::Point;
use crate::ui::Interaction;
pub type FocusID = u16;
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum Focused {
No,
Yes,
Trigger,
}
impl From<Focused> for Interaction {
fn from(focused: Focused) -> Self {
match focused {
Focused::No => Self::None,
Focused::Yes => Self::Pressed(Point::zero()),
Focused::Trigger => Self::Clicked(Point::zero()),
}
}
}
impl From<Focused> for crate::widget_state::RenderStatus {
fn from(focused: Focused) -> Self {
match focused {
Focused::No => Self::Normal,
Focused::Yes => Self::Focused,
Focused::Trigger => Self::Triggered,
}
}
}
#[derive(Debug, Default)]
pub struct FocusTracker {
pub(crate) pos: usize,
pub(crate) size: usize,
pub(crate) trigger: Option<FocusID>,
}
#[derive(Debug)]
pub struct FocusState<const N: usize> {
pub(crate) widgets_id: [FocusID; N],
pub(crate) tracker: FocusTracker,
}
impl<const N: usize> FocusState<N> {
pub fn new() -> Self {
Self {
widgets_id: [0; N],
tracker: FocusTracker::default(),
}
}
pub fn clear_focus(&mut self) {
self.tracker.pos = 0;
self.tracker.size = 0;
self.tracker.trigger = None;
}
#[allow(clippy::should_implement_trait)]
pub fn focus_next(&mut self) -> bool {
self.tracker.trigger = None;
if self.tracker.pos < self.tracker.size {
self.tracker.pos += 1;
if self.tracker.pos >= self.tracker.size {
self.tracker.pos = 0;
}
true
} else {
false
}
}
pub fn focus_prev(&mut self) -> bool {
self.tracker.trigger = None;
if self.tracker.size > self.tracker.pos {
if self.tracker.pos > 0 {
self.tracker.pos -= 1;
} else {
self.tracker.pos = self.tracker.size - 1;
}
true
} else {
false
}
}
pub fn trigger_focus(&mut self) {
if self.tracker.pos < self.tracker.size {
self.tracker.trigger = self.widgets_id.get(self.tracker.pos).copied();
}
}
}
impl<const N: usize> Default for FocusState<N> {
fn default() -> Self {
Self::new()
}
}
pub(crate) struct Focus<'a> {
pub widgets_id: &'a mut [FocusID],
pub tracker: &'a mut FocusTracker,
}
impl<'a> Focus<'a> {
pub fn new<const N: usize>(focus_state: &'a mut FocusState<N>) -> Self {
Self {
widgets_id: &mut focus_state.widgets_id,
tracker: &mut focus_state.tracker,
}
}
pub fn register_focus(&mut self, id: usize) -> bool {
let id = id as FocusID;
if self.tracker.size > 0
&& self
.widgets_id
.get(..self.tracker.size)
.map_or(false, |slice| slice.contains(&id))
{
return true;
}
if self.tracker.size < self.widgets_id.len() {
if let Some(slot) = self.widgets_id.get_mut(self.tracker.size) {
*slot = id;
self.tracker.size += 1;
true
} else {
false
}
} else {
false
}
}
pub fn is_focused(&self, id: usize) -> bool {
self.widgets_id
.get(self.tracker.pos)
.map_or(false, |&widget_id| widget_id == id as FocusID)
}
}