use embedded_graphics::primitives::Rectangle;
use crate::{Button, TouchEvent, TouchPhase};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ButtonTouchResponse<K> {
pub action: Option<K>,
pub captured: bool,
pub redraw: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct ActiveButton<K> {
key: K,
frame: Rectangle,
highlighted: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ButtonTouchState<K> {
active: Option<ActiveButton<K>>,
}
impl<K: Copy + Eq> ButtonTouchState<K> {
pub const fn new() -> Self {
Self { active: None }
}
pub fn clear(&mut self) {
self.active = None;
}
pub fn is_highlighted(&self, button: &Button<'_, K>) -> bool {
matches!(
self.active,
Some(active)
if active.highlighted
&& active.key == button.spec.key
&& active.frame == button.frame
)
}
pub fn handle_touch<'a>(
&mut self,
touch: TouchEvent,
buttons: &[Button<'a, K>],
) -> ButtonTouchResponse<K> {
let was_active = self.active;
match touch.phase {
TouchPhase::Start => {
self.active = buttons.iter().find_map(|button| {
touch.within(button.frame).then_some(ActiveButton {
key: button.spec.key,
frame: button.frame,
highlighted: true,
})
});
ButtonTouchResponse {
action: None,
captured: self.active.is_some(),
redraw: was_active != self.active,
}
}
TouchPhase::Move => self.move_touch(touch),
TouchPhase::End => self.finish_touch(touch),
TouchPhase::Cancel => self.cancel_touch(),
}
}
fn move_touch(&mut self, touch: TouchEvent) -> ButtonTouchResponse<K> {
let Some(mut active) = self.active else {
return ButtonTouchResponse {
action: None,
captured: false,
redraw: false,
};
};
let highlighted = touch.within(active.frame);
let redraw = highlighted != active.highlighted;
active.highlighted = highlighted;
self.active = Some(active);
ButtonTouchResponse {
action: None,
captured: true,
redraw,
}
}
fn finish_touch(&mut self, touch: TouchEvent) -> ButtonTouchResponse<K> {
let Some(active) = self.active.take() else {
return ButtonTouchResponse {
action: None,
captured: false,
redraw: false,
};
};
ButtonTouchResponse {
action: (active.highlighted && touch.within(active.frame)).then_some(active.key),
captured: true,
redraw: active.highlighted,
}
}
fn cancel_touch(&mut self) -> ButtonTouchResponse<K> {
let Some(active) = self.active.take() else {
return ButtonTouchResponse {
action: None,
captured: false,
redraw: false,
};
};
ButtonTouchResponse {
action: None,
captured: true,
redraw: active.highlighted,
}
}
}