diff --git a/emigui/README.md b/emigui/README.md index 23e25ed8..b31025b3 100644 --- a/emigui/README.md +++ b/emigui/README.md @@ -77,7 +77,7 @@ Add extremely quick animations for some things, maybe 2-3 frames. For instance: * e.g. `ui.containers((Frame::new(), Resize::new(), ScrollArea::new()), |ui| ...)` ### Input -* [ ] Distinguish between clicks and drags +* [x] Distinguish between clicks and drags * [ ] Double-click * [x] Text diff --git a/emigui/src/containers/scroll_area.rs b/emigui/src/containers/scroll_area.rs index d26884f0..153cb264 100644 --- a/emigui/src/containers/scroll_area.rs +++ b/emigui/src/containers/scroll_area.rs @@ -154,7 +154,7 @@ impl Prepared { } // TODO: check that nothing else is being inteacted with - if ui.contains_mouse(outer_rect) && ui.memory().active_id.is_none() { + if ui.contains_mouse(outer_rect) { state.offset.y -= ui.input().scroll_delta.y; } diff --git a/emigui/src/containers/window.rs b/emigui/src/containers/window.rs index 8977d49e..a279ec98 100644 --- a/emigui/src/containers/window.rs +++ b/emigui/src/containers/window.rs @@ -358,9 +358,9 @@ fn window_interaction( rect: Rect, ) -> Option { { - let active_id = ctx.memory().active_id; + let drag_id = ctx.memory().interaction.drag_id; - if active_id.is_some() && active_id != Some(id) { + if drag_id.is_some() && drag_id != Some(id) { return None; } } @@ -371,7 +371,7 @@ fn window_interaction( if let Some(hover_window_interaction) = resize_hover(ctx, possible, area_layer, rect) { hover_window_interaction.set_cursor(ctx); if ctx.input().mouse.pressed { - ctx.memory().active_id = Some(id); + ctx.memory().interaction.drag_id = Some(id); window_interaction = Some(hover_window_interaction); ctx.memory().window_interaction = window_interaction; } @@ -379,7 +379,7 @@ fn window_interaction( } if let Some(window_interaction) = window_interaction { - let is_active = ctx.memory().active_id == Some(id); + let is_active = ctx.memory().interaction.drag_id == Some(id); if is_active && window_interaction.area_layer == area_layer { return Some(window_interaction); diff --git a/emigui/src/context.rs b/emigui/src/context.rs index f7c0d587..49b4343f 100644 --- a/emigui/src/context.rs +++ b/emigui/src/context.rs @@ -147,9 +147,14 @@ impl Context { } fn begin_frame_mut(&mut self, new_raw_input: RawInput) { + if !self.input().mouse.could_be_click { + self.memory().interaction.click_id = None; + } + if !self.input.mouse.down || self.input.mouse.pos.is_none() { // mouse was not down last frame - self.memory().active_id = None; + self.memory().interaction.click_id = None; + self.memory().interaction.drag_id = None; let window_interaction = self.memory().window_interaction.take(); if let Some(window_interaction) = window_interaction { @@ -234,11 +239,6 @@ impl Context { // --------------------------------------------------------------------- - /// Is the user interacting with anything? - pub fn any_active(&self) -> bool { - self.memory().active_id.is_some() - } - /// Generate a id from the given source. /// If it is not unique, an error will be printed at the given position. pub fn make_unique_id(&self, source: IdSource, pos: Pos2) -> Id @@ -307,39 +307,31 @@ impl Context { let interaction_id = interaction_id.unwrap(); let mut memory = self.memory(); - let active = memory.active_id == Some(interaction_id); - - if active && !sense.drag && !self.input().mouse.could_be_click { - // Aborted click - memory.active_id = None; - return InteractInfo { - rect, - hovered: false, - clicked: false, - active: false, - }; - } + let active = memory.interaction.click_id == Some(interaction_id) + || memory.interaction.drag_id == Some(interaction_id); if self.input.mouse.pressed { if hovered { - if memory.active_id.is_some() { - // Already clicked something else this frame - InteractInfo { - rect, - hovered, - clicked: false, - active: false, - } - } else { - // start of a click or drag - memory.active_id = Some(interaction_id); - InteractInfo { - rect, - hovered, - clicked: false, - active: true, - } + let mut info = InteractInfo { + rect, + hovered: true, + clicked: false, + active: false, + }; + + if sense.click && !memory.interaction.click_id.is_some() { + // start of a click + memory.interaction.click_id = Some(interaction_id); + info.active = true; } + + if sense.drag && !memory.interaction.drag_id.is_some() { + // start of a drag + memory.interaction.drag_id = Some(interaction_id); + info.active = true; + } + + info } else { // miss InteractInfo { diff --git a/emigui/src/memory.rs b/emigui/src/memory.rs index 62728e44..1504b505 100644 --- a/emigui/src/memory.rs +++ b/emigui/src/memory.rs @@ -9,9 +9,8 @@ use crate::{ #[derive(Clone, Debug, Default, serde_derive::Deserialize, serde_derive::Serialize)] #[serde(default)] pub struct Memory { - /// The widget being interacted with (e.g. dragged, in case of a slider). #[serde(skip)] - pub(crate) active_id: Option, + pub(crate) interaction: Interaction, /// The widget with keyboard focus (i.e. a text input field). #[serde(skip)] @@ -30,6 +29,22 @@ pub struct Memory { pub(crate) areas: Areas, } +/// Say there is a butotn in a scroll area. +/// If the user clicks the button, the button should click. +/// If the user drags the button we should scroll the scroll area. +/// So what we do is that when the mouse is pressed we register both the button +/// and the scroll area (as `click_id`/`drag_id`). +/// If the user releases the button without moving the mouse we register it as a click on `click_id`. +/// If the cursor moves too much we clear the `click_id` and start passing move events to `drag_id`. +#[derive(Clone, Debug, Default)] +pub struct Interaction { + /// A widget interested in clicks that has a mouse press on it. + pub click_id: Option, + + /// A widget interested in drags that has a mouse press on it. + pub drag_id: Option, +} + #[derive(Clone, Debug, Default, serde_derive::Deserialize, serde_derive::Serialize)] #[serde(default)] pub struct Areas {