chiro 0.1.3

A curses-style terminal view that runs inside a pixel buffer (Rewrite of chiropterm)
Documentation
use enum_map::EnumMap;
use euclid::point2;

use crate::shared::*;

use super::{Event, MouseEvent, TypeEvent, MouseButton, PressKey, PressEvent};

#[derive(Clone)]
pub struct Input {
    keyboard: Keyboard,
    mouse: Mouse,
}

impl Input {
    pub fn new() -> Input {
        Input { keyboard: Keyboard::new(), mouse: Mouse::new() }
    }

    pub(crate) fn on_event(&mut self, event: Event) {
        match event {
            Event::Exit => {}
            Event::Tick(_) => { 
                self.keyboard.on_tick();
                self.mouse.on_tick();
            }
            Event::Press(k) => { self.keyboard.on_simple_event(k) }
            Event::Type(k) => { self.keyboard.on_event(k) }
            Event::Mouse(m) => { self.mouse.on_event(m) }
        }
    }

    pub fn keyboard(&self) -> &Keyboard {
        &self.keyboard
    }

    pub fn mouse(&self) -> &Mouse {
        &self.mouse
    }
}

#[derive(Clone)]
pub struct Keyboard {
    typed_chars: String,
    is_down: EnumMap<PressKey, bool>,
    is_pressed: EnumMap<PressKey, bool>,
    is_released: EnumMap<PressKey, bool>,
}

impl Keyboard {
    pub fn new() -> Keyboard {
        Keyboard {
            typed_chars: String::new(),
            is_down: EnumMap::default(),
            is_pressed: EnumMap::default(),
            is_released: EnumMap::default(),
        }
    }

    fn on_tick(&mut self) {
        self.typed_chars.clear();
        self.is_pressed = EnumMap::default();
        self.is_released = EnumMap::default();
    }

    fn on_event(&mut self, k: TypeEvent) {
        match k {
            TypeEvent::Down(_) => { }
            TypeEvent::Up(_) => { }
            TypeEvent::Type(c) => {
                self.typed_chars.push(c)
            },
        }
    }

    fn on_simple_event(&mut self, k: PressEvent) {
        match k {
            PressEvent::Press(kc) => {
                self.is_down[kc] = true;
                self.is_pressed[kc] = true;
            }
            PressEvent::Release(kc) => {
                self.is_down[kc] = false;
                self.is_released[kc] = true;
            }
        }
    }

    pub fn typed_chars(&self) -> &str { &self.typed_chars }

    pub fn any_is_pressed(&self) -> bool { self.is_pressed.values().any(|x| *x) }
    pub fn any_is_released(&self) -> bool { self.is_released.values().any(|x| *x) }
    pub fn any_is_down(&self) -> bool { self.is_down.values().any(|x| *x) }

    pub fn is_pressed(&self, key: PressKey) -> bool { self.is_pressed[key] }
    pub fn is_released(&self, key: PressKey) -> bool { self.is_released[key] }
    pub fn is_down(&self, key: PressKey) -> bool { self.is_down[key] }
}

#[derive(Clone)]
pub struct Mouse {
    click_selection: Option<Affordance>,
    scroll_selection: Option<Affordance>,

    position: Zel,
    scroll: f32,

    is_down: EnumMap<MouseButton, bool>,
    is_pressed: EnumMap<MouseButton, bool>,
    is_released: EnumMap<MouseButton, bool>,

    drag: EnumMap<MouseButton, Option<Drag>>,
}

impl Mouse {
    pub fn new() -> Mouse {
        Mouse {
            click_selection: None,
            scroll_selection: None,

            position: point2(0, 0),
            scroll: 0.0,

            is_down: EnumMap::default(),
            is_pressed: EnumMap::default(),
            is_released: EnumMap::default(),

            drag: EnumMap::default(),
        }
    }

    fn on_tick(&mut self) {
        self.scroll = 0.0;

        self.is_pressed = EnumMap::default();
        self.is_released = EnumMap::default();
    }

    fn on_event(&mut self, m: MouseEvent) {
        match m {
            MouseEvent::Click { mouse_button: mb, .. } => {
                self.is_pressed[mb] = true;
                self.is_down[mb] = true;
            }
            MouseEvent::Up { mouse_button: mb, .. } => {
                self.is_down[mb] = false;
                self.is_released[mb] = true;
                self.drag[mb] = None;
            }
            MouseEvent::Drag { mouse_button: mb, start, last, now, now_click_selection: _, now_scroll_selection: _} => {
                self.drag[mb] = Some(Drag { start, last, now })
            }
            MouseEvent::Wiggle { last: _, now, now_click_selection, now_scroll_selection } => {
                self.click_selection = now_click_selection;
                self.scroll_selection = now_scroll_selection;
                self.position = now;
            }
            MouseEvent::Scroll(amt, _, _) => {
                self.scroll += amt;
            }
        }
    }

    pub fn is_click_over(&self, affordance: Affordance) -> bool { self.click_selection == Some(affordance) }
    pub fn is_scroll_over(&self, affordance: Affordance) -> bool { self.scroll_selection == Some(affordance) }

    pub fn any_is_pressed(&self) -> bool { self.is_pressed.values().any(|x| *x) }
    pub fn any_is_released(&self) -> bool { self.is_released.values().any(|x| *x) }
    pub fn any_is_down(&self) -> bool { self.is_down.values().any(|x| *x) }

    pub fn is_pressed(&self, button: MouseButton) -> bool { self.is_pressed[button] }
    pub fn is_released(&self, button: MouseButton) -> bool { self.is_pressed[button] }
    pub fn is_down(&self, button: MouseButton) -> bool { self.is_pressed[button] }

    pub fn any_clicked(&self, affordance: Affordance) -> bool { self.any_is_pressed() && self.is_click_over(affordance) }
    pub fn left_clicked(&self, affordance: Affordance) -> bool { self.is_pressed(MouseButton::Left) && self.is_click_over(affordance) }
    pub fn right_clicked(&self, affordance: Affordance) -> bool { self.is_pressed(MouseButton::Right) && self.is_click_over(affordance) }
    pub fn scrolled_on(&self, affordance: Affordance) -> Option<f32> {
        if self.scroll == 0.0 || !self.is_scroll_over(affordance) { return None }
        return Some(self.scroll);
    }
}

#[derive(Clone)]
pub struct Drag {
    pub start: Zel,
    pub last: Zel,
    pub now: Zel,
}