This commit is contained in:
griffi-gh 2024-03-11 20:16:01 +01:00
parent b0df6a3ea2
commit 35a536a0bc

View file

@ -140,11 +140,15 @@ pub struct MouseButtonMeta {
} }
#[derive(Default)] #[derive(Default)]
pub struct MousePointer { pub struct MouseState {
/// Current position of the mouse pointer /// Current position of the mouse pointer
pub current_position: Vec2, pub current_position: Vec2,
/// Current state of each mouse button (if down) /// Current state of each mouse button (if down)
pub buttons: HashMap<MouseButton, MouseButtonMeta, BuildNoHashHasher<u16>>, pub buttons: HashMap<MouseButton, MouseButtonMeta, BuildNoHashHasher<u16>>,
/// mouse buttons that were released *in the current frame*
pub released_buttons: HashMap<MouseButton, MouseButtonMeta, BuildNoHashHasher<u16>>,
} }
/// Unique identifier of a touch pointer (finger) /// Unique identifier of a touch pointer (finger)
@ -160,43 +164,61 @@ pub struct TouchFinger {
pub(crate) struct UiInputState { pub(crate) struct UiInputState {
// pointers: HashMap<u32, Pointer, BuildNoHashHasher<u32>>, // pointers: HashMap<u32, Pointer, BuildNoHashHasher<u32>>,
mouse_pointer: MousePointer, mouse_pointer: MouseState,
keyboard_state: Set64<KeyboardKey>, keyboard_state: Set64<KeyboardKey>,
/// events that happened in the current frame
just_happened: Vec<UiEvent>,
} }
impl UiInputState { impl UiInputState {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
// pointers: HashMap::default(), // pointers: HashMap::default(),
mouse_pointer: MousePointer::default(), mouse_pointer: MouseState::default(),
keyboard_state: Set64::new(), keyboard_state: Set64::new(),
just_happened: Vec::new(),
} }
} }
/// Drain the event queue and update the internal input state /// Drain the event queue and update the internal input state
///
/// This function should be called exactly once per frame
pub fn update_state(&mut self, event_queue: &mut EventQueue) { pub fn update_state(&mut self, event_queue: &mut EventQueue) {
for event in event_queue.drain() { self.mouse_pointer.released_buttons.clear();
self.just_happened.clear();
self.just_happened.extend(event_queue.drain());
for event in &self.just_happened {
#[allow(clippy::single_match)] #[allow(clippy::single_match)]
match event { match event {
UiEvent::MouseMove(pos) => { UiEvent::MouseMove(pos) => {
self.mouse_pointer.current_position = pos; self.mouse_pointer.current_position = *pos;
}, },
UiEvent::MouseButton { button, state } => { UiEvent::MouseButton { button, state } => {
match state { match state {
//wtf should we do with buttons that are pressed and released in the same frame?
//i have no fvcking idea
ButtonState::Pressed => { ButtonState::Pressed => {
let button = self.mouse_pointer.buttons.entry(button) let button = self.mouse_pointer.buttons.entry(*button)
.or_insert(MouseButtonMeta::default()); .or_insert(MouseButtonMeta::default());
button.start_position = self.mouse_pointer.current_position; button.start_position = self.mouse_pointer.current_position;
}, },
ButtonState::Released => { ButtonState::Released => {
self.mouse_pointer.buttons.remove(&button); if let Some(button_meta) = self.mouse_pointer.buttons.remove(button) {
self.mouse_pointer.released_buttons.insert(*button, button_meta);
} else {
//huh
//this can happen i guess ¯\_(=^・ω・^)_/¯
self.mouse_pointer.released_buttons.insert(*button, MouseButtonMeta {
start_position: self.mouse_pointer.current_position,
});
}
}, },
} }
}, },
UiEvent::KeyboardButton { key, state } => { UiEvent::KeyboardButton { key, state } => {
match state { match state {
ButtonState::Pressed => self.keyboard_state.insert(key), ButtonState::Pressed => self.keyboard_state.insert(*key),
ButtonState::Released => self.keyboard_state.remove(&key), ButtonState::Released => self.keyboard_state.remove(key),
}; };
}, },
//TODO touch, text input //TODO touch, text input
@ -251,7 +273,35 @@ impl<'a> InputCtx<'a> {
} }
/// Check if a rect can be considered "hovered" /// Check if a rect can be considered "hovered"
///
/// This can be triggered by multiple input sources, such as mouse, touch, etc.
pub fn check_hover(&self, rect: Rect) -> bool { pub fn check_hover(&self, rect: Rect) -> bool {
rect.contains_point(self.0.mouse_pointer.current_position) rect.contains_point(self.0.mouse_pointer.current_position)
} }
/// Check if a rect can be considered "active" (i.e. held down)
///
/// WIP: Not implemented yet, always returns `false`
pub fn check_active(&self, rect: Rect) -> bool {
//TODO `check_active`
false
}
/// Check if a rect can be considered "clicked"
///
/// This can be triggered by multiple input sources, such as mouse, touch, etc.\
/// In case of a mouse, these conditions must be met:
/// - The mouse button got released in the current frame
/// - The mouse pointer is currently inside the rectangle
/// - The mouse pointer was inside the rectangle at the time the button was pressed down
///
/// By default, this function only checks for the primary mouse button\
/// This is a limitation of the current API and may change in the future\
/// (as the current implementation of this function checks for both mouse and touch input, and the touch input quite obviously only supports one "button")
pub fn check_click(&self, rect: Rect) -> bool {
let pos = self.0.mouse_pointer.current_position;
self.0.mouse_pointer.released_buttons.get(&MouseButton::Primary).map_or(false, |meta| {
rect.contains_point(meta.start_position) && rect.contains_point(pos)
})
}
} }