#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct WidgetId(u64);
impl WidgetId {
#[must_use]
pub const fn new(raw: u64) -> Self {
Self(raw)
}
#[must_use]
pub const fn raw(self) -> u64 {
self.0
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FocusDirection {
Forward,
Backward,
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct FocusState {
focused: Option<WidgetId>,
}
impl FocusState {
#[must_use]
pub const fn new() -> Self {
Self { focused: None }
}
#[must_use]
pub const fn focused(self) -> Option<WidgetId> {
self.focused
}
pub fn set(&mut self, focused: Option<WidgetId>) {
self.focused = focused;
}
pub fn clear(&mut self) {
self.focused = None;
}
pub fn reconcile(&mut self, order: &[WidgetId]) {
if let Some(id) = self.focused
&& !order.contains(&id)
{
self.focused = None;
}
}
pub fn advance(&mut self, order: &[WidgetId], direction: FocusDirection) {
if order.is_empty() {
self.focused = None;
return;
}
let current = self
.focused
.and_then(|id| order.iter().position(|candidate| *candidate == id));
let next = match (direction, current) {
(FocusDirection::Forward, Some(idx)) => (idx + 1) % order.len(),
(FocusDirection::Backward, Some(0)) => order.len() - 1,
(FocusDirection::Backward, Some(idx)) => idx - 1,
(FocusDirection::Forward | FocusDirection::Backward, None) => 0,
};
self.focused = Some(order[next]);
}
}