use crate::buttons::core::PollButton;
use crate::buttons::monitors::holding::{
Event as SingleButtonEvent,
HoldAnnotator,
HoldDescriptor,
};
#[cfg(test)]
#[path = "../../../unit_tests/buttons/dual_monitor_with_hold_tests.rs"]
mod tests;
#[derive(PartialEq, Eq, Debug)]
pub enum Event {
ClickA,
ClickB,
ClickAB,
HoldA,
HoldB,
HoldAB,
}
#[derive(PartialEq, Eq, Debug)]
enum State {
SeenOne,
SeenBoth,
HeldASeenB,
HeldBSeenA,
ReportedHold,
}
trait ButtonDescriptor {
const CLICK_EVENT: Event;
const HOLD_EVENT: Event;
const HELD_STATE: State;
const OTHER_HELD_STATE: State;
}
struct ButtonADescriptor();
struct ButtonBDescriptor();
impl ButtonDescriptor for ButtonADescriptor {
const CLICK_EVENT: Event = Event::ClickA;
const HOLD_EVENT: Event = Event::HoldA;
const HELD_STATE: State = State::HeldASeenB;
const OTHER_HELD_STATE: State = State::HeldBSeenA;
}
impl ButtonDescriptor for ButtonBDescriptor {
const CLICK_EVENT: Event = Event::ClickB;
const HOLD_EVENT: Event = Event::HoldB;
const HELD_STATE: State = State::HeldBSeenA;
const OTHER_HELD_STATE: State = State::HeldASeenB;
}
struct MonitorState {
state: State,
}
impl MonitorState {
fn new() -> MonitorState {
MonitorState {
state: State::ReportedHold,
}
}
fn handle<T: ButtonDescriptor>(
&mut self,
event: SingleButtonEvent,
other_button_is_pressed: bool,
) -> Option<Event> {
match event {
SingleButtonEvent::Press if !other_button_is_pressed => {
self.state = State::SeenOne;
}
SingleButtonEvent::Press if self.state == State::SeenOne => {
self.state = State::SeenBoth;
}
SingleButtonEvent::Release if self.state == State::SeenOne => {
return Some(T::CLICK_EVENT);
}
SingleButtonEvent::Release if self.state != State::ReportedHold => {
if !other_button_is_pressed {
return Some(Event::ClickAB);
}
}
SingleButtonEvent::Hold if self.state == State::SeenOne => {
self.state = State::ReportedHold;
return Some(T::HOLD_EVENT);
}
SingleButtonEvent::Hold if self.state == State::SeenBoth => {
self.state = T::HELD_STATE;
}
SingleButtonEvent::Hold if self.state == T::OTHER_HELD_STATE => {
self.state = State::ReportedHold;
return Some(Event::HoldAB);
}
_ => {}
};
None
}
fn handle_a(
&mut self,
event: SingleButtonEvent,
other_button_is_pressed: bool,
) -> Option<Event> {
self.handle::<ButtonADescriptor>(event, other_button_is_pressed)
}
fn handle_b(
&mut self,
event: SingleButtonEvent,
other_button_is_pressed: bool,
) -> Option<Event> {
self.handle::<ButtonBDescriptor>(event, other_button_is_pressed)
}
}
pub struct Monitor<A: PollButton, B: PollButton, H: HoldDescriptor> {
button_a: A,
button_b: B,
hold_annotator_a: HoldAnnotator<H>,
hold_annotator_b: HoldAnnotator<H>,
state: MonitorState,
}
impl<A: PollButton, B: PollButton, H: HoldDescriptor> Monitor<A, B, H> {
pub fn new(button_a: A, button_b: B) -> Monitor<A, B, H> {
Monitor {
button_a,
button_b,
hold_annotator_a: HoldAnnotator::new(),
hold_annotator_b: HoldAnnotator::new(),
state: MonitorState::new(),
}
}
pub fn free(self) -> (A, B) {
(self.button_a, self.button_b)
}
fn poll_a(&mut self) -> Option<Event> {
self.hold_annotator_a.annotate(self.button_a.poll_transition())
.and_then(|event| {
self.state.handle_a(event, self.button_b.is_pressed())
})
}
fn poll_b(&mut self) -> Option<Event> {
self.hold_annotator_b.annotate(self.button_b.poll_transition())
.and_then(|event| {
self.state.handle_b(event, self.button_a.is_pressed())
})
}
pub fn poll(&mut self) -> Option<Event> {
let event_a = self.poll_a();
let event_b = self.poll_b();
assert!(event_a.is_none() || event_b.is_none());
event_a.or(event_b)
}
}