From d1b00ff1b00f7ee0d9321038d373c1b6f8259095 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sat, 23 May 2020 00:08:43 +0200 Subject: [PATCH] refactor input code --- emigui/src/containers/menu.rs | 2 +- emigui/src/context.rs | 47 +++----------- emigui/src/input.rs | 111 ++++++++++++++++++++++++---------- emigui/src/ui.rs | 2 +- 4 files changed, 89 insertions(+), 73 deletions(-) diff --git a/emigui/src/containers/menu.rs b/emigui/src/containers/menu.rs index 5b4175aa..32d8c601 100644 --- a/emigui/src/containers/menu.rs +++ b/emigui/src/containers/menu.rs @@ -109,7 +109,7 @@ fn menu_impl<'c>( fn interact_with_menu_button( bar_state: &mut BarState, - input: &GuiInput, + input: &InputState, menu_id: Id, button_interact: &GuiResponse, ) { diff --git a/emigui/src/context.rs b/emigui/src/context.rs index e41d0c1d..77b9a7c2 100644 --- a/emigui/src/context.rs +++ b/emigui/src/context.rs @@ -25,11 +25,7 @@ pub struct Context { new_fonts: Mutex>>, memory: Arc>, - // Input releated stuff: - raw_input: RawInput, - previus_input: GuiInput, - input: GuiInput, - mouse_tracker: MovementTracker, + input: InputState, // The output of a frame: graphics: Mutex, @@ -49,10 +45,7 @@ impl Clone for Context { fonts: self.fonts.clone(), new_fonts: Mutex::new(self.new_fonts.lock().clone()), memory: self.memory.clone(), - raw_input: self.raw_input.clone(), - previus_input: self.previus_input.clone(), input: self.input.clone(), - mouse_tracker: self.mouse_tracker.clone(), graphics: Mutex::new(self.graphics.lock().clone()), output: Mutex::new(self.output.lock().clone()), used_ids: Mutex::new(self.used_ids.lock().clone()), @@ -70,10 +63,7 @@ impl Context { new_fonts: Default::default(), memory: Default::default(), - raw_input: Default::default(), - previus_input: Default::default(), input: Default::default(), - mouse_tracker: MovementTracker::new(1000, 0.1), graphics: Default::default(), output: Default::default(), @@ -98,20 +88,10 @@ impl Context { self.output.try_lock().expect("output already locked") } - /// Input previous frame. Compare to `input()` to check for changes. - pub fn previus_input(&self) -> &GuiInput { - &self.previus_input - } - - pub fn input(&self) -> &GuiInput { + pub fn input(&self) -> &InputState { &self.input } - /// Smoothed mouse velocity, in points per second - pub fn mouse_vel(&self) -> Vec2 { - self.mouse_tracker.velocity().unwrap_or_default() - } - pub fn fonts(&self) -> &Fonts { &*self.fonts } @@ -167,7 +147,7 @@ impl Context { } fn begin_frame_mut(&mut self, new_raw_input: RawInput) { - if !self.raw_input.mouse_down || self.raw_input.mouse_pos.is_none() { + if !self.input.mouse.down || self.input.mouse.pos.is_none() { self.memory().active_id = None; let window_interaction = self.memory().window_interaction.take(); @@ -188,17 +168,7 @@ impl Context { self.fonts = new_fonts; } - if let Some(mouse_pos) = new_raw_input.mouse_pos { - self.mouse_tracker.add(new_raw_input.time, mouse_pos); - } else { - // we do not clear the `mouse_tracker` here, because it is exactly when a finger has - // released from the touch screen that we may want to assign a velocity to whatever - // the user tried to throw - } - let new_input = GuiInput::from_last_and_new(&self.raw_input, &new_raw_input); - self.previus_input = std::mem::replace(&mut self.input, new_input); - self.input.mouse.velocity = self.mouse_vel(); - self.raw_input = new_raw_input; + self.input = std::mem::take(&mut self.input).begin_frame(new_raw_input); } pub fn end_frame(&self) -> (Output, PaintBatches) { @@ -505,12 +475,9 @@ impl Context { pub fn inspection_ui(&self, ui: &mut Ui) { use crate::containers::*; - ui.collapsing("Input", |ui| { - CollapsingHeader::new("Raw Input").show(ui, |ui| ui.ctx().raw_input.clone().ui(ui)); - CollapsingHeader::new("Input") - .default_open(true) - .show(ui, |ui| ui.input().clone().ui(ui)); - }); + CollapsingHeader::new("Input") + .default_open(true) + .show(ui, |ui| ui.input().clone().ui(ui)); ui.collapsing("Stats", |ui| { ui.add(label!( diff --git a/emigui/src/input.rs b/emigui/src/input.rs index def9b0ff..403eb793 100644 --- a/emigui/src/input.rs +++ b/emigui/src/input.rs @@ -1,6 +1,6 @@ use serde_derive::Deserialize; -use crate::math::*; +use crate::{math::*, movement_tracker::MovementTracker}; /// What the integration gives to the gui. /// All coordinates in emigui is in point/logical coordinates. @@ -35,7 +35,10 @@ pub struct RawInput { /// What emigui maintains #[derive(Clone, Debug, Default)] -pub struct GuiInput { +pub struct InputState { + /// The raw input we got this fraem + pub raw: RawInput, + pub mouse: MouseInput, /// How many pixels the user scrolled @@ -61,7 +64,7 @@ pub struct GuiInput { } /// What emigui maintains -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct MouseInput { /// Is the button currently down? /// true the frame when it is pressed, @@ -83,6 +86,24 @@ pub struct MouseInput { /// Current velocity of mouse cursor. pub velocity: Vec2, + + /// Recent movement of the mouse. + /// Used for calculating velocity of mouse pointer. + pub pos_tracker: MovementTracker, +} + +impl Default for MouseInput { + fn default() -> Self { + Self { + down: false, + pressed: false, + released: false, + pos: None, + delta: Vec2::zero(), + velocity: Vec2::zero(), + pos_tracker: MovementTracker::new(1000, 0.1), + } + } } #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize)] @@ -123,46 +144,53 @@ pub enum Key { Up, } -impl GuiInput { - pub fn from_last_and_new(last: &RawInput, new: &RawInput) -> GuiInput { - let dt = (new.time - last.time) as f32; - GuiInput { - mouse: MouseInput::from_last_and_new(last, new), +impl InputState { + #[must_use] + pub fn begin_frame(self, new: RawInput) -> InputState { + let mouse = self.mouse.begin_frame(&new); + let dt = (new.time - self.raw.time) as f32; + InputState { + mouse, scroll_delta: new.scroll_delta, screen_size: new.screen_size, pixels_per_point: new.pixels_per_point.unwrap_or(1.0), time: new.time, dt, seconds_since_midnight: new.seconds_since_midnight, - events: new.events.clone(), + events: new.events.clone(), // TODO: remove clone() and use raw.events + raw: new, } } } impl MouseInput { - pub fn from_last_and_new(last: &GuiInput, new: &RawInput) -> MouseInput { + #[must_use] + pub fn begin_frame(mut self, new: &RawInput) -> MouseInput { let delta = new .mouse_pos - .and_then(|new| last.mouse.pos.map(|last| new - last)) + .and_then(|new| self.pos.map(|last| new - last)) .unwrap_or_default(); - let dt = (new.time - last.time) as f32; - let mut velocity = delta / dt; - if !velocity.is_finite() { - velocity = Vec2::zero(); - } - let pressed = !last.mouse.down && new.mouse_down; - let mut press_origin = last.mouse.press_origin; - if pressed { - press_origin = new.mouse_pos; + let pressed = !self.down && new.mouse_down; + + if let Some(mouse_pos) = new.mouse_pos { + self.pos_tracker.add(new.time, mouse_pos); + } else { + // we do not clear the `mouse_tracker` here, because it is exactly when a finger has + // released from the touch screen that we may want to assign a velocity to whatever + // the user tried to throw } + + // TODO: pass current time as argument so we don't have a velocity after mouse up + let velocity = self.pos_tracker.velocity().unwrap_or_default(); + MouseInput { down: new.mouse_down && new.mouse_pos.is_some(), pressed, - released: last.mouse.down && !new.mouse_down, + released: self.down && !new.mouse_down, pos: new.mouse_pos, - press_origin, delta, velocity, + pos_tracker: self.pos_tracker, } } } @@ -174,27 +202,48 @@ impl RawInput { // TODO: easily change default font! ui.add(label!("mouse_down: {}", self.mouse_down)); ui.add(label!("mouse_pos: {:.1?}", self.mouse_pos)); - ui.add(label!("scroll_delta: {:?}", self.scroll_delta)); - ui.add(label!("screen_size: {:?}", self.screen_size)); - ui.add(label!("pixels_per_point: {:?}", self.pixels_per_point)); + ui.add(label!("scroll_delta: {:?} points", self.scroll_delta)); + ui.add(label!("screen_size: {:?} points", self.screen_size)); + ui.add(label!("pixels_per_point: {:?}", self.pixels_per_point)) + .tooltip_text( + "Also called hdpi factor.\nNumber of physical pixels per each logical pixel.", + ); ui.add(label!("time: {:.3} s", self.time)); - ui.add(label!("events: {:?}", self.events)); + ui.add(label!( + "seconds_since_midnight: {:?} s", + self.seconds_since_midnight + )); + ui.add(label!("events: {:?}", self.events)) + .tooltip_text("key presses etc"); } } -impl GuiInput { +impl InputState { pub fn ui(&self, ui: &mut crate::Ui) { use crate::label; + + ui.collapsing("Raw Input", |ui| self.raw.ui(ui)); + crate::containers::CollapsingHeader::new("mouse") .default_open(true) .show(ui, |ui| { self.mouse.ui(ui); }); - ui.add(label!("scroll_delta: {:?}", self.scroll_delta)); - ui.add(label!("screen_size: {:?}", self.screen_size)); - ui.add(label!("pixels_per_point: {}", self.pixels_per_point)); + + ui.add(label!("scroll_delta: {:?} points", self.scroll_delta)); + ui.add(label!("screen_size: {:?} points", self.screen_size)); + ui.add(label!( + "{} points for each physical pixel (hdpi factor)", + self.pixels_per_point + )); ui.add(label!("time: {:.3} s", self.time)); - ui.add(label!("events: {:?}", self.events)); + ui.add(label!("dt: {:.3} s", self.dt)); + ui.add(label!( + "seconds_since_midnight: {:?} s", + self.seconds_since_midnight + )); + ui.add(label!("events: {:?}", self.events)) + .tooltip_text("key presses etc"); } } diff --git a/emigui/src/ui.rs b/emigui/src/ui.rs index 79f4e542..ccdf2339 100644 --- a/emigui/src/ui.rs +++ b/emigui/src/ui.rs @@ -119,7 +119,7 @@ impl Ui { &self.ctx } - pub fn input(&self) -> &GuiInput { + pub fn input(&self) -> &InputState { self.ctx.input() }