diff --git a/crates/egui/src/containers/panel.rs b/crates/egui/src/containers/panel.rs index f5267e0f0c7..ffc073920da 100644 --- a/crates/egui/src/containers/panel.rs +++ b/crates/egui/src/containers/panel.rs @@ -702,9 +702,9 @@ impl TopBottomPanel { if ui.input(|i| i.pointer.any_pressed() && i.pointer.any_down()) && mouse_over_resize_line { - ui.memory_mut(|mem| mem.interaction.drag_id = Some(resize_id)); + ui.memory_mut(|mem| mem.interaction_mut().drag_id = Some(resize_id)); } - is_resizing = ui.memory(|mem| mem.interaction.drag_id == Some(resize_id)); + is_resizing = ui.memory(|mem| mem.interaction().drag_id == Some(resize_id)); if is_resizing { let height = (pointer.y - side.side_y(panel_rect)).abs(); let height = diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index f1973684979..264672f2406 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -633,7 +633,7 @@ fn window_interaction( rect: Rect, ) -> Option { { - let drag_id = ctx.memory(|mem| mem.interaction.drag_id); + let drag_id = ctx.memory(|mem| mem.interaction().drag_id); if drag_id.is_some() && drag_id != Some(id) { return None; @@ -647,8 +647,8 @@ fn window_interaction( hover_window_interaction.set_cursor(ctx); if ctx.input(|i| i.pointer.any_pressed() && i.pointer.primary_down()) { ctx.memory_mut(|mem| { - mem.interaction.drag_id = Some(id); - mem.interaction.drag_is_window = true; + mem.interaction_mut().drag_id = Some(id); + mem.interaction_mut().drag_is_window = true; window_interaction = Some(hover_window_interaction); mem.set_window_interaction(window_interaction); }); @@ -657,7 +657,7 @@ fn window_interaction( } if let Some(window_interaction) = window_interaction { - let is_active = ctx.memory_mut(|mem| mem.interaction.drag_id == Some(id)); + let is_active = ctx.memory_mut(|mem| mem.interaction().drag_id == Some(id)); if is_active && window_interaction.area_layer_id == area_layer_id { return Some(window_interaction); @@ -685,7 +685,7 @@ fn resize_hover( } } - if ctx.memory(|mem| mem.interaction.drag_interest) { + if ctx.memory(|mem| mem.interaction().drag_interest) { // Another widget will become active if we drag here return None; } diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 65d3068ab81..234506d2d4a 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -191,13 +191,6 @@ struct ContextImpl { impl ContextImpl { fn begin_frame_mut(&mut self, mut new_raw_input: RawInput, id_pair: ViewportIdPair) { - if let Some(id_pair) = self.viewport_stack.last().copied() { - let previous_viewport_id = id_pair.this; - - // Pause the active viewport - self.memory.pause_frame(previous_viewport_id); - } - let viewport_id = id_pair.this; self.viewport_stack.push(id_pair); self.output.entry(self.viewport_id()).or_default(); @@ -915,21 +908,25 @@ impl Context { } if sense.click || sense.drag { - memory.interaction.click_interest |= hovered && sense.click; - memory.interaction.drag_interest |= hovered && sense.drag; + let interaction = memory.interaction_mut(); - response.dragged = memory.interaction.drag_id == Some(id); + interaction.click_interest |= hovered && sense.click; + interaction.drag_interest |= hovered && sense.drag; + + response.dragged = interaction.drag_id == Some(id); response.is_pointer_button_down_on = - memory.interaction.click_id == Some(id) || response.dragged; + interaction.click_id == Some(id) || response.dragged; for pointer_event in &input.pointer.pointer_events { match pointer_event { PointerEvent::Moved(_) => {} PointerEvent::Pressed { .. } => { if hovered { - if sense.click && memory.interaction.click_id.is_none() { + let interaction = memory.interaction_mut(); + + if sense.click && interaction.click_id.is_none() { // potential start of a click - memory.interaction.click_id = Some(id); + interaction.click_id = Some(id); response.is_pointer_button_down_on = true; } @@ -939,12 +936,11 @@ impl Context { // This is needed because we do window interaction first (to prevent frame delay), // and then do content layout. if sense.drag - && (memory.interaction.drag_id.is_none() - || memory.interaction.drag_is_window) + && (interaction.drag_id.is_none() || interaction.drag_is_window) { // potential start of a drag - memory.interaction.drag_id = Some(id); - memory.interaction.drag_is_window = false; + interaction.drag_id = Some(id); + interaction.drag_is_window = false; memory.set_window_interaction(None); // HACK: stop moving windows (if any) response.is_pointer_button_down_on = true; response.dragged = true; @@ -1598,7 +1594,7 @@ impl Context { } else { let viewport_id = self.viewport_id(); self.write(|ctx| { - ctx.memory.resume_frame(viewport_id); + ctx.memory.set_viewport_id(viewport_id); }); } @@ -1751,12 +1747,12 @@ impl Context { /// /// NOTE: this will return `false` if the pointer is just hovering over an egui area. pub fn is_using_pointer(&self) -> bool { - self.memory(|m| m.interaction.is_using_pointer()) + self.memory(|m| m.interaction().is_using_pointer()) } /// If `true`, egui is currently listening on text input (e.g. typing text in a [`TextEdit`]). pub fn wants_keyboard_input(&self) -> bool { - self.memory(|m| m.interaction.focus.focused().is_some()) + self.memory(|m| m.interaction().focus.focused().is_some()) } /// Highlight this widget, to make it look like it is hovered, even if it isn't. @@ -1960,7 +1956,7 @@ impl Context { .on_hover_text("Is egui currently listening for text input?"); ui.label(format!( "Keyboard focus widget: {}", - self.memory(|m| m.interaction.focus.focused()) + self.memory(|m| m.interaction().focus.focused()) .as_ref() .map(Id::short_debug_format) .unwrap_or_default() @@ -2167,7 +2163,7 @@ impl Context { ui.label("NOTE: the position of this window cannot be reset from within itself."); ui.collapsing("Interaction", |ui| { - let interaction = self.memory(|mem| mem.interaction.clone()); + let interaction = self.memory(|mem| mem.interaction().clone()); interaction.ui(ui); }); } diff --git a/crates/egui/src/memory.rs b/crates/egui/src/memory.rs index fcff2d5f77e..343e0598d37 100644 --- a/crates/egui/src/memory.rs +++ b/crates/egui/src/memory.rs @@ -78,12 +78,6 @@ pub struct Memory { #[cfg_attr(feature = "persistence", serde(skip))] pub(crate) new_font_definitions: Option, - #[cfg_attr(feature = "persistence", serde(skip))] - pub(crate) interactions: ViewportIdMap, - - #[cfg_attr(feature = "persistence", serde(skip))] - pub(crate) interaction: Interaction, - // Current viewport #[cfg_attr(feature = "persistence", serde(skip))] pub(crate) viewport_id: ViewportId, @@ -100,11 +94,13 @@ pub struct Memory { everything_is_visible: bool, // ------------------------------------------------- - // Per-viewport: #[cfg_attr(feature = "persistence", serde(skip))] areas: ViewportIdMap, + #[cfg_attr(feature = "persistence", serde(skip))] + pub(crate) interactions: ViewportIdMap, + #[cfg_attr(feature = "persistence", serde(skip))] window_interactions: ViewportIdMap, } @@ -118,7 +114,6 @@ impl Default for Memory { override_pixels_per_point: Default::default(), new_font_definitions: Default::default(), interactions: Default::default(), - interaction: Default::default(), viewport_id: Default::default(), window_interactions: Default::default(), drag_value: Default::default(), @@ -126,6 +121,7 @@ impl Default for Memory { popup: Default::default(), everything_is_visible: Default::default(), }; + slf.interactions.entry(slf.viewport_id).or_default(); slf.areas.entry(slf.viewport_id).or_default(); slf } @@ -555,7 +551,6 @@ impl Memory { .entry(viewport_id) .or_default() .begin_frame(prev_input, new_input); - self.interaction = self.interactions.remove(&viewport_id).unwrap(); self.areas.entry(viewport_id).or_default(); if !prev_input.pointer.any_down() { @@ -563,11 +558,6 @@ impl Memory { } } - pub(crate) fn pause_frame(&mut self, viewport_id: ViewportId) { - self.interactions - .insert(viewport_id, std::mem::take(&mut self.interaction)); - } - pub(crate) fn end_frame( &mut self, input: &InputState, @@ -576,9 +566,7 @@ impl Memory { ) { self.caches.update(); self.areas_mut().end_frame(); - self.interaction.focus.end_frame(used_ids); - self.interactions - .insert(self.viewport_id, std::mem::take(&mut self.interaction)); + self.interaction_mut().focus.end_frame(used_ids); self.drag_value.end_frame(input); self.interactions.retain(|id, _| viewports.contains(id)); self.areas.retain(|id, _| viewports.contains(id)); @@ -586,8 +574,7 @@ impl Memory { .retain(|id, _| viewports.contains(id)); } - pub(crate) fn resume_frame(&mut self, viewport_id: ViewportId) { - self.interaction = self.interactions.remove(&viewport_id).unwrap_or_default(); + pub(crate) fn set_viewport_id(&mut self, viewport_id: ViewportId) { self.viewport_id = viewport_id; } @@ -614,7 +601,7 @@ impl Memory { } pub(crate) fn had_focus_last_frame(&self, id: Id) -> bool { - self.interaction.focus.id_previous_frame == Some(id) + self.interaction().focus.id_previous_frame == Some(id) } /// True if the given widget had keyboard focus last frame, but not this one. @@ -635,12 +622,12 @@ impl Memory { /// from the window and back. #[inline(always)] pub fn has_focus(&self, id: Id) -> bool { - self.interaction.focus.focused() == Some(id) + self.interaction().focus.focused() == Some(id) } /// Which widget has keyboard focus? pub fn focus(&self) -> Option { - self.interaction.focus.focused() + self.interaction().focus.focused() } /// Set an event filter for a widget. @@ -651,7 +638,7 @@ impl Memory { /// You must first give focus to the widget before calling this. pub fn set_focus_lock_filter(&mut self, id: Id, event_filter: EventFilter) { if self.had_focus_last_frame(id) && self.has_focus(id) { - if let Some(focused) = &mut self.interaction.focus.focused_widget { + if let Some(focused) = &mut self.interaction_mut().focus.focused_widget { if focused.id == id { focused.filter = event_filter; } @@ -678,15 +665,16 @@ impl Memory { /// See also [`crate::Response::request_focus`]. #[inline(always)] pub fn request_focus(&mut self, id: Id) { - self.interaction.focus.focused_widget = Some(FocusWidget::new(id)); + self.interaction_mut().focus.focused_widget = Some(FocusWidget::new(id)); } /// Surrender keyboard focus for a specific widget. /// See also [`crate::Response::surrender_focus`]. #[inline(always)] pub fn surrender_focus(&mut self, id: Id) { - if self.interaction.focus.focused() == Some(id) { - self.interaction.focus.focused_widget = None; + let interaction = self.interaction_mut(); + if interaction.focus.focused() == Some(id) { + interaction.focus.focused_widget = None; } } @@ -699,37 +687,37 @@ impl Memory { /// and rendered correctly in a single frame. #[inline(always)] pub fn interested_in_focus(&mut self, id: Id) { - self.interaction.focus.interested_in_focus(id); + self.interaction_mut().focus.interested_in_focus(id); } /// Stop editing of active [`TextEdit`](crate::TextEdit) (if any). #[inline(always)] pub fn stop_text_input(&mut self) { - self.interaction.focus.focused_widget = None; + self.interaction_mut().focus.focused_widget = None; } /// Is any widget being dragged? #[inline(always)] pub fn is_anything_being_dragged(&self) -> bool { - self.interaction.drag_id.is_some() + self.interaction().drag_id.is_some() } /// Is this specific widget being dragged? #[inline(always)] pub fn is_being_dragged(&self, id: Id) -> bool { - self.interaction.drag_id == Some(id) + self.interaction().drag_id == Some(id) } /// Set which widget is being dragged. #[inline(always)] pub fn set_dragged_id(&mut self, id: Id) { - self.interaction.drag_id = Some(id); + self.interaction_mut().drag_id = Some(id); } /// Stop dragging any widget. #[inline(always)] pub fn stop_dragging(&mut self) { - self.interaction.drag_id = None; + self.interaction_mut().drag_id = None; } /// Forget window positions, sizes etc. @@ -754,6 +742,16 @@ impl Memory { self.window_interactions.remove(&self.viewport_id); } } + + pub(crate) fn interaction(&self) -> &Interaction { + self.interactions + .get(&self.viewport_id) + .expect("Failed to get interaction") + } + + pub(crate) fn interaction_mut(&mut self) -> &mut Interaction { + self.interactions.entry(self.viewport_id).or_default() + } } /// ## Popups